luaur_ast/methods/
parser_parse_for.rs1use crate::records::allocator::Allocator;
11use crate::records::ast_array::AstArray;
12use crate::records::ast_expr::AstExpr;
13use crate::records::ast_node::AstNode;
14use crate::records::ast_stat::AstStat;
15use crate::records::ast_stat_for::AstStatFor;
16use crate::records::ast_stat_for_in::AstStatForIn;
17use crate::records::cst_node::CstNode;
18use crate::records::cst_stat_for::CstStatFor;
19use crate::records::cst_stat_for_in::CstStatForIn;
20use crate::records::lexeme::Type;
21use crate::records::location::Location;
22use crate::records::match_lexeme::MatchLexeme;
23use crate::records::parser::Parser;
24use crate::records::position::Position;
25use crate::records::temp_vector::TempVector;
26
27impl Parser {
28 pub fn parse_for(&mut self) -> *mut AstStat {
29 let start = self.lexer.current().location;
30
31 self.next_lexeme(); let varname = self.parse_binding(false);
34
35 if self.lexer.current().r#type == Type(b'=' as i32) {
36 let equals_position = self.lexer.current().location.begin;
37 self.next_lexeme();
38
39 let from = self.parse_expr_i32(0);
40
41 let has_end_comma = self.expect_and_consume_char(',', "index range");
42 let end_comma_position = if has_end_comma {
43 self.lexer.previous_location().begin
44 } else {
45 Position::missing()
46 };
47
48 let to = self.parse_expr_i32(0);
49
50 let mut step_comma_position = Position::missing();
51 let mut step: *mut AstExpr = core::ptr::null_mut();
52
53 if self.lexer.current().r#type == Type(b',' as i32) {
54 step_comma_position = self.lexer.current().location.begin;
55 self.next_lexeme();
56
57 step = self.parse_expr_i32(0);
58 }
59
60 let match_do = *self.lexer.current();
61 let has_do = self.expect_and_consume_type(Type::ReservedDo, "for loop");
62
63 let locals_begin = self.save_locals();
64
65 unsafe {
66 (*self.function_stack.last_mut().unwrap()).loop_depth += 1;
67 }
68
69 let var = self.push_local(&varname);
70
71 let body = self.parse_block();
72
73 unsafe {
74 (*self.function_stack.last_mut().unwrap()).loop_depth -= 1;
75 }
76
77 self.restore_locals(locals_begin);
78
79 let end = self.lexer.current().location;
80
81 let has_end =
82 self.expect_match_end_and_consume(Type::ReservedEnd, &MatchLexeme::new(&match_do));
83 unsafe {
84 (*body).has_end = has_end;
85 }
86
87 let node = unsafe {
88 (*self.allocator).alloc(AstStatFor::new(
89 Location::new(start.begin, end.end),
90 var,
91 from,
92 to,
93 step,
94 body,
95 has_do,
96 match_do.location,
97 ))
98 };
99
100 if self.options.store_cst_data {
101 let cst_node = unsafe {
102 (*self.allocator).alloc(CstStatFor::new(
103 varname.colon_position,
104 equals_position,
105 end_comma_position,
106 step_comma_position,
107 ))
108 };
109 self.cst_node_map
110 .try_insert(node as *mut AstNode, cst_node as *mut CstNode);
111 }
112
113 node as *mut AstStat
114 } else {
115 let mut names = TempVector::new(&mut self.scratch_binding);
116 let mut vars_comma_position: AstArray<Position> = AstArray {
117 data: core::ptr::null_mut(),
118 size: 0,
119 };
120 names.push_back(varname);
121
122 if self.lexer.current().r#type == Type(b',' as i32) {
123 if self.options.store_cst_data {
124 let mut initial_comma_position = self.lexer.current().location.begin;
125 self.next_lexeme();
126 let _ = self.parse_binding_list(
127 &mut names,
128 false,
129 &mut vars_comma_position,
130 &mut initial_comma_position,
131 core::ptr::null_mut(),
132 false,
133 );
134 } else {
135 self.next_lexeme();
136 let _ = self.parse_binding_list(
137 &mut names,
138 false,
139 core::ptr::null_mut(),
140 core::ptr::null_mut(),
141 core::ptr::null_mut(),
142 false,
143 );
144 }
145 }
146
147 let in_location = self.lexer.current().location;
148 let has_in = self.expect_and_consume_type(Type::ReservedIn, "for loop");
149
150 let mut values = TempVector::new(&mut self.scratch_expr);
151 let mut values_comma_positions = TempVector::new(&mut self.scratch_position);
152 self.parse_expr_list(
153 &mut values,
154 if self.options.store_cst_data {
155 Some(&mut values_comma_positions)
156 } else {
157 None
158 },
159 );
160
161 let match_do = *self.lexer.current();
162 let has_do = self.expect_and_consume_type(Type::ReservedDo, "for loop");
163
164 let locals_begin = self.save_locals();
165
166 unsafe {
167 (*self.function_stack.last_mut().unwrap()).loop_depth += 1;
168 }
169
170 let mut vars = TempVector::new(&mut self.scratch_local);
171
172 for i in 0..names.size() {
173 let local = self.push_local(names.operator_index(i));
174 vars.push_back(local);
175 }
176
177 let body = self.parse_block();
178
179 unsafe {
180 (*self.function_stack.last_mut().unwrap()).loop_depth -= 1;
181 }
182
183 self.restore_locals(locals_begin);
184
185 let end = self.lexer.current().location;
186
187 let has_end =
188 self.expect_match_end_and_consume(Type::ReservedEnd, &MatchLexeme::new(&match_do));
189 unsafe {
190 (*body).has_end = has_end;
191 }
192
193 let vars_array = self.copy_temp_vector_t(&vars);
194 let values_array = self.copy_temp_vector_t(&values);
195
196 let node = unsafe {
197 (*self.allocator).alloc(AstStatForIn::new(
198 Location::new(start.begin, end.end),
199 vars_array,
200 values_array,
201 body,
202 has_in,
203 in_location,
204 has_do,
205 match_do.location,
206 ))
207 };
208
209 if self.options.store_cst_data {
210 let annotation = self.extract_annotation_colon_positions(&names);
211 let values_comma = self.copy_temp_vector_t(&values_comma_positions);
212 let cst_node = unsafe {
213 (*self.allocator).alloc(CstStatForIn::new(
214 annotation,
215 vars_comma_position,
216 values_comma,
217 ))
218 };
219 self.cst_node_map
220 .try_insert(node as *mut AstNode, cst_node as *mut CstNode);
221 }
222
223 node as *mut AstStat
224 }
225 }
226}