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> {
|
||||
let mut localsyms = syms.clone();
|
||||
let mut locals = vec![];
|
||||
let locals_form: &Seg;
|
||||
let eval_forms: &Seg;
|
||||
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())),
|
||||
None),
|
||||
);
|
||||
locals.push(name.clone());
|
||||
}
|
||||
} else if let Ctr::None = *var_form.car {
|
||||
// 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());
|
||||
}
|
||||
|
||||
// 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())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -79,6 +79,10 @@ impl SymTable {
|
|||
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> {
|
||||
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]
|
||||
fn test_let_multibody_evals() {
|
||||
let document = "(let ((temp '1')) temp (cons () temp '2'))";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue