aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Hall <hallmatthew314@gmail.com>2023-03-13 13:10:50 +1300
committerMatthew Hall <hallmatthew314@gmail.com>2023-03-13 13:10:50 +1300
commitc2197ee71ac1cc3cb2ad3bf8a93b579f7251316e (patch)
treee4c23056e68652fe37972faf4c2bea7b74fb8a21
parentc340687df1215940d33eb822f46598f51e5b3b95 (diff)
Fix Many hanging when wrapped parser never fails
-rw-r--r--spec/parcom_spec.cr10
-rw-r--r--src/parcom.cr23
-rw-r--r--src/parcom/many.cr28
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
+