1use super::problems;
2use super::VagueIngester;
3use crate::ast::structure as i;
4use crate::high_level::problem::{CompileProblem, FilePosition};
5use crate::vague::structure as o;
6
7impl<'a> VagueIngester<'a> {
8 pub(super) fn convert_macro_signature<'n>(
9 &mut self,
10 node: i::Node<'n>,
11 ) -> Result<(Vec<o::VariableId>, Vec<i::Node<'n>>), CompileProblem> {
12 debug_assert!(node.as_rule() == i::Rule::macro_signature);
13 let mut children = node.into_inner();
14 let inputs_node = children.next().expect("bad AST");
15 let outputs_node = children.next();
16 let outputs = outputs_node
17 .map(|node| node.into_inner().collect())
18 .unwrap_or_default();
19 let input_ids = inputs_node
20 .into_inner()
21 .map(|child| {
22 debug_assert!(child.as_rule() == i::Rule::identifier);
23 let name = child.as_str();
24 let var = o::Variable::variable(self.make_position(&child), None);
25 self.target
26 .adopt_and_define_symbol(self.current_scope, name, var)
27 })
28 .collect();
29 Ok((input_ids, outputs))
30 }
31
32 pub(super) fn convert_macro_definition(&mut self, node: i::Node) -> Result<(), CompileProblem> {
33 debug_assert!(node.as_rule() == i::Rule::macro_definition);
34 let position = self.make_position(&node);
35 let mut children = node.into_inner();
36 let macro_name_node = children.next().expect("bad AST");
37 let signature_node = children.next().expect("bad AST");
38 let header_pos = {
39 let mut pos = self.make_position(¯o_name_node);
40 pos.include(&signature_node);
41 pos
42 };
43 let body_node = children.next().expect("bad AST");
44
45 let body_scope = self.target.create_child_scope(self.current_scope);
46 let old_current_scope = self.current_scope;
47 self.current_scope = body_scope;
48
49 let (input_ids, output_nodes) = self.convert_macro_signature(signature_node)?;
50 for id in input_ids {
51 self.target[self.current_scope].add_input(id);
52 }
53 self.convert_code_block(body_node)?;
54 let macro_name = macro_name_node.as_str();
55 for node in output_nodes {
56 let name = node.as_str();
57 if let Some(id) = self.lookup_identifier_without_error(name) {
58 self.target[self.current_scope].add_output(id);
59 } else {
60 let pos = self.make_position(&node);
61 return Err(problems::missing_output_definition(pos, macro_name, &name));
62 };
63 }
64
65 self.current_scope = old_current_scope;
66 let var = o::Variable::macro_def(o::MacroData::new(body_scope, header_pos));
67 let var_id = self
68 .target
69 .adopt_and_define_symbol(self.current_scope, macro_name, var);
70 self.add_statement(o::Statement::CreationPoint {
71 var: var_id,
72 var_type: Box::new(o::VPExpression::Literal(
73 o::KnownData::DataType(o::DataType::Macro),
74 FilePosition::placeholder(),
75 )),
76 position,
77 });
78 Ok(())
79 }
80
81 pub(super) fn convert_code_block(&mut self, node: i::Node) -> Result<(), CompileProblem> {
82 self.enter_scope();
83 debug_assert!(node.as_rule() == i::Rule::code_block);
84 for child in node.into_inner() {
85 self.convert_statement(child)?;
86 }
87 self.exit_scope();
88 Ok(())
89 }
90
91 pub(super) fn convert_code_block_in_new_scope(
92 &mut self,
93 node: i::Node,
94 ) -> Result<o::ScopeId, CompileProblem> {
95 debug_assert!(node.as_rule() == i::Rule::code_block);
96 self.enter_scope();
97 let new_scope = self.target.create_child_scope(self.current_scope);
98 let old_scope = self.current_scope;
99 self.current_scope = new_scope;
100 for child in node.into_inner() {
101 self.convert_statement(child)?;
102 }
103 self.current_scope = old_scope;
104 self.exit_scope();
105 Ok(new_scope)
106 }
107
108 pub(super) fn convert_return_statement(&mut self, node: i::Node) -> Result<(), CompileProblem> {
109 debug_assert!(node.as_rule() == i::Rule::return_statement);
110 let position = self.make_position(&node);
111 if self.current_scope == self.target.get_entry_point() {
112 Err(problems::return_from_root(position))
113 } else {
114 self.add_statement(o::Statement::Return(position));
115 Ok(())
116 }
117 }
118
119 pub(super) fn convert_assert_statement(&mut self, node: i::Node) -> Result<(), CompileProblem> {
120 debug_assert!(node.as_rule() == i::Rule::assert_statement);
121 let position = self.make_position(&node);
122 let mut children = node.into_inner();
123 let condition_node = children.next().expect("bad AST");
124 let condition = self.convert_vpe(condition_node)?;
125 self.add_statement(o::Statement::Assert(Box::new(condition), position));
126 Ok(())
127 }
128
129 pub(super) fn convert_if_statement(&mut self, node: i::Node) -> Result<(), CompileProblem> {
130 debug_assert!(node.as_rule() == i::Rule::if_statement);
131 let position = self.make_position(&node);
132 let mut children = node.into_inner();
133 let primary_condition = self.convert_vpe(children.next().expect("bad AST"))?;
134 let primary_body_node = children.next().expect("bad AST");
135 let primary_body = self.convert_code_block_in_new_scope(primary_body_node)?;
136
137 let mut clauses = vec![(primary_condition, primary_body)];
138 let mut else_clause = None;
139 for child in children {
140 match child.as_rule() {
141 i::Rule::else_if_clause => {
142 debug_assert!(else_clause.is_none(), "bad AST");
144 let mut children = child.into_inner();
145 let condition_node = children.next().expect("bad AST");
146 let condition = self.convert_vpe(condition_node)?;
147 let body_node = children.next().expect("bad AST");
148 let body = self.convert_code_block_in_new_scope(body_node)?;
149 clauses.push((condition, body));
150 }
151 i::Rule::else_clause => {
152 debug_assert!(else_clause.is_none(), "bad AST");
153 let mut children = child.into_inner();
154 let body_node = children.next().expect("bad AST");
155 let body = self.convert_code_block_in_new_scope(body_node)?;
156 else_clause = Some(body);
157 }
158 _ => unreachable!("bad AST"),
159 }
160 }
161
162 self.add_statement(o::Statement::Branch {
163 clauses,
164 else_clause,
165 position,
166 });
167 Ok(())
168 }
169
170 pub(super) fn convert_for_loop_statement(
171 &mut self,
172 node: i::Node,
173 ) -> Result<(), CompileProblem> {
174 debug_assert!(node.as_rule() == i::Rule::for_loop_statement);
175 let position = self.make_position(&node);
176 let mut children = node.into_inner();
177 let counter_node = children.next().expect("bad AST");
178 let counter_pos = self.make_position(&counter_node);
179 let counter_name = counter_node.as_str();
180 let start = self.convert_vpe(children.next().expect("bad AST"))?;
181 let end = self.convert_vpe(children.next().expect("bad AST"))?;
182 let body_scope = self.target.create_child_scope(self.current_scope);
183 let counter = o::Variable::variable(counter_pos.clone(), None);
184 let counter_id = self
185 .target
186 .adopt_and_define_symbol(body_scope, counter_name, counter);
187 let old_current_scope = self.current_scope;
188 self.current_scope = body_scope;
189
190 let possibly_body = children.next().expect("bad AST");
191 let (body, allow_unroll) = if possibly_body.as_rule() == i::Rule::no_unroll_keyword {
192 (children.next().expect("bad AST"), false)
193 } else {
194 (possibly_body, true)
195 };
196 self.convert_code_block(body)?;
197 self.current_scope = old_current_scope;
198 self.add_statement(o::Statement::ForLoop {
199 allow_unroll,
200 counter: counter_id,
201 start: Box::new(start),
202 end: Box::new(end),
203 body: body_scope,
204 position,
205 });
206 Ok(())
207 }
208
209 pub(super) fn convert_input_variable_statement(
210 &mut self,
211 node: i::Node,
212 ) -> Result<(), CompileProblem> {
213 debug_assert!(node.as_rule() == i::Rule::input_variable_statement);
214 if self.current_scope != self.target.get_entry_point() {
215 return Err(problems::io_inside_macro(self.make_position(&node)));
216 }
217 let mut children = node.into_inner();
218 let data_type = self.convert_vpe(children.next().expect("bad AST"))?;
219 for child in children {
220 let pos = self.make_position(&child);
221 let name = child.as_str();
222 let var_id = self.create_variable(data_type.clone(), name, pos);
223 self.target[self.current_scope].add_input(var_id);
224 }
225 Ok(())
226 }
227
228 pub(super) fn convert_output_variable_statement(
229 &mut self,
230 node: i::Node,
231 ) -> Result<(), CompileProblem> {
232 debug_assert!(node.as_rule() == i::Rule::output_variable_statement);
233 if self.current_scope != self.target.get_entry_point() {
234 return Err(problems::io_inside_macro(self.make_position(&node)));
235 }
236 let mut children = node.into_inner();
237 let data_type = self.convert_vpe(children.next().expect("bad AST"))?;
238 for child in children {
239 let pos = self.make_position(&child);
240 let name = child.as_str();
241 let var_id = self.create_variable(data_type.clone(), name, pos);
242 self.target[self.current_scope].add_output(var_id);
243 }
244 Ok(())
245 }
246
247 pub(super) fn convert_static_variable_statement(
250 &mut self,
251 node: i::Node,
252 ) -> Result<(), CompileProblem> {
253 debug_assert!(node.as_rule() == i::Rule::static_variable_statement);
254 let mut exported_vars = Vec::new();
255 for child in node.into_inner() {
256 if child.as_rule() == i::Rule::identifier {
257 let pos = FilePosition::from_pair(&child, self.current_file_id);
258 let name = child.as_str().to_owned();
259 exported_vars.push((name, pos));
260 } else if child.as_rule() == i::Rule::code_block {
261 let static_scope = self.target.create_child_scope(self.current_scope);
262 let old_scope = self.current_scope;
263 self.current_scope = static_scope;
264 self.convert_code_block(child)?;
265 let mut exported_ids = Vec::new();
266 for (name, pos) in exported_vars {
267 if let Some(id) = self.lookup_identifier_without_error(&name) {
268 self.target[old_scope].define_symbol(&name, id);
269 exported_ids.push(id);
270 } else {
271 return Err(problems::missing_export_definition(pos, &name));
272 }
273 }
274 self.current_scope = old_scope;
275 self.add_statement(o::Statement::StaticInit {
276 body: static_scope,
277 exports: exported_ids,
278 position: FilePosition::placeholder(), });
280 return Ok(());
281 } else {
282 unreachable!("bad AST");
283 }
284 }
285 unreachable!("bad AST");
286 }
287
288 pub(super) fn convert_assign_statement(&mut self, node: i::Node) -> Result<(), CompileProblem> {
289 debug_assert!(node.as_rule() == i::Rule::assign_statement);
290 let position = self.make_position(&node);
291 let mut children = node.into_inner();
292 let vce = self.convert_vce(children.next().expect("bad AST"))?;
293 let vpe = self.convert_vpe(children.next().expect("bad AST"))?;
294 self.add_statement(o::Statement::Assign {
295 target: Box::new(vce),
296 value: Box::new(vpe),
297 position,
298 });
299 Ok(())
300 }
301
302 fn convert_string_literal(&mut self, node: i::Node) -> String {
303 debug_assert!(node.as_rule() == i::Rule::string);
304 let text = node.as_str();
305 snailquote::unescape(text).expect("bad AST")
306 }
307
308 fn convert_include_statement(&mut self, node: i::Node) -> Result<(), CompileProblem> {
309 debug_assert!(node.as_rule() == i::Rule::include_statement);
310 let position = self.make_position(&node);
311 let mut children = node.into_inner();
312 let filename_node = children.next().expect("bad AST");
313 let filename = self.convert_string_literal(filename_node);
314 if let Some(file_index) = self.source_set.find_source(&filename) {
315 if self.aux_scope_data.included_files.contains(&file_index) {
316 return Ok(());
318 }
319 self.aux_scope_data.included_files.insert(file_index);
320 let (_name, content) = self.source_set.borrow_source(file_index);
321 let timer = std::time::Instant::now();
322 let mut ast = match crate::ast::ingest(content, file_index) {
323 Ok(ast) => ast,
324 Err(mut problem) => {
325 problems::hint_encountered_while_including(&mut problem, position);
326 return Err(problem);
327 }
328 };
329
330 self.perf_counters.ast.time += timer.elapsed().as_millis();
331 self.perf_counters.ast.num_invocations += 1;
332
333 let old_file_id = self.current_file_id;
334 self.current_file_id = file_index;
335 if let Err(mut problem) = self.execute(&mut ast) {
336 problems::hint_encountered_while_including(&mut problem, position);
337 return Err(problem);
338 }
339 self.current_file_id = old_file_id;
340 } else {
341 return Err(problems::nonexistant_include(position, &filename));
342 }
343 Ok(())
344 }
345
346 pub(super) fn convert_statement(&mut self, node: i::Node) -> Result<(), CompileProblem> {
347 debug_assert!(node.as_rule() == i::Rule::statement);
348 let child = node.into_inner().next().expect("bad AST");
349 match child.as_rule() {
350 i::Rule::macro_definition => self.convert_macro_definition(child)?,
351 i::Rule::code_block => self.convert_code_block(child)?,
352 i::Rule::return_statement => self.convert_return_statement(child)?,
353 i::Rule::assert_statement => self.convert_assert_statement(child)?,
354 i::Rule::if_statement => self.convert_if_statement(child)?,
355 i::Rule::for_loop_statement => self.convert_for_loop_statement(child)?,
356 i::Rule::input_variable_statement => self.convert_input_variable_statement(child)?,
357 i::Rule::output_variable_statement => self.convert_output_variable_statement(child)?,
358 i::Rule::static_variable_statement => self.convert_static_variable_statement(child)?,
359 i::Rule::assign_statement => self.convert_assign_statement(child)?,
360 i::Rule::macro_call => {
361 let expr = self.convert_macro_call(child, false)?;
362 self.add_statement(o::Statement::RawVPExpression(Box::new(expr)));
363 }
364 i::Rule::var_dec => {
365 self.convert_var_dec(child)?;
366 }
367 i::Rule::include_statement => self.convert_include_statement(child)?,
368 _ => unreachable!("bad AST"),
369 }
370 Ok(())
371 }
372}