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