diff --git a/gigaparsec.go b/gigaparsec.go index e2a43c1..dde93a0 100644 --- a/gigaparsec.go +++ b/gigaparsec.go @@ -3,20 +3,21 @@ package gigaparsec import ( "errors" "fmt" -) + "io" -// TODO Everything. See https://smunix.github.io/dev.stephendiehl.com/fun/002_parsers.html. + "git.codemonkeysoftware.net/b/gigaparsec/cursor" +) var ErrNoParse = errors.New("no parse") -type Result[T any] struct { - Value T - State +type Result[In, Out any] struct { + Value Out + State[In] Message } type Message struct { - Pos + Pos uint64 Msg string Expected []string } @@ -29,47 +30,46 @@ func (pe ParseError) Error() string { return fmt.Sprintf("parse error: %d: %s", pe.Message.Pos, pe.Message.Msg) } -type Pos uint64 +type State[T any] cursor.Cursor[T] -type State struct { - Pos - Input []byte -} +type Parser[In, Out any] func(State[In]) (consumed bool, reply Result[In, Out], err error) -type Parser[T any] func(State) (consumed bool, reply Result[T], err error) - -func Return[T any](value T) Parser[T] { - return func(state State) (bool, Result[T], error) { - return false, Result[T]{Value: value, State: state}, nil +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 } } -func Satisfy(pred func(byte) bool) Parser[byte] { - return func(state State) (bool, Result[byte], error) { - if len(state.Input) == 0 { - return false, Result[byte]{}, ErrNoParse +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) + if errors.Is(err, io.EOF) { + return false, Result[T, T]{}, ErrNoParse } - b := state.Input[0] - if pred(b) { - return true, Result[byte]{Value: b, State: state.Input[1:]}, nil + if n != 1 { + panic(fmt.Sprintf("expected 1 element from Read, but got %d", n)) } - return false, Result[byte]{}, ErrNoParse + if pred(b[0]) { + return true, Result[T, T]{Value: b[0], State: next}, nil + } + return false, Result[T, T]{}, ErrNoParse } } -func Bind[A, B any](p Parser[A], f func(A) Parser[B]) Parser[B] { - return func(input State) (bool, Result[B], error) { - consumed, replyA, err := p(input) +func Bind[In, A, B any](p Parser[In, A], f func(A) Parser[In, B]) Parser[In, B] { + return func(input State[In]) (bool, Result[In, B], error) { + consumed, resultA, err := p(input) if err != nil { - return false, Result[B]{}, err + return false, Result[In, B]{}, err } - consumed2, replyB, err := f(replyA.Value)(replyA.Rest) + consumed2, replyB, err := f(resultA.Value)(resultA.State) return consumed || consumed2, replyB, err } } -func Choose[A any](p, q Parser[A]) Parser[A] { - return func(input State) (bool, Result[A], error) { +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) if consumedP { return consumedP, replyP, errP @@ -85,11 +85,11 @@ func Choose[A any](p, q Parser[A]) Parser[A] { } } -func Try[A any](p Parser[A]) Parser[A] { - return func(input State) (bool, Result[A], error) { +func Try[In, Out any](p Parser[In, Out]) Parser[In, Out] { + return func(input State[In]) (bool, Result[In, Out], error) { consumed, reply, err := p(input) if err != nil { - return false, Result[A]{}, err + return false, Result[In, Out]{}, err } return consumed, reply, err }