(in-package "SB!IMPL")
;;; the guts of the DEFMACRO macro, pulled out into a separate
-;;; function in order to make it easier to express the common
+;;; function in order to make it easier to express the common
;;; bootstrap idiom
;;; CL:DEFMACRO SB!XC:DEFMACRO
;;; SB!XC:DEFMACRO CL:DEFMACRO
-(eval-when (:compile-toplevel :load-toplevel :execute)
+(eval-when (#-sb-xc :compile-toplevel :load-toplevel :execute)
(defun %expander-for-defmacro (name lambda-list body)
- (let ((whole (gensym "WHOLE-"))
- (environment (gensym "ENV-")))
+ (unless (symbolp name)
+ (error "The macro name ~S is not a symbol." name))
+ ;; When we are building the cross-compiler, we could be in a host
+ ;; lisp which implements CL macros (e.g. CL:AND) as special
+ ;; operators (while still providing a macroexpansion for
+ ;; compliance): therefore can't use the host's SPECIAL-OPERATOR-P
+ ;; as a discriminator, but that's OK because the set of forms the
+ ;; cross-compiler compiles is tightly controlled. -- CSR,
+ ;; 2003-04-20
+ #-sb-xc-host
+ (when (special-operator-p name)
+ (error "The special operator ~S can't be redefined as a macro."
+ name))
+ (with-unique-names (whole environment)
(multiple-value-bind (new-body local-decs doc)
(parse-defmacro lambda-list whole body name 'defmacro
:environment environment)
(let ((def `(lambda (,whole ,environment)
,@local-decs
- (block ,name
- ,new-body))))
- `(sb!c::%defmacro ',name #',def ',lambda-list ,doc))))))
+ ,new-body))
+ ;; If we want to move over to list-style names
+ ;; [e.g. (DEFMACRO FOO), maybe to support some XREF-like
+ ;; functionality] here might be a good place to start.
+ (debug-name (sb!c::debug-name 'macro-function name)))
+ `(eval-when (:compile-toplevel :load-toplevel :execute)
+ (sb!c::%defmacro ',name #',def ',lambda-list
+ ,doc ',debug-name)))))))
-;;; Ordinarily this definition of SB!C:%DEFMACRO as an ordinary
-;;; function is not used: the parallel (but different) definition as
-;;; an IR1 transform takes precedence. However, this definition is
-;;; still useful in the target interpreter, and in the
-;;; cross-compilation host.
-(defun sb!c::%defmacro (name definition lambda-list doc)
- (try-to-rename-interpreted-function-as-macro definition name lambda-list)
- (sb!c::%%defmacro name definition doc))
-
-;;; (called by SB!C::%DEFMACRO)
-(eval-when (:compile-toplevel :load-toplevel :execute)
- (defun sb!c::%%defmacro (name definition doc)
- ;; Old note (ca. 1985, maybe:-): "Eventually %%DEFMACRO should deal with
- ;; clearing old compiler information for the functional value."
- (clear-info :function :where-from name)
- ;; FIXME: It would be nice to warn about DEFMACRO of an
- ;; already-defined macro, but that's slightly hard to do because
- ;; in common usage DEFMACRO is defined at compile time and then
- ;; redefined at load time. We'd need to make a distinction between
- ;; the defined-at-compile-time state and the defined-at-load-time
- ;; state to make this work. (Trying to warn about duplicate DEFTYPEs
- ;; runs into the same problem.)
- #+nil (when (sb!xc:macro-function name)
- (style-warn "redefining ~S in DEFMACRO" name))
- (setf (sb!xc:macro-function name) definition
- (fdocumentation name 'function) doc)
- name))
+(macrolet
+ ((def (times set-p)
+ `(eval-when (,@times)
+ (defun sb!c::%defmacro (name definition lambda-list doc debug-name)
+ ;; old note (ca. 1985, maybe:-): "Eventually %%DEFMACRO
+ ;; should deal with clearing old compiler information for
+ ;; the functional value."
+ ,@(unless set-p
+ '((declare (ignore lambda-list debug-name))))
+ (ecase (info :function :kind name)
+ ((nil))
+ (:function
+ ;; (remhash name *free-funs*)
+ (undefine-fun-name name)
+ (style-warn
+ "~S is being redefined as a macro when it was ~
+ previously ~(~A~) to be a function."
+ name
+ (info :function :where-from name)))
+ (:macro)
+ (:special-form
+ (error "The special form ~S can't be redefined as a macro."
+ name)))
+ (clear-info :function :where-from name)
+ ;; FIXME: It would be nice to warn about DEFMACRO of an
+ ;; already-defined macro, but that's slightly hard to do
+ ;; because in common usage DEFMACRO is defined at compile
+ ;; time and then redefined at load time. We'd need to make a
+ ;; distinction between the defined-at-compile-time state and
+ ;; the defined-at-load-time state to make this work. (Trying
+ ;; to warn about duplicate DEFTYPEs runs into the same
+ ;; problem.)
+ #+nil (when (sb!xc:macro-function name)
+ ;; Someday we could check for macro arguments
+ ;; being incompatibly redefined. Doing this right
+ ;; will involve finding the old macro lambda-list
+ ;; and comparing it with the new one.
+ (style-warn "redefining ~S in DEFMACRO" name))
+ (setf (sb!xc:macro-function name) definition
+ (fdocumentation name 'function) doc)
+ ,(when set-p
+ `(case (widetag-of definition)
+ (#.sb!vm:closure-header-widetag
+ (setf (%simple-fun-arglist (%closure-fun definition))
+ lambda-list
+ (%simple-fun-name (%closure-fun definition))
+ debug-name))
+ (#.sb!vm:simple-fun-header-widetag
+ (setf (%simple-fun-arglist definition) lambda-list
+ (%simple-fun-name definition) debug-name))))
+ name))))
+ (progn
+ (def (:load-toplevel :execute) #-sb-xc-host t #+sb-xc-host nil)
+ (def (#-sb-xc :compile-toplevel) nil)))
;;; Parse the definition and make an expander function. The actual
-;;; definition is done by %DEFMACRO which we expand into, and which is
-;;; handled magically by an IR1 transform. After the compiler has
-;;; gotten the information it wants out of macro definition, it
-;;; compiles a call to %%DEFMACRO which happens at load time.
+;;; definition is done by %DEFMACRO which we expand into. After the
+;;; compiler has gotten the information it wants out of macro
+;;; definition, it compiles a call to %DEFMACRO which happens at load
+;;; time.
(defmacro sb!xc:defmacro (name lambda-list &rest body)
(%expander-for-defmacro name lambda-list body))
;;; have any EVAL-WHEN or IR1 magic associated with it, so it only
;;; takes effect in :LOAD-TOPLEVEL or :EXECUTE situations.
(def!macro defmacro-mundanely (name lambda-list &body body)
- (let ((whole (gensym "WHOLE-"))
- (environment (gensym "ENVIRONMENT-")))
- (multiple-value-bind (new-body local-decs doc)
- (parse-defmacro lambda-list whole body name 'defmacro
- :environment environment)
- `(progn
- (setf (sb!xc:macro-function ',name)
- (lambda (,whole ,environment)
- ,@local-decs
- (block ,name
- ,new-body)))
- (setf (fdocumentation ',name 'macro)
- ,doc)
- ',name))))
+
+ ;; old way:
+ ;;(let ((whole (gensym "WHOLE-"))
+ ;; (environment (gensym "ENVIRONMENT-")))
+ ;; (multiple-value-bind (new-body local-decs doc)
+ ;; (parse-defmacro lambda-list whole body name 'defmacro
+ ;; :environment environment)
+ ;; `(progn
+ ;; (setf (sb!xc:macro-function ',name)
+ ;; (lambda (,whole ,environment)
+ ;; ,@local-decs
+ ;; (block ,name
+ ;; ,new-body)))
+ ;; (setf (fdocumentation ',name 'macro)
+ ;; ,doc)
+ ;; ',name)))
+
+ `(let ()
+ (sb!xc:defmacro ,name ,lambda-list ,@body)))