parser: make State part of InputStream

This commit is contained in:
René Kijewski 2025-08-14 08:10:01 +02:00 committed by René Kijewski
parent e5189b933d
commit 81252cd0a2
5 changed files with 615 additions and 734 deletions

View File

@ -8,35 +8,30 @@ use winnow::token::{any, one_of, take, take_until};
use crate::node::CondTest; use crate::node::CondTest;
use crate::{ use crate::{
CharLit, ErrorContext, HashSet, InputStream, Level, Num, ParseResult, PathOrIdentifier, StrLit, CharLit, ErrorContext, HashSet, InputStream, Num, ParseResult, PathOrIdentifier, StrLit,
StrPrefix, WithSpan, can_be_variable_name, char_lit, cut_error, filter, identifier, keyword, StrPrefix, WithSpan, can_be_variable_name, char_lit, cut_error, filter, identifier,
not_suffix_with_hash, num_lit, path_or_identifier, skip_ws0, skip_ws1, str_lit, ws, is_rust_keyword, keyword, not_suffix_with_hash, num_lit, path_or_identifier, skip_ws0,
skip_ws1, str_lit, ws,
}; };
macro_rules! expr_prec_layer { macro_rules! expr_prec_layer {
( $name:ident, $inner:ident, $op:expr ) => { ( $name:ident, $inner:ident, $op:expr ) => {
fn $name( fn $name(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
i: &mut InputStream<'a>, expr_prec_layer(i, Expr::$inner, |i: &mut _| $op.parse_next(i))
level: Level<'_>,
) -> ParseResult<'a, WithSpan<Box<Self>>> {
expr_prec_layer(i, level, Expr::$inner, |i: &mut _| $op.parse_next(i))
} }
}; };
} }
fn expr_prec_layer<'a>( fn expr_prec_layer<'a: 'l, 'l>(
i: &mut InputStream<'a>, i: &mut InputStream<'a, 'l>,
level: Level<'_>, inner: fn(&mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Expr<'a>>>>,
inner: fn(&mut InputStream<'a>, Level<'_>) -> ParseResult<'a, WithSpan<Box<Expr<'a>>>>, op: fn(&mut InputStream<'a, 'l>) -> ParseResult<'a>,
op: fn(&mut InputStream<'a>) -> ParseResult<'a>,
) -> ParseResult<'a, WithSpan<Box<Expr<'a>>>> { ) -> ParseResult<'a, WithSpan<Box<Expr<'a>>>> {
let mut expr = inner(i, level)?; let mut expr = inner(i)?;
let mut i_before = *i; let mut i_before = *i;
let mut level_guard = level.guard(); let mut level_guard = i.state.level.guard();
while let Some(((op, span), rhs)) = while let Some(((op, span), rhs)) = opt((ws(op.with_span()), inner)).parse_next(i)? {
opt((ws(op.with_span()), |i: &mut _| inner(i, level))).parse_next(i)?
{
level_guard.nest(&i_before)?; level_guard.nest(&i_before)?;
expr = WithSpan::new(Box::new(Expr::BinOp(BinOp { op, lhs: expr, rhs })), span); expr = WithSpan::new(Box::new(Expr::BinOp(BinOp { op, lhs: expr, rhs })), span);
i_before = *i; i_before = *i;
@ -165,7 +160,7 @@ pub struct PathComponent<'a> {
pub generics: Option<WithSpan<Vec<WithSpan<TyGenerics<'a>>>>>, pub generics: Option<WithSpan<Vec<WithSpan<TyGenerics<'a>>>>>,
} }
impl<'a> PathComponent<'a> { impl<'a: 'l, 'l> PathComponent<'a> {
#[inline] #[inline]
pub fn new_with_name(name: WithSpan<&'a str>) -> Self { pub fn new_with_name(name: WithSpan<&'a str>) -> Self {
Self { Self {
@ -174,10 +169,10 @@ impl<'a> PathComponent<'a> {
} }
} }
pub(crate) fn parse(i: &mut InputStream<'a>, level: Level<'_>) -> ParseResult<'a, Self> { pub(crate) fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Self> {
let mut p = ( let mut p = (
identifier.with_span(), identifier.with_span(),
opt(preceded(ws("::"), |i: &mut _| TyGenerics::args(i, level))), opt(preceded(ws("::"), TyGenerics::args)),
); );
let ((name, name_span), generics) = p.parse_next(i)?; let ((name, name_span), generics) = p.parse_next(i)?;
Ok(Self { Ok(Self {
@ -242,12 +237,11 @@ pub struct BinOp<'a> {
pub rhs: WithSpan<Box<Expr<'a>>>, pub rhs: WithSpan<Box<Expr<'a>>>,
} }
impl<'a> Expr<'a> { impl<'a: 'l, 'l> Expr<'a> {
pub(super) fn arguments( pub(super) fn arguments(
i: &mut InputStream<'a>, i: &mut InputStream<'a, 'l>,
level: Level<'_>,
) -> ParseResult<'a, WithSpan<Vec<WithSpan<Box<Self>>>>> { ) -> ParseResult<'a, WithSpan<Vec<WithSpan<Box<Self>>>>> {
let _level_guard = level.nest(i)?; let _level_guard = i.state.level.nest(i)?;
let mut named_arguments = HashSet::default(); let mut named_arguments = HashSet::default();
let mut p = ( let mut p = (
ws('('.span()), ws('('.span()),
@ -261,8 +255,8 @@ impl<'a> Expr<'a> {
let has_named_arguments = !named_arguments.is_empty(); let has_named_arguments = !named_arguments.is_empty();
let mut p = alt(( let mut p = alt((
move |i: &mut _| Self::named_argument(i, level, named_arguments), move |i: &mut _| Self::named_argument(i, named_arguments),
move |i: &mut _| Self::parse(i, level, false), move |i: &mut _| Self::parse(i, false),
)); ));
let expr = p.parse_next(i)?; let expr = p.parse_next(i)?;
if has_named_arguments && !matches!(**expr, Self::NamedArgument(..)) { if has_named_arguments && !matches!(**expr, Self::NamedArgument(..)) {
@ -287,13 +281,12 @@ impl<'a> Expr<'a> {
} }
fn named_argument( fn named_argument(
i: &mut InputStream<'a>, i: &mut InputStream<'a, 'l>,
level: Level<'_>,
named_arguments: &mut HashSet<&'a str>, named_arguments: &mut HashSet<&'a str>,
) -> ParseResult<'a, WithSpan<Box<Self>>> { ) -> ParseResult<'a, WithSpan<Box<Self>>> {
let (((argument, arg_span), _, value), span) = let (((argument, arg_span), _, value), span) =
(identifier.with_span(), ws('='), move |i: &mut _| { (identifier.with_span(), ws('='), move |i: &mut _| {
Self::parse(i, level, false) Self::parse(i, false)
}) })
.with_span() .with_span()
.parse_next(i)?; .parse_next(i)?;
@ -317,25 +310,20 @@ impl<'a> Expr<'a> {
} }
pub(super) fn parse( pub(super) fn parse(
i: &mut InputStream<'a>, i: &mut InputStream<'a, 'l>,
level: Level<'_>,
allow_underscore: bool, allow_underscore: bool,
) -> ParseResult<'a, WithSpan<Box<Self>>> { ) -> ParseResult<'a, WithSpan<Box<Self>>> {
let _level_guard = level.nest(i)?; let _level_guard = i.state.level.nest(i)?;
Self::range(i, level, allow_underscore) Self::range(i, allow_underscore)
} }
fn range( fn range(
i: &mut InputStream<'a>, i: &mut InputStream<'a, 'l>,
level: Level<'_>,
allow_underscore: bool, allow_underscore: bool,
) -> ParseResult<'a, WithSpan<Box<Self>>> { ) -> ParseResult<'a, WithSpan<Box<Self>>> {
let range_right = move |i: &mut InputStream<'a>| { let range_right = move |i: &mut InputStream<'a, 'l>| {
let ((op, span), rhs) = ( let ((op, span), rhs) =
ws(alt(("..=", "..")).with_span()), (ws(alt(("..=", "..")).with_span()), opt(Self::or)).parse_next(i)?;
opt(move |i: &mut _| Self::or(i, level)),
)
.parse_next(i)?;
Ok((op, rhs, span)) Ok((op, rhs, span))
}; };
@ -345,19 +333,17 @@ impl<'a> Expr<'a> {
}); });
// `expr..expr` or `expr..` // `expr..expr` or `expr..`
let range_from = (move |i: &mut _| Self::or(i, level), opt(range_right)).map( let range_from = (Self::or, opt(range_right)).map(move |(lhs, rhs)| match rhs {
move |(lhs, rhs)| match rhs { Some((op, rhs, span)) => WithSpan::new(
Some((op, rhs, span)) => WithSpan::new( Box::new(Self::Range(Range {
Box::new(Self::Range(Range { op,
op, lhs: Some(lhs),
lhs: Some(lhs), rhs,
rhs, })),
})), span,
span, ),
), None => lhs,
None => lhs, });
},
);
let expr = alt((range_to, range_from)).parse_next(i)?; let expr = alt((range_to, range_from)).parse_next(i)?;
check_expr( check_expr(
@ -373,14 +359,10 @@ impl<'a> Expr<'a> {
expr_prec_layer!(or, and, "||"); expr_prec_layer!(or, and, "||");
expr_prec_layer!(and, compare, "&&"); expr_prec_layer!(and, compare, "&&");
fn compare(i: &mut InputStream<'a>, level: Level<'_>) -> ParseResult<'a, WithSpan<Box<Self>>> { fn compare(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
let mut parse_op = ws(alt(("==", "!=", ">=", ">", "<=", "<")).with_span()); let mut parse_op = ws(alt(("==", "!=", ">=", ">", "<=", "<")).with_span());
let (expr, rhs) = ( let (expr, rhs) = (Self::bor, opt((parse_op.by_ref(), Self::bor))).parse_next(i)?;
|i: &mut _| Self::bor(i, level),
opt((parse_op.by_ref(), |i: &mut _| Self::bor(i, level))),
)
.parse_next(i)?;
let Some(((op, span), rhs)) = rhs else { let Some(((op, span), rhs)) = rhs else {
return Ok(expr); return Ok(expr);
}; };
@ -405,15 +387,14 @@ 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 InputStream<'a>, level: Level<'_>) -> ParseResult<'a, WithSpan<Box<Self>>> { fn concat(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
fn concat_expr<'a>( fn concat_expr<'a: 'l, 'l>(
i: &mut InputStream<'a>, i: &mut InputStream<'a, 'l>,
level: Level<'_>,
) -> ParseResult<'a, Option<(WithSpan<Box<Expr<'a>>>, std::ops::Range<usize>)>> { ) -> ParseResult<'a, Option<(WithSpan<Box<Expr<'a>>>, std::ops::Range<usize>)>> {
let ws1 = |i: &mut _| opt(skip_ws1).parse_next(i); let ws1 = |i: &mut _| opt(skip_ws1).parse_next(i);
let tilde = (ws1, '~', ws1).with_span(); let tilde = (ws1, '~', ws1).with_span();
let data = opt((tilde, |i: &mut _| Expr::muldivmod(i, level))).parse_next(i)?; let data = opt((tilde, Expr::muldivmod)).parse_next(i)?;
let Some((((t1, _, t2), span), expr)) = data else { let Some((((t1, _, t2), span), expr)) = data else {
return Ok(None); return Ok(None);
@ -425,11 +406,11 @@ impl<'a> Expr<'a> {
Ok(Some((expr, span))) Ok(Some((expr, span)))
} }
let expr = Self::muldivmod(i, level)?; let expr = Self::muldivmod(i)?;
let expr2 = concat_expr(i, level)?; let expr2 = concat_expr(i)?;
if let Some((expr2, span)) = expr2 { if let Some((expr2, span)) = expr2 {
let mut exprs = vec![expr, expr2]; let mut exprs = vec![expr, expr2];
while let Some((expr, _)) = concat_expr(i, level)? { while let Some((expr, _)) = concat_expr(i)? {
exprs.push(expr); exprs.push(expr);
} }
Ok(WithSpan::new(Box::new(Self::Concat(exprs)), span)) Ok(WithSpan::new(Box::new(Self::Concat(exprs)), span))
@ -440,13 +421,13 @@ impl<'a> Expr<'a> {
expr_prec_layer!(muldivmod, is_as, alt(("*", "/", "%"))); expr_prec_layer!(muldivmod, is_as, alt(("*", "/", "%")));
fn is_as(i: &mut InputStream<'a>, level: Level<'_>) -> ParseResult<'a, WithSpan<Box<Self>>> { fn is_as(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
let lhs = Self::filtered(i, level)?; let lhs = Self::filtered(i)?;
let checkpoint = i.checkpoint(); let checkpoint = i.checkpoint();
let rhs = opt(ws(identifier.with_span())).parse_next(i)?; let rhs = opt(ws(identifier.with_span())).parse_next(i)?;
match rhs { match rhs {
Some(("is", span)) => Self::is_as_handle_is(i, lhs, span), Some(("is", span)) => Self::is_as_handle_is(i, lhs, span),
Some(("as", span)) => Self::is_as_handle_as(i, level, lhs, span), Some(("as", span)) => Self::is_as_handle_as(i, lhs, span),
_ => { _ => {
i.reset(&checkpoint); i.reset(&checkpoint);
Ok(lhs) Ok(lhs)
@ -455,7 +436,7 @@ impl<'a> Expr<'a> {
} }
fn is_as_handle_is( fn is_as_handle_is(
i: &mut InputStream<'a>, i: &mut InputStream<'a, 'l>,
lhs: WithSpan<Box<Expr<'a>>>, lhs: WithSpan<Box<Expr<'a>>>,
span: std::ops::Range<usize>, span: std::ops::Range<usize>,
) -> ParseResult<'a, WithSpan<Box<Self>>> { ) -> ParseResult<'a, WithSpan<Box<Self>>> {
@ -483,12 +464,11 @@ impl<'a> Expr<'a> {
} }
fn is_as_handle_as( fn is_as_handle_as(
i: &mut InputStream<'a>, i: &mut InputStream<'a, 'l>,
level: Level<'_>,
lhs: WithSpan<Box<Expr<'a>>>, lhs: WithSpan<Box<Expr<'a>>>,
span: std::ops::Range<usize>, span: std::ops::Range<usize>,
) -> ParseResult<'a, WithSpan<Box<Self>>> { ) -> ParseResult<'a, WithSpan<Box<Self>>> {
let target = opt(|i: &mut _| path_or_identifier(i, level)).parse_next(i)?; let target = opt(path_or_identifier).parse_next(i)?;
let Some(PathOrIdentifier::Identifier(target)) = target else { let Some(PathOrIdentifier::Identifier(target)) = target else {
return cut_error!( return cut_error!(
"`as` operator expects the name of a primitive type on its right-hand side, \ "`as` operator expects the name of a primitive type on its right-hand side, \
@ -516,14 +496,12 @@ impl<'a> Expr<'a> {
} }
} }
fn filtered(i: &mut InputStream<'a>, level: Level<'_>) -> ParseResult<'a, WithSpan<Box<Self>>> { fn filtered(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
let mut res = Self::prefix(i, level)?; let mut res = Self::prefix(i)?;
let mut level_guard = level.guard(); let mut level_guard = i.state.level.guard();
let mut i_before = *i; let mut i_before = *i;
while let Some((mut filter, span)) = while let Some((mut filter, span)) = opt(ws(filter.with_span())).parse_next(i)? {
opt(ws((|i: &mut _| filter(i, level)).with_span())).parse_next(i)?
{
level_guard.nest(&i_before)?; level_guard.nest(&i_before)?;
filter.arguments.insert(0, res); filter.arguments.insert(0, res);
res = WithSpan::new(Box::new(Self::Filter(filter)), span); res = WithSpan::new(Box::new(Self::Filter(filter)), span);
@ -532,11 +510,11 @@ impl<'a> Expr<'a> {
Ok(res) Ok(res)
} }
fn prefix(i: &mut InputStream<'a>, level: Level<'_>) -> ParseResult<'a, WithSpan<Box<Self>>> { fn prefix(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
// 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.
let mut level_guard = level.guard(); let mut level_guard = i.state.level.guard();
let mut i_before = *i; let mut i_before = *i;
let mut ops = vec![]; let mut ops = vec![];
while let Some(op) = opt(ws(alt(("!", "-", "*", "&")).with_span())).parse_next(i)? { while let Some(op) = opt(ws(alt(("!", "-", "*", "&")).with_span())).parse_next(i)? {
@ -545,7 +523,7 @@ impl<'a> Expr<'a> {
i_before = *i; i_before = *i;
} }
let mut expr = Suffix::parse(i, level)?; let mut expr = Suffix::parse(i)?;
for (op, span) in ops.into_iter().rev() { for (op, span) in ops.into_iter().rev() {
expr = WithSpan::new(Box::new(Self::Unary(op, expr)), span); expr = WithSpan::new(Box::new(Self::Unary(op, expr)), span);
} }
@ -553,44 +531,36 @@ impl<'a> Expr<'a> {
Ok(expr) Ok(expr)
} }
fn single(i: &mut InputStream<'a>, level: Level<'_>) -> ParseResult<'a, WithSpan<Box<Self>>> { fn single(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
alt(( alt((
Self::num, Self::num,
Self::str, Self::str,
Self::char, Self::char,
move |i: &mut _| Self::path_var_bool(i, level), Self::path_var_bool,
move |i: &mut _| Self::array(i, level), Self::array,
move |i: &mut _| Self::group(i, level), Self::group,
)) ))
.parse_next(i) .parse_next(i)
} }
fn group(i: &mut InputStream<'a>, level: Level<'_>) -> ParseResult<'a, WithSpan<Box<Self>>> { fn group(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
(skip_ws0, peek('(')).parse_next(i)?; (skip_ws0, peek('(')).parse_next(i)?;
Self::group_actually(i, level) Self::group_actually(i)
} }
// `Self::group()` is quite big. Let's only put it on the stack if needed. // `Self::group()` is quite big. Let's only put it on the stack if needed.
#[inline(never)] #[inline(never)]
fn group_actually( fn group_actually(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
i: &mut InputStream<'a>, let (expr, span) = cut_err(preceded('(', Self::group_actually_inner))
level: Level<'_>, .with_span()
) -> ParseResult<'a, WithSpan<Box<Self>>> { .parse_next(i)?;
let (expr, span) = cut_err(preceded('(', |i: &mut _| {
Self::group_actually_inner(i, level)
}))
.with_span()
.parse_next(i)?;
Ok(WithSpan::new(expr, span)) Ok(WithSpan::new(expr, span))
} }
#[inline] #[inline]
fn group_actually_inner( fn group_actually_inner(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Self>> {
i: &mut InputStream<'a>,
level: Level<'_>,
) -> ParseResult<'a, Box<Self>> {
let (expr, comma, closing) = ( let (expr, comma, closing) = (
ws(opt(|i: &mut _| Self::parse(i, level, true))), ws(opt(|i: &mut _| Self::parse(i, true))),
opt(terminated(','.span(), skip_ws0)), opt(terminated(','.span(), skip_ws0)),
opt(')'), opt(')'),
) )
@ -617,7 +587,7 @@ impl<'a> Expr<'a> {
let collect_items = opt(separated( let collect_items = opt(separated(
1.., 1..,
|i: &mut _| { |i: &mut _| {
exprs.push(Self::parse(i, level, true)?); exprs.push(Self::parse(i, true)?);
Ok(()) Ok(())
}, },
ws(','), ws(','),
@ -639,12 +609,12 @@ impl<'a> Expr<'a> {
cut_error!(msg, span) cut_error!(msg, span)
} }
fn array(i: &mut InputStream<'a>, level: Level<'_>) -> ParseResult<'a, WithSpan<Box<Self>>> { fn array(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
let (array, span) = preceded( let (array, span) = preceded(
ws('['), ws('['),
cut_err(terminated( cut_err(terminated(
opt(terminated( opt(terminated(
separated(1.., ws(move |i: &mut _| Self::parse(i, level, true)), ','), separated(1.., ws(move |i: &mut _| Self::parse(i, true)), ','),
ws(opt(',')), ws(opt(',')),
)), )),
']', ']',
@ -658,13 +628,8 @@ impl<'a> Expr<'a> {
)) ))
} }
fn path_var_bool( fn path_var_bool(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
i: &mut InputStream<'a>, let (ret, span) = path_or_identifier.with_span().parse_next(i)?;
level: Level<'_>,
) -> ParseResult<'a, WithSpan<Box<Self>>> {
let (ret, span) = (|i: &mut _| path_or_identifier(i, level))
.with_span()
.parse_next(i)?;
let ret = match ret { let ret = match ret {
PathOrIdentifier::Path(v) => Box::new(Self::Path(v)), PathOrIdentifier::Path(v) => Box::new(Self::Path(v)),
PathOrIdentifier::Identifier(v) if *v == "true" => Box::new(Self::BoolLit(true)), PathOrIdentifier::Identifier(v) if *v == "true" => Box::new(Self::BoolLit(true)),
@ -674,17 +639,17 @@ impl<'a> Expr<'a> {
Ok(WithSpan::new(ret, span)) Ok(WithSpan::new(ret, span))
} }
fn str(i: &mut InputStream<'a>) -> ParseResult<'a, WithSpan<Box<Self>>> { fn str(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
let (s, span) = str_lit.with_span().parse_next(i)?; let (s, span) = str_lit.with_span().parse_next(i)?;
Ok(WithSpan::new(Box::new(Self::StrLit(s)), span)) Ok(WithSpan::new(Box::new(Self::StrLit(s)), span))
} }
fn num(i: &mut InputStream<'a>) -> ParseResult<'a, WithSpan<Box<Self>>> { fn num(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
let ((num, full), span) = num_lit.with_taken().with_span().parse_next(i)?; let ((num, full), span) = num_lit.with_taken().with_span().parse_next(i)?;
Ok(WithSpan::new(Box::new(Expr::NumLit(full, num)), span)) Ok(WithSpan::new(Box::new(Expr::NumLit(full, num)), span))
} }
fn char(i: &mut InputStream<'a>) -> ParseResult<'a, WithSpan<Box<Self>>> { fn char(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Self>>> {
let (c, span) = char_lit.with_span().parse_next(i)?; let (c, span) = char_lit.with_span().parse_next(i)?;
Ok(WithSpan::new(Box::new(Self::CharLit(c)), span)) Ok(WithSpan::new(Box::new(Self::CharLit(c)), span))
} }
@ -722,7 +687,7 @@ impl<'a> Expr<'a> {
} }
} }
fn token_xor<'a>(i: &mut InputStream<'a>) -> ParseResult<'a> { fn token_xor<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a> {
let (good, span) = alt((keyword("xor").value(true), '^'.value(false))) let (good, span) = alt((keyword("xor").value(true), '^'.value(false)))
.with_span() .with_span()
.parse_next(i)?; .parse_next(i)?;
@ -733,7 +698,7 @@ fn token_xor<'a>(i: &mut InputStream<'a>) -> ParseResult<'a> {
} }
} }
fn token_bitand<'a>(i: &mut InputStream<'a>) -> ParseResult<'a> { fn token_bitand<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a> {
let (good, span) = alt((keyword("bitand").value(true), ('&', not('&')).value(false))) let (good, span) = alt((keyword("bitand").value(true), ('&', not('&')).value(false)))
.with_span() .with_span()
.parse_next(i)?; .parse_next(i)?;
@ -750,12 +715,9 @@ pub struct Filter<'a> {
pub arguments: Vec<WithSpan<Box<Expr<'a>>>>, pub arguments: Vec<WithSpan<Box<Expr<'a>>>>,
} }
impl<'a> Filter<'a> { impl<'a: 'l, 'l> Filter<'a> {
pub(crate) fn parse(i: &mut InputStream<'a>, level: Level<'_>) -> ParseResult<'a, Self> { pub(crate) fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Self> {
let mut p = ( let mut p = (ws(path_or_identifier), opt(Expr::arguments));
ws(|i: &mut _| path_or_identifier(i, level)),
opt(|i: &mut _| Expr::arguments(i, level)),
);
let (name, arguments) = p.parse_next(i)?; let (name, arguments) = p.parse_next(i)?;
Ok(Self { Ok(Self {
name, name,
@ -782,17 +744,14 @@ enum Suffix<'a> {
Try, Try,
} }
impl<'a> Suffix<'a> { impl<'a: 'l, 'l> Suffix<'a> {
fn parse( fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Box<Expr<'a>>>> {
i: &mut InputStream<'a>, let mut level_guard = i.state.level.guard();
level: Level<'_>, let mut expr = Expr::single(i)?;
) -> ParseResult<'a, WithSpan<Box<Expr<'a>>>> {
let mut level_guard = level.guard();
let mut expr = Expr::single(i, level)?;
let mut right = opt(alt(( let mut right = opt(alt((
|i: &mut _| Self::associated_item(i, level), Self::associated_item,
|i: &mut _| Self::index(i, level), Self::index,
|i: &mut _| Self::call(i, level), Self::call,
Self::r#try, Self::r#try,
Self::r#macro, Self::r#macro,
))); )));
@ -852,7 +811,7 @@ impl<'a> Suffix<'a> {
Ok(expr) Ok(expr)
} }
fn r#macro(i: &mut InputStream<'a>) -> ParseResult<'a, WithSpan<Self>> { fn r#macro(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Self>> {
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Token { enum Token {
SomeOther, SomeOther,
@ -877,14 +836,14 @@ impl<'a> Suffix<'a> {
} }
} }
fn macro_arguments<'a>( fn macro_arguments<'a: 'l, 'l>(
i: &mut InputStream<'a>, i: &mut InputStream<'a, 'l>,
open_token: Group, open_token: Group,
) -> ParseResult<'a, Suffix<'a>> { ) -> ParseResult<'a, Suffix<'a>> {
fn inner<'a>( fn inner<'a: 'l, 'l>(
i: &mut InputStream<'a>, i: &mut InputStream<'a, 'l>,
open_token: Group, open_token: Group,
) -> ParseResult<'a, <InputStream<'a> as Stream>::Checkpoint> { ) -> ParseResult<'a, <InputStream<'a, 'l> as Stream>::Checkpoint> {
let mut open_list = vec![open_token]; let mut open_list = vec![open_token];
loop { loop {
let before = i.checkpoint(); let before = i.checkpoint();
@ -925,36 +884,50 @@ impl<'a> Suffix<'a> {
Ok(Suffix::MacroCall(inner)) Ok(Suffix::MacroCall(inner))
} }
fn lifetime<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, ()> { fn lifetime<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, ()> {
// Before the 2021 edition, we can have whitespace characters between "r#" and the // this code assumes that we tried to match char literals before calling this function
// identifier so we allow it here. let p = (
let start = *i; '\''.void(),
'\''.parse_next(i)?; identifier,
let Some((is_raw, identifier)) = opt(alt(( opt((repeat(1.., '#'), opt(identifier))),
('r', '#', identifier).map(|(_, _, ident)| (true, ident)), opt('\'').map(|o| o.is_some()),
(identifier, not(peek('#'))).map(|(ident, _)| (false, ident)), );
))) let ((_, front, back, quot), span) = p.with_span().parse_next(i)?;
.parse_next(i)? match (front, back, quot) {
else { // this case should never be encountered
return cut_error!("wrong lifetime format", **start); (_, _, true) => cut_error!(
}; "cannot have multiple characters in a character literal, \
if !is_raw { use `\"...\"` to write a string",
if crate::is_rust_keyword(identifier) { span
return cut_error!( ),
"a non-raw lifetime cannot be named like an existing keyword", // a normal lifetime
**start, (identifier, None, _) => {
); if !is_rust_keyword(identifier) {
Ok(())
} else {
cut_error!(
"a non-raw lifetime cannot be named like an existing keyword",
span,
)
}
} }
} else if ["Self", "self", "crate", "super", "_"].contains(&identifier) { // a raw lifetime
return cut_error!(format!("`{identifier}` cannot be a raw lifetime"), **start,); ("r", Some((1, Some(identifier))), _) => {
if matches!(identifier, "Self" | "self" | "crate" | "super" | "_") {
cut_error!(
format!("`{}` cannot be a raw lifetime", identifier.escape_debug()),
span,
)
} else {
Ok(())
}
}
// an illegal prefix (not `'r#..`, multiple `#` or no identifier after `#`)
(_, Some(_), _) => cut_error!("wrong lifetime format", span),
} }
if opt(peek('\'')).parse_next(i)?.is_some() {
return cut_error!("unexpected `'` after lifetime", **start);
}
Ok(())
} }
fn token<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, Token> { fn token<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Token> {
// <https://doc.rust-lang.org/reference/tokens.html> // <https://doc.rust-lang.org/reference/tokens.html>
let some_other = alt(( let some_other = alt((
// literals // literals
@ -974,8 +947,8 @@ impl<'a> Suffix<'a> {
alt((open.map(Token::Open), close.map(Token::Close), some_other)).parse_next(i) alt((open.map(Token::Open), close.map(Token::Close), some_other)).parse_next(i)
} }
fn line_comment<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, ()> { fn line_comment<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, ()> {
fn inner<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, bool> { fn inner<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, bool> {
let mut p = ( let mut p = (
"//".span(), "//".span(),
alt(( alt((
@ -1000,8 +973,8 @@ impl<'a> Suffix<'a> {
doc_comment_no_bare_cr(i, inner) doc_comment_no_bare_cr(i, inner)
} }
fn block_comment<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, ()> { fn block_comment<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, ()> {
fn inner<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, bool> { fn inner<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, bool> {
let is_doc_comment = alt(( let is_doc_comment = alt((
('*', not(peek(one_of(['*', '/'])))).value(true), ('*', not(peek(one_of(['*', '/'])))).value(true),
'!'.value(true), '!'.value(true),
@ -1034,7 +1007,9 @@ impl<'a> Suffix<'a> {
doc_comment_no_bare_cr(i, inner) doc_comment_no_bare_cr(i, inner)
} }
fn identifier_or_prefixed_string<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, ()> { fn identifier_or_prefixed_string<'a: 'l, 'l>(
i: &mut InputStream<'a, 'l>,
) -> ParseResult<'a, ()> {
// <https://doc.rust-lang.org/reference/tokens.html#r-lex.token.literal.str-raw.syntax> // <https://doc.rust-lang.org/reference/tokens.html#r-lex.token.literal.str-raw.syntax>
let ((prefix, hashes, quot), prefix_span): ((_, usize, _), _) = let ((prefix, hashes, quot), prefix_span): ((_, usize, _), _) =
@ -1145,7 +1120,7 @@ impl<'a> Suffix<'a> {
} }
} }
fn hash<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, Token> { fn hash<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Token> {
let (quot, span) = preceded('#', opt('"')).with_span().parse_next(i)?; let (quot, span) = preceded('#', opt('"')).with_span().parse_next(i)?;
if quot.is_some() { if quot.is_some() {
return cut_error!( return cut_error!(
@ -1156,7 +1131,7 @@ impl<'a> Suffix<'a> {
Ok(Token::SomeOther) Ok(Token::SomeOther)
} }
fn punctuation<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, ()> { fn punctuation<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, ()> {
// <https://doc.rust-lang.org/reference/tokens.html#punctuation> // <https://doc.rust-lang.org/reference/tokens.html#punctuation>
// hash '#' omitted // hash '#' omitted
@ -1200,7 +1175,7 @@ impl<'a> Suffix<'a> {
alt((three_chars, two_chars, one_char)).parse_next(i) alt((three_chars, two_chars, one_char)).parse_next(i)
} }
fn open<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, Group> { fn open<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Group> {
alt(( alt((
'('.value(Group::Paren), '('.value(Group::Paren),
'{'.value(Group::Brace), '{'.value(Group::Brace),
@ -1209,7 +1184,7 @@ impl<'a> Suffix<'a> {
.parse_next(i) .parse_next(i)
} }
fn close<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, Group> { fn close<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Group> {
alt(( alt((
')'.value(Group::Paren), ')'.value(Group::Paren),
'}'.value(Group::Brace), '}'.value(Group::Brace),
@ -1223,10 +1198,7 @@ impl<'a> Suffix<'a> {
Ok(WithSpan::new(inner, span)) Ok(WithSpan::new(inner, span))
} }
fn associated_item( fn associated_item(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Self>> {
i: &mut InputStream<'a>,
level: Level<'_>,
) -> ParseResult<'a, WithSpan<Self>> {
let mut p = ( let mut p = (
ws(terminated('.'.span(), not('.'))), ws(terminated('.'.span(), not('.'))),
cut_err(( cut_err((
@ -1240,7 +1212,7 @@ impl<'a> Suffix<'a> {
} }
Ok(WithSpan::new(name, span)) Ok(WithSpan::new(name, span))
}, },
opt(|i: &mut _| call_generics(i, level)), opt(call_generics),
)), )),
); );
let (span, (name, generics)) = p.parse_next(i)?; let (span, (name, generics)) = p.parse_next(i)?;
@ -1250,10 +1222,10 @@ impl<'a> Suffix<'a> {
)) ))
} }
fn index(i: &mut InputStream<'a>, level: Level<'_>) -> ParseResult<'a, WithSpan<Self>> { fn index(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Self>> {
let mut p = ( let mut p = (
ws('['.span()), ws('['.span()),
cut_err((ws(move |i: &mut _| Expr::parse(i, level, true)), opt(']'))), cut_err((ws(move |i: &mut _| Expr::parse(i, true)), opt(']'))),
); );
let (span, (expr, closed)) = p.parse_next(i)?; let (span, (expr, closed)) = p.parse_next(i)?;
if closed.is_none() { if closed.is_none() {
@ -1262,24 +1234,22 @@ impl<'a> Suffix<'a> {
Ok(WithSpan::new(Self::Index(expr), span)) Ok(WithSpan::new(Self::Index(expr), span))
} }
fn call(i: &mut InputStream<'a>, level: Level<'_>) -> ParseResult<'a, WithSpan<Self>> { fn call(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Self>> {
let mut p = (opt(|i: &mut _| call_generics(i, level)), |i: &mut _| { let mut p = (opt(call_generics), Expr::arguments);
Expr::arguments(i, level)
});
let (generics, args) = p.parse_next(i)?; let (generics, args) = p.parse_next(i)?;
let (args, span) = args.deconstruct(); let (args, span) = args.deconstruct();
Ok(WithSpan::new(Self::Call { generics, args }, span)) Ok(WithSpan::new(Self::Call { generics, args }, span))
} }
fn r#try(i: &mut InputStream<'a>) -> ParseResult<'a, WithSpan<Self>> { fn r#try(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Self>> {
let span = preceded(skip_ws0, '?'.span()).parse_next(i)?; let span = preceded(skip_ws0, '?'.span()).parse_next(i)?;
Ok(WithSpan::new(Self::Try, span)) Ok(WithSpan::new(Self::Try, span))
} }
} }
fn doc_comment_no_bare_cr<'a>( fn doc_comment_no_bare_cr<'a: 'l, 'l>(
i: &mut InputStream<'a>, i: &mut InputStream<'a, 'l>,
inner: fn(i: &mut InputStream<'a>) -> ParseResult<'a, bool>, inner: fn(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, bool>,
) -> ParseResult<'a, ()> { ) -> ParseResult<'a, ()> {
let ((is_doc_comment, comment), span) = inner.with_taken().with_span().parse_next(i)?; let ((is_doc_comment, comment), span) = inner.with_taken().with_span().parse_next(i)?;
if is_doc_comment && comment.split('\r').skip(1).any(|s| !s.starts_with('\n')) { if is_doc_comment && comment.split('\r').skip(1).any(|s| !s.starts_with('\n')) {
@ -1307,8 +1277,8 @@ pub struct TyGenerics<'a> {
pub args: Option<WithSpan<Vec<WithSpan<TyGenerics<'a>>>>>, pub args: Option<WithSpan<Vec<WithSpan<TyGenerics<'a>>>>>,
} }
impl<'i> TyGenerics<'i> { impl<'a: 'l, 'l> TyGenerics<'a> {
fn parse(i: &mut InputStream<'i>, level: Level<'_>) -> ParseResult<'i, WithSpan<Self>> { fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Self>> {
let path = separated( let path = separated(
1.., 1..,
ws(identifier ws(identifier
@ -1318,11 +1288,7 @@ impl<'i> TyGenerics<'i> {
) )
.map(|v: Vec<_>| v); .map(|v: Vec<_>| v);
let p = ws(( let p = ws((repeat(0.., ws('&')), path, opt(Self::args)));
repeat(0.., ws('&')),
path,
opt(|i: &mut _| Self::args(i, level)),
));
let ((refs, path, args), span) = p.with_span().parse_next(i)?; let ((refs, path, args), span) = p.with_span().parse_next(i)?;
if let [name] = path.as_slice() { if let [name] = path.as_slice() {
@ -1347,27 +1313,25 @@ impl<'i> TyGenerics<'i> {
} }
fn args( fn args(
i: &mut InputStream<'i>, i: &mut InputStream<'a, 'l>,
level: Level<'_>, ) -> ParseResult<'a, WithSpan<Vec<WithSpan<TyGenerics<'a>>>>> {
) -> ParseResult<'i, WithSpan<Vec<WithSpan<TyGenerics<'i>>>>> {
let mut p = cut_err(terminated( let mut p = cut_err(terminated(
opt(terminated( opt(terminated(
separated(1.., |i: &mut _| TyGenerics::parse(i, level), ws(',')), separated(1.., TyGenerics::parse, ws(',')),
ws(opt(',')), ws(opt(',')),
)), )),
'>', '>',
)); ));
let span = ws('<'.span()).parse_next(i)?; let span = ws('<'.span()).parse_next(i)?;
let _level_guard = level.nest(i)?; let _level_guard = i.state.level.nest(i)?;
let args = p.parse_next(i)?; let args = p.parse_next(i)?;
Ok(WithSpan::new(args.unwrap_or_default(), span)) Ok(WithSpan::new(args.unwrap_or_default(), span))
} }
} }
pub(crate) fn call_generics<'i>( pub(crate) fn call_generics<'a: 'l, 'l>(
i: &mut InputStream<'i>, i: &mut InputStream<'a, 'l>,
level: Level<'_>, ) -> ParseResult<'a, WithSpan<Vec<WithSpan<TyGenerics<'a>>>>> {
) -> ParseResult<'i, WithSpan<Vec<WithSpan<TyGenerics<'i>>>>> { preceded(ws("::"), cut_err(TyGenerics::args)).parse_next(i)
preceded(ws("::"), cut_err(|i: &mut _| TyGenerics::args(i, level))).parse_next(i)
} }

View File

@ -103,7 +103,7 @@ mod _parsed {
pub use _parsed::Parsed; pub use _parsed::Parsed;
type InputStream<'a> = Stateful<LocatingSlice<&'a str>, ()>; type InputStream<'a, 'l> = Stateful<LocatingSlice<&'a str>, &'l State<'l>>;
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct Ast<'a> { pub struct Ast<'a> {
@ -117,18 +117,16 @@ impl<'a> Ast<'a> {
src: &'a str, src: &'a str,
file_path: Option<Arc<Path>>, file_path: Option<Arc<Path>>,
syntax: &Syntax<'_>, syntax: &Syntax<'_>,
) -> Result<Self, ParseError> { ) -> Result<Ast<'a>, ParseError> {
let level = Cell::new(Level::MAX_DEPTH);
let state = State { let state = State {
syntax, syntax: *syntax,
loop_depth: Cell::new(0), ..State::default()
level: Level(&level),
}; };
let mut src = InputStream { let mut src = InputStream {
input: LocatingSlice::new(src), input: LocatingSlice::new(src),
state: (), state: &state,
}; };
match Node::parse_template(&mut src, &state) { match Node::parse_template(&mut src) {
Ok(nodes) if src.is_empty() => Ok(Self { nodes }), Ok(nodes) if src.is_empty() => Ok(Self { nodes }),
Ok(_) | Err(ErrMode::Incomplete(_)) => unreachable!(), Ok(_) | Err(ErrMode::Incomplete(_)) => unreachable!(),
Err( Err(
@ -164,13 +162,6 @@ pub struct Span {
end: usize, end: usize,
} }
impl From<&InputStream<'_>> for Span {
#[inline]
fn from(i: &InputStream<'_>) -> Self {
(*i).into()
}
}
impl Default for Span { impl Default for Span {
#[inline] #[inline]
fn default() -> Self { fn default() -> Self {
@ -178,9 +169,16 @@ impl Default for Span {
} }
} }
impl From<InputStream<'_>> for Span { impl From<&InputStream<'_, '_>> for Span {
#[inline] #[inline]
fn from(mut i: InputStream<'_>) -> Self { fn from(i: &InputStream<'_, '_>) -> Self {
(*i).into()
}
}
impl From<InputStream<'_, '_>> for Span {
#[inline]
fn from(mut i: InputStream<'_, '_>) -> Self {
let start = i.current_token_start(); let start = i.current_token_start();
i.finish(); i.finish();
Self { Self {
@ -471,11 +469,11 @@ impl ErrorContext {
} }
} }
impl<'a> winnow::error::ParserError<InputStream<'a>> for ErrorContext { impl<'a: 'l, 'l> winnow::error::ParserError<InputStream<'a, 'l>> for ErrorContext {
type Inner = Self; type Inner = Self;
#[inline] #[inline]
fn from_input(input: &InputStream<'a>) -> Self { fn from_input(input: &InputStream<'a, 'l>) -> Self {
Self { Self {
span: input.into(), span: input.into(),
message: None, message: None,
@ -488,35 +486,35 @@ impl<'a> winnow::error::ParserError<InputStream<'a>> for ErrorContext {
} }
} }
fn skip_ws0<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, ()> { fn skip_ws0<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, ()> {
take_while(0.., |c: char| c.is_ascii_whitespace()) take_while(0.., |c: char| c.is_ascii_whitespace())
.void() .void()
.parse_next(i) .parse_next(i)
} }
fn skip_ws1<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, ()> { fn skip_ws1<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, ()> {
take_while(1.., |c: char| c.is_ascii_whitespace()) take_while(1.., |c: char| c.is_ascii_whitespace())
.void() .void()
.parse_next(i) .parse_next(i)
} }
fn ws<'a, O>( fn ws<'a: 'l, 'l, O>(
inner: impl ModalParser<InputStream<'a>, O, ErrorContext>, inner: impl ModalParser<InputStream<'a, 'l>, O, ErrorContext>,
) -> impl ModalParser<InputStream<'a>, O, ErrorContext> { ) -> impl ModalParser<InputStream<'a, 'l>, O, ErrorContext> {
delimited(skip_ws0, inner, skip_ws0) delimited(skip_ws0, inner, skip_ws0)
} }
fn keyword<'a>(k: &str) -> impl ModalParser<InputStream<'a>, &'a str, ErrorContext> { fn keyword<'a: 'l, 'l>(k: &str) -> impl ModalParser<InputStream<'a, 'l>, &'a str, ErrorContext> {
identifier.verify(move |v: &str| v == k) identifier.verify(move |v: &str| v == k)
} }
fn identifier<'i>(input: &mut InputStream<'i>) -> ParseResult<'i> { fn identifier<'a: 'l, 'l>(input: &mut InputStream<'a, 'l>) -> ParseResult<'a> {
let head = any.verify(|&c| c == '_' || unicode_ident::is_xid_start(c)); let head = any.verify(|&c| c == '_' || unicode_ident::is_xid_start(c));
let tail = take_while(.., unicode_ident::is_xid_continue); let tail = take_while(.., unicode_ident::is_xid_continue);
(head, tail).take().parse_next(input) (head, tail).take().parse_next(input)
} }
fn bool_lit<'i>(i: &mut InputStream<'i>) -> ParseResult<'i> { fn bool_lit<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a> {
alt((keyword("false"), keyword("true"))).parse_next(i) alt((keyword("false"), keyword("true"))).parse_next(i)
} }
@ -526,11 +524,11 @@ pub enum Num<'a> {
Float(&'a str, Option<FloatKind>), Float(&'a str, Option<FloatKind>),
} }
fn num_lit<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, Num<'a>> { fn num_lit<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Num<'a>> {
fn num_lit_suffix<'a, T: Copy>( fn num_lit_suffix<'a: 'l, 'l, T: Copy>(
kind: &'a str, kind: &'a str,
list: &[(&str, T)], list: &[(&str, T)],
i: &mut InputStream<'a>, i: &mut InputStream<'a, 'l>,
) -> ParseResult<'a, T> { ) -> ParseResult<'a, T> {
let (suffix, span) = identifier.with_span().parse_next(i)?; let (suffix, span) = identifier.with_span().parse_next(i)?;
if let Some(value) = list if let Some(value) = list
@ -558,7 +556,7 @@ fn num_lit<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, Num<'a>> {
// Equivalent to <https://github.com/rust-lang/rust/blob/e3f909b2bbd0b10db6f164d466db237c582d3045/compiler/rustc_lexer/src/lib.rs#L626-L653>: // Equivalent to <https://github.com/rust-lang/rust/blob/e3f909b2bbd0b10db6f164d466db237c582d3045/compiler/rustc_lexer/src/lib.rs#L626-L653>:
// no `_` directly after the decimal point `.`, or between `e` and `+/-`. // no `_` directly after the decimal point `.`, or between `e` and `+/-`.
let float = |i: &mut InputStream<'a>| -> ParseResult<'a, ()> { let float = |i: &mut InputStream<'a, 'l>| -> ParseResult<'a, ()> {
let has_dot = opt(('.', separated_digits(10, true))).parse_next(i)?; let has_dot = opt(('.', separated_digits(10, true))).parse_next(i)?;
let has_exp = opt(|i: &mut _| { let has_exp = opt(|i: &mut _| {
let ((kind, op), span) = (one_of(['e', 'E']), opt(one_of(['+', '-']))) let ((kind, op), span) = (one_of(['e', 'E']), opt(one_of(['+', '-'])))
@ -605,10 +603,10 @@ fn num_lit<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, Num<'a>> {
/// Underscore separated digits of the given base, unless `start` is true this may start /// Underscore separated digits of the given base, unless `start` is true this may start
/// with an underscore. /// with an underscore.
fn separated_digits<'a>( fn separated_digits<'a: 'l, 'l>(
radix: u32, radix: u32,
start: bool, start: bool,
) -> impl ModalParser<InputStream<'a>, &'a str, ErrorContext> { ) -> impl ModalParser<InputStream<'a, 'l>, &'a str, ErrorContext> {
( (
cond(!start, repeat(0.., '_').map(|()| ())), cond(!start, repeat(0.., '_').map(|()| ())),
one_of(move |ch: char| ch.is_digit(radix)), one_of(move |ch: char| ch.is_digit(radix)),
@ -661,10 +659,10 @@ pub struct StrLit<'a> {
pub contains_high_ascii: bool, pub contains_high_ascii: bool,
} }
fn str_lit<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, StrLit<'a>> { fn str_lit<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, StrLit<'a>> {
// <https://doc.rust-lang.org/reference/tokens.html#r-lex.token.literal.str.syntax> // <https://doc.rust-lang.org/reference/tokens.html#r-lex.token.literal.str.syntax>
fn inner<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, StrLit<'a>> { fn inner<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, StrLit<'a>> {
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
enum Sequence<'a> { enum Sequence<'a> {
Text(&'a str), Text(&'a str),
@ -800,7 +798,7 @@ fn str_lit<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, StrLit<'a>> {
Ok(lit) Ok(lit)
} }
fn not_suffix_with_hash<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, ()> { fn not_suffix_with_hash<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, ()> {
if let Some(span) = opt(identifier.span()).parse_next(i)? { if let Some(span) = opt(identifier.span()).parse_next(i)? {
return cut_error!( return cut_error!(
"you are missing a space to separate two string literals", "you are missing a space to separate two string literals",
@ -810,7 +808,7 @@ fn not_suffix_with_hash<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, ()> {
Ok(()) Ok(())
} }
fn str_lit_without_prefix<'a>(i: &mut InputStream<'a>) -> ParseResult<'a> { fn str_lit_without_prefix<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a> {
let (lit, span) = str_lit.with_span().parse_next(i)?; let (lit, span) = str_lit.with_span().parse_next(i)?;
let kind = match lit.prefix { let kind = match lit.prefix {
@ -841,7 +839,7 @@ pub struct CharLit<'a> {
// Information about allowed character escapes is available at: // Information about allowed character escapes is available at:
// <https://doc.rust-lang.org/reference/tokens.html#character-literals>. // <https://doc.rust-lang.org/reference/tokens.html#character-literals>.
fn char_lit<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, CharLit<'a>> { fn char_lit<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, CharLit<'a>> {
let ((prefix, _, content, is_closed), span) = ( let ((prefix, _, content, is_closed), span) = (
alt(('b'.value(Some(CharPrefix::Binary)), empty.value(None))), alt(('b'.value(Some(CharPrefix::Binary)), empty.value(None))),
'\'', '\'',
@ -985,18 +983,13 @@ pub enum PathOrIdentifier<'a> {
Identifier(WithSpan<&'a str>), Identifier(WithSpan<&'a str>),
} }
fn path_or_identifier<'a>( fn path_or_identifier<'a: 'l, 'l>(
i: &mut InputStream<'a>, i: &mut InputStream<'a, 'l>,
level: Level<'_>,
) -> ParseResult<'a, PathOrIdentifier<'a>> { ) -> ParseResult<'a, PathOrIdentifier<'a>> {
let mut p = |i: &mut _| { let mut p = |i: &mut _| {
let root = ws(opt(terminated(empty.span(), "::"))); let root = ws(opt(terminated(empty.span(), "::")));
let start = move |i: &mut _| PathComponent::parse(i, level); let start = PathComponent::parse;
let tail = opt(repeat( let tail = opt(repeat(1.., preceded(ws("::"), PathComponent::parse)).map(|v: Vec<_>| v));
1..,
preceded(ws("::"), move |i: &mut _| PathComponent::parse(i, level)),
)
.map(|v: Vec<_>| v));
let (root, start, rest) = (root, start, tail).parse_next(i)?; let (root, start, rest) = (root, start, tail).parse_next(i)?;
Ok((root, start, rest.unwrap_or_default())) Ok((root, start, rest.unwrap_or_default()))
@ -1037,41 +1030,50 @@ fn path_or_identifier<'a>(
} }
} }
struct State<'a, 'l> { #[derive(Debug, Clone, Default)]
syntax: &'l Syntax<'a>, struct State<'a> {
syntax: Syntax<'a>,
loop_depth: Cell<usize>, loop_depth: Cell<usize>,
level: Level<'l>, level: Level,
} }
impl State<'_, '_> { fn block_start<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, ()> {
fn tag_block_start<'i>(&self, i: &mut InputStream<'i>) -> ParseResult<'i, ()> { i.state.syntax.block_start.void().parse_next(i)
self.syntax.block_start.value(()).parse_next(i) }
}
fn tag_block_end<'i>(&self, i: &mut InputStream<'i>) -> ParseResult<'i, ()> { fn block_end<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, ()> {
let (control, span) = alt(( let (control, span) = alt((
self.syntax.block_end.value(None), i.state.syntax.block_end.value(None),
peek(delimited('%', alt(('-', '~', '+')).map(Some), '}')), peek(delimited('%', alt(('-', '~', '+')).map(Some), '}')),
fail, // rollback on partial matches in the previous line fail, // rollback on partial matches in the previous line
)) ))
.with_span() .with_span()
.parse_next(i)?; .parse_next(i)?;
let Some(control) = control else { let Some(control) = control else {
return Ok(()); return Ok(());
}; };
let err = ErrorContext::new( let err = ErrorContext::new(
format!( format!(
"unclosed block, you likely meant to apply whitespace control: \"{}{}\"", "unclosed block, you likely meant to apply whitespace control: \"{}{}\"",
control.escape_default(), control.escape_default(),
self.syntax.block_end.escape_default(), i.state.syntax.block_end.escape_default(),
), ),
span, span,
); );
Err(err.backtrack()) Err(err.backtrack())
} }
fn expr_start<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, ()> {
i.state.syntax.expr_start.void().parse_next(i)
}
fn expr_end<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, ()> {
i.state.syntax.expr_end.void().parse_next(i)
}
impl State<'_> {
fn enter_loop(&self) { fn enter_loop(&self) {
self.loop_depth.set(self.loop_depth.get() + 1); self.loop_depth.set(self.loop_depth.get() + 1);
} }
@ -1244,27 +1246,34 @@ impl<'a> SyntaxBuilder<'a> {
/// [`Level::nest()`] / [`LevelGuard::nest()`] will return an error. The same [`Level`] instance is /// [`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 /// shared across all usages in a [`Parsed::new()`] / [`Ast::from_str()`] call, using a reference
/// to an interior mutable counter. /// to an interior mutable counter.
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone)]
struct Level<'l>(&'l Cell<usize>); struct Level(Cell<usize>);
impl Level<'_> { impl Default for Level {
#[inline]
fn default() -> Self {
Self(Cell::new(Level::MAX_DEPTH))
}
}
impl Level {
const MAX_DEPTH: usize = 128; const MAX_DEPTH: usize = 128;
/// Acquire a [`LevelGuard`] without decrementing the counter, to be used with loops. /// Acquire a [`LevelGuard`] without decrementing the counter, to be used with loops.
fn guard(&self) -> LevelGuard<'_> { fn guard(&self) -> LevelGuard<'_> {
LevelGuard { LevelGuard {
level: *self, level: self,
count: 0, count: 0,
} }
} }
/// Decrement the remaining level counter, and return a [`LevelGuard`] that increments it again /// Decrement the remaining level counter, and return a [`LevelGuard`] that increments it again
/// when it's dropped. /// when it's dropped.
fn nest<'a>(&self, i: &InputStream<'a>) -> ParseResult<'a, LevelGuard<'_>> { fn nest<'a: 'l, 'l>(&self, i: &InputStream<'a, 'l>) -> ParseResult<'a, LevelGuard<'_>> {
if let Some(new_level) = self.0.get().checked_sub(1) { if let Some(new_level) = self.0.get().checked_sub(1) {
self.0.set(new_level); self.0.set(new_level);
Ok(LevelGuard { Ok(LevelGuard {
level: *self, level: self,
count: 1, count: 1,
}) })
} else { } else {
@ -1274,7 +1283,7 @@ impl Level<'_> {
#[cold] #[cold]
#[inline(never)] #[inline(never)]
fn _fail<'a, T>(i: &InputStream<'a>) -> ParseResult<'a, T> { fn _fail<'a: 'l, 'l, T>(i: &InputStream<'a, 'l>) -> ParseResult<'a, T> {
let msg = "your template code is too deeply nested, or the last expression is too complex"; let msg = "your template code is too deeply nested, or the last expression is too complex";
Err(ErrorContext::new(msg, i).cut()) Err(ErrorContext::new(msg, i).cut())
} }
@ -1284,7 +1293,7 @@ impl Level<'_> {
/// remaining level counter when it is dropped / falls out of scope. /// remaining level counter when it is dropped / falls out of scope.
#[must_use] #[must_use]
struct LevelGuard<'l> { struct LevelGuard<'l> {
level: Level<'l>, level: &'l Level,
count: usize, count: usize,
} }
@ -1296,7 +1305,7 @@ impl Drop for LevelGuard<'_> {
impl LevelGuard<'_> { impl LevelGuard<'_> {
/// Used to decrement the level multiple times, e.g. for every iteration of a loop. /// Used to decrement the level multiple times, e.g. for every iteration of a loop.
fn nest<'a>(&mut self, i: &InputStream<'a>) -> ParseResult<'a, ()> { fn nest<'a: 'l, 'l>(&mut self, i: &InputStream<'a, 'l>) -> ParseResult<'a, ()> {
if let Some(new_level) = self.level.0.get().checked_sub(1) { if let Some(new_level) = self.level.0.get().checked_sub(1) {
self.level.0.set(new_level); self.level.0.set(new_level);
self.count += 1; self.count += 1;
@ -1307,12 +1316,8 @@ impl LevelGuard<'_> {
} }
} }
fn filter<'a>(i: &mut InputStream<'a>, level: Level<'_>) -> ParseResult<'a, Filter<'a>> { fn filter<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Filter<'a>> {
preceded( preceded(('|', not('|')), cut_err(Filter::parse)).parse_next(i)
('|', not('|')),
cut_err(|i: &mut _| Filter::parse(i, level)),
)
.parse_next(i)
} }
/// Returns the common parts of two paths. /// Returns the common parts of two paths.
@ -1602,78 +1607,82 @@ mod test {
assert_eq!(strip_common(&cwd, Path::new("/a/b/c")), "/a/b/c"); assert_eq!(strip_common(&cwd, Path::new("/a/b/c")), "/a/b/c");
} }
fn parse_peek<'a, T>( #[track_caller]
mut parser: impl ModalParser<InputStream<'a>, T, ErrorContext>, fn parse_peek<'a: 'l, 'l, T>(
state: &'l State<'l>,
parser: impl FnOnce(&mut InputStream<'a, 'l>) -> ParseResult<'a, T>,
input: &'a str, input: &'a str,
) -> ParseResult<'a, (&'a str, T)> { ) -> ParseResult<'a, (&'a str, T)> {
let mut i = InputStream { let mut i = InputStream {
input: LocatingSlice::new(input), input: LocatingSlice::new(input),
state: (), state,
}; };
let value = parser.parse_next(&mut i)?; let value = parser(&mut i)?;
Ok((**i, value)) Ok((**i, value))
} }
#[test] #[test]
fn test_num_lit() { fn test_num_lit() {
let s = State::default();
// Should fail. // Should fail.
assert!(parse_peek(num_lit, ".").is_err()); assert!(parse_peek(&s, num_lit, ".").is_err());
// Should succeed. // Should succeed.
assert_eq!( assert_eq!(
parse_peek(num_lit, "1.2E-02").unwrap(), parse_peek(&s, num_lit, "1.2E-02").unwrap(),
("", Num::Float("1.2E-02", None)) ("", Num::Float("1.2E-02", None))
); );
assert_eq!( assert_eq!(
parse_peek(num_lit, "4e3").unwrap(), parse_peek(&s, num_lit, "4e3").unwrap(),
("", Num::Float("4e3", None)), ("", Num::Float("4e3", None)),
); );
assert_eq!( assert_eq!(
parse_peek(num_lit, "4e+_3").unwrap(), parse_peek(&s, num_lit, "4e+_3").unwrap(),
("", Num::Float("4e+_3", None)), ("", Num::Float("4e+_3", None)),
); );
// Not supported because Rust wants a number before the `.`. // Not supported because Rust wants a number before the `.`.
assert!(parse_peek(num_lit, ".1").is_err()); assert!(parse_peek(&s, num_lit, ".1").is_err());
assert!(parse_peek(num_lit, ".1E-02").is_err()); assert!(parse_peek(&s, num_lit, ".1E-02").is_err());
// A `_` directly after the `.` denotes a field. // A `_` directly after the `.` denotes a field.
assert_eq!( assert_eq!(
parse_peek(num_lit, "1._0").unwrap(), parse_peek(&s, num_lit, "1._0").unwrap(),
("._0", Num::Int("1", None)) ("._0", Num::Int("1", None))
); );
assert_eq!( assert_eq!(
parse_peek(num_lit, "1_.0").unwrap(), parse_peek(&s, num_lit, "1_.0").unwrap(),
("", Num::Float("1_.0", None)) ("", Num::Float("1_.0", None))
); );
// Not supported (voluntarily because of `1..` syntax). // Not supported (voluntarily because of `1..` syntax).
assert_eq!( assert_eq!(
parse_peek(num_lit, "1.").unwrap(), parse_peek(&s, num_lit, "1.").unwrap(),
(".", Num::Int("1", None)) (".", Num::Int("1", None))
); );
assert_eq!( assert_eq!(
parse_peek(num_lit, "1_.").unwrap(), parse_peek(&s, num_lit, "1_.").unwrap(),
(".", Num::Int("1_", None)) (".", Num::Int("1_", None))
); );
assert_eq!( assert_eq!(
parse_peek(num_lit, "1_2.").unwrap(), parse_peek(&s, num_lit, "1_2.").unwrap(),
(".", Num::Int("1_2", None)) (".", Num::Int("1_2", None))
); );
// Numbers with suffixes // Numbers with suffixes
assert_eq!( assert_eq!(
parse_peek(num_lit, "-1usize").unwrap(), parse_peek(&s, num_lit, "-1usize").unwrap(),
("", Num::Int("-1", Some(IntKind::Usize))) ("", Num::Int("-1", Some(IntKind::Usize)))
); );
assert_eq!( assert_eq!(
parse_peek(num_lit, "123_f32").unwrap(), parse_peek(&s, num_lit, "123_f32").unwrap(),
("", Num::Float("123_", Some(FloatKind::F32))) ("", Num::Float("123_", Some(FloatKind::F32)))
); );
assert_eq!( assert_eq!(
parse_peek(num_lit, "1_.2_e+_3_f64|into_isize").unwrap(), parse_peek(&s, num_lit, "1_.2_e+_3_f64|into_isize").unwrap(),
( (
"|into_isize", "|into_isize",
Num::Float("1_.2_e+_3_", Some(FloatKind::F64)) Num::Float("1_.2_e+_3_", Some(FloatKind::F64))
) )
); );
assert_eq!( assert_eq!(
parse_peek(num_lit, "4e3f128").unwrap(), parse_peek(&s, num_lit, "4e3f128").unwrap(),
("", Num::Float("4e3", Some(FloatKind::F128))), ("", Num::Float("4e3", Some(FloatKind::F128))),
); );
} }
@ -1684,43 +1693,59 @@ mod test {
prefix: None, prefix: None,
content: s, content: s,
}; };
let s = State::default();
assert_eq!(parse_peek(char_lit, "'a'").unwrap(), ("", lit("a"))); assert_eq!(parse_peek(&s, char_lit, "'a'").unwrap(), ("", lit("a")));
assert_eq!(parse_peek(char_lit, "'字'").unwrap(), ("", lit(""))); assert_eq!(parse_peek(&s, char_lit, "'字'").unwrap(), ("", lit("")));
// Escaped single characters. // Escaped single characters.
assert_eq!(parse_peek(char_lit, "'\\\"'").unwrap(), ("", lit("\\\""))); assert_eq!(
assert_eq!(parse_peek(char_lit, "'\\''").unwrap(), ("", lit("\\'"))); parse_peek(&s, char_lit, "'\\\"'").unwrap(),
assert_eq!(parse_peek(char_lit, "'\\t'").unwrap(), ("", lit("\\t"))); ("", lit("\\\""))
assert_eq!(parse_peek(char_lit, "'\\n'").unwrap(), ("", lit("\\n"))); );
assert_eq!(parse_peek(char_lit, "'\\r'").unwrap(), ("", lit("\\r"))); assert_eq!(parse_peek(&s, char_lit, "'\\''").unwrap(), ("", lit("\\'")));
assert_eq!(parse_peek(char_lit, "'\\0'").unwrap(), ("", lit("\\0"))); assert_eq!(parse_peek(&s, char_lit, "'\\t'").unwrap(), ("", lit("\\t")));
assert_eq!(parse_peek(&s, char_lit, "'\\n'").unwrap(), ("", lit("\\n")));
assert_eq!(parse_peek(&s, char_lit, "'\\r'").unwrap(), ("", lit("\\r")));
assert_eq!(parse_peek(&s, char_lit, "'\\0'").unwrap(), ("", lit("\\0")));
// Escaped ascii characters (up to `0x7F`). // Escaped ascii characters (up to `0x7F`).
assert_eq!(parse_peek(char_lit, "'\\x12'").unwrap(), ("", lit("\\x12"))); assert_eq!(
assert_eq!(parse_peek(char_lit, "'\\x02'").unwrap(), ("", lit("\\x02"))); parse_peek(&s, char_lit, "'\\x12'").unwrap(),
assert_eq!(parse_peek(char_lit, "'\\x6a'").unwrap(), ("", lit("\\x6a"))); ("", lit("\\x12"))
assert_eq!(parse_peek(char_lit, "'\\x7F'").unwrap(), ("", lit("\\x7F"))); );
assert_eq!(
parse_peek(&s, char_lit, "'\\x02'").unwrap(),
("", lit("\\x02"))
);
assert_eq!(
parse_peek(&s, char_lit, "'\\x6a'").unwrap(),
("", lit("\\x6a"))
);
assert_eq!(
parse_peek(&s, char_lit, "'\\x7F'").unwrap(),
("", lit("\\x7F"))
);
// Escaped unicode characters (up to `0x10FFFF`). // Escaped unicode characters (up to `0x10FFFF`).
assert_eq!( assert_eq!(
parse_peek(char_lit, "'\\u{A}'").unwrap(), parse_peek(&s, char_lit, "'\\u{A}'").unwrap(),
("", lit("\\u{A}")) ("", lit("\\u{A}"))
); );
assert_eq!( assert_eq!(
parse_peek(char_lit, "'\\u{10}'").unwrap(), parse_peek(&s, char_lit, "'\\u{10}'").unwrap(),
("", lit("\\u{10}")) ("", lit("\\u{10}"))
); );
assert_eq!( assert_eq!(
parse_peek(char_lit, "'\\u{aa}'").unwrap(), parse_peek(&s, char_lit, "'\\u{aa}'").unwrap(),
("", lit("\\u{aa}")) ("", lit("\\u{aa}"))
); );
assert_eq!( assert_eq!(
parse_peek(char_lit, "'\\u{10FFFF}'").unwrap(), parse_peek(&s, char_lit, "'\\u{10FFFF}'").unwrap(),
("", lit("\\u{10FFFF}")) ("", lit("\\u{10FFFF}"))
); );
// Check with `b` prefix. // Check with `b` prefix.
assert_eq!( assert_eq!(
parse_peek(char_lit, "b'a'").unwrap(), parse_peek(&s, char_lit, "b'a'").unwrap(),
( (
"", "",
crate::CharLit { crate::CharLit {
@ -1731,20 +1756,21 @@ mod test {
); );
// Should fail. // Should fail.
assert!(parse_peek(char_lit, "''").is_err()); assert!(parse_peek(&s, char_lit, "''").is_err());
assert!(parse_peek(char_lit, "'\\o'").is_err()); assert!(parse_peek(&s, char_lit, "'\\o'").is_err());
assert!(parse_peek(char_lit, "'\\x'").is_err()); assert!(parse_peek(&s, char_lit, "'\\x'").is_err());
assert!(parse_peek(char_lit, "'\\x1'").is_err()); assert!(parse_peek(&s, char_lit, "'\\x1'").is_err());
assert!(parse_peek(char_lit, "'\\x80'").is_err()); assert!(parse_peek(&s, char_lit, "'\\x80'").is_err());
assert!(parse_peek(char_lit, "'\\u'").is_err()); assert!(parse_peek(&s, char_lit, "'\\u'").is_err());
assert!(parse_peek(char_lit, "'\\u{}'").is_err()); assert!(parse_peek(&s, char_lit, "'\\u{}'").is_err());
assert!(parse_peek(char_lit, "'\\u{110000}'").is_err()); assert!(parse_peek(&s, char_lit, "'\\u{110000}'").is_err());
} }
#[test] #[test]
fn test_str_lit() { fn test_str_lit() {
let s = State::default();
assert_eq!( assert_eq!(
parse_peek(str_lit, r#"b"hello""#).unwrap(), parse_peek(&s, str_lit, r#"b"hello""#).unwrap(),
( (
"", "",
StrLit { StrLit {
@ -1758,7 +1784,7 @@ mod test {
) )
); );
assert_eq!( assert_eq!(
parse_peek(str_lit, r#"c"hello""#).unwrap(), parse_peek(&s, str_lit, r#"c"hello""#).unwrap(),
( (
"", "",
StrLit { StrLit {
@ -1771,7 +1797,7 @@ mod test {
} }
) )
); );
assert!(parse_peek(str_lit, r#"d"hello""#).is_err()); assert!(parse_peek(&s, str_lit, r#"d"hello""#).is_err());
} }
#[test] #[test]

View File

@ -10,9 +10,9 @@ use winnow::token::{any, literal, rest, take, take_until};
use winnow::{ModalParser, Parser}; use winnow::{ModalParser, Parser};
use crate::{ use crate::{
ErrorContext, Expr, Filter, HashSet, InputStream, ParseErr, ParseResult, Span, State, Target, ErrorContext, Expr, Filter, HashSet, InputStream, ParseErr, ParseResult, Span, Target,
WithSpan, cut_error, filter, identifier, is_rust_keyword, keyword, skip_ws0, WithSpan, block_end, block_start, cut_error, expr_end, expr_start, filter, identifier,
str_lit_without_prefix, ws, is_rust_keyword, keyword, skip_ws0, str_lit_without_prefix, ws,
}; };
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -36,18 +36,12 @@ pub enum Node<'a> {
FilterBlock(WithSpan<FilterBlock<'a>>), FilterBlock(WithSpan<FilterBlock<'a>>),
} }
impl<'a> Node<'a> { impl<'a: 'l, 'l> Node<'a> {
pub(super) fn parse_template( pub(super) fn parse_template(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Vec<Box<Self>>> {
i: &mut InputStream<'a>, let mut p = parse_with_unexpected_fallback(Self::many, unexpected_tag);
s: &State<'_, '_>,
) -> ParseResult<'a, Vec<Box<Self>>> {
let mut p = parse_with_unexpected_fallback(
|i: &mut _| Self::many(i, s),
|i: &mut _| unexpected_tag(i, s),
);
let nodes = p.parse_next(i)?; let nodes = p.parse_next(i)?;
if !i.is_empty() { if !i.is_empty() {
opt(|i: &mut _| unexpected_tag(i, s)).parse_next(i)?; opt(unexpected_tag).parse_next(i)?;
return cut_error!( return cut_error!(
"cannot parse entire template\n\ "cannot parse entire template\n\
you should never encounter this error\n\ you should never encounter this error\n\
@ -58,24 +52,19 @@ impl<'a> Node<'a> {
Ok(nodes) Ok(nodes)
} }
fn many(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, Vec<Box<Self>>> { fn many(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Vec<Box<Self>>> {
repeat( repeat(
0.., 0..,
alt(( alt((Lit::parse, Comment::parse, Self::expr, Self::parse)),
|i: &mut _| Lit::parse(i, s),
|i: &mut _| Comment::parse(i, s),
|i: &mut _| Self::expr(i, s),
|i: &mut _| Self::parse(i, s),
)),
) )
.map(|v: Vec<_>| v) .map(|v: Vec<_>| v)
.parse_next(i) .parse_next(i)
} }
fn parse(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, Box<Self>> { fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Self>> {
let start = i.checkpoint(); let start = i.checkpoint();
let (span, tag) = ( let (span, tag) = (
s.syntax.block_start.span(), block_start.span(),
peek(preceded((opt(Whitespace::parse), skip_ws0), identifier)), peek(preceded((opt(Whitespace::parse), skip_ws0), identifier)),
) )
.parse_next(i)?; .parse_next(i)?;
@ -86,9 +75,9 @@ impl<'a> Node<'a> {
"if" => If::parse, "if" => If::parse,
"for" => Loop::parse, "for" => Loop::parse,
"match" => Match::parse, "match" => Match::parse,
"extends" => |i: &mut InputStream<'a>, _s: &State<'_, '_>| Extends::parse(i), "extends" => Extends::parse,
"include" => |i: &mut InputStream<'a>, _s: &State<'_, '_>| Include::parse(i), "include" => Include::parse,
"import" => |i: &mut InputStream<'a>, _s: &State<'_, '_>| Import::parse(i), "import" => Import::parse,
"block" => BlockDef::parse, "block" => BlockDef::parse,
"macro" => Macro::parse, "macro" => Macro::parse,
"raw" => Raw::parse, "raw" => Raw::parse,
@ -101,23 +90,22 @@ impl<'a> Node<'a> {
} }
}; };
let _level_guard = s.level.nest(i)?; let _level_guard = i.state.level.nest(i)?;
let node = func(i, s)?; let node = func(i)?;
let closed = cut_node( let closed =
None, cut_node(None, alt((ws(eof).value(false), block_end.value(true)))).parse_next(i)?;
alt((
ws(eof).value(false),
(|i: &mut _| s.tag_block_end(i)).value(true),
)),
)
.parse_next(i)?;
match closed { match closed {
true => Ok(node), true => Ok(node),
false => Err(ErrorContext::unclosed("block", s.syntax.block_end, span).cut()), false => {
Err(
ErrorContext::unclosed("block", i.state.syntax.block_end, Span::new(span))
.cut(),
)
}
} }
} }
fn r#break(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, Box<Node<'a>>> { fn r#break(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Node<'a>>> {
let mut p = ( let mut p = (
opt(Whitespace::parse), opt(Whitespace::parse),
ws(keyword("break").span()), ws(keyword("break").span()),
@ -125,13 +113,13 @@ impl<'a> Node<'a> {
); );
let (pws, span, nws) = p.parse_next(i)?; let (pws, span, nws) = p.parse_next(i)?;
if !s.is_in_loop() { if !i.state.is_in_loop() {
return cut_error!("you can only `break` inside a `for` loop", span); return cut_error!("you can only `break` inside a `for` loop", span);
} }
Ok(Box::new(Self::Break(WithSpan::new(Ws(pws, nws), span)))) Ok(Box::new(Self::Break(WithSpan::new(Ws(pws, nws), span))))
} }
fn r#continue(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, Box<Node<'a>>> { fn r#continue(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Node<'a>>> {
let mut p = ( let mut p = (
opt(Whitespace::parse), opt(Whitespace::parse),
ws(keyword("continue").span()), ws(keyword("continue").span()),
@ -139,27 +127,27 @@ impl<'a> Node<'a> {
); );
let (pws, span, nws) = p.parse_next(i)?; let (pws, span, nws) = p.parse_next(i)?;
if !s.is_in_loop() { if !i.state.is_in_loop() {
return cut_error!("you can only `continue` inside a `for` loop", span); return cut_error!("you can only `continue` inside a `for` loop", span);
} }
Ok(Box::new(Self::Continue(WithSpan::new(Ws(pws, nws), span)))) Ok(Box::new(Self::Continue(WithSpan::new(Ws(pws, nws), span))))
} }
fn expr(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, Box<Self>> { fn expr(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Self>> {
let mut p = ( let mut p = (
s.syntax.expr_start.span(), expr_start.span(),
cut_node( cut_node(
None, None,
( (
opt(Whitespace::parse), opt(Whitespace::parse),
ws(|i: &mut _| Expr::parse(i, s.level, false)), ws(|i: &mut _| Expr::parse(i, false)),
), ),
), ),
cut_node( cut_node(
None, None,
( (
opt(Whitespace::parse), opt(Whitespace::parse),
alt((s.syntax.expr_end.value(true), ws(eof).value(false))), alt((expr_end.value(true), ws(eof).value(false))),
), ),
), ),
); );
@ -168,7 +156,7 @@ impl<'a> Node<'a> {
if closed { if closed {
Ok(Box::new(Self::Expr(Ws(pws, nws), expr))) Ok(Box::new(Self::Expr(Ws(pws, nws), expr)))
} else { } else {
Err(ErrorContext::unclosed("expression", s.syntax.expr_end, start).cut()) Err(ErrorContext::unclosed("expression", i.state.syntax.expr_end, start).cut())
} }
} }
@ -197,15 +185,15 @@ impl<'a> Node<'a> {
} }
#[inline] #[inline]
fn parse_with_unexpected_fallback<'a, O>( fn parse_with_unexpected_fallback<'a: 'l, 'l, O>(
mut parser: impl ModalParser<InputStream<'a>, O, ErrorContext>, mut parser: impl ModalParser<InputStream<'a, 'l>, O, ErrorContext>,
mut unexpected_parser: impl FnMut(&mut InputStream<'a>) -> ParseResult<'a, ()>, mut unexpected_parser: impl FnMut(&mut InputStream<'a, 'l>) -> ParseResult<'a, ()>,
) -> impl ModalParser<InputStream<'a>, O, ErrorContext> { ) -> impl ModalParser<InputStream<'a, 'l>, O, ErrorContext> {
#[cold] #[cold]
#[inline(never)] #[inline(never)]
fn try_assign_fallback_error<'a>( fn try_assign_fallback_error<'a: 'l, 'l>(
i: &mut InputStream<'a>, i: &mut InputStream<'a, 'l>,
unexpected_parser: &mut dyn FnMut(&mut InputStream<'a>) -> ParseResult<'a, ()>, unexpected_parser: &mut dyn FnMut(&mut InputStream<'a, 'l>) -> ParseResult<'a, ()>,
err: &mut ErrMode<ErrorContext>, err: &mut ErrMode<ErrorContext>,
) { ) {
let (ErrMode::Backtrack(err_ctx) | ErrMode::Cut(err_ctx)) = &err else { let (ErrMode::Backtrack(err_ctx) | ErrMode::Cut(err_ctx)) = &err else {
@ -227,7 +215,7 @@ fn parse_with_unexpected_fallback<'a, O>(
i.reset(&checkpoint); i.reset(&checkpoint);
} }
move |i: &mut InputStream<'a>| { move |i: &mut InputStream<'a, 'l>| {
let mut result = parser.parse_next(i); let mut result = parser.parse_next(i);
if let Err(err) = &mut result { if let Err(err) = &mut result {
try_assign_fallback_error(i, &mut unexpected_parser, err); try_assign_fallback_error(i, &mut unexpected_parser, err);
@ -237,26 +225,24 @@ fn parse_with_unexpected_fallback<'a, O>(
} }
#[inline] #[inline]
fn cut_node<'a, O>( fn cut_node<'a: 'l, 'l, O>(
kind: Option<&'static str>, kind: Option<&'static str>,
inner: impl ModalParser<InputStream<'a>, O, ErrorContext>, inner: impl ModalParser<InputStream<'a, 'l>, O, ErrorContext>,
) -> impl ModalParser<InputStream<'a>, O, ErrorContext> { ) -> impl ModalParser<InputStream<'a, 'l>, O, ErrorContext> {
parse_with_unexpected_fallback(cut_err(inner), move |i: &mut _| unexpected_raw_tag(kind, i)) parse_with_unexpected_fallback(cut_err(inner), move |i: &mut _| unexpected_raw_tag(kind, i))
} }
fn unexpected_tag<'a>(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, ()> { fn unexpected_tag<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, ()> {
( (block_start, opt(Whitespace::parse), |i: &mut _| {
|i: &mut _| s.tag_block_start(i), unexpected_raw_tag(None, i)
opt(Whitespace::parse), })
|i: &mut _| unexpected_raw_tag(None, i),
)
.void() .void()
.parse_next(i) .parse_next(i)
} }
fn unexpected_raw_tag<'a>( fn unexpected_raw_tag<'a: 'l, 'l>(
kind: Option<&'static str>, kind: Option<&'static str>,
i: &mut InputStream<'a>, i: &mut InputStream<'a, 'l>,
) -> ParseResult<'a, ()> { ) -> ParseResult<'a, ()> {
let (tag, span) = peek(ws(identifier.with_span())).parse_next(i)?; let (tag, span) = peek(ws(identifier.with_span())).parse_next(i)?;
cut_error!( cut_error!(
@ -281,18 +267,18 @@ pub struct When<'a> {
pub nodes: Vec<Box<Node<'a>>>, pub nodes: Vec<Box<Node<'a>>>,
} }
impl<'a> When<'a> { impl<'a: 'l, 'l> When<'a> {
fn r#else(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, WithSpan<Self>> { fn r#else(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Self>> {
let mut p = ( let mut p = (
|i: &mut _| s.tag_block_start(i), block_start,
opt(Whitespace::parse), opt(Whitespace::parse),
ws(keyword("else").span()), ws(keyword("else").span()),
cut_node( cut_node(
Some("match-else"), Some("match-else"),
( (
opt(Whitespace::parse), opt(Whitespace::parse),
|i: &mut _| s.tag_block_end(i), block_end,
cut_node(Some("match-else"), |i: &mut _| Node::many(i, s)), cut_node(Some("match-else"), Node::many),
), ),
), ),
); );
@ -308,19 +294,19 @@ impl<'a> When<'a> {
} }
#[allow(clippy::self_named_constructors)] #[allow(clippy::self_named_constructors)]
fn when(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, WithSpan<Self>> { fn when(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Self>> {
let mut p = ( let mut p = (
|i: &mut _| s.tag_block_start(i), block_start,
opt(Whitespace::parse), opt(Whitespace::parse),
ws(keyword("when").span()), ws(keyword("when").span()),
cut_node( cut_node(
Some("match-when"), Some("match-when"),
( (
separated(1.., ws(|i: &mut _| Target::parse(i, s)), '|'), separated(1.., ws(Target::parse), '|'),
opt(Whitespace::parse), opt(Whitespace::parse),
|i: &mut _| s.tag_block_end(i), block_end,
cut_node(Some("match-when"), |i: &mut _| Node::many(i, s)), cut_node(Some("match-when"), Node::many),
opt(|i: &mut _| Self::endwhen(i, s)), opt(Self::endwhen),
), ),
), ),
); );
@ -338,10 +324,10 @@ impl<'a> When<'a> {
)) ))
} }
fn endwhen(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, Box<Node<'a>>> { fn endwhen(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Node<'a>>> {
let mut p = ws(terminated( let mut p = ws(terminated(
( (
|i: &mut _| s.tag_block_start(i), block_start,
opt(Whitespace::parse), opt(Whitespace::parse),
ws(keyword("endwhen").span()), ws(keyword("endwhen").span()),
), ),
@ -349,8 +335,8 @@ impl<'a> When<'a> {
Some("match-endwhen"), Some("match-endwhen"),
( (
opt(Whitespace::parse), opt(Whitespace::parse),
|i: &mut _| s.tag_block_end(i), block_end,
repeat(0.., ws(|i: &mut _| Comment::parse(i, s)).void()).map(|()| ()), repeat(0.., ws(Comment::parse).void()).map(|()| ()),
), ),
), ),
)); ));
@ -372,28 +358,25 @@ pub struct Cond<'a> {
pub nodes: Vec<Box<Node<'a>>>, pub nodes: Vec<Box<Node<'a>>>,
} }
impl<'a> Cond<'a> { impl<'a: 'l, 'l> Cond<'a> {
fn parse(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, WithSpan<Self>> { fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Self>> {
let alt_else = ( let alt_else = (ws(keyword("else").span()), opt(CondTest::parse));
ws(keyword("else").span()),
opt(|i: &mut _| CondTest::parse(i, s)),
);
let alt_elif = |i: &mut _| { let alt_elif = |i: &mut _| {
let mut p = ( let mut p = (
ws(keyword("elif").span()), ws(keyword("elif").span()),
cut_node(Some("if-elif"), |i: &mut _| CondTest::parse_cond(i, s)), cut_node(Some("if-elif"), CondTest::parse_cond),
); );
let (span, cond) = p.parse_next(i)?; let (span, cond) = p.parse_next(i)?;
Ok((span.clone(), Some(WithSpan::new(cond, span)))) Ok((span.clone(), Some(WithSpan::new(cond, span))))
}; };
let (_, pws, (span, cond), nws, _, nodes) = ( let (_, pws, (span, cond), nws, _, nodes) = (
|i: &mut _| s.tag_block_start(i), block_start,
opt(Whitespace::parse), opt(Whitespace::parse),
alt((alt_else, alt_elif)), alt((alt_else, alt_elif)),
opt(Whitespace::parse), opt(Whitespace::parse),
cut_node(Some("if"), |i: &mut _| s.tag_block_end(i)), cut_node(Some("if"), block_end),
cut_node(Some("if"), |i: &mut _| Node::many(i, s)), cut_node(Some("if"), Node::many),
) )
.parse_next(i)?; .parse_next(i)?;
@ -415,39 +398,37 @@ pub struct CondTest<'a> {
pub contains_bool_lit_or_is_defined: bool, pub contains_bool_lit_or_is_defined: bool,
} }
impl<'a> CondTest<'a> { impl<'a: 'l, 'l> CondTest<'a> {
fn parse(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, WithSpan<Self>> { fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, WithSpan<Self>> {
let mut p = ( let mut p = (
ws(keyword("if").span()), ws(keyword("if").span()),
cut_node(Some("if"), |i: &mut _| Self::parse_cond(i, s)), cut_node(Some("if"), Self::parse_cond),
); );
let (span, cond) = p.parse_next(i)?; let (span, cond) = p.parse_next(i)?;
Ok(WithSpan::new(cond, span)) Ok(WithSpan::new(cond, span))
} }
fn parse_cond(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, Self> { fn parse_cond(i: &mut InputStream<'a, 'l>) -> 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")))),
ws(|i: &mut _| Target::parse(i, s)), ws(Target::parse),
ws('='), ws('='),
)), )),
ws(|i: &mut InputStream<'a>| { ws(|i: &mut InputStream<'a, 'l>| {
let start_checkpoint = i.checkpoint(); let start_checkpoint = i.checkpoint();
let start_offset = i.current_token_start(); let start_offset = i.current_token_start();
let mut expr = Expr::parse(i, s.level, false)?; let mut expr = Expr::parse(i, false)?;
if let Expr::BinOp(v) = &mut *expr.inner if let Expr::BinOp(v) = &mut *expr.inner
&& matches!(*v.rhs.inner, Expr::Var("set" | "let")) && matches!(*v.rhs.inner, Expr::Var("set" | "let"))
{ {
let _level_guard = s.level.nest(i)?; let _level_guard = i.state.level.nest(i)?;
i.reset(&start_checkpoint); i.reset(&start_checkpoint);
i.next_slice(v.rhs.span.start - start_offset); i.next_slice(v.rhs.span.start - start_offset);
let (new_right, span) = (|i: &mut _| Self::parse_cond(i, s)) let (new_right, span) = Self::parse_cond.with_span().parse_next(i)?;
.with_span()
.parse_next(i)?;
v.rhs.inner = Box::new(Expr::LetCond(WithSpan::new(new_right, span))); v.rhs.inner = Box::new(Expr::LetCond(WithSpan::new(new_right, span)));
} }
Ok(expr) Ok(expr)
@ -474,7 +455,7 @@ pub enum Whitespace {
} }
impl Whitespace { impl Whitespace {
fn parse<'i>(i: &mut InputStream<'i>) -> ParseResult<'i, Self> { fn parse<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Self> {
any.verify_map(Self::parse_char).parse_next(i) any.verify_map(Self::parse_char).parse_next(i)
} }
@ -509,10 +490,9 @@ impl FromStr for Whitespace {
} }
} }
fn check_block_start<'a>( fn check_block_start<'a: 'l, 'l>(
i: &mut InputStream<'a>, i: &mut InputStream<'a, 'l>,
start: Span, start: Span,
s: &State<'_, '_>,
node: &str, node: &str,
expected: &str, expected: &str,
) -> ParseResult<'a, ()> { ) -> ParseResult<'a, ()> {
@ -522,7 +502,7 @@ fn check_block_start<'a>(
start, start,
); );
} }
(|i: &mut _| s.tag_block_start(i)).parse_next(i) i.state.syntax.block_start.void().parse_next(i)
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -537,15 +517,12 @@ pub struct Loop<'a> {
pub ws3: Ws, pub ws3: Ws,
} }
impl<'a> Loop<'a> { impl<'a: 'l, 'l> Loop<'a> {
fn parse(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, Box<Node<'a>>> { fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Node<'a>>> {
fn content<'a>( fn content<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Vec<Box<Node<'a>>>> {
i: &mut InputStream<'a>, i.state.enter_loop();
s: &State<'_, '_>, let result = Node::many(i);
) -> ParseResult<'a, Vec<Box<Node<'a>>>> { i.state.leave_loop();
s.enter_loop();
let result = (|i: &mut _| Node::many(i, s)).parse_next(i);
s.leave_loop();
result result
} }
@ -554,24 +531,17 @@ impl<'a> Loop<'a> {
let if_cond = preceded( let if_cond = preceded(
ws(keyword("if")), ws(keyword("if")),
cut_node( cut_node(Some("for-if"), ws(|i: &mut _| Expr::parse(i, true))),
Some("for-if"),
ws(|i: &mut _| Expr::parse(i, s.level, true)),
),
); );
let else_block = |i: &mut _| { let else_block = |i: &mut InputStream<'a, 'l>| {
let mut p = preceded( let mut p = preceded(
ws(keyword("else")), ws(keyword("else")),
cut_node( cut_node(
Some("for-else"), Some("for-else"),
( (
opt(Whitespace::parse), opt(Whitespace::parse),
delimited( delimited(block_end, Node::many, block_start),
|i: &mut _| s.tag_block_end(i),
|i: &mut _| Node::many(i, s),
|i: &mut _| s.tag_block_start(i),
),
opt(Whitespace::parse), opt(Whitespace::parse),
), ),
), ),
@ -584,11 +554,11 @@ impl<'a> Loop<'a> {
let (body, (_, pws, else_block, _, nws)) = cut_node( let (body, (_, pws, else_block, _, nws)) = cut_node(
Some("for"), Some("for"),
( (
|i: &mut _| content(i, s), content,
cut_node( cut_node(
Some("for"), Some("for"),
( (
|i: &mut _| check_block_start(i, span, s, "for", "endfor"), |i: &mut _| check_block_start(i, span, "for", "endfor"),
opt(Whitespace::parse), opt(Whitespace::parse),
opt(else_block), opt(else_block),
end_node("for", "endfor"), end_node("for", "endfor"),
@ -604,15 +574,15 @@ impl<'a> Loop<'a> {
let mut p = cut_node( let mut p = cut_node(
Some("for"), Some("for"),
( (
ws(|i: &mut _| Target::parse(i, s)), ws(Target::parse),
ws(keyword("in")), ws(keyword("in")),
cut_node( cut_node(
Some("for"), Some("for"),
( (
ws(|i: &mut _| Expr::parse(i, s.level, true)), ws(|i: &mut _| Expr::parse(i, true)),
opt(if_cond), opt(if_cond),
opt(Whitespace::parse), opt(Whitespace::parse),
|i: &mut _| s.tag_block_end(i), block_end,
body_and_end, body_and_end,
), ),
), ),
@ -664,8 +634,8 @@ fn check_duplicated_name<'a>(
Ok(()) Ok(())
} }
impl<'a> Macro<'a> { impl<'a: 'l, 'l> Macro<'a> {
fn parse(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, Box<Node<'a>>> { fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Node<'a>>> {
let (pws1, keyword_span, (name, name_span)) = ( let (pws1, keyword_span, (name, name_span)) = (
opt(Whitespace::parse), opt(Whitespace::parse),
ws(keyword("macro").span()), ws(keyword("macro").span()),
@ -683,10 +653,7 @@ impl<'a> Macro<'a> {
let macro_arg = |i: &mut _| { let macro_arg = |i: &mut _| {
let mut p = ( let mut p = (
ws(identifier.with_span()), ws(identifier.with_span()),
opt(preceded( opt(preceded('=', ws(|i: &mut _| Expr::parse(i, false)))),
'=',
ws(|i: &mut _| Expr::parse(i, s.level, false)),
)),
); );
let ((name, name_span), default) = p.parse_next(i)?; let ((name, name_span), default) = p.parse_next(i)?;
Ok(MacroArg { Ok(MacroArg {
@ -709,7 +676,7 @@ impl<'a> Macro<'a> {
let (params, nws1, _) = cut_node( let (params, nws1, _) = cut_node(
Some("macro"), Some("macro"),
(parameters, opt(Whitespace::parse), s.syntax.block_end), (parameters, opt(Whitespace::parse), block_end),
) )
.parse_next(i)?; .parse_next(i)?;
@ -745,11 +712,11 @@ impl<'a> Macro<'a> {
let mut end = cut_node( let mut end = cut_node(
Some("macro"), Some("macro"),
( (
|i: &mut _| Node::many(i, s), Node::many,
cut_node( cut_node(
Some("macro"), Some("macro"),
( (
|i: &mut _| check_block_start(i, keyword_span, s, "macro", "endmacro"), |i: &mut _| check_block_start(i, keyword_span, "macro", "endmacro"),
opt(Whitespace::parse), opt(Whitespace::parse),
end_node("macro", "endmacro"), end_node("macro", "endmacro"),
check_end_name(name, "macro"), check_end_name(name, "macro"),
@ -780,21 +747,19 @@ pub struct FilterBlock<'a> {
pub ws2: Ws, pub ws2: Ws,
} }
impl<'a> FilterBlock<'a> { impl<'a: 'l, 'l> FilterBlock<'a> {
fn parse(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, Box<Node<'a>>> { fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Node<'a>>> {
let (pws1, span) = (opt(Whitespace::parse), ws(keyword("filter").span())).parse_next(i)?; let (pws1, span) = (opt(Whitespace::parse), ws(keyword("filter").span())).parse_next(i)?;
let span = Span::new(span); let span = Span::new(span);
fn filters<'a>(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, Filter<'a>> { fn filters<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Filter<'a>> {
let mut filter = opt(ws(|i: &mut InputStream<'a>| filter(i, s.level)).with_span()); let mut filter = opt(ws(filter.with_span()));
let (mut res, span) = (|i: &mut _| Filter::parse(i, s.level)) let (mut res, span) = Filter::parse.with_span().parse_next(i)?;
.with_span()
.parse_next(i)?;
res.arguments res.arguments
.insert(0, WithSpan::new(Box::new(Expr::FilterSource), span)); .insert(0, WithSpan::new(Box::new(Expr::FilterSource), span));
let mut level_guard = s.level.guard(); let mut level_guard = i.state.level.guard();
let mut i_before = *i; let mut i_before = *i;
while let Some((mut filter, span)) = filter.parse_next(i)? { while let Some((mut filter, span)) = filter.parse_next(i)? {
level_guard.nest(&i_before)?; level_guard.nest(&i_before)?;
@ -810,17 +775,13 @@ impl<'a> FilterBlock<'a> {
let mut p = ( let mut p = (
cut_node( cut_node(
Some("filter"), Some("filter"),
( (ws(filters), opt(Whitespace::parse), block_end),
ws(|i: &mut _| filters(i, s)),
opt(Whitespace::parse),
|i: &mut _| s.tag_block_end(i),
),
), ),
cut_node(Some("filter"), |i: &mut _| Node::many(i, s)), cut_node(Some("filter"), Node::many),
cut_node( cut_node(
Some("filter"), Some("filter"),
( (
|i: &mut _| check_block_start(i, span, s, "filter", "endfilter"), |i: &mut _| check_block_start(i, span, "filter", "endfilter"),
opt(Whitespace::parse), opt(Whitespace::parse),
end_node("filter", "endfilter"), end_node("filter", "endfilter"),
opt(Whitespace::parse), opt(Whitespace::parse),
@ -848,8 +809,8 @@ pub struct Import<'a> {
pub scope: &'a str, pub scope: &'a str,
} }
impl<'a> Import<'a> { impl<'a: 'l, 'l> Import<'a> {
fn parse(i: &mut InputStream<'a>) -> ParseResult<'a, Box<Node<'a>>> { fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Node<'a>>> {
let mut p = ( let mut p = (
opt(Whitespace::parse), opt(Whitespace::parse),
ws(keyword("import").span()), ws(keyword("import").span()),
@ -885,8 +846,8 @@ pub struct Call<'a> {
pub ws2: Ws, pub ws2: Ws,
} }
impl<'a> Call<'a> { impl<'a: 'l, 'l> Call<'a> {
fn parse(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, Box<Node<'a>>> { fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Node<'a>>> {
let (pws, span) = (opt(Whitespace::parse), ws(keyword("call").span())).parse_next(i)?; let (pws, span) = (opt(Whitespace::parse), ws(keyword("call").span())).parse_next(i)?;
let keyword_span = Span::new(span); let keyword_span = Span::new(span);
@ -915,9 +876,9 @@ impl<'a> Call<'a> {
Ok(WithSpan::new(scope, span)) Ok(WithSpan::new(scope, span))
}), }),
ws(identifier.with_span()), ws(identifier.with_span()),
opt(ws(|nested: &mut _| Expr::arguments(nested, s.level))), opt(ws(Expr::arguments)),
opt(Whitespace::parse), opt(Whitespace::parse),
|i: &mut _| s.tag_block_end(i), block_end,
), ),
), ),
); );
@ -926,11 +887,11 @@ impl<'a> Call<'a> {
let mut end = cut_node( let mut end = cut_node(
Some("call"), Some("call"),
( (
|i: &mut _| Node::many(i, s), Node::many,
cut_node( cut_node(
Some("call"), Some("call"),
( (
|i: &mut _| check_block_start(i, keyword_span, s, "call", "endcall"), |i: &mut _| check_block_start(i, keyword_span, "call", "endcall"),
opt(Whitespace::parse), opt(Whitespace::parse),
end_node("call", "endcall"), end_node("call", "endcall"),
opt(Whitespace::parse), opt(Whitespace::parse),
@ -963,28 +924,28 @@ pub struct Match<'a> {
pub ws2: Ws, pub ws2: Ws,
} }
impl<'a> Match<'a> { impl<'a: 'l, 'l> Match<'a> {
fn parse(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, Box<Node<'a>>> { fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Node<'a>>> {
let (pws1, span) = (opt(Whitespace::parse), ws(keyword("match").span())).parse_next(i)?; let (pws1, span) = (opt(Whitespace::parse), ws(keyword("match").span())).parse_next(i)?;
let span = Span::new(span); let span = Span::new(span);
let mut p = cut_node( let mut p = cut_node(
Some("match"), Some("match"),
( (
ws(|i: &mut _| Expr::parse(i, s.level, false)), ws(|i: &mut _| Expr::parse(i, false)),
opt(Whitespace::parse), opt(Whitespace::parse),
|i: &mut _| s.tag_block_end(i), block_end,
cut_node( cut_node(
Some("match"), Some("match"),
( (
ws(repeat(0.., ws(|i: &mut _| Comment::parse(i, s)))).map(|()| ()), ws(repeat(0.., ws(Comment::parse))).map(|()| ()),
repeat(0.., |i: &mut _| When::when(i, s)).map(|v: Vec<_>| v), repeat(0.., When::when).map(|v: Vec<_>| v),
), ),
), ),
cut_node(Some("match"), opt(|i: &mut _| When::r#else(i, s))), cut_node(Some("match"), opt(When::r#else)),
cut_node( cut_node(
Some("match"), Some("match"),
( (
ws(|i: &mut _| check_block_start(i, span, s, "match", "endmatch")), ws(|i: &mut _| check_block_start(i, span, "match", "endmatch")),
opt(Whitespace::parse), opt(Whitespace::parse),
end_node("match", "endmatch"), end_node("match", "endmatch"),
opt(Whitespace::parse), opt(Whitespace::parse),
@ -1024,8 +985,8 @@ pub struct BlockDef<'a> {
pub ws2: Ws, pub ws2: Ws,
} }
impl<'a> BlockDef<'a> { impl<'a: 'l, 'l> BlockDef<'a> {
fn parse(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, Box<Node<'a>>> { fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Node<'a>>> {
let mut start = ( let mut start = (
opt(Whitespace::parse), opt(Whitespace::parse),
ws(keyword("block").span()), ws(keyword("block").span()),
@ -1034,7 +995,7 @@ impl<'a> BlockDef<'a> {
( (
ws(identifier.with_span()), ws(identifier.with_span()),
opt(Whitespace::parse), opt(Whitespace::parse),
|i: &mut _| s.tag_block_end(i), block_end,
), ),
), ),
); );
@ -1044,11 +1005,11 @@ impl<'a> BlockDef<'a> {
let mut end = cut_node( let mut end = cut_node(
Some("block"), Some("block"),
( (
|i: &mut _| Node::many(i, s), Node::many,
cut_node( cut_node(
Some("block"), Some("block"),
( (
|i: &mut _| check_block_start(i, keyword_span, s, "block", "endblock"), |i: &mut _| check_block_start(i, keyword_span, "block", "endblock"),
opt(Whitespace::parse), opt(Whitespace::parse),
end_node("block", "endblock"), end_node("block", "endblock"),
check_end_name(name, "block"), check_end_name(name, "block"),
@ -1070,11 +1031,11 @@ impl<'a> BlockDef<'a> {
} }
} }
fn check_end_name<'a>( fn check_end_name<'a: 'l, 'l>(
name: &'a str, name: &'a str,
kind: &'static str, kind: &'static str,
) -> impl ModalParser<InputStream<'a>, Option<Whitespace>, ErrorContext> { ) -> impl ModalParser<InputStream<'a, 'l>, Option<Whitespace>, ErrorContext> {
let name = move |i: &mut InputStream<'a>| { let name = move |i: &mut InputStream<'a, 'l>| {
let Some((end_name, span)) = ws(opt(identifier.with_span())).parse_next(i)? else { let Some((end_name, span)) = ws(opt(identifier.with_span())).parse_next(i)? else {
return Ok(()); return Ok(());
}; };
@ -1101,14 +1062,14 @@ pub struct Lit<'a> {
pub rws: WithSpan<&'a str>, pub rws: WithSpan<&'a str>,
} }
impl<'a> Lit<'a> { impl<'a: 'l, 'l> Lit<'a> {
fn parse(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, Box<Node<'a>>> { fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Node<'a>>> {
let content = take_until( let content = take_until(
.., ..,
( (
s.syntax.block_start, i.state.syntax.block_start,
s.syntax.comment_start, i.state.syntax.comment_start,
s.syntax.expr_start, i.state.syntax.expr_start,
), ),
); );
let (content, span) = preceded(not(eof), alt((content, rest))) let (content, span) = preceded(not(eof), alt((content, rest)))
@ -1153,11 +1114,10 @@ pub struct Raw<'a> {
pub ws2: Ws, pub ws2: Ws,
} }
impl<'a> Raw<'a> { impl<'a: 'l, 'l> Raw<'a> {
fn parse(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, Box<Node<'a>>> { fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Node<'a>>> {
fn endraw<'a>( fn endraw<'a: 'l, 'l>(
i: &mut InputStream<'a>, i: &mut InputStream<'a, 'l>,
s: &State<'_, '_>,
) -> ParseResult<'a, (Ws, WithSpan<Lit<'a>>)> { ) -> ParseResult<'a, (Ws, WithSpan<Lit<'a>>)> {
let start_i = ***i; let start_i = ***i;
let start_idx = i.current_token_start(); let start_idx = i.current_token_start();
@ -1178,7 +1138,7 @@ impl<'a> Raw<'a> {
(inner, None) (inner, None)
}; };
let Some(inner) = inner.strip_suffix(s.syntax.block_start) else { let Some(inner) = inner.strip_suffix(i.state.syntax.block_start) else {
continue; continue;
}; };
let span = start_idx..start_idx + inner.len(); let span = start_idx..start_idx + inner.len();
@ -1187,7 +1147,7 @@ impl<'a> Raw<'a> {
skip_ws0(i)?; skip_ws0(i)?;
let i_before_nws = i.checkpoint(); let i_before_nws = i.checkpoint();
let nws = opt(Whitespace::parse).parse_next(i)?; let nws = opt(Whitespace::parse).parse_next(i)?;
if opt(peek(s.syntax.block_end)).parse_next(i)?.is_none() { if opt(peek(block_end)).parse_next(i)?.is_none() {
i.reset(&i_before_nws); // `block_start` might start with the `nws` character i.reset(&i_before_nws); // `block_start` might start with the `nws` character
continue; continue;
} }
@ -1204,11 +1164,7 @@ impl<'a> Raw<'a> {
ws(keyword("raw").span()), ws(keyword("raw").span()),
cut_node( cut_node(
Some("raw"), Some("raw"),
separated_pair( separated_pair(opt(Whitespace::parse), block_end, endraw),
opt(Whitespace::parse),
|i: &mut _| s.tag_block_end(i),
|i: &mut _| endraw(i, s),
),
), ),
); );
let (pws, span, (nws, (ws2, lit))) = p.parse_next(i)?; let (pws, span, (nws, (ws2, lit))) = p.parse_next(i)?;
@ -1228,8 +1184,8 @@ pub struct Let<'a> {
pub is_mutable: bool, pub is_mutable: bool,
} }
impl<'a> Let<'a> { impl<'a: 'l, 'l> Let<'a> {
fn parse(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, Box<Node<'a>>> { fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Node<'a>>> {
let mut p = ( let mut p = (
opt(Whitespace::parse), opt(Whitespace::parse),
ws(alt((keyword("let"), keyword("set"))).span()), ws(alt((keyword("let"), keyword("set"))).span()),
@ -1237,11 +1193,8 @@ impl<'a> Let<'a> {
cut_node( cut_node(
Some("let"), Some("let"),
( (
ws((|i: &mut _| Target::parse(i, s)).with_span()), ws(Target::parse.with_span()),
opt(preceded( opt(preceded(ws('='), ws(|i: &mut _| Expr::parse(i, false)))),
ws('='),
ws(|i: &mut _| Expr::parse(i, s.level, false)),
)),
opt(Whitespace::parse), opt(Whitespace::parse),
), ),
), ),
@ -1300,15 +1253,14 @@ pub struct If<'a> {
pub branches: Vec<WithSpan<Cond<'a>>>, pub branches: Vec<WithSpan<Cond<'a>>>,
} }
impl<'a> If<'a> { impl<'a: 'l, 'l> If<'a> {
fn parse(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, Box<Node<'a>>> { fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Node<'a>>> {
let (pws1, cond) = let (pws1, cond) = (opt(Whitespace::parse), CondTest::parse).parse_next(i)?;
(opt(Whitespace::parse), (|i: &mut _| CondTest::parse(i, s))).parse_next(i)?;
let cond_span = cond.span; let cond_span = cond.span;
let end_if = cut_node( let end_if = cut_node(
Some("if"), Some("if"),
( (
|i: &mut _| check_block_start(i, cond_span, s, "if", "endif"), |i: &mut _| check_block_start(i, cond_span, "if", "endif"),
opt(Whitespace::parse), opt(Whitespace::parse),
end_node("if", "endif"), end_node("if", "endif"),
opt(Whitespace::parse), opt(Whitespace::parse),
@ -1318,12 +1270,12 @@ impl<'a> If<'a> {
Some("if"), Some("if"),
( (
opt(Whitespace::parse), opt(Whitespace::parse),
|i: &mut _| s.tag_block_end(i), block_end,
cut_node( cut_node(
Some("if"), Some("if"),
( (
|i: &mut _| Node::many(i, s), Node::many,
repeat(0.., |i: &mut _| Cond::parse(i, s)).map(|v: Vec<_>| v), repeat(0.., Cond::parse).map(|v: Vec<_>| v),
end_if, end_if,
), ),
), ),
@ -1357,8 +1309,8 @@ pub struct Include<'a> {
pub path: &'a str, pub path: &'a str,
} }
impl<'a> Include<'a> { impl<'a: 'l, 'l> Include<'a> {
fn parse(i: &mut InputStream<'a>) -> ParseResult<'a, Box<Node<'a>>> { fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Node<'a>>> {
let p = ( let p = (
opt(Whitespace::parse), opt(Whitespace::parse),
ws(keyword("include")), ws(keyword("include")),
@ -1383,8 +1335,8 @@ pub struct Extends<'a> {
pub path: &'a str, pub path: &'a str,
} }
impl<'a> Extends<'a> { impl<'a: 'l, 'l> Extends<'a> {
fn parse(i: &mut InputStream<'a>) -> ParseResult<'a, Box<Node<'a>>> { fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Node<'a>>> {
let p = preceded( let p = preceded(
(opt(Whitespace::parse), ws(keyword("extends"))), (opt(Whitespace::parse), ws(keyword("extends"))),
cut_node( cut_node(
@ -1403,18 +1355,22 @@ pub struct Comment<'a> {
pub content: &'a str, pub content: &'a str,
} }
impl<'a> Comment<'a> { impl<'a: 'l, 'l> Comment<'a> {
fn parse(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, Box<Node<'a>>> { fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Box<Node<'a>>> {
fn content<'a>(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, ()> { fn content<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, ()> {
let mut depth = 0usize; let mut depth = 0usize;
loop { loop {
take_until(.., (s.syntax.comment_start, s.syntax.comment_end)).parse_next(i)?; take_until(
let is_open = opt(s.syntax.comment_start).parse_next(i)?.is_some(); ..,
(i.state.syntax.comment_start, i.state.syntax.comment_end),
)
.parse_next(i)?;
let is_open = opt(i.state.syntax.comment_start).parse_next(i)?.is_some();
if is_open { if is_open {
// cannot overflow: `i` cannot be longer than `isize::MAX`, cf. [std::alloc::Layout] // cannot overflow: `i` cannot be longer than `isize::MAX`, cf. [std::alloc::Layout]
depth += 1; depth += 1;
} else if let Some(new_depth) = depth.checked_sub(1) { } else if let Some(new_depth) = depth.checked_sub(1) {
literal(s.syntax.comment_end).parse_next(i)?; literal(i.state.syntax.comment_end).parse_next(i)?;
depth = new_depth; depth = new_depth;
} else { } else {
return Ok(()); return Ok(());
@ -1422,19 +1378,18 @@ impl<'a> Comment<'a> {
} }
} }
fn comment<'a>(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a> { fn comment<'a: 'l, 'l>(i: &mut InputStream<'a, 'l>) -> ParseResult<'a> {
let start = s.syntax.comment_start.span().parse_next(i)?; let start = i.state.syntax.comment_start.span().parse_next(i)?;
let mut content = opt(terminated( let mut content = opt(terminated(content.take(), i.state.syntax.comment_end));
(|i: &mut _| content(i, s)).take(),
s.syntax.comment_end,
));
let Some(content) = content.parse_next(i)? else { let Some(content) = content.parse_next(i)? else {
return Err(ErrorContext::unclosed("comment", s.syntax.comment_end, start).cut()); return Err(
ErrorContext::unclosed("comment", i.state.syntax.comment_end, start).cut(),
);
}; };
Ok(content) Ok(content)
} }
let (content, span) = (|i: &mut _| comment(i, s)).with_span().parse_next(i)?; let (content, span) = comment.with_span().parse_next(i)?;
let ws = match *content.as_bytes() { let ws = match *content.as_bytes() {
[b'-' | b'+' | b'~'] => { [b'-' | b'+' | b'~'] => {
return cut_error!( return cut_error!(
@ -1442,7 +1397,7 @@ impl<'a> Comment<'a> {
"ambiguous whitespace stripping\n\ "ambiguous whitespace stripping\n\
use `{}{content} {content}{}` to apply the same whitespace stripping on \ use `{}{content} {content}{}` to apply the same whitespace stripping on \
both sides", both sides",
s.syntax.comment_start, s.syntax.comment_end, i.state.syntax.comment_start, i.state.syntax.comment_end,
), ),
span, span,
); );
@ -1463,11 +1418,11 @@ impl<'a> Comment<'a> {
#[derive(Clone, Copy, Debug, PartialEq)] #[derive(Clone, Copy, Debug, PartialEq)]
pub struct Ws(pub Option<Whitespace>, pub Option<Whitespace>); pub struct Ws(pub Option<Whitespace>, pub Option<Whitespace>);
fn end_node<'a, 'g: 'a>( fn end_node<'a: 'l, 'g: 'a, 'l>(
node: &'g str, node: &'g str,
expected: &'g str, expected: &'g str,
) -> impl ModalParser<InputStream<'a>, &'a str, ErrorContext> + 'g { ) -> impl ModalParser<InputStream<'a, 'l>, &'a str, ErrorContext> + 'g {
move |i: &mut InputStream<'a>| { move |i: &mut InputStream<'a, 'l>| {
let start = i.checkpoint(); let start = i.checkpoint();
let (actual, span) = ws(identifier.with_span()).parse_next(i)?; let (actual, span) = ws(identifier.with_span()).parse_next(i)?;
if actual == expected { if actual == expected {

View File

@ -6,8 +6,8 @@ use winnow::{ModalParser, Parser};
use crate::{ use crate::{
CharLit, ErrorContext, InputStream, Num, ParseErr, ParseResult, PathComponent, CharLit, ErrorContext, InputStream, Num, ParseErr, ParseResult, PathComponent,
PathOrIdentifier, Span, State, StrLit, WithSpan, bool_lit, can_be_variable_name, char_lit, PathOrIdentifier, Span, StrLit, WithSpan, bool_lit, can_be_variable_name, char_lit, cut_error,
cut_error, identifier, is_rust_keyword, keyword, num_lit, path_or_identifier, str_lit, ws, identifier, is_rust_keyword, keyword, num_lit, path_or_identifier, str_lit, ws,
}; };
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
@ -40,7 +40,7 @@ impl<'a> From<(WithSpan<&'a str>, Target<'a>)> for NamedTarget<'a> {
} }
} }
impl<'a> Target<'a> { impl<'a: 'l, 'l> Target<'a> {
pub fn span(&self) -> Span { pub fn span(&self) -> Span {
match self { match self {
Target::Name(v) => v.span(), Target::Name(v) => v.span(),
@ -59,17 +59,15 @@ impl<'a> Target<'a> {
} }
/// Parses multiple targets with `or` separating them /// Parses multiple targets with `or` separating them
pub(super) fn parse(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, Self> { pub(super) fn parse(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Self> {
enum OneOrMany<'a> { enum OneOrMany<'a> {
One(Target<'a>), One(Target<'a>),
Many(Vec<Target<'a>>), Many(Vec<Target<'a>>),
} }
let mut or_more = opt(preceded(ws(keyword("or")), |i: &mut _| { let mut or_more = opt(preceded(ws(keyword("or")), Self::parse_one));
Self::parse_one(i, s)
}));
let one_or_many = |i: &mut _| { let one_or_many = |i: &mut _| {
let target = Self::parse_one(i, s)?; let target = Self::parse_one(i)?;
let Some(snd_target) = or_more.parse_next(i)? else { let Some(snd_target) = or_more.parse_next(i)? else {
return Ok(OneOrMany::One(target)); return Ok(OneOrMany::One(target));
}; };
@ -81,7 +79,7 @@ impl<'a> Target<'a> {
Ok(OneOrMany::Many(targets)) Ok(OneOrMany::Many(targets))
}; };
let _level_guard = s.level.nest(i)?; let _level_guard = i.state.level.nest(i)?;
let (inner, span) = one_or_many.with_span().parse_next(i)?; let (inner, span) = one_or_many.with_span().parse_next(i)?;
match inner { match inner {
OneOrMany::One(target) => Ok(target), OneOrMany::One(target) => Ok(target),
@ -90,7 +88,7 @@ impl<'a> Target<'a> {
} }
/// 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 InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, Self> { fn parse_one(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Self> {
let mut opt_opening_paren = opt(ws('(').span()).map(|o| o.is_some()); let mut opt_opening_paren = opt(ws('(').span()).map(|o| o.is_some());
let mut opt_opening_brace = opt(ws('{').span()).map(|o| o.is_some()); let mut opt_opening_brace = opt(ws('{').span()).map(|o| o.is_some());
let mut opt_opening_bracket = opt(ws('[').span()).map(|o| o.is_some()); let mut opt_opening_bracket = opt(ws('[').span()).map(|o| o.is_some());
@ -105,8 +103,7 @@ impl<'a> Target<'a> {
// match tuples // match tuples
let target_is_tuple = opt_opening_paren.parse_next(i)?; let target_is_tuple = opt_opening_paren.parse_next(i)?;
if target_is_tuple { if target_is_tuple {
let (is_singleton, mut targets) = let (is_singleton, mut targets) = collect_targets(i, ')', Self::unnamed)?;
collect_targets(i, ')', |i: &mut _| Self::unnamed(i, s))?;
if is_singleton && let Some(target) = targets.pop() { if is_singleton && let Some(target) = targets.pop() {
return Ok(target); return Ok(target);
} }
@ -119,14 +116,14 @@ impl<'a> Target<'a> {
// match array // match array
let target_is_array = opt_opening_bracket.parse_next(i)?; let target_is_array = opt_opening_bracket.parse_next(i)?;
if target_is_array { if target_is_array {
let targets = collect_targets(i, ']', |i: &mut _| Self::unnamed(i, s))?.1; let targets = collect_targets(i, ']', Self::unnamed)?.1;
let inner = only_one_rest_pattern(targets, true, "array")?; let inner = only_one_rest_pattern(targets, true, "array")?;
let range = start..i.current_token_start(); let range = start..i.current_token_start();
return Ok(Self::Array(WithSpan::new(inner, range))); return Ok(Self::Array(WithSpan::new(inner, range)));
} }
// match structs // match structs
let path = (|i: &mut _| path_or_identifier(i, s.level)).verify_map(|r| match r { let path = path_or_identifier.verify_map(|r| match r {
PathOrIdentifier::Path(v) => Some(v), PathOrIdentifier::Path(v) => Some(v),
PathOrIdentifier::Identifier(_) => None, PathOrIdentifier::Identifier(_) => None,
}); });
@ -137,14 +134,14 @@ impl<'a> Target<'a> {
let is_unnamed_struct = opt_opening_paren.parse_next(i)?; let is_unnamed_struct = opt_opening_paren.parse_next(i)?;
if is_unnamed_struct { if is_unnamed_struct {
let targets = collect_targets(i, ')', |i: &mut _| Self::unnamed(i, s))?.1; let targets = collect_targets(i, ')', Self::unnamed)?.1;
let inner = only_one_rest_pattern(targets, false, "struct")?; let inner = only_one_rest_pattern(targets, false, "struct")?;
return Ok(Self::Tuple(WithSpan::new((path, inner), path_span))); return Ok(Self::Tuple(WithSpan::new((path, inner), path_span)));
} }
let is_named_struct = opt_opening_brace.parse_next(i)?; let is_named_struct = opt_opening_brace.parse_next(i)?;
if is_named_struct { if is_named_struct {
let targets = collect_targets(i, '}', |i: &mut _| Self::named(i, s))?.1; let targets = collect_targets(i, '}', Self::named)?.1;
return Ok(Self::Struct(WithSpan::new((path, targets), path_span))); return Ok(Self::Struct(WithSpan::new((path, targets), path_span)));
} }
@ -184,7 +181,7 @@ impl<'a> Target<'a> {
} }
} }
fn lit(i: &mut InputStream<'a>) -> ParseResult<'a, Self> { fn lit(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Self> {
enum Lit<'a> { enum Lit<'a> {
Str(StrLit<'a>), Str(StrLit<'a>),
Bool(&'a str), Bool(&'a str),
@ -208,13 +205,12 @@ impl<'a> Target<'a> {
} }
} }
fn unnamed(i: &mut InputStream<'a>, s: &State<'_, '_>) -> ParseResult<'a, Self> { fn unnamed(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Self> {
alt((Self::rest, |i: &mut _| Self::parse(i, s))).parse_next(i) alt((Self::rest, Self::parse)).parse_next(i)
} }
fn named<O: From<(WithSpan<&'a str>, Self)>>( fn named<O: From<(WithSpan<&'a str>, Self)>>(
i: &mut InputStream<'a>, i: &mut InputStream<'a, 'l>,
s: &State<'_, '_>,
) -> ParseResult<'a, O> { ) -> ParseResult<'a, O> {
if let Some(rest) = opt(Self::rest_inner).parse_next(i)? { if let Some(rest) = opt(Self::rest_inner).parse_next(i)? {
let chr = peek(ws(opt(one_of([',', ':']).with_span()))).parse_next(i)?; let chr = peek(ws(opt(one_of([',', ':']).with_span()))).parse_next(i)?;
@ -233,11 +229,8 @@ impl<'a> Target<'a> {
} }
Ok((WithSpan::new("..", rest.span), Target::Rest(rest)).into()) Ok((WithSpan::new("..", rest.span), Target::Rest(rest)).into())
} else { } else {
let ((src, span), target) = ( let ((src, span), target) =
identifier.with_span(), (identifier.with_span(), opt(preceded(ws(':'), Self::parse))).parse_next(i)?;
opt(preceded(ws(':'), |i: &mut _| Self::parse(i, s))),
)
.parse_next(i)?;
let src = WithSpan::new(src, span); let src = WithSpan::new(src, span);
if *src == "_" { if *src == "_" {
@ -255,11 +248,13 @@ impl<'a> Target<'a> {
} }
} }
fn rest(i: &mut InputStream<'a>) -> ParseResult<'a, Self> { fn rest(i: &mut InputStream<'a, 'l>) -> ParseResult<'a, Self> {
Self::rest_inner.map(Self::Rest).parse_next(i) Self::rest_inner.map(Self::Rest).parse_next(i)
} }
fn rest_inner(i: &mut InputStream<'a>) -> ParseResult<'a, WithSpan<Option<WithSpan<&'a str>>>> { fn rest_inner(
i: &mut InputStream<'a, 'l>,
) -> ParseResult<'a, WithSpan<Option<WithSpan<&'a str>>>> {
let p = |i: &mut _| { let p = |i: &mut _| {
let id = let id =
terminated(opt(terminated(identifier.with_span(), ws('@'))), "..").parse_next(i)?; terminated(opt(terminated(identifier.with_span(), ws('@'))), "..").parse_next(i)?;
@ -297,10 +292,10 @@ fn verify_name<'a>(name: WithSpan<&'a str>) -> Result<Target<'a>, ErrMode<ErrorC
} }
} }
fn collect_targets<'a, T>( fn collect_targets<'a: 'l, 'l, T>(
i: &mut InputStream<'a>, i: &mut InputStream<'a, 'l>,
delim: char, delim: char,
one: impl ModalParser<InputStream<'a>, T, ErrorContext>, one: impl ModalParser<InputStream<'a, 'l>, T, ErrorContext>,
) -> ParseResult<'a, (bool, Vec<T>)> { ) -> ParseResult<'a, (bool, Vec<T>)> {
let opt_comma = ws(opt(',')).map(|o| o.is_some()); let opt_comma = ws(opt(',')).map(|o| o.is_some());
let mut opt_end = ws(opt(one_of(delim))).map(|o| o.is_some()); let mut opt_end = ws(opt(one_of(delim))).map(|o| o.is_some());

View File

@ -1,10 +1,12 @@
use std::cell::Cell;
use winnow::{LocatingSlice, Parser}; use winnow::{LocatingSlice, Parser};
use crate::expr::BinOp; use crate::expr::BinOp;
use crate::node::{Let, Lit, Raw, Whitespace, Ws}; use crate::node::{Let, Lit, Raw, Whitespace, Ws};
use crate::{ use crate::{
Ast, Expr, Filter, InnerSyntax, InputStream, Node, Num, PathComponent, PathOrIdentifier, Ast, Expr, Filter, InnerSyntax, InputStream, Level, Node, Num, PathComponent, PathOrIdentifier,
StrLit, Syntax, SyntaxBuilder, Target, WithSpan, State, StrLit, Syntax, SyntaxBuilder, Target, WithSpan,
}; };
fn as_path<'a>(path: &'a [&'a str]) -> Vec<PathComponent<'a>> { fn as_path<'a>(path: &'a [&'a str]) -> Vec<PathComponent<'a>> {
@ -36,7 +38,8 @@ fn test_ws_splitter() {
#[test] #[test]
#[should_panic] #[should_panic]
fn test_invalid_block() { fn test_invalid_block() {
Ast::from_str("{% extend \"blah\" %}", None, &Syntax::default()).unwrap(); let syntax = Syntax::default();
Ast::from_str("{% extend \"blah\" %}", None, &syntax).unwrap();
} }
fn int_lit<'a>(i: &'a str) -> WithSpan<Box<Expr<'a>>> { fn int_lit<'a>(i: &'a str) -> WithSpan<Box<Expr<'a>>> {
@ -133,17 +136,17 @@ fn test_parse_numbers() {
#[test] #[test]
fn test_parse_var() { fn test_parse_var() {
let s = Syntax::default(); let syntax = Syntax::default();
assert_eq!( assert_eq!(
Ast::from_str("{{ foo }}", None, &s).unwrap().nodes, Ast::from_str("{{ foo }}", None, &syntax).unwrap().nodes,
[Box::new(Node::Expr( [Box::new(Node::Expr(
Ws(None, None), Ws(None, None),
WithSpan::no_span(Box::new(Expr::Var("foo"))) WithSpan::no_span(Box::new(Expr::Var("foo")))
))] ))]
); );
assert_eq!( assert_eq!(
Ast::from_str("{{ foo_bar }}", None, &s).unwrap().nodes, Ast::from_str("{{ foo_bar }}", None, &syntax).unwrap().nodes,
[Box::new(Node::Expr( [Box::new(Node::Expr(
Ws(None, None), Ws(None, None),
WithSpan::no_span(Box::new(Expr::Var("foo_bar"))) WithSpan::no_span(Box::new(Expr::Var("foo_bar")))
@ -151,7 +154,7 @@ fn test_parse_var() {
); );
assert_eq!( assert_eq!(
Ast::from_str("{{ none }}", None, &s).unwrap().nodes, Ast::from_str("{{ none }}", None, &syntax).unwrap().nodes,
[Box::new(Node::Expr( [Box::new(Node::Expr(
Ws(None, None), Ws(None, None),
WithSpan::no_span(Box::new(Expr::Var("none"))) WithSpan::no_span(Box::new(Expr::Var("none")))
@ -161,17 +164,17 @@ fn test_parse_var() {
#[test] #[test]
fn test_parse_const() { fn test_parse_const() {
let s = Syntax::default(); let syntax = Syntax::default();
assert_eq!( assert_eq!(
Ast::from_str("{{ FOO }}", None, &s).unwrap().nodes, Ast::from_str("{{ FOO }}", None, &syntax).unwrap().nodes,
[Box::new(Node::Expr( [Box::new(Node::Expr(
Ws(None, None), Ws(None, None),
WithSpan::no_span(Box::new(Expr::Path(as_path(&["FOO"])))) WithSpan::no_span(Box::new(Expr::Path(as_path(&["FOO"]))))
))] ))]
); );
assert_eq!( assert_eq!(
Ast::from_str("{{ FOO_BAR }}", None, &s).unwrap().nodes, Ast::from_str("{{ FOO_BAR }}", None, &syntax).unwrap().nodes,
[Box::new(Node::Expr( [Box::new(Node::Expr(
Ws(None, None), Ws(None, None),
WithSpan::no_span(Box::new(Expr::Path(as_path(&["FOO_BAR"])))) WithSpan::no_span(Box::new(Expr::Path(as_path(&["FOO_BAR"]))))
@ -179,7 +182,7 @@ fn test_parse_const() {
); );
assert_eq!( assert_eq!(
Ast::from_str("{{ NONE }}", None, &s).unwrap().nodes, Ast::from_str("{{ NONE }}", None, &syntax).unwrap().nodes,
[Box::new(Node::Expr( [Box::new(Node::Expr(
Ws(None, None), Ws(None, None),
WithSpan::no_span(Box::new(Expr::Path(as_path(&["NONE"])))) WithSpan::no_span(Box::new(Expr::Path(as_path(&["NONE"]))))
@ -189,17 +192,19 @@ fn test_parse_const() {
#[test] #[test]
fn test_parse_path() { fn test_parse_path() {
let s = Syntax::default(); let syntax = Syntax::default();
assert_eq!( assert_eq!(
Ast::from_str("{{ None }}", None, &s).unwrap().nodes, Ast::from_str("{{ None }}", None, &syntax).unwrap().nodes,
[Box::new(Node::Expr( [Box::new(Node::Expr(
Ws(None, None), Ws(None, None),
WithSpan::no_span(Box::new(Expr::Path(as_path(&["None"])))), WithSpan::no_span(Box::new(Expr::Path(as_path(&["None"])))),
))] ))]
); );
assert_eq!( assert_eq!(
Ast::from_str("{{ Some(123) }}", None, &s).unwrap().nodes, Ast::from_str("{{ Some(123) }}", None, &syntax)
.unwrap()
.nodes,
[Box::new(Node::Expr( [Box::new(Node::Expr(
Ws(None, None), Ws(None, None),
call( call(
@ -210,7 +215,7 @@ fn test_parse_path() {
); );
assert_eq!( assert_eq!(
Ast::from_str("{{ Ok(123) }}", None, &s).unwrap().nodes, Ast::from_str("{{ Ok(123) }}", None, &syntax).unwrap().nodes,
[Box::new(Node::Expr( [Box::new(Node::Expr(
Ws(None, None), Ws(None, None),
call( call(
@ -220,7 +225,9 @@ fn test_parse_path() {
))], ))],
); );
assert_eq!( assert_eq!(
Ast::from_str("{{ Err(123) }}", None, &s).unwrap().nodes, Ast::from_str("{{ Err(123) }}", None, &syntax)
.unwrap()
.nodes,
[Box::new(Node::Expr( [Box::new(Node::Expr(
Ws(None, None), Ws(None, None),
call( call(
@ -233,8 +240,10 @@ fn test_parse_path() {
#[test] #[test]
fn test_parse_var_call() { fn test_parse_var_call() {
let syntax = Syntax::default();
assert_eq!( assert_eq!(
Ast::from_str("{{ function(\"123\", 3) }}", None, &Syntax::default()) Ast::from_str("{{ function(\"123\", 3) }}", None, &syntax)
.unwrap() .unwrap()
.nodes, .nodes,
[Box::new(Node::Expr( [Box::new(Node::Expr(
@ -259,17 +268,19 @@ fn test_parse_var_call() {
#[test] #[test]
fn test_parse_path_call() { fn test_parse_path_call() {
let s = Syntax::default(); let syntax = Syntax::default();
assert_eq!( assert_eq!(
Ast::from_str("{{ Option::None }}", None, &s).unwrap().nodes, Ast::from_str("{{ Option::None }}", None, &syntax)
.unwrap()
.nodes,
[Box::new(Node::Expr( [Box::new(Node::Expr(
Ws(None, None), Ws(None, None),
WithSpan::no_span(Box::new(Expr::Path(as_path(&["Option", "None"])))), WithSpan::no_span(Box::new(Expr::Path(as_path(&["Option", "None"])))),
))], ))],
); );
assert_eq!( assert_eq!(
Ast::from_str("{{ Option::Some(123) }}", None, &s) Ast::from_str("{{ Option::Some(123) }}", None, &syntax)
.unwrap() .unwrap()
.nodes, .nodes,
[Box::new(Node::Expr( [Box::new(Node::Expr(
@ -282,7 +293,7 @@ fn test_parse_path_call() {
); );
assert_eq!( assert_eq!(
Ast::from_str("{{ self::function(\"123\", 3) }}", None, &s) Ast::from_str("{{ self::function(\"123\", 3) }}", None, &syntax)
.unwrap() .unwrap()
.nodes, .nodes,
[Box::new(Node::Expr( [Box::new(Node::Expr(
@ -741,8 +752,8 @@ fn test_odd_calls() {
fn test_parse_comments() { fn test_parse_comments() {
#[track_caller] #[track_caller]
fn one_comment_ws(source: &str, ws: Ws) { fn one_comment_ws(source: &str, ws: Ws) {
let s = &Syntax::default(); let syntax = Syntax::default();
let mut nodes = Ast::from_str(source, None, s).unwrap().nodes; let mut nodes = Ast::from_str(source, None, &syntax).unwrap().nodes;
assert_eq!(nodes.len(), 1, "expected to parse one node"); assert_eq!(nodes.len(), 1, "expected to parse one node");
match *nodes.pop().unwrap() { match *nodes.pop().unwrap() {
Node::Comment(comment) => assert_eq!(comment.ws, ws), Node::Comment(comment) => assert_eq!(comment.ws, ws),
@ -1055,10 +1066,12 @@ fn fuzzed_unary_recursion() {
#[test] #[test]
fn fuzzed_comment_depth() { fn fuzzed_comment_depth() {
let syntax = Syntax::default();
let (sender, receiver) = std::sync::mpsc::channel(); let (sender, receiver) = std::sync::mpsc::channel();
let test = std::thread::spawn(move || { let test = std::thread::spawn(move || {
const TEMPLATE: &str = include_str!("../tests/comment-depth.txt"); const TEMPLATE: &str = include_str!("../tests/comment-depth.txt");
assert!(Ast::from_str(TEMPLATE, None, &Syntax::default()).is_ok()); assert!(Ast::from_str(TEMPLATE, None, &syntax).is_ok());
sender.send(()).unwrap(); sender.send(()).unwrap();
}); });
receiver receiver
@ -1069,13 +1082,10 @@ fn fuzzed_comment_depth() {
#[test] #[test]
fn let_set() { fn let_set() {
let syntax = Syntax::default();
assert_eq!( assert_eq!(
Ast::from_str("{% let a %}", None, &Syntax::default()) Ast::from_str("{% let a %}", None, &syntax).unwrap().nodes(),
.unwrap() Ast::from_str("{% set a %}", None, &syntax).unwrap().nodes(),
.nodes(),
Ast::from_str("{% set a %}", None, &Syntax::default())
.unwrap()
.nodes(),
); );
} }
@ -1181,110 +1191,35 @@ fn fuzzed_excessive_filter_block() {
#[test] #[test]
fn test_generics_parsing() { fn test_generics_parsing() {
let syntax = Syntax::default();
// Method call. // Method call.
Ast::from_str("{{ a.b::<&str, H<B<C>>>() }}", None, &Syntax::default()).unwrap(); Ast::from_str("{{ a.b::<&str, H<B<C>>>() }}", None, &syntax).unwrap();
Ast::from_str( Ast::from_str("{{ a.b::<&str, H<B<C> , &u32>>() }}", None, &syntax).unwrap();
"{{ a.b::<&str, H<B<C> , &u32>>() }}",
None,
&Syntax::default(),
)
.unwrap();
// Call. // Call.
Ast::from_str( Ast::from_str("{{ a::<&str, H<B<C> , &u32>>() }}", None, &syntax).unwrap();
"{{ a::<&str, H<B<C> , &u32>>() }}",
None,
&Syntax::default(),
)
.unwrap();
// Filter. // Filter.
Ast::from_str("{{ 12 | a::<&str> }}", None, &Syntax::default()).unwrap(); Ast::from_str("{{ 12 | a::<&str> }}", None, &syntax).unwrap();
Ast::from_str("{{ 12 | a::<&str, u32>('a') }}", None, &Syntax::default()).unwrap(); Ast::from_str("{{ 12 | a::<&str, u32>('a') }}", None, &syntax).unwrap();
// Unclosed `<`. // Unclosed `<`.
assert!( assert!(Ast::from_str("{{ a.b::<&str, H<B<C> , &u32>() }}", None, &syntax).is_err());
Ast::from_str(
"{{ a.b::<&str, H<B<C> , &u32>() }}",
None,
&Syntax::default()
)
.is_err()
);
// With path and spaces // With path and spaces
Ast::from_str( Ast::from_str("{{ a.b::<&&core::primitive::str>() }}", None, &syntax).unwrap();
"{{ a.b::<&&core::primitive::str>() }}", Ast::from_str("{{ a.b ::<&&core::primitive::str>() }}", None, &syntax).unwrap();
None, Ast::from_str("{{ a.b:: <&&core::primitive::str>() }}", None, &syntax).unwrap();
&Syntax::default(), Ast::from_str("{{ a.b::< &&core::primitive::str>() }}", None, &syntax).unwrap();
) Ast::from_str("{{ a.b::<& &core::primitive::str>() }}", None, &syntax).unwrap();
.unwrap(); Ast::from_str("{{ a.b::<&& core::primitive::str>() }}", None, &syntax).unwrap();
Ast::from_str( Ast::from_str("{{ a.b::<&&core ::primitive::str>() }}", None, &syntax).unwrap();
"{{ a.b ::<&&core::primitive::str>() }}", Ast::from_str("{{ a.b::<&&core:: primitive::str>() }}", None, &syntax).unwrap();
None, Ast::from_str("{{ a.b::<&&core::primitive ::str>() }}", None, &syntax).unwrap();
&Syntax::default(), Ast::from_str("{{ a.b::<&&core::primitive:: str>() }}", None, &syntax).unwrap();
) Ast::from_str("{{ a.b::<&&core::primitive::str >() }}", None, &syntax).unwrap();
.unwrap(); Ast::from_str("{{ a.b::<&&core::primitive::str> () }}", None, &syntax).unwrap();
Ast::from_str(
"{{ a.b:: <&&core::primitive::str>() }}",
None,
&Syntax::default(),
)
.unwrap();
Ast::from_str(
"{{ a.b::< &&core::primitive::str>() }}",
None,
&Syntax::default(),
)
.unwrap();
Ast::from_str(
"{{ a.b::<& &core::primitive::str>() }}",
None,
&Syntax::default(),
)
.unwrap();
Ast::from_str(
"{{ a.b::<&& core::primitive::str>() }}",
None,
&Syntax::default(),
)
.unwrap();
Ast::from_str(
"{{ a.b::<&&core ::primitive::str>() }}",
None,
&Syntax::default(),
)
.unwrap();
Ast::from_str(
"{{ a.b::<&&core:: primitive::str>() }}",
None,
&Syntax::default(),
)
.unwrap();
Ast::from_str(
"{{ a.b::<&&core::primitive ::str>() }}",
None,
&Syntax::default(),
)
.unwrap();
Ast::from_str(
"{{ a.b::<&&core::primitive:: str>() }}",
None,
&Syntax::default(),
)
.unwrap();
Ast::from_str(
"{{ a.b::<&&core::primitive::str >() }}",
None,
&Syntax::default(),
)
.unwrap();
Ast::from_str(
"{{ a.b::<&&core::primitive::str> () }}",
None,
&Syntax::default(),
)
.unwrap();
} }
#[test] #[test]
@ -1365,9 +1300,14 @@ fn test_filter_with_path() {
#[test] #[test]
fn underscore_is_an_identifier() { fn underscore_is_an_identifier() {
let state = State {
syntax: Syntax::default(),
loop_depth: Cell::new(0),
level: Level::default(),
};
let mut input = InputStream { let mut input = InputStream {
input: LocatingSlice::new("_"), input: LocatingSlice::new("_"),
state: (), state: &state,
}; };
let result = crate::identifier.parse_next(&mut input); let result = crate::identifier.parse_next(&mut input);
assert_eq!(result.unwrap(), "_"); assert_eq!(result.unwrap(), "_");
@ -1512,6 +1452,7 @@ fn macro_comments_in_macro_calls() {
#[test] #[test]
fn test_raw() { fn test_raw() {
let syntax = Syntax::default(); let syntax = Syntax::default();
let val = "hello {{ endraw %} my {%* endraw %} green {% endraw }} world"; let val = "hello {{ endraw %} my {%* endraw %} green {% endraw }} world";
assert_eq!( assert_eq!(
Ast::from_str( Ast::from_str(