summaryrefslogtreecommitdiffstats
path: root/eval.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2019-11-14 07:13:03 -0800
committerKaz Kylheku <kaz@kylheku.com>2019-11-18 14:26:19 -0800
commitc0dd2645afdc2aac8bfb6f331a7d9344c4982c15 (patch)
treec8f1ed07bab540f6548cc9a822eab5f6599a99dd /eval.c
parent57867881e31273f91c398b55f75417484f11ddc0 (diff)
downloadtxr-c0dd2645afdc2aac8bfb6f331a7d9344c4982c15.tar.gz
txr-c0dd2645afdc2aac8bfb6f331a7d9344c4982c15.tar.bz2
txr-c0dd2645afdc2aac8bfb6f331a7d9344c4982c15.zip
eval: bugfix: expansion wrongly always in null env.
The eval function uses a null macro environment for expanding a form, even when it's given an environment object. This causes spurious warnings about unbound variables/functions. For instance: (let ((env (make-env '((x . 42)) nil nil))) (eval '(+ x x) env)) ;; warning: unbound variable x To fix this, we have to create a macro version of the incoming environment and expand with that. * eval.c (env_to_menv): Take an evaluation environment chain and convert it to a (flattened) macro environment. (expand_eval): Take a macro environment parameter and use that for expanding the form to be evaluated, rather than nil. (eval_intrinsic): Calculate a macro environment corresponding to the given evaluation environment. Use that for the macroexpand call, and also pass it down to expand_eval to be used for the full expansion.
Diffstat (limited to 'eval.c')
-rw-r--r--eval.c39
1 files changed, 34 insertions, 5 deletions
diff --git a/eval.c b/eval.c
index 84f1dc41..58b745fd 100644
--- a/eval.c
+++ b/eval.c
@@ -232,6 +232,34 @@ static void env_vb_to_fb(val env)
}
}
+static val env_to_menv(val env, val self, val menv)
+{
+ if (env == nil) {
+ return menv;
+ } else {
+ val iter;
+ type_check(self, env, ENV);
+
+ if (!menv)
+ menv = make_env(nil, nil, nil);
+
+ if (env->e.up_env)
+ menv = env_to_menv(env->e.up_env, self, menv);
+
+ for (iter = env->e.vbindings; iter; iter = cdr(iter)) {
+ val binding = car(iter);
+ env_vbind(menv, car(binding), special_s);
+ }
+
+ for (iter = env->e.fbindings; iter; iter = cdr(iter)) {
+ val binding = car(iter);
+ env_fbind(menv, car(binding), special_s);
+ }
+
+ return menv;
+ }
+}
+
val ctx_form(val obj)
{
if (consp(obj))
@@ -1434,11 +1462,11 @@ val funcall_interp(val interp_fun, struct args *args)
return ret;
}
-static val expand_eval(val form, val env)
+static val expand_eval(val form, val env, val menv)
{
val lfe_save = last_form_evaled;
val form_ex = (last_form_evaled = nil,
- expand(form, nil));
+ expand(form, menv));
val loading = cdr(lookup_var(dyn_env, load_recursive_s));
val ret = ((void) (loading || uw_release_deferred_warnings()),
eval(form_ex, default_null_arg(env), form));
@@ -1450,7 +1478,8 @@ static val macroexpand(val form, val menv);
val eval_intrinsic(val form, val env)
{
- val form_ex = macroexpand(form, nil);
+ val menv = env_to_menv(default_null_arg(env), lit("eval"), nil);
+ val form_ex = macroexpand(form, menv);
val op;
if (consp(form_ex) &&
@@ -1460,14 +1489,14 @@ val eval_intrinsic(val form, val env)
val res = nil, next = cdr(form_ex);
while (next) {
- res = expand_eval(car(next), env);
+ res = expand_eval(car(next), env, menv);
next = cdr(next);
}
return res;
}
- return expand_eval(form_ex, env);
+ return expand_eval(form_ex, env, menv);
}
val eval_intrinsic_noerr(val form, val env, val *error_p)