variables defined using def in a let statement now escape local scope
test added as well.
This commit is contained in:
parent
3848d3bcfa
commit
2dfe73de6b
3 changed files with 37 additions and 0 deletions
|
|
@ -111,6 +111,7 @@ Since the call to some-func is the final form, its value is returned.";
|
||||||
|
|
||||||
pub fn let_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
pub fn let_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
||||||
let mut localsyms = syms.clone();
|
let mut localsyms = syms.clone();
|
||||||
|
let mut locals = vec![];
|
||||||
let locals_form: &Seg;
|
let locals_form: &Seg;
|
||||||
let eval_forms: &Seg;
|
let eval_forms: &Seg;
|
||||||
if let Ctr::Seg(ref locals_form_list) = *ast.car {
|
if let Ctr::Seg(ref locals_form_list) = *ast.car {
|
||||||
|
|
@ -156,6 +157,7 @@ pub fn let_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
||||||
&Seg::from_mono(Box::new(*var_val_res.unwrap().clone())),
|
&Seg::from_mono(Box::new(*var_val_res.unwrap().clone())),
|
||||||
None),
|
None),
|
||||||
);
|
);
|
||||||
|
locals.push(name.clone());
|
||||||
}
|
}
|
||||||
} else if let Ctr::None = *var_form.car {
|
} else if let Ctr::None = *var_form.car {
|
||||||
// nothing to declare
|
// nothing to declare
|
||||||
|
|
@ -201,6 +203,17 @@ pub fn let_callback(ast: &Seg, syms: &mut SymTable) -> Result<Ctr, String> {
|
||||||
return Err("evaluation failure".to_string());
|
return Err("evaluation failure".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// we need to get any var declared from within the let eval forms
|
||||||
|
// those need to exist in the outside context
|
||||||
|
for i in localsyms.iter() {
|
||||||
|
if !locals.contains(i.0) && !syms.contains_key(i.0) {
|
||||||
|
syms.insert(
|
||||||
|
i.0.clone(),
|
||||||
|
i.1.clone(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok((*result).clone())
|
Ok((*result).clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,10 @@ impl SymTable {
|
||||||
self.0.get(arg)
|
self.0.get(arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn contains_key(&self, arg: &String) -> bool {
|
||||||
|
self.0.contains_key(arg)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn insert(&mut self, k: String, v: Symbol) -> Option<Symbol> {
|
pub fn insert(&mut self, k: String, v: Symbol) -> Option<Symbol> {
|
||||||
self.0.insert(k, v)
|
self.0.insert(k, v)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,26 @@ mod control_lib_tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_let_def_escapes_locals() {
|
||||||
|
let document1 = "(let (
|
||||||
|
(temp 'hello')
|
||||||
|
(temp (concat temp ' ' 'world')))
|
||||||
|
(def global '' temp))";
|
||||||
|
let document2 = "global";
|
||||||
|
let result = "('hello world')";
|
||||||
|
let mut syms = SymTable::new();
|
||||||
|
static_stdlib(&mut syms).unwrap();
|
||||||
|
dynamic_stdlib(&mut syms).unwrap();
|
||||||
|
eval(&lex(&document1.to_string()).unwrap(), &mut syms).unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
*eval(&lex(&document2.to_string()).unwrap(), &mut syms)
|
||||||
|
.unwrap()
|
||||||
|
.to_string(),
|
||||||
|
result.to_string(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_let_multibody_evals() {
|
fn test_let_multibody_evals() {
|
||||||
let document = "(let ((temp '1')) temp (cons () temp '2'))";
|
let document = "(let ((temp '1')) temp (cons () temp '2'))";
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue