Skip to content

Commit

Permalink
Merge pull request rinja-rs#118 from Kijewski/pr-end
Browse files Browse the repository at this point in the history
parser: tell user proper keyword to end node
  • Loading branch information
GuillaumeGomez authored Aug 7, 2024
2 parents ebcfff6 + 5efd313 commit f39ef73
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 47 deletions.
9 changes: 3 additions & 6 deletions rinja_parser/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::str;
use nom::branch::alt;
use nom::bytes::complete::{tag, take_till};
use nom::character::complete::char;
use nom::combinator::{cut, map, not, opt, peek, recognize, value};
use nom::combinator::{cut, fail, map, not, opt, peek, recognize, value};
use nom::error::ErrorKind;
use nom::error_position;
use nom::multi::{fold_many0, many0, separated_list0};
Expand Down Expand Up @@ -127,7 +127,7 @@ impl<'a> Expr<'a> {
if !is_template_macro {
// If this is not a template macro, we don't want to parse named arguments so
// we instead return an error which will allow to continue the parsing.
return Err(nom::Err::Error(error_position!(i, ErrorKind::Alt)));
return fail(i);
}

let (_, level) = level.nest(i)?;
Expand Down Expand Up @@ -486,10 +486,7 @@ impl<'a> Suffix<'a> {
if nested == 0 {
Ok((&input[last..], ()))
} else {
Err(nom::Err::Error(error_position!(
input,
ErrorKind::SeparatedNonEmptyList
)))
fail(input)
}
}

Expand Down
28 changes: 5 additions & 23 deletions rinja_parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ use std::{fmt, str};
use nom::branch::alt;
use nom::bytes::complete::{escaped, is_not, tag, take_till, take_while_m_n};
use nom::character::complete::{anychar, char, one_of, satisfy};
use nom::combinator::{complete, cut, eof, map, not, opt, recognize};
use nom::error::{Error, ErrorKind, FromExternalError};
use nom::combinator::{complete, cut, eof, fail, map, not, opt, recognize};
use nom::error::{ErrorKind, FromExternalError};
use nom::multi::{many0_count, many1};
use nom::sequence::{delimited, pair, preceded, terminated, tuple};
use nom::{error_position, AsChar, InputTakeAtPosition};
use nom::{AsChar, InputTakeAtPosition};

pub mod expr;
pub use expr::{Expr, Filter};
Expand Down Expand Up @@ -240,20 +240,6 @@ impl<'a> ErrorContext<'a> {
message: Some(message.into()),
}
}

pub(crate) fn from_err(error: nom::Err<Error<&'a str>>) -> 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,
}),
}
}
}

impl<'a> nom::error::ParseError<&'a str> for ErrorContext<'a> {
Expand Down Expand Up @@ -323,11 +309,7 @@ fn skip_till<'a, 'b, O>(
fn keyword<'a>(k: &'a str) -> impl FnMut(&'a str) -> ParseResult<'_> {
move |i: &'a str| -> ParseResult<'a> {
let (j, v) = identifier(i)?;
if k == v {
Ok((j, v))
} else {
Err(nom::Err::Error(error_position!(i, ErrorKind::Tag)))
}
if k == v { Ok((j, v)) } else { fail(i) }
}
}

Expand Down Expand Up @@ -366,7 +348,7 @@ fn num_lit(i: &str) -> ParseResult<'_> {
Ok((i, suffix))
} else if ignore.contains(&suffix) {
// no need for a message, this case only occures in an `opt(…)`
Err(nom::Err::Error(ErrorContext::new("", i)))
fail(i)
} else {
Err(nom::Err::Failure(ErrorContext::new(
format!("unknown {kind} suffix `{suffix}`"),
Expand Down
46 changes: 29 additions & 17 deletions rinja_parser/src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ use std::str;
use nom::branch::alt;
use nom::bytes::complete::{tag, take_till};
use nom::character::complete::char;
use nom::combinator::{complete, consumed, cut, eof, map, not, opt, peek, recognize, value};
use nom::error::ErrorKind;
use nom::error_position;
use nom::combinator::{complete, consumed, cut, eof, fail, map, not, opt, peek, recognize, value};
use nom::multi::{many0, many1, separated_list0};
use nom::sequence::{delimited, pair, preceded, tuple};

Expand Down Expand Up @@ -79,12 +77,7 @@ impl<'a> Node<'a> {
"break" => |i, s| Self::r#break(i, s),
"continue" => |i, s| Self::r#continue(i, s),
"filter" => |i, s| wrap(Self::FilterBlock, FilterBlock::parse(i, s)),
_ => {
return Err(ErrorContext::from_err(nom::Err::Error(error_position!(
i,
ErrorKind::Tag
))));
}
_ => return fail(i),
};

let (i, node) = s.nest(j, |i| func(i, s))?;
Expand Down Expand Up @@ -377,7 +370,7 @@ impl<'a> Loop<'a> {
|i| s.tag_block_start(i),
opt(Whitespace::parse),
opt(else_block),
ws(keyword("endfor")),
end_node("for", "endfor"),
opt(Whitespace::parse),
))),
))),
Expand Down Expand Up @@ -449,7 +442,7 @@ impl<'a> Macro<'a> {
cut(tuple((
|i| s.tag_block_start(i),
opt(Whitespace::parse),
ws(keyword("endmacro")),
end_node("macro", "endmacro"),
cut(preceded(
opt(|before| {
let (after, end_name) = ws(identifier)(before)?;
Expand Down Expand Up @@ -525,7 +518,7 @@ impl<'a> FilterBlock<'a> {
cut(tuple((
|i| s.tag_block_start(i),
opt(Whitespace::parse),
ws(keyword("endfilter")),
end_node("filter", "endfilter"),
opt(Whitespace::parse),
))),
)));
Expand Down Expand Up @@ -645,7 +638,7 @@ impl<'a> Match<'a> {
cut(tuple((
ws(|i| s.tag_block_start(i)),
opt(Whitespace::parse),
ws(keyword("endmatch")),
end_node("match", "endmatch"),
opt(Whitespace::parse),
))),
))),
Expand Down Expand Up @@ -699,7 +692,7 @@ impl<'a> BlockDef<'a> {
cut(tuple((
|i| s.tag_block_start(i),
opt(Whitespace::parse),
ws(keyword("endblock")),
end_node("block", "endblock"),
cut(tuple((
opt(|before| {
let (after, end_name) = ws(identifier)(before)?;
Expand Down Expand Up @@ -773,7 +766,7 @@ impl<'a> Lit<'a> {
let (i, content) = match content {
Some("") => {
// {block,comment,expr}_start follows immediately.
return Err(nom::Err::Error(error_position!(i, ErrorKind::TakeUntil)));
return fail(i);
}
Some(content) => (i, content),
None => ("", i), // there is no {block,comment,expr}_start: take everything
Expand Down Expand Up @@ -806,7 +799,7 @@ impl<'a> Raw<'a> {
let endraw = tuple((
|i| s.tag_block_start(i),
opt(Whitespace::parse),
ws(keyword("endraw")),
ws(keyword("endraw")), // sic: ignore `{% end %}` in raw blocks
opt(Whitespace::parse),
peek(|i| s.tag_block_end(i)),
));
Expand Down Expand Up @@ -888,7 +881,7 @@ impl<'a> If<'a> {
cut(tuple((
|i| s.tag_block_start(i),
opt(Whitespace::parse),
ws(keyword("endif")),
end_node("if", "endif"),
opt(Whitespace::parse),
))),
))),
Expand Down Expand Up @@ -1057,6 +1050,25 @@ impl<'a> Comment<'a> {
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Ws(pub Option<Whitespace>, pub Option<Whitespace>);

fn end_node<'a, 'g: 'a>(
node: &'g str,
expected: &'g str,
) -> impl Fn(&'a str) -> ParseResult<'a> + 'g {
move |start| {
let (i, actual) = ws(identifier)(start)?;
if actual == expected {
Ok((i, actual))
} else if actual.starts_with("end") {
Err(nom::Err::Failure(ErrorContext::new(
format!("expected `{expected}` to terminate `{node}` node, found `{actual}`"),
start,
)))
} else {
fail(start)
}
}
}

#[doc(hidden)]
pub const MAX_KW_LEN: usize = 8;
const MAX_REPL_LEN: usize = MAX_KW_LEN + 2;
Expand Down
2 changes: 1 addition & 1 deletion testing/tests/ui/typo_in_keyword.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error: failed to parse template source
error: expected `endfor` to terminate `for` node, found `endfo`
--> <source attribute>:1:26
"endfo%}\n1234567890123456789012345678901234567890"
--> tests/ui/typo_in_keyword.rs:5:14
Expand Down
31 changes: 31 additions & 0 deletions testing/tests/ui/wrong-end.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use rinja::Template;

#[derive(Template)]
#[template(source = "{% for _ in 1..=10 %}{% end %}", ext = "txt")]
struct For;

#[derive(Template)]
#[template(source = "{% macro test() %}{% end %}", ext = "txt")]
struct Macro;

#[derive(Template)]
#[template(source = "{% filter upper %}{% end %}", ext = "txt")]
struct Filter;

#[derive(Template)]
#[template(source = "{% match () %}{% when () %}{% end %}", ext = "txt")]
struct Match;

#[derive(Template)]
#[template(source = "{% block body %}{% end %}", ext = "txt")]
struct Block;

#[derive(Template)]
#[template(source = "{% if true %}{% end %}", ext = "txt")]
struct If;

#[derive(Template)]
#[template(source = "{% if true %}{% endfor %}", ext = "txt")]
struct IfFor;

fn main() {}
55 changes: 55 additions & 0 deletions testing/tests/ui/wrong-end.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
error: expected `endfor` to terminate `for` node, found `end`
--> <source attribute>:1:23
" end %}"
--> tests/ui/wrong-end.rs:4:21
|
4 | #[template(source = "{% for _ in 1..=10 %}{% end %}", ext = "txt")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: expected `endmacro` to terminate `macro` node, found `end`
--> <source attribute>:1:20
" end %}"
--> tests/ui/wrong-end.rs:8:21
|
8 | #[template(source = "{% macro test() %}{% end %}", ext = "txt")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: expected `endfilter` to terminate `filter` node, found `end`
--> <source attribute>:1:20
" end %}"
--> tests/ui/wrong-end.rs:12:21
|
12 | #[template(source = "{% filter upper %}{% end %}", ext = "txt")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: expected `endmatch` to terminate `match` node, found `end`
--> <source attribute>:1:30
"end %}"
--> tests/ui/wrong-end.rs:16:21
|
16 | #[template(source = "{% match () %}{% when () %}{% end %}", ext = "txt")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: expected `endblock` to terminate `block` node, found `end`
--> <source attribute>:1:18
" end %}"
--> tests/ui/wrong-end.rs:20:21
|
20 | #[template(source = "{% block body %}{% end %}", ext = "txt")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: expected `endif` to terminate `if` node, found `end`
--> <source attribute>:1:15
" end %}"
--> tests/ui/wrong-end.rs:24:21
|
24 | #[template(source = "{% if true %}{% end %}", ext = "txt")]
| ^^^^^^^^^^^^^^^^^^^^^^^^

error: expected `endif` to terminate `if` node, found `endfor`
--> <source attribute>:1:15
" endfor %}"
--> tests/ui/wrong-end.rs:28:21
|
28 | #[template(source = "{% if true %}{% endfor %}", ext = "txt")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^

0 comments on commit f39ef73

Please sign in to comment.