evaluator
This commit is contained in:
parent
40fdac182f
commit
c4c6ba80c6
2 changed files with 162 additions and 2 deletions
157
src/eval.rs
Normal file
157
src/eval.rs
Normal 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())));
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
use crate::{inst::Inst, parse::parse};
|
||||
use crate::{eval::run, inst::Inst, parse::parse};
|
||||
use std::io::{self, Read};
|
||||
|
||||
mod eval;
|
||||
mod inst;
|
||||
mod parse;
|
||||
|
||||
|
|
@ -9,5 +10,7 @@ fn main() {
|
|||
let _ = io::stdin().read_to_string(&mut src).unwrap();
|
||||
|
||||
let insts = parse(&src);
|
||||
println!("{}!\n{insts:#?}", Inst::Block(insts.clone()));
|
||||
eprintln!("{}!\n{insts:#?}", Inst::Block(insts.clone()));
|
||||
|
||||
run(&insts);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue