diff options
-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: |