diff --git a/seqproto.go b/seqproto.go new file mode 100644 index 0000000..fdc4632 --- /dev/null +++ b/seqproto.go @@ -0,0 +1,111 @@ +package gigaparsec + +func Seq3[In, Out, T1, T2, T3 any]( + p1 Parser[In, T1], + p2 Parser[In, T2], + p3 Parser[In, T3], + f func(T1, T2, T3) Out, +) Parser[In, Out] { + return func(s State[In]) (Result[In, Out], error) { + var anyConsumed bool + var failed bool + var msg Message + var next = s + + r1, err := p1(next) + if err != nil { + return Result[In, Out]{}, err + } + anyConsumed = anyConsumed || r1.Consumed() + failed, _, msg = r1.Failed() + if failed { + return Fail[In, Out](anyConsumed, msg), nil + } + _, _, val1, next, _ := r1.Succeeded() + + r2, err := p2(next) + if err != nil { + return Result[In, Out]{}, err + } + anyConsumed = anyConsumed || r2.Consumed() + failed, _, msg = r2.Failed() + if failed { + return Fail[In, Out](anyConsumed, msg), nil + } + _, _, val2, next, _ := r2.Succeeded() + + r3, err := p3(next) + if err != nil { + return Result[In, Out]{}, err + } + anyConsumed = anyConsumed || r3.Consumed() + failed, _, msg = r3.Failed() + if failed { + return Fail[In, Out](anyConsumed, msg), nil + } + _, _, val3, next, _ := r3.Succeeded() + + val := f(val1, val2, val3) + return Succeed(anyConsumed, val, next, MessageOK(s.Pos())), nil + } +} + +func Bind3[In, Out, T1, T2, T3 any]( + p Parser[In, T1], + f1 func(T1) Parser[In, T2], + f2 func(T2) Parser[In, T3], + f3 func(T3) Parser[In, Out], +) Parser[In, Out] { + return func(s State[In]) (Result[In, Out], error) { + var anyConsumed bool + var failed bool + var msg Message + var next = s + + r1, err := p(next) + if err != nil { + return Result[In, Out]{}, err + } + anyConsumed = anyConsumed || r1.Consumed() + failed, _, msg = r1.Failed() + if failed { + return Fail[In, Out](anyConsumed, msg), nil + } + _, _, val1, next, _ := r1.Succeeded() + + r2, err := f1(val1)(next) + if err != nil { + return Result[In, Out]{}, err + } + anyConsumed = anyConsumed || r2.Consumed() + failed, _, msg = r2.Failed() + if failed { + return Fail[In, Out](anyConsumed, msg), nil + } + _, _, val2, next, _ := r2.Succeeded() + + r3, err := f2(val2)(next) + if err != nil { + return Result[In, Out]{}, err + } + anyConsumed = anyConsumed || r3.Consumed() + failed, _, msg = r3.Failed() + if failed { + return Fail[In, Out](anyConsumed, msg), nil + } + _, _, val3, next, _ := r3.Succeeded() + + r4, err := f3(val3)(next) + if err != nil { + return Result[In, Out]{}, err + } + anyConsumed = anyConsumed || r4.Consumed() + failed, _, msg = r4.Failed() + if failed { + return Fail[In, Out](anyConsumed, msg), nil + } + _, _, val4, next, _ := r4.Succeeded() + + return Succeed(anyConsumed, val4, next, MessageOK(s.Pos())), nil + } +}