From 986535fc958c0d19c10fd6fc5781fe0b2dcdd442 Mon Sep 17 00:00:00 2001 From: Lars Erik Rosengren Date: Sun, 3 Sep 2017 18:07:55 +0200 Subject: Changed implementation of precedence rules This implementation resolves djc/askama#44 by changing the precedence implementation. The previous solution was very slow because it had to try to parse all combinations of precedence layers leading to 2^9 iterations for each expr_any. This is solved by reusing the left operand instead of reparsing it when the operator isn't found. This implementation also solves another related issue that expressions with multiple operators couldn't be parsed, for example {{1 * 2 * 3}}. This is handled by using expr_any for the right operand instead of only using higher level precedence layers. --- askama_shared/src/parser.rs | 18 ++++++++++++------ testing/templates/precedence.html | 7 +++++++ testing/tests/precedence.rs | 15 +++++++++++++++ 3 files changed, 34 insertions(+), 6 deletions(-) create mode 100644 testing/templates/precedence.html create mode 100644 testing/tests/precedence.rs diff --git a/askama_shared/src/parser.rs b/askama_shared/src/parser.rs index 8732f0e..8ff2063 100644 --- a/askama_shared/src/parser.rs +++ b/askama_shared/src/parser.rs @@ -229,15 +229,21 @@ named!(expr_filtered, do_parse!( macro_rules! expr_prec_layer { ( $name:ident, $inner:ident, $( $op:expr ),* ) => { - named!($name, alt!( + named!($name, do_parse!( left: $inner >> - op: ws!(alt!($( tag_s!($op) )|*)) >> - right: $inner >> - (Expr::BinOp(str::from_utf8(op).unwrap(), + op_and_right: opt!(pair!(ws!(alt!($( tag_s!($op) )|*)), expr_any)) >> + ( + if op_and_right.is_some() { + let (op, right) = op_and_right.unwrap(); + (Expr::BinOp(str::from_utf8(op).unwrap(), Box::new(left), Box::new(right))) - ) | $inner - )); + } else { + left + } + ) + ) + ); } } diff --git a/testing/templates/precedence.html b/testing/templates/precedence.html new file mode 100644 index 0000000..e5d12dd --- /dev/null +++ b/testing/templates/precedence.html @@ -0,0 +1,7 @@ +{{ 3 * 4 / 2 -}} +{{ 26 / 2 % 7 -}} +{{ 3 % 2 * 6 -}} +{{ 1 * 2 + 4 -}} +{{ 11 - 15 / 3 -}} +{{ 4 + 5 % 3 -}} +{{ 4 | 2 + 5 & 2 -}} diff --git a/testing/tests/precedence.rs b/testing/tests/precedence.rs new file mode 100644 index 0000000..f02189d --- /dev/null +++ b/testing/tests/precedence.rs @@ -0,0 +1,15 @@ +#[macro_use] +extern crate askama; + +use askama::Template; + +#[derive(Template)] +#[template(path = "precedence.html")] +struct PrecedenceTemplate { +} + +#[test] +fn test_precedence() { + let t = PrecedenceTemplate { }; + assert_eq!(t.render().unwrap(), "6".repeat(7)); +} -- cgit