From c4c6ba80c69bf6b4583e9f442fe1bc4838ea3a08 Mon Sep 17 00:00:00 2001 From: mehbark Date: Wed, 2 Jul 2025 17:25:46 -0400 Subject: [PATCH] evaluator --- src/eval.rs | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 7 ++- 2 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 src/eval.rs diff --git a/src/eval.rs b/src/eval.rs new file mode 100644 index 0000000..f91c7ea --- /dev/null +++ b/src/eval.rs @@ -0,0 +1,157 @@ +use core::fmt; +use std::{ + cell::RefCell, + collections::{HashMap, hash_map::Entry}, + rc::Rc, +}; + +use crate::inst::Inst; + +type Key<'a> = &'a str; + +#[derive(Debug, Clone)] +enum Val<'a> { + Num(f64), + Fun { + insts: &'a [Inst<'a>], + env: Rc>>, + }, +} + +impl Default for Val<'_> { + fn default() -> Self { + Self::Num(0.) + } +} + +impl fmt::Display for Val<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Val::Num(n) => write!(f, "{n}"), + Val::Fun { insts, env } => write!(f, "{} {env:?}", Inst::Block(insts.to_vec())), + } + } +} + +impl Val<'_> { + fn to_num(&self) -> f64 { + match self { + Val::Num(n) => *n, + Val::Fun { insts: _, env: _ } => 0., + } + } + + fn call(&self, stack: &mut Vec) { + match self { + Val::Num(_) => stack.push(self.clone()), + Val::Fun { insts, env } => { + eval(insts, stack, &env.clone()); + } + } + } +} + +type EnvMap<'a> = HashMap, Val<'a>>; + +#[derive(Debug, Clone)] +enum Env<'a> { + Local(EnvMap<'a>), + Closure { + local: EnvMap<'a>, + above: Rc>>, + }, +} + +impl Default for Env<'_> { + fn default() -> Self { + Env::Local(HashMap::new()) + } +} + +impl<'a> Env<'a> { + fn set(&mut self, key: Key<'a>, val: Val<'a>) { + match self { + Env::Local(map) => { + map.insert(key, val); + } + Env::Closure { local, above } => match local.entry(key) { + Entry::Occupied(mut e) => { + e.insert(val); + } + Entry::Vacant(e) => { + if !above.borrow_mut().set_if_exists(key, val.clone()) { + e.insert(val); + } + } + }, + } + } + + /// Returns whether the key was set + fn set_if_exists(&mut self, key: Key<'a>, val: Val<'a>) -> bool { + match self { + Env::Local(map) => { + if let Entry::Occupied(mut e) = map.entry(key) { + e.insert(val); + true + } else { + false + } + } + Env::Closure { local, above } => { + if let Entry::Occupied(mut e) = local.entry(key) { + e.insert(val); + true + } else { + above.borrow_mut().set_if_exists(key, val) + } + } + } + } + + fn get(&self, key: Key<'a>) -> Option> { + match self { + Env::Local(map) => map.get(key).cloned(), + Env::Closure { local, above } => local + .get(key) + .cloned() + .or_else(|| above.borrow().get(key).clone()), + } + } +} + +fn eval<'a>(insts: &'a [Inst<'a>], stack: &mut Vec>, env: &Rc>>) { + for i in insts { + match i { + Inst::Set(var) => env.borrow_mut().set(var, stack.pop().unwrap_or_default()), + Inst::Var(var) => match *var { + "+" => { + let a = stack.pop().unwrap_or_default(); + let b = stack.pop().unwrap_or_default(); + stack.push(Val::Num(a.to_num() + b.to_num())); + } + "print" => { + println!("{}", stack.pop().unwrap_or_default()); + } + _ => stack.push(env.borrow().get(var).expect("idk this var")), + }, + Inst::Num(n) => stack.push(Val::Num(*n)), + Inst::Call => { + let f = stack.pop().unwrap_or_default(); + f.call(stack); + } + Inst::Block(insts) => stack.push(Val::Fun { + insts, + env: Rc::new(RefCell::new(Env::Closure { + local: HashMap::new(), + above: env.clone(), + })), + }), + } + } +} + +pub fn run(insts: &[Inst<'_>]) { + let mut stack = Vec::new(); + eval(insts, &mut stack, &Rc::new(RefCell::new(Env::default()))); +} diff --git a/src/main.rs b/src/main.rs index 470a925..4bd1c61 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ -use crate::{inst::Inst, parse::parse}; +use crate::{eval::run, inst::Inst, parse::parse}; use std::io::{self, Read}; +mod eval; mod inst; mod parse; @@ -9,5 +10,7 @@ fn main() { let _ = io::stdin().read_to_string(&mut src).unwrap(); let insts = parse(&src); - println!("{}!\n{insts:#?}", Inst::Block(insts.clone())); + eprintln!("{}!\n{insts:#?}", Inst::Block(insts.clone())); + + run(&insts); }