Added Slice parser
This commit is contained in:
parent
c92ffde044
commit
727426d704
@ -9,8 +9,6 @@ import (
|
|||||||
"git.codemonkeysoftware.net/b/gigaparsec/cursor"
|
"git.codemonkeysoftware.net/b/gigaparsec/cursor"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrNoParse = errors.New("no parse")
|
|
||||||
|
|
||||||
type Result[In, Out any] struct {
|
type Result[In, Out any] struct {
|
||||||
Value Out
|
Value Out
|
||||||
State[In]
|
State[In]
|
||||||
@ -33,7 +31,22 @@ func (pe ParseError) Error() string {
|
|||||||
return fmt.Sprintf("parse error: %d: %s", pe.Pos, pe.Got)
|
return fmt.Sprintf("parse error: %d: %s", pe.Pos, pe.Got)
|
||||||
}
|
}
|
||||||
|
|
||||||
type State[T any] cursor.Cursor[T]
|
type State[T any] struct {
|
||||||
|
cursor cursor.Cursor[T]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s State[T]) Cursor() cursor.Cursor[T] {
|
||||||
|
return s.cursor
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s State[T]) Read(dst []T) (n uint64, next State[T], err error) {
|
||||||
|
n, c, err := s.cursor.Read(dst)
|
||||||
|
return n, State[T]{cursor: c}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s State[T]) Pos() uint64 {
|
||||||
|
return s.cursor.Pos()
|
||||||
|
}
|
||||||
|
|
||||||
type Parser[In, Out any] func(State[In]) (consumed bool, reply Result[In, Out], err error)
|
type Parser[In, Out any] func(State[In]) (consumed bool, reply Result[In, Out], err error)
|
||||||
|
|
||||||
@ -54,6 +67,9 @@ func Satisfy[T any](pred func(T) bool) Parser[T, T] {
|
|||||||
if errors.Is(err, io.EOF) {
|
if errors.Is(err, io.EOF) {
|
||||||
return false, Result[T, T]{}, ParseError(MessageEnd(state.Pos()))
|
return false, Result[T, T]{}, ParseError(MessageEnd(state.Pos()))
|
||||||
}
|
}
|
||||||
|
if err != nil {
|
||||||
|
return false, Result[T, T]{}, err
|
||||||
|
}
|
||||||
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))
|
||||||
}
|
}
|
||||||
@ -71,6 +87,32 @@ func Satisfy[T any](pred func(T) bool) Parser[T, T] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Slice[T comparable](s []T) Parser[T, []T] {
|
||||||
|
expected := fmt.Sprint(s)
|
||||||
|
return func(state State[T]) (consumed bool, reply Result[T, []T], err error) {
|
||||||
|
token := make([]T, len(s))
|
||||||
|
_, next, err := state.Read(token)
|
||||||
|
if errors.Is(err, io.EOF) {
|
||||||
|
return false, Result[T, []T]{}, ParseError(MessageEnd(state.Pos()))
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return false, Result[T, []T]{}, err
|
||||||
|
}
|
||||||
|
if !slices.Equal(s, token) {
|
||||||
|
return false, Result[T, []T]{}, ParseError{
|
||||||
|
Pos: state.Pos(),
|
||||||
|
Got: fmt.Sprint(token),
|
||||||
|
Expected: []string{expected},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, Result[T, []T]{
|
||||||
|
Value: token,
|
||||||
|
State: next,
|
||||||
|
Message: MessageOK(state.Pos()),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func Bind[In, A, B any](p Parser[In, A], f func(A) Parser[In, B]) Parser[In, B] {
|
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) {
|
return func(input State[In]) (bool, Result[In, B], error) {
|
||||||
consumed, resultA, err := p(input)
|
consumed, resultA, err := p(input)
|
||||||
|
Loading…
Reference in New Issue
Block a user