emmylua_parser/syntax/traits/
mod.rs1mod comment_trait;
2mod description_trait;
3
4use std::marker::PhantomData;
5
6use rowan::{TextRange, TextSize, WalkEvent};
7
8use crate::{
9 LuaAstPtr,
10 kind::{LuaSyntaxKind, LuaTokenKind},
11};
12
13use super::LuaSyntaxId;
14pub use super::{
15 LuaSyntaxElementChildren, LuaSyntaxNode, LuaSyntaxNodeChildren, LuaSyntaxToken, node::*,
16};
17pub use comment_trait::*;
18pub use description_trait::*;
19
20pub trait LuaAstNode {
21 fn syntax(&self) -> &LuaSyntaxNode;
22
23 fn can_cast(kind: LuaSyntaxKind) -> bool
24 where
25 Self: Sized;
26
27 fn cast(syntax: LuaSyntaxNode) -> Option<Self>
28 where
29 Self: Sized;
30
31 fn child<N: LuaAstNode>(&self) -> Option<N> {
32 self.syntax().children().find_map(N::cast)
33 }
34
35 fn token<N: LuaAstToken>(&self) -> Option<N> {
36 self.syntax()
37 .children_with_tokens()
38 .find_map(|it| it.into_token().and_then(N::cast))
39 }
40
41 fn token_by_kind(&self, kind: LuaTokenKind) -> Option<LuaGeneralToken> {
42 let token = self
43 .syntax()
44 .children_with_tokens()
45 .filter_map(|it| it.into_token())
46 .find(|it| it.kind() == kind.into())?;
47
48 LuaGeneralToken::cast(token)
49 }
50
51 fn tokens<N: LuaAstToken>(&self) -> LuaAstTokenChildren<N> {
52 LuaAstTokenChildren::new(self.syntax())
53 }
54
55 fn children<N: LuaAstNode>(&self) -> LuaAstChildren<N> {
56 LuaAstChildren::new(self.syntax())
57 }
58
59 fn descendants<N: LuaAstNode>(&self) -> impl Iterator<Item = N> {
60 self.syntax().descendants().filter_map(N::cast)
61 }
62
63 fn walk_descendants<N: LuaAstNode>(&self) -> impl Iterator<Item = WalkEvent<N>> {
64 self.syntax().preorder().filter_map(|event| match event {
65 WalkEvent::Enter(node) => N::cast(node).map(WalkEvent::Enter),
66 WalkEvent::Leave(node) => N::cast(node).map(WalkEvent::Leave),
67 })
68 }
69
70 fn ancestors<N: LuaAstNode>(&self) -> impl Iterator<Item = N> {
71 self.syntax().ancestors().filter_map(N::cast)
72 }
73
74 fn get_root(&self) -> LuaSyntaxNode {
75 let syntax = self.syntax();
76 if syntax.kind() == LuaSyntaxKind::Chunk.into() {
77 syntax.clone()
78 } else {
79 syntax.ancestors().last().unwrap()
80 }
81 }
82
83 fn get_parent<N: LuaAstNode>(&self) -> Option<N> {
84 self.syntax().parent().and_then(N::cast)
85 }
86
87 fn get_position(&self) -> TextSize {
88 let range = self.syntax().text_range();
89 range.start()
90 }
91
92 fn get_range(&self) -> TextRange {
93 self.syntax().text_range()
94 }
95
96 fn get_syntax_id(&self) -> LuaSyntaxId {
97 LuaSyntaxId::from_node(self.syntax())
98 }
99
100 fn get_text(&self) -> String {
101 format!("{}", self.syntax().text())
102 }
103
104 fn dump(&self) -> String {
105 format!("{:#?}", self.syntax())
106 }
107
108 fn to_ptr(&self) -> LuaAstPtr<Self>
109 where
110 Self: Sized,
111 {
112 LuaAstPtr::new(self)
113 }
114}
115
116#[derive(Debug, Clone)]
118pub struct LuaAstChildren<N> {
119 inner: LuaSyntaxNodeChildren,
120 ph: PhantomData<N>,
121}
122
123impl<N> LuaAstChildren<N> {
124 pub fn new(parent: &LuaSyntaxNode) -> LuaAstChildren<N> {
125 LuaAstChildren {
126 inner: parent.children(),
127 ph: PhantomData,
128 }
129 }
130}
131
132impl<N: LuaAstNode> Iterator for LuaAstChildren<N> {
133 type Item = N;
134
135 fn next(&mut self) -> Option<N> {
136 self.inner.find_map(N::cast)
137 }
138}
139
140pub trait LuaAstToken {
141 fn syntax(&self) -> &LuaSyntaxToken;
142
143 fn can_cast(kind: LuaTokenKind) -> bool
144 where
145 Self: Sized;
146
147 fn cast(syntax: LuaSyntaxToken) -> Option<Self>
148 where
149 Self: Sized;
150
151 fn get_token_kind(&self) -> LuaTokenKind {
152 self.syntax().kind().into()
153 }
154
155 fn get_position(&self) -> TextSize {
156 let range = self.syntax().text_range();
157 range.start()
158 }
159
160 fn get_range(&self) -> TextRange {
161 self.syntax().text_range()
162 }
163
164 fn get_syntax_id(&self) -> LuaSyntaxId {
165 LuaSyntaxId::from_token(self.syntax())
166 }
167
168 fn get_text(&self) -> &str {
169 self.syntax().text()
170 }
171
172 fn slice(&self, range: TextRange) -> Option<&str> {
173 let text = self.get_text();
174 let self_range = self.get_range();
175 if range.start() >= self_range.start() && range.end() <= self_range.end() {
176 let start = (range.start() - self_range.start()).into();
177 let end = (range.end() - self_range.start()).into();
178 text.get(start..end)
179 } else {
180 None
181 }
182 }
183
184 fn get_parent<N: LuaAstNode>(&self) -> Option<N> {
185 self.syntax().parent().and_then(N::cast)
186 }
187
188 fn ancestors<N: LuaAstNode>(&self) -> impl Iterator<Item = N> {
189 self.syntax().parent_ancestors().filter_map(N::cast)
190 }
191
192 fn dump(&self) -> String {
193 format!("{:#?}", self.syntax())
194 }
195}
196
197#[derive(Debug, Clone)]
198pub struct LuaAstTokenChildren<N> {
199 inner: LuaSyntaxElementChildren,
200 ph: PhantomData<N>,
201}
202
203impl<N> LuaAstTokenChildren<N> {
204 pub fn new(parent: &LuaSyntaxNode) -> LuaAstTokenChildren<N> {
205 LuaAstTokenChildren {
206 inner: parent.children_with_tokens(),
207 ph: PhantomData,
208 }
209 }
210}
211
212impl<N: LuaAstToken> Iterator for LuaAstTokenChildren<N> {
213 type Item = N;
214
215 fn next(&mut self) -> Option<N> {
216 self.inner.find_map(|it| it.into_token().and_then(N::cast))
217 }
218}