diff options
| author | Matthew Hall <hallmatthew314@gmail.com> | 2023-03-13 13:10:50 +1300 |
|---|---|---|
| committer | Matthew Hall <hallmatthew314@gmail.com> | 2023-03-13 13:10:50 +1300 |
| commit | c2197ee71ac1cc3cb2ad3bf8a93b579f7251316e (patch) | |
| tree | e4c23056e68652fe37972faf4c2bea7b74fb8a21 | |
| parent | c340687df1215940d33eb822f46598f51e5b3b95 (diff) | |
Fix Many hanging when wrapped parser never fails
| -rw-r--r-- | spec/parcom_spec.cr | 10 | ||||
| -rw-r--r-- | src/parcom.cr | 23 | ||||
| -rw-r--r-- | src/parcom/many.cr | 28 |
3 files changed, 38 insertions, 23 deletions
diff --git a/spec/parcom_spec.cr b/spec/parcom_spec.cr index 11d2446..dde6f21 100644 --- a/spec/parcom_spec.cr +++ b/spec/parcom_spec.cr @@ -494,6 +494,16 @@ describe Many do result.value.should eq("aaa".chars) result.tokens.should eq(tokens[3..]) end + + it "stops parsing when the wapped parser succeeds without consuming any input" do + a_optional : Parser(Char, Char?) + a_optional = Optional.new(Token.new('a')) + tokens = Tokens.from_string("aaa") + result = Many(Char, Char?).new(a_optional).parse(tokens) + + result.value.should eq("aaa".chars) + result.tokens.should eq(tokens[3..]) + end end end diff --git a/src/parcom.cr b/src/parcom.cr index 6715e07..c7dde7b 100644 --- a/src/parcom.cr +++ b/src/parcom.cr @@ -119,29 +119,6 @@ module Parcom end end - class Many(T, V) < Parser(T, Array(V)) - def initialize(@p : Parser(T, V)) - end - - def parse(tokens : Tokens(T)) : Result(T, Array(V)) - parsed = [] of V - - loop do - result = @p.parse?(tokens) - if result.nil? - break - else - parsed << result.value - tokens = result.tokens - end - end - - Result.new(tokens, parsed) - rescue ex : ParserFail - raise ParserFail.new("Many: #{ex.message}") - end - end - class Some(T, V) < Parser(T, Array(V)) @p : Assert(T, Array(V)) diff --git a/src/parcom/many.cr b/src/parcom/many.cr new file mode 100644 index 0000000..dbe3b13 --- /dev/null +++ b/src/parcom/many.cr @@ -0,0 +1,28 @@ +require "./parser.cr" + +module Parcom + class Many(T, V) < Parser(T, Array(V)) + def initialize(@p : Parser(T, V)) + end + + def parse(tokens : Tokens(T)) : Result(T, Array(V)) + parsed = [] of V + + loop do + result = @p.parse?(tokens) + + if !result.nil? && result.tokens != tokens + parsed << result.value + tokens = result.tokens + else + break + end + end + + Result.new(tokens, parsed) + rescue ex : ParserFail + raise ParserFail.new("Many: #{ex.message}") + end + end +end + |
