diff options
| author | Matthew Hall <hallmatthew314@gmail.com> | 2023-03-09 16:20:10 +1300 |
|---|---|---|
| committer | Matthew Hall <hallmatthew314@gmail.com> | 2023-03-09 16:20:10 +1300 |
| commit | 5b94e65c29f141b40b4d0333a1de6968d1670b1e (patch) | |
| tree | 9997696b6a9e346bce63848a30062c14efab6b81 | |
| parent | 15e3a96876ca9e8bd67c7408ebcc123c35a1e447 (diff) | |
Implement Sequence
| -rw-r--r-- | spec/parcom_spec.cr | 26 | ||||
| -rw-r--r-- | src/parcom.cr | 17 |
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 |
