schala/schala-lang/language/src/tree_walk_eval/mod.rs

232 lines
7.2 KiB
Rust
Raw Normal View History

2021-10-24 02:54:21 -07:00
use crate::reduced_ir::{ReducedIR, Expression, Lookup, Function, FunctionDefinition, Statement, Literal};
use crate::symbol_table::{DefId};
use crate::util::ScopeStack;
2021-10-24 06:36:16 -07:00
use crate::builtin::Builtin;
use std::fmt::Write;
use std::convert::From;
type EvalResult<T> = Result<T, String>;
#[derive(Debug)]
pub struct State<'a> {
2021-10-24 02:54:21 -07:00
environments: ScopeStack<'a, Memory, RuntimeValue>,
}
//TODO - eh, I dunno, maybe it doesn't matter exactly how memory works in the tree-walking
//evaluator
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
enum Memory {
Index(u32)
}
impl From<&DefId> for Memory {
fn from(id: &DefId) -> Self {
Self::Index(id.as_u32())
}
}
#[derive(Debug)]
struct RuntimeError {
msg: String
}
impl From<String> for RuntimeError {
fn from(msg: String) -> Self {
Self {
msg
}
}
}
impl RuntimeError {
fn get_msg(&self) -> String {
format!("Runtime error: {}", self.msg)
}
}
fn paren_wrapped(terms: impl Iterator<Item=String>) -> String {
let mut buf = String::new();
write!(buf, "(").unwrap();
for term in terms.map(Some).intersperse(None) {
match term {
Some(e) => write!(buf, "{}", e).unwrap(),
None => write!(buf, ", ").unwrap(),
};
}
write!(buf, ")").unwrap();
buf
}
#[derive(Debug)]
enum RuntimeValue {
2021-10-24 02:54:21 -07:00
Function(FunctionDefinition),
2021-10-24 06:04:58 -07:00
Primitive(Primitive),
}
2021-10-24 06:04:58 -07:00
impl From<Primitive> for RuntimeValue {
fn from(prim: Primitive) -> Self {
Self::Primitive(prim)
}
}
fn expr_to_repl(expr: &Expression) -> String {
match expr {
Expression::Unimplemented => format!("Expression {:?} not implemented", expr),
Expression::Literal(lit) => match lit {
Literal::Nat(n) => format!("{}", n),
Literal::Int(i) => format!("{}", i),
Literal::Float(f) => format!("{}", f),
Literal::Bool(b) => format!("{}", b),
Literal::StringLit(s) => format!("\"{}\"", s),
}
Expression::Tuple(terms) => paren_wrapped(terms.iter().map(|x| expr_to_repl(x))),
Expression::Assign { lval, rval } => {
"".to_string()
},
e => format!("Expression {:?} shouldn't be here", e),
}
}
impl RuntimeValue {
fn to_repl(&self) -> String {
match self {
2021-10-24 06:04:58 -07:00
RuntimeValue::Primitive(ref prim) => expr_to_repl(&prim.to_expr()),
2021-10-24 02:54:21 -07:00
RuntimeValue::Function(ref expr) => "<function>".to_string(),
}
}
}
2021-10-24 06:04:58 -07:00
/// A fully-reduced value
#[derive(Debug, Clone)]
enum Primitive {
Tuple(Vec<Primitive>),
Literal(Literal),
2021-10-24 06:36:16 -07:00
Callable(Function),
2021-10-24 06:04:58 -07:00
Unimplemented,
/*
PrimObject {
name: Rc<String>,
tag: usize,
items: Vec<Node>,
},
*/
}
impl Primitive {
fn to_expr(&self) -> Expression {
match self {
Primitive::Tuple(items) => Expression::Tuple(items.iter().map(|item| item.to_expr()).collect()),
Primitive::Literal(lit) => Expression::Literal(lit.clone()),
2021-10-24 06:36:16 -07:00
Primitive::Callable(function) => Expression::Callable(function.clone()),
2021-10-24 06:04:58 -07:00
Primitive::Unimplemented => Expression::Unimplemented,
}
}
}
impl<'a> State<'a> {
pub fn new() -> Self {
Self {
environments: ScopeStack::new(Some("global".to_string()))
}
}
pub fn evaluate(&mut self, reduced: ReducedIR, repl: bool) -> Vec<Result<String, String>> {
let mut acc = vec![];
2021-10-24 02:54:21 -07:00
for (def_id, function) in reduced.functions.into_iter() {
let mem = (&def_id).into();
self.environments.insert(mem, RuntimeValue::Function(function));
}
for statement in reduced.entrypoint.into_iter() {
match self.statement(statement) {
Ok(Some(output)) if repl => {
acc.push(Ok(output.to_repl()))
},
Ok(_) => (),
Err(error) => {
acc.push(Err(error.into()));
return acc;
}
}
}
acc
}
fn statement(&mut self, stmt: Statement) -> EvalResult<Option<RuntimeValue>> {
match stmt {
2021-10-24 02:54:21 -07:00
Statement::Binding { ref id, expr, constant } => {
println!("eval() binding id: {}", id);
let evaluated = self.expression(expr)?;
2021-10-24 02:54:21 -07:00
self.environments.insert(id.into(), evaluated.into());
Ok(None)
},
Statement::Expression(expr) => {
let evaluated = self.expression(expr)?;
Ok(Some(evaluated.into()))
}
}
}
2021-10-24 06:04:58 -07:00
fn expression(&mut self, expression: Expression) -> EvalResult<Primitive> {
use Expression::Unimplemented;
Ok(match expression {
2021-10-24 06:04:58 -07:00
Expression::Literal(lit) => Primitive::Literal(lit),
Expression::Tuple(items) => Primitive::Tuple(items.into_iter().map(|expr| self.expression(expr)).collect::<EvalResult<Vec<Primitive>>>()?),
2021-10-24 02:54:21 -07:00
Expression::Lookup { ref id, kind } => {
let mem = id.into();
match kind {
2021-10-24 06:36:16 -07:00
Lookup::Function => match self.environments.lookup(&mem) {
//TODO is this right? not sure
Some(RuntimeValue::Primitive(prim)) => prim.clone(),
_ => return Err(format!("Function not found for id: {}", id)),
2021-10-24 02:54:21 -07:00
},
kind @ Lookup::LocalVar | kind @ Lookup::GlobalVar | kind @ Lookup::Param => {
match self.environments.lookup(&mem) {
2021-10-24 06:04:58 -07:00
Some(RuntimeValue::Primitive(expr)) => expr.clone(),
2021-10-24 02:54:21 -07:00
_ => return Err(format!("Nothing found for variable lookup {} of kind {:?}", id, kind)),
}
},
}
},
Expression::Assign { ref lval, box rval } => {
let mem = lval.into();
let mut env = self.environments.lookup(&mem);
2021-10-24 06:04:58 -07:00
Primitive::Unimplemented
},
2021-10-24 02:54:21 -07:00
Expression::Call { box f, args } => self.call_expression(f, args)?,
2021-10-24 06:04:58 -07:00
Unimplemented => Primitive::Unimplemented,
Expression::ReductionError(e) => return Err(e.into()),
2021-10-24 02:54:21 -07:00
e => return Err(format!("Can't yet handle {:?}", e)),
})
}
2021-10-24 06:04:58 -07:00
fn call_expression(&mut self, f: Expression, args: Vec<Expression>) -> EvalResult<Primitive> {
2021-10-24 06:36:16 -07:00
let func = match self.expression(f)? {
Primitive::Callable(func) => func,
other => return Err(format!("Trying to call non-function value: {:?}", other)),
};
match func {
Function::Builtin(builtin) => self.apply_builtin(builtin, args),
Function::UserDefined(def_id) => self.apply_function(def_id, args),
}
}
fn apply_builtin(&mut self, builtin: Builtin, args: Vec<Expression>) -> EvalResult<Primitive> {
return Err("unimplemented apply-builtin".to_string());
}
fn apply_function(&mut self, def_id: DefId, args: Vec<Expression>) -> EvalResult<Primitive> {
let mem = (&def_id).into();
Ok(match self.environments.lookup(&mem) {
Some(RuntimeValue::Function(FunctionDefinition { body })) => {
return Err("unimplemented apply-function".to_string());
},
e => return Err(format!("Error looking up function with id {}: {:?}", def_id, e)),
})
}
}