emmylua_parser/syntax/node/lua/
expr.rs

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