From b274828831fec26cd8b3089ffef14cb96ce2de2f Mon Sep 17 00:00:00 2001 From: Matthew Hall Date: Thu, 16 Mar 2023 20:36:03 +1300 Subject: Second rewrite attempt, this one should work, monkaS --- src/parcom.cr | 56 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 13 deletions(-) (limited to 'src/parcom.cr') diff --git a/src/parcom.cr b/src/parcom.cr index ddb2e50..d12b011 100644 --- a/src/parcom.cr +++ b/src/parcom.cr @@ -5,17 +5,6 @@ module Parcom # A ParserFail exception should be raised by `Parser#parse` when # a parse attempt is unsuccessful. - # Raising this exception in the `#parse` method of a Parser "Foo" - # usually follows this pattern to allow for error tracing: - # - # ``` - # class Foo(T, V) < Parser(T, V) - # def parse(tokens : Tokens(T)) : Result(T, V) - # helper.parse(tokens) - # rescue ex : ParserFail - # raise ParserFail.new("Foo: #{ex.message}") - # end - # ``` class ParserFail < Exception end @@ -74,10 +63,51 @@ module Parcom # This is used instead of a `Tuple` or `NamedTuple` because: # 1. This is more idiomatic than a `Tuple`. # 2. Crystal does not support generic named tuples. - struct Result(T, V) + struct Result(T, U) getter tokens, value - def initialize(@tokens : Tokens(T), @value : V) + def initialize(@tokens : Tokens(T), @value : U) + end + end + + class Parser(T, U) + getter name + + def initialize(@name : String, @f : Tokens(T) -> Result(T, U)) + end + + def initialize(@name : String, &block : Tokens(T) -> Result(T, U)) + @f = block + end + + def named(name : String) : self + @name = name + self + end + + def parse(tokens : Tokens(T)) : Result(T, U) + @f.call(tokens) + end + + def parse(tokens : Tokens(T)) : Result(T, U)? + parse(tokens) + rescue + nil + end + + def assert(f : U -> Bool) : Parser(T, U) + p = self + Parser.new("#{p.name} assertion") do |tokens| + result = p.parse(tokens) + unless f.call(r.value) + raise ParserFail.new("Assertion failed for value #{r.value}") + end + result + end + end + + def assert(&block : U -> Bool) : Parser(T, U) + assert(block) end end end -- cgit v1.2.1