crftng-intrprtrs/src/interpreter/world.rs

76 lines
1.7 KiB
Rust

use std::{cell::RefCell, collections::HashMap};
use gc::{allocator::GCAllocator, gc_ref::GcRef, trace::GCTrace};
use crate::ast::statement::Statement;
use super::{
ast_walker::{Interpret, RuntimeError},
types::Primitive,
};
#[derive(Default, GCTrace)]
pub struct Environment {
variables: HashMap<String, Primitive>,
parent: Option<GcRef<RefCell<Environment>>>,
}
impl Environment {
// Update an already existing variable in current scope
pub fn update_var(&mut self, name: &str, v: Primitive) -> Option<Primitive> {
if let Some(cur) = self.variables.get_mut(name) {
Some(std::mem::replace(cur, v))
} else {
self.parent
.as_ref()
.and_then(|parent| parent.borrow_mut().update_var(name, v))
}
}
pub fn set_var(&mut self, name: String, v: Primitive) -> Option<Primitive> {
self.update_var(&name, v.clone())
.or_else(|| self.variables.insert(name, v))
}
pub fn get_var(&self, name: &str) -> Option<Primitive> {
self.variables.get(name).cloned().or_else(|| {
self.parent
.as_ref()
.and_then(|v| (**v).borrow().get_var(name))
})
}
}
pub struct World {
env: GcRef<RefCell<Environment>>,
_gc: GCAllocator,
}
impl World {
pub fn set_var(&mut self, name: String, v: Primitive) -> Option<Primitive> {
self.env.borrow_mut().set_var(name, v)
}
pub fn get_var(&self, name: &str) -> Option<Primitive> {
self.env.borrow().get_var(name)
}
}
impl World {
pub fn new() -> Self {
Self::default()
}
pub fn exec(&mut self, nodes: Vec<Statement>) -> Result<Primitive, RuntimeError> {
nodes
.into_iter()
.try_fold(Primitive::Nil, |_, stmnt| stmnt.interpret(self))
}
}
impl Default for World {
fn default() -> Self {
let mut gc = GCAllocator::default();
let env = gc.alloc(RefCell::default());
Self { env, _gc: gc }
}
}