blues_lsp/syntax/cst/
view.rs1use 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 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 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 Decl(BindDecl<'cst>),
293 }
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 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 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 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 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 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);