Use resume_after_cut instead of resume_after to simplify code
Signed-off-by: Marcel Müller <neikos@neikos.email>
This commit is contained in:
parent
b07bef7904
commit
4177649202
2 changed files with 67 additions and 12 deletions
|
|
@ -10,6 +10,7 @@ use winnow::Parser;
|
|||
use winnow::RecoverableParser;
|
||||
use winnow::ascii::multispace1;
|
||||
use winnow::combinator::alt;
|
||||
use winnow::combinator::cut_err;
|
||||
use winnow::combinator::eof;
|
||||
use winnow::combinator::peek;
|
||||
use winnow::combinator::repeat_till;
|
||||
|
|
@ -265,19 +266,21 @@ fn parse_whitespace<'input>(input: &mut Input<'input>) -> PResult<'input, Templa
|
|||
}
|
||||
|
||||
fn parse_ident<'input>(input: &mut Input<'input>) -> PResult<'input, TemplateToken<'input>> {
|
||||
let ident = ident.map(TemplateToken::Ident).parse_next(input)?;
|
||||
|
||||
ident_terminator_check
|
||||
resume_after_cut(
|
||||
terminated(
|
||||
ident.map(TemplateToken::Ident),
|
||||
cut_err(ident_terminator_check),
|
||||
)
|
||||
.context(
|
||||
ParseError::ctx()
|
||||
.msg("Invalid variable identifier")
|
||||
.help("valid variable identifiers are alphanumeric"),
|
||||
)
|
||||
.value(ident)
|
||||
.resume_after(bad_ident)
|
||||
.with_taken()
|
||||
.map(|(val, taken)| val.unwrap_or(TemplateToken::Invalid(taken)))
|
||||
.parse_next(input)
|
||||
),
|
||||
bad_ident,
|
||||
)
|
||||
.with_taken()
|
||||
.map(|(val, taken)| val.unwrap_or(TemplateToken::Invalid(taken)))
|
||||
.parse_next(input)
|
||||
}
|
||||
|
||||
fn ident<'input>(input: &mut Input<'input>) -> PResult<'input, &'input str> {
|
||||
|
|
@ -303,6 +306,58 @@ fn ident_terminator<'input>(input: &mut Input<'input>) -> PResult<'input, ()> {
|
|||
.parse_next(input)
|
||||
}
|
||||
|
||||
// This is just like the standard .resume_after(), except we only resume on Cut errors.
|
||||
fn resume_after_cut<Input, Output, Error, ParseNext, ParseRecover>(
|
||||
mut parser: ParseNext,
|
||||
mut recover: ParseRecover,
|
||||
) -> impl Parser<Input, Option<Output>, Error>
|
||||
where
|
||||
Input: Stream + winnow::stream::Recover<Error>,
|
||||
Error: ParserError<Input> + FromRecoverableError<Input, Error>,
|
||||
ParseNext: Parser<Input, Output, Error>,
|
||||
ParseRecover: Parser<Input, (), Error>,
|
||||
{
|
||||
trace("resume_after_cut", move |input: &mut Input| {
|
||||
resume_after_cut_inner(&mut parser, &mut recover, input)
|
||||
})
|
||||
}
|
||||
|
||||
fn resume_after_cut_inner<P, R, I, O, E>(
|
||||
parser: &mut P,
|
||||
recover: &mut R,
|
||||
i: &mut I,
|
||||
) -> winnow::Result<Option<O>, E>
|
||||
where
|
||||
P: Parser<I, O, E>,
|
||||
R: Parser<I, (), E>,
|
||||
I: Stream,
|
||||
I: winnow::stream::Recover<E>,
|
||||
E: ParserError<I> + FromRecoverableError<I, E>,
|
||||
{
|
||||
let token_start = i.checkpoint();
|
||||
let mut err = match parser.parse_next(i) {
|
||||
Ok(o) => {
|
||||
return Ok(Some(o));
|
||||
}
|
||||
Err(e) if e.is_incomplete() || e.is_backtrack() => {
|
||||
return Err(e);
|
||||
}
|
||||
Err(err) => err,
|
||||
};
|
||||
let err_start = i.checkpoint();
|
||||
if recover.parse_next(i).is_ok() {
|
||||
if let Err(err_) = i.record_err(&token_start, &err_start, err) {
|
||||
err = err_;
|
||||
} else {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
|
||||
i.reset(&err_start);
|
||||
err = E::from_recoverable_error(&token_start, &err_start, i, err);
|
||||
Err(err)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::parser::parse;
|
||||
|
|
@ -377,10 +432,10 @@ mod tests {
|
|||
),
|
||||
span: Some(
|
||||
SourceSpan {
|
||||
range: 25..28,
|
||||
range: 22..28,
|
||||
},
|
||||
),
|
||||
is_fatal: false,
|
||||
is_fatal: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue