diff --git a/src/eval.rs b/src/eval.rs index f91c7ea..9d8b4e9 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -2,6 +2,7 @@ use core::fmt; use std::{ cell::RefCell, collections::{HashMap, hash_map::Entry}, + ops, process, rc::Rc, }; @@ -25,15 +26,17 @@ impl Default 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 { 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 { match self { Val::Num(n) => *n, @@ -41,9 +44,9 @@ impl Val<'_> { } } - fn call(&self, stack: &mut Vec) { + fn call(&self, stack: &mut Stack<'a>) { match self { - Val::Num(_) => stack.push(self.clone()), + Val::Num(n) => stack.push(Val::Num(*n)), Val::Fun { insts, env } => { eval(insts, stack, &env.clone()); } @@ -120,24 +123,102 @@ impl<'a> Env<'a> { } } -fn eval<'a>(insts: &'a [Inst<'a>], stack: &mut Vec>, env: &Rc>>) { +#[derive(Debug)] +struct Stack<'a>(Vec>); + +impl<'a> Stack<'a> { + fn new() -> Self { + Self(Vec::new()) + } + + fn pop(&mut self) -> Option> { + 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>>) { for i in insts { 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 { - "+" => { - let a = stack.pop().unwrap_or_default(); - let b = stack.pop().unwrap_or_default(); - stack.push(Val::Num(a.to_num() + b.to_num())); + "+" => stack.run_dyadic(ops::Add::add), + "-" => stack.run_dyadic(ops::Sub::sub), + "*" => stack.run_dyadic(ops::Mul::mul), + "/" => 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" => { - 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")), }, Inst::Num(n) => stack.push(Val::Num(*n)), Inst::Call => { - let f = stack.pop().unwrap_or_default(); + let f = stack.pop_default(); f.call(stack); } Inst::Block(insts) => stack.push(Val::Fun { @@ -152,6 +233,6 @@ fn eval<'a>(insts: &'a [Inst<'a>], stack: &mut Vec>, env: &Rc]) { - let mut stack = Vec::new(); + let mut stack = Stack::new(); eval(insts, &mut stack, &Rc::new(RefCell::new(Env::default()))); }