aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--askama_shared/src/parser.rs317
-rw-r--r--testing/tests/ui/typo_in_keyword.rs11
-rw-r--r--testing/tests/ui/typo_in_keyword.stderr8
3 files changed, 205 insertions, 131 deletions
diff --git a/askama_shared/src/parser.rs b/askama_shared/src/parser.rs
index a965025..957c778 100644
--- a/askama_shared/src/parser.rs
+++ b/askama_shared/src/parser.rs
@@ -1,7 +1,7 @@
use nom::branch::alt;
use nom::bytes::complete::{escaped, is_not, tag, take_until};
use nom::character::complete::{anychar, char, digit1};
-use nom::combinator::{complete, map, opt, recognize, value};
+use nom::combinator::{complete, cut, map, opt, recognize, value};
use nom::error::{Error, ParseError};
use nom::multi::{fold_many0, many0, many1, separated_list0, separated_list1};
use nom::sequence::{delimited, pair, preceded, terminated, tuple};
@@ -387,13 +387,13 @@ fn target(i: &[u8]) -> IResult<&[u8], Target<'_>> {
}
let mut targets = vec![first_target];
- let (i, _) = tuple((
+ let (i, _) = cut(tuple((
fold_many0(preceded(ws(tag(",")), target), (), |_, target| {
targets.push(target);
}),
opt(ws(tag(","))),
- ws(tag(")")),
- ))(i)?;
+ ws(cut(tag(")"))),
+ )))(i)?;
return Ok((i, Target::Tuple(Vec::new(), targets)));
}
@@ -408,8 +408,8 @@ fn target(i: &[u8]) -> IResult<&[u8], Target<'_>> {
let (i, targets) = alt((
map(tag(")"), |_| Vec::new()),
terminated(
- separated_list1(ws(tag(",")), target),
- pair(opt(ws(tag(","))), ws(tag(")"))),
+ cut(separated_list1(ws(tag(",")), target)),
+ pair(opt(ws(tag(","))), ws(cut(tag(")")))),
),
))(i)?;
return Ok((i, Target::Tuple(path, targets)));
@@ -420,8 +420,8 @@ fn target(i: &[u8]) -> IResult<&[u8], Target<'_>> {
let (i, targets) = alt((
map(tag("}"), |_| Vec::new()),
terminated(
- separated_list1(ws(tag(",")), named_target),
- pair(opt(ws(tag(","))), ws(tag("}"))),
+ cut(separated_list1(ws(tag(",")), named_target)),
+ pair(opt(ws(tag(","))), ws(cut(tag("}")))),
),
))(i)?;
return Ok((i, Target::Struct(path, targets)));
@@ -664,12 +664,11 @@ fn expr_any(i: &[u8]) -> IResult<&[u8], Expr<'_>> {
fn expr_node<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Node<'a>> {
let mut p = tuple((
|i| tag_expr_start(i, s),
- opt(tag("-")),
- ws(expr_any),
- opt(tag("-")),
- |i| tag_expr_end(i, s),
+ cut(tuple((opt(tag("-")), ws(expr_any), opt(tag("-")), |i| {
+ tag_expr_end(i, s)
+ }))),
));
- let (i, (_, pws, expr, nws, _)) = p(i)?;
+ let (i, (_, (pws, expr, nws, _))) = p(i)?;
Ok((i, Node::Expr(Ws(pws.is_some(), nws.is_some()), expr)))
}
@@ -677,12 +676,14 @@ fn block_call(i: &[u8]) -> IResult<&[u8], Node<'_>> {
let mut p = tuple((
opt(tag("-")),
ws(tag("call")),
- opt(tuple((ws(identifier), ws(tag("::"))))),
- ws(identifier),
- ws(arguments),
- opt(tag("-")),
+ cut(tuple((
+ opt(tuple((ws(identifier), ws(tag("::"))))),
+ ws(identifier),
+ ws(arguments),
+ opt(tag("-")),
+ ))),
));
- let (i, (pws, _, scope, name, args, nws)) = p(i)?;
+ let (i, (pws, _, (scope, name, args, nws))) = p(i)?;
let scope = scope.map(|(scope, _)| scope);
Ok((
i,
@@ -691,23 +692,19 @@ fn block_call(i: &[u8]) -> IResult<&[u8], Node<'_>> {
}
fn cond_if(i: &[u8]) -> IResult<&[u8], CondTest<'_>> {
- let mut p = tuple((
+ let mut p = preceded(
ws(tag("if")),
- opt(tuple((
- ws(alt((tag("let"), tag("set")))),
- ws(target),
- ws(tag("=")),
+ cut(tuple((
+ opt(delimited(
+ ws(alt((tag("let"), tag("set")))),
+ ws(target),
+ ws(tag("=")),
+ )),
+ ws(expr_any),
))),
- ws(expr_any),
- ));
- let (i, (_, dest, expr)) = p(i)?;
- Ok((
- i,
- CondTest {
- target: dest.map(|(_, target, _)| target),
- expr,
- },
- ))
+ );
+ let (i, (target, expr)) = p(i)?;
+ Ok((i, CondTest { target, expr }))
}
fn cond_block<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Cond<'a>> {
@@ -715,12 +712,14 @@ fn cond_block<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Cond<'a>>
|i| tag_block_start(i, s),
opt(tag("-")),
ws(tag("else")),
- opt(cond_if),
- opt(tag("-")),
- |i| tag_block_end(i, s),
- |i| parse_template(i, s),
+ cut(tuple((
+ opt(cond_if),
+ opt(tag("-")),
+ |i| tag_block_end(i, s),
+ cut(|i| parse_template(i, s)),
+ ))),
));
- let (i, (_, pws, _, cond, nws, _, block)) = p(i)?;
+ let (i, (_, pws, _, (cond, nws, _, block))) = p(i)?;
Ok((i, (Ws(pws.is_some(), nws.is_some()), cond, block)))
}
@@ -728,16 +727,22 @@ fn block_if<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Node<'a>> {
let mut p = tuple((
opt(tag("-")),
cond_if,
- opt(tag("-")),
- |i| tag_block_end(i, s),
- |i| parse_template(i, s),
- many0(|i| cond_block(i, s)),
- |i| tag_block_start(i, s),
- opt(tag("-")),
- ws(tag("endif")),
- opt(tag("-")),
+ cut(tuple((
+ opt(tag("-")),
+ |i| tag_block_end(i, s),
+ cut(tuple((
+ |i| parse_template(i, s),
+ many0(|i| cond_block(i, s)),
+ cut(tuple((
+ |i| tag_block_start(i, s),
+ opt(tag("-")),
+ ws(tag("endif")),
+ opt(tag("-")),
+ ))),
+ ))),
+ ))),
));
- let (i, (pws1, cond, nws1, _, block, elifs, _, pws2, _, nws2)) = p(i)?;
+ let (i, (pws1, cond, (nws1, _, (block, elifs, (_, pws2, _, nws2))))) = p(i)?;
let mut res = vec![(Ws(pws1.is_some(), nws1.is_some()), Some(cond), block)];
res.extend(elifs);
@@ -749,11 +754,13 @@ fn match_else_block<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Whe
|i| tag_block_start(i, s),
opt(tag("-")),
ws(tag("else")),
- opt(tag("-")),
- |i| tag_block_end(i, s),
- |i| parse_template(i, s),
+ cut(tuple((
+ opt(tag("-")),
+ |i| tag_block_end(i, s),
+ cut(|i| parse_template(i, s)),
+ ))),
));
- let (i, (_, pws, _, nws, _, block)) = p(i)?;
+ let (i, (_, pws, _, (nws, _, block))) = p(i)?;
Ok((
i,
(Ws(pws.is_some(), nws.is_some()), Target::Name("_"), block),
@@ -765,12 +772,14 @@ fn when_block<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], When<'a>>
|i| tag_block_start(i, s),
opt(tag("-")),
ws(tag("when")),
- ws(target),
- opt(tag("-")),
- |i| tag_block_end(i, s),
- |i| parse_template(i, s),
+ cut(tuple((
+ ws(target),
+ opt(tag("-")),
+ |i| tag_block_end(i, s),
+ cut(|i| parse_template(i, s)),
+ ))),
));
- let (i, (_, pws, _, target, nws, _, block)) = p(i)?;
+ let (i, (_, pws, _, (target, nws, _, block))) = p(i)?;
Ok((i, (Ws(pws.is_some(), nws.is_some()), target, block)))
}
@@ -778,18 +787,26 @@ fn block_match<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Node<'a>
let mut p = tuple((
opt(tag("-")),
ws(tag("match")),
- ws(expr_any),
- opt(tag("-")),
- |i| tag_block_end(i, s),
- opt(|i| take_content(i, s)),
- many1(|i| when_block(i, s)),
- opt(|i| match_else_block(i, s)),
- ws(|i| tag_block_start(i, s)),
- opt(tag("-")),
- ws(tag("endmatch")),
- opt(tag("-")),
+ cut(tuple((
+ ws(expr_any),
+ opt(tag("-")),
+ |i| tag_block_end(i, s),
+ cut(tuple((
+ opt(|i| take_content(i, s)),
+ many1(|i| when_block(i, s)),
+ cut(tuple((
+ opt(|i| match_else_block(i, s)),
+ cut(tuple((
+ ws(|i| tag_block_start(i, s)),
+ opt(tag("-")),
+ ws(tag("endmatch")),
+ opt(tag("-")),
+ ))),
+ ))),
+ ))),
+ ))),
));
- let (i, (pws1, _, expr, nws1, _, inter, arms, else_arm, _, pws2, _, nws2)) = p(i)?;
+ let (i, (pws1, _, (expr, nws1, _, (inter, arms, (else_arm, (_, pws2, _, nws2)))))) = p(i)?;
let mut arms = arms;
if let Some(arm) = else_arm {
@@ -828,11 +845,13 @@ fn block_let(i: &[u8]) -> IResult<&[u8], Node<'_>> {
let mut p = tuple((
opt(tag("-")),
ws(alt((tag("let"), tag("set")))),
- ws(target),
- opt(tuple((ws(tag("=")), ws(expr_any)))),
- opt(tag("-")),
+ cut(tuple((
+ ws(target),
+ opt(tuple((ws(tag("=")), ws(expr_any)))),
+ opt(tag("-")),
+ ))),
));
- let (i, (pws, _, var, val, nws)) = p(i)?;
+ let (i, (pws, _, (var, val, nws))) = p(i)?;
Ok((
i,
@@ -848,18 +867,26 @@ fn block_for<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Node<'a>>
let mut p = tuple((
opt(tag("-")),
ws(tag("for")),
- ws(target),
- ws(tag("in")),
- ws(expr_any),
- opt(tag("-")),
- |i| tag_block_end(i, s),
- |i| parse_template(i, s),
- |i| tag_block_start(i, s),
- opt(tag("-")),
- ws(tag("endfor")),
- opt(tag("-")),
+ cut(tuple((
+ ws(target),
+ ws(tag("in")),
+ cut(tuple((
+ ws(expr_any),
+ opt(tag("-")),
+ |i| tag_block_end(i, s),
+ cut(tuple((
+ |i| parse_template(i, s),
+ cut(tuple((
+ |i| tag_block_start(i, s),
+ opt(tag("-")),
+ ws(tag("endfor")),
+ opt(tag("-")),
+ ))),
+ ))),
+ ))),
+ ))),
));
- let (i, (pws1, _, var, _, iter, nws1, _, block, _, pws2, _, nws2)) = p(i)?;
+ let (i, (pws1, _, (var, _, (iter, nws1, _, (block, (_, pws2, _, nws2)))))) = p(i)?;
Ok((
i,
Node::Loop(
@@ -881,21 +908,22 @@ fn block_block<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Node<'a>
let mut start = tuple((
opt(tag("-")),
ws(tag("block")),
- ws(identifier),
- opt(tag("-")),
- |i| tag_block_end(i, s),
- |i| parse_template(i, s),
+ cut(tuple((ws(identifier), opt(tag("-")), |i| {
+ tag_block_end(i, s)
+ }))),
));
- let (i, (pws1, _, name, nws1, _, contents)) = start(i)?;
+ let (i, (pws1, _, (name, nws1, _))) = start(i)?;
- let mut end = tuple((
- |i| tag_block_start(i, s),
- opt(tag("-")),
- ws(tag("endblock")),
- opt(ws(tag(name))),
- opt(tag("-")),
- ));
- let (i, (_, pws2, _, _, nws2)) = end(i)?;
+ let mut end = cut(tuple((
+ |i| parse_template(i, s),
+ cut(tuple((
+ |i| tag_block_start(i, s),
+ opt(tag("-")),
+ ws(tag("endblock")),
+ cut(tuple((opt(ws(tag(name))), opt(tag("-"))))),
+ ))),
+ )));
+ let (i, (contents, (_, pws2, _, (_, nws2)))) = end(i)?;
Ok((
i,
@@ -912,10 +940,9 @@ fn block_include(i: &[u8]) -> IResult<&[u8], Node<'_>> {
let mut p = tuple((
opt(tag("-")),
ws(tag("include")),
- ws(expr_str_lit),
- opt(tag("-")),
+ cut(pair(ws(expr_str_lit), opt(tag("-")))),
));
- let (i, (pws, _, name, nws)) = p(i)?;
+ let (i, (pws, _, (name, nws))) = p(i)?;
Ok((
i,
Node::Include(
@@ -932,12 +959,13 @@ fn block_import(i: &[u8]) -> IResult<&[u8], Node<'_>> {
let mut p = tuple((
opt(tag("-")),
ws(tag("import")),
- ws(expr_str_lit),
- ws(tag("as")),
- ws(identifier),
- opt(tag("-")),
+ cut(tuple((
+ ws(expr_str_lit),
+ ws(tag("as")),
+ cut(pair(ws(identifier), opt(tag("-")))),
+ ))),
));
- let (i, (pws, _, name, _, scope, nws)) = p(i)?;
+ let (i, (pws, _, (name, _, (scope, nws)))) = p(i)?;
Ok((
i,
Node::Import(
@@ -955,18 +983,24 @@ fn block_macro<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Node<'a>
let mut p = tuple((
opt(tag("-")),
ws(tag("macro")),
- ws(identifier),
- ws(parameters),
- opt(tag("-")),
- |i| tag_block_end(i, s),
- |i| parse_template(i, s),
- |i| tag_block_start(i, s),
- opt(tag("-")),
- ws(tag("endmacro")),
- opt(tag("-")),
+ cut(tuple((
+ ws(identifier),
+ ws(parameters),
+ opt(tag("-")),
+ |i| tag_block_end(i, s),
+ cut(tuple((
+ |i| parse_template(i, s),
+ cut(tuple((
+ |i| tag_block_start(i, s),
+ opt(tag("-")),
+ ws(tag("endmacro")),
+ opt(tag("-")),
+ ))),
+ ))),
+ ))),
));
- let (i, (pws1, _, name, params, nws1, _, contents, _, pws2, _, nws2)) = p(i)?;
+ let (i, (pws1, _, (name, params, nws1, _, (contents, (_, pws2, _, nws2))))) = p(i)?;
if name == "super" {
panic!("invalid macro name 'super'");
}
@@ -989,16 +1023,18 @@ fn block_raw<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Node<'a>>
let mut p = tuple((
opt(tag("-")),
ws(tag("raw")),
- opt(tag("-")),
- |i| tag_block_end(i, s),
- take_until("{% endraw %}"),
- |i| tag_block_start(i, s),
- opt(tag("-")),
- ws(tag("endraw")),
- opt(tag("-")),
+ cut(tuple((
+ opt(tag("-")),
+ |i| tag_block_end(i, s),
+ take_until("{% endraw %}"),
+ |i| tag_block_start(i, s),
+ opt(tag("-")),
+ ws(tag("endraw")),
+ opt(tag("-")),
+ ))),
));
- let (i, (pws1, _, nws1, _, contents, _, pws2, _, nws2)) = p(i)?;
+ let (i, (pws1, _, (nws1, _, contents, _, pws2, _, nws2))) = p(i)?;
let str_contents = str::from_utf8(contents).unwrap();
Ok((
i,
@@ -1026,7 +1062,7 @@ fn block_node<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Node<'a>>
|i| block_macro(i, s),
|i| block_raw(i, s),
)),
- |i| tag_block_end(i, s),
+ cut(|i| tag_block_end(i, s)),
));
let (i, (_, contents, _)) = p(i)?;
Ok((i, contents))
@@ -1053,11 +1089,13 @@ fn block_comment_body<'a>(mut i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8
fn block_comment<'a>(i: &'a [u8], s: &'a Syntax<'a>) -> IResult<&'a [u8], Node<'a>> {
let mut p = tuple((
|i| tag_comment_start(i, s),
- opt(tag("-")),
- |i| block_comment_body(i, s),
- |i| tag_comment_end(i, s),
+ cut(tuple((
+ opt(tag("-")),
+ |i| block_comment_body(i, s),
+ |i| tag_comment_end(i, s),
+ ))),
));
- let (i, (_, pws, tail, _)) = p(i)?;
+ let (i, (_, (pws, tail, _))) = p(i)?;
Ok((i, Node::Comment(Ws(pws.is_some(), tail.ends_with(b"-")))))
}
@@ -1099,12 +1137,29 @@ pub fn parse<'a>(src: &'a str, syntax: &'a Syntax<'a>) -> Result<Vec<Node<'a>>,
Ok(res)
}
}
- Err(nom::Err::Error(err)) => {
- Err(format!("problems parsing template source: {:?}", err).into())
- }
- Err(nom::Err::Failure(err)) => {
- Err(format!("problems parsing template source: {:?}", err).into())
+
+ Err(nom::Err::Error(err)) | Err(nom::Err::Failure(err)) => {
+ let nom::error::Error { input, .. } = err;
+ let offset = src.len() - input.len();
+ let (source_before, source_after) = src.split_at(offset);
+
+ let source_after = match source_after.char_indices().enumerate().take(41).last() {
+ Some((40, (i, _))) => format!("{:?}...", &source_after[..i]),
+ _ => format!("{:?}", source_after),
+ };
+
+ let (row, last_line) = source_before.lines().enumerate().last().unwrap();
+ let column = last_line.chars().count();
+
+ let msg = format!(
+ "problems parsing template source at row {}, column {} near:\n{}",
+ row + 1,
+ column,
+ source_after,
+ );
+ Err(msg.into())
}
+
Err(nom::Err::Incomplete(_)) => Err("parsing incomplete".into()),
}
}
diff --git a/testing/tests/ui/typo_in_keyword.rs b/testing/tests/ui/typo_in_keyword.rs
new file mode 100644
index 0000000..acbf5d7
--- /dev/null
+++ b/testing/tests/ui/typo_in_keyword.rs
@@ -0,0 +1,11 @@
+use askama::Template;
+
+#[derive(Template)]
+#[template(
+ source = "{%for i in 1..=10%}{{i}}{%endfo%}\n1234567890123456789012345678901234567890",
+ ext = "txt"
+)]
+struct MyTemplate;
+
+fn main() {
+}
diff --git a/testing/tests/ui/typo_in_keyword.stderr b/testing/tests/ui/typo_in_keyword.stderr
new file mode 100644
index 0000000..545476e
--- /dev/null
+++ b/testing/tests/ui/typo_in_keyword.stderr
@@ -0,0 +1,8 @@
+error: problems parsing template source at row 1, column 26 near:
+"endfo%}\n12345678901234567890123456789012"...
+ --> $DIR/typo_in_keyword.rs:3:10
+ |
+3 | #[derive(Template)]
+ | ^^^^^^^^
+ |
+ = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info)