mutable state
This commit is contained in:
parent
9618575f7a
commit
a9e4875f1e
9 changed files with 181 additions and 231 deletions
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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<Vec<(&str, Expr)>> 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<Vec<(&str, Expr)>> 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<Vec<Statement>> 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())),
|
||||
|
|
|
|||
|
|
@ -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<ast:
|
|||
Ok::<Option<ast::Value>, Error>(Some(result))
|
||||
}
|
||||
StatementResult::Return(result) => {
|
||||
return Ok::<Option<ast::Value>, Error>(Some(result));
|
||||
Ok::<Option<ast::Value>, Error>(Some(result))
|
||||
}
|
||||
}
|
||||
})? {
|
||||
|
|
@ -101,11 +102,7 @@ fn eval_expr(expr_env: &Env, state: &mut State, expr: &ast::Expr) -> Result<ast:
|
|||
}
|
||||
}
|
||||
ast::Expr::Access { expr, field } => 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<ast:
|
|||
_ => 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<ast::Ref, Error> {
|
||||
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!()
|
||||
) -> Result<ast::Value, Error> {
|
||||
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())),
|
||||
}
|
||||
}
|
||||
// vector, closure
|
||||
_ => todo!(), // unexpected
|
||||
}
|
||||
}
|
||||
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)?;
|
||||
|
|
|
|||
|
|
@ -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<ast::Ref, ast::Value>);
|
||||
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) -> 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<ast::EnvName, Error> {
|
||||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -10,17 +10,13 @@ Ok(
|
|||
),
|
||||
),
|
||||
op: Assign,
|
||||
rhs: Value(
|
||||
Vector(
|
||||
Vector(
|
||||
rhs: Vector(
|
||||
[
|
||||
Value(
|
||||
Int(
|
||||
2,
|
||||
),
|
||||
),
|
||||
Value(
|
||||
Record(
|
||||
Record(
|
||||
{
|
||||
Label(
|
||||
|
|
@ -32,11 +28,7 @@ Ok(
|
|||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -16,21 +16,15 @@ Ok(
|
|||
[
|
||||
Return(
|
||||
Some(
|
||||
Value(
|
||||
Record(
|
||||
Record(
|
||||
{
|
||||
Label(
|
||||
"player",
|
||||
): Value(
|
||||
Record(
|
||||
Record(
|
||||
): Record(
|
||||
{
|
||||
Label(
|
||||
"position",
|
||||
): Value(
|
||||
Record(
|
||||
Record(
|
||||
): Record(
|
||||
{
|
||||
Label(
|
||||
"x",
|
||||
|
|
@ -48,18 +42,12 @@ Ok(
|
|||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
},
|
||||
|
|
@ -175,15 +163,11 @@ Ok(
|
|||
[
|
||||
Return(
|
||||
Some(
|
||||
Value(
|
||||
Record(
|
||||
Record(
|
||||
{
|
||||
Label(
|
||||
"player",
|
||||
): Value(
|
||||
Record(
|
||||
Record(
|
||||
): Record(
|
||||
{
|
||||
Label(
|
||||
"pos",
|
||||
|
|
@ -204,14 +188,10 @@ Ok(
|
|||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@ source: src/parser/parser.rs
|
|||
expression: result
|
||||
---
|
||||
Ok(
|
||||
Value(
|
||||
Record(
|
||||
Record(
|
||||
{
|
||||
Label(
|
||||
|
|
@ -23,6 +21,4 @@ Ok(
|
|||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@ source: src/parser/parser.rs
|
|||
expression: result
|
||||
---
|
||||
Ok(
|
||||
Value(
|
||||
Vector(
|
||||
Vector(
|
||||
[
|
||||
Var(
|
||||
|
|
@ -29,6 +27,4 @@ Ok(
|
|||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,11 +3,7 @@ source: src/parser/parser.rs
|
|||
expression: result
|
||||
---
|
||||
Ok(
|
||||
Value(
|
||||
Vector(
|
||||
Vector(
|
||||
[],
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue