Write a few core parsers from the Parsec paper

This commit is contained in:
Brandon Dyck 2024-09-02 11:34:26 -06:00
parent 3e524a5a5b
commit ffe949b97b

View File

@ -3,20 +3,21 @@ package gigaparsec
import ( import (
"errors" "errors"
"fmt" "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") var ErrNoParse = errors.New("no parse")
type Result[T any] struct { type Result[In, Out any] struct {
Value T Value Out
State State[In]
Message Message
} }
type Message struct { type Message struct {
Pos Pos uint64
Msg string Msg string
Expected []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) 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 { type Parser[In, Out any] func(State[In]) (consumed bool, reply Result[In, Out], err error)
Pos
Input []byte
}
type Parser[T any] func(State) (consumed bool, reply Result[T], err error) func Return[In, Out any](value Out) Parser[In, Out] {
return func(state State[In]) (bool, Result[In, Out], error) {
func Return[T any](value T) Parser[T] { return false, Result[In, Out]{Value: value, State: state}, nil
return func(state State) (bool, Result[T], error) {
return false, Result[T]{Value: value, State: state}, nil
} }
} }
func Satisfy(pred func(byte) bool) Parser[byte] { func Satisfy[T any](pred func(T) bool) Parser[T, T] {
return func(state State) (bool, Result[byte], error) { return func(state State[T]) (bool, Result[T, T], error) {
if len(state.Input) == 0 { b := make([]T, 1)
return false, Result[byte]{}, ErrNoParse n, next, err := state.Read(b)
if errors.Is(err, io.EOF) {
return false, Result[T, T]{}, ErrNoParse
} }
b := state.Input[0] if n != 1 {
if pred(b) { panic(fmt.Sprintf("expected 1 element from Read, but got %d", n))
return true, Result[byte]{Value: b, State: state.Input[1:]}, nil
} }
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] { func Bind[In, A, B any](p Parser[In, A], f func(A) Parser[In, B]) Parser[In, B] {
return func(input State) (bool, Result[B], error) { return func(input State[In]) (bool, Result[In, B], error) {
consumed, replyA, err := p(input) consumed, resultA, err := p(input)
if err != nil { 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 return consumed || consumed2, replyB, err
} }
} }
func Choose[A any](p, q Parser[A]) Parser[A] { func Choose[In, Out any](p, q Parser[In, Out]) Parser[In, Out] {
return func(input State) (bool, Result[A], error) { return func(input State[In]) (bool, Result[In, Out], error) {
consumedP, replyP, errP := p(input) consumedP, replyP, errP := p(input)
if consumedP { if consumedP {
return consumedP, replyP, errP 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] { func Try[In, Out any](p Parser[In, Out]) Parser[In, Out] {
return func(input State) (bool, Result[A], error) { return func(input State[In]) (bool, Result[In, Out], error) {
consumed, reply, err := p(input) consumed, reply, err := p(input)
if err != nil { if err != nil {
return false, Result[A]{}, err return false, Result[In, Out]{}, err
} }
return consumed, reply, err return consumed, reply, err
} }