todo: arbitrary ir
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user