From 8943da5aeeefb0db7775837dbfea729d75cc8434 Mon Sep 17 00:00:00 2001 From: Brandon Dyck Date: Mon, 9 Sep 2024 15:00:17 -0600 Subject: [PATCH] Check that Slice has correct position after matching --- gigaparsec.go | 23 ++++++++++------------- parser_test.go | 23 ++++++++++++++++------- 2 files changed, 26 insertions(+), 20 deletions(-) diff --git a/gigaparsec.go b/gigaparsec.go index 2f734fb..874f7a3 100644 --- a/gigaparsec.go +++ b/gigaparsec.go @@ -31,30 +31,27 @@ func (pe ParseError) Error() string { return fmt.Sprintf("parse error: %d: %s", pe.Pos, pe.Got) } -type State[T any] struct { - cursor cursor.Cursor[T] +func MakeState[In any](c cursor.Cursor[In]) State[In] { + return State[In]{cursor: c} } -func (s State[T]) Cursor() cursor.Cursor[T] { +type State[In any] struct { + cursor cursor.Cursor[In] +} + +func (s State[In]) Cursor() cursor.Cursor[In] { return s.cursor } -func (s State[T]) Read(dst []T) (n uint64, next State[T], err error) { +func (s State[In]) Read(dst []In) (n uint64, next State[In], err error) { n, c, err := s.cursor.Read(dst) - return n, State[T]{cursor: c}, err + return n, State[In]{cursor: c}, err } -func (s State[T]) Pos() uint64 { +func (s State[In]) Pos() uint64 { return s.cursor.Pos() } -func Parse[In, Out any](p Parser[In, Out], c cursor.Cursor[In]) (result Out, err error) { - st := State[In]{cursor: c} - var reply Result[In, Out] - _, reply, err = p(st) - return reply.Value, err -} - type Parser[In, Out any] func(State[In]) (consumed bool, reply Result[In, Out], err error) func Return[In, Out any](value Out) Parser[In, Out] { diff --git a/parser_test.go b/parser_test.go index 74c6409..babbe67 100644 --- a/parser_test.go +++ b/parser_test.go @@ -27,26 +27,35 @@ func TestSlice(t *testing.T) { s := rapid.SliceOfN(rapid.Byte(), 1, -1).Draw(t, "s") input := rapid.SliceOfN(rapid.Byte(), len(s), -1). Filter(notP(hasPrefix(s))).Draw(t, "input") - out, err := gigaparsec.Parse(gigaparsec.Slice(s), cursor.NewSlice(input)) + start := gigaparsec.MakeState(cursor.NewSlice(input)) + + consumed, result, err := gigaparsec.Slice(s)(start) test.ErrorAs(t, err, &gigaparsec.ParseError{}) - test.SliceEmpty(t, out) + test.False(t, consumed, test.Sprint("expected consumed to be false")) + test.SliceEmpty(t, result.Value) })) t.Run("fails at end of input", rapid.MakeCheck(func(t *rapid.T) { s := rapid.SliceOfN(rapid.Byte(), 1, -1).Draw(t, "s") inputLen := rapid.IntRange(0, len(s)-1).Draw(t, "inputLen") input := s[:inputLen] - out, err := gigaparsec.Parse(gigaparsec.Slice(s), cursor.NewSlice(input)) + start := gigaparsec.MakeState(cursor.NewSlice(input)) + + consumed, result, err := gigaparsec.Slice(s)(start) test.ErrorAs(t, err, &gigaparsec.ParseError{}) - test.SliceEmpty(t, out) + test.False(t, consumed, test.Sprint("expected consumed to be false")) + test.SliceEmpty(t, result.Value) })) t.Run("fails when read fails", Todo) t.Run("succeeds when contents match", rapid.MakeCheck(func(t *rapid.T) { input := rapid.SliceOfN(rapid.Byte(), 1, -1).Draw(t, "input") sLen := rapid.IntRange(0, len(input)).Draw(t, "sLen") s := input[:sLen] - out, err := gigaparsec.Parse(gigaparsec.Slice(s), cursor.NewSlice(input)) + start := gigaparsec.MakeState(cursor.NewSlice(input)) + + consumed, result, err := gigaparsec.Slice(s)(start) test.NoError(t, err) - test.SliceEqOp(t, s, out) + test.True(t, consumed, test.Sprint("expected consumed to be true")) + test.SliceEqOp(t, s, result.Value) + test.EqOp(t, uint64(len(s)), result.State.Pos()) })) - t.Run("next state has correct position", Todo) }