variables defined using def in a let statement now escape local scope

test added as well.
This commit is contained in:
Ava Apples Affine 2023-03-17 12:01:43 -07:00
parent 3848d3bcfa
commit 2dfe73de6b
Signed by: affine
GPG key ID: 3A4645B8CF806069
3 changed files with 37 additions and 0 deletions

View file

@ -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())
} }

View file

@ -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)
} }

View file

@ -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'))";