Don't require so much Pos() when making messages

This commit is contained in:
b
2026-08-21 22:36:36 -06:00
parent cc25ac923f
commit 17b2a0eee5
9 changed files with 81 additions and 69 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
Think about not requiring so much Pos() when making messages
Think about changing "consume" to "commit" Think about changing "consume" to "commit"
Should MakeState be private now that there's Run? Should MakeState be private now that there's Run?
I need to be able to test combinators at a lower level than Run.
What's Megaparsec got that we ain't got? What's Megaparsec got that we ain't got?
chainl chainl
+9 -9
View File
@@ -33,7 +33,7 @@ func Bind[In, Out, T any](
return Fail[In, Out](anyConsumed, r2.Message()), nil return Fail[In, Out](anyConsumed, r2.Message()), nil
} }
return Succeed(anyConsumed, val2, next, MessageOK(s.Pos())), nil return Succeed(anyConsumed, val2, next, s.MessageOK()), nil
} }
} }
@@ -77,7 +77,7 @@ func Bind2[In, Out, T, T2 any](
return Fail[In, Out](anyConsumed, r3.Message()), nil return Fail[In, Out](anyConsumed, r3.Message()), nil
} }
return Succeed(anyConsumed, val3, next, MessageOK(s.Pos())), nil return Succeed(anyConsumed, val3, next, s.MessageOK()), nil
} }
} }
@@ -132,7 +132,7 @@ func Bind3[In, Out, T, T2, T3 any](
return Fail[In, Out](anyConsumed, r4.Message()), nil return Fail[In, Out](anyConsumed, r4.Message()), nil
} }
return Succeed(anyConsumed, val4, next, MessageOK(s.Pos())), nil return Succeed(anyConsumed, val4, next, s.MessageOK()), nil
} }
} }
@@ -198,7 +198,7 @@ func Bind4[In, Out, T, T2, T3, T4 any](
return Fail[In, Out](anyConsumed, r5.Message()), nil return Fail[In, Out](anyConsumed, r5.Message()), nil
} }
return Succeed(anyConsumed, val5, next, MessageOK(s.Pos())), nil return Succeed(anyConsumed, val5, next, s.MessageOK()), nil
} }
} }
@@ -275,7 +275,7 @@ func Bind5[In, Out, T, T2, T3, T4, T5 any](
return Fail[In, Out](anyConsumed, r6.Message()), nil return Fail[In, Out](anyConsumed, r6.Message()), nil
} }
return Succeed(anyConsumed, val6, next, MessageOK(s.Pos())), nil return Succeed(anyConsumed, val6, next, s.MessageOK()), nil
} }
} }
@@ -363,7 +363,7 @@ func Bind6[In, Out, T, T2, T3, T4, T5, T6 any](
return Fail[In, Out](anyConsumed, r7.Message()), nil return Fail[In, Out](anyConsumed, r7.Message()), nil
} }
return Succeed(anyConsumed, val7, next, MessageOK(s.Pos())), nil return Succeed(anyConsumed, val7, next, s.MessageOK()), nil
} }
} }
@@ -462,7 +462,7 @@ func Bind7[In, Out, T, T2, T3, T4, T5, T6, T7 any](
return Fail[In, Out](anyConsumed, r8.Message()), nil return Fail[In, Out](anyConsumed, r8.Message()), nil
} }
return Succeed(anyConsumed, val8, next, MessageOK(s.Pos())), nil return Succeed(anyConsumed, val8, next, s.MessageOK()), nil
} }
} }
@@ -572,7 +572,7 @@ func Bind8[In, Out, T, T2, T3, T4, T5, T6, T7, T8 any](
return Fail[In, Out](anyConsumed, r9.Message()), nil return Fail[In, Out](anyConsumed, r9.Message()), nil
} }
return Succeed(anyConsumed, val9, next, MessageOK(s.Pos())), nil return Succeed(anyConsumed, val9, next, s.MessageOK()), nil
} }
} }
@@ -693,6 +693,6 @@ func Bind9[In, Out, T, T2, T3, T4, T5, T6, T7, T8, T9 any](
return Fail[In, Out](anyConsumed, r10.Message()), nil return Fail[In, Out](anyConsumed, r10.Message()), nil
} }
return Succeed(anyConsumed, val10, next, MessageOK(s.Pos())), nil return Succeed(anyConsumed, val10, next, s.MessageOK()), nil
} }
} }
+6 -6
View File
@@ -70,14 +70,14 @@ func Regexp(pattern string) gigaparsec.Parser[byte, string] {
} }
if idx == nil { if idx == nil {
if err == io.EOF { if err == io.EOF {
return gigaparsec.Fail[byte, string](false, gigaparsec.MessageEnd(input.Pos())), nil return gigaparsec.Fail[byte, string](false, input.MessageOK()), nil
} }
got := make([]byte, r.Count()) got := make([]byte, r.Count())
_, _, err = input.Read(got) _, _, err = input.Read(got)
if err != nil { if err != nil {
return gigaparsec.Result[byte, string]{}, fmt.Errorf("Regexp: unexpected error: %w", err) return gigaparsec.Result[byte, string]{}, fmt.Errorf("Regexp: unexpected error: %w", err)
} }
return gigaparsec.Fail[byte, string](false, gigaparsec.MakeMessage(input.Pos(), string(got), expected)), nil return gigaparsec.Fail[byte, string](false, input.Message(string(got), expected)), nil
} }
// Alas, this is a little wasteful because a Regexp can only return indices // Alas, this is a little wasteful because a Regexp can only return indices
// when searching a RuneReader. // when searching a RuneReader.
@@ -87,7 +87,7 @@ func Regexp(pattern string) gigaparsec.Parser[byte, string] {
return gigaparsec.Result[byte, string]{}, fmt.Errorf("Regexp: unexpected error: %w", err) return gigaparsec.Result[byte, string]{}, fmt.Errorf("Regexp: unexpected error: %w", err)
} }
next := input.At(input.Pos() + n) next := input.At(input.Pos() + n)
return gigaparsec.Succeed(true, string(dst), next, gigaparsec.MessageOK(input.Pos())), nil return gigaparsec.Succeed(true, string(dst), next, input.MessageOK()), nil
} }
} }
@@ -98,14 +98,14 @@ func MatchString(s string) gigaparsec.Parser[byte, string] {
dst := make([]byte, len(s)) dst := make([]byte, len(s))
_, next, err := input.Read(dst) _, next, err := input.Read(dst)
if errors.Is(err, io.EOF) { if errors.Is(err, io.EOF) {
return gigaparsec.Fail[byte, string](false, gigaparsec.MessageEnd(input.Pos(), expected)), nil return gigaparsec.Fail[byte, string](false, input.MessageEnd(expected)), nil
} }
if err != nil { if err != nil {
return gigaparsec.Result[byte, string]{}, fmt.Errorf("MatchString: %w", err) return gigaparsec.Result[byte, string]{}, fmt.Errorf("MatchString: %w", err)
} }
if !bytes.Equal(dst, b) { if !bytes.Equal(dst, b) {
return gigaparsec.Fail[byte, string](false, gigaparsec.MakeMessage(input.Pos(), string(dst), expected)), nil return gigaparsec.Fail[byte, string](false, input.Message(string(dst), expected)), nil
} }
return gigaparsec.Succeed(true, s, next, gigaparsec.MessageOK(input.Pos())), nil return gigaparsec.Succeed(true, s, next, input.MessageOK()), nil
} }
} }
+51 -39
View File
@@ -59,12 +59,24 @@ func (r Result[In, Out]) Message() Message {
return r.message return r.message
} }
func MakeMessage(pos uint64, got string, expected ...string) Message { type ReaderAt[T any] interface {
return Message{ ReadAt(p []T, off int64) (n int, err error)
pos: pos,
got: got,
expected: expected,
} }
type SliceReaderAt[T any] []T
func (s SliceReaderAt[T]) ReadAt(dst []T, off int64) (n int, err error) {
if off < 0 {
return 0, errors.New("SliceReaderAt.ReadAt: negative offset")
}
if off >= int64(len(s)) {
return 0, io.EOF
}
n = copy(dst, s[off:])
if n < len(dst) {
err = io.EOF
}
return n, err
} }
type Message struct { type Message struct {
@@ -107,36 +119,26 @@ func (m Message) String() string {
return s return s
} }
func MakeMessage(pos uint64, got string, expected ...string) Message {
return Message{
pos: pos,
got: got,
expected: expected,
}
}
func MessageOK(pos uint64) Message { return Message{pos: pos} } func MessageOK(pos uint64) Message { return Message{pos: pos} }
func MessageEnd(pos uint64, expected ...string) Message { func MessageEnd(pos uint64, expected ...string) Message {
return Message{pos: pos, got: "end of input", expected: expected} return Message{pos: pos, got: "end of input", expected: expected}
} }
type ReaderAt[T any] interface { // MakeState creates a new State
ReadAt(p []T, off int64) (n int, err error)
}
type SliceReaderAt[T any] []T
func (s SliceReaderAt[T]) ReadAt(dst []T, off int64) (n int, err error) {
if off < 0 {
return 0, errors.New("SliceReaderAt.ReadAt: negative offset")
}
if off >= int64(len(s)) {
return 0, io.EOF
}
n = copy(dst, s[off:])
if n < len(dst) {
err = io.EOF
}
return n, err
}
func MakeState[In any](r ReaderAt[In]) State[In] { func MakeState[In any](r ReaderAt[In]) State[In] {
return State[In]{r: r} return State[In]{r: r}
} }
// State represents a position in an input source.
type State[In any] struct { type State[In any] struct {
r ReaderAt[In] r ReaderAt[In]
pos uint64 pos uint64
@@ -176,6 +178,16 @@ func (s State[In]) At(pos uint64) State[In] {
return State[In]{r: s.r, pos: pos} return State[In]{r: s.r, pos: pos}
} }
func (s State[In]) Message(got string, expected ...string) Message {
return MakeMessage(s.pos, got, expected...)
}
func (s State[In]) MessageOK() Message { return MessageOK(s.pos) }
func (s State[in]) MessageEnd(expected ...string) Message {
return MessageEnd(s.pos, expected...)
}
type Parser[In, Out any] func(State[In]) (Result[In, Out], error) type Parser[In, Out any] func(State[In]) (Result[In, Out], error)
// Label creates a parser identical to p, except that a failed result will // Label creates a parser identical to p, except that a failed result will
@@ -238,7 +250,7 @@ func (pe ParseError) Error() string {
// Return creates a parser that always succeeds and returns value without consuming any input. // Return creates a parser that always succeeds and returns value without consuming any input.
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]) (Result[In, Out], error) { return func(state State[In]) (Result[In, Out], error) {
return Succeed(false, value, state, MessageOK(state.Pos())), nil return Succeed(false, value, state, state.MessageOK()), nil
} }
} }
@@ -249,7 +261,7 @@ func Satisfy[T any](pred func(T) bool) Parser[T, T] {
token := make([]T, 1) token := make([]T, 1)
n, next, err := state.Read(token) n, next, err := state.Read(token)
if errors.Is(err, io.EOF) { if errors.Is(err, io.EOF) {
return Fail[T, T](false, MessageEnd(state.Pos())), nil return Fail[T, T](false, state.MessageEnd()), nil
} }
if err != nil { if err != nil {
return Result[T, T]{}, err return Result[T, T]{}, err
@@ -258,9 +270,9 @@ func Satisfy[T any](pred func(T) bool) Parser[T, T] {
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(token[0]) { if pred(token[0]) {
return Succeed(true, token[0], next, MessageOK(state.Pos())), nil return Succeed(true, token[0], next, state.MessageOK()), nil
} }
return Fail[T, T](false, MakeMessage(state.Pos(), fmt.Sprint(token))), nil return Fail[T, T](false, state.Message(fmt.Sprint(token))), nil
} }
} }
@@ -272,15 +284,15 @@ func Match[T comparable](x T) Parser[T, T] {
token := make([]T, 1) token := make([]T, 1)
_, next, err := state.Read(token) _, next, err := state.Read(token)
if errors.Is(err, io.EOF) { if errors.Is(err, io.EOF) {
return Fail[T, T](false, MessageEnd(state.Pos())), nil return Fail[T, T](false, state.MessageEnd()), nil
} }
if err != nil { if err != nil {
return Result[T, T]{}, err return Result[T, T]{}, err
} }
if token[0] == x { if token[0] == x {
return Succeed(true, token[0], next, MessageOK(state.Pos())), nil return Succeed(true, token[0], next, state.MessageOK()), nil
} }
return Fail[T, T](false, MakeMessage(state.Pos(), fmt.Sprint(token), expected)), nil return Fail[T, T](false, state.Message(fmt.Sprint(token), expected)), nil
} }
} }
@@ -292,15 +304,15 @@ func MatchSlice[T comparable](s []T) Parser[T, []T] {
token := make([]T, len(s)) token := make([]T, len(s))
_, next, err := state.Read(token) _, next, err := state.Read(token)
if errors.Is(err, io.EOF) { if errors.Is(err, io.EOF) {
return Fail[T, []T](false, MessageEnd(state.Pos())), nil return Fail[T, []T](false, state.MessageEnd()), nil
} }
if err != nil { if err != nil {
return Result[T, []T]{}, err return Result[T, []T]{}, err
} }
if !slices.Equal(s, token) { if !slices.Equal(s, token) {
return Fail[T, []T](false, MakeMessage(state.Pos(), fmt.Sprint(token), expected)), nil return Fail[T, []T](false, state.Message(fmt.Sprint(token), expected)), nil
} }
return Succeed(true, token, next, MessageOK(state.Pos())), nil return Succeed(true, token, next, state.MessageOK()), nil
} }
} }
@@ -337,7 +349,7 @@ func Choose[In, Out any](p Parser[In, Out], ps ...Parser[In, Out]) Parser[In, Ou
got = qMsg.got got = qMsg.got
} }
} }
msg := MakeMessage(input.Pos(), got, slices.Concat(expecteds...)...) msg := input.Message(got, slices.Concat(expecteds...)...)
if failed { if failed {
return Fail[In, Out](false, msg), nil return Fail[In, Out](false, msg), nil
} }
@@ -367,12 +379,12 @@ func Try[In, Out any](p Parser[In, Out]) Parser[In, Out] {
func end[In any](s State[In]) (Result[In, struct{}], error) { func end[In any](s State[In]) (Result[In, struct{}], error) {
_, _, err := s.Read([]In{}) _, _, err := s.Read([]In{})
if errors.Is(err, io.EOF) { if errors.Is(err, io.EOF) {
return Succeed(true, struct{}{}, s, MessageOK(s.Pos())), nil return Succeed(true, struct{}{}, s, s.MessageOK()), nil
} }
if err != nil { if err != nil {
return Result[In, struct{}]{}, fmt.Errorf("End: unexpected error: %w", err) return Result[In, struct{}]{}, fmt.Errorf("End: unexpected error: %w", err)
} }
return Fail[In, struct{}](false, MakeMessage(s.Pos(), "", "end of input")), nil return Fail[In, struct{}](false, s.Message("", "end of input")), nil
} }
// End creates a parser that succeeds at the end of the input and fails otherwise. // End creates a parser that succeeds at the end of the input and fails otherwise.
@@ -407,7 +419,7 @@ func Repeat[In, Out any](minCount int, p Parser[In, Out]) Parser[In, []Out] {
success, value, nextState := result.Status() success, value, nextState := result.Status()
if !success { if !success {
if len(values) >= minCount { if len(values) >= minCount {
return Succeed(consumed, values, currState, MessageOK(state.Pos())), nil return Succeed(consumed, values, currState, state.MessageOK()), nil
} }
return Fail[In, []Out](consumed, result.Message()), nil return Fail[In, []Out](consumed, result.Message()), nil
} }
+1 -1
View File
@@ -24,7 +24,7 @@ func Bind{{.}}[In, Out{{range .Count}}, T{{.}}{{end}} any](
return Fail[In, Out](anyConsumed, r{{.}}.Message()), nil return Fail[In, Out](anyConsumed, r{{.}}.Message()), nil
} }
{{end}} {{end}}
return Succeed(anyConsumed, val{{.Next}}, next, MessageOK(s.Pos())), nil return Succeed(anyConsumed, val{{.Next}}, next, s.MessageOK()), nil
} }
}{{end -}} }{{end -}}
+1 -1
View File
@@ -22,7 +22,7 @@ func Seq{{if gt . 2}}{{.}}{{end}}[In, Out{{range .Count}}, T{{.}}{{end}} any](
} }
{{end}} {{end}}
final := f({{range .Count}}{{if ne . 1}}, {{end}}val{{.}}{{end}}) final := f({{range .Count}}{{if ne . 1}}, {{end}}val{{.}}{{end}})
return Succeed(anyConsumed, final, next, MessageOK(s.Pos())), nil return Succeed(anyConsumed, final, next, s.MessageOK()), nil
} }
}{{end}}{{end -}} }{{end}}{{end -}}
+8 -8
View File
@@ -35,7 +35,7 @@ func Seq[In, Out, T, T2 any](
} }
final := f(val, val2) final := f(val, val2)
return Succeed(anyConsumed, final, next, MessageOK(s.Pos())), nil return Succeed(anyConsumed, final, next, s.MessageOK()), nil
} }
} }
@@ -81,7 +81,7 @@ func Seq3[In, Out, T, T2, T3 any](
} }
final := f(val, val2, val3) final := f(val, val2, val3)
return Succeed(anyConsumed, final, next, MessageOK(s.Pos())), nil return Succeed(anyConsumed, final, next, s.MessageOK()), nil
} }
} }
@@ -138,7 +138,7 @@ func Seq4[In, Out, T, T2, T3, T4 any](
} }
final := f(val, val2, val3, val4) final := f(val, val2, val3, val4)
return Succeed(anyConsumed, final, next, MessageOK(s.Pos())), nil return Succeed(anyConsumed, final, next, s.MessageOK()), nil
} }
} }
@@ -206,7 +206,7 @@ func Seq5[In, Out, T, T2, T3, T4, T5 any](
} }
final := f(val, val2, val3, val4, val5) final := f(val, val2, val3, val4, val5)
return Succeed(anyConsumed, final, next, MessageOK(s.Pos())), nil return Succeed(anyConsumed, final, next, s.MessageOK()), nil
} }
} }
@@ -285,7 +285,7 @@ func Seq6[In, Out, T, T2, T3, T4, T5, T6 any](
} }
final := f(val, val2, val3, val4, val5, val6) final := f(val, val2, val3, val4, val5, val6)
return Succeed(anyConsumed, final, next, MessageOK(s.Pos())), nil return Succeed(anyConsumed, final, next, s.MessageOK()), nil
} }
} }
@@ -375,7 +375,7 @@ func Seq7[In, Out, T, T2, T3, T4, T5, T6, T7 any](
} }
final := f(val, val2, val3, val4, val5, val6, val7) final := f(val, val2, val3, val4, val5, val6, val7)
return Succeed(anyConsumed, final, next, MessageOK(s.Pos())), nil return Succeed(anyConsumed, final, next, s.MessageOK()), nil
} }
} }
@@ -476,7 +476,7 @@ func Seq8[In, Out, T, T2, T3, T4, T5, T6, T7, T8 any](
} }
final := f(val, val2, val3, val4, val5, val6, val7, val8) final := f(val, val2, val3, val4, val5, val6, val7, val8)
return Succeed(anyConsumed, final, next, MessageOK(s.Pos())), nil return Succeed(anyConsumed, final, next, s.MessageOK()), nil
} }
} }
@@ -588,6 +588,6 @@ func Seq9[In, Out, T, T2, T3, T4, T5, T6, T7, T8, T9 any](
} }
final := f(val, val2, val3, val4, val5, val6, val7, val8, val9) final := f(val, val2, val3, val4, val5, val6, val7, val8, val9)
return Succeed(anyConsumed, final, next, MessageOK(s.Pos())), nil return Succeed(anyConsumed, final, next, s.MessageOK()), nil
} }
} }
+3 -3
View File
@@ -42,15 +42,15 @@ func ForceResult(state gigaparsec.State[ForcedResult]) (gigaparsec.Result[Forced
buf := make([]ForcedResult, 1) buf := make([]ForcedResult, 1)
_, next, err := state.Read(buf) _, next, err := state.Read(buf)
if errors.Is(err, io.EOF) { if errors.Is(err, io.EOF) {
return gigaparsec.Fail[ForcedResult, struct{}](false, gigaparsec.MessageEnd(state.Pos())), nil return gigaparsec.Fail[ForcedResult, struct{}](false, state.MessageEnd()), nil
} }
if err != nil { if err != nil {
return gigaparsec.Result[ForcedResult, struct{}]{}, err return gigaparsec.Result[ForcedResult, struct{}]{}, err
} }
tok := buf[0] tok := buf[0]
if tok.Succeed { if tok.Succeed {
return gigaparsec.Succeed(tok.Consume, struct{}{}, next, gigaparsec.MessageOK(state.Pos())), nil return gigaparsec.Succeed(tok.Consume, struct{}{}, next, state.MessageOK()), nil
} else { } else {
return gigaparsec.Fail[ForcedResult, struct{}](tok.Consume, gigaparsec.MakeMessage(state.Pos(), "Succeed=false", "Succeed=true")), nil return gigaparsec.Fail[ForcedResult, struct{}](tok.Consume, state.Message("Succeed=false", "Succeed=true")), nil
} }
} }