From a26ccb40ca98c82f486f1c57334ccc04534a1a23 Mon Sep 17 00:00:00 2001 From: Matthew Hall Date: Thu, 9 Mar 2023 21:32:35 +1300 Subject: Implement between + improve error handling --- src/parcom.cr | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 68 insertions(+), 9 deletions(-) (limited to 'src/parcom.cr') diff --git a/src/parcom.cr b/src/parcom.cr index 0a97e51..c1ac147 100644 --- a/src/parcom.cr +++ b/src/parcom.cr @@ -121,6 +121,8 @@ module Parcom def parse(tokens : TokenStream(T)) : Result(T, V) result = @p.parse(tokens) Result.new(tokens, result.value) + rescue ex : ParserException + raise ParserException.new("Peek: #{ex.message}") end end @@ -131,18 +133,28 @@ module Parcom def parse(tokens : TokenStream(T)) : Result(T, V) result = @p.parse(tokens) - + rescue ex : ParserException + raise ParserException.new("Assert (pre-assertion): #{ex.message}") + else unless @f.call(result.value) raise ParserException.new("Assert: predicate failed for <#{result.value}>") end - result + return result end end - class Satisfy(T) < Assert(T, T) + class Satisfy(T) < Parser(T, T) + @p : Assert(T, T) + def initialize(&block : T -> Bool) - super(AnyToken(T).new, &block) + @p = AnyToken(T).new.assert(&block) + end + + def parse(tokens : TokenStream(T)) : Result(T, T) + @p.parse(tokens) + rescue ex : ParserException + raise ParserException.new("Satisfy: #{ex.message}") end end @@ -164,8 +176,12 @@ module Parcom def parse(tokens : TokenStream(T)) : Result(T, V) @p1.parse(tokens) - rescue ParserException - @p2.parse(tokens) + rescue ex1 : ParserException + begin + @p2.parse(tokens) + rescue ex2 : ParserException + raise ParserException.new("Alt (#{ex1.message}), (#{ex2.message})") + end end end @@ -177,6 +193,8 @@ module Parcom def parse(tokens : TokenStream(T)) : Result(T, U) result = @p.parse(tokens) Result.new(result.tokens, @f.call(result.value)) + rescue ex : ParserException + raise ParserException.new("Map: #{ex.message}") end end @@ -189,6 +207,8 @@ module Parcom def parse(tokens : TokenStream(T)) : Result(T, V) @p.parse(tokens) + rescue ex : ParserException + raise ParserException.new("Phrase: #{ex.message}") end end @@ -197,8 +217,18 @@ module Parcom end def parse(tokens : TokenStream(T)) : Result(T, {V, U}) - r1 = @p1.parse(tokens) - r2 = @p2.parse(r1.tokens) + begin + r1 = @p1.parse(tokens) + rescue ex : ParserException + raise ParserException.new("Plus (left): #{ex.message}") + end + + begin + r2 = @p2.parse(r1.tokens) + rescue ex : ParserException + raise ParserException.new("Plus (right): #{ex.message}") + end + Result.new(r2.tokens, {r1.value, r2.value}) end end @@ -244,6 +274,8 @@ module Parcom end Result.new(tokens, parsed) + rescue ex : ParserException + raise ParserException.new("Sequence: #{ex.message}") end end @@ -259,6 +291,8 @@ module Parcom def parse(tokens : TokenStream(T)) : Result(T, Array(T)) @p.parse(tokens) + rescue ex : ParserException + raise ParserException.new("Tokens: #{ex.message}") end end @@ -280,6 +314,8 @@ module Parcom end Result.new(tokens, parsed) + rescue ex : ParserException + raise ParserException.new("Many: #{ex.message}") end end @@ -292,6 +328,8 @@ module Parcom def parse(tokens : TokenStream(T)) : Result(T, Array(V)) @p.parse(tokens) + rescue ex : ParserException + raise ParserException.new("Some: #{ex.message}") end end @@ -305,6 +343,8 @@ module Parcom def parse(tokens : TokenStream(T)) : Result(T, Array(V)) @p.parse(tokens) + rescue ex : ParserException + raise ParserException.new("Exactly: #{ex.message}") end end @@ -319,6 +359,8 @@ module Parcom def parse(tokens : TokenStream(T)) : Result(T, Array(V)) @p.parse(tokens) + rescue ex : ParserException + raise ParserException.new("AtLeast: #{ex.message}") end end @@ -331,10 +373,27 @@ module Parcom def parse(tokens : TokenStream(T)) : Result(T, Array(V)) @p.parse(tokens) + rescue ex : ParserException + raise ParserException.new("AtMost: #{ex.message}") end end - class Between + class Between(T, V) < Parser(T, Array(V)) + @p : Map(T, {Array(V), Array(V)}, Array(V)) + + def initialize(i : Int, j : Int, p : Parser(T, V)) + lower = i < j ? i : j + upper = (i - j).abs + @p = (Exactly.new(lower, p) + AtMost.new(upper, p)).map do |tup| + tup[0] + tup[1] + end + end + + def parse(tokens : TokenStream(T)) : Result(T, Array(V)) + @p.parse(tokens) + rescue ex : ParserException + raise ParserException.new("Between: #{ex.message}") + end end class StopAt -- cgit v1.2.1