Skip to content

Commit

Permalink
Fix parsing arrays
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Kijewski authored and djc committed Jul 31, 2023
1 parent 107bdfd commit 985eb89
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 12 deletions.
12 changes: 7 additions & 5 deletions askama_parser/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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)
}

Expand Down
83 changes: 83 additions & 0 deletions askama_parser/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"))
),
)],
);
}
3 changes: 0 additions & 3 deletions testing/tests/ui/loop_cycle_empty.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
// Nb. this test fails because currently an empty array "[]" is always a syntax error in askama,
// but even if this changes, this test should keep failing, but possibly with another error message

use askama::Template;

#[derive(Template)]
Expand Down
7 changes: 3 additions & 4 deletions testing/tests/ui/loop_cycle_empty.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
error: problems parsing template source at row 1, column 35 near:
"[]) }}{{ v }},{% endfor %}"
--> tests/ui/loop_cycle_empty.rs:6:10
error: loop.cycle(…) cannot use an empty array
--> tests/ui/loop_cycle_empty.rs:3:10
|
6 | #[derive(Template)]
3 | #[derive(Template)]
| ^^^^^^^^
|
= note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info)

0 comments on commit 985eb89

Please sign in to comment.