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::{
|
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())));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue