summaryrefslogtreecommitdiffstats
path: root/eval.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2021-12-23 07:39:34 -0800
committerKaz Kylheku <kaz@kylheku.com>2021-12-23 07:39:34 -0800
commitda6829688c5ff6d294cb6157a84166837c880562 (patch)
treed0b32cfe41d62ac8e95d1b02329e793ca4d0bfe5 /eval.c
parent7eef2749ca3282585e65415712ebb810f2462a01 (diff)
downloadtxr-da6829688c5ff6d294cb6157a84166837c880562.tar.gz
txr-da6829688c5ff6d294cb6157a84166837c880562.tar.bz2
txr-da6829688c5ff6d294cb6157a84166837c880562.zip
eval: fix optional parameter bug from 2014.
This bug affects optional parameters which either have no default expression, or one that is nil. For instance x in (lambda (: (x nil))) or (lambda (: x)). When such a parameter is given the : symbol as an argument, it is not being bound, as if it weren't there. ((lambda (: x) x) :) -> ;; error: unbound variable x This issue is not a regression; it was introduced in the commit which introduced the colon convention to optionals, as well as init expressions and presence-indicating variables, commit 68c084269581f32f0a7b859446ae2efb6c6a26c0 made in February 2014. This might be the first instance of an interpreter bug being found that is not present in the compiler. * eval.c (bind_args): The idea here was that when the argument to an optional the colon keyword symbol, and the optional's initform is nil, we can skip the overhead of calling eval to get that initform's value. Unfortunately, the skip was extended over the code which binds the parameter. Only the eval can be skipped! * tests/012/lambda.tl: New test cases to cover this.
Diffstat (limited to 'eval.c')
-rw-r--r--eval.c7
1 files changed, 3 insertions, 4 deletions
diff --git a/eval.c b/eval.c
index b3a6e869..7517eb8b 100644
--- a/eval.c
+++ b/eval.c
@@ -973,11 +973,10 @@ static val bind_args(val env, val params, struct args *args, val ctx)
val present = nil;
if (arg == colon_k) {
- if (initform) {
+ if (initform)
initval = eval(initform, new_env, ctx);
- new_env = lex_or_dyn_bind_seq(&dyn_env_made, new_env,
- param, initval);
- }
+ new_env = lex_or_dyn_bind_seq(&dyn_env_made, new_env,
+ param, initval);
} else {
lex_or_dyn_bind(&dyn_env_made, new_env, param, arg);
present = t;