diff options
-rw-r--r-- | lisplib.c | 6 | ||||
-rw-r--r-- | share/txr/stdlib/build.tl | 50 | ||||
-rw-r--r-- | txr.1 | 87 |
3 files changed, 129 insertions, 14 deletions
@@ -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)) @@ -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 |