emmylua_parser/syntax/node/lua/
expr.rs

1use crate::{
2    kind::LuaSyntaxKind,
3    syntax::{
4        comment_trait::LuaCommentOwner,
5        node::{LuaBinaryOpToken, LuaNameToken, LuaUnaryOpToken},
6        traits::{LuaAstChildren, LuaAstNode},
7    },
8    LuaAstToken, LuaIndexToken, LuaLiteralToken, LuaSyntaxNode, LuaSyntaxToken, LuaTokenKind,
9};
10
11use super::{
12    path_trait::PathTrait, LuaBlock, LuaCallArgList, LuaIndexKey, LuaParamList, LuaTableField,
13};
14
15#[derive(Debug, Clone, PartialEq, Eq, Hash)]
16pub enum LuaExpr {
17    CallExpr(LuaCallExpr),
18    TableExpr(LuaTableExpr),
19    LiteralExpr(LuaLiteralExpr),
20    BinaryExpr(LuaBinaryExpr),
21    UnaryExpr(LuaUnaryExpr),
22    ClosureExpr(LuaClosureExpr),
23    ParenExpr(LuaParenExpr),
24    NameExpr(LuaNameExpr),
25    IndexExpr(LuaIndexExpr),
26}
27
28impl LuaAstNode for LuaExpr {
29    fn syntax(&self) -> &LuaSyntaxNode {
30        match self {
31            LuaExpr::CallExpr(node) => node.syntax(),
32            LuaExpr::TableExpr(node) => node.syntax(),
33            LuaExpr::LiteralExpr(node) => node.syntax(),
34            LuaExpr::BinaryExpr(node) => node.syntax(),
35            LuaExpr::UnaryExpr(node) => node.syntax(),
36            LuaExpr::ClosureExpr(node) => node.syntax(),
37            LuaExpr::ParenExpr(node) => node.syntax(),
38            LuaExpr::NameExpr(node) => node.syntax(),
39            LuaExpr::IndexExpr(node) => node.syntax(),
40        }
41    }
42
43    fn can_cast(kind: LuaSyntaxKind) -> bool
44    where
45        Self: Sized,
46    {
47        match kind {
48            LuaSyntaxKind::CallExpr
49            | LuaSyntaxKind::AssertCallExpr
50            | LuaSyntaxKind::ErrorCallExpr
51            | LuaSyntaxKind::RequireCallExpr
52            | LuaSyntaxKind::TypeCallExpr
53            | LuaSyntaxKind::SetmetatableCallExpr => true,
54            LuaSyntaxKind::TableArrayExpr
55            | LuaSyntaxKind::TableObjectExpr
56            | LuaSyntaxKind::TableEmptyExpr => true,
57            LuaSyntaxKind::LiteralExpr => true,
58            LuaSyntaxKind::BinaryExpr => true,
59            LuaSyntaxKind::UnaryExpr => true,
60            LuaSyntaxKind::ClosureExpr => true,
61            LuaSyntaxKind::ParenExpr => true,
62            LuaSyntaxKind::NameExpr => true,
63            LuaSyntaxKind::IndexExpr => true,
64            _ => false,
65        }
66    }
67
68    fn cast(syntax: LuaSyntaxNode) -> Option<Self>
69    where
70        Self: Sized,
71    {
72        match syntax.kind().into() {
73            LuaSyntaxKind::CallExpr
74            | LuaSyntaxKind::AssertCallExpr
75            | LuaSyntaxKind::ErrorCallExpr
76            | LuaSyntaxKind::RequireCallExpr
77            | LuaSyntaxKind::TypeCallExpr
78            | LuaSyntaxKind::SetmetatableCallExpr => {
79                LuaCallExpr::cast(syntax).map(LuaExpr::CallExpr)
80            }
81            LuaSyntaxKind::TableArrayExpr
82            | LuaSyntaxKind::TableObjectExpr
83            | LuaSyntaxKind::TableEmptyExpr => LuaTableExpr::cast(syntax).map(LuaExpr::TableExpr),
84            LuaSyntaxKind::LiteralExpr => LuaLiteralExpr::cast(syntax).map(LuaExpr::LiteralExpr),
85            LuaSyntaxKind::BinaryExpr => LuaBinaryExpr::cast(syntax).map(LuaExpr::BinaryExpr),
86            LuaSyntaxKind::UnaryExpr => LuaUnaryExpr::cast(syntax).map(LuaExpr::UnaryExpr),
87            LuaSyntaxKind::ClosureExpr => LuaClosureExpr::cast(syntax).map(LuaExpr::ClosureExpr),
88            LuaSyntaxKind::ParenExpr => LuaParenExpr::cast(syntax).map(LuaExpr::ParenExpr),
89            LuaSyntaxKind::NameExpr => LuaNameExpr::cast(syntax).map(LuaExpr::NameExpr),
90            LuaSyntaxKind::IndexExpr => LuaIndexExpr::cast(syntax).map(LuaExpr::IndexExpr),
91            _ => None,
92        }
93    }
94}
95
96#[derive(Debug, Clone, PartialEq, Eq, Hash)]
97pub enum LuaVarExpr {
98    NameExpr(LuaNameExpr),
99    IndexExpr(LuaIndexExpr),
100}
101
102impl LuaAstNode for LuaVarExpr {
103    fn syntax(&self) -> &LuaSyntaxNode {
104        match self {
105            LuaVarExpr::NameExpr(node) => node.syntax(),
106            LuaVarExpr::IndexExpr(node) => node.syntax(),
107        }
108    }
109
110    fn can_cast(kind: LuaSyntaxKind) -> bool
111    where
112        Self: Sized,
113    {
114        match kind {
115            LuaSyntaxKind::NameExpr => true,
116            LuaSyntaxKind::IndexExpr => true,
117            _ => false,
118        }
119    }
120
121    fn cast(syntax: LuaSyntaxNode) -> Option<Self>
122    where
123        Self: Sized,
124    {
125        match syntax.kind().into() {
126            LuaSyntaxKind::NameExpr => LuaNameExpr::cast(syntax).map(LuaVarExpr::NameExpr),
127            LuaSyntaxKind::IndexExpr => LuaIndexExpr::cast(syntax).map(LuaVarExpr::IndexExpr),
128            _ => None,
129        }
130    }
131}
132
133impl From<LuaVarExpr> for LuaExpr {
134    fn from(expr: LuaVarExpr) -> Self {
135        match expr {
136            LuaVarExpr::NameExpr(node) => LuaExpr::NameExpr(node),
137            LuaVarExpr::IndexExpr(node) => LuaExpr::IndexExpr(node),
138        }
139    }
140}
141
142impl PathTrait for LuaVarExpr {}
143
144#[derive(Debug, Clone, PartialEq, Eq, Hash)]
145pub enum LuaSingleArgExpr {
146    TableExpr(LuaTableExpr),
147    LiteralExpr(LuaLiteralExpr),
148}
149
150impl LuaAstNode for LuaSingleArgExpr {
151    fn syntax(&self) -> &LuaSyntaxNode {
152        match self {
153            LuaSingleArgExpr::TableExpr(node) => node.syntax(),
154            LuaSingleArgExpr::LiteralExpr(node) => node.syntax(),
155        }
156    }
157
158    fn can_cast(kind: LuaSyntaxKind) -> bool
159    where
160        Self: Sized,
161    {
162        match kind {
163            LuaSyntaxKind::TableArrayExpr
164            | LuaSyntaxKind::TableObjectExpr
165            | LuaSyntaxKind::TableEmptyExpr => true,
166            LuaSyntaxKind::LiteralExpr => true,
167            _ => false,
168        }
169    }
170
171    fn cast(syntax: LuaSyntaxNode) -> Option<Self>
172    where
173        Self: Sized,
174    {
175        match syntax.kind().into() {
176            LuaSyntaxKind::TableArrayExpr
177            | LuaSyntaxKind::TableObjectExpr
178            | LuaSyntaxKind::TableEmptyExpr => {
179                LuaTableExpr::cast(syntax).map(LuaSingleArgExpr::TableExpr)
180            }
181            LuaSyntaxKind::LiteralExpr => {
182                LuaLiteralExpr::cast(syntax).map(LuaSingleArgExpr::LiteralExpr)
183            }
184            _ => None,
185        }
186    }
187}
188
189impl From<LuaSingleArgExpr> for LuaExpr {
190    fn from(expr: LuaSingleArgExpr) -> Self {
191        match expr {
192            LuaSingleArgExpr::TableExpr(node) => LuaExpr::TableExpr(node),
193            LuaSingleArgExpr::LiteralExpr(node) => LuaExpr::LiteralExpr(node),
194        }
195    }
196}
197
198#[derive(Debug, Clone, PartialEq, Eq, Hash)]
199pub struct LuaNameExpr {
200    syntax: LuaSyntaxNode,
201}
202
203impl LuaAstNode for LuaNameExpr {
204    fn syntax(&self) -> &LuaSyntaxNode {
205        &self.syntax
206    }
207
208    fn can_cast(kind: LuaSyntaxKind) -> bool
209    where
210        Self: Sized,
211    {
212        kind == LuaSyntaxKind::NameExpr
213    }
214
215    fn cast(syntax: LuaSyntaxNode) -> Option<Self>
216    where
217        Self: Sized,
218    {
219        if Self::can_cast(syntax.kind().into()) {
220            Some(Self { syntax })
221        } else {
222            None
223        }
224    }
225}
226
227impl LuaCommentOwner for LuaNameExpr {}
228
229impl LuaNameExpr {
230    pub fn get_name_token(&self) -> Option<LuaNameToken> {
231        self.token()
232    }
233
234    pub fn get_name_text(&self) -> Option<String> {
235        self.get_name_token()
236            .map(|it| it.get_name_text().to_string())
237    }
238}
239
240impl PathTrait for LuaNameExpr {}
241
242impl From<LuaNameExpr> for LuaVarExpr {
243    fn from(expr: LuaNameExpr) -> Self {
244        LuaVarExpr::NameExpr(expr)
245    }
246}
247
248#[derive(Debug, Clone, PartialEq, Eq, Hash)]
249pub struct LuaIndexExpr {
250    syntax: LuaSyntaxNode,
251}
252
253impl LuaAstNode for LuaIndexExpr {
254    fn syntax(&self) -> &LuaSyntaxNode {
255        &self.syntax
256    }
257
258    fn can_cast(kind: LuaSyntaxKind) -> bool
259    where
260        Self: Sized,
261    {
262        kind == LuaSyntaxKind::IndexExpr
263    }
264
265    fn cast(syntax: LuaSyntaxNode) -> Option<Self>
266    where
267        Self: Sized,
268    {
269        if Self::can_cast(syntax.kind().into()) {
270            Some(Self { syntax })
271        } else {
272            None
273        }
274    }
275}
276
277impl LuaIndexExpr {
278    pub fn get_prefix_expr(&self) -> Option<LuaExpr> {
279        self.child()
280    }
281
282    pub fn get_index_token(&self) -> Option<LuaIndexToken> {
283        self.token()
284    }
285
286    pub fn get_index_key(&self) -> Option<LuaIndexKey> {
287        let mut meet_left_bracket = false;
288        for child in self.syntax.children_with_tokens() {
289            if meet_left_bracket {
290                match child {
291                    rowan::NodeOrToken::Node(node) => {
292                        if LuaLiteralExpr::can_cast(node.kind().into()) {
293                            let literal_expr = LuaLiteralExpr::cast(node.clone()).unwrap();
294                            if let Some(literal_token) = literal_expr.get_literal() {
295                                match literal_token {
296                                    LuaLiteralToken::String(token) => {
297                                        return Some(LuaIndexKey::String(token.clone()));
298                                    }
299                                    LuaLiteralToken::Number(token) => {
300                                        return Some(LuaIndexKey::Integer(token.clone()));
301                                    }
302                                    _ => {}
303                                }
304                            }
305                        }
306
307                        return Some(LuaIndexKey::Expr(LuaExpr::cast(node).unwrap()));
308                    }
309                    _ => return None,
310                }
311            } else if let Some(token) = child.as_token() {
312                if token.kind() == LuaTokenKind::TkLeftBracket.into() {
313                    meet_left_bracket = true;
314                } else if token.kind() == LuaTokenKind::TkName.into() {
315                    return Some(LuaIndexKey::Name(
316                        LuaNameToken::cast(token.clone()).unwrap(),
317                    ));
318                }
319            }
320        }
321
322        None
323    }
324
325    pub fn get_index_name_token(&self) -> Option<LuaSyntaxToken> {
326        let index_token = self.get_index_token()?;
327        index_token.syntax().next_token()
328    }
329
330    pub fn get_name_token(&self) -> Option<LuaNameToken> {
331        self.token()
332    }
333}
334
335impl PathTrait for LuaIndexExpr {}
336
337impl From<LuaIndexExpr> for LuaVarExpr {
338    fn from(expr: LuaIndexExpr) -> Self {
339        LuaVarExpr::IndexExpr(expr)
340    }
341}
342
343#[derive(Debug, Clone, PartialEq, Eq, Hash)]
344pub struct LuaCallExpr {
345    syntax: LuaSyntaxNode,
346}
347
348impl LuaAstNode for LuaCallExpr {
349    fn syntax(&self) -> &LuaSyntaxNode {
350        &self.syntax
351    }
352
353    fn can_cast(kind: LuaSyntaxKind) -> bool
354    where
355        Self: Sized,
356    {
357        kind == LuaSyntaxKind::CallExpr
358            || kind == LuaSyntaxKind::AssertCallExpr
359            || kind == LuaSyntaxKind::ErrorCallExpr
360            || kind == LuaSyntaxKind::RequireCallExpr
361            || kind == LuaSyntaxKind::TypeCallExpr
362            || kind == LuaSyntaxKind::SetmetatableCallExpr
363    }
364
365    fn cast(syntax: LuaSyntaxNode) -> Option<Self>
366    where
367        Self: Sized,
368    {
369        if Self::can_cast(syntax.kind().into()) {
370            Some(Self { syntax })
371        } else {
372            None
373        }
374    }
375}
376
377impl LuaCallExpr {
378    pub fn get_prefix_expr(&self) -> Option<LuaExpr> {
379        self.child()
380    }
381
382    pub fn get_args_list(&self) -> Option<LuaCallArgList> {
383        self.child()
384    }
385
386    pub fn get_args_count(&self) -> Option<usize> {
387        self.get_args_list().map(|it| it.get_args().count())
388    }
389
390    pub fn is_colon_call(&self) -> bool {
391        if let Some(index_token) = self.get_colon_token() {
392            return index_token.is_colon();
393        }
394        false
395    }
396
397    pub fn get_colon_token(&self) -> Option<LuaIndexToken> {
398        self.get_prefix_expr().and_then(|prefix| match prefix {
399            LuaExpr::IndexExpr(index_expr) => index_expr.get_index_token(),
400            _ => None,
401        })
402    }
403
404    pub fn is_require(&self) -> bool {
405        self.syntax().kind() == LuaSyntaxKind::RequireCallExpr.into()
406    }
407
408    pub fn is_error(&self) -> bool {
409        self.syntax().kind() == LuaSyntaxKind::ErrorCallExpr.into()
410    }
411
412    pub fn is_assert(&self) -> bool {
413        self.syntax().kind() == LuaSyntaxKind::AssertCallExpr.into()
414    }
415
416    pub fn is_type(&self) -> bool {
417        self.syntax().kind() == LuaSyntaxKind::TypeCallExpr.into()
418    }
419
420    pub fn is_setmetatable(&self) -> bool {
421        self.syntax().kind() == LuaSyntaxKind::SetmetatableCallExpr.into()
422    }
423}
424
425impl PathTrait for LuaCallExpr {}
426
427impl From<LuaCallExpr> for LuaExpr {
428    fn from(expr: LuaCallExpr) -> Self {
429        LuaExpr::CallExpr(expr)
430    }
431}
432
433/// In Lua, tables are a fundamental data structure that can be used to represent arrays, objects,
434/// and more. To facilitate parsing and handling of different table structures, we categorize tables
435/// into three types: `TableArrayExpr`, `TableObjectExpr`, and `TableEmptyExpr`.
436///
437/// - `TableArrayExpr`: Represents a table used as an array, where elements are indexed by integers.
438/// - `TableObjectExpr`: Represents a table used as an object, where elements are indexed by strings or other keys.
439/// - `TableEmptyExpr`: Represents an empty table with no elements.
440///
441/// This categorization helps in accurately parsing and processing Lua code by distinguishing between
442/// different uses of tables, thereby enabling more precise syntax analysis and manipulation.
443#[derive(Debug, Clone, PartialEq, Eq, Hash)]
444pub struct LuaTableExpr {
445    syntax: LuaSyntaxNode,
446}
447
448impl LuaAstNode for LuaTableExpr {
449    fn syntax(&self) -> &LuaSyntaxNode {
450        &self.syntax
451    }
452
453    fn can_cast(kind: LuaSyntaxKind) -> bool
454    where
455        Self: Sized,
456    {
457        kind == LuaSyntaxKind::TableArrayExpr
458            || kind == LuaSyntaxKind::TableObjectExpr
459            || kind == LuaSyntaxKind::TableEmptyExpr
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 LuaCommentOwner for LuaTableExpr {}
475
476impl LuaTableExpr {
477    pub fn is_empty(&self) -> bool {
478        self.syntax().kind() == LuaSyntaxKind::TableEmptyExpr.into()
479    }
480
481    pub fn is_array(&self) -> bool {
482        self.syntax().kind() == LuaSyntaxKind::TableArrayExpr.into()
483    }
484
485    pub fn is_object(&self) -> bool {
486        self.syntax().kind() == LuaSyntaxKind::TableObjectExpr.into()
487    }
488
489    pub fn get_fields(&self) -> LuaAstChildren<LuaTableField> {
490        self.children()
491    }
492}
493
494impl From<LuaTableExpr> for LuaSingleArgExpr {
495    fn from(expr: LuaTableExpr) -> Self {
496        LuaSingleArgExpr::TableExpr(expr)
497    }
498}
499
500#[derive(Debug, Clone, PartialEq, Eq, Hash)]
501pub struct LuaLiteralExpr {
502    syntax: LuaSyntaxNode,
503}
504
505impl LuaAstNode for LuaLiteralExpr {
506    fn syntax(&self) -> &LuaSyntaxNode {
507        &self.syntax
508    }
509
510    fn can_cast(kind: LuaSyntaxKind) -> bool
511    where
512        Self: Sized,
513    {
514        kind == LuaSyntaxKind::LiteralExpr
515    }
516
517    fn cast(syntax: LuaSyntaxNode) -> Option<Self>
518    where
519        Self: Sized,
520    {
521        if Self::can_cast(syntax.kind().into()) {
522            Some(Self { syntax })
523        } else {
524            None
525        }
526    }
527}
528
529impl LuaLiteralExpr {
530    pub fn get_literal(&self) -> Option<LuaLiteralToken> {
531        self.token()
532    }
533}
534
535impl From<LuaLiteralExpr> for LuaSingleArgExpr {
536    fn from(expr: LuaLiteralExpr) -> Self {
537        LuaSingleArgExpr::LiteralExpr(expr)
538    }
539}
540
541#[derive(Debug, Clone, PartialEq, Eq, Hash)]
542pub struct LuaBinaryExpr {
543    syntax: LuaSyntaxNode,
544}
545
546impl LuaAstNode for LuaBinaryExpr {
547    fn syntax(&self) -> &LuaSyntaxNode {
548        &self.syntax
549    }
550
551    fn can_cast(kind: LuaSyntaxKind) -> bool
552    where
553        Self: Sized,
554    {
555        kind == LuaSyntaxKind::BinaryExpr
556    }
557
558    fn cast(syntax: LuaSyntaxNode) -> Option<Self>
559    where
560        Self: Sized,
561    {
562        if Self::can_cast(syntax.kind().into()) {
563            Some(Self { syntax })
564        } else {
565            None
566        }
567    }
568}
569
570impl LuaBinaryExpr {
571    pub fn get_exprs(&self) -> Option<(LuaExpr, LuaExpr)> {
572        let exprs = self.children::<LuaExpr>().collect::<Vec<_>>();
573        if exprs.len() == 2 {
574            Some((exprs[0].clone(), exprs[1].clone()))
575        } else {
576            None
577        }
578    }
579
580    pub fn get_op_token(&self) -> Option<LuaBinaryOpToken> {
581        self.token()
582    }
583
584    pub fn get_left_expr(&self) -> Option<LuaExpr> {
585        self.child()
586    }
587}
588
589impl From<LuaBinaryExpr> for LuaExpr {
590    fn from(expr: LuaBinaryExpr) -> Self {
591        LuaExpr::BinaryExpr(expr)
592    }
593}
594
595#[derive(Debug, Clone, PartialEq, Eq, Hash)]
596pub struct LuaUnaryExpr {
597    syntax: LuaSyntaxNode,
598}
599
600impl LuaAstNode for LuaUnaryExpr {
601    fn syntax(&self) -> &LuaSyntaxNode {
602        &self.syntax
603    }
604
605    fn can_cast(kind: LuaSyntaxKind) -> bool
606    where
607        Self: Sized,
608    {
609        kind == LuaSyntaxKind::UnaryExpr
610    }
611
612    fn cast(syntax: LuaSyntaxNode) -> Option<Self>
613    where
614        Self: Sized,
615    {
616        if Self::can_cast(syntax.kind().into()) {
617            Some(Self { syntax })
618        } else {
619            None
620        }
621    }
622}
623
624impl LuaUnaryExpr {
625    pub fn get_expr(&self) -> Option<LuaExpr> {
626        self.child()
627    }
628
629    pub fn get_op_token(&self) -> Option<LuaUnaryOpToken> {
630        self.token()
631    }
632}
633
634impl From<LuaUnaryExpr> for LuaExpr {
635    fn from(expr: LuaUnaryExpr) -> Self {
636        LuaExpr::UnaryExpr(expr)
637    }
638}
639
640#[derive(Debug, Clone, PartialEq, Eq, Hash)]
641pub struct LuaClosureExpr {
642    syntax: LuaSyntaxNode,
643}
644
645impl LuaAstNode for LuaClosureExpr {
646    fn syntax(&self) -> &LuaSyntaxNode {
647        &self.syntax
648    }
649
650    fn can_cast(kind: LuaSyntaxKind) -> bool
651    where
652        Self: Sized,
653    {
654        kind == LuaSyntaxKind::ClosureExpr
655    }
656
657    fn cast(syntax: LuaSyntaxNode) -> Option<Self>
658    where
659        Self: Sized,
660    {
661        if Self::can_cast(syntax.kind().into()) {
662            Some(Self { syntax })
663        } else {
664            None
665        }
666    }
667}
668
669impl LuaClosureExpr {
670    pub fn get_block(&self) -> Option<LuaBlock> {
671        self.child()
672    }
673
674    pub fn get_params_list(&self) -> Option<LuaParamList> {
675        self.child()
676    }
677}
678
679impl From<LuaClosureExpr> for LuaExpr {
680    fn from(expr: LuaClosureExpr) -> Self {
681        LuaExpr::ClosureExpr(expr)
682    }
683}
684
685#[derive(Debug, Clone, PartialEq, Eq, Hash)]
686pub struct LuaParenExpr {
687    syntax: LuaSyntaxNode,
688}
689
690impl LuaAstNode for LuaParenExpr {
691    fn syntax(&self) -> &LuaSyntaxNode {
692        &self.syntax
693    }
694
695    fn can_cast(kind: LuaSyntaxKind) -> bool
696    where
697        Self: Sized,
698    {
699        kind == LuaSyntaxKind::ParenExpr
700    }
701
702    fn cast(syntax: LuaSyntaxNode) -> Option<Self>
703    where
704        Self: Sized,
705    {
706        if Self::can_cast(syntax.kind().into()) {
707            Some(Self { syntax })
708        } else {
709            None
710        }
711    }
712}
713
714impl LuaParenExpr {
715    pub fn get_expr(&self) -> Option<LuaExpr> {
716        self.child()
717    }
718}
719
720impl From<LuaParenExpr> for LuaExpr {
721    fn from(expr: LuaParenExpr) -> Self {
722        LuaExpr::ParenExpr(expr)
723    }
724}