1use std::collections::HashMap;
2use std::fmt;
3
4#[derive(Clone, Copy, Debug, PartialEq, Default)]
6pub struct WS {
7 pub left: bool,
9 pub right: bool,
11}
12
13#[derive(Copy, Clone, Debug, PartialEq)]
15pub enum MathOperator {
16 Add,
18 Sub,
20 Mul,
22 Div,
24 Modulo,
26}
27
28impl fmt::Display for MathOperator {
29 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
30 write!(
31 f,
32 "{}",
33 match *self {
34 MathOperator::Add => "+",
35 MathOperator::Sub => "-",
36 MathOperator::Mul => "*",
37 MathOperator::Div => "/",
38 MathOperator::Modulo => "%",
39 }
40 )
41 }
42}
43
44#[derive(Copy, Clone, Debug, PartialEq)]
46pub enum LogicOperator {
47 Gt,
49 Gte,
51 Lt,
53 Lte,
55 Eq,
57 NotEq,
59 And,
61 Or,
63}
64
65impl fmt::Display for LogicOperator {
66 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
67 write!(
68 f,
69 "{}",
70 match *self {
71 LogicOperator::Gt => ">",
72 LogicOperator::Gte => ">=",
73 LogicOperator::Lt => "<",
74 LogicOperator::Lte => "<=",
75 LogicOperator::Eq => "==",
76 LogicOperator::NotEq => "!=",
77 LogicOperator::And => "and",
78 LogicOperator::Or => "or",
79 }
80 )
81 }
82}
83
84#[derive(Clone, Debug, PartialEq)]
86pub struct FunctionCall {
87 pub name: String,
89 pub args: HashMap<String, Expr>,
91}
92
93#[derive(Clone, Debug, PartialEq)]
95pub struct MathExpr {
96 pub lhs: Box<Expr>,
98 pub rhs: Box<Expr>,
100 pub operator: MathOperator,
102}
103
104#[derive(Clone, Debug, PartialEq)]
106pub struct LogicExpr {
107 pub lhs: Box<Expr>,
109 pub rhs: Box<Expr>,
111 pub operator: LogicOperator,
113}
114
115#[derive(Clone, Debug, PartialEq)]
117pub struct StringConcat {
118 pub values: Vec<ExprVal>,
120}
121
122impl StringConcat {
123 pub(crate) fn to_template_string(&self) -> String {
124 let mut res = Vec::new();
125 for value in &self.values {
126 match value {
127 ExprVal::String(ref s) => res.push(format!("'{}'", s)),
128 ExprVal::Ident(ref s) => res.push(s.to_string()),
129 _ => res.push("unknown".to_string()),
130 }
131 }
132
133 res.join(" ~ ")
134 }
135}
136
137#[derive(Clone, Debug, PartialEq)]
139pub struct In {
140 pub lhs: Box<Expr>,
142 pub rhs: Box<Expr>,
144 pub negated: bool,
146}
147
148#[derive(Clone, Debug, PartialEq)]
150#[allow(missing_docs)]
151pub enum ExprVal {
152 String(String),
153 Int(i64),
154 Float(f64),
155 Bool(bool),
156 Ident(String),
157 Math(MathExpr),
158 Logic(LogicExpr),
159 Test(Test),
160 MacroCall(MacroCall),
161 FunctionCall(FunctionCall),
162 Array(Vec<Expr>),
165 StringConcat(StringConcat),
166 In(In),
167}
168
169#[derive(Clone, Debug, PartialEq)]
172pub struct Expr {
173 pub val: ExprVal,
175 pub negated: bool,
177 pub filters: Vec<FunctionCall>,
179}
180
181impl Expr {
182 pub fn new(val: ExprVal) -> Expr {
184 Expr { val, negated: false, filters: vec![] }
185 }
186
187 pub fn new_negated(val: ExprVal) -> Expr {
189 Expr { val, negated: true, filters: vec![] }
190 }
191
192 pub fn with_filters(val: ExprVal, filters: Vec<FunctionCall>) -> Expr {
194 Expr { val, filters, negated: false }
195 }
196
197 pub fn has_default_filter(&self) -> bool {
199 if self.filters.is_empty() {
200 return false;
201 }
202
203 self.filters[0].name == "default"
204 }
205
206 pub fn is_marked_safe(&self) -> bool {
208 if self.filters.is_empty() {
209 return false;
210 }
211
212 self.filters[self.filters.len() - 1].name == "safe"
213 }
214}
215
216#[derive(Clone, Debug, PartialEq)]
218pub struct Test {
219 pub ident: String,
221 pub negated: bool,
223 pub name: String,
225 pub args: Vec<Expr>,
227}
228
229#[derive(Clone, Debug, PartialEq)]
231pub struct FilterSection {
232 pub filter: FunctionCall,
234 pub body: Vec<Node>,
236}
237
238#[derive(Clone, Debug, PartialEq)]
240pub struct Set {
241 pub key: String,
243 pub value: Expr,
245 pub global: bool,
248}
249
250#[derive(Clone, Debug, PartialEq)]
252pub struct MacroCall {
253 pub namespace: String,
255 pub name: String,
257 pub args: HashMap<String, Expr>,
259}
260
261#[derive(Clone, Debug, PartialEq)]
263pub struct MacroDefinition {
264 pub name: String,
266 pub args: HashMap<String, Option<Expr>>,
268 pub body: Vec<Node>,
270}
271
272#[derive(Clone, Debug, PartialEq)]
274pub struct Block {
275 pub name: String,
277 pub body: Vec<Node>,
279}
280
281#[derive(Clone, Debug, PartialEq)]
283pub struct Forloop {
284 pub key: Option<String>,
286 pub value: String,
288 pub container: Expr,
290 pub body: Vec<Node>,
292 pub empty_body: Option<Vec<Node>>,
294}
295
296#[derive(Clone, Debug, PartialEq)]
298pub struct If {
299 pub conditions: Vec<(WS, Expr, Vec<Node>)>,
301 pub otherwise: Option<(WS, Vec<Node>)>,
303}
304
305#[derive(Clone, Debug, PartialEq)]
307pub enum Node {
308 Super,
310
311 Text(String),
313 VariableBlock(WS, Expr),
315 MacroDefinition(WS, MacroDefinition, WS),
317
318 Extends(WS, String),
320 Include(WS, Vec<String>, bool),
322 ImportMacro(WS, String, String),
324 Set(WS, Set),
326
327 Raw(WS, String, WS),
329
330 FilterSection(WS, FilterSection, WS),
332 Block(WS, Block, WS),
334 Forloop(WS, Forloop, WS),
336
337 If(If, WS),
339
340 Break(WS),
342 Continue(WS),
344
345 Comment(WS, String),
347}