1 | ;;;-*-Mode: LISP; Package: CCL -*- |
---|
2 | ;;; |
---|
3 | ;;; Copyright (C) 1994-2001 Digitool, Inc |
---|
4 | ;;; This file is part of OpenMCL. |
---|
5 | ;;; |
---|
6 | ;;; OpenMCL is licensed under the terms of the Lisp Lesser GNU Public |
---|
7 | ;;; License , known as the LLGPL and distributed with OpenMCL as the |
---|
8 | ;;; file "LICENSE". The LLGPL consists of a preamble and the LGPL, |
---|
9 | ;;; which is distributed with OpenMCL as the file "LGPL". Where these |
---|
10 | ;;; conflict, the preamble takes precedence. |
---|
11 | ;;; |
---|
12 | ;;; OpenMCL is referenced in the preamble as the "LIBRARY." |
---|
13 | ;;; |
---|
14 | ;;; The LLGPL is also available online at |
---|
15 | ;;; http://opensource.franz.com/preamble.html |
---|
16 | |
---|
17 | ;;; Macros (and functions/constants used at macroexpand-time) ONLY. |
---|
18 | |
---|
19 | (in-package "CCL") |
---|
20 | |
---|
21 | (eval-when (eval compile) |
---|
22 | (require "LEVEL-2") |
---|
23 | (require "BACKQUOTE") |
---|
24 | (require "DEFSTRUCT-MACROS")) |
---|
25 | |
---|
26 | ;; Constants |
---|
27 | |
---|
28 | (defmacro defconstant (sym val &optional (doc () doc-p) &environment env) |
---|
29 | "Define a global constant, saying that the value is constant and may be |
---|
30 | compiled into code. If the variable already has a value, and this is not |
---|
31 | EQL to the new value, the code is not portable (undefined behavior). The |
---|
32 | third argument is an optional documentation string for the variable." |
---|
33 | (setq sym (require-type sym 'symbol) |
---|
34 | doc (if doc-p (require-type doc 'string))) |
---|
35 | `(progn |
---|
36 | (eval-when (:compile-toplevel) |
---|
37 | (define-compile-time-constant ',sym ',val ,env)) |
---|
38 | (eval-when (:load-toplevel :execute) |
---|
39 | (%defconstant ',sym ,val ,@(if doc-p (list doc)))))) |
---|
40 | |
---|
41 | ;; Lists |
---|
42 | |
---|
43 | (defmacro %car (x) |
---|
44 | `(car (the cons ,x))) |
---|
45 | |
---|
46 | (defmacro %cdr (x) |
---|
47 | `(cdr (the cons ,x))) |
---|
48 | |
---|
49 | (defmacro %caar (x) |
---|
50 | `(%car (%car ,x))) |
---|
51 | |
---|
52 | (defmacro %cadr (x) |
---|
53 | `(%car (%cdr ,x))) |
---|
54 | |
---|
55 | (defmacro %cdar (x) |
---|
56 | `(%cdr (%car ,x))) |
---|
57 | |
---|
58 | (defmacro %cddr (x) |
---|
59 | `(%cdr (%cdr ,x))) |
---|
60 | |
---|
61 | (defmacro %caaar (x) |
---|
62 | `(%car (%car (%car ,x)))) |
---|
63 | |
---|
64 | (defmacro %caadr (x) |
---|
65 | `(%car (%car (%cdr ,x)))) |
---|
66 | |
---|
67 | (defmacro %cadar (x) |
---|
68 | `(%car (%cdr (%car ,x)))) |
---|
69 | |
---|
70 | (defmacro %caddr (x) |
---|
71 | `(%car (%cdr (%cdr ,x)))) |
---|
72 | |
---|
73 | (defmacro %cdaar (x) |
---|
74 | `(%cdr (%car (%car ,x)))) |
---|
75 | |
---|
76 | (defmacro %cdadr (x) |
---|
77 | `(%cdr (%car (%cdr ,x)))) |
---|
78 | |
---|
79 | (defmacro %cddar (x) |
---|
80 | `(%cdr (%cdr (%car ,x)))) |
---|
81 | |
---|
82 | (defmacro %cdddr (x) |
---|
83 | `(%cdr (%cdr (%cdr ,x)))) |
---|
84 | |
---|
85 | (defmacro %rplaca (x y) |
---|
86 | `(rplaca (the cons ,x) ,y)) |
---|
87 | |
---|
88 | (defmacro %rplacd (x y) |
---|
89 | `(rplacd (the cons ,x) ,y)) |
---|
90 | |
---|
91 | ; These are open-coded by the compiler to isolate platform |
---|
92 | ; dependencies. |
---|
93 | |
---|
94 | (defmacro %unbound-marker-8 () |
---|
95 | `(%unbound-marker)) |
---|
96 | |
---|
97 | (defmacro %slot-missing-marker () |
---|
98 | `(%illegal-marker)) |
---|
99 | |
---|
100 | |
---|
101 | |
---|
102 | |
---|
103 | (defmacro %null-ptr () '(%int-to-ptr 0)) |
---|
104 | |
---|
105 | ;;;Assorted useful macro definitions |
---|
106 | |
---|
107 | (defmacro def-accessors (ref &rest names) |
---|
108 | (define-accessors ref names)) |
---|
109 | |
---|
110 | (defmacro def-accessor-macros (ref &rest names) |
---|
111 | (define-accessors ref names t)) |
---|
112 | |
---|
113 | (defun define-accessors (ref names &optional no-constants |
---|
114 | &aux (arg (gensym)) (index 0) progn types) |
---|
115 | (when (listp ref) |
---|
116 | (setq types ref |
---|
117 | ref (pop names))) |
---|
118 | (dolist (name names) |
---|
119 | (when name |
---|
120 | (unless (listp name) (setq name (list name))) |
---|
121 | (dolist (sym name) |
---|
122 | (when sym |
---|
123 | (push `(defmacro ,sym (,arg) (list ',ref ,arg ,index)) progn) |
---|
124 | (unless no-constants |
---|
125 | (push `(defconstant ,sym ,index) progn))))) |
---|
126 | (setq index (1+ index))) |
---|
127 | `(progn |
---|
128 | ,.(nreverse progn) |
---|
129 | ,@(if types `((add-accessor-types ',types ',names))) |
---|
130 | ,index)) |
---|
131 | |
---|
132 | (defmacro specialv (var) |
---|
133 | `(locally (declare (special ,var)) ,var)) |
---|
134 | |
---|
135 | |
---|
136 | (defmacro prog1 (valform &rest otherforms) |
---|
137 | (let ((val (gensym))) |
---|
138 | `(let ((,val ,valform)) |
---|
139 | ,@otherforms |
---|
140 | ,val))) |
---|
141 | |
---|
142 | (defmacro prog2 (first second &rest others) |
---|
143 | `(progn ,first (prog1 ,second ,@others))) |
---|
144 | |
---|
145 | (defmacro prog (inits &body body &environment env) |
---|
146 | (multiple-value-bind (forms decls) (parse-body body env nil) |
---|
147 | `(block nil |
---|
148 | (let ,inits |
---|
149 | ,@decls |
---|
150 | (tagbody ,@forms))))) |
---|
151 | |
---|
152 | (defmacro prog* (inits &body body &environment env) |
---|
153 | (multiple-value-bind (forms decls) (parse-body body env nil) |
---|
154 | `(block nil |
---|
155 | (let* ,inits |
---|
156 | ,@decls |
---|
157 | (tagbody ,@forms))))) |
---|
158 | |
---|
159 | |
---|
160 | (defmacro %stack-block ((&rest specs) &body forms &aux vars lets) |
---|
161 | (dolist (spec specs) |
---|
162 | (destructuring-bind (var ptr &key clear) spec |
---|
163 | (push var vars) |
---|
164 | (push `(,var (%new-ptr ,ptr ,clear)) lets))) |
---|
165 | `(let* ,(nreverse lets) |
---|
166 | (declare (dynamic-extent ,@vars)) |
---|
167 | (declare (type macptr ,@vars)) |
---|
168 | (declare (unsettable ,@vars)) |
---|
169 | ,@forms)) |
---|
170 | |
---|
171 | (defmacro %vstack-block (spec &body forms) |
---|
172 | `(%stack-block (,spec) ,@forms)) |
---|
173 | |
---|
174 | (defmacro dolist ((varsym list &optional ret) &body body &environment env) |
---|
175 | (if (not (symbolp varsym)) (signal-program-error $XNotSym varsym)) |
---|
176 | (let* ((toplab (gensym)) |
---|
177 | (tstlab (gensym)) |
---|
178 | (lstsym (gensym))) |
---|
179 | (multiple-value-bind (forms decls) (parse-body body env nil) |
---|
180 | `(block nil |
---|
181 | (let* ((,lstsym ,list) ,varsym) |
---|
182 | ,@decls |
---|
183 | (tagbody |
---|
184 | (go ,tstlab) |
---|
185 | ,toplab |
---|
186 | (setq ,lstsym (cdr (the list ,lstsym))) |
---|
187 | ,@forms |
---|
188 | ,tstlab |
---|
189 | (setq ,varsym (car ,lstsym)) |
---|
190 | (if ,lstsym (go ,toplab))) |
---|
191 | ,@(if ret `((progn ,ret)))))))) |
---|
192 | |
---|
193 | |
---|
194 | (defmacro dovector ((varsym vector &optional ret) &body body &environment env) |
---|
195 | (if (not (symbolp varsym))(signal-program-error $XNotSym varsym)) |
---|
196 | (let* ((toplab (gensym)) |
---|
197 | (tstlab (gensym)) |
---|
198 | (lengthsym (gensym)) |
---|
199 | (indexsym (gensym)) |
---|
200 | (vecsym (gensym))) |
---|
201 | (multiple-value-bind (forms decls) (parse-body body env nil) |
---|
202 | `(let* ((,vecsym ,vector) |
---|
203 | (,lengthsym (length ,vecsym)) |
---|
204 | (,indexsym 0) |
---|
205 | ,varsym) |
---|
206 | ,@decls |
---|
207 | ,@(let ((type (nx-form-type vector env))) |
---|
208 | (unless (eq type t) |
---|
209 | `((declare (type ,type ,vecsym))))) |
---|
210 | (block nil |
---|
211 | (tagbody |
---|
212 | (go ,tstlab) |
---|
213 | ,toplab |
---|
214 | (setq ,varsym (locally (declare (optimize (speed 3) (safety 0))) |
---|
215 | (aref ,vecsym ,indexsym)) |
---|
216 | ,indexsym (%i+ ,indexsym 1)) |
---|
217 | ,@forms |
---|
218 | ,tstlab |
---|
219 | (if (%i< ,indexsym ,lengthsym) (go ,toplab))) |
---|
220 | ,@(if ret `((progn (setq ,varsym nil) ,ret)))))))) |
---|
221 | |
---|
222 | (defmacro report-bad-arg (&rest args) |
---|
223 | `(values (%badarg ,@args))) |
---|
224 | |
---|
225 | (defmacro %cons-restart (name action report interactive test) |
---|
226 | `(gvector :istruct 'restart ,name ,action ,report ,interactive ,test)) |
---|
227 | |
---|
228 | (defmacro restart-bind (clauses &body body) |
---|
229 | "Executes forms in a dynamic context where the given restart bindings are |
---|
230 | in effect. Users probably want to use RESTART-CASE. When clauses contain |
---|
231 | the same restart name, FIND-RESTART will find the first such clause." |
---|
232 | (let* ((restarts (mapcar #'(lambda (clause) |
---|
233 | (list (make-symbol (symbol-name (require-type (car clause) 'symbol))) |
---|
234 | `(%cons-restart nil nil nil nil nil))) |
---|
235 | clauses)) |
---|
236 | (bindings (mapcar #'(lambda (clause name) |
---|
237 | `(make-restart ,(car name) ',(car clause) |
---|
238 | ,@(cdr clause))) |
---|
239 | clauses restarts)) |
---|
240 | (cluster (gensym))) |
---|
241 | `(let* (,@restarts) |
---|
242 | (declare (dynamic-extent ,@(mapcar #'car restarts))) |
---|
243 | (let* ((,cluster (list ,@bindings)) |
---|
244 | (%restarts% (cons ,cluster %restarts%))) |
---|
245 | (declare (dynamic-extent ,cluster %restarts%)) |
---|
246 | (progn |
---|
247 | ,@body))))) |
---|
248 | |
---|
249 | (defmacro handler-bind (clauses &body body) |
---|
250 | "(HANDLER-BIND ( {(type handler)}* ) body) |
---|
251 | Executes body in a dynamic context where the given handler bindings are |
---|
252 | in effect. Each handler must take the condition being signalled as an |
---|
253 | argument. The bindings are searched first to last in the event of a |
---|
254 | signalled condition." |
---|
255 | (let* ((fns) |
---|
256 | (decls) |
---|
257 | (bindings (mapcan #'(lambda (clause) |
---|
258 | (destructuring-bind (condition handler) clause |
---|
259 | (if (and (consp handler)(eq (car handler) 'function) |
---|
260 | (consp (cadr handler))(eq (car (cadr handler)) 'lambda)) |
---|
261 | (let ((fn (gensym))) |
---|
262 | (push `(,fn ,handler) fns) |
---|
263 | (push `(declare (dynamic-extent ,fn)) decls) |
---|
264 | `(',condition ,fn)) |
---|
265 | (list `',condition |
---|
266 | `,handler)))) |
---|
267 | clauses)) |
---|
268 | (cluster (gensym))) |
---|
269 | `(let* (,@fns |
---|
270 | (,cluster (list ,@bindings)) |
---|
271 | (%handlers% (cons ,cluster %handlers%))) |
---|
272 | (declare (dynamic-extent ,cluster %handlers%)) |
---|
273 | ,@decls |
---|
274 | (progn |
---|
275 | ,@body)))) |
---|
276 | |
---|
277 | (defmacro restart-case (&environment env form &rest clauses) |
---|
278 | "(RESTART-CASE form |
---|
279 | {(case-name arg-list {keyword value}* body)}*) |
---|
280 | The form is evaluated in a dynamic context where the clauses have special |
---|
281 | meanings as points to which control may be transferred (see INVOKE-RESTART). |
---|
282 | When clauses contain the same case-name, FIND-RESTART will find the first |
---|
283 | such clause. If Expression is a call to SIGNAL, ERROR, CERROR or WARN (or |
---|
284 | macroexpands into such) then the signalled condition will be associated with |
---|
285 | the new restarts." |
---|
286 | (let ((cluster nil)) |
---|
287 | (when clauses (setq cluster (gensym) form (restart-case-form form env cluster))) |
---|
288 | (flet ((restart-case-1 (name arglist &rest forms) |
---|
289 | (let (interactive report test) |
---|
290 | (loop |
---|
291 | (case (car forms) |
---|
292 | (:interactive (setq interactive (cadr forms))) |
---|
293 | (:report (setq report (cadr forms))) |
---|
294 | (:test (setq test (cadr forms))) |
---|
295 | (t (return nil))) |
---|
296 | (setq forms (cddr forms))) |
---|
297 | (when (and report (not (stringp report))) |
---|
298 | (setq report `#',report)) |
---|
299 | (when interactive |
---|
300 | (setq interactive `#',interactive)) |
---|
301 | (when test |
---|
302 | (setq test `#',test)) |
---|
303 | (values (require-type name 'symbol) arglist report interactive test forms)))) |
---|
304 | (cond ((null clauses) form) |
---|
305 | ((and (null (cdr clauses)) (null (cadr (car clauses)))) |
---|
306 | (let ((block (gensym)) |
---|
307 | (restart-name (gensym))) |
---|
308 | (multiple-value-bind (name arglist report interactive test body) |
---|
309 | (apply #'restart-case-1 (car clauses)) |
---|
310 | (declare (ignore arglist)) |
---|
311 | `(block ,block |
---|
312 | (let* ((,restart-name (%cons-restart ',name () ,report ,interactive ,test)) |
---|
313 | (,cluster (list ,restart-name)) |
---|
314 | (%restarts% (cons ,cluster %restarts%))) |
---|
315 | (declare (dynamic-extent ,restart-name ,cluster %restarts%)) |
---|
316 | (catch ,cluster (return-from ,block ,form))) |
---|
317 | ,@body)))) |
---|
318 | (t |
---|
319 | (let ((block (gensym)) (val (gensym)) |
---|
320 | (index -1) restarts restart-names restart-name cases) |
---|
321 | (while clauses |
---|
322 | (setq index (1+ index)) |
---|
323 | (multiple-value-bind (name arglist report interactive test body) |
---|
324 | (apply #'restart-case-1 (pop clauses)) |
---|
325 | (push (setq restart-name (make-symbol (symbol-name name))) restart-names) |
---|
326 | (push (list restart-name `(%cons-restart ',name ,index ,report ,interactive ,test)) |
---|
327 | restarts) |
---|
328 | (when (null clauses) (setq index t)) |
---|
329 | (push `(,index (apply #'(lambda ,arglist ,@body) ,val)) |
---|
330 | cases))) |
---|
331 | `(block ,block |
---|
332 | (let ((,val (let* (,@restarts |
---|
333 | (,cluster (list ,@(reverse restart-names))) |
---|
334 | (%restarts% (cons ,cluster %restarts%))) |
---|
335 | (declare (dynamic-extent ,@restart-names ,cluster %restarts%)) |
---|
336 | (catch ,cluster (return-from ,block ,form))))) |
---|
337 | (case (pop ,val) |
---|
338 | ,@(nreverse cases)))))))))) |
---|
339 | |
---|
340 | |
---|
341 | ; Anything this hairy should die a slow and painful death. |
---|
342 | ; Unless, of course, I grossly misunderstand... |
---|
343 | (defun restart-case-form (form env clustername) |
---|
344 | (let ((expansion (macroexpand form env)) |
---|
345 | (head nil)) |
---|
346 | (if (and (listp expansion) ; already an ugly hack, made uglier by %error case ... |
---|
347 | (memq (setq head (pop expansion)) '(signal error cerror warn %error))) |
---|
348 | (let ((condform nil) |
---|
349 | (signalform nil) |
---|
350 | (cname (gensym))) |
---|
351 | (case head |
---|
352 | (cerror |
---|
353 | (destructuring-bind |
---|
354 | (continue cond &rest args) expansion |
---|
355 | (setq condform `(condition-arg ,cond (list ,@args) 'simple-error) |
---|
356 | signalform `(cerror ,continue ,cname)))) |
---|
357 | ((signal error warn) |
---|
358 | (destructuring-bind |
---|
359 | (cond &rest args) expansion |
---|
360 | (setq condform `(condition-arg ,cond (list ,@args) ,(if (eq head 'warning) |
---|
361 | ''simple-warning |
---|
362 | (if (eq head 'error) |
---|
363 | ''simple-error |
---|
364 | ''simple-condition))) |
---|
365 | signalform `(,head ,cname)))) |
---|
366 | (t ;%error |
---|
367 | (destructuring-bind (cond args fp) expansion |
---|
368 | (setq condform `(condition-arg ,cond ,args 'simple-error) |
---|
369 | signalform `(%error ,cname nil ,fp))))) |
---|
370 | `(let ((,cname ,condform)) |
---|
371 | (with-condition-restarts ,cname ,clustername |
---|
372 | ,signalform))) |
---|
373 | form))) |
---|
374 | |
---|
375 | |
---|
376 | (defmacro handler-case (form &rest clauses) |
---|
377 | "(HANDLER-CASE form |
---|
378 | { (type ([var]) body) }* ) |
---|
379 | Execute FORM in a context with handlers established for the condition |
---|
380 | types. A peculiar property allows type to be :NO-ERROR. If such a clause |
---|
381 | occurs, and form returns normally, all its values are passed to this clause |
---|
382 | as if by MULTIPLE-VALUE-CALL. The :NO-ERROR clause accepts more than one |
---|
383 | var specification." |
---|
384 | (let* ((no-error-clause (assoc :no-error clauses))) |
---|
385 | (if no-error-clause |
---|
386 | (let* ((normal-return (gensym)) |
---|
387 | (error-return (gensym))) |
---|
388 | `(block ,error-return |
---|
389 | (multiple-value-call #'(lambda ,@(cdr no-error-clause)) |
---|
390 | (block ,normal-return |
---|
391 | (return-from ,error-return |
---|
392 | (handler-case (return-from ,normal-return ,form) |
---|
393 | ,@(remove no-error-clause clauses))))))) |
---|
394 | (flet ((handler-case (type var &rest body) |
---|
395 | (when (eq type :no-error) |
---|
396 | (signal-program-error "Duplicate :no-error clause. ")) |
---|
397 | (values type var body))) |
---|
398 | (cond ((null clauses) form) |
---|
399 | ((null (cdr clauses)) |
---|
400 | (let ((block (gensym)) |
---|
401 | (cluster (gensym))) |
---|
402 | (multiple-value-bind (type var body) |
---|
403 | (apply #'handler-case (car clauses)) |
---|
404 | (if var |
---|
405 | `(block ,block |
---|
406 | ((lambda ,var ,@body) |
---|
407 | (let* ((,cluster (list ',type)) |
---|
408 | (%handlers% (cons ,cluster %handlers%))) |
---|
409 | (declare (dynamic-extent ,cluster %handlers%)) |
---|
410 | (catch ,cluster (return-from ,block ,form))))) |
---|
411 | `(block ,block |
---|
412 | (let* ((,cluster (list ',type)) |
---|
413 | (%handlers% (cons ,cluster %handlers%))) |
---|
414 | (declare (dynamic-extent ,cluster %handlers%)) |
---|
415 | (catch ,cluster (return-from ,block ,form))) |
---|
416 | (locally ,@body)))))) |
---|
417 | (t (let ((block (gensym)) (cluster (gensym)) (val (gensym)) |
---|
418 | (index -1) handlers cases) |
---|
419 | (while clauses |
---|
420 | (setq index (1+ index)) |
---|
421 | (multiple-value-bind (type var body) |
---|
422 | (apply #'handler-case (pop clauses)) |
---|
423 | (push `',type handlers) |
---|
424 | (push index handlers) |
---|
425 | (when (null clauses) (setq index t)) |
---|
426 | (push (if var |
---|
427 | `(,index ((lambda ,var ,@body) ,val)) |
---|
428 | `(,index (locally ,@body))) cases))) |
---|
429 | `(block ,block |
---|
430 | (let ((,val (let* ((,cluster (list ,@(nreverse handlers))) |
---|
431 | (%handlers% (cons ,cluster %handlers%))) |
---|
432 | (declare (dynamic-extent ,cluster %handlers%)) |
---|
433 | (catch ,cluster (return-from ,block ,form))))) |
---|
434 | (case (pop ,val) |
---|
435 | ,@(nreverse cases))))))))))) |
---|
436 | |
---|
437 | (defmacro with-simple-restart ((restart-name format-string &rest format-args) |
---|
438 | &body body |
---|
439 | &aux (cluster (gensym)) (temp (make-symbol (symbol-name restart-name)))) |
---|
440 | "(WITH-SIMPLE-RESTART (restart-name format-string format-arguments) |
---|
441 | body) |
---|
442 | If restart-name is not invoked, then all values returned by forms are |
---|
443 | returned. If control is transferred to this restart, it immediately |
---|
444 | returns the values NIL and T." |
---|
445 | (unless (and (stringp format-string) |
---|
446 | (null format-args) |
---|
447 | (not (%str-member #\~ (ensure-simple-string format-string)))) |
---|
448 | (let ((stream (gensym))) |
---|
449 | (setq format-string `#'(lambda (,stream) (format ,stream ,format-string ,@format-args))))) |
---|
450 | `(let* ((,temp (%cons-restart ',restart-name |
---|
451 | 'simple-restart |
---|
452 | ,format-string |
---|
453 | nil |
---|
454 | nil)) |
---|
455 | (,cluster (list ,temp)) |
---|
456 | (%restarts% (cons ,cluster %restarts%))) |
---|
457 | (declare (dynamic-extent ,temp ,cluster %restarts%)) |
---|
458 | (catch ,cluster ,@body))) |
---|
459 | |
---|
460 | ;Like with-simple-restart but takes a pre-consed restart. Not CL. |
---|
461 | (defmacro with-restart (restart &body body &aux (cluster (gensym))) |
---|
462 | `(let* ((,cluster (list ,restart)) |
---|
463 | (%restarts% (cons ,cluster %restarts%))) |
---|
464 | (declare (dynamic-extent ,cluster %restarts%)) |
---|
465 | (catch ,cluster ,@body))) |
---|
466 | |
---|
467 | (defmacro ignore-errors (&rest forms) |
---|
468 | "Execute FORMS handling ERROR conditions, returning the result of the last |
---|
469 | form, or (VALUES NIL the-ERROR-that-was-caught) if an ERROR was handled." |
---|
470 | `(handler-case (progn ,@forms) |
---|
471 | (error (condition) (values nil condition)))) |
---|
472 | |
---|
473 | (defmacro def-kernel-restart (&environment env errno name arglist &body body) |
---|
474 | (multiple-value-bind (body decls) |
---|
475 | (parse-body body env) |
---|
476 | `(let* ((fn (nfunction ,name (lambda ,arglist ,@decls (block ,name ,@body)))) |
---|
477 | (pair (assq ,errno ccl::*kernel-restarts*))) |
---|
478 | (if pair |
---|
479 | (rplacd pair fn) |
---|
480 | (push (cons ,errno fn) ccl::*kernel-restarts*)) |
---|
481 | fn))) |
---|
482 | |
---|
483 | |
---|
484 | ;;; Setf. |
---|
485 | |
---|
486 | ; If you change anything here, be sure to make the corresponding change |
---|
487 | ; in get-setf-method. |
---|
488 | (defmacro setf (&rest args &environment env) |
---|
489 | "Takes pairs of arguments like SETQ. The first is a place and the second |
---|
490 | is the value that is supposed to go into that place. Returns the last |
---|
491 | value. The place argument may be any of the access forms for which SETF |
---|
492 | knows a corresponding setting form." |
---|
493 | (let ((temp (length args)) |
---|
494 | (accessor nil)) |
---|
495 | (cond ((eq temp 2) |
---|
496 | (let* ((form (car args)) |
---|
497 | (value (cadr args))) |
---|
498 | ;This must match get-setf-method . |
---|
499 | (if (atom form) |
---|
500 | (progn |
---|
501 | (unless (symbolp form)(signal-program-error $XNotSym form)) |
---|
502 | `(setq ,form ,value)) |
---|
503 | (multiple-value-bind (ftype local-p) |
---|
504 | (function-information (setq accessor (car form)) ENV) |
---|
505 | (if local-p |
---|
506 | (if (eq ftype :function) |
---|
507 | ;Local function, so don't use global setf definitions. |
---|
508 | (default-setf form value env) |
---|
509 | `(setf ,(macroexpand-1 form env) ,value)) |
---|
510 | (cond |
---|
511 | ((setq temp (%setf-method accessor)) |
---|
512 | (if (symbolp temp) |
---|
513 | `(,temp ,@(cdar args) ,value) |
---|
514 | (multiple-value-bind (dummies vals storevars setter #|getter|#) |
---|
515 | (funcall temp form env) |
---|
516 | (do* ((d dummies (cdr d)) |
---|
517 | (v vals (cdr v)) |
---|
518 | (let-list nil)) |
---|
519 | ((null d) |
---|
520 | (setq let-list (nreverse let-list)) |
---|
521 | `(let* ,let-list |
---|
522 | (declare (ignorable ,@dummies)) |
---|
523 | (multiple-value-bind ,storevars ,value |
---|
524 | #|,getter|# |
---|
525 | ,setter))) |
---|
526 | (push (list (car d) (car v)) let-list))))) |
---|
527 | ((and (type-and-refinfo-p (setq temp (or (environment-structref-info accessor env) |
---|
528 | (and #-bccl (boundp '%structure-refs%) |
---|
529 | (gethash accessor %structure-refs%))))) |
---|
530 | (not (refinfo-r/o (if (consp temp) (%cdr temp) temp)))) |
---|
531 | (if (consp temp) |
---|
532 | ;; strip off type, but add in a require-type |
---|
533 | (let ((type (%car temp))) |
---|
534 | `(the ,type (setf ,(defstruct-ref-transform (%cdr temp) (%cdar args)) |
---|
535 | (require-type ,value ',type)))) |
---|
536 | `(setf ,(defstruct-ref-transform temp (%cdar args)) |
---|
537 | ,value))) |
---|
538 | (t |
---|
539 | (multiple-value-bind (res win) |
---|
540 | (macroexpand-1 form env) |
---|
541 | (if win |
---|
542 | `(setf ,res ,value) |
---|
543 | (default-setf form value env)))))))))) |
---|
544 | ((oddp temp) |
---|
545 | (error "Odd number of args to SETF : ~s." args)) |
---|
546 | (t (do* ((a args (cddr a)) (l nil)) |
---|
547 | ((null a) `(progn ,@(nreverse l))) |
---|
548 | (push `(setf ,(car a) ,(cadr a)) l)))))) |
---|
549 | |
---|
550 | |
---|
551 | (defun default-setf (setter value &optional env) |
---|
552 | (let* ((reader (car setter)) |
---|
553 | (args (cdr setter)) |
---|
554 | (gensyms (mapcar #'(lambda (sym) (declare (ignore sym)) (gensym)) args)) |
---|
555 | types declares) |
---|
556 | (flet ((form-type (form) |
---|
557 | (nx-form-type form env))) |
---|
558 | (declare (dynamic-extent #'form-type)) |
---|
559 | (setq types (mapcar #'form-type args))) |
---|
560 | (dolist (sym gensyms) |
---|
561 | (let ((sym-type (pop types))) |
---|
562 | (unless (eq sym-type t) |
---|
563 | (push `(type ,sym-type ,sym) declares)))) |
---|
564 | `(let ,(mapcar #'list gensyms args) |
---|
565 | ,@(and declares (list `(declare ,@(nreverse declares)))) |
---|
566 | (funcall #'(setf ,reader) ,value ,@gensyms)))) |
---|
567 | |
---|
568 | ;; Establishing these setf-inverses is something that should |
---|
569 | ;; happen at compile-time |
---|
570 | (defsetf elt set-elt) |
---|
571 | (defsetf car set-car) |
---|
572 | (defsetf first set-car) |
---|
573 | (defsetf cdr set-cdr) |
---|
574 | (defsetf rest set-cdr) |
---|
575 | (defsetf uvref uvset) |
---|
576 | (defsetf aref aset) |
---|
577 | (defsetf svref svset) |
---|
578 | (defsetf %svref %svset) |
---|
579 | (defsetf char set-char) |
---|
580 | (defsetf schar set-schar) |
---|
581 | (defsetf %scharcode %set-scharcode) |
---|
582 | (defsetf symbol-value set) |
---|
583 | (defsetf symbol-plist set-symbol-plist) |
---|
584 | (defsetf fill-pointer set-fill-pointer) |
---|
585 | |
---|
586 | ; This sux; it calls the compiler twice (once to shove the macro in the |
---|
587 | ; environment, once to dump it into the file.) |
---|
588 | (defmacro defmacro (name arglist &body body &environment env) |
---|
589 | (unless (symbolp name)(signal-program-error $XNotSym name)) |
---|
590 | (unless (listp arglist) (signal-program-error "~S is not a list." arglist)) |
---|
591 | (multiple-value-bind (lambda-form doc) |
---|
592 | (parse-macro-1 name arglist body env) |
---|
593 | (let* ((normalized (normalize-lambda-list arglist t t)) |
---|
594 | (body-pos (position '&body normalized)) |
---|
595 | (argstring (let ((temp nil)) |
---|
596 | (dolist (arg normalized) |
---|
597 | (if (eq arg '&aux) |
---|
598 | (return) |
---|
599 | (push arg temp))) |
---|
600 | (format nil "~:a" (nreverse temp))))) |
---|
601 | (if (and body-pos (memq '&optional normalized)) (decf body-pos)) |
---|
602 | `(progn |
---|
603 | (eval-when (:compile-toplevel) |
---|
604 | (define-compile-time-macro ',name ',lambda-form ',env)) |
---|
605 | (eval-when (:load-toplevel :execute) |
---|
606 | (%macro |
---|
607 | (nfunction ,name ,lambda-form) |
---|
608 | '(,doc ,body-pos . ,argstring)) |
---|
609 | ',name))))) |
---|
610 | |
---|
611 | (defmacro define-symbol-macro (name expansion &environment env) |
---|
612 | (unless (symbolp name)(signal-program-error $XNotSym name)) |
---|
613 | `(progn |
---|
614 | (eval-when (:compile-toplevel) |
---|
615 | (define-compile-time-symbol-macro ',name ',expansion ',env)) |
---|
616 | (eval-when (:load-toplevel :execute) |
---|
617 | (%define-symbol-macro ',name ',expansion)))) |
---|
618 | |
---|
619 | ;; ---- allow inlining setf functions |
---|
620 | (defmacro defun (spec args &body body &environment env &aux global-name inline-spec) |
---|
621 | "Define a function at top level." |
---|
622 | (validate-function-name spec) |
---|
623 | (setq args (require-type args 'list)) |
---|
624 | (setq body (require-type body 'list)) |
---|
625 | (multiple-value-bind (forms decls doc) (parse-body body env t) |
---|
626 | (cond ((symbolp spec) |
---|
627 | (setq global-name spec) |
---|
628 | (setq inline-spec spec) |
---|
629 | (setq body `(block ,spec ,@forms))) |
---|
630 | ((and (consp spec) (eq 'setf (%car spec))) |
---|
631 | (setq inline-spec spec) |
---|
632 | (setq body `(block ,(cadr spec) ,@forms))) |
---|
633 | (t (setq body `(progn ,@forms)))) |
---|
634 | (let* ((lambda-expression `(lambda ,args |
---|
635 | ,@(if global-name |
---|
636 | `((declare (global-function-name ,global-name)))) |
---|
637 | ,@decls ,body)) |
---|
638 | (info (if (and inline-spec |
---|
639 | (or (null env) |
---|
640 | (definition-environment env t)) |
---|
641 | (nx-declared-inline-p inline-spec env) |
---|
642 | (not (and (symbolp inline-spec) |
---|
643 | (gethash inline-spec *NX1-ALPHATIZERS*)))) |
---|
644 | (cons doc lambda-expression) |
---|
645 | doc))) |
---|
646 | `(progn |
---|
647 | (eval-when (:compile-toplevel) |
---|
648 | (note-function-info ',spec ',lambda-expression ,env)) |
---|
649 | (%defun (nfunction ,spec ,lambda-expression) ',info) |
---|
650 | ',spec)))) |
---|
651 | |
---|
652 | (defmacro %defvar-init (var initform doc) |
---|
653 | `(unless (%defvar ',var ,doc) |
---|
654 | (setq ,var ,initform))) |
---|
655 | |
---|
656 | (defmacro defvar (&environment env var &optional (value () value-p) doc) |
---|
657 | "Define a global variable at top level. Declare the variable |
---|
658 | SPECIAL and, optionally, initialize it. If the variable already has a |
---|
659 | value, the old value is not clobbered. The third argument is an optional |
---|
660 | documentation string for the variable." |
---|
661 | (if (and doc (not (stringp doc))) (report-bad-arg doc 'string)) |
---|
662 | (if (and (compile-file-environment-p env) (not *fasl-save-doc-strings*)) |
---|
663 | (setq doc nil)) |
---|
664 | `(progn |
---|
665 | (eval-when (:compile-toplevel) |
---|
666 | (note-variable-info ',var ,value-p ,env)) |
---|
667 | ,(if value-p |
---|
668 | `(%defvar-init ,var ,value ,doc) |
---|
669 | `(%defvar ',var)) |
---|
670 | ',var)) |
---|
671 | |
---|
672 | (defmacro def-standard-initial-binding (name &optional (form name) &environment env) |
---|
673 | `(progn |
---|
674 | (eval-when (:compile-toplevel) |
---|
675 | (note-variable-info ',name t ,env)) |
---|
676 | (define-standard-initial-binding ',name #'(lambda () ,form)) |
---|
677 | ',name)) |
---|
678 | |
---|
679 | (defmacro defparameter (&environment env var value &optional doc) |
---|
680 | "Define a parameter that is not normally changed by the program, |
---|
681 | but that may be changed without causing an error. Declare the |
---|
682 | variable special and sets its value to VAL, overwriting any |
---|
683 | previous value. The third argument is an optional documentation |
---|
684 | string for the parameter." |
---|
685 | (if (and doc (not (stringp doc))) (signal-program-error "~S is not a string." doc)) |
---|
686 | (if (and (compile-file-environment-p env) (not *fasl-save-doc-strings*)) |
---|
687 | (setq doc nil)) |
---|
688 | `(progn |
---|
689 | (eval-when (:compile-toplevel) |
---|
690 | (note-variable-info ',var t ,env)) |
---|
691 | (%defparameter ',var ,value ,doc))) |
---|
692 | |
---|
693 | |
---|
694 | (defmacro defstatic (&environment env var value &optional doc) |
---|
695 | "Syntax is like DEFPARAMETER. Proclaims the symbol to be special, |
---|
696 | but also asserts that it will never be given a per-thread dynamic |
---|
697 | binding. The value of the variable can be changed (via SETQ, etc.), |
---|
698 | but since all threads access the same static binding of the variable, |
---|
699 | such changes should be made with care." |
---|
700 | (if (and doc (not (stringp doc))) (signal-program-error "~S is not a string." doc)) |
---|
701 | (if (and (compile-file-environment-p env) (not *fasl-save-doc-strings*)) |
---|
702 | (setq doc nil)) |
---|
703 | `(progn |
---|
704 | (eval-when (:compile-toplevel) |
---|
705 | (note-variable-info ',var :global ,env)) |
---|
706 | (%defglobal ',var ,value ,doc))) |
---|
707 | |
---|
708 | |
---|
709 | (defmacro defglobal (&rest args) |
---|
710 | "Synonym for DEFSTATIC." |
---|
711 | `(defstatic ,@args)) |
---|
712 | |
---|
713 | |
---|
714 | (defmacro defloadvar (&environment env var value &optional doc) |
---|
715 | `(progn |
---|
716 | (defstatic ,var ,nil ,@(if doc `(,doc))) |
---|
717 | (def-ccl-pointers ,var () |
---|
718 | (setq ,var ,value)) |
---|
719 | ',var)) |
---|
720 | |
---|
721 | |
---|
722 | |
---|
723 | |
---|
724 | (defmacro qlfun (name args &body body) |
---|
725 | `(nfunction ,name (lambda ,args ,@body))) |
---|
726 | |
---|
727 | (defmacro lfun-bits-known-function (f) |
---|
728 | (let* ((temp (gensym))) |
---|
729 | `(let* ((,temp (function-to-function-vector ,f))) |
---|
730 | (%svref ,temp (the fixnum (1- (the fixnum (uvsize ,temp)))))))) |
---|
731 | |
---|
732 | ; %Pascal-Functions% Entry |
---|
733 | ; Used by "l1;ppc-callback-support" & "lib;dumplisp" |
---|
734 | (def-accessor-macros %svref |
---|
735 | pfe.routine-descriptor |
---|
736 | pfe.proc-info |
---|
737 | pfe.lisp-function |
---|
738 | pfe.sym |
---|
739 | pfe.without-interrupts |
---|
740 | pfe.trace-p) |
---|
741 | |
---|
742 | (defmacro cond (&rest args &aux clause) |
---|
743 | (when args |
---|
744 | (setq clause (car args)) |
---|
745 | (if (cdr clause) |
---|
746 | `(if ,(car clause) (progn ,@(cdr clause)) (cond ,@(cdr args))) |
---|
747 | (if (cdr args) `(or ,(car clause) (cond ,@(cdr args))) |
---|
748 | `(values ,(car clause)))))) |
---|
749 | |
---|
750 | (defmacro and (&rest args) |
---|
751 | "And Form* |
---|
752 | AND evaluates each form in sequence, from left to right. If any form |
---|
753 | returns NIL, AND returns NIL; otherwise, AND returns the values(s) returned |
---|
754 | by the last form. If there are no forms, AND returns T." |
---|
755 | (if (null args) t |
---|
756 | (if (null (cdr args)) (car args) |
---|
757 | `(if ,(car args) (and ,@(cdr args)))))) |
---|
758 | |
---|
759 | (defmacro or (&rest args) |
---|
760 | "Or Form* |
---|
761 | OR evaluates each Form, in sequence, from left to right. |
---|
762 | If any Form but the last returns a non-NIL value, OR returns that |
---|
763 | single value (without evaluating any subsequent Forms.) If OR evaluates |
---|
764 | the last Form, it returns all values returned by that Form. If there |
---|
765 | are no Forms, OR returns NIL." |
---|
766 | (if args |
---|
767 | (if (cdr args) |
---|
768 | (do* ((temp (gensym)) |
---|
769 | (handle (list nil)) |
---|
770 | (forms `(let ((,temp ,(pop args))) |
---|
771 | (if ,temp ,temp ,@handle)))) |
---|
772 | ((null (cdr args)) |
---|
773 | (%rplaca handle (%car args)) |
---|
774 | forms) |
---|
775 | (%rplaca handle `(if (setq ,temp ,(%car args)) |
---|
776 | ,temp |
---|
777 | ,@(setq handle (list nil)))) |
---|
778 | (setq args (%cdr args))) |
---|
779 | (%car args)))) |
---|
780 | |
---|
781 | (defmacro case (key &body forms) |
---|
782 | "CASE Keyform {({(Key*) | Key} Form*)}* |
---|
783 | Evaluates the Forms in the first clause with a Key EQL to the value of |
---|
784 | Keyform. If a singleton key is T then the clause is a default clause." |
---|
785 | (let ((key-var (gensym))) |
---|
786 | `(let ((,key-var ,key)) |
---|
787 | (declare (ignorable ,key-var)) |
---|
788 | (cond ,@(case-aux forms key-var nil nil))))) |
---|
789 | |
---|
790 | (defmacro ccase (keyplace &body forms) |
---|
791 | "CCASE Keyform {({(Key*) | Key} Form*)}* |
---|
792 | Evaluates the Forms in the first clause with a Key EQL to the value of |
---|
793 | Keyform. If none of the keys matches then a correctable error is |
---|
794 | signalled." |
---|
795 | (let* ((key-var (gensym)) |
---|
796 | (tag (gensym))) |
---|
797 | `(prog (,key-var) |
---|
798 | ,tag |
---|
799 | (setq ,key-var ,keyplace) |
---|
800 | (return (cond ,@(case-aux forms key-var tag keyplace)))))) |
---|
801 | |
---|
802 | (defmacro ecase (key &body forms) |
---|
803 | "ECASE Keyform {({(Key*) | Key} Form*)}* |
---|
804 | Evaluates the Forms in the first clause with a Key EQL to the value of |
---|
805 | Keyform. If none of the keys matches then an error is signalled." |
---|
806 | (let* ((key-var (gensym))) |
---|
807 | `(let ((,key-var ,key)) |
---|
808 | (declare (ignorable ,key-var)) |
---|
809 | (cond ,@(case-aux forms key-var 'ecase nil))))) |
---|
810 | |
---|
811 | (defun case-aux (clauses key-var e-c-p placename &optional (used-keys (list (list '%case-core)))) |
---|
812 | (if clauses |
---|
813 | (let* ((key-list (caar clauses)) |
---|
814 | (stype (if e-c-p (if (eq e-c-p 'ecase) e-c-p 'ccase) 'case)) |
---|
815 | (test (cond ((and (not e-c-p) |
---|
816 | (or (eq key-list 't) |
---|
817 | (eq key-list 'otherwise))) |
---|
818 | t) |
---|
819 | (key-list |
---|
820 | (cons 'or |
---|
821 | (case-key-testers key-var used-keys key-list stype))))) |
---|
822 | (consequent-list (or (%cdar clauses) '(nil)))) |
---|
823 | (if (eq test t) |
---|
824 | (progn |
---|
825 | (when (%cdr clauses) (warn "~s or ~s clause in the middle of a ~s statement. Subsequent clauses ignored." |
---|
826 | 't 'otherwise 'case)) |
---|
827 | (cons (cons t consequent-list) nil)) |
---|
828 | (cons (cons test consequent-list) |
---|
829 | (case-aux (%cdr clauses) key-var e-c-p placename used-keys)))) |
---|
830 | (when e-c-p |
---|
831 | (setq used-keys `(member ,@(mapcar #'car (cdr used-keys)))) |
---|
832 | (if (eq e-c-p 'ecase) |
---|
833 | `((t (values (%err-disp #.$XWRONGTYPE ,key-var ',used-keys)))) |
---|
834 | `((t (setf ,placename (ensure-value-of-type ,key-var ',used-keys ',placename)) |
---|
835 | (go ,e-c-p))))))) |
---|
836 | |
---|
837 | |
---|
838 | ;;; We don't want to descend list structure more than once (like this has |
---|
839 | ;;; been doing for the last 18 years or so.) |
---|
840 | (defun case-key-testers (symbol used-keys atom-or-list statement-type &optional recursive) |
---|
841 | (if (or recursive (atom atom-or-list)) |
---|
842 | (progn |
---|
843 | (if (assoc atom-or-list used-keys) |
---|
844 | (warn "Duplicate keyform ~s in ~s statement." atom-or-list statement-type) |
---|
845 | (nconc used-keys (list (cons atom-or-list t)))) |
---|
846 | `((,(if (typep atom-or-list '(and number (not fixnum))) |
---|
847 | 'eql |
---|
848 | 'eq) |
---|
849 | ,symbol ',atom-or-list))) |
---|
850 | (nconc (case-key-testers symbol used-keys (car atom-or-list) statement-type t) |
---|
851 | (when (cdr atom-or-list) |
---|
852 | (case-key-testers symbol used-keys (%cdr atom-or-list) statement-type nil))))) |
---|
853 | |
---|
854 | |
---|
855 | ; generate the COND body of a {C,E}TYPECASE form |
---|
856 | (defun typecase-aux (key-var clauses &optional e-c-p keyform) |
---|
857 | (let* ((construct (if e-c-p (if (eq e-c-p 'etypecase) e-c-p 'ctypecase) 'typecase)) |
---|
858 | (types ()) |
---|
859 | (body ()) |
---|
860 | otherwise-seen-p) |
---|
861 | (flet ((bad-clause (c) |
---|
862 | (error "Invalid clause ~S in ~S form." c construct))) |
---|
863 | (dolist (clause clauses) |
---|
864 | (if (atom clause) |
---|
865 | (bad-clause clause)) |
---|
866 | (if otherwise-seen-p |
---|
867 | (error "OTHERWISE must be final clause in ~S form." construct)) |
---|
868 | (destructuring-bind (typespec &body consequents) clause |
---|
869 | (when (eq construct 'typecase) |
---|
870 | (if (eq typespec 'otherwise) |
---|
871 | (progn (setq typespec t) |
---|
872 | (setq otherwise-seen-p t)))) |
---|
873 | (unless |
---|
874 | (dolist (already types nil) |
---|
875 | (when (subtypep typespec already) |
---|
876 | (warn "Clause ~S ignored in ~S form - shadowed by ~S ." clause construct (assq already clauses)) |
---|
877 | (return t))) |
---|
878 | (push typespec types) |
---|
879 | (setq typespec `(typep ,key-var ',typespec)) |
---|
880 | (push `(,typespec nil ,@consequents) body)))) |
---|
881 | (when e-c-p |
---|
882 | (setq types `(or ,@(nreverse types))) |
---|
883 | (if (eq construct 'etypecase) |
---|
884 | (push `(t (values (%err-disp #.$XWRONGTYPE ,key-var ',types))) body) |
---|
885 | (push `(t (setf ,keyform (ensure-value-of-type ,key-var ',types ',keyform)) |
---|
886 | (go ,e-c-p)) body)))) |
---|
887 | `(cond ,@(nreverse body)))) |
---|
888 | |
---|
889 | (defmacro typecase (keyform &body clauses) |
---|
890 | "TYPECASE Keyform {(Type Form*)}* |
---|
891 | Evaluates the Forms in the first clause for which TYPEP of Keyform and Type |
---|
892 | is true." |
---|
893 | (let ((key-var (gensym))) |
---|
894 | `(let ((,key-var ,keyform)) |
---|
895 | (declare (ignorable ,key-var)) |
---|
896 | ,(typecase-aux key-var clauses)))) |
---|
897 | |
---|
898 | (defmacro etypecase (keyform &body clauses) |
---|
899 | "ETYPECASE Keyform {(Type Form*)}* |
---|
900 | Evaluates the Forms in the first clause for which TYPEP of Keyform and Type |
---|
901 | is true. If no form is satisfied then an error is signalled." |
---|
902 | (let ((key-var (gensym))) |
---|
903 | `(let ((,key-var ,keyform)) |
---|
904 | (declare (ignorable ,key-var)) |
---|
905 | ,(typecase-aux key-var clauses 'etypecase)))) |
---|
906 | |
---|
907 | (defmacro ctypecase (keyplace &body clauses) |
---|
908 | "CTYPECASE Key {(Type Form*)}* |
---|
909 | Evaluates the Forms in the first clause for which TYPEP of Keyform and Type |
---|
910 | is true. If no form is satisfied then a correctable error is signalled." |
---|
911 | (let ((key-var (gensym)) |
---|
912 | (tag (gensym))) |
---|
913 | `(prog (,key-var) |
---|
914 | ,tag |
---|
915 | (setq ,key-var ,keyplace) |
---|
916 | (return ,(typecase-aux key-var clauses tag keyplace))))) |
---|
917 | |
---|
918 | (defmacro destructuring-bind (lambda-list expression &body body) |
---|
919 | "Bind the variables in LAMBDA-LIST to the contents of ARG-LIST." |
---|
920 | (multiple-value-bind (bindings decls) |
---|
921 | (%destructure-lambda-list lambda-list expression nil nil) |
---|
922 | `(let* ,(nreverse bindings) |
---|
923 | ,@(when decls `((declare ,@decls))) |
---|
924 | ,@body))) |
---|
925 | |
---|
926 | (defmacro make-destructure-state (tail whole lambda) |
---|
927 | `(gvector :istruct 'destructure-state ,tail ,whole ,lambda)) |
---|
928 | |
---|
929 | |
---|
930 | ; This is supposedly ANSI CL. |
---|
931 | (defmacro lambda (&whole lambda-expression (&rest paramlist) &body body) |
---|
932 | (unless (lambda-expression-p lambda-expression) |
---|
933 | (warn "Invalid lambda expression: ~s" lambda-expression)) |
---|
934 | `(function (lambda ,paramlist ,@body))) |
---|
935 | |
---|
936 | |
---|
937 | (defmacro when (test &body body) |
---|
938 | "If the first argument is true, the rest of the forms are |
---|
939 | evaluated as a PROGN." |
---|
940 | `(if ,test |
---|
941 | (progn ,@body))) |
---|
942 | |
---|
943 | (defmacro unless (test &body body) |
---|
944 | "If the first argument is not true, the rest of the forms are |
---|
945 | evaluated as a PROGN." |
---|
946 | `(if (not ,test) |
---|
947 | (progn ,@body))) |
---|
948 | |
---|
949 | (defmacro return (&optional (form nil form-p)) |
---|
950 | `(return-from nil ,@(if form-p `(,form)))) |
---|
951 | |
---|
952 | ; since they use tagbody, while & until BOTH return NIL |
---|
953 | (defmacro while (test &body body) |
---|
954 | (let ((testlab (gensym)) |
---|
955 | (toplab (gensym))) |
---|
956 | `(tagbody |
---|
957 | (go ,testlab) |
---|
958 | ,toplab |
---|
959 | (progn ,@body) |
---|
960 | ,testlab |
---|
961 | (when ,test (go ,toplab))))) |
---|
962 | |
---|
963 | (defmacro until (test &body body) |
---|
964 | (let ((testlab (gensym)) |
---|
965 | (toplab (gensym))) |
---|
966 | `(tagbody |
---|
967 | (go ,testlab) |
---|
968 | ,toplab |
---|
969 | (progn ,@body) |
---|
970 | ,testlab |
---|
971 | (if (not ,test) |
---|
972 | (go ,toplab))))) |
---|
973 | |
---|
974 | (defmacro psetq (&whole call &body pairs &environment env) |
---|
975 | "PSETQ {var value}* |
---|
976 | Set the variables to the values, like SETQ, except that assignments |
---|
977 | happen in parallel, i.e. no assignments take place until all the |
---|
978 | forms have been evaluated." |
---|
979 | (when pairs |
---|
980 | (if (evenp (length pairs)) |
---|
981 | (do* ((l pairs (%cddr l)) |
---|
982 | (sym (%car l) (%car l))) |
---|
983 | ((null l) (%pset pairs)) |
---|
984 | (unless (symbolp sym) (report-bad-arg sym 'symbol)) |
---|
985 | (when (nth-value 1 (macroexpand-1 sym env)) |
---|
986 | (return `(psetf ,@pairs)))) |
---|
987 | (error "Uneven number of args in the call ~S" call)))) |
---|
988 | |
---|
989 | ; generates body for psetq. |
---|
990 | ; "pairs" is a proper list whose length is not odd. |
---|
991 | (defun %pset (pairs) |
---|
992 | (when pairs |
---|
993 | (let (vars vals gensyms let-list var val sets) |
---|
994 | (loop |
---|
995 | (setq var (pop pairs) |
---|
996 | val (pop pairs)) |
---|
997 | (if (null pairs) (return)) |
---|
998 | (push var vars) |
---|
999 | (push val vals) |
---|
1000 | (push (gensym) gensyms)) |
---|
1001 | (dolist (g gensyms) |
---|
1002 | (push g sets) |
---|
1003 | (push (pop vars) sets) |
---|
1004 | (push (list g (pop vals)) let-list)) |
---|
1005 | (push val sets) |
---|
1006 | (push var sets) |
---|
1007 | `(progn |
---|
1008 | (let ,let-list |
---|
1009 | (setq ,@sets)) |
---|
1010 | nil)))) |
---|
1011 | |
---|
1012 | |
---|
1013 | (eval-when (:compile-toplevel :load-toplevel :execute) |
---|
1014 | (defun do-loop (binder setter env var-init-steps end-test result body) |
---|
1015 | (let ((toptag (gensym)) |
---|
1016 | (testtag (gensym))) |
---|
1017 | (multiple-value-bind (forms decls) (parse-body body env nil) |
---|
1018 | `(block nil |
---|
1019 | (,binder ,(do-let-vars var-init-steps) |
---|
1020 | ,@decls |
---|
1021 | (tagbody ; crocks-r-us. |
---|
1022 | (go ,testtag) |
---|
1023 | ,toptag |
---|
1024 | (tagbody |
---|
1025 | ,@forms) |
---|
1026 | (,setter ,@(do-step-vars var-init-steps)) |
---|
1027 | ,testtag |
---|
1028 | (unless ,end-test |
---|
1029 | (go ,toptag))) |
---|
1030 | ,@result))))) |
---|
1031 | ) |
---|
1032 | |
---|
1033 | (defmacro do (&environment env var-init-steps (&optional end-test &rest result) &body body) |
---|
1034 | "DO ({(Var [Init] [Step])}*) (Test Exit-Form*) Declaration* Form* |
---|
1035 | Iteration construct. Each Var is initialized in parallel to the value of the |
---|
1036 | specified Init form. On subsequent iterations, the Vars are assigned the |
---|
1037 | value of the Step form (if any) in parallel. The Test is evaluated before |
---|
1038 | each evaluation of the body Forms. When the Test is true, the Exit-Forms |
---|
1039 | are evaluated as a PROGN, with the result being the value of the DO. A block |
---|
1040 | named NIL is established around the entire expansion, allowing RETURN to be |
---|
1041 | used as an alternate exit mechanism." |
---|
1042 | (do-loop 'let 'psetq env var-init-steps end-test result body)) |
---|
1043 | |
---|
1044 | (defmacro do* (&environment env var-init-steps (&optional end-test &rest result) &body body) |
---|
1045 | "DO* ({(Var [Init] [Step])}*) (Test Exit-Form*) Declaration* Form* |
---|
1046 | Iteration construct. Each Var is initialized sequentially (like LET*) to the |
---|
1047 | value of the specified Init form. On subsequent iterations, the Vars are |
---|
1048 | sequentially assigned the value of the Step form (if any). The Test is |
---|
1049 | evaluated before each evaluation of the body Forms. When the Test is true, |
---|
1050 | the Exit-Forms are evaluated as a PROGN, with the result being the value |
---|
1051 | of the DO. A block named NIL is established around the entire expansion, |
---|
1052 | allowing RETURN to be used as an laternate exit mechanism." |
---|
1053 | (do-loop 'let* 'setq env var-init-steps end-test result body)) |
---|
1054 | |
---|
1055 | |
---|
1056 | (defun do-let-vars (var-init-steps) |
---|
1057 | (if var-init-steps |
---|
1058 | (cons (list (do-let-vars-var (car var-init-steps)) |
---|
1059 | (do-let-vars-init (car var-init-steps))) |
---|
1060 | (do-let-vars (cdr var-init-steps))))) |
---|
1061 | |
---|
1062 | (defun do-let-vars-var (var-init-step) |
---|
1063 | (if (consp var-init-step) |
---|
1064 | (car var-init-step) |
---|
1065 | var-init-step)) |
---|
1066 | |
---|
1067 | (defun do-let-vars-init (var-init-step) |
---|
1068 | (if (consp var-init-step) |
---|
1069 | (cadr var-init-step) |
---|
1070 | nil)) |
---|
1071 | |
---|
1072 | (defun do-step-vars (var-init-steps) |
---|
1073 | (if var-init-steps |
---|
1074 | (if (do-step-vars-step? (car var-init-steps)) |
---|
1075 | (append (list (do-let-vars-var (car var-init-steps)) |
---|
1076 | (do-step-vars-step (car var-init-steps))) |
---|
1077 | (do-step-vars (cdr var-init-steps))) |
---|
1078 | (do-step-vars (cdr var-init-steps))))) |
---|
1079 | |
---|
1080 | (defun do-step-vars-step? (var-init-step) |
---|
1081 | (if (consp var-init-step) |
---|
1082 | (cddr var-init-step))) |
---|
1083 | |
---|
1084 | (defun do-step-vars-step (var-init-step) |
---|
1085 | (if (consp var-init-step) |
---|
1086 | (caddr var-init-step))) |
---|
1087 | |
---|
1088 | |
---|
1089 | (defmacro dotimes ((i n &optional result) &body body &environment env) |
---|
1090 | (multiple-value-bind (forms decls) |
---|
1091 | (parse-body body env) |
---|
1092 | (if (not (symbolp i))(signal-program-error $Xnotsym i)) |
---|
1093 | (let* ((toptag (gensym)) |
---|
1094 | (limit (gensym))) |
---|
1095 | `(block nil |
---|
1096 | (let ((,limit ,n) (,i 0)) |
---|
1097 | ,@decls |
---|
1098 | (declare (unsettable ,i)) |
---|
1099 | (if (int>0-p ,limit) |
---|
1100 | (tagbody |
---|
1101 | ,toptag |
---|
1102 | ,@forms |
---|
1103 | (locally |
---|
1104 | (declare (settable ,i)) |
---|
1105 | (setq ,i (1+ ,i))) |
---|
1106 | (unless (eql ,i ,limit) (go ,toptag)))) |
---|
1107 | ,result))))) |
---|
1108 | |
---|
1109 | (defun do-syms-result (var resultform) |
---|
1110 | (unless (eq var resultform) |
---|
1111 | (if (and (consp resultform) (not (quoted-form-p resultform))) |
---|
1112 | `(progn (setq ,var nil) ,resultform) |
---|
1113 | resultform))) |
---|
1114 | |
---|
1115 | (defun expand-package-iteration-macro (iteration-function var pkg-spec resultform body env) |
---|
1116 | (multiple-value-bind (body decls) (parse-body body env nil) |
---|
1117 | (let* ((ftemp (gensym)) |
---|
1118 | (vtemp (gensym)) |
---|
1119 | (ptemp (gensym)) |
---|
1120 | (result (do-syms-result var resultform))) |
---|
1121 | `(block nil |
---|
1122 | (let* ((,var nil) |
---|
1123 | (,ptemp ,pkg-spec)) |
---|
1124 | ,@decls |
---|
1125 | (flet ((,ftemp (,vtemp) (declare (debugging-function-name nil)) (setq ,var ,vtemp) (tagbody ,@body))) |
---|
1126 | (declare (dynamic-extent #',ftemp)) |
---|
1127 | (,iteration-function ,ptemp #',ftemp)) |
---|
1128 | ,@(when result `(,result))))))) |
---|
1129 | |
---|
1130 | (defmacro do-symbols ((var &optional pkg result) &body body &environment env) |
---|
1131 | "DO-SYMBOLS (VAR [PACKAGE [RESULT-FORM]]) {DECLARATION}* {TAG | FORM}* |
---|
1132 | Executes the FORMs at least once for each symbol accessible in the given |
---|
1133 | PACKAGE with VAR bound to the current symbol." |
---|
1134 | (expand-package-iteration-macro 'iterate-over-accessable-symbols var pkg result body env)) |
---|
1135 | |
---|
1136 | (defmacro do-present-symbols ((var &optional pkg result) &body body &environment env) |
---|
1137 | (expand-package-iteration-macro 'iterate-over-present-symbols var pkg result body env)) |
---|
1138 | |
---|
1139 | (defmacro do-external-symbols ((var &optional pkg result) &body body &environment env) |
---|
1140 | "DO-EXTERNAL-SYMBOLS (VAR [PACKAGE [RESULT-FORM]]) {DECL}* {TAG | FORM}* |
---|
1141 | Executes the FORMs once for each external symbol in the given PACKAGE with |
---|
1142 | VAR bound to the current symbol." |
---|
1143 | (expand-package-iteration-macro 'iterate-over-external-symbols var pkg result body env)) |
---|
1144 | |
---|
1145 | (defmacro do-all-symbols ((var &optional resultform) |
---|
1146 | &body body &environment env) |
---|
1147 | "DO-ALL-SYMBOLS (VAR [RESULT-FORM]) {DECLARATION}* {TAG | FORM}* |
---|
1148 | Executes the FORMs once for each symbol in every package with VAR bound |
---|
1149 | to the current symbol." |
---|
1150 | (multiple-value-bind (body decls) (parse-body body env nil) |
---|
1151 | (let* ((ftemp (gensym)) |
---|
1152 | (vtemp (gensym)) |
---|
1153 | (result (do-syms-result var resultform))) |
---|
1154 | `(block nil |
---|
1155 | (let* ((,var nil)) |
---|
1156 | ,@decls |
---|
1157 | (flet ((,ftemp (,vtemp) (declare (debugging-function-name nil)) (setq ,var ,vtemp) (tagbody ,@body))) |
---|
1158 | (declare (dynamic-extent #',ftemp)) |
---|
1159 | (iterate-over-all-symbols #',ftemp)) |
---|
1160 | ,@(when result `(,result))))))) |
---|
1161 | |
---|
1162 | (defmacro multiple-value-list (form) |
---|
1163 | `(multiple-value-call #'list ,form)) |
---|
1164 | |
---|
1165 | |
---|
1166 | |
---|
1167 | |
---|
1168 | (defmacro %i> (x y) |
---|
1169 | `(> (the fixnum ,x) (the fixnum ,y))) |
---|
1170 | |
---|
1171 | (defmacro %i< (x y) |
---|
1172 | `(< (the fixnum ,x) (the fixnum ,y))) |
---|
1173 | |
---|
1174 | (defmacro %i<= (x y) |
---|
1175 | `(not (%i> ,x ,y))) |
---|
1176 | |
---|
1177 | (defmacro %i>= (x y) |
---|
1178 | `(not (%i< ,x ,y))) |
---|
1179 | |
---|
1180 | (defmacro bitset (bit number) |
---|
1181 | `(logior (ash 1 ,bit) ,number)) |
---|
1182 | |
---|
1183 | (defmacro bitclr (bit number) |
---|
1184 | `(logand (lognot (ash 1 ,bit)) ,number)) |
---|
1185 | |
---|
1186 | (defmacro bitopf ((op bit place) &environment env) |
---|
1187 | (multiple-value-bind (vars vals stores store-form access-form) |
---|
1188 | (get-setf-method place env) |
---|
1189 | (let* ((constant-bit-p (constantp bit)) |
---|
1190 | (bitvar (if constant-bit-p bit (gensym)))) |
---|
1191 | `(let ,(unless constant-bit-p `((,bitvar ,bit))) ; compiler isn't smart enough |
---|
1192 | (let* ,(mapcar #'list `(,@vars ,@stores) `(,@vals (,op ,bitvar ,access-form))) |
---|
1193 | ,store-form))))) |
---|
1194 | |
---|
1195 | (defmacro bitsetf (bit place) |
---|
1196 | `(bitopf (bitset ,bit ,place))) |
---|
1197 | |
---|
1198 | (defmacro bitclrf (bit place) |
---|
1199 | `(bitopf (bitclr ,bit ,place))) |
---|
1200 | |
---|
1201 | (defmacro %svref (v i) |
---|
1202 | (let* ((vtemp (make-symbol "VECTOR")) |
---|
1203 | (itemp (make-symbol "INDEX"))) |
---|
1204 | `(let* ((,vtemp ,v) |
---|
1205 | (,itemp ,i)) |
---|
1206 | (locally (declare (optimize (speed 3) (safety 0))) |
---|
1207 | (svref ,vtemp ,itemp))))) |
---|
1208 | |
---|
1209 | (defmacro %svset (v i new &environment env) |
---|
1210 | (let* ((vtemp (make-symbol "VECTOR")) |
---|
1211 | (itemp (make-symbol "INDEX")) |
---|
1212 | (ntemp (make-symbol "NEW"))) |
---|
1213 | `(let* ((,vtemp ,v) |
---|
1214 | (,itemp ,i) |
---|
1215 | (,ntemp ,new)) |
---|
1216 | (locally (declare (optimize (speed 3) (safety 0))) |
---|
1217 | (setf (svref ,vtemp ,itemp) ,ntemp))))) |
---|
1218 | |
---|
1219 | |
---|
1220 | (defmacro %schar (v i) |
---|
1221 | (let* ((vtemp (make-symbol "STRING")) |
---|
1222 | (itemp (make-symbol "INDEX"))) |
---|
1223 | `(let* ((,vtemp ,v) |
---|
1224 | (,itemp ,i)) |
---|
1225 | (locally (declare (optimize (speed 3) (safety 0))) |
---|
1226 | (schar ,vtemp ,itemp))))) |
---|
1227 | |
---|
1228 | (defmacro %set-schar (v i new) |
---|
1229 | (let* ((vtemp (make-symbol "STRING")) |
---|
1230 | (itemp (make-symbol "INDEX")) |
---|
1231 | (ntemp (make-symbol "NEW"))) |
---|
1232 | `(let* ((,vtemp ,v) |
---|
1233 | (,itemp ,i) |
---|
1234 | (,ntemp ,new)) |
---|
1235 | (locally (declare (optimize (speed 3) (safety 0))) |
---|
1236 | (setf (schar ,vtemp ,itemp) ,ntemp))))) |
---|
1237 | |
---|
1238 | |
---|
1239 | |
---|
1240 | (defmacro %char-code (c) `(char-code (the character ,c))) |
---|
1241 | (defmacro %code-char (i) `(code-char (the (mod 256) ,i))) |
---|
1242 | |
---|
1243 | (defmacro %izerop (x) `(eq ,x 0)) |
---|
1244 | (defmacro %iminusp (x) `(< (the fixnum ,x) 0)) |
---|
1245 | (defmacro %i+ (&rest (&optional (n0 0) &rest others)) |
---|
1246 | (if others |
---|
1247 | `(the fixnum (+ (the fixnum ,n0) (%i+ ,@others))) |
---|
1248 | `(the fixnum ,n0))) |
---|
1249 | (defmacro %i- (x y &rest others) |
---|
1250 | (if (not others) |
---|
1251 | `(the fixnum (- (the fixnum ,x) (the fixnum ,y))) |
---|
1252 | `(the fixnum (- (the fixnum ,x) (the fixnum (%i+ ,y ,@others)))))) |
---|
1253 | |
---|
1254 | |
---|
1255 | (defmacro %i* (x y) `(the fixnum (* (the fixnum ,x) (the fixnum ,y)))) |
---|
1256 | |
---|
1257 | (defmacro %ilogbitp (b i) |
---|
1258 | (target-word-size-case |
---|
1259 | (32 |
---|
1260 | `(logbitp (the (integer 0 29) ,b) (the fixnum ,i))) |
---|
1261 | (64 |
---|
1262 | `(logbitp (the (integer 0 60) ,b) (the fixnum ,i))))) |
---|
1263 | |
---|
1264 | ;;; Seq-Dispatch does an efficient type-dispatch on the given Sequence. |
---|
1265 | |
---|
1266 | (defmacro seq-dispatch (sequence list-form array-form) |
---|
1267 | `(if (sequence-type ,sequence) |
---|
1268 | ,list-form |
---|
1269 | ,array-form)) |
---|
1270 | |
---|
1271 | |
---|
1272 | (defsetf %get-byte %set-byte) |
---|
1273 | (defsetf %get-unsigned-byte %set-unsigned-byte) |
---|
1274 | (defsetf %get-signed-byte %set-byte) |
---|
1275 | (defsetf %get-word %set-word) |
---|
1276 | (defsetf %get-signed-word %set-word) |
---|
1277 | (defsetf %get-unsigned-word %set-unsigned-word) |
---|
1278 | (defsetf %get-long %set-long) |
---|
1279 | (defsetf %get-signed-long %set-long) |
---|
1280 | (defsetf %get-unsigned-long %set-unsigned-long) |
---|
1281 | (defsetf %get-full-long %set-long) |
---|
1282 | (defsetf %get-point %set-long) |
---|
1283 | (defsetf %get-ptr %set-ptr) |
---|
1284 | (defsetf %get-double-float %set-double-float) |
---|
1285 | (defsetf %get-single-float %set-single-float) |
---|
1286 | (defsetf %get-bit %set-bit) |
---|
1287 | (defsetf %get-unsigned-long-long %set-unsigned-long-long) |
---|
1288 | (defsetf %%get-unsigned-longlong %%set-unsigned-longlong) |
---|
1289 | (defsetf %get-signed-long-long %set-signed-long-long) |
---|
1290 | (defsetf %%get-signed-longlong %%set-signed-longlong) |
---|
1291 | (defsetf %get-bitfield %set-bitfield) |
---|
1292 | |
---|
1293 | (defmacro %ilognot (int) `(%i- -1 ,int)) |
---|
1294 | |
---|
1295 | (defmacro %ilogior2 (x y) |
---|
1296 | `(logior (the fixnum ,x) (the fixnum ,y))) |
---|
1297 | |
---|
1298 | (defmacro %ilogior (body &body args) |
---|
1299 | (while args |
---|
1300 | (setq body (list '%ilogior2 body (pop args)))) |
---|
1301 | body) |
---|
1302 | |
---|
1303 | (defmacro %ilogand2 (x y) |
---|
1304 | `(logand (the fixnum ,x) (the fixnum ,y))) |
---|
1305 | |
---|
1306 | (defmacro %ilogand (body &body args) |
---|
1307 | (while args |
---|
1308 | (setq body (list '%ilogand2 body (pop args)))) |
---|
1309 | body) |
---|
1310 | |
---|
1311 | (defmacro %ilogxor2 (x y) |
---|
1312 | `(logxor (the fixnum ,x) (the fixnum ,y))) |
---|
1313 | |
---|
1314 | (defmacro %ilogxor (body &body args) |
---|
1315 | (while args |
---|
1316 | (setq body (list '%ilogxor2 body (pop args)))) |
---|
1317 | body) |
---|
1318 | |
---|
1319 | (defmacro with-macptrs (varlist &rest body &environment env) |
---|
1320 | (multiple-value-bind (body other-decls) (parse-body body env) |
---|
1321 | (collect ((temp-bindings) |
---|
1322 | (temp-decls) |
---|
1323 | (bindings) |
---|
1324 | (our-decls) |
---|
1325 | (inits)) |
---|
1326 | (dolist (var varlist) |
---|
1327 | (let* ((temp (gensym))) |
---|
1328 | (temp-decls temp) |
---|
1329 | (if (consp var) |
---|
1330 | (progn |
---|
1331 | (our-decls (car var)) |
---|
1332 | (temp-bindings `(,temp (%null-ptr))) |
---|
1333 | (bindings `(,(car var) ,temp)) |
---|
1334 | (if (cdr var) |
---|
1335 | (inits `(%setf-macptr ,temp ,@(cdr var))))) |
---|
1336 | (progn |
---|
1337 | (our-decls var) |
---|
1338 | (temp-bindings `(,temp (%null-ptr))) |
---|
1339 | (bindings `(,var ,temp)))))) |
---|
1340 | `(let* ,(temp-bindings) |
---|
1341 | (declare (dynamic-extent ,@(temp-decls))) |
---|
1342 | (declare (type macptr ,@(temp-decls))) |
---|
1343 | ,@(inits) |
---|
1344 | (let* ,(bindings) |
---|
1345 | (declare (type macptr ,@(our-decls))) |
---|
1346 | ,@other-decls |
---|
1347 | ,@body))))) |
---|
1348 | |
---|
1349 | |
---|
1350 | (defmacro with-loading-file (filename &rest body) |
---|
1351 | `(let ((*loading-files* (cons ,filename (locally (declare (special *loading-files*)) |
---|
1352 | *loading-files*)))) |
---|
1353 | (declare (special *loading-files*)) |
---|
1354 | ,@body)) |
---|
1355 | |
---|
1356 | (defmacro with-input-from-string ((var string &key index start end) &body forms &environment env) |
---|
1357 | "Create an input string stream, provide an opportunity to perform |
---|
1358 | operations on the stream (returning zero or more values), and then close |
---|
1359 | the string stream. |
---|
1360 | |
---|
1361 | STRING is evaluated first, and VAR is bound to a character input string |
---|
1362 | stream that supplies characters from the subsequence of the resulting |
---|
1363 | string bounded by start and end. BODY is executed as an implicit progn." |
---|
1364 | (multiple-value-bind (forms decls) (parse-body forms env nil) |
---|
1365 | `(let ((,var |
---|
1366 | ,(cond ((null end) |
---|
1367 | `(make-string-input-stream ,string ,(or start 0))) |
---|
1368 | ((symbolp end) |
---|
1369 | `(if ,end |
---|
1370 | (make-string-input-stream ,string ,(or start 0) ,end) |
---|
1371 | (make-string-input-stream ,string ,(or start 0)))) |
---|
1372 | (t |
---|
1373 | `(make-string-input-stream ,string ,(or start 0) ,end))))) |
---|
1374 | ,@decls |
---|
1375 | (unwind-protect |
---|
1376 | (multiple-value-prog1 |
---|
1377 | (progn ,@forms) |
---|
1378 | ,@(if index `((setf ,index (string-input-stream-index ,var))))) |
---|
1379 | (close ,var))))) |
---|
1380 | |
---|
1381 | (defmacro with-output-to-string ((var &optional string &key (element-type 'base-char element-type-p)) |
---|
1382 | &body body |
---|
1383 | &environment env) |
---|
1384 | "Create a character output stream, perform a series of operations that |
---|
1385 | may send results to this stream, and then close the stream. BODY is |
---|
1386 | executed as an implicit progn with VAR bound to an output string stream. |
---|
1387 | All output to that string stream is saved in a string." |
---|
1388 | (let ((string-var (gensym "string"))) |
---|
1389 | (multiple-value-bind (forms decls) (parse-body body env nil) |
---|
1390 | `(let* ((,string-var ,string) |
---|
1391 | (,var (if ,string-var |
---|
1392 | ,@(if element-type-p |
---|
1393 | `((progn |
---|
1394 | ,element-type |
---|
1395 | (%make-string-output-stream ,string-var))) |
---|
1396 | `((%make-string-output-stream ,string-var))) |
---|
1397 | ,@(if element-type-p |
---|
1398 | `((make-string-output-stream :element-type ,element-type)) |
---|
1399 | `((make-string-output-stream)))))) |
---|
1400 | ,@decls |
---|
1401 | (unwind-protect |
---|
1402 | (progn |
---|
1403 | ,@forms |
---|
1404 | ,@(if string () `((get-output-stream-string ,var)))) |
---|
1405 | (close ,var)))))) |
---|
1406 | |
---|
1407 | (defmacro with-output-to-truncating-string-stream ((var len) &body body |
---|
1408 | &environment env) |
---|
1409 | (multiple-value-bind (forms decls) (parse-body body env nil) |
---|
1410 | `(let* ((,var (make-truncating-string-stream ,len))) |
---|
1411 | ,@decls |
---|
1412 | (unwind-protect |
---|
1413 | (progn |
---|
1414 | ,@forms |
---|
1415 | (values (get-output-stream-string ,var) |
---|
1416 | (slot-value ,var 'truncated))) |
---|
1417 | (close ,var))))) |
---|
1418 | |
---|
1419 | (defmacro with-open-file ((var . args) &body body &aux (stream (gensym))(done (gensym))) |
---|
1420 | "Use open to create a file stream to file named by filespec. Filespec is |
---|
1421 | the name of the file to be opened. Options are used as keyword arguments |
---|
1422 | to open." |
---|
1423 | `(let (,stream ,done) |
---|
1424 | (unwind-protect |
---|
1425 | (multiple-value-prog1 |
---|
1426 | (let ((,var (setq ,stream (open ,@args)))) |
---|
1427 | ,@body) |
---|
1428 | (setq ,done t)) |
---|
1429 | (when ,stream (close ,stream :abort (null ,done)))))) |
---|
1430 | |
---|
1431 | (defmacro with-compilation-unit ((&key override) &body body) |
---|
1432 | "WITH-COMPILATION-UNIT ({Key Value}*) Form* |
---|
1433 | This form affects compilations that take place within its dynamic extent. It |
---|
1434 | is intended to be wrapped around the compilation of all files in the same |
---|
1435 | system. These keywords are defined: |
---|
1436 | :OVERRIDE Boolean-Form |
---|
1437 | One of the effects of this form is to delay undefined warnings |
---|
1438 | until the end of the form, instead of giving them at the end of each |
---|
1439 | compilation. If OVERRIDE is NIL (the default), then the outermost |
---|
1440 | WITH-COMPILATION-UNIT form grabs the undefined warnings. Specifying |
---|
1441 | OVERRIDE true causes that form to grab any enclosed warnings, even if |
---|
1442 | it is enclosed by another WITH-COMPILATION-UNIT." |
---|
1443 | `(let* ((*outstanding-deferred-warnings* (%defer-warnings ,override))) |
---|
1444 | (multiple-value-prog1 (progn ,@body) (report-deferred-warnings)))) |
---|
1445 | |
---|
1446 | ; Yow! Another Done Fun. |
---|
1447 | (defmacro with-standard-io-syntax (&body body &environment env) |
---|
1448 | "Bind the reader and printer control variables to values that enable READ |
---|
1449 | to reliably read the results of PRINT. These values are: |
---|
1450 | *PACKAGE* the COMMON-LISP-USER package |
---|
1451 | *PRINT-ARRAY* T |
---|
1452 | *PRINT-BASE* 10 |
---|
1453 | *PRINT-CASE* :UPCASE |
---|
1454 | *PRINT-CIRCLE* NIL |
---|
1455 | *PRINT-ESCAPE* T |
---|
1456 | *PRINT-GENSYM* T |
---|
1457 | *PRINT-LENGTH* NIL |
---|
1458 | *PRINT-LEVEL* NIL |
---|
1459 | *PRINT-LINES* NIL |
---|
1460 | *PRINT-MISER-WIDTH* NIL |
---|
1461 | *PRINT-PRETTY* NIL |
---|
1462 | *PRINT-RADIX* NIL |
---|
1463 | *PRINT-READABLY* T |
---|
1464 | *PRINT-RIGHT-MARGIN* NIL |
---|
1465 | *READ-BASE* 10 |
---|
1466 | *READ-DEFAULT-FLOAT-FORMAT* SINGLE-FLOAT |
---|
1467 | *READ-EVAL* T |
---|
1468 | *READ-SUPPRESS* NIL |
---|
1469 | *READTABLE* the standard readtable" |
---|
1470 | (multiple-value-bind (decls body) (parse-body body env) |
---|
1471 | `(let ((*package* (find-package "CL-USER")) |
---|
1472 | (*print-array* t) |
---|
1473 | (*print-base* 10.) |
---|
1474 | (*print-case* :upcase) |
---|
1475 | (*print-circle* nil) |
---|
1476 | (*print-escape* t) |
---|
1477 | (*print-gensym* t) |
---|
1478 | (*print-length* nil) |
---|
1479 | (*print-level* nil) |
---|
1480 | (*print-lines* nil) ; This doesn't exist as of 5/15/90 - does now |
---|
1481 | (*print-miser-width* nil) |
---|
1482 | (*print-pprint-dispatch* nil) |
---|
1483 | (*print-pretty* nil) |
---|
1484 | (*print-radix* nil) |
---|
1485 | (*print-readably* t) |
---|
1486 | (*print-right-margin* nil) |
---|
1487 | (*read-base* 10.) |
---|
1488 | (*read-default-float-format* 'single-float) |
---|
1489 | (*read-eval* t) ; Also MIA as of 5/15/90 |
---|
1490 | (*read-suppress* nil) |
---|
1491 | (*readtable* %initial-readtable%)) |
---|
1492 | ,@decls |
---|
1493 | ,@body))) |
---|
1494 | |
---|
1495 | (defmacro with-self-bound-io-control-vars (&body body) |
---|
1496 | `(let ( |
---|
1497 | (*print-array* *print-array*) |
---|
1498 | (*print-base* *print-base*) |
---|
1499 | (*print-case* *print-case*) |
---|
1500 | (*print-circle* *print-circle*) |
---|
1501 | (*print-escape* *print-escape*) |
---|
1502 | (*print-gensym* *print-gensym*) |
---|
1503 | (*print-length* *print-length*) |
---|
1504 | (*print-level* *print-level*) |
---|
1505 | (*print-lines* *print-lines*) |
---|
1506 | (*print-miser-width* *print-miser-width*) |
---|
1507 | (*print-pprint-dispatch* *print-pprint-dispatch*) |
---|
1508 | (*print-pretty* *print-pretty*) |
---|
1509 | (*print-radix* *print-radix*) |
---|
1510 | (*print-readably* *print-readably*) |
---|
1511 | (*print-right-margin* *print-right-margin*) |
---|
1512 | (*read-base* *read-base*) |
---|
1513 | (*read-default-float-format* *read-default-float-format*) |
---|
1514 | (*read-eval* *read-eval*) |
---|
1515 | (*read-suppress* *read-suppress*) |
---|
1516 | (*readtable* *readtable*)) |
---|
1517 | ,@body)) |
---|
1518 | |
---|
1519 | (defmacro print-unreadable-object (&environment env (object stream &key type identity) &body forms) |
---|
1520 | "Output OBJECT to STREAM with \"#<\" prefix, \">\" suffix, optionally |
---|
1521 | with object-type prefix and object-identity suffix, and executing the |
---|
1522 | code in BODY to provide possible further output." |
---|
1523 | (multiple-value-bind (body decls) (parse-body forms env) |
---|
1524 | (if body |
---|
1525 | (let ((thunk (gensym))) |
---|
1526 | `(let ((,thunk #'(lambda () ,@decls ,@body))) |
---|
1527 | (declare (dynamic-extent ,thunk)) |
---|
1528 | (%print-unreadable-object ,object ,stream ,type ,identity ,thunk))) |
---|
1529 | `(%print-unreadable-object ,object ,stream ,type ,identity nil)))) |
---|
1530 | ;; Pointers and Handles |
---|
1531 | |
---|
1532 | ;;Add function to lisp system pointer functions, and run it if it's not already |
---|
1533 | ;; there. |
---|
1534 | (defmacro def-ccl-pointers (name arglist &body body &aux (old (gensym))) |
---|
1535 | `(flet ((,name ,arglist ,@body)) |
---|
1536 | (let ((,old (member ',name *lisp-system-pointer-functions* :key #'function-name))) |
---|
1537 | (if ,old |
---|
1538 | (rplaca ,old #',name) |
---|
1539 | (progn |
---|
1540 | (push #',name *lisp-system-pointer-functions*) |
---|
1541 | (,name)))))) |
---|
1542 | |
---|
1543 | (defmacro def-load-pointers (name arglist &body body &aux (old (gensym))) |
---|
1544 | `(flet ((,name ,arglist ,@body)) |
---|
1545 | (let ((,old (member ',name *lisp-user-pointer-functions* :key #'function-name))) |
---|
1546 | (if ,old |
---|
1547 | (rplaca ,old #',name) |
---|
1548 | (progn |
---|
1549 | (push #',name *lisp-user-pointer-functions*) |
---|
1550 | (,name)))))) |
---|
1551 | |
---|
1552 | ;Queue up some code to run after ccl all loaded up, or, if ccl is already |
---|
1553 | ;loaded up, just run it right now. |
---|
1554 | (defmacro queue-fixup (&rest body &aux (fn (gensym))) |
---|
1555 | `(let ((,fn #'(lambda () ,@body))) |
---|
1556 | (if (eq %lisp-system-fixups% T) |
---|
1557 | (funcall ,fn) |
---|
1558 | (push (cons ,fn *loading-file-source-file*) %lisp-system-fixups%)))) |
---|
1559 | |
---|
1560 | (defmacro %incf-ptr (p &optional (by 1)) |
---|
1561 | (if (symbolp p) ;once-only |
---|
1562 | `(%setf-macptr (the macptr ,p) (%inc-ptr ,p ,by)) |
---|
1563 | (let ((var (gensym))) |
---|
1564 | `(let ((,var ,p)) (%setf-macptr (the macptr ,var) (%inc-ptr ,var ,by)))))) |
---|
1565 | |
---|
1566 | (defmacro with-string-from-cstring ((s ptr) &body body) |
---|
1567 | (let* ((len (gensym)) |
---|
1568 | (p (gensym))) |
---|
1569 | `(let* ((,p ,ptr) |
---|
1570 | (,len (%cstrlen ,p)) |
---|
1571 | (,s (make-string ,len))) |
---|
1572 | (declare (fixnum ,len)) |
---|
1573 | (%copy-ptr-to-ivector ,p 0 ,s 0 ,len) |
---|
1574 | (locally |
---|
1575 | ,@body)))) |
---|
1576 | |
---|
1577 | |
---|
1578 | (defmacro with-cstr ((sym str &optional start end) &rest body &environment env) |
---|
1579 | (multiple-value-bind (body decls) (parse-body body env nil) |
---|
1580 | (if (and (base-string-p str) (null start) (null end)) |
---|
1581 | (let ((strlen (%i+ (length str) 1))) |
---|
1582 | `(%stack-block ((,sym ,strlen)) |
---|
1583 | ,@decls |
---|
1584 | (%cstr-pointer ,str ,sym) |
---|
1585 | ,@body)) |
---|
1586 | (let ((strname (gensym)) |
---|
1587 | (start-name (gensym)) |
---|
1588 | (end-name (gensym))) |
---|
1589 | `(let ((,strname ,str) |
---|
1590 | ,@(if (or start end) |
---|
1591 | `((,start-name ,(or start 0)) |
---|
1592 | (,end-name ,(or end `(length ,strname)))))) |
---|
1593 | (%vstack-block (,sym |
---|
1594 | (the fixnum |
---|
1595 | (1+ |
---|
1596 | (the fixnum |
---|
1597 | ,(if (or start end) |
---|
1598 | `(byte-length |
---|
1599 | ,strname ,start-name ,end-name) |
---|
1600 | `(length ,strname)))))) |
---|
1601 | ,@decls |
---|
1602 | ,(if (or start end) |
---|
1603 | `(%cstr-segment-pointer ,strname ,sym ,start-name ,end-name) |
---|
1604 | `(%cstr-pointer ,strname ,sym)) |
---|
1605 | ,@body)))))) |
---|
1606 | |
---|
1607 | (defmacro with-utf-8-cstr ((sym str) &body body) |
---|
1608 | (let* ((data (gensym)) |
---|
1609 | (offset (gensym)) |
---|
1610 | (string (gensym)) |
---|
1611 | (len (gensym)) |
---|
1612 | (noctets (gensym)) |
---|
1613 | (end (gensym))) |
---|
1614 | `(let* ((,string ,str) |
---|
1615 | (,len (length ,string))) |
---|
1616 | (multiple-value-bind (,data ,offset) (array-data-and-offset ,string) |
---|
1617 | (let* ((,end (+ ,offset ,len)) |
---|
1618 | (,noctets (utf-8-octets-in-string ,data ,offset ,end))) |
---|
1619 | (%stack-block ((,sym (1+ ,noctets))) |
---|
1620 | (utf-8-memory-encode ,data ,sym 0 ,offset ,end) |
---|
1621 | (setf (%get-unsigned-byte ,sym ,noctets) 0) |
---|
1622 | ,@body)))))) |
---|
1623 | |
---|
1624 | |
---|
1625 | |
---|
1626 | |
---|
1627 | |
---|
1628 | (defmacro with-pointers (speclist &body body) |
---|
1629 | (with-specs-aux 'with-pointer speclist body)) |
---|
1630 | |
---|
1631 | |
---|
1632 | |
---|
1633 | (defmacro with-cstrs (speclist &body body) |
---|
1634 | (with-specs-aux 'with-cstr speclist body)) |
---|
1635 | |
---|
1636 | (defmacro with-utf-8-cstrs (speclist &body body) |
---|
1637 | (with-specs-aux 'with-utf-8-cstr speclist body)) |
---|
1638 | |
---|
1639 | (defmacro with-encoded-cstr ((encoding-name (sym string &optional start end)) |
---|
1640 | &rest body &environment env) |
---|
1641 | (let* ((encoding (get-character-encoding encoding-name)) |
---|
1642 | (str (gensym)) |
---|
1643 | (len (gensym)) |
---|
1644 | (nzeros (floor (character-encoding-code-unit-size encoding) 8))) |
---|
1645 | (collect ((trailing-zeros)) |
---|
1646 | (case nzeros |
---|
1647 | (1 (trailing-zeros `(setf (%get-unsigned-byte ,sym ,len) 0))) |
---|
1648 | (2 (trailing-zeros `(setf (%get-unsigned-word ,sym ,len) 0))) |
---|
1649 | (4 (trailing-zeros `(setf (%get-unsigned-long ,sym ,len) 0))) |
---|
1650 | (t |
---|
1651 | (dotimes (i nzeros) |
---|
1652 | (trailing-zeros `(setf (%get-unsigned-byte ,sym (the fixnum (+ ,len ,i))) 0))))) |
---|
1653 | (multiple-value-bind (body decls) (parse-body body env nil) |
---|
1654 | `(let* ((,str ,string)) |
---|
1655 | (%stack-block ((,sym (cstring-encoded-length-in-bytes ,encoding ,str ,start ,end))) |
---|
1656 | ,@decls |
---|
1657 | (let* ((,len (encode-string-to-memory ,encoding ,sym 0 ,str ,start ,end))) |
---|
1658 | (declare (fixnum ,len)) |
---|
1659 | ,@(trailing-zeros) |
---|
1660 | ,@body))))))) |
---|
1661 | |
---|
1662 | (defmacro with-encoded-cstrs (encoding-name bindings &body body) |
---|
1663 | (with-specs-aux 'with-encoded-cstr (mapcar #'(lambda (b) |
---|
1664 | `(,encoding-name ,b)) |
---|
1665 | bindings) body)) |
---|
1666 | |
---|
1667 | |
---|
1668 | (defun with-specs-aux (name spec-list original-body) |
---|
1669 | (multiple-value-bind (body decls) (parse-body original-body nil) |
---|
1670 | (when decls (error "declarations not allowed in ~s" original-body)) |
---|
1671 | (setq body (cons 'progn body)) |
---|
1672 | (dolist (spec (reverse spec-list)) |
---|
1673 | (setq body (list name spec body))) |
---|
1674 | body)) |
---|
1675 | |
---|
1676 | |
---|
1677 | (defmacro type-predicate (type) |
---|
1678 | `(get-type-predicate ,type)) |
---|
1679 | |
---|
1680 | (defsetf type-predicate set-type-predicate) |
---|
1681 | |
---|
1682 | (defmacro defmethod (name &rest args &environment env) |
---|
1683 | (multiple-value-bind (function-form specializers-form qualifiers lambda-list documentation specializers) |
---|
1684 | (parse-defmethod name args env) |
---|
1685 | `(progn |
---|
1686 | (eval-when (:compile-toplevel) |
---|
1687 | (note-function-info ',name nil ,env)) |
---|
1688 | (compiler-let ((*nx-method-warning-name* |
---|
1689 | (list ',name |
---|
1690 | ,@(mapcar #'(lambda (x) `',x) qualifiers) |
---|
1691 | ',specializers))) |
---|
1692 | (ensure-method ',name ,specializers-form |
---|
1693 | :function ,function-form |
---|
1694 | :qualifiers ',qualifiers |
---|
1695 | :lambda-list ',lambda-list |
---|
1696 | ,@(if documentation `(:documentation ,documentation))))))) |
---|
1697 | |
---|
1698 | |
---|
1699 | (defun seperate-defmethod-decls (decls) |
---|
1700 | (let (outer inner) |
---|
1701 | (dolist (decl decls) |
---|
1702 | (if (neq (car decl) 'declare) |
---|
1703 | (push decl outer) |
---|
1704 | (let (outer-list inner-list) |
---|
1705 | (dolist (d (cdr decl)) |
---|
1706 | (if (and (listp d) (eq (car d) 'dynamic-extent)) |
---|
1707 | (let (in out) |
---|
1708 | (dolist (fspec (cdr d)) |
---|
1709 | (if (and (listp fspec) |
---|
1710 | (eq (car fspec) 'function) |
---|
1711 | (listp (cdr fspec)) |
---|
1712 | (null (cddr fspec)) |
---|
1713 | (memq (cadr fspec) '(call-next-method next-method-p))) |
---|
1714 | (push fspec in) |
---|
1715 | (push fspec out))) |
---|
1716 | (when out |
---|
1717 | (push `(dynamic-extent ,@(nreverse out)) outer-list)) |
---|
1718 | (when in |
---|
1719 | (push `(dynamic-extent ,@(nreverse in)) inner-list))) |
---|
1720 | (push d outer-list))) |
---|
1721 | (when outer-list |
---|
1722 | (push `(declare ,@(nreverse outer-list)) outer)) |
---|
1723 | (when inner-list |
---|
1724 | (push `(declare ,@(nreverse inner-list)) inner))))) |
---|
1725 | (values (nreverse outer) (nreverse inner)))) |
---|
1726 | |
---|
1727 | |
---|
1728 | (defun parse-defmethod (name args env) |
---|
1729 | (validate-function-name name) |
---|
1730 | (let (qualifiers lambda-list parameters specializers specializers-form refs types temp) |
---|
1731 | (until (listp (car args)) |
---|
1732 | (push (pop args) qualifiers)) |
---|
1733 | (setq lambda-list (pop args)) |
---|
1734 | (while (and lambda-list (not (memq (car lambda-list) lambda-list-keywords))) |
---|
1735 | (let ((p (pop lambda-list))) |
---|
1736 | (cond ((consp p) |
---|
1737 | (unless (and (consp (%cdr p)) (null (%cddr p))) |
---|
1738 | (signal-program-error "Illegal arg ~S" p)) |
---|
1739 | (push (%car p) parameters) |
---|
1740 | (push (%car p) refs) |
---|
1741 | (setq p (%cadr p)) |
---|
1742 | (cond ((and (consp p) (eq (%car p) 'eql) |
---|
1743 | (consp (%cdr p)) (null (%cddr p))) |
---|
1744 | (push `(list 'eql ,(%cadr p)) specializers-form) |
---|
1745 | (push p specializers)) |
---|
1746 | ((or (setq temp (non-nil-symbol-p p)) |
---|
1747 | (specializer-p p)) |
---|
1748 | (push `',p specializers-form) |
---|
1749 | (push p specializers) |
---|
1750 | (unless (or (eq p t) (not temp)) |
---|
1751 | ;Should be `(guaranteed-type ...). |
---|
1752 | (push `(type ,p ,(%car parameters)) types))) |
---|
1753 | (t (signal-program-error "Illegal arg ~S" p)))) |
---|
1754 | (t |
---|
1755 | (push p parameters) |
---|
1756 | (push t specializers-form) |
---|
1757 | (push t specializers))))) |
---|
1758 | (setq lambda-list (nreconc parameters lambda-list)) |
---|
1759 | (multiple-value-bind (body decls doc) (parse-body args env t) |
---|
1760 | (multiple-value-bind (outer-decls inner-decls) |
---|
1761 | (seperate-defmethod-decls decls) |
---|
1762 | (let* ((methvar (make-symbol "NEXT-METHOD-CONTEXT")) |
---|
1763 | (cnm-args (gensym)) |
---|
1764 | (lambda-form `(lambda ,(list* '&method methvar lambda-list) |
---|
1765 | (declare ;,@types |
---|
1766 | (ignorable ,@refs)) |
---|
1767 | ,@outer-decls |
---|
1768 | (block ,(if (consp name) (cadr name) name) |
---|
1769 | (flet ((call-next-method (&rest ,cnm-args) |
---|
1770 | (declare (dynamic-extent ,cnm-args)) |
---|
1771 | (if ,cnm-args |
---|
1772 | (apply #'%call-next-method-with-args ,methvar ,cnm-args) |
---|
1773 | (%call-next-method ,methvar))) |
---|
1774 | (next-method-p () (%next-method-p ,methvar))) |
---|
1775 | (declare (inline call-next-method next-method-p)) |
---|
1776 | ,@inner-decls |
---|
1777 | ,@body))))) |
---|
1778 | (values |
---|
1779 | (if name `(nfunction ,name ,lambda-form) `(function ,lambda-form)) |
---|
1780 | `(list ,@(nreverse specializers-form)) |
---|
1781 | (nreverse qualifiers) |
---|
1782 | lambda-list |
---|
1783 | doc |
---|
1784 | (nreverse specializers))))))) |
---|
1785 | |
---|
1786 | (defmacro anonymous-method (name &rest args &environment env) |
---|
1787 | (multiple-value-bind (function-form specializers-form qualifiers method-class documentation) |
---|
1788 | (parse-defmethod name args env) |
---|
1789 | |
---|
1790 | `(%anonymous-method |
---|
1791 | ,function-form |
---|
1792 | ,specializers-form |
---|
1793 | ',qualifiers |
---|
1794 | ,@(if (or method-class documentation) `(',method-class)) |
---|
1795 | ,@(if documentation `(,documentation))))) |
---|
1796 | |
---|
1797 | |
---|
1798 | |
---|
1799 | (defmacro defclass (class-name superclasses slots &rest class-options &environment env) |
---|
1800 | (flet ((duplicate-options (where) (signal-program-error "Duplicate options in ~S" where)) |
---|
1801 | (illegal-option (option) (signal-program-error "Illegal option ~s" option)) |
---|
1802 | (make-initfunction (form) |
---|
1803 | (cond ((or (eq form 't) |
---|
1804 | (equal form ''t)) |
---|
1805 | '(function true)) |
---|
1806 | ((or (eq form 'nil) |
---|
1807 | (equal form ''nil)) |
---|
1808 | '(function false)) |
---|
1809 | (t |
---|
1810 | `(function (lambda () ,form)))))) |
---|
1811 | (setq class-name (require-type class-name '(and symbol (not null)))) |
---|
1812 | (setq superclasses (mapcar #'(lambda (s) (require-type s 'symbol)) superclasses)) |
---|
1813 | (let* ((options-seen ()) |
---|
1814 | (signatures ()) |
---|
1815 | (slot-names)) |
---|
1816 | (flet ((canonicalize-defclass-option (option) |
---|
1817 | (let* ((option-name (car option))) |
---|
1818 | (if (member option-name options-seen :test #'eq) |
---|
1819 | (duplicate-options class-options) |
---|
1820 | (push option-name options-seen)) |
---|
1821 | (case option-name |
---|
1822 | (:default-initargs |
---|
1823 | (let ((canonical ()) |
---|
1824 | (initargs-seen ())) |
---|
1825 | (let (key val (tail (cdr option))) |
---|
1826 | (loop (when (null tail) (return nil)) |
---|
1827 | (setq key (pop tail) |
---|
1828 | val (pop tail)) |
---|
1829 | (when (memq key initargs-seen) |
---|
1830 | (SIGNAL-PROGRAM-error "Duplicate initialization argument name ~S in :DEFAULT-INITARGS of DEFCLASS ~S" key class-name)) |
---|
1831 | (push key initargs-seen) |
---|
1832 | (push ``(,',key ,',val ,,(make-initfunction val)) canonical)) |
---|
1833 | `(':direct-default-initargs (list ,@(nreverse canonical)))))) |
---|
1834 | (:metaclass |
---|
1835 | (unless (and (cadr option) |
---|
1836 | (typep (cadr option) 'symbol)) |
---|
1837 | (illegal-option option)) |
---|
1838 | `(:metaclass ',(cadr option))) |
---|
1839 | (:documentation |
---|
1840 | `(:documentation ',(cadr option))) |
---|
1841 | (t |
---|
1842 | (list `',option-name `',(cdr option)))))) |
---|
1843 | (canonicalize-slot-spec (slot) |
---|
1844 | (if (null slot) (signal-program-error "Illegal slot NIL")) |
---|
1845 | (if (not (listp slot)) (setq slot (list slot))) |
---|
1846 | (let* ((slot-name (require-type (car slot) 'symbol)) |
---|
1847 | (initargs nil) |
---|
1848 | (other-options ()) |
---|
1849 | (initform nil) |
---|
1850 | (initform-p nil) |
---|
1851 | (initfunction nil) |
---|
1852 | (type nil) |
---|
1853 | (type-p nil) |
---|
1854 | (allocation nil) |
---|
1855 | (allocation-p nil) |
---|
1856 | (documentation nil) |
---|
1857 | (documentation-p nil) |
---|
1858 | (readers nil) |
---|
1859 | (writers nil)) |
---|
1860 | (when (memq slot-name slot-names) |
---|
1861 | (SIGNAL-PROGRAM-error "Multiple slots named ~S in DEFCLASS ~S" slot-name class-name)) |
---|
1862 | (push slot-name slot-names) |
---|
1863 | (do ((options (cdr slot) (cddr options)) |
---|
1864 | name) |
---|
1865 | ((null options)) |
---|
1866 | (when (null (cdr options)) (signal-program-error "Illegal slot spec ~S" slot)) |
---|
1867 | (case (car options) |
---|
1868 | (:reader |
---|
1869 | (setq name (cadr options)) |
---|
1870 | (push name signatures) |
---|
1871 | (push name readers)) |
---|
1872 | (:writer |
---|
1873 | (setq name (cadr options)) |
---|
1874 | (push name signatures) |
---|
1875 | (push name writers)) |
---|
1876 | (:accessor |
---|
1877 | (setq name (cadr options)) |
---|
1878 | (push name signatures) |
---|
1879 | (push name readers) |
---|
1880 | (push `(setf ,name) signatures) |
---|
1881 | (push `(setf ,name) writers)) |
---|
1882 | (:initarg |
---|
1883 | (push (require-type (cadr options) 'symbol) initargs)) |
---|
1884 | (:type |
---|
1885 | (if type-p |
---|
1886 | (duplicate-options slot) |
---|
1887 | (setq type-p t)) |
---|
1888 | ;(when (null (cadr options)) (signal-program-error "Illegal options ~S" options)) |
---|
1889 | (setq type (cadr options))) |
---|
1890 | (:initform |
---|
1891 | (if initform-p |
---|
1892 | (duplicate-options slot) |
---|
1893 | (setq initform-p t)) |
---|
1894 | (let ((option (cadr options))) |
---|
1895 | (setq initform `',option |
---|
1896 | initfunction |
---|
1897 | (if (constantp option) |
---|
1898 | `(constantly ,option) |
---|
1899 | `#'(lambda () ,option))))) |
---|
1900 | (:allocation |
---|
1901 | (if allocation-p |
---|
1902 | (duplicate-options slot) |
---|
1903 | (setq allocation-p t)) |
---|
1904 | (setq allocation (cadr options))) |
---|
1905 | (:documentation |
---|
1906 | (if documentation-p |
---|
1907 | (duplicate-options slot) |
---|
1908 | (setq documentation-p t)) |
---|
1909 | (setq documentation (cadr options))) |
---|
1910 | (t |
---|
1911 | (let* ((pair (or (assq (car options) other-options) |
---|
1912 | (car (push (list (car options)) other-options))))) |
---|
1913 | (push (cadr options) (cdr pair)))))) |
---|
1914 | `(list :name ',slot-name |
---|
1915 | ,@(when allocation `(:allocation ',allocation)) |
---|
1916 | ,@(when initform-p `(:initform ,initform |
---|
1917 | :initfunction ,initfunction)) |
---|
1918 | ,@(when initargs `(:initargs ',initargs)) |
---|
1919 | ,@(when readers `(:readers ',readers)) |
---|
1920 | ,@(when writers `(:writers ',writers)) |
---|
1921 | ,@(when type-p `(:type ',type)) |
---|
1922 | ,@(when documentation-p `(:documentation ,documentation)) |
---|
1923 | ,@(mapcan #'(lambda (opt) |
---|
1924 | `(',(car opt) ',(if (null (cddr opt)) |
---|
1925 | (cadr opt) |
---|
1926 | (cdr opt)))) other-options))))) |
---|
1927 | (let* ((direct-superclasses superclasses) |
---|
1928 | (direct-slot-specs (mapcar #'canonicalize-slot-spec slots)) |
---|
1929 | (other-options (apply #'append (mapcar #'canonicalize-defclass-option class-options )))) |
---|
1930 | `(progn |
---|
1931 | (eval-when (:compile-toplevel) |
---|
1932 | (%compile-time-defclass ',class-name ,env) |
---|
1933 | (progn |
---|
1934 | ,@(mapcar #'(lambda (s) `(note-function-info ',s nil ,env)) |
---|
1935 | signatures))) |
---|
1936 | (ensure-class-for-defclass ',class-name |
---|
1937 | :direct-superclasses ',direct-superclasses |
---|
1938 | :direct-slots ,`(list ,@direct-slot-specs) |
---|
1939 | ,@other-options))))))) |
---|
1940 | |
---|
1941 | (defmacro define-method-combination (name &rest rest &environment env) |
---|
1942 | (setq name (require-type name 'symbol)) |
---|
1943 | (cond ((or (null rest) (and (car rest) (symbolp (car rest)))) |
---|
1944 | `(short-form-define-method-combination ',name ',rest)) |
---|
1945 | ((listp (car rest)) |
---|
1946 | (destructuring-bind (lambda-list method-group-specifiers . forms) rest |
---|
1947 | (long-form-define-method-combination |
---|
1948 | name lambda-list method-group-specifiers forms env))) |
---|
1949 | (t (%badarg (car rest) '(or (and null symbol) list))))) |
---|
1950 | |
---|
1951 | (defmacro defgeneric (function-name lambda-list &rest options-and-methods &environment env) |
---|
1952 | (fboundp function-name) ; type-check |
---|
1953 | (multiple-value-bind (method-combination generic-function-class options methods) |
---|
1954 | (parse-defgeneric function-name t lambda-list options-and-methods) |
---|
1955 | (let ((gf (gensym))) |
---|
1956 | `(progn |
---|
1957 | (eval-when (:compile-toplevel) |
---|
1958 | (note-function-info ',function-name nil ,env)) |
---|
1959 | (let ((,gf (%defgeneric |
---|
1960 | ',function-name ',lambda-list ',method-combination ',generic-function-class |
---|
1961 | ',(apply #'append options)))) |
---|
1962 | (%set-defgeneric-methods ,gf ,@methods) |
---|
1963 | ,gf))))) |
---|
1964 | |
---|
1965 | |
---|
1966 | |
---|
1967 | (defun parse-defgeneric (function-name global-p lambda-list options-and-methods) |
---|
1968 | (check-generic-function-lambda-list lambda-list) |
---|
1969 | (let ((method-combination '(standard)) |
---|
1970 | (generic-function-class 'standard-generic-function) |
---|
1971 | options declarations methods option-keywords method-class) |
---|
1972 | (flet ((bad-option (o) |
---|
1973 | (signal-program-error "Bad option: ~s to ~s." o 'defgeneric))) |
---|
1974 | (dolist (o options-and-methods) |
---|
1975 | (let ((keyword (car o)) |
---|
1976 | (defmethod (if global-p 'defmethod 'anonymous-method))) |
---|
1977 | (if (eq keyword :method) |
---|
1978 | (push `(,defmethod ,function-name ,@(%cdr o)) methods) |
---|
1979 | (cond ((and (not (eq keyword 'declare)) |
---|
1980 | (memq keyword (prog1 option-keywords (push keyword option-keywords)))) |
---|
1981 | (signal-program-error "Duplicate option: ~s to ~s" keyword 'defgeneric)) |
---|
1982 | ((eq keyword :method-combination) |
---|
1983 | (unless (symbolp (cadr o)) |
---|
1984 | (bad-option o)) |
---|
1985 | (setq method-combination (cdr o))) |
---|
1986 | ((eq keyword :generic-function-class) |
---|
1987 | (unless (and (cdr o) (symbolp (cadr o)) (null (%cddr o))) |
---|
1988 | (bad-option o)) |
---|
1989 | (setq generic-function-class (%cadr o))) |
---|
1990 | ((eq keyword 'declare) |
---|
1991 | (push (cadr o) declarations)) |
---|
1992 | ((eq keyword :argument-precedence-order) |
---|
1993 | (dolist (arg (cdr o)) |
---|
1994 | (unless (and (symbolp arg) (memq arg lambda-list)) |
---|
1995 | (bad-option o))) |
---|
1996 | (push (list keyword (cdr o)) options)) |
---|
1997 | ((eq keyword :method-class) |
---|
1998 | (push o options) |
---|
1999 | (when (or (cddr o) (not (symbolp (setq method-class (%cadr o))))) |
---|
2000 | (bad-option o))) |
---|
2001 | ((eq keyword :documentation) |
---|
2002 | (push o options) |
---|
2003 | (when (or (cddr o) (not (stringp (%cadr o)))) |
---|
2004 | (bad-option o))) |
---|
2005 | (t (bad-option o))))))) |
---|
2006 | (when method-class |
---|
2007 | (dolist (m methods) |
---|
2008 | (push `(:method-class ,method-class) (cddr m)))) |
---|
2009 | (when declarations |
---|
2010 | (setq options `((:declarations ,declarations) ,@options))) |
---|
2011 | (values method-combination generic-function-class options methods))) |
---|
2012 | |
---|
2013 | |
---|
2014 | (defmacro def-aux-init-functions (class &rest functions) |
---|
2015 | `(set-aux-init-functions ',class (list ,@functions))) |
---|
2016 | |
---|
2017 | |
---|
2018 | |
---|
2019 | |
---|
2020 | |
---|
2021 | |
---|
2022 | ;;; A powerful way of defining REPORT-CONDITION... |
---|
2023 | ;;; Do they really expect that each condition type has a unique method on PRINT-OBJECT |
---|
2024 | ;;; which tests *print-escape* ? Scary if so ... |
---|
2025 | |
---|
2026 | (defmacro define-condition (name (&rest supers) &optional ((&rest slots)) &body options) |
---|
2027 | "DEFINE-CONDITION Name (Parent-Type*) (Slot-Spec*) Option* |
---|
2028 | Define NAME as a condition type. This new type inherits slots and its |
---|
2029 | report function from the specified PARENT-TYPEs. A slot spec is a list of: |
---|
2030 | (slot-name :reader <rname> :initarg <iname> {Option Value}* |
---|
2031 | |
---|
2032 | The DEFINE-CLASS slot options :ALLOCATION, :INITFORM, [slot] :DOCUMENTATION |
---|
2033 | and :TYPE and the overall options :DEFAULT-INITARGS and |
---|
2034 | [type] :DOCUMENTATION are also allowed. |
---|
2035 | |
---|
2036 | The :REPORT option is peculiar to DEFINE-CONDITION. Its argument is either |
---|
2037 | a string or a two-argument lambda or function name. If a function, the |
---|
2038 | function is called with the condition and stream to report the condition. |
---|
2039 | If a string, the string is printed. |
---|
2040 | |
---|
2041 | Condition types are classes, but (as allowed by ANSI and not as described in |
---|
2042 | CLtL2) are neither STANDARD-OBJECTs nor STRUCTURE-OBJECTs. WITH-SLOTS and |
---|
2043 | SLOT-VALUE may not be used on condition objects." |
---|
2044 | ; If we could tell what environment we're being expanded in, we'd |
---|
2045 | ; probably want to check to ensure that all supers name conditions |
---|
2046 | ; in that environment. |
---|
2047 | (let ((classopts nil) |
---|
2048 | (duplicate nil) |
---|
2049 | (docp nil) |
---|
2050 | (default-initargs-p nil) |
---|
2051 | (reporter nil)) |
---|
2052 | (dolist (option options) |
---|
2053 | (unless (and (consp option) |
---|
2054 | (consp (%cdr option))) |
---|
2055 | (error "Invalid option ~s ." option)) |
---|
2056 | (ecase (%car option) |
---|
2057 | (:default-initargs |
---|
2058 | (unless (plistp (cdr option)) |
---|
2059 | (signal-program-error "~S is not a plist." (%cdr option))) |
---|
2060 | (if default-initargs-p |
---|
2061 | (setq duplicate t) |
---|
2062 | (push (setq default-initargs-p option) classopts))) |
---|
2063 | (:documentation |
---|
2064 | (unless (null (%cddr option)) |
---|
2065 | (error "Invalid option ~s ." option)) |
---|
2066 | (if docp |
---|
2067 | (setq duplicate t) |
---|
2068 | (push (setq docp option) classopts))) |
---|
2069 | (:report |
---|
2070 | (unless (null (%cddr option)) |
---|
2071 | (error "Invalid option ~s ." option)) |
---|
2072 | (if reporter |
---|
2073 | (setq duplicate t) |
---|
2074 | (progn |
---|
2075 | (if (or (lambda-expression-p (setq reporter (%cadr option))) |
---|
2076 | (symbolp reporter)) |
---|
2077 | (setq reporter `(function ,reporter)) |
---|
2078 | (if (stringp reporter) |
---|
2079 | (setq reporter `(function (lambda (c s) (declare (ignore c)) (write-string ,reporter s)))) |
---|
2080 | (error "~a expression is not a string, symbol, or lambda expression ." (%car option)))) |
---|
2081 | (setq reporter `((defmethod report-condition ((c ,name) s) |
---|
2082 | (funcall ,reporter c s)))))))) |
---|
2083 | (if duplicate (error "Duplicate option ~s ." option))) |
---|
2084 | `(progn |
---|
2085 | (defclass ,name ,(or supers '(condition)) ,slots ,@classopts) |
---|
2086 | ,@reporter |
---|
2087 | ',name))) |
---|
2088 | |
---|
2089 | (defmacro with-condition-restarts (&environment env condition restarts &body body) |
---|
2090 | "Evaluates the BODY in a dynamic environment where the restarts in the list |
---|
2091 | RESTARTS-FORM are associated with the condition returned by CONDITION-FORM. |
---|
2092 | This allows FIND-RESTART, etc., to recognize restarts that are not related |
---|
2093 | to the error currently being debugged. See also RESTART-CASE." |
---|
2094 | (multiple-value-bind (body decls) |
---|
2095 | (parse-body body env) |
---|
2096 | (let ((cond (gensym)) |
---|
2097 | (r (gensym))) |
---|
2098 | `(let* ((*condition-restarts* *condition-restarts*)) |
---|
2099 | ,@decls |
---|
2100 | (let ((,cond ,condition)) |
---|
2101 | (dolist (,r ,restarts) (push (cons ,r ,cond) *condition-restarts*)) |
---|
2102 | ,@body))))) |
---|
2103 | |
---|
2104 | (defmacro setf-find-class (name arg1 &optional (arg2 () 2-p) (arg3 () 3-p)) |
---|
2105 | (cond (3-p ;might want to pass env (arg2) to find-class someday? |
---|
2106 | `(set-find-class ,name (progn ,arg1 ,arg2 ,arg3))) |
---|
2107 | (2-p |
---|
2108 | `(set-find-class ,name (progn ,arg1 ,arg2))) |
---|
2109 | (t `(set-find-class ,name ,arg1)))) |
---|
2110 | |
---|
2111 | (defsetf find-class setf-find-class) |
---|
2112 | |
---|
2113 | (defmacro restoring-interrupt-level (var &body body) |
---|
2114 | `(unwind-protect |
---|
2115 | (progn ,@body) |
---|
2116 | (restore-interrupt-level ,var) |
---|
2117 | (%interrupt-poll))) |
---|
2118 | |
---|
2119 | (defmacro without-interrupts (&body body) |
---|
2120 | "Evaluate its body in an environment in which process-interrupt |
---|
2121 | requests are deferred." |
---|
2122 | `(let* ((*interrupt-level* -1)) |
---|
2123 | ,@body)) |
---|
2124 | |
---|
2125 | (defmacro with-interrupts-enabled (&body body) |
---|
2126 | "Evaluate its body in an environment in which process-interrupt |
---|
2127 | has immediate effect." |
---|
2128 | `(let* ((*interrupt-level* 0)) |
---|
2129 | ,@body)) |
---|
2130 | |
---|
2131 | ;;; undoes the effect of one enclosing without-interrupts during execution of body. |
---|
2132 | (defmacro ignoring-without-interrupts (&body body) |
---|
2133 | `(let* ((*interrupt-level* 0)) |
---|
2134 | ,@body)) |
---|
2135 | |
---|
2136 | |
---|
2137 | |
---|
2138 | (defmacro error-ignoring-without-interrupts (format-string &rest format-args) |
---|
2139 | `(ignoring-without-interrupts |
---|
2140 | (error ,format-string ,@format-args))) |
---|
2141 | |
---|
2142 | |
---|
2143 | ;init-list-default: if there is no init pair for <keyword>, |
---|
2144 | ; add a <keyword> <value> pair to init-list |
---|
2145 | (defmacro init-list-default (the-init-list &rest args) |
---|
2146 | (let ((result) |
---|
2147 | (init-list-sym (gensym))) |
---|
2148 | (do ((args args (cddr args))) |
---|
2149 | ((not args)) |
---|
2150 | (setq result |
---|
2151 | (cons `(if (eq '%novalue (getf ,init-list-sym ,(car args) |
---|
2152 | '%novalue)) |
---|
2153 | (setq ,init-list-sym (cons ,(car args) |
---|
2154 | (cons ,(cadr args) |
---|
2155 | ,init-list-sym)))) |
---|
2156 | result))) |
---|
2157 | `(let ((,init-list-sym ,the-init-list)) |
---|
2158 | (progn ,@result) |
---|
2159 | ,init-list-sym) |
---|
2160 | )) |
---|
2161 | |
---|
2162 | ; This can only be partially backward-compatible: even if only |
---|
2163 | ; the "name" arg is supplied, the old function would create the |
---|
2164 | ; package if it didn't exist. |
---|
2165 | ; Should see how well this works & maybe flush the whole idea. |
---|
2166 | |
---|
2167 | (defmacro in-package (name) |
---|
2168 | (let ((form nil)) |
---|
2169 | (when (quoted-form-p name) |
---|
2170 | (warn "Unquoting argument ~S to ~S." name 'in-package ) |
---|
2171 | (setq name (cadr name))) |
---|
2172 | (setq form `(set-package ,(string name))) |
---|
2173 | `(eval-when (:execute :load-toplevel :compile-toplevel) |
---|
2174 | ,form))) |
---|
2175 | |
---|
2176 | (defmacro defpackage (name &rest options) |
---|
2177 | "Defines a new package called PACKAGE. Each of OPTIONS should be one of the |
---|
2178 | following: |
---|
2179 | (NICKNAMES {package-name}*) |
---|
2180 | |
---|
2181 | (SIZE <integer>) |
---|
2182 | (SHADOW {symbol-name}*) |
---|
2183 | (SHADOWING-IMPORT-FROM <package-name> {symbol-name}*) |
---|
2184 | (USE {package-name}*) |
---|
2185 | (IMPORT-FROM <package-name> {symbol-name}*) |
---|
2186 | (INTERN {symbol-name}*) |
---|
2187 | (EXPORT {symbol-name}*) |
---|
2188 | (IMPLEMENT {package-name}*) |
---|
2189 | (LOCK boolean) |
---|
2190 | (DOCUMENTATION doc-string) |
---|
2191 | All options except SIZE, LOCK, and :DOCUMENTATION can be used multiple |
---|
2192 | times." |
---|
2193 | (let* ((size nil) |
---|
2194 | (all-names-size 0) |
---|
2195 | (intern-export-size 0) |
---|
2196 | (shadow-etc-size 0) |
---|
2197 | (documentation nil) |
---|
2198 | (all-names-hash (let ((all-options-alist nil)) |
---|
2199 | (dolist (option options) |
---|
2200 | (let ((option-name (car option))) |
---|
2201 | (when (memq option-name |
---|
2202 | '(:nicknames :shadow :shadowing-import-from |
---|
2203 | :use :import-from :intern :export)) |
---|
2204 | (let ((option-size (length (cdr option))) |
---|
2205 | (cell (assq option-name all-options-alist))) |
---|
2206 | (declare (fixnum option-size)) |
---|
2207 | (if cell |
---|
2208 | (incf (cdr cell) option-size) |
---|
2209 | (push (cons option-name option-size) all-options-alist)) |
---|
2210 | (when (memq option-name '(:shadow :shadowing-import-from :import-from :intern)) |
---|
2211 | (incf shadow-etc-size option-size)) |
---|
2212 | (when (memq option-name '(:export :intern)) |
---|
2213 | (incf intern-export-size option-size)))))) |
---|
2214 | (dolist (cell all-options-alist) |
---|
2215 | (let ((option-size (cdr cell))) |
---|
2216 | (when (> option-size all-names-size) |
---|
2217 | (setq all-names-size option-size)))) |
---|
2218 | (when (> all-names-size 0) |
---|
2219 | (make-hash-table :test 'equal :size all-names-size)))) |
---|
2220 | (intern-export-hash (when (> intern-export-size 0) |
---|
2221 | (make-hash-table :test 'equal :size intern-export-size))) |
---|
2222 | (shadow-etc-hash (when (> shadow-etc-size 0) |
---|
2223 | (make-hash-table :test 'equal :size shadow-etc-size))) |
---|
2224 | (external-size nil) |
---|
2225 | (nicknames nil) |
---|
2226 | (shadow nil) |
---|
2227 | (shadowing-import-from-specs nil) |
---|
2228 | (use :default) |
---|
2229 | (import-from-specs nil) |
---|
2230 | (intern nil) |
---|
2231 | (export nil)) |
---|
2232 | (declare (fixnum all-names-size intern-export-size shadow-etc-size)) |
---|
2233 | (labels ((string-or-name (s) (string s)) |
---|
2234 | (duplicate-option (o) |
---|
2235 | (signal-program-error "Duplicate ~S option in ~S ." o options)) |
---|
2236 | (duplicate-name (name option-name) |
---|
2237 | (signal-program-error "Name ~s, used in ~s option, is already used in a conflicting option ." name option-name)) |
---|
2238 | (all-names (option-name tail already) |
---|
2239 | (when (eq already :default) (setq already nil)) |
---|
2240 | (when all-names-hash |
---|
2241 | (clrhash all-names-hash)) |
---|
2242 | (dolist (name already) |
---|
2243 | (setf (gethash (string-or-name name) all-names-hash) t)) |
---|
2244 | (dolist (name tail already) |
---|
2245 | (setq name (string-or-name name)) |
---|
2246 | (unless (gethash name all-names-hash) ; Ok to repeat name in same option. |
---|
2247 | (when (memq option-name '(:shadow :shadowing-import-from :import-from :intern)) |
---|
2248 | (if (gethash name shadow-etc-hash) |
---|
2249 | (duplicate-name name option-name)) |
---|
2250 | (setf (gethash name shadow-etc-hash) t)) |
---|
2251 | (when (memq option-name '(:export :intern)) |
---|
2252 | (if (gethash name intern-export-hash) |
---|
2253 | (duplicate-name name option-name)) |
---|
2254 | (setf (gethash name intern-export-hash) t)) |
---|
2255 | (setf (gethash name all-names-hash) t) |
---|
2256 | (push name already))))) |
---|
2257 | (dolist (option options) |
---|
2258 | (let ((args (cdr option))) |
---|
2259 | (ecase (%car option) |
---|
2260 | (:size |
---|
2261 | (if size |
---|
2262 | (duplicate-option :size) |
---|
2263 | (setq size (car args)))) |
---|
2264 | (:external-size |
---|
2265 | (if external-size |
---|
2266 | (duplicate-option :external-size) |
---|
2267 | (setq external-size (car args)))) |
---|
2268 | (:nicknames (setq nicknames (all-names nil args nicknames))) |
---|
2269 | (:shadow (setq shadow (all-names :shadow args shadow))) |
---|
2270 | (:shadowing-import-from |
---|
2271 | (destructuring-bind (from &rest shadowing-imports) args |
---|
2272 | (push (cons (string-or-name from) |
---|
2273 | (all-names :shadowing-import-from shadowing-imports nil)) |
---|
2274 | shadowing-import-from-specs))) |
---|
2275 | (:use (setq use (all-names nil args use))) |
---|
2276 | (:import-from |
---|
2277 | (destructuring-bind (from &rest imports) args |
---|
2278 | (push (cons (string-or-name from) |
---|
2279 | (all-names :import-from imports nil)) |
---|
2280 | import-from-specs))) |
---|
2281 | (:intern (setq intern (all-names :intern args intern))) |
---|
2282 | (:export (setq export (all-names :export args export))) |
---|
2283 | (:documentation |
---|
2284 | (if documentation |
---|
2285 | (duplicate-option :documentation) |
---|
2286 | (setq documentation (cadr option))))))) |
---|
2287 | `(eval-when (:execute :compile-toplevel :load-toplevel) |
---|
2288 | (%define-package ',(string-or-name name) |
---|
2289 | ',size |
---|
2290 | ',external-size |
---|
2291 | ',nicknames |
---|
2292 | ',shadow |
---|
2293 | ',shadowing-import-from-specs |
---|
2294 | ',use |
---|
2295 | ',import-from-specs |
---|
2296 | ',intern |
---|
2297 | ',export |
---|
2298 | ',documentation))))) |
---|
2299 | |
---|
2300 | |
---|
2301 | |
---|
2302 | (defmacro with-package-iterator ((mname package-list first-type &rest other-types) |
---|
2303 | &body body) |
---|
2304 | "Within the lexical scope of the body forms, MNAME is defined via macrolet |
---|
2305 | such that successive invocations of (MNAME) will return the symbols, |
---|
2306 | one by one, from the packages in PACKAGE-LIST. SYMBOL-TYPES may be |
---|
2307 | any of :INHERITED :EXTERNAL :INTERNAL." |
---|
2308 | (setq mname (require-type mname 'symbol)) |
---|
2309 | (let ((state (make-symbol "WITH-PACKAGE-ITERATOR_STATE"))) |
---|
2310 | (declare (fixnum types)) |
---|
2311 | (dolist (type (push first-type other-types)) |
---|
2312 | (ecase type |
---|
2313 | ((:external :internal :inherited)))) |
---|
2314 | `(let ((,state (%setup-pkg-iter-state ,package-list ',other-types))) |
---|
2315 | (macrolet ((,mname () `(%pkg-iter-next ,',state))) |
---|
2316 | ,@body)))) |
---|
2317 | |
---|
2318 | ; Does NOT evaluate the constructor, but DOES evaluate the destructor & initializer |
---|
2319 | (defmacro defresource (name &key constructor destructor initializer) |
---|
2320 | `(defparameter ,name (make-resource #'(lambda () ,constructor) |
---|
2321 | ,@(when destructor |
---|
2322 | `(:destructor ,destructor)) |
---|
2323 | ,@(when initializer |
---|
2324 | `(:initializer ,initializer))))) |
---|
2325 | |
---|
2326 | (defmacro using-resource ((var resource) &body body) |
---|
2327 | (let ((resource-var (gensym))) |
---|
2328 | `(let ((,resource-var ,resource) |
---|
2329 | ,var) |
---|
2330 | (unwind-protect |
---|
2331 | (progn |
---|
2332 | (setq ,var (allocate-resource ,resource-var)) |
---|
2333 | ,@body) |
---|
2334 | (when ,var |
---|
2335 | (free-resource ,resource-var ,var)))))) |
---|
2336 | |
---|
2337 | ;;; Bind per-thread specials which help with lock accounting. |
---|
2338 | (defmacro with-lock-context (&body body) |
---|
2339 | #+lock-accounting |
---|
2340 | `(let* ((*locks-held* *locks-held*) |
---|
2341 | (*locks-pending* *locks-pending*) |
---|
2342 | (*lock-conses* *lock-conses*)) |
---|
2343 | ,@body) |
---|
2344 | #-lock-accounting |
---|
2345 | `(progn ,@body)) |
---|
2346 | |
---|
2347 | (defmacro with-lock-grabbed ((lock &optional |
---|
2348 | (whostate "Lock")) |
---|
2349 | &body body) |
---|
2350 | "Wait until a given lock can be obtained, then evaluate its body with |
---|
2351 | the lock held." |
---|
2352 | (declare (ignore whostate)) |
---|
2353 | (let* ((locked (gensym)) |
---|
2354 | (l (gensym))) |
---|
2355 | ` (with-lock-context |
---|
2356 | (let ((,locked (make-lock-acquisition)) |
---|
2357 | (,l ,lock)) |
---|
2358 | (declare (dynamic-extent ,locked)) |
---|
2359 | (unwind-protect |
---|
2360 | (progn |
---|
2361 | (%lock-recursive-lock-object ,l ,locked ) |
---|
2362 | ,@body) |
---|
2363 | (when (lock-acquisition.status ,locked) (%unlock-recursive-lock-object ,l))))))) |
---|
2364 | |
---|
2365 | (defmacro with-lock-grabbed-maybe ((lock &optional |
---|
2366 | (whostate "Lock")) |
---|
2367 | &body body) |
---|
2368 | (declare (ignore whostate)) |
---|
2369 | (let* ((l (gensym))) |
---|
2370 | `(with-lock-context |
---|
2371 | (let* ((,l ,lock)) |
---|
2372 | (when (%try-recursive-lock-object ,l) |
---|
2373 | (unwind-protect |
---|
2374 | (progn ,@body) |
---|
2375 | (%unlock-recursive-lock-object ,l))))))) |
---|
2376 | |
---|
2377 | (defmacro with-standard-abort-handling (abort-message &body body) |
---|
2378 | (let ((stream (gensym))) |
---|
2379 | `(restart-case |
---|
2380 | (catch :abort |
---|
2381 | (catch-cancel |
---|
2382 | ,@body)) |
---|
2383 | (abort () ,@(when abort-message |
---|
2384 | `(:report (lambda (,stream) |
---|
2385 | (write-string ,abort-message ,stream))))) |
---|
2386 | (abort-break ())))) |
---|
2387 | |
---|
2388 | |
---|
2389 | |
---|
2390 | |
---|
2391 | (defmacro %lexpr-count (l) |
---|
2392 | `(%lisp-word-ref ,l 0)) |
---|
2393 | |
---|
2394 | (defmacro %lexpr-ref (lexpr count i) |
---|
2395 | `(%lisp-word-ref ,lexpr (%i- ,count ,i))) |
---|
2396 | |
---|
2397 | ;;; args will be list if old style clos |
---|
2398 | (defmacro apply-with-method-context (magic function args) |
---|
2399 | (let ((m (gensym)) |
---|
2400 | (f (gensym)) |
---|
2401 | (as (gensym))) |
---|
2402 | `((lambda (,m ,f ,as) |
---|
2403 | (if (listp ,as) |
---|
2404 | (%apply-with-method-context ,m ,f ,as) |
---|
2405 | (%apply-lexpr-with-method-context ,m ,f ,as))) ,magic ,function ,args))) |
---|
2406 | |
---|
2407 | (defmacro defcallback (name arglist &body body &environment env) |
---|
2408 | "Proclaim name to be a special variable; sets its value to a MACPTR which, |
---|
2409 | when called by foreign code, calls a lisp function which expects foreign |
---|
2410 | arguments of the specified types and which returns a foreign value of the |
---|
2411 | specified result type. Any argument variables which correspond to foreign |
---|
2412 | arguments of type :ADDRESS are bound to stack-allocated MACPTRs. |
---|
2413 | |
---|
2414 | If name is already a callback function pointer, its value is not changed; |
---|
2415 | instead, it's arranged that an updated version of the lisp callback function |
---|
2416 | will be called. This feature allows for callback functions to be redefined |
---|
2417 | incrementally, just like Lisp functions are. |
---|
2418 | |
---|
2419 | defcallback returns the callback pointer, e.g., the value of name." |
---|
2420 | (define-callback name arglist body env)) |
---|
2421 | |
---|
2422 | (declare-arch-specific-macro %get-single-float-from-double-ptr) |
---|
2423 | |
---|
2424 | (declare-arch-specific-macro lfun-vector) |
---|
2425 | (declare-arch-specific-macro lfun-vector-lfun) |
---|
2426 | |
---|
2427 | (declare-arch-specific-macro symptr->symvector) |
---|
2428 | (declare-arch-specific-macro symvector->symptr) |
---|
2429 | |
---|
2430 | (declare-arch-specific-macro function-to-function-vector) |
---|
2431 | (declare-arch-specific-macro function-vector-to-function) |
---|
2432 | |
---|
2433 | (declare-arch-specific-macro with-ffcall-results) |
---|
2434 | |
---|
2435 | (defvar *trace-print-functions* nil) |
---|
2436 | (defun %trace-print-arg (stream arg val type) |
---|
2437 | (format stream " ") |
---|
2438 | (let ((fn (assoc type *trace-print-functions*))) |
---|
2439 | (if fn |
---|
2440 | (funcall (cdr fn) stream arg val) |
---|
2441 | (progn |
---|
2442 | (when arg |
---|
2443 | (format stream "~A = " arg)) |
---|
2444 | (if (and type (not (eq type :void))) |
---|
2445 | (format stream "[:~A] ~A~%" type val) |
---|
2446 | (format stream ":VOID~%" val)))))) |
---|
2447 | |
---|
2448 | (defun def-trace-print-function (type fn) |
---|
2449 | (push (cons type fn) *trace-print-functions*)) |
---|
2450 | |
---|
2451 | (defun define-callback (name args body env) |
---|
2452 | (let* ((stack-word (gensym)) |
---|
2453 | (stack-ptr (gensym)) |
---|
2454 | (fp-args-ptr (gensym)) |
---|
2455 | (result-type-spec :void) |
---|
2456 | (args args) |
---|
2457 | (woi nil) |
---|
2458 | (monitor nil) |
---|
2459 | (need-struct-arg) |
---|
2460 | (struct-return-arg-name) |
---|
2461 | (error-return nil)) |
---|
2462 | (collect ((arg-names) |
---|
2463 | (arg-specs)) |
---|
2464 | (let* ((spec (car (last args))) |
---|
2465 | (rtype (ignore-errors (parse-foreign-type spec)))) |
---|
2466 | (setq need-struct-arg (typep rtype 'foreign-record-type)) |
---|
2467 | (if rtype |
---|
2468 | (setq result-type-spec spec args (butlast args)))) |
---|
2469 | (loop |
---|
2470 | (when (null args) (return)) |
---|
2471 | (if (eq (car args) :without-interrupts) |
---|
2472 | (setq woi (cadr args) args (cddr args)) |
---|
2473 | (if (eq (car args) :monitor-exception-ports) |
---|
2474 | (setq monitor (cadr args) args (cddr args)) |
---|
2475 | |
---|
2476 | (if (eq (car args) :error-return) |
---|
2477 | (setq error-return |
---|
2478 | (cadr args) |
---|
2479 | args (cddr args)) |
---|
2480 | (if need-struct-arg |
---|
2481 | (setq struct-return-arg-name (pop args) need-struct-arg nil) |
---|
2482 | (progn |
---|
2483 | (arg-specs (pop args)) |
---|
2484 | (arg-names (pop args)))))))) |
---|
2485 | (multiple-value-bind (rlets lets dynamic-extent-names inits foreign-return-type fp-args-form error-return-offset) |
---|
2486 | (funcall (ftd-callback-bindings-function *target-ftd*) |
---|
2487 | stack-ptr fp-args-ptr (arg-names) (arg-specs) result-type-spec struct-return-arg-name) |
---|
2488 | (multiple-value-bind (body decls doc) (parse-body body env t) |
---|
2489 | `(progn |
---|
2490 | (declaim (special ,name)) |
---|
2491 | (define-callback-function |
---|
2492 | (nfunction ,name |
---|
2493 | (lambda (,stack-word) |
---|
2494 | (declare (ignorable ,stack-word)) |
---|
2495 | (block ,name |
---|
2496 | (with-macptrs ((,stack-ptr)) |
---|
2497 | (%setf-macptr-to-object ,stack-ptr ,stack-word) |
---|
2498 | (with-macptrs (,@(when fp-args-form |
---|
2499 | `((,fp-args-ptr ,fp-args-form)))) |
---|
2500 | ,(defcallback-body stack-ptr |
---|
2501 | fp-args-ptr |
---|
2502 | lets |
---|
2503 | rlets |
---|
2504 | inits |
---|
2505 | `(declare (dynamic-extent ,@dynamic-extent-names)) |
---|
2506 | decls |
---|
2507 | body |
---|
2508 | foreign-return-type |
---|
2509 | struct-return-arg-name |
---|
2510 | error-return |
---|
2511 | error-return-offset |
---|
2512 | )))))) |
---|
2513 | ,doc |
---|
2514 | ,woi |
---|
2515 | ,monitor))))))) |
---|
2516 | |
---|
2517 | |
---|
2518 | (defun defcallback-body (&rest args) |
---|
2519 | (declare (dynamic-extent args)) |
---|
2520 | (destructuring-bind (stack-ptr fp-args-ptr lets rlets inits dynamic-extent-decls other-decls body return-type struct-return-arg error-return error-delta) args |
---|
2521 | (declare (ignorable dynamic-extent-decls)) |
---|
2522 | (let* ((result (gensym)) |
---|
2523 | (condition-name (if (atom error-return) 'error (car error-return))) |
---|
2524 | (error-return-function (if (atom error-return) error-return (cadr error-return))) |
---|
2525 | (body |
---|
2526 | `(rlet ,rlets |
---|
2527 | (let ,lets |
---|
2528 | ,dynamic-extent-decls |
---|
2529 | ,@other-decls |
---|
2530 | ,@inits |
---|
2531 | (let ((,result (progn ,@body))) |
---|
2532 | (declare (ignorable ,result) |
---|
2533 | (dynamic-extent ,result)) |
---|
2534 | |
---|
2535 | ,(funcall (ftd-callback-return-value-function *target-ftd*) |
---|
2536 | stack-ptr |
---|
2537 | fp-args-ptr |
---|
2538 | result |
---|
2539 | return-type |
---|
2540 | struct-return-arg) |
---|
2541 | nil))))) |
---|
2542 | (if error-return |
---|
2543 | (let* ((cond (gensym)) |
---|
2544 | (block (gensym)) |
---|
2545 | (handler (gensym))) |
---|
2546 | `(block ,block |
---|
2547 | (let* ((,handler (lambda (,cond) |
---|
2548 | (,error-return-function ,cond ,stack-ptr (%inc-ptr ,stack-ptr ,error-delta)) |
---|
2549 | (return-from ,block |
---|
2550 | nil)))) |
---|
2551 | (declare (dynamic-extent ,handler)) |
---|
2552 | (handler-bind ((,condition-name ,handler)) |
---|
2553 | (values ,body))))) |
---|
2554 | body)))) |
---|
2555 | |
---|
2556 | |
---|
2557 | (defmacro errchk (form) |
---|
2558 | (let* ((res (gensym))) |
---|
2559 | `(let* ((,res ,form)) |
---|
2560 | (if (eql 0 ,res) |
---|
2561 | 0 |
---|
2562 | (signal-posix-error ,res))))) |
---|
2563 | |
---|
2564 | (defmacro define-toplevel-command (group-name name arglist &body body &environment env) |
---|
2565 | (let* ((key (make-keyword name))) |
---|
2566 | (multiple-value-bind (body decls doc) (parse-body body env) |
---|
2567 | `(%define-toplevel-command ',group-name ,key ',name |
---|
2568 | (nfunction ,name (lambda ,arglist |
---|
2569 | ,@decls |
---|
2570 | (block ,name |
---|
2571 | ,@body))) |
---|
2572 | ,doc |
---|
2573 | ',(mapcar #'symbol-name arglist))))) |
---|
2574 | |
---|
2575 | (defmacro with-toplevel-commands (group-name &body body) |
---|
2576 | `(let* ((*active-toplevel-commands* *active-toplevel-commands*)) |
---|
2577 | (progn |
---|
2578 | (%use-toplevel-commands ',group-name) |
---|
2579 | ,@body))) |
---|
2580 | |
---|
2581 | (defmacro assert (test-form &optional (places ()) string &rest args) |
---|
2582 | "ASSERT Test-Form [(Place*) [String Arg*]] |
---|
2583 | If the Test-Form is not true, then signal a correctable error. If Places |
---|
2584 | are specified, then new values are prompted for when the error is proceeded. |
---|
2585 | String and Args are the format string and args to the error call." |
---|
2586 | (let* ((TOP (gensym)) |
---|
2587 | (setf-places-p (not (null places)))) |
---|
2588 | `(tagbody |
---|
2589 | ,TOP |
---|
2590 | (unless ,test-form |
---|
2591 | (%assertion-failure ,setf-places-p ',test-form ,string ,@args) |
---|
2592 | ,@(if places |
---|
2593 | `((write-line "Type expressions to set places to, or nothing to leave them alone." |
---|
2594 | *query-io*) |
---|
2595 | ,@(mapcar #'(lambda (place &aux (new-val (gensym)) |
---|
2596 | (set-p (gensym))) |
---|
2597 | `(multiple-value-bind |
---|
2598 | (,new-val ,set-p) |
---|
2599 | (assertion-value-prompt ',place) |
---|
2600 | (when ,set-p (setf ,place (values-list ,new-val))))) |
---|
2601 | places))) |
---|
2602 | (go ,TOP))))) |
---|
2603 | |
---|
2604 | |
---|
2605 | (defmacro check-type (place typespec &optional string) |
---|
2606 | "CHECK-TYPE Place Typespec [String] |
---|
2607 | Signal a restartable error of type TYPE-ERROR if the value of PLACE is |
---|
2608 | not of the specified type. If an error is signalled and the restart is |
---|
2609 | used to return, this can only return if the STORE-VALUE restart is |
---|
2610 | invoked. In that case it will store into PLACE and start over." |
---|
2611 | `(progn |
---|
2612 | (setf ,place |
---|
2613 | (ensure-value-of-type |
---|
2614 | ,place |
---|
2615 | ',typespec |
---|
2616 | ',place |
---|
2617 | ,string)) |
---|
2618 | nil)) |
---|
2619 | |
---|
2620 | |
---|
2621 | |
---|
2622 | (defmacro with-hash-table-iterator ((mname hash-table) &body body &environment env) |
---|
2623 | "WITH-HASH-TABLE-ITERATOR ((function hash-table) &body body) |
---|
2624 | provides a method of manually looping over the elements of a hash-table. |
---|
2625 | FUNCTION is bound to a generator-macro that, within the scope of the |
---|
2626 | invocation, returns one or three values. The first value tells whether |
---|
2627 | any objects remain in the hash table. When the first value is non-NIL, |
---|
2628 | the second and third values are the key and the value of the next object." |
---|
2629 | (let* ((hash (gensym)) |
---|
2630 | (keys (gensym)) |
---|
2631 | (state (gensym))) |
---|
2632 | `(let* ((,hash ,hash-table) |
---|
2633 | (,keys (make-array (the fixnum (hash-table-count ,hash)))) |
---|
2634 | (,state (vector ,hash 0 ,keys (enumerate-hash-keys ,hash ,keys)))) |
---|
2635 | (declare (dynamic-extent ,keys ,state)) |
---|
2636 | (macrolet ((,mname () `(next-hash-table-iteration ,',state))) |
---|
2637 | ,@body)))) |
---|
2638 | |
---|
2639 | |
---|
2640 | (eval-when (compile load eval) |
---|
2641 | (defmacro pprint-logical-block ((stream-symbol list |
---|
2642 | &key (prefix "" prefixp) |
---|
2643 | (per-line-prefix "" per-line-prefix-p) |
---|
2644 | (suffix "" suffixp)) |
---|
2645 | &body body) |
---|
2646 | (cond ((eq stream-symbol nil) (setq stream-symbol '*standard-output*)) |
---|
2647 | ((eq stream-symbol T) (setq stream-symbol '*terminal-io*))) |
---|
2648 | (when (not (symbolp stream-symbol)) |
---|
2649 | (warn "STREAM-SYMBOL arg ~S to PPRINT-LOGICAL-BLOCK is not a bindable symbol" |
---|
2650 | stream-symbol) |
---|
2651 | (setq stream-symbol '*standard-output*)) |
---|
2652 | (when (and prefixp per-line-prefix-p) |
---|
2653 | (warn "prefix ~S and per-line-prefix ~S cannot both be specified ~ |
---|
2654 | in PPRINT-LOGICAL-BLOCK") |
---|
2655 | (setq per-line-prefix nil)) |
---|
2656 | `(let ((*logical-block-p* t)) |
---|
2657 | (maybe-initiate-xp-printing |
---|
2658 | #'(lambda (,stream-symbol) |
---|
2659 | (let ((+l ,list) |
---|
2660 | (+p (or (and ,prefixp |
---|
2661 | (require-type ,prefix 'string)) |
---|
2662 | (and ,per-line-prefix-p |
---|
2663 | (require-type ,per-line-prefix 'string)))) |
---|
2664 | (+s (require-type ,suffix 'string))) |
---|
2665 | (pprint-logical-block+ |
---|
2666 | (,stream-symbol +l +p +s ,per-line-prefix-p T nil) |
---|
2667 | ,@ body nil))) |
---|
2668 | (decode-stream-arg ,stream-symbol)))) |
---|
2669 | |
---|
2670 | |
---|
2671 | ;Assumes var and args must be variables. Other arguments must be literals or variables. |
---|
2672 | |
---|
2673 | (defmacro pprint-logical-block+ ((var args prefix suffix per-line? circle-check? atsign?) |
---|
2674 | &body body) |
---|
2675 | "Group some output into a logical block. STREAM-SYMBOL should be either a |
---|
2676 | stream, T (for *TERMINAL-IO*), or NIL (for *STANDARD-OUTPUT*). The printer |
---|
2677 | control variable *PRINT-LEVEL* is automatically handled." |
---|
2678 | (when (and circle-check? atsign?) |
---|
2679 | (setq circle-check? 'not-first-p)) |
---|
2680 | `(let ((*current-level* (1+ *current-level*)) |
---|
2681 | (*current-length* -1) |
---|
2682 | ;(*parents* *parents*) |
---|
2683 | ,@(if (and circle-check? atsign?) `((not-first-p (plusp *current-length*))))) |
---|
2684 | (unless (check-block-abbreviation ,var ,args ,circle-check?) |
---|
2685 | (start-block ,var ,prefix ,per-line? ,suffix) |
---|
2686 | (when |
---|
2687 | (catch 'line-limit-abbreviation-exit |
---|
2688 | (block logical-block |
---|
2689 | (macrolet ((pprint-pop () `(pprint-pop+ ,',args ,',var)) |
---|
2690 | (pprint-exit-if-list-exhausted () |
---|
2691 | `(if (null ,',args) (return-from logical-block nil)))) |
---|
2692 | ,@ body)) |
---|
2693 | (end-block ,var ,suffix) |
---|
2694 | nil) |
---|
2695 | (end-block ,var ,suffix) |
---|
2696 | (throw 'line-limit-abbreviation-exit T))))) |
---|
2697 | ) ; eval-when |
---|
2698 | |
---|
2699 | (defmacro %old-class-local-shared-slotds (class &optional default) |
---|
2700 | (if default ; so setf works |
---|
2701 | `(%class-get ,class '%old-class-local-shared-slotds ,default) |
---|
2702 | `(%class-get ,class '%old-class-local-shared-slotds))) |
---|
2703 | |
---|
2704 | (defmacro with-slot-values (slot-entries instance-form &body body) |
---|
2705 | ; Simplified form of with-slots. Expands into a let instead of a symbol-macrolet |
---|
2706 | ; Thus, you can access the slot values, but you can't setq them. |
---|
2707 | (let ((instance (gensym)) var slot-name bindings) |
---|
2708 | (dolist (slot-entry slot-entries) |
---|
2709 | (cond ((symbolp slot-entry) |
---|
2710 | (setq var slot-entry slot-name slot-entry)) |
---|
2711 | ((and (listp slot-entry) (cdr slot-entry) (null (cddr slot-entry)) |
---|
2712 | (symbolp (car slot-entry)) (symbolp (cadr slot-entry))) |
---|
2713 | (setq var (car slot-entry) slot-name (cadr slot-entry))) |
---|
2714 | (t (error "Malformed slot-entry: ~a to with-slot-values.~@ |
---|
2715 | Should be a symbol or a list of two symbols." |
---|
2716 | slot-entry))) |
---|
2717 | (push `(,var (slot-value ,instance ',slot-name)) bindings)) |
---|
2718 | `(let ((,instance ,instance-form)) |
---|
2719 | (let ,(nreverse bindings) |
---|
2720 | ,@body)))) |
---|
2721 | |
---|
2722 | (defmacro with-slots (slot-entries instance-form &body body) |
---|
2723 | "Establish a lexical environment for referring to the slots in the |
---|
2724 | instance named by the given slot-names as though they were variables. |
---|
2725 | Within such a context the value of the slot can be specified by using |
---|
2726 | its slot name, as if it were a lexically bound variable. Both setf and |
---|
2727 | setq can be used to set the value of the slot." |
---|
2728 | (let ((instance (gensym)) var slot-name bindings) |
---|
2729 | (dolist (slot-entry slot-entries) |
---|
2730 | (cond ((symbolp slot-entry) |
---|
2731 | (setq var slot-entry slot-name slot-entry)) |
---|
2732 | ((and (listp slot-entry) (cdr slot-entry) (null (cddr slot-entry)) |
---|
2733 | (symbolp (car slot-entry)) (symbolp (cadr slot-entry))) |
---|
2734 | (setq var (car slot-entry) slot-name (cadr slot-entry))) |
---|
2735 | (t (error "Malformed slot-entry: ~a to with-slots.~@ |
---|
2736 | Should be a symbol or a list of two symbols." |
---|
2737 | slot-entry))) |
---|
2738 | (push `(,var (slot-value ,instance ',slot-name)) bindings)) |
---|
2739 | `(let ((,instance ,instance-form)) |
---|
2740 | ,@(if bindings |
---|
2741 | (list `(declare (ignorable ,instance))) |
---|
2742 | (list `(declare (ignore ,instance)))) |
---|
2743 | (symbol-macrolet ,(nreverse bindings) |
---|
2744 | ,@body)))) |
---|
2745 | |
---|
2746 | (defmacro with-accessors (slot-entries instance-form &body body) |
---|
2747 | "Create a lexical environment in which the slots specified by slot-entry |
---|
2748 | are lexically available through their accessors as if they were variables. |
---|
2749 | The appropriate accessors are invoked to access the slots specified by |
---|
2750 | slot-entry. Both setf and setq can be used to set the value of the slot." |
---|
2751 | (let ((instance (gensym)) var reader bindings) |
---|
2752 | (dolist (slot-entry slot-entries) |
---|
2753 | (cond ((and (listp slot-entry) (cdr slot-entry) (null (cddr slot-entry)) |
---|
2754 | (symbolp (car slot-entry)) (symbolp (cadr slot-entry))) |
---|
2755 | (setq var (car slot-entry) reader (cadr slot-entry))) |
---|
2756 | (t (error "Malformed slot-entry: ~a to with-accessors.~@ |
---|
2757 | Should be a list of two symbols." |
---|
2758 | slot-entry))) |
---|
2759 | (push `(,var (,reader ,instance)) bindings)) |
---|
2760 | `(let ((,instance ,instance-form)) |
---|
2761 | ,@(if bindings |
---|
2762 | (list `(declare (ignorable ,instance))) |
---|
2763 | (list `(declare (ignore ,instance)))) |
---|
2764 | (symbol-macrolet ,(nreverse bindings) |
---|
2765 | ,@body)))) |
---|
2766 | |
---|
2767 | ; I wanted to call this ":method" |
---|
2768 | (defmacro reference-method (gf &rest qualifiers-and-specializers) |
---|
2769 | (let ((qualifiers (butlast qualifiers-and-specializers)) |
---|
2770 | (specializers (car (last qualifiers-and-specializers)))) |
---|
2771 | (if (null specializers) (report-bad-arg qualifiers-and-specializers '(not null))) |
---|
2772 | `(find-method #',gf ',qualifiers (mapcar #'find-specializer ',specializers)))) |
---|
2773 | |
---|
2774 | (defmacro time (form) |
---|
2775 | "Execute FORM and print timing information on *TRACE-OUTPUT*." |
---|
2776 | `(report-time ',form #'(lambda () (progn ,form)))) |
---|
2777 | |
---|
2778 | (defmacro with-error-reentry-detection (&body body) |
---|
2779 | (let ((thunk (gensym))) |
---|
2780 | `(let ((,thunk #'(lambda () ,@body))) |
---|
2781 | (declare (dynamic-extent ,thunk)) |
---|
2782 | (funcall-with-error-reentry-detection ,thunk)))) |
---|
2783 | |
---|
2784 | #+ppc-target |
---|
2785 | (defmacro scan-for-instr (mask opcode fn pc-index &optional (tries *trap-lookup-tries*)) |
---|
2786 | `(%scan-for-instr ,mask ,opcode ,fn ,pc-index ,tries)) |
---|
2787 | |
---|
2788 | |
---|
2789 | (declare-arch-specific-macro codevec-header-p) |
---|
2790 | |
---|
2791 | #+ppc-target |
---|
2792 | (defmacro match-instr (instr mask bits-to-match) |
---|
2793 | `(eql (logand ,instr ,mask) ,bits-to-match)) |
---|
2794 | |
---|
2795 | (defmacro with-xp-stack-frames ((xp trap-function &optional stack-frame) &body body) |
---|
2796 | (let ((thunk (gensym)) |
---|
2797 | (sf (or stack-frame (gensym)))) |
---|
2798 | `(let ((,thunk #'(lambda (&optional ,sf) |
---|
2799 | ,@(unless stack-frame `((declare (ignore ,sf)))) |
---|
2800 | ,@body))) |
---|
2801 | (declare (dynamic-extent ,thunk)) |
---|
2802 | (funcall-with-xp-stack-frames ,xp ,trap-function ,thunk)))) |
---|
2803 | |
---|
2804 | (defmacro signal-eof-error (stream) |
---|
2805 | `(error 'end-of-file :stream ,stream)) |
---|
2806 | |
---|
2807 | (defmacro check-eof (valform stream eof-error-p eof-value) |
---|
2808 | (let* ((val (gensym))) |
---|
2809 | `(let ((,val ,valform)) |
---|
2810 | (if (eq ,val :eof) |
---|
2811 | (if ,eof-error-p |
---|
2812 | (signal-eof-error ,stream) |
---|
2813 | ,eof-value) |
---|
2814 | ,val)))) |
---|
2815 | |
---|
2816 | (defmacro designated-input-stream (input-stream) |
---|
2817 | `(if ,input-stream |
---|
2818 | (if (eq t ,input-stream) |
---|
2819 | *terminal-io* |
---|
2820 | ,input-stream) |
---|
2821 | *standard-input*)) |
---|
2822 | |
---|
2823 | (defmacro pref (pointer accessor) |
---|
2824 | "Reference an instance of a foreign type (or a component of a foreign |
---|
2825 | type) accessible via ptr. |
---|
2826 | |
---|
2827 | Expand into code which references the indicated scalar type or component, |
---|
2828 | or returns a pointer to a composite type." |
---|
2829 | (let* ((*target-ftd* (backend-target-foreign-type-data *target-backend*))) |
---|
2830 | (destructuring-bind (type-name &rest accessors) (decompose-record-accessor accessor) |
---|
2831 | (%foreign-access-form pointer (%foreign-type-or-record type-name) 0 accessors)))) |
---|
2832 | |
---|
2833 | (defmacro paref (pointer type-name index) |
---|
2834 | (let* ((*target-ftd* (backend-target-foreign-type-data *target-backend*))) |
---|
2835 | (%foreign-array-access-form pointer (%foreign-type-or-record type-name) index))) |
---|
2836 | |
---|
2837 | (defmacro rref (pointer accessor &key (storage :pointer storage-p)) |
---|
2838 | (when storage-p |
---|
2839 | (warn "Use of :storage option ignored: ~a" storage)) |
---|
2840 | `(pref ,pointer ,accessor)) |
---|
2841 | |
---|
2842 | (defmacro rlet (spec &body body) |
---|
2843 | "Execute body in an environment in which each var is bound to a MACPTR |
---|
2844 | encapsulating the address of a stack-allocated foreign memory block, |
---|
2845 | allocated and initialized from typespec and initforms as per make-record. |
---|
2846 | Return whatever value(s) body returns." |
---|
2847 | (let* ((*target-ftd* (backend-target-foreign-type-data *target-backend*))) |
---|
2848 | `(%stack-block ,(rlet-sizes spec) |
---|
2849 | ,@(rlet-inits spec) |
---|
2850 | ,@body))) |
---|
2851 | |
---|
2852 | (defmacro rletz (spec &body body) |
---|
2853 | "Execute body in an environment in which each var is bound to a MACPTR |
---|
2854 | encapuslating the address of a stack-allocated foreign memory block, |
---|
2855 | allocated and initialized from typespec and initforms as per make-record. |
---|
2856 | Return whatever value(s) body returns. |
---|
2857 | |
---|
2858 | Unlike rlet, record fields that aren't explicitly initialized are set |
---|
2859 | to binary 0." |
---|
2860 | (let* ((*target-ftd* (backend-target-foreign-type-data *target-backend*))) |
---|
2861 | `(%stack-block ,(rlet-sizes spec t) |
---|
2862 | ,@(rlet-inits spec) |
---|
2863 | ,@body))) |
---|
2864 | |
---|
2865 | (defun rlet-sizes (inits &optional clear-p &aux result) |
---|
2866 | (dolist (item inits (nreverse result)) |
---|
2867 | (push `(,(car item) |
---|
2868 | ,(%foreign-type-or-record-size (cadr item) :bytes) |
---|
2869 | ,@(if clear-p '(:clear t))) |
---|
2870 | result))) |
---|
2871 | |
---|
2872 | (defun rlet-inits (inits &aux result) |
---|
2873 | (dolist (item inits result) |
---|
2874 | (let* ((name (car item)) |
---|
2875 | (record-name (cadr item)) |
---|
2876 | (inits (cddr item)) |
---|
2877 | (ftype (%foreign-type-or-record record-name)) |
---|
2878 | (ordinal (foreign-type-ordinal ftype)) |
---|
2879 | (ordinal-form (if (< ordinal max-canonical-foreign-type-ordinal) |
---|
2880 | ordinal |
---|
2881 | `(foreign-type-ordinal (load-time-value (%foreign-type-or-record ',record-name)))))) |
---|
2882 | (when (eq *host-backend* *target-backend*) |
---|
2883 | (setq result (nconc result `((%set-macptr-type ,name ,ordinal-form))))) |
---|
2884 | (if (typep ftype 'foreign-record-type) |
---|
2885 | (setq result |
---|
2886 | (nconc result (%foreign-record-field-forms name ftype record-name inits))) |
---|
2887 | (progn |
---|
2888 | (when inits |
---|
2889 | (if (and ftype (null (cdr inits))) |
---|
2890 | (setq result |
---|
2891 | (nconc result |
---|
2892 | `((setf ,(%foreign-access-form name ftype 0 nil) |
---|
2893 | ,(car inits))))) |
---|
2894 | (error "Unexpected or malformed initialization forms: ~s in field type: ~s" |
---|
2895 | inits record-name)))))))) |
---|
2896 | |
---|
2897 | (defun %foreign-record-field-forms (ptr record-type record-name inits) |
---|
2898 | (unless (evenp (length inits)) |
---|
2899 | (error "Unexpected or malformed initialization forms: ~s in field type: ~s" |
---|
2900 | inits record-name)) |
---|
2901 | (let* ((result ())) |
---|
2902 | (do* () |
---|
2903 | ((null inits) |
---|
2904 | `((progn |
---|
2905 | ;(%assert-macptr-ftype ,ptr ,record-type) |
---|
2906 | ,@(nreverse result)))) |
---|
2907 | (let* ((accessor (decompose-record-accessor (pop inits))) |
---|
2908 | (valform (pop inits))) |
---|
2909 | (push `(setf ,(%foreign-access-form ptr record-type 0 accessor) ,valform) |
---|
2910 | result))))) |
---|
2911 | |
---|
2912 | (defmacro get-field-offset (accessor) |
---|
2913 | (destructuring-bind (type-name field-name) (decompose-record-accessor accessor) |
---|
2914 | (let* ((record-type (require-type (%foreign-type-or-record type-name) 'foreign-record-type)) |
---|
2915 | (field (%find-foreign-record-type-field record-type field-name)) |
---|
2916 | (bit-offset (foreign-record-field-offset field))) |
---|
2917 | `(values ,(floor bit-offset 8) ,(foreign-record-field-type field) ,bit-offset)))) |
---|
2918 | |
---|
2919 | (defmacro record-length (recname) |
---|
2920 | (%foreign-type-or-record-size recname :bytes)) |
---|
2921 | |
---|
2922 | (defun make-record-form (record-name allocator &rest initforms) |
---|
2923 | (let* ((ftype (%foreign-type-or-record record-name)) |
---|
2924 | (ordinal (foreign-type-ordinal ftype)) |
---|
2925 | (ordinal-form (if (< ordinal max-canonical-foreign-type-ordinal) |
---|
2926 | ordinal |
---|
2927 | `(foreign-type-ordinal (load-time-value (%foreign-type-or-record ',record-name))))) |
---|
2928 | (bits (ensure-foreign-type-bits ftype)) |
---|
2929 | (bytes (if bits |
---|
2930 | (ceiling bits 8) |
---|
2931 | (error "Unknown size for foreign type ~S." |
---|
2932 | (unparse-foreign-type ftype)))) |
---|
2933 | (p (gensym)) |
---|
2934 | (bzero (read-from-string "#_bzero"))) |
---|
2935 | `(let* ((,p (,allocator ,bytes))) |
---|
2936 | ,@(when (eq *host-backend* *target-backend*) |
---|
2937 | `((%set-macptr-type ,p ,ordinal-form))) |
---|
2938 | (,bzero ,p ,bytes) |
---|
2939 | ,@(%foreign-record-field-forms p ftype record-name initforms) |
---|
2940 | ,p))) |
---|
2941 | |
---|
2942 | (defmacro make-record (record-name &rest initforms) |
---|
2943 | "Expand into code which allocates and initalizes an instance of the type |
---|
2944 | denoted by typespec, on the foreign heap. The record is allocated using the |
---|
2945 | C function malloc, and the user of make-record must explicitly call the C |
---|
2946 | function free to deallocate the record, when it is no longer needed." |
---|
2947 | (apply 'make-record-form record-name 'malloc initforms)) |
---|
2948 | |
---|
2949 | (defmacro make-gcable-record (record-name &rest initforms) |
---|
2950 | "Like MAKE-RECORD, only advises the GC that the foreign memory can |
---|
2951 | be deallocated if the returned pointer becomes garbage." |
---|
2952 | (apply 'make-record-form record-name '%new-gcable-ptr initforms)) |
---|
2953 | |
---|
2954 | (defmacro copy-record (type source dest) |
---|
2955 | (let* ((size (* (%foreign-type-or-record-size type :words) #+64-bit-target 1 #+32-bit-target 2)) |
---|
2956 | (src (gensym "SRC")) |
---|
2957 | (dst (gensym "DST")) |
---|
2958 | (accessor #+64-bit-target '%get-unsigned-long #+32-bit-target '%get-unsigned-word) |
---|
2959 | (i (gensym "I")) |
---|
2960 | (j (gensym "J"))) |
---|
2961 | `(with-macptrs ((,src ,source) |
---|
2962 | (,dst ,dest)) |
---|
2963 | (do* ((,i 0 (+ ,i #+64-bit-target 4 #+32-bit-target 2)) |
---|
2964 | (,j 0 (+ ,j 1))) |
---|
2965 | ((= ,j ,size)) |
---|
2966 | (declare (fixnum ,i)) |
---|
2967 | (setf (,accessor ,dst ,i) (,accessor ,src ,i)))))) |
---|
2968 | |
---|
2969 | (defmacro assert-pointer-type (pointer type) |
---|
2970 | "Assert that the pointer points to an instance of the specified foreign type. |
---|
2971 | Return the pointer." |
---|
2972 | (let* ((ptr (gensym))) |
---|
2973 | `(let* ((,ptr ,pointer)) |
---|
2974 | (%set-macptr-type ,ptr (foreign-type-ordinal (load-time-value (parse-foreign-type ',type)))) |
---|
2975 | ,ptr))) |
---|
2976 | |
---|
2977 | |
---|
2978 | |
---|
2979 | (defmacro with-terminal-input (&body body) |
---|
2980 | "Execute body in an environment with exclusive read access to the terminal." |
---|
2981 | (let* ((got-it (gensym))) |
---|
2982 | `(let* ((,got-it (%request-terminal-input))) |
---|
2983 | (unwind-protect |
---|
2984 | (progn ,@body) |
---|
2985 | (%restore-terminal-input ,got-it))))) |
---|
2986 | |
---|
2987 | |
---|
2988 | (defmacro with-process-whostate ((whostate) &body body) |
---|
2989 | (let* ((p (gensym)) |
---|
2990 | (old-whostate (gensym))) |
---|
2991 | `(let* ((,p *current-process*) |
---|
2992 | (,old-whostate (process-whostate ,p))) |
---|
2993 | (unwind-protect |
---|
2994 | (progn |
---|
2995 | (setf (%process-whostate ,p) ,whostate) |
---|
2996 | ,@body) |
---|
2997 | (setf (%process-whostate ,p) ,old-whostate))))) |
---|
2998 | |
---|
2999 | |
---|
3000 | |
---|
3001 | |
---|
3002 | |
---|
3003 | (defmacro with-read-lock ((lock) &body body) |
---|
3004 | "Wait until a given lock is available for read-only access, then evaluate |
---|
3005 | its body with the lock held." |
---|
3006 | (let* ((p (gensym))) |
---|
3007 | `(with-lock-context |
---|
3008 | (let* ((,p ,lock)) |
---|
3009 | (unwind-protect |
---|
3010 | (progn |
---|
3011 | (read-lock-rwlock ,p) |
---|
3012 | ,@body) |
---|
3013 | (unlock-rwlock ,p)))))) |
---|
3014 | |
---|
3015 | |
---|
3016 | (defmacro with-write-lock ((lock) &body body) |
---|
3017 | "Wait until the given lock is available for write access, then execute |
---|
3018 | its body with the lock held." |
---|
3019 | (let* ((p (gensym))) |
---|
3020 | `(with-lock-context |
---|
3021 | (let* ((,p ,lock)) |
---|
3022 | (unwind-protect |
---|
3023 | (progn |
---|
3024 | (write-lock-rwlock ,p) |
---|
3025 | ,@body) |
---|
3026 | (unlock-rwlock ,p)))))) |
---|
3027 | |
---|
3028 | |
---|
3029 | |
---|
3030 | (defmacro without-gcing (&body body) |
---|
3031 | `(unwind-protect |
---|
3032 | (progn |
---|
3033 | (%lock-gc-lock) |
---|
3034 | ,@body) |
---|
3035 | (%unlock-gc-lock))) |
---|
3036 | |
---|
3037 | (defmacro with-deferred-gc (&body body) |
---|
3038 | "Execute BODY without responding to the signal used to suspend |
---|
3039 | threads for GC. BODY must be very careful not to do anything which |
---|
3040 | could cause an exception (note that attempting to allocate lisp memory |
---|
3041 | may cause an exception.)" |
---|
3042 | `(let* ((*interrupt-level* -2)) |
---|
3043 | ,@body)) |
---|
3044 | |
---|
3045 | (defmacro allowing-deferred-gc (&body body) |
---|
3046 | "Within the extent of a surrounding WITH-DEFERRED-GC, allow GC." |
---|
3047 | `(let* ((*interrupt-level* -1)) |
---|
3048 | (%check-deferred-gc) |
---|
3049 | ,@body)) |
---|
3050 | |
---|
3051 | (defmacro defer-gc () |
---|
3052 | `(setq *interrupt-level* -2)) |
---|
3053 | |
---|
3054 | |
---|
3055 | (defmacro with-pointer-to-ivector ((ptr ivector) &body body) |
---|
3056 | "Executes BODY with PTR bound to a pointer to the first byte of data |
---|
3057 | in IVECTOR. The GC is disabled during execution of BODY; PTR has |
---|
3058 | has dynamic-extent (and the address it references may become invalid |
---|
3059 | after the BODY exits.) IVECTOR should be a (SIMPLE-ARRAY (*)) whose |
---|
3060 | element-type is numeric." |
---|
3061 | (let* ((v (gensym))) |
---|
3062 | `(let* ((,v ,ivector)) |
---|
3063 | (unless (typep ,v 'ivector) (report-bad-arg ,v 'ivector)) |
---|
3064 | (without-gcing |
---|
3065 | (with-macptrs ((,ptr)) |
---|
3066 | (%vect-data-to-macptr ,v ,ptr) |
---|
3067 | ,@body))))) |
---|
3068 | |
---|
3069 | |
---|
3070 | |
---|
3071 | (defmacro with-other-threads-suspended (&body body) |
---|
3072 | `(unwind-protect |
---|
3073 | (progn |
---|
3074 | (%suspend-other-threads) |
---|
3075 | ,@body) |
---|
3076 | (%resume-other-threads))) |
---|
3077 | |
---|
3078 | (defmacro with-package-read-lock ((p) &body body) |
---|
3079 | `(with-read-lock ((pkg.lock ,p)) ,@body)) |
---|
3080 | |
---|
3081 | (defmacro with-package-write-lock ((p) &body body) |
---|
3082 | `(with-write-lock ((pkg.lock ,p)) ,@body)) |
---|
3083 | |
---|
3084 | (defmacro with-package-lock ((p) &body body) |
---|
3085 | `(with-package-write-lock (,p) ,@body)) |
---|
3086 | |
---|
3087 | ;;; Lock %all-packages-lock%, for shared read access to %all-packages% |
---|
3088 | |
---|
3089 | (defmacro with-package-list-read-lock (&body body) |
---|
3090 | `(with-read-lock (%all-packages-lock%) ,@body)) |
---|
3091 | |
---|
3092 | ;;; Lock %all-packages-lock%, to allow modification to %all-packages% |
---|
3093 | (defmacro with-package-list-write-lock (&body body) |
---|
3094 | `(with-write-lock (%all-packages-lock%) ,@body)) |
---|
3095 | |
---|
3096 | (defmacro atomic-incf-decf (place delta &environment env) |
---|
3097 | (setq place (macroexpand place env)) |
---|
3098 | (if (consp place) |
---|
3099 | (let* ((sym (car place)) |
---|
3100 | (struct-transform (or (environment-structref-info sym env) |
---|
3101 | (gethash sym %structure-refs%)))) |
---|
3102 | (if struct-transform |
---|
3103 | (setq place (defstruct-ref-transform struct-transform (cdr place)) |
---|
3104 | sym (car place))) |
---|
3105 | (ecase sym |
---|
3106 | (the `(the ,(cadr place) (atomic-incf-decf ,(caddr place) ,delta))) |
---|
3107 | (car `(%atomic-incf-car ,(cadr place) ,delta)) |
---|
3108 | (cdr `(%atomic-incf-cdr ,(cadr place) ,delta)) |
---|
3109 | ((svref %svref) `(%atomic-incf-gvector ,@(cdr place) ,delta)))) |
---|
3110 | (if (and (symbolp place) (eq :special (variable-information place env))) |
---|
3111 | (let* ((base (gensym)) |
---|
3112 | (offset (gensym))) |
---|
3113 | `(multiple-value-bind (,base ,offset) |
---|
3114 | (%symbol-binding-address ',place) |
---|
3115 | (%atomic-incf-node ,delta ,base ,offset))) |
---|
3116 | (error "~S is not a special variable" place)))) |
---|
3117 | |
---|
3118 | (defmacro atomic-incf (place) |
---|
3119 | `(atomic-incf-decf ,place 1)) |
---|
3120 | |
---|
3121 | (defmacro atomic-decf (place) |
---|
3122 | `(atomic-incf-decf ,place -1)) |
---|
3123 | |
---|
3124 | ; Some of these macros were stolen from CMUCL. Sort of ... |
---|
3125 | |
---|
3126 | (defmacro iterate (name binds &body body) |
---|
3127 | "Iterate Name ({(Var Initial-Value)}*) Declaration* Form* |
---|
3128 | This is syntactic sugar for Labels. It creates a local function Name with |
---|
3129 | the specified Vars as its arguments and the Declarations and Forms as its |
---|
3130 | body. This function is then called with the Initial-Values, and the result |
---|
3131 | of the call is return from the macro." |
---|
3132 | (dolist (x binds) |
---|
3133 | (unless (and (listp x) |
---|
3134 | (= (length x) 2)) |
---|
3135 | (error "Malformed iterate variable spec: ~S." x))) |
---|
3136 | |
---|
3137 | `(labels ((,name ,(mapcar #'first binds) ,@body)) |
---|
3138 | (,name ,@(mapcar #'second binds)))) |
---|
3139 | |
---|
3140 | ;;;; The Collect macro: |
---|
3141 | |
---|
3142 | ;;; Collect-Normal-Expander -- Internal |
---|
3143 | ;;; |
---|
3144 | ;;; This function does the real work of macroexpansion for normal collection |
---|
3145 | ;;; macros. N-Value is the name of the variable which holds the current |
---|
3146 | ;;; value. Fun is the function which does collection. Forms is the list of |
---|
3147 | ;;; forms whose values we are supposed to collect. |
---|
3148 | ;;; |
---|
3149 | (eval-when (:compile-toplevel :load-toplevel :execute) |
---|
3150 | |
---|
3151 | |
---|
3152 | (defun collect-normal-expander (n-value fun forms) |
---|
3153 | `(progn |
---|
3154 | ,@(mapcar #'(lambda (form) `(setq ,n-value (,fun ,form ,n-value))) forms) |
---|
3155 | ,n-value)) |
---|
3156 | |
---|
3157 | |
---|
3158 | ) |
---|
3159 | |
---|
3160 | (defmacro once-only (specs &body body) |
---|
3161 | "Once-Only ({(Var Value-Expression)}*) Form* |
---|
3162 | Create a Let* which evaluates each Value-Expression, binding a temporary |
---|
3163 | variable to the result, and wrapping the Let* around the result of the |
---|
3164 | evaluation of Body. Within the body, each Var is bound to the corresponding |
---|
3165 | temporary variable." |
---|
3166 | (iterate frob |
---|
3167 | ((specs specs) |
---|
3168 | (body body)) |
---|
3169 | (if (null specs) |
---|
3170 | `(progn ,@body) |
---|
3171 | (let ((spec (first specs))) |
---|
3172 | (when (/= (length spec) 2) |
---|
3173 | (error "Malformed Once-Only binding spec: ~S." spec)) |
---|
3174 | (let ((name (first spec)) |
---|
3175 | (exp-temp (gensym))) |
---|
3176 | `(let ((,exp-temp ,(second spec)) |
---|
3177 | (,name (gensym))) |
---|
3178 | `(let ((,,name ,,exp-temp)) |
---|
3179 | ,,(frob (rest specs) body)))))))) |
---|
3180 | |
---|
3181 | (eval-when (:compile-toplevel :load-toplevel :execute) |
---|
3182 | (defun form-symbol (first &rest others) |
---|
3183 | (intern (apply #'concatenate 'simple-base-string (string first) (mapcar #'string others)))) |
---|
3184 | ) |
---|
3185 | |
---|
3186 | |
---|
3187 | ;;; Collect-List-Expander -- Internal |
---|
3188 | ;;; |
---|
3189 | ;;; This function deals with the list collection case. N-Tail is the pointer |
---|
3190 | ;;; to the current tail of the list, which is NIL if the list is empty. |
---|
3191 | ;;; |
---|
3192 | (defun collect-list-expander (n-value n-tail forms) |
---|
3193 | (let ((n-res (gensym))) |
---|
3194 | `(progn |
---|
3195 | ,@(mapcar #'(lambda (form) |
---|
3196 | `(let ((,n-res (cons ,form nil))) |
---|
3197 | (cond (,n-tail |
---|
3198 | (setf (cdr ,n-tail) ,n-res) |
---|
3199 | (setq ,n-tail ,n-res)) |
---|
3200 | (t |
---|
3201 | (setq ,n-tail ,n-res ,n-value ,n-res))))) |
---|
3202 | forms) |
---|
3203 | ,n-value))) |
---|
3204 | |
---|
3205 | ;;; |
---|
3206 | ;;; The ultimate collection macro... |
---|
3207 | ;;; |
---|
3208 | |
---|
3209 | (defmacro collect (collections &body body) |
---|
3210 | "Collect ({(Name [Initial-Value] [Function])}*) {Form}* |
---|
3211 | Collect some values somehow. Each of the collections specifies a bunch of |
---|
3212 | things which collected during the evaluation of the body of the form. The |
---|
3213 | name of the collection is used to define a local macro, a la MACROLET. |
---|
3214 | Within the body, this macro will evaluate each of its arguments and collect |
---|
3215 | the result, returning the current value after the collection is done. The |
---|
3216 | body is evaluated as a PROGN; to get the final values when you are done, just |
---|
3217 | call the collection macro with no arguments. |
---|
3218 | |
---|
3219 | Initial-Value is the value that the collection starts out with, which |
---|
3220 | defaults to NIL. Function is the function which does the collection. It is |
---|
3221 | a function which will accept two arguments: the value to be collected and the |
---|
3222 | current collection. The result of the function is made the new value for the |
---|
3223 | collection. As a totally magical special-case, the Function may be Collect, |
---|
3224 | which tells us to build a list in forward order; this is the default. If an |
---|
3225 | Initial-Value is supplied for Collect, the stuff will be rplacd'd onto the |
---|
3226 | end. Note that Function may be anything that can appear in the functional |
---|
3227 | position, including macros and lambdas." |
---|
3228 | |
---|
3229 | |
---|
3230 | (let ((macros ()) |
---|
3231 | (binds ())) |
---|
3232 | (dolist (spec collections) |
---|
3233 | (unless (<= 1 (length spec) 3) |
---|
3234 | (error "Malformed collection specifier: ~S." spec)) |
---|
3235 | (let ((n-value (gensym)) |
---|
3236 | (name (first spec)) |
---|
3237 | (default (second spec)) |
---|
3238 | (kind (or (third spec) 'collect))) |
---|
3239 | |
---|
3240 | (push `(,n-value ,default) binds) |
---|
3241 | (if (eq kind 'collect) |
---|
3242 | (let ((n-tail (gensym))) |
---|
3243 | (if default |
---|
3244 | (push `(,n-tail (last ,n-value)) binds) |
---|
3245 | (push n-tail binds)) |
---|
3246 | (push `(,name (&rest args) |
---|
3247 | (collect-list-expander ',n-value ',n-tail args)) |
---|
3248 | macros)) |
---|
3249 | (push `(,name (&rest args) |
---|
3250 | (collect-normal-expander ',n-value ',kind args)) |
---|
3251 | macros)))) |
---|
3252 | `(macrolet ,macros (let* ,(nreverse binds) (declare (ignorable ,@binds)) ,@body)))) |
---|
3253 | |
---|
3254 | |
---|
3255 | ;;; DEFENUM -- Internal Interface. |
---|
3256 | ;;; |
---|
3257 | (defmacro defenum ((&key (prefix "") (suffix "") (start 0) (step 1)) |
---|
3258 | &rest identifiers) |
---|
3259 | (let ((results nil) |
---|
3260 | (index 0) |
---|
3261 | (start (eval start)) |
---|
3262 | (step (eval step))) |
---|
3263 | (dolist (id identifiers) |
---|
3264 | (multiple-value-bind |
---|
3265 | (root docs) |
---|
3266 | (if (consp id) |
---|
3267 | (values (car id) (cdr id)) |
---|
3268 | (values id nil)) |
---|
3269 | (push `(defconstant ,(intern (concatenate 'simple-base-string |
---|
3270 | (string prefix) |
---|
3271 | (string root) |
---|
3272 | (string suffix))) |
---|
3273 | ,(+ start (* step index)) |
---|
3274 | ,@docs) |
---|
3275 | results)) |
---|
3276 | (incf index)) |
---|
3277 | `(eval-when (:compile-toplevel :load-toplevel :execute) |
---|
3278 | ,@(nreverse results)))) |
---|
3279 | |
---|
3280 | |
---|
3281 | ;;; This does something like special binding, but the "bindings" established |
---|
3282 | ;;; aren't thread-specific. |
---|
3283 | |
---|
3284 | (defmacro let-globally ((&rest vars) &body body &environment env) |
---|
3285 | (multiple-value-bind (body decls) (parse-body body env) |
---|
3286 | (let* ((initforms nil) |
---|
3287 | (psetform nil) |
---|
3288 | (specvars nil) |
---|
3289 | (restoreform nil)) |
---|
3290 | (flet ((pair-name-value (p) |
---|
3291 | (if (atom p) |
---|
3292 | (values (require-global-symbol p env) nil) |
---|
3293 | (if (and (consp (%cdr p)) (null (%cddr p))) |
---|
3294 | (values (require-global-symbol (%car p) env) (%cadr p)) |
---|
3295 | (error "Invalid variable initialization form : ~s"))))) |
---|
3296 | (declare (inline pair-name-value)) |
---|
3297 | (dolist (v vars) |
---|
3298 | (let* ((oldval (gensym)) |
---|
3299 | (newval (gensym))) |
---|
3300 | (multiple-value-bind (var valueform) (pair-name-value v) |
---|
3301 | (push var specvars) |
---|
3302 | (push var restoreform) |
---|
3303 | (push oldval restoreform) |
---|
3304 | (push `(,oldval (uvref (symptr->symvector ',var) #.target::symbol.vcell-cell)) initforms) |
---|
3305 | (push `(,newval ,valueform) initforms) |
---|
3306 | (push var psetform) |
---|
3307 | (push newval psetform)))) |
---|
3308 | `(let ,(nreverse initforms) |
---|
3309 | ,@decls |
---|
3310 | (locally (declare (special ,@(nreverse specvars))) |
---|
3311 | (unwind-protect |
---|
3312 | (progn (psetq ,@(nreverse psetform)) ,@body) |
---|
3313 | (psetq ,@(nreverse restoreform))))))))) |
---|
3314 | ;;; From CLX. |
---|
3315 | |
---|
3316 | ;;; The good news is that this uses an interlocked load/store sequence |
---|
3317 | ;;; and is fairly efficient. |
---|
3318 | ;;; The bad news is that it only handles a few types of "place" forms. |
---|
3319 | ;;; The good news is that CLX only uses a few types of "place" forms. |
---|
3320 | |
---|
3321 | (defmacro conditional-store (place old-value new-value &environment env) |
---|
3322 | (setq place (macroexpand place env)) |
---|
3323 | (if (atom place) |
---|
3324 | ;; CLX uses special variables' value cells as place forms. |
---|
3325 | (if (and (symbolp place) |
---|
3326 | (eq :special (ccl::variable-information place env))) |
---|
3327 | (let* ((base (gensym)) |
---|
3328 | (offset (gensym))) |
---|
3329 | `(multiple-value-bind (,base ,offset) |
---|
3330 | (ccl::%symbol-binding-address ',place) |
---|
3331 | (ccl::%store-node-conditional ,offset ,base ,old-value ,new-value))) |
---|
3332 | (error "~s is not a special variable ." place)) |
---|
3333 | (let* ((sym (car place)) |
---|
3334 | (struct-transform (or (ccl::environment-structref-info sym env) |
---|
3335 | (gethash sym ccl::%structure-refs%)))) |
---|
3336 | (if struct-transform |
---|
3337 | (setq place (ccl::defstruct-ref-transform struct-transform (cdr place)) |
---|
3338 | sym (car place))) |
---|
3339 | (if (member sym '(svref ccl::%svref ccl::struct-ref)) |
---|
3340 | (let* ((v (gensym))) |
---|
3341 | `(let* ((,v ,(cadr place))) |
---|
3342 | (ccl::store-gvector-conditional ,(caddr place) |
---|
3343 | ,v ,old-value ,new-value))) |
---|
3344 | (error "Don't know how to do conditional store to ~s" place))))) |
---|
3345 | |
---|
3346 | (defmacro step (form) |
---|
3347 | "The form is evaluated with single stepping enabled. Function calls |
---|
3348 | outside the lexical scope of the form can be stepped into only if the |
---|
3349 | functions in question have been compiled with sufficient DEBUG policy |
---|
3350 | to be at least partially steppable." |
---|
3351 | form) |
---|
3352 | |
---|
3353 | (defmacro target-arch-case (&rest clauses) |
---|
3354 | `(case (backend-target-arch-name *target-backend*) |
---|
3355 | ,@clauses)) |
---|
3356 | |
---|
3357 | (defmacro target-os-case (&rest clauses) |
---|
3358 | `(ecase (backend-target-os *target-backend*) |
---|
3359 | ,@clauses)) |
---|
3360 | |
---|
3361 | (defmacro target-word-size-case (&rest clauses) |
---|
3362 | `(ecase (arch::target-nbits-in-word (backend-target-arch *target-backend*)) |
---|
3363 | ,@clauses)) |
---|
3364 | |
---|
3365 | (defmacro %get-natural (&body body) |
---|
3366 | "A free copy of the next OpenMCL release to anyone who remembers Flakey Foont" |
---|
3367 | (target-word-size-case |
---|
3368 | (32 `(%get-unsigned-long ,@body)) |
---|
3369 | (64 `(%%get-unsigned-longlong ,@body)))) |
---|
3370 | |
---|
3371 | (defmacro %get-signed-natural (&body body) |
---|
3372 | "And that's my final offer." |
---|
3373 | (target-word-size-case |
---|
3374 | (32 `(%get-signed-long ,@body)) |
---|
3375 | (64 `(%%get-signed-longlong ,@body)))) |
---|
3376 | |
---|
3377 | (declare-arch-specific-macro %target-kernel-global) |
---|
3378 | |
---|
3379 | ;;; This behaves like a function, but looks up the kernel global |
---|
3380 | ;;; at compile time if possible. Probably should be done as a function |
---|
3381 | ;;; and a compiler macro, but we can't define compiler macros yet, |
---|
3382 | ;;; and I don't want to add it to "ccl:compiler;optimizers.lisp" |
---|
3383 | (declare-arch-specific-macro %get-kernel-global) |
---|
3384 | |
---|
3385 | (declare-arch-specific-macro %get-kernel-global-ptr) |
---|
3386 | |
---|
3387 | (declare-arch-specific-macro area-code) |
---|
3388 | |
---|
3389 | (declare-arch-specific-macro nth-immediate) |
---|
3390 | |
---|
3391 | (declare-arch-specific-macro set-nth-immediate) |
---|
3392 | |
---|
3393 | (defsetf nth-immediate set-nth-immediate) |
---|
3394 | |
---|
3395 | (defmacro do-consing-areas ((area) &body body) |
---|
3396 | (let ((code (gensym))) |
---|
3397 | `(do-gc-areas (,area) |
---|
3398 | (let ((,code (%fixnum-ref ,area (area-code)))) |
---|
3399 | (when (or (eql ,code area-readonly) |
---|
3400 | (eql ,code area-managed-static) |
---|
3401 | (eql ,code area-static) |
---|
3402 | (eql ,code area-dynamic)) |
---|
3403 | ,@body))))) |
---|
3404 | |
---|
3405 | (declare-arch-specific-macro area-succ) |
---|
3406 | |
---|
3407 | (defmacro with-ioblock-lock-grabbed ((lock) |
---|
3408 | &body body) |
---|
3409 | `(with-lock-grabbed (,lock) |
---|
3410 | ,@body)) |
---|
3411 | |
---|
3412 | (defmacro with-ioblock-lock-grabbed-maybe ((lock) |
---|
3413 | &body body) |
---|
3414 | `(with-lock-grabbed-maybe (,lock) |
---|
3415 | ,@body)) |
---|
3416 | |
---|
3417 | |
---|
3418 | (defmacro do-gc-areas ((area) &body body) |
---|
3419 | (let ((initial-area (gensym))) |
---|
3420 | `(let* ((,initial-area (%get-kernel-global 'all-areas)) |
---|
3421 | (,area ,initial-area)) |
---|
3422 | (declare (fixnum ,initial-area ,area)) |
---|
3423 | (loop |
---|
3424 | (setq ,area (%fixnum-ref ,area (area-succ))) |
---|
3425 | (when (eql ,area ,initial-area) |
---|
3426 | (return)) |
---|
3427 | ,@body)))) |
---|
3428 | |
---|
3429 | (defmacro with-ioblock-input-lock-grabbed ((ioblock) &body body) |
---|
3430 | `(with-lock-grabbed ((ioblock-inbuf-lock ,ioblock)) |
---|
3431 | ,@body)) |
---|
3432 | |
---|
3433 | (defmacro with-ioblock-output-lock-grabbed ((ioblock) &body body) |
---|
3434 | `(with-lock-grabbed ((ioblock-outbuf-lock ,ioblock)) |
---|
3435 | ,@body)) |
---|
3436 | |
---|
3437 | |
---|
3438 | (defmacro with-stream-ioblock-input ((ioblock stream &key |
---|
3439 | speedy) |
---|
3440 | &body body) |
---|
3441 | `(let ((,ioblock (stream-ioblock ,stream t))) |
---|
3442 | ,@(when speedy `((declare (optimize (speed 3) (safety 0))))) |
---|
3443 | (with-ioblock-input-locked (,ioblock) ,@body))) |
---|
3444 | |
---|
3445 | (defmacro with-stream-ioblock-output ((ioblock stream &key |
---|
3446 | speedy) |
---|
3447 | &body body) |
---|
3448 | `(let ((,ioblock (stream-ioblock ,stream t))) |
---|
3449 | ,@(when speedy `((declare (optimize (speed 3) (safety 0))))) |
---|
3450 | (with-ioblock-output-locked (,ioblock) ,@body))) |
---|
3451 | |
---|
3452 | (defmacro with-stream-ioblock-output-maybe ((ioblock stream &key |
---|
3453 | speedy) |
---|
3454 | &body body) |
---|
3455 | `(let ((,ioblock (stream-ioblock ,stream t))) |
---|
3456 | ,@(when speedy `((declare (optimize (speed 3) (safety 0))))) |
---|
3457 | (with-ioblock-output-locked-maybe (,ioblock) ,@body))) |
---|
3458 | |
---|
3459 | (defmacro with-ioblock-input-locked ((ioblock) &body body) |
---|
3460 | (let* ((lock (gensym))) |
---|
3461 | `(let* ((,lock (locally (declare (optimize (speed 3) (safety 0))) |
---|
3462 | (ioblock-inbuf-lock ,ioblock)))) |
---|
3463 | (if ,lock |
---|
3464 | (with-lock-grabbed (,lock) |
---|
3465 | ,@body) |
---|
3466 | (progn |
---|
3467 | (check-ioblock-owner ,ioblock) |
---|
3468 | ,@body))))) |
---|
3469 | |
---|
3470 | (defmacro with-ioblock-output-locked ((ioblock) &body body) |
---|
3471 | (let* ((lock (gensym))) |
---|
3472 | `(let* ((,lock (locally (declare (optimize (speed 3) (safety 0))) |
---|
3473 | (ioblock-outbuf-lock ,ioblock)))) |
---|
3474 | (if ,lock |
---|
3475 | (with-lock-grabbed (,lock) |
---|
3476 | ,@body) |
---|
3477 | (progn |
---|
3478 | (check-ioblock-owner ,ioblock) |
---|
3479 | ,@body))))) |
---|
3480 | |
---|
3481 | |
---|
3482 | |
---|
3483 | (defmacro with-ioblock-output-locked-maybe ((ioblock) &body body) |
---|
3484 | (let* ((lock (gensym))) |
---|
3485 | `(let* ((,lock (locally (declare (optimize (speed 3) (safety 0))) |
---|
3486 | (ioblock-outbuf-lock ,ioblock)))) |
---|
3487 | (if ,lock |
---|
3488 | (with-lock-grabbed-maybe (,lock) |
---|
3489 | ,@body) |
---|
3490 | (progn |
---|
3491 | (check-ioblock-owner ,ioblock) |
---|
3492 | ,@body))))) |
---|
3493 | |
---|
3494 | ;;; Use this when it's possible that the fd might be in |
---|
3495 | ;;; a non-blocking state. Body must return a negative of |
---|
3496 | ;;; the os error number on failure. |
---|
3497 | ;;; The use of READ-FROM-STRING below is certainly ugly, but macros |
---|
3498 | ;;; that expand into reader-macros don't generally trigger the reader-macro's |
---|
3499 | ;;; side-effects. (Besides, the reader-macro might return a different |
---|
3500 | ;;; value when the macro function is expanded than it did when the macro |
---|
3501 | ;;; function was defined; this can happen during cross-compilation.) |
---|
3502 | (defmacro with-eagain (fd direction &body body) |
---|
3503 | (let* ((res (gensym)) |
---|
3504 | (eagain (symbol-value (read-from-string "#$EAGAIN")))) |
---|
3505 | `(loop |
---|
3506 | (let ((,res (progn ,@body))) |
---|
3507 | (if (eql ,res (- ,eagain)) |
---|
3508 | (,(ecase direction |
---|
3509 | (:input 'process-input-wait) |
---|
3510 | (:output 'process-output-wait)) |
---|
3511 | ,fd) |
---|
3512 | (return ,res)))))) |
---|
3513 | |
---|
3514 | (defmacro basic-stream-ioblock (s) |
---|
3515 | `(or (basic-stream.state ,s) |
---|
3516 | (stream-is-closed ,s))) |
---|
3517 | |
---|
3518 | (defsetf interrupt-level set-interrupt-level) |
---|
3519 | |
---|
3520 | (defmacro %swap-u16 (val) |
---|
3521 | (let* ((arg (gensym))) |
---|
3522 | `(let* ((,arg ,val)) |
---|
3523 | (declare (type (unsigned-byte 16) ,arg)) |
---|
3524 | (logand #xffff (the fixnum (logior (the fixnum (ash ,arg -8)) |
---|
3525 | (the fixnum (ash ,arg 8)))))))) |
---|
3526 | |
---|
3527 | (defmacro %swap-u32 (val) |
---|
3528 | (let* ((arg (gensym))) |
---|
3529 | `(let ((,arg ,val)) |
---|
3530 | (declare (type (unsigned-byte 32) ,arg)) |
---|
3531 | (the (unsigned-byte 32) (logior (the (unsigned-byte 32) |
---|
3532 | (ash (logand #xff ,arg) 24)) |
---|
3533 | (the (unsigned-byte 24) |
---|
3534 | (logior |
---|
3535 | (the (unsigned-byte 24) (ash (logand #xff00 ,arg) 8)) |
---|
3536 | (the (unsigned-byte 16) |
---|
3537 | (logior |
---|
3538 | (the (unsigned-byte 16) (ash (logand #xff0000 ,arg) -8)) |
---|
3539 | (the (unsigned-byte 8) (ash ,arg -24))))))))))) |
---|
3540 | |
---|
3541 | |
---|
3542 | (defmacro multiple-value-bind (varlist values-form &body body &environment env) |
---|
3543 | (multiple-value-bind (body decls) |
---|
3544 | (parse-body body env) |
---|
3545 | (let ((ignore (make-symbol "IGNORE"))) |
---|
3546 | `(multiple-value-call #'(lambda (&optional ,@varlist &rest ,ignore) |
---|
3547 | (declare (ignore ,ignore)) |
---|
3548 | ,@decls |
---|
3549 | ,@body) |
---|
3550 | ,values-form)))) |
---|
3551 | |
---|
3552 | (defmacro multiple-value-setq (vars val) |
---|
3553 | (if vars |
---|
3554 | `(values (setf (values ,@(mapcar #'(lambda (s) (require-type s 'symbol)) vars)) ,val)) |
---|
3555 | `(prog1 ,val))) |
---|
3556 | |
---|
3557 | (defmacro nth-value (n form) |
---|
3558 | "Evaluate FORM and return the Nth value (zero based). This involves no |
---|
3559 | consing when N is a trivial constant integer." |
---|
3560 | `(car (nthcdr ,n (multiple-value-list ,form)))) |
---|