emmylua_parser/syntax/node/doc/
mod.rs1mod description;
2mod tag;
3mod test;
4mod types;
5
6pub use description::*;
7pub use tag::*;
8pub use types::*;
9
10use super::{LuaAst, LuaBinaryOpToken, LuaNameToken, LuaNumberToken, LuaStringToken};
11use crate::{
12 kind::{LuaSyntaxKind, LuaTokenKind},
13 syntax::traits::LuaAstNode,
14 LuaAstChildren, LuaAstToken, LuaAstTokenChildren, LuaKind, LuaSyntaxNode,
15};
16
17#[derive(Debug, Clone, PartialEq, Eq, Hash)]
18pub struct LuaComment {
19 syntax: LuaSyntaxNode,
20}
21
22impl LuaAstNode for LuaComment {
23 fn syntax(&self) -> &LuaSyntaxNode {
24 &self.syntax
25 }
26
27 fn can_cast(kind: LuaSyntaxKind) -> bool
28 where
29 Self: Sized,
30 {
31 kind == LuaSyntaxKind::Comment
32 }
33
34 fn cast(syntax: LuaSyntaxNode) -> Option<Self>
35 where
36 Self: Sized,
37 {
38 if Self::can_cast(syntax.kind().into()) {
39 Some(Self { syntax })
40 } else {
41 None
42 }
43 }
44}
45
46impl LuaDocDescriptionOwner for LuaComment {}
47
48impl LuaComment {
49 pub fn get_owner(&self) -> Option<LuaAst> {
50 if let Some(inline_node) = find_inline_node(&self.syntax) {
51 LuaAst::cast(inline_node)
52 } else if let Some(attached_node) = find_attached_node(&self.syntax) {
53 LuaAst::cast(attached_node)
54 } else {
55 None
56 }
57 }
58
59 pub fn get_doc_tags(&self) -> LuaAstChildren<LuaDocTag> {
60 self.children()
61 }
62}
63
64fn find_inline_node(comment: &LuaSyntaxNode) -> Option<LuaSyntaxNode> {
65 let mut prev_sibling = comment.prev_sibling_or_token();
66 loop {
67 prev_sibling.as_ref()?;
68
69 if let Some(sibling) = prev_sibling {
70 match sibling.kind() {
71 LuaKind::Token(
72 LuaTokenKind::TkWhitespace | LuaTokenKind::TkComma | LuaTokenKind::TkSemicolon,
73 ) => {}
74 LuaKind::Token(LuaTokenKind::TkEndOfLine)
75 | LuaKind::Syntax(LuaSyntaxKind::Comment) => {
76 return None;
77 }
78 LuaKind::Token(k) if k != LuaTokenKind::TkName => {
79 return comment.parent();
80 }
81 _ => match sibling {
82 rowan::NodeOrToken::Node(node) => {
83 return Some(node);
84 }
85 rowan::NodeOrToken::Token(token) => {
86 return token.parent();
87 }
88 },
89 }
90 prev_sibling = sibling.prev_sibling_or_token();
91 } else {
92 return None;
93 }
94 }
95}
96
97fn find_attached_node(comment: &LuaSyntaxNode) -> Option<LuaSyntaxNode> {
98 let mut meet_end_of_line = false;
99
100 let mut next_sibling = comment.next_sibling_or_token();
101 loop {
102 next_sibling.as_ref()?;
103
104 if let Some(sibling) = next_sibling {
105 match sibling.kind() {
106 LuaKind::Token(LuaTokenKind::TkEndOfLine) => {
107 if meet_end_of_line {
108 return None;
109 }
110
111 meet_end_of_line = true;
112 }
113 LuaKind::Token(LuaTokenKind::TkWhitespace) => {}
114 LuaKind::Syntax(LuaSyntaxKind::Comment) => {
115 return None;
116 }
117 LuaKind::Syntax(LuaSyntaxKind::Block) => {
118 let first_child = comment.first_child()?;
119 if first_child.kind() == LuaKind::Syntax(LuaSyntaxKind::Comment) {
120 return None;
121 }
122 return Some(first_child);
123 }
124 _ => match sibling {
125 rowan::NodeOrToken::Node(node) => {
126 return Some(node);
127 }
128 rowan::NodeOrToken::Token(token) => {
129 return token.parent();
130 }
131 },
132 }
133 next_sibling = sibling.next_sibling_or_token();
134 }
135 }
136}
137
138#[derive(Debug, Clone, PartialEq, Eq, Hash)]
139pub struct LuaDocGenericDeclList {
140 syntax: LuaSyntaxNode,
141}
142
143impl LuaAstNode for LuaDocGenericDeclList {
144 fn syntax(&self) -> &LuaSyntaxNode {
145 &self.syntax
146 }
147
148 fn can_cast(kind: LuaSyntaxKind) -> bool
149 where
150 Self: Sized,
151 {
152 kind == LuaSyntaxKind::DocGenericDeclareList
153 }
154
155 fn cast(syntax: LuaSyntaxNode) -> Option<Self>
156 where
157 Self: Sized,
158 {
159 if Self::can_cast(syntax.kind().into()) {
160 Some(Self { syntax })
161 } else {
162 None
163 }
164 }
165}
166
167impl LuaDocGenericDeclList {
168 pub fn get_generic_decl(&self) -> LuaAstChildren<LuaDocGenericDecl> {
169 self.children()
170 }
171}
172
173#[derive(Debug, Clone, PartialEq, Eq, Hash)]
174pub struct LuaDocGenericDecl {
175 syntax: LuaSyntaxNode,
176}
177
178impl LuaAstNode for LuaDocGenericDecl {
179 fn syntax(&self) -> &LuaSyntaxNode {
180 &self.syntax
181 }
182
183 fn can_cast(kind: LuaSyntaxKind) -> bool
184 where
185 Self: Sized,
186 {
187 kind == LuaSyntaxKind::DocGenericParameter
188 }
189
190 fn cast(syntax: LuaSyntaxNode) -> Option<Self>
191 where
192 Self: Sized,
193 {
194 if Self::can_cast(syntax.kind().into()) {
195 Some(Self { syntax })
196 } else {
197 None
198 }
199 }
200}
201
202impl LuaDocGenericDecl {
203 pub fn get_name_token(&self) -> Option<LuaNameToken> {
204 self.token()
205 }
206
207 pub fn get_type(&self) -> Option<LuaDocType> {
208 self.child()
209 }
210}
211
212#[derive(Debug, Clone, PartialEq, Eq, Hash)]
213pub struct LuaDocTypeList {
214 syntax: LuaSyntaxNode,
215}
216
217impl LuaAstNode for LuaDocTypeList {
218 fn syntax(&self) -> &LuaSyntaxNode {
219 &self.syntax
220 }
221
222 fn can_cast(kind: LuaSyntaxKind) -> bool
223 where
224 Self: Sized,
225 {
226 kind == LuaSyntaxKind::DocTypeList
227 }
228
229 fn cast(syntax: LuaSyntaxNode) -> Option<Self>
230 where
231 Self: Sized,
232 {
233 if Self::can_cast(syntax.kind().into()) {
234 Some(Self { syntax })
235 } else {
236 None
237 }
238 }
239}
240
241impl LuaDocTypeList {
242 pub fn get_types(&self) -> LuaAstChildren<LuaDocType> {
243 self.children()
244 }
245
246 pub fn get_return_type_list(&self) -> LuaAstChildren<LuaDocNamedReturnType> {
247 self.children()
248 }
249}
250
251#[derive(Debug, Clone, PartialEq, Eq, Hash)]
252pub struct LuaDocOpType {
253 syntax: LuaSyntaxNode,
254}
255
256impl LuaAstNode for LuaDocOpType {
257 fn syntax(&self) -> &LuaSyntaxNode {
258 &self.syntax
259 }
260
261 fn can_cast(kind: LuaSyntaxKind) -> bool
262 where
263 Self: Sized,
264 {
265 kind == LuaSyntaxKind::DocOpType
266 }
267
268 fn cast(syntax: LuaSyntaxNode) -> Option<Self>
269 where
270 Self: Sized,
271 {
272 if Self::can_cast(syntax.kind().into()) {
273 Some(Self { syntax })
274 } else {
275 None
276 }
277 }
278}
279
280impl LuaDocOpType {
281 pub fn get_op(&self) -> Option<LuaBinaryOpToken> {
282 self.token()
283 }
284
285 pub fn get_type(&self) -> Option<LuaDocType> {
286 self.child()
287 }
288
289 pub fn is_nullable(&self) -> bool {
290 self.token_by_kind(LuaTokenKind::TkDocQuestion).is_some()
291 }
292}
293
294#[derive(Debug, Clone, PartialEq, Eq, Hash)]
295pub struct LuaDocObjectField {
296 syntax: LuaSyntaxNode,
297}
298
299impl LuaAstNode for LuaDocObjectField {
300 fn syntax(&self) -> &LuaSyntaxNode {
301 &self.syntax
302 }
303
304 fn can_cast(kind: LuaSyntaxKind) -> bool
305 where
306 Self: Sized,
307 {
308 kind == LuaSyntaxKind::DocObjectField
309 }
310
311 fn cast(syntax: LuaSyntaxNode) -> Option<Self>
312 where
313 Self: Sized,
314 {
315 if Self::can_cast(syntax.kind().into()) {
316 Some(Self { syntax })
317 } else {
318 None
319 }
320 }
321}
322
323impl LuaDocObjectField {
324 pub fn get_field_key(&self) -> Option<LuaDocObjectFieldKey> {
325 for child in self.syntax.children_with_tokens() {
326 match child.kind() {
327 LuaKind::Token(LuaTokenKind::TkName) => {
328 return LuaNameToken::cast(child.into_token().unwrap())
329 .map(LuaDocObjectFieldKey::Name);
330 }
331 LuaKind::Token(LuaTokenKind::TkString) => {
332 return LuaStringToken::cast(child.into_token().unwrap())
333 .map(LuaDocObjectFieldKey::String);
334 }
335 LuaKind::Token(LuaTokenKind::TkInt) => {
336 return LuaNumberToken::cast(child.into_token().unwrap())
337 .map(LuaDocObjectFieldKey::Integer);
338 }
339 kind if LuaDocType::can_cast(kind.into()) => {
340 return LuaDocType::cast(child.into_node().unwrap())
341 .map(LuaDocObjectFieldKey::Type);
342 }
343 LuaKind::Token(LuaTokenKind::TkColon) => {
344 return None;
345 }
346 _ => {}
347 }
348 }
349
350 None
351 }
352
353 pub fn get_type(&self) -> Option<LuaDocType> {
354 self.children().last()
355 }
356
357 pub fn is_nullable(&self) -> bool {
358 self.token_by_kind(LuaTokenKind::TkDocQuestion).is_some()
359 }
360}
361
362#[derive(Debug, Clone, PartialEq, Eq, Hash)]
363pub enum LuaDocObjectFieldKey {
364 Name(LuaNameToken),
365 String(LuaStringToken),
366 Integer(LuaNumberToken),
367 Type(LuaDocType),
368}
369
370#[derive(Debug, Clone, PartialEq, Eq, Hash)]
371pub struct LuaDocAttribute {
372 syntax: LuaSyntaxNode,
373}
374
375impl LuaAstNode for LuaDocAttribute {
376 fn syntax(&self) -> &LuaSyntaxNode {
377 &self.syntax
378 }
379
380 fn can_cast(kind: LuaSyntaxKind) -> bool
381 where
382 Self: Sized,
383 {
384 kind == LuaSyntaxKind::DocAttribute
385 }
386
387 fn cast(syntax: LuaSyntaxNode) -> Option<Self>
388 where
389 Self: Sized,
390 {
391 if Self::can_cast(syntax.kind().into()) {
392 Some(Self { syntax })
393 } else {
394 None
395 }
396 }
397}
398
399impl LuaDocAttribute {
400 pub fn get_attrib_tokens(&self) -> LuaAstTokenChildren<LuaNameToken> {
401 self.tokens()
402 }
403}
404
405#[derive(Debug, Clone, PartialEq, Eq, Hash)]
406pub struct LuaDocNamedReturnType {
407 syntax: LuaSyntaxNode,
408}
409
410impl LuaAstNode for LuaDocNamedReturnType {
411 fn syntax(&self) -> &LuaSyntaxNode {
412 &self.syntax
413 }
414
415 fn can_cast(kind: LuaSyntaxKind) -> bool
416 where
417 Self: Sized,
418 {
419 kind == LuaSyntaxKind::DocNamedReturnType
420 }
421
422 fn cast(syntax: LuaSyntaxNode) -> Option<Self>
423 where
424 Self: Sized,
425 {
426 if Self::can_cast(syntax.kind().into()) {
427 Some(Self { syntax })
428 } else {
429 None
430 }
431 }
432}
433
434impl LuaDocNamedReturnType {
435 pub fn get_name_and_type(&self) -> (Option<LuaNameToken>, Option<LuaDocType>) {
436 let types = self.children().collect::<Vec<LuaDocType>>();
437 if types.len() == 1 {
438 (None, Some(types[0].clone()))
439 } else if types.len() == 2 {
440 if let LuaDocType::Name(name) = &types[0] {
441 (name.get_name_token(), Some(types[1].clone()))
442 } else {
443 (None, None)
444 }
445 } else {
446 (None, None)
447 }
448 }
449}