mirror of
https://github.com/askama-rs/askama.git
synced 2025-10-03 07:45:14 +00:00
parser: simplify ErrorContext construction
This commit is contained in:
parent
c3582f5d89
commit
627d58bc3b
@ -1,4 +1,3 @@
|
|||||||
use std::borrow::Cow;
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
@ -111,12 +110,10 @@ impl<'a> Expr<'a> {
|
|||||||
move |i| Self::parse(i, level),
|
move |i| Self::parse(i, level),
|
||||||
))(i)?;
|
))(i)?;
|
||||||
if has_named_arguments && !matches!(expr, Self::NamedArgument(_, _)) {
|
if has_named_arguments && !matches!(expr, Self::NamedArgument(_, _)) {
|
||||||
Err(nom::Err::Failure(ErrorContext {
|
Err(nom::Err::Failure(ErrorContext::new(
|
||||||
input: start,
|
"named arguments must always be passed last",
|
||||||
message: Some(Cow::Borrowed(
|
start,
|
||||||
"named arguments must always be passed last",
|
)))
|
||||||
)),
|
|
||||||
}))
|
|
||||||
} else {
|
} else {
|
||||||
Ok((i, expr))
|
Ok((i, expr))
|
||||||
}
|
}
|
||||||
@ -146,12 +143,10 @@ impl<'a> Expr<'a> {
|
|||||||
if named_arguments.insert(argument) {
|
if named_arguments.insert(argument) {
|
||||||
Ok((i, Self::NamedArgument(argument, Box::new(value))))
|
Ok((i, Self::NamedArgument(argument, Box::new(value))))
|
||||||
} else {
|
} else {
|
||||||
Err(nom::Err::Failure(ErrorContext {
|
Err(nom::Err::Failure(ErrorContext::new(
|
||||||
input: start,
|
format!("named argument `{argument}` was passed more than once"),
|
||||||
message: Some(Cow::Owned(format!(
|
start,
|
||||||
"named argument `{argument}` was passed more than once"
|
)))
|
||||||
))),
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,9 +168,13 @@ pub(crate) struct ErrorContext<'a> {
|
|||||||
|
|
||||||
impl<'a> ErrorContext<'a> {
|
impl<'a> ErrorContext<'a> {
|
||||||
fn unclosed(kind: &str, tag: &str, i: &'a str) -> Self {
|
fn unclosed(kind: &str, tag: &str, i: &'a str) -> Self {
|
||||||
|
Self::new(format!("unclosed {kind}, missing {tag:?}"), i)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new(message: impl Into<Cow<'static, str>>, input: &'a str) -> Self {
|
||||||
Self {
|
Self {
|
||||||
input: i,
|
input,
|
||||||
message: Some(Cow::Owned(format!("unclosed {kind}, missing {tag:?}"))),
|
message: Some(message.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,19 +377,20 @@ fn char_lit(i: &str) -> ParseResult<'_> {
|
|||||||
opt(escaped(is_not("\\\'"), '\\', anychar)),
|
opt(escaped(is_not("\\\'"), '\\', anychar)),
|
||||||
char('\''),
|
char('\''),
|
||||||
)(i)?;
|
)(i)?;
|
||||||
|
|
||||||
let Some(s) = s else {
|
let Some(s) = s else {
|
||||||
return Err(nom::Err::Failure(ErrorContext {
|
return Err(nom::Err::Failure(ErrorContext::new(
|
||||||
input: start,
|
"empty character literal",
|
||||||
// Same error as rustc.
|
start,
|
||||||
message: Some(Cow::Borrowed("empty character literal")),
|
)));
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
let Ok(("", c)) = Char::parse(s) else {
|
let Ok(("", c)) = Char::parse(s) else {
|
||||||
return Err(nom::Err::Failure(ErrorContext {
|
return Err(nom::Err::Failure(ErrorContext::new(
|
||||||
input: start,
|
"invalid character",
|
||||||
message: Some(Cow::Borrowed("invalid character")),
|
start,
|
||||||
}));
|
)));
|
||||||
};
|
};
|
||||||
|
|
||||||
let (nb, max_value, err1, err2) = match c {
|
let (nb, max_value, err1, err2) = match c {
|
||||||
Char::Literal | Char::Escaped => return Ok((i, s)),
|
Char::Literal | Char::Escaped => return Ok((i, s)),
|
||||||
Char::AsciiEscape(nb) => (
|
Char::AsciiEscape(nb) => (
|
||||||
@ -405,17 +410,12 @@ fn char_lit(i: &str) -> ParseResult<'_> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let Ok(nb) = u32::from_str_radix(nb, 16) else {
|
let Ok(nb) = u32::from_str_radix(nb, 16) else {
|
||||||
return Err(nom::Err::Failure(ErrorContext {
|
return Err(nom::Err::Failure(ErrorContext::new(err1, start)));
|
||||||
input: start,
|
|
||||||
message: Some(Cow::Borrowed(err1)),
|
|
||||||
}));
|
|
||||||
};
|
};
|
||||||
if nb > max_value {
|
if nb > max_value {
|
||||||
return Err(nom::Err::Failure(ErrorContext {
|
return Err(nom::Err::Failure(ErrorContext::new(err2, start)));
|
||||||
input: start,
|
|
||||||
message: Some(Cow::Borrowed(err2)),
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((i, s))
|
Ok((i, s))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
use std::borrow::Cow;
|
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
use nom::branch::alt;
|
use nom::branch::alt;
|
||||||
@ -113,10 +112,10 @@ impl<'a> Node<'a> {
|
|||||||
));
|
));
|
||||||
let (j, (pws, _, nws)) = p(i)?;
|
let (j, (pws, _, nws)) = p(i)?;
|
||||||
if !s.is_in_loop() {
|
if !s.is_in_loop() {
|
||||||
return Err(nom::Err::Failure(ErrorContext {
|
return Err(nom::Err::Failure(ErrorContext::new(
|
||||||
input: i,
|
"you can only `break` inside a `for` loop",
|
||||||
message: Some(Cow::Borrowed("you can only `break` inside a `for` loop")),
|
i,
|
||||||
}));
|
)));
|
||||||
}
|
}
|
||||||
Ok((j, Self::Break(Ws(pws, nws))))
|
Ok((j, Self::Break(Ws(pws, nws))))
|
||||||
}
|
}
|
||||||
@ -129,10 +128,10 @@ impl<'a> Node<'a> {
|
|||||||
));
|
));
|
||||||
let (j, (pws, _, nws)) = p(i)?;
|
let (j, (pws, _, nws)) = p(i)?;
|
||||||
if !s.is_in_loop() {
|
if !s.is_in_loop() {
|
||||||
return Err(nom::Err::Failure(ErrorContext {
|
return Err(nom::Err::Failure(ErrorContext::new(
|
||||||
input: i,
|
"you can only `continue` inside a `for` loop",
|
||||||
message: Some(Cow::Borrowed("you can only `continue` inside a `for` loop")),
|
i,
|
||||||
}));
|
)));
|
||||||
}
|
}
|
||||||
Ok((j, Self::Continue(Ws(pws, nws))))
|
Ok((j, Self::Continue(Ws(pws, nws))))
|
||||||
}
|
}
|
||||||
@ -297,10 +296,10 @@ impl<'a> Target<'a> {
|
|||||||
|
|
||||||
fn verify_name(input: &'a str, name: &'a str) -> Result<Self, nom::Err<ErrorContext<'a>>> {
|
fn verify_name(input: &'a str, name: &'a str) -> Result<Self, nom::Err<ErrorContext<'a>>> {
|
||||||
match name {
|
match name {
|
||||||
"self" | "writer" => Err(nom::Err::Failure(ErrorContext {
|
"self" | "writer" => Err(nom::Err::Failure(ErrorContext::new(
|
||||||
|
format!("cannot use `{name}` as a name"),
|
||||||
input,
|
input,
|
||||||
message: Some(Cow::Owned(format!("Cannot use `{name}` as a name"))),
|
))),
|
||||||
})),
|
|
||||||
_ => Ok(Self::Name(name)),
|
_ => Ok(Self::Name(name)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -375,12 +374,10 @@ impl<'a> Cond<'a> {
|
|||||||
opt(Whitespace::parse),
|
opt(Whitespace::parse),
|
||||||
ws(alt((keyword("else"), |i| {
|
ws(alt((keyword("else"), |i| {
|
||||||
let _ = keyword("elif")(i)?;
|
let _ = keyword("elif")(i)?;
|
||||||
Err(nom::Err::Failure(ErrorContext {
|
Err(nom::Err::Failure(ErrorContext::new(
|
||||||
input: i,
|
"unknown `elif` keyword; did you mean `else if`?",
|
||||||
message: Some(Cow::Borrowed(
|
i,
|
||||||
"unknown `elif` keyword; did you mean `else if`?",
|
)))
|
||||||
)),
|
|
||||||
}))
|
|
||||||
}))),
|
}))),
|
||||||
cut(tuple((
|
cut(tuple((
|
||||||
opt(|i| CondTest::parse(i, s)),
|
opt(|i| CondTest::parse(i, s)),
|
||||||
@ -559,10 +556,10 @@ impl<'a> Macro<'a> {
|
|||||||
));
|
));
|
||||||
let (j, (pws1, _, (name, params, nws1, _))) = start(i)?;
|
let (j, (pws1, _, (name, params, nws1, _))) = start(i)?;
|
||||||
if name == "super" {
|
if name == "super" {
|
||||||
return Err(nom::Err::Failure(ErrorContext {
|
return Err(nom::Err::Failure(ErrorContext::new(
|
||||||
input: i,
|
"'super' is not a valid name for a macro",
|
||||||
message: Some(Cow::Borrowed("'super' is not a valid name for a macro")),
|
i,
|
||||||
}));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut end = cut(tuple((
|
let mut end = cut(tuple((
|
||||||
@ -831,15 +828,14 @@ fn check_end_name<'a>(
|
|||||||
if name == end_name {
|
if name == end_name {
|
||||||
return Ok((after, end_name));
|
return Ok((after, end_name));
|
||||||
}
|
}
|
||||||
let message = if name.is_empty() && !end_name.is_empty() {
|
|
||||||
format!("unexpected name `{end_name}` in `end{kind}` tag for unnamed `{kind}`")
|
Err(nom::Err::Failure(ErrorContext::new(
|
||||||
} else {
|
match name.is_empty() && !end_name.is_empty() {
|
||||||
format!("expected name `{name}` in `end{kind}` tag, found `{end_name}`")
|
true => format!("unexpected name `{end_name}` in `end{kind}` tag for unnamed `{kind}`"),
|
||||||
};
|
false => format!("expected name `{name}` in `end{kind}` tag, found `{end_name}`"),
|
||||||
Err(nom::Err::Failure(ErrorContext {
|
},
|
||||||
input: before,
|
before,
|
||||||
message: Some(Cow::Owned(message)),
|
)))
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
@ -1036,12 +1032,10 @@ impl<'a> Extends<'a> {
|
|||||||
))(i)?;
|
))(i)?;
|
||||||
match (pws, nws) {
|
match (pws, nws) {
|
||||||
(None, None) => Ok((i, Self { path })),
|
(None, None) => Ok((i, Self { path })),
|
||||||
(_, _) => Err(nom::Err::Failure(ErrorContext {
|
(_, _) => Err(nom::Err::Failure(ErrorContext::new(
|
||||||
input: start,
|
"whitespace control is not allowed on `extends`",
|
||||||
message: Some(Cow::Borrowed(
|
start,
|
||||||
"whitespace control is not allowed on `extends`",
|
))),
|
||||||
)),
|
|
||||||
})),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1078,10 +1072,10 @@ impl<'a> Comment<'a> {
|
|||||||
Tag::Open => match depth.checked_add(1) {
|
Tag::Open => match depth.checked_add(1) {
|
||||||
Some(new_depth) => depth = new_depth,
|
Some(new_depth) => depth = new_depth,
|
||||||
None => {
|
None => {
|
||||||
return Err(nom::Err::Failure(ErrorContext {
|
return Err(nom::Err::Failure(ErrorContext::new(
|
||||||
input: i,
|
"too deeply nested comments",
|
||||||
message: Some(Cow::Borrowed("too deeply nested comments")),
|
i,
|
||||||
}))
|
)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Tag::Close => match depth.checked_sub(1) {
|
Tag::Close => match depth.checked_sub(1) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user