From e7e30c4f28e54df16e86ac996f9e63a27da4f559 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Fri, 30 Sep 2022 21:05:18 -0400 Subject: [PATCH] Add pattern statement --- assets/parser.d.erb | 11 ++++------- lib/propane/grammar.rb | 13 +++++++++++++ lib/propane/lexer.rb | 4 +++- spec/propane_spec.rb | 13 +++++++++++++ spec/test_pattern.d | 18 ++++++++++++++++++ 5 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 spec/test_pattern.d diff --git a/assets/parser.d.erb b/assets/parser.d.erb index ee5c9de..ca6821c 100644 --- a/assets/parser.d.erb +++ b/assets/parser.d.erb @@ -163,7 +163,7 @@ class <%= @classname %> for (;;) { LexedToken lt = attempt_lex_token(); - if (lt.token != _TOKEN_DROP) + if ((lt.token != _TOKEN_DROP) && (lt.token != _TOKEN_NONE)) { return lt; } @@ -236,7 +236,8 @@ class <%= @classname %> attempt_match_info.delta_col++; } current_state = dest; - if (states[current_state].token != _TOKEN_NONE) + if ((states[current_state].token != _TOKEN_NONE) || + (states[current_state].code_id != 0xFFFF_FFFFu)) { attempt_match_info.token = states[current_state].token; attempt_match_info.code_id = states[current_state].code_id; @@ -279,11 +280,7 @@ class <%= @classname %> { m_input_col += longest_match_info.delta_col; } - } - if (token_to_accept != _TOKEN_NONE) - { - /* We have a token to accept. */ - lt.token = longest_match_info.token; + lt.token = token_to_accept; lt.length = longest_match_info.length; break; } diff --git a/lib/propane/grammar.rb b/lib/propane/grammar.rb index 8fb499c..acfc6b6 100644 --- a/lib/propane/grammar.rb +++ b/lib/propane/grammar.rb @@ -32,6 +32,7 @@ class Propane elsif parse_comment_line! elsif parse_module_statement! elsif parse_class_statement! + elsif parse_pattern_statement! elsif parse_token_statement! elsif parse_tokenid_statement! elsif parse_drop_statement! @@ -125,6 +126,18 @@ class Propane end end + def parse_pattern_statement! + if pattern = parse_pattern! + consume!(/\s+/) + unless code = parse_code_block! + raise Error.new("Line #{@line_number}: expected code block to follow pattern") + end + code_id = @code_id + @code_id += 1 + @patterns << Pattern.new(pattern: pattern, line_number: @line_number, code: code, code_id: code_id) + end + end + def parse_pattern! if md = consume!(%r{/}) pattern = "" diff --git a/lib/propane/lexer.rb b/lib/propane/lexer.rb index ccb1835..2e05e58 100644 --- a/lib/propane/lexer.rb +++ b/lib/propane/lexer.rb @@ -19,8 +19,10 @@ class Propane TOKEN_NONE elsif state.accepts.drop? TOKEN_DROP - else + elsif state.accepts.token state.accepts.token.id + else + TOKEN_NONE end code_id = if state.accepts && state.accepts.code_id diff --git a/spec/propane_spec.rb b/spec/propane_spec.rb index 0d7af0c..50b8601 100644 --- a/spec/propane_spec.rb +++ b/spec/propane_spec.rb @@ -110,4 +110,17 @@ EOF compile("spec/test_user_code.d") run end + + it "supports a pattern statement" do + write_grammar <> +Start -> abc; +EOF + build_parser + compile("spec/test_pattern.d") + run + end end diff --git a/spec/test_pattern.d b/spec/test_pattern.d new file mode 100644 index 0000000..e441b95 --- /dev/null +++ b/spec/test_pattern.d @@ -0,0 +1,18 @@ +import testparser; +import std.stdio; + +int main() +{ + return 0; +} + +unittest +{ + string input = "abcdef"; + auto parser = new Testparser.Parser(cast(const(ubyte) *)input.ptr, input.length); + assert(parser.parse() == true); + + input = "defabcdef"; + parser = new Testparser.Parser(cast(const(ubyte) *)input.ptr, input.length); + assert(parser.parse() == true); +}