aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--spec/parcom_spec.cr32
-rw-r--r--src/parcom.cr36
2 files changed, 68 insertions, 0 deletions
diff --git a/spec/parcom_spec.cr b/spec/parcom_spec.cr
index 77a14dd..d67f19a 100644
--- a/spec/parcom_spec.cr
+++ b/spec/parcom_spec.cr
@@ -308,6 +308,38 @@ describe Plus do
end
end
+# most behavior shouldn't need to be tested
+# since it is based on tested bbehavior from
+# Plus and Map
+describe Left do
+ describe "#parse" do
+ it "returns the value of the first parser if both succeed" do
+ tokens = TokenStream.from_string("testing")
+ letter_t = Token.new('t')
+ letter_e = Token.new('e')
+ result = (letter_t << letter_e).parse(tokens)
+
+ result.value.should eq('t')
+ result.tokens.should eq(tokens[2..])
+ end
+ end
+end
+
+# same deal as Left
+describe Right do
+ describe "#parse" do
+ it "returns the value of the second parser if both succeed" do
+ tokens = TokenStream.from_string("testing")
+ letter_t = Token.new('t')
+ letter_e = Token.new('e')
+ result = (letter_t >> letter_e).parse(tokens)
+
+ result.value.should eq('e')
+ result.tokens.should eq(tokens[2..])
+ end
+ end
+end
+
describe Phrase do
p = Phrase.new(Token.new('t'))
diff --git a/src/parcom.cr b/src/parcom.cr
index 2a61c2d..f0295a3 100644
--- a/src/parcom.cr
+++ b/src/parcom.cr
@@ -67,6 +67,14 @@ module Parcom
Plus.new(self, other)
end
+ def <<(other : Parser(T, U)) : Left(T, V, U) forall U
+ Left.new(self, other)
+ end
+
+ def >>(other : Parser(T, U)) : Right(T, V, U) forall U
+ Right.new(self, other)
+ end
+
def assert(f : V -> Bool)
Assert.new(self, &f)
end
@@ -233,6 +241,34 @@ module Parcom
end
end
+ class Left(T, V, U) < Parser(T, V)
+ @p : Map(T, {V, U}, V)
+
+ def initialize(p1 : Parser(T, V), p2 : Parser(T, U))
+ @p = (p1 + p2).map(&.first)
+ end
+
+ def parse(tokens : TokenStream(T)) : Result(T, V)
+ @p.parse(tokens)
+ rescue ex : ParserException
+ raise ParserException.new("Left: #{ex.message}")
+ end
+ end
+
+ class Right(T, V, U) < Parser(T, U)
+ @p : Map(T, {V, U}, U)
+
+ def initialize(p1 : Parser(T, V), p2 : Parser(T, U))
+ @p = (p1 + p2).map(&.last)
+ end
+
+ def parse(tokens : TokenStream(T)) : Result(T, U)
+ @p.parse(tokens)
+ rescue ex : ParserException
+ raise ParserException.new("Right: #{ex.message}")
+ end
+ end
+
class Recover(T, V) < Parser(T, V)
@p : Map(T, V?, V)