Skip to main content

blues_lsp/syntax/cst/
view.rs

1use arcstr::Substr;
2
3use crate::{
4    syntax::{
5        cst::kind::TreeKind,
6        lexer::token::{Kw, Sym, TokenKind},
7        parser::token::Tt,
8    },
9    util::data::either::Either,
10};
11
12use super::tree::NodeRef;
13
14pub trait View<'cst>: Sized {
15    fn try_cast(node: NodeRef<'cst>) -> Option<Self>;
16    fn syntax(&self) -> NodeRef<'cst>;
17
18    fn cast(node: NodeRef<'cst>) -> Self {
19        Self::try_cast(node).expect("cast called on mismatching node")
20    }
21
22    fn tt(&self, tt: impl Into<Tt>) -> Option<NodeRef<'cst>> {
23        self.syntax().children().find_tt(tt)
24    }
25
26    fn tts(&self, tt: impl Into<Tt>) -> impl Iterator<Item = NodeRef<'cst>> {
27        let tt = tt.into();
28        self.syntax().children().filter(move |n| n.is_tt(tt))
29    }
30}
31
32macro_rules! simple_accessor {
33    ($name:ident) => {
34        #[derive(Debug, Clone, Copy)]
35        pub struct $name<'cst>(NodeRef<'cst>);
36
37        impl<'cst> View<'cst> for $name<'cst> {
38            fn try_cast(node: NodeRef<'cst>) -> Option<Self> {
39                if !node.is_open(TreeKind::$name) {
40                    return None;
41                }
42                Some(Self(node))
43            }
44
45            fn syntax(&self) -> NodeRef<'cst> {
46                self.0
47            }
48        }
49    };
50}
51
52simple_accessor!(Package);
53impl<'cst> Package<'cst> {
54    pub fn name(&self) -> Option<Ident<'cst>> {
55        self.0
56            .children()
57            .find_kind(TreeKind::StartClause)
58            .and_then(|n| n.children().find_map(Ident::try_cast))
59    }
60
61    pub fn end_name(&self) -> Option<Ident<'cst>> {
62        self.0
63            .children()
64            .find_kind(TreeKind::EndClause)
65            .and_then(|n| n.children().find_map(Ident::try_cast))
66    }
67
68    pub fn body(&self) -> Option<Body<'cst>> {
69        // cst.children(self.0).find_map(|n| Body::cast(cst, n))
70        self.0.children().find_map(Body::try_cast)
71    }
72}
73
74simple_accessor!(Body);
75impl<'cst> Body<'cst> {
76    pub fn stmts(&self) -> impl Iterator<Item = Stmt<'cst>> {
77        self.0.children().filter_map(Stmt::try_cast)
78    }
79}
80
81simple_accessor!(Stmt);
82impl<'cst> Stmt<'cst> {
83    // Mising: Attributes
84
85    pub fn kind(&self) -> Option<StmtKind<'cst>> {
86        let stmt = self.0.children().find_kind_where(TreeKind::is_stmt)?;
87
88        match stmt.open_kind()? {
89            TreeKind::StmtFunction => StmtFunction::try_cast(stmt).map(StmtKind::Function),
90            TreeKind::StmtImport => StmtImport::try_cast(stmt).map(StmtKind::Import),
91            TreeKind::StmtExport => StmtExport::try_cast(stmt).map(StmtKind::Export),
92            TreeKind::StmtExprOrBind => StmtExprOrBind::try_cast(stmt).map(StmtKind::ExprOrBind),
93            TreeKind::StmtInterface => StmtInterface::try_cast(stmt).map(StmtKind::Interface),
94            TreeKind::StmtModule => StmtModule::try_cast(stmt).map(StmtKind::Module),
95            TreeKind::StmtTypedef => StmtTypedef::try_cast(stmt).map(StmtKind::Typedef),
96            TreeKind::StmtInstance => StmtInstance::try_cast(stmt).map(StmtKind::Instance),
97            TreeKind::StmtTypeclass => StmtTypeclass::try_cast(stmt).map(StmtKind::Typeclass),
98            _ => None,
99        }
100    }
101}
102
103#[derive(Debug)]
104pub enum StmtKind<'cst> {
105    Function(StmtFunction<'cst>),
106    Method(StmtMethod<'cst>),
107    Import(StmtImport<'cst>),
108    Export(StmtExport<'cst>),
109    ExprOrBind(StmtExprOrBind<'cst>),
110    Interface(StmtInterface<'cst>),
111    Module(StmtModule<'cst>),
112    Typedef(StmtTypedef<'cst>),
113    Instance(StmtInstance<'cst>),
114    Typeclass(StmtTypeclass<'cst>),
115}
116
117simple_accessor!(StmtTypeclass);
118impl<'cst> StmtTypeclass<'cst> {
119    pub fn name(&self) -> Option<Ident<'cst>> {
120        self.0.children().find_map(Ident::try_cast)
121    }
122}
123
124simple_accessor!(StmtInstance);
125
126simple_accessor!(StmtTypedef);
127impl StmtTypedef<'_> {
128    pub fn kind(&self) -> Option<TypedefKind<'_>> {
129        self.0.children().find_map(|node| match node.open_kind()? {
130            TreeKind::TypedefEnum => TypedefEnum::try_cast(node).map(TypedefKind::Enum),
131            TreeKind::TypedefStruct => TypedefStruct::try_cast(node).map(TypedefKind::Struct),
132            TreeKind::TypedefUnion => TypedefUnion::try_cast(node).map(TypedefKind::Union),
133            TreeKind::TypedefAlias => TypedefAlias::try_cast(node).map(TypedefKind::Alias),
134            _ => None,
135        })
136    }
137}
138
139pub enum TypedefKind<'cst> {
140    Enum(TypedefEnum<'cst>),
141    Struct(TypedefStruct<'cst>),
142    Union(TypedefUnion<'cst>),
143    Alias(TypedefAlias<'cst>),
144}
145
146simple_accessor!(TypedefEnum);
147impl<'cst> TypedefEnum<'cst> {
148    pub fn name(&self) -> Option<Ident<'_>> {
149        self.0.children().find_map(Ident::try_cast)
150    }
151
152    pub fn param_list(&self) -> Option<TypedefParamList<'cst>> {
153        self.0.children().find_map(TypedefParamList::try_cast)
154    }
155
156    pub fn derives(&self) -> Option<Derives<'cst>> {
157        self.0.children().find_map(Derives::try_cast)
158    }
159
160    pub fn variant_list(&self) -> Option<EnumVariantList<'cst>> {
161        self.0.children().find_map(EnumVariantList::try_cast)
162    }
163}
164
165simple_accessor!(TypedefStruct);
166impl<'cst> TypedefStruct<'cst> {
167    pub fn name(&self) -> Option<Ident<'_>> {
168        self.0.children().find_map(Ident::try_cast)
169    }
170
171    pub fn param_list(&self) -> Option<TypedefParamList<'cst>> {
172        self.0.children().find_map(TypedefParamList::try_cast)
173    }
174
175    pub fn derives(&self) -> Option<Derives<'cst>> {
176        self.0.children().find_map(Derives::try_cast)
177    }
178
179    pub fn field_list(&self) -> Option<TypedefFieldList<'cst>> {
180        self.0.children().find_map(TypedefFieldList::try_cast)
181    }
182}
183
184simple_accessor!(TypedefUnion);
185impl<'cst> TypedefUnion<'cst> {
186    pub fn name(&self) -> Option<Ident<'_>> {
187        self.0.children().find_map(Ident::try_cast)
188    }
189
190    pub fn param_list(&self) -> Option<TypedefParamList<'cst>> {
191        self.0.children().find_map(TypedefParamList::try_cast)
192    }
193
194    pub fn derives(&self) -> Option<Derives<'cst>> {
195        self.0.children().find_map(Derives::try_cast)
196    }
197
198    pub fn field_list(&self) -> Option<TypedefFieldList<'cst>> {
199        self.0.children().find_map(TypedefFieldList::try_cast)
200    }
201}
202
203simple_accessor!(TypedefAlias);
204impl<'cst> TypedefAlias<'cst> {
205    pub fn name(&self) -> Option<Ident<'_>> {
206        self.0.children().find_map(Ident::try_cast)
207    }
208
209    pub fn param_list(&self) -> Option<TypedefParamList<'cst>> {
210        self.0.children().find_map(TypedefParamList::try_cast)
211    }
212
213    pub fn derives(&self) -> Option<Derives<'cst>> {
214        self.0.children().find_map(Derives::try_cast)
215    }
216
217    pub fn definition(&self) -> Option<TypeExpr<'cst>> {
218        self.0.children().find_map(TypeExpr::try_cast)
219    }
220}
221
222simple_accessor!(TypedefFieldList);
223simple_accessor!(EnumVariantList);
224
225simple_accessor!(StmtModule);
226impl StmtModule<'_> {
227    pub fn name(&self) -> Option<Ident<'_>> {
228        self.0.children().find_map(Ident::try_cast)
229    }
230}
231
232simple_accessor!(ModuleParam);
233impl<'cst> ModuleParam<'cst> {
234    pub fn typed_name(&self) -> Option<TypedName<'cst>> {
235        self.0.children().find_map(TypedName::try_cast)
236    }
237}
238
239simple_accessor!(ModulePortParam);
240impl<'cst> ModulePortParam<'cst> {
241    pub fn name(&self) -> Option<Ident<'cst>> {
242        self.0.children().find_map(Ident::try_cast)
243    }
244}
245
246simple_accessor!(StmtInterface);
247impl StmtInterface<'_> {
248    pub fn name(&self) -> Option<Ident<'_>> {
249        self.0.children().find_map(Ident::try_cast)
250    }
251}
252
253simple_accessor!(StmtExprOrBind);
254impl StmtExprOrBind<'_> {
255    pub fn bind(&self) -> Option<ExprOrBind<'_>> {
256        self.0.children().find_map(ExprOrBind::try_cast)
257    }
258}
259
260#[derive(Debug)]
261pub struct ExprOrBind<'cst>(NodeRef<'cst>);
262
263impl<'cst> View<'cst> for ExprOrBind<'cst> {
264    fn try_cast(node: NodeRef<'cst>) -> Option<Self> {
265        use TreeKind::*;
266        match node.open_kind()? {
267            BindAssign | BindDecl | BindMatch => Some(Self(node)),
268            kind if kind.is_expr() => Some(Self(node)),
269            _ => None,
270        }
271    }
272    fn syntax(&self) -> NodeRef<'cst> {
273        self.0
274    }
275}
276
277impl<'cst> ExprOrBind<'cst> {
278    pub fn expr_or_bind(&self) -> Option<Either<Expr<'cst>, BindKind<'cst>>> {
279        match self.0.open_kind()? {
280            TreeKind::BindDecl => BindDecl::try_cast(self.0)
281                .map(BindKind::Decl)
282                .map(Either::Right),
283            kind if kind.is_expr() => Expr::try_cast(self.0).map(Either::Left),
284            _ => None,
285        }
286    }
287}
288
289pub enum BindKind<'cst> {
290    // TODO:
291    // Assign(BindAssign<'cst>),
292    Decl(BindDecl<'cst>),
293    // Match(BindMatch<'cst>),
294}
295
296simple_accessor!(StmtExport);
297impl StmtExport<'_> {
298    pub fn items(&self) -> impl Iterator<Item = ExportItem<'_>> {
299        self.0.children().filter_map(ExportItem::try_cast)
300    }
301}
302
303simple_accessor!(ExportItem);
304impl<'cst> ExportItem<'cst> {
305    pub fn kind(&self) -> Option<ExportItemKind<'cst>> {
306        let id = self.0.children().find_map(Ident::try_cast)?;
307        if self.0.children().find_tt(Sym::ColonColon).is_some() {
308            Some(ExportItemKind::Package(id))
309        } else if self.0.children().find_tt(Sym::Lparen).is_some() {
310            Some(ExportItemKind::Struct(id))
311        } else {
312            Some(ExportItemKind::Def(id))
313        }
314    }
315}
316
317pub enum ExportItemKind<'cst> {
318    Def(Ident<'cst>),
319    Package(Ident<'cst>),
320    Struct(Ident<'cst>),
321}
322
323simple_accessor!(BindDecl);
324impl<'cst> BindDecl<'cst> {
325    /// Left = 'let'
326    /// Right = 'type expr'
327    pub fn ty(&self) -> Option<Either<(), TypeExpr<'cst>>> {
328        self.0
329            .children()
330            .find_map(TypeExpr::try_cast)
331            .map(Either::Right)
332            .or_else(|| self.0.children().find_tt(Kw::Let).map(|_| Either::Left(())))
333    }
334
335    pub fn init_list(&self) -> Option<VarInitList<'cst>> {
336        self.0.children().find_map(VarInitList::try_cast)
337    }
338}
339
340simple_accessor!(StmtImport);
341impl StmtImport<'_> {
342    pub fn items(&self) -> impl Iterator<Item = ImportItem<'_>> {
343        self.0.children().filter_map(ImportItem::try_cast)
344    }
345}
346
347simple_accessor!(ImportItem);
348impl<'cst> ImportItem<'cst> {
349    pub fn name(&self) -> Option<Ident<'cst>> {
350        self.0.children().find_map(Ident::try_cast)
351    }
352}
353
354simple_accessor!(VarInitList);
355impl<'cst> VarInitList<'cst> {
356    pub fn inits(&self) -> impl Iterator<Item = VarInit<'cst>> {
357        self.0.children().filter_map(VarInit::try_cast)
358    }
359}
360
361simple_accessor!(VarInit);
362impl<'cst> VarInit<'cst> {
363    pub fn target(&self) -> Option<Either<Ident<'_>, DeclPatternList<'_>>> {
364        self.0
365            .children()
366            .find_map(Ident::try_cast)
367            .map(Either::Left)
368            .or_else(|| {
369                self.0
370                    .children()
371                    .find_map(DeclPatternList::try_cast)
372                    .map(Either::Right)
373            })
374    }
375
376    // Missing: array dimensions
377    // Missing: init operator (=, <-, <=)
378
379    pub fn init(&self) -> Option<Expr<'cst>> {
380        self.0.children().find_map(Expr::try_cast)
381    }
382}
383
384simple_accessor!(DeclPatternList);
385impl DeclPatternList<'_> {
386    pub fn elems(&self) -> impl Iterator<Item = DeclPattern<'_>> {
387        self.0.children().filter_map(DeclPattern::try_cast)
388    }
389}
390
391simple_accessor!(DeclPattern);
392impl DeclPattern<'_> {
393    // Left = wildcard (.*)
394    pub fn name(&self) -> Option<Either<(), Ident<'_>>> {
395        self.0
396            .children()
397            .find_map(Ident::try_cast)
398            .map(Either::Right)
399            .or_else(|| {
400                self.0
401                    .children()
402                    .find_tt(Sym::DotStar)
403                    .map(|_| Either::Left(()))
404            })
405    }
406}
407
408simple_accessor!(StmtFunction);
409impl<'cst> StmtFunction<'cst> {
410    pub fn typed_name(&self) -> Option<TypedFunName<'cst>> {
411        self.0.children().find_map(TypedFunName::try_cast)
412    }
413
414    pub fn param_list(&self) -> Option<FunctionParamList<'cst>> {
415        self.0.children().find_map(FunctionParamList::try_cast)
416    }
417
418    pub fn body(&self) -> Option<Either<Expr<'cst>, Body<'cst>>> {
419        self.0
420            .children()
421            .find_map(|n| Expr::try_cast(n).map(Either::Left))
422            .or_else(|| {
423                self.0
424                    .children()
425                    .find_map(Body::try_cast)
426                    .map(Either::Right)
427            })
428    }
429}
430
431simple_accessor!(StmtMethod);
432impl<'cst> StmtMethod<'cst> {
433    pub fn typed_name(&self) -> Option<TypedFunName<'cst>> {
434        self.0.children().find_map(TypedFunName::try_cast)
435    }
436
437    pub fn param_list(&self) -> Option<FunctionParamList<'cst>> {
438        self.0.children().find_map(FunctionParamList::try_cast)
439    }
440}
441
442simple_accessor!(TypedFunName);
443impl<'cst> TypedFunName<'cst> {
444    // Missing: Type
445
446    pub fn name(&self) -> Option<Ident<'cst>> {
447        self.0.children().find_map(Ident::try_cast)
448    }
449}
450
451simple_accessor!(FunctionParamList);
452impl<'cst> FunctionParamList<'cst> {
453    pub fn params(&self) -> impl Iterator<Item = FunctionParam<'cst>> {
454        self.0.children().filter_map(FunctionParam::try_cast)
455    }
456}
457
458simple_accessor!(FunctionParam);
459impl<'cst> FunctionParam<'cst> {
460    // Missing: Attributes
461
462    pub fn typed_name(&self) -> Option<TypedName<'cst>> {
463        self.0.children().find_map(TypedName::try_cast)
464    }
465}
466
467#[derive(Debug)]
468pub struct Expr<'cst>(NodeRef<'cst>);
469
470impl<'cst> View<'cst> for Expr<'cst> {
471    fn try_cast(node: NodeRef<'cst>) -> Option<Self> {
472        if !node.is_open_where(TreeKind::is_expr) {
473            return None;
474        }
475        Some(Self(node))
476    }
477
478    fn syntax(&self) -> NodeRef<'cst> {
479        self.0
480    }
481}
482
483impl<'cst> Expr<'cst> {
484    pub fn kind(&self) -> Option<ExprKind<'cst>> {
485        match self.0.open_kind()? {
486            TreeKind::ExprVar => ExprVar::try_cast(self.0).map(ExprKind::Var),
487            TreeKind::ExprBinary => ExprBinary::try_cast(self.0).map(ExprKind::Binary),
488            TreeKind::ExprPrefixOp => ExprPrefixOp::try_cast(self.0).map(ExprKind::PrefixOp),
489            TreeKind::ExprStructInit => ExprStructInit::try_cast(self.0).map(ExprKind::StructInit),
490            _ => None,
491        }
492    }
493}
494
495pub enum ExprKind<'cst> {
496    Var(ExprVar<'cst>),
497    Binary(ExprBinary<'cst>),
498    PrefixOp(ExprPrefixOp<'cst>),
499    StructInit(ExprStructInit<'cst>),
500}
501
502simple_accessor!(ExprBinary);
503impl<'cst> ExprBinary<'cst> {
504    pub fn op(&self) -> Option<NodeRef<'cst>> {
505        self.0.children().find(|n| {
506            n.token()
507                .map(|t| matches!(t.kind, TokenKind::Sym(_)))
508                .unwrap_or(false)
509        })
510    }
511}
512
513simple_accessor!(ExprPrefixOp);
514impl<'cst> ExprPrefixOp<'cst> {
515    pub fn op(&self) -> Option<NodeRef<'cst>> {
516        self.0.children().find(|n| {
517            n.token()
518                .map(|t| matches!(t.kind, TokenKind::Sym(_)))
519                .unwrap_or(false)
520        })
521    }
522}
523
524simple_accessor!(ExprStructInit);
525
526simple_accessor!(ExprVar);
527impl<'cst> ExprVar<'cst> {
528    pub fn id(&self) -> Option<QualId<'cst>> {
529        self.0.children().find_map(QualId::try_cast)
530    }
531}
532
533pub struct TypeExpr<'cst>(NodeRef<'cst>);
534
535impl<'cst> View<'cst> for TypeExpr<'cst> {
536    fn try_cast(node: NodeRef<'cst>) -> Option<Self> {
537        if !node.is_open_where(TreeKind::is_type) {
538            return None;
539        }
540        Some(Self(node))
541    }
542
543    fn syntax(&self) -> NodeRef<'cst> {
544        self.0
545    }
546}
547
548impl<'cst> TypeExpr<'cst> {
549    pub fn kind(&self) -> Option<TypeKind<'cst>> {
550        match self.0.open_kind()? {
551            TreeKind::TypeCons => TypeCons::try_cast(self.0).map(TypeKind::Cons),
552            TreeKind::TypeVar => TypeVar::try_cast(self.0).map(TypeKind::Var),
553            _ => None,
554        }
555    }
556}
557
558pub enum TypeKind<'cst> {
559    Cons(TypeCons<'cst>),
560    Var(TypeVar<'cst>),
561}
562
563simple_accessor!(TypeCons);
564impl<'cst> TypeCons<'cst> {
565    pub fn id(&self) -> Option<QualId<'cst>> {
566        self.0.children().find_map(QualId::try_cast)
567    }
568}
569
570simple_accessor!(TypeVar);
571impl<'cst> TypeVar<'cst> {
572    pub fn name(&self) -> Option<Ident<'cst>> {
573        self.0.children().find_map(Ident::try_cast)
574    }
575}
576
577simple_accessor!(TypeArgList);
578
579simple_accessor!(QualId);
580impl<'cst> QualId<'cst> {
581    pub fn pkg(&self) -> Option<Ident<'cst>> {
582        self.0
583            .children()
584            .find_kind(TreeKind::PkgId)
585            .and_then(|n| n.children().find_map(Ident::try_cast))
586    }
587
588    pub fn colon_colon(&self) -> Option<NodeRef<'_>> {
589        self.0
590            .children()
591            .find_kind(TreeKind::PkgId)
592            .and_then(|n| n.children().find_tt(Sym::ColonColon))
593    }
594
595    pub fn name(&self) -> Option<Ident<'cst>> {
596        self.0.children().find_map(Ident::try_cast)
597    }
598}
599
600simple_accessor!(TypedName);
601impl<'cst> TypedName<'cst> {
602    pub fn ty(&self) -> Option<Either<TypeExpr<'cst>, FunctionProto<'cst>>> {
603        self.0
604            .children()
605            .find_map(FunctionProto::try_cast)
606            .map(Either::Right)
607            .or_else(|| {
608                self.0
609                    .children()
610                    .find_map(TypeExpr::try_cast)
611                    .map(Either::Left)
612            })
613    }
614
615    pub fn name(&self) -> Option<Ident<'cst>> {
616        self.0
617            .children()
618            .find_map(FunctionProto::try_cast)
619            .and_then(|f| f.name())
620            .or_else(|| self.0.children().find_map(Ident::try_cast))
621    }
622}
623
624simple_accessor!(FunctionProto);
625impl<'cst> FunctionProto<'cst> {
626    pub fn name(&self) -> Option<Ident<'cst>> {
627        self.0.children().find_map(Ident::try_cast)
628    }
629
630    pub fn param_list(&self) -> Option<FunctionParamList<'cst>> {
631        self.0.children().find_map(FunctionParamList::try_cast)
632    }
633}
634
635#[derive(Debug, Clone, Copy)]
636pub struct Ident<'cst>(NodeRef<'cst>);
637
638impl<'cst> View<'cst> for Ident<'cst> {
639    fn try_cast(node: NodeRef<'cst>) -> Option<Self> {
640        if !node.is_tt(Tt::Ident) {
641            return None;
642        }
643        Some(Self(node))
644    }
645    fn syntax(&self) -> NodeRef<'cst> {
646        self.0
647    }
648}
649impl Ident<'_> {
650    pub fn str(&self) -> Substr {
651        self.0
652            .token()
653            .and_then(|t| t.kind.ident())
654            .expect("Ident accessor created on non-ident node")
655            .clone()
656    }
657}
658
659simple_accessor!(AttributeList);
660simple_accessor!(Attribute);
661simple_accessor!(AttributeName);
662simple_accessor!(AttributeValue);
663simple_accessor!(AttributeValueList);
664
665simple_accessor!(SoftKw);
666
667simple_accessor!(TypedefParamList);
668
669simple_accessor!(TypedefParam);
670impl<'cst> TypedefParam<'cst> {
671    pub fn name(&self) -> Option<Ident<'cst>> {
672        self.0.children().find_map(Ident::try_cast)
673    }
674}
675
676simple_accessor!(Derives);