emmylua_parser/syntax/node/lua/
mod.rs

1mod expr;
2mod path_trait;
3mod stat;
4mod test;
5
6use crate::{
7    kind::{LuaSyntaxKind, LuaTokenKind},
8    syntax::traits::{LuaAstChildren, LuaAstNode, LuaAstToken},
9    LuaCommentOwner, LuaSyntaxNode,
10};
11
12pub use expr::*;
13pub use path_trait::*;
14use rowan::TextRange;
15pub use stat::*;
16
17use super::{LuaLiteralToken, LuaNameToken, LuaNumberToken, LuaStringToken};
18
19#[derive(Debug, Clone, PartialEq, Eq, Hash)]
20pub struct LuaChunk {
21    syntax: LuaSyntaxNode,
22}
23
24impl LuaAstNode for LuaChunk {
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::Chunk
34    }
35
36    fn cast(syntax: LuaSyntaxNode) -> Option<Self>
37    where
38        Self: Sized,
39    {
40        if syntax.kind() == LuaSyntaxKind::Chunk.into() {
41            Some(Self { syntax })
42        } else {
43            None
44        }
45    }
46}
47
48impl LuaChunk {
49    pub fn get_block(&self) -> Option<LuaBlock> {
50        self.child()
51    }
52}
53
54#[derive(Debug, Clone, PartialEq, Eq, Hash)]
55pub struct LuaBlock {
56    syntax: LuaSyntaxNode,
57}
58
59impl LuaAstNode for LuaBlock {
60    fn syntax(&self) -> &LuaSyntaxNode {
61        &self.syntax
62    }
63
64    fn can_cast(kind: LuaSyntaxKind) -> bool
65    where
66        Self: Sized,
67    {
68        kind == LuaSyntaxKind::Block
69    }
70
71    fn cast(syntax: LuaSyntaxNode) -> Option<Self>
72    where
73        Self: Sized,
74    {
75        if syntax.kind() == LuaSyntaxKind::Block.into() {
76            Some(Self { syntax })
77        } else {
78            None
79        }
80    }
81}
82
83impl LuaBlock {
84    pub fn get_stats(&self) -> LuaAstChildren<LuaStat> {
85        self.children()
86    }
87}
88
89#[derive(Debug, Clone, PartialEq, Eq, Hash)]
90pub struct LuaLocalName {
91    syntax: LuaSyntaxNode,
92}
93
94impl LuaAstNode for LuaLocalName {
95    fn syntax(&self) -> &LuaSyntaxNode {
96        &self.syntax
97    }
98
99    fn can_cast(kind: LuaSyntaxKind) -> bool
100    where
101        Self: Sized,
102    {
103        kind == LuaSyntaxKind::LocalName
104    }
105
106    fn cast(syntax: LuaSyntaxNode) -> Option<Self>
107    where
108        Self: Sized,
109    {
110        if Self::can_cast(syntax.kind().into()) {
111            Some(Self { syntax })
112        } else {
113            None
114        }
115    }
116}
117
118impl LuaLocalName {
119    pub fn get_name_token(&self) -> Option<LuaNameToken> {
120        self.token()
121    }
122
123    pub fn get_attrib(&self) -> Option<LuaLocalAttribute> {
124        self.child()
125    }
126}
127
128#[derive(Debug, Clone, PartialEq, Eq, Hash)]
129pub struct LuaCallArgList {
130    syntax: LuaSyntaxNode,
131}
132
133impl LuaAstNode for LuaCallArgList {
134    fn syntax(&self) -> &LuaSyntaxNode {
135        &self.syntax
136    }
137
138    fn can_cast(kind: LuaSyntaxKind) -> bool
139    where
140        Self: Sized,
141    {
142        kind == LuaSyntaxKind::CallArgList
143    }
144
145    fn cast(syntax: LuaSyntaxNode) -> Option<Self>
146    where
147        Self: Sized,
148    {
149        if Self::can_cast(syntax.kind().into()) {
150            Some(Self { syntax })
151        } else {
152            None
153        }
154    }
155}
156
157impl LuaCallArgList {
158    pub fn is_single_arg_no_parens(&self) -> bool {
159        self.token_by_kind(LuaTokenKind::TkLeftParen).is_none()
160    }
161
162    pub fn get_args(&self) -> LuaAstChildren<LuaExpr> {
163        self.children()
164    }
165
166    pub fn get_single_arg_expr(&self) -> Option<LuaSingleArgExpr> {
167        self.child()
168    }
169}
170
171#[derive(Debug, Clone, PartialEq, Eq, Hash)]
172pub struct LuaLocalAttribute {
173    syntax: LuaSyntaxNode,
174}
175
176impl LuaAstNode for LuaLocalAttribute {
177    fn syntax(&self) -> &LuaSyntaxNode {
178        &self.syntax
179    }
180
181    fn can_cast(kind: LuaSyntaxKind) -> bool
182    where
183        Self: Sized,
184    {
185        kind == LuaSyntaxKind::Attribute
186    }
187
188    fn cast(syntax: LuaSyntaxNode) -> Option<Self>
189    where
190        Self: Sized,
191    {
192        if Self::can_cast(syntax.kind().into()) {
193            Some(Self { syntax })
194        } else {
195            None
196        }
197    }
198}
199
200impl LuaLocalAttribute {
201    pub fn get_name_token(&self) -> Option<LuaNameToken> {
202        self.token()
203    }
204
205    pub fn is_close(&self) -> bool {
206        match self.get_name_token() {
207            None => false,
208            Some(name_token) => name_token.get_name_text() == "close",
209        }
210    }
211
212    pub fn is_const(&self) -> bool {
213        match self.get_name_token() {
214            None => false,
215            Some(name_token) => name_token.get_name_text() == "const",
216        }
217    }
218}
219
220#[derive(Debug, Clone, PartialEq, Eq, Hash)]
221pub struct LuaTableField {
222    syntax: LuaSyntaxNode,
223}
224
225impl LuaAstNode for LuaTableField {
226    fn syntax(&self) -> &LuaSyntaxNode {
227        &self.syntax
228    }
229
230    fn can_cast(kind: LuaSyntaxKind) -> bool
231    where
232        Self: Sized,
233    {
234        kind == LuaSyntaxKind::TableFieldAssign || kind == LuaSyntaxKind::TableFieldValue
235    }
236
237    fn cast(syntax: LuaSyntaxNode) -> Option<Self>
238    where
239        Self: Sized,
240    {
241        if Self::can_cast(syntax.kind().into()) {
242            Some(Self { syntax })
243        } else {
244            None
245        }
246    }
247}
248
249impl LuaCommentOwner for LuaTableField {}
250
251impl LuaTableField {
252    /// TableFieldAssign: { a = "a" }
253    pub fn is_assign_field(&self) -> bool {
254        self.syntax().kind() == LuaSyntaxKind::TableFieldAssign.into()
255    }
256
257    /// TableFieldValue: { "a" }
258    pub fn is_value_field(&self) -> bool {
259        self.syntax().kind() == LuaSyntaxKind::TableFieldValue.into()
260    }
261
262    pub fn get_field_key(&self) -> Option<LuaIndexKey> {
263        if !self.is_assign_field() {
264            let parent_table = self.get_parent::<LuaTableExpr>()?;
265            let fields = parent_table.get_fields();
266            let mut idx = 1;
267            for field in fields {
268                if field.is_value_field() {
269                    if field.syntax() == self.syntax() {
270                        return Some(LuaIndexKey::Idx(idx));
271                    }
272                    idx += 1;
273                }
274            }
275
276            return None;
277        }
278
279        let mut meet_left_bracket = false;
280        for child in self.syntax.children_with_tokens() {
281            if meet_left_bracket {
282                match child {
283                    rowan::NodeOrToken::Node(node) => {
284                        if LuaLiteralExpr::can_cast(node.kind().into()) {
285                            let literal_expr = LuaLiteralExpr::cast(node.clone()).unwrap();
286                            if let Some(literal_token) = literal_expr.get_literal() {
287                                match literal_token {
288                                    LuaLiteralToken::String(token) => {
289                                        return Some(LuaIndexKey::String(token.clone()));
290                                    }
291                                    LuaLiteralToken::Number(token) => {
292                                        return Some(LuaIndexKey::Integer(token.clone()));
293                                    }
294                                    _ => {}
295                                }
296                            }
297                        }
298
299                        return Some(LuaIndexKey::Expr(LuaExpr::cast(node).unwrap()));
300                    }
301                    _ => return None,
302                }
303            } else if let Some(token) = child.as_token() {
304                if token.kind() == LuaTokenKind::TkLeftBracket.into() {
305                    meet_left_bracket = true;
306                } else if token.kind() == LuaTokenKind::TkName.into() {
307                    return Some(LuaIndexKey::Name(
308                        LuaNameToken::cast(token.clone()).unwrap(),
309                    ));
310                }
311            }
312        }
313
314        None
315    }
316
317    pub fn get_value_expr(&self) -> Option<LuaExpr> {
318        if self.is_assign_field() {
319            self.children().last()
320        } else {
321            self.child()
322        }
323    }
324}
325
326#[derive(Debug, Clone, PartialEq, Eq, Hash)]
327pub enum LuaIndexKey {
328    Name(LuaNameToken),
329    String(LuaStringToken),
330    Integer(LuaNumberToken),
331    Expr(LuaExpr),
332    Idx(usize),
333}
334
335impl LuaIndexKey {
336    pub fn is_name(&self) -> bool {
337        matches!(self, LuaIndexKey::Name(_))
338    }
339
340    pub fn is_string(&self) -> bool {
341        matches!(self, LuaIndexKey::String(_))
342    }
343
344    pub fn is_integer(&self) -> bool {
345        matches!(self, LuaIndexKey::Integer(_))
346    }
347
348    pub fn is_expr(&self) -> bool {
349        matches!(self, LuaIndexKey::Expr(_))
350    }
351
352    pub fn get_name(&self) -> Option<&LuaNameToken> {
353        match self {
354            LuaIndexKey::Name(token) => Some(token),
355            _ => None,
356        }
357    }
358
359    pub fn get_string(&self) -> Option<&LuaStringToken> {
360        match self {
361            LuaIndexKey::String(token) => Some(token),
362            _ => None,
363        }
364    }
365
366    pub fn get_integer(&self) -> Option<&LuaNumberToken> {
367        match self {
368            LuaIndexKey::Integer(token) => Some(token),
369            _ => None,
370        }
371    }
372
373    pub fn get_expr(&self) -> Option<&LuaExpr> {
374        match self {
375            LuaIndexKey::Expr(expr) => Some(expr),
376            _ => None,
377        }
378    }
379
380    pub fn get_path_part(&self) -> String {
381        match self {
382            LuaIndexKey::String(s) => s.get_value(),
383            LuaIndexKey::Name(name) => name.get_name_text().to_string(),
384            LuaIndexKey::Integer(i) => {
385                format!("[{}]", i.get_int_value())
386            }
387            LuaIndexKey::Expr(expr) => {
388                format!("[{}]", expr.syntax().text())
389            }
390            LuaIndexKey::Idx(i) => {
391                format!("[{}]", i)
392            }
393        }
394    }
395
396    pub fn get_range(&self) -> Option<TextRange> {
397        match self {
398            LuaIndexKey::Name(token) => Some(token.get_range()),
399            LuaIndexKey::String(token) => Some(token.get_range()),
400            LuaIndexKey::Integer(token) => Some(token.get_range()),
401            LuaIndexKey::Expr(expr) => Some(expr.syntax().text_range()),
402            LuaIndexKey::Idx(_) => None,
403        }
404    }
405}
406
407#[derive(Debug, Clone, PartialEq, Eq, Hash)]
408pub struct LuaParamName {
409    syntax: LuaSyntaxNode,
410}
411
412impl LuaAstNode for LuaParamName {
413    fn syntax(&self) -> &LuaSyntaxNode {
414        &self.syntax
415    }
416
417    fn can_cast(kind: LuaSyntaxKind) -> bool
418    where
419        Self: Sized,
420    {
421        kind == LuaSyntaxKind::ParamName
422    }
423
424    fn cast(syntax: LuaSyntaxNode) -> Option<Self>
425    where
426        Self: Sized,
427    {
428        if Self::can_cast(syntax.kind().into()) {
429            Some(Self { syntax })
430        } else {
431            None
432        }
433    }
434}
435
436impl LuaParamName {
437    pub fn get_name_token(&self) -> Option<LuaNameToken> {
438        self.token()
439    }
440
441    pub fn is_dots(&self) -> bool {
442        self.token_by_kind(LuaTokenKind::TkDots).is_some()
443    }
444}
445
446#[derive(Debug, Clone, PartialEq, Eq, Hash)]
447pub struct LuaParamList {
448    syntax: LuaSyntaxNode,
449}
450
451impl LuaAstNode for LuaParamList {
452    fn syntax(&self) -> &LuaSyntaxNode {
453        &self.syntax
454    }
455
456    fn can_cast(kind: LuaSyntaxKind) -> bool
457    where
458        Self: Sized,
459    {
460        kind == LuaSyntaxKind::ParamList
461    }
462
463    fn cast(syntax: LuaSyntaxNode) -> Option<Self>
464    where
465        Self: Sized,
466    {
467        if Self::can_cast(syntax.kind().into()) {
468            Some(Self { syntax })
469        } else {
470            None
471        }
472    }
473}
474
475impl LuaParamList {
476    pub fn get_params(&self) -> LuaAstChildren<LuaParamName> {
477        self.children()
478    }
479}
480
481#[derive(Debug, Clone, PartialEq, Eq, Hash)]
482pub enum LuaIndexMemberExpr {
483    IndexExpr(LuaIndexExpr),
484    TableField(LuaTableField),
485}
486
487impl LuaAstNode for LuaIndexMemberExpr {
488    fn syntax(&self) -> &LuaSyntaxNode {
489        match self {
490            LuaIndexMemberExpr::IndexExpr(expr) => expr.syntax(),
491            LuaIndexMemberExpr::TableField(field) => field.syntax(),
492        }
493    }
494
495    fn can_cast(kind: LuaSyntaxKind) -> bool
496    where
497        Self: Sized,
498    {
499        LuaIndexExpr::can_cast(kind) || LuaTableField::can_cast(kind)
500    }
501
502    fn cast(syntax: LuaSyntaxNode) -> Option<Self>
503    where
504        Self: Sized,
505    {
506        if LuaIndexExpr::can_cast(syntax.kind().into()) {
507            Some(Self::IndexExpr(LuaIndexExpr::cast(syntax).unwrap()))
508        } else if LuaTableField::can_cast(syntax.kind().into()) {
509            Some(Self::TableField(LuaTableField::cast(syntax).unwrap()))
510        } else {
511            None
512        }
513    }
514}
515
516impl LuaIndexMemberExpr {
517    pub fn get_index_expr(&self) -> Option<LuaIndexExpr> {
518        match self {
519            LuaIndexMemberExpr::IndexExpr(expr) => Some(expr.clone()),
520            _ => None,
521        }
522    }
523
524    pub fn get_table_field(&self) -> Option<LuaTableField> {
525        match self {
526            LuaIndexMemberExpr::TableField(field) => Some(field.clone()),
527            _ => None,
528        }
529    }
530
531    pub fn get_index_key(&self) -> Option<LuaIndexKey> {
532        match self {
533            LuaIndexMemberExpr::IndexExpr(expr) => expr.get_index_key(),
534            LuaIndexMemberExpr::TableField(field) => field.get_field_key(),
535        }
536    }
537
538    pub fn get_prefix_expr(&self) -> Option<LuaExpr> {
539        match self {
540            LuaIndexMemberExpr::IndexExpr(expr) => expr.get_prefix_expr(),
541            LuaIndexMemberExpr::TableField(field) => field.get_parent(),
542        }
543    }
544}