97 lines
2.0 KiB
Go
97 lines
2.0 KiB
Go
|
package gigaparsec
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
)
|
||
|
|
||
|
// TODO Everything. See https://smunix.github.io/dev.stephendiehl.com/fun/002_parsers.html.
|
||
|
|
||
|
var ErrNoParse = errors.New("no parse")
|
||
|
|
||
|
type Result[T any] struct {
|
||
|
Value T
|
||
|
State
|
||
|
Message
|
||
|
}
|
||
|
|
||
|
type Message struct {
|
||
|
Pos
|
||
|
Msg string
|
||
|
Expected []string
|
||
|
}
|
||
|
|
||
|
type ParseError struct {
|
||
|
Message
|
||
|
}
|
||
|
|
||
|
func (pe ParseError) Error() string {
|
||
|
return fmt.Sprintf("parse error: %d: %s", pe.Message.Pos, pe.Message.Msg)
|
||
|
}
|
||
|
|
||
|
type Pos uint64
|
||
|
|
||
|
type State struct {
|
||
|
Pos
|
||
|
Input []byte
|
||
|
}
|
||
|
|
||
|
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 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
|
||
|
}
|
||
|
b := state.Input[0]
|
||
|
if pred(b) {
|
||
|
return true, Result[byte]{Value: b, State: state.Input[1:]}, nil
|
||
|
}
|
||
|
return false, Result[byte]{}, 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)
|
||
|
if err != nil {
|
||
|
return false, Result[B]{}, err
|
||
|
}
|
||
|
consumed2, replyB, err := f(replyA.Value)(replyA.Rest)
|
||
|
return consumed || consumed2, replyB, err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func Choose[A any](p, q Parser[A]) Parser[A] {
|
||
|
return func(input State) (bool, Result[A], error) {
|
||
|
consumedP, replyP, errP := p(input)
|
||
|
if consumedP {
|
||
|
return consumedP, replyP, errP
|
||
|
}
|
||
|
if errP != nil {
|
||
|
return q(input)
|
||
|
}
|
||
|
consumedQ, replyQ, errQ := q(input)
|
||
|
if consumedQ {
|
||
|
return consumedQ, replyQ, errQ
|
||
|
}
|
||
|
return consumedP, replyP, errP
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func Try[A any](p Parser[A]) Parser[A] {
|
||
|
return func(input State) (bool, Result[A], error) {
|
||
|
consumed, reply, err := p(input)
|
||
|
if err != nil {
|
||
|
return false, Result[A]{}, err
|
||
|
}
|
||
|
return consumed, reply, err
|
||
|
}
|
||
|
}
|