//! Types used in the interpreter. use crate::ast; use std::collections::BTreeMap; use std::collections::HashMap; #[derive(PartialEq, Debug, thiserror::Error)] pub enum Error { #[error("Closure generation failed. Duplicate env names: {0:?}")] DuplicateEnvNames(ast::EnvName), #[error("Duplicate names: {0:?}")] DuplicateNames(ast::Name), #[error("Name not found: {0:?}")] NameNotFound(ast::Name), #[error("Field not found: {0:?}")] FieldNotFound(ast::Label), #[error("Env not found: {0:?}")] EnvNotFound(ast::EnvName), #[error("Last statement is not an expression")] LastStatementNotAnExpr, #[error("Not a function {0:?}")] NotAFunction(ast::Expr), #[error("Not a record {0:?}")] NotARecord(ast::Value), #[error("Not a boolean {0:?}")] NotABoolean(ast::Value), #[error("Arguments mismatch")] ArgumentsMismatch, } impl From for Error { fn from(error: ast::Error) -> Error { match error { ast::Error::LabelNotFound(l) => Error::FieldNotFound(l), } } } #[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, variable_namer: Namer, pub variables: Variables, } pub struct Variables(pub HashMap); impl State { pub fn new(name: String) -> State { State { name, env_namer: Namer::new(), envs: Envs(BTreeMap::new()), variable_namer: Namer::new(), variables: Variables(HashMap::new()), } } pub fn generate_env(&mut self, env: Env) -> Result { let env_name = ast::EnvName(format!("{}_{}", self.name, self.env_namer.next())); self.envs.insert(&env_name, env)?; Ok(env_name) } pub fn insert_variable(&mut self, value: ast::Value) -> ast::Ref { let name = ast::Ref(self.variable_namer.next()); self.variables.0.insert(name.clone(), value); name } } #[derive(PartialEq, Debug, Clone)] pub struct Env { env: BTreeMap, 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())) } 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())) } else { Ok(()) } } } #[derive(PartialEq, Debug, Clone)] pub struct Envs(pub BTreeMap); 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())) } 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())) } 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())) } else { Ok(()) } } }