208 lines
6.7 KiB
Rust
208 lines
6.7 KiB
Rust
//! Types used in the interpreter.
|
|
|
|
use crate::ast;
|
|
use std::backtrace::Backtrace;
|
|
use std::collections::BTreeMap;
|
|
use std::collections::HashMap;
|
|
|
|
#[derive(Debug)]
|
|
pub enum Error {
|
|
DuplicateEnvNames(ast::EnvName, Backtrace),
|
|
DuplicateNames(ast::Name, Backtrace),
|
|
NameNotFound(ast::Name, Backtrace),
|
|
FieldNotFound(ast::Label, Backtrace),
|
|
EnvNotFound(ast::EnvName, Backtrace),
|
|
LastStatementNotAnExpr(Backtrace),
|
|
NotAFunction(ast::Expr, Backtrace),
|
|
NotARecord(ast::Value, Backtrace),
|
|
NotAReference(ast::Value, Backtrace),
|
|
NotABoolean(ast::Value, Backtrace),
|
|
ArgumentsMismatch(Backtrace),
|
|
}
|
|
impl PartialEq for Error {
|
|
fn eq(&self, other: &Self) -> bool {
|
|
match (self, other) {
|
|
(Error::DuplicateEnvNames(a1, _), Error::DuplicateEnvNames(a2, _)) => a1 == a2,
|
|
(Error::DuplicateNames(a1, _), Error::DuplicateNames(a2, _)) => a1 == a2,
|
|
(Error::NameNotFound(a1, _), Error::NameNotFound(a2, _)) => a1 == a2,
|
|
(Error::FieldNotFound(a1, _), Error::FieldNotFound(a2, _)) => a1 == a2,
|
|
(Error::EnvNotFound(a1, _), Error::EnvNotFound(a2, _)) => a1 == a2,
|
|
(Error::LastStatementNotAnExpr(_), Error::LastStatementNotAnExpr(_)) => true,
|
|
|
|
(Error::NotAFunction(a1, _), Error::NotAFunction(a2, _)) => a1 == a2,
|
|
(Error::NotARecord(a1, _), Error::NotARecord(a2, _)) => a1 == a2,
|
|
(Error::NotAReference(a1, _), Error::NotAReference(a2, _)) => a1 == a2,
|
|
(Error::NotABoolean(a1, _), Error::NotABoolean(a2, _)) => a1 == a2,
|
|
(Error::ArgumentsMismatch(_), Error::ArgumentsMismatch(_)) => true,
|
|
_ => false,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for Error {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
Error::DuplicateEnvNames(a, b) => {
|
|
write!(
|
|
f,
|
|
"Closure generation failed. Duplicate env names: {a:?}\n{b}"
|
|
)
|
|
}
|
|
Error::DuplicateNames(a, b) => write!(f, "Duplicate names: {a:?}\n{b}"),
|
|
Error::NameNotFound(a, b) => write!(f, "Name not found: {a:?}\n{b}"),
|
|
Error::FieldNotFound(a, b) => write!(f, "Field not found: {a:?}\n{b}"),
|
|
Error::EnvNotFound(a, b) => write!(f, "Env not found: {a:?}\n{b}"),
|
|
Error::LastStatementNotAnExpr(a) => {
|
|
write!(f, "Last statement is not an expression\n{a}")
|
|
}
|
|
Error::NotAFunction(a, b) => write!(f, "Not a function {a:?}\n{b}"),
|
|
Error::NotARecord(a, b) => write!(f, "Not a record {a:?}\n{b}"),
|
|
Error::NotAReference(a, b) => write!(f, "Not a reference {a:?}\n{b}"),
|
|
Error::NotABoolean(a, b) => write!(f, "Not a boolean {a:?}\n{b}"),
|
|
Error::ArgumentsMismatch(a) => write!(f, "Arguments mismatch\n{a}"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<ast::Error> for Error {
|
|
fn from(error: ast::Error) -> Error {
|
|
match error {
|
|
ast::Error::LabelNotFound(l) => Error::FieldNotFound(l, Backtrace::capture()),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(PartialEq, Debug, Clone)]
|
|
struct Namer {
|
|
counter: u64,
|
|
}
|
|
impl Namer {
|
|
fn new() -> Namer {
|
|
Namer { counter: 0 }
|
|
}
|
|
pub fn next(&mut self) -> u64 {
|
|
self.counter += 1;
|
|
self.counter
|
|
}
|
|
}
|
|
|
|
pub struct State {
|
|
pub name: String,
|
|
env_namer: Namer,
|
|
pub envs: Envs,
|
|
pub variables: Variables,
|
|
pub primitive_funcs: PrimitiveFuncs,
|
|
}
|
|
|
|
pub struct PrimitiveFuncs {
|
|
pub map: HashMap<ast::Name, PrimFunc>,
|
|
}
|
|
|
|
pub type PrimFunc = fn(Vec<ast::Value>) -> ast::Value;
|
|
|
|
impl PrimitiveFuncs {
|
|
pub fn new(prims: Vec<(&str, PrimFunc)>) -> Self {
|
|
let mut map: HashMap<ast::Name, PrimFunc> = HashMap::new();
|
|
for (key, func) in prims.into_iter() {
|
|
map.insert(key.into(), func);
|
|
}
|
|
PrimitiveFuncs { map }
|
|
}
|
|
pub fn get(&self, name: &ast::Name) -> Option<&PrimFunc> {
|
|
self.map.get(name)
|
|
}
|
|
}
|
|
|
|
pub struct Variables {
|
|
pub vars: HashMap<ast::Ref, ast::Value>,
|
|
namer: Namer,
|
|
}
|
|
|
|
impl Variables {
|
|
pub fn new() -> Self {
|
|
Variables {
|
|
vars: HashMap::new(),
|
|
namer: Namer::new(),
|
|
}
|
|
}
|
|
pub fn insert(&mut self, value: ast::Value) -> ast::Ref {
|
|
let name = ast::Ref(self.namer.next());
|
|
self.vars.insert(name.clone(), value);
|
|
name
|
|
}
|
|
pub fn get<'a>(&'a self, reference: &ast::Ref) -> &'a ast::Value {
|
|
self.vars.get(reference).unwrap()
|
|
}
|
|
pub fn set(&mut self, reference: ast::Ref, new_value: ast::Value) {
|
|
self.vars.insert(reference, new_value);
|
|
}
|
|
}
|
|
impl State {
|
|
pub fn new(name: String, primitive_funcs: PrimitiveFuncs) -> State {
|
|
State {
|
|
name,
|
|
env_namer: Namer::new(),
|
|
envs: Envs(BTreeMap::new()),
|
|
variables: Variables::new(),
|
|
primitive_funcs,
|
|
}
|
|
}
|
|
pub fn generate_env(&mut self, env: Env) -> Result<ast::EnvName, Error> {
|
|
let env_name = ast::EnvName(format!("{}_{}", self.name, self.env_namer.next()));
|
|
self.envs.insert(&env_name, env)?;
|
|
Ok(env_name)
|
|
}
|
|
}
|
|
|
|
#[derive(PartialEq, Debug, Clone)]
|
|
pub struct Env {
|
|
env: BTreeMap<ast::Name, ast::Value>,
|
|
pub name: ast::EnvName,
|
|
}
|
|
|
|
impl Env {
|
|
pub fn new(name: ast::EnvName) -> Env {
|
|
Env {
|
|
env: BTreeMap::new(),
|
|
name,
|
|
}
|
|
}
|
|
pub fn get(&self, name: &ast::Name) -> Result<&ast::Value, Error> {
|
|
self.env
|
|
.get(name)
|
|
.ok_or(Error::NameNotFound(name.clone(), Backtrace::capture()))
|
|
}
|
|
pub fn insert(&mut self, name: ast::Name, value: ast::Value) {
|
|
self.env.insert(name.clone(), value);
|
|
}
|
|
pub fn insert_nodup(&mut self, name: &ast::Name, value: ast::Value) -> Result<(), Error> {
|
|
if self.env.insert(name.clone(), value).is_some() {
|
|
Err(Error::DuplicateNames(name.clone(), Backtrace::capture()))
|
|
} else {
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(PartialEq, Debug, Clone)]
|
|
pub struct Envs(pub BTreeMap<ast::EnvName, Env>);
|
|
|
|
impl Envs {
|
|
pub fn get(&self, env_name: &ast::EnvName) -> Result<&Env, Error> {
|
|
self.0
|
|
.get(env_name)
|
|
.ok_or(Error::EnvNotFound(env_name.clone(), Backtrace::capture()))
|
|
}
|
|
pub fn get_mut(&mut self, env_name: &ast::EnvName) -> Result<&mut Env, Error> {
|
|
self.0
|
|
.get_mut(env_name)
|
|
.ok_or(Error::EnvNotFound(env_name.clone(), Backtrace::capture()))
|
|
}
|
|
pub fn insert(&mut self, name: &ast::EnvName, env: Env) -> Result<(), Error> {
|
|
if self.0.insert(name.clone(), env).is_some() {
|
|
Err(Error::DuplicateEnvNames(name.clone(), Backtrace::capture()))
|
|
} else {
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|