Implement mutablility
We'll need it eventually, and it lets me steal lox testsclosure
parent
bc00dbe69e
commit
03fd228c9b
|
@ -5,6 +5,7 @@ use std::rc::Rc;
|
||||||
crate enum Tree {
|
crate enum Tree {
|
||||||
Leaf(Literal),
|
Leaf(Literal),
|
||||||
Define(String, Box<Tree>),
|
Define(String, Box<Tree>),
|
||||||
|
Set(String, Box<Tree>),
|
||||||
If(Box<[Tree; 3]>),
|
If(Box<[Tree; 3]>),
|
||||||
// Its easier to box the lambdas in the parser than the vm, as
|
// Its easier to box the lambdas in the parser than the vm, as
|
||||||
// here we see all of them exactly once
|
// here we see all of them exactly once
|
||||||
|
|
17
src/eval.rs
17
src/eval.rs
|
@ -70,6 +70,11 @@ pub(crate) fn eval(t: &ast::Tree, env: Rc<RefCell<Env>>) -> Result<Value, RTErro
|
||||||
env.borrow_mut().define(name.to_owned(), val);
|
env.borrow_mut().define(name.to_owned(), val);
|
||||||
Value::Trap
|
Value::Trap
|
||||||
}
|
}
|
||||||
|
ast::Tree::Set(name, to) => {
|
||||||
|
let val = eval(to, Rc::clone(&env))?;
|
||||||
|
env.borrow_mut().set(name, val)?;
|
||||||
|
Value::Trap
|
||||||
|
}
|
||||||
ast::Tree::If(box [cond, tcase, fcase]) => {
|
ast::Tree::If(box [cond, tcase, fcase]) => {
|
||||||
let b = eval(cond, Rc::clone(&env))?.as_bool()?;
|
let b = eval(cond, Rc::clone(&env))?.as_bool()?;
|
||||||
let body = if b { tcase } else { fcase };
|
let body = if b { tcase } else { fcase };
|
||||||
|
@ -134,8 +139,20 @@ impl Env {
|
||||||
pub(crate) fn define(&mut self, name: String, val: Value) {
|
pub(crate) fn define(&mut self, name: String, val: Value) {
|
||||||
assert_ne!(val, Value::Trap); // TODO: Better error
|
assert_ne!(val, Value::Trap); // TODO: Better error
|
||||||
|
|
||||||
|
// TODO: Error on previous def
|
||||||
self.vars.insert(name, val);
|
self.vars.insert(name, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
crate fn set(&mut self, name: &str, val: Value) -> Result<(), RTError> {
|
||||||
|
if let Some(loc) = self.vars.get_mut(name) {
|
||||||
|
*loc = val;
|
||||||
|
Ok(())
|
||||||
|
} else if let Some(parent) = &self.enclosing {
|
||||||
|
parent.borrow_mut().set(name, val)
|
||||||
|
} else {
|
||||||
|
err(format!("Tried to `set!` un `define`d var `{}`", name))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn default_env() -> Env {
|
pub(crate) fn default_env() -> Env {
|
||||||
|
|
|
@ -21,6 +21,7 @@ pub(crate) Tree: Tree = {
|
||||||
=> Tree::Define(name, Box::new(Tree::Func(Rc::new(Func{args, body})))),
|
=> Tree::Define(name, Box::new(Tree::Func(Rc::new(Func{args, body})))),
|
||||||
"(" "if" <Tree> <Tree> <Tree> ")" => Tree::If(Box::new([<>])),
|
"(" "if" <Tree> <Tree> <Tree> ")" => Tree::If(Box::new([<>])),
|
||||||
"(" "lambda (" <args:Sym*> ")" <body:Trees> ")" => Tree::Func(Rc::new(Func{<>})),
|
"(" "lambda (" <args:Sym*> ")" <body:Trees> ")" => Tree::Func(Rc::new(Func{<>})),
|
||||||
|
"(" "set!" <Sym> <BTree> ")" => Tree::Set(<>),
|
||||||
Literal => Tree::Leaf(<>),
|
Literal => Tree::Leaf(<>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1217
src/grammar.rs
1217
src/grammar.rs
File diff suppressed because it is too large
Load Diff
|
@ -18,7 +18,7 @@ upstream for this
|
||||||
fn run_pass() {
|
fn run_pass() {
|
||||||
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
|
let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
|
||||||
insta::glob!("test/run-pass/**.scm", |p| {
|
insta::glob!("test/run-pass/**/*.scm", |p| {
|
||||||
let p = PathBuf::from(
|
let p = PathBuf::from(
|
||||||
p.canonicalize()
|
p.canonicalize()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
Loading…
Reference in New Issue