maolang_core/
interp.rs

1//! Core interpetter
2
3use std::{
4    error::Error,
5    fmt::Display,
6    ops::{Add, Div, Mul, Sub},
7};
8
9use sf::Stack;
10
11use crate::parser::ast::{BinaryOp, Expr, Literal, UnaryOp};
12
13pub mod sf;
14
15/// An AST interpretter
16#[derive(Debug, Default, Clone)]
17pub struct Interpretter<'a> {
18    /// Local variables
19    stack: Stack<'a>,
20}
21
22/// An error during execution
23#[derive(Debug, Clone)]
24pub struct RuntimeError(pub String);
25
26impl Display for RuntimeError {
27    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28        write!(f, "{}", self.0)
29    }
30}
31
32impl Error for RuntimeError {}
33
34impl<'a> Interpretter<'a> {
35    /// Interprets an AST
36    pub fn eval(&mut self, ast: &Expr<'a>) -> Result<Literal<'a>, RuntimeError> {
37        match ast {
38            Expr::ForLoop {
39                init,
40                cond,
41                inc,
42                exec,
43            } => {
44                self.eval(init)?;
45                while self.eval(cond)?.bool()? {
46                    self.eval(exec)?;
47                    self.eval(inc)?;
48                }
49
50                Ok(Literal::Null)
51            }
52            Expr::WhileLoop { condition, eval } => {
53                while self.eval(condition)?.bool()? {
54                    self.eval(eval)?;
55                }
56
57                Ok(Literal::Null)
58            }
59            Expr::Conditional {
60                condition,
61                true_branch,
62                else_branch,
63            } => {
64                let condition = self.eval(condition)?.bool()?;
65
66                if condition {
67                    self.eval(true_branch)
68                } else if let Some(else_branch) = else_branch {
69                    self.eval(else_branch)
70                } else {
71                    Ok(Literal::Null)
72                }
73            }
74            Expr::Block(all) => {
75                for val in all {
76                    self.eval(val)?;
77                }
78
79                Ok(Literal::Null)
80            }
81            Expr::Variable(var) => self.stack.get(var).cloned(),
82            Expr::Print(node) => {
83                println!("{}", self.eval(node)?);
84                Ok(Literal::Null)
85            }
86            Expr::Assignment(name, val) => {
87                let val = self.eval(val)?;
88                self.stack.set(name.to_string(), val);
89                Ok(Literal::Null)
90            }
91            Expr::Literal(l) => Ok(*l),
92            Expr::Grouping(inner) => self.eval(inner),
93            Expr::Binary { op, left, right } => op.eval(self.eval(left)?, self.eval(right)?),
94            Expr::Unary { op, node } => op.eval(self.eval(node)?),
95        }
96    }
97}
98
99impl BinaryOp {
100    /// Evaluates a binary operation
101    pub fn eval<'a>(
102        &self,
103        left: Literal<'a>,
104        right: Literal<'a>,
105    ) -> Result<Literal<'a>, RuntimeError> {
106        match self {
107            Self::Add => left + right,
108            Self::Sub => left - right,
109            Self::Mul => left * right,
110            Self::Div => left / right,
111
112            Self::Gt => Ok(Literal::Bool(left.number()? > right.number()?)),
113            Self::Gte => Ok(Literal::Bool(left.number()? >= right.number()?)),
114            Self::Lt => Ok(Literal::Bool(left.number()? < right.number()?)),
115            Self::Lte => Ok(Literal::Bool(left.number()? <= right.number()?)),
116
117            Self::Eq => left.equals(&right),
118            Self::Neq => left.not_equals(&right),
119        }
120    }
121}
122
123impl UnaryOp {
124    /// Evaluates a unary operation
125    pub fn eval<'a>(&self, node: Literal<'a>) -> Result<Literal<'a>, RuntimeError> {
126        match self {
127            Self::Neg => Ok(Literal::Number(-node.number()?)),
128            Self::Not => Ok(Literal::Bool(!node.bool()?)),
129        }
130    }
131}
132
133impl Literal<'_> {
134    /// Gets a literal's type name
135    pub fn type_of(&self) -> &'static str {
136        match self {
137            Self::Number(_) => "number",
138            Self::String(_) => "string",
139            Self::Bool(_) => "bool",
140            Self::Null => "null",
141        }
142    }
143}
144
145impl Add for Literal<'_> {
146    type Output = Result<Self, RuntimeError>;
147
148    fn add(self, rhs: Self) -> Self::Output {
149        match (self, rhs) {
150            (Self::Number(n1), Self::Number(n2)) => Ok(Literal::Number(n1 + n2)),
151
152            _ => Err(RuntimeError(format!(
153                "Can't add literals of type {} and {} together",
154                self.type_of(),
155                rhs.type_of(),
156            ))),
157        }
158    }
159}
160
161impl Sub for Literal<'_> {
162    type Output = Result<Self, RuntimeError>;
163    fn sub(self, rhs: Self) -> Self::Output {
164        match (self, rhs) {
165            (Self::Number(n1), Self::Number(n2)) => Ok(Self::Number(n1 - n2)),
166
167            _ => Err(RuntimeError(format!(
168                "Can't subtract literals of type {} and {} together",
169                self.type_of(),
170                rhs.type_of(),
171            ))),
172        }
173    }
174}
175
176impl Mul for Literal<'_> {
177    type Output = Result<Self, RuntimeError>;
178    fn mul(self, rhs: Self) -> Self::Output {
179        match (self, rhs) {
180            (Self::Number(n1), Self::Number(n2)) => Ok(Self::Number(n1 * n2)),
181
182            _ => Err(RuntimeError(format!(
183                "Can't multiply literals of type {} and {} together",
184                self.type_of(),
185                rhs.type_of(),
186            ))),
187        }
188    }
189}
190
191impl Div for Literal<'_> {
192    type Output = Result<Self, RuntimeError>;
193    fn div(self, rhs: Self) -> Self::Output {
194        match (self, rhs) {
195            (Self::Number(n1), Self::Number(n2)) => Ok(Self::Number(n1 / n2)),
196            _ => Err(RuntimeError(format!(
197                "Can't divide literals of type {} and {} together",
198                self.type_of(),
199                rhs.type_of(),
200            ))),
201        }
202    }
203}
204
205impl<'a> Literal<'a> {
206    /// Returns the inner literal if it's a proper unsigned integer truly, asserting a runtime
207    /// error if not
208    pub fn uint(&self) -> Result<usize, RuntimeError> {
209        match self {
210            Self::Number(n) if *n >= 0.0 && n.round() == *n => Ok(*n as usize),
211            _ => Err(RuntimeError(format!("{self} is not an unsigned integer"))),
212        }
213    }
214    /// Returns the inner literal if it's numeric, asserting a runtime error if not
215    pub fn number(&self) -> Result<f64, RuntimeError> {
216        match self {
217            Self::Number(n) => Ok(*n),
218            _ => Err(RuntimeError(format!("{self} is not a number"))),
219        }
220    }
221
222    /// Returns the inner literal if it's boolean, asserting a runtime error if not
223    pub fn bool(&self) -> Result<bool, RuntimeError> {
224        match self {
225            Self::Bool(val) => Ok(*val),
226            Self::Number(0.0) => Ok(false),
227            Self::Number(_) => Ok(true),
228            _ => Err(RuntimeError(format!("{self} is not a boolean"))),
229        }
230    }
231
232    /// Returns the True literal if the two literals are losely equal
233    pub fn equals(&self, other: &Self) -> Result<Literal<'a>, RuntimeError> {
234        match (self, other) {
235            (Self::Number(n1), Self::Number(n2)) => Ok(Self::Bool(n1 == n2)),
236            (Self::Bool(b1), Self::Bool(b2)) => Ok(Self::Bool(b1 == b2)),
237
238            (Self::Null, Self::Null) => Ok(Self::Bool(true)),
239
240            (crazy1, crazy2) => Ok(Literal::Bool(crazy1.to_string() == crazy2.to_string())),
241        }
242    }
243
244    /// Returns the True literal if the two literals are not losely equal
245    pub fn not_equals(&self, other: &Self) -> Result<Literal<'a>, RuntimeError> {
246        match (self, other) {
247            (Self::Number(n1), Self::Number(n2)) => Ok(Self::Bool(n1 != n2)),
248            (Self::Bool(b1), Self::Bool(b2)) => Ok(Self::Bool(b1 != b2)),
249
250            (Self::Null, Self::Null) => Ok(Self::Bool(false)),
251
252            (crazy1, crazy2) => Ok(Literal::Bool(crazy1.to_string() != crazy2.to_string())),
253        }
254    }
255}