1use crate::SyntaxKind::{self, DOC_COMMENT_INNER, DOC_COMMENT_OUTER, IDENT, L_PAREN};
10use crate::ast::ast_node;
11use crate::ast::support;
12use crate::{SyntaxNode, SyntaxToken};
13
14ast_node!(DocComment, DOC_COMMENT);
17
18ast_node!(SourceFile, SOURCE_FILE);
21ast_node!(FlowDecl, FLOW_DECL);
22ast_node!(FnDecl, FN_DECL);
23ast_node!(ParamList, PARAM_LIST);
24ast_node!(Param, PARAM);
25ast_node!(VarDecl, VAR_DECL);
26ast_node!(ConstDecl, CONST_DECL);
27ast_node!(FlagsDecl, FLAGS_DECL);
28ast_node!(FlagsMemberList, FLAGS_MEMBER_LIST);
29ast_node!(FlagsMember, FLAGS_MEMBER);
30ast_node!(StructDecl, STRUCT_DECL);
31ast_node!(StructField, STRUCT_FIELD);
32ast_node!(ExternDecl, EXTERN_DECL);
33ast_node!(UseDecl, USE_DECL);
34ast_node!(UseTree, USE_TREE);
35ast_node!(UseTreeList, USE_TREE_LIST);
36ast_node!(ImportDecl, IMPORT_DECL);
37ast_node!(ModuleDecl, MODULE_DECL);
38
39ast_node!(Block, BLOCK);
42ast_node!(ContentLine, CONTENT_LINE);
43ast_node!(Text, TEXT);
44ast_node!(Interpolation, INTERPOLATION);
45ast_node!(GlueNode, GLUE_NODE);
46ast_node!(TagLine, TAG_LINE);
47ast_node!(Tag, TAG);
48
49ast_node!(ChoicePoint, CHOICE_POINT);
52ast_node!(Choice, CHOICE);
53ast_node!(ChoiceBullet, CHOICE_BULLET);
54ast_node!(Label, LABEL);
55ast_node!(ChoiceGuard, CHOICE_GUARD);
56ast_node!(ChoiceStartContent, CHOICE_START_CONTENT);
57ast_node!(ChoiceBracketContent, CHOICE_BRACKET_CONTENT);
58ast_node!(ChoiceInnerContent, CHOICE_INNER_CONTENT);
59ast_node!(ChoiceBody, CHOICE_BODY);
60ast_node!(ElseBranch, ELSE_BRANCH);
61ast_node!(Splice, SPLICE);
62
63ast_node!(ConditionalBlock, CONDITIONAL_BLOCK);
66ast_node!(IfArm, IF_ARM);
67ast_node!(MatchArm, MATCH_ARM);
68ast_node!(MatchPattern, MATCH_PATTERN);
69ast_node!(AlternationBlock, ALTERNATION_BLOCK);
70ast_node!(AlternationMarker, ALTERNATION_MARKER);
71ast_node!(Entry, ENTRY);
72
73ast_node!(AnnotationLine, ANNOTATION_LINE);
76ast_node!(AnnotationArgs, ANNOTATION_ARGS);
77ast_node!(AnnotationArg, ANNOTATION_ARG);
78
79ast_node!(DivertStmt, DIVERT_STMT);
82ast_node!(TunnelCall, TUNNEL_CALL);
83ast_node!(DivertTarget, DIVERT_TARGET);
84ast_node!(ReturnStmt, RETURN_STMT);
85ast_node!(ReturnRedirect, RETURN_REDIRECT);
86
87ast_node!(Path, PATH);
90ast_node!(PathSegment, PATH_SEGMENT);
91
92ast_node!(IntegerLit, INTEGER_LIT);
95ast_node!(FloatLit, FLOAT_LIT);
96ast_node!(StringLit, STRING_LIT);
97ast_node!(BooleanLit, BOOLEAN_LIT);
98ast_node!(PathExpr, PATH_EXPR);
99ast_node!(ParenExpr, PAREN_EXPR);
100ast_node!(PrefixExpr, PREFIX_EXPR);
101ast_node!(InfixExpr, INFIX_EXPR);
102ast_node!(CallExpr, CALL_EXPR);
103ast_node!(ArgList, ARG_LIST);
104ast_node!(LambdaExpr, LAMBDA_EXPR);
105ast_node!(LambdaParams, LAMBDA_PARAMS);
106
107ast_node!(Error, ERROR);
110
111impl DocComment {
114 pub fn is_inner(&self) -> bool {
122 self.syntax
123 .children_with_tokens()
124 .filter_map(rowan::NodeOrToken::into_token)
125 .any(|t| t.kind() == DOC_COMMENT_INNER)
126 }
127
128 pub fn lines(&self) -> Vec<(String, rowan::TextRange)> {
135 self.syntax
136 .children_with_tokens()
137 .filter_map(rowan::NodeOrToken::into_token)
138 .filter(|t| matches!(t.kind(), DOC_COMMENT_OUTER | DOC_COMMENT_INNER))
139 .map(|t| {
140 let text = t.text();
141 let body = text
142 .strip_prefix("///")
143 .or_else(|| text.strip_prefix("//!"))
144 .unwrap_or(text);
145 (body.trim_start().to_string(), t.text_range())
146 })
147 .collect()
148 }
149}
150
151impl SourceFile {
152 pub fn flows(&self) -> impl Iterator<Item = FlowDecl> {
155 support::children(&self.syntax)
156 }
157
158 pub fn fns(&self) -> impl Iterator<Item = FnDecl> {
160 support::children(&self.syntax)
161 }
162
163 pub fn syntax_children(&self) -> impl Iterator<Item = SyntaxNode> {
167 self.syntax.children()
168 }
169
170 pub fn doc(&self) -> Option<DocComment> {
176 support::child(&self.syntax)
177 }
178}
179
180impl FlowDecl {
181 pub fn name_token(&self) -> Option<SyntaxToken> {
183 support::token(&self.syntax, IDENT)
184 }
185
186 pub fn param_list(&self) -> Option<ParamList> {
187 support::child(&self.syntax)
188 }
189
190 pub fn body(&self) -> Option<Block> {
191 support::child(&self.syntax)
192 }
193
194 pub fn stitches(&self) -> impl Iterator<Item = FlowDecl> {
197 self.body()
198 .into_iter()
199 .flat_map(|b| support::children::<FlowDecl>(&b.syntax).collect::<Vec<_>>())
200 }
201
202 pub fn doc(&self) -> Option<DocComment> {
204 support::child(&self.syntax)
205 }
206}
207
208impl FnDecl {
209 pub fn name_token(&self) -> Option<SyntaxToken> {
210 support::token(&self.syntax, IDENT)
211 }
212
213 pub fn param_list(&self) -> Option<ParamList> {
214 support::child(&self.syntax)
215 }
216
217 pub fn body(&self) -> Option<Block> {
218 support::child(&self.syntax)
219 }
220
221 pub fn doc(&self) -> Option<DocComment> {
223 support::child(&self.syntax)
224 }
225}
226
227impl ParamList {
228 pub fn params(&self) -> impl Iterator<Item = Param> {
229 support::children(&self.syntax)
230 }
231}
232
233impl Param {
234 pub fn name_token(&self) -> Option<SyntaxToken> {
235 support::token(&self.syntax, IDENT)
236 }
237
238 pub fn is_ref(&self) -> bool {
240 support::token(&self.syntax, SyntaxKind::KW_REF).is_some()
241 }
242}
243
244impl Block {
245 pub fn items(&self) -> impl Iterator<Item = SyntaxNode> {
253 self.syntax.children()
254 }
255
256 pub fn doc(&self) -> Option<DocComment> {
262 support::child(&self.syntax)
263 }
264}
265
266impl VarDecl {
267 pub fn name_token(&self) -> Option<SyntaxToken> {
268 support::token(&self.syntax, IDENT)
269 }
270
271 pub fn value(&self) -> Option<SyntaxNode> {
276 self.syntax
277 .children()
278 .find(|n| n.kind() != SyntaxKind::DOC_COMMENT)
279 }
280
281 pub fn doc(&self) -> Option<DocComment> {
283 support::child(&self.syntax)
284 }
285}
286
287impl ConstDecl {
288 pub fn name_token(&self) -> Option<SyntaxToken> {
289 support::token(&self.syntax, IDENT)
290 }
291
292 pub fn value(&self) -> Option<SyntaxNode> {
294 self.syntax
295 .children()
296 .find(|n| n.kind() != SyntaxKind::DOC_COMMENT)
297 }
298
299 pub fn doc(&self) -> Option<DocComment> {
301 support::child(&self.syntax)
302 }
303}
304
305impl FlagsDecl {
306 pub fn name_token(&self) -> Option<SyntaxToken> {
307 support::token(&self.syntax, IDENT)
308 }
309
310 pub fn member_list(&self) -> Option<FlagsMemberList> {
311 support::child(&self.syntax)
312 }
313
314 pub fn doc(&self) -> Option<DocComment> {
316 support::child(&self.syntax)
317 }
318}
319
320impl FlagsMemberList {
321 pub fn members(&self) -> impl Iterator<Item = FlagsMember> {
322 support::children(&self.syntax)
323 }
324}
325
326impl FlagsMember {
327 pub fn name_token(&self) -> Option<SyntaxToken> {
328 support::token(&self.syntax, IDENT)
329 }
330
331 pub fn is_active(&self) -> bool {
333 support::token(&self.syntax, L_PAREN).is_some()
334 }
335}
336
337impl StructDecl {
338 pub fn name_token(&self) -> Option<SyntaxToken> {
339 support::token(&self.syntax, IDENT)
340 }
341
342 pub fn fields(&self) -> impl Iterator<Item = StructField> {
343 support::children(&self.syntax)
344 }
345
346 pub fn doc(&self) -> Option<DocComment> {
348 support::child(&self.syntax)
349 }
350}
351
352impl StructField {
353 pub fn name_token(&self) -> Option<SyntaxToken> {
354 support::token(&self.syntax, IDENT)
355 }
356
357 pub fn type_path(&self) -> Option<Path> {
360 support::child(&self.syntax)
361 }
362}
363
364impl ExternDecl {
365 pub fn name_token(&self) -> Option<SyntaxToken> {
366 support::token(&self.syntax, IDENT)
367 }
368
369 pub fn param_list(&self) -> Option<ParamList> {
370 support::child(&self.syntax)
371 }
372
373 pub fn doc(&self) -> Option<DocComment> {
375 support::child(&self.syntax)
376 }
377}
378
379impl ImportDecl {
380 pub fn path(&self) -> Option<Path> {
381 support::child(&self.syntax)
382 }
383
384 pub fn doc(&self) -> Option<DocComment> {
389 support::child(&self.syntax)
390 }
391}
392
393impl UseDecl {
394 pub fn tree(&self) -> Option<UseTree> {
395 support::child(&self.syntax)
396 }
397
398 pub fn doc(&self) -> Option<DocComment> {
400 support::child(&self.syntax)
401 }
402}
403
404impl UseTree {
405 pub fn path_segments(&self) -> impl Iterator<Item = SyntaxToken> + '_ {
411 self.syntax
412 .children_with_tokens()
413 .filter_map(rowan::NodeOrToken::into_token)
414 .take_while(|t| t.kind() != SyntaxKind::KW_AS)
415 .filter(|t| t.kind() == IDENT)
416 }
417
418 pub fn alias_token(&self) -> Option<SyntaxToken> {
420 let mut saw_as = false;
421 for el in self.syntax.children_with_tokens() {
422 let Some(tok) = el.into_token() else {
423 continue;
424 };
425 if tok.kind().is_trivia() {
426 continue;
427 }
428 if saw_as {
429 return if tok.kind() == IDENT { Some(tok) } else { None };
430 }
431 if tok.kind() == SyntaxKind::KW_AS {
432 saw_as = true;
433 }
434 }
435 None
436 }
437
438 pub fn nested_list(&self) -> Option<UseTreeList> {
440 support::child(&self.syntax)
441 }
442}
443
444impl UseTreeList {
445 pub fn trees(&self) -> impl Iterator<Item = UseTree> {
446 support::children(&self.syntax)
447 }
448}
449
450impl ModuleDecl {
451 pub fn name_token(&self) -> Option<SyntaxToken> {
452 support::token(&self.syntax, IDENT)
453 }
454
455 pub fn body(&self) -> Option<Block> {
456 support::child(&self.syntax)
457 }
458
459 pub fn doc(&self) -> Option<DocComment> {
462 support::child(&self.syntax)
463 }
464}
465
466impl Path {
467 pub fn segments(&self) -> impl Iterator<Item = SyntaxToken> {
469 support::children::<PathSegment>(&self.syntax)
470 .filter_map(|seg| support::token(&seg.syntax, IDENT))
471 }
472
473 pub fn crosses_module_wall(&self) -> bool {
476 support::tokens(&self.syntax, SyntaxKind::COLON_COLON)
477 .next()
478 .is_some()
479 }
480}
481
482impl ChoicePoint {
483 pub fn choices(&self) -> impl Iterator<Item = Choice> {
484 support::children(&self.syntax)
485 }
486
487 pub fn else_branch(&self) -> Option<ElseBranch> {
488 support::child(&self.syntax)
489 }
490}
491
492impl Choice {
493 pub fn is_sticky(&self) -> bool {
505 support::child::<ChoiceBullet>(&self.syntax)
506 .is_some_and(|b| support::token(&b.syntax, SyntaxKind::PLUS).is_some())
507 }
508
509 pub fn label(&self) -> Option<Label> {
510 support::child(&self.syntax)
511 }
512
513 pub fn guard(&self) -> Option<ChoiceGuard> {
514 support::child(&self.syntax)
515 }
516
517 pub fn body(&self) -> Option<ChoiceBody> {
518 support::child(&self.syntax)
519 }
520}
521
522impl AnnotationLine {
523 pub fn name_token(&self) -> Option<SyntaxToken> {
525 support::token(&self.syntax, IDENT)
526 }
527
528 pub fn args(&self) -> Option<AnnotationArgs> {
529 support::child(&self.syntax)
530 }
531}
532
533impl AnnotationArgs {
534 pub fn args(&self) -> impl Iterator<Item = AnnotationArg> {
535 support::children(&self.syntax)
536 }
537}
538
539impl AnnotationArg {
540 pub fn name_token(&self) -> Option<SyntaxToken> {
541 support::token(&self.syntax, IDENT)
542 }
543
544 pub fn nested_args(&self) -> Option<AnnotationArgs> {
547 support::child(&self.syntax)
548 }
549}
550
551impl CallExpr {
552 pub fn callee(&self) -> Option<Path> {
559 support::child(&self.syntax)
560 }
561
562 pub fn arg_list(&self) -> Option<ArgList> {
563 support::child(&self.syntax)
564 }
565}
566
567impl PathExpr {
568 pub fn path(&self) -> Option<Path> {
569 support::child(&self.syntax)
570 }
571}
572
573impl IntegerLit {
574 pub fn value_token(&self) -> Option<SyntaxToken> {
575 support::token(&self.syntax, crate::SyntaxKind::INTEGER)
576 }
577
578 pub fn value(&self) -> Option<i64> {
579 self.value_token()
580 .and_then(|t| t.text().parse::<i64>().ok())
581 }
582}
583
584impl FloatLit {
585 pub fn value_token(&self) -> Option<SyntaxToken> {
586 support::token(&self.syntax, crate::SyntaxKind::FLOAT)
587 }
588
589 pub fn value(&self) -> Option<f64> {
590 self.value_token()
591 .and_then(|t| t.text().parse::<f64>().ok())
592 }
593}
594
595impl BooleanLit {
596 pub fn value(&self) -> Option<bool> {
597 let tok = self
598 .syntax
599 .children_with_tokens()
600 .filter_map(rowan::NodeOrToken::into_token)
601 .find(|t| matches!(t.kind(), SyntaxKind::KW_TRUE | SyntaxKind::KW_FALSE))?;
602 match tok.kind() {
603 SyntaxKind::KW_TRUE => Some(true),
604 SyntaxKind::KW_FALSE => Some(false),
605 _ => None,
606 }
607 }
608}
609
610impl ParenExpr {
611 pub fn inner(&self) -> Option<SyntaxNode> {
613 self.syntax.children().next()
614 }
615}
616
617impl PrefixExpr {
618 pub fn op_token(&self) -> Option<SyntaxToken> {
620 self.syntax
621 .children_with_tokens()
622 .filter_map(rowan::NodeOrToken::into_token)
623 .find(|t| matches!(t.kind(), SyntaxKind::MINUS | SyntaxKind::BANG))
624 }
625
626 pub fn operand(&self) -> Option<SyntaxNode> {
628 self.syntax.children().next()
629 }
630}
631
632impl InfixExpr {
633 pub fn lhs(&self) -> Option<SyntaxNode> {
635 self.syntax.children().next()
636 }
637
638 pub fn rhs(&self) -> Option<SyntaxNode> {
640 self.syntax.children().last()
641 }
642
643 pub fn op_token(&self) -> Option<SyntaxToken> {
648 self.syntax
649 .children_with_tokens()
650 .filter_map(rowan::NodeOrToken::into_token)
651 .find(|t| {
652 matches!(
653 t.kind(),
654 SyntaxKind::AMP_AMP
655 | SyntaxKind::EQ_EQ
656 | SyntaxKind::BANG_EQ
657 | SyntaxKind::LT
658 | SyntaxKind::GT
659 | SyntaxKind::LT_EQ
660 | SyntaxKind::GT_EQ
661 | SyntaxKind::PLUS
662 | SyntaxKind::MINUS
663 | SyntaxKind::STAR
664 | SyntaxKind::SLASH
665 | SyntaxKind::PERCENT
666 | SyntaxKind::PIPE
667 )
668 })
669 }
670
671 pub fn is_double_pipe(&self) -> bool {
674 let mut pipes = self
675 .syntax
676 .children_with_tokens()
677 .filter_map(rowan::NodeOrToken::into_token)
678 .filter(|t| t.kind() == SyntaxKind::PIPE);
679 pipes.next().is_some() && pipes.next().is_some()
680 }
681}
682
683impl ArgList {
684 pub fn is_open(&self) -> bool {
688 support::token(&self.syntax, L_PAREN).is_some()
689 }
690}
691
692impl DivertTarget {
693 pub fn is_end(&self) -> bool {
694 support::token(&self.syntax, SyntaxKind::KW_END).is_some()
695 }
696
697 pub fn is_done(&self) -> bool {
698 support::token(&self.syntax, SyntaxKind::KW_DONE).is_some()
699 }
700
701 pub fn path(&self) -> Option<Path> {
702 support::child(&self.syntax)
703 }
704}
705
706impl ContentLine {
715 pub fn label(&self) -> Option<Label> {
717 support::child(&self.syntax)
718 }
719}
720
721impl Label {
722 pub fn name_token(&self) -> Option<SyntaxToken> {
723 support::token(&self.syntax, IDENT)
724 }
725}
726
727impl DivertStmt {
728 pub fn target(&self) -> Option<DivertTarget> {
729 support::child(&self.syntax)
730 }
731}
732
733impl TunnelCall {
734 pub fn target(&self) -> Option<DivertTarget> {
738 support::child(&self.syntax)
739 }
740}
741
742impl ReturnRedirect {
743 pub fn target(&self) -> Option<DivertTarget> {
744 support::child(&self.syntax)
745 }
746}
747
748impl Choice {
749 pub fn start_content(&self) -> Option<ChoiceStartContent> {
750 support::child(&self.syntax)
751 }
752
753 pub fn bracket_content(&self) -> Option<ChoiceBracketContent> {
754 support::child(&self.syntax)
755 }
756
757 pub fn inner_content(&self) -> Option<ChoiceInnerContent> {
758 support::child(&self.syntax)
759 }
760}
761
762impl ChoiceGuard {
763 pub fn expr(&self) -> Option<SyntaxNode> {
766 self.syntax.children().next()
767 }
768}
769
770impl ChoiceBody {
771 pub fn items(&self) -> impl Iterator<Item = SyntaxNode> {
772 self.syntax.children()
773 }
774}
775
776impl ElseBranch {
777 pub fn choice_body(&self) -> Option<ChoiceBody> {
780 support::child(&self.syntax)
781 }
782
783 pub fn block(&self) -> Option<Block> {
786 support::child(&self.syntax)
787 }
788
789 pub fn items(&self) -> impl Iterator<Item = SyntaxNode> {
793 self.syntax.children()
794 }
795}
796
797impl Splice {
798 pub fn path(&self) -> Option<Path> {
799 support::child(&self.syntax)
800 }
801
802 pub fn arg_list(&self) -> Option<ArgList> {
803 support::child(&self.syntax)
804 }
805}
806
807impl ConditionalBlock {
808 pub fn is_if(&self) -> bool {
809 support::token(&self.syntax, SyntaxKind::KW_IF).is_some()
810 }
811
812 pub fn is_match(&self) -> bool {
813 support::token(&self.syntax, SyntaxKind::KW_MATCH).is_some()
814 }
815
816 pub fn condition(&self) -> Option<SyntaxNode> {
821 self.syntax.children().find(|n| {
822 !matches!(
823 n.kind(),
824 SyntaxKind::IF_ARM | SyntaxKind::ELSE_BRANCH | SyntaxKind::MATCH_ARM
825 )
826 })
827 }
828
829 pub fn if_arm(&self) -> Option<IfArm> {
830 support::child(&self.syntax)
831 }
832
833 pub fn else_arm(&self) -> Option<ElseBranch> {
834 support::child(&self.syntax)
835 }
836
837 pub fn match_arms(&self) -> impl Iterator<Item = MatchArm> {
840 support::children(&self.syntax)
841 }
842}
843
844impl IfArm {
845 pub fn block(&self) -> Option<Block> {
847 support::child(&self.syntax)
848 }
849
850 pub fn items(&self) -> impl Iterator<Item = SyntaxNode> {
852 self.syntax.children()
853 }
854}
855
856impl MatchArm {
857 pub fn pattern_expr(&self) -> Option<SyntaxNode> {
859 support::child::<MatchPattern>(&self.syntax).and_then(|p| p.syntax.children().next())
860 }
861
862 pub fn block(&self) -> Option<Block> {
864 support::child(&self.syntax)
865 }
866
867 pub fn bare_expr(&self) -> Option<SyntaxNode> {
870 self.syntax
871 .children()
872 .find(|n| !matches!(n.kind(), SyntaxKind::MATCH_PATTERN | SyntaxKind::BLOCK))
873 }
874}
875
876impl AlternationBlock {
877 pub fn marker_token(&self) -> Option<SyntaxToken> {
879 support::child::<AlternationMarker>(&self.syntax).and_then(|m| {
880 m.syntax
881 .children_with_tokens()
882 .filter_map(rowan::NodeOrToken::into_token)
883 .find(|t| {
884 matches!(
885 t.kind(),
886 SyntaxKind::TILDE | SyntaxKind::AMP | SyntaxKind::BANG | SyntaxKind::PIPE
887 )
888 })
889 })
890 }
891
892 pub fn entries(&self) -> impl Iterator<Item = Entry> {
898 support::children(&self.syntax)
899 }
900}
901
902impl Entry {
903 pub fn items(&self) -> impl Iterator<Item = SyntaxNode> {
906 self.syntax.children()
907 }
908}
909
910impl TagLine {
911 pub fn tags(&self) -> impl Iterator<Item = Tag> {
912 support::children(&self.syntax)
913 }
914}