Skip to main content

luaur_ast/methods/
parser_parse_stat.rs

1use crate::functions::get_identifier::get_identifier;
2use crate::records::ast_array::AstArray;
3use crate::records::ast_attr::AstAttr;
4use crate::records::ast_expr::AstExpr;
5use crate::records::ast_expr_binary::AstExprBinaryOp;
6use crate::records::ast_expr_call::AstExprCall;
7use crate::records::ast_name::AstName;
8use crate::records::ast_stat::AstStat;
9use crate::records::ast_stat_expr::AstStatExpr;
10use crate::records::lexeme::Lexeme;
11use crate::records::lexeme::Type;
12use crate::records::location::Location;
13use crate::records::parser::Parser;
14
15impl Parser {
16    pub fn parse_stat(&mut self) -> *mut AstStat {
17        match self.lexer.current().r#type {
18            Type::ReservedIf => return self.parse_if(),
19            Type::ReservedWhile => return self.parse_while(),
20            Type::ReservedDo => return self.parse_do(),
21            Type::ReservedFor => return self.parse_for(),
22            Type::ReservedRepeat => return self.parse_repeat(),
23            Type::ReservedFunction => {
24                return self.parse_function_stat(&AstArray {
25                    data: core::ptr::null_mut(),
26                    size: 0,
27                }) as *mut AstStat;
28            }
29            Type::ReservedLocal => {
30                if luaur_common::FFlag::LuauConst2.get() {
31                    let start = self.lexer.current().location;
32                    return self.parse_local(
33                        start,
34                        start.begin,
35                        &AstArray {
36                            data: core::ptr::null_mut(),
37                            size: 0,
38                        },
39                        false,
40                    );
41                } else {
42                    return self.parseLocal_DEPRECATED(&AstArray {
43                        data: core::ptr::null_mut(),
44                        size: 0,
45                    });
46                }
47            }
48            Type::ReservedReturn => return self.parse_return(),
49            Type::ReservedBreak => return self.parser_parse_break(),
50            Type::Attribute | Type::AttributeOpen => return self.parse_attribute_stat(),
51            _ => {}
52        }
53
54        let start = self.lexer.current().location;
55        let expr = self.parse_primary_expr(true);
56
57        if unsafe {
58            crate::rtti::ast_node_is::<AstExprCall>(unsafe { &*std::ptr::addr_of!((*expr).base) })
59        } {
60            return unsafe {
61                (*self.allocator).alloc(AstStatExpr::new((*expr).base.location, expr))
62                    as *mut AstStat
63            };
64        }
65
66        let current_type = self.lexer.current().r#type;
67        if current_type == Type(',' as i32) || current_type == Type('=' as i32) {
68            return self.parse_assignment(expr);
69        }
70
71        if let Some(op) = self.parse_compound_op(self.lexer.current()) {
72            return self.parse_compound_assignment(expr, op);
73        }
74
75        let ident = get_identifier(expr);
76
77        if ident.operator_eq_c_char(c"type".as_ptr()) {
78            return self.parse_type_alias(&unsafe { (*expr).base.location }, false, unsafe {
79                (*expr).base.location.begin
80            });
81        }
82
83        if luaur_common::FFlag::DebugLuauUserDefinedClasses.get()
84            && ident.operator_eq_c_char(c"class".as_ptr())
85        {
86            return self.parse_class_stat(&start, false);
87        }
88
89        if ident.operator_eq_c_char(c"export".as_ptr()) {
90            if luaur_common::FFlag::LuauConst2.get() {
91                let current = self.lexer.current();
92                let is_local = current.r#type == Type::ReservedLocal;
93                let is_function = current.r#type == Type::ReservedFunction;
94                let is_const = current.r#type == Type::Name
95                    && AstName::ast_name_c_char(unsafe { current.data.name })
96                        .operator_eq_c_char(c"const".as_ptr());
97                let is_class = luaur_common::FFlag::DebugLuauUserDefinedClasses.get()
98                    && current.r#type == Type::Name
99                    && AstName::ast_name_c_char(unsafe { current.data.name })
100                        .operator_eq_c_char(c"class".as_ptr());
101
102                if is_local || is_function || is_const || is_class {
103                    return self.parse_export_value(
104                        &unsafe { (*expr).base.location },
105                        unsafe { (*expr).base.location.begin },
106                        &AstArray {
107                            data: core::ptr::null_mut(),
108                            size: 0,
109                        },
110                    );
111                } else if current.r#type == Type::Name
112                    && AstName::ast_name_c_char(unsafe { current.data.name })
113                        .operator_eq_c_char(c"type".as_ptr())
114                {
115                    let type_keyword_position = current.location.begin;
116                    self.next_lexeme();
117                    return self.parse_type_alias(
118                        &unsafe { (*expr).base.location },
119                        true,
120                        type_keyword_position,
121                    );
122                }
123            } else if luaur_common::FFlag::DebugLuauUserDefinedClasses.get()
124                && AstName::ast_name_c_char(unsafe { self.lexer.current().data.name })
125                    .operator_eq_c_char(c"class".as_ptr())
126            {
127                self.next_lexeme();
128                return self.parse_class_stat(&start, true);
129            } else if self.lexer.current().r#type == Type::Name
130                && AstName::ast_name_c_char(unsafe { self.lexer.current().data.name })
131                    .operator_eq_c_char(c"type".as_ptr())
132            {
133                let type_keyword_position = self.lexer.current().location.begin;
134                self.next_lexeme();
135                return self.parse_type_alias(
136                    &unsafe { (*expr).base.location },
137                    true,
138                    type_keyword_position,
139                );
140            }
141        }
142
143        if ident.operator_eq_c_char(c"continue".as_ptr()) {
144            return self.parser_parse_continue(&unsafe { (*expr).base.location });
145        }
146
147        if luaur_common::FFlag::LuauConst2.get() && ident.operator_eq_c_char(c"const".as_ptr()) {
148            return self.parse_local(
149                unsafe { (*expr).base.location },
150                unsafe { (*expr).base.location.begin },
151                &AstArray {
152                    data: core::ptr::null_mut(),
153                    size: 0,
154                },
155                true,
156            );
157        }
158
159        if self.options.allow_declaration_syntax {
160            if ident.operator_eq_c_char(c"declare".as_ptr()) {
161                return self.parse_declaration(
162                    &unsafe { (*expr).base.location },
163                    &AstArray {
164                        data: core::ptr::null_mut(),
165                        size: 0,
166                    },
167                );
168            }
169        }
170
171        if start
172            .begin
173            .operator_eq(&self.lexer.current().location.begin)
174        {
175            self.next_lexeme();
176        }
177
178        let expr_location = unsafe { (*expr).base.location };
179        let exprs = self.copy_initializer_list_t(&[expr]);
180
181        self.report_stat_error(
182            expr_location,
183            exprs,
184            AstArray {
185                data: core::ptr::null_mut(),
186                size: 0,
187            },
188            format_args!("Incomplete statement: expected assignment or a function call"),
189        ) as *mut AstStat
190    }
191}