rocks_lang/
interpreter.rs

1use std::cmp::Ordering;
2use std::collections::HashMap;
3use std::rc::Rc;
4use std::cell::RefCell;
5
6use crate::class::Class;
7use crate::environment::Environment;
8use crate::error::{self, Error, ReturnType, RuntimeError, ReturnError, BreakError};
9use crate::expr::{Expr, ExprVisitor};
10use crate::function::{NativeFunction, Function};
11use crate::object::{Object, Callable};
12use crate::stmt::{Stmt, StmtVisitor};
13use crate::token::{Type, Token};
14use crate::literal::Literal;
15
16pub struct Interpreter<'w> {
17    // Interior mutability with multiple owners
18    environment: Rc<RefCell<Environment>>,
19    globals: Rc<RefCell<Environment>>,
20    locals: HashMap<Token, usize>,
21    writer: Box<dyn std::io::Write + 'w>,
22}
23
24impl<'w> Interpreter<'w> {
25    pub fn new<W: std::io::Write>(writer: &'w mut W) -> Self {
26        let globals = Rc::new(RefCell::new(Environment::default()));
27
28        NativeFunction::get_globals().iter().for_each(|native| {
29            globals.borrow_mut().define(&native.name.lexeme, Object::from(native.clone()));
30        });
31
32        Interpreter {
33            environment: Rc::clone(&globals),
34            globals: Rc::clone(&globals),
35            locals: HashMap::new(),
36            writer: Box::new(writer),
37        }
38    }
39
40    pub fn interpret(&mut self, statements: &Vec<Stmt>) {
41        for statement in statements {
42            self.execute(statement).unwrap_or_else(|error| {
43                if let ReturnType::Error(error) = error {
44                    error.throw();
45                }
46            });
47        }
48    }
49 
50    fn execute(&mut self, stmt: &Stmt) -> Result<(), ReturnType> {
51        stmt.accept(self)
52    }
53
54    pub fn resolve(&mut self, name: &Token, depth: usize) {
55        self.locals.insert(name.clone(), depth);
56    }
57
58    fn lookup_variable(&mut self, name: &Token) -> Result<Object, ReturnType> {
59        let variable = match self.locals.get(name) {
60            Some(distance) => self.environment.borrow().get_at(*distance, name),
61            None => self.globals.borrow().get(name),
62        };
63
64        return match variable {
65            Ok(value) => Ok(value),
66            Err(error) => Err(ReturnType::Error(error)),
67        };
68    }
69
70    pub fn execute_block(
71        &mut self,
72        statements: &Vec<Stmt>,
73        environment: Rc<RefCell<Environment>>
74    ) -> Result<(), ReturnType> {
75        let previous = self.environment.clone();
76        self.environment = environment;
77
78        for statement in statements {
79            if let Err(return_type) = self.execute(statement) {
80                self.environment = previous;
81                return Err(return_type);
82            }
83        }
84
85        self.environment = previous;
86
87        Ok(())
88    }
89
90    fn evaluate(&mut self, expr: &Expr) -> Result<Object, ReturnType> {
91        expr.accept(self)
92    }
93}
94
95impl<'w> Default for Interpreter<'w> {
96    fn default() -> Self {
97        Self::new(Box::leak(Box::new(std::io::stdout())))
98    }
99}
100
101impl<'w> ExprVisitor<Result<Object, ReturnType>> for Interpreter<'w> {
102    fn visit_literal_expr(&mut self, expr: &Expr) -> Result<Object, ReturnType> {
103        let Expr::Literal(literal) = expr else { unreachable!() };
104        Ok(Object::Literal(literal.clone()))
105    }
106
107    fn visit_logical_expr(&mut self, expr: &Expr) -> Result<Object, ReturnType> {
108        let Expr::Logical(logical) = expr else { unreachable!() };
109        let left = self.evaluate(&logical.left)?;
110
111        match logical.operator.r#type {
112            Type::Or => if left.as_bool().is_some_and(|x| x) { return Ok(left) },
113            Type::And => if !left.as_bool().is_some_and(|x| x) { return Ok(left) },
114            _ => unreachable!(),
115        };
116
117        self.evaluate(&logical.right)
118    }
119
120    fn visit_unary_expr(&mut self, expr: &Expr) -> Result<Object, ReturnType> {
121        let Expr::Unary(unary) = expr else { unreachable!() };
122        let right = self.evaluate(&unary.expr)?;
123
124        let error_message = format!(
125            "Unary operation '{}' is not supported for {} type",
126            unary.operator.lexeme.clone(),
127            right.type_str()
128        );
129
130        let result = match unary.operator.r#type {
131            Type::Minus => -right,
132            Type::Bang => !right,
133            _ => unreachable!(),
134        };
135
136        if let Some(result) = result {
137            Ok(result)
138        } else {
139            return Err(ReturnType::Error(RuntimeError {
140                token: unary.operator.clone(),
141                message: error_message,
142            }));
143        }
144    }
145
146    fn visit_binary_expr(&mut self, expr: &Expr) -> Result<Object, ReturnType> {
147        let Expr::Binary(binary) = expr else { unreachable!() };
148        let left = self.evaluate(&binary.left)?;
149        let right = self.evaluate(&binary.right)?;
150
151        let error_message = format!(
152            "Binary operation '{}' is not supported between {} type and {} type",
153            binary.operator.lexeme.clone(),
154            left.type_str(),
155            right.type_str()
156        );
157
158        let result = match binary.operator.r#type {
159            Type::Plus => left + right,
160            Type::Minus => left - right,
161            Type::Slash => left / right,
162            Type::Star => left * right,
163
164            Type::EqualEqual => Some(Object::Literal(Literal::Bool(left == right))),
165            Type::BangEqual => Some(Object::Literal(Literal::Bool(left != right))),
166
167            Type::Greater => left.partial_cmp(&right)
168                .map(|x| Object::Literal(Literal::Bool(x == Ordering::Greater))),
169            Type::Less => left.partial_cmp(&right)
170                .map(|x| Object::Literal(Literal::Bool(x == Ordering::Less))),
171            Type::GreaterEqual => left.partial_cmp(&right)
172                .map(|x| Object::Literal(Literal::Bool(x == Ordering::Greater || x == Ordering::Equal))),
173            Type::LessEqual => left.partial_cmp(&right)
174                .map(|x| Object::Literal(Literal::Bool(x == Ordering::Less || x == Ordering::Equal))),
175
176            _ => { unreachable!() }
177        };
178
179        if let Some(result) = result {
180            return Ok(result);
181        } else {
182            return Err(ReturnType::Error(RuntimeError {
183                token: binary.operator.clone(),
184                message: error_message,
185            }));
186        }
187    }
188
189    fn visit_call_expr(&mut self, expr: &Expr) -> Result<Object, ReturnType> {
190        let Expr::Call(call) = expr else { unreachable!() };
191        let callee = self.evaluate(call.callee.as_ref())?;
192
193        // Early return if callee is not found
194        // TODO: handle the case where the callee is "null"
195        if let Object::Literal(Literal::Null) = callee {
196            return Ok(Object::from(Literal::Null));
197        }
198
199        // Collect will fail if Result::Err is is found
200        let arguments = call.arguments
201            .iter()
202            .map(|expr| self.evaluate(expr))
203            .collect::<Result<Vec<Object>, ReturnType>>()?;
204
205        match callee {
206            Object::Function(function) => {
207                if arguments.len() != function.arity() {
208                    return Err(ReturnType::Error(RuntimeError {
209                        token: call.paren.clone(),
210                        message: format!("Expected {} arguments but got {}", function.arity(), arguments.len()),
211                    }));
212                }
213
214                return match function.call(self, arguments) {
215                    Ok(value) => Ok(value),
216                    Err(error) => {
217                        // TODO: look into implementing call stack on error
218                        // error.token = call.paren.clone();
219                        return Err(ReturnType::Error(error));
220                    }
221                };
222            },
223            Object::NativeFunction(function) => {
224                if arguments.len() != function.arity() {
225                    return Err(ReturnType::Error(RuntimeError {
226                        token: call.paren.clone(),
227                        message: format!("Expected {} arguments but got {}", function.arity(), arguments.len()),
228                    }));
229                }
230
231                return match function.call(self, arguments) {
232                    Ok(result) => Ok(result),
233                    Err(error) => {
234                        // error.token = call.paren.clone();
235                        return Err(ReturnType::Error(error));
236                    }
237                };
238            },
239            Object::Class(class) => {
240                if arguments.len() != class.borrow().arity() {
241                    return Err(ReturnType::Error(RuntimeError {
242                        token: call.paren.clone(),
243                        message: format!("Expected {} arguments but got {}", class.borrow().arity(), arguments.len()),
244                    }));
245                }
246
247                return match class.borrow().call(self, arguments) {
248                    Ok(result) => Ok(result),
249                    Err(error) => {
250                        // error.token = call.paren.clone();
251                        return Err(ReturnType::Error(error));
252                    }
253                };
254            },
255            _ => {
256                return Err(ReturnType::Error(RuntimeError {
257                    token: call.paren.clone(),
258                    message: "Can only call functions and classes".to_string(),
259                }));
260            }
261        }
262    }
263
264    fn visit_grouping_expr(&mut self, expr: &Expr) -> Result<Object, ReturnType> {
265        let Expr::Grouping(grouping) = expr else { unreachable!() };
266        self.evaluate(&grouping.expr)
267    }
268
269    fn visit_variable_expr(&mut self, expr: &Expr) -> Result<Object, ReturnType> {
270        let Expr::Variable(variable) = expr else { unreachable!() };
271        self.lookup_variable(&variable.name)
272    }
273
274    fn visit_assign_expr(&mut self, expr: &Expr) -> Result<Object, ReturnType> {
275        let Expr::Assign(assign) = expr else { unreachable!() };
276        let value = self.evaluate(&assign.value)?;
277
278        if let Some(distance) = self.locals.get(&assign.name) {
279            self.environment.borrow_mut().assign_at(*distance, &assign.name, value.clone());
280        } else {
281            self.globals.borrow_mut().assign(&assign.name, value.clone());
282        }
283
284        Ok(value)
285    }
286
287    fn visit_get_expr(&mut self, expr: &Expr) -> Result<Object, ReturnType> {
288        let Expr::Get(get) = expr else { unreachable!() };
289        let object = self.evaluate(&get.object)?;
290
291        if let Object::Instance(ref instance) = object {
292            return match instance.borrow().get(&get.name, &object) {
293                Ok(value) => Ok(value),
294                Err(error) => Err(ReturnType::Error(error)),
295            }
296        }
297
298        return Err(ReturnType::Error(RuntimeError {
299            token: get.name.clone(),
300            message: "Only instances have properties".to_owned(),
301        }));
302    }
303
304    fn visit_set_expr(&mut self, expr: &Expr) -> Result<Object, ReturnType> {
305        let Expr::Set(set) = expr else { unreachable!() };
306
307        let object = self.evaluate(&set.object)?;
308
309        if let Object::Instance(instance) = object {
310            let value = self.evaluate(&set.value)?;
311            instance.borrow_mut().set(&set.name, value.clone());
312            return Ok(value);
313        } else {
314            return Err(ReturnType::Error(RuntimeError {
315                token: set.name.clone(),
316                message: "Only instances can have fields".to_string(),
317            }));
318        }
319    }
320
321    fn visit_this_expr(&mut self, expr: &Expr) -> Result<Object, ReturnType> {
322        let Expr::This(this) = expr else { unreachable!() };
323
324        self.lookup_variable(&this.keyword)
325    }
326
327    fn visit_super_expr(&mut self, expr: &Expr) -> Result<Object, ReturnType> {
328        let Expr::Super(super_expr) = expr else { unreachable!() };
329
330        // Resolver would have catched if super was used incorrectly.
331        // It is okay to unwrap here.
332        let distance = self.locals.get(&super_expr.keyword).unwrap();
333        let superclass = match self.environment.borrow().get_at(*distance, &super_expr.keyword) {
334            Ok(value) => Ok(value),
335            Err(error) => Err(ReturnType::Error(error)),
336        }?;
337
338        let object = match self.environment.borrow().get_at(distance - 1, &Token::from("this")) {
339            Ok(value) => Ok(value),
340            Err(error) => Err(ReturnType::Error(error)),
341        }?;
342
343        if let Object::Class(superclass) = superclass {
344            let method = superclass.borrow().get_method(&super_expr.method.lexeme);
345
346            if let Some(mut method) = method {
347                return Ok(Object::from(method.bind(object)));
348            } else {
349                return Err(ReturnType::Error(RuntimeError {
350                    token: super_expr.method.clone(),
351                    message: format!("Undefined property '{}'", super_expr.method.lexeme)
352                }));
353            }
354        } else {
355            unreachable!();
356        }
357    }
358}
359
360impl<'w> StmtVisitor<Result<(), ReturnType>> for Interpreter<'w> {
361    fn visit_expression_stmt(&mut self, stmt: &Stmt) -> Result<(), ReturnType> {
362        let Stmt::Expression(data) = stmt else { unreachable!() };
363        self.evaluate(&data.expr)?;
364
365        Ok(())
366    }
367
368    fn visit_function_stmt(&mut self, stmt: &Stmt) -> Result<(), ReturnType> {
369        let Stmt::Function(_) = stmt else { unreachable!() };
370
371        let function = Function::new(stmt.to_owned(), Rc::clone(&self.environment), false);
372
373        self.environment.borrow_mut().define(&function.name.lexeme.clone(), Object::from(function));
374
375        Ok(())
376    }
377
378    fn visit_if_stmt(&mut self, stmt: &Stmt) -> Result<(), ReturnType> {
379        let Stmt::If(data) = stmt else { unreachable!() };
380        if self.evaluate(&data.condition)?.as_bool().is_some_and(|x| x) {
381            self.execute(&data.then_branch)
382        } else if let Some(else_branch) = &data.else_branch {
383            self.execute(else_branch)
384        } else {
385            Ok(())
386        }
387    }
388
389    fn visit_print_stmt(&mut self, stmt: &Stmt) -> Result<(), ReturnType> {
390        let Stmt::Print(data) = stmt else { unreachable!() };
391        let value = self.evaluate(&data.expr)?;
392
393        // Make sure evaluate didn't throw an error
394        if error::did_error() {
395            return Ok(());
396        }
397
398        writeln!(self.writer, "{value}").expect("writer to not fail on write");
399
400        Ok(())
401    }
402
403    fn visit_return_stmt(&mut self, stmt: &Stmt) -> Result<(), ReturnType> {
404        let Stmt::Return(data) = stmt else { unreachable!() };
405
406        let value = if let Some(expr) = &data.value {
407            self.evaluate(expr)?
408        } else {
409            Object::from(Literal::Null)
410        };
411
412        Err(ReturnType::Return(ReturnError { value }))
413    }
414
415    fn visit_break_stmt(&mut self, stmt: &Stmt) -> Result<(), ReturnType> {
416        let Stmt::Break(_) = stmt else { unreachable!() };
417
418        Err(ReturnType::Break(BreakError {}))
419    }
420
421    fn visit_var_stmt(&mut self, stmt: &Stmt) -> Result<(), ReturnType> {
422        let Stmt::Var(data) = stmt else { unreachable!() };
423        let value = match &data.initializer {
424            Some(value) => self.evaluate(value)?,
425            None => Object::from(Literal::Null),
426        };
427
428        self.environment.borrow_mut().define(&data.name.lexeme, value);
429
430        Ok(())
431    }
432
433    fn visit_while_stmt(&mut self, stmt: &Stmt) -> Result<(), ReturnType> {
434        let Stmt::While(data) = stmt else { unreachable!() };
435        while self.evaluate(&data.condition)?.as_bool().is_some_and(|x| x) {
436            match self.execute(&data.body) {
437                Err(ReturnType::Break(_)) => break,
438                Err(err)=> return Err(err),
439                _ => {},
440            }
441        }
442
443        Ok(())
444    }
445
446    fn visit_block_stmt(&mut self, stmt: &Stmt) -> Result<(), ReturnType> {
447        let Stmt::Block(data) = stmt else { unreachable!() };
448        self.execute_block(
449            &data.statements,
450            Rc::new(RefCell::new(Environment::new(Some(Rc::clone(&self.environment)))))
451        )
452    }
453
454    fn visit_class_stmt(&mut self, stmt: &Stmt) -> Result<(), ReturnType> {
455        let Stmt::Class(data) = stmt else { unreachable!() };
456
457        let superclass = match data.superclass.as_ref() {
458            Some(class) => Some(self.evaluate(class)?),
459            None => None,
460        };
461
462        if let Some(ref superclass) = superclass {
463            match superclass {
464                Object::Class(_) => (),
465                _ => {
466                    return Err(ReturnType::Error(RuntimeError {
467                        // This is reporting the lexeme of the class name,
468                        // it is non-trivial to get the superclass name.
469                        token: data.name.clone(),
470                        message: "Superclass must be a class".to_string()
471                    }));
472                },
473            }
474        }
475
476        self.environment.borrow_mut().define(&data.name.lexeme, Object::Literal(Literal::Null));
477
478        if let Some(ref superclass) = superclass {
479            let mut environment = Environment::new(Some(Rc::clone(&self.environment)));
480            environment.define("super", superclass.clone());
481            self.environment = Rc::new(RefCell::new(environment));
482        }
483
484        let mut methods: HashMap<String, Function> = HashMap::new();
485        for method in &data.methods {
486            if let Stmt::Function(function) = method {
487                let function = Function::new(
488                    method.clone(),
489                    Rc::clone(&self.environment),
490                    function.name.lexeme.eq("init")
491                );
492                methods.insert(function.name.lexeme.clone(), function);
493            } else {
494                unreachable!();
495            }
496        }
497
498        let class = Class::new(data.name.lexeme.clone(), superclass.clone(), methods);
499
500        if superclass.is_some() {
501            let enclosing = self.environment.borrow().enclosing.clone().expect("enclosing to exist");
502            self.environment = enclosing;
503        }
504
505        self.environment.borrow_mut().assign(&data.name, Object::from(Rc::new(RefCell::new(class))));
506
507        Ok(())
508    }
509}