1use std::ops::Deref;
2
3#[cfg(feature = "internal_debug")]
4use std::fmt;
5
6use crate::compiler::tokens::Span;
7use crate::value::{ops, value_map_with_capacity, Value};
8
9#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
16pub struct Spanned<T> {
17 inner: Box<(T, Span)>,
18}
19
20impl<T> Spanned<T> {
21 pub fn new(node: T, span: Span) -> Spanned<T> {
23 Spanned {
24 inner: Box::new((node, span)),
25 }
26 }
27
28 pub fn span(&self) -> Span {
30 self.inner.1
31 }
32}
33
34impl<T> Deref for Spanned<T> {
35 type Target = T;
36
37 fn deref(&self) -> &Self::Target {
38 &self.inner.0
39 }
40}
41
42#[cfg(feature = "internal_debug")]
43impl<T: fmt::Debug> fmt::Debug for Spanned<T> {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 ok!(fmt::Debug::fmt(&self.inner.0, f));
46 write!(f, "{:?}", self.inner.1)
47 }
48}
49
50#[cfg_attr(
52 feature = "unstable_machinery_serde",
53 derive(serde::Serialize),
54 serde(tag = "stmt")
55)]
56pub enum Stmt<'a> {
57 Template(Spanned<Template<'a>>),
58 EmitExpr(Spanned<EmitExpr<'a>>),
59 EmitRaw(Spanned<EmitRaw<'a>>),
60 ForLoop(Spanned<ForLoop<'a>>),
61 IfCond(Spanned<IfCond<'a>>),
62 WithBlock(Spanned<WithBlock<'a>>),
63 Set(Spanned<Set<'a>>),
64 SetBlock(Spanned<SetBlock<'a>>),
65 AutoEscape(Spanned<AutoEscape<'a>>),
66 FilterBlock(Spanned<FilterBlock<'a>>),
67 #[cfg(feature = "multi_template")]
68 Block(Spanned<Block<'a>>),
69 #[cfg(feature = "multi_template")]
70 Import(Spanned<Import<'a>>),
71 #[cfg(feature = "multi_template")]
72 FromImport(Spanned<FromImport<'a>>),
73 #[cfg(feature = "multi_template")]
74 Extends(Spanned<Extends<'a>>),
75 #[cfg(feature = "multi_template")]
76 Include(Spanned<Include<'a>>),
77 #[cfg(feature = "macros")]
78 Macro(Spanned<Macro<'a>>),
79 #[cfg(feature = "macros")]
80 CallBlock(Spanned<CallBlock<'a>>),
81 #[cfg(feature = "loop_controls")]
82 Continue(Spanned<Continue>),
83 #[cfg(feature = "loop_controls")]
84 Break(Spanned<Break>),
85 Do(Spanned<Do<'a>>),
86}
87
88#[cfg(feature = "internal_debug")]
89impl fmt::Debug for Stmt<'_> {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 match self {
92 Stmt::Template(s) => fmt::Debug::fmt(s, f),
93 Stmt::EmitExpr(s) => fmt::Debug::fmt(s, f),
94 Stmt::EmitRaw(s) => fmt::Debug::fmt(s, f),
95 Stmt::ForLoop(s) => fmt::Debug::fmt(s, f),
96 Stmt::IfCond(s) => fmt::Debug::fmt(s, f),
97 Stmt::WithBlock(s) => fmt::Debug::fmt(s, f),
98 Stmt::Set(s) => fmt::Debug::fmt(s, f),
99 Stmt::SetBlock(s) => fmt::Debug::fmt(s, f),
100 Stmt::AutoEscape(s) => fmt::Debug::fmt(s, f),
101 Stmt::FilterBlock(s) => fmt::Debug::fmt(s, f),
102 #[cfg(feature = "multi_template")]
103 Stmt::Block(s) => fmt::Debug::fmt(s, f),
104 #[cfg(feature = "multi_template")]
105 Stmt::Extends(s) => fmt::Debug::fmt(s, f),
106 #[cfg(feature = "multi_template")]
107 Stmt::Include(s) => fmt::Debug::fmt(s, f),
108 #[cfg(feature = "multi_template")]
109 Stmt::Import(s) => fmt::Debug::fmt(s, f),
110 #[cfg(feature = "multi_template")]
111 Stmt::FromImport(s) => fmt::Debug::fmt(s, f),
112 #[cfg(feature = "macros")]
113 Stmt::Macro(s) => fmt::Debug::fmt(s, f),
114 #[cfg(feature = "macros")]
115 Stmt::CallBlock(s) => fmt::Debug::fmt(s, f),
116 #[cfg(feature = "loop_controls")]
117 Stmt::Continue(s) => fmt::Debug::fmt(s, f),
118 #[cfg(feature = "loop_controls")]
119 Stmt::Break(s) => fmt::Debug::fmt(s, f),
120 Stmt::Do(s) => fmt::Debug::fmt(s, f),
121 }
122 }
123}
124
125#[allow(clippy::enum_variant_names)]
127#[cfg_attr(
128 feature = "unstable_machinery_serde",
129 derive(serde::Serialize),
130 serde(tag = "expr")
131)]
132pub enum Expr<'a> {
133 Var(Spanned<Var<'a>>),
134 Const(Spanned<Const>),
135 Slice(Spanned<Slice<'a>>),
136 UnaryOp(Spanned<UnaryOp<'a>>),
137 BinOp(Spanned<BinOp<'a>>),
138 IfExpr(Spanned<IfExpr<'a>>),
139 Filter(Spanned<Filter<'a>>),
140 Test(Spanned<Test<'a>>),
141 GetAttr(Spanned<GetAttr<'a>>),
142 GetItem(Spanned<GetItem<'a>>),
143 Call(Spanned<Call<'a>>),
144 List(Spanned<List<'a>>),
145 Map(Spanned<Map<'a>>),
146}
147
148#[cfg(feature = "internal_debug")]
149impl fmt::Debug for Expr<'_> {
150 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
151 match self {
152 Expr::Var(s) => fmt::Debug::fmt(s, f),
153 Expr::Const(s) => fmt::Debug::fmt(s, f),
154 Expr::Slice(s) => fmt::Debug::fmt(s, f),
155 Expr::UnaryOp(s) => fmt::Debug::fmt(s, f),
156 Expr::BinOp(s) => fmt::Debug::fmt(s, f),
157 Expr::IfExpr(s) => fmt::Debug::fmt(s, f),
158 Expr::Filter(s) => fmt::Debug::fmt(s, f),
159 Expr::Test(s) => fmt::Debug::fmt(s, f),
160 Expr::GetAttr(s) => fmt::Debug::fmt(s, f),
161 Expr::GetItem(s) => fmt::Debug::fmt(s, f),
162 Expr::Call(s) => fmt::Debug::fmt(s, f),
163 Expr::List(s) => fmt::Debug::fmt(s, f),
164 Expr::Map(s) => fmt::Debug::fmt(s, f),
165 }
166 }
167}
168
169impl Expr<'_> {
170 pub fn description(&self) -> &'static str {
171 match self {
172 Expr::Var(_) => "variable",
173 Expr::Const(_) => "constant",
174 Expr::Slice(_)
175 | Expr::UnaryOp(_)
176 | Expr::BinOp(_)
177 | Expr::IfExpr(_)
178 | Expr::GetAttr(_)
179 | Expr::GetItem(_) => "expression",
180 Expr::Call(_) => "call",
181 Expr::List(_) => "list literal",
182 Expr::Map(_) => "map literal",
183 Expr::Test(_) => "test expression",
184 Expr::Filter(_) => "filter expression",
185 }
186 }
187
188 pub fn span(&self) -> Span {
189 match self {
190 Expr::Var(s) => s.span(),
191 Expr::Const(s) => s.span(),
192 Expr::Slice(s) => s.span(),
193 Expr::UnaryOp(s) => s.span(),
194 Expr::BinOp(s) => s.span(),
195 Expr::IfExpr(s) => s.span(),
196 Expr::Filter(s) => s.span(),
197 Expr::Test(s) => s.span(),
198 Expr::GetAttr(s) => s.span(),
199 Expr::GetItem(s) => s.span(),
200 Expr::Call(s) => s.span(),
201 Expr::List(s) => s.span(),
202 Expr::Map(s) => s.span(),
203 }
204 }
205
206 pub fn as_const(&self) -> Option<Value> {
207 match self {
208 Expr::Const(c) => Some(c.value.clone()),
209 Expr::List(l) => l.as_const(),
210 Expr::Map(m) => m.as_const(),
211 Expr::UnaryOp(c) => match c.op {
212 UnaryOpKind::Not => c.expr.as_const().map(|value| Value::from(!value.is_true())),
213 UnaryOpKind::Neg => c.expr.as_const().and_then(|v| ops::neg(&v).ok()),
214 },
215 Expr::BinOp(c) => {
216 let (Some(left), Some(right)) = (c.left.as_const(), c.right.as_const()) else {
217 return None;
218 };
219 match c.op {
220 BinOpKind::Add => ops::add(&left, &right).ok(),
221 BinOpKind::Sub => ops::sub(&left, &right).ok(),
222 BinOpKind::Mul => ops::mul(&left, &right).ok(),
223 BinOpKind::Div => ops::div(&left, &right).ok(),
224 BinOpKind::FloorDiv => ops::int_div(&left, &right).ok(),
225 BinOpKind::Rem => ops::rem(&left, &right).ok(),
226 BinOpKind::Pow => ops::pow(&left, &right).ok(),
227 BinOpKind::Concat => Some(ops::string_concat(left, &right)),
228 BinOpKind::Eq => Some(Value::from(left == right)),
229 BinOpKind::Ne => Some(Value::from(left != right)),
230 BinOpKind::Lt => Some(Value::from(left < right)),
231 BinOpKind::Lte => Some(Value::from(left <= right)),
232 BinOpKind::Gt => Some(Value::from(left > right)),
233 BinOpKind::Gte => Some(Value::from(left >= right)),
234 BinOpKind::In => ops::contains(&right, &left).ok(),
235 BinOpKind::ScAnd => Some(if left.is_true() && right.is_true() {
236 right
237 } else {
238 Value::from(false)
239 }),
240 BinOpKind::ScOr => Some(if left.is_true() { left } else { right }),
241 }
242 }
243 _ => None,
244 }
245 }
246}
247
248#[cfg_attr(feature = "internal_debug", derive(Debug))]
250#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
251pub struct Template<'a> {
252 pub children: Vec<Stmt<'a>>,
253}
254
255#[cfg_attr(feature = "internal_debug", derive(Debug))]
257#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
258pub struct ForLoop<'a> {
259 pub target: Expr<'a>,
260 pub iter: Expr<'a>,
261 pub filter_expr: Option<Expr<'a>>,
262 pub recursive: bool,
263 pub body: Vec<Stmt<'a>>,
264 pub else_body: Vec<Stmt<'a>>,
265}
266
267#[cfg_attr(feature = "internal_debug", derive(Debug))]
269#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
270pub struct IfCond<'a> {
271 pub expr: Expr<'a>,
272 pub true_body: Vec<Stmt<'a>>,
273 pub false_body: Vec<Stmt<'a>>,
274}
275
276#[cfg_attr(feature = "internal_debug", derive(Debug))]
278#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
279pub struct WithBlock<'a> {
280 pub assignments: Vec<(Expr<'a>, Expr<'a>)>,
281 pub body: Vec<Stmt<'a>>,
282}
283
284#[cfg_attr(feature = "internal_debug", derive(Debug))]
286#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
287pub struct Set<'a> {
288 pub target: Expr<'a>,
289 pub expr: Expr<'a>,
290}
291
292#[cfg_attr(feature = "internal_debug", derive(Debug))]
294#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
295pub struct SetBlock<'a> {
296 pub target: Expr<'a>,
297 pub filter: Option<Expr<'a>>,
298 pub body: Vec<Stmt<'a>>,
299}
300
301#[cfg_attr(feature = "internal_debug", derive(Debug))]
303#[cfg(feature = "multi_template")]
304#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
305pub struct Block<'a> {
306 pub name: &'a str,
307 pub body: Vec<Stmt<'a>>,
308}
309
310#[cfg_attr(feature = "internal_debug", derive(Debug))]
312#[cfg(feature = "multi_template")]
313#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
314pub struct Extends<'a> {
315 pub name: Expr<'a>,
316}
317
318#[cfg_attr(feature = "internal_debug", derive(Debug))]
320#[cfg(feature = "multi_template")]
321#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
322pub struct Include<'a> {
323 pub name: Expr<'a>,
324 pub ignore_missing: bool,
325}
326
327#[cfg_attr(feature = "internal_debug", derive(Debug))]
329#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
330pub struct AutoEscape<'a> {
331 pub enabled: Expr<'a>,
332 pub body: Vec<Stmt<'a>>,
333}
334
335#[cfg_attr(feature = "internal_debug", derive(Debug))]
337#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
338pub struct FilterBlock<'a> {
339 pub filter: Expr<'a>,
340 pub body: Vec<Stmt<'a>>,
341}
342
343#[cfg_attr(feature = "internal_debug", derive(Debug))]
345#[cfg(feature = "macros")]
346#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
347pub struct Macro<'a> {
348 pub name: &'a str,
349 pub args: Vec<Expr<'a>>,
350 pub defaults: Vec<Expr<'a>>,
351 pub body: Vec<Stmt<'a>>,
352}
353
354#[cfg_attr(feature = "internal_debug", derive(Debug))]
356#[cfg(feature = "macros")]
357#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
358pub struct CallBlock<'a> {
359 pub call: Spanned<Call<'a>>,
360 pub macro_decl: Spanned<Macro<'a>>,
361}
362
363#[cfg_attr(feature = "internal_debug", derive(Debug))]
365#[cfg(feature = "loop_controls")]
366#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
367pub struct Continue;
368
369#[cfg_attr(feature = "internal_debug", derive(Debug))]
371#[cfg(feature = "loop_controls")]
372#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
373pub struct Break;
374
375#[cfg_attr(feature = "internal_debug", derive(Debug))]
377#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
378pub struct Do<'a> {
379 pub call: Spanned<Call<'a>>,
380}
381
382#[cfg_attr(feature = "internal_debug", derive(Debug))]
384#[cfg(feature = "multi_template")]
385#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
386pub struct FromImport<'a> {
387 pub expr: Expr<'a>,
388 pub names: Vec<(Expr<'a>, Option<Expr<'a>>)>,
389}
390
391#[cfg_attr(feature = "internal_debug", derive(Debug))]
393#[cfg(feature = "multi_template")]
394#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
395pub struct Import<'a> {
396 pub expr: Expr<'a>,
397 pub name: Expr<'a>,
398}
399
400#[cfg_attr(feature = "internal_debug", derive(Debug))]
402#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
403pub struct EmitExpr<'a> {
404 pub expr: Expr<'a>,
405}
406
407#[cfg_attr(feature = "internal_debug", derive(Debug))]
409#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
410pub struct EmitRaw<'a> {
411 pub raw: &'a str,
412}
413
414#[cfg_attr(feature = "internal_debug", derive(Debug))]
416#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
417pub struct Var<'a> {
418 pub id: &'a str,
419}
420
421#[cfg_attr(feature = "internal_debug", derive(Debug))]
423#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
424pub struct Const {
425 pub value: Value,
426}
427
428#[cfg_attr(feature = "internal_debug", derive(Debug))]
430#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
431pub struct Slice<'a> {
432 pub expr: Expr<'a>,
433 pub start: Option<Expr<'a>>,
434 pub stop: Option<Expr<'a>>,
435 pub step: Option<Expr<'a>>,
436}
437
438#[cfg_attr(feature = "internal_debug", derive(Debug))]
440#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
441pub enum UnaryOpKind {
442 Not,
443 Neg,
444}
445
446#[cfg_attr(feature = "internal_debug", derive(Debug))]
448#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
449pub struct UnaryOp<'a> {
450 pub op: UnaryOpKind,
451 pub expr: Expr<'a>,
452}
453
454#[cfg_attr(feature = "internal_debug", derive(Debug))]
456#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
457pub enum BinOpKind {
458 Eq,
459 Ne,
460 Lt,
461 Lte,
462 Gt,
463 Gte,
464 ScAnd,
465 ScOr,
466 Add,
467 Sub,
468 Mul,
469 Div,
470 FloorDiv,
471 Rem,
472 Pow,
473 Concat,
474 In,
475}
476
477#[cfg_attr(feature = "internal_debug", derive(Debug))]
479#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
480pub struct BinOp<'a> {
481 pub op: BinOpKind,
482 pub left: Expr<'a>,
483 pub right: Expr<'a>,
484}
485
486#[cfg_attr(feature = "internal_debug", derive(Debug))]
488#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
489pub struct IfExpr<'a> {
490 pub test_expr: Expr<'a>,
491 pub true_expr: Expr<'a>,
492 pub false_expr: Option<Expr<'a>>,
493}
494
495#[cfg_attr(feature = "internal_debug", derive(Debug))]
497#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
498pub struct Filter<'a> {
499 pub name: &'a str,
500 pub expr: Option<Expr<'a>>,
501 pub args: Vec<CallArg<'a>>,
502}
503
504#[cfg_attr(feature = "internal_debug", derive(Debug))]
506#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
507pub struct Test<'a> {
508 pub name: &'a str,
509 pub expr: Expr<'a>,
510 pub args: Vec<CallArg<'a>>,
511}
512
513#[cfg_attr(feature = "internal_debug", derive(Debug))]
515#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
516pub struct GetAttr<'a> {
517 pub expr: Expr<'a>,
518 pub name: &'a str,
519}
520
521#[cfg_attr(feature = "internal_debug", derive(Debug))]
523#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
524pub struct GetItem<'a> {
525 pub expr: Expr<'a>,
526 pub subscript_expr: Expr<'a>,
527}
528
529#[cfg_attr(feature = "internal_debug", derive(Debug))]
531#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
532pub struct Call<'a> {
533 pub expr: Expr<'a>,
534 pub args: Vec<CallArg<'a>>,
535}
536
537#[cfg_attr(feature = "internal_debug", derive(Debug))]
539#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
540pub enum CallArg<'a> {
541 Pos(Expr<'a>),
542 Kwarg(&'a str, Expr<'a>),
543 PosSplat(Expr<'a>),
544 KwargSplat(Expr<'a>),
545}
546
547#[cfg_attr(feature = "internal_debug", derive(Debug))]
549#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
550pub struct List<'a> {
551 pub items: Vec<Expr<'a>>,
552}
553
554impl List<'_> {
555 pub fn as_const(&self) -> Option<Value> {
556 if !self.items.iter().all(|x| matches!(x, Expr::Const(_))) {
557 return None;
558 }
559
560 let items = self.items.iter();
561 let sequence = items.filter_map(|expr| match expr {
562 Expr::Const(v) => Some(v.value.clone()),
563 _ => None,
564 });
565
566 Some(Value::from(sequence.collect::<Vec<_>>()))
567 }
568}
569
570#[cfg_attr(feature = "internal_debug", derive(Debug))]
572#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
573pub struct Map<'a> {
574 pub keys: Vec<Expr<'a>>,
575 pub values: Vec<Expr<'a>>,
576}
577
578impl Map<'_> {
579 pub fn as_const(&self) -> Option<Value> {
580 if !self.keys.iter().all(|x| matches!(x, Expr::Const(_)))
581 || !self.values.iter().all(|x| matches!(x, Expr::Const(_)))
582 {
583 return None;
584 }
585
586 let mut rv = value_map_with_capacity(self.keys.len());
587 for (key, value) in self.keys.iter().zip(self.values.iter()) {
588 if let (Expr::Const(maybe_key), Expr::Const(value)) = (key, value) {
589 rv.insert(maybe_key.value.clone(), value.value.clone());
590 }
591 }
592
593 Some(Value::from_object(rv))
594 }
595}
596
597#[cfg_attr(feature = "internal_debug", derive(Debug))]
599#[cfg_attr(feature = "unstable_machinery_serde", derive(serde::Serialize))]
600pub enum CallType<'ast, 'source> {
601 Function(&'source str),
602 Method(&'ast Expr<'source>, &'source str),
603 #[cfg(feature = "multi_template")]
604 Block(&'source str),
605 Object(&'ast Expr<'source>),
606}
607
608impl<'a> Call<'a> {
609 pub fn identify_call(&self) -> CallType<'_, 'a> {
615 match self.expr {
616 Expr::Var(ref var) => CallType::Function(var.id),
617 Expr::GetAttr(ref attr) => {
618 #[cfg(feature = "multi_template")]
619 {
620 if let Expr::Var(ref var) = attr.expr {
621 if var.id == "self" {
622 return CallType::Block(attr.name);
623 }
624 }
625 }
626 CallType::Method(&attr.expr, attr.name)
627 }
628 _ => CallType::Object(&self.expr),
629 }
630 }
631}