1use crate::{decl::Decl, expr::Expr, stmt::Stmt};
4
5mod parents;
6
7use bitflags::bitflags;
8use gramatika::{ArcStr, Spanned, Substr};
9pub use parents::{find_parent, find_parents};
10
11#[cfg(feature = "lsp")]
12use lsp_types::{Position, Range};
13
14#[derive(DebugLisp, Clone)]
15pub enum SyntaxNode {
16 Decl(Decl),
17 Stmt(Stmt),
18 Expr(Expr),
19}
20
21bitflags! {
22 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
23 pub struct SyntaxKind: u8 {
24 const DECL = 0b001;
25 const STMT = 0b010;
26 const EXPR = 0b100;
27 }
28}
29
30pub trait GetSyntaxKind {
31 const KIND: SyntaxKind;
32}
33impl GetSyntaxKind for Decl {
34 const KIND: SyntaxKind = SyntaxKind::DECL;
35}
36impl GetSyntaxKind for Stmt {
37 const KIND: SyntaxKind = SyntaxKind::STMT;
38}
39impl GetSyntaxKind for Expr {
40 const KIND: SyntaxKind = SyntaxKind::EXPR;
41}
42impl GetSyntaxKind for SyntaxNode {
43 const KIND: SyntaxKind = SyntaxKind::all();
44}
45
46impl Spanned for SyntaxNode {
47 fn span(&self) -> gramatika::Span {
48 match self {
49 SyntaxNode::Decl(decl) => decl.span(),
50 SyntaxNode::Stmt(stmt) => stmt.span(),
51 SyntaxNode::Expr(expr) => expr.span(),
52 }
53 }
54}
55
56impl From<SyntaxNode> for Decl {
57 fn from(value: SyntaxNode) -> Self {
58 match value {
59 SyntaxNode::Decl(inner) => inner,
60 _ => panic!("Expected a `SyntaxNode::Decl(...)`"),
61 }
62 }
63}
64
65impl From<SyntaxNode> for Stmt {
66 fn from(value: SyntaxNode) -> Self {
67 match value {
68 SyntaxNode::Stmt(inner) => inner,
69 _ => panic!("Expected a `SyntaxNode::Stmt(...)`"),
70 }
71 }
72}
73
74impl From<SyntaxNode> for Expr {
75 fn from(value: SyntaxNode) -> Self {
76 match value {
77 SyntaxNode::Expr(inner) => inner,
78 _ => panic!("Expected a `SyntaxNode::Expr(...)`"),
79 }
80 }
81}
82
83#[cfg(feature = "lsp")]
84pub trait ToRange {
85 fn to_range(self) -> Range;
86}
87
88#[cfg(feature = "lsp")]
89impl ToRange for gramatika::Span {
90 fn to_range(self) -> Range {
91 Range {
92 start: Position {
93 line: self.start.line as _,
94 character: self.start.character as _,
95 },
96 end: Position {
97 line: self.end.line as _,
98 character: self.end.character as _,
99 },
100 }
101 }
102}
103
104pub(crate) fn join_substrs(start: &Substr, end: &Substr) -> Substr {
111 assert!(ArcStr::ptr_eq(start.parent(), end.parent()));
112 assert!(end.range().end > start.range().start);
113
114 let source = start.parent().clone();
115 let range = start.range().start..end.range().end;
116
117 unsafe { Substr::from_parts_unchecked(source, range) }
118}
119
120#[cfg(test)]
121pub(crate) trait WithComments {
122 type Output: Sized + std::fmt::Debug;
123
124 fn get(&self) -> &[Self::Output];
125}
126
127#[cfg(test)]
128pub(crate) trait WithTokens {
129 type Output: Sized + std::fmt::Debug;
130
131 fn into(self) -> Vec<Self::Output>;
132}
133
134#[cfg(test)]
135pub(crate) trait WithErrors {
136 type Output: Sized + std::fmt::Display;
137
138 fn get(&self) -> &[Self::Output];
139}