]> git.proxmox.com Git - rustc.git/blob - src/vendor/handlebars/src/grammar.rs
New upstream version 1.20.0+dfsg1
[rustc.git] / src / vendor / handlebars / src / grammar.rs
1 use pest::prelude::*;
2
3 #[cfg(feature="partial_legacy")]
4 impl_rdp! {
5 grammar! {
6 whitespace = _{ [" "]|["\t"]|["\n"]|["\r"] }
7
8 raw_text = @{ ( ["\\{{{{"]? ~ ["\\{{"]? ~ !["{{"] ~ any )+ }
9 raw_block_text = @{ ( !["{{{{"] ~ any )* }
10
11 // Note: this is not full and strict json literal definition, just for tokenize string,
12 // array and object types which may contains whitespace. We will use a real json parser
13 // for real json processing
14 literal = { string_literal |
15 array_literal |
16 object_literal |
17 number_literal |
18 null_literal |
19 boolean_literal }
20
21 null_literal = { ["null"] }
22 boolean_literal = { ["true"]|["false"] }
23 number_literal = @{ ["-"]? ~ ['0'..'9']+ ~ ["."]? ~ ['0'..'9']* ~ (["E"] ~ ["-"]? ~ ['0'..'9']+)? }
24 string_literal = @{ ["\""] ~ (!["\""] ~ (["\\\""] | any))* ~ ["\""] }
25 array_literal = { ["["] ~ literal? ~ ([","] ~ literal)* ~ ["]"] }
26 object_literal = { ["{"] ~ (string_literal ~ [":"] ~ literal)? ~ ([","] ~ string_literal ~ [":"] ~ literal)* ~ ["}"] }
27
28 // FIXME: a[0], a["b]
29 symbol_char = _{ ['a'..'z']|['A'..'Z']|['0'..'9']|["_"]|["."]|["@"]|["$"]|["-"]|["<"]|[">"] }
30 path_char = _{ ["/"] }
31
32 identifier = @{ symbol_char ~ ( symbol_char | path_char )* }
33 reference = @{ identifier ~ (["["] ~ (string_literal|['0'..'9']+) ~ ["]"])* ~ ["-"]* ~ reference* }
34 name = _{ subexpression | reference }
35
36 param = { !["as"] ~ (literal | reference | subexpression) }
37 hash = { identifier ~ ["="] ~ param }
38 block_param = { ["as"] ~ ["|"] ~ identifier ~ identifier? ~ ["|"]}
39 exp_line = _{ identifier ~ (hash|param)* ~ block_param?}
40 partial_exp_line = _{ name ~ (hash|param)* }
41
42 subexpression = { ["("] ~ name ~ (hash|param)* ~ [")"] }
43
44 pre_whitespace_omitter = { ["~"] }
45 pro_whitespace_omitter = { ["~"] }
46 escape = { ["\\"] }
47
48 expression = { !escape ~ !invert_tag ~ ["{{"] ~ pre_whitespace_omitter? ~ name ~
49 pro_whitespace_omitter? ~ ["}}"] }
50
51 html_expression = { !escape ~ ["{{{"] ~ pre_whitespace_omitter? ~ name ~
52 pro_whitespace_omitter? ~ ["}}}"] }
53
54 helper_expression = { !escape ~ !invert_tag ~ ["{{"] ~ pre_whitespace_omitter? ~ exp_line ~
55 pro_whitespace_omitter? ~ ["}}"] }
56
57 directive_expression = { !escape ~ ["{{"] ~ pre_whitespace_omitter? ~ ["*"] ~ exp_line ~
58 pro_whitespace_omitter? ~ ["}}"] }
59 partial_expression = { !escape ~ ["{{"] ~ pre_whitespace_omitter? ~ [">"] ~ partial_exp_line ~
60 pro_whitespace_omitter? ~ ["}}"] }
61
62 invert_tag_item = { ["else"]|["^"] }
63 invert_tag = { !escape ~ ["{{"] ~ pre_whitespace_omitter? ~ invert_tag_item
64 ~ pro_whitespace_omitter? ~ ["}}"]}
65
66 helper_block_start = { !escape ~ ["{{"] ~ pre_whitespace_omitter? ~ ["#"] ~ exp_line ~
67 pro_whitespace_omitter? ~ ["}}"] }
68 helper_block_end = { !escape ~ ["{{"] ~ pre_whitespace_omitter? ~ ["/"] ~ name ~
69 pro_whitespace_omitter? ~ ["}}"] }
70 helper_block = _{ helper_block_start ~ template ~
71 (invert_tag ~ template)? ~
72 helper_block_end }
73
74 directive_block_start = { !escape ~ ["{{"] ~ pre_whitespace_omitter? ~ ["#"] ~ ["*"] ~ exp_line ~
75 pro_whitespace_omitter? ~ ["}}"] }
76 directive_block_end = { !escape ~ ["{{"] ~ pre_whitespace_omitter? ~ ["/"] ~ name ~
77 pro_whitespace_omitter? ~ ["}}"] }
78 directive_block = _{ directive_block_start ~ template ~
79 directive_block_end }
80
81 partial_block_start = { !escape ~ ["{{"] ~ pre_whitespace_omitter? ~ ["#"] ~ [">"] ~ partial_exp_line ~
82 pro_whitespace_omitter? ~ ["}}"] }
83 partial_block_end = { !escape ~ ["{{"] ~ pre_whitespace_omitter? ~ ["/"] ~ name ~
84 pro_whitespace_omitter? ~ ["}}"] }
85 partial_block = _{ partial_block_start ~ template ~ partial_block_end }
86
87 raw_block_start = { !escape ~ ["{{{{"] ~ pre_whitespace_omitter? ~ exp_line ~
88 pro_whitespace_omitter? ~ ["}}}}"] }
89 raw_block_end = { !escape ~ ["{{{{"] ~ pre_whitespace_omitter? ~ ["/"] ~ name ~
90 pro_whitespace_omitter? ~ ["}}}}"] }
91 raw_block = _{ raw_block_start ~ raw_block_text ~ raw_block_end }
92
93 hbs_comment = { !escape ~ ["{{!"] ~ (!["}}"] ~ any)* ~ ["}}"] }
94
95 template = { (
96 raw_text |
97 expression |
98 html_expression |
99 helper_expression |
100 helper_block |
101 raw_block |
102 hbs_comment |
103 directive_expression |
104 directive_block )*
105 }
106
107 parameter = _{ param ~ eoi }
108 handlebars = _{ template ~ eoi }
109
110 // json path visitor
111 path_ident = _{ ['a'..'z']|['A'..'Z']|['0'..'9']|["_"]|["@"]|["$"]|["<"]|[">"]|["-"]}
112 path_id = { path_ident+ }
113 path_num_id = { ['0'..'9']+ }
114 path_raw_id = { (path_ident|["/"])* }
115 path_sep = _{ ["/"] | ["."] }
116 path_up = { [".."] }
117 path_var = { path_id }
118 path_key = { ["["] ~ (["\""]|["'"])? ~ path_raw_id ~ (["\""]|["'"])? ~ ["]"] }
119 path_idx = { ["["] ~ path_num_id ~ ["]"]}
120 path_item = _{ path_up|path_var }
121 path = _{ ["./"]? ~ path_item ~ ((path_sep ~ path_item) | (path_sep? ~ (path_key | path_idx)))* ~ eoi }
122 }
123 }
124
125 #[cfg(not(feature="partial_legacy"))]
126 impl_rdp! {
127 grammar! {
128 whitespace = _{ [" "]|["\t"]|["\n"]|["\r"] }
129
130 raw_text = @{ ( ["\\{{{{"]? ~ ["\\{{"]? ~ !["{{"] ~ any )+ }
131 raw_block_text = @{ ( !["{{{{"] ~ any )* }
132
133 // Note: this is not full and strict json literal definition, just for tokenize string,
134 // array and object types which may contains whitespace. We will use a real json parser
135 // for real json processing
136 literal = { string_literal |
137 array_literal |
138 object_literal |
139 number_literal |
140 null_literal |
141 boolean_literal }
142
143 null_literal = { ["null"] }
144 boolean_literal = { ["true"]|["false"] }
145 number_literal = @{ ["-"]? ~ ['0'..'9']+ ~ ["."]? ~ ['0'..'9']* ~ (["E"] ~ ["-"]? ~ ['0'..'9']+)? }
146 string_literal = @{ ["\""] ~ (!["\""] ~ (["\\\""] | any))* ~ ["\""] }
147 array_literal = { ["["] ~ literal? ~ ([","] ~ literal)* ~ ["]"] }
148 object_literal = { ["{"] ~ (string_literal ~ [":"] ~ literal)? ~ ([","] ~ string_literal ~ [":"] ~ literal)* ~ ["}"] }
149
150 // FIXME: a[0], a["b]
151 symbol_char = _{ ['a'..'z']|['A'..'Z']|['0'..'9']|["_"]|["."]|["@"]|["$"]|["-"] }
152 path_char = _{ ["/"] }
153
154 identifier = @{ symbol_char ~ ( symbol_char | path_char )* }
155 reference = @{ identifier ~ (["["] ~ (string_literal|['0'..'9']+) ~ ["]"])* ~ ["-"]* ~ reference* }
156 name = _{ subexpression | reference }
157
158 param = { !["as"] ~ (literal | reference | subexpression) }
159 hash = { identifier ~ ["="] ~ param }
160 block_param = { ["as"] ~ ["|"] ~ identifier ~ identifier? ~ ["|"]}
161 exp_line = _{ identifier ~ (hash|param)* ~ block_param?}
162 partial_exp_line = _{ name ~ (hash|param)* }
163
164 subexpression = { ["("] ~ name ~ (hash|param)* ~ [")"] }
165
166 pre_whitespace_omitter = { ["~"] }
167 pro_whitespace_omitter = { ["~"] }
168 escape = { ["\\"] }
169
170 expression = { !escape ~ !invert_tag ~ ["{{"] ~ pre_whitespace_omitter? ~ name ~
171 pro_whitespace_omitter? ~ ["}}"] }
172
173 html_expression = { !escape ~ ["{{{"] ~ pre_whitespace_omitter? ~ name ~
174 pro_whitespace_omitter? ~ ["}}}"] }
175
176 helper_expression = { !invert_tag ~ ["{{"] ~ pre_whitespace_omitter? ~ exp_line ~
177 pro_whitespace_omitter? ~ ["}}"] }
178
179 directive_expression = { !escape ~ ["{{"] ~ pre_whitespace_omitter? ~ ["*"] ~ exp_line ~
180 pro_whitespace_omitter? ~ ["}}"] }
181 partial_expression = { !escape ~ ["{{"] ~ pre_whitespace_omitter? ~ [">"] ~ partial_exp_line ~
182 pro_whitespace_omitter? ~ ["}}"] }
183 invert_tag_item = { ["else"]|["^"] }
184 invert_tag = { !escape ~ ["{{"] ~ pre_whitespace_omitter? ~ invert_tag_item
185 ~ pro_whitespace_omitter? ~ ["}}"]}
186 helper_block_start = { !escape ~ ["{{"] ~ pre_whitespace_omitter? ~ ["#"] ~ exp_line ~
187 pro_whitespace_omitter? ~ ["}}"] }
188 helper_block_end = { !escape ~ ["{{"] ~ pre_whitespace_omitter? ~ ["/"] ~ name ~
189 pro_whitespace_omitter? ~ ["}}"] }
190 helper_block = _{ helper_block_start ~ template ~
191 (invert_tag ~ template)? ~
192 helper_block_end }
193
194 directive_block_start = { !escape ~ ["{{"] ~ pre_whitespace_omitter? ~ ["#"] ~ ["*"] ~ exp_line ~
195 pro_whitespace_omitter? ~ ["}}"] }
196 directive_block_end = { !escape ~ ["{{"] ~ pre_whitespace_omitter? ~ ["/"] ~ name ~
197 pro_whitespace_omitter? ~ ["}}"] }
198 directive_block = _{ directive_block_start ~ template ~
199 directive_block_end }
200
201 partial_block_start = { !escape ~ ["{{"] ~ pre_whitespace_omitter? ~ ["#"] ~ [">"] ~ partial_exp_line ~
202 pro_whitespace_omitter? ~ ["}}"] }
203 partial_block_end = { !escape ~ ["{{"] ~ pre_whitespace_omitter? ~ ["/"] ~ name ~
204 pro_whitespace_omitter? ~ ["}}"] }
205 partial_block = _{ partial_block_start ~ template ~ partial_block_end }
206
207 raw_block_start = { !escape ~ ["{{{{"] ~ pre_whitespace_omitter? ~ exp_line ~
208 pro_whitespace_omitter? ~ ["}}}}"] }
209 raw_block_end = { !escape ~ ["{{{{"] ~ pre_whitespace_omitter? ~ ["/"] ~ name ~
210 pro_whitespace_omitter? ~ ["}}}}"] }
211 raw_block = _{ raw_block_start ~ raw_block_text ~ raw_block_end }
212
213 hbs_comment = { !escape ~ ["{{!"] ~ (!["}}"] ~ any)* ~ ["}}"] }
214
215 template = { (
216 raw_text |
217 expression |
218 html_expression |
219 helper_expression |
220 helper_block |
221 raw_block |
222 hbs_comment |
223 directive_expression |
224 directive_block |
225 partial_expression |
226 partial_block )*
227 }
228
229 parameter = _{ param ~ eoi }
230 handlebars = _{ template ~ eoi }
231
232 // json path visitor
233 path_ident = _{ ['a'..'z']|['A'..'Z']|['0'..'9']|["_"]|["@"]|["$"]|["<"]|[">"]|["-"]}
234 path_id = { path_ident+ }
235 path_num_id = { ['0'..'9']+ }
236 path_raw_id = { (path_ident|["/"])* }
237 path_sep = _{ ["/"] | ["."] }
238 path_up = { [".."] }
239 path_var = { path_id }
240 path_key = { ["["] ~ (["\""]|["'"])? ~ path_raw_id ~ (["\""]|["'"])? ~ ["]"] }
241 path_idx = { ["["] ~ path_num_id ~ ["]"]}
242 path_item = _{ path_up|path_var }
243 path = _{ ["./"]? ~ path_item ~ ((path_sep ~ path_item) | (path_sep? ~ (path_key | path_idx)))* ~ eoi }
244 }
245 }
246
247 #[test]
248 fn test_raw_text() {
249 let s = vec!["<h1> helloworld </h1> ",
250 "hello\\{{world}}",
251 "hello\\{{#if world}}nice\\{{/if}}",
252 "hello \\{{{{raw}}}}hello\\{{{{/raw}}}}"];
253 for i in s.iter() {
254 let mut rdp = Rdp::new(StringInput::new(i));
255 assert!(rdp.raw_text());
256 assert!(rdp.end());
257 }
258 }
259
260 #[test]
261 fn test_raw_block_text() {
262 let mut rdp = Rdp::new(StringInput::new("<h1> {{hello}} </h1>"));
263 assert!(rdp.raw_block_text());
264 assert!(rdp.end());
265 }
266
267 #[test]
268 fn test_reference() {
269 let s = vec!["a",
270 "abc",
271 "../a",
272 "a.b",
273 "@abc",
274 "a[\"abc\"]",
275 "aBc[\"abc\"]",
276 "abc[0][\"nice\"]",
277 "some-name",
278 "this.[0].ok"];
279 for i in s.iter() {
280 let mut rdp = Rdp::new(StringInput::new(i));
281 assert!(rdp.reference());
282 assert!(rdp.end());
283 }
284 }
285
286 #[test]
287 fn test_name() {
288 let s = vec!["if", "(abc)"];
289 for i in s.iter() {
290 let mut rdp = Rdp::new(StringInput::new(i));
291 assert!(rdp.name());
292 assert!(rdp.end());
293 }
294 }
295
296 #[test]
297 fn test_param() {
298 let s = vec!["hello", "\"json literal\""];
299 for i in s.iter() {
300 let mut rdp = Rdp::new(StringInput::new(i));
301 assert!(rdp.param());
302 assert!(rdp.end());
303 }
304 }
305
306 #[test]
307 fn test_hash() {
308 let s = vec!["hello=world", "hello=\"world\"", "hello=(world)", "hello=(world 0)"];
309 for i in s.iter() {
310 let mut rdp = Rdp::new(StringInput::new(i));
311 assert!(rdp.hash());
312 assert!(rdp.end());
313 }
314 }
315
316 #[test]
317 fn test_json_literal() {
318 let s = vec!["\"json string\"",
319 "\"quot: \\\"\"",
320 "[]",
321 "[\"hello\"]",
322 "[1,2,3,4,true]",
323 "{\"hello\": \"world\"}",
324 "{}",
325 "{\"a\":1, \"b\":2 }"];
326 for i in s.iter() {
327 let mut rdp = Rdp::new(StringInput::new(i));
328 assert!(rdp.literal());
329 assert!(rdp.end());
330 }
331 }
332
333 #[test]
334 fn test_comment() {
335 let s = vec!["{{! hello }}"];
336 for i in s.iter() {
337 let mut rdp = Rdp::new(StringInput::new(i));
338 assert!(rdp.hbs_comment());
339 assert!(rdp.end());
340 }
341 }
342
343 #[test]
344 fn test_subexpression() {
345 let s = vec!["(sub)", "(sub 0)", "(sub a=1)"];
346 for i in s.iter() {
347 let mut rdp = Rdp::new(StringInput::new(i));
348 assert!(rdp.subexpression());
349 assert!(rdp.end());
350 }
351 }
352
353 #[test]
354 fn test_expression() {
355 let s = vec!["{{exp}}", "{{(exp)}}", "{{this.name}}", "{{this.[0].name}}"];
356 for i in s.iter() {
357 let mut rdp = Rdp::new(StringInput::new(i));
358 assert!(rdp.expression());
359 assert!(rdp.end());
360 }
361 }
362
363 #[test]
364 fn test_helper_expression() {
365 let s = vec!["{{exp 1}}",
366 "{{exp \"literal\"}}",
367 "{{exp ref}}",
368 "{{exp (sub)}}",
369 "{{exp (sub 123)}}",
370 "{{exp []}}",
371 "{{exp {}}}",
372 "{{exp key=1}}",
373 "{{exp key=ref}}",
374 "{{exp key=(sub)}}",
375 "{{exp key=(sub 0)}}"];
376 for i in s.iter() {
377 let mut rdp = Rdp::new(StringInput::new(i));
378 assert!(rdp.helper_expression());
379 assert!(rdp.end());
380 }
381 }
382
383
384 #[test]
385 fn test_identifier_with_dash() {
386 let s = vec!["{{exp-foo}}"];
387 for i in s.iter() {
388 let mut rdp = Rdp::new(StringInput::new(i));
389 assert!(rdp.expression());
390 assert!(rdp.end());
391 }
392 }
393
394
395 #[test]
396 fn test_html_expression() {
397 let s = vec!["{{{html}}}", "{{{(html)}}}", "{{{(html)}}}"];
398 for i in s.iter() {
399 let mut rdp = Rdp::new(StringInput::new(i));
400 assert!(rdp.html_expression());
401 assert!(rdp.end());
402 }
403 }
404
405 #[test]
406 fn test_helper_start() {
407 let s = vec!["{{#if hello}}",
408 "{{#if (hello)}}",
409 "{{#if hello=world}}",
410 "{{#if hello hello=world}}",
411 "{{#if []}}",
412 "{{#if {}}}",
413 "{{#if}}",
414 "{{~#if hello~}}",
415 "{{#each people as |person|}}",
416 "{{#each-obj obj as |key val|}}"];
417 for i in s.iter() {
418 let mut rdp = Rdp::new(StringInput::new(i));
419 assert!(rdp.helper_block_start());
420 assert!(rdp.end());
421 }
422 }
423
424 #[test]
425 fn test_helper_end() {
426 let s = vec!["{{/if}}", "{{~/if}}", "{{~/if ~}}", "{{/if ~}}"];
427 for i in s.iter() {
428 let mut rdp = Rdp::new(StringInput::new(i));
429 assert!(rdp.helper_block_end());
430 assert!(rdp.end());
431 }
432 }
433
434 #[test]
435 fn test_helper_block() {
436 let s = vec!["{{#if hello}}hello{{/if}}",
437 "{{#if true}}hello{{/if}}",
438 "{{#if nice ok=1}}hello{{/if}}",
439 "{{#if}}hello{{else}}world{{/if}}",
440 "{{#if}}hello{{^}}world{{/if}}",
441 "{{#if}}{{#if}}hello{{/if}}{{/if}}",
442 "{{#if}}hello{{~else}}world{{/if}}",
443 "{{#if}}hello{{else~}}world{{/if}}",
444 "{{#if}}hello{{~^~}}world{{/if}}",
445 "{{#if}}{{/if}}"];
446 for i in s.iter() {
447 let mut rdp = Rdp::new(StringInput::new(i));
448 assert!(rdp.helper_block());
449 assert!(rdp.end());
450 }
451 }
452
453 #[test]
454 fn test_raw_block() {
455 let s = vec!["{{{{if hello}}}}good {{hello}}{{{{/if}}}}",
456 "{{{{if hello}}}}{{#if nice}}{{/if}}{{{{/if}}}}"];
457 for i in s.iter() {
458 let mut rdp = Rdp::new(StringInput::new(i));
459 assert!(rdp.raw_block());
460 assert!(rdp.end());
461 }
462 }
463
464 #[test]
465 fn test_block_param() {
466 let s = vec!["as |person|", "as |key val|"];
467 for i in s.iter() {
468 let mut rdp = Rdp::new(StringInput::new(i));
469 assert!(rdp.block_param());
470 assert!(rdp.end());
471 }
472 }
473
474 #[test]
475 fn test_path() {
476 let s = vec!["a",
477 "a.b.c.d",
478 "a[0][1][2]",
479 "a[\"abc\"]",
480 "a/v/c.d.s",
481 "a[0]/b/c/../d",
482 "a[\"bbc\"]/b/c/../d",
483 "../a/b[0][1]",
484 "./this[0][1]/this/../a",
485 "./this_name",
486 "./goo[/bar]"];
487 for i in s.iter() {
488 let mut rdp = Rdp::new(StringInput::new(i));
489 assert!(rdp.path());
490 assert!(rdp.end());
491 }
492 }
493
494 #[test]
495 fn test_directive_expression() {
496 let s = vec!["{{* ssh}}", "{{~* ssh}}"];
497 for i in s.iter() {
498 let mut rdp = Rdp::new(StringInput::new(i));
499 assert!(rdp.directive_expression());
500 assert!(rdp.end());
501 }
502 }
503
504 #[test]
505 fn test_directive_block() {
506 let s = vec!["{{#* inline}}something{{/inline}}",
507 "{{~#* inline}}hello{{/inline}}",
508 "{{#* inline \"partialname\"}}something{{/inline}}"];
509 for i in s.iter() {
510 let mut rdp = Rdp::new(StringInput::new(i));
511 assert!(rdp.directive_block());
512 assert!(rdp.end());
513 }
514 }
515
516 #[test]
517 fn test_partial_expression() {
518 let s = vec!["{{> hello}}", "{{> (hello)}}", "{{~> hello a}}", "{{> hello a=1}}"];
519 for i in s.iter() {
520 let mut rdp = Rdp::new(StringInput::new(i));
521 assert!(rdp.partial_expression());
522 assert!(rdp.end());
523 }
524 }
525
526 #[test]
527 fn test_partial_block() {
528 let s = vec!["{{#> hello}}nice{{/hello}}"];
529 for i in s.iter() {
530 let mut rdp = Rdp::new(StringInput::new(i));
531 assert!(rdp.partial_block());
532 assert!(rdp.end());
533 }
534 }