From 9760da4df4ee38af9f133547c06290c674661848 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sun, 20 Aug 2023 21:19:34 -0400 Subject: [PATCH] wip --- spec/propane_spec.rb | 139 +++++++++++++++++-- spec/test_error_positions.c | 39 ++++++ spec/test_error_positions.d | 1 - spec/test_lexer_match_text.c | 15 ++ spec/test_lexer_modes.c | 20 +++ spec/test_lexer_result_value.c | 19 +++ spec/test_parser_identical_rules_lookahead.c | 17 +++ spec/test_parser_rule_from_multiple_states.c | 24 ++++ spec/test_parser_rule_user_code.c | 13 ++ spec/test_parsing_lists.c | 24 ++++ spec/test_pattern.c | 20 +++ spec/test_return_token_from_pattern.c | 13 ++ spec/test_user_code.c | 20 +++ 13 files changed, 355 insertions(+), 9 deletions(-) create mode 100644 spec/test_error_positions.c create mode 100644 spec/test_lexer_match_text.c create mode 100644 spec/test_lexer_modes.c create mode 100644 spec/test_lexer_result_value.c create mode 100644 spec/test_parser_identical_rules_lookahead.c create mode 100644 spec/test_parser_rule_from_multiple_states.c create mode 100644 spec/test_parser_rule_user_code.c create mode 100644 spec/test_parsing_lists.c create mode 100644 spec/test_pattern.c create mode 100644 spec/test_return_token_from_pattern.c create mode 100644 spec/test_user_code.c diff --git a/spec/propane_spec.rb b/spec/propane_spec.rb index 7d0d612..8f84189 100644 --- a/spec/propane_spec.rb +++ b/spec/propane_spec.rb @@ -310,7 +310,22 @@ EOF end it "executes user code when matching lexer token" do - write_grammar < +>> +token abc << + printf("abc!\\n"); +>> +token def; +Start -> Abcs def; +Abcs -> ; +Abcs -> abc Abcs; +EOF + when "d" + write_grammar <> @@ -322,6 +337,7 @@ Start -> Abcs def; Abcs -> ; Abcs -> abc Abcs; EOF + end build_parser(language: language) compile("spec/test_user_code.#{language}", language: language) results = run @@ -336,7 +352,20 @@ EOF end it "supports a pattern statement" do - write_grammar < +>> +token abc; +/def/ << + printf("def!\\n"); +>> +Start -> abc; +EOF + when "d" + write_grammar <> @@ -346,6 +375,7 @@ token abc; >> Start -> abc; EOF + end build_parser(language: language) compile("spec/test_pattern.#{language}", language: language) results = run @@ -360,7 +390,24 @@ EOF end it "supports returning tokens from pattern code blocks" do - write_grammar < +>> +token abc; +/def/ << + printf("def!\\n"); +>> +/ghi/ << + printf("ghi!\\n"); + return $token(abc); +>> +Start -> abc; +EOF + when "d" + write_grammar <> @@ -374,6 +421,7 @@ token abc; >> Start -> abc; EOF + end build_parser(language: language) compile("spec/test_return_token_from_pattern.#{language}", language: language) results = run @@ -386,7 +434,31 @@ EOF end it "supports lexer modes" do - write_grammar < +>> +token abc; +token def; +tokenid string; +drop /\\s+/; +/"/ << + printf("begin string mode\\n"); + $mode(string); +>> +string: /[^"]+/ << + printf("captured string\\n"); +>> +string: /"/ << + $mode(default); + return $token(string); +>> +Start -> abc string def; +EOF + when "d" + write_grammar <> @@ -407,6 +479,7 @@ string: /"/ << >> Start -> abc string def; EOF + end build_parser(language: language) compile("spec/test_lexer_modes.#{language}", language: language) results = run @@ -422,7 +495,26 @@ EOF end it "executes user code associated with a parser rule" do - write_grammar < +>> +token a; +token b; +Start -> A B << + printf("Start!\\n"); +>> +A -> a << + printf("A!\\n"); +>> +B -> b << + printf("B!\\n"); +>> +EOF + when "d" + write_grammar <> @@ -438,6 +530,7 @@ B -> b << writeln("B!"); >> EOF + end build_parser(language: language) compile("spec/test_parser_rule_user_code.#{language}", language: language) results = run @@ -451,7 +544,7 @@ EOF it "parses lists" do write_grammar < As << $$ = $1; @@ -490,7 +583,23 @@ EOF end it "provides matched text to user code blocks" do - write_grammar < +#include +>> +token id /[a-zA-Z_][a-zA-Z0-9_]*/ << + char * t = malloc(match_length + 1); + strncpy(t, (char *)match, match_length); + printf("Matched token is %s\\n", t); + free(t); +>> +Start -> id; +EOF + when "d" + write_grammar <> @@ -499,6 +608,7 @@ token id /[a-zA-Z_][a-zA-Z0-9_]*/ << >> Start -> id; EOF + end build_parser(language: language) compile("spec/test_lexer_match_text.#{language}", language: language) results = run @@ -510,7 +620,19 @@ EOF end it "allows storing a result value for the lexer" do - write_grammar <> +Start -> word << + $$ = $1; +>> +EOF + when "d" + write_grammar < word << $$ = $1; >> EOF + end build_parser(language: language) compile("spec/test_lexer_result_value.#{language}", language: language) results = run diff --git a/spec/test_error_positions.c b/spec/test_error_positions.c new file mode 100644 index 0000000..b871449 --- /dev/null +++ b/spec/test_error_positions.c @@ -0,0 +1,39 @@ +#include "testparser.h" +#include +#include + +int main() +{ + char const * input = "a 42"; + p_context_t context; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_SUCCESS); + + input = "a\n123\na a"; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_UNEXPECTED_TOKEN); + assert(p_position(&context).row == 2); + assert(p_position(&context).col == 3); + assert(context.token == TOKEN_a); + + input = "12"; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_UNEXPECTED_TOKEN); + assert(p_position(&context).row == 0); + assert(p_position(&context).col == 0); + assert(context.token == TOKEN_num); + + input = "a 12\n\nab"; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_UNEXPECTED_INPUT); + assert(p_position(&context).row == 2); + assert(p_position(&context).col == 1); + + input = "a 12\n\na\n\n77\na \xAA"; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_DECODE_ERROR); + assert(p_position(&context).row == 5); + assert(p_position(&context).col == 4); + + return 0; +} diff --git a/spec/test_error_positions.d b/spec/test_error_positions.d index c8c4059..0282252 100644 --- a/spec/test_error_positions.d +++ b/spec/test_error_positions.d @@ -33,6 +33,5 @@ unittest input = "a 12\n\na\n\n77\na \xAA"; p_context_init(&context, input); assert(p_parse(&context) == P_DECODE_ERROR); - writeln(p_position(&context)); assert(p_position(&context) == p_position_t(5, 4)); } diff --git a/spec/test_lexer_match_text.c b/spec/test_lexer_match_text.c new file mode 100644 index 0000000..e7104d9 --- /dev/null +++ b/spec/test_lexer_match_text.c @@ -0,0 +1,15 @@ +#include "testparser.h" +#include +#include +#include + +int main() +{ + char const * input = "identifier_123"; + p_context_t context; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_SUCCESS); + printf("pass1\n"); + + return 0; +} diff --git a/spec/test_lexer_modes.c b/spec/test_lexer_modes.c new file mode 100644 index 0000000..c8e3c90 --- /dev/null +++ b/spec/test_lexer_modes.c @@ -0,0 +1,20 @@ +#include "testparser.h" +#include +#include +#include + +int main() +{ + char const * input = "abc \"a string\" def"; + p_context_t context; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_SUCCESS); + printf("pass1\n"); + + input = "abc \"abc def\" def"; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_SUCCESS); + printf("pass2\n"); + + return 0; +} diff --git a/spec/test_lexer_result_value.c b/spec/test_lexer_result_value.c new file mode 100644 index 0000000..251c6f2 --- /dev/null +++ b/spec/test_lexer_result_value.c @@ -0,0 +1,19 @@ +#include "testparser.h" +#include +#include + +int main() +{ + char const * input = "x"; + p_context_t context; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_SUCCESS); + assert(p_result(&context) == 1u); + + input = "fabulous"; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_SUCCESS); + assert(p_result(&context) == 8u); + + return 0; +} diff --git a/spec/test_parser_identical_rules_lookahead.c b/spec/test_parser_identical_rules_lookahead.c new file mode 100644 index 0000000..c66932d --- /dev/null +++ b/spec/test_parser_identical_rules_lookahead.c @@ -0,0 +1,17 @@ +#include "testparser.h" +#include +#include + +int main() +{ + char const * input = "aba"; + p_context_t context; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_SUCCESS); + + input = "abb"; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_SUCCESS); + + return 0; +} diff --git a/spec/test_parser_rule_from_multiple_states.c b/spec/test_parser_rule_from_multiple_states.c new file mode 100644 index 0000000..3acf0ce --- /dev/null +++ b/spec/test_parser_rule_from_multiple_states.c @@ -0,0 +1,24 @@ +#include "testparser.h" +#include +#include + +int main() +{ + char const * input = "a"; + p_context_t context; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_UNEXPECTED_TOKEN); + assert(p_position(&context).row == 0); + assert(p_position(&context).col == 1); + assert(context.token == TOKEN___EOF); + + input = "a b"; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_SUCCESS); + + input = "bb"; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_SUCCESS); + + return 0; +} diff --git a/spec/test_parser_rule_user_code.c b/spec/test_parser_rule_user_code.c new file mode 100644 index 0000000..d191cc7 --- /dev/null +++ b/spec/test_parser_rule_user_code.c @@ -0,0 +1,13 @@ +#include "testparser.h" +#include +#include + +int main() +{ + char const * input = "ab"; + p_context_t context; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_SUCCESS); + + return 0; +} diff --git a/spec/test_parsing_lists.c b/spec/test_parsing_lists.c new file mode 100644 index 0000000..e78d8f1 --- /dev/null +++ b/spec/test_parsing_lists.c @@ -0,0 +1,24 @@ +#include "testparser.h" +#include +#include + +int main() +{ + char const * input = "a"; + p_context_t context; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_SUCCESS); + assert(p_result(&context) == 1u); + + input = ""; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_SUCCESS); + assert(p_result(&context) == 0u); + + input = "aaaaaaaaaaaaaaaa"; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_SUCCESS); + assert(p_result(&context) == 16u); + + return 0; +} diff --git a/spec/test_pattern.c b/spec/test_pattern.c new file mode 100644 index 0000000..193c957 --- /dev/null +++ b/spec/test_pattern.c @@ -0,0 +1,20 @@ +#include "testparser.h" +#include +#include +#include + +int main() +{ + char const * input = "abcdef"; + p_context_t context; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_SUCCESS); + printf("pass1\n"); + + input = "defabcdef"; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_SUCCESS); + printf("pass2\n"); + + return 0; +} diff --git a/spec/test_return_token_from_pattern.c b/spec/test_return_token_from_pattern.c new file mode 100644 index 0000000..a8be3d2 --- /dev/null +++ b/spec/test_return_token_from_pattern.c @@ -0,0 +1,13 @@ +#include "testparser.h" +#include +#include + +int main() +{ + char const * input = "defghidef"; + p_context_t context; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_SUCCESS); + + return 0; +} diff --git a/spec/test_user_code.c b/spec/test_user_code.c new file mode 100644 index 0000000..cd853bc --- /dev/null +++ b/spec/test_user_code.c @@ -0,0 +1,20 @@ +#include "testparser.h" +#include +#include +#include + +int main() +{ + char const * input = "abcdef"; + p_context_t context; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_SUCCESS); + printf("pass1\n"); + + input = "abcabcdef"; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert(p_parse(&context) == P_SUCCESS); + printf("pass2\n"); + + return 0; +}