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

181 lines
4.9 KiB
Rust
Raw Normal View History

2021-10-27 10:23:51 -07:00
use std::{convert::From, fmt::Write};
use crate::{
2021-10-27 10:23:51 -07:00
reduced_ir::{Callable, Expression, FunctionDefinition, Literal, ReducedIR},
symbol_table::DefId,
2021-10-27 10:23:51 -07:00
type_inference::{TypeContext, TypeId},
util::ScopeStack,
};
2021-10-27 10:23:51 -07:00
mod evaluator;
2021-10-24 21:54:08 -07:00
mod test;
2021-10-24 22:23:48 -07:00
type EvalResult<T> = Result<T, RuntimeError>;
#[derive(Debug)]
pub struct State<'a> {
environments: ScopeStack<'a, Memory, MemoryValue>,
2021-10-24 02:54:21 -07:00
}
//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),
2021-10-24 02:54:21 -07:00
}
2021-10-24 17:57:56 -07:00
// 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))
}
}
2021-10-24 02:54:21 -07:00
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 }
}
}
2021-10-24 22:23:48 -07:00
impl From<&str> for RuntimeError {
fn from(msg: &str) -> Self {
Self { msg: msg.to_string() }
2021-10-24 22:23:48 -07:00
}
}
impl RuntimeError {
2021-10-24 22:39:11 -07:00
#[allow(dead_code)]
fn get_msg(&self) -> String {
format!("Runtime error: {}", self.msg)
}
}
2021-11-02 21:19:29 -07:00
fn delim_wrapped(lhs: char, rhs: char, terms: impl Iterator<Item = String>) -> String {
let mut buf = String::new();
2021-11-02 21:19:29 -07:00
write!(buf, "{}", lhs).unwrap();
for term in terms.map(Some).intersperse(None) {
match term {
Some(e) => write!(buf, "{}", e).unwrap(),
None => write!(buf, ", ").unwrap(),
};
}
2021-11-02 21:19:29 -07:00
write!(buf, "{}", rhs).unwrap();
buf
}
2021-10-25 19:42:49 -07:00
/// Anything that can be stored in memory; that is, a function definition, or a fully-evaluated
/// program value.
#[derive(Debug)]
2021-10-25 19:09:05 -07:00
enum MemoryValue {
2021-10-24 02:54:21 -07:00
Function(FunctionDefinition),
2021-10-24 06:04:58 -07:00
Primitive(Primitive),
}
2021-10-25 19:09:05 -07:00
impl From<Primitive> for MemoryValue {
2021-10-24 06:04:58 -07:00
fn from(prim: Primitive) -> Self {
Self::Primitive(prim)
}
}
2021-10-25 19:34:05 -07:00
#[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)
}
}
2021-10-24 06:04:58 -07:00
/// A fully-reduced value
#[derive(Debug, Clone)]
enum Primitive {
Tuple(Vec<Primitive>),
2021-11-02 21:19:29 -07:00
List(Vec<Primitive>),
2021-10-24 06:04:58 -07:00
Literal(Literal),
Callable(Callable),
2021-10-29 22:03:34 -07:00
Object { type_id: TypeId, tag: u32, ordered_fields: Option<Vec<String>>, items: Vec<Primitive> },
2021-10-24 06:04:58 -07:00
}
2021-10-24 22:55:12 -07:00
impl Primitive {
fn to_repl(&self, type_context: &TypeContext) -> String {
2021-10-25 19:42:49 -07:00
match self {
2021-10-29 22:03:34 -07:00
Primitive::Object { type_id, items, tag, ordered_fields: _ } if items.is_empty() =>
type_context.variant_local_name(type_id, *tag).unwrap().to_string(),
2021-10-29 22:03:34 -07:00
Primitive::Object { type_id, items, tag, ordered_fields: None } => {
format!(
"{}{}",
type_context.variant_local_name(type_id, *tag).unwrap(),
2021-11-02 21:19:29 -07:00
delim_wrapped('(', ')', items.iter().map(|item| item.to_repl(type_context)))
)
}
2021-10-29 22:03:34 -07:00
Primitive::Object { type_id, items, tag, ordered_fields: Some(fields) } => {
2021-10-30 00:01:59 -07:00
let mut buf = format!("{} {{ ", type_context.variant_local_name(type_id, *tag).unwrap());
2021-10-29 22:03:34 -07:00
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
}
2021-10-25 19:42:49 -07:00
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),
},
2021-11-02 21:19:29 -07:00
Primitive::Tuple(terms) => delim_wrapped('(', ')', terms.iter().map(|x| x.to_repl(type_context))),
Primitive::List(terms) => delim_wrapped('[', ']', terms.iter().map(|x| x.to_repl(type_context))),
2021-10-25 19:42:49 -07:00
Primitive::Callable(..) => "<some-callable>".to_string(),
}
}
2021-10-24 22:55:12 -07:00
fn unit() -> Self {
Primitive::Tuple(vec![])
}
}
2021-10-24 06:54:48 -07:00
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())) }
}
2021-10-27 10:23:51 -07:00
pub fn evaluate(
&mut self,
2021-10-27 10:23:51 -07:00
reduced: ReducedIR,
type_context: &TypeContext,
repl: bool,
) -> Vec<Result<String, String>> {
2021-11-01 01:42:04 -07:00
let mut evaluator = evaluator::Evaluator::new(self, type_context);
2021-10-27 10:23:51 -07:00
evaluator.evaluate(reduced, repl)
}
}