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::{
11 LuaAst, LuaBinaryOpToken, LuaLiteralToken, LuaNameToken, LuaNumberToken, LuaStringToken,
12};
13use crate::{
14 LuaAstChildren, LuaAstToken, LuaAstTokenChildren, LuaKind, LuaLiteralExpr, LuaSyntaxNode,
15 kind::{LuaSyntaxKind, LuaTokenKind},
16 syntax::traits::LuaAstNode,
17};
18
19#[derive(Debug, Clone, PartialEq, Eq, Hash)]
20pub struct LuaComment {
21 syntax: LuaSyntaxNode,
22}
23
24impl LuaAstNode for LuaComment {
25 fn syntax(&self) -> &LuaSyntaxNode {
26 &self.syntax
27 }
28
29 fn can_cast(kind: LuaSyntaxKind) -> bool
30 where
31 Self: Sized,
32 {
33 kind == LuaSyntaxKind::Comment
34 }
35
36 fn cast(syntax: LuaSyntaxNode) -> Option<Self>
37 where
38 Self: Sized,
39 {
40 if Self::can_cast(syntax.kind().into()) {
41 Some(Self { syntax })
42 } else {
43 None
44 }
45 }
46}
47
48fn is_additive_doc_tag(kind: LuaSyntaxKind) -> bool {
52 matches!(
53 kind,
54 LuaSyntaxKind::DocTagVisibility
55 | LuaSyntaxKind::DocTagExport
56 | LuaSyntaxKind::DocTagVersion
57 | LuaSyntaxKind::DocTagNodiscard
58 )
59}
60
61impl LuaComment {
62 pub fn get_owner(&self) -> Option<LuaAst> {
63 if let Some(inline_node) = find_inline_node(&self.syntax) {
64 LuaAst::cast(inline_node)
65 } else if let Some(attached_node) = find_attached_node(&self.syntax) {
66 LuaAst::cast(attached_node)
67 } else {
68 None
69 }
70 }
71
72 pub fn get_doc_tags(&self) -> LuaAstChildren<LuaDocTag> {
73 self.children()
74 }
75
76 pub fn get_description(&self) -> Option<LuaDocDescription> {
77 for child in self.syntax.children_with_tokens() {
78 match child.kind() {
79 LuaKind::Syntax(LuaSyntaxKind::DocDescription) => {
80 return LuaDocDescription::cast(child.into_node().unwrap());
81 }
82 LuaKind::Token(LuaTokenKind::TkDocStart) => {}
83 LuaKind::Syntax(syntax_kind) => {
84 if !is_additive_doc_tag(syntax_kind) {
85 return None;
86 }
87 }
88 _ => {}
89 }
90 }
91 None
92 }
93}
94
95fn find_inline_node(comment: &LuaSyntaxNode) -> Option<LuaSyntaxNode> {
96 let mut prev_sibling = comment.prev_sibling_or_token();
97 loop {
98 prev_sibling.as_ref()?;
99
100 if let Some(sibling) = prev_sibling {
101 match sibling.kind() {
102 LuaKind::Token(
103 LuaTokenKind::TkWhitespace | LuaTokenKind::TkComma | LuaTokenKind::TkSemicolon,
104 ) => {}
105 LuaKind::Token(LuaTokenKind::TkEndOfLine)
106 | LuaKind::Syntax(LuaSyntaxKind::Comment) => {
107 return None;
108 }
109 LuaKind::Token(k) if k != LuaTokenKind::TkName => {
110 return comment.parent();
111 }
112 _ => match sibling {
113 rowan::NodeOrToken::Node(node) => {
114 return Some(node);
115 }
116 rowan::NodeOrToken::Token(token) => {
117 return token.parent();
118 }
119 },
120 }
121 prev_sibling = sibling.prev_sibling_or_token();
122 } else {
123 return None;
124 }
125 }
126}
127
128fn find_attached_node(comment: &LuaSyntaxNode) -> Option<LuaSyntaxNode> {
129 let mut meet_end_of_line = false;
130
131 let mut next_sibling = comment.next_sibling_or_token();
132 loop {
133 next_sibling.as_ref()?;
134
135 if let Some(sibling) = next_sibling {
136 match sibling.kind() {
137 LuaKind::Token(LuaTokenKind::TkEndOfLine) => {
138 if meet_end_of_line {
139 return None;
140 }
141
142 meet_end_of_line = true;
143 }
144 LuaKind::Token(LuaTokenKind::TkWhitespace) => {}
145 LuaKind::Syntax(LuaSyntaxKind::Comment) => {
146 return None;
147 }
148 LuaKind::Syntax(LuaSyntaxKind::Block) => {
149 let first_child = comment.first_child()?;
150 if first_child.kind() == LuaKind::Syntax(LuaSyntaxKind::Comment) {
151 return None;
152 }
153 return Some(first_child);
154 }
155 _ => match sibling {
156 rowan::NodeOrToken::Node(node) => {
157 return Some(node);
158 }
159 rowan::NodeOrToken::Token(token) => {
160 return token.parent();
161 }
162 },
163 }
164 next_sibling = sibling.next_sibling_or_token();
165 }
166 }
167}
168
169#[derive(Debug, Clone, PartialEq, Eq, Hash)]
170pub struct LuaDocGenericDeclList {
171 syntax: LuaSyntaxNode,
172}
173
174impl LuaAstNode for LuaDocGenericDeclList {
175 fn syntax(&self) -> &LuaSyntaxNode {
176 &self.syntax
177 }
178
179 fn can_cast(kind: LuaSyntaxKind) -> bool
180 where
181 Self: Sized,
182 {
183 kind == LuaSyntaxKind::DocGenericDeclareList
184 }
185
186 fn cast(syntax: LuaSyntaxNode) -> Option<Self>
187 where
188 Self: Sized,
189 {
190 if Self::can_cast(syntax.kind().into()) {
191 Some(Self { syntax })
192 } else {
193 None
194 }
195 }
196}
197
198impl LuaDocGenericDeclList {
199 pub fn get_generic_decl(&self) -> LuaAstChildren<LuaDocGenericDecl> {
200 self.children()
201 }
202}
203
204#[derive(Debug, Clone, PartialEq, Eq, Hash)]
205pub struct LuaDocGenericDecl {
206 syntax: LuaSyntaxNode,
207}
208
209impl LuaAstNode for LuaDocGenericDecl {
210 fn syntax(&self) -> &LuaSyntaxNode {
211 &self.syntax
212 }
213
214 fn can_cast(kind: LuaSyntaxKind) -> bool
215 where
216 Self: Sized,
217 {
218 kind == LuaSyntaxKind::DocGenericParameter
219 }
220
221 fn cast(syntax: LuaSyntaxNode) -> Option<Self>
222 where
223 Self: Sized,
224 {
225 if Self::can_cast(syntax.kind().into()) {
226 Some(Self { syntax })
227 } else {
228 None
229 }
230 }
231}
232
233impl LuaDocGenericDecl {
234 pub fn get_name_token(&self) -> Option<LuaNameToken> {
235 self.token()
236 }
237
238 pub fn get_type(&self) -> Option<LuaDocType> {
239 self.child()
240 }
241
242 pub fn is_variadic(&self) -> bool {
243 self.token_by_kind(LuaTokenKind::TkDots).is_some()
244 }
245}
246
247#[derive(Debug, Clone, PartialEq, Eq, Hash)]
248pub struct LuaDocTypeList {
249 syntax: LuaSyntaxNode,
250}
251
252impl LuaAstNode for LuaDocTypeList {
253 fn syntax(&self) -> &LuaSyntaxNode {
254 &self.syntax
255 }
256
257 fn can_cast(kind: LuaSyntaxKind) -> bool
258 where
259 Self: Sized,
260 {
261 kind == LuaSyntaxKind::DocTypeList
262 }
263
264 fn cast(syntax: LuaSyntaxNode) -> Option<Self>
265 where
266 Self: Sized,
267 {
268 if Self::can_cast(syntax.kind().into()) {
269 Some(Self { syntax })
270 } else {
271 None
272 }
273 }
274}
275
276impl LuaDocTypeList {
277 pub fn get_types(&self) -> LuaAstChildren<LuaDocType> {
278 self.children()
279 }
280
281 pub fn get_return_type_list(&self) -> LuaAstChildren<LuaDocNamedReturnType> {
282 self.children()
283 }
284}
285
286#[derive(Debug, Clone, PartialEq, Eq, Hash)]
287pub struct LuaDocOpType {
288 syntax: LuaSyntaxNode,
289}
290
291impl LuaAstNode for LuaDocOpType {
292 fn syntax(&self) -> &LuaSyntaxNode {
293 &self.syntax
294 }
295
296 fn can_cast(kind: LuaSyntaxKind) -> bool
297 where
298 Self: Sized,
299 {
300 kind == LuaSyntaxKind::DocOpType
301 }
302
303 fn cast(syntax: LuaSyntaxNode) -> Option<Self>
304 where
305 Self: Sized,
306 {
307 if Self::can_cast(syntax.kind().into()) {
308 Some(Self { syntax })
309 } else {
310 None
311 }
312 }
313}
314
315impl LuaDocOpType {
316 pub fn get_op(&self) -> Option<LuaBinaryOpToken> {
317 self.token()
318 }
319
320 pub fn get_type(&self) -> Option<LuaDocType> {
321 self.child()
322 }
323
324 pub fn is_nullable(&self) -> bool {
325 self.token_by_kind(LuaTokenKind::TkDocQuestion).is_some()
326 }
327}
328
329#[derive(Debug, Clone, PartialEq, Eq, Hash)]
330pub struct LuaDocObjectField {
331 syntax: LuaSyntaxNode,
332}
333
334impl LuaAstNode for LuaDocObjectField {
335 fn syntax(&self) -> &LuaSyntaxNode {
336 &self.syntax
337 }
338
339 fn can_cast(kind: LuaSyntaxKind) -> bool
340 where
341 Self: Sized,
342 {
343 kind == LuaSyntaxKind::DocObjectField
344 }
345
346 fn cast(syntax: LuaSyntaxNode) -> Option<Self>
347 where
348 Self: Sized,
349 {
350 if Self::can_cast(syntax.kind().into()) {
351 Some(Self { syntax })
352 } else {
353 None
354 }
355 }
356}
357
358impl LuaDocObjectField {
359 pub fn get_field_key(&self) -> Option<LuaDocObjectFieldKey> {
360 for child in self.syntax.children_with_tokens() {
361 match child.kind() {
362 LuaKind::Token(LuaTokenKind::TkName) => {
363 return LuaNameToken::cast(child.into_token().unwrap())
364 .map(LuaDocObjectFieldKey::Name);
365 }
366 kind if LuaDocType::can_cast(kind.into()) => {
367 let doc_type = LuaDocType::cast(child.into_node().unwrap())?;
368 if let LuaDocType::Literal(literal) = &doc_type {
369 let literal = literal.get_literal()?;
370 match literal {
371 LuaLiteralToken::Number(num) => {
372 return Some(LuaDocObjectFieldKey::Integer(num));
373 }
374 LuaLiteralToken::String(str) => {
375 return Some(LuaDocObjectFieldKey::String(str));
376 }
377 _ => {}
378 }
379 }
380
381 return LuaDocObjectFieldKey::Type(doc_type).into();
382 }
383 LuaKind::Token(LuaTokenKind::TkColon) => {
384 return None;
385 }
386 _ => {}
387 }
388 }
389
390 None
391 }
392
393 pub fn get_type(&self) -> Option<LuaDocType> {
394 self.children().last()
395 }
396
397 pub fn is_nullable(&self) -> bool {
398 self.token_by_kind(LuaTokenKind::TkDocQuestion).is_some()
399 }
400}
401
402#[derive(Debug, Clone, PartialEq, Eq, Hash)]
403pub enum LuaDocObjectFieldKey {
404 Name(LuaNameToken),
405 String(LuaStringToken),
406 Integer(LuaNumberToken),
407 Type(LuaDocType),
408}
409
410#[derive(Debug, Clone, PartialEq, Eq, Hash)]
411pub struct LuaDocTypeFlag {
412 syntax: LuaSyntaxNode,
413}
414
415impl LuaAstNode for LuaDocTypeFlag {
416 fn syntax(&self) -> &LuaSyntaxNode {
417 &self.syntax
418 }
419
420 fn can_cast(kind: LuaSyntaxKind) -> bool
421 where
422 Self: Sized,
423 {
424 kind == LuaSyntaxKind::DocTypeFlag
425 }
426
427 fn cast(syntax: LuaSyntaxNode) -> Option<Self>
428 where
429 Self: Sized,
430 {
431 if Self::can_cast(syntax.kind().into()) {
432 Some(Self { syntax })
433 } else {
434 None
435 }
436 }
437}
438
439impl LuaDocTypeFlag {
440 pub fn get_attrib_tokens(&self) -> LuaAstTokenChildren<LuaNameToken> {
441 self.tokens()
442 }
443}
444
445#[derive(Debug, Clone, PartialEq, Eq, Hash)]
446pub struct LuaDocNamedReturnType {
447 syntax: LuaSyntaxNode,
448}
449
450impl LuaAstNode for LuaDocNamedReturnType {
451 fn syntax(&self) -> &LuaSyntaxNode {
452 &self.syntax
453 }
454
455 fn can_cast(kind: LuaSyntaxKind) -> bool
456 where
457 Self: Sized,
458 {
459 kind == LuaSyntaxKind::DocNamedReturnType
460 }
461
462 fn cast(syntax: LuaSyntaxNode) -> Option<Self>
463 where
464 Self: Sized,
465 {
466 if Self::can_cast(syntax.kind().into()) {
467 Some(Self { syntax })
468 } else {
469 None
470 }
471 }
472}
473
474impl LuaDocNamedReturnType {
475 pub fn get_name_and_type(&self) -> (Option<LuaNameToken>, Option<LuaDocType>) {
476 let types = self.children().collect::<Vec<LuaDocType>>();
477 if types.len() == 1 {
478 (None, Some(types[0].clone()))
479 } else if types.len() == 2 {
480 if let LuaDocType::Name(name) = &types[0] {
481 (name.get_name_token(), Some(types[1].clone()))
482 } else {
483 (None, None)
484 }
485 } else {
486 (None, None)
487 }
488 }
489}
490
491#[derive(Debug, Clone, PartialEq, Eq, Hash)]
492pub struct LuaDocAttributeUse {
493 syntax: LuaSyntaxNode,
494}
495
496impl LuaAstNode for LuaDocAttributeUse {
497 fn syntax(&self) -> &LuaSyntaxNode {
498 &self.syntax
499 }
500
501 fn can_cast(kind: LuaSyntaxKind) -> bool
502 where
503 Self: Sized,
504 {
505 kind == LuaSyntaxKind::DocAttributeUse
506 }
507
508 fn cast(syntax: LuaSyntaxNode) -> Option<Self>
509 where
510 Self: Sized,
511 {
512 if Self::can_cast(syntax.kind().into()) {
513 Some(Self { syntax })
514 } else {
515 None
516 }
517 }
518}
519
520impl LuaDocAttributeUse {
521 pub fn get_type(&self) -> Option<LuaDocNameType> {
522 self.child()
523 }
524
525 pub fn get_arg_list(&self) -> Option<LuaDocAttributeCallArgList> {
526 self.child()
527 }
528}
529
530#[derive(Debug, Clone, PartialEq, Eq, Hash)]
531pub struct LuaDocAttributeCallArgList {
532 syntax: LuaSyntaxNode,
533}
534
535impl LuaAstNode for LuaDocAttributeCallArgList {
536 fn syntax(&self) -> &LuaSyntaxNode {
537 &self.syntax
538 }
539
540 fn can_cast(kind: LuaSyntaxKind) -> bool
541 where
542 Self: Sized,
543 {
544 kind == LuaSyntaxKind::DocAttributeCallArgList
545 }
546
547 fn cast(syntax: LuaSyntaxNode) -> Option<Self>
548 where
549 Self: Sized,
550 {
551 if Self::can_cast(syntax.kind().into()) {
552 Some(Self { syntax })
553 } else {
554 None
555 }
556 }
557}
558
559impl LuaDocAttributeCallArgList {
560 pub fn get_args(&self) -> LuaAstChildren<LuaLiteralExpr> {
561 self.children()
562 }
563}
564
565#[derive(Debug, Clone, PartialEq, Eq, Hash)]
566pub struct LuaDocTagCallGeneric {
567 syntax: LuaSyntaxNode,
568}
569
570impl LuaAstNode for LuaDocTagCallGeneric {
571 fn syntax(&self) -> &LuaSyntaxNode {
572 &self.syntax
573 }
574
575 fn can_cast(kind: LuaSyntaxKind) -> bool
576 where
577 Self: Sized,
578 {
579 kind == LuaSyntaxKind::DocTagCallGeneric
580 }
581
582 fn cast(syntax: LuaSyntaxNode) -> Option<Self>
583 where
584 Self: Sized,
585 {
586 if Self::can_cast(syntax.kind().into()) {
587 Some(Self { syntax })
588 } else {
589 None
590 }
591 }
592}
593
594impl LuaDocTagCallGeneric {
595 pub fn get_type_list(&self) -> Option<LuaDocTypeList> {
596 self.child()
597 }
598}