summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2014-03-23 02:09:05 -0700
committerKaz Kylheku <kaz@kylheku.com>2014-03-23 02:09:05 -0700
commitf456fef7fb28cfa3ed5872b778219e5dc02c442b (patch)
tree7a06683073ba89522f162cc3fa49f143141d2b4e
parent93e2bea59699815979259cc2b2d8adffcc852ec9 (diff)
downloadtxr-f456fef7fb28cfa3ed5872b778219e5dc02c442b.tar.gz
txr-f456fef7fb28cfa3ed5872b778219e5dc02c442b.tar.bz2
txr-f456fef7fb28cfa3ed5872b778219e5dc02c442b.zip
* eval.c (not_s): New symbol var.
(me_unless, me_while, m_until): New static functions. (eval_init): Register macros unless, while and until. * txr.1: Document unless, while and until.
-rw-r--r--ChangeLog8
-rw-r--r--eval.c29
-rw-r--r--txr.140
3 files changed, 72 insertions, 5 deletions
diff --git a/ChangeLog b/ChangeLog
index 0254802f..1f72f094 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2014-03-23 Kaz Kylheku <kaz@kylheku.com>
+
+ * eval.c (not_s): New symbol var.
+ (me_unless, me_while, m_until): New static functions.
+ (eval_init): Register macros unless, while and until.
+
+ * txr.1: Document unless, while and until.
+
2014-03-22 Kaz Kylheku <kaz@kylheku.com>
Version 87
diff --git a/eval.c b/eval.c
index ba287c5c..3d4ca301 100644
--- a/eval.c
+++ b/eval.c
@@ -73,7 +73,7 @@ val dyn_env;
val eval_error_s;
val dwim_s, progn_s, prog1_s, let_s, let_star_s, lambda_s, call_s;
val cond_s, if_s, defvar_s, defun_s, defmacro_s, tree_case_s, tree_bind_s;
-val inc_s, dec_s, push_s, pop_s, flip_s, gethash_s, car_s, cdr_s;
+val inc_s, dec_s, push_s, pop_s, flip_s, gethash_s, car_s, cdr_s, not_s;
val del_s, vecref_s;
val for_s, for_star_s, each_s, each_star_s, collect_each_s, collect_each_star_s;
val append_each_s, append_each_star_s;
@@ -2027,6 +2027,27 @@ static val me_when(val form, val menv)
return cons(cond_s, cons(rest(form), nil));
}
+static val me_unless(val form, val menv)
+{
+ (void) menv;
+ return list(if_s, second(form), nil, cons(progn_s, rest(rest(form))), nao);
+}
+
+static val me_while(val form, val menv)
+{
+ (void) menv;
+ return apply_frob_args(list(for_s, nil, cons(second(form), nil), nil,
+ rest(rest(form)), nao));
+}
+
+static val me_until(val form, val menv)
+{
+ val inv = cons(not_s, cons(second(form), nil));
+ (void) menv;
+ return apply_frob_args(list(for_s, nil, cons(inv, nil), nil,
+ rest(rest(form)), nao));
+}
+
val expand_forms(val form, val menv)
{
if (atom(form)) {
@@ -3104,6 +3125,7 @@ void eval_init(void)
gethash_s = intern(lit("gethash"), user_package);
car_s = intern(lit("car"), user_package);
cdr_s = intern(lit("cdr"), user_package);
+ not_s = intern(lit("not"), user_package);
vecref_s = intern(lit("vecref"), user_package);
list_s = intern(lit("list"), user_package);
append_s = intern(lit("append"), user_package);
@@ -3186,6 +3208,9 @@ void eval_init(void)
reg_mac(sys_qquote_s, me_qquote);
reg_mac(intern(lit("pprof"), user_package), me_pprof);
reg_mac(intern(lit("when"), user_package), me_when);
+ reg_mac(intern(lit("unless"), user_package), me_unless);
+ reg_mac(intern(lit("while"), user_package), me_while);
+ reg_mac(intern(lit("until"), user_package), me_until);
reg_fun(cons_s, func_n2(cons));
reg_fun(intern(lit("make-lazy-cons"), user_package), func_n1(make_lazy_cons));
@@ -3207,7 +3232,7 @@ void eval_init(void)
reg_fun(intern(lit("atom"), user_package), func_n1(atom));
reg_fun(intern(lit("null"), user_package), func_n1(null));
- reg_fun(intern(lit("not"), user_package), func_n1(null));
+ reg_fun(not_s, func_n1(null));
reg_fun(intern(lit("consp"), user_package), func_n1(consp));
reg_fun(intern(lit("listp"), user_package), func_n1(listp));
reg_fun(intern(lit("proper-listp"), user_package), func_n1(proper_listp));
diff --git a/txr.1 b/txr.1
index c59d3f3b..f0fd80b4 100644
--- a/txr.1
+++ b/txr.1
@@ -5580,21 +5580,55 @@ 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 Macro when
+.SS Macros when and unless
.TP
Syntax:
- (when <expression> {<form>}*)
+ (when <expression> <form>*)
+ (unless <expression> <form>*)
.TP
Description:
The when macro operator evaluates <expression>. If <expression> yields
-true, and there are additiona forms, then each <form> is evaluated.
+true, and there are additional forms, then each <form> is evaluated.
The value of the last form is becomes the result value of the when form.
If there are no forms, then the result is nil.
+The unless operator is similar to when, except that it reverses the
+logic of the test. The forms, if any, are evaluated if, and only if
+<expression> is false.
+
+.SS Macros while and until
+
+.TP
+Syntax:
+
+ (while <expression> <form>*)
+ (until <expression> <form>*)
+
+.TP
+Description:
+
+The while macro operator provides a looping construct. It evaluates
+<expression>. If <expression> yields nil, then the evaluation of the while form
+terminates, producing the value nil. Otherwise, if there are additional forms,
+then each <form> is evaluated. Next, evaluation returns to <expression>,
+repeating all of the previous steps.
+
+The until macro operator is similar to while, except that the until form
+terminates when <expression> evaluates true, rather than false.
+
+These operators arrange for the evaluation of all their enclosed forms
+in an anonymous block. Any of the <form>-s, or <expression>, may use
+the return operator to terminate the loop, and optionally to specify
+a result value for the form.
+
+The only way these forms can yield a value other than nil is if
+the return operator is used to terminate the implicit anonymous block,
+and is given an argument, which becomes the result value.
+
.SS Operator/function if
.TP