From 9653290ead0b3cbcb4d10c1b6c01f5cc3e88d39b Mon Sep 17 00:00:00 2001 From: Jerko Steiner Date: Mon, 27 May 2024 21:04:21 +0200 Subject: [PATCH] Closes #882 (#908) --- src/parser/mod.rs | 1 + src/parser/tera.pest | 2 +- src/parser/tests/parser.rs | 24 ++++++++++++++++++++++++ src/renderer/tests/basic.rs | 13 +++++++++++++ 4 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 07982c1a..0419cbea 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -427,6 +427,7 @@ fn parse_logic_val(pair: Pair) -> TeraResult { Rule::in_cond => expr = Some(parse_in_condition(p)?), Rule::comparison_expr => expr = Some(parse_comparison_expression(p)?), Rule::string_expr_filter => expr = Some(parse_string_expr_with_filters(p)?), + Rule::logic_expr => expr = Some(parse_logic_expr(p)?), _ => unreachable!(), }; } diff --git a/src/parser/tera.pest b/src/parser/tera.pest index ec2b1729..0c897537 100644 --- a/src/parser/tera.pest +++ b/src/parser/tera.pest @@ -98,7 +98,7 @@ comparison_expr = { (string_expr_filter | comparison_val) ~ (comparison_op ~ (st in_cond_container = {string_expr_filter | array_filter | dotted_square_bracket_ident} in_cond = !{ (string_expr_filter | basic_expr_filter) ~ op_not? ~ "in" ~ in_cond_container } -logic_val = !{ op_not? ~ (in_cond | comparison_expr) } +logic_val = !{ op_not? ~ (in_cond | comparison_expr) | "(" ~ logic_expr ~ ")" } logic_expr = !{ logic_val ~ ((op_or | op_and) ~ logic_val)* } array = !{ "[" ~ (logic_val ~ ",")* ~ logic_val? ~ "]"} diff --git a/src/parser/tests/parser.rs b/src/parser/tests/parser.rs index 5a793f62..73db69b2 100644 --- a/src/parser/tests/parser.rs +++ b/src/parser/tests/parser.rs @@ -360,6 +360,30 @@ fn parse_variable_tag_negated_expr() { ); } +#[test] +fn parse_variable_tag_negated_expr_with_parentheses() { + let ast = parse("{{ (not id or not true) and not 1 + 1 }}").unwrap(); + assert_eq!( + ast[0], + Node::VariableBlock( + WS::default(), + Expr::new(ExprVal::Logic(LogicExpr { + lhs: Box::new(Expr::new(ExprVal::Logic(LogicExpr { + lhs: Box::new(Expr::new_negated(ExprVal::Ident("id".to_string()))), + operator: LogicOperator::Or, + rhs: Box::new(Expr::new_negated(ExprVal::Bool(true))), + },))), + operator: LogicOperator::And, + rhs: Box::new(Expr::new_negated(ExprVal::Math(MathExpr { + lhs: Box::new(Expr::new(ExprVal::Int(1))), + operator: MathOperator::Add, + rhs: Box::new(Expr::new(ExprVal::Int(1))), + },))), + },)) + ) + ); +} + #[test] fn parse_variable_tag_simple_test() { let ast = parse("{{ id is defined }}").unwrap(); diff --git a/src/renderer/tests/basic.rs b/src/renderer/tests/basic.rs index 10545534..ca621be7 100644 --- a/src/renderer/tests/basic.rs +++ b/src/renderer/tests/basic.rs @@ -476,6 +476,19 @@ fn render_if_elif_else() { ("{% if 'n' in name %}Admin{% else %}Hmm{% endif %}", "Admin"), // function in if ("{% if get_true() %}Truth{% endif %}", "Truth"), + // Parentheses around logic expressions + ("{% if age >= 18 and name == 'john' %}Truth{% endif %}", "Truth"), + ("{% if (age >= 18) and (name == 'john') %}Truth{% endif %}", "Truth"), + ("{% if (age >= 18) or (name == 'john') %}Truth{% endif %}", "Truth"), + ("{% if (age < 18) or (name == 'john') %}Truth{% endif %}", "Truth"), + ("{% if (age >= 18) or (name != 'john') %}Truth{% endif %}", "Truth"), + ("{% if (age < 18) and (name != 'john') %}Truth{% endif %}", ""), + ("{% if (age >= 18) and (name != 'john') %}Truth{% endif %}", ""), + ("{% if (age >= 18 and name == 'john') %}Truth{% endif %}", "Truth"), + ("{% if (age < 18 and name == 'john') %}Truth{% endif %}", ""), + ("{% if (age >= 18 and name != 'john') %}Truth{% endif %}", ""), + ("{% if age >= 18 or name == 'john' and is_false %}Truth{% endif %}", "Truth"), + ("{% if (age >= 18 or name == 'john') and is_false %}Truth{% endif %}", ""), ]; for (input, expected) in inputs {