1use logos::{Lexer, Logos};
18pub use rowan::Direction;
19pub use rowan::GreenNode;
22pub use rowan::GreenNodeBuilder;
26pub use rowan::Language;
27pub use rowan::SyntaxText;
28pub use rowan::TextLen;
29pub use rowan::TextRange;
30pub use rowan::TextSize;
31pub use rowan::WalkEvent;
32use std::fmt;
33use std::fmt::Formatter;
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Logos)]
36#[allow(non_camel_case_types)]
37#[repr(u16)]
38pub enum SyntaxKind {
39 #[regex(r"[ \t]+")]
44 TK_WHITESPACE = 0,
45 #[regex(r"((\n)|(\r\n))+")]
46 TK_LINE_BREAK,
47 #[regex(r"([a-zA-Z]|([@\#_\$][a-zA-Z])|_)[a-zA-Z0-9_\-]*")]
51 TK_WORD,
52 #[regex(r"twig(\:[a-zA-Z0-9_\-]+)+")]
54 TK_TWIG_COMPONENT_NAME,
55 #[regex(r"[0-9]+(\.[0-9]+)?([Ee][\+\-][0-9]+)?")]
57 TK_NUMBER,
58 #[regex(r"\&(([a-zA-Z][a-zA-Z0-9]*)|(\#[0-9]+)|(\#x[0-9a-fA-F]+));")]
60 TK_HTML_ESCAPE_CHARACTER,
61 #[token(".")]
62 TK_DOT,
63 #[token("..")]
64 TK_DOUBLE_DOT,
65 #[token("...")]
66 TK_TRIPLE_DOT,
67 #[token(",")]
68 TK_COMMA,
69 #[token(":")]
70 TK_COLON,
71 #[token(";")]
72 TK_SEMICOLON,
73 #[token("!")]
74 TK_EXCLAMATION_MARK,
75 #[token("!=")]
76 TK_EXCLAMATION_MARK_EQUALS,
77 #[token("!==")]
78 TK_EXCLAMATION_MARK_DOUBLE_EQUALS,
79 #[token("?")]
80 TK_QUESTION_MARK,
81 #[token("??")]
82 TK_DOUBLE_QUESTION_MARK,
83 #[token("%")]
84 TK_PERCENT,
85 #[token("~")]
86 TK_TILDE,
87 #[token("|")]
88 TK_SINGLE_PIPE,
89 #[token("||")]
90 TK_DOUBLE_PIPE,
91 #[token("&")]
92 TK_AMPERSAND,
93 #[token("&&")]
94 TK_DOUBLE_AMPERSAND,
95 #[token("/")]
96 TK_FORWARD_SLASH,
97 #[token("//")]
98 TK_DOUBLE_FORWARD_SLASH,
99 #[token("\\")]
100 TK_BACKWARD_SLASH,
101 #[token("(")]
102 TK_OPEN_PARENTHESIS,
103 #[token(")")]
104 TK_CLOSE_PARENTHESIS,
105 #[token("{")]
106 TK_OPEN_CURLY,
107 #[token("}")]
108 TK_CLOSE_CURLY,
109 #[token("[")]
110 TK_OPEN_SQUARE,
111 #[token("]")]
112 TK_CLOSE_SQUARE,
113 #[token("<")]
114 TK_LESS_THAN,
115 #[token("<=")]
116 TK_LESS_THAN_EQUAL,
117 #[token("<=>")]
118 TK_LESS_THAN_EQUAL_GREATER_THAN,
119 #[token("</")]
120 TK_LESS_THAN_SLASH,
121 #[token("<!")]
122 TK_LESS_THAN_EXCLAMATION_MARK,
123 #[token("DOCTYPE", ignore(case))]
124 TK_DOCTYPE,
125 #[token(">")]
126 TK_GREATER_THAN,
127 #[token(">=")]
128 TK_GREATER_THAN_EQUAL,
129 #[token("=>")]
130 TK_EQUAL_GREATER_THAN,
131 #[token("/>")]
132 TK_SLASH_GREATER_THAN,
133 #[token("<!--")]
134 TK_LESS_THAN_EXCLAMATION_MARK_MINUS_MINUS,
135 #[token("-->")]
136 TK_MINUS_MINUS_GREATER_THAN,
137 #[token("=")]
138 TK_EQUAL,
139 #[token("==")]
140 TK_DOUBLE_EQUAL,
141 #[token("===")]
142 TK_TRIPLE_EQUAL,
143 #[token("+")]
144 TK_PLUS,
145 #[token("-")]
146 TK_MINUS,
147 #[token("*")]
148 TK_STAR,
149 #[token("**")]
150 TK_DOUBLE_STAR,
151 #[token("\"")]
152 TK_DOUBLE_QUOTES,
153 #[token("'")]
154 TK_SINGLE_QUOTES,
155 #[token("`")]
156 TK_GRAVE_ACCENT_QUOTES,
157 #[token("{%")]
158 TK_CURLY_PERCENT,
159 #[token("%}")]
160 TK_PERCENT_CURLY,
161 #[token("{{")]
162 TK_OPEN_CURLY_CURLY,
163 #[token("}}")]
164 TK_CLOSE_CURLY_CURLY,
165 #[token("{#")]
166 TK_OPEN_CURLY_HASHTAG,
167 #[token("#}")]
168 TK_HASHTAG_CLOSE_CURLY,
169 #[token("#")]
170 TK_HASHTAG,
171
172 #[token("true", ignore(case))]
173 TK_TRUE,
174 #[token("false", ignore(case))]
175 TK_FALSE,
176
177 #[token("block")]
179 TK_BLOCK,
180 #[token("endblock")]
181 TK_ENDBLOCK,
182 #[token("if")]
183 TK_IF,
184 #[token("elseif")]
185 TK_ELSE_IF,
186 #[token("else")]
187 TK_ELSE,
188 #[token("endif")]
189 TK_ENDIF,
190 #[token("apply")]
191 TK_APPLY,
192 #[token("endapply")]
193 TK_ENDAPPLY,
194 #[token("autoescape")]
195 TK_AUTOESCAPE,
196 #[token("endautoescape")]
197 TK_ENDAUTOESCAPE,
198 #[token("cache")]
199 TK_CACHE,
200 #[token("endcache")]
201 TK_ENDCACHE,
202 #[token("deprecated")]
203 TK_DEPRECATED,
204 #[token("do")]
205 TK_DO,
206 #[token("embed")]
207 TK_EMBED,
208 #[token("endembed")]
209 TK_ENDEMBED,
210 #[token("extends")]
211 TK_EXTENDS,
212 #[token("flush")]
213 TK_FLUSH,
214 #[token("for")]
215 TK_FOR,
216 #[token("endfor")]
217 TK_ENDFOR,
218 #[token("from")]
219 TK_FROM,
220 #[token("import")]
221 TK_IMPORT,
222 #[token("macro")]
223 TK_MACRO,
224 #[token("endmacro")]
225 TK_ENDMACRO,
226 #[token("sandbox")]
227 TK_SANDBOX,
228 #[token("endsandbox")]
229 TK_ENDSANDBOX,
230 #[token("set")]
231 TK_SET,
232 #[token("endset")]
233 TK_ENDSET,
234 #[token("use")]
235 TK_USE,
236 #[token("verbatim")]
237 TK_VERBATIM,
238 #[token("endverbatim")]
239 TK_ENDVERBATIM,
240 #[token("only")]
241 TK_ONLY,
242 #[token("ignore missing")]
243 TK_IGNORE_MISSING,
244 #[token("with")]
245 TK_WITH,
246 #[token("endwith")]
247 TK_ENDWITH,
248 #[token("ttl")]
249 TK_TTL,
250 #[token("tags")]
251 TK_TAGS,
252 #[token("props")]
253 TK_PROPS,
254 #[token("component")]
255 TK_COMPONENT,
256 #[token("endcomponent")]
257 TK_ENDCOMPONENT,
258 #[token("not", cb_not)]
260 TK_NOT,
261 TK_NOT_IN,
262 #[token("or")]
263 TK_OR,
264 #[token("and")]
265 TK_AND,
266 #[token("b-or")]
267 TK_BINARY_OR,
268 #[token("b-xor")]
269 TK_BINARY_XOR,
270 #[token("b-and")]
271 TK_BINARY_AND,
272 #[token("in")]
273 TK_IN,
274 #[token("matches")]
275 TK_MATCHES,
276 #[token("starts with")]
277 TK_STARTS_WITH,
278 #[token("ends with")]
279 TK_ENDS_WITH,
280 #[token("is", cb_is)]
281 TK_IS,
282 TK_IS_NOT,
283 #[token("even")]
285 TK_EVEN,
286 #[token("odd")]
287 TK_ODD,
288 #[token("defined")]
289 TK_DEFINED,
290 #[token("same as")]
291 TK_SAME_AS,
292 #[token("as")]
293 TK_AS,
294 #[token("none", ignore(case))]
295 TK_NONE,
296 #[token("null", ignore(case))]
297 TK_NULL,
298 #[token("divisible by")]
299 TK_DIVISIBLE_BY,
300 #[token("constant")]
301 TK_CONSTANT,
302 #[token("empty")]
303 TK_EMPTY,
304 #[token("iterable")]
305 TK_ITERABLE,
306 #[token("max")]
308 TK_MAX,
309 #[token("min")]
310 TK_MIN,
311 #[token("range")]
312 TK_RANGE,
313 #[token("cycle")]
314 TK_CYCLE,
315 #[token("random")]
316 TK_RANDOM,
317 #[token("date")]
318 TK_DATE,
319 #[token("include")]
320 TK_INCLUDE,
321 #[token("source")]
322 TK_SOURCE,
323
324 #[token("trans")]
326 TK_TRANS,
327 #[token("endtrans")]
328 TK_ENDTRANS,
329
330 #[token("sw_extends")]
332 TK_SW_EXTENDS,
333 #[token("sw_silent_feature_call")]
334 TK_SW_SILENT_FEATURE_CALL,
335 #[token("endsw_silent_feature_call")]
336 TK_ENDSW_SILENT_FEATURE_CALL,
337 #[token("sw_include")]
338 TK_SW_INCLUDE,
339 #[token("return")]
340 TK_RETURN,
341 #[token("sw_icon")]
342 TK_SW_ICON,
343 #[token("sw_thumbnails")]
344 TK_SW_THUMBNAILS,
345 #[token("style")]
346 TK_STYLE,
347 #[token("sw_embed")]
348 TK_SW_EMBED,
349 #[token("sw_end_embed")]
350 TK_SW_END_EMBED,
351 #[token("sw_use")]
352 TK_SW_USE,
353 #[token("sw_import")]
354 TK_SW_IMPORT,
355 #[token("sw_from")]
356 TK_SW_FROM,
357
358 #[token("ludtwig-ignore-file", ignore(case))]
360 TK_LUDTWIG_IGNORE_FILE,
361 #[token("ludtwig-ignore", ignore(case))]
362 TK_LUDTWIG_IGNORE,
363 TK_UNKNOWN, BODY,
370 TWIG_VAR,
371 TWIG_EXPRESSION, TWIG_BINARY_EXPRESSION,
373 TWIG_UNARY_EXPRESSION,
374 TWIG_PARENTHESES_EXPRESSION,
375 TWIG_CONDITIONAL_EXPRESSION,
376
377 TWIG_OPERAND, TWIG_ACCESSOR, TWIG_FILTER, TWIG_INDEX_LOOKUP, TWIG_INDEX, TWIG_INDEX_RANGE, TWIG_FUNCTION_CALL,
386 TWIG_ARROW_FUNCTION, TWIG_ARGUMENTS,
388 TWIG_NAMED_ARGUMENT,
389
390 TWIG_LITERAL_STRING,
392 TWIG_LITERAL_STRING_INNER,
393 TWIG_LITERAL_STRING_INTERPOLATION,
394 TWIG_LITERAL_NUMBER,
395 TWIG_LITERAL_ARRAY,
396 TWIG_LITERAL_ARRAY_INNER,
397 TWIG_LITERAL_NULL,
398 TWIG_LITERAL_BOOLEAN,
399 TWIG_LITERAL_HASH,
400 TWIG_LITERAL_HASH_ITEMS,
401 TWIG_LITERAL_HASH_PAIR,
402 TWIG_LITERAL_HASH_KEY,
403 TWIG_LITERAL_HASH_VALUE,
404 TWIG_LITERAL_NAME,
405
406 TWIG_COMMENT,
408 TWIG_BLOCK,
410 TWIG_STARTING_BLOCK,
411 TWIG_ENDING_BLOCK,
412 TWIG_IF,
414 TWIG_IF_BLOCK,
415 TWIG_ELSE_IF_BLOCK,
416 TWIG_ELSE_BLOCK,
417 TWIG_ENDIF_BLOCK,
418 TWIG_SET,
420 TWIG_SET_BLOCK,
421 TWIG_ENDSET_BLOCK,
422 TWIG_ASSIGNMENT,
423 TWIG_FOR,
425 TWIG_FOR_BLOCK,
426 TWIG_FOR_ELSE_BLOCK,
427 TWIG_ENDFOR_BLOCK,
428 TWIG_EXTENDS,
430 TWIG_INCLUDE,
432 TWIG_INCLUDE_WITH,
433 TWIG_USE,
435 TWIG_OVERRIDE,
436 TWIG_APPLY,
438 TWIG_APPLY_STARTING_BLOCK,
439 TWIG_APPLY_ENDING_BLOCK,
440 TWIG_AUTOESCAPE,
442 TWIG_AUTOESCAPE_STARTING_BLOCK,
443 TWIG_AUTOESCAPE_ENDING_BLOCK,
444 TWIG_DEPRECATED,
446 TWIG_DO,
448 TWIG_EMBED,
450 TWIG_EMBED_STARTING_BLOCK,
451 TWIG_EMBED_ENDING_BLOCK,
452 TWIG_FLUSH,
454 TWIG_FROM, TWIG_IMPORT,
458 TWIG_SANDBOX,
460 TWIG_SANDBOX_STARTING_BLOCK,
461 TWIG_SANDBOX_ENDING_BLOCK,
462 TWIG_VERBATIM,
464 TWIG_VERBATIM_STARTING_BLOCK,
465 TWIG_VERBATIM_ENDING_BLOCK,
466 TWIG_MACRO,
468 TWIG_MACRO_STARTING_BLOCK,
469 TWIG_MACRO_ENDING_BLOCK,
470 TWIG_WITH,
472 TWIG_WITH_STARTING_BLOCK,
473 TWIG_WITH_ENDING_BLOCK,
474 TWIG_CACHE,
476 TWIG_CACHE_TTL,
477 TWIG_CACHE_TAGS,
478 TWIG_CACHE_STARTING_BLOCK,
479 TWIG_CACHE_ENDING_BLOCK,
480 TWIG_PROPS,
482 TWIG_PROP_DECLARATION,
483 TWIG_COMPONENT,
485 TWIG_COMPONENT_STARTING_BLOCK,
486 TWIG_COMPONENT_ENDING_BLOCK,
487
488 TWIG_TRANS,
490 TWIG_TRANS_STARTING_BLOCK,
491 TWIG_TRANS_ENDING_BLOCK,
492
493 SHOPWARE_TWIG_SW_EXTENDS,
495 SHOPWARE_TWIG_SW_INCLUDE,
496 SHOPWARE_SILENT_FEATURE_CALL,
497 SHOPWARE_SILENT_FEATURE_CALL_STARTING_BLOCK,
498 SHOPWARE_SILENT_FEATURE_CALL_ENDING_BLOCK,
499 SHOPWARE_RETURN,
500 SHOPWARE_ICON,
501 SHOPWARE_ICON_STYLE,
502 SHOPWARE_THUMBNAILS,
503 SHOPWARE_THUMBNAILS_WITH,
504
505 HTML_DOCTYPE,
507 HTML_ATTRIBUTE_LIST,
508 HTML_ATTRIBUTE,
509 HTML_STRING, HTML_STRING_INNER, HTML_TEXT, HTML_RAW_TEXT, HTML_COMMENT,
514 HTML_TAG,
515 HTML_STARTING_TAG,
516 HTML_ENDING_TAG,
517
518 LUDTWIG_DIRECTIVE_FILE_IGNORE,
520 LUDTWIG_DIRECTIVE_IGNORE,
521 LUDTWIG_DIRECTIVE_RULE_LIST,
522 ERROR, ROOT, }
529
530fn cb_not(lexer: &mut Lexer<'_, SyntaxKind>) -> SyntaxKind {
532 const SUFFIX: &str = " in";
533 if lexer.remainder().starts_with(SUFFIX) {
534 let after = lexer.remainder().get(SUFFIX.len()..);
535 if after.is_none_or(|s| s.starts_with([' ', '\t', '\n']) || s.is_empty()) {
536 lexer.bump(SUFFIX.len());
537 SyntaxKind::TK_NOT_IN
538 } else {
539 SyntaxKind::TK_NOT
540 }
541 } else {
542 SyntaxKind::TK_NOT
543 }
544}
545
546fn cb_is(lexer: &mut Lexer<'_, SyntaxKind>) -> SyntaxKind {
548 const SUFFIX: &str = " not";
549 if lexer.remainder().starts_with(SUFFIX) {
550 let after = lexer.remainder().get(SUFFIX.len()..);
551 if after.is_none_or(|s| s.starts_with([' ', '\t', '\n']) || s.is_empty()) {
552 lexer.bump(SUFFIX.len());
553 SyntaxKind::TK_IS_NOT
554 } else {
555 SyntaxKind::TK_IS
556 }
557 } else {
558 SyntaxKind::TK_IS
559 }
560}
561
562#[macro_export]
563macro_rules! T {
564 [ws] => { $crate::syntax::untyped::SyntaxKind::TK_WHITESPACE };
565 [lb] => { $crate::syntax::untyped::SyntaxKind::TK_LINE_BREAK };
566 [word] => { $crate::syntax::untyped::SyntaxKind::TK_WORD };
567 [twig component name] => { $crate::syntax::untyped::SyntaxKind::TK_TWIG_COMPONENT_NAME };
568 [number] => { $crate::syntax::untyped::SyntaxKind::TK_NUMBER };
569 [html escape character] => { $crate::syntax::untyped::SyntaxKind::TK_HTML_ESCAPE_CHARACTER };
570 [unknown] => { $crate::syntax::untyped::SyntaxKind::TK_UNKNOWN };
571 ["."] => { $crate::syntax::untyped::SyntaxKind::TK_DOT };
572 [".."] => { $crate::syntax::untyped::SyntaxKind::TK_DOUBLE_DOT };
573 ["..."] => { $crate::syntax::untyped::SyntaxKind::TK_TRIPLE_DOT };
574 [","] => { $crate::syntax::untyped::SyntaxKind::TK_COMMA };
575 [":"] => { $crate::syntax::untyped::SyntaxKind::TK_COLON };
576 [";"] => { $crate::syntax::untyped::SyntaxKind::TK_SEMICOLON };
577 ["!"] => { $crate::syntax::untyped::SyntaxKind::TK_EXCLAMATION_MARK };
578 ["!="] => { $crate::syntax::untyped::SyntaxKind::TK_EXCLAMATION_MARK_EQUALS };
579 ["!=="] => { $crate::syntax::untyped::SyntaxKind::TK_EXCLAMATION_MARK_DOUBLE_EQUALS };
580 ["?"] => { $crate::syntax::untyped::SyntaxKind::TK_QUESTION_MARK };
581 ["??"] => { $crate::syntax::untyped::SyntaxKind::TK_DOUBLE_QUESTION_MARK };
582 ["%"] => { $crate::syntax::untyped::SyntaxKind::TK_PERCENT };
583 ["~"] => { $crate::syntax::untyped::SyntaxKind::TK_TILDE };
584 ["|"] => { $crate::syntax::untyped::SyntaxKind::TK_SINGLE_PIPE };
585 ["||"] => { $crate::syntax::untyped::SyntaxKind::TK_DOUBLE_PIPE };
586 ["&"] => { $crate::syntax::untyped::SyntaxKind::TK_AMPERSAND };
587 ["&&"] => { $crate::syntax::untyped::SyntaxKind::TK_DOUBLE_AMPERSAND };
588 ["/"] => { $crate::syntax::untyped::SyntaxKind::TK_FORWARD_SLASH };
589 ["//"] => { $crate::syntax::untyped::SyntaxKind::TK_DOUBLE_FORWARD_SLASH };
590 ["\\"] => { $crate::syntax::untyped::SyntaxKind::TK_BACKWARD_SLASH };
591 ["("] => { $crate::syntax::untyped::SyntaxKind::TK_OPEN_PARENTHESIS };
592 [")"] => { $crate::syntax::untyped::SyntaxKind::TK_CLOSE_PARENTHESIS };
593 ["{"] => { $crate::syntax::untyped::SyntaxKind::TK_OPEN_CURLY };
594 ["}"] => { $crate::syntax::untyped::SyntaxKind::TK_CLOSE_CURLY };
595 ["["] => { $crate::syntax::untyped::SyntaxKind::TK_OPEN_SQUARE };
596 ["]"] => { $crate::syntax::untyped::SyntaxKind::TK_CLOSE_SQUARE };
597 ["<"] => { $crate::syntax::untyped::SyntaxKind::TK_LESS_THAN };
598 ["<="] => { $crate::syntax::untyped::SyntaxKind::TK_LESS_THAN_EQUAL };
599 ["<=>"] => { $crate::syntax::untyped::SyntaxKind::TK_LESS_THAN_EQUAL_GREATER_THAN };
600 ["</"] => { $crate::syntax::untyped::SyntaxKind::TK_LESS_THAN_SLASH };
601 ["<!"] => { $crate::syntax::untyped::SyntaxKind::TK_LESS_THAN_EXCLAMATION_MARK };
602 ["DOCTYPE"] => { $crate::syntax::untyped::SyntaxKind::TK_DOCTYPE };
603 [">"] => { $crate::syntax::untyped::SyntaxKind::TK_GREATER_THAN };
604 [">="] => { $crate::syntax::untyped::SyntaxKind::TK_GREATER_THAN_EQUAL };
605 ["=>"] => { $crate::syntax::untyped::SyntaxKind::TK_EQUAL_GREATER_THAN };
606 ["/>"] => { $crate::syntax::untyped::SyntaxKind::TK_SLASH_GREATER_THAN };
607 ["<!--"] => { $crate::syntax::untyped::SyntaxKind::TK_LESS_THAN_EXCLAMATION_MARK_MINUS_MINUS };
608 ["-->"] => { $crate::syntax::untyped::SyntaxKind::TK_MINUS_MINUS_GREATER_THAN };
609 ["="] => { $crate::syntax::untyped::SyntaxKind::TK_EQUAL };
610 ["=="] => { $crate::syntax::untyped::SyntaxKind::TK_DOUBLE_EQUAL };
611 ["==="] => { $crate::syntax::untyped::SyntaxKind::TK_TRIPLE_EQUAL };
612 ["+"] => { $crate::syntax::untyped::SyntaxKind::TK_PLUS };
613 ["-"] => { $crate::syntax::untyped::SyntaxKind::TK_MINUS };
614 ["*"] => { $crate::syntax::untyped::SyntaxKind::TK_STAR };
615 ["**"] => { $crate::syntax::untyped::SyntaxKind::TK_DOUBLE_STAR };
616 ["\""] => { $crate::syntax::untyped::SyntaxKind::TK_DOUBLE_QUOTES };
617 ["'"] => { $crate::syntax::untyped::SyntaxKind::TK_SINGLE_QUOTES };
618 ["`"] => { $crate::syntax::untyped::SyntaxKind::TK_GRAVE_ACCENT_QUOTES };
619 ["{%"] => { $crate::syntax::untyped::SyntaxKind::TK_CURLY_PERCENT };
620 ["%}"] => { $crate::syntax::untyped::SyntaxKind::TK_PERCENT_CURLY };
621 ["{{"] => { $crate::syntax::untyped::SyntaxKind::TK_OPEN_CURLY_CURLY };
622 ["}}"] => { $crate::syntax::untyped::SyntaxKind::TK_CLOSE_CURLY_CURLY };
623 ["{#"] => { $crate::syntax::untyped::SyntaxKind::TK_OPEN_CURLY_HASHTAG };
624 ["#}"] => { $crate::syntax::untyped::SyntaxKind::TK_HASHTAG_CLOSE_CURLY };
625 ["#"] => { $crate::syntax::untyped::SyntaxKind::TK_HASHTAG };
626 ["true"] => { $crate::syntax::untyped::SyntaxKind::TK_TRUE };
627 ["false"] => { $crate::syntax::untyped::SyntaxKind::TK_FALSE };
628 ["block"] => { $crate::syntax::untyped::SyntaxKind::TK_BLOCK };
629 ["endblock"] => { $crate::syntax::untyped::SyntaxKind::TK_ENDBLOCK };
630 ["if"] => { $crate::syntax::untyped::SyntaxKind::TK_IF };
631 ["elseif"] => { $crate::syntax::untyped::SyntaxKind::TK_ELSE_IF };
632 ["else"] => { $crate::syntax::untyped::SyntaxKind::TK_ELSE };
633 ["endif"] => { $crate::syntax::untyped::SyntaxKind::TK_ENDIF };
634 ["apply"] => { $crate::syntax::untyped::SyntaxKind::TK_APPLY };
635 ["endapply"] => { $crate::syntax::untyped::SyntaxKind::TK_ENDAPPLY };
636 ["autoescape"] => { $crate::syntax::untyped::SyntaxKind::TK_AUTOESCAPE };
637 ["endautoescape"] => { $crate::syntax::untyped::SyntaxKind::TK_ENDAUTOESCAPE };
638 ["cache"] => { $crate::syntax::untyped::SyntaxKind::TK_CACHE };
639 ["endcache"] => { $crate::syntax::untyped::SyntaxKind::TK_ENDCACHE };
640 ["deprecated"] => { $crate::syntax::untyped::SyntaxKind::TK_DEPRECATED };
641 ["do"] => { $crate::syntax::untyped::SyntaxKind::TK_DO };
642 ["embed"] => { $crate::syntax::untyped::SyntaxKind::TK_EMBED };
643 ["endembed"] => { $crate::syntax::untyped::SyntaxKind::TK_ENDEMBED };
644 ["extends"] => { $crate::syntax::untyped::SyntaxKind::TK_EXTENDS };
645 ["flush"] => { $crate::syntax::untyped::SyntaxKind::TK_FLUSH };
646 ["for"] => { $crate::syntax::untyped::SyntaxKind::TK_FOR };
647 ["endfor"] => { $crate::syntax::untyped::SyntaxKind::TK_ENDFOR };
648 ["from"] => { $crate::syntax::untyped::SyntaxKind::TK_FROM };
649 ["import"] => { $crate::syntax::untyped::SyntaxKind::TK_IMPORT };
650 ["macro"] => { $crate::syntax::untyped::SyntaxKind::TK_MACRO };
651 ["endmacro"] => { $crate::syntax::untyped::SyntaxKind::TK_ENDMACRO };
652 ["sandbox"] => { $crate::syntax::untyped::SyntaxKind::TK_SANDBOX };
653 ["endsandbox"] => { $crate::syntax::untyped::SyntaxKind::TK_ENDSANDBOX };
654 ["set"] => { $crate::syntax::untyped::SyntaxKind::TK_SET };
655 ["endset"] => { $crate::syntax::untyped::SyntaxKind::TK_ENDSET };
656 ["use"] => { $crate::syntax::untyped::SyntaxKind::TK_USE };
657 ["verbatim"] => { $crate::syntax::untyped::SyntaxKind::TK_VERBATIM };
658 ["endverbatim"] => { $crate::syntax::untyped::SyntaxKind::TK_ENDVERBATIM };
659 ["only"] => { $crate::syntax::untyped::SyntaxKind::TK_ONLY };
660 ["ignore missing"] => { $crate::syntax::untyped::SyntaxKind::TK_IGNORE_MISSING };
661 ["with"] => { $crate::syntax::untyped::SyntaxKind::TK_WITH };
662 ["endwith"] => { $crate::syntax::untyped::SyntaxKind::TK_ENDWITH };
663 ["ttl"] => { $crate::syntax::untyped::SyntaxKind::TK_TTL };
664 ["tags"] => { $crate::syntax::untyped::SyntaxKind::TK_TAGS };
665 ["props"] => { $crate::syntax::untyped::SyntaxKind::TK_PROPS };
666 ["component"] => { $crate::syntax::untyped::SyntaxKind::TK_COMPONENT };
667 ["endcomponent"] => { $crate::syntax::untyped::SyntaxKind::TK_ENDCOMPONENT };
668 ["not"] => { $crate::syntax::untyped::SyntaxKind::TK_NOT };
669 ["not in"] => { $crate::syntax::untyped::SyntaxKind::TK_NOT_IN };
670 ["or"] => { $crate::syntax::untyped::SyntaxKind::TK_OR };
671 ["and"] => { $crate::syntax::untyped::SyntaxKind::TK_AND };
672 ["b-or"] => { $crate::syntax::untyped::SyntaxKind::TK_BINARY_OR };
673 ["b-xor"] => { $crate::syntax::untyped::SyntaxKind::TK_BINARY_XOR };
674 ["b-and"] => { $crate::syntax::untyped::SyntaxKind::TK_BINARY_AND };
675 ["in"] => { $crate::syntax::untyped::SyntaxKind::TK_IN };
676 ["matches"] => { $crate::syntax::untyped::SyntaxKind::TK_MATCHES };
677 ["starts with"] => { $crate::syntax::untyped::SyntaxKind::TK_STARTS_WITH };
678 ["ends with"] => { $crate::syntax::untyped::SyntaxKind::TK_ENDS_WITH };
679 ["is"] => { $crate::syntax::untyped::SyntaxKind::TK_IS };
680 ["is not"] => { $crate::syntax::untyped::SyntaxKind::TK_IS_NOT };
681 ["even"] => { $crate::syntax::untyped::SyntaxKind::TK_EVEN };
682 ["odd"] => { $crate::syntax::untyped::SyntaxKind::TK_ODD };
683 ["defined"] => { $crate::syntax::untyped::SyntaxKind::TK_DEFINED };
684 ["same as"] => { $crate::syntax::untyped::SyntaxKind::TK_SAME_AS };
685 ["as"] => { $crate::syntax::untyped::SyntaxKind::TK_AS };
686 ["none"] => { $crate::syntax::untyped::SyntaxKind::TK_NONE };
687 ["null"] => { $crate::syntax::untyped::SyntaxKind::TK_NULL };
688 ["divisible by"] => { $crate::syntax::untyped::SyntaxKind::TK_DIVISIBLE_BY };
689 ["constant"] => { $crate::syntax::untyped::SyntaxKind::TK_CONSTANT };
690 ["empty"] => { $crate::syntax::untyped::SyntaxKind::TK_EMPTY };
691 ["iterable"] => { $crate::syntax::untyped::SyntaxKind::TK_ITERABLE };
692 ["max"] => { $crate::syntax::untyped::SyntaxKind::TK_MAX };
693 ["min"] => { $crate::syntax::untyped::SyntaxKind::TK_MIN };
694 ["range"] => { $crate::syntax::untyped::SyntaxKind::TK_RANGE };
695 ["cycle"] => { $crate::syntax::untyped::SyntaxKind::TK_CYCLE };
696 ["random"] => { $crate::syntax::untyped::SyntaxKind::TK_RANDOM };
697 ["date"] => { $crate::syntax::untyped::SyntaxKind::TK_DATE };
698 ["include"] => { $crate::syntax::untyped::SyntaxKind::TK_INCLUDE };
699 ["source"] => { $crate::syntax::untyped::SyntaxKind::TK_SOURCE };
700 ["trans"] => { $crate::syntax::untyped::SyntaxKind::TK_TRANS };
701 ["endtrans"] => { $crate::syntax::untyped::SyntaxKind::TK_ENDTRANS };
702 ["sw_extends"] => { $crate::syntax::untyped::SyntaxKind::TK_SW_EXTENDS };
703 ["sw_silent_feature_call"] => { $crate::syntax::untyped::SyntaxKind::TK_SW_SILENT_FEATURE_CALL };
704 ["endsw_silent_feature_call"] => { $crate::syntax::untyped::SyntaxKind::TK_ENDSW_SILENT_FEATURE_CALL };
705 ["sw_include"] => { $crate::syntax::untyped::SyntaxKind::TK_SW_INCLUDE };
706 ["return"] => { $crate::syntax::untyped::SyntaxKind::TK_RETURN };
707 ["sw_icon"] => { $crate::syntax::untyped::SyntaxKind::TK_SW_ICON };
708 ["sw_thumbnails"] => { $crate::syntax::untyped::SyntaxKind::TK_SW_THUMBNAILS };
709 ["style"] => { $crate::syntax::untyped::SyntaxKind::TK_STYLE };
710 ["sw_embed"] => { $crate::syntax::untyped::SyntaxKind::TK_SW_EMBED };
711 ["sw_end_embed"] => { $crate::syntax::untyped::SyntaxKind::TK_SW_END_EMBED };
712 ["sw_use"] => { $crate::syntax::untyped::SyntaxKind::TK_SW_USE };
713 ["sw_import"] => { $crate::syntax::untyped::SyntaxKind::TK_SW_IMPORT };
714 ["sw_from"] => { $crate::syntax::untyped::SyntaxKind::TK_SW_FROM };
715 ["ludtwig-ignore-file"] => { $crate::syntax::untyped::SyntaxKind::TK_LUDTWIG_IGNORE_FILE };
716 ["ludtwig-ignore"] => { $crate::syntax::untyped::SyntaxKind::TK_LUDTWIG_IGNORE };
717}
718
719impl SyntaxKind {
720 #[must_use]
721 pub fn is_trivia(self) -> bool {
722 matches!(self, T![ws] | T![lb])
724 }
725}
726
727#[allow(clippy::too_many_lines)]
728impl fmt::Display for SyntaxKind {
729 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
730 f.write_str(match self {
731 SyntaxKind::TK_WHITESPACE => "whitespace",
732 SyntaxKind::TK_LINE_BREAK => "line break",
733 SyntaxKind::TK_WORD => "word",
734 SyntaxKind::TK_TWIG_COMPONENT_NAME => "twig component name",
735 SyntaxKind::TK_NUMBER => "number",
736 SyntaxKind::TK_HTML_ESCAPE_CHARACTER => "html escape character",
737 SyntaxKind::TK_DOT => ".",
738 SyntaxKind::TK_DOUBLE_DOT => "..",
739 SyntaxKind::TK_TRIPLE_DOT => "...",
740 SyntaxKind::TK_COMMA => ",",
741 SyntaxKind::TK_COLON => ":",
742 SyntaxKind::TK_SEMICOLON => ";",
743 SyntaxKind::TK_EXCLAMATION_MARK => "!",
744 SyntaxKind::TK_EXCLAMATION_MARK_EQUALS => "!=",
745 SyntaxKind::TK_EXCLAMATION_MARK_DOUBLE_EQUALS => "!==",
746 SyntaxKind::TK_QUESTION_MARK => "?",
747 SyntaxKind::TK_DOUBLE_QUESTION_MARK => "??",
748 SyntaxKind::TK_PERCENT => "%",
749 SyntaxKind::TK_TILDE => "~",
750 SyntaxKind::TK_SINGLE_PIPE => "|",
751 SyntaxKind::TK_DOUBLE_PIPE => "||",
752 SyntaxKind::TK_AMPERSAND => "&",
753 SyntaxKind::TK_DOUBLE_AMPERSAND => "&&",
754 SyntaxKind::TK_FORWARD_SLASH => "/",
755 SyntaxKind::TK_DOUBLE_FORWARD_SLASH => "//",
756 SyntaxKind::TK_BACKWARD_SLASH => "\\",
757 SyntaxKind::TK_OPEN_PARENTHESIS => "(",
758 SyntaxKind::TK_CLOSE_PARENTHESIS => ")",
759 SyntaxKind::TK_OPEN_CURLY => "{",
760 SyntaxKind::TK_CLOSE_CURLY => "}",
761 SyntaxKind::TK_OPEN_SQUARE => "[",
762 SyntaxKind::TK_CLOSE_SQUARE => "]",
763 SyntaxKind::TK_LESS_THAN => "<",
764 SyntaxKind::TK_LESS_THAN_EQUAL => "<=",
765 SyntaxKind::TK_LESS_THAN_EQUAL_GREATER_THAN => "<=>",
766 SyntaxKind::TK_LESS_THAN_SLASH => "</",
767 SyntaxKind::TK_LESS_THAN_EXCLAMATION_MARK => "<!",
768 SyntaxKind::TK_DOCTYPE => "DOCTYPE",
769 SyntaxKind::TK_GREATER_THAN => ">",
770 SyntaxKind::TK_GREATER_THAN_EQUAL => ">=",
771 SyntaxKind::TK_EQUAL_GREATER_THAN => "=>",
772 SyntaxKind::TK_SLASH_GREATER_THAN => "/>",
773 SyntaxKind::TK_LESS_THAN_EXCLAMATION_MARK_MINUS_MINUS => "<!--",
774 SyntaxKind::TK_MINUS_MINUS_GREATER_THAN => "-->",
775 SyntaxKind::TK_EQUAL => "=",
776 SyntaxKind::TK_DOUBLE_EQUAL => "==",
777 SyntaxKind::TK_TRIPLE_EQUAL => "===",
778 SyntaxKind::TK_PLUS => "+",
779 SyntaxKind::TK_MINUS => "-",
780 SyntaxKind::TK_STAR => "*",
781 SyntaxKind::TK_DOUBLE_STAR => "**",
782 SyntaxKind::TK_DOUBLE_QUOTES => "\"",
783 SyntaxKind::TK_SINGLE_QUOTES => "'",
784 SyntaxKind::TK_GRAVE_ACCENT_QUOTES => "`",
785 SyntaxKind::TK_CURLY_PERCENT => "{%",
786 SyntaxKind::TK_PERCENT_CURLY => "%}",
787 SyntaxKind::TK_OPEN_CURLY_CURLY => "{{",
788 SyntaxKind::TK_CLOSE_CURLY_CURLY => "}}",
789 SyntaxKind::TK_OPEN_CURLY_HASHTAG => "{#",
790 SyntaxKind::TK_HASHTAG_CLOSE_CURLY => "#}",
791 SyntaxKind::TK_HASHTAG => "#",
792 SyntaxKind::TK_TRUE => "true",
793 SyntaxKind::TK_FALSE => "false",
794 SyntaxKind::TK_BLOCK => "block",
795 SyntaxKind::TK_ENDBLOCK => "endblock",
796 SyntaxKind::TK_IF => "if",
797 SyntaxKind::TK_ELSE_IF => "elseif",
798 SyntaxKind::TK_ELSE => "else",
799 SyntaxKind::TK_ENDIF => "endif",
800 SyntaxKind::TK_APPLY => "apply",
801 SyntaxKind::TK_ENDAPPLY => "endapply",
802 SyntaxKind::TK_AUTOESCAPE => "autoescape",
803 SyntaxKind::TK_ENDAUTOESCAPE => "endautoescape",
804 SyntaxKind::TK_CACHE => "cache",
805 SyntaxKind::TK_ENDCACHE => "endcache",
806 SyntaxKind::TK_DEPRECATED => "deprecated",
807 SyntaxKind::TK_DO => "do",
808 SyntaxKind::TK_EMBED => "embed",
809 SyntaxKind::TK_ENDEMBED => "endembed",
810 SyntaxKind::TK_EXTENDS => "extends",
811 SyntaxKind::TK_FLUSH => "flush",
812 SyntaxKind::TK_FOR => "for",
813 SyntaxKind::TK_ENDFOR => "endfor",
814 SyntaxKind::TK_FROM => "from",
815 SyntaxKind::TK_IMPORT => "import",
816 SyntaxKind::TK_MACRO => "macro",
817 SyntaxKind::TK_ENDMACRO => "endmacro",
818 SyntaxKind::TK_SANDBOX => "sandbox",
819 SyntaxKind::TK_ENDSANDBOX => "endsandbox",
820 SyntaxKind::TK_SET => "set",
821 SyntaxKind::TK_ENDSET => "endset",
822 SyntaxKind::TK_USE => "use",
823 SyntaxKind::TK_VERBATIM => "verbatim",
824 SyntaxKind::TK_ENDVERBATIM => "endverbatim",
825 SyntaxKind::TK_ONLY => "only",
826 SyntaxKind::TK_IGNORE_MISSING => "ignore missing",
827 SyntaxKind::TK_WITH => "with",
828 SyntaxKind::TK_ENDWITH => "endwith",
829 SyntaxKind::TK_TTL => "ttl",
830 SyntaxKind::TK_TAGS => "tags",
831 SyntaxKind::TK_PROPS => "props",
832 SyntaxKind::TK_COMPONENT => "component",
833 SyntaxKind::TK_ENDCOMPONENT => "endcomponent",
834 SyntaxKind::TK_NOT => "not",
835 SyntaxKind::TK_NOT_IN => "not in",
836 SyntaxKind::TK_OR => "or",
837 SyntaxKind::TK_AND => "and",
838 SyntaxKind::TK_BINARY_OR => "b-or",
839 SyntaxKind::TK_BINARY_XOR => "b-xor",
840 SyntaxKind::TK_BINARY_AND => "b-and",
841 SyntaxKind::TK_IN => "in",
842 SyntaxKind::TK_MATCHES => "matches",
843 SyntaxKind::TK_STARTS_WITH => "starts with",
844 SyntaxKind::TK_ENDS_WITH => "ends with",
845 SyntaxKind::TK_IS => "is",
846 SyntaxKind::TK_IS_NOT => "is not",
847 SyntaxKind::TK_EVEN => "even",
848 SyntaxKind::TK_ODD => "odd",
849 SyntaxKind::TK_DEFINED => "defined",
850 SyntaxKind::TK_SAME_AS => "same as",
851 SyntaxKind::TK_AS => "as",
852 SyntaxKind::TK_NONE => "none",
853 SyntaxKind::TK_NULL => "null",
854 SyntaxKind::TK_DIVISIBLE_BY => "divisible by",
855 SyntaxKind::TK_CONSTANT => "constant",
856 SyntaxKind::TK_EMPTY => "empty",
857 SyntaxKind::TK_ITERABLE => "iterable",
858 SyntaxKind::TK_MAX => "max",
859 SyntaxKind::TK_MIN => "min",
860 SyntaxKind::TK_RANGE => "range",
861 SyntaxKind::TK_CYCLE => "cycle",
862 SyntaxKind::TK_RANDOM => "random",
863 SyntaxKind::TK_DATE => "date",
864 SyntaxKind::TK_INCLUDE => "include",
865 SyntaxKind::TK_SOURCE => "source",
866 SyntaxKind::TK_TRANS => "trans",
867 SyntaxKind::TK_ENDTRANS => "endtrans",
868 SyntaxKind::TK_SW_EXTENDS => "sw_extends",
869 SyntaxKind::TK_SW_SILENT_FEATURE_CALL => "sw_silent_feature_call",
870 SyntaxKind::TK_ENDSW_SILENT_FEATURE_CALL => "endsw_silent_feature_call",
871 SyntaxKind::TK_SW_INCLUDE => "sw_include",
872 SyntaxKind::TK_RETURN => "return",
873 SyntaxKind::TK_SW_ICON => "sw_icon",
874 SyntaxKind::TK_SW_THUMBNAILS => "sw_thumbnails",
875 SyntaxKind::TK_STYLE => "style",
876 SyntaxKind::TK_SW_EMBED => "sw_embed",
877 SyntaxKind::TK_SW_END_EMBED => "sw_end_embed",
878 SyntaxKind::TK_SW_USE => "sw_use",
879 SyntaxKind::TK_SW_IMPORT => "sw_import",
880 SyntaxKind::TK_SW_FROM => "sw_from",
881 SyntaxKind::TK_LUDTWIG_IGNORE_FILE => "ludtwig-ignore-file",
882 SyntaxKind::TK_LUDTWIG_IGNORE => "ludtwig-ignore",
883 SyntaxKind::TK_UNKNOWN => "unknown",
884 SyntaxKind::ERROR => "error",
885 t => unreachable!("Display not implemented for {:?}", t),
886 })
887 }
888}
889
890impl From<SyntaxKind> for rowan::SyntaxKind {
896 fn from(kind: SyntaxKind) -> Self {
897 Self(kind as u16)
898 }
899}
900
901#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
905pub enum TemplateLanguage {}
906impl Language for TemplateLanguage {
907 type Kind = SyntaxKind;
908 fn kind_from_raw(raw: rowan::SyntaxKind) -> Self::Kind {
909 assert!(raw.0 <= SyntaxKind::ROOT as u16);
910 unsafe { std::mem::transmute::<u16, SyntaxKind>(raw.0) }
911 }
912 fn kind_to_raw(kind: Self::Kind) -> rowan::SyntaxKind {
913 kind.into()
914 }
915}
916
917pub type SyntaxNode = rowan::SyntaxNode<TemplateLanguage>;
923pub type SyntaxToken = rowan::SyntaxToken<TemplateLanguage>;
924pub type SyntaxElement = rowan::NodeOrToken<SyntaxNode, SyntaxToken>;
925pub type SyntaxNodeChildren = rowan::SyntaxNodeChildren<TemplateLanguage>;
926pub type SyntaxElementChildren = rowan::SyntaxElementChildren<TemplateLanguage>;
927pub type Preorder = rowan::api::Preorder<TemplateLanguage>;
928pub type PreorderWithTokens = rowan::api::PreorderWithTokens<TemplateLanguage>;
929
930#[must_use]
931pub fn debug_tree(syntax_node: &SyntaxNode) -> String {
932 let formatted = format!("{syntax_node:#?}");
933 formatted[0..formatted.len() - 1].to_string()
935}
936
937pub trait SyntaxNodeExt {
938 fn text_range_trimmed_trivia(&self) -> TextRange;
939}
940
941impl SyntaxNodeExt for SyntaxNode {
942 fn text_range_trimmed_trivia(&self) -> TextRange {
944 let mut range = self.text_range();
945
946 for element in self.children_with_tokens() {
947 match element {
948 SyntaxElement::Token(t) if t.kind().is_trivia() => {
949 let new_start = range.start() + t.text_range().len();
950 if new_start < range.end() {
951 range = TextRange::new(new_start, range.end());
952 }
953 }
954 _ => return range,
955 }
956 }
957
958 range
959 }
960}