summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eval.c13
-rw-r--r--lisplib.c21
-rw-r--r--share/txr/stdlib/op.tl94
-rw-r--r--txr.157
4 files changed, 157 insertions, 28 deletions
diff --git a/eval.c b/eval.c
index 2310c2d0..a614335d 100644
--- a/eval.c
+++ b/eval.c
@@ -3400,6 +3400,10 @@ val expand_quasi(val quasi_forms, val menv)
if (consp(form)) {
val sym = car(form);
+ int comp_184 = opt_compat && opt_compat <= 184;
+
+ if (!comp_184)
+ form_ex = expand(form, menv);
if (sym == var_s) {
val param = second(form);
@@ -3410,7 +3414,8 @@ val expand_quasi(val quasi_forms, val menv)
if (param_ex != param || mods_ex != mods)
form_ex = rlcp(list(sym, param_ex, mods_ex, nao), form);
} else {
- form_ex = expand(form, menv);
+ if (comp_184)
+ form_ex = expand(form, menv);
}
}
@@ -5677,8 +5682,10 @@ void eval_init(void)
reg_mac(gen_s, func_n2(me_gen));
reg_mac(gun_s, func_n2(me_gun));
reg_mac(intern(lit("delay"), user_package), func_n2(me_delay));
- reg_mac(op_s, func_n2(me_op));
- reg_mac(do_s, func_n2(me_op));
+ if (opt_compat && opt_compat <= 184) {
+ reg_mac(op_s, func_n2(me_op));
+ reg_mac(do_s, func_n2(me_op));
+ }
reg_mac(ap_s, func_n2(me_ap));
reg_mac(intern(lit("ip"), user_package), func_n2(me_ip));
reg_mac(intern(lit("ado"), user_package), func_n2(me_ado));
diff --git a/lisplib.c b/lisplib.c
index 588384df..8379abf9 100644
--- a/lisplib.c
+++ b/lisplib.c
@@ -560,6 +560,23 @@ static val doloop_instantiate(val set_fun)
return nil;
}
+static val op_set_entries(val dlt, val fun)
+{
+ val name[] = {
+ lit("op"), lit("do"),
+ nil
+ };
+ set_dlt_entries(dlt, name, fun);
+ return nil;
+}
+
+static val op_instantiate(val set_fun)
+{
+ funcall1(set_fun, nil);
+ load(format(nil, lit("~aop.tl"), stdlib_path, nao));
+ return nil;
+}
+
val dlt_register(val dlt,
val (*instantiate)(val),
val (*set_entries)(val, val))
@@ -601,6 +618,10 @@ void lisplib_init(void)
dlt_register(dl_table, keyparams_instantiate, keyparams_set_entries);
dlt_register(dl_table, ffi_instantiate, ffi_set_entries);
dlt_register(dl_table, doloop_instantiate, doloop_set_entries);
+
+ if (!opt_compat || opt_compat >= 185)
+ dlt_register(dl_table, op_instantiate, op_set_entries);
+
reg_fun(intern(lit("try-load"), system_package), func_n1(lisplib_try_load));
}
diff --git a/share/txr/stdlib/op.tl b/share/txr/stdlib/op.tl
new file mode 100644
index 00000000..78658658
--- /dev/null
+++ b/share/txr/stdlib/op.tl
@@ -0,0 +1,94 @@
+;; Copyright 2017
+;; Kaz Kylheku <kaz@kylheku.com>
+;; Vancouver, Canada
+;; All rights reserved.
+;;
+;; Redistribution and use in source and binary forms, with or without
+;; modification, are permitted provided that the following conditions are met:
+;;
+;; 1. Redistributions of source code must retain the above copyright notice, this
+;; list of conditions and the following disclaimer.
+;;
+;; 2. Redistributions in binary form must reproduce the above copyright notice,
+;; this list of conditions and the following disclaimer in the documentation
+;; and/or other materials provided with the distribution.
+;;
+;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+;; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+;; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+;; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+;; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+;; CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+;; OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+;; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+(sys:make-struct-type
+ 'sys:op-ctx nil nil '(form gens up meta) nil
+ (lambda (me)
+ (slotset me 'up sys:*op-ctx*)
+ (slotset me 'meta (gensym "meta-")))
+ nil nil)
+
+(defvar sys:*op-ctx*)
+
+(defun sys:ensure-op-arg (ctx n)
+ (let ((ag (slot ctx 'gens)))
+ (when (> n 1024)
+ ['compile-error (slot ctx 'form)
+ "@~a calls for function with too many arguments" n])
+ (for ((i (len ag)) (l))
+ ((<= i n)
+ (sys:setq ag (append ag (nreverse l)))
+ (slotset ctx 'gens ag)
+ [ag n])
+ ((sys:setq i (succ i)))
+ (sys:setq l (cons (gensym `arg-@(if (plusp i) i "rest")-`) l)))))
+
+(defun sys:op-meta-p (expr)
+ (tree-case expr
+ ((x y . r) (and (null r)
+ (cond
+ ((eq x 'sys:expr) (sys:op-meta-p y))
+ ((eq x 'sys:var) (or (integerp y)
+ (eq y 'rest))))))))
+
+(defun sys:op-alpha-rename (f e op-args do-nested-metas)
+ (let* ((ctx sys:*op-ctx*)
+ (code ^(macrolet ((sys:expr (:form f arg)
+ (let ((ctx ,ctx))
+ (if (and (slot ctx 'up) (sys:op-meta-p arg))
+ ^(,(slot (slot ctx 'up) 'meta) (quote ,arg))
+ f)))
+ (sys:var (:form f arg . mods)
+ (cond
+ ((and (not mods) (sys:op-meta-p f))
+ (unless (integerp arg)
+ (sys:setq arg 0))
+ (sys:ensure-op-arg ,ctx arg))
+ (t f)))
+ ,*(if do-nested-metas
+ ^((,(slot ctx 'meta) ((quote arg)) arg))))
+ ,op-args)))
+ (sys:expand code e)))
+
+(defun sys:op-expand (f e args)
+ (let* ((ctx (make-struct 'sys:op-ctx ^(form ,f)))
+ (sys:*op-ctx* ctx)
+ (sym (car f))
+ (syntax-0 (if (eq sym 'do) ^(,*args) ^[,*args]))
+ (syntax-1 (sys:op-alpha-rename f e syntax-0 nil))
+ (syntax-2 (sys:op-alpha-rename f e syntax-1 t))
+ (have-metas (slot ctx 'gens))
+ (rest-sym (sys:ensure-op-arg ctx 0)))
+ ^(lambda (,*(cdr (slot ctx 'gens)) . ,rest-sym)
+ ,(if (or have-metas (eq sym 'do))
+ syntax-2
+ (append syntax-2 rest-sym)))))
+
+(defmacro op (:form f :env e . args)
+ (sys:op-expand f e args))
+
+(defmacro do (:form f :env e . args)
+ (sys:op-expand f e args))
diff --git a/txr.1 b/txr.1
index 8efcfd10..7c53b1f5 100644
--- a/txr.1
+++ b/txr.1
@@ -39875,23 +39875,23 @@ can be used in the dot position of a function call, such as:
[(op list 1 . @1) 2] -> (1 . 2)
.cble
-Even though the notation
-.code @1
-produces a compound form, which the dot notation then splices into
-the surrounding form, the expander for the
-.code op
-and
-.code do
-macro takes recognizes and takes care of this special case.
+This is a consequence of the special transformations described
+in the paragraph
+.B "Dot Position in Function Calls"
+in the subsection
+.B "Additional Syntax"
+of the
+.BR "TXR Lisp"
+section.
The
.code op
-syntax interacts with quasiliterals which are nested within it.
+syntax works in conjunction with quasiliterals which are nested within it.
The metanumber notation as well as
.code @rest
are recognized without requiring an additional
.code @
-escape:
+escape, which is effectively optional:
.cblk
(apply (op list `@1-@rest`) '(1 2 3)) -> "1-2 3"
@@ -39899,29 +39899,19 @@ escape:
(apply (op list `@@1-@@rest`) '(1 2 3)) -> "1-2 3"
.cble
-This is because the
-.code op
-macro traverses the code structure produced by the literal without recognizing
-it specially, and there imposes its own meaning on these elements.
-
Though they produce the same result, the above two examples differ in that
.code @rest
embeds a metasymbol into the quasiliteral structure, whereas
.code @@rest
embeds the Lisp expression
.code @rest
-into the quasiliteral.
-
-Under the
-.code op
-macro and its relatives, occurrences of
+into the quasiliteral. Either way, in the scope of
+.codn op ,
.code @rest
-are replaced with syntax which refers to the trailing arguments
-of the anonymous function. This happens before the interior of the
+undergoes the macro-expansion which renames it to the machine-generated
+function argument symbol of the implicit function denoted by the
.code op
-syntax undergoes expansion. Therefore the quasiliteral expander never
-sees the
-.codn @rest .
+macro form.
This convenient omission of the
.code @
@@ -61276,6 +61266,23 @@ of these version values, the described behaviors are provided if
is given an argument which is equal or lower. For instance
.code "-C 103"
selects the behaviors described below for version 105, but not those for 102.
+.IP 184
+A value of 184 or lower switches to the old implementation of the
+.code op
+and
+.code do
+macros which was replaced starting in \*(TX 185. Also, this has the
+effect of disabling the special recognition of meta-expressions
+and meta-variables in the dot position of function calls, and
+the macro expansion of meta-variables in quasiliterals. This is
+because the old
+.code op
+implementation implements these behaviors itself. The implication
+is that user code which binds custom macros to
+.code sys:var
+or
+.code sys:expr
+may be affected by 184 or lower compatibility.
.IP 183
A value of 183 or lower restores an inconsistent behavior in the
.code "@(bind)"