diff options
Diffstat (limited to 'askama_parser')
| -rw-r--r-- | askama_parser/src/expr.rs | 74 | ||||
| -rw-r--r-- | askama_parser/src/lib.rs | 128 | ||||
| -rw-r--r-- | askama_parser/src/node.rs | 76 | 
3 files changed, 183 insertions, 95 deletions
diff --git a/askama_parser/src/expr.rs b/askama_parser/src/expr.rs index 3b6bced..803681e 100644 --- a/askama_parser/src/expr.rs +++ b/askama_parser/src/expr.rs @@ -12,11 +12,12 @@ use nom::{error_position, IResult};  use super::{      char_lit, identifier, not_ws, num_lit, path_or_identifier, str_lit, ws, Level, PathOrIdentifier,  }; +use crate::ErrorContext;  macro_rules! expr_prec_layer {      ( $name:ident, $inner:ident, $op:expr ) => { -        fn $name(i: &'a str, level: Level) -> IResult<&'a str, Self> { -            let level = level.nest(i)?; +        fn $name(i: &'a str, level: Level) -> IResult<&'a str, Self, ErrorContext<&'a str>> { +            let (_, level) = level.nest(i)?;              let (i, left) = Self::$inner(i, level)?;              let (i, right) = many0(pair(                  ws(tag($op)), @@ -31,8 +32,8 @@ macro_rules! expr_prec_layer {          }      };      ( $name:ident, $inner:ident, $( $op:expr ),+ ) => { -        fn $name(i: &'a str, level: Level) -> IResult<&'a str, Self> { -            let level = level.nest(i)?; +        fn $name(i: &'a str, level: Level) -> IResult<&'a str, Self, ErrorContext<&'a str>> { +            let (_, level) = level.nest(i)?;              let (i, left) = Self::$inner(i, level)?;              let (i, right) = many0(pair(                  ws(alt(($( tag($op) ),+,))), @@ -71,8 +72,11 @@ pub enum Expr<'a> {  }  impl<'a> Expr<'a> { -    pub(super) fn arguments(i: &'a str, level: Level) -> IResult<&'a str, Vec<Self>> { -        let level = level.nest(i)?; +    pub(super) fn arguments( +        i: &'a str, +        level: Level, +    ) -> IResult<&'a str, Vec<Self>, ErrorContext<&'a str>> { +        let (_, level) = level.nest(i)?;          preceded(              ws(char('(')),              cut(terminated( @@ -82,8 +86,8 @@ impl<'a> Expr<'a> {          )(i)      } -    pub(super) fn parse(i: &'a str, level: Level) -> IResult<&'a str, Self> { -        let level = level.nest(i)?; +    pub(super) fn parse(i: &'a str, level: Level) -> IResult<&'a str, Self, ErrorContext<&'a str>> { +        let (_, level) = level.nest(i)?;          let range_right = move |i| {              pair(                  ws(alt((tag("..="), tag("..")))), @@ -114,9 +118,13 @@ impl<'a> Expr<'a> {      expr_prec_layer!(addsub, muldivmod, "+", "-");      expr_prec_layer!(muldivmod, filtered, "*", "/", "%"); -    fn filtered(i: &'a str, level: Level) -> IResult<&'a str, Self> { -        let level = level.nest(i)?; -        fn filter(i: &str, level: Level) -> IResult<&str, (&str, Option<Vec<Expr<'_>>>)> { +    fn filtered(i: &'a str, level: Level) -> IResult<&'a str, Self, ErrorContext<&'a str>> { +        let (_, level) = level.nest(i)?; +        #[allow(clippy::type_complexity)] +        fn filter( +            i: &str, +            level: Level, +        ) -> IResult<&str, (&str, Option<Vec<Expr<'_>>>), ErrorContext<&str>> {              let (i, (_, fname, args)) = tuple((                  char('|'),                  ws(identifier), @@ -143,8 +151,8 @@ impl<'a> Expr<'a> {          Ok((i, res))      } -    fn prefix(i: &'a str, level: Level) -> IResult<&'a str, Self> { -        let level = level.nest(i)?; +    fn prefix(i: &'a str, level: Level) -> IResult<&'a str, Self, ErrorContext<&'a str>> { +        let (_, level) = level.nest(i)?;          let (i, (ops, mut expr)) = pair(many0(ws(alt((tag("!"), tag("-"))))), |i| {              Suffix::parse(i, level)          })(i)?; @@ -154,8 +162,8 @@ impl<'a> Expr<'a> {          Ok((i, expr))      } -    fn single(i: &'a str, level: Level) -> IResult<&'a str, Self> { -        let level = level.nest(i)?; +    fn single(i: &'a str, level: Level) -> IResult<&'a str, Self, ErrorContext<&'a str>> { +        let (_, level) = level.nest(i)?;          alt((              Self::num,              Self::str, @@ -166,8 +174,8 @@ impl<'a> Expr<'a> {          ))(i)      } -    fn group(i: &'a str, level: Level) -> IResult<&'a str, Self> { -        let level = level.nest(i)?; +    fn group(i: &'a str, level: Level) -> IResult<&'a str, Self, ErrorContext<&'a str>> { +        let (_, level) = level.nest(i)?;          let (i, expr) = preceded(ws(char('(')), opt(|i| Self::parse(i, level)))(i)?;          let expr = match expr {              Some(expr) => expr, @@ -195,8 +203,8 @@ impl<'a> Expr<'a> {          Ok((i, Self::Tuple(exprs)))      } -    fn array(i: &'a str, level: Level) -> IResult<&'a str, Self> { -        let level = level.nest(i)?; +    fn array(i: &'a str, level: Level) -> IResult<&'a str, Self, ErrorContext<&'a str>> { +        let (_, level) = level.nest(i)?;          preceded(              ws(char('[')),              cut(terminated( @@ -209,7 +217,7 @@ impl<'a> Expr<'a> {          )(i)      } -    fn path_var_bool(i: &'a str) -> IResult<&'a str, Self> { +    fn path_var_bool(i: &'a str) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          map(path_or_identifier, |v| match v {              PathOrIdentifier::Path(v) => Self::Path(v),              PathOrIdentifier::Identifier(v @ "true") => Self::BoolLit(v), @@ -218,15 +226,15 @@ impl<'a> Expr<'a> {          })(i)      } -    fn str(i: &'a str) -> IResult<&'a str, Self> { +    fn str(i: &'a str) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          map(str_lit, Self::StrLit)(i)      } -    fn num(i: &'a str) -> IResult<&'a str, Self> { +    fn num(i: &'a str) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          map(num_lit, Self::NumLit)(i)      } -    fn char(i: &'a str) -> IResult<&'a str, Self> { +    fn char(i: &'a str) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          map(char_lit, Self::CharLit)(i)      }  } @@ -241,8 +249,8 @@ enum Suffix<'a> {  }  impl<'a> Suffix<'a> { -    fn parse(i: &'a str, level: Level) -> IResult<&'a str, Expr<'a>> { -        let level = level.nest(i)?; +    fn parse(i: &'a str, level: Level) -> IResult<&'a str, Expr<'a>, ErrorContext<&'a str>> { +        let (_, level) = level.nest(i)?;          let (mut i, mut expr) = Expr::single(i, level)?;          loop {              let (j, suffix) = opt(alt(( @@ -271,8 +279,8 @@ impl<'a> Suffix<'a> {          Ok((i, expr))      } -    fn r#macro(i: &'a str) -> IResult<&'a str, Self> { -        fn nested_parenthesis(input: &str) -> IResult<&str, ()> { +    fn r#macro(i: &'a str) -> IResult<&'a str, Self, ErrorContext<&'a str>> { +        fn nested_parenthesis(input: &str) -> IResult<&str, (), ErrorContext<&str>> {              let mut nested = 0;              let mut last = 0;              let mut in_str = false; @@ -329,7 +337,7 @@ impl<'a> Suffix<'a> {          )(i)      } -    fn attr(i: &'a str) -> IResult<&'a str, Self> { +    fn attr(i: &'a str) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          map(              preceded(                  ws(pair(char('.'), not(char('.')))), @@ -339,8 +347,8 @@ impl<'a> Suffix<'a> {          )(i)      } -    fn index(i: &'a str, level: Level) -> IResult<&'a str, Self> { -        let level = level.nest(i)?; +    fn index(i: &'a str, level: Level) -> IResult<&'a str, Self, ErrorContext<&'a str>> { +        let (_, level) = level.nest(i)?;          map(              preceded(                  ws(char('[')), @@ -350,12 +358,12 @@ impl<'a> Suffix<'a> {          )(i)      } -    fn call(i: &'a str, level: Level) -> IResult<&'a str, Self> { -        let level = level.nest(i)?; +    fn call(i: &'a str, level: Level) -> IResult<&'a str, Self, ErrorContext<&'a str>> { +        let (_, level) = level.nest(i)?;          map(move |i| Expr::arguments(i, level), Self::Call)(i)      } -    fn r#try(i: &'a str) -> IResult<&'a str, Self> { +    fn r#try(i: &'a str) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          map(preceded(take_till(not_ws), char('?')), |_| Self::Try)(i)      }  } diff --git a/askama_parser/src/lib.rs b/askama_parser/src/lib.rs index 78b0807..ba5f6a4 100644 --- a/askama_parser/src/lib.rs +++ b/askama_parser/src/lib.rs @@ -1,6 +1,7 @@  #![deny(unreachable_pub)]  #![deny(elided_lifetimes_in_paths)] +use std::borrow::Cow;  use std::cell::Cell;  use std::{fmt, str}; @@ -9,7 +10,7 @@ use nom::bytes::complete::{escaped, is_not, tag, take_till};  use nom::character::complete::char;  use nom::character::complete::{anychar, digit1};  use nom::combinator::{cut, eof, map, opt, recognize}; -use nom::error::ErrorKind; +use nom::error::{Error, ErrorKind, FromExternalError};  use nom::multi::many1;  use nom::sequence::{delimited, pair, preceded, terminated, tuple};  use nom::{error_position, AsChar, IResult, InputTakeAtPosition}; @@ -76,14 +77,16 @@ pub struct Ast<'a> {  impl<'a> Ast<'a> {      pub fn from_str(src: &'a str, syntax: &Syntax<'_>) -> Result<Self, ParseError> {          let parse = |i: &'a str| Node::many(i, &State::new(syntax)); -        let err = match terminated(parse, cut(eof))(src) { +        let (input, message) = match terminated(parse, cut(eof))(src) {              Ok(("", nodes)) => return Ok(Self { nodes }),              Ok(_) => unreachable!("eof() is not eof?"), -            Err(nom::Err::Error(err)) | Err(nom::Err::Failure(err)) => err, +            Err( +                nom::Err::Error(ErrorContext { input, message, .. }) +                | nom::Err::Failure(ErrorContext { input, message, .. }), +            ) => (input, message),              Err(nom::Err::Incomplete(_)) => return Err(ParseError("parsing incomplete".into())),          }; -        let nom::error::Error { input, .. } = err;          let offset = src.len() - input.len();          let (source_before, source_after) = src.split_at(offset); @@ -96,7 +99,12 @@ impl<'a> Ast<'a> {          let column = last_line.chars().count();          let msg = format!( -            "problems parsing template source at row {}, column {} near:\n{}", +            "{}problems parsing template source at row {}, column {} near:\n{}", +            if let Some(message) = message { +                format!("error: {message}\n") +            } else { +                String::new() +            },              row + 1,              column,              source_after, @@ -121,6 +129,55 @@ impl fmt::Display for ParseError {      }  } +/// This type is used to handle `nom` errors and in particular to add custom error messages. +/// It used to generate `ParserError`. +/// +/// It cannot be used to replace `ParseError` because it expects a generic, which would make +/// `askama`'s users experience less good (since this generic is only needed for `nom`). +#[derive(Debug)] +pub(crate) struct ErrorContext<I> { +    pub(crate) input: I, +    pub(crate) message: Option<Cow<'static, str>>, +} + +impl<I> nom::error::ParseError<I> for ErrorContext<I> { +    fn from_error_kind(input: I, _code: ErrorKind) -> Self { +        Self { +            input, +            message: None, +        } +    } + +    fn append(_: I, _: ErrorKind, other: Self) -> Self { +        other +    } +} + +impl<I, E: std::fmt::Display> FromExternalError<I, E> for ErrorContext<I> { +    fn from_external_error(input: I, _kind: ErrorKind, e: E) -> Self { +        Self { +            input, +            message: Some(Cow::Owned(e.to_string())), +        } +    } +} + +impl<I> ErrorContext<I> { +    pub(crate) fn from_err(error: nom::Err<Error<I>>) -> nom::Err<Self> { +        match error { +            nom::Err::Incomplete(i) => nom::Err::Incomplete(i), +            nom::Err::Failure(Error { input, .. }) => nom::Err::Failure(Self { +                input, +                message: None, +            }), +            nom::Err::Error(Error { input, .. }) => nom::Err::Error(Self { +                input, +                message: None, +            }), +        } +    } +} +  fn is_ws(c: char) -> bool {      matches!(c, ' ' | '\t' | '\r' | '\n')  } @@ -130,16 +187,16 @@ fn not_ws(c: char) -> bool {  }  fn ws<'a, O>( -    inner: impl FnMut(&'a str) -> IResult<&'a str, O>, -) -> impl FnMut(&'a str) -> IResult<&'a str, O> { +    inner: impl FnMut(&'a str) -> IResult<&'a str, O, ErrorContext<&'a str>>, +) -> impl FnMut(&'a str) -> IResult<&'a str, O, ErrorContext<&'a str>> {      delimited(take_till(not_ws), inner, take_till(not_ws))  }  /// Skips input until `end` was found, but does not consume it.  /// Returns tuple that would be returned when parsing `end`.  fn skip_till<'a, O>( -    end: impl FnMut(&'a str) -> IResult<&'a str, O>, -) -> impl FnMut(&'a str) -> IResult<&'a str, (&'a str, O)> { +    end: impl FnMut(&'a str) -> IResult<&'a str, O, ErrorContext<&'a str>>, +) -> impl FnMut(&'a str) -> IResult<&'a str, (&'a str, O), ErrorContext<&'a str>> {      enum Next<O> {          IsEnd(O),          NotEnd(char), @@ -157,8 +214,10 @@ fn skip_till<'a, O>(      }  } -fn keyword<'a>(k: &'a str) -> impl FnMut(&'a str) -> IResult<&'a str, &'a str> { -    move |i: &'a str| -> IResult<&'a str, &'a str> { +fn keyword<'a>( +    k: &'a str, +) -> impl FnMut(&'a str) -> IResult<&'a str, &'a str, ErrorContext<&'a str>> { +    move |i: &'a str| -> IResult<&'a str, &'a str, ErrorContext<&'a str>> {          let (j, v) = identifier(i)?;          if k == v {              Ok((j, v)) @@ -168,15 +227,15 @@ fn keyword<'a>(k: &'a str) -> impl FnMut(&'a str) -> IResult<&'a str, &'a str> {      }  } -fn identifier(input: &str) -> IResult<&str, &str> { -    fn start(s: &str) -> IResult<&str, &str> { +fn identifier(input: &str) -> IResult<&str, &str, ErrorContext<&str>> { +    fn start(s: &str) -> IResult<&str, &str, ErrorContext<&str>> {          s.split_at_position1_complete(              |c| !(c.is_alpha() || c == '_' || c >= '\u{0080}'),              nom::error::ErrorKind::Alpha,          )      } -    fn tail(s: &str) -> IResult<&str, &str> { +    fn tail(s: &str) -> IResult<&str, &str, ErrorContext<&str>> {          s.split_at_position1_complete(              |c| !(c.is_alphanum() || c == '_' || c >= '\u{0080}'),              nom::error::ErrorKind::Alpha, @@ -186,11 +245,11 @@ fn identifier(input: &str) -> IResult<&str, &str> {      recognize(pair(start, opt(tail)))(input)  } -fn bool_lit(i: &str) -> IResult<&str, &str> { +fn bool_lit(i: &str) -> IResult<&str, &str, ErrorContext<&str>> {      alt((keyword("false"), keyword("true")))(i)  } -fn num_lit(i: &str) -> IResult<&str, &str> { +fn num_lit(i: &str) -> IResult<&str, &str, ErrorContext<&str>> {      recognize(tuple((          opt(char('-')),          digit1, @@ -198,7 +257,7 @@ fn num_lit(i: &str) -> IResult<&str, &str> {      )))(i)  } -fn str_lit(i: &str) -> IResult<&str, &str> { +fn str_lit(i: &str) -> IResult<&str, &str, ErrorContext<&str>> {      let (i, s) = delimited(          char('"'),          opt(escaped(is_not("\\\""), '\\', anychar)), @@ -207,7 +266,7 @@ fn str_lit(i: &str) -> IResult<&str, &str> {      Ok((i, s.unwrap_or_default()))  } -fn char_lit(i: &str) -> IResult<&str, &str> { +fn char_lit(i: &str) -> IResult<&str, &str, ErrorContext<&str>> {      let (i, s) = delimited(          char('\''),          opt(escaped(is_not("\\\'"), '\\', anychar)), @@ -221,7 +280,7 @@ enum PathOrIdentifier<'a> {      Identifier(&'a str),  } -fn path_or_identifier(i: &str) -> IResult<&str, PathOrIdentifier<'_>> { +fn path_or_identifier(i: &str) -> IResult<&str, PathOrIdentifier<'_>, ErrorContext<&str>> {      let root = ws(opt(tag("::")));      let tail = opt(many1(preceded(ws(tag("::")), identifier))); @@ -267,36 +326,40 @@ impl<'a> State<'a> {          }      } -    fn nest<'b>(&self, i: &'b str) -> Result<(), nom::Err<nom::error::Error<&'b str>>> { -        self.level.set(self.level.get().nest(i)?); -        Ok(()) +    fn nest<'b>(&self, i: &'b str) -> IResult<&'b str, (), ErrorContext<&'b str>> { +        let (_, level) = self.level.get().nest(i)?; +        self.level.set(level); +        Ok((i, ()))      }      fn leave(&self) {          self.level.set(self.level.get().leave());      } -    fn tag_block_start<'i>(&self, i: &'i str) -> IResult<&'i str, &'i str> { +    fn tag_block_start<'i>(&self, i: &'i str) -> IResult<&'i str, &'i str, ErrorContext<&'i str>> {          tag(self.syntax.block_start)(i)      } -    fn tag_block_end<'i>(&self, i: &'i str) -> IResult<&'i str, &'i str> { +    fn tag_block_end<'i>(&self, i: &'i str) -> IResult<&'i str, &'i str, ErrorContext<&'i str>> {          tag(self.syntax.block_end)(i)      } -    fn tag_comment_start<'i>(&self, i: &'i str) -> IResult<&'i str, &'i str> { +    fn tag_comment_start<'i>( +        &self, +        i: &'i str, +    ) -> IResult<&'i str, &'i str, ErrorContext<&'i str>> {          tag(self.syntax.comment_start)(i)      } -    fn tag_comment_end<'i>(&self, i: &'i str) -> IResult<&'i str, &'i str> { +    fn tag_comment_end<'i>(&self, i: &'i str) -> IResult<&'i str, &'i str, ErrorContext<&'i str>> {          tag(self.syntax.comment_end)(i)      } -    fn tag_expr_start<'i>(&self, i: &'i str) -> IResult<&'i str, &'i str> { +    fn tag_expr_start<'i>(&self, i: &'i str) -> IResult<&'i str, &'i str, ErrorContext<&'i str>> {          tag(self.syntax.expr_start)(i)      } -    fn tag_expr_end<'i>(&self, i: &'i str) -> IResult<&'i str, &'i str> { +    fn tag_expr_end<'i>(&self, i: &'i str) -> IResult<&'i str, &'i str, ErrorContext<&'i str>> {          tag(self.syntax.expr_end)(i)      } @@ -340,12 +403,15 @@ impl Default for Syntax<'static> {  pub(crate) struct Level(u8);  impl Level { -    fn nest(self, i: &str) -> Result<Level, nom::Err<nom::error::Error<&str>>> { +    fn nest(self, i: &str) -> IResult<&str, Level, ErrorContext<&str>> {          if self.0 >= Self::MAX_DEPTH { -            return Err(nom::Err::Failure(error_position!(i, ErrorKind::TooLarge))); +            return Err(ErrorContext::from_err(nom::Err::Failure(error_position!( +                i, +                ErrorKind::TooLarge +            ))));          } -        Ok(Level(self.0 + 1)) +        Ok((i, Level(self.0 + 1)))      }      fn leave(&self) -> Self { diff --git a/askama_parser/src/node.rs b/askama_parser/src/node.rs index ba4d09e..596b99a 100644 --- a/askama_parser/src/node.rs +++ b/askama_parser/src/node.rs @@ -11,6 +11,8 @@ use nom::multi::{fold_many0, many0, many1, separated_list0, separated_list1};  use nom::sequence::{delimited, pair, preceded, terminated, tuple};  use nom::{error_position, IResult}; +use crate::ErrorContext; +  use super::{      bool_lit, char_lit, identifier, is_ws, keyword, num_lit, path_or_identifier, skip_till,      str_lit, ws, Expr, PathOrIdentifier, State, @@ -37,7 +39,10 @@ pub enum Node<'a> {  }  impl<'a> Node<'a> { -    pub(super) fn many(i: &'a str, s: &State<'_>) -> IResult<&'a str, Vec<Self>> { +    pub(super) fn many( +        i: &'a str, +        s: &State<'_>, +    ) -> IResult<&'a str, Vec<Self>, ErrorContext<&'a str>> {          complete(many0(alt((              map(|i| Lit::parse(i, s), Self::Lit),              map(|i| Comment::parse(i, s), Self::Comment), @@ -46,7 +51,7 @@ impl<'a> Node<'a> {          ))))(i)      } -    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self> { +    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          let mut p = delimited(              |i| s.tag_block_start(i),              alt(( @@ -74,7 +79,7 @@ impl<'a> Node<'a> {          result      } -    fn r#break(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self> { +    fn r#break(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          let mut p = tuple((              opt(Whitespace::parse),              ws(keyword("break")), @@ -87,7 +92,7 @@ impl<'a> Node<'a> {          Ok((j, Self::Break(Ws(pws, nws))))      } -    fn r#continue(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self> { +    fn r#continue(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          let mut p = tuple((              opt(Whitespace::parse),              ws(keyword("continue")), @@ -100,7 +105,7 @@ impl<'a> Node<'a> {          Ok((j, Self::Continue(Ws(pws, nws))))      } -    fn expr(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self> { +    fn expr(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          let mut p = tuple((              |i| s.tag_expr_start(i),              cut(tuple(( @@ -128,7 +133,7 @@ pub enum Target<'a> {  }  impl<'a> Target<'a> { -    pub(super) fn parse(i: &'a str) -> IResult<&'a str, Self> { +    pub(super) fn parse(i: &'a str) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          let mut opt_opening_paren = map(opt(ws(char('('))), |o| o.is_some());          let mut opt_closing_paren = map(opt(ws(char(')'))), |o| o.is_some());          let mut opt_opening_brace = map(opt(ws(char('{'))), |o| o.is_some()); @@ -211,7 +216,7 @@ impl<'a> Target<'a> {          map(identifier, Self::Name)(i)      } -    fn lit(i: &'a str) -> IResult<&'a str, Self> { +    fn lit(i: &'a str) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          alt((              map(str_lit, Self::StrLit),              map(char_lit, Self::CharLit), @@ -220,7 +225,7 @@ impl<'a> Target<'a> {          ))(i)      } -    fn named(i: &'a str) -> IResult<&str, (&str, Self)> { +    fn named(i: &'a str) -> IResult<&str, (&str, Self), ErrorContext<&'a str>> {          let (i, (src, target)) = pair(identifier, opt(preceded(ws(char(':')), Self::parse)))(i)?;          Ok((i, (src, target.unwrap_or(Self::Name(src)))))      } @@ -234,7 +239,7 @@ pub struct When<'a> {  }  impl<'a> When<'a> { -    fn r#match(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self> { +    fn r#match(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          let mut p = tuple((              |i| s.tag_block_start(i),              opt(Whitespace::parse), @@ -257,7 +262,7 @@ impl<'a> When<'a> {      }      #[allow(clippy::self_named_constructors)] -    fn when(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self> { +    fn when(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          let mut p = tuple((              |i| s.tag_block_start(i),              opt(Whitespace::parse), @@ -289,7 +294,7 @@ pub struct Cond<'a> {  }  impl<'a> Cond<'a> { -    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self> { +    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          let mut p = tuple((              |i| s.tag_block_start(i),              opt(Whitespace::parse), @@ -320,7 +325,7 @@ pub struct CondTest<'a> {  }  impl<'a> CondTest<'a> { -    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self> { +    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          let mut p = preceded(              ws(keyword("if")),              cut(tuple(( @@ -345,7 +350,7 @@ pub enum Whitespace {  }  impl Whitespace { -    fn parse(i: &str) -> IResult<&str, Self> { +    fn parse(i: &str) -> IResult<&str, Self, ErrorContext<&str>> {          alt((              value(Self::Preserve, char('+')),              value(Self::Suppress, char('-')), @@ -367,8 +372,11 @@ pub struct Loop<'a> {  }  impl<'a> Loop<'a> { -    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self> { -        fn content<'a>(i: &'a str, s: &State<'_>) -> IResult<&'a str, Vec<Node<'a>>> { +    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self, ErrorContext<&'a str>> { +        fn content<'a>( +            i: &'a str, +            s: &State<'_>, +        ) -> IResult<&'a str, Vec<Node<'a>>, ErrorContext<&'a str>> {              s.enter_loop();              let result = Node::many(i, s);              s.leave_loop(); @@ -448,8 +456,8 @@ pub struct Macro<'a> {  }  impl<'a> Macro<'a> { -    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self> { -        fn parameters(i: &str) -> IResult<&str, Vec<&str>> { +    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self, ErrorContext<&'a str>> { +        fn parameters(i: &str) -> IResult<&str, Vec<&str>, ErrorContext<&str>> {              delimited(                  ws(char('(')),                  separated_list0(char(','), ws(identifier)), @@ -482,7 +490,10 @@ impl<'a> Macro<'a> {          if name == "super" {              // TODO: yield a a better error message here -            return Err(nom::Err::Failure(Error::new(i, ErrorKind::Fail))); +            return Err(ErrorContext::from_err(nom::Err::Failure(Error::new( +                i, +                ErrorKind::Fail, +            ))));          }          Ok(( @@ -506,7 +517,7 @@ pub struct Import<'a> {  }  impl<'a> Import<'a> { -    fn parse(i: &'a str) -> IResult<&'a str, Self> { +    fn parse(i: &'a str) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          let mut p = tuple((              opt(Whitespace::parse),              ws(keyword("import")), @@ -537,7 +548,7 @@ pub struct Call<'a> {  }  impl<'a> Call<'a> { -    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self> { +    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          let mut p = tuple((              opt(Whitespace::parse),              ws(keyword("call")), @@ -572,7 +583,7 @@ pub struct Match<'a> {  }  impl<'a> Match<'a> { -    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self> { +    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          let mut p = tuple((              opt(Whitespace::parse),              ws(keyword("match")), @@ -623,7 +634,7 @@ pub struct BlockDef<'a> {  }  impl<'a> BlockDef<'a> { -    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self> { +    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          let mut start = tuple((              opt(Whitespace::parse),              ws(keyword("block")), @@ -664,7 +675,7 @@ pub struct Lit<'a> {  }  impl<'a> Lit<'a> { -    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self> { +    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          let p_start = alt((              tag(s.syntax.block_start),              tag(s.syntax.comment_start), @@ -704,7 +715,7 @@ pub struct Raw<'a> {  }  impl<'a> Raw<'a> { -    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self> { +    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          let endraw = tuple((              |i| s.tag_block_start(i),              opt(Whitespace::parse), @@ -739,7 +750,7 @@ pub struct Let<'a> {  }  impl<'a> Let<'a> { -    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self> { +    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          let mut p = tuple((              opt(Whitespace::parse),              ws(alt((keyword("let"), keyword("set")))), @@ -772,7 +783,7 @@ pub struct If<'a> {  }  impl<'a> If<'a> { -    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self> { +    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          let mut p = tuple((              opt(Whitespace::parse),              |i| CondTest::parse(i, s), @@ -817,7 +828,7 @@ pub struct Include<'a> {  }  impl<'a> Include<'a> { -    fn parse(i: &'a str) -> IResult<&'a str, Self> { +    fn parse(i: &'a str) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          let mut p = tuple((              opt(Whitespace::parse),              ws(keyword("include")), @@ -840,7 +851,7 @@ pub struct Extends<'a> {  }  impl<'a> Extends<'a> { -    fn parse(i: &'a str) -> IResult<&'a str, Self> { +    fn parse(i: &'a str) -> IResult<&'a str, Self, ErrorContext<&'a str>> {          let (i, path) = preceded(ws(keyword("extends")), cut(ws(str_lit)))(i)?;          Ok((i, Self { path }))      } @@ -853,12 +864,15 @@ pub struct Comment<'a> {  }  impl<'a> Comment<'a> { -    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self> { -        fn body<'a>(mut i: &'a str, s: &State<'_>) -> IResult<&'a str, &'a str> { +    fn parse(i: &'a str, s: &State<'_>) -> IResult<&'a str, Self, ErrorContext<&'a str>> { +        fn body<'a>( +            mut i: &'a str, +            s: &State<'_>, +        ) -> IResult<&'a str, &'a str, ErrorContext<&'a str>> {              let mut level = 0;              loop {                  let (end, tail) = take_until(s.syntax.comment_end)(i)?; -                match take_until::<_, _, Error<_>>(s.syntax.comment_start)(i) { +                match take_until::<_, _, ErrorContext<_>>(s.syntax.comment_start)(i) {                      Ok((start, _)) if start.as_ptr() < end.as_ptr() => {                          level += 1;                          i = &start[2..];  | 
