rue_ast/
lib.rs

1use paste::paste;
2use rue_parser::{SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, T};
3
4pub trait AstNode {
5    fn cast(node: SyntaxNode) -> Option<Self>
6    where
7        Self: Sized;
8
9    fn syntax(&self) -> &SyntaxNode;
10}
11
12macro_rules! ast_nodes {
13    ($( $kind:ident),+ $(,)?) => { paste! { $(
14        #[derive(Debug, Clone)]
15        pub struct [< Ast $kind >](SyntaxNode);
16
17        impl AstNode for [< Ast $kind >] {
18            fn cast(node: SyntaxNode) -> Option<Self> {
19                match node.kind() {
20                    SyntaxKind::$kind => Some(Self(node)),
21                    _ => None,
22                }
23            }
24
25            fn syntax(&self) -> &SyntaxNode {
26                &self.0
27            }
28        }
29    )+ } };
30}
31
32macro_rules! ast_enum {
33    ($name:ident, $( $kind:ident ),+ $(,)? ) => { paste! {
34        #[derive(Debug, Clone)]
35        pub enum [< Ast $name >] {
36            $( $kind([< Ast $kind >]), )+
37        }
38
39        impl AstNode for [< Ast $name >] {
40            fn cast(node: SyntaxNode) -> Option<Self> {
41                $( if let Some(node) = [< Ast $kind >]::cast(node.clone()) {
42                    return Some(Self::$kind(node));
43                } )+
44                None
45            }
46
47            fn syntax(&self) -> &SyntaxNode {
48                match self {
49                    $( Self::$kind(node) => node.syntax(), )+
50                }
51            }
52        }
53    } };
54}
55
56ast_nodes!(
57    Document,
58    ModuleItem,
59    FunctionItem,
60    FunctionParameter,
61    ConstantItem,
62    TypeAliasItem,
63    StructItem,
64    StructField,
65    ImportItem,
66    ImportPath,
67    ImportPathSegment,
68    GenericParameters,
69    GenericArguments,
70    LiteralType,
71    PathType,
72    UnionType,
73    GroupType,
74    PairType,
75    ListType,
76    ListTypeItem,
77    LambdaType,
78    LambdaParameter,
79    Block,
80    LetStmt,
81    ExprStmt,
82    IfStmt,
83    ReturnStmt,
84    AssertStmt,
85    RaiseStmt,
86    DebugStmt,
87    PathExpr,
88    PathSegment,
89    StructInitializerExpr,
90    StructInitializerField,
91    LiteralExpr,
92    GroupExpr,
93    PairExpr,
94    ListExpr,
95    ListItem,
96    PrefixExpr,
97    BinaryExpr,
98    FunctionCallExpr,
99    IfExpr,
100    GuardExpr,
101    CastExpr,
102    FieldAccessExpr,
103    LambdaExpr,
104    NamedBinding,
105    PairBinding,
106    ListBinding,
107    ListBindingItem,
108    StructBinding,
109    StructFieldBinding,
110);
111
112ast_enum!(Item, TypeItem, SymbolItem, ImportItem);
113ast_enum!(TypeItem, TypeAliasItem, StructItem);
114ast_enum!(SymbolItem, ModuleItem, FunctionItem, ConstantItem);
115ast_enum!(
116    Stmt, LetStmt, ExprStmt, IfStmt, ReturnStmt, AssertStmt, RaiseStmt, DebugStmt
117);
118ast_enum!(StmtOrExpr, Stmt, Expr);
119ast_enum!(
120    Expr,
121    PathExpr,
122    StructInitializerExpr,
123    LiteralExpr,
124    GroupExpr,
125    PairExpr,
126    ListExpr,
127    PrefixExpr,
128    BinaryExpr,
129    FunctionCallExpr,
130    Block,
131    IfExpr,
132    GuardExpr,
133    CastExpr,
134    FieldAccessExpr,
135    LambdaExpr,
136);
137ast_enum!(
138    Type,
139    LiteralType,
140    PathType,
141    UnionType,
142    GroupType,
143    PairType,
144    ListType,
145    LambdaType,
146);
147ast_enum!(
148    Binding,
149    NamedBinding,
150    PairBinding,
151    ListBinding,
152    StructBinding,
153);
154
155impl AstDocument {
156    pub fn items(&self) -> impl Iterator<Item = AstItem> {
157        self.syntax().children().filter_map(AstItem::cast)
158    }
159}
160
161impl AstModuleItem {
162    pub fn export(&self) -> Option<SyntaxToken> {
163        self.syntax()
164            .children_with_tokens()
165            .filter_map(SyntaxElement::into_token)
166            .find(|token| token.kind() == T![export])
167    }
168
169    pub fn name(&self) -> Option<SyntaxToken> {
170        self.syntax()
171            .children_with_tokens()
172            .filter_map(SyntaxElement::into_token)
173            .find(|token| token.kind() == SyntaxKind::Ident)
174    }
175
176    pub fn items(&self) -> impl Iterator<Item = AstItem> {
177        self.syntax().children().filter_map(AstItem::cast)
178    }
179}
180
181impl AstFunctionItem {
182    pub fn export(&self) -> Option<SyntaxToken> {
183        self.syntax()
184            .children_with_tokens()
185            .filter_map(SyntaxElement::into_token)
186            .find(|token| token.kind() == T![export])
187    }
188
189    pub fn extern_kw(&self) -> Option<SyntaxToken> {
190        self.syntax()
191            .children_with_tokens()
192            .filter_map(SyntaxElement::into_token)
193            .find(|token| token.kind() == T![extern])
194    }
195
196    pub fn inline(&self) -> Option<SyntaxToken> {
197        self.syntax()
198            .children_with_tokens()
199            .filter_map(SyntaxElement::into_token)
200            .find(|token| token.kind() == T![inline])
201    }
202
203    pub fn test(&self) -> Option<SyntaxToken> {
204        self.syntax()
205            .children_with_tokens()
206            .filter_map(SyntaxElement::into_token)
207            .find(|token| token.kind() == T![test])
208    }
209
210    pub fn name(&self) -> Option<SyntaxToken> {
211        self.syntax()
212            .children_with_tokens()
213            .filter_map(SyntaxElement::into_token)
214            .find(|token| token.kind() == SyntaxKind::Ident)
215    }
216
217    pub fn generic_parameters(&self) -> Option<AstGenericParameters> {
218        self.syntax()
219            .children()
220            .find_map(AstGenericParameters::cast)
221    }
222
223    pub fn parameters(&self) -> impl Iterator<Item = AstFunctionParameter> {
224        self.syntax()
225            .children()
226            .filter_map(AstFunctionParameter::cast)
227    }
228
229    pub fn return_type(&self) -> Option<AstType> {
230        self.syntax().children().find_map(AstType::cast)
231    }
232
233    pub fn body(&self) -> Option<AstBlock> {
234        self.syntax().children().find_map(AstBlock::cast)
235    }
236}
237
238impl AstConstantItem {
239    pub fn export(&self) -> Option<SyntaxToken> {
240        self.syntax()
241            .children_with_tokens()
242            .filter_map(SyntaxElement::into_token)
243            .find(|token| token.kind() == T![export])
244    }
245
246    pub fn inline(&self) -> Option<SyntaxToken> {
247        self.syntax()
248            .children_with_tokens()
249            .filter_map(SyntaxElement::into_token)
250            .find(|token| token.kind() == T![inline])
251    }
252
253    pub fn name(&self) -> Option<SyntaxToken> {
254        self.syntax()
255            .children_with_tokens()
256            .filter_map(SyntaxElement::into_token)
257            .find(|token| token.kind() == SyntaxKind::Ident)
258    }
259
260    pub fn ty(&self) -> Option<AstType> {
261        self.syntax().children().find_map(AstType::cast)
262    }
263
264    pub fn value(&self) -> Option<AstExpr> {
265        self.syntax().children().find_map(AstExpr::cast)
266    }
267}
268
269impl AstTypeAliasItem {
270    pub fn export(&self) -> Option<SyntaxToken> {
271        self.syntax()
272            .children_with_tokens()
273            .filter_map(SyntaxElement::into_token)
274            .find(|token| token.kind() == T![export])
275    }
276
277    pub fn name(&self) -> Option<SyntaxToken> {
278        self.syntax()
279            .children_with_tokens()
280            .filter_map(SyntaxElement::into_token)
281            .find(|token| token.kind() == SyntaxKind::Ident)
282    }
283
284    pub fn generic_parameters(&self) -> Option<AstGenericParameters> {
285        self.syntax()
286            .children()
287            .find_map(AstGenericParameters::cast)
288    }
289
290    pub fn ty(&self) -> Option<AstType> {
291        self.syntax().children().find_map(AstType::cast)
292    }
293}
294
295impl AstStructItem {
296    pub fn export(&self) -> Option<SyntaxToken> {
297        self.syntax()
298            .children_with_tokens()
299            .filter_map(SyntaxElement::into_token)
300            .find(|token| token.kind() == T![export])
301    }
302
303    pub fn name(&self) -> Option<SyntaxToken> {
304        self.syntax()
305            .children_with_tokens()
306            .filter_map(SyntaxElement::into_token)
307            .find(|token| token.kind() == SyntaxKind::Ident)
308    }
309
310    pub fn generic_parameters(&self) -> Option<AstGenericParameters> {
311        self.syntax()
312            .children()
313            .find_map(AstGenericParameters::cast)
314    }
315
316    pub fn fields(&self) -> impl Iterator<Item = AstStructField> {
317        self.syntax().children().filter_map(AstStructField::cast)
318    }
319}
320
321impl AstStructField {
322    pub fn spread(&self) -> Option<SyntaxToken> {
323        self.syntax()
324            .children_with_tokens()
325            .filter_map(SyntaxElement::into_token)
326            .find(|token| token.kind() == T![...])
327    }
328
329    pub fn name(&self) -> Option<SyntaxToken> {
330        self.syntax()
331            .children_with_tokens()
332            .filter_map(SyntaxElement::into_token)
333            .find(|token| token.kind() == SyntaxKind::Ident)
334    }
335
336    pub fn ty(&self) -> Option<AstType> {
337        self.syntax().children().find_map(AstType::cast)
338    }
339
340    pub fn expr(&self) -> Option<AstExpr> {
341        self.syntax().children().find_map(AstExpr::cast)
342    }
343}
344
345impl AstImportItem {
346    pub fn export(&self) -> Option<SyntaxToken> {
347        self.syntax()
348            .children_with_tokens()
349            .filter_map(SyntaxElement::into_token)
350            .find(|token| token.kind() == T![export])
351    }
352
353    pub fn path(&self) -> Option<AstImportPath> {
354        self.syntax().children().find_map(AstImportPath::cast)
355    }
356}
357
358impl AstImportPath {
359    pub fn segments(&self) -> impl Iterator<Item = AstImportPathSegment> {
360        self.syntax()
361            .children()
362            .filter_map(AstImportPathSegment::cast)
363    }
364}
365
366impl AstImportPathSegment {
367    pub fn separator(&self) -> Option<SyntaxToken> {
368        self.syntax()
369            .children_with_tokens()
370            .filter_map(SyntaxElement::into_token)
371            .find(|token| token.kind() == T![::])
372    }
373
374    pub fn name(&self) -> Option<SyntaxToken> {
375        self.syntax()
376            .children_with_tokens()
377            .filter_map(SyntaxElement::into_token)
378            .find(|token| token.kind() == SyntaxKind::Ident || token.kind() == T![super])
379    }
380
381    pub fn star(&self) -> Option<SyntaxToken> {
382        self.syntax()
383            .children_with_tokens()
384            .filter_map(SyntaxElement::into_token)
385            .find(|token| token.kind() == T![*])
386    }
387
388    pub fn items(&self) -> impl Iterator<Item = AstImportPath> {
389        self.syntax().children().filter_map(AstImportPath::cast)
390    }
391}
392
393impl AstFunctionParameter {
394    pub fn spread(&self) -> Option<SyntaxToken> {
395        self.syntax()
396            .children_with_tokens()
397            .filter_map(SyntaxElement::into_token)
398            .find(|token| token.kind() == T![...])
399    }
400
401    pub fn binding(&self) -> Option<AstBinding> {
402        self.syntax().children().find_map(AstBinding::cast)
403    }
404
405    pub fn ty(&self) -> Option<AstType> {
406        self.syntax().children().find_map(AstType::cast)
407    }
408}
409
410impl AstGenericParameters {
411    pub fn names(&self) -> impl Iterator<Item = SyntaxToken> {
412        self.syntax()
413            .children_with_tokens()
414            .filter_map(SyntaxElement::into_token)
415            .filter(|token| token.kind() == SyntaxKind::Ident)
416    }
417}
418
419impl AstGenericArguments {
420    pub fn types(&self) -> impl Iterator<Item = AstType> {
421        self.syntax().children().filter_map(AstType::cast)
422    }
423}
424
425impl AstBlock {
426    pub fn items(&self) -> impl Iterator<Item = AstStmtOrExpr> {
427        self.syntax().children().filter_map(AstStmtOrExpr::cast)
428    }
429}
430
431impl AstLetStmt {
432    pub fn inline(&self) -> Option<SyntaxToken> {
433        self.syntax()
434            .children_with_tokens()
435            .filter_map(SyntaxElement::into_token)
436            .find(|token| token.kind() == T![inline])
437    }
438
439    pub fn binding(&self) -> Option<AstBinding> {
440        self.syntax().children().find_map(AstBinding::cast)
441    }
442
443    pub fn ty(&self) -> Option<AstType> {
444        self.syntax().children().find_map(AstType::cast)
445    }
446
447    pub fn value(&self) -> Option<AstExpr> {
448        self.syntax().children().find_map(AstExpr::cast)
449    }
450}
451
452impl AstExprStmt {
453    pub fn expr(&self) -> Option<AstExpr> {
454        self.syntax().children().find_map(AstExpr::cast)
455    }
456}
457
458impl AstIfStmt {
459    pub fn inline(&self) -> Option<SyntaxToken> {
460        self.syntax()
461            .children_with_tokens()
462            .filter_map(SyntaxElement::into_token)
463            .find(|token| token.kind() == T![inline])
464    }
465
466    pub fn condition(&self) -> Option<AstExpr> {
467        self.syntax().children().find_map(AstExpr::cast)
468    }
469
470    pub fn then_block(&self) -> Option<AstBlock> {
471        self.syntax()
472            .children()
473            .filter(|node| AstExpr::cast(node.clone()).is_some())
474            .nth(1)
475            .and_then(AstBlock::cast)
476    }
477}
478
479impl AstReturnStmt {
480    pub fn expr(&self) -> Option<AstExpr> {
481        self.syntax().children().find_map(AstExpr::cast)
482    }
483}
484
485impl AstAssertStmt {
486    pub fn expr(&self) -> Option<AstExpr> {
487        self.syntax().children().find_map(AstExpr::cast)
488    }
489}
490
491impl AstRaiseStmt {
492    pub fn expr(&self) -> Option<AstExpr> {
493        self.syntax().children().find_map(AstExpr::cast)
494    }
495}
496
497impl AstDebugStmt {
498    pub fn expr(&self) -> Option<AstExpr> {
499        self.syntax().children().find_map(AstExpr::cast)
500    }
501}
502
503impl AstPathExpr {
504    pub fn segments(&self) -> impl Iterator<Item = AstPathSegment> {
505        self.syntax().children().filter_map(AstPathSegment::cast)
506    }
507}
508
509impl AstPathSegment {
510    pub fn separator(&self) -> Option<SyntaxToken> {
511        self.syntax()
512            .children_with_tokens()
513            .filter_map(SyntaxElement::into_token)
514            .find(|token| token.kind() == T![::])
515            .filter(|token| {
516                let Some(name) = self.name() else {
517                    return true;
518                };
519                token.text_range().start() < name.text_range().start()
520            })
521    }
522
523    pub fn name(&self) -> Option<SyntaxToken> {
524        self.syntax()
525            .children_with_tokens()
526            .filter_map(SyntaxElement::into_token)
527            .find(|token| token.kind() == SyntaxKind::Ident || token.kind() == T![super])
528    }
529
530    pub fn generic_arguments(&self) -> Option<AstGenericArguments> {
531        self.syntax().children().find_map(AstGenericArguments::cast)
532    }
533}
534
535impl AstStructInitializerExpr {
536    pub fn path(&self) -> Option<AstPathExpr> {
537        self.syntax().children().find_map(AstPathExpr::cast)
538    }
539
540    pub fn fields(&self) -> impl Iterator<Item = AstStructInitializerField> {
541        self.syntax()
542            .children()
543            .filter_map(AstStructInitializerField::cast)
544    }
545}
546
547impl AstStructInitializerField {
548    pub fn name(&self) -> Option<SyntaxToken> {
549        self.syntax()
550            .children_with_tokens()
551            .filter_map(SyntaxElement::into_token)
552            .find(|token| token.kind() == SyntaxKind::Ident)
553    }
554
555    pub fn expr(&self) -> Option<AstExpr> {
556        self.syntax().children().find_map(AstExpr::cast)
557    }
558}
559
560impl AstLiteralExpr {
561    pub fn value(&self) -> Option<SyntaxToken> {
562        self.syntax()
563            .children_with_tokens()
564            .filter_map(SyntaxElement::into_token)
565            .find(|token| SyntaxKind::LITERAL.contains(&token.kind()))
566    }
567}
568
569impl AstGroupExpr {
570    pub fn expr(&self) -> Option<AstExpr> {
571        self.syntax().children().find_map(AstExpr::cast)
572    }
573}
574
575impl AstPairExpr {
576    pub fn first(&self) -> Option<AstExpr> {
577        self.syntax().children().find_map(AstExpr::cast)
578    }
579
580    pub fn rest(&self) -> Option<AstExpr> {
581        self.syntax().children().filter_map(AstExpr::cast).nth(1)
582    }
583}
584
585impl AstListExpr {
586    pub fn items(&self) -> impl Iterator<Item = AstListItem> {
587        self.syntax().children().filter_map(AstListItem::cast)
588    }
589}
590
591impl AstListItem {
592    pub fn spread(&self) -> Option<SyntaxToken> {
593        self.syntax()
594            .children_with_tokens()
595            .filter_map(SyntaxElement::into_token)
596            .find(|token| token.kind() == T![...])
597    }
598
599    pub fn expr(&self) -> Option<AstExpr> {
600        self.syntax().children().find_map(AstExpr::cast)
601    }
602}
603
604impl AstPrefixExpr {
605    pub fn op(&self) -> Option<SyntaxToken> {
606        self.syntax()
607            .children_with_tokens()
608            .filter_map(SyntaxElement::into_token)
609            .find(|token| SyntaxKind::PREFIX_OPS.contains(&token.kind()))
610    }
611
612    pub fn expr(&self) -> Option<AstExpr> {
613        self.syntax().children().find_map(AstExpr::cast)
614    }
615}
616
617impl AstBinaryExpr {
618    pub fn op(&self) -> Option<SyntaxToken> {
619        self.syntax()
620            .children_with_tokens()
621            .filter_map(SyntaxElement::into_token)
622            .find(|token| SyntaxKind::BINARY_OPS.contains(&token.kind()))
623    }
624
625    pub fn left(&self) -> Option<AstExpr> {
626        self.syntax().children().find_map(AstExpr::cast)
627    }
628
629    pub fn right(&self) -> Option<AstExpr> {
630        self.syntax().children().filter_map(AstExpr::cast).nth(1)
631    }
632}
633
634impl AstFunctionCallExpr {
635    pub fn expr(&self) -> Option<AstExpr> {
636        self.syntax().children().find_map(AstExpr::cast)
637    }
638
639    pub fn args(&self) -> impl Iterator<Item = AstListItem> {
640        self.syntax().children().filter_map(AstListItem::cast)
641    }
642}
643
644impl AstIfExpr {
645    pub fn inline(&self) -> Option<SyntaxToken> {
646        self.syntax()
647            .children_with_tokens()
648            .filter_map(SyntaxElement::into_token)
649            .find(|token| token.kind() == T![inline])
650    }
651
652    pub fn condition(&self) -> Option<AstExpr> {
653        self.syntax().children().find_map(AstExpr::cast)
654    }
655
656    pub fn then_expr(&self) -> Option<AstExpr> {
657        self.syntax().children().filter_map(AstExpr::cast).nth(1)
658    }
659
660    pub fn else_expr(&self) -> Option<AstExpr> {
661        self.syntax().children().filter_map(AstExpr::cast).nth(2)
662    }
663}
664
665impl AstGuardExpr {
666    pub fn expr(&self) -> Option<AstExpr> {
667        self.syntax().children().find_map(AstExpr::cast)
668    }
669
670    pub fn ty(&self) -> Option<AstType> {
671        self.syntax().children().find_map(AstType::cast)
672    }
673}
674
675impl AstCastExpr {
676    pub fn expr(&self) -> Option<AstExpr> {
677        self.syntax().children().find_map(AstExpr::cast)
678    }
679
680    pub fn ty(&self) -> Option<AstType> {
681        self.syntax().children().find_map(AstType::cast)
682    }
683}
684
685impl AstFieldAccessExpr {
686    pub fn expr(&self) -> Option<AstExpr> {
687        self.syntax().children().find_map(AstExpr::cast)
688    }
689
690    pub fn dot(&self) -> Option<SyntaxToken> {
691        self.syntax()
692            .children_with_tokens()
693            .filter_map(SyntaxElement::into_token)
694            .find(|token| token.kind() == T![.])
695    }
696
697    pub fn field(&self) -> Option<SyntaxToken> {
698        self.syntax()
699            .children_with_tokens()
700            .filter_map(SyntaxElement::into_token)
701            .find(|token| token.kind() == SyntaxKind::Ident)
702    }
703}
704
705impl AstLambdaExpr {
706    pub fn generic_parameters(&self) -> Option<AstGenericParameters> {
707        self.syntax()
708            .children()
709            .find_map(AstGenericParameters::cast)
710    }
711
712    pub fn parameters(&self) -> impl Iterator<Item = AstFunctionParameter> {
713        self.syntax()
714            .children()
715            .filter_map(AstFunctionParameter::cast)
716    }
717
718    pub fn ty(&self) -> Option<AstType> {
719        self.syntax().children().find_map(AstType::cast)
720    }
721
722    pub fn body(&self) -> Option<AstExpr> {
723        self.syntax().children().find_map(AstExpr::cast)
724    }
725}
726
727impl AstLiteralType {
728    pub fn value(&self) -> Option<SyntaxToken> {
729        self.syntax()
730            .children_with_tokens()
731            .filter_map(SyntaxElement::into_token)
732            .find(|token| SyntaxKind::LITERAL.contains(&token.kind()))
733    }
734}
735
736impl AstPathType {
737    pub fn segments(&self) -> impl Iterator<Item = AstPathSegment> {
738        self.syntax().children().filter_map(AstPathSegment::cast)
739    }
740}
741
742impl AstUnionType {
743    pub fn types(&self) -> impl Iterator<Item = AstType> {
744        self.syntax().children().filter_map(AstType::cast)
745    }
746}
747
748impl AstGroupType {
749    pub fn ty(&self) -> Option<AstType> {
750        self.syntax().children().find_map(AstType::cast)
751    }
752}
753
754impl AstPairType {
755    pub fn first(&self) -> Option<AstType> {
756        self.syntax().children().find_map(AstType::cast)
757    }
758
759    pub fn rest(&self) -> Option<AstType> {
760        self.syntax().children().filter_map(AstType::cast).nth(1)
761    }
762}
763
764impl AstListType {
765    pub fn items(&self) -> impl Iterator<Item = AstListTypeItem> {
766        self.syntax().children().filter_map(AstListTypeItem::cast)
767    }
768}
769
770impl AstListTypeItem {
771    pub fn spread(&self) -> Option<SyntaxToken> {
772        self.syntax()
773            .children_with_tokens()
774            .filter_map(SyntaxElement::into_token)
775            .find(|token| token.kind() == T![...])
776    }
777
778    pub fn ty(&self) -> Option<AstType> {
779        self.syntax().children().find_map(AstType::cast)
780    }
781}
782
783impl AstLambdaType {
784    pub fn generic_parameters(&self) -> Option<AstGenericParameters> {
785        self.syntax()
786            .children()
787            .find_map(AstGenericParameters::cast)
788    }
789
790    pub fn parameters(&self) -> impl Iterator<Item = AstLambdaParameter> {
791        self.syntax()
792            .children()
793            .filter_map(AstLambdaParameter::cast)
794    }
795
796    pub fn return_type(&self) -> Option<AstType> {
797        self.syntax().children().find_map(AstType::cast)
798    }
799}
800
801impl AstLambdaParameter {
802    pub fn spread(&self) -> Option<SyntaxToken> {
803        self.syntax()
804            .children_with_tokens()
805            .filter_map(SyntaxElement::into_token)
806            .find(|token| token.kind() == T![...])
807    }
808
809    pub fn name(&self) -> Option<SyntaxToken> {
810        self.syntax()
811            .children_with_tokens()
812            .filter_map(SyntaxElement::into_token)
813            .find(|token| token.kind() == SyntaxKind::Ident)
814    }
815
816    pub fn ty(&self) -> Option<AstType> {
817        self.syntax().children().find_map(AstType::cast)
818    }
819}
820
821impl AstNamedBinding {
822    pub fn name(&self) -> Option<SyntaxToken> {
823        self.syntax()
824            .children_with_tokens()
825            .filter_map(SyntaxElement::into_token)
826            .find(|token| token.kind() == SyntaxKind::Ident)
827    }
828}
829
830impl AstPairBinding {
831    pub fn first(&self) -> Option<AstBinding> {
832        self.syntax().children().find_map(AstBinding::cast)
833    }
834
835    pub fn rest(&self) -> Option<AstBinding> {
836        self.syntax().children().filter_map(AstBinding::cast).nth(1)
837    }
838}
839
840impl AstListBinding {
841    pub fn items(&self) -> impl Iterator<Item = AstListBindingItem> {
842        self.syntax()
843            .children()
844            .filter_map(AstListBindingItem::cast)
845    }
846}
847
848impl AstListBindingItem {
849    pub fn spread(&self) -> Option<SyntaxToken> {
850        self.syntax()
851            .children_with_tokens()
852            .filter_map(SyntaxElement::into_token)
853            .find(|token| token.kind() == T![...])
854    }
855
856    pub fn binding(&self) -> Option<AstBinding> {
857        self.syntax().children().find_map(AstBinding::cast)
858    }
859}
860
861impl AstStructBinding {
862    pub fn fields(&self) -> impl Iterator<Item = AstStructFieldBinding> {
863        self.syntax()
864            .children()
865            .filter_map(AstStructFieldBinding::cast)
866    }
867}
868
869impl AstStructFieldBinding {
870    pub fn name(&self) -> Option<SyntaxToken> {
871        self.syntax()
872            .children_with_tokens()
873            .filter_map(SyntaxElement::into_token)
874            .find(|token| token.kind() == SyntaxKind::Ident)
875    }
876
877    pub fn binding(&self) -> Option<AstBinding> {
878        self.syntax().children().find_map(AstBinding::cast)
879    }
880}