aboutsummaryrefslogtreecommitdiffstats
path: root/askama_shared
diff options
context:
space:
mode:
authorLibravatar René Kijewski <kijewski@library.vetmed.fu-berlin.de>2022-01-04 20:55:18 +0100
committerLibravatar Dirkjan Ochtman <dirkjan@ochtman.nl>2022-01-06 16:29:47 +0100
commitaf552ee3744016ac1db741888318649a64dfee50 (patch)
treee071ec74787a6ce397a0b8d232159a121e54560a /askama_shared
parent803d32cd46245d72884ad1b251964906fd50dd00 (diff)
downloadaskama-af552ee3744016ac1db741888318649a64dfee50.tar.gz
askama-af552ee3744016ac1db741888318649a64dfee50.tar.bz2
askama-af552ee3744016ac1db741888318649a64dfee50.zip
Optimize parsing of ranges
Right now almost every expression needs to be parsed twice: `expr_any()` first parses the left-hand side of a range expression, and if no `..` or `..=` was found the left-hand expression is parsed again, this time as the result of the function. This diff removes the second parsing step by first looking for `.. (opt rhs)`, then for `lhs .. (opt rhs)`.
Diffstat (limited to '')
-rw-r--r--askama_shared/src/parser.rs30
1 files changed, 13 insertions, 17 deletions
diff --git a/askama_shared/src/parser.rs b/askama_shared/src/parser.rs
index da9a6a0..f5685b9 100644
--- a/askama_shared/src/parser.rs
+++ b/askama_shared/src/parser.rs
@@ -640,24 +640,20 @@ expr_prec_layer!(expr_compare, expr_bor, "==", "!=", ">=", ">", "<=", "<");
expr_prec_layer!(expr_and, expr_compare, "&&");
expr_prec_layer!(expr_or, expr_and, "||");
-fn range_right(i: &str) -> IResult<&str, Expr<'_>> {
- let (i, (_, incl, right)) = tuple((ws(tag("..")), opt(ws(char('='))), opt(expr_or)))(i)?;
- Ok((
- i,
- Expr::Range(
- if incl.is_some() { "..=" } else { ".." },
- None,
- right.map(Box::new),
- ),
- ))
-}
-
fn expr_any(i: &str) -> IResult<&str, Expr<'_>> {
- let compound = map(tuple((expr_or, range_right)), |(left, rest)| match rest {
- Expr::Range(op, _, right) => Expr::Range(op, Some(Box::new(left)), right),
- _ => unreachable!(),
- });
- alt((range_right, compound, expr_or))(i)
+ let range_right = |i| pair(ws(alt((tag("..="), tag("..")))), opt(expr_or))(i);
+ alt((
+ map(range_right, |(op, right)| {
+ Expr::Range(op, None, right.map(Box::new))
+ }),
+ map(
+ pair(expr_or, opt(range_right)),
+ |(left, right)| match right {
+ Some((op, right)) => Expr::Range(op, Some(Box::new(left)), right.map(Box::new)),
+ None => left,
+ },
+ ),
+ ))(i)
}
fn expr_node<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, Node<'a>> {