emmylua_parser/syntax/node/doc/
mod.rs

1mod 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}