]> git.proxmox.com Git - rustc.git/blob - vendor/tera/src/parser/tera.pest
New upstream version 1.55.0+dfsg1
[rustc.git] / vendor / tera / src / parser / tera.pest
1 WHITESPACE = _{ " " | "\t" | "\r" | "\n" }
2
3 /// LITERALS
4 int = @{ "-" ? ~ ("0" | '1'..'9' ~ '0'..'9' * ) }
5 float = @{
6 "-" ? ~
7 (
8 "0" ~ "." ~ '0'..'9' + |
9 '1'..'9' ~ '0'..'9' * ~ "." ~ '0'..'9' +
10 )
11 }
12 // matches anything between 2 double quotes
13 double_quoted_string = @{ "\"" ~ (!("\"") ~ ANY)* ~ "\""}
14 // matches anything between 2 single quotes
15 single_quoted_string = @{ "\'" ~ (!("\'") ~ ANY)* ~ "\'"}
16 // matches anything between 2 backquotes\backticks
17 backquoted_quoted_string = @{ "`" ~ (!("`") ~ ANY)* ~ "`"}
18
19 string = @{
20 double_quoted_string |
21 single_quoted_string |
22 backquoted_quoted_string
23 }
24
25 boolean = { "true" | "false" | "True" | "False" }
26
27 // -----------------------------------------------
28
29 /// OPERATORS
30 op_or = @{ "or" ~ WHITESPACE }
31 op_and = @{ "and" ~ WHITESPACE }
32 op_not = @{ "not" ~ WHITESPACE }
33 op_lte = { "<=" }
34 op_gte = { ">=" }
35 op_lt = { "<" }
36 op_gt = { ">" }
37 op_eq = { "==" }
38 op_ineq = { "!=" }
39 op_plus = { "+" }
40 op_minus = { "-" }
41 op_times = { "*" }
42 op_slash = { "/" }
43 op_modulo = { "%" }
44
45 // -------------------------------------------------
46
47 /// Idents
48
49 all_chars = _{'a'..'z' | 'A'..'Z' | "_" | '0'..'9'}
50 // Used everywhere where an ident is used, except when accessing
51 // data from the context.
52 // Eg block name, argument name, macro name etc
53 ident = @{
54 ('a'..'z' | 'A'..'Z' | "_") ~
55 all_chars*
56 }
57
58 // The context_ident used to get data from the context.
59 // Same as ident but allows `.` in it
60 dotted_ident = @{
61 ('a'..'z' | 'A'..'Z' | "_") ~
62 all_chars* ~
63 ("." ~ all_chars+)*
64 }
65
66 square_brackets = @{
67 "[" ~ (int | string | dotted_square_bracket_ident) ~ "]"
68 }
69
70 dotted_square_bracket_ident = @{
71 dotted_ident ~ ( ("." ~ all_chars+) | square_brackets )*
72 }
73
74 string_concat = { (fn_call | float | int | string | dotted_square_bracket_ident) ~ ("~" ~ (fn_call | float | int | string | dotted_square_bracket_ident))+ }
75
76 // ----------------------------------------------------
77
78 /// EXPRESSIONS
79 /// We'll use precedence climbing on those in the parser phase
80
81 // boolean first so they are not caught as identifiers
82 basic_val = _{ boolean | test_not | test | macro_call | fn_call | dotted_square_bracket_ident | float | int }
83 basic_op = _{ op_plus | op_minus | op_times | op_slash | op_modulo }
84 basic_expr = { ("(" ~ basic_expr ~ ")" | basic_val) ~ (basic_op ~ basic_val)* }
85 basic_expr_filter = !{ basic_expr ~ filter* }
86 string_expr_filter = !{ (string_concat | string) ~ filter* }
87
88 comparison_val = { basic_expr_filter ~ (basic_op ~ basic_expr_filter)* }
89 comparison_op = _{ op_lte | op_gte | op_gt | op_lt | op_eq | op_ineq }
90 comparison_expr = { (string_expr_filter | comparison_val) ~ (comparison_op ~ (string_expr_filter | comparison_val))? }
91
92 // The `in` operator
93 in_cond_container = {string_expr_filter | array_filter | dotted_square_bracket_ident}
94 in_cond = !{ (string_expr_filter | basic_expr_filter) ~ op_not? ~ "in" ~ in_cond_container }
95
96 logic_val = !{ op_not? ~ (in_cond | comparison_expr) }
97 logic_expr = !{ logic_val ~ ((op_or | op_and) ~ logic_val)* }
98
99 array = !{ "[" ~ (logic_val ~ ",")* ~ logic_val? ~ "]"}
100 array_filter = !{ array ~ filter* }
101
102 string_array = !{ "[" ~ (string ~ ",")* ~ string? ~ "]"}
103
104 // ----------------------------------------------------
105
106 /// FUNCTIONS & FILTERS
107
108 // A keyword argument: something=10, something="a value", something=1+10 etc
109 kwarg = { ident ~ "=" ~ (logic_expr | array_filter) }
110 kwargs = _{ kwarg ~ ("," ~ kwarg )* ~ ","? }
111 fn_call = !{ ident ~ "(" ~ kwargs? ~ ")" }
112 filter = { "|" ~ (fn_call | ident) }
113
114
115 // ------------------------------------------------------
116
117 /// MACROS
118
119 // A macro argument can have default value, only a literal though
120 macro_def_arg = ${ (ident ~ "=" ~ (boolean | string | float | int)) | ident }
121 macro_def_args = _{ macro_def_arg ~ ("," ~ macro_def_arg)* }
122 macro_fn = _{ ident ~ "(" ~ macro_def_args? ~ ")" }
123 macro_fn_wrapper = !{ macro_fn }
124 macro_call = { ident ~ "::" ~ ident ~ "(" ~ kwargs? ~ ")" }
125
126
127 // -------------------------------------------------------
128
129 /// TESTS
130
131 // It's a bit weird that tests are the only thing in Tera not using kwargs
132 // but at the same time it's one arg most of the time so...
133 test_arg = { logic_expr | array_filter }
134 test_args = _{ test_arg ~ ("," ~ test_arg)* }
135 test_call = !{ ident ~ ("(" ~ test_args ~ ")")? }
136 test_not = { dotted_ident ~ "is" ~ "not" ~ test_call }
137 test = { dotted_ident ~ "is" ~ test_call }
138
139 // -------------------------------------------------------
140
141 /// TERA
142
143 // All the blocks that Tera recognises
144 variable_start = { "{{-" | "{{" }
145 variable_end = { "-}}" | "}}" }
146 // whitespace control
147 tag_start = { "{%-" | "{%" }
148 tag_end = { "-%}" | "%}" }
149 comment_start = { "{#-" | "{#" }
150 comment_end = { "-#}" | "#}" }
151 block_start = _{ variable_start | tag_start | comment_start }
152
153 comment_text = ${ (!(comment_end) ~ ANY)+ }
154
155 // Tag marks
156 ignore_missing = { "ignore" ~ WHITESPACE* ~ "missing" }
157
158
159 // Actual tags
160 include_tag = ${ tag_start ~ WHITESPACE* ~ "include" ~ WHITESPACE+ ~ (string | string_array) ~ WHITESPACE* ~ ignore_missing? ~ WHITESPACE* ~ tag_end }
161 comment_tag = ${ comment_start ~ comment_text ~ comment_end }
162 block_tag = ${ tag_start ~ WHITESPACE* ~ "block" ~ WHITESPACE+ ~ ident ~ WHITESPACE* ~ tag_end }
163 macro_tag = ${ tag_start ~ WHITESPACE* ~ "macro" ~ WHITESPACE+ ~ macro_fn_wrapper ~ WHITESPACE* ~ tag_end }
164 if_tag = ${ tag_start ~ WHITESPACE* ~ "if" ~ WHITESPACE+ ~ logic_expr ~ WHITESPACE* ~ tag_end }
165 elif_tag = ${ tag_start ~ WHITESPACE* ~ "elif" ~ WHITESPACE+ ~ logic_expr ~ WHITESPACE* ~ tag_end }
166 else_tag = !{ tag_start ~ "else" ~ tag_end }
167 for_tag = ${
168 tag_start ~ WHITESPACE*
169 ~ "for"~ WHITESPACE+ ~ ident ~ ("," ~ WHITESPACE* ~ ident)? ~ WHITESPACE+ ~ "in" ~ WHITESPACE+ ~ (basic_expr_filter | array_filter)
170 ~ WHITESPACE* ~ tag_end
171 }
172 filter_tag = ${
173 tag_start ~ WHITESPACE*
174 ~ "filter" ~ WHITESPACE+ ~ (fn_call | ident)
175 ~ WHITESPACE* ~ tag_end
176 }
177 set_tag = ${
178 tag_start ~ WHITESPACE*
179 ~ "set" ~ WHITESPACE+ ~ ident ~ WHITESPACE* ~ "=" ~ WHITESPACE* ~ (logic_expr | array_filter)
180 ~ WHITESPACE* ~ tag_end
181 }
182 set_global_tag = ${
183 tag_start ~ WHITESPACE*
184 ~ "set_global" ~ WHITESPACE+ ~ ident ~ WHITESPACE* ~ "=" ~ WHITESPACE* ~ (logic_expr | array_filter)
185 ~ WHITESPACE* ~ tag_end
186 }
187 endblock_tag = !{ tag_start ~ "endblock" ~ ident? ~ tag_end }
188 endmacro_tag = !{ tag_start ~ "endmacro" ~ ident? ~ tag_end }
189 endif_tag = !{ tag_start ~ "endif" ~ tag_end }
190 endfor_tag = !{ tag_start ~ "endfor" ~ tag_end }
191 endfilter_tag = !{ tag_start ~ "endfilter" ~ tag_end }
192 break_tag = !{ tag_start ~ "break" ~ tag_end }
193 continue_tag = !{ tag_start ~ "continue" ~ tag_end }
194
195 variable_tag = !{ variable_start ~ (logic_expr | array_filter) ~ variable_end }
196 super_tag = !{ variable_start ~ "super()" ~ variable_end }
197
198 text = ${ (!(block_start) ~ ANY)+ }
199
200 raw_tag = !{ tag_start ~ "raw" ~ tag_end }
201 endraw_tag = !{ tag_start ~ "endraw" ~ tag_end }
202 raw_text = ${ (!endraw_tag ~ ANY)* }
203 raw = ${ raw_tag ~ raw_text ~ endraw_tag }
204
205 filter_section = ${ filter_tag ~ filter_section_content* ~ endfilter_tag }
206
207 forloop = ${ for_tag ~ for_content* ~ (else_tag ~ for_content*)* ~ endfor_tag }
208
209 macro_if = ${ if_tag ~ macro_content* ~ (elif_tag ~ macro_content*)* ~ (else_tag ~ macro_content*)? ~ endif_tag }
210 block_if = ${ if_tag ~ block_content* ~ (elif_tag ~ block_content*)* ~ (else_tag ~ block_content*)? ~ endif_tag }
211 for_if = ${ if_tag ~ for_content* ~ (elif_tag ~ for_content*)* ~ (else_tag ~ for_content*)? ~ endif_tag }
212 filter_section_if = ${ if_tag ~ filter_section_content* ~ (elif_tag ~ filter_section_content*)* ~ (else_tag ~ filter_section_content*)? ~ endif_tag }
213 content_if = ${ if_tag ~ content* ~ (elif_tag ~ content*)* ~ (else_tag ~ content*)? ~ endif_tag }
214
215 block = ${ block_tag ~ block_content* ~ endblock_tag }
216 macro_definition = ${ macro_tag ~ macro_content* ~ endmacro_tag }
217
218 filter_section_content = @{
219 include_tag |
220 variable_tag |
221 comment_tag |
222 set_tag |
223 set_global_tag |
224 block |
225 forloop |
226 filter_section_if |
227 raw |
228 filter_section |
229 text
230 }
231
232 // smaller sets of allowed content in macros
233 macro_content = @{
234 include_tag |
235 variable_tag |
236 comment_tag |
237 set_tag |
238 set_global_tag |
239 macro_if |
240 forloop |
241 filter_section |
242 raw |
243 text
244 }
245
246 // smaller set of allowed content in block
247 block_content = @{
248 include_tag |
249 super_tag |
250 variable_tag |
251 comment_tag |
252 set_tag |
253 set_global_tag |
254 block |
255 block_if |
256 forloop |
257 filter_section |
258 raw |
259 text
260 }
261
262 // set of allowed content inside for loops
263 for_content = @{
264 include_tag |
265 variable_tag |
266 comment_tag |
267 set_tag |
268 set_global_tag |
269 for_if |
270 forloop |
271 break_tag |
272 continue_tag |
273 filter_section |
274 raw |
275 text
276 }
277
278 content = @{
279 include_tag |
280 variable_tag |
281 comment_tag |
282 set_tag |
283 set_global_tag |
284 macro_definition |
285 block |
286 content_if |
287 forloop |
288 filter_section |
289 raw |
290 text
291 }
292
293 extends_tag = ${
294 WHITESPACE* ~ tag_start ~ WHITESPACE*
295 ~ "extends" ~ WHITESPACE+ ~ string
296 ~ WHITESPACE* ~ tag_end ~ WHITESPACE*
297 }
298 import_macro_tag = ${
299 WHITESPACE* ~ tag_start ~ WHITESPACE*
300 ~ "import" ~ WHITESPACE+ ~ string ~ WHITESPACE+ ~ "as" ~ WHITESPACE+ ~ ident
301 ~ WHITESPACE* ~ tag_end ~ WHITESPACE*
302 }
303 top_imports = _{
304 (extends_tag ~ import_macro_tag*)
305 |
306 (import_macro_tag+ ~ extends_tag?)
307 }
308
309 // top level rule
310 template = ${
311 SOI
312 ~ comment_tag*
313 ~ top_imports?
314 ~ content*
315 ~ EOI
316 }