diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2014-01-22 01:03:54 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2014-01-22 01:03:54 -0800 |
commit | 8ced687d65438141be8a1305fa4058a76fa3cc59 (patch) | |
tree | fc806ca24868f5ce0255668e6440f22ab38d7fa9 | |
parent | 97865d48b22fd96e75ca216e2dd67850b1c84b2a (diff) | |
download | txr-8ced687d65438141be8a1305fa4058a76fa3cc59.tar.gz txr-8ced687d65438141be8a1305fa4058a76fa3cc59.tar.bz2 txr-8ced687d65438141be8a1305fa4058a76fa3cc59.zip |
Support function versions of if, and, or so that partial
evaluation like (op or @1 42) or (op if (eq @1 foo) bar xyzzy)
is possible.
* eval.c (do_eval): Change precedence between operator and
function lookup to favor operators. This is important since
there are several operators now which are also functions.
(if_fun, or_fun, and_fun): New static functions.
(eval_init): New functions registered as intrinsics.
* txr.1: Documented that if, and, or exist as both functions
and operators.
-rw-r--r-- | ChangeLog | 15 | ||||
-rw-r--r-- | eval.c | 48 | ||||
-rw-r--r-- | txr.1 | 41 |
3 files changed, 91 insertions, 13 deletions
@@ -1,5 +1,20 @@ 2014-01-22 Kaz Kylheku <kaz@kylheku.com> + Support function versions of if, and, or so that partial + evaluation like (op or @1 42) or (op if (eq @1 foo) bar xyzzy) + is possible. + + * eval.c (do_eval): Change precedence between operator and + function lookup to favor operators. This is important since + there are several operators now which are also functions. + (if_fun, or_fun, and_fun): New static functions. + (eval_init): New functions registered as intrinsics. + + * txr.1: Documented that if, and, or exist as both functions + and operators. + +2014-01-22 Kaz Kylheku <kaz@kylheku.com> + * eval.c (eval_instrinsic): Changed to external linkage. * eval.h (eval_intrinsic): Declared. @@ -463,16 +463,9 @@ static val do_eval(val form, val env, val ctx_form, debug_return (oper); { - val fbinding = lookup_fun(env, oper); - - if (fbinding) { - val args = do_eval_args(rest(form), env, form, lookup); - debug_frame(oper, args, nil, env, nil, nil, nil); - debug_return (apply(cdr(fbinding), args, form)); - debug_end; - } else { - val entry = gethash(op_table, oper); + val entry = gethash(op_table, oper); + if (entry) { if (!entry) { eval_error(form, lit("no such function or operator: ~s"), oper, nao); abort(); @@ -480,6 +473,12 @@ static val do_eval(val form, val env, val ctx_form, opfun_t fp = (opfun_t) cptr_get(entry); debug_return (fp(form, env)); } + } else { + val fbinding = lookup_fun(env, oper); + val args = do_eval_args(rest(form), env, form, lookup); + debug_frame(oper, args, nil, env, nil, nil, nil); + debug_return (apply(cdr(fbinding), args, form)); + debug_end; } } } else { @@ -2191,6 +2190,34 @@ static void reg_var(val sym, val *loc) sethash(top_vb, sym, cobj((mem_t *) cv, cptr_s, &c_var_ops)); } +static val if_fun(val cond, val then, val alt) +{ + return if3(cond, then, alt); +} + +static val or_fun(val vals) +{ + for (; vals != nil; vals = cdr(vals)) { + val item = car(vals); + if (item) + return item; + } + return nil; +} + +static val and_fun(val vals) +{ + val item = t; + + for (; vals != nil; vals = cdr(vals)) { + item = car(vals); + if (!item) + return nil; + } + + return item; +} + void eval_init(void) { protect(&top_vb, &top_fb, &op_table, (val *) 0); @@ -2450,6 +2477,9 @@ void eval_init(void) reg_fun(intern(lit("orf"), user_package), func_n0v(orv)); reg_fun(intern(lit("iff"), user_package), func_n3o(iff, 2)); reg_fun(intern(lit("iffi"), user_package), func_n3o(iffi, 2)); + reg_fun(intern(lit("if"), user_package), func_n3o(if_fun, 2)); + reg_fun(intern(lit("or"), user_package), func_n0v(or_fun)); + reg_fun(intern(lit("and"), user_package), func_n0v(and_fun)); reg_var(intern(lit("*stdout*"), user_package), &std_output); reg_var(intern(lit("*stddebug*"), user_package), &std_debug); @@ -5135,16 +5135,22 @@ If the first form of a group yields nil, then processing continues with the next group, if any. If all form groups yield nil, then the cond form yields nil. This holds in the case that the syntax is empty: (cond) yields nil. -.SS Operator if +.SS Operator/function if .TP Syntax: (if <cond> <t-form> [<e-form>]) + [if <cond> <then> [<else>]] .TP Description: +There exist both an if operator and an if function. A list form with the symbol +if in the fist position is interpreted as an invocation of the if operator. +The function can be accessed using the DWIM bracket notation and in other +ways. + The if operator provides a simple two-way-selective evaluation control. The <cond> form is evaluated. If it yields true then <t-form> is evaluated, and that form's return value becomes the return value of the if. @@ -5152,16 +5158,27 @@ If <cond> yields false, then <e-form> is evaluated and its return value is taken to be that of if. If <e-form> is omitted, then the behavior is as if <e-form> were specified as nil. -.SS Operator and +The if function provides no evaluation control. All of arguments +are evaluated from left to right. If the <cond> argument is true, then it +returns the <then> argument, otherwise it returns the value of the +<else> argument, if present, otherwise it returns nil. + +.SS Operator/function and .TP Syntax: (and {<form>}*) + [and {<arg>]*) .TP Description: +There exist both an and operator and an and function. A list form with the +symbol and in the fist position is interpreted as an invocation of the +operator. The function can be accessed using the DWIM bracket notation and in +other ways. + The and operator provides three functionalities in one. It computes the logical "and" function over several forms. It controls evaluation (a.k.a. "short-circuiting"). It also allows the convenient substitution of an @@ -5174,6 +5191,11 @@ the result of each form. Evaluation stops when all forms are exhausted, or when any of them yields nil. When evaluation stops, the operator yields the return value. +The and function provides no evaluation control; it receives all of its +arguments fully evaluated. If it is given no arguments, it returns t. +If it is given one or more arguments, and any of them are nil, it returns +nil. Otherwise it returns the value of the last argument. + .TP Examples: @@ -5181,17 +5203,23 @@ Examples: (and (> 10 5) (stringp "foo")) -> t (and 1 2 3) -> 3 -.SS Operator or +.SS Operator/function or .TP Syntax: (or {<form>}*) + [or {<arg>}*] .TP Description: -The and operator provides three functionalities in one. It computes the +There exist both an or operator and an or function. A list form with the +symbol or in the fist position is interpreted as an invocation of the +operator. The function can be accessed using the DWIM bracket notation and in +other ways. + +The or operator provides three functionalities in one. It computes the logical "or" function over several forms. It controls evaluation (a.k.a. "short-circuiting"). The behavior of or also provides for a simplified selection of the first non-nil value from a sequence of forms. @@ -5203,6 +5231,11 @@ with the result of each form. Evaluation stops when all forms are exhausted, or when a form yields a true value. When evaluation stops, the operator yields the return value. +The and function provides no evaluation control; it receives all of its +arguments fully evaluated. If it is given no arguments, it returns nil. +If all of its arguments are nil, it also returns nil. Otherwise, it +returns the value of the first non-nil argument. + .TP Examples: |