roan_engine/interpreter/
stmt.rs

1use crate::{
2    context::Context,
3    module::{loaders::remove_surrounding_quotes, ExportType, Module, StoredConst, StoredFunction},
4    value::Value,
5    vm::VM,
6};
7use anyhow::Result;
8use roan_ast::{Block, Fn, GetSpan, Let, Loop, Stmt, Token, Use, While};
9use roan_error::{
10    error::{
11        RoanError,
12        RoanError::{FailedToImportModule, ImportError, NonBooleanCondition},
13    },
14    print_diagnostic, TextSpan,
15};
16use tracing::debug;
17
18impl Module {
19    /// Interpret statement from the module.
20    ///
21    /// # Arguments
22    /// * `stmt` - [`Stmt`] - The statement to interpret.
23    /// * `ctx` - [`Context`] - The context in which to interpret the statement.
24    pub fn interpret_stmt(&mut self, stmt: Stmt, ctx: &mut Context, vm: &mut VM) -> Result<()> {
25        match stmt {
26            Stmt::Fn(f) => self.interpret_function(f, ctx)?,
27            Stmt::Use(u) => self.interpret_use(u, ctx, vm)?,
28            Stmt::While(while_stmt) => self.interpret_while(while_stmt, ctx, vm)?,
29            Stmt::Loop(loop_stmt) => self.interpret_loop(loop_stmt, ctx, vm)?,
30            Stmt::Block(block) => self.execute_block(block, ctx, vm)?,
31            Stmt::If(if_stmt) => self.interpret_if(if_stmt, ctx, vm)?,
32            Stmt::Break(token) => {
33                debug!("Interpreting break statement");
34                return Err(RoanError::LoopBreak(token.span).into());
35            }
36            Stmt::Continue(token) => {
37                debug!("Interpreting continue statement");
38                return Err(RoanError::LoopContinue(token.span).into());
39            }
40            Stmt::Throw(throw) => self.interpret_throw(throw, ctx, vm)?,
41            Stmt::Try(try_stmt) => self.interpret_try(try_stmt, ctx, vm)?,
42            Stmt::Let(l) => self.interpret_let(l, vm, ctx)?,
43            Stmt::Expr(expr) => self.interpret_expr(expr.as_ref(), ctx, vm)?,
44            Stmt::Return(r) => {
45                debug!("Interpreting return: {:?}", r);
46
47                if let Some(expr) = r.expr {
48                    self.interpret_expr(expr.as_ref(), ctx, vm)?;
49                } else {
50                    vm.push(Value::Void);
51                }
52            }
53            Stmt::Struct(struct_stmt) => self.interpret_struct(struct_stmt, ctx)?,
54            Stmt::TraitDef(trait_stmt) => self.interpret_trait(trait_stmt, ctx)?,
55            Stmt::StructImpl(impl_stmt) => self.interpret_struct_impl(impl_stmt, ctx)?,
56            Stmt::TraitImpl(impl_stmt) => self.interpret_trait_impl(impl_stmt, ctx)?,
57            Stmt::Const(c) => {
58                let def_expr = c.expr.clone();
59                let ident_literal = c.ident.literal();
60                let is_public = c.public;
61
62                self.interpret_expr(&def_expr, ctx, vm)?;
63
64                let val = vm.pop().expect("Expected value on stack");
65
66                let stored_val = StoredConst {
67                    ident: c.ident.clone(),
68                    value: val.clone(),
69                };
70
71                self.consts.push(stored_val.clone());
72
73                if is_public {
74                    self.exports
75                        .push((ident_literal, ExportType::Const(stored_val)));
76                }
77            }
78        }
79
80        Ok(())
81    }
82
83    /// Interpret a let statement.
84    ///
85    /// # Arguments
86    /// * `let_stmt` - [`Let`] - The let statement to interpret.
87    /// * `vm` - [`VM`] - The virtual machine to use for interpretation.
88    /// * `ctx` - [`Context`] - The context in which to interpret the statement.
89    pub fn interpret_let(&mut self, l: Let, vm: &mut VM, ctx: &mut Context) -> Result<()> {
90        debug!("Interpreting let: {:?}", l.ident);
91        self.interpret_expr(l.initializer.as_ref(), ctx, vm)?;
92
93        let val = vm.pop().unwrap();
94        let ident = l.ident.literal();
95
96        if let Some(type_annotation) = &l.type_annotation {
97            let type_name = type_annotation.type_name.literal();
98
99            if type_annotation.is_array {
100                match val.clone() {
101                    Value::Vec(v) => {
102                        // TODO: actually display what part of the array is wrong
103                        for item in v.iter() {
104                            item.check_type(&type_name, l.initializer.span())?
105                        }
106                    }
107                    _ => {
108                        return Err(RoanError::TypeMismatch(
109                            format!(
110                                "Expected array of type {} but got {}",
111                                type_name,
112                                val.type_name()
113                            ),
114                            l.initializer.span(),
115                        )
116                        .into());
117                    }
118                }
119            } else {
120                if val.is_null() && type_annotation.is_nullable {
121                    self.declare_variable(ident.clone(), val);
122                    return Ok(());
123                }
124
125                val.check_type(
126                    &type_name,
127                    TextSpan::combine(vec![
128                        l.ident.span,
129                        type_annotation.type_name.span.clone(),
130                        l.initializer.span(),
131                    ])
132                    .unwrap(),
133                )?
134            }
135        }
136
137        self.declare_variable(ident.clone(), val);
138
139        Ok(())
140    }
141
142    /// Handle the result of a loop statement.
143    ///
144    /// [RoanError::LoopBreak] and [RoanError::LoopContinue] are handled if they are inside a loop otherwise they are returned as an error.
145    ///
146    /// # Arguments
147    /// * `result` - [Result<()>] - The result to handle.
148    pub fn handle_loop_result(&mut self, result: Result<()>) -> Result<()> {
149        match result {
150            Ok(_) => {}
151            Err(e) => match e.downcast::<RoanError>() {
152                Ok(RoanError::LoopBreak(_)) => {}
153                Ok(RoanError::LoopContinue(_)) => {}
154                Ok(other) => return Err(other.into()),
155                Err(e) => return Err(e),
156            },
157        }
158
159        Ok(())
160    }
161
162    /// Interpret a loop statement.
163    ///
164    /// # Arguments
165    /// * `loop_stmt` - [`Loop`] - The loop to interpret.
166    /// * `ctx` - [`Context`] - The context in which to interpret the loop.
167    pub fn interpret_loop(
168        &mut self,
169        loop_stmt: Loop,
170        ctx: &mut Context,
171        vm: &mut VM,
172    ) -> Result<()> {
173        debug!("Interpreting infinite loop");
174        loop {
175            self.enter_scope();
176            let result = self.execute_block(loop_stmt.block.clone(), ctx, vm);
177            self.exit_scope();
178
179            self.handle_loop_result(result)?
180        }
181    }
182
183    /// Interpret a while loop.
184    ///
185    /// # Arguments
186    /// * `while_stmt` - [`While`] - The while loop to interpret.
187    /// * `ctx` - [`Context`] - The context in which to interpret the while loop.
188    pub fn interpret_while(
189        &mut self,
190        while_stmt: While,
191        ctx: &mut Context,
192        vm: &mut VM,
193    ) -> Result<()> {
194        debug!("Interpreting while loop");
195
196        loop {
197            self.interpret_expr(&while_stmt.condition, ctx, vm)?;
198            let condition_value = vm.pop().expect("Expected value on stack");
199
200            let condition = match condition_value {
201                Value::Bool(b) => b,
202                _ => {
203                    return Err(NonBooleanCondition(
204                        "While loop condition".into(),
205                        while_stmt.condition.span(),
206                    )
207                    .into())
208                }
209            };
210
211            if !condition {
212                break;
213            }
214
215            self.enter_scope();
216            let result = self.execute_block(while_stmt.block.clone(), ctx, vm);
217            self.exit_scope();
218
219            self.handle_loop_result(result)?
220        }
221
222        Ok(())
223    }
224
225    /// Interpret a function declaration.
226    ///
227    /// # Arguments
228    /// * `function` - [`Fn`] - The function to interpret.
229    /// * `ctx` - [`Context`] - The context in which to interpret the function.
230    pub fn interpret_function(&mut self, function: Fn, ctx: &mut Context) -> Result<()> {
231        debug!("Interpreting function: {}", function.name);
232
233        self.functions.push(StoredFunction::Function {
234            function: function.clone(),
235            defining_module: self.id(),
236        });
237
238        if function.public {
239            self.exports.push((
240                function.name.clone(),
241                ExportType::Function(function.clone()),
242            ));
243        }
244
245        ctx.upsert_module(self.id().clone(), self.clone());
246        Ok(())
247    }
248
249    /// Interpret an use statement.
250    ///
251    /// # Arguments
252    /// * `use_stmt` - [`Use`] - The use statement to interpret.
253    /// * `ctx` - [`Context`] - The context in which to interpret the statement.
254    pub fn interpret_use(&mut self, u: Use, ctx: &mut Context, vm: &mut VM) -> Result<()> {
255        debug!("Interpreting use: {}", u.from.literal());
256
257        let mut loaded_module = ctx
258            .load_module(&self.clone(), remove_surrounding_quotes(&u.from.literal()))
259            .map_err(|err| {
260                FailedToImportModule(
261                    u.from.literal().to_string(),
262                    err.to_string(),
263                    u.from.span.clone(),
264                )
265            })?;
266
267        match loaded_module.parse() {
268            Ok(_) => {}
269            Err(e) => {
270                print_diagnostic(e, Some(loaded_module.source().content()));
271                std::process::exit(1);
272            }
273        }
274
275        match loaded_module.interpret(ctx, vm) {
276            Ok(_) => {}
277            Err(e) => {
278                print_diagnostic(e, Some(loaded_module.source().content()));
279                std::process::exit(1);
280            }
281        }
282
283        // Collect the items to import
284        let imported_items: Vec<(String, &Token)> =
285            u.items.iter().map(|i| (i.literal(), i)).collect();
286
287        for (name, item) in imported_items {
288            let export = loaded_module.exports.iter().find(|(n, _)| n == &name);
289
290            if let Some((name, value)) = export {
291                debug!("Importing {} from {}", name, u.from.literal());
292                match value {
293                    ExportType::Function(f) => {
294                        self.functions.push(StoredFunction::Function {
295                            function: f.clone(),
296                            defining_module: loaded_module.id(),
297                        });
298                    }
299                    ExportType::Struct(s) => {
300                        self.structs.push(s.clone());
301                    }
302                    ExportType::Trait(t) => {
303                        self.traits.push(t.clone());
304                    }
305                    ExportType::Const(c) => {
306                        self.consts.push(c.clone());
307                    }
308                }
309            } else {
310                return Err(ImportError(name, item.span.clone()).into());
311            }
312        }
313
314        Ok(())
315    }
316
317    /// Execute a block of statements within a new scope.
318    ///
319    /// # Arguments
320    /// * `block` - [`Block`] - The block of statements to execute.
321    pub fn execute_block(&mut self, block: Block, ctx: &mut Context, vm: &mut VM) -> Result<()> {
322        debug!("Interpreting block statement");
323
324        self.enter_scope();
325        for stmt in block.stmts {
326            self.interpret_stmt(stmt, ctx, vm)?;
327        }
328        self.exit_scope();
329        Ok(())
330    }
331}