From b3b90b7e6bfacb74104eade47dde479edcf2dddb Mon Sep 17 00:00:00 2001 From: Brandon Dyck Date: Mon, 2 Sep 2024 15:31:08 -0600 Subject: [PATCH] Return error messages from Return and Satisfy --- gigaparsec.go | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) diff --git a/gigaparsec.go b/gigaparsec.go index d6d223f..2cc9f02 100644 --- a/gigaparsec.go +++ b/gigaparsec.go @@ -18,16 +18,18 @@ type Result[In, Out any] struct { type Message struct { Pos uint64 - Msg string + Got string Expected []string } -type ParseError struct { - Message -} +func MessageOK(pos uint64) Message { return Message{Pos: pos} } + +func MessageEnd(pos uint64) Message { return Message{Pos: pos, Got: "end of input"} } + +type ParseError Message func (pe ParseError) Error() string { - return fmt.Sprintf("parse error: %d: %s", pe.Message.Pos, pe.Message.Msg) + return fmt.Sprintf("parse error: %d: %s", pe.Pos, pe.Got) } type State[T any] cursor.Cursor[T] @@ -36,24 +38,35 @@ type Parser[In, Out any] func(State[In]) (consumed bool, reply Result[In, Out], func Return[In, Out any](value Out) Parser[In, Out] { return func(state State[In]) (bool, Result[In, Out], error) { - return false, Result[In, Out]{Value: value, State: state}, nil + return false, Result[In, Out]{ + Value: value, + State: state, + Message: MessageOK(state.Pos()), + }, nil } } func Satisfy[T any](pred func(T) bool) Parser[T, T] { return func(state State[T]) (bool, Result[T, T], error) { - b := make([]T, 1) - n, next, err := state.Read(b) + token := make([]T, 1) + n, next, err := state.Read(token) if errors.Is(err, io.EOF) { - return false, Result[T, T]{}, ErrNoParse + return false, Result[T, T]{}, ParseError(MessageEnd(state.Pos())) } if n != 1 { panic(fmt.Sprintf("expected 1 element from Read, but got %d", n)) } - if pred(b[0]) { - return true, Result[T, T]{Value: b[0], State: next}, nil + if pred(token[0]) { + return true, Result[T, T]{ + Value: token[0], + State: next, + Message: MessageOK(state.Pos()), + }, nil + } + return false, Result[T, T]{}, ParseError{ + Pos: state.Pos(), + Got: fmt.Sprint(token), } - return false, Result[T, T]{}, ErrNoParse } } @@ -68,6 +81,7 @@ func Bind[In, A, B any](p Parser[In, A], f func(A) Parser[In, B]) Parser[In, B] } } +// TODO Add error propagation func Choose[In, Out any](p, q Parser[In, Out]) Parser[In, Out] { return func(input State[In]) (bool, Result[In, Out], error) { consumedP, replyP, errP := p(input)