Propagate errors through Choose
This commit is contained in:
parent
b3b90b7e6b
commit
183e4db928
@ -4,6 +4,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"slices"
|
||||
|
||||
"git.codemonkeysoftware.net/b/gigaparsec/cursor"
|
||||
)
|
||||
@ -99,6 +100,52 @@ func Choose[In, Out any](p, q Parser[In, Out]) Parser[In, Out] {
|
||||
}
|
||||
}
|
||||
|
||||
func ChooseMany[In, Out any](p Parser[In, Out], ps ...Parser[In, Out]) Parser[In, Out] {
|
||||
all := append([]Parser[In, Out]{p}, ps...)
|
||||
return func(input State[In]) (bool, Result[In, Out], error) {
|
||||
expecteds := make([][]string, 0, len(all))
|
||||
var value Out
|
||||
var got string
|
||||
var gotGot bool
|
||||
var failed bool
|
||||
for _, q := range all {
|
||||
consumed, result, err := q(input)
|
||||
if consumed {
|
||||
return consumed, result, err
|
||||
}
|
||||
var qMsg Message
|
||||
if err != nil {
|
||||
var parseErr ParseError
|
||||
if !errors.As(err, &parseErr) {
|
||||
// It broke. Give up.
|
||||
return consumed, result, err
|
||||
}
|
||||
failed = failed && true
|
||||
qMsg = Message(parseErr)
|
||||
} else {
|
||||
if failed {
|
||||
value = result.Value
|
||||
failed = false
|
||||
}
|
||||
qMsg = result.Message
|
||||
}
|
||||
if !gotGot {
|
||||
got = qMsg.Got
|
||||
gotGot = true
|
||||
}
|
||||
}
|
||||
msg := Message{Pos: input.Pos(), Got: got, Expected: slices.Concat(expecteds...)}
|
||||
if failed {
|
||||
return false, Result[In, Out]{}, ParseError(msg)
|
||||
}
|
||||
return false, Result[In, Out]{
|
||||
Value: value,
|
||||
State: input,
|
||||
Message: msg,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Try behaves identically to p, except that if p returns an error,
|
||||
// Try will pretend that no input was consumed. This allows infinite
|
||||
// lookahead: Since Choose only calls another parser when the previous
|
||||
|
Loading…
Reference in New Issue
Block a user