From a9e4875f1ebd41b97fe1a6ebfaa4f9408208bb84 Mon Sep 17 00:00:00 2001 From: me Date: Fri, 19 Dec 2025 00:12:50 +0200 Subject: [PATCH] mutable state --- src/ast/helpers.rs | 12 +- src/ast/types.rs | 19 +--- src/interpret/interpret.rs | 97 ++++++++-------- src/interpret/types.rs | 42 ++++--- .../ayin__parser__parser__tests__assign.snap | 44 +++----- ...__parser__parser__tests__full_program.snap | 106 +++++++----------- .../ayin__parser__parser__tests__record.snap | 36 +++--- .../ayin__parser__parser__tests__vector.snap | 48 ++++---- ...__parser__parser__tests__vector_empty.snap | 8 +- 9 files changed, 181 insertions(+), 231 deletions(-) diff --git a/src/ast/helpers.rs b/src/ast/helpers.rs index 5e788a2..5aaed4e 100644 --- a/src/ast/helpers.rs +++ b/src/ast/helpers.rs @@ -12,16 +12,12 @@ pub fn var(str: &str) -> Expr { Expr::Var(name(str)) } -pub fn record(rec: Vec<(&str, Expr)>) -> Value { - Value::Record(Record({ +pub fn record(rec: Vec<(&str, Expr)>) -> Expr { + Expr::Record( rec.into_iter() .map(|(lbl, val)| (Label(lbl.into()), val)) - .collect() - })) -} - -pub fn record_expr(rec: Vec<(&str, Expr)>) -> Expr { - Expr::Value(record(rec)) + .collect(), + ) } pub fn assign(name: &str, expr: Expr) -> Statement { diff --git a/src/ast/types.rs b/src/ast/types.rs index 990a01b..6f180a9 100644 --- a/src/ast/types.rs +++ b/src/ast/types.rs @@ -1,7 +1,6 @@ //! Ast definition for Ayin. use std::collections::BTreeMap; -use std::rc; /// An expression. #[derive(PartialEq, PartialOrd, Debug, Clone)] @@ -135,19 +134,13 @@ impl From<&str> for Expr { } } -impl From> for Value { - fn from(rec: Vec<(&str, Expr)>) -> Value { - Value::Record(Record({ - rec.into_iter() - .map(|(lbl, expr)| (Label(lbl.into()), expr)) - .collect() - })) - } -} - impl From> for Expr { fn from(rec: Vec<(&str, Expr)>) -> Expr { - Expr::Value(rec.into()) + Expr::Record( + rec.into_iter() + .map(|(lbl, expr)| (Label(lbl.into()), expr)) + .collect(), + ) } } @@ -203,7 +196,7 @@ impl From> for Expr { } impl Record { - pub fn get(&self, label: &Label) -> Result<&Expr, Error> { + pub fn get(&self, label: &Label) -> Result<&Ref, Error> { match self.0.get(label) { Some(v) => Ok(v), None => Err(Error::LabelNotFound(label.clone())), diff --git a/src/interpret/interpret.rs b/src/interpret/interpret.rs index b6a7082..921a308 100644 --- a/src/interpret/interpret.rs +++ b/src/interpret/interpret.rs @@ -1,6 +1,7 @@ //! Interpreter for Ayin. use super::types::*; +use std::collections::BTreeMap; use crate::ast; @@ -46,7 +47,7 @@ fn eval_statement( }) => { let mut result = eval_expr(expr_env, state, expr)?; if *mutable { - let reference = state.insert_variable(result); + let reference = state.variables.insert(result); result = ast::Value::Ref(reference); } expr_env.insert(name.clone(), result.clone()); @@ -91,7 +92,7 @@ fn eval_expr(expr_env: &Env, state: &mut State, expr: &ast::Expr) -> Result, Error>(Some(result)) } StatementResult::Return(result) => { - return Ok::, Error>(Some(result)); + Ok::, Error>(Some(result)) } } })? { @@ -101,11 +102,7 @@ fn eval_expr(expr_env: &Env, state: &mut State, expr: &ast::Expr) -> Result match eval_expr(expr_env, state, expr)? { - ast::Value::Record(record) => eval_expr( - expr_env, - state, - &record.get(field).map_err(Error::from)?.clone(), - ), + ast::Value::Record(record) => Ok(state.variables.get(record.get(&field)?).clone()), v => Err(Error::NotARecord(v)), }, ast::Expr::Var(var) => { @@ -140,67 +137,61 @@ fn eval_expr(expr_env: &Env, state: &mut State, expr: &ast::Expr) -> Result Ok(v.clone()), }, ast::Expr::Op { lhs, rhs, op } => match op { - ast::Op::Assign => match &**lhs { - ast::Expr::Var(name) => { + ast::Op::Assign => match eval_expr_shallow(expr_env, state, lhs)? { + ast::Value::Ref(reference) => { let rhs = eval_expr(expr_env, state, rhs)?; - state - .envs - .get_mut(&expr_env.name) - .unwrap() - .insert(name.clone(), rhs); - eval_expr(expr_env, state, &ast::UNIT) - } - - // access via labels - ast::Expr::Access { expr, field } => { - let lhs = eval_expr(expr_env, state, lhs)?; - let rhs = eval_expr(expr_env, state, rhs)?; - if let Some(mut nested_field) = - access_nested_field(expr_env, state, expr, field)? - { - todo!() - } else { - todo!() // error nested field unreachable - } + state.variables.set(reference, rhs.clone()); + Ok(rhs) } _ => todo!(), }, + /* _ => { let _lhs = eval_expr(expr_env, state, lhs)?; let _rhs = eval_expr(expr_env, state, rhs)?; todo!() } + */ }, + ast::Expr::Record(record) => { + let mut map = BTreeMap::new(); + for (field, expr) in record { + let value = eval_expr(expr_env, state, expr)?; + let reference = state.variables.insert(value); + map.insert(field.clone(), reference); + } + Ok(ast::Value::Record(ast::Record(map))) + } + ast::Expr::Vector(vector) => { + let mut vec = Vec::with_capacity(vector.len()); + for expr in vector { + let value = eval_expr(expr_env, state, expr)?; + let reference = state.variables.insert(value); + vec.push(reference); + } + Ok(ast::Value::Vector(ast::Vector(vec))) + } } } -fn access_nested_field( + +fn eval_expr_shallow( expr_env: &Env, - state: &State, + state: &mut State, expr: &ast::Expr, - labels: &[ast::Label], -) -> Result { - let lhs = eval_expr(&expr_env, state, expr)?; - match lhs { - ast::Value::Ref(reference) => { - let mut current_ref = reference.clone(); - let mut current: ast::Value = state.get_variable(&reference); - for label in labels { - match current { - ast::Value::Record(record) => { - if let Some(next) = record.0.get(label) { - current_ref = next; - current = state.get_variable(¤t_ref); - } else { - todo!() - } - } - // vector, closure - _ => todo!(), // unexpected - } +) -> Result { + match expr { + ast::Expr::Var(var) => { + let result = expr_env.get(&var)?; + match result { + ast::Value::Ref(_) => Ok(result.clone()), + v => Err(Error::NotAReference(v.clone())), } - Ok(current_ref) } - _ => todo!(), + ast::Expr::Access { expr, field } => match eval_expr(expr_env, state, expr)? { + ast::Value::Record(record) => Ok(ast::Value::Ref(record.get(&field)?.clone())), + v => Err(Error::NotARecord(v)), + }, + _ => eval_expr(expr_env, state, expr), } } @@ -227,7 +218,7 @@ fn defs_to_env( ), }; if mutable { - let reference = state.insert_variable(closure); + let reference = state.variables.insert(closure); env.insert_nodup(&name, ast::Value::Ref(reference))?; } else { env.insert_nodup(&name, closure)?; diff --git a/src/interpret/types.rs b/src/interpret/types.rs index 417456a..31dc0aa 100644 --- a/src/interpret/types.rs +++ b/src/interpret/types.rs @@ -23,6 +23,8 @@ pub enum Error { NotAFunction(ast::Expr), #[error("Not a record {0:?}")] NotARecord(ast::Value), + #[error("Not a reference {0:?}")] + NotAReference(ast::Value), #[error("Not a boolean {0:?}")] NotABoolean(ast::Value), #[error("Arguments mismatch")] @@ -55,20 +57,40 @@ pub struct State { pub name: String, env_namer: Namer, pub envs: Envs, - variable_namer: Namer, pub variables: Variables, } -pub struct Variables(pub HashMap); +pub struct Variables { + pub vars: HashMap, + 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) -> State { State { name, env_namer: Namer::new(), envs: Envs(BTreeMap::new()), - variable_namer: Namer::new(), - variables: Variables(HashMap::new()), + variables: Variables::new(), } } pub fn generate_env(&mut self, env: Env) -> Result { @@ -76,18 +98,6 @@ impl State { 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(), Rc::new(value)); - name - } - pub fn get_variable<'a>(&'a self, reference: &ast::Ref) -> &'a ast::Value { - self.variables.0.get(reference).unwrap() - } - pub fn set_variable(&mut self, reference: ast::Ref, new_value: ast::Value) { - self.variables.0.insert(reference, new_value) - } } #[derive(PartialEq, Debug, Clone)] diff --git a/src/parser/snapshots/ayin__parser__parser__tests__assign.snap b/src/parser/snapshots/ayin__parser__parser__tests__assign.snap index 6085047..795fc18 100644 --- a/src/parser/snapshots/ayin__parser__parser__tests__assign.snap +++ b/src/parser/snapshots/ayin__parser__parser__tests__assign.snap @@ -10,33 +10,25 @@ Ok( ), ), op: Assign, - rhs: Value( - Vector( - Vector( - [ - Value( - Int( - 2, - ), - ), - Value( - Record( - Record( - { - Label( - "hello", - ): Value( - Int( - 7, - ), - ), - }, - ), - ), - ), - ], + rhs: Vector( + [ + Value( + Int( + 2, + ), ), - ), + Record( + { + Label( + "hello", + ): Value( + Int( + 7, + ), + ), + }, + ), + ], ), }, ) diff --git a/src/parser/snapshots/ayin__parser__parser__tests__full_program.snap b/src/parser/snapshots/ayin__parser__parser__tests__full_program.snap index 07b80cb..b4ce559 100644 --- a/src/parser/snapshots/ayin__parser__parser__tests__full_program.snap +++ b/src/parser/snapshots/ayin__parser__parser__tests__full_program.snap @@ -16,47 +16,35 @@ Ok( [ Return( Some( - Value( - Record( - Record( + Record( + { + Label( + "player", + ): Record( { Label( - "player", - ): Value( - Record( - Record( - { - Label( - "position", - ): Value( - Record( - Record( - { - Label( - "x", - ): Value( - Int( - 10, - ), - ), - Label( - "y", - ): Value( - Int( - 20, - ), - ), - }, - ), - ), - ), - }, + "position", + ): Record( + { + Label( + "x", + ): Value( + Int( + 10, + ), ), - ), + Label( + "y", + ): Value( + Int( + 20, + ), + ), + }, ), }, ), - ), + }, ), ), ), @@ -175,40 +163,32 @@ Ok( [ Return( Some( - Value( - Record( - Record( + Record( + { + Label( + "player", + ): Record( { Label( - "player", - ): Value( - Record( - Record( - { - Label( - "pos", - ): Access { - expr: Access { - expr: Var( - Name( - "state", - ), - ), - field: Label( - "player", - ), - }, - field: Label( - "position", - ), - }, - }, + "pos", + ): Access { + expr: Access { + expr: Var( + Name( + "state", + ), ), + field: Label( + "player", + ), + }, + field: Label( + "position", ), - ), + }, }, ), - ), + }, ), ), ), diff --git a/src/parser/snapshots/ayin__parser__parser__tests__record.snap b/src/parser/snapshots/ayin__parser__parser__tests__record.snap index b6ee964..8d06324 100644 --- a/src/parser/snapshots/ayin__parser__parser__tests__record.snap +++ b/src/parser/snapshots/ayin__parser__parser__tests__record.snap @@ -3,26 +3,22 @@ source: src/parser/parser.rs expression: result --- Ok( - Value( - Record( - Record( - { - Label( - "hello", - ): Value( - Int( - 17, - ), - ), - Label( - "hi", - ): Value( - String( - "cool", - ), - ), - }, + Record( + { + Label( + "hello", + ): Value( + Int( + 17, + ), ), - ), + Label( + "hi", + ): Value( + String( + "cool", + ), + ), + }, ), ) diff --git a/src/parser/snapshots/ayin__parser__parser__tests__vector.snap b/src/parser/snapshots/ayin__parser__parser__tests__vector.snap index c248ed9..a28a958 100644 --- a/src/parser/snapshots/ayin__parser__parser__tests__vector.snap +++ b/src/parser/snapshots/ayin__parser__parser__tests__vector.snap @@ -3,32 +3,28 @@ source: src/parser/parser.rs expression: result --- Ok( - Value( - Vector( - Vector( - [ - Var( - Name( - "x", - ), - ), - Value( - Int( - 1, - ), - ), - Value( - Int( - 2, - ), - ), - Value( - Int( - 3, - ), - ), - ], + Vector( + [ + Var( + Name( + "x", + ), ), - ), + Value( + Int( + 1, + ), + ), + Value( + Int( + 2, + ), + ), + Value( + Int( + 3, + ), + ), + ], ), ) diff --git a/src/parser/snapshots/ayin__parser__parser__tests__vector_empty.snap b/src/parser/snapshots/ayin__parser__parser__tests__vector_empty.snap index fe4ff38..e93ee61 100644 --- a/src/parser/snapshots/ayin__parser__parser__tests__vector_empty.snap +++ b/src/parser/snapshots/ayin__parser__parser__tests__vector_empty.snap @@ -3,11 +3,7 @@ source: src/parser/parser.rs expression: result --- Ok( - Value( - Vector( - Vector( - [], - ), - ), + Vector( + [], ), )