evaluator: basic ops

This commit is contained in:
mehbark 2025-07-02 17:58:52 -04:00
parent c4c6ba80c6
commit 6de9b49349

View file

@ -2,6 +2,7 @@ use core::fmt;
use std::{ use std::{
cell::RefCell, cell::RefCell,
collections::{HashMap, hash_map::Entry}, collections::{HashMap, hash_map::Entry},
ops, process,
rc::Rc, rc::Rc,
}; };
@ -25,15 +26,17 @@ impl Default for Val<'_> {
} }
impl fmt::Display for Val<'_> { impl fmt::Display for Val<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
Val::Num(n) => write!(f, "{n}"), Val::Num(n) => write!(f, "{n}"),
Val::Fun { insts, env } => write!(f, "{} {env:?}", Inst::Block(insts.to_vec())), Val::Fun { insts, env: _ } => {
write!(f, "{}", Inst::Block(insts.to_vec()))
}
} }
} }
} }
impl Val<'_> { impl<'a> Val<'a> {
fn to_num(&self) -> f64 { fn to_num(&self) -> f64 {
match self { match self {
Val::Num(n) => *n, Val::Num(n) => *n,
@ -41,9 +44,9 @@ impl Val<'_> {
} }
} }
fn call(&self, stack: &mut Vec<Self>) { fn call(&self, stack: &mut Stack<'a>) {
match self { match self {
Val::Num(_) => stack.push(self.clone()), Val::Num(n) => stack.push(Val::Num(*n)),
Val::Fun { insts, env } => { Val::Fun { insts, env } => {
eval(insts, stack, &env.clone()); eval(insts, stack, &env.clone());
} }
@ -120,24 +123,102 @@ impl<'a> Env<'a> {
} }
} }
fn eval<'a>(insts: &'a [Inst<'a>], stack: &mut Vec<Val<'a>>, env: &Rc<RefCell<Env<'a>>>) { #[derive(Debug)]
struct Stack<'a>(Vec<Val<'a>>);
impl<'a> Stack<'a> {
fn new() -> Self {
Self(Vec::new())
}
fn pop(&mut self) -> Option<Val<'a>> {
self.0.pop()
}
fn pop_num(&mut self) -> f64 {
self.pop_default().to_num()
}
fn push(&mut self, val: Val<'a>) {
self.0.push(val);
}
fn push_num(&mut self, n: f64) {
self.push(Val::Num(n));
}
fn pop_default(&mut self) -> Val<'a> {
self.pop().unwrap_or_default()
}
fn run_dyadic(&mut self, f: impl Fn(f64, f64) -> f64) {
let b = self.pop_default();
let a = self.pop_default();
self.push_num(f(a.to_num(), b.to_num()));
}
fn run_monadic(&mut self, f: impl Fn(f64) -> f64) {
let n = self.pop_num();
self.push_num(f(n));
}
}
fn eval<'a>(insts: &'a [Inst<'a>], stack: &mut Stack<'a>, env: &Rc<RefCell<Env<'a>>>) {
for i in insts { for i in insts {
match i { match i {
Inst::Set(var) => env.borrow_mut().set(var, stack.pop().unwrap_or_default()), Inst::Set(var) => env.borrow_mut().set(var, stack.pop_default()),
Inst::Var(var) => match *var { Inst::Var(var) => match *var {
"+" => { "+" => stack.run_dyadic(ops::Add::add),
let a = stack.pop().unwrap_or_default(); "-" => stack.run_dyadic(ops::Sub::sub),
let b = stack.pop().unwrap_or_default(); "*" => stack.run_dyadic(ops::Mul::mul),
stack.push(Val::Num(a.to_num() + b.to_num())); "/" => stack.run_dyadic(ops::Div::div),
"%" | "rem" => stack.run_dyadic(ops::Rem::rem),
"sin" => stack.run_monadic(f64::sin),
"cos" => stack.run_monadic(f64::cos),
"tan" => stack.run_monadic(f64::tan),
"abs" => stack.run_monadic(f64::abs),
"ceil" => stack.run_monadic(f64::ceil),
"floor" => stack.run_monadic(f64::floor),
"round" => stack.run_monadic(f64::round),
"expt" => stack.run_dyadic(f64::powf),
"=" => stack.run_dyadic(|a, b| if (a - b).abs() < 1e-10 { 1. } else { 0. }),
"<" => stack.run_dyadic(|a, b| if a < b { 1. } else { 0. }),
"dup" => {
let top = stack.pop_default();
stack.push(top.clone());
stack.push(top);
}
"swap" => {
let a = stack.pop_default();
let b = stack.pop_default();
stack.push(a);
stack.push(b);
} }
"print" => { "print" => {
println!("{}", stack.pop().unwrap_or_default()); println!("{}", stack.pop_default());
}
"explode" => {
eprintln!("I ESPLODED");
for (i, val) in stack.0.iter().rev().enumerate() {
eprintln!("{}. {val}", i + 1);
}
process::exit(3);
}
"ite" => {
let r#else = stack.pop_default();
let then = stack.pop_default();
let test = stack.pop_default();
if test.to_num() == 0.0 {
r#else.call(stack);
} else {
then.call(stack);
}
} }
_ => stack.push(env.borrow().get(var).expect("idk this var")), _ => stack.push(env.borrow().get(var).expect("idk this var")),
}, },
Inst::Num(n) => stack.push(Val::Num(*n)), Inst::Num(n) => stack.push(Val::Num(*n)),
Inst::Call => { Inst::Call => {
let f = stack.pop().unwrap_or_default(); let f = stack.pop_default();
f.call(stack); f.call(stack);
} }
Inst::Block(insts) => stack.push(Val::Fun { Inst::Block(insts) => stack.push(Val::Fun {
@ -152,6 +233,6 @@ fn eval<'a>(insts: &'a [Inst<'a>], stack: &mut Vec<Val<'a>>, env: &Rc<RefCell<En
} }
pub fn run(insts: &[Inst<'_>]) { pub fn run(insts: &[Inst<'_>]) {
let mut stack = Vec::new(); let mut stack = Stack::new();
eval(insts, &mut stack, &Rc::new(RefCell::new(Env::default()))); eval(insts, &mut stack, &Rc::new(RefCell::new(Env::default())));
} }