emmylua_parser/syntax/node/doc/
mod.rs

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