From 385434aa1d31defafe1f85ec429903b4067bff32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kijewski?= Date: Fri, 17 May 2024 16:07:44 +0200 Subject: [PATCH 1/2] Add unclosed node ui tests --- testing/tests/ui/unclosed-nodes.rs | 51 ++++++++++++ testing/tests/ui/unclosed-nodes.stderr | 107 +++++++++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 testing/tests/ui/unclosed-nodes.rs create mode 100644 testing/tests/ui/unclosed-nodes.stderr diff --git a/testing/tests/ui/unclosed-nodes.rs b/testing/tests/ui/unclosed-nodes.rs new file mode 100644 index 00000000..9fc69ecc --- /dev/null +++ b/testing/tests/ui/unclosed-nodes.rs @@ -0,0 +1,51 @@ +use askama::Template; + +#[derive(Template)] +#[template(source = "{{ expr", ext = "txt")] +struct Expr1; + +#[derive(Template)] +#[template(source = "{{ expr ", ext = "txt")] +struct Expr2; + +#[derive(Template)] +#[template(source = "{{ expr -", ext = "txt")] +struct Expr3; + +#[derive(Template)] +#[template(source = "{{ expr -}", ext = "txt")] +struct Expr4; + +#[derive(Template)] +#[template(source = "{% let x", ext = "txt")] +struct Node1; + +#[derive(Template)] +#[template(source = "{% let x ", ext = "txt")] +struct Node2; + +#[derive(Template)] +#[template(source = "{% let x -", ext = "txt")] +struct Node3; + +#[derive(Template)] +#[template(source = "{% let x -%", ext = "txt")] +struct Node4; + +#[derive(Template)] +#[template(source = "{# comment", ext = "txt")] +struct Comment1; + +#[derive(Template)] +#[template(source = "{# comment ", ext = "txt")] +struct Comment2; + +#[derive(Template)] +#[template(source = "{# comment -", ext = "txt")] +struct Comment3; + +#[derive(Template)] +#[template(source = "{# comment -#", ext = "txt")] +struct Comment4; + +fn main() {} diff --git a/testing/tests/ui/unclosed-nodes.stderr b/testing/tests/ui/unclosed-nodes.stderr new file mode 100644 index 00000000..d48c01bd --- /dev/null +++ b/testing/tests/ui/unclosed-nodes.stderr @@ -0,0 +1,107 @@ +error: failed to parse template source at row 1, column 7 near: + "" + --> tests/ui/unclosed-nodes.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) + +error: failed to parse template source at row 1, column 8 near: + "" + --> tests/ui/unclosed-nodes.rs:7:10 + | +7 | #[derive(Template)] + | ^^^^^^^^ + | + = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: failed to parse template source at row 1, column 9 near: + "" + --> tests/ui/unclosed-nodes.rs:11:10 + | +11 | #[derive(Template)] + | ^^^^^^^^ + | + = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: failed to parse template source at row 1, column 9 near: + "}" + --> tests/ui/unclosed-nodes.rs:15:10 + | +15 | #[derive(Template)] + | ^^^^^^^^ + | + = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: failed to parse template source at row 1, column 8 near: + "" + --> tests/ui/unclosed-nodes.rs:19:10 + | +19 | #[derive(Template)] + | ^^^^^^^^ + | + = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: failed to parse template source at row 1, column 9 near: + "" + --> tests/ui/unclosed-nodes.rs:23:10 + | +23 | #[derive(Template)] + | ^^^^^^^^ + | + = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: failed to parse template source at row 1, column 10 near: + "" + --> tests/ui/unclosed-nodes.rs:27:10 + | +27 | #[derive(Template)] + | ^^^^^^^^ + | + = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: failed to parse template source at row 1, column 10 near: + "%" + --> tests/ui/unclosed-nodes.rs:31:10 + | +31 | #[derive(Template)] + | ^^^^^^^^ + | + = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: failed to parse template source at row 1, column 10 near: + "" + --> tests/ui/unclosed-nodes.rs:35:10 + | +35 | #[derive(Template)] + | ^^^^^^^^ + | + = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: failed to parse template source at row 1, column 11 near: + "" + --> tests/ui/unclosed-nodes.rs:39:10 + | +39 | #[derive(Template)] + | ^^^^^^^^ + | + = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: failed to parse template source at row 1, column 12 near: + "" + --> tests/ui/unclosed-nodes.rs:43:10 + | +43 | #[derive(Template)] + | ^^^^^^^^ + | + = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: failed to parse template source at row 1, column 13 near: + "" + --> tests/ui/unclosed-nodes.rs:47:10 + | +47 | #[derive(Template)] + | ^^^^^^^^ + | + = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) From fa26fd6dbe432b4ba9db5df266c713794b66d094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kijewski?= Date: Fri, 17 May 2024 16:26:16 +0200 Subject: [PATCH 2/2] Better error messages for truncated files --- askama_parser/src/node.rs | 47 +++++++++++++++++++------- testing/tests/ui/unclosed-nodes.stderr | 38 +++++++++++++-------- 2 files changed, 58 insertions(+), 27 deletions(-) diff --git a/askama_parser/src/node.rs b/askama_parser/src/node.rs index 5ba5e5fe..408a8000 100644 --- a/askama_parser/src/node.rs +++ b/askama_parser/src/node.rs @@ -12,7 +12,7 @@ use nom::error_position; use nom::multi::{fold_many0, many0, many1, separated_list0, separated_list1}; use nom::sequence::{delimited, pair, preceded, terminated, tuple}; -use crate::{not_ws, ErrorContext, ParseResult}; +use crate::{not_ws, ErrorContext, ParseErr, ParseResult}; use super::{ bool_lit, char_lit, filter, identifier, is_ws, keyword, num_lit, path_or_identifier, skip_till, @@ -93,10 +93,16 @@ impl<'a> Node<'a> { let (i, _) = s.nest(j)?; let result = func(i, s); s.leave(); - let (i, node) = result?; - let (i, _) = cut(|i| s.tag_block_end(i))(i)?; - Ok((i, node)) + + let (i, closed) = cut(alt(( + value(true, |i| s.tag_block_end(i)), + value(false, ws(eof)), + )))(i)?; + match closed { + true => Ok((i, node)), + false => Err(fail_unclosed("block", s.syntax.block_end, i)), + } } fn r#break(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> { @@ -132,17 +138,22 @@ impl<'a> Node<'a> { } fn expr(i: &'a str, s: &State<'_>) -> ParseResult<'a, Self> { - let mut p = tuple(( + let (i, (pws, expr)) = preceded( |i| s.tag_expr_start(i), - cut(tuple(( + cut(pair( opt(Whitespace::parse), ws(|i| Expr::parse(i, s.level.get())), - opt(Whitespace::parse), - |i| s.tag_expr_end(i), - ))), - )); - let (i, (_, (pws, expr, nws, _))) = p(i)?; - Ok((i, Self::Expr(Ws(pws, nws), expr))) + )), + )(i)?; + + let (i, (nws, closed)) = cut(pair( + opt(Whitespace::parse), + alt((value(true, |i| s.tag_expr_end(i)), value(false, ws(eof)))), + ))(i)?; + match closed { + true => Ok((i, Self::Expr(Ws(pws, nws), expr))), + false => Err(fail_unclosed("expression", s.syntax.expr_end, i)), + } } } @@ -1059,7 +1070,10 @@ impl<'a> Comment<'a> { fn content<'a>(mut i: &'a str, s: &State<'_>) -> ParseResult<'a, ()> { let mut depth = 0usize; loop { - let (_, (j, tag)) = skip_till(|i| tag(i, s))(i)?; + let (_, tag) = opt(skip_till(|i| tag(i, s)))(i)?; + let Some((j, tag)) = tag else { + return Err(fail_unclosed("comment", s.syntax.comment_end, i)); + }; match tag { Tag::Open => match depth.checked_add(1) { Some(new_depth) => depth = new_depth, @@ -1109,3 +1123,10 @@ impl<'a> Comment<'a> { /// Second field is "minus/plus sign was used on the right part of the item". #[derive(Clone, Copy, Debug, PartialEq)] pub struct Ws(pub Option, pub Option); + +fn fail_unclosed<'a>(kind: &str, tag: &str, i: &'a str) -> ParseErr<'a> { + nom::Err::Failure(ErrorContext { + input: i, + message: Some(Cow::Owned(format!("unclosed {kind}, missing {tag:?}"))), + }) +} diff --git a/testing/tests/ui/unclosed-nodes.stderr b/testing/tests/ui/unclosed-nodes.stderr index d48c01bd..44312cc0 100644 --- a/testing/tests/ui/unclosed-nodes.stderr +++ b/testing/tests/ui/unclosed-nodes.stderr @@ -1,4 +1,5 @@ -error: failed to parse template source at row 1, column 7 near: +error: unclosed expression, missing "}}" + failed to parse template source at row 1, column 7 near: "" --> tests/ui/unclosed-nodes.rs:3:10 | @@ -7,7 +8,8 @@ error: failed to parse template source at row 1, column 7 near: | = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) -error: failed to parse template source at row 1, column 8 near: +error: unclosed expression, missing "}}" + failed to parse template source at row 1, column 8 near: "" --> tests/ui/unclosed-nodes.rs:7:10 | @@ -16,7 +18,8 @@ error: failed to parse template source at row 1, column 8 near: | = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) -error: failed to parse template source at row 1, column 9 near: +error: unclosed expression, missing "}}" + failed to parse template source at row 1, column 9 near: "" --> tests/ui/unclosed-nodes.rs:11:10 | @@ -34,7 +37,8 @@ error: failed to parse template source at row 1, column 9 near: | = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) -error: failed to parse template source at row 1, column 8 near: +error: unclosed block, missing "%}" + failed to parse template source at row 1, column 8 near: "" --> tests/ui/unclosed-nodes.rs:19:10 | @@ -43,7 +47,8 @@ error: failed to parse template source at row 1, column 8 near: | = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) -error: failed to parse template source at row 1, column 9 near: +error: unclosed block, missing "%}" + failed to parse template source at row 1, column 9 near: "" --> tests/ui/unclosed-nodes.rs:23:10 | @@ -52,7 +57,8 @@ error: failed to parse template source at row 1, column 9 near: | = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) -error: failed to parse template source at row 1, column 10 near: +error: unclosed block, missing "%}" + failed to parse template source at row 1, column 10 near: "" --> tests/ui/unclosed-nodes.rs:27:10 | @@ -70,8 +76,9 @@ error: failed to parse template source at row 1, column 10 near: | = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) -error: failed to parse template source at row 1, column 10 near: - "" +error: unclosed comment, missing "#}" + failed to parse template source at row 1, column 2 near: + " comment" --> tests/ui/unclosed-nodes.rs:35:10 | 35 | #[derive(Template)] @@ -79,8 +86,9 @@ error: failed to parse template source at row 1, column 10 near: | = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) -error: failed to parse template source at row 1, column 11 near: - "" +error: unclosed comment, missing "#}" + failed to parse template source at row 1, column 2 near: + " comment " --> tests/ui/unclosed-nodes.rs:39:10 | 39 | #[derive(Template)] @@ -88,8 +96,9 @@ error: failed to parse template source at row 1, column 11 near: | = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) -error: failed to parse template source at row 1, column 12 near: - "" +error: unclosed comment, missing "#}" + failed to parse template source at row 1, column 2 near: + " comment -" --> tests/ui/unclosed-nodes.rs:43:10 | 43 | #[derive(Template)] @@ -97,8 +106,9 @@ error: failed to parse template source at row 1, column 12 near: | = note: this error originates in the derive macro `Template` (in Nightly builds, run with -Z macro-backtrace for more info) -error: failed to parse template source at row 1, column 13 near: - "" +error: unclosed comment, missing "#}" + failed to parse template source at row 1, column 2 near: + " comment -#" --> tests/ui/unclosed-nodes.rs:47:10 | 47 | #[derive(Template)]