mirror of
https://github.com/askama-rs/askama.git
synced 2025-09-30 22:41:13 +00:00
parser: use drop guards to track nesting level
Not for all operations the nesting level was incremented when needed and/or the un-incremented nesting level was used in subfunction calls. Binary operators such as `*` did not properly increment the nesting level. This PR changes `Level` in such a way that it can be used to keep track of the nesting level when used in a loop. It is now impossible to accidentally refer to an old nesting level value. Resolves <https://issues.oss-fuzz.com/issues/385256115>.
This commit is contained in:
parent
802d980a47
commit
4b8bd45844
@ -9,7 +9,8 @@ extend-exclude = [
|
|||||||
"fuzzing/fuzz/corpus/",
|
"fuzzing/fuzz/corpus/",
|
||||||
"target/",
|
"target/",
|
||||||
"rinja_parser/tests/*.txt",
|
"rinja_parser/tests/*.txt",
|
||||||
# fillter texts
|
"testing/templates/fuzzed-*",
|
||||||
|
# filler texts
|
||||||
"rinja/benches/strings.inc",
|
"rinja/benches/strings.inc",
|
||||||
# too many false positives
|
# too many false positives
|
||||||
"testing/tests/gen_ws_tests.py",
|
"testing/tests/gen_ws_tests.py",
|
||||||
|
@ -18,16 +18,18 @@ use crate::{
|
|||||||
|
|
||||||
macro_rules! expr_prec_layer {
|
macro_rules! expr_prec_layer {
|
||||||
( $name:ident, $inner:ident, $op:expr ) => {
|
( $name:ident, $inner:ident, $op:expr ) => {
|
||||||
fn $name(i: &mut &'a str, level: Level) -> ParseResult<'a, WithSpan<'a, Self>> {
|
fn $name(i: &mut &'a str, level: Level<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||||
let level = level.nest(i)?;
|
let mut level_guard = level.guard();
|
||||||
let start = *i;
|
let start = *i;
|
||||||
let left = Self::$inner(i, level)?;
|
let mut expr = Self::$inner(i, level)?;
|
||||||
let right = repeat(0.., (ws($op), |i: &mut _| Self::$inner(i, level)))
|
let mut i_before = *i;
|
||||||
.map(|v: Vec<_>| v)
|
let mut right = opt((ws($op), |i: &mut _| Self::$inner(i, level)));
|
||||||
.parse_next(i)?;
|
while let Some((op, right)) = right.parse_next(i)? {
|
||||||
Ok(right.into_iter().fold(left, |left, (op, right)| {
|
level_guard.nest(i_before)?;
|
||||||
WithSpan::new(Self::BinOp(op, Box::new(left), Box::new(right)), start)
|
i_before = *i;
|
||||||
}))
|
expr = WithSpan::new(Self::BinOp(op, Box::new(expr), Box::new(right)), start);
|
||||||
|
}
|
||||||
|
Ok(expr)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -136,10 +138,10 @@ pub enum Expr<'a> {
|
|||||||
impl<'a> Expr<'a> {
|
impl<'a> Expr<'a> {
|
||||||
pub(super) fn arguments(
|
pub(super) fn arguments(
|
||||||
i: &mut &'a str,
|
i: &mut &'a str,
|
||||||
level: Level,
|
level: Level<'_>,
|
||||||
is_template_macro: bool,
|
is_template_macro: bool,
|
||||||
) -> ParseResult<'a, Vec<WithSpan<'a, Self>>> {
|
) -> ParseResult<'a, Vec<WithSpan<'a, Self>>> {
|
||||||
let level = level.nest(i)?;
|
let _level_guard = level.nest(i)?;
|
||||||
let mut named_arguments = HashSet::new();
|
let mut named_arguments = HashSet::new();
|
||||||
let start = *i;
|
let start = *i;
|
||||||
|
|
||||||
@ -186,7 +188,7 @@ impl<'a> Expr<'a> {
|
|||||||
|
|
||||||
fn named_argument(
|
fn named_argument(
|
||||||
i: &mut &'a str,
|
i: &mut &'a str,
|
||||||
level: Level,
|
level: Level<'_>,
|
||||||
named_arguments: &mut HashSet<&'a str>,
|
named_arguments: &mut HashSet<&'a str>,
|
||||||
start: &'a str,
|
start: &'a str,
|
||||||
is_template_macro: bool,
|
is_template_macro: bool,
|
||||||
@ -197,7 +199,6 @@ impl<'a> Expr<'a> {
|
|||||||
return fail.parse_next(i);
|
return fail.parse_next(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
let level = level.nest(i)?;
|
|
||||||
let (argument, _, value) = (identifier, ws('='), move |i: &mut _| {
|
let (argument, _, value) = (identifier, ws('='), move |i: &mut _| {
|
||||||
Self::parse(i, level, false)
|
Self::parse(i, level, false)
|
||||||
})
|
})
|
||||||
@ -217,10 +218,10 @@ impl<'a> Expr<'a> {
|
|||||||
|
|
||||||
pub(super) fn parse(
|
pub(super) fn parse(
|
||||||
i: &mut &'a str,
|
i: &mut &'a str,
|
||||||
level: Level,
|
level: Level<'_>,
|
||||||
allow_underscore: bool,
|
allow_underscore: bool,
|
||||||
) -> ParseResult<'a, WithSpan<'a, Self>> {
|
) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||||
let level = level.nest(i)?;
|
let _level_guard = level.nest(i)?;
|
||||||
let start = Span::from(*i);
|
let start = Span::from(*i);
|
||||||
let range_right = move |i: &mut _| {
|
let range_right = move |i: &mut _| {
|
||||||
(
|
(
|
||||||
@ -257,10 +258,10 @@ impl<'a> Expr<'a> {
|
|||||||
expr_prec_layer!(shifts, addsub, alt((">>", "<<")));
|
expr_prec_layer!(shifts, addsub, alt((">>", "<<")));
|
||||||
expr_prec_layer!(addsub, concat, alt(("+", "-")));
|
expr_prec_layer!(addsub, concat, alt(("+", "-")));
|
||||||
|
|
||||||
fn concat(i: &mut &'a str, level: Level) -> ParseResult<'a, WithSpan<'a, Self>> {
|
fn concat(i: &mut &'a str, level: Level<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||||
fn concat_expr<'a>(
|
fn concat_expr<'a>(
|
||||||
i: &mut &'a str,
|
i: &mut &'a str,
|
||||||
level: Level,
|
level: Level<'_>,
|
||||||
) -> ParseResult<'a, Option<WithSpan<'a, Expr<'a>>>> {
|
) -> ParseResult<'a, Option<WithSpan<'a, Expr<'a>>>> {
|
||||||
let ws1 = |i: &mut _| opt(skip_ws1).parse_next(i);
|
let ws1 = |i: &mut _| opt(skip_ws1).parse_next(i);
|
||||||
|
|
||||||
@ -295,7 +296,7 @@ impl<'a> Expr<'a> {
|
|||||||
|
|
||||||
expr_prec_layer!(muldivmod, is_as, alt(("*", "/", "%")));
|
expr_prec_layer!(muldivmod, is_as, alt(("*", "/", "%")));
|
||||||
|
|
||||||
fn is_as(i: &mut &'a str, level: Level) -> ParseResult<'a, WithSpan<'a, Self>> {
|
fn is_as(i: &mut &'a str, level: Level<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||||
let start = *i;
|
let start = *i;
|
||||||
let lhs = Self::filtered(i, level)?;
|
let lhs = Self::filtered(i, level)?;
|
||||||
let before_keyword = *i;
|
let before_keyword = *i;
|
||||||
@ -358,10 +359,13 @@ impl<'a> Expr<'a> {
|
|||||||
Ok(WithSpan::new(ctor(var_name), start))
|
Ok(WithSpan::new(ctor(var_name), start))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filtered(i: &mut &'a str, mut level: Level) -> ParseResult<'a, WithSpan<'a, Self>> {
|
fn filtered(i: &mut &'a str, level: Level<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||||
|
let mut level_guard = level.guard();
|
||||||
let start = *i;
|
let start = *i;
|
||||||
let mut res = Self::prefix(i, level)?;
|
let mut res = Self::prefix(i, level)?;
|
||||||
while let Some((name, args)) = opt(|i: &mut _| filter(i, &mut level)).parse_next(i)? {
|
while let Some((name, args)) = opt(|i: &mut _| filter(i, level)).parse_next(i)? {
|
||||||
|
level_guard.nest(i)?;
|
||||||
|
|
||||||
let mut arguments = args.unwrap_or_else(|| Vec::with_capacity(1));
|
let mut arguments = args.unwrap_or_else(|| Vec::with_capacity(1));
|
||||||
arguments.insert(0, res);
|
arguments.insert(0, res);
|
||||||
|
|
||||||
@ -370,28 +374,30 @@ impl<'a> Expr<'a> {
|
|||||||
Ok(res)
|
Ok(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prefix(i: &mut &'a str, mut level: Level) -> ParseResult<'a, WithSpan<'a, Self>> {
|
fn prefix(i: &mut &'a str, level: Level<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||||
let nested = level.nest(i)?;
|
|
||||||
let start = *i;
|
let start = *i;
|
||||||
let (ops, mut expr) = (
|
|
||||||
repeat(0.., ws(alt(("!", "-", "*", "&")))).map(|v: Vec<_>| v),
|
|
||||||
|i: &mut _| Suffix::parse(i, nested),
|
|
||||||
)
|
|
||||||
.parse_next(i)?;
|
|
||||||
|
|
||||||
for op in ops.iter().rev() {
|
|
||||||
// This is a rare place where we create recursion in the parsed AST
|
// This is a rare place where we create recursion in the parsed AST
|
||||||
// without recursing the parser call stack. However, this can lead
|
// without recursing the parser call stack. However, this can lead
|
||||||
// to stack overflows in drop glue when the AST is very deep.
|
// to stack overflows in drop glue when the AST is very deep.
|
||||||
level = level.nest(i)?;
|
let mut level_guard = level.guard();
|
||||||
|
let mut ops = vec![];
|
||||||
|
let mut i_before = *i;
|
||||||
|
while let Some(op) = opt(ws(alt(("!", "-", "*", "&")))).parse_next(i)? {
|
||||||
|
level_guard.nest(i_before)?;
|
||||||
|
ops.push(op);
|
||||||
|
i_before = *i;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut expr = Suffix::parse(i, level)?;
|
||||||
|
for op in ops.iter().rev() {
|
||||||
expr = WithSpan::new(Self::Unary(op, Box::new(expr)), start);
|
expr = WithSpan::new(Self::Unary(op, Box::new(expr)), start);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn single(i: &mut &'a str, level: Level) -> ParseResult<'a, WithSpan<'a, Self>> {
|
fn single(i: &mut &'a str, level: Level<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||||
let level = level.nest(i)?;
|
|
||||||
alt((
|
alt((
|
||||||
Self::num,
|
Self::num,
|
||||||
Self::str,
|
Self::str,
|
||||||
@ -403,8 +409,7 @@ impl<'a> Expr<'a> {
|
|||||||
.parse_next(i)
|
.parse_next(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn group(i: &mut &'a str, level: Level) -> ParseResult<'a, WithSpan<'a, Self>> {
|
fn group(i: &mut &'a str, level: Level<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||||
let level = level.nest(i)?;
|
|
||||||
let start = *i;
|
let start = *i;
|
||||||
let expr = preceded(ws('('), opt(|i: &mut _| Self::parse(i, level, true))).parse_next(i)?;
|
let expr = preceded(ws('('), opt(|i: &mut _| Self::parse(i, level, true))).parse_next(i)?;
|
||||||
let Some(expr) = expr else {
|
let Some(expr) = expr else {
|
||||||
@ -434,9 +439,8 @@ impl<'a> Expr<'a> {
|
|||||||
Ok(WithSpan::new(Self::Tuple(exprs), start))
|
Ok(WithSpan::new(Self::Tuple(exprs), start))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn array(i: &mut &'a str, level: Level) -> ParseResult<'a, WithSpan<'a, Self>> {
|
fn array(i: &mut &'a str, level: Level<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||||
let start = *i;
|
let start = *i;
|
||||||
let level = level.nest(i)?;
|
|
||||||
let array = preceded(
|
let array = preceded(
|
||||||
ws('['),
|
ws('['),
|
||||||
cut_err(terminated(
|
cut_err(terminated(
|
||||||
@ -556,32 +560,36 @@ enum Suffix<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Suffix<'a> {
|
impl<'a> Suffix<'a> {
|
||||||
fn parse(i: &mut &'a str, level: Level) -> ParseResult<'a, WithSpan<'a, Expr<'a>>> {
|
fn parse(i: &mut &'a str, level: Level<'_>) -> ParseResult<'a, WithSpan<'a, Expr<'a>>> {
|
||||||
let level = level.nest(i)?;
|
let mut level_guard = level.guard();
|
||||||
let mut expr = Expr::single(i, level)?;
|
let mut expr = Expr::single(i, level)?;
|
||||||
loop {
|
let mut right = opt(alt((
|
||||||
let before_suffix = *i;
|
|
||||||
let suffix = opt(alt((
|
|
||||||
Self::attr,
|
Self::attr,
|
||||||
|i: &mut _| Self::index(i, level),
|
|i: &mut _| Self::index(i, level),
|
||||||
|i: &mut _| Self::call(i, level),
|
|i: &mut _| Self::call(i, level),
|
||||||
Self::r#try,
|
Self::r#try,
|
||||||
Self::r#macro,
|
Self::r#macro,
|
||||||
)))
|
)));
|
||||||
.parse_next(i)?;
|
loop {
|
||||||
|
let before_suffix = *i;
|
||||||
|
let suffix = right.parse_next(i)?;
|
||||||
|
let Some(suffix) = suffix else {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
level_guard.nest(before_suffix)?;
|
||||||
|
|
||||||
match suffix {
|
match suffix {
|
||||||
Some(Self::Attr(attr)) => {
|
Self::Attr(attr) => {
|
||||||
expr = WithSpan::new(Expr::Attr(expr.into(), attr), before_suffix)
|
expr = WithSpan::new(Expr::Attr(expr.into(), attr), before_suffix)
|
||||||
}
|
}
|
||||||
Some(Self::Index(index)) => {
|
Self::Index(index) => {
|
||||||
expr = WithSpan::new(Expr::Index(expr.into(), index.into()), before_suffix);
|
expr = WithSpan::new(Expr::Index(expr.into(), index.into()), before_suffix);
|
||||||
}
|
}
|
||||||
Some(Self::Call(args)) => {
|
Self::Call(args) => {
|
||||||
expr = WithSpan::new(Expr::Call(expr.into(), args), before_suffix)
|
expr = WithSpan::new(Expr::Call(expr.into(), args), before_suffix)
|
||||||
}
|
}
|
||||||
Some(Self::Try) => expr = WithSpan::new(Expr::Try(expr.into()), before_suffix),
|
Self::Try => expr = WithSpan::new(Expr::Try(expr.into()), before_suffix),
|
||||||
Some(Self::MacroCall(args)) => match expr.inner {
|
Self::MacroCall(args) => match expr.inner {
|
||||||
Expr::Path(path) => {
|
Expr::Path(path) => {
|
||||||
expr = WithSpan::new(Expr::RustMacro(path, args), before_suffix)
|
expr = WithSpan::new(Expr::RustMacro(path, args), before_suffix)
|
||||||
}
|
}
|
||||||
@ -596,7 +604,6 @@ impl<'a> Suffix<'a> {
|
|||||||
.cut());
|
.cut());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
None => break,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
@ -665,8 +672,7 @@ impl<'a> Suffix<'a> {
|
|||||||
.parse_next(i)
|
.parse_next(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn index(i: &mut &'a str, level: Level) -> ParseResult<'a, Self> {
|
fn index(i: &mut &'a str, level: Level<'_>) -> ParseResult<'a, Self> {
|
||||||
let level = level.nest(i)?;
|
|
||||||
preceded(
|
preceded(
|
||||||
ws('['),
|
ws('['),
|
||||||
cut_err(terminated(
|
cut_err(terminated(
|
||||||
@ -678,8 +684,7 @@ impl<'a> Suffix<'a> {
|
|||||||
.parse_next(i)
|
.parse_next(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(i: &mut &'a str, level: Level) -> ParseResult<'a, Self> {
|
fn call(i: &mut &'a str, level: Level<'_>) -> ParseResult<'a, Self> {
|
||||||
let level = level.nest(i)?;
|
|
||||||
(move |i: &mut _| Expr::arguments(i, level, false))
|
(move |i: &mut _| Expr::arguments(i, level, false))
|
||||||
.map(Self::Call)
|
.map(Self::Call)
|
||||||
.parse_next(i)
|
.parse_next(i)
|
||||||
|
@ -111,7 +111,13 @@ impl<'a> Ast<'a> {
|
|||||||
syntax: &Syntax<'_>,
|
syntax: &Syntax<'_>,
|
||||||
) -> Result<Self, ParseError> {
|
) -> Result<Self, ParseError> {
|
||||||
let start = src;
|
let start = src;
|
||||||
match Node::parse_template(&mut src, &State::new(syntax)) {
|
let level = Cell::new(Level::MAX_DEPTH);
|
||||||
|
let state = State {
|
||||||
|
syntax,
|
||||||
|
loop_depth: Cell::new(0),
|
||||||
|
level: Level(&level),
|
||||||
|
};
|
||||||
|
match Node::parse_template(&mut src, &state) {
|
||||||
Ok(nodes) if src.is_empty() => Ok(Self { nodes }),
|
Ok(nodes) if src.is_empty() => Ok(Self { nodes }),
|
||||||
Ok(_) | Err(winnow::error::ErrMode::Incomplete(_)) => unreachable!(),
|
Ok(_) | Err(winnow::error::ErrMode::Incomplete(_)) => unreachable!(),
|
||||||
Err(
|
Err(
|
||||||
@ -728,34 +734,13 @@ fn path_or_identifier<'a>(i: &mut &'a str) -> ParseResult<'a, PathOrIdentifier<'
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct State<'a> {
|
struct State<'a, 'l> {
|
||||||
syntax: &'a Syntax<'a>,
|
syntax: &'l Syntax<'a>,
|
||||||
loop_depth: Cell<usize>,
|
loop_depth: Cell<usize>,
|
||||||
level: Cell<Level>,
|
level: Level<'l>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> State<'a> {
|
impl State<'_, '_> {
|
||||||
fn new(syntax: &'a Syntax<'a>) -> State<'a> {
|
|
||||||
State {
|
|
||||||
syntax,
|
|
||||||
loop_depth: Cell::new(0),
|
|
||||||
level: Cell::new(Level::default()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn nest<'b, T, F: Parser<&'b str, T, ErrorContext<'b>>>(
|
|
||||||
&self,
|
|
||||||
i: &mut &'b str,
|
|
||||||
mut callback: F,
|
|
||||||
) -> ParseResult<'b, T> {
|
|
||||||
let prev_level = self.level.get();
|
|
||||||
let level = prev_level.nest(i)?;
|
|
||||||
self.level.set(level);
|
|
||||||
let ret = callback.parse_next(i);
|
|
||||||
self.level.set(prev_level);
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tag_block_start<'i>(&self, i: &mut &'i str) -> ParseResult<'i, ()> {
|
fn tag_block_start<'i>(&self, i: &mut &'i str) -> ParseResult<'i, ()> {
|
||||||
self.syntax.block_start.value(()).parse_next(i)
|
self.syntax.block_start.value(()).parse_next(i)
|
||||||
}
|
}
|
||||||
@ -960,35 +945,87 @@ impl<'a> SyntaxBuilder<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default)]
|
/// The nesting level of nodes and expressions.
|
||||||
pub(crate) struct Level(u8);
|
///
|
||||||
|
/// The level counts down from [`Level::MAX_DEPTH`] to 0. Once the value would reach below 0,
|
||||||
|
/// [`Level::nest()`] / [`LevelGuard::nest()`] will return an error. The same [`Level`] instance is
|
||||||
|
/// shared across all usages in a [`Parsed::new()`] / [`Ast::from_str()`] call, using a reference
|
||||||
|
/// to an interior mutable counter.
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct Level<'l>(&'l Cell<usize>);
|
||||||
|
|
||||||
impl Level {
|
impl Level<'_> {
|
||||||
fn nest(self, i: &str) -> ParseResult<'_, Level> {
|
const MAX_DEPTH: usize = 128;
|
||||||
if self.0 >= Self::MAX_DEPTH {
|
|
||||||
return Err(winnow::error::ErrMode::Cut(ErrorContext::new(
|
/// Acquire a [`LevelGuard`] without decrementing the counter, to be used with loops.
|
||||||
"your template code is too deeply nested, or last expression is too complex",
|
fn guard(&self) -> LevelGuard<'_> {
|
||||||
|
LevelGuard {
|
||||||
|
level: *self,
|
||||||
|
count: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decrement the remaining level counter, and return a [`LevelGuard`] that increments it again
|
||||||
|
/// when it's dropped.
|
||||||
|
fn nest<'a>(&self, i: &'a str) -> ParseResult<'a, LevelGuard<'_>> {
|
||||||
|
if let Some(new_level) = self.0.get().checked_sub(1) {
|
||||||
|
self.0.set(new_level);
|
||||||
|
Ok(LevelGuard {
|
||||||
|
level: *self,
|
||||||
|
count: 1,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(Self::_fail(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cold]
|
||||||
|
#[inline(never)]
|
||||||
|
fn _fail(i: &str) -> ParseErr<'_> {
|
||||||
|
winnow::error::ErrMode::Cut(ErrorContext::new(
|
||||||
|
"your template code is too deeply nested, or the last expression is too complex",
|
||||||
i,
|
i,
|
||||||
)));
|
))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(Level(self.0 + 1))
|
/// Used to keep track how often [`LevelGuard::nest()`] was called and to re-increment the
|
||||||
|
/// remaining level counter when it is dropped / falls out of scope.
|
||||||
|
#[must_use]
|
||||||
|
struct LevelGuard<'l> {
|
||||||
|
level: Level<'l>,
|
||||||
|
count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for LevelGuard<'_> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.level.0.set(self.level.0.get() + self.count);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const MAX_DEPTH: u8 = 128;
|
impl LevelGuard<'_> {
|
||||||
|
/// Used to decrement the level multiple times, e.g. for every iteration of a loop.
|
||||||
|
fn nest<'a>(&mut self, i: &'a str) -> ParseResult<'a, ()> {
|
||||||
|
if let Some(new_level) = self.level.0.get().checked_sub(1) {
|
||||||
|
self.level.0.set(new_level);
|
||||||
|
self.count += 1;
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Level::_fail(i))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter<'a>(
|
fn filter<'a>(
|
||||||
i: &mut &'a str,
|
i: &mut &'a str,
|
||||||
level: &mut Level,
|
level: Level<'_>,
|
||||||
) -> ParseResult<'a, (&'a str, Option<Vec<WithSpan<'a, Expr<'a>>>>)> {
|
) -> ParseResult<'a, (&'a str, Option<Vec<WithSpan<'a, Expr<'a>>>>)> {
|
||||||
let start = *i;
|
ws(('|', not('|'))).parse_next(i)?;
|
||||||
let _ = ws(('|', not('|'))).parse_next(i)?;
|
|
||||||
|
|
||||||
*level = level.nest(start)?;
|
let _level_guard = level.nest(i)?;
|
||||||
cut_err((
|
cut_err((
|
||||||
ws(identifier),
|
ws(identifier),
|
||||||
opt(|i: &mut _| Expr::arguments(i, *level, false)),
|
opt(|i: &mut _| Expr::arguments(i, level, false)),
|
||||||
))
|
))
|
||||||
.parse_next(i)
|
.parse_next(i)
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ pub enum Node<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Node<'a> {
|
impl<'a> Node<'a> {
|
||||||
pub(super) fn parse_template(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, Vec<Self>> {
|
pub(super) fn parse_template(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, Vec<Self>> {
|
||||||
let start = *i;
|
let start = *i;
|
||||||
let result = match (|i: &mut _| Self::many(i, s)).parse_next(i) {
|
let result = match (|i: &mut _| Self::many(i, s)).parse_next(i) {
|
||||||
Ok(result) => result,
|
Ok(result) => result,
|
||||||
@ -68,7 +68,7 @@ impl<'a> Node<'a> {
|
|||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn many(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, Vec<Self>> {
|
fn many(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, Vec<Self>> {
|
||||||
repeat(
|
repeat(
|
||||||
0..,
|
0..,
|
||||||
alt((
|
alt((
|
||||||
@ -82,7 +82,7 @@ impl<'a> Node<'a> {
|
|||||||
.parse_next(i)
|
.parse_next(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
|
fn parse(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, Self> {
|
||||||
let mut start = *i;
|
let mut start = *i;
|
||||||
let tag = preceded(
|
let tag = preceded(
|
||||||
|i: &mut _| s.tag_block_start(i),
|
|i: &mut _| s.tag_block_start(i),
|
||||||
@ -108,8 +108,8 @@ impl<'a> Node<'a> {
|
|||||||
_ => return fail.parse_next(&mut start),
|
_ => return fail.parse_next(&mut start),
|
||||||
};
|
};
|
||||||
|
|
||||||
let node = s.nest(i, |i: &mut _| func(i, s))?;
|
let _level_guard = s.level.nest(i)?;
|
||||||
|
let node = func(i, s)?;
|
||||||
let closed = cut_node(
|
let closed = cut_node(
|
||||||
None,
|
None,
|
||||||
alt((
|
alt((
|
||||||
@ -124,7 +124,7 @@ impl<'a> Node<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn r#break(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
|
fn r#break(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, Self> {
|
||||||
let mut p = (
|
let mut p = (
|
||||||
opt(Whitespace::parse),
|
opt(Whitespace::parse),
|
||||||
ws(keyword("break")),
|
ws(keyword("break")),
|
||||||
@ -142,7 +142,7 @@ impl<'a> Node<'a> {
|
|||||||
Ok(Self::Break(WithSpan::new(Ws(pws, nws), start)))
|
Ok(Self::Break(WithSpan::new(Ws(pws, nws), start)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn r#continue(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
|
fn r#continue(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, Self> {
|
||||||
let mut p = (
|
let mut p = (
|
||||||
opt(Whitespace::parse),
|
opt(Whitespace::parse),
|
||||||
ws(keyword("continue")),
|
ws(keyword("continue")),
|
||||||
@ -160,15 +160,16 @@ impl<'a> Node<'a> {
|
|||||||
Ok(Self::Continue(WithSpan::new(Ws(pws, nws), start)))
|
Ok(Self::Continue(WithSpan::new(Ws(pws, nws), start)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expr(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
|
fn expr(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, Self> {
|
||||||
let start = *i;
|
let start = *i;
|
||||||
|
let level = s.level;
|
||||||
let (pws, expr) = preceded(
|
let (pws, expr) = preceded(
|
||||||
|i: &mut _| s.tag_expr_start(i),
|
|i: &mut _| s.tag_expr_start(i),
|
||||||
cut_node(
|
cut_node(
|
||||||
None,
|
None,
|
||||||
(
|
(
|
||||||
opt(Whitespace::parse),
|
opt(Whitespace::parse),
|
||||||
ws(|i: &mut _| Expr::parse(i, s.level.get(), false)),
|
ws(|i: &mut _| Expr::parse(i, level, false)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -237,7 +238,7 @@ fn cut_node<'a, O>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unexpected_tag<'a>(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, ()> {
|
fn unexpected_tag<'a>(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, ()> {
|
||||||
(
|
(
|
||||||
|i: &mut _| s.tag_block_start(i),
|
|i: &mut _| s.tag_block_start(i),
|
||||||
opt(Whitespace::parse),
|
opt(Whitespace::parse),
|
||||||
@ -270,7 +271,7 @@ pub struct When<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> When<'a> {
|
impl<'a> When<'a> {
|
||||||
fn r#else(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
fn r#else(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||||
let mut p = (
|
let mut p = (
|
||||||
|i: &mut _| s.tag_block_start(i),
|
|i: &mut _| s.tag_block_start(i),
|
||||||
opt(Whitespace::parse),
|
opt(Whitespace::parse),
|
||||||
@ -298,7 +299,7 @@ impl<'a> When<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::self_named_constructors)]
|
#[allow(clippy::self_named_constructors)]
|
||||||
fn when(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
fn when(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||||
let start = *i;
|
let start = *i;
|
||||||
let endwhen = ws((
|
let endwhen = ws((
|
||||||
delimited(
|
delimited(
|
||||||
@ -367,7 +368,7 @@ pub struct Cond<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Cond<'a> {
|
impl<'a> Cond<'a> {
|
||||||
fn parse(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
fn parse(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||||
let start = *i;
|
let start = *i;
|
||||||
let (_, pws, cond, nws, _, nodes) = (
|
let (_, pws, cond, nws, _, nodes) = (
|
||||||
|i: &mut _| s.tag_block_start(i),
|
|i: &mut _| s.tag_block_start(i),
|
||||||
@ -405,7 +406,7 @@ pub struct CondTest<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CondTest<'a> {
|
impl<'a> CondTest<'a> {
|
||||||
fn parse(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
|
fn parse(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, Self> {
|
||||||
preceded(
|
preceded(
|
||||||
ws(keyword("if")),
|
ws(keyword("if")),
|
||||||
cut_node(Some("if"), |i: &mut _| Self::parse_cond(i, s)),
|
cut_node(Some("if"), |i: &mut _| Self::parse_cond(i, s)),
|
||||||
@ -413,7 +414,7 @@ impl<'a> CondTest<'a> {
|
|||||||
.parse_next(i)
|
.parse_next(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_cond(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
|
fn parse_cond(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, Self> {
|
||||||
let (target, expr) = (
|
let (target, expr) = (
|
||||||
opt(delimited(
|
opt(delimited(
|
||||||
ws(alt((keyword("let"), keyword("set")))),
|
ws(alt((keyword("let"), keyword("set")))),
|
||||||
@ -422,7 +423,7 @@ impl<'a> CondTest<'a> {
|
|||||||
)),
|
)),
|
||||||
ws(|i: &mut _| {
|
ws(|i: &mut _| {
|
||||||
let start = *i;
|
let start = *i;
|
||||||
let mut expr = Expr::parse(i, s.level.get(), false)?;
|
let mut expr = Expr::parse(i, s.level, false)?;
|
||||||
if let Expr::BinOp(_, _, ref mut right) = expr.inner {
|
if let Expr::BinOp(_, _, ref mut right) = expr.inner {
|
||||||
if matches!(right.inner, Expr::Var("set" | "let")) {
|
if matches!(right.inner, Expr::Var("set" | "let")) {
|
||||||
*i = right.span.as_suffix_of(start).unwrap();
|
*i = right.span.as_suffix_of(start).unwrap();
|
||||||
@ -485,7 +486,7 @@ impl FromStr for Whitespace {
|
|||||||
fn check_block_start<'a>(
|
fn check_block_start<'a>(
|
||||||
i: &mut &'a str,
|
i: &mut &'a str,
|
||||||
start: &'a str,
|
start: &'a str,
|
||||||
s: &State<'_>,
|
s: &State<'_, '_>,
|
||||||
node: &str,
|
node: &str,
|
||||||
expected: &str,
|
expected: &str,
|
||||||
) -> ParseResult<'a, ()> {
|
) -> ParseResult<'a, ()> {
|
||||||
@ -511,8 +512,8 @@ pub struct Loop<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Loop<'a> {
|
impl<'a> Loop<'a> {
|
||||||
fn parse(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
fn parse(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||||
fn content<'a>(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, Vec<Node<'a>>> {
|
fn content<'a>(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, Vec<Node<'a>>> {
|
||||||
s.enter_loop();
|
s.enter_loop();
|
||||||
let result = (|i: &mut _| Node::many(i, s)).parse_next(i);
|
let result = (|i: &mut _| Node::many(i, s)).parse_next(i);
|
||||||
s.leave_loop();
|
s.leave_loop();
|
||||||
@ -524,7 +525,7 @@ impl<'a> Loop<'a> {
|
|||||||
ws(keyword("if")),
|
ws(keyword("if")),
|
||||||
cut_node(
|
cut_node(
|
||||||
Some("for-if"),
|
Some("for-if"),
|
||||||
ws(|i: &mut _| Expr::parse(i, s.level.get(), true)),
|
ws(|i: &mut _| Expr::parse(i, s.level, true)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -580,7 +581,7 @@ impl<'a> Loop<'a> {
|
|||||||
cut_node(
|
cut_node(
|
||||||
Some("for"),
|
Some("for"),
|
||||||
(
|
(
|
||||||
ws(|i: &mut _| Expr::parse(i, s.level.get(), true)),
|
ws(|i: &mut _| Expr::parse(i, s.level, true)),
|
||||||
opt(if_cond),
|
opt(if_cond),
|
||||||
opt(Whitespace::parse),
|
opt(Whitespace::parse),
|
||||||
|i: &mut _| s.tag_block_end(i),
|
|i: &mut _| s.tag_block_end(i),
|
||||||
@ -633,8 +634,8 @@ fn check_duplicated_name<'a>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Macro<'a> {
|
impl<'a> Macro<'a> {
|
||||||
fn parse(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
fn parse(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||||
let level = s.level.get();
|
let level = s.level;
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
let parameters = |i: &mut _| -> ParseResult<
|
let parameters = |i: &mut _| -> ParseResult<
|
||||||
'_,
|
'_,
|
||||||
@ -762,8 +763,7 @@ pub struct FilterBlock<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FilterBlock<'a> {
|
impl<'a> FilterBlock<'a> {
|
||||||
fn parse(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
fn parse(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||||
let mut level = s.level.get();
|
|
||||||
let start_s = *i;
|
let start_s = *i;
|
||||||
let mut start = (
|
let mut start = (
|
||||||
opt(Whitespace::parse),
|
opt(Whitespace::parse),
|
||||||
@ -772,10 +772,10 @@ impl<'a> FilterBlock<'a> {
|
|||||||
Some("filter"),
|
Some("filter"),
|
||||||
(
|
(
|
||||||
ws(identifier),
|
ws(identifier),
|
||||||
opt(|i: &mut _| Expr::arguments(i, s.level.get(), false)),
|
opt(|i: &mut _| Expr::arguments(i, s.level, false)),
|
||||||
repeat(0.., |i: &mut _| {
|
repeat(0.., |i: &mut _| {
|
||||||
let start = *i;
|
let start = *i;
|
||||||
filter(i, &mut level).map(|(name, params)| (name, params, start))
|
filter(i, s.level).map(|(name, params)| (name, params, start))
|
||||||
})
|
})
|
||||||
.map(|v: Vec<_>| v),
|
.map(|v: Vec<_>| v),
|
||||||
ws(empty),
|
ws(empty),
|
||||||
@ -875,7 +875,7 @@ pub struct Call<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Call<'a> {
|
impl<'a> Call<'a> {
|
||||||
fn parse(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
fn parse(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||||
let start = *i;
|
let start = *i;
|
||||||
let mut p = (
|
let mut p = (
|
||||||
opt(Whitespace::parse),
|
opt(Whitespace::parse),
|
||||||
@ -885,9 +885,7 @@ impl<'a> Call<'a> {
|
|||||||
(
|
(
|
||||||
opt((ws(identifier), ws("::"))),
|
opt((ws(identifier), ws("::"))),
|
||||||
ws(identifier),
|
ws(identifier),
|
||||||
opt(ws(|nested: &mut _| {
|
opt(ws(|nested: &mut _| Expr::arguments(nested, s.level, true))),
|
||||||
Expr::arguments(nested, s.level.get(), true)
|
|
||||||
})),
|
|
||||||
opt(Whitespace::parse),
|
opt(Whitespace::parse),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -916,7 +914,7 @@ pub struct Match<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Match<'a> {
|
impl<'a> Match<'a> {
|
||||||
fn parse(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
fn parse(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||||
let start = *i;
|
let start = *i;
|
||||||
let mut p = (
|
let mut p = (
|
||||||
opt(Whitespace::parse),
|
opt(Whitespace::parse),
|
||||||
@ -924,7 +922,7 @@ impl<'a> Match<'a> {
|
|||||||
cut_node(
|
cut_node(
|
||||||
Some("match"),
|
Some("match"),
|
||||||
(
|
(
|
||||||
ws(|i: &mut _| Expr::parse(i, s.level.get(), false)),
|
ws(|i: &mut _| Expr::parse(i, s.level, false)),
|
||||||
opt(Whitespace::parse),
|
opt(Whitespace::parse),
|
||||||
|i: &mut _| s.tag_block_end(i),
|
|i: &mut _| s.tag_block_end(i),
|
||||||
cut_node(
|
cut_node(
|
||||||
@ -988,7 +986,7 @@ pub struct BlockDef<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> BlockDef<'a> {
|
impl<'a> BlockDef<'a> {
|
||||||
fn parse(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
fn parse(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||||
let start_s = *i;
|
let start_s = *i;
|
||||||
let mut start = (
|
let mut start = (
|
||||||
opt(Whitespace::parse),
|
opt(Whitespace::parse),
|
||||||
@ -1068,7 +1066,7 @@ pub struct Lit<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Lit<'a> {
|
impl<'a> Lit<'a> {
|
||||||
fn parse(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
fn parse(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||||
let start = *i;
|
let start = *i;
|
||||||
not(eof).parse_next(i)?;
|
not(eof).parse_next(i)?;
|
||||||
|
|
||||||
@ -1115,7 +1113,7 @@ pub struct Raw<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Raw<'a> {
|
impl<'a> Raw<'a> {
|
||||||
fn parse(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
fn parse(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||||
let start = *i;
|
let start = *i;
|
||||||
let endraw = (
|
let endraw = (
|
||||||
|i: &mut _| s.tag_block_start(i),
|
|i: &mut _| s.tag_block_start(i),
|
||||||
@ -1155,7 +1153,7 @@ pub struct Let<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Let<'a> {
|
impl<'a> Let<'a> {
|
||||||
fn parse(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
fn parse(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||||
let start = *i;
|
let start = *i;
|
||||||
let mut p = (
|
let mut p = (
|
||||||
opt(Whitespace::parse),
|
opt(Whitespace::parse),
|
||||||
@ -1166,7 +1164,7 @@ impl<'a> Let<'a> {
|
|||||||
ws(|i: &mut _| Target::parse(i, s)),
|
ws(|i: &mut _| Target::parse(i, s)),
|
||||||
opt(preceded(
|
opt(preceded(
|
||||||
ws('='),
|
ws('='),
|
||||||
ws(|i: &mut _| Expr::parse(i, s.level.get(), false)),
|
ws(|i: &mut _| Expr::parse(i, s.level, false)),
|
||||||
)),
|
)),
|
||||||
opt(Whitespace::parse),
|
opt(Whitespace::parse),
|
||||||
),
|
),
|
||||||
@ -1217,7 +1215,7 @@ pub struct If<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> If<'a> {
|
impl<'a> If<'a> {
|
||||||
fn parse(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
fn parse(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||||
let start = *i;
|
let start = *i;
|
||||||
let mut p = (
|
let mut p = (
|
||||||
opt(Whitespace::parse),
|
opt(Whitespace::parse),
|
||||||
@ -1323,14 +1321,14 @@ pub struct Comment<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Comment<'a> {
|
impl<'a> Comment<'a> {
|
||||||
fn parse(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
fn parse(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, WithSpan<'a, Self>> {
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
enum Tag {
|
enum Tag {
|
||||||
Open,
|
Open,
|
||||||
Close,
|
Close,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tag<'a>(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, Tag> {
|
fn tag<'a>(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, Tag> {
|
||||||
alt((
|
alt((
|
||||||
(|i: &mut _| s.tag_comment_start(i)).value(Tag::Open),
|
(|i: &mut _| s.tag_comment_start(i)).value(Tag::Open),
|
||||||
(|i: &mut _| s.tag_comment_end(i)).value(Tag::Close),
|
(|i: &mut _| s.tag_comment_end(i)).value(Tag::Close),
|
||||||
@ -1338,7 +1336,7 @@ impl<'a> Comment<'a> {
|
|||||||
.parse_next(i)
|
.parse_next(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn content<'a>(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a> {
|
fn content<'a>(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a> {
|
||||||
let mut depth = 0usize;
|
let mut depth = 0usize;
|
||||||
let start = *i;
|
let start = *i;
|
||||||
loop {
|
loop {
|
||||||
|
@ -27,22 +27,26 @@ pub enum Target<'a> {
|
|||||||
|
|
||||||
impl<'a> Target<'a> {
|
impl<'a> Target<'a> {
|
||||||
/// Parses multiple targets with `or` separating them
|
/// Parses multiple targets with `or` separating them
|
||||||
pub(super) fn parse(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
|
pub(super) fn parse(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, Self> {
|
||||||
separated(
|
let _level_guard = s.level.nest(i)?;
|
||||||
1..,
|
let mut p = opt(preceded(ws(keyword("or")), |i: &mut _| {
|
||||||
|i: &mut _| s.nest(i, |i: &mut _| Self::parse_one(i, s)),
|
Self::parse_one(i, s)
|
||||||
ws("or"),
|
}));
|
||||||
)
|
|
||||||
.map(|v: Vec<_>| v)
|
let target = Self::parse_one(i, s)?;
|
||||||
.map(|mut opts| match opts.len() {
|
let Some(snd_target) = p.parse_next(i)? else {
|
||||||
1 => opts.pop().unwrap(),
|
return Ok(target);
|
||||||
_ => Self::OrChain(opts),
|
};
|
||||||
})
|
|
||||||
.parse_next(i)
|
let mut targets = vec![target, snd_target];
|
||||||
|
while let Some(target) = p.parse_next(i)? {
|
||||||
|
targets.push(target);
|
||||||
|
}
|
||||||
|
Ok(Self::OrChain(targets))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses a single target without an `or`, unless it is wrapped in parentheses.
|
/// Parses a single target without an `or`, unless it is wrapped in parentheses.
|
||||||
fn parse_one(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
|
fn parse_one(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, Self> {
|
||||||
let mut opt_opening_paren = opt(ws('(')).map(|o| o.is_some());
|
let mut opt_opening_paren = opt(ws('(')).map(|o| o.is_some());
|
||||||
let mut opt_opening_brace = opt(ws('{')).map(|o| o.is_some());
|
let mut opt_opening_brace = opt(ws('{')).map(|o| o.is_some());
|
||||||
let mut opt_opening_bracket = opt(ws('[')).map(|o| o.is_some());
|
let mut opt_opening_bracket = opt(ws('[')).map(|o| o.is_some());
|
||||||
@ -130,11 +134,11 @@ impl<'a> Target<'a> {
|
|||||||
.parse_next(i)
|
.parse_next(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unnamed(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, Self> {
|
fn unnamed(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, Self> {
|
||||||
alt((Self::rest, |i: &mut _| Self::parse(i, s))).parse_next(i)
|
alt((Self::rest, |i: &mut _| Self::parse(i, s))).parse_next(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn named(i: &mut &'a str, s: &State<'_>) -> ParseResult<'a, (&'a str, Self)> {
|
fn named(i: &mut &'a str, s: &State<'_, '_>) -> ParseResult<'a, (&'a str, Self)> {
|
||||||
let start = *i;
|
let start = *i;
|
||||||
let rest = opt(Self::rest.with_taken()).parse_next(i)?;
|
let rest = opt(Self::rest.with_taken()).parse_next(i)?;
|
||||||
if let Some(rest) = rest {
|
if let Some(rest) = rest {
|
||||||
|
4
testing/templates/fuzzed-recursion-mul-deref.txt
Normal file
4
testing/templates/fuzzed-recursion-mul-deref.txt
Normal file
File diff suppressed because one or more lines are too long
@ -1,6 +1,6 @@
|
|||||||
error: your template code is too deeply nested, or last expression is too complex
|
error: your template code is too deeply nested, or the last expression is too complex
|
||||||
--> <source attribute>:14:42
|
--> <source attribute>:15:58
|
||||||
"%}{%if 1%}{%if 1%}{%if 1%}{%if 1%}{%if 1%}\n {%if 1%}{%if 1%}{%if 1%}{%if 1%}{"...
|
"%}{%if 1%}{%if 1%}{%if 1%}\n {%if 1%}{%if 1%}{%if 1%}{%if 1%}{%if 1%}{%if 1%}{"...
|
||||||
--> tests/ui/excessive_nesting.rs:5:14
|
--> tests/ui/excessive_nesting.rs:5:14
|
||||||
|
|
|
|
||||||
5 | source = "
|
5 | source = "
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
error: your template code is too deeply nested, or last expression is too complex
|
error: your template code is too deeply nested, or the last expression is too complex
|
||||||
--> testing/templates/filter-recursion.html:1:255
|
--> testing/templates/filter-recursion.html:1:275
|
||||||
"|A|AA|A|A|A|A|AA|A|A|A|A|AA|A|A|A|A|AA|A|A|A|A|AA|A|A|A|A|AA|A|A|A||A|A|AA|A|A|A"...
|
"|A|A|AA|A|A|A|A|AA|A|A|A|A|AA|A|A|A|A|AA|A|A|A||A|A|AA|A|A|A|A|AA|A|A|A|A|AA|A|A"...
|
||||||
--> tests/ui/filter-recursion.rs:4:19
|
--> tests/ui/filter-recursion.rs:4:19
|
||||||
|
|
|
|
||||||
4 | #[template(path = "filter-recursion.html")]
|
4 | #[template(path = "filter-recursion.html")]
|
||||||
|
9
testing/tests/ui/fuzzed_recursion_depth_mul_deref.rs
Normal file
9
testing/tests/ui/fuzzed_recursion_depth_mul_deref.rs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
use rinja::Template;
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(path = "fuzzed-recursion-mul-deref.txt")]
|
||||||
|
struct Filtered {
|
||||||
|
s: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
7
testing/tests/ui/fuzzed_recursion_depth_mul_deref.stderr
Normal file
7
testing/tests/ui/fuzzed_recursion_depth_mul_deref.stderr
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
error: your template code is too deeply nested, or the last expression is too complex
|
||||||
|
--> testing/templates/fuzzed-recursion-mul-deref.txt:2:486
|
||||||
|
"!**y**false|yz***y**false|z**yz**s**fa*galse|iz**!**y**false|yz***y**f*!**y**fal"...
|
||||||
|
--> tests/ui/fuzzed_recursion_depth_mul_deref.rs:4:19
|
||||||
|
|
|
||||||
|
4 | #[template(path = "fuzzed-recursion-mul-deref.txt")]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
Loading…
x
Reference in New Issue
Block a user