From 1170d54c3b0ed286787bb86e5b006bed1feeb4c9 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Fri, 7 Jun 2024 11:27:17 +0200 Subject: [PATCH] parser: improve parse error structure --- askama_derive/Cargo.toml | 2 +- askama_parser/Cargo.toml | 2 +- askama_parser/src/lib.rs | 72 ++++++++++++++++++++++++++-------------- 3 files changed, 49 insertions(+), 27 deletions(-) diff --git a/askama_derive/Cargo.toml b/askama_derive/Cargo.toml index a476857de..4a6764434 100644 --- a/askama_derive/Cargo.toml +++ b/askama_derive/Cargo.toml @@ -25,7 +25,7 @@ with-rocket = [] with-warp = [] [dependencies] -parser = { package = "askama_parser", version = "0.2", path = "../askama_parser" } +parser = { package = "askama_parser", version = "0.3", path = "../askama_parser" } mime = "0.3" mime_guess = "2" proc-macro2 = "1" diff --git a/askama_parser/Cargo.toml b/askama_parser/Cargo.toml index 0b11abdf9..789a41fc8 100644 --- a/askama_parser/Cargo.toml +++ b/askama_parser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "askama_parser" -version = "0.2.1" +version = "0.3.0" description = "Parser for Askama templates" documentation = "https://docs.rs/askama" keywords = ["markup", "template", "jinja2", "html"] diff --git a/askama_parser/src/lib.rs b/askama_parser/src/lib.rs index 666c3fb58..c5e4bb447 100644 --- a/askama_parser/src/lib.rs +++ b/askama_parser/src/lib.rs @@ -3,6 +3,7 @@ use std::borrow::Cow; use std::cell::Cell; +use std::env::current_dir; use std::path::Path; use std::rc::Rc; use std::{fmt, str}; @@ -99,7 +100,7 @@ impl<'a> Ast<'a> { nom::Err::Error(ErrorContext { input, message, .. }) | nom::Err::Failure(ErrorContext { input, message, .. }), ) => (input, message), - Err(nom::Err::Incomplete(_)) => return Err(ParseError("parsing incomplete".into())), + Err(nom::Err::Incomplete(_)) => return Err(ParseError::Incomplete), }; let offset = src.len() - input.len(); @@ -112,28 +113,13 @@ impl<'a> Ast<'a> { let (row, last_line) = source_before.lines().enumerate().last().unwrap_or_default(); let column = last_line.chars().count(); - - let file_info = file_path.and_then(|file_path| { - let cwd = std::env::current_dir().ok()?; - Some((cwd, file_path)) - }); - let message = message - .map(|message| format!("{message}\n")) - .unwrap_or_default(); - let error_msg = if let Some((cwd, file_path)) = file_info { - format!( - "{message}failed to parse template source\n --> {path}:{row}:{column}\n{source_after}", - path = strip_common(&cwd, &file_path), - row = row + 1, - ) - } else { - format!( - "{message}failed to parse template source at row {}, column {column} near:\n{source_after}", - row + 1, - ) - }; - - Err(ParseError(error_msg)) + Err(ParseError::Details { + message, + row, + column, + source_after, + file_path, + }) } pub fn nodes(&self) -> &[Node<'a>] { @@ -142,13 +128,49 @@ impl<'a> Ast<'a> { } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct ParseError(String); +pub enum ParseError { + Incomplete, + Details { + message: Option>, + row: usize, + column: usize, + source_after: String, + file_path: Option>, + }, +} impl std::error::Error for ParseError {} impl fmt::Display for ParseError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) + let (message, mut row, column, source, path) = match self { + ParseError::Incomplete => return write!(f, "parsing incomplete"), + ParseError::Details { + message, + row, + column, + source_after, + file_path, + } => (message, *row, column, source_after, file_path), + }; + + if let Some(message) = message { + writeln!(f, "{}", message)?; + } + + let path = path + .as_ref() + .and_then(|path| Some(strip_common(¤t_dir().ok()?, path))); + + row += 1; + match path { + Some(path) => f.write_fmt(format_args!( + "failed to parse template source\n --> {path}:{row}:{column}\n{source}", + )), + None => f.write_fmt(format_args!( + "failed to parse template source at row {row}, column {column} near:\n{source}", + )), + } } }