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))
|
Expr::Var(name(str))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn record(rec: Vec<(&str, Expr)>) -> Value {
|
pub fn record(rec: Vec<(&str, Expr)>) -> Expr {
|
||||||
Value::Record(Record({
|
Expr::Record(
|
||||||
rec.into_iter()
|
rec.into_iter()
|
||||||
.map(|(lbl, val)| (Label(lbl.into()), val))
|
.map(|(lbl, val)| (Label(lbl.into()), val))
|
||||||
.collect()
|
.collect(),
|
||||||
}))
|
)
|
||||||
}
|
|
||||||
|
|
||||||
pub fn record_expr(rec: Vec<(&str, Expr)>) -> Expr {
|
|
||||||
Expr::Value(record(rec))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assign(name: &str, expr: Expr) -> Statement {
|
pub fn assign(name: &str, expr: Expr) -> Statement {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
//! Ast definition for Ayin.
|
//! Ast definition for Ayin.
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::rc;
|
|
||||||
|
|
||||||
/// An expression.
|
/// An expression.
|
||||||
#[derive(PartialEq, PartialOrd, Debug, Clone)]
|
#[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 {
|
impl From<Vec<(&str, Expr)>> for Expr {
|
||||||
fn from(rec: Vec<(&str, Expr)>) -> 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 {
|
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) {
|
match self.0.get(label) {
|
||||||
Some(v) => Ok(v),
|
Some(v) => Ok(v),
|
||||||
None => Err(Error::LabelNotFound(label.clone())),
|
None => Err(Error::LabelNotFound(label.clone())),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
//! Interpreter for Ayin.
|
//! Interpreter for Ayin.
|
||||||
|
|
||||||
use super::types::*;
|
use super::types::*;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use crate::ast;
|
use crate::ast;
|
||||||
|
|
||||||
|
|
@ -46,7 +47,7 @@ fn eval_statement(
|
||||||
}) => {
|
}) => {
|
||||||
let mut result = eval_expr(expr_env, state, expr)?;
|
let mut result = eval_expr(expr_env, state, expr)?;
|
||||||
if *mutable {
|
if *mutable {
|
||||||
let reference = state.insert_variable(result);
|
let reference = state.variables.insert(result);
|
||||||
result = ast::Value::Ref(reference);
|
result = ast::Value::Ref(reference);
|
||||||
}
|
}
|
||||||
expr_env.insert(name.clone(), result.clone());
|
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))
|
Ok::<Option<ast::Value>, Error>(Some(result))
|
||||||
}
|
}
|
||||||
StatementResult::Return(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::Expr::Access { expr, field } => match eval_expr(expr_env, state, expr)? {
|
||||||
ast::Value::Record(record) => eval_expr(
|
ast::Value::Record(record) => Ok(state.variables.get(record.get(&field)?).clone()),
|
||||||
expr_env,
|
|
||||||
state,
|
|
||||||
&record.get(field).map_err(Error::from)?.clone(),
|
|
||||||
),
|
|
||||||
v => Err(Error::NotARecord(v)),
|
v => Err(Error::NotARecord(v)),
|
||||||
},
|
},
|
||||||
ast::Expr::Var(var) => {
|
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()),
|
_ => Ok(v.clone()),
|
||||||
},
|
},
|
||||||
ast::Expr::Op { lhs, rhs, op } => match op {
|
ast::Expr::Op { lhs, rhs, op } => match op {
|
||||||
ast::Op::Assign => match &**lhs {
|
ast::Op::Assign => match eval_expr_shallow(expr_env, state, lhs)? {
|
||||||
ast::Expr::Var(name) => {
|
ast::Value::Ref(reference) => {
|
||||||
let rhs = eval_expr(expr_env, state, rhs)?;
|
let rhs = eval_expr(expr_env, state, rhs)?;
|
||||||
state
|
state.variables.set(reference, rhs.clone());
|
||||||
.envs
|
Ok(rhs)
|
||||||
.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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
},
|
},
|
||||||
|
/*
|
||||||
_ => {
|
_ => {
|
||||||
let _lhs = eval_expr(expr_env, state, lhs)?;
|
let _lhs = eval_expr(expr_env, state, lhs)?;
|
||||||
let _rhs = eval_expr(expr_env, state, rhs)?;
|
let _rhs = eval_expr(expr_env, state, rhs)?;
|
||||||
todo!()
|
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,
|
expr_env: &Env,
|
||||||
state: &State,
|
state: &mut State,
|
||||||
expr: &ast::Expr,
|
expr: &ast::Expr,
|
||||||
labels: &[ast::Label],
|
) -> Result<ast::Value, Error> {
|
||||||
) -> Result<ast::Ref, Error> {
|
match expr {
|
||||||
let lhs = eval_expr(&expr_env, state, expr)?;
|
ast::Expr::Var(var) => {
|
||||||
match lhs {
|
let result = expr_env.get(&var)?;
|
||||||
ast::Value::Ref(reference) => {
|
match result {
|
||||||
let mut current_ref = reference.clone();
|
ast::Value::Ref(_) => Ok(result.clone()),
|
||||||
let mut current: ast::Value = state.get_variable(&reference);
|
v => Err(Error::NotAReference(v.clone())),
|
||||||
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
|
ast::Expr::Access { expr, field } => match eval_expr(expr_env, state, expr)? {
|
||||||
_ => todo!(), // unexpected
|
ast::Value::Record(record) => Ok(ast::Value::Ref(record.get(&field)?.clone())),
|
||||||
}
|
v => Err(Error::NotARecord(v)),
|
||||||
}
|
},
|
||||||
Ok(current_ref)
|
_ => eval_expr(expr_env, state, expr),
|
||||||
}
|
|
||||||
_ => todo!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -227,7 +218,7 @@ fn defs_to_env(
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
if mutable {
|
if mutable {
|
||||||
let reference = state.insert_variable(closure);
|
let reference = state.variables.insert(closure);
|
||||||
env.insert_nodup(&name, ast::Value::Ref(reference))?;
|
env.insert_nodup(&name, ast::Value::Ref(reference))?;
|
||||||
} else {
|
} else {
|
||||||
env.insert_nodup(&name, closure)?;
|
env.insert_nodup(&name, closure)?;
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@ pub enum Error {
|
||||||
NotAFunction(ast::Expr),
|
NotAFunction(ast::Expr),
|
||||||
#[error("Not a record {0:?}")]
|
#[error("Not a record {0:?}")]
|
||||||
NotARecord(ast::Value),
|
NotARecord(ast::Value),
|
||||||
|
#[error("Not a reference {0:?}")]
|
||||||
|
NotAReference(ast::Value),
|
||||||
#[error("Not a boolean {0:?}")]
|
#[error("Not a boolean {0:?}")]
|
||||||
NotABoolean(ast::Value),
|
NotABoolean(ast::Value),
|
||||||
#[error("Arguments mismatch")]
|
#[error("Arguments mismatch")]
|
||||||
|
|
@ -55,20 +57,40 @@ pub struct State {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
env_namer: Namer,
|
env_namer: Namer,
|
||||||
pub envs: Envs,
|
pub envs: Envs,
|
||||||
variable_namer: Namer,
|
|
||||||
pub variables: Variables,
|
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 {
|
impl State {
|
||||||
pub fn new(name: String) -> State {
|
pub fn new(name: String) -> State {
|
||||||
State {
|
State {
|
||||||
name,
|
name,
|
||||||
env_namer: Namer::new(),
|
env_namer: Namer::new(),
|
||||||
envs: Envs(BTreeMap::new()),
|
envs: Envs(BTreeMap::new()),
|
||||||
variable_namer: Namer::new(),
|
variables: Variables::new(),
|
||||||
variables: Variables(HashMap::new()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn generate_env(&mut self, env: Env) -> Result<ast::EnvName, Error> {
|
pub fn generate_env(&mut self, env: Env) -> Result<ast::EnvName, Error> {
|
||||||
|
|
@ -76,18 +98,6 @@ impl State {
|
||||||
self.envs.insert(&env_name, env)?;
|
self.envs.insert(&env_name, env)?;
|
||||||
Ok(env_name)
|
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)]
|
#[derive(PartialEq, Debug, Clone)]
|
||||||
|
|
|
||||||
|
|
@ -10,17 +10,13 @@ Ok(
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
op: Assign,
|
op: Assign,
|
||||||
rhs: Value(
|
rhs: Vector(
|
||||||
Vector(
|
|
||||||
Vector(
|
|
||||||
[
|
[
|
||||||
Value(
|
Value(
|
||||||
Int(
|
Int(
|
||||||
2,
|
2,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Value(
|
|
||||||
Record(
|
|
||||||
Record(
|
Record(
|
||||||
{
|
{
|
||||||
Label(
|
Label(
|
||||||
|
|
@ -32,11 +28,7 @@ Ok(
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -16,21 +16,15 @@ Ok(
|
||||||
[
|
[
|
||||||
Return(
|
Return(
|
||||||
Some(
|
Some(
|
||||||
Value(
|
|
||||||
Record(
|
|
||||||
Record(
|
Record(
|
||||||
{
|
{
|
||||||
Label(
|
Label(
|
||||||
"player",
|
"player",
|
||||||
): Value(
|
): Record(
|
||||||
Record(
|
|
||||||
Record(
|
|
||||||
{
|
{
|
||||||
Label(
|
Label(
|
||||||
"position",
|
"position",
|
||||||
): Value(
|
): Record(
|
||||||
Record(
|
|
||||||
Record(
|
|
||||||
{
|
{
|
||||||
Label(
|
Label(
|
||||||
"x",
|
"x",
|
||||||
|
|
@ -48,18 +42,12 @@ Ok(
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
@ -175,15 +163,11 @@ Ok(
|
||||||
[
|
[
|
||||||
Return(
|
Return(
|
||||||
Some(
|
Some(
|
||||||
Value(
|
|
||||||
Record(
|
|
||||||
Record(
|
Record(
|
||||||
{
|
{
|
||||||
Label(
|
Label(
|
||||||
"player",
|
"player",
|
||||||
): Value(
|
): Record(
|
||||||
Record(
|
|
||||||
Record(
|
|
||||||
{
|
{
|
||||||
Label(
|
Label(
|
||||||
"pos",
|
"pos",
|
||||||
|
|
@ -204,14 +188,10 @@ Ok(
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@ source: src/parser/parser.rs
|
||||||
expression: result
|
expression: result
|
||||||
---
|
---
|
||||||
Ok(
|
Ok(
|
||||||
Value(
|
|
||||||
Record(
|
|
||||||
Record(
|
Record(
|
||||||
{
|
{
|
||||||
Label(
|
Label(
|
||||||
|
|
@ -23,6 +21,4 @@ Ok(
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@ source: src/parser/parser.rs
|
||||||
expression: result
|
expression: result
|
||||||
---
|
---
|
||||||
Ok(
|
Ok(
|
||||||
Value(
|
|
||||||
Vector(
|
|
||||||
Vector(
|
Vector(
|
||||||
[
|
[
|
||||||
Var(
|
Var(
|
||||||
|
|
@ -29,6 +27,4 @@ Ok(
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -3,11 +3,7 @@ source: src/parser/parser.rs
|
||||||
expression: result
|
expression: result
|
||||||
---
|
---
|
||||||
Ok(
|
Ok(
|
||||||
Value(
|
|
||||||
Vector(
|
|
||||||
Vector(
|
Vector(
|
||||||
[],
|
[],
|
||||||
),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue