2023-01-25 19:01:13 +01:00
|
|
|
use std::rc::Rc;
|
2023-01-20 21:44:27 +01:00
|
|
|
|
2023-01-22 23:33:57 +01:00
|
|
|
use crate::error::RuntimeError;
|
2023-01-25 19:01:13 +01:00
|
|
|
use crate::parser::{BinaryOp, Expr, Literal, LogicalOp, Stmt, UnaryOp};
|
2023-01-20 21:44:27 +01:00
|
|
|
|
2023-01-22 23:33:57 +01:00
|
|
|
use super::environment::Environment;
|
2023-01-25 19:01:13 +01:00
|
|
|
use super::{LoxFunction, Value};
|
2023-01-22 23:33:57 +01:00
|
|
|
|
|
|
|
|
pub type EvalResult<T> = Result<T, RuntimeError>;
|
2023-01-20 21:44:27 +01:00
|
|
|
|
|
|
|
|
/*====================================================================================================================*/
|
|
|
|
|
|
2023-01-22 23:33:57 +01:00
|
|
|
pub fn execute(statement: Stmt, env: &mut Environment) -> Result<(), RuntimeError> {
|
2023-01-25 19:01:13 +01:00
|
|
|
statement.execute(env)
|
2023-01-20 21:44:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*====================================================================================================================*/
|
|
|
|
|
|
2023-01-22 23:33:57 +01:00
|
|
|
/* trait Eval {
|
|
|
|
|
fn eval(self, env: &mut Environment) -> EvalResult;
|
|
|
|
|
} */
|
2023-01-20 21:44:27 +01:00
|
|
|
|
2023-01-22 23:33:57 +01:00
|
|
|
impl 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
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-22 23:33:57 +01:00
|
|
|
impl 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),
|
2023-01-25 19:01:13 +01:00
|
|
|
Expr::Variable { name } => env.get(name),
|
2023-01-22 23:33:57 +01:00
|
|
|
Expr::Assignment { name, value } => {
|
|
|
|
|
let value = value.eval(env)?;
|
2023-01-25 19:01:13 +01:00
|
|
|
env.assign(name, value.clone())?;
|
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 {
|
|
|
|
|
Value::Function(fun) => fun.call(args, env),
|
|
|
|
|
Value::ExternFunction(ext_fun) => ext_fun.call(args, env),
|
|
|
|
|
_ => Err(RuntimeError::NotCallable { callee }),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Expr::Function {
|
|
|
|
|
name,
|
|
|
|
|
param_names,
|
|
|
|
|
body,
|
|
|
|
|
} => Ok(Value::function(LoxFunction::new(
|
|
|
|
|
name,
|
|
|
|
|
param_names.clone(),
|
|
|
|
|
body.as_ref().clone(),
|
|
|
|
|
))),
|
2023-01-22 23:33:57 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Stmt {
|
2023-01-25 19:01:13 +01:00
|
|
|
fn execute(&self, env: &mut Environment) -> EvalResult<()> {
|
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}"),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
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.execute(env)
|
|
|
|
|
} else if let Some(else_branch) = else_branch {
|
|
|
|
|
else_branch.execute(env)
|
|
|
|
|
} else {
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Stmt::While { condition, body } => {
|
|
|
|
|
while condition.eval(env)?.is_truthy() {
|
|
|
|
|
match body.execute(env) {
|
|
|
|
|
Ok(_) => {}
|
|
|
|
|
Err(RuntimeError::Break) => break,
|
|
|
|
|
Err(err) => return Err(err),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
2023-01-22 23:33:57 +01:00
|
|
|
Stmt::VarDecl { name, initializer } => {
|
|
|
|
|
let initializer = initializer.eval(env)?;
|
2023-01-25 19:01:13 +01:00
|
|
|
env.define(name.as_ref(), initializer);
|
2023-01-22 23:33:57 +01:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
Stmt::Block { statements } => {
|
|
|
|
|
env.enter_scope();
|
|
|
|
|
for statement in statements {
|
|
|
|
|
// on error the current frame gets destroyed anyways, so no need to exit scope
|
2023-01-25 19:01:13 +01:00
|
|
|
statement.execute(env)?;
|
2023-01-20 21:44:27 +01:00
|
|
|
}
|
2023-01-22 23:33:57 +01:00
|
|
|
env.exit_scope();
|
|
|
|
|
Ok(())
|
2023-01-20 21:44:27 +01:00
|
|
|
}
|
2023-01-25 19:01:13 +01:00
|
|
|
Stmt::ExprStmt { expr } => {
|
|
|
|
|
// expr.eval(env)?;
|
|
|
|
|
// Ok(Value::Nil)
|
|
|
|
|
expr.eval(env)?;
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
Stmt::Break => Err(RuntimeError::Break),
|
|
|
|
|
Stmt::Return { expr } => {
|
|
|
|
|
let value = expr.eval(env)?;
|
|
|
|
|
Err(RuntimeError::Return { value })
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*====================================================================================================================*/
|
|
|
|
|
|
|
|
|
|
impl LoxFunction {
|
|
|
|
|
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(),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
env.push_frame(self.closure().clone());
|
|
|
|
|
|
|
|
|
|
for (name, value) in std::iter::zip(self.param_names(), args) {
|
|
|
|
|
env.define(name.as_ref(), value);
|
2023-01-20 21:44:27 +01:00
|
|
|
}
|
2023-01-25 19:01:13 +01:00
|
|
|
|
|
|
|
|
let ret_val = match self.body().execute(env) {
|
|
|
|
|
Ok(()) => Value::Nil,
|
|
|
|
|
Err(RuntimeError::Return { value }) => value,
|
|
|
|
|
Err(err) => return Err(err),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
env.pop_frame();
|
|
|
|
|
|
|
|
|
|
Ok(ret_val)
|
2023-01-20 21:44:27 +01:00
|
|
|
}
|
|
|
|
|
}
|