rlox/interpreter/src/interpret.rs

355 lines
13 KiB
Rust
Raw Normal View History

2023-01-28 14:19:12 +01:00
use std::collections::HashMap;
2023-01-25 19:01:13 +01:00
use std::rc::Rc;
2023-01-20 21:44:27 +01:00
use rlox2_frontend::parser::{BinaryOp, Expr, Literal, LogicalOp, Stmt, UnaryOp};
2023-01-22 23:33:57 +01:00
use crate::error::RuntimeError;
2023-01-28 14:19:12 +01:00
use crate::function::LoxExternFunction;
use crate::{LoxClass, LoxReference};
2023-01-20 21:44:27 +01:00
2023-01-22 23:33:57 +01:00
use super::environment::Environment;
use super::{LoxFunction, Runtime, Value};
2023-01-22 23:33:57 +01:00
pub type EvalResult<T> = Result<T, RuntimeError>;
2023-01-20 21:44:27 +01:00
/*====================================================================================================================*/
pub fn execute(statement: Stmt, runtime: &mut Runtime) -> Result<(), RuntimeError> {
let mut env = Environment::new(runtime);
statement.eval(&mut env)?;
Ok(())
2023-01-20 21:44:27 +01:00
}
/*====================================================================================================================*/
trait Eval {
fn eval(&self, env: &mut Environment) -> EvalResult<Value>;
}
2023-01-20 21:44:27 +01:00
impl Eval for Literal {
2023-01-25 19:01:13 +01:00
fn eval(&self, env: &mut Environment) -> EvalResult<Value> {
let _ = env;
2023-01-20 21:44:27 +01:00
match self {
2023-01-25 19:01:13 +01:00
Literal::String(s) => Ok(Value::String(Rc::clone(s))),
Literal::Number(num) => Ok(Value::Number(*num)),
Literal::Bool(b) => Ok(Value::Bool(*b)),
2023-01-22 23:33:57 +01:00
Literal::Nil => Ok(Value::Nil),
2023-01-20 21:44:27 +01:00
}
}
}
impl Eval for Expr {
2023-01-25 19:01:13 +01:00
fn eval(&self, env: &mut Environment) -> EvalResult<Value> {
2023-01-20 21:44:27 +01:00
match self {
2023-01-22 23:33:57 +01:00
Expr::Literal { literal } => literal.eval(env),
Expr::Unary { op, expr } => {
let arg = expr.eval(env)?;
2023-01-20 21:44:27 +01:00
2023-01-25 19:01:13 +01:00
match (*op, arg) {
2023-01-22 23:33:57 +01:00
(UnaryOp::Negate, Value::Number(num)) => Ok(Value::Number(-num)),
(UnaryOp::Not, Value::Bool(b)) => Ok(Value::Bool(!b)),
(UnaryOp::Not, primitive) => Ok(Value::Bool(!primitive.is_truthy())),
(op, arg) => Err(RuntimeError::UnaryOpInvalidArgument { op, arg }),
2023-01-20 21:44:27 +01:00
}
}
2023-01-22 23:33:57 +01:00
Expr::Binary { left, op, right } => {
use Value::{Bool, Number, String};
2023-01-20 21:44:27 +01:00
2023-01-22 23:33:57 +01:00
let left = left.eval(env)?;
let right = right.eval(env)?;
2023-01-20 21:44:27 +01:00
2023-01-25 19:01:13 +01:00
match (left, *op, right) {
2023-01-20 21:44:27 +01:00
(Number(left), BinaryOp::Add, Number(right)) => Ok(Number(left + right)),
(Number(left), BinaryOp::Subtract, Number(right)) => Ok(Number(left - right)),
(Number(left), BinaryOp::Multiply, Number(right)) => Ok(Number(left * right)),
(Number(left), BinaryOp::Divide, Number(right)) => {
if right == 0.0 {
2023-01-22 23:33:57 +01:00
return Err(RuntimeError::DivisionByZero);
2023-01-20 21:44:27 +01:00
}
Ok(Number(left / right))
}
2023-01-25 19:01:13 +01:00
(String(left), BinaryOp::Add, String(right)) => {
let mut s = std::string::String::with_capacity(left.capacity() + right.capacity());
s += &left;
s += &right;
Ok(String(Rc::new(s)))
}
2023-01-20 21:44:27 +01:00
(left, BinaryOp::Equal, right) => Ok(Bool(left == right)),
(left, BinaryOp::NotEqual, right) => Ok(Bool(left != right)),
(Number(left), BinaryOp::Less, Number(right)) => Ok(Bool(left < right)),
(Number(left), BinaryOp::LessEqual, Number(right)) => Ok(Bool(left <= right)),
(Number(left), BinaryOp::Greater, Number(right)) => Ok(Bool(left > right)),
(Number(left), BinaryOp::GreaterEqual, Number(right)) => Ok(Bool(left >= right)),
(String(left), BinaryOp::Less, String(right)) => Ok(Bool(left < right)),
(String(left), BinaryOp::LessEqual, String(right)) => Ok(Bool(left <= right)),
(String(left), BinaryOp::Greater, String(right)) => Ok(Bool(left > right)),
(String(left), BinaryOp::GreaterEqual, String(right)) => Ok(Bool(left >= right)),
2023-01-22 23:33:57 +01:00
(left, op, right) => Err(RuntimeError::BinaryOpInvalidArguments { left, op, right }),
}
}
2023-01-25 19:01:13 +01:00
Expr::Logical { left, op, right } => {
let left = left.eval(env)?;
match op {
LogicalOp::Or => {
if left.is_truthy() {
return Ok(left);
}
}
LogicalOp::And => {
if !left.is_truthy() {
return Ok(left);
}
}
}
let right = right.eval(env)?;
Ok(right)
}
2023-01-22 23:33:57 +01:00
Expr::Grouping { expr } => expr.eval(env),
Expr::Variable { name } => panic!("Unresolved variable {name}"),
Expr::LocalVariable { name, level } => env.get_local(name, *level),
Expr::GlobalVariable { name } => env.get_global(name),
Expr::Assignment { target, value } => {
2023-01-22 23:33:57 +01:00
let value = value.eval(env)?;
match target.as_ref() {
Expr::LocalVariable { name, level } => env.assign(name, value.clone(), *level)?,
Expr::GlobalVariable { name } => env.assign_global(name, value.clone())?,
_ => panic!("Invalid assigment target {target}"),
}
2023-01-22 23:33:57 +01:00
Ok(value)
}
2023-01-25 19:01:13 +01:00
Expr::Call { callee, args } => {
let callee = callee.eval(env)?;
let args = args
.iter()
.map(|arg| arg.eval(env))
.collect::<EvalResult<Vec<Value>>>()?;
match callee {
2023-01-28 21:11:01 +01:00
Value::Function(fun) => LoxFunction::call(fun, args, env),
2023-01-25 19:01:13 +01:00
Value::ExternFunction(ext_fun) => ext_fun.call(args, env),
2023-01-28 14:19:12 +01:00
Value::Class(class) => LoxClass::call(class, args, env),
2023-01-25 19:01:13 +01:00
_ => Err(RuntimeError::NotCallable { callee }),
}
}
2023-01-28 14:19:12 +01:00
Expr::Get { target, name } => {
let target = target.eval(env)?;
if let Value::Object(object) = target {
object.get(name).ok_or_else(|| {
let class = object.class();
let name = name.to_owned();
RuntimeError::UndefinedAttribute { class, name }
})
} else {
Err(RuntimeError::InvalidGetTarget)
}
}
Expr::Set { target, name, value } => {
let target = target.eval(env)?;
if let Value::Object(mut object) = target {
let value = value.eval(env)?;
object.set(name, value);
Ok(Value::Nil)
} else {
Err(RuntimeError::InvalidSetTarget)
}
}
2023-01-25 19:01:13 +01:00
Expr::Function {
name,
param_names,
closure_vars,
2023-01-25 19:01:13 +01:00
body,
} => Ok(Value::function(LoxFunction::new(
2023-01-28 14:19:12 +01:00
name.as_ref(),
env.collect_closure(closure_vars),
2023-01-28 14:19:12 +01:00
param_names.as_ref().clone(),
2023-01-25 19:01:13 +01:00
body.as_ref().clone(),
))),
2023-01-28 14:19:12 +01:00
Expr::Class {
superclass,
name,
methods: method_exprs,
} => {
let superclass = match superclass.as_ref().map(|expr| expr.eval(env)) {
Some(Ok(Value::Class(superclass))) => Some(superclass),
Some(Ok(value)) => return Err(RuntimeError::InvalidSuperclass { value }),
Some(Err(err)) => return Err(err),
None => None,
};
let mut methods: HashMap<String, Value> = HashMap::new();
// this is the scope "this" will get injected in
env.enter_scope();
for method_expr in method_exprs.iter() {
let method = method_expr.eval(env)?;
if let Value::Function(ref fun) = method {
let name = fun.name().to_owned();
methods.insert(name, method);
}
}
env.exit_scope();
Ok(Value::class(LoxClass::new(name, methods, superclass)))
}
Expr::This => panic!("Unresolved this"),
Expr::Super {
super_var,
this_var,
method,
} => match (super_var.eval(env)?, this_var.eval(env)?) {
(Value::Class(superclass), Value::Object(this)) => {
if let Some(method) = superclass.get_method(method, this) {
Ok(method)
} else {
Err(RuntimeError::InvalidGetTarget)
}
}
(super_val, this_val) => panic!("super evaluated to {super_val} and this evaluated to {this_val}"),
},
2023-01-22 23:33:57 +01:00
}
}
}
impl Eval for Stmt {
fn eval(&self, env: &mut Environment) -> EvalResult<Value> {
2023-01-22 23:33:57 +01:00
match self {
Stmt::Print { expr } => {
match expr.eval(env)? {
// special case: when printing a string, drop the surrounding ""
Value::String(s) => println!("{s}"),
val => println!("{val}"),
}
}
2023-01-25 19:01:13 +01:00
Stmt::IfStmt {
condition,
then_branch,
else_branch,
} => {
let condition = condition.eval(env)?;
if condition.is_truthy() {
then_branch.eval(env)?;
2023-01-25 19:01:13 +01:00
} else if let Some(else_branch) = else_branch {
else_branch.eval(env)?;
2023-01-25 19:01:13 +01:00
}
}
Stmt::While { condition, body } => {
while condition.eval(env)?.is_truthy() {
match body.eval(env) {
2023-01-25 19:01:13 +01:00
Ok(_) => {}
Err(RuntimeError::Break) => break,
Err(err) => return Err(err),
}
}
}
2023-01-22 23:33:57 +01:00
Stmt::VarDecl { name, initializer } => {
let initializer = initializer.eval(env)?;
env.define(name, initializer);
2023-01-22 23:33:57 +01:00
}
Stmt::Block { statements } => {
env.enter_scope();
for statement in statements {
if let Err(err) = statement.eval(env) {
env.exit_scope();
return Err(err);
}
2023-01-20 21:44:27 +01:00
}
2023-01-22 23:33:57 +01:00
env.exit_scope();
}
2023-01-25 19:01:13 +01:00
Stmt::ExprStmt { expr } => {
// expr.eval(env)?;
// Ok(Value::Nil)
expr.eval(env)?;
}
Stmt::Break => return Err(RuntimeError::Break),
2023-01-25 19:01:13 +01:00
Stmt::Return { expr } => {
let value = expr.eval(env)?;
return Err(RuntimeError::Return { value });
2023-01-25 19:01:13 +01:00
}
}
Ok(Value::Nil)
2023-01-25 19:01:13 +01:00
}
}
/*====================================================================================================================*/
impl LoxFunction {
2023-01-28 21:11:01 +01:00
pub fn call(fun: Rc<LoxFunction>, args: Vec<Value>, env: &mut Environment) -> EvalResult<Value> {
if args.len() != fun.arity() {
2023-01-25 19:01:13 +01:00
return Err(RuntimeError::WrongArity {
2023-01-28 21:11:01 +01:00
name: fun.name().to_owned(),
arity: fun.arity(),
2023-01-25 19:01:13 +01:00
given: args.len(),
});
}
2023-01-28 21:11:01 +01:00
env.enter_scope();
env.define(fun.name(), Value::Function(fun.clone()));
env.insert_closure(fun.closure().clone());
2023-01-25 19:01:13 +01:00
2023-01-28 21:11:01 +01:00
for (name, value) in std::iter::zip(fun.param_names(), args) {
env.define(name, value);
2023-01-20 21:44:27 +01:00
}
2023-01-25 19:01:13 +01:00
2023-01-28 21:11:01 +01:00
let ret_val = match fun.body().eval(env) {
Ok(_) => Ok(Value::Nil),
Err(RuntimeError::Return { value }) => Ok(value),
Err(err) => Err(err),
2023-01-25 19:01:13 +01:00
};
env.exit_scope();
2023-01-25 19:01:13 +01:00
ret_val
2023-01-20 21:44:27 +01:00
}
}
2023-01-28 14:19:12 +01:00
impl LoxExternFunction {
pub fn call(&self, args: Vec<Value>, env: &mut Environment) -> EvalResult<Value> {
if args.len() != self.arity() {
return Err(RuntimeError::WrongArity {
name: self.name().to_owned(),
arity: self.arity(),
given: args.len(),
});
}
(self.closure())(args, env)
}
}
impl LoxClass {
// has to take class as an argument instead of as self to leave it behind its Rc
pub fn call(class: Rc<LoxClass>, args: Vec<Value>, env: &mut Environment) -> EvalResult<Value> {
if args.len() != class.arity() {
return Err(RuntimeError::WrongArity {
name: class.name().to_owned(),
arity: class.arity(),
given: args.len(),
});
}
let object = LoxReference::new(class);
// object.init(args, env)?;
if let Some(Value::Function(method)) = object.get("init") {
2023-01-28 21:11:01 +01:00
LoxFunction::call(method, args, env)?;
2023-01-28 14:19:12 +01:00
}
Ok(Value::Object(object))
}
}