1 ;;;; This file is for macroexpander tests which have side effects
3 ;;;; This software is part of the SBCL system. See the README file for
6 ;;;; While most of SBCL is derived from the CMU CL system, the test
7 ;;;; files (like this one) were written from scratch after the fork
10 ;;;; This software is in the public domain and is provided with
11 ;;;; absolutely no warranty. See the COPYING and CREDITS files for
12 ;;;; more information.
14 ;;; From Matthew Swank on cll 2005-10-06
16 (defmacro defglobal
* (name &optional value
)
17 (let ((internal (gensym)))
19 (defparameter ,internal
,value
)
20 (define-symbol-macro ,name
,internal
))))
24 (assert (= (let ((glob 4)) glob
)))
26 (assert (equal (let ((glob nil
)) (setf glob
(cons 'foo glob
)) glob
) '(foo)))
28 (assert (equal (let ((glob nil
)) (push 'foo glob
) glob
) '(foo)))
33 ;;; CLHS 3.1.2.1.1 specifies that symbol macro expansion must also
34 ;;; go through *MACROEXPAND-HOOK*. (2007-09-22, -TCR.)
36 (define-symbol-macro .foo.
'foobar
)
38 ;;; An evaluated macroexpand-hook leads to infinite recursion.
39 ;;; These tests used to be runnable only if *evaluator-mode* started out
40 ;;; as :compile, but now we support running the test suite with any
41 ;;; *evaluator-mode*, so must explicitly COMPILE the macroexpand hook.
42 ;;; Notice that the lambda expressions being compiled are closures.
43 ;;; This is allowed by sb-interpreter but not sb-eval.
45 (let* ((expanded-p nil
)
47 (compile nil
#'(lambda (fn form env
)
48 (when (eq form
'.foo.
)
50 (funcall fn form env
)))))
51 (multiple-value-bind (expansion flag
) (macroexpand '.foo.
)
52 (assert (equal expansion
'(quote foobar
)))
56 #+(or sb-eval sb-fasteval
)
57 (let ((sb-ext:*evaluator-mode
* :interpret
))
58 (let* ((expanded-p nil
)
60 (compile nil
#'(lambda (fn form env
)
61 (when (eq form
'.foo.
)
63 (funcall fn form env
)))))
67 (let* ((expanded-p nil
)
69 (compile nil
#'(lambda (fn form env
)
70 (when (eq form
'/foo
/)
72 (funcall fn form env
)))))
73 (compile nil
'(lambda ()
74 (symbol-macrolet ((/foo
/ 'foobar
))
75 (macrolet ((expand (symbol &environment env
)
76 (macroexpand symbol env
)))
80 ;; Check that DEFINE-SYMBOL-MACRO on a variable whose global :KIND
81 ;; was :ALIEN gets a sane error message instead of ECASE failure.
82 (sb-alien:define-alien-variable
("posix_argv" foo-argv
) (* (* char
)))
83 (handler-case (define-symbol-macro foo-argv
(silly))
85 (assert (string= "Symbol FOO-ARGV is already defined as an alien variable."
86 (write-to-string e
:escape nil
))))
87 (:no-error
() (error "Expected an error")))
89 (with-test (:name
:binding
*-expander
)
90 (assert (equal (macroexpand-1
91 '(sb-int:binding
* (((foo x bar zz
) (f) :exit-if-null
)
93 (declare (integer x foo
) (special foo y
))
94 (declare (special zz bar l
) (real q foo
))
96 '(MULTIPLE-VALUE-BIND (FOO X BAR ZZ
) (F)
98 (INTEGER X FOO
) (SPECIAL FOO
) (SPECIAL ZZ BAR
) (REAL FOO
))
99 (WHEN FOO
(MULTIPLE-VALUE-BIND (BAZ Y
) (G BAR
)
100 (DECLARE (SPECIAL Y
))
101 (DECLARE (SPECIAL L
) (REAL Q
)) (THING))))))
103 (assert (equal (macroexpand-1
104 '(sb-int:binding
* (((x y
) (f))
106 (declare (integer x
))
108 '(MULTIPLE-VALUE-BIND (X Y
) (F)
110 (DECLARE (INTEGER X
))
113 ;; The conversion of a trailing sequence of individual bindings
114 ;; into one LET* failed to remove declarations that were already
115 ;; injected pertinent to ealier bound variables.
116 (assert (equal-mod-gensyms
118 '(sb-int:binding
* (((v1 v2 nil
) (foo))
121 (declare (special fred
) (optimize speed
)
122 (optimize (debug 3)))
123 (declare (integer v1 v2
))
125 '(multiple-value-bind (v1 v2
#1=#:g538
) (foo)
126 (declare (integer v1 v2
))
127 (declare (ignorable #1#))
128 (let* ((a (f v1
)) (b (g v2
)))
129 (declare (special fred
) (optimize speed
) (optimize (debug 3)))
132 ;; :EXIT-IF-NULL was inserting declarations into the WHEN expression.
133 (assert (equal-mod-gensyms
135 '(sb-int:binding
* (((a1 a2
) (f))
137 ((c1 nil c2
) (h) :exit-if-null
)
139 (nil (e) :exit-if-null
))
140 (declare (special fff c2
) (integer d1
))
142 (special *x
* *y
* c1
))
143 (declare (cons b
) (type integer
*y
* a1
))
145 (another-body-form)))
146 '(multiple-value-bind (a1 a2
) (f)
147 (declare (fixnum a2
) (type integer a1
))
150 (multiple-value-bind (c1 #2=#:dummy-1 c2
) (h)
151 (declare (special c2
) (special c1
))
152 (declare (ignorable #2#))
154 (multiple-value-bind (d1 d1
) (f)
155 (declare (integer d1
))
156 (let* ((#3=#:dummy-2
(e)))
157 (declare (ignorable #3#))
158 (declare (special fff
))
159 (declare (special *y
* *x
*))
160 (declare (type integer
*y
*))
162 (a-body-form) (another-body-form))))))))))
164 ) ; end BINDING*-EXPANDER test
166 (eval-when (:compile-toplevel
:load-toplevel
:execute
)
167 (import '(sb-int:&more sb-int
:parse-lambda-list
)))
169 (with-test (:name
:parse-lambda-list
)
170 ;; 3.4.1 - ordinary lambda list
171 (assert-error (parse-lambda-list '(foo &body bar
)))
172 (assert-error (parse-lambda-list '(foo &whole bar
)))
173 (assert-error (parse-lambda-list '(foo &environment bar
)))
174 ;; &more expects exactly two following symbols
175 (assert-error (parse-lambda-list '(foo &more
)))
176 (assert-error (parse-lambda-list '(foo &more c
)))
177 (assert-error (parse-lambda-list '(foo &more ctxt ct junk
)))
178 ;; &more and &rest are mutually exclusive
179 (assert-error (parse-lambda-list '(foo &rest foo
&more ctxt n
)))
180 (assert-error (parse-lambda-list '(foo &more ctxt n
&rest foo
)))
182 ;; 3.4.2 - generic function lambda lists
183 (macroexpand-1 '(defgeneric foo
(a b
&key size
&allow-other-keys
)))
184 (assert-error (macroexpand-1 '(defgeneric foo
(a b
&aux x
)))
185 sb-pcl
::generic-function-lambda-list-error
)
186 ;; 3.4.3 - FIXME: add tests
188 ;; 3.4.4 - doesn't use PARSE-LAMBDA-LIST yet
191 ;; 3.4.6 - BOA lambda list is a function lambda list,
192 ;; but the expander silently disregarded the internal &MORE keyword,
193 ;; which has no place in DEFSTRUCT.
195 (macroexpand-1 '(defstruct (s (:constructor
196 make-s
(a b
&more ctxt n
)))
199 ;; 3.4.7 - DEFSETF disallows &AUX
200 (assert-error (macroexpand-1
201 '(defsetf foof
(a b
&optional k
&aux
) (v1 v2
) (forms))))
203 ;; 3.4.8 - DEFTYPE is exactly like DEFMACRO
204 ;; except for the implied default-default of '*
206 ;; 3.4.9 - DEFINE-MODIFY-MACRO allows only &OPTIONAL and &REST
207 (assert-error (macroexpand-1
208 '(define-modify-macro foof
(a b
&optional k
&key
) foo
)))
209 (assert-error (macroexpand-1
210 '(define-modify-macro foof
(a b
&optional k
&body
) foo
)))
212 ;; 3.4.10 - DEFINE-METHOD-COMBINATION. Not even sure what this does.
216 (defstruct foo
(a 0 :type fixnum
))
217 (defstruct bar
(a 0 :type fixnum
))
218 (declaim (notinline (setf bar-a
)))
219 ;; This macro definition is technically violating the dynamic-extent
220 ;; nature of environment objects (as per X3J13), but of course ours don't.
221 (defmacro capture-env
(&environment e
&rest r
)
224 (with-test (:name
:macroexpand-of-setf-structure-access
)
225 (assert (equal (macroexpand-1 '(setf (foo-a x
) 3))
226 `(sb-kernel:%instance-set
(the foo x
)
227 ,sb-vm
:instance-data-start
230 ;; Lexical definition of (SETF FOO-A) inhibits source-transform.
231 ;; This is not required behavior - SETF of structure slots
232 ;; do not necessarily go through a function named (SETF your-slot),
233 ;; but it's this implementation's behavior, so should be asserted.
234 (flet (((setf foo-a
) (new obj
) (declare (ignore obj
)) new
))
235 (assert (equal-mod-gensyms
236 (macroexpand-1 '(setf (foo-a x
) 3) (capture-env))
237 '(let* ((#1=#:x x
) (new 3)) (funcall #'(setf foo-a
) new
#1#)))))
239 ;; Same, not required behavior - NOTINLINE inhibits transform.
240 (assert (equal-mod-gensyms
241 (macroexpand-1 '(setf (bar-a x
) 3))
242 '(let* ((#2=#:x x
) (new 3)) (funcall #'(setf bar-a
) new
#2#)))))