aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMatthew Hall <hallmatthew314@gmail.com>2023-03-17 23:32:54 +1300
committerMatthew Hall <hallmatthew314@gmail.com>2023-03-17 23:32:54 +1300
commit72236e9bcaf7bff4a2bfbeb50ddf5d0261f74927 (patch)
tree231d0b059e1a19c8b096395d88d14b069711b763 /src
parent982d239252b54297ff3558894038871f8d3a4175 (diff)
So far so good
Diffstat (limited to 'src')
-rw-r--r--src/parcom/parser.cr44
1 files changed, 42 insertions, 2 deletions
diff --git a/src/parcom/parser.cr b/src/parcom/parser.cr
index adf0bba..3098080 100644
--- a/src/parcom/parser.cr
+++ b/src/parcom/parser.cr
@@ -80,9 +80,19 @@ module Parcom
satisfy(block)
end
+ # Creates a parser that parses the fist token in the input stream
+ # if that token matches the provided token.
+ def self.token(token : T) : Parser(T, T)
+ Parser(T, T).satisfy { |x| x == token }.named("Token <#{token}>")
+ end
+
+ # Creates a new parser from a `Proc`.
+ # The `Proc` should have the properties outlined above.
def initialize(@name : String, @f : Tokens(T) -> Result(T, U))
end
+ # Creates a new parser from a block.
+ # The block should have the properties outline above.
def initialize(@name : String, &block : Tokens(T) -> Result(T, U))
@f = block
end
@@ -97,16 +107,24 @@ module Parcom
self
end
+ # Tries to parse some kind of data from the given input stream.
+ # This method calls the `Proc` or block this parser object was
+ # initialized with.
def parse(tokens : Tokens(T)) : Result(T, U)
@f.call(tokens)
end
+ # Same as `#parse(Tokens(T)) : Result(T, U)`, but returns `nil`
+ # instead of raising an exception if parsing fails.
def parse?(tokens : Tokens(T)) : Result(T, U)?
parse(tokens)
rescue
nil
end
+ # Creates a new parser that is the same as the parser object it is
+ # called from, but tests the result against a given predicate.
+ # If the value does not pass the test, the parser fails.
def assert(f : U -> Bool) : Parser(T, U)
p = self
Parser(T, U).new("#{p.name} (assertion)") do |tokens|
@@ -118,20 +136,42 @@ module Parcom
end
end
+ # :ditto:
def assert(&block : U -> Bool) : Parser(T, U)
assert(block)
end
- def map(f : U -> T) : Parser(T, V) forall V
+ # Creates a new parser that is the same as the parser object it is
+ # called from, but transforms the result into something else via a
+ # given function.
+ # The function in question should not introduce side effects.
+ def map(f : U -> V) : Parser(T, V) forall V
p = self
Parser(T, V).new("#{p.name} (mapped)") do |tokens|
p.parse(tokens).map(f)
end
end
- def map(&block : U -> T) : Parser(T, V) forall V
+ # :ditto:
+ def map(&block : U -> V) : Parser(T, V) forall V
map(block)
end
+
+ def |(p2 : Parser(T, U)) : Parser(T, U)
+ p1 = self
+ Parser(T, U).new("#{p1.name} or #{p2.name}") do |tokens|
+ p1.parse(tokens)
+ rescue ParserFail
+ p2.parse(tokens)
+ end
+ end
+
+ # Creates a new parser that is the same as the parser object it is
+ # called from, but it will return a default value without consuming
+ # any input instead of failing.
+ #def recover(default : U) : Parser(T, U)
+ # nil
+ #end
end
end