evaluator: basic ops
This commit is contained in:
parent
c4c6ba80c6
commit
6de9b49349
1 changed files with 95 additions and 14 deletions
109
src/eval.rs
109
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<Self>) {
|
||||
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<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 {
|
||||
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<Val<'a>>, env: &Rc<RefCell<En
|
|||
}
|
||||
|
||||
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())));
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue