From 985eb8955f36e909d18f7ea6eaf4c748e7afd17a Mon Sep 17 00:00:00 2001 From: René Kijewski Date: Mon, 31 Jul 2023 20:58:23 +0200 Subject: Fix parsing arrays This change * allows using empty arrays `[]` in expessions, * adds a cut when the leading `[` was encountered, and * fixes the interaction between arrays and boolean OR. IMO the restriction that you couldn't use empty arrays is not needed. The missing cut made error messages slictly worse if you forget to add the closing `]`. Filter expressions must not have white spaces before the pipe `|`. The white space is used to tell a filter expressions, and `std::ops::Or` apart. --- askama_parser/src/expr.rs | 12 ++++--- askama_parser/src/tests.rs | 83 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 5 deletions(-) (limited to 'askama_parser') diff --git a/askama_parser/src/expr.rs b/askama_parser/src/expr.rs index ab7caff..9610c05 100644 --- a/askama_parser/src/expr.rs +++ b/askama_parser/src/expr.rs @@ -5,8 +5,8 @@ use nom::bytes::complete::{tag, take_till}; use nom::character::complete::char; use nom::combinator::{cut, map, not, opt, peek, recognize}; use nom::error::ErrorKind; -use nom::multi::{fold_many0, many0, separated_list0, separated_list1}; -use nom::sequence::{delimited, pair, preceded, terminated, tuple}; +use nom::multi::{fold_many0, many0, separated_list0}; +use nom::sequence::{pair, preceded, terminated, tuple}; use nom::{error_position, IResult}; use super::{bool_lit, char_lit, identifier, not_ws, num_lit, path, str_lit, ws}; @@ -177,10 +177,12 @@ impl<'a> Expr<'a> { } fn array(i: &'a str) -> IResult<&'a str, Self> { - delimited( + preceded( ws(char('[')), - map(separated_list1(ws(char(',')), Self::parse), Self::Array), - ws(char(']')), + cut(terminated( + map(separated_list0(char(','), ws(Self::parse)), Self::Array), + char(']'), + )), )(i) } diff --git a/askama_parser/src/tests.rs b/askama_parser/src/tests.rs index 2beeb38..61aa279 100644 --- a/askama_parser/src/tests.rs +++ b/askama_parser/src/tests.rs @@ -761,3 +761,86 @@ fn test_missing_space_after_kw() { "unable to parse template:\n\n\"{%leta=b%}\"" )); } + +#[test] +fn test_parse_array() { + let syntax = Syntax::default(); + assert_eq!( + Ast::from_str("{{ [] }}", &syntax).unwrap().nodes, + vec![Node::Expr(Ws(None, None), Expr::Array(vec![]))], + ); + assert_eq!( + Ast::from_str("{{ [1] }}", &syntax).unwrap().nodes, + vec![Node::Expr( + Ws(None, None), + Expr::Array(vec![Expr::NumLit("1")]) + )], + ); + assert_eq!( + Ast::from_str("{{ [ 1] }}", &syntax).unwrap().nodes, + vec![Node::Expr( + Ws(None, None), + Expr::Array(vec![Expr::NumLit("1")]) + )], + ); + assert_eq!( + Ast::from_str("{{ [1 ] }}", &syntax).unwrap().nodes, + vec![Node::Expr( + Ws(None, None), + Expr::Array(vec![Expr::NumLit("1")]) + )], + ); + assert_eq!( + Ast::from_str("{{ [1,2] }}", &syntax).unwrap().nodes, + vec![Node::Expr( + Ws(None, None), + Expr::Array(vec![Expr::NumLit("1"), Expr::NumLit("2")]) + )], + ); + assert_eq!( + Ast::from_str("{{ [1 ,2] }}", &syntax).unwrap().nodes, + vec![Node::Expr( + Ws(None, None), + Expr::Array(vec![Expr::NumLit("1"), Expr::NumLit("2")]) + )], + ); + assert_eq!( + Ast::from_str("{{ [1, 2] }}", &syntax).unwrap().nodes, + vec![Node::Expr( + Ws(None, None), + Expr::Array(vec![Expr::NumLit("1"), Expr::NumLit("2")]) + )], + ); + assert_eq!( + Ast::from_str("{{ [1,2 ] }}", &syntax).unwrap().nodes, + vec![Node::Expr( + Ws(None, None), + Expr::Array(vec![Expr::NumLit("1"), Expr::NumLit("2")]) + )], + ); + assert_eq!( + Ast::from_str("{{ []|foo }}", &syntax).unwrap().nodes, + vec![Node::Expr( + Ws(None, None), + Expr::Filter("foo", vec![Expr::Array(vec![])]) + )], + ); + assert_eq!( + Ast::from_str("{{ []| foo }}", &syntax).unwrap().nodes, + vec![Node::Expr( + Ws(None, None), + Expr::Filter("foo", vec![Expr::Array(vec![])]) + )], + ); + assert_eq!( + Ast::from_str("{{ [] |foo }}", &syntax).unwrap().nodes, + vec![Node::Expr( + Ws(None, None), + Expr::BinOp( + "|", + Box::new(Expr::Array(vec![])), + Box::new(Expr::Var("foo")) + ), + )], + ); +} -- cgit