Skip to main content

luaur_ast/methods/
parser_parse_assignment.rs

1//! Node: `cxx:Method:Luau.Ast:Ast/src/Parser.cpp:2004:parseAssignment`
2//!
3//! Faithful port of `Parser::parseAssignment` — `var {, var} = expr {, expr}`.
4//! Each assignment target is validated as an l-value (a non-l-value is replaced
5//! by an error node, gated on the export-value flag pair like the C++). The
6//! target and value lists are gathered in scratch arenas (vars/values share the
7//! comma-position arena, stack-disciplined) and copied into the node.
8
9use crate::functions::is_expr_l_value::is_expr_l_value;
10use crate::records::ast_expr::AstExpr;
11use crate::records::ast_node::AstNode;
12use crate::records::ast_stat::AstStat;
13use crate::records::ast_stat_assign::AstStatAssign;
14use crate::records::cst_node::CstNode;
15use crate::records::cst_stat_assign::CstStatAssign;
16use crate::records::lexeme::Type;
17use crate::records::location::Location;
18use crate::records::parser::Parser;
19use crate::records::position::Position;
20use crate::records::temp_vector::TempVector;
21
22impl Parser {
23    pub fn parse_assignment(&mut self, mut initial: *mut AstExpr) -> *mut AstStat {
24        if !is_expr_l_value(initial) {
25            initial = if luaur_common::FFlag::LuauExportValueSyntax.get()
26                && luaur_common::FFlag::LuauConst2.get()
27            {
28                self.report_l_value_error(initial) as *mut AstExpr
29            } else {
30                let expressions = self.copy_initializer_list_t(&[initial]);
31                self.report_expr_error(
32                    unsafe { (*initial).base.location },
33                    expressions,
34                    format_args!("Assigned expression must be a variable or a field"),
35                ) as *mut AstExpr
36            };
37        }
38
39        let mut vars = TempVector::new(&mut self.scratch_expr);
40        let mut vars_comma_positions = TempVector::new(&mut self.scratch_position);
41        vars.push_back(initial);
42
43        while self.lexer.current().r#type == Type(b',' as i32) {
44            if self.options.store_cst_data {
45                vars_comma_positions.push_back(self.lexer.current().location.begin);
46            }
47            self.next_lexeme();
48
49            let mut expr = self.parse_primary_expr(true);
50
51            if !is_expr_l_value(expr) {
52                expr = if luaur_common::FFlag::LuauExportValueSyntax.get()
53                    && luaur_common::FFlag::LuauConst2.get()
54                {
55                    self.report_l_value_error(expr) as *mut AstExpr
56                } else {
57                    let expressions = self.copy_initializer_list_t(&[expr]);
58                    self.report_expr_error(
59                        unsafe { (*expr).base.location },
60                        expressions,
61                        format_args!("Assigned expression must be a variable or a field"),
62                    ) as *mut AstExpr
63                };
64            }
65
66            vars.push_back(expr);
67        }
68
69        let equals_found = self.expect_and_consume_char('=', "assignment");
70        let equals_position = if equals_found {
71            self.lexer.previous_location().begin
72        } else {
73            Position::missing()
74        };
75
76        let mut values = TempVector::new(&mut self.scratch_expr_aux);
77        let mut values_comma_positions = TempVector::new(&mut self.scratch_position);
78        self.parse_expr_list(
79            &mut values,
80            if self.options.store_cst_data {
81                Some(&mut values_comma_positions)
82            } else {
83                None
84            },
85        );
86
87        let vars_array = self.copy_temp_vector_t(&vars);
88        let values_array = self.copy_temp_vector_t(&values);
89
90        let node = unsafe {
91            (*self.allocator).alloc(AstStatAssign::new(
92                Location::new(
93                    (*initial).base.location.begin,
94                    (**values.back()).base.location.end,
95                ),
96                vars_array,
97                values_array,
98            ))
99        };
100
101        if self.options.store_cst_data {
102            let vars_comma = self.copy_temp_vector_t(&vars_comma_positions);
103            let values_comma = self.copy_temp_vector_t(&values_comma_positions);
104            let cst_node = unsafe {
105                (*self.allocator).alloc(CstStatAssign::new(
106                    vars_comma,
107                    equals_position,
108                    values_comma,
109                ))
110            };
111            self.cst_node_map
112                .try_insert(node as *mut AstNode, cst_node as *mut CstNode);
113        }
114
115        node as *mut AstStat
116    }
117}