summaryrefslogtreecommitdiffstats
path: root/eval.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2014-02-05 02:34:09 -0800
committerKaz Kylheku <kaz@kylheku.com>2014-02-05 02:34:09 -0800
commit68c084269581f32f0a7b859446ae2efb6c6a26c0 (patch)
treed3e41aecaf7405771fac7579872520bc104c3c6b /eval.c
parentecefd793e54d3cf0a56df705a18deb587d2a19c1 (diff)
downloadtxr-68c084269581f32f0a7b859446ae2efb6c6a26c0.tar.gz
txr-68c084269581f32f0a7b859446ae2efb6c6a26c0.tar.bz2
txr-68c084269581f32f0a7b859446ae2efb6c6a26c0.zip
* eval.c (bind_args): Support optional parameters in the
form (sym initform present-p-sym). Also, support the convention that a value of : explicitly passed for an optional argument produces the same behavior as if that argument value were missing. * txr.1: Document new conventions.
Diffstat (limited to 'eval.c')
-rw-r--r--eval.c53
1 files changed, 48 insertions, 5 deletions
diff --git a/eval.c b/eval.c
index 7c3bb8da..ff6e82ea 100644
--- a/eval.c
+++ b/eval.c
@@ -225,6 +225,8 @@ static val bind_args(val env, val params, val args, val ctx_form)
for (; args && consp(params); args = cdr(args), params = cdr(params)) {
val param = car(params);
+ val initform = nil;
+ val presentsym = nil;
if (param == colon_k) {
if (optargs)
@@ -236,14 +238,41 @@ static val bind_args(val env, val params, val args, val ctx_form)
param = car(params);
}
- if (optargs && consp(param))
- param = car(param);
+ if (optargs && consp(param)) {
+ val sym = pop(&param);
+ initform = pop(&param);
+ presentsym = pop(&param);
+ param = sym;
+ }
if (!bindable(param))
eval_error(ctx_form, lit("~a: ~s is not a bindable symbol"),
car(ctx_form), param, nao);
- env_vbind(new_env, param, car(args));
+ if (presentsym && !bindable(presentsym))
+ eval_error(ctx_form, lit("~a: ~s is not a bindable symbol"),
+ car(ctx_form), presentsym, nao);
+
+ if (optargs) {
+ val arg = car(args);
+ val initval = nil;
+ val present = nil;
+
+ if (arg == colon_k) {
+ if (initform) {
+ initval = eval(initform, new_env, ctx_form);
+ new_env = make_env(nil, nil, new_env);
+ }
+ } else {
+ initval = arg;
+ present = t;
+ }
+ env_vbind(new_env, param, initval);
+ if (presentsym)
+ env_vbind(new_env, presentsym, present);
+ } else {
+ env_vbind(new_env, param, car(args));
+ }
}
if (bindable(params)) {
@@ -262,9 +291,22 @@ static val bind_args(val env, val params, val args, val ctx_form)
if (param == colon_k)
goto twocol;
if (consp(param)) {
- val initval = eval(car(cdr(param)), new_env, ctx_form);
+ val sym = pop(&param);
+ val initform = pop(&param);
+ val presentsym = pop(&param);
+ val initval = eval(initform, new_env, ctx_form);
+ if (!bindable(sym))
+ eval_error(ctx_form, lit("~a: ~s is not a bindable symbol"),
+ car(ctx_form), sym, nao);
+
new_env = make_env(nil, nil, new_env);
- env_vbind(new_env, car(param), initval);
+ env_vbind(new_env, sym, initval);
+ if (presentsym) {
+ if (!bindable(presentsym))
+ eval_error(ctx_form, lit("~a: ~s is not a bindable symbol"),
+ car(ctx_form), presentsym, nao);
+ env_vbind(new_env, presentsym, nil);
+ }
} else {
env_vbind(new_env, param, nil);
}
@@ -279,6 +321,7 @@ static val bind_args(val env, val params, val args, val ctx_form)
eval_error(ctx_form, lit("~s: too many arguments"), car(ctx_form), nao);
}
+
return new_env;
twocol:
eval_error(ctx_form, lit("~a: multiple colons in parameter list"),