chumsky
chumsky copied to clipboard
Recovering from missing input at eof
I am having trouble recovering from the top-level nesting error that occurs when missing brackets. Here is a simplified nano rust example:
fn main() -> i32 {
0
As you can clearly see, the closing bracket is missing.
Using the nested_delimiters
recovery method, I can propagate an arbitrary nesting error to the top level, but I am unable to handle this top-level error.
To solve this, I propose adding a recovery which creates a virtual stream from the faulty span amended with a constant expression. If the amended stream succeeds, the recovery returns the result; otherwise it returns the original result.
The code below displays a proposed usage.
nested_block
.recover_with(amend_then_retry([Token::Ctrl('}')]));
The pseudocode below displays the proposed functionality.
pub struct AmendThenRetry<I, const N: usize>(
pub(crate) [I; N],
);
type StreamOf<'a, I, E> = Stream<'a, I, <E as Error<I>>::Span>;
type PResult<I, O, E> = (
Vec<chumsky::error::Located<I, E>>,
Result<(O, Option<chumsky::error::Located<I, E>>), chumsky::error::Located<I, E>>,
);
impl<I: Clone + PartialEq, O, E: chumsky::Error<I>, const N: usize> chumsky::recovery::Strategy<I, O, E> for AmendThenRetry<I, N> {
fn recover<D: chumsky::debug::Debugger, P: Parser<I, O, Error = E>>(
&self,
recovered_errors: Vec<chumsky::error::Located<I, P::Error>>,
fatal_error: chumsky::error::Located<I, P::Error>,
parser: P,
debugger: &mut D,
stream: &mut StreamOf<I, P::Error>,
) -> PResult<I, O, P::Error> {
let fatal_span = fatal_error.at..stream.offset();
let amended_span = fatal_span.start..(fatal_span.end+ N);
stream.revert(fatal_span.start);
let amended = stream.take(fatal_span.len())
.chain(self.0.into_iter());
let amended = StreamOf::from_iter(amended_span, amended);
let res = amended.try_parse(parser);
stream.revert(fatal_span.end);
res
}
}
Depending on which position fatal_error.at
refers to, the recovery might need to wrap the parser instead. Input needed.
Before opening a PR for this, I'd love to collect more opinions on my proposed solution. If there is already a method available that solves this particular problem, feel free to educate me :)