emmylua_parser/syntax/node/lua/
expr.rs

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