summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2018-05-03 20:40:10 -0700
committerKaz Kylheku <kaz@kylheku.com>2018-05-03 20:40:10 -0700
commitad23b416cbd93e49f6fdc0c096c2b309448ef1c2 (patch)
tree5a8a043b05becf73ca7484f7d17281016679c8e7
parent6eadc61ddd50207b582a1bcf2b4a9def30104b7a (diff)
downloadtxr-ad23b416cbd93e49f6fdc0c096c2b309448ef1c2.tar.gz
txr-ad23b416cbd93e49f6fdc0c096c2b309448ef1c2.tar.bz2
txr-ad23b416cbd93e49f6fdc0c096c2b309448ef1c2.zip
bugfix: interpreted destructuring doesn't do specials.
It looks like I neglected to treat dynamically scoped variables in destructuring; all parameters are treated as lexical. This is only true in interpreted code; compiled destructuring treats dynamics properly because it generates a let to bind all the variables which occur, and then uses assignment to populate them. * eval.c (bind_macro_params): Instead of env_vbind, use the newly introduced lex_or_dyn_bind helper function. (op_tree_bind, op_mac_param_bind): Save and restore dyn_env around bind_macro_params and the evaluation of the associated body. In op_defmacro, this is already done.
-rw-r--r--eval.c26
1 files changed, 18 insertions, 8 deletions
diff --git a/eval.c b/eval.c
index 45c5ced2..98d8cfdf 100644
--- a/eval.c
+++ b/eval.c
@@ -1207,6 +1207,7 @@ static val bind_macro_params(val env, val menv, val params, val form,
val loose_p, val ctx_form)
{
val new_env = make_env(nil, nil, env);
+ val dyn_env_made = nil;
val whole = form;
val optargs = nil;
uw_frame_t uw_cc;
@@ -1228,7 +1229,7 @@ static val bind_macro_params(val env, val menv, val params, val form,
nparam = car(next);
if (atom(nparam)) {
- env_vbind(new_env, nparam, bform);
+ lex_or_dyn_bind(&dyn_env_made, new_env, nparam, bform);
} else {
new_env = bind_macro_params(new_env, menv,
nparam, bform,
@@ -1253,7 +1254,7 @@ static val bind_macro_params(val env, val menv, val params, val form,
}
if (!listp(param)) {
- env_vbind(new_env, param, car(form));
+ lex_or_dyn_bind(&dyn_env_made, new_env, param, car(form));
} else {
if (optargs) {
val nparam = pop(&param);
@@ -1266,7 +1267,7 @@ static val bind_macro_params(val env, val menv, val params, val form,
nparam, car(form), t, ctx_form);
if (presentsym)
- env_vbind(new_env, presentsym, t);
+ lex_or_dyn_bind(&dyn_env_made, new_env, presentsym, t);
} else {
new_env = bind_macro_params(new_env, menv,
param, car(form),
@@ -1297,7 +1298,7 @@ static val bind_macro_params(val env, val menv, val params, val form,
noarg:
if (!listp(param)) {
- env_vbind(new_env, param, nil);
+ lex_or_dyn_bind(&dyn_env_made, new_env, param, nil);
} else {
val nparam = pop(&param);
val initform = pop(&param);
@@ -1313,14 +1314,14 @@ noarg:
}
if (presentsym)
- env_vbind(new_env, presentsym, nil);
+ lex_or_dyn_bind(&dyn_env_made, new_env, presentsym, nil);
}
params = cdr(params);
}
if (params) {
- env_vbind(new_env, params, form);
+ lex_or_dyn_bind(&dyn_env_made, new_env, params, form);
goto out;
}
@@ -2156,13 +2157,16 @@ static val op_tree_case(val form, val env)
for (; consp(cases); cases = cdr(cases)) {
val onecase = car(cases);
cons_bind (params, forms, onecase);
+ val saved_de = dyn_env;
val new_env = bind_macro_params(env, nil, params, expr_val,
colon_k, onecase);
if (new_env) {
val ret = eval_progn(forms, new_env, forms);
+ dyn_env = saved_de;
if (ret != colon_k)
return ret;
}
+ dyn_env = saved_de;
}
return nil;
@@ -2218,8 +2222,11 @@ static val op_tree_bind(val form, val env)
val expr = third(form);
val body = rest(rest(rest(form)));
val expr_val = eval(expr, env, expr);
+ val saved_de = dyn_env;
val new_env = bind_macro_params(env, nil, params, expr_val, nil, form);
- return eval_progn(body, new_env, body);
+ val ret = eval_progn(body, new_env, body);
+ dyn_env = saved_de;
+ return ret;
}
static val op_mac_param_bind(val form, val env)
@@ -2230,8 +2237,11 @@ static val op_mac_param_bind(val form, val env)
val expr = pop(&body);
val ctx_val = eval(ctx_form, env, ctx_form);
val expr_val = eval(expr, env, expr);
+ val saved_de = dyn_env;
val new_env = bind_macro_params(env, nil, params, expr_val, nil, ctx_val);
- return eval_progn(body, new_env, body);
+ val ret = eval_progn(body, new_env, body);
+ dyn_env = saved_de;
+ return ret;
}
static val op_setq(val form, val env)