mirror of
https://github.com/askama-rs/askama.git
synced 2025-09-27 13:00:57 +00:00
parser: make State
part of InputStream
This commit is contained in:
parent
e5189b933d
commit
81252cd0a2
@ -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)
|
|
||||||
}
|
}
|
||||||
|
@ -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]
|
||||||
|
@ -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 {
|
||||||
|
@ -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());
|
||||||
|
@ -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(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user