2 ;;;; Additional Common Lisp Functions for XLISP-STAT 2.0
3 ;;;; XLISP-STAT 2.1 Copyright (c) 1990-95, by Luke Tierney
4 ;;;; Additions to Xlisp 2.1, Copyright (c) 1989 by David Michael Betz
5 ;;;; You may give out copies of this software; for conditions see the file
6 ;;;; COPYING included with this distribution.
12 ;;;;;; Environment Access and Modification Routines
15 (defvar *cmp-global-macros
* nil
)
17 (defvar *cmp-specials
*)
19 (export '(ftype ignorable ignore inline notinline
))
23 ;;;; PARSE-MACRO and ENCLOSE
26 (export '(enclose parse-macro
))
28 (defun split-declarations (x)
29 (flet ((head-is-declaration (x)
30 (and (consp (first x
)) (eq (first (first x
)) 'declare
)))
31 (head-is-docstring (x) (and (stringp (first x
)) (consp (rest x
))))
32 (check-declarations (decls)
35 (if (and (consp i
) (eq (first i
) 'special
))
37 (warn "special declaration for ~s ignored." v
)))))))
43 ((head-is-declaration body
) (push (first body
) decls
))
44 ((head-is-docstring body
) (setf doc
(first body
)))
45 (t (check-declarations decls
)
46 (return (list (nreverse decls
) body doc
)))))))
48 ;; This returns a lambda expression consistent with the CLtL2
49 ;; specification of macro expansion functions as functions of two
50 ;; arguments, the form to be expanded and the environment to use. The
51 ;; internal calling conventions and construction of macro closures has
52 ;; been modified accordingly. This definition does not do the right
53 ;; thing with declarations at this point.
54 (defun make-macro-lambda-expression (name lambda-list body
)
55 (flet ((fixup-macro-args (args)
58 (setf args
(copy-list args
))
59 (let ((last (last args
)))
60 (unless (null (cdr last
))
61 (rplacd last
(list '&rest
(cdr last
)))))
62 (setf args
(nsubst '&rest
'&body args
))
63 (when (find '&environment args
)
64 (setf esym
(second (member '&environment args
)))
65 (setf args
(remove esym
(remove '&environment args
))))
67 ((eq (first args
) '&whole
)
68 (setf wsym
(second args
))
69 (setf args
(rest (rest args
))))
70 (t (setf wsym
(gensym "WHOLE"))))
71 (cons esym
(cons wsym args
))))
72 (destructuring-arglist-p (x)
74 (find-if #'(lambda (x)
75 (or (member x lambda-list-keywords
) (consp x
)))
77 (let* ((args (fixup-macro-args lambda-list
))
78 (bd (split-declarations body
))
79 (body `(,@(first bd
) (block ,name
,@(second bd
))))
84 (llist (rest (rest args
))))
86 (setf esym
(gensym "ENV"))
87 (setf edecl
`((declare (ignore ,esym
)))))
89 `(lambda (,wsym
,esym
)
91 ,(if (destructuring-arglist-p args
)
92 `(destructuring-bind ,llist
(rest ,wsym
) ,@body
)
93 `(apply #'(lambda ,llist
,@body
) (rest ,wsym
))))
97 ;; This implementation produces an interpreted function
98 (defun enclose (expr &optional env
) (evalhook expr nil nil env
))
100 (defun parse-macro (name lambda-list body
&optional env
)
101 (enclose (make-macro-lambda-expression name lambda-list body
) env
))
105 ;;;; DEFINE-COMPILER-MACRO
107 ;;;; Fake version to be overridded if the compiler is loaded
109 (export 'define-compiler-macro
)
111 (defmacro set-cmp-macro
(symarg funarg
)
112 `(let* ((sym ,symarg
)
114 (entry (assoc sym
*cmp-global-macros
*)))
117 (push (cons sym fun
) *cmp-global-macros
*))
120 (defmacro define-compiler-macro
(sym args
&rest body
)
121 (let ((fexpr (make-macro-lambda-expression sym args body
)))
123 (set-cmp-macro ',sym
(coerce-to-macro #',fexpr
))
126 (defmacro define-special-form-macro
(sym args
&rest body
)
127 (let ((fexpr (make-macro-lambda-expression sym args body
)))
129 (%set-get
',sym
'macro
(coerce-to-macro #',fexpr
))
134 ;;;; AUGMENT-ENVIRONMENT, VARIABLE-INFORMATION, and FUNCTION-INFORMATION
137 (export '(augment-environment variable-information function-information
))
139 ;; Environments are of the form (venv . fenv). Each of venv and fenv
140 ;; is a list of frames, and frames are lists of bindings. Bindings are
141 ;; pairs (name . value). If the value in a variable binding is
142 ;; :symbol-macro and the next pair has name :symbol-macro, then the
143 ;; value of the second of these bindings represente the symbol macro
144 ;; expansion of the symbol in the first binding.
146 (defun special-variable-p (sym)
148 (and (boundp '*cmp-specials
*) (member sym
*cmp-specials
*))))
150 (defun augment-environment (env &key
151 variable symbol-macro function macro declare
)
152 (declare (ignore declare
))
153 (when (intersection variable
(mapcar #'first symbol-macro
))
154 (error "adding some symbols as variables and as symbol macros"))
155 (when (intersection function
(mapcar #'first macro
))
156 (error "adding some symbols as functions and macros"))
158 (when (special-variable-p v
)
159 (error "cant't make lexical binding for the special variable ~s" v
)))
160 (dolist (sm symbol-macro
)
161 (let ((v (first sm
)))
162 (when (special-variable-p v
)
163 (error "cant't make lexical binding for the special variable ~s"
165 (flet ((add-variable-frame (frame env
)
166 (if frame
(cons (cons frame
(car env
)) (cdr env
)) env
))
167 (add-function-frame (frame env
)
168 (if frame
(cons (car env
) (cons frame
(cdr env
))) env
))
169 (make-variable-frame (vars) (mapcar #'list vars
))
170 (make-function-frame (funs) (mapcar #'list funs
))
171 (make-macro-frame (macs)
172 (mapcar #'(lambda (x) (cons (first x
) (coerce-to-macro (second x
))))
174 (make-symbol-macro-frame (smacs)
177 (push (cons :symbol-macro
(second s
)) frame
)
178 (push (cons (first s
) :symbol-macro
) frame
))
180 (setf env
(add-variable-frame (make-variable-frame variable
) env
))
181 (setf env
(add-variable-frame (make-symbol-macro-frame symbol-macro
) env
))
182 (setf env
(add-function-frame (make-function-frame function
) env
))
183 (setf env
(add-function-frame (make-macro-frame macro
) env
))
186 (defun get-environment-entry (name env
)
188 (let ((m (member name frame
:key
#'car
)))
190 (if (and (eq (cdr (first m
)) :symbol-macro
)
191 (eq (car (second m
)) :symbol-macro
))
192 (return (values t
:symbol-macro
(second m
) frame
))
193 (return (values t
(cdr (first m
)) nil frame
)))))))
195 (defun global-symbol-macro (sym)
196 (if (or (boundp sym
) (special-variable-p sym
))
198 (let ((m (member :symbol-macro
(symbol-plist sym
))))
200 (values (second m
) t
)
203 ;;**** this needs fixing once special declarations are supported
204 (defun variable-information (sym &optional env
)
205 (multiple-value-bind (found value extra
)
206 (get-environment-entry sym
(first env
))
209 (if (and found
(eq value
:symbol-macro
) (eq (car extra
) :symbol-macro
))
210 (values :symbol-macro t nil
)
211 (values :lexical t nil
)))
212 ((constantp sym
) (values :constant nil nil
))
213 ((special-variable-p sym
) (values :special nil nil
))
214 ((nth-value 1 (global-symbol-macro sym
))
215 (values :symbol-macro nil nil
))
216 (t (values nil nil nil
)))))
218 ;;**** needs to be fixed for special forms
219 ;;**** needs to be fixed for C-compiler macroe is they ever materialize
220 (defun function-information (sym &optional env
)
222 (and (or (typep f
'byte-code-closure
) (typep f
'closure
))
223 (not (functionp f
))))
225 (or (eq f
*cmp-global-macros
*)
226 (and (boundp '*cmp-macros
*)
227 (eq f
*cmp-macros
*)))))
228 (multiple-value-bind (found value extra frame
)
229 (get-environment-entry sym
(rest env
))
230 (declare (ignore extra
))
232 ((and found
(macrop value
))
233 (values :macro
(not (global-frame-p frame
)) nil
))
234 (found (values :function t nil
))
235 ((and (fboundp sym
) (macrop (symbol-function sym
)))
236 (values :macro nil nil
))
237 ((and (fboundp sym
) (typep (symbol-function sym
) 'fsubr
))
238 (values :special-form nil nil
))
239 ((and (fboundp sym
) (functionp (symbol-function sym
)))
240 (values :function nil nil
))
241 (t (values nil nil nil
))))))
245 ;;;; New versions of MACROEXPAND and MACROEXPAND-1 that handle symbol macros
248 (export '(macroexpand macroexpand-1
))
250 ;; This function copies symbol macro forms to protect them from
251 ;; splicing that occurs if *displace-macros* in non-nil.
252 (defun macroexpand-symbol-1 (symbol &optional env
)
253 (unless (symbolp symbol
) (error "not a symbol - ~s" symbol
))
254 (multiple-value-bind (found value extra
)
255 (get-environment-entry symbol
(first env
))
256 (if (and found
(eq value
:symbol-macro
) (eq (car extra
) :symbol-macro
))
257 (let ((form (cdr extra
)))
258 (values (if (consp form
) (copy-tree form
) form
) t
))
259 (multiple-value-bind (form found
)
260 (global-symbol-macro symbol
)
262 (values (if (consp form
) (copy-tree form
) form
) t
)
263 (values symbol nil
))))))
265 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
266 (unless (fboundp 'base-macroexpand-1
)
267 (setf (symbol-function 'base-macroexpand-1
)
270 ;; new version that expands symbol macros
271 (defun macroexpand-1 (form &optional env
)
273 (macroexpand-symbol-1 form env
)
274 (base-macroexpand-1 form env
)))
276 ;; new version that expands symbol macros
277 (defun macroexpand (form &optional env
)
280 (macroexpand-1 form env
)
285 (macroexpand-1 form env
)
286 (unless expanded
(return (values newform t
)))
287 (setf form newform
)))
292 ;;;; DEFINE-SYMBOL-MACRO
295 (export 'define-symbol-macro
)
297 (defmacro define-symbol-macro
(name form
)
298 `(eval-when (:compile-toplevel
:load-toplevel
:execute
)
299 (when (or (special-variable-p ',name
) (boundp ',name
))
300 (error "can't assign symbol macro to ~s" ',name
))
301 (setf (get ',name
:symbol-macro
) ',form
)
306 ;;;;; New Setf Macro Expansion System
309 (export '(get-setf-method setf
))
311 (defun get-cmp-setf-info (sym &optional env
)
312 (declare (ignore env
))
313 (if (boundp '*cmp-setf
*) (assoc sym
*cmp-setf
*)))
315 (defun get-cmp-setf-method (sym &optional env
)
316 (let ((cmpsetf (get-cmp-setf-info sym env
)))
317 (if (and cmpsetf
(eq (second cmpsetf
) '*setf
*)) (third cmpsetf
))))
319 (defun get-cmp-setf-lambda (sym &optional env
)
320 (let ((cmpsetf (get-cmp-setf-info sym env
)))
321 (if (and cmpsetf
(eq (second cmpsetf
) '*setf-lambda
*)) (third cmpsetf
))))
323 (defun get-xlisp-setf-method (sym &optional env
)
324 (declare (ignore env
))
327 (defun get-xlisp-setf-lambda (sym &optional env
)
328 (declare (ignore env
))
329 (get sym
'*setf-lambda
*))
331 ;; This function checks for defsetf expanders before doing macro expansion,
332 ;; so one can defsetf a macro. This seems to be what many implementations
333 ;; do, but I'm not sure it is consistent with CLtL2.
334 (defun get-setf-method (form &optional env
)
338 (let* ((sym (first form
))
339 (is-global (not (nth-value 1 (function-information sym env
))))
340 (cmpsfun (get-cmp-setf-method sym env
))
341 (cmpslam (get-cmp-setf-lambda sym env
))
342 (sxfun (get-xlisp-setf-method sym env
))
343 (sxlam (get-xlisp-setf-lambda sym env
)))
344 (when (and (or cmpsfun cmpslam sxfun sxlam
) is-global
)
345 (let* ((args (rest form
))
346 (tvars (mapcar #'(lambda (x) (gensym "T")) args
))
347 (vvars (list (gensym "V")))
348 (aform `(,sym
,@tvars
)))
354 (cmpsfun `(,cmpsfun
,@tvars
,@vvars
))
355 (cmpslam (apply cmpslam
(append tvars vvars
)))
356 ((and sxfun
(symbolp sxfun
))
357 `(,sxfun
,@tvars
,@vvars
))
359 `(funcall (get ',sym
'*setf
*) ,@tvars
,@vvars
))
360 (sxlam (apply sxlam
(append tvars vvars
))))
362 (when (and (eq sym
'apply
) is-global
)
363 (return (get-apply-setf-method form env
)))
364 (multiple-value-bind (newform changed
) (macroexpand-1 form env
)
365 (unless changed
(error "bad place form - ~s" form
))
366 (setf form newform
))))
368 (multiple-value-bind (newform changed
) (macroexpand-1 form env
)
370 (changed (setf form newform
))
372 (let ((sym (gensym (string form
))))
373 (return (values nil nil
`(,sym
) `(setq ,newform
,sym
) newform
)))))))
374 (t (error "bad place form - ~s" form
)))))
376 ;; The implementation here seems consistent with AKCL and common
377 ;; sense, but not with CLtL. The specification in CLtL would not work
378 ;; for things with setf methods defined by the simple form of defsetf
379 (defun get-apply-setf-method (form &optional env
)
380 (declare (ignore env
))
381 (let ((fun (second form
)))
382 (unless (and (consp fun
)
383 (eq (first fun
) 'function
)
384 (symbolp (second fun
))
385 (null (rest (rest fun
))))
386 (error "bad place form - ~s" form
)))
388 (tvars tvals vvars sform aform
)
389 (get-setf-method `(,(second (second form
)) ,@(rest (rest form
))))
391 ((equal (last tvars
) (last sform
)) ;; simple case as described in CLtL
395 `(apply #',(first sform
) ,@(rest sform
))
396 `(apply #',(first aform
) ,@(rest aform
))))
397 ((equal (last tvars
) (last (butlast sform
))) ;; covers simple defsetf's
401 (let* ((lv (first (last sform
)))
403 (rv (first (last bl
))))
404 `(apply #',(first sform
)
405 ,@(butlast (rest bl
))
406 (append ,rv
(list ,lv
))))
407 `(apply #',(first aform
) ,@(rest aform
))))
408 (t (error "bad place form - ~s" form
)))))
411 ;; The special variable *simplify-setf* controls the tradeoff of speed
412 ;; and correctness used by make-setf-form in expanding setf forms. If
413 ;; this variable is nil, then make-setf-form is careful about avoiding
414 ;; multiple evaluation and doing evaluations in the proper order. If
415 ;; *simplify-setf* is not nil, then subforms of place forms and the
416 ;; value form are not protect against multiple evaluation occurring in
417 ;; setf expansions. This is consistent with the internal
418 ;; implementation. It should not be a problem for any f the standard
419 ;; setf methods. The compiler should be able to optimize out all
420 ;; unnecessary variables the careful version setsup, so the compiler
421 ;; should probably bind this variable to nil.
423 (export '*simplify-setf
*)
425 (defvar *simplify-setf
* nil
)
427 (defun make-setf-form (form value
&optional env
)
428 (multiple-value-bind (tvars args vvars sform
)
429 (get-setf-method form env
)
430 (let ((vars (append tvars vvars
))
431 (vals (append args
(list value
))))
433 (sublis (mapcar #'cons vars vals
) sform
)
434 `(let* ,(mapcar #'list vars vals
) ,sform
)))))
436 (defmacro setf
(&rest pairs
&environment env
)
440 (return (if (consp (rest forms
))
441 `(progn ,@(nreverse forms
))
443 (unless (consp (rest pairs
))
444 (error "setf requires an even number of arguments"))
445 ;; need to use setq here to avoid infinite recursion
447 (cons (make-setf-form (first pairs
) (second pairs
) env
) forms
))
448 (setq pairs
(rest (rest pairs
))))))
451 ;;;;;; New versions of Some Modifier Macros
453 ;;;;;; These versions (except rotatef) attempt to optimize simple
454 ;;;;;; symbol place forms with so symbol macro bindings.
456 (export '(incf decf push pop pushnew remf rotatef
))
458 ;; this checks if place is a symbol with no macro definition in env
459 (defun non-macro-variable-symbol-p (place env
)
461 (not (eq :symbol-macro
(variable-information place env
)))))
463 (defmacro incf
(place &optional
(delta 1) &environment env
)
464 (if (non-macro-variable-symbol-p place env
)
465 `(setf ,place
(+ ,place
,delta
))
467 (tvars args vvars sform aform
)
468 (get-setf-method place env
)
469 (let ((vars (append tvars vvars
))
470 (vals (append args
(list `(+ ,aform
,delta
)))))
471 `(let* ,(mapcar #'list vars vals
) ,sform
)))))
473 (defmacro decf
(place &optional
(delta 1) &environment env
)
474 (if (non-macro-variable-symbol-p place env
)
475 `(setf ,place
(- ,place
,delta
))
477 (tvars args vvars sform aform
)
478 (get-setf-method place env
)
479 (let ((vars (append tvars vvars
))
480 (vals (append args
(list `(- ,aform
,delta
)))))
481 `(let* ,(mapcar #'list vars vals
) ,sform
)))))
483 (defmacro push
(val place
&environment env
)
484 (if (non-macro-variable-symbol-p place env
)
485 `(setq ,place
(cons ,val
,place
))
487 (tvars args vvars sform aform
)
488 (get-setf-method place env
)
489 (let ((vars (append tvars vvars
))
490 (vals (append args
(list `(cons ,val
,aform
)))))
491 `(let* ,(mapcar #'list vars vals
) ,sform
)))))
493 (defmacro pop
(place &environment env
)
494 (if (non-macro-variable-symbol-p place env
)
495 `(prog1 (first ,place
) (setq ,place
(rest ,place
)))
497 (tvars args vvars sform aform
)
498 (get-setf-method place env
)
499 (let ((vars (append tvars vvars
))
500 (vals (append args
(list `(rest ,aform
)))))
501 `(let* ,(mapcar #'list vars vals
)
502 (prog1 (first ,aform
) ,sform
))))))
504 (defmacro pushnew
(val place
&rest rest
&environment env
)
505 (if (non-macro-variable-symbol-p place env
)
506 `(setq ,place
(adjoin ,val
,place
,@rest
))
508 (tvars args vvars sform aform
)
509 (get-setf-method place env
)
510 (let ((vars (append tvars vvars
))
511 (vals (append args
(list `(adjoin ,val
,aform
,@rest
)))))
512 `(let* ,(mapcar #'list vars vals
) ,sform
)))))
514 (defun rem-f (list y
)
517 ((null x
) (values list nil
))
518 (when (eq y
(first x
))
521 (rplacd last
(cddr x
))
522 (return (values list t
)))
523 (t (return (values (cddr list
) t
)))))))
525 (defmacro remf
(place indicator
&environment env
)
526 (if (non-macro-variable-symbol-p place env
)
527 `(setq ,place
(rem-f ,place
,indicator
))
529 (tvars args vvars sform aform
)
530 (get-setf-method place env
)
531 (let ((vars (append tvars vvars
))
532 (vals (append args
(list `(rem-f ,aform
,indicator
)))))
533 `(let* ,(mapcar #'list vars vals
) ,sform
)))))
535 ;; This version does not optimize out the case where some places are
536 ;; symbols, but it is not the most used macro in the world, and the
537 ;; compiler should take care of these optimizations anyway.
538 (defmacro rotatef
(&rest places
&environment env
)
539 (let* ((smethods (mapcar #'(lambda (x)
540 (multiple-value-list (get-setf-method x env
)))
542 (tvars (apply #'append
(mapcar #'first smethods
)))
543 (args (apply #'append
(mapcar #'second smethods
)))
544 (vvars (apply #'append
(mapcar #'third smethods
)))
545 (sforms (mapcar #'fourth smethods
))
546 (aforms (mapcar #'fifth smethods
))
547 (rotaforms (append (rest aforms
) (list (first aforms
))))
548 (vars (append tvars vvars
))
549 (vals (append args rotaforms
)))
550 `(let* ,(mapcar #'list vars vals
) ,@sforms nil
)))
554 ;;;;;; Replacements for Some Internal Special Forms
557 (export '(psetq psetf
))
560 ;;;; Replacements for internal PSETQ and PSETF
563 (defun expand-pset-form (name pairs
)
568 (if (null pairs
) (return))
569 (push (gensym) gsyms
)
570 (push (first pairs
) syms
)
571 (push (second pairs
) vals
)
572 (setf pairs
(rest (rest pairs
))))
573 (setf gsyms
(reverse gsyms
))
574 (setf syms
(reverse syms
))
575 (setf vals
(reverse vals
))
576 (let ((bds (mapcar #'list gsyms vals
))
577 (vsets (mapcar #'(lambda (x y
) `(,name
,x
,y
)) syms gsyms
)))
578 `(let* ,bds
,@vsets nil
))))
580 (defmacro psetq
(&rest pairs
) (expand-pset-form 'setq pairs
))
581 (defmacro psetf
(&rest pairs
) (expand-pset-form 'setf pairs
))
585 ;;;;;; Macro Definitions for Special Forms
588 ;;;;;; There is one non-standard special forms, ERRSET. In addition,
589 ;;;;;; the compiler treats CASE and NTH-VALUE as special forms. Code
590 ;;;;;; walkers will need to handle these three cases separately.
591 ;;;;;; ERRSET cannot be macroexpanded, and providing macro definitions
592 ;;;;;; for NTH-VALUE and CASE would result in poor compiled
593 ;;;;;; code. Perhaps they should CASE and NTH-VALUE should be handled
594 ;;;;;; with compiler macros.
597 ;;;; DEFUN and DEFMACRO
600 (define-special-form-macro defun
(f args
&rest body
)
601 (let* ((db (split-declarations body
))
605 (fexpr `#'(lambda ,args
,@decls
(block ,f
,@b
))))
607 ,@(if doc
`((%set-get
',f
'function-documentation
,doc
)))
608 (install-function ',f
,fexpr
))))
610 (define-special-form-macro defmacro
(f args
&rest body
)
611 (multiple-value-bind (fexpr doc
)
612 (make-macro-lambda-expression f args body
)
614 (eval-when (:compile-toplevel
)
615 (push (cons ',f
(coerce-to-macro ,fexpr
)) *cmp-macros
*))
616 ,@(if doc
`((%set-get
',f
'function-documentation
,doc
)))
617 (install-function ',f
(coerce-to-macro ,fexpr
)))))
621 ;;;; DEFMETH and DEFPROTO
625 (define-special-form-macro defmeth
(ob sym args
&rest body
)
626 (let* ((db (split-declarations body
))
630 (fexpr `#'(lambda ,(cons 'self args
) ,@decls
(block ,sym
,@b
))))
632 (xlisp::add-method
,ob
',sym
,fexpr
,doc
)
636 (define-special-form-macro defproto
(name &optional ivars cvars parents doc
)
640 `(let* ((,pp
,parents
)
641 (,p
(apply #'make-object
(if (listp ,pp
) ,pp
(list ,pp
))))
643 (dolist (s ,cvars
) (send ,p
:add-slot s
))
644 (send ,p
:make-prototype
',name
,ivars
)
645 (if ,d
(send ,p
:documentation
'proto
,d
))
651 ;;;; DEFVAR, DEFPARAMETER and DEFCONSTANT
654 (define-special-form-macro defvar
(var &optional
(value nil have-val
) doc
)
656 (eval-when (:compile-toplevel
)
657 (pushnew ',var
*cmp-specials
*))
658 (mark-as-special ',var
)
659 ,@(if have-val
`((unless (boundp ',var
) (set ',var
,value
))))
660 ,@(if doc
`((%set-get
',var
'variable-documentation
,doc
)))
663 (define-special-form-macro defparameter
(var value
&optional doc
)
665 (eval-when (:compile-toplevel
)
666 (pushnew ',var
*cmp-specials
*))
667 (mark-as-special ',var
)
669 ,@(if doc
`((%set-get
',var
'variable-documentation
,doc
)))
672 ;;**** is this the best way?
673 (define-special-form-macro defconstant
(var value
&optional doc
)
674 `(eval-when (:compile-toplevel
:load-toplevel
:execute
)
675 (mark-as-special ',var t
,value
)
676 ,@(if doc
`((%set-get
',var
'variable-documentation
,doc
)))
681 ;;;; AND, OR, UNLESS, WHEN, and COND Macros
684 (defun make-progn-form (body)
685 (if (consp body
) (if (consp (rest body
)) `(progn ,@body
) (first body
))))
687 (defun make-tagbody-body (body)
688 (if (find-if-not #'consp body
) `((tagbody ,@body
)) `(,@body nil
)))
690 (define-special-form-macro and
(&rest args
)
691 (labels ((expand (args)
693 (let ((a (first args
))
695 (if rest
`(if ,a
,(expand rest
)) a
))
699 (define-special-form-macro or
(&rest args
)
700 (labels ((expand (args)
702 (let ((a (first args
))
707 (if ,s
,s
,(expand rest
))))
712 (define-special-form-macro unless
(test &rest body
)
713 `(if ,test nil
,(make-progn-form body
)))
715 (define-special-form-macro when
(test &rest body
)
716 `(if ,test
,(make-progn-form body
)))
719 (define-special-form-macro cond
(&rest clauses
)
720 (labels ((expand (clauses)
722 (let* ((fc (first clauses
))
725 (consequents (rest fc
)))
727 (if consequents
(make-progn-form consequents
) t
)
730 ,(make-progn-form consequents
)
732 (let ((tsym (gensym "T")))
733 `(let ((,tsym
,test
))
734 (if ,tsym
,tsym
,(expand rc
))))))))))
742 (define-special-form-macro return
(&optional val
) `(return-from nil
,val
))
746 ;;;; PROG, PROG*, PROG1, and PROG2 Macros
749 (define-special-form-macro prog
(vlist &rest body
)
750 (let ((db (split-declarations body
)))
751 `(block nil
(let ,vlist
,@(first db
) ,@(make-tagbody-body (second db
))))))
753 (define-special-form-macro prog
* (vlist &rest body
)
754 (let ((db (split-declarations body
)))
755 `(block nil
(let* ,vlist
,@(first db
) ,@(make-tagbody-body (second db
))))))
757 (define-special-form-macro prog1
(first &rest rest
)
759 `(let ((,s
,first
)) ,@rest
,s
)))
761 (define-special-form-macro prog2
(first second
&rest rest
)
763 `(progn ,first
(let ((,s
,second
)) ,@rest
,s
))))
767 ;;;; LOOP, DOTIMES, DOLIST, DO, and DO* Macros
770 (define-special-form-macro loop
(&rest body
)
771 (let ((start (gensym "LOOP")))
772 `(block nil
(tagbody ,start
(progn ,@body
) (go ,start
)))))
774 (defun do-loop-binding-variables (bds)
775 (mapcar #'(lambda (x) (if (consp x
) (first x
) x
)) bds
))
777 (defun do-loop-binding-values (bds)
778 (mapcar #'(lambda (x) (if (consp x
) (second x
) nil
)) bds
))
780 (defun do-loop-binding-steps (bds)
781 (mapcar #'(lambda (x) (if (consp x
) (rest (rest x
)) nil
)) bds
))
783 (defun make-do-step-pairs (vars steps
)
785 (delete nil
(mapcar #'(lambda (x y
) (if y
(cons x y
))) vars steps
))))
787 ;; This definition duplicates the test form (it is used at the start
788 ;; of the loop and in the body, so the code may be a little longer
789 ;; than it could be. But it is now possible to define dotimes and
790 ;; dolist in terms of do without loss of efficiency. Also this version
791 ;; removes the need for a jump label bewteen the update and test
792 ;; forms. It may therefore be possible to reduce the updte-branch
793 ;; instructions to a single instruction in the peephole optimization
795 (defun make-do-loop (letsym setsym bds tr body
)
796 (let* ((vars (do-loop-binding-variables bds
))
797 (ivals (do-loop-binding-values bds
))
798 (slist (make-do-step-pairs vars
(do-loop-binding-steps bds
)))
801 (db (split-declarations body
))
802 (loop-sym (gensym "LOOP"))
803 (return-sym (gensym "RETURN")))
805 (,letsym
,(mapcar #'list vars ivals
)
808 (when ,test
(go ,return-sym
))
812 (unless ,test
(go ,loop-sym
))
814 (return-from nil
,(make-progn-form result
)))))))
816 (define-special-form-macro do
(bds tr
&rest body
)
817 (make-do-loop 'let
'psetq bds tr body
))
819 (define-special-form-macro do
* (bds tr
&rest body
)
820 (make-do-loop 'let
* 'setq bds tr body
))
822 (define-special-form-macro dotimes
((isym nval
&optional res
) &rest body
)
823 (let ((nsym (gensym "N")))
824 `(do ((,isym
0 (1+ ,isym
))
826 ((not (< ,isym
,nsym
)) ,res
)
829 (define-special-form-macro dolist
((esym lval
&optional res
) &rest body
)
830 (let ((lsym (gensym "LIST")))
831 `(do* ((,lsym
,lval
(cdr ,lsym
))
832 (,esym
(car ,lsym
) (car ,lsym
)))
833 ((not (consp ,lsym
)) ,res
)
838 ;;;; IN-PACKAGE Macro
841 (define-special-form-macro in-package
(name)
842 `(eval-when (:compile-toplevel
:load-toplevel
:execute
)
843 (let ((newpack (find-package ',name
)))
844 (unless newpack
(error "can't find package ~s" ',name
))
845 (setf *package
* newpack
))))
852 (define-special-form-macro time
(expr)
853 (let ((rtsym (gensym "RUN"))
854 (gtsym (gensym "GC")))
855 `(let ((,rtsym
(get-internal-run-time))
856 (,gtsym
(get-internal-gc-time)))
857 (multiple-value-prog1
859 (format t
"The evaluation took ~,2f seconds; ~,2f seconds in GC.~%"
860 (float (/ (- (get-internal-run-time) ,rtsym
)
861 internal-time-units-per-second
))
862 (float (/ (- (get-internal-gc-time) ,gtsym
)
863 internal-time-units-per-second
)))))))
867 ;;;; TRACE and UNTRACE Macros
870 (define-special-form-macro trace
(&rest args
)
871 `(dolist (s ',args
*tracelist
*)
872 (unless (symbolp s
) (error "not a symbol - ~s" s
))
873 (pushnew s
*tracelist
*)))
875 (define-special-form-macro untrace
(&rest args
)
877 `(dolist (s ',args
*tracelist
*)
878 (unless (symbolp s
) (error "not a symbol - ~s" s
))
879 (setf *tracelist
* (delete s
*tracelist
*)))
880 `(setf *tracelist
* nil
)))
884 ;;;; WITHOUT-INTERRUPTS Macro
887 (export 'system
::without-interrupts
"SYSTEM")
888 (defmacro system
::without-interrupts
(&rest body
)
890 (system::enable-interrupts nil
)
893 (system::enable-interrupts t
))))
897 ;;;; This is the final file in the common module