diff options
author | René Kijewski <kijewski@library.vetmed.fu-berlin.de> | 2022-01-04 20:55:18 +0100 |
---|---|---|
committer | Dirkjan Ochtman <dirkjan@ochtman.nl> | 2022-01-06 16:29:47 +0100 |
commit | af552ee3744016ac1db741888318649a64dfee50 (patch) | |
tree | e071ec74787a6ce397a0b8d232159a121e54560a | |
parent | 803d32cd46245d72884ad1b251964906fd50dd00 (diff) | |
download | askama-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)`.
-rw-r--r-- | askama_shared/src/parser.rs | 30 |
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>> { |