roan_engine/interpreter/
conditions.rs

1use crate::{context::Context, module::Module, value::Value, vm::VM};
2use roan_ast::{GetSpan, If, ThenElse};
3use tracing::debug;
4
5use anyhow::Result;
6use roan_error::{error::RoanError::NonBooleanCondition, TextSpan};
7
8impl Module {
9    /// Interpret a then-else expression.
10    ///
11    /// # Arguments
12    /// * `then_else` - [ThenElse] expression to interpret.
13    /// * `ctx` - The context in which to interpret the then-else expression.
14    /// * `vm` - The virtual machine to use.
15    ///
16    /// # Returns
17    /// The result of the then-else expression.
18    pub fn interpret_then_else(
19        &mut self,
20        then_else: ThenElse,
21        ctx: &mut Context,
22        vm: &mut VM,
23    ) -> Result<Value> {
24        debug!("Interpreting then-else");
25
26        self.interpret_expr(&then_else.condition, ctx, vm)?;
27        let condition = vm.pop().unwrap();
28
29        let b = match condition {
30            Value::Bool(b) => b,
31            _ => condition.is_truthy(),
32        };
33
34        if b {
35            self.interpret_expr(&then_else.then_expr, ctx, vm)?;
36        } else {
37            self.interpret_expr(&then_else.else_expr, ctx, vm)?;
38        }
39
40        Ok(vm.pop().expect("Expected value on stack"))
41    }
42
43    /// Interpret an if statement.
44    ///
45    /// # Arguments
46    /// * `if_stmt` - [`If`] - The if statement to interpret.
47    /// * `ctx` - [`Context`] - The context in which to interpret the statement.
48    pub fn interpret_if(&mut self, if_stmt: If, ctx: &mut Context, vm: &mut VM) -> Result<()> {
49        debug!("Interpreting if statement");
50
51        self.interpret_expr(&if_stmt.condition, ctx, vm)?;
52        let condition_value = vm.pop().expect("Expected value on stack");
53
54        let condition = match condition_value {
55            Value::Bool(b) => b,
56            Value::Null => false,
57            _ => {
58                return Err(NonBooleanCondition(
59                    "If condition".into(),
60                    TextSpan::combine(vec![if_stmt.if_token.span, if_stmt.condition.span()])
61                        .unwrap(),
62                )
63                .into())
64            }
65        };
66
67        if condition {
68            self.execute_block(if_stmt.then_block, ctx, vm)?;
69        } else {
70            let mut executed = false;
71            for else_if in if_stmt.else_ifs {
72                self.interpret_expr(&else_if.condition, ctx, vm)?;
73                let else_if_condition = vm.pop().expect("Expected value on stack");
74
75                let else_if_result = match else_if_condition {
76                    Value::Bool(b) => b,
77                    Value::Null => false,
78                    _ => {
79                        return Err(NonBooleanCondition(
80                            "Else if condition".into(),
81                            else_if.condition.span(),
82                        )
83                        .into())
84                    }
85                };
86
87                if else_if_result {
88                    self.execute_block(else_if.block, ctx, vm)?;
89                    executed = true;
90                    break;
91                }
92            }
93
94            if !executed {
95                if let Some(else_block) = if_stmt.else_block {
96                    self.execute_block(else_block.block, ctx, vm)?;
97                }
98            }
99        }
100
101        Ok(())
102    }
103}