Skip to main content

interpreter/
lib.rs

1use std::cell::RefCell;
2use std::collections::HashMap;
3use std::rc::Rc;
4
5use object::builtins::*;
6use object::environment::*;
7use object::{BoundMethodObject, ClassObject, EvalError, InstanceObject, InstanceRef, Object};
8use parser::ast::*;
9use parser::lexer::token::{Token, TokenKind};
10use parser::validation::validate_program;
11
12mod interpreter_test;
13
14pub fn eval(node: Node, env: &Env) -> Result<Rc<Object>, EvalError> {
15    match node {
16        Node::Program(p) => {
17            let mut predefined_names = env.borrow().visible_names();
18            predefined_names.extend(BuiltIns.iter().map(|builtin| builtin.name.to_string()));
19            let predefined_names = predefined_names
20                .iter()
21                .map(String::as_str)
22                .collect::<Vec<_>>();
23            validate_program(&p, &predefined_names).map_err(|error| error.message)?;
24            eval_block_statements(&p.body, env)
25        }
26        Node::Statement(statements) => eval_statement(&statements, env),
27        Node::Expression(expression) => eval_expression(&expression, env),
28    }
29}
30
31fn eval_block_statements(statements: &Vec<Statement>, env: &Env) -> Result<Rc<Object>, EvalError> {
32    let mut result = Rc::new(Object::Null);
33    for statement in statements {
34        // `debugger` is completion-transparent: it neither produces nor
35        // clears the surrounding block's result.
36        if matches!(statement, Statement::Debugger(_)) {
37            continue;
38        }
39        let val = eval_statement(statement, &Rc::clone(env))?;
40        match *val {
41            Object::ReturnValue(_) => return Ok(val),
42            _ => {
43                result = val;
44            }
45        }
46    }
47
48    return Ok(result);
49}
50
51fn eval_statement(statement: &Statement, env: &Env) -> Result<Rc<Object>, EvalError> {
52    match statement {
53        Statement::Expr(expr) => eval_expression(expr, env),
54        Statement::Return(ReturnStatement {
55            argument,
56            ..
57        }) => {
58            let val = eval_expression(argument, env)?;
59            return Ok(Rc::new(Object::ReturnValue(val)));
60        }
61        Statement::Let(Let {
62            identifier: id,
63            expr,
64            ..
65        }) => {
66            let val = eval_expression(expr, &Rc::clone(env))?;
67            let obj: Rc<Object> = Rc::clone(&val);
68            env.borrow_mut().set(id.name.clone(), obj);
69            return Ok(Rc::new(Object::Null));
70        }
71        Statement::Class(class) => eval_class_declaration(class, env),
72        Statement::Debugger(_) => Ok(Rc::new(Object::Null)),
73        Statement::SetProperty(statement) => {
74            let receiver = eval_expression(&statement.object, env)?;
75            let value = eval_expression(&statement.value, env)?;
76            set_property(&receiver, statement.property.name.clone(), value)?;
77            Ok(Rc::new(Object::Null))
78        }
79    }
80}
81
82fn eval_class_declaration(
83    declaration: &ClassDeclaration,
84    env: &Env,
85) -> Result<Rc<Object>, EvalError> {
86    let declaration_env = Rc::new(RefCell::new(env.borrow().snapshot()));
87    let mut constructor = None;
88    let mut methods = HashMap::new();
89    for method in &declaration.methods {
90        let function = Rc::new(Object::Function(
91            method.params.clone(),
92            method.body.clone(),
93            Rc::clone(&declaration_env),
94        ));
95        match method.kind {
96            MethodKind::Constructor => constructor = Some(function),
97            MethodKind::Method => {
98                methods.insert(method.name.name.clone(), function);
99            }
100        }
101    }
102
103    let class = Rc::new(RefCell::new(ClassObject {
104        name: declaration.name.name.clone(),
105        constructor,
106        methods,
107    }));
108    let class = Rc::new(Object::Class(class));
109    declaration_env
110        .borrow_mut()
111        .set(declaration.name.name.clone(), Rc::clone(&class));
112    env.borrow_mut().set(declaration.name.name.clone(), class);
113    Ok(Rc::new(Object::Null))
114}
115
116fn is_truthy(obj: &Object) -> bool {
117    match obj {
118        Object::Null => return false,
119        Object::Boolean(false) => return false,
120        _ => true,
121    }
122}
123
124fn eval_expression(expression: &Expression, env: &Env) -> Result<Rc<Object>, EvalError> {
125    match expression {
126        Expression::LITERAL(literal) => eval_literal(literal, env),
127        Expression::PREFIX(UnaryExpression {
128            op,
129            operand: expr,
130            ..
131        }) => {
132            let right = eval_expression(expr, &Rc::clone(env))?;
133            return eval_prefix(op, &right);
134        }
135        Expression::INFIX(BinaryExpression {
136            op,
137            left,
138            right,
139            ..
140        }) => {
141            let left = eval_expression(left, &Rc::clone(env))?;
142            let right = eval_expression(right, &Rc::clone(env))?;
143            return eval_infix(op, &left, &right);
144        }
145        Expression::IF(IF {
146            condition,
147            consequent,
148            alternate,
149            ..
150        }) => {
151            let condition = eval_expression(condition, &Rc::clone(env))?;
152            if is_truthy(&condition) {
153                eval_block_statements(&(consequent.body), env)
154            } else {
155                match alternate {
156                    Some(alt) => eval_block_statements(&(alt.body), env),
157                    None => Ok(Rc::new(Object::Null)),
158                }
159            }
160        }
161        Expression::IDENTIFIER(IDENTIFIER {
162            name: id,
163            ..
164        }) => eval_identifier(id, env),
165        Expression::FUNCTION(FunctionDeclaration {
166            params,
167            body,
168            name,
169            ..
170        }) => {
171            let declaration_env = Rc::new(RefCell::new(env.borrow().snapshot()));
172            let function = Rc::new(Object::Function(
173                params.clone(),
174                body.clone(),
175                Rc::clone(&declaration_env),
176            ));
177            if !name.is_empty() {
178                declaration_env
179                    .borrow_mut()
180                    .set(name.clone(), Rc::clone(&function));
181            }
182            return Ok(function);
183        }
184        Expression::FunctionCall(FunctionCall {
185            callee,
186            arguments,
187            ..
188        }) => {
189            let func = eval_expression(callee, &Rc::clone(env))?;
190            let args = eval_expressions(arguments, env)?;
191            apply_function(&func, &args)
192        }
193        Expression::Index(Index {
194            object: left,
195            index,
196            ..
197        }) => {
198            let literal = eval_expression(left, &Rc::clone(env))?;
199            let index = eval_expression(index, env)?;
200            eval_index_expression(&literal, &index)
201        }
202        Expression::This(_) => eval_identifier("this", env),
203        Expression::Property(property) => {
204            let receiver = eval_expression(&property.object, env)?;
205            get_property(&receiver, &property.property.name)
206        }
207        Expression::New(new_expression) => {
208            let class = eval_identifier(&new_expression.callee.name, env)?;
209            let arguments = eval_expressions(&new_expression.arguments, env)?;
210            construct_instance(&class, &arguments)
211        }
212    }
213}
214
215fn get_property(receiver: &Rc<Object>, name: &str) -> Result<Rc<Object>, EvalError> {
216    let Object::Instance(instance) = &**receiver else {
217        return Err(format!("cannot read property '{}' of {}", name, receiver));
218    };
219
220    if let Some(value) = instance.borrow().fields.get(name).cloned() {
221        return Ok(value);
222    }
223
224    let (class_name, method) = {
225        let instance = instance.borrow();
226        let class = instance.class.borrow();
227        (class.name.clone(), class.methods.get(name).cloned())
228    };
229    if let Some(method) = method {
230        return Ok(Rc::new(Object::BoundMethod(Rc::new(BoundMethodObject {
231            receiver: Rc::clone(instance),
232            method,
233            name: name.to_string(),
234        }))));
235    }
236
237    Err(format!("property '{}' does not exist on {}", name, class_name))
238}
239
240fn set_property(receiver: &Rc<Object>, name: String, value: Rc<Object>) -> Result<(), EvalError> {
241    let Object::Instance(instance) = &**receiver else {
242        return Err(format!("cannot set property '{}' of {}", name, receiver));
243    };
244    instance.borrow_mut().fields.insert(name, value);
245    Ok(())
246}
247
248fn construct_instance(
249    class_value: &Rc<Object>,
250    args: &[Rc<Object>],
251) -> Result<Rc<Object>, EvalError> {
252    let Object::Class(class) = &**class_value else {
253        return Err(format!("cannot construct {}", class_value));
254    };
255    let instance = Rc::new(RefCell::new(InstanceObject {
256        class: Rc::clone(class),
257        fields: HashMap::new(),
258    }));
259    let instance_value = Rc::new(Object::Instance(Rc::clone(&instance)));
260    let constructor = class.borrow().constructor.clone();
261    if let Some(constructor) = constructor {
262        apply_method(
263            &constructor,
264            &instance,
265            args,
266            &format!("{}.constructor", class.borrow().name),
267        )?;
268    } else if !args.is_empty() {
269        return Err(format!(
270            "wrong number of arguments for {}.constructor: want=0, got={}",
271            class.borrow().name,
272            args.len()
273        ));
274    }
275    Ok(instance_value)
276}
277
278fn eval_index_expression(left: &Rc<Object>, index: &Rc<Object>) -> Result<Rc<Object>, EvalError> {
279    match (&**left, &**index) {
280        (Object::Array(arr), Object::Integer(idx)) => match arr.get(*idx as usize) {
281            Some(obj) => return Ok(Rc::clone(obj)),
282            None => return Ok(Rc::new(Object::Null)),
283        },
284        (Object::Hash(map), key) => {
285            if !(key.is_hashable()) {
286                return Err("not a valid hash key".to_string());
287            }
288
289            match map.get(key) {
290                Some(obj) => return Ok(Rc::clone(obj)),
291                None => return Ok(Rc::new(Object::Null)),
292            }
293        }
294        _ => return Err(format!("index operator not supported for {}", left)),
295    }
296}
297
298fn apply_function(function: &Rc<Object>, args: &[Rc<Object>]) -> Result<Rc<Object>, EvalError> {
299    match &**function {
300        Object::Function(params, body, env) => {
301            if params.len() != args.len() {
302                return Err(format!(
303                    "wrong number of arguments: want={}, got={}",
304                    params.len(),
305                    args.len()
306                ));
307            }
308            let mut env = Environment::new_enclosed_environment(env);
309
310            params.iter().enumerate().for_each(|(i, param)| {
311                env.set(param.identifier.name.clone(), args[i].clone());
312            });
313
314            let evaluated = eval_block_statements(&body.body, &Rc::new(RefCell::new(env)))?;
315            return unwrap_return(evaluated);
316        }
317        Object::Builtin(b) => {
318            let result = b(args.to_vec());
319            // Builtins report failures as Object::Error values. Every other runtime
320            // failure here is an Err, so lift them instead of letting an error keep
321            // flowing as an ordinary value.
322            match &*result {
323                Object::Error(message) => Err(message.clone()),
324                _ => Ok(result),
325            }
326        }
327        Object::BoundMethod(bound) => {
328            apply_method(&bound.method, &bound.receiver, args, &bound.name)
329        }
330        Object::Class(class) => {
331            Err(format!("class {} must be constructed with new", class.borrow().name))
332        }
333        f => Err(format!("expected {} to be a function", f)),
334    }
335}
336
337fn apply_method(
338    method: &Rc<Object>,
339    receiver: &InstanceRef,
340    args: &[Rc<Object>],
341    display_name: &str,
342) -> Result<Rc<Object>, EvalError> {
343    let Object::Function(params, body, declaration_env) = &**method else {
344        return Err(format!("{} is not a method", display_name));
345    };
346    if params.len() != args.len() {
347        return Err(format!(
348            "wrong number of arguments for {}: want={}, got={}",
349            display_name,
350            params.len(),
351            args.len()
352        ));
353    }
354
355    let mut call_env = Environment::new_enclosed_environment(declaration_env);
356    call_env.set("this".to_string(), Rc::new(Object::Instance(Rc::clone(receiver))));
357    for (parameter, argument) in params.iter().zip(args) {
358        call_env.set(parameter.identifier.name.clone(), Rc::clone(argument));
359    }
360    let evaluated = eval_block_statements(&body.body, &Rc::new(RefCell::new(call_env)))?;
361    unwrap_return(evaluated)
362}
363
364fn unwrap_return(obj: Rc<Object>) -> Result<Rc<Object>, EvalError> {
365    if let Object::ReturnValue(val) = &*obj {
366        Ok(Rc::clone(val))
367    } else {
368        Ok(obj)
369    }
370}
371
372fn eval_expressions(exprs: &Vec<Expression>, env: &Env) -> Result<Vec<Rc<Object>>, EvalError> {
373    let mut list = Vec::new();
374    for expr in exprs {
375        let val = eval_expression(expr, &Rc::clone(env))?;
376        list.push(val);
377    }
378
379    Ok(list)
380}
381
382fn eval_identifier(identifier: &str, env: &Env) -> Result<Rc<Object>, EvalError> {
383    match env.borrow().get(identifier) {
384        Some(obj) => Ok(obj.clone()),
385        None => match BuiltIns.iter().find(|builtin| builtin.name == identifier) {
386            Some(obj) => Ok(Rc::new(Object::Builtin(obj.function))),
387            None => Err(format!("unknown identifier {}", identifier)),
388        },
389    }
390}
391
392fn eval_prefix(op: &Token, right: &Object) -> Result<Rc<Object>, EvalError> {
393    match op.kind {
394        TokenKind::BANG => eval_prefix_bang(right),
395        TokenKind::MINUS => eval_prefix_minus(right),
396        _ => Err(format!("unknown prefix operator: {}", op)),
397    }
398}
399
400fn eval_prefix_bang(expr: &Object) -> Result<Rc<Object>, EvalError> {
401    match *expr {
402        Object::Null => Ok(Rc::new(Object::Boolean(true))),
403        Object::Boolean(b) => Ok(Rc::new(Object::Boolean(!b))),
404        _ => Ok(Rc::new(Object::Boolean(false))),
405    }
406}
407
408fn eval_prefix_minus(expr: &Object) -> Result<Rc<Object>, EvalError> {
409    match *expr {
410        Object::Integer(i) => match i.checked_neg() {
411            Some(value) => Ok(Rc::from(Object::Integer(value))),
412            None => Err("integer overflow in negation".to_string()),
413        },
414        _ => Err(format!("can't apply prefix minus operator: {}", expr)),
415    }
416}
417
418fn eval_infix(op: &Token, left: &Object, right: &Object) -> Result<Rc<Object>, EvalError> {
419    if op.kind == TokenKind::EQ || op.kind == TokenKind::NotEq {
420        let equal = left == right;
421        return Ok(Rc::new(Object::Boolean(if op.kind == TokenKind::EQ { equal } else { !equal })));
422    }
423    match (left, right) {
424        (Object::Integer(left), Object::Integer(right)) => {
425            return eval_integer_infix(op, *left, *right);
426        }
427        (Object::Boolean(left), Object::Boolean(right)) => {
428            return eval_boolean_infix(op, *left, *right);
429        }
430        (Object::String(left), Object::String(right)) => {
431            return eval_string_infix(op, left.to_string(), right.to_string());
432        }
433        _ => Err(format!("eval infix error for op: {}, left: {}, right: {}", op, left, right)),
434    }
435}
436
437fn eval_integer_infix(op: &Token, left: i64, right: i64) -> Result<Rc<Object>, EvalError> {
438    // Checked arithmetic so overflow and division by zero surface as runtime
439    // errors (same wording as the bytecode VM) instead of panicking in debug
440    // builds and wrapping in release builds.
441    let result = match &op.kind {
442        TokenKind::PLUS => match left.checked_add(right) {
443            Some(value) => Object::Integer(value),
444            None => return Err("integer overflow in addition".to_string()),
445        },
446        TokenKind::MINUS => match left.checked_sub(right) {
447            Some(value) => Object::Integer(value),
448            None => return Err("integer overflow in subtraction".to_string()),
449        },
450        TokenKind::ASTERISK => match left.checked_mul(right) {
451            Some(value) => Object::Integer(value),
452            None => return Err("integer overflow in multiplication".to_string()),
453        },
454        TokenKind::SLASH if right == 0 => return Err("division by zero".to_string()),
455        TokenKind::SLASH => match left.checked_div(right) {
456            Some(value) => Object::Integer(value),
457            None => return Err("integer overflow in division".to_string()),
458        },
459        TokenKind::LT => Object::Boolean(left < right),
460        TokenKind::GT => Object::Boolean(left > right),
461        TokenKind::EQ => Object::Boolean(left == right),
462        TokenKind::NotEq => Object::Boolean(left != right),
463        op => return Err(format!("Invalid infix operator {} for int", op)),
464    };
465
466    Ok(Rc::from(result))
467}
468
469fn eval_boolean_infix(op: &Token, left: bool, right: bool) -> Result<Rc<Object>, EvalError> {
470    let result = match &op.kind {
471        TokenKind::EQ => Object::Boolean(left == right),
472        TokenKind::NotEq => Object::Boolean(left != right),
473        op => return Err(format!("Invalid infix operator for boolean: {}", op)),
474    };
475
476    Ok(Rc::from(result))
477}
478
479fn eval_string_infix(op: &Token, left: String, right: String) -> Result<Rc<Object>, EvalError> {
480    let result = match &op.kind {
481        TokenKind::EQ => Object::Boolean(left == right),
482        TokenKind::NotEq => Object::Boolean(left != right),
483        TokenKind::PLUS => Object::String(format!("{}{}", left, right)),
484        op => return Err(format!("Invalid infix {} operator for string", op)),
485    };
486
487    Ok(Rc::from(result))
488}
489
490fn eval_literal(literal: &Literal, env: &Env) -> Result<Rc<Object>, EvalError> {
491    match literal {
492        Literal::Integer(Integer {
493            raw: i,
494            ..
495        }) => Ok(Rc::from(Object::Integer(*i))),
496        Literal::Boolean(Boolean {
497            raw: b,
498            ..
499        }) => Ok(Rc::from(Object::Boolean(*b))),
500        Literal::String(StringType {
501            raw: s,
502            ..
503        }) => Ok(Rc::from(Object::String(s.clone()))),
504        Literal::Array(Array {
505            elements,
506            ..
507        }) => {
508            let list = eval_expressions(elements, env)?;
509            return Ok(Rc::from(Object::Array(list)));
510        }
511        Literal::Hash(Hash {
512            elements: map,
513            ..
514        }) => {
515            // Object's Hash impl only covers Integer/Boolean/String, which have no
516            // interior mutability; keys are checked with is_hashable() before insert.
517            #[allow(clippy::mutable_key_type)]
518            let mut hash_map = HashMap::new();
519
520            for (k, v) in map {
521                let key = eval_expression(k, env)?;
522                if !key.is_hashable() {
523                    return Err(format!("key {} is not hashable", key));
524                }
525                let value = eval_expression(v, env)?;
526                hash_map.insert(key, value);
527            }
528
529            return Ok(Rc::new(Object::Hash(hash_map)));
530        } // l => return Err(format!("unknown literal: {}", *l))
531    }
532}