summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2014-01-22 01:03:54 -0800
committerKaz Kylheku <kaz@kylheku.com>2014-01-22 01:03:54 -0800
commit8ced687d65438141be8a1305fa4058a76fa3cc59 (patch)
treefc806ca24868f5ce0255668e6440f22ab38d7fa9
parent97865d48b22fd96e75ca216e2dd67850b1c84b2a (diff)
downloadtxr-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--ChangeLog15
-rw-r--r--eval.c48
-rw-r--r--txr.141
3 files changed, 91 insertions, 13 deletions
diff --git a/ChangeLog b/ChangeLog
index 671e8ddd..8b134c00 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/eval.c b/eval.c
index 1562d1be..85233904 100644
--- a/eval.c
+++ b/eval.c
@@ -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);
diff --git a/txr.1 b/txr.1
index b43630fa..8c7683e9 100644
--- a/txr.1
+++ b/txr.1
@@ -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: