Return error messages from Return and Satisfy

This commit is contained in:
Brandon Dyck 2024-09-02 15:31:08 -06:00
parent 0a1fe0821a
commit b3b90b7e6b

View File

@ -18,16 +18,18 @@ type Result[In, Out any] struct {
type Message struct { type Message struct {
Pos uint64 Pos uint64
Msg string Got string
Expected []string Expected []string
} }
type ParseError struct { func MessageOK(pos uint64) Message { return Message{Pos: pos} }
Message
} func MessageEnd(pos uint64) Message { return Message{Pos: pos, Got: "end of input"} }
type ParseError Message
func (pe ParseError) Error() string { 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] 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] { func Return[In, Out any](value Out) Parser[In, Out] {
return func(state State[In]) (bool, Result[In, Out], error) { 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] { func Satisfy[T any](pred func(T) bool) Parser[T, T] {
return func(state State[T]) (bool, Result[T, T], error) { return func(state State[T]) (bool, Result[T, T], error) {
b := make([]T, 1) token := make([]T, 1)
n, next, err := state.Read(b) n, next, err := state.Read(token)
if errors.Is(err, io.EOF) { if errors.Is(err, io.EOF) {
return false, Result[T, T]{}, ErrNoParse return false, Result[T, T]{}, ParseError(MessageEnd(state.Pos()))
} }
if n != 1 { if n != 1 {
panic(fmt.Sprintf("expected 1 element from Read, but got %d", n)) panic(fmt.Sprintf("expected 1 element from Read, but got %d", n))
} }
if pred(b[0]) { if pred(token[0]) {
return true, Result[T, T]{Value: b[0], State: next}, nil 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] { func Choose[In, Out any](p, q Parser[In, Out]) Parser[In, Out] {
return func(input State[In]) (bool, Result[In, Out], error) { return func(input State[In]) (bool, Result[In, Out], error) {
consumedP, replyP, errP := p(input) consumedP, replyP, errP := p(input)