parser: introduce askama_parser::expr::Range

This commit is contained in:
René Kijewski 2025-06-23 18:11:28 +02:00 committed by René Kijewski
parent 9f882e2ca7
commit 49d4397f51
3 changed files with 30 additions and 17 deletions

View File

@ -76,8 +76,8 @@ impl<'a> Generator<'a, '_> {
}) => self.visit_filter(ctx, buf, name, arguments, generics, expr.span())?, }) => self.visit_filter(ctx, buf, name, arguments, generics, expr.span())?,
Expr::Unary(op, ref inner) => self.visit_unary(ctx, buf, op, inner)?, Expr::Unary(op, ref inner) => self.visit_unary(ctx, buf, op, inner)?,
Expr::BinOp(ref v) => self.visit_binop(ctx, buf, v.op, &v.lhs, &v.rhs)?, Expr::BinOp(ref v) => self.visit_binop(ctx, buf, v.op, &v.lhs, &v.rhs)?,
Expr::Range(op, ref left, ref right) => { Expr::Range(ref v) => {
self.visit_range(ctx, buf, op, left.as_deref(), right.as_deref())? self.visit_range(ctx, buf, v.op, v.lhs.as_ref(), v.rhs.as_ref())?
} }
Expr::Group(ref inner) => self.visit_group(ctx, buf, inner)?, Expr::Group(ref inner) => self.visit_group(ctx, buf, inner)?,
Expr::Call { Expr::Call {

View File

@ -199,7 +199,7 @@ impl<'a> Generator<'a, '_> {
| Expr::Attr(_, _) | Expr::Attr(_, _)
| Expr::Index(_, _) | Expr::Index(_, _)
| Expr::Filter(_) | Expr::Filter(_)
| Expr::Range(_, _, _) | Expr::Range(_)
| Expr::Call { .. } | Expr::Call { .. }
| Expr::RustMacro(_, _) | Expr::RustMacro(_, _)
| Expr::Try(_) | Expr::Try(_)
@ -1649,9 +1649,8 @@ fn is_cacheable(expr: &WithSpan<'_, Expr<'_>>) -> bool {
Expr::Unary(_, arg) => is_cacheable(arg), Expr::Unary(_, arg) => is_cacheable(arg),
Expr::BinOp(v) => is_cacheable(&v.lhs) && is_cacheable(&v.rhs), Expr::BinOp(v) => is_cacheable(&v.lhs) && is_cacheable(&v.rhs),
Expr::IsDefined(_) | Expr::IsNotDefined(_) => true, Expr::IsDefined(_) | Expr::IsNotDefined(_) => true,
Expr::Range(_, lhs, rhs) => { Expr::Range(v) => {
lhs.as_ref().is_none_or(|v| is_cacheable(v)) v.lhs.as_ref().is_none_or(is_cacheable) && v.rhs.as_ref().is_none_or(is_cacheable)
&& rhs.as_ref().is_none_or(|v| is_cacheable(v))
} }
Expr::Group(arg) => is_cacheable(arg), Expr::Group(arg) => is_cacheable(arg),
Expr::Tuple(args) => args.iter().all(is_cacheable), Expr::Tuple(args) => args.iter().all(is_cacheable),

View File

@ -101,11 +101,11 @@ fn check_expr<'a>(expr: &WithSpan<'a, Expr<'a>>, allowed: Allowed) -> Result<(),
check_expr(&v.lhs, Allowed::default())?; check_expr(&v.lhs, Allowed::default())?;
check_expr(&v.rhs, Allowed::default()) check_expr(&v.rhs, Allowed::default())
} }
Expr::Range(_, elem1, elem2) => { Expr::Range(v) => {
if let Some(elem1) = elem1 { if let Some(elem1) = v.lhs.as_ref() {
check_expr(elem1, Allowed::default())?; check_expr(elem1, Allowed::default())?;
} }
if let Some(elem2) = elem2 { if let Some(elem2) = v.rhs.as_ref() {
check_expr(elem2, Allowed::default())?; check_expr(elem2, Allowed::default())?;
} }
Ok(()) Ok(())
@ -170,11 +170,7 @@ pub enum Expr<'a> {
NamedArgument(&'a str, Box<WithSpan<'a, Expr<'a>>>), NamedArgument(&'a str, Box<WithSpan<'a, Expr<'a>>>),
Unary(&'a str, Box<WithSpan<'a, Expr<'a>>>), Unary(&'a str, Box<WithSpan<'a, Expr<'a>>>),
BinOp(Box<BinOp<'a>>), BinOp(Box<BinOp<'a>>),
Range( Range(Box<Range<'a>>),
&'a str,
Option<Box<WithSpan<'a, Expr<'a>>>>,
Option<Box<WithSpan<'a, Expr<'a>>>>,
),
Group(Box<WithSpan<'a, Expr<'a>>>), Group(Box<WithSpan<'a, Expr<'a>>>),
Tuple(Vec<WithSpan<'a, Expr<'a>>>), Tuple(Vec<WithSpan<'a, Expr<'a>>>),
Call { Call {
@ -196,6 +192,13 @@ pub enum Expr<'a> {
ArgumentPlaceholder, ArgumentPlaceholder,
} }
#[derive(Clone, Debug, PartialEq)]
pub struct Range<'a> {
pub op: &'a str,
pub lhs: Option<WithSpan<'a, Expr<'a>>>,
pub rhs: Option<WithSpan<'a, Expr<'a>>>,
}
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct BinOp<'a> { pub struct BinOp<'a> {
pub op: &'a str, pub op: &'a str,
@ -300,12 +303,23 @@ impl<'a> Expr<'a> {
}; };
let expr = alt(( let expr = alt((
range_right.map(move |(op, right)| { range_right.map(move |(op, right)| {
WithSpan::new(Self::Range(op, None, right.map(Box::new)), start) WithSpan::new(
Self::Range(Box::new(Range {
op,
lhs: None,
rhs: right,
})),
start,
)
}), }),
(move |i: &mut _| Self::or(i, level), opt(range_right)).map(move |(left, right)| { (move |i: &mut _| Self::or(i, level), opt(range_right)).map(move |(left, right)| {
match right { match right {
Some((op, right)) => WithSpan::new( Some((op, right)) => WithSpan::new(
Self::Range(op, Some(Box::new(left)), right.map(Box::new)), Self::Range(Box::new(Range {
op,
lhs: Some(left),
rhs: right,
})),
start, start,
), ),
None => left, None => left,
@ -611,7 +625,7 @@ impl<'a> Expr<'a> {
| Self::RustMacro(_, _) | Self::RustMacro(_, _)
| Self::As(_, _) | Self::As(_, _)
| Self::Call { .. } | Self::Call { .. }
| Self::Range(_, _, _) | Self::Range(_)
| Self::Try(_) | Self::Try(_)
| Self::NamedArgument(_, _) | Self::NamedArgument(_, _)
| Self::Filter(_) | Self::Filter(_)