diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2017-01-24 01:47:59 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2017-01-24 01:47:59 -0800 |
commit | 71bd153f6efd3cc3157bb9dbdf55c97b6e0ad2f5 (patch) | |
tree | 97b1627e0f02c9655e0c4f1477fc1367e376ba95 | |
parent | 2f4e1ba3ba68c2b5c0f92778352866d6ed9959b0 (diff) | |
download | txr-71bd153f6efd3cc3157bb9dbdf55c97b6e0ad2f5.tar.gz txr-71bd153f6efd3cc3157bb9dbdf55c97b6e0ad2f5.tar.bz2 txr-71bd153f6efd3cc3157bb9dbdf55c97b6e0ad2f5.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.c | 32 |
1 files changed, 22 insertions, 10 deletions
@@ -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); |