mirror of
https://github.com/kanaka/mal.git
synced 2024-09-21 10:37:58 +03:00
4ef4b17cd0
This rewrites the rust implementation to use many new features of the current version of rust. The refactor is much more concise (only 2/3rds the size) and switches to using a lot of the more functional features (iterators, closures, etc) that have been added or improved in rust. Unfortunately, the implementation is a fair bit slower (about 30% on perf3). It's not clear why this is the case but concision and being more idiomatic wins over performance.
85 lines
2.2 KiB
Rust
85 lines
2.2 KiB
Rust
use std::rc::Rc;
|
|
use std::cell::RefCell;
|
|
//use std::collections::HashMap;
|
|
use fnv::FnvHashMap;
|
|
|
|
use types::{MalVal,MalRet,MalErr,error};
|
|
use types::MalVal::{Nil,Sym,List,Vector};
|
|
use types::MalErr::{ErrString};
|
|
|
|
#[derive(Debug)]
|
|
pub struct EnvStruct {
|
|
data: RefCell<FnvHashMap<String,MalVal>>,
|
|
pub outer: Option<Env>,
|
|
}
|
|
|
|
pub type Env = Rc<EnvStruct>;
|
|
|
|
// TODO: it would be nice to use impl here but it doesn't work on
|
|
// a deftype (i.e. Env)
|
|
|
|
pub fn env_new(outer: Option<Env>) -> Env {
|
|
Rc::new(EnvStruct{data: RefCell::new(FnvHashMap::default()), outer: outer})
|
|
}
|
|
|
|
// TODO: mbinds and exprs as & types
|
|
pub fn env_bind(outer: Option<Env>, mbinds: MalVal,
|
|
exprs: Vec<MalVal>) -> Result<Env,MalErr> {
|
|
let env = env_new(outer);
|
|
match mbinds {
|
|
List(binds,_) | Vector(binds,_) => {
|
|
for (i, b) in binds.iter().enumerate() {
|
|
match b {
|
|
Sym(s) if s == "&" => {
|
|
env_set(&env, binds[i+1].clone(), list!(exprs[i..].to_vec()))?;
|
|
break;
|
|
},
|
|
_ => {
|
|
env_set(&env, b.clone(), exprs[i].clone())?;
|
|
},
|
|
}
|
|
}
|
|
Ok(env)
|
|
},
|
|
_ => Err(ErrString("env_bind binds not List/Vector".to_string())),
|
|
}
|
|
}
|
|
|
|
pub fn env_find(env: &Env, key: &str) -> Option<Env> {
|
|
match (env.data.borrow().contains_key(key), env.outer.clone()) {
|
|
(true, _) => Some(env.clone()),
|
|
(false, Some(o)) => env_find(&o, key),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn env_get(env: &Env, key: &MalVal) -> MalRet {
|
|
match key {
|
|
Sym(ref s) => {
|
|
match env_find(env, s) {
|
|
Some(e) => Ok(e.data.borrow().get(s)
|
|
.ok_or(ErrString(format!("'{}' not found", s)))?
|
|
.clone()),
|
|
_ => error(&format!("'{}' not found", s)),
|
|
}
|
|
},
|
|
_ => error("Env.get called with non-Str"),
|
|
}
|
|
}
|
|
|
|
pub fn env_set(env: &Env, key: MalVal, val: MalVal) -> MalRet {
|
|
match key {
|
|
Sym(ref s) => {
|
|
env.data.borrow_mut().insert(s.to_string(), val.clone());
|
|
Ok(val)
|
|
},
|
|
_ => error("Env.set called with non-Str")
|
|
}
|
|
}
|
|
|
|
pub fn env_sets(env: &Env, key: &str, val: MalVal) {
|
|
env.data.borrow_mut().insert(key.to_string(), val);
|
|
}
|
|
|
|
// vim: ts=2:sw=2:expandtab
|