todo: arbitrary ir

This commit is contained in:
2023-12-03 17:32:37 -08:00
parent 93cac44a99
commit 2c2268925a
16 changed files with 298 additions and 163 deletions

View File

@@ -1,33 +1,55 @@
use super::{Primitive, Type, ValueOrRef};
use crate::eval::{EvalEnvironment, EvalError, Value};
use crate::ir::{Expression, Program, TopLevel};
use crate::eval::{EvalError, Value};
use crate::ir::{Expression, Program, TopLevel, Variable};
use crate::util::scoped_map::ScopedMap;
impl<Type> Program<Type> {
/// Evaluate the program, returning either an error or a string containing everything
/// the program printed out.
type IRValue<T> = Value<Expression<T>>;
type IREvalError<T> = EvalError<Expression<T>>;
impl<T: Clone + Into<Type>> Program<T> {
/// Evaluate the program, returning either an error or the result of the final
/// statement and the complete contents of the console output.
///
/// The print outs will be newline separated, with one print out per line.
pub fn eval(&self) -> Result<String, EvalError> {
let mut env = EvalEnvironment::empty();
pub fn eval(&self) -> Result<(IRValue<T>, String), IREvalError<T>> {
let mut env: ScopedMap<Variable, IRValue<T>> = ScopedMap::new();
let mut stdout = String::new();
let mut last_value = Value::Void;
for stmt in self.items.iter() {
match stmt {
TopLevel::Function(_, _, _, _) => unimplemented!(),
TopLevel::Function(name, args, _, body) => {
let closure = Value::Closure(
Some(name.clone()),
env.clone(),
args.iter().map(|(x, _)| x.clone()).collect(),
body.clone(),
);
TopLevel::Statement(_) => unimplemented!(),
env.insert(name.clone(), closure.clone());
last_value = closure;
}
TopLevel::Statement(expr) => {
last_value = expr.eval(&env, &mut stdout)?;
}
}
}
Ok(stdout)
Ok((last_value, stdout))
}
}
impl<T> Expression<T>
where
T: Clone + Into<Type>,
T: Clone + Into<Type>,
{
fn eval(&self, env: &EvalEnvironment) -> Result<Value, EvalError> {
fn eval(
&self,
env: &ScopedMap<Variable, IRValue<T>>,
stdout: &mut String,
) -> Result<IRValue<T>, IREvalError<T>> {
match self {
Expression::Atomic(x) => x.eval(env),
@@ -45,7 +67,7 @@ where
let arg_values = args
.iter()
.map(|x| x.eval(env))
.collect::<Result<Vec<Value>, EvalError>>()?;
.collect::<Result<Vec<IRValue<T>>, IREvalError<T>>>()?;
// and then finally we call `calculate` to run them. trust me, it's nice
// to not have to deal with all the nonsense hidden under `calculate`.
@@ -61,15 +83,25 @@ where
unimplemented!()
}
Expression::Print(_, _) => unimplemented!(),
Expression::Print(loc, n) => {
let value = env
.get(n)
.cloned()
.ok_or_else(|| EvalError::LookupFailed(loc.clone(), n.to_string()))?;
stdout.push_str(&format!("{} = {}\n", n, value));
Ok(Value::Void)
}
Expression::Bind(_, _, _, _) => unimplemented!(),
}
}
}
impl<T> ValueOrRef<T> {
fn eval(&self, env: &EvalEnvironment) -> Result<Value, EvalError> {
impl<T: Clone> ValueOrRef<T> {
fn eval(
&self,
env: &ScopedMap<Variable, IRValue<T>>,
) -> Result<IRValue<T>, IREvalError<T>> {
match self {
ValueOrRef::Value(_, _, v) => match v {
super::Value::I8(_, v) => Ok(Value::I8(*v)),
@@ -82,7 +114,10 @@ impl<T> ValueOrRef<T> {
super::Value::U64(_, v) => Ok(Value::U64(*v)),
},
ValueOrRef::Ref(_, _, n) => Ok(env.lookup(n.clone())?),
ValueOrRef::Ref(loc, _, n) => env
.get(n)
.cloned()
.ok_or_else(|| EvalError::LookupFailed(loc.clone(), n.to_string())),
}
}
}
@@ -91,7 +126,7 @@ impl<T> ValueOrRef<T> {
fn two_plus_three() {
let input = crate::syntax::Program::parse(0, "x = 2 + 3; print x;").expect("parse works");
let ir = input.type_infer().expect("test should be type-valid");
let output = ir.eval().expect("runs successfully");
let (_, output) = ir.eval().expect("runs successfully");
assert_eq!("x = 5u64\n", &output);
}
@@ -100,6 +135,6 @@ fn lotsa_math() {
let input =
crate::syntax::Program::parse(0, "x = 2 + 3 * 10 / 5 - 1; print x;").expect("parse works");
let ir = input.type_infer().expect("test should be type-valid");
let output = ir.eval().expect("runs successfully");
let (_, output) = ir.eval().expect("runs successfully");
assert_eq!("x = 7u64\n", &output);
}