evaluator

This commit is contained in:
mehbark 2025-07-02 17:25:46 -04:00
parent 40fdac182f
commit c4c6ba80c6
2 changed files with 162 additions and 2 deletions

157
src/eval.rs Normal file
View file

@ -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<RefCell<Env<'a>>>,
},
}
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<Self>) {
match self {
Val::Num(_) => stack.push(self.clone()),
Val::Fun { insts, env } => {
eval(insts, stack, &env.clone());
}
}
}
}
type EnvMap<'a> = HashMap<Key<'a>, Val<'a>>;
#[derive(Debug, Clone)]
enum Env<'a> {
Local(EnvMap<'a>),
Closure {
local: EnvMap<'a>,
above: Rc<RefCell<Env<'a>>>,
},
}
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<Val<'a>> {
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<Val<'a>>, env: &Rc<RefCell<Env<'a>>>) {
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())));
}

View file

@ -1,6 +1,7 @@
use crate::{inst::Inst, parse::parse}; use crate::{eval::run, inst::Inst, parse::parse};
use std::io::{self, Read}; use std::io::{self, Read};
mod eval;
mod inst; mod inst;
mod parse; mod parse;
@ -9,5 +10,7 @@ fn main() {
let _ = io::stdin().read_to_string(&mut src).unwrap(); let _ = io::stdin().read_to_string(&mut src).unwrap();
let insts = parse(&src); let insts = parse(&src);
println!("{}!\n{insts:#?}", Inst::Block(insts.clone())); eprintln!("{}!\n{insts:#?}", Inst::Block(insts.clone()));
run(&insts);
} }