0.6.7.22: removed CVS dollar-Header-dollar tags from sources
[sbcl.git] / src / code / boot-extensions.lisp
1 ;;;; extensions which are needed in order to (cross-)compile target-only code
2
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
11
12 (in-package "SB!EXT")
13
14 ;;; Lots of code wants to get to the KEYWORD package or the COMMON-LISP package
15 ;;; without a lot of fuss, so we cache them in variables. TO DO: How much
16 ;;; does this actually buy us? It sounds sensible, but I don't know for sure
17 ;;; that it saves space or time.. -- WHN 19990521
18 (declaim (type package *cl-package* *keyword-package*))
19 (defvar *cl-package*        (find-package "COMMON-LISP"))
20 (defvar *keyword-package*   (find-package "KEYWORD"))
21 \f
22 ;;;; the COLLECT macro
23
24 ;;; helper functions for COLLECT, which become the expanders of the MACROLET
25 ;;; definitions created by COLLECT
26 ;;;
27 ;;; COLLECT-NORMAL-EXPANDER handles normal collection macros.
28 ;;;
29 ;;; COLLECT-LIST-EXPANDER handles the list collection case. N-TAIL
30 ;;; is the pointer to the current tail of the list, or NIL if the list
31 ;;; is empty.
32 (defun collect-normal-expander (n-value fun forms)
33   `(progn
34     ,@(mapcar #'(lambda (form) `(setq ,n-value (,fun ,form ,n-value))) forms)
35     ,n-value))
36 (defun collect-list-expander (n-value n-tail forms)
37   (let ((n-res (gensym)))
38     `(progn
39       ,@(mapcar #'(lambda (form)
40                     `(let ((,n-res (cons ,form nil)))
41                        (cond (,n-tail
42                               (setf (cdr ,n-tail) ,n-res)
43                               (setq ,n-tail ,n-res))
44                              (t
45                               (setq ,n-tail ,n-res  ,n-value ,n-res)))))
46                 forms)
47       ,n-value)))
48
49 ;;; the ultimate collection macro...
50 (defmacro collect (collections &body body)
51   #!+sb-doc
52   "Collect ({(Name [Initial-Value] [Function])}*) {Form}*
53   Collect some values somehow. Each of the collections specifies a bunch of
54   things which collected during the evaluation of the body of the form. The
55   name of the collection is used to define a local macro, a la MACROLET.
56   Within the body, this macro will evaluate each of its arguments and collect
57   the result, returning the current value after the collection is done. The
58   body is evaluated as a PROGN; to get the final values when you are done, just
59   call the collection macro with no arguments.
60
61   INITIAL-VALUE is the value that the collection starts out with, which
62   defaults to NIL. FUNCTION is the function which does the collection. It is
63   a function which will accept two arguments: the value to be collected and the
64   current collection. The result of the function is made the new value for the
65   collection. As a totally magical special-case, FUNCTION may be COLLECT,
66   which tells us to build a list in forward order; this is the default. If an
67   INITIAL-VALUE is supplied for Collect, the stuff will be RPLACD'd onto the
68   end. Note that FUNCTION may be anything that can appear in the functional
69   position, including macros and lambdas."
70
71   (let ((macros ())
72         (binds ()))
73     (dolist (spec collections)
74       (unless (proper-list-of-length-p spec 1 3)
75         (error "Malformed collection specifier: ~S." spec))
76       (let* ((name (first spec))
77              (default (second spec))
78              (kind (or (third spec) 'collect))
79              (n-value (gensym (concatenate 'string
80                                            (symbol-name name)
81                                            "-N-VALUE-"))))
82         (push `(,n-value ,default) binds)
83         (if (eq kind 'collect)
84           (let ((n-tail (gensym (concatenate 'string
85                                              (symbol-name name)
86                                              "-N-TAIL-"))))
87             (if default
88               (push `(,n-tail (last ,n-value)) binds)
89               (push n-tail binds))
90             (push `(,name (&rest args)
91                      (collect-list-expander ',n-value ',n-tail args))
92                   macros))
93           (push `(,name (&rest args)
94                    (collect-normal-expander ',n-value ',kind args))
95                 macros))))
96     `(macrolet ,macros (let* ,(nreverse binds) ,@body))))
97 \f
98 (declaim (ftype (function () nil) required-argument))
99 (defun required-argument ()
100   #!+sb-doc
101   "This function can be used as the default value for keyword arguments that
102   must be always be supplied. Since it is known by the compiler to never
103   return, it will avoid any compile-time type warnings that would result from a
104   default value inconsistent with the declared type. When this function is
105   called, it signals an error indicating that a required keyword argument was
106   not supplied. This function is also useful for DEFSTRUCT slot defaults
107   corresponding to required arguments."
108   (/show0 "entering REQUIRED-ARGUMENT")
109   (error "A required keyword argument was not supplied."))
110 \f
111 ;;; "the ultimate iteration macro"
112 ;;;
113 ;;; note for Schemers: This seems to be identical to Scheme's "named LET".
114 (defmacro iterate (name binds &body body)
115   #!+sb-doc
116   "Iterate Name ({(Var Initial-Value)}*) Declaration* Form*
117   This is syntactic sugar for Labels. It creates a local function Name with
118   the specified Vars as its arguments and the Declarations and Forms as its
119   body. This function is then called with the Initial-Values, and the result
120   of the call is returned from the macro."
121   (dolist (x binds)
122     (unless (proper-list-of-length-p x 2)
123       (error "Malformed ITERATE variable spec: ~S." x)))
124   `(labels ((,name ,(mapcar #'first binds) ,@body))
125      (,name ,@(mapcar #'second binds))))
126 \f
127 ;;; Once-Only is a utility useful in writing source transforms and macros.
128 ;;; It provides an easy way to wrap a LET around some code to ensure that some
129 ;;; forms are only evaluated once.
130 (defmacro once-only (specs &body body)
131   #!+sb-doc
132   "Once-Only ({(Var Value-Expression)}*) Form*
133   Create a Let* which evaluates each Value-Expression, binding a temporary
134   variable to the result, and wrapping the Let* around the result of the
135   evaluation of Body. Within the body, each Var is bound to the corresponding
136   temporary variable."
137   (iterate frob
138            ((specs specs)
139             (body body))
140     (if (null specs)
141         `(progn ,@body)
142         (let ((spec (first specs)))
143           ;; FIXME: should just be DESTRUCTURING-BIND of SPEC
144           (unless (proper-list-of-length-p spec 2)
145             (error "malformed ONCE-ONLY binding spec: ~S" spec))
146           (let* ((name (first spec))
147                  (exp-temp (gensym (symbol-name name))))
148             `(let ((,exp-temp ,(second spec))
149                    (,name (gensym "OO-")))
150                `(let ((,,name ,,exp-temp))
151                   ,,(frob (rest specs) body))))))))
152 \f
153 ;;;; some old-fashioned functions. (They're not just for old-fashioned
154 ;;;; code, they're also used as optimized forms of the corresponding
155 ;;;; general functions when the compiler can prove that they're
156 ;;;; equivalent.)
157
158 ;;; like (MEMBER ITEM LIST :TEST #'EQ)
159 (defun memq (item list)
160   #!+sb-doc
161   "Returns tail of LIST beginning with first element EQ to ITEM."
162   ;; KLUDGE: These could be and probably should be defined as
163   ;;   (MEMBER ITEM LIST :TEST #'EQ)),
164   ;; but when I try to cross-compile that, I get an error from
165   ;; LTN-ANALYZE-KNOWN-CALL, "Recursive known function definition". The
166   ;; comments for that error say it "is probably a botched interpreter stub".
167   ;; Rather than try to figure that out, I just rewrote this function from
168   ;; scratch. -- WHN 19990512
169   (do ((i list (cdr i)))
170       ((null i))
171     (when (eq (car i) item)
172       (return i))))
173
174 ;;; like (ASSOC ITEM ALIST :TEST #'EQ)
175 (defun assq (item alist)
176   #!+sb-doc
177   "Return the first pair of ALIST where ITEM is EQ to the key of the pair."
178   ;; KLUDGE: CMU CL defined this with
179   ;;   (DECLARE (INLINE ASSOC))
180   ;;   (ASSOC ITEM ALIST :TEST #'EQ))
181   ;; which is pretty, but which would have required adding awkward
182   ;; build order constraints on SBCL (or figuring out some way to make
183   ;; inline definitions installable at build-the-cross-compiler time,
184   ;; which was too ambitious for now). Rather than mess with that,
185   ;; we just define ASSQ explicitly in terms of more primitive operations:
186   (dolist (pair alist)
187     (when (eq (car pair) item)
188       (return pair))))
189
190 (defun delq (item list)
191   #!+sb-doc
192   "Delete all LIST entries EQ to ITEM (destructively modifying LIST), and
193   return the modified LIST."
194   (let ((list list))
195     (do ((x list (cdr x))
196          (splice '()))
197         ((endp x) list)
198       (cond ((eq item (car x))
199              (if (null splice)
200                (setq list (cdr x))
201                (rplacd splice (cdr x))))
202             (t (setq splice x)))))) ; Move splice along to include element.