summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-01-24 01:47:59 -0800
committerKaz Kylheku <kaz@kylheku.com>2017-01-24 01:47:59 -0800
commite437089fb74917b1238cc04c6a53a6e7b25a8869 (patch)
tree97b1627e0f02c9655e0c4f1477fc1367e376ba95
parent301534d838d6666e565ef346132d9ae2c20914de (diff)
downloadtxr-e437089fb74917b1238cc04c6a53a6e7b25a8869.tar.gz
txr-e437089fb74917b1238cc04c6a53a6e7b25a8869.tar.bz2
txr-e437089fb74917b1238cc04c6a53a6e7b25a8869.zip
bugfix: wrong macro env across param expansion.
The issue is that optional argument init forms have visibility to prior arguments. However, they are being expanded in the original macro environment which doesn't take into account any preceding variable bindings. This is wrong: the preceding variables must shadow any symbol macros in the outer environment. * eval.c (expand_opt_params_rec, expand_params_rec): Create a var shadowing macro environment for every parameter name (or destructuring parameter list) that is traversed, and use that macro environment to process the remaining parameters. (make_var_shadowing_env): Allow the function to take a single symbol instead of a list of symbols.
-rw-r--r--eval.c32
1 files changed, 22 insertions, 10 deletions
diff --git a/eval.c b/eval.c
index fed5c7ed..e21ec820 100644
--- a/eval.c
+++ b/eval.c
@@ -795,6 +795,10 @@ static val not_bindable_warning(val form, val sym)
car(form), sym, nao);
}
+static val make_var_shadowing_env(val menv, val vars);
+
+static val get_param_syms(val params);
+
static val expand_params_rec(val params, val menv,
val macro_style_p, val form,
val *pspecials);
@@ -814,6 +818,8 @@ static val expand_opt_params_rec(val params, val menv,
} else {
val pair = car(params);
if (atom(pair)) {
+ val new_menv = menv;
+
if (pair == whole_k || pair == form_k || pair == env_k) {
if (!macro_style_p)
eval_error(form, lit("~s: ~s not usable in function parameter list"),
@@ -829,13 +835,15 @@ static val expand_opt_params_rec(val params, val menv,
eval_error(form, lit("~s: multiple colons in parameter list"),
car(form), nao);
not_bindable_error(form, pair);
+ } else {
+ new_menv = make_var_shadowing_env(menv, pair);
}
if (special_var_p(pair))
push(pair, pspecials);
{
- val params_ex = expand_opt_params_rec(cdr(params), menv,
+ val params_ex = expand_opt_params_rec(cdr(params), new_menv,
macro_style_p,
form, pspecials);
@@ -848,15 +856,17 @@ static val expand_opt_params_rec(val params, val menv,
eval_error(form, lit("~s: parameter symbol expected, not ~s"),
car(form), car(pair), nao);
} else {
- val car_ex = expand_params_rec(car(pair), menv,
- macro_style_p,
- form, pspecials);
+ val param = car(pair);
+ val param_ex = expand_params_rec(param, menv,
+ macro_style_p,
+ form, pspecials);
val initform = cadr(pair);
val initform_ex = rlcp(expand(initform, menv), initform);
val opt_sym = caddr(pair);
- val form_ex = rlcp(cons(car_ex, cons(initform_ex,
- cons(opt_sym, nil))),
+ val form_ex = rlcp(cons(param_ex, cons(initform_ex,
+ cons(opt_sym, nil))),
pair);
+ val new_menv = make_var_shadowing_env(menv, get_param_syms(param_ex));
if (cdddr(pair))
eval_error(form, lit("~s: extra forms ~s in ~s"),
@@ -869,7 +879,7 @@ static val expand_opt_params_rec(val params, val menv,
push(opt_sym, pspecials);
}
- return rlcp(cons(form_ex, expand_opt_params_rec(rest(params), menv,
+ return rlcp(cons(form_ex, expand_opt_params_rec(rest(params), new_menv,
macro_style_p, form,
pspecials)),
cdr(params));
@@ -902,6 +912,7 @@ static val expand_params_rec(val params, val menv,
} else {
val param = car(params);
val param_ex;
+ val new_menv = menv;
if (param == whole_k || param == form_k || param == env_k) {
if (!macro_style_p)
@@ -916,10 +927,11 @@ static val expand_params_rec(val params, val menv,
param_ex = param;
} else {
param_ex = expand_params_rec(param, menv, macro_style_p, form, pspecials);
+ new_menv = make_var_shadowing_env(menv, get_param_syms(param_ex));
}
{
- val params_ex = expand_params_rec(cdr(params), menv,
+ val params_ex = expand_params_rec(cdr(params), new_menv,
macro_style_p,
form, pspecials);
if (param_ex == car(params) && params_ex == cdr(params))
@@ -978,8 +990,6 @@ static val expand_params(val params, val body, val menv,
return cons(params_ex, body_out);
}
-static val get_param_syms(val params);
-
static val get_opt_param_syms(val params)
{
if (bindable(params)) {
@@ -1873,6 +1883,8 @@ static val make_var_shadowing_env(val menv, val vars)
{
if (nilp(vars)) {
return menv;
+ } else if (atom(vars)) {
+ return make_env(cons(cons(vars, special_s), nil), nil, menv);
} else {
list_collect_decl (shadows, ptail);