summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lisplib.c6
-rw-r--r--share/txr/stdlib/build.tl50
-rw-r--r--txr.187
3 files changed, 129 insertions, 14 deletions
diff --git a/lisplib.c b/lisplib.c
index a5116043..43c9e5d1 100644
--- a/lisplib.c
+++ b/lisplib.c
@@ -426,11 +426,13 @@ static val awk_instantiate(val set_fun)
static val build_set_entries(val dlt, val fun)
{
val name[] = {
- lit("list-builder"), lit("build-list"), lit("build"), nil
+ lit("list-builder"), lit("build-list"), lit("build"), lit("buildn"), nil
};
val name_noload[] = {
lit("head"), lit("tail"), lit("add"), lit("add*"), lit("pend"),
- lit("pend*"), lit("ncon"), lit("ncon*"), lit("get"), nil
+ lit("pend*"), lit("ncon"), lit("ncon*"), lit("get"),
+ lit("del"), lit("del*"),
+ nil
};
set_dlt_entries(dlt, name, fun);
diff --git a/share/txr/stdlib/build.tl b/share/txr/stdlib/build.tl
index a2a3edc4..c7af1df7 100644
--- a/share/txr/stdlib/build.tl
+++ b/share/txr/stdlib/build.tl
@@ -83,7 +83,35 @@
(set self.tail pf))))
(:method get (self)
- (cdr self.head)))
+ (cdr self.head))
+
+ (:method del (self)
+ (whenlet ((hd self.head)
+ (chd (cdr self.head)))
+ (when (eq self.tail chd)
+ (set self.tail hd))
+ (prog1 (car chd) (usr:rplacd hd (cdr chd)))))
+
+ (:method del* (self)
+ (whenlet ((hd self.head)
+ (chd (cdr self.head)))
+ (if (cdr chd)
+ (let* ((tl self.tail)
+ (l2 (nthlast 2 tl)))
+ (if (cdr l2)
+ (prog1
+ (cadr l2)
+ (usr:rplacd l2 nil))
+ (let* ((l10 (nthlast 10 hd))
+ (l2 (nthlast 2 l10)))
+ (prog1
+ (cadr l2)
+ (usr:rplacd l2 nil)
+ (set self.tail l10)))))
+ (prog1
+ (car chd)
+ (usr:rplacd hd nil)
+ (set self.tail hd))))))
(defun sys:list-builder-flets (lb-form)
(nconc
@@ -91,14 +119,26 @@
^(,op (. args)
(qref ,lb-form (,op . args))))
^((get ()
- (qref ,lb-form (get))))))
+ (qref ,lb-form (get)))
+ (del* ()
+ (qref ,lb-form (del*)))
+ (do-del ()
+ (qref ,lb-form (del))))))
(defun build-list (: init)
(new list-builder head init))
-(defmacro build (. forms)
+(defun sys:build-expander (forms return-get)
(with-gensyms (name)
^(let ((,name (new list-builder)))
(flet ,(sys:list-builder-flets name)
- ,*forms
- (qref ,name (get))))))
+ (macrolet ((del (:form f : (expr nil expr-p))
+ (if expr-p f '(do-del))))
+ ,*forms
+ ,*(if return-get ^((qref ,name (get)))))))))
+
+(defmacro build (. forms)
+ (sys:build-expander forms t))
+
+(defmacro buildn (. forms)
+ (sys:build-expander forms nil))
diff --git a/txr.1 b/txr.1
index 423585b5..ad72c762 100644
--- a/txr.1
+++ b/txr.1
@@ -32073,6 +32073,13 @@ iterative or recursive process can be collected easily using
.code list-builder
in the order they are visited.
+The
+.code list-builder
+type provides methods for adding and removing items at either end of
+the list, making it suitable where a
+.I dequeue
+structure is required.
+
The basic workflow begins with the instantiation of a
.code list-builder
object. This object may be initialized with a piece of list material which
@@ -32320,22 +32327,57 @@ into the construction methods on the same object.
-> (1 2 1 2 1 2 1 2)
.brev
-.coNP Macro @ build
+.coNP Methods @ del and @ del*
+.synb
+.mets << list-builder .(del)
+.mets << list-builder .(del*)
+.syne
+.desc
+The
+.code del
+and
+.code del*
+methods each remove an element from the list and return it.
+If the list is empty, they return
+.codn nil .
+
+The
+.code del
+method removes an element from the front of the list, whereas
+.code del*
+removes an element from the end of the list.
+
+Note: this orientation is opposite to
+.code add
+and
+.codn add* .
+Thus
+.code del
+pairs with
+.code add
+to produce FIFO queuing behavior.
+
+.coNP Macros @ build and @ buildn
.synb
.mets (build << form *)
+.mets (buildn << form *)
.syne
.desc
The
.code build
-macro provides a shorthand notation for constructing lists using the
+and
+.code buildn
+macros provide a shorthand notation for constructing lists using the
.code list-builder
-structure. It eliminates the explicit call to the
+structure. They eliminate the explicit call to the
.code build-list
-function to construct the object, and eliminates the explicit
+function to construct the object, and eliminate the explicit
references to the object.
Instead,
.code build
+and
+.code buildn
creates a lexical environment in which a
.code list-builder
object is implicitly constructed and bound to a hidden variable.
@@ -32344,14 +32386,45 @@ Local functions which mimic the
methods operate implicitly on this hidden variable, so that
the object need not be mentioned as an argument.
+Then, each
+.meta form
+is evaluated in order.
+
+When the last
+.meta form
+is evaluated,
+.code build
+returns the constructed list, whereas
+.code buildn
+returns the value of the last
+.metn form .
+
+If no forms are enclosed, both macros return
+.codn nil .
+
With the exception of
.codn get ,
-these local functions
-.codn get ,
-have unspecified return values, like the same-named
+the local functions have unspecified return values, like the same-named
.code list-builder
methods.
+Note: because the local function
+.code del
+has the same name as a global macro, it is implemented as a
+.code macrolet.
+Inside a
+.code build
+or
+.codn buildn ,
+if
+.code del
+is invoked with no arguments, then it denotes a call to the
+.code list-builder
+.code del
+method. If invoked with an argument, then it resolves to the global
+.code del
+macro for deleting a place.
+
.TP* Examples:
.verb