From 38a2a86e5569ad44cbea06144562ee075c3e5fce 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] 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)]