Propagate errors through Choose
This commit is contained in:
parent
b3b90b7e6b
commit
183e4db928
@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"slices"
|
||||||
|
|
||||||
"git.codemonkeysoftware.net/b/gigaparsec/cursor"
|
"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 behaves identically to p, except that if p returns an error,
|
||||||
// Try will pretend that no input was consumed. This allows infinite
|
// Try will pretend that no input was consumed. This allows infinite
|
||||||
// lookahead: Since Choose only calls another parser when the previous
|
// lookahead: Since Choose only calls another parser when the previous
|
||||||
|
Loading…
Reference in New Issue
Block a user