diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2014-01-29 06:58:15 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2014-01-29 06:58:15 -0800 |
commit | ff17df5e47559aa87ffd828c6126a63165805ad2 (patch) | |
tree | 3a0aa3cf65ed8ff39356fd1a8a5eaf78d7dbfefb | |
parent | b8966f0bf73f01e1e380a08e6949ccc9ddd45637 (diff) | |
download | txr-ff17df5e47559aa87ffd828c6126a63165805ad2.tar.gz txr-ff17df5e47559aa87ffd828c6126a63165805ad2.tar.bz2 txr-ff17df5e47559aa87ffd828c6126a63165805ad2.zip |
Default argument initializer scoping rule change, allowing
things like (defun foo (s : (l (length s))) ...).
Default arguments can be initialized by expressions that
refer to the arguments.
* eval.c (bind_args): By means of a local array, defer the evaluation
of optional argument init forms until the lexical environment,
including all the parameters, is captured. Then valuates the forms
in the array, and set the variable values.
* txr.1: Clarify the new scoping rules.
-rw-r--r-- | ChangeLog | 14 | ||||
-rw-r--r-- | eval.c | 25 | ||||
-rw-r--r-- | txr.1 | 24 |
3 files changed, 50 insertions, 13 deletions
@@ -1,3 +1,17 @@ +2014-01-29 Kaz Kylheku <kaz@kylheku.com> + + Default argument initializer scoping rule change, allowing + things like (defun foo (s : (l (length s))) ...). + Default arguments can be initialized by expressions that + refer to the arguments. + + * eval.c (bind_args): By means of a local array, defer the evaluation + of optional argument init forms until the lexical environment, + including all the parameters, is captured. Then valuates the forms + in the array, and set the variable values. + + * txr.1: Clarify the new scoping rules. + 2014-01-28 Kaz Kylheku <kaz@kylheku.com> * eval.c (eval_init): Registered existing make_catenated_stream as @@ -220,8 +220,11 @@ static val lookup_sym_lisp1(val env, val sym) static val bind_args(val env, val params, val args, val ctx_form) { + val opt_init_parm[32]; + val *oi_parm = &opt_init_parm[0], *oi_end = &opt_init_parm[32], *oi_iter; val new_bindings = nil; val optargs = nil; + val new_env; for (; args && consp(params); args = cdr(args), params = cdr(params)) { val param = car(params); @@ -259,15 +262,18 @@ static val bind_args(val env, val params, val args, val ctx_form) eval_error(ctx_form, lit("~s: too few arguments"), car(ctx_form), nao); while (consp(params)) { val param = car(params); - val val = nil; if (param == colon_k) goto twocol; if (consp(param)) { - val = car(cdr(param)); - param = car(param); + if (oi_parm == oi_end) + eval_error(ctx_form, + lit("~s: too many optional args with initializers"), + car(ctx_form), nao); + new_bindings = acons(car(param), car(cdr(param)), new_bindings); + *oi_parm++ = car(new_bindings); + } else { + new_bindings = acons(param, nil, new_bindings); } - new_bindings = acons(param, eval(val, env, ctx_form), - new_bindings); params = cdr(params); } if (bindable(params)) @@ -279,7 +285,14 @@ 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 make_env(new_bindings, nil, env); + new_env = make_env(new_bindings, nil, env); + + for (oi_iter = &opt_init_parm[0]; oi_iter < oi_parm; oi_iter++) { + val initval = eval(cdr(*oi_iter), new_env, ctx_form); + rplacd(*oi_iter, initval); + } + + return new_env; twocol: eval_error(ctx_form, lit("~a: multiple colons in parameter list"), car(ctx_form), nao); @@ -5912,19 +5912,29 @@ 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 : 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. +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 expression is evaluated in the environment in which the lambda -was constructed. -Functions created by lambda capture the surrounding variable bindings. +The initializer expressions are evaluated an environment in which +all of the parameters are visible, which extends the environment in +which the lambda was constructed. For instance: + (let ((default 0)) + (lambda (str : (end (length str)) (counter default)) + (list str end counter))) + +In this lambda, the initializing expression for the optional parameter +end is (length str), and the str variable it refers to is the previous +argument. The initializer for the optional variable counter is +the expression default, and it refers to the binding established +by the surrounding let. This reference is captured as part of the +lambda's lexical closure. .TP Examples: |