nodespeak/vague/ingest/
statements.rs

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(&macro_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                    // Else if clauses should only show up before the else clause.
143                    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    // TODO: This will result in multiple static variables being created if a function is called
248    // multiple times. Or maybe don't fix it? Maybe make it a feature?
249    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(), // TODO: Better position.
279                });
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                // Don't include the file a second time.
317                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}