179 lines
4.8 KiB
Rust
179 lines
4.8 KiB
Rust
use std::{convert::From, fmt::Write};
|
|
|
|
use crate::{
|
|
reduced_ir::{Callable, Expression, FunctionDefinition, Literal, ReducedIR},
|
|
symbol_table::DefId,
|
|
type_inference::{TypeContext, TypeId},
|
|
util::ScopeStack,
|
|
};
|
|
|
|
mod evaluator;
|
|
mod test;
|
|
|
|
type EvalResult<T> = Result<T, RuntimeError>;
|
|
|
|
#[derive(Debug)]
|
|
pub struct State<'a> {
|
|
environments: ScopeStack<'a, Memory, MemoryValue>,
|
|
}
|
|
|
|
//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),
|
|
}
|
|
|
|
// This is for function param lookups, and is a hack
|
|
impl From<u8> for Memory {
|
|
fn from(n: u8) -> Self {
|
|
Memory::Index(4_000_000 + (n as 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 From<&str> for RuntimeError {
|
|
fn from(msg: &str) -> Self {
|
|
Self { msg: msg.to_string() }
|
|
}
|
|
}
|
|
|
|
impl RuntimeError {
|
|
#[allow(dead_code)]
|
|
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
|
|
}
|
|
|
|
/// Anything that can be stored in memory; that is, a function definition, or a fully-evaluated
|
|
/// program value.
|
|
#[derive(Debug)]
|
|
enum MemoryValue {
|
|
Function(FunctionDefinition),
|
|
Primitive(Primitive),
|
|
}
|
|
|
|
impl From<Primitive> for MemoryValue {
|
|
fn from(prim: Primitive) -> Self {
|
|
Self::Primitive(prim)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
enum RuntimeValue {
|
|
Expression(Expression),
|
|
Evaluated(Primitive),
|
|
}
|
|
|
|
impl From<Expression> for RuntimeValue {
|
|
fn from(expr: Expression) -> Self {
|
|
Self::Expression(expr)
|
|
}
|
|
}
|
|
|
|
impl From<Primitive> for RuntimeValue {
|
|
fn from(prim: Primitive) -> Self {
|
|
Self::Evaluated(prim)
|
|
}
|
|
}
|
|
|
|
/// A fully-reduced value
|
|
#[derive(Debug, Clone)]
|
|
enum Primitive {
|
|
Tuple(Vec<Primitive>),
|
|
Literal(Literal),
|
|
Callable(Callable),
|
|
Object { type_id: TypeId, tag: u32, ordered_fields: Option<Vec<String>>, items: Vec<Primitive> },
|
|
}
|
|
|
|
impl Primitive {
|
|
fn to_repl(&self, type_context: &TypeContext) -> String {
|
|
match self {
|
|
Primitive::Object { type_id, items, tag, ordered_fields: _ } if items.is_empty() =>
|
|
type_context.variant_local_name(type_id, *tag).unwrap().to_string(),
|
|
Primitive::Object { type_id, items, tag, ordered_fields: None } => {
|
|
format!(
|
|
"{}{}",
|
|
type_context.variant_local_name(type_id, *tag).unwrap(),
|
|
paren_wrapped(items.iter().map(|item| item.to_repl(type_context)))
|
|
)
|
|
}
|
|
Primitive::Object { type_id, items, tag, ordered_fields: Some(fields) } => {
|
|
let mut buf = format!("{} {{ ", type_context.variant_local_name(type_id, *tag).unwrap());
|
|
for item in fields.iter().zip(items.iter()).map(Some).intersperse(None) {
|
|
match item {
|
|
Some((name, val)) => write!(buf, "{}: {}", name, val.to_repl(type_context)).unwrap(),
|
|
None => write!(buf, ", ").unwrap(),
|
|
}
|
|
}
|
|
write!(buf, " }}").unwrap();
|
|
buf
|
|
}
|
|
Primitive::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),
|
|
},
|
|
Primitive::Tuple(terms) => paren_wrapped(terms.iter().map(|x| x.to_repl(type_context))),
|
|
Primitive::Callable(..) => "<some-callable>".to_string(),
|
|
}
|
|
}
|
|
|
|
fn unit() -> Self {
|
|
Primitive::Tuple(vec![])
|
|
}
|
|
}
|
|
|
|
impl From<Literal> for Primitive {
|
|
fn from(lit: Literal) -> Self {
|
|
Primitive::Literal(lit)
|
|
}
|
|
}
|
|
|
|
impl<'a> State<'a> {
|
|
pub fn new() -> Self {
|
|
Self { environments: ScopeStack::new(Some("global".to_string())) }
|
|
}
|
|
|
|
pub fn evaluate(
|
|
&mut self,
|
|
reduced: ReducedIR,
|
|
type_context: &TypeContext,
|
|
repl: bool,
|
|
) -> Vec<Result<String, String>> {
|
|
let mut evaluator = evaluator::Evaluator::new(self, type_context);
|
|
evaluator.evaluate(reduced, repl)
|
|
}
|
|
}
|