use crate::ast::{self, Statement};
use crate::error::{Error, Result};
use crate::value::Value;
use crate::Script;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use crate::value::Visitor;
pub struct Runtime {
interpreter: Interpreter,
}
impl Runtime {
pub fn new() -> Self {
Self {
interpreter: Interpreter::new(),
}
}
pub async fn execute(&mut self, script: Script) -> Result<Value> {
self.interpreter.interpret(script.statements())
}
}
#[derive(Debug, Clone)]
pub struct Environment {
enclosing: Option<Rc<RefCell<Environment>>>,
values: HashMap<String, Value>,
}
impl Environment {
pub fn new() -> Self {
Self {
enclosing: None,
values: HashMap::new(),
}
}
pub fn with_enclosing(enclosing: Rc<RefCell<Environment>>) -> Self {
Self {
enclosing: Some(enclosing),
values: HashMap::new(),
}
}
pub fn define(&mut self, name: String, value: Value) {
self.values.insert(name, value);
}
pub fn get(&self, name: &str) -> Result<Value> {
if let Some(value) = self.values.get(name) {
Ok(value.clone())
} else if let Some(enclosing) = &self.enclosing {
enclosing.borrow().get(name)
} else {
Err(Error::undefined_variable(name))
}
}
pub fn set(&mut self, name: &str, value: Value) -> Result<()> {
if self.values.contains_key(name) {
self.values.insert(name.to_string(), value);
Ok(())
} else if let Some(enclosing) = &self.enclosing {
enclosing.borrow_mut().set(name, value)
} else {
Err(Error::undefined_variable(name))
}
}
}
struct Interpreter {
environment: Rc<RefCell<Environment>>,
}
impl Interpreter {
fn new() -> Self {
let environment = Rc::new(RefCell::new(Environment::new()));
Self::define_builtins(&environment);
Self { environment }
}
fn interpret(&mut self, statements: &[Statement]) -> Result<Value> {
let mut result = Value::Null;
for statement in statements {
result = self.visit_statement(statement)?;
}
Ok(result)
}
fn define_builtins(environment: &Rc<RefCell<Environment>>) {
let mut env = environment.borrow_mut();
env.define("print".to_string(), Value::native_function(
"print", None, |args| {
let output = args.iter()
.map(|v| v.to_string())
.collect::<Vec<_>>()
.join(" ");
println!("{}", output);
Ok(Value::Null)
}
));
}
fn execute_block(&mut self, statements: &[Statement], environment: Rc<RefCell<Environment>>) -> Result<Value> {
let previous = self.environment.clone();
self.environment = environment;
let mut result = Ok(Value::Null);
for statement in statements {
match self.visit_statement(statement) {
Ok(_) => {},
Err(e) => {
result = Err(e);
break;
}
}
}
self.environment = previous;
result
}
}
impl Visitor<Result<Value>> for Interpreter {
fn visit_statement(&mut self, stmt: &Statement) -> Result<Value> {
match stmt {
Statement::Expression(expr) => self.visit_expression(expr),
Statement::VarDeclaration { name, value, .. } => {
let value = self.visit_expression(value)?;
self.environment.borrow_mut().define(name.clone(), value);
Ok(Value::Null)
}
Statement::Block(statements) => {
let new_env = Rc::new(RefCell::new(Environment::with_enclosing(self.environment.clone())));
self.execute_block(statements, new_env)
}
_ => unimplemented!(),
}
}
fn visit_expression(&mut self, expr: &ast::Expression) -> Result<Value> {
match expr {
ast::Expression::Literal(value) => Ok(value.clone()),
ast::Expression::Variable(name) => self.environment.borrow().get(name),
ast::Expression::Binary { left, operator, right } => {
let left = self.visit_expression(left)?;
let right = self.visit_expression(right)?;
match operator {
ast::BinaryOperator::Add => {
match (left, right) {
(Value::Number(l), Value::Number(r)) => Ok(Value::Number(l + r)),
_ => Err(Error::type_error("numbers", "operands for '+'"))
}
}
_ => unimplemented!(),
}
}
_ => unimplemented!(),
}
}
}