ayin/src/interpret/types.rs
2025-12-17 23:20:26 +02:00

135 lines
3.7 KiB
Rust

//! 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<ast::Error> 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<ast::Ref, ast::Value>);
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<ast::EnvName, Error> {
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<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()))
}
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<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()))
}
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(())
}
}
}