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::RecoverableParser;
|
||||||
use winnow::ascii::multispace1;
|
use winnow::ascii::multispace1;
|
||||||
use winnow::combinator::alt;
|
use winnow::combinator::alt;
|
||||||
|
use winnow::combinator::cut_err;
|
||||||
use winnow::combinator::eof;
|
use winnow::combinator::eof;
|
||||||
use winnow::combinator::peek;
|
use winnow::combinator::peek;
|
||||||
use winnow::combinator::repeat_till;
|
use winnow::combinator::repeat_till;
|
||||||
|
|
@ -265,16 +266,18 @@ fn parse_whitespace<'input>(input: &mut Input<'input>) -> PResult<'input, Templa
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_ident<'input>(input: &mut Input<'input>) -> PResult<'input, TemplateToken<'input>> {
|
fn parse_ident<'input>(input: &mut Input<'input>) -> PResult<'input, TemplateToken<'input>> {
|
||||||
let ident = ident.map(TemplateToken::Ident).parse_next(input)?;
|
resume_after_cut(
|
||||||
|
terminated(
|
||||||
ident_terminator_check
|
ident.map(TemplateToken::Ident),
|
||||||
|
cut_err(ident_terminator_check),
|
||||||
|
)
|
||||||
.context(
|
.context(
|
||||||
ParseError::ctx()
|
ParseError::ctx()
|
||||||
.msg("Invalid variable identifier")
|
.msg("Invalid variable identifier")
|
||||||
.help("valid variable identifiers are alphanumeric"),
|
.help("valid variable identifiers are alphanumeric"),
|
||||||
|
),
|
||||||
|
bad_ident,
|
||||||
)
|
)
|
||||||
.value(ident)
|
|
||||||
.resume_after(bad_ident)
|
|
||||||
.with_taken()
|
.with_taken()
|
||||||
.map(|(val, taken)| val.unwrap_or(TemplateToken::Invalid(taken)))
|
.map(|(val, taken)| val.unwrap_or(TemplateToken::Invalid(taken)))
|
||||||
.parse_next(input)
|
.parse_next(input)
|
||||||
|
|
@ -303,6 +306,58 @@ fn ident_terminator<'input>(input: &mut Input<'input>) -> PResult<'input, ()> {
|
||||||
.parse_next(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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::parser::parse;
|
use crate::parser::parse;
|
||||||
|
|
@ -377,10 +432,10 @@ mod tests {
|
||||||
),
|
),
|
||||||
span: Some(
|
span: Some(
|
||||||
SourceSpan {
|
SourceSpan {
|
||||||
range: 25..28,
|
range: 22..28,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
is_fatal: false,
|
is_fatal: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,6 @@ expression: error.to_report()
|
||||||
[1m[91merror[0m[1m: Invalid variable identifier[0m
|
[1m[91merror[0m[1m: Invalid variable identifier[0m
|
||||||
[1m[94m ╭▸ [0m
|
[1m[94m ╭▸ [0m
|
||||||
[1m[94m1[0m [1m[94m│[0m Hello {{ the2re }} {{ the@re }}
|
[1m[94m1[0m [1m[94m│[0m Hello {{ the2re }} {{ the@re }}
|
||||||
[1m[94m│[0m [1m[91m━━━[0m
|
[1m[94m│[0m [1m[91m━━━━━━[0m
|
||||||
[1m[94m│[0m
|
[1m[94m│[0m
|
||||||
[1m[94m╰ [0m[1mhelp[0m: valid variable identifiers are alphanumeric
|
[1m[94m╰ [0m[1mhelp[0m: valid variable identifiers are alphanumeric
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue