mirror of
https://github.com/askama-rs/askama.git
synced 2025-10-02 15:25:19 +00:00
Rename Expr::Attr
into Expr::AssociatedItem
This commit is contained in:
parent
338369a424
commit
ca6573bf56
@ -594,16 +594,18 @@ fn is_copyable_within_op(expr: &Expr<'_>, within_op: bool) -> bool {
|
|||||||
// will solve that issue. However, if the operand is
|
// will solve that issue. However, if the operand is
|
||||||
// implicitly borrowed, then it's likely not even possible
|
// implicitly borrowed, then it's likely not even possible
|
||||||
// to get the template to compile.
|
// to get the template to compile.
|
||||||
_ => within_op && is_attr_self(expr),
|
_ => within_op && is_associated_item_self(expr),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if this is an `Attr` where the `obj` is `"self"`.
|
/// Returns `true` if this is an `AssociatedItem` where the `obj` is `"self"`.
|
||||||
fn is_attr_self(mut expr: &Expr<'_>) -> bool {
|
fn is_associated_item_self(mut expr: &Expr<'_>) -> bool {
|
||||||
loop {
|
loop {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::Attr(obj, _) if matches!(***obj, Expr::Var("self")) => return true,
|
Expr::AssociatedItem(obj, _) if matches!(***obj, Expr::Var("self")) => return true,
|
||||||
Expr::Attr(obj, _) if matches!(***obj, Expr::Attr(..)) => expr = obj,
|
Expr::AssociatedItem(obj, _) if matches!(***obj, Expr::AssociatedItem(..)) => {
|
||||||
|
expr = obj
|
||||||
|
}
|
||||||
_ => return false,
|
_ => return false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use parser::node::CondTest;
|
use parser::node::CondTest;
|
||||||
use parser::{Attr, CharLit, CharPrefix, Expr, Span, StrLit, Target, TyGenerics, WithSpan};
|
use parser::{
|
||||||
|
AssociatedItem, CharLit, CharPrefix, Expr, Span, StrLit, Target, TyGenerics, WithSpan,
|
||||||
|
};
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
@ -46,7 +48,7 @@ impl<'a> Generator<'a, '_> {
|
|||||||
}
|
}
|
||||||
// If accessing a field then it most likely needs to be
|
// If accessing a field then it most likely needs to be
|
||||||
// borrowed, to prevent an attempt of moving.
|
// borrowed, to prevent an attempt of moving.
|
||||||
Expr::Attr(..) => buf.write(format_args!("(&{expr_code}).into_iter()")),
|
Expr::AssociatedItem(..) => buf.write(format_args!("(&{expr_code}).into_iter()")),
|
||||||
// Otherwise, we borrow `iter` assuming that it implements `IntoIterator`.
|
// Otherwise, we borrow `iter` assuming that it implements `IntoIterator`.
|
||||||
_ => buf.write(format_args!("({expr_code}).into_iter()")),
|
_ => buf.write(format_args!("({expr_code}).into_iter()")),
|
||||||
}
|
}
|
||||||
@ -67,7 +69,9 @@ impl<'a> Generator<'a, '_> {
|
|||||||
Expr::Var(s) => self.visit_var(buf, s),
|
Expr::Var(s) => self.visit_var(buf, s),
|
||||||
Expr::Path(ref path) => self.visit_path(buf, path),
|
Expr::Path(ref path) => self.visit_path(buf, path),
|
||||||
Expr::Array(ref elements) => self.visit_array(ctx, buf, elements)?,
|
Expr::Array(ref elements) => self.visit_array(ctx, buf, elements)?,
|
||||||
Expr::Attr(ref obj, ref attr) => self.visit_attr(ctx, buf, obj, attr)?,
|
Expr::AssociatedItem(ref obj, ref associated_item) => {
|
||||||
|
self.visit_associated_item(ctx, buf, obj, associated_item)?
|
||||||
|
}
|
||||||
Expr::Index(ref obj, ref key) => self.visit_index(ctx, buf, obj, key)?,
|
Expr::Index(ref obj, ref key) => self.visit_index(ctx, buf, obj, key)?,
|
||||||
Expr::Filter(ref v) => {
|
Expr::Filter(ref v) => {
|
||||||
self.visit_filter(ctx, buf, &v.name, &v.arguments, &v.generics, expr.span())?
|
self.visit_filter(ctx, buf, &v.name, &v.arguments, &v.generics, expr.span())?
|
||||||
@ -389,15 +393,15 @@ impl<'a> Generator<'a, '_> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn visit_attr(
|
pub(crate) fn visit_associated_item(
|
||||||
&mut self,
|
&mut self,
|
||||||
ctx: &Context<'_>,
|
ctx: &Context<'_>,
|
||||||
buf: &mut Buffer,
|
buf: &mut Buffer,
|
||||||
obj: &WithSpan<'a, Expr<'a>>,
|
obj: &WithSpan<'a, Expr<'a>>,
|
||||||
attr: &Attr<'a>,
|
associated_item: &AssociatedItem<'a>,
|
||||||
) -> Result<DisplayWrap, CompileError> {
|
) -> Result<DisplayWrap, CompileError> {
|
||||||
if let Expr::Var("loop") = **obj {
|
if let Expr::Var("loop") = **obj {
|
||||||
buf.write(match attr.name {
|
buf.write(match associated_item.name {
|
||||||
"index0" => "__askama_item.index0",
|
"index0" => "__askama_item.index0",
|
||||||
"index" => "(__askama_item.index0 + 1)",
|
"index" => "(__askama_item.index0 + 1)",
|
||||||
"first" => "(__askama_item.index0 == 0)",
|
"first" => "(__askama_item.index0 == 0)",
|
||||||
@ -413,8 +417,11 @@ impl<'a> Generator<'a, '_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.visit_expr(ctx, buf, obj)?;
|
self.visit_expr(ctx, buf, obj)?;
|
||||||
buf.write(format_args!(".{}", normalize_identifier(attr.name)));
|
buf.write(format_args!(
|
||||||
self.visit_call_generics(buf, &attr.generics);
|
".{}",
|
||||||
|
normalize_identifier(associated_item.name)
|
||||||
|
));
|
||||||
|
self.visit_call_generics(buf, &associated_item.generics);
|
||||||
Ok(DisplayWrap::Unwrapped)
|
Ok(DisplayWrap::Unwrapped)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,7 +486,9 @@ impl<'a> Generator<'a, '_> {
|
|||||||
generics: &[WithSpan<'a, TyGenerics<'a>>],
|
generics: &[WithSpan<'a, TyGenerics<'a>>],
|
||||||
) -> Result<DisplayWrap, CompileError> {
|
) -> Result<DisplayWrap, CompileError> {
|
||||||
match &**left {
|
match &**left {
|
||||||
Expr::Attr(sub_left, Attr { name, .. }) if ***sub_left == Expr::Var("loop") => {
|
Expr::AssociatedItem(sub_left, AssociatedItem { name, .. })
|
||||||
|
if ***sub_left == Expr::Var("loop") =>
|
||||||
|
{
|
||||||
match *name {
|
match *name {
|
||||||
"cycle" => {
|
"cycle" => {
|
||||||
if let [generic, ..] = generics {
|
if let [generic, ..] = generics {
|
||||||
|
@ -196,7 +196,7 @@ impl<'a> Generator<'a, '_> {
|
|||||||
| Expr::Var(_)
|
| Expr::Var(_)
|
||||||
| Expr::Path(_)
|
| Expr::Path(_)
|
||||||
| Expr::Array(_)
|
| Expr::Array(_)
|
||||||
| Expr::Attr(_, _)
|
| Expr::AssociatedItem(_, _)
|
||||||
| Expr::Index(_, _)
|
| Expr::Index(_, _)
|
||||||
| Expr::Filter(_)
|
| Expr::Filter(_)
|
||||||
| Expr::Range(_)
|
| Expr::Range(_)
|
||||||
@ -702,12 +702,12 @@ impl<'a> Generator<'a, '_> {
|
|||||||
this.locals
|
this.locals
|
||||||
.insert(Cow::Borrowed(arg), LocalMeta::with_ref(var));
|
.insert(Cow::Borrowed(arg), LocalMeta::with_ref(var));
|
||||||
}
|
}
|
||||||
Expr::Attr(obj, attr) => {
|
Expr::AssociatedItem(obj, associated_item) => {
|
||||||
let mut attr_buf = Buffer::new();
|
let mut associated_item_buf = Buffer::new();
|
||||||
this.visit_attr(ctx, &mut attr_buf, obj, attr)?;
|
this.visit_associated_item(ctx, &mut associated_item_buf, obj, associated_item)?;
|
||||||
|
|
||||||
let attr = attr_buf.into_string();
|
let associated_item = associated_item_buf.into_string();
|
||||||
let var = this.locals.resolve(&attr).unwrap_or(attr);
|
let var = this.locals.resolve(&associated_item).unwrap_or(associated_item);
|
||||||
this.locals
|
this.locals
|
||||||
.insert(Cow::Borrowed(arg), LocalMeta::with_ref(var));
|
.insert(Cow::Borrowed(arg), LocalMeta::with_ref(var));
|
||||||
}
|
}
|
||||||
@ -1133,12 +1133,20 @@ impl<'a> Generator<'a, '_> {
|
|||||||
this.locals
|
this.locals
|
||||||
.insert(Cow::Borrowed(arg), LocalMeta::with_ref(var));
|
.insert(Cow::Borrowed(arg), LocalMeta::with_ref(var));
|
||||||
}
|
}
|
||||||
Expr::Attr(obj, attr) => {
|
Expr::AssociatedItem(obj, associated_item) => {
|
||||||
let mut attr_buf = Buffer::new();
|
let mut associated_item_buf = Buffer::new();
|
||||||
this.visit_attr(ctx, &mut attr_buf, obj, attr)?;
|
this.visit_associated_item(
|
||||||
|
ctx,
|
||||||
|
&mut associated_item_buf,
|
||||||
|
obj,
|
||||||
|
associated_item,
|
||||||
|
)?;
|
||||||
|
|
||||||
let attr = attr_buf.into_string();
|
let associated_item = associated_item_buf.into_string();
|
||||||
let var = this.locals.resolve(&attr).unwrap_or(attr);
|
let var = this
|
||||||
|
.locals
|
||||||
|
.resolve(&associated_item)
|
||||||
|
.unwrap_or(associated_item);
|
||||||
this.locals
|
this.locals
|
||||||
.insert(Cow::Borrowed(arg), LocalMeta::with_ref(var));
|
.insert(Cow::Borrowed(arg), LocalMeta::with_ref(var));
|
||||||
}
|
}
|
||||||
@ -1639,7 +1647,7 @@ fn is_cacheable(expr: &WithSpan<'_, Expr<'_>>) -> bool {
|
|||||||
Expr::Path(_) => true,
|
Expr::Path(_) => true,
|
||||||
// Check recursively:
|
// Check recursively:
|
||||||
Expr::Array(args) => args.iter().all(is_cacheable),
|
Expr::Array(args) => args.iter().all(is_cacheable),
|
||||||
Expr::Attr(lhs, _) => is_cacheable(lhs),
|
Expr::AssociatedItem(lhs, _) => is_cacheable(lhs),
|
||||||
Expr::Index(lhs, rhs) => is_cacheable(lhs) && is_cacheable(rhs),
|
Expr::Index(lhs, rhs) => is_cacheable(lhs) && is_cacheable(rhs),
|
||||||
Expr::Filter(v) => v.arguments.iter().all(is_cacheable),
|
Expr::Filter(v) => v.arguments.iter().all(is_cacheable),
|
||||||
Expr::Unary(_, arg) => is_cacheable(arg),
|
Expr::Unary(_, arg) => is_cacheable(arg),
|
||||||
|
@ -84,11 +84,11 @@ fn check_expr<'a>(expr: &WithSpan<'a, Expr<'a>>, allowed: Allowed) -> Result<(),
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Expr::Attr(elem, attr) => {
|
Expr::AssociatedItem(elem, associated_item) => {
|
||||||
if attr.name == "_" {
|
if associated_item.name == "_" {
|
||||||
Err(err_underscore_identifier(attr.name))
|
Err(err_underscore_identifier(associated_item.name))
|
||||||
} else if !crate::can_be_variable_name(attr.name) {
|
} else if !crate::can_be_variable_name(associated_item.name) {
|
||||||
Err(err_reserved_identifier(attr.name))
|
Err(err_reserved_identifier(associated_item.name))
|
||||||
} else {
|
} else {
|
||||||
check_expr(elem, Allowed::default())
|
check_expr(elem, Allowed::default())
|
||||||
}
|
}
|
||||||
@ -163,7 +163,7 @@ pub enum Expr<'a> {
|
|||||||
Var(&'a str),
|
Var(&'a str),
|
||||||
Path(Vec<&'a str>),
|
Path(Vec<&'a str>),
|
||||||
Array(Vec<WithSpan<'a, Expr<'a>>>),
|
Array(Vec<WithSpan<'a, Expr<'a>>>),
|
||||||
Attr(Box<WithSpan<'a, Expr<'a>>>, Attr<'a>),
|
AssociatedItem(Box<WithSpan<'a, Expr<'a>>>, AssociatedItem<'a>),
|
||||||
Index(Box<WithSpan<'a, Expr<'a>>>, Box<WithSpan<'a, Expr<'a>>>),
|
Index(Box<WithSpan<'a, Expr<'a>>>, Box<WithSpan<'a, Expr<'a>>>),
|
||||||
Filter(Box<Filter<'a>>),
|
Filter(Box<Filter<'a>>),
|
||||||
As(Box<WithSpan<'a, Expr<'a>>>, &'a str),
|
As(Box<WithSpan<'a, Expr<'a>>>, &'a str),
|
||||||
@ -460,7 +460,7 @@ impl<'a> Expr<'a> {
|
|||||||
};
|
};
|
||||||
let var_name = match *lhs {
|
let var_name = match *lhs {
|
||||||
Self::Var(var_name) => var_name,
|
Self::Var(var_name) => var_name,
|
||||||
Self::Attr(_, _) => {
|
Self::AssociatedItem(_, _) => {
|
||||||
return Err(ErrMode::Cut(ErrorContext::new(
|
return Err(ErrMode::Cut(ErrorContext::new(
|
||||||
"`is defined` operator can only be used on variables, not on their fields",
|
"`is defined` operator can only be used on variables, not on their fields",
|
||||||
start,
|
start,
|
||||||
@ -632,7 +632,7 @@ impl<'a> Expr<'a> {
|
|||||||
| Self::Try(_)
|
| Self::Try(_)
|
||||||
| Self::NamedArgument(_, _)
|
| Self::NamedArgument(_, _)
|
||||||
| Self::Filter(_)
|
| Self::Filter(_)
|
||||||
| Self::Attr(_, _)
|
| Self::AssociatedItem(_, _)
|
||||||
| Self::Index(_, _)
|
| Self::Index(_, _)
|
||||||
| Self::Tuple(_)
|
| Self::Tuple(_)
|
||||||
| Self::Array(_)
|
| Self::Array(_)
|
||||||
@ -677,13 +677,13 @@ pub struct Filter<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct Attr<'a> {
|
pub struct AssociatedItem<'a> {
|
||||||
pub name: &'a str,
|
pub name: &'a str,
|
||||||
pub generics: Vec<WithSpan<'a, TyGenerics<'a>>>,
|
pub generics: Vec<WithSpan<'a, TyGenerics<'a>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Suffix<'a> {
|
enum Suffix<'a> {
|
||||||
Attr(Attr<'a>),
|
AssociatedItem(AssociatedItem<'a>),
|
||||||
Index(WithSpan<'a, Expr<'a>>),
|
Index(WithSpan<'a, Expr<'a>>),
|
||||||
Call {
|
Call {
|
||||||
args: Vec<WithSpan<'a, Expr<'a>>>,
|
args: Vec<WithSpan<'a, Expr<'a>>>,
|
||||||
@ -699,7 +699,7 @@ impl<'a> Suffix<'a> {
|
|||||||
let mut level_guard = level.guard();
|
let mut level_guard = level.guard();
|
||||||
let mut expr = Expr::single(i, level)?;
|
let mut expr = Expr::single(i, level)?;
|
||||||
let mut right = opt(alt((
|
let mut right = opt(alt((
|
||||||
|i: &mut _| Self::attr(i, level),
|
|i: &mut _| Self::associated_item(i, level),
|
||||||
|i: &mut _| Self::index(i, level),
|
|i: &mut _| Self::index(i, level),
|
||||||
|i: &mut _| Self::call(i, level),
|
|i: &mut _| Self::call(i, level),
|
||||||
Self::r#try,
|
Self::r#try,
|
||||||
@ -714,8 +714,11 @@ impl<'a> Suffix<'a> {
|
|||||||
level_guard.nest(before_suffix)?;
|
level_guard.nest(before_suffix)?;
|
||||||
|
|
||||||
match suffix {
|
match suffix {
|
||||||
Self::Attr(attr) => {
|
Self::AssociatedItem(associated_item) => {
|
||||||
expr = WithSpan::new(Expr::Attr(expr.into(), attr), before_suffix)
|
expr = WithSpan::new(
|
||||||
|
Expr::AssociatedItem(expr.into(), associated_item),
|
||||||
|
before_suffix,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Self::Index(index) => {
|
Self::Index(index) => {
|
||||||
expr = WithSpan::new(Expr::Index(expr.into(), index.into()), before_suffix);
|
expr = WithSpan::new(Expr::Index(expr.into(), index.into()), before_suffix);
|
||||||
@ -1034,7 +1037,7 @@ impl<'a> Suffix<'a> {
|
|||||||
(|i: &mut _| macro_arguments(i, open_token)).parse_next(i)
|
(|i: &mut _| macro_arguments(i, open_token)).parse_next(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn attr(i: &mut &'a str, level: Level<'_>) -> ParseResult<'a, Self> {
|
fn associated_item(i: &mut &'a str, level: Level<'_>) -> ParseResult<'a, Self> {
|
||||||
preceded(
|
preceded(
|
||||||
ws(('.', not('.'))),
|
ws(('.', not('.'))),
|
||||||
cut_err((
|
cut_err((
|
||||||
@ -1053,7 +1056,7 @@ impl<'a> Suffix<'a> {
|
|||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
.map(|(name, generics)| {
|
.map(|(name, generics)| {
|
||||||
Self::Attr(Attr {
|
Self::AssociatedItem(AssociatedItem {
|
||||||
name,
|
name,
|
||||||
generics: generics.unwrap_or_default(),
|
generics: generics.unwrap_or_default(),
|
||||||
})
|
})
|
||||||
|
@ -27,7 +27,7 @@ use winnow::token::{any, none_of, one_of, take_till, take_while};
|
|||||||
use winnow::{ModalParser, Parser};
|
use winnow::{ModalParser, Parser};
|
||||||
|
|
||||||
use crate::ascii_str::{AsciiChar, AsciiStr};
|
use crate::ascii_str::{AsciiChar, AsciiStr};
|
||||||
pub use crate::expr::{Attr, Expr, Filter, TyGenerics};
|
pub use crate::expr::{AssociatedItem, Expr, Filter, TyGenerics};
|
||||||
pub use crate::node::Node;
|
pub use crate::node::Node;
|
||||||
pub use crate::target::Target;
|
pub use crate::target::Target;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user