Added Repeat and listed necessary tests

This commit is contained in:
Brandon Dyck 2024-09-24 12:31:38 -06:00
parent 447058020f
commit 9cab6d266d
3 changed files with 35 additions and 1 deletions

View File

@ -1,4 +1,4 @@
Add repetition parsers to avoid some recursion
Write Repeat tests
Think about not requiring so much Pos() when making messages
Rename Seq2 to Seq
Document Seq

View File

@ -342,3 +342,30 @@ func Pipe[In, Ignore, Through any](p Parser[In, Ignore]) func(Through) Parser[In
})
}
}
// Repeat applies p until p fails, and returns the collected outputs.
// It succeeds if and only if p succeeds at least minCount times.
// It consumes if and only if at least one of the applications of p consumes.
func Repeat[In, Out any](minCount int, p Parser[In, Out]) Parser[In, []Out] {
return func(s State[In]) (Result[In, []Out], error) {
var values []Out
var consumed bool
next := s
for {
result, err := p(s)
if err != nil {
return Result[In, []Out]{}, fmt.Errorf("AtLeastN: %w", err)
}
consumed = consumed || result.Consumed()
if failed, _, msg := result.Failed(); failed {
if len(values) >= minCount {
return Succeed(consumed, values, next, MessageOK(s.Pos())), nil
}
return Fail[In, []Out](consumed, msg), nil
}
var value Out
_, _, value, next, _ = result.Succeeded()
values = append(values, value)
}
}
}

View File

@ -137,3 +137,10 @@ func TestLabel(t *testing.T) {
func TestEnd(t *testing.T) {
Todo(t)
}
func TestRepeat(t *testing.T) {
t.Run("fails when number of successes is less than minCount", Todo)
t.Run("succeeds when number of successes is greater than minCount", Todo)
t.Run("consumes iff at least one application consumes", Todo)
t.Run("fails on error", Todo)
}