summaryrefslogtreecommitdiffstats
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
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.
-rw-r--r--ChangeLog9
-rw-r--r--eval.c53
-rw-r--r--txr.129
3 files changed, 75 insertions, 16 deletions
diff --git a/ChangeLog b/ChangeLog
index d0f2c9a9..8dcd1fbd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
2014-02-05 Kaz Kylheku <kaz@kylheku.com>
+ * 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.
+
+2014-02-05 Kaz Kylheku <kaz@kylheku.com>
+
* eval.c (apply): Pass missing optional arguments as colon_k.
to functions for which this is requested.
(reg_fun_mark): New static function.
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"),
diff --git a/txr.1 b/txr.1
index dc88581e..002e9988 100644
--- a/txr.1
+++ b/txr.1
@@ -5920,7 +5920,7 @@ Examples:
.TP
Syntax:
- (defun <name> ({<param> [. <rest-param>]}*) <body-form>*)
+ (defun <name> (<param>* [: <opt-param>*] [. <rest-param>]) <body-form>*)
Description:
@@ -5940,9 +5940,9 @@ A function may call itself by name, allowing for recursion.
.TP
Syntax:
- (lambda ({<sym>}*[. <sym>]) {<body-form>}*)
+ (lambda (<param>* [: <opt-param>*] [. <rest-param>]) {<body-form>}*)
- (lambda <sym> {<body-form>}*)
+ (lambda <rest-param> {<body-form>}*)
.TP
Description:
@@ -5967,14 +5967,21 @@ The dotted notation can be used to write a function that accepts
a variable number of arguments. To write a function that accepts
variable arguments only, with no required arguments, use a single symbol.
-The keyword symbol : (colon) can appear in the parameter list. It is not an
-argument, but a separator between required parameters and optional parameters.
-When the function is called, optional parameter for which arguments are not
-supplied take on the value nil.
-
-An optional parameter can also be written in the form (<name> <expr>).
-In this situation, if the call does not specify a value for the parameter,
-then the parameter takes on the value of the expression <expr>.
+The keyword symbol : (colon) can appear in the parameter list. This is
+the symbol in the keyword package whose name is the empty string. This
+symbol is treated specially: it serves as a separator between
+required parameters and optional parameters. Furthermore, the : symbol
+has a role to play in function calls: it can be specified as an argument
+value to an optional parameter by which the caller indicates that the
+optional argument is not being specified. It will be processed exactly
+that way.
+
+An optional parameter can also be written in the form (<name> <expr> [<sym>]).
+In this situation, if the call does not specify a value for the parameter
+(or specifies a value as the keyword : (colon)) then the parameter takes on the
+value of the expression <expr>. If <sym> is specified, then <sym> will be
+introduced as an additional binding with a boolean value which indicates
+whether or not the optional parameter had been specified by the caller.
The initializer expressions are evaluated an environment in which
all of the previous parameters are visible, in addition to the surrounding