aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthew Hall <hallmatthew314@gmail.com>2023-03-09 16:20:10 +1300
committerMatthew Hall <hallmatthew314@gmail.com>2023-03-09 16:20:10 +1300
commit5b94e65c29f141b40b4d0333a1de6968d1670b1e (patch)
tree9997696b6a9e346bce63848a30062c14efab6b81
parent15e3a96876ca9e8bd67c7408ebcc123c35a1e447 (diff)
Implement Sequence
-rw-r--r--spec/parcom_spec.cr26
-rw-r--r--src/parcom.cr17
2 files changed, 43 insertions, 0 deletions
diff --git a/spec/parcom_spec.cr b/spec/parcom_spec.cr
index 57c5024..9051cb7 100644
--- a/spec/parcom_spec.cr
+++ b/spec/parcom_spec.cr
@@ -378,6 +378,32 @@ describe Optional do
end
end
+describe Sequence do
+ # HACK: ps has to be declared this way due to contravariance
+ # https://crystal-lang.org/reference/1.7/syntax_and_semantics/inheritance.html#covariance-and-contravariance
+ ps = [] of Parser(Char, Char)
+ ps = ps + "abcd".chars.map { |c| Token.new(c) }
+ p = Sequence.new(ps)
+
+ describe "#parse" do
+ it "runs each wrapped parser in order, returns each result" do
+ tokens = TokenStream.from_string("abcd")
+ result = p.parse(tokens)
+
+ result.value.should eq("abcd".chars)
+ result.tokens.empty?.should be_true
+ end
+
+ it "fails if any of the wrapped parsers fail" do
+ fail_strings = ["", "abed", "bbcd", "abce"]
+ fail_strings.each do |s|
+ tokens = TokenStream.from_string(s)
+ expect_raises(ParserException) { p.parse(tokens) }
+ end
+ end
+ end
+end
+
describe Tokens do
p = Tokens.new("test".chars)
diff --git a/src/parcom.cr b/src/parcom.cr
index 8d7c754..6fc6339 100644
--- a/src/parcom.cr
+++ b/src/parcom.cr
@@ -228,6 +228,23 @@ module Parcom
end
end
+ class Sequence(T, V) < Parser(T, Array(V))
+ def initialize(@ps : Iterable(Parser(T, V)))
+ end
+
+ def parse(tokens : TokenStream(T)) : Result(T, Array(V))
+ parsed = [] of V
+
+ @ps.each do |p|
+ r = p.parse(tokens)
+ parsed << r.value
+ tokens = r.tokens
+ end
+
+ Result.new(tokens, parsed)
+ end
+ end
+
class Tokens(T) < Parser(T, Array(T))
def initialize(@expected : Iterable(T))
end