1 ;;;; tree-il.test --- test suite for compiling tree-il -*- scheme -*-
2 ;;;; Andy Wingo <wingo@pobox.com> --- May 2009
4 ;;;; Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
6 ;;;; This library is free software; you can redistribute it and/or
7 ;;;; modify it under the terms of the GNU Lesser General Public
8 ;;;; License as published by the Free Software Foundation; either
9 ;;;; version 3 of the License, or (at your option) any later version.
11 ;;;; This library is distributed in the hope that it will be useful,
12 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ;;;; Lesser General Public License for more details.
16 ;;;; You should have received a copy of the GNU Lesser General Public
17 ;;;; License along with this library; if not, write to the Free Software
18 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 (define-module (test-suite tree-il)
21 #:use-module (test-suite lib)
22 #:use-module (system base compile)
23 #:use-module (system base pmatch)
24 #:use-module (system base message)
25 #:use-module (language tree-il)
26 #:use-module (language glil)
27 #:use-module (srfi srfi-13))
29 ;; Of course, the GLIL that is emitted depends on the source info of the
30 ;; input. Here we're not concerned about that, so we strip source
31 ;; information from the incoming tree-il.
33 (define (strip-source x)
34 (post-order! (lambda (x) (set! (tree-il-src x) #f))
37 (define-syntax assert-tree-il->glil
38 (syntax-rules (with-partial-evaluation without-partial-evaluation
40 ((_ with-partial-evaluation in pat test ...)
41 (assert-tree-il->glil with-options (#:partial-eval? #t)
43 ((_ without-partial-evaluation in pat test ...)
44 (assert-tree-il->glil with-options (#:partial-eval? #f)
46 ((_ with-options opts in pat test ...)
49 (let ((glil (unparse-glil
50 (compile (strip-source (parse-tree-il exp))
51 #:from 'tree-il #:to 'glil
54 (pat (guard test ...) #t)
57 (assert-tree-il->glil with-partial-evaluation
60 (define-syntax pass-if-tree-il->scheme
63 (assert-scheme->tree-il->scheme in pat #t))
66 (pmatch (tree-il->scheme
67 (compile 'in #:from 'scheme #:to 'tree-il))
68 (pat (guard guard-exp) #t)
72 ;; The partial evaluator.
73 (@@ (language tree-il optimize) peval))
75 (define-syntax pass-if-peval
79 (let ((evaled (unparse-tree-il
80 (peval (compile 'in #:from 'scheme #:to 'tree-il)))))
83 (_ (pk 'peval-mismatch evaled) #f)))))))
86 (with-test-prefix "tree-il->scheme"
87 (pass-if-tree-il->scheme
88 (case-lambda ((a) a) ((b c) (list b c)))
89 (case-lambda ((,a) ,a1) ((,b ,c) (list ,b1 ,c1)))
90 (and (eq? a a1) (eq? b b1) (eq? c c1))))
92 (with-test-prefix "void"
95 (program () (std-prelude 0 0 #f) (label _) (void) (call return 1)))
97 (begin (void) (const 1))
98 (program () (std-prelude 0 0 #f) (label _) (const 1) (call return 1)))
100 (apply (primitive +) (void) (const 1))
101 (program () (std-prelude 0 0 #f) (label _) (void) (call add1 1) (call return 1))))
103 (with-test-prefix "application"
104 (assert-tree-il->glil
105 (apply (toplevel foo) (const 1))
106 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (const 1) (call tail-call 1)))
107 (assert-tree-il->glil
108 (begin (apply (toplevel foo) (const 1)) (void))
109 (program () (std-prelude 0 0 #f) (label _) (call new-frame 0) (toplevel ref foo) (const 1) (mv-call 1 ,l1)
110 (call drop 1) (branch br ,l2)
111 (label ,l3) (mv-bind 0 #f)
113 (void) (call return 1))
114 (and (eq? l1 l3) (eq? l2 l4)))
115 (assert-tree-il->glil
116 (apply (toplevel foo) (apply (toplevel bar)))
117 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (call new-frame 0) (toplevel ref bar) (call call 0)
118 (call tail-call 1))))
120 (with-test-prefix "conditional"
121 (assert-tree-il->glil
122 (if (toplevel foo) (const 1) (const 2))
123 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (branch br-if-not ,l1)
124 (const 1) (call return 1)
125 (label ,l2) (const 2) (call return 1))
128 (assert-tree-il->glil without-partial-evaluation
129 (begin (if (toplevel foo) (const 1) (const 2)) (const #f))
130 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (branch br-if-not ,l1) (branch br ,l2)
131 (label ,l3) (label ,l4) (const #f) (call return 1))
132 (eq? l1 l3) (eq? l2 l4))
134 (assert-tree-il->glil
135 (apply (primitive null?) (if (toplevel foo) (const 1) (const 2)))
136 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (branch br-if-not ,l1)
137 (const 1) (branch br ,l2)
138 (label ,l3) (const 2) (label ,l4)
139 (call null? 1) (call return 1))
140 (eq? l1 l3) (eq? l2 l4)))
142 (with-test-prefix "primitive-ref"
143 (assert-tree-il->glil
145 (program () (std-prelude 0 0 #f) (label _) (toplevel ref +) (call return 1)))
147 (assert-tree-il->glil
148 (begin (primitive +) (const #f))
149 (program () (std-prelude 0 0 #f) (label _) (const #f) (call return 1)))
151 (assert-tree-il->glil
152 (apply (primitive null?) (primitive +))
153 (program () (std-prelude 0 0 #f) (label _) (toplevel ref +) (call null? 1)
156 (with-test-prefix "lexical refs"
157 (assert-tree-il->glil without-partial-evaluation
158 (let (x) (y) ((const 1)) (lexical x y))
159 (program () (std-prelude 0 1 #f) (label _)
160 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
161 (lexical #t #f ref 0) (call return 1)
164 (assert-tree-il->glil without-partial-evaluation
165 (let (x) (y) ((const 1)) (begin (lexical x y) (const #f)))
166 (program () (std-prelude 0 1 #f) (label _)
167 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
168 (const #f) (call return 1)
171 (assert-tree-il->glil without-partial-evaluation
172 (let (x) (y) ((const 1)) (apply (primitive null?) (lexical x y)))
173 (program () (std-prelude 0 1 #f) (label _)
174 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
175 (lexical #t #f ref 0) (call null? 1) (call return 1)
178 (with-test-prefix "lexical sets"
179 (assert-tree-il->glil
180 ;; unreferenced sets may be optimized away -- make sure they are ref'd
181 (let (x) (y) ((const 1))
182 (set! (lexical x y) (apply (primitive 1+) (lexical x y))))
183 (program () (std-prelude 0 1 #f) (label _)
184 (const 1) (bind (x #t 0)) (lexical #t #t box 0)
185 (lexical #t #t ref 0) (call add1 1) (lexical #t #t set 0)
186 (void) (call return 1)
189 (assert-tree-il->glil
190 (let (x) (y) ((const 1))
191 (begin (set! (lexical x y) (apply (primitive 1+) (lexical x y)))
193 (program () (std-prelude 0 1 #f) (label _)
194 (const 1) (bind (x #t 0)) (lexical #t #t box 0)
195 (lexical #t #t ref 0) (call add1 1) (lexical #t #t set 0)
196 (lexical #t #t ref 0) (call return 1)
199 (assert-tree-il->glil
200 (let (x) (y) ((const 1))
201 (apply (primitive null?)
202 (set! (lexical x y) (apply (primitive 1+) (lexical x y)))))
203 (program () (std-prelude 0 1 #f) (label _)
204 (const 1) (bind (x #t 0)) (lexical #t #t box 0)
205 (lexical #t #t ref 0) (call add1 1) (lexical #t #t set 0) (void)
206 (call null? 1) (call return 1)
209 (with-test-prefix "module refs"
210 (assert-tree-il->glil
212 (program () (std-prelude 0 0 #f) (label _)
213 (module public ref (foo) bar)
216 (assert-tree-il->glil
217 (begin (@ (foo) bar) (const #f))
218 (program () (std-prelude 0 0 #f) (label _)
219 (module public ref (foo) bar) (call drop 1)
220 (const #f) (call return 1)))
222 (assert-tree-il->glil
223 (apply (primitive null?) (@ (foo) bar))
224 (program () (std-prelude 0 0 #f) (label _)
225 (module public ref (foo) bar)
226 (call null? 1) (call return 1)))
228 (assert-tree-il->glil
230 (program () (std-prelude 0 0 #f) (label _)
231 (module private ref (foo) bar)
234 (assert-tree-il->glil
235 (begin (@@ (foo) bar) (const #f))
236 (program () (std-prelude 0 0 #f) (label _)
237 (module private ref (foo) bar) (call drop 1)
238 (const #f) (call return 1)))
240 (assert-tree-il->glil
241 (apply (primitive null?) (@@ (foo) bar))
242 (program () (std-prelude 0 0 #f) (label _)
243 (module private ref (foo) bar)
244 (call null? 1) (call return 1))))
246 (with-test-prefix "module sets"
247 (assert-tree-il->glil
248 (set! (@ (foo) bar) (const 2))
249 (program () (std-prelude 0 0 #f) (label _)
250 (const 2) (module public set (foo) bar)
251 (void) (call return 1)))
253 (assert-tree-il->glil
254 (begin (set! (@ (foo) bar) (const 2)) (const #f))
255 (program () (std-prelude 0 0 #f) (label _)
256 (const 2) (module public set (foo) bar)
257 (const #f) (call return 1)))
259 (assert-tree-il->glil
260 (apply (primitive null?) (set! (@ (foo) bar) (const 2)))
261 (program () (std-prelude 0 0 #f) (label _)
262 (const 2) (module public set (foo) bar)
263 (void) (call null? 1) (call return 1)))
265 (assert-tree-il->glil
266 (set! (@@ (foo) bar) (const 2))
267 (program () (std-prelude 0 0 #f) (label _)
268 (const 2) (module private set (foo) bar)
269 (void) (call return 1)))
271 (assert-tree-il->glil
272 (begin (set! (@@ (foo) bar) (const 2)) (const #f))
273 (program () (std-prelude 0 0 #f) (label _)
274 (const 2) (module private set (foo) bar)
275 (const #f) (call return 1)))
277 (assert-tree-il->glil
278 (apply (primitive null?) (set! (@@ (foo) bar) (const 2)))
279 (program () (std-prelude 0 0 #f) (label _)
280 (const 2) (module private set (foo) bar)
281 (void) (call null? 1) (call return 1))))
283 (with-test-prefix "toplevel refs"
284 (assert-tree-il->glil
286 (program () (std-prelude 0 0 #f) (label _)
290 (assert-tree-il->glil without-partial-evaluation
291 (begin (toplevel bar) (const #f))
292 (program () (std-prelude 0 0 #f) (label _)
293 (toplevel ref bar) (call drop 1)
294 (const #f) (call return 1)))
296 (assert-tree-il->glil
297 (apply (primitive null?) (toplevel bar))
298 (program () (std-prelude 0 0 #f) (label _)
300 (call null? 1) (call return 1))))
302 (with-test-prefix "toplevel sets"
303 (assert-tree-il->glil
304 (set! (toplevel bar) (const 2))
305 (program () (std-prelude 0 0 #f) (label _)
306 (const 2) (toplevel set bar)
307 (void) (call return 1)))
309 (assert-tree-il->glil
310 (begin (set! (toplevel bar) (const 2)) (const #f))
311 (program () (std-prelude 0 0 #f) (label _)
312 (const 2) (toplevel set bar)
313 (const #f) (call return 1)))
315 (assert-tree-il->glil
316 (apply (primitive null?) (set! (toplevel bar) (const 2)))
317 (program () (std-prelude 0 0 #f) (label _)
318 (const 2) (toplevel set bar)
319 (void) (call null? 1) (call return 1))))
321 (with-test-prefix "toplevel defines"
322 (assert-tree-il->glil
323 (define bar (const 2))
324 (program () (std-prelude 0 0 #f) (label _)
325 (const 2) (toplevel define bar)
326 (void) (call return 1)))
328 (assert-tree-il->glil
329 (begin (define bar (const 2)) (const #f))
330 (program () (std-prelude 0 0 #f) (label _)
331 (const 2) (toplevel define bar)
332 (const #f) (call return 1)))
334 (assert-tree-il->glil
335 (apply (primitive null?) (define bar (const 2)))
336 (program () (std-prelude 0 0 #f) (label _)
337 (const 2) (toplevel define bar)
338 (void) (call null? 1) (call return 1))))
340 (with-test-prefix "constants"
341 (assert-tree-il->glil
343 (program () (std-prelude 0 0 #f) (label _)
344 (const 2) (call return 1)))
346 (assert-tree-il->glil
347 (begin (const 2) (const #f))
348 (program () (std-prelude 0 0 #f) (label _)
349 (const #f) (call return 1)))
351 (assert-tree-il->glil
352 ;; This gets simplified by `peval'.
353 (apply (primitive null?) (const 2))
354 (program () (std-prelude 0 0 #f) (label _)
355 (const #f) (call return 1))))
357 (with-test-prefix "letrec"
358 ;; simple bindings -> let
359 (assert-tree-il->glil without-partial-evaluation
360 (letrec (x y) (x1 y1) ((const 10) (const 20))
361 (apply (toplevel foo) (lexical x x1) (lexical y y1)))
362 (program () (std-prelude 0 2 #f) (label _)
363 (const 10) (const 20)
364 (bind (x #f 0) (y #f 1))
365 (lexical #t #f set 1) (lexical #t #f set 0)
367 (lexical #t #f ref 0) (lexical #t #f ref 1)
371 ;; complex bindings -> box and set! within let
372 (assert-tree-il->glil without-partial-evaluation
373 (letrec (x y) (x1 y1) ((apply (toplevel foo)) (apply (toplevel bar)))
374 (apply (primitive +) (lexical x x1) (lexical y y1)))
375 (program () (std-prelude 0 4 #f) (label _)
376 (void) (void) ;; what are these?
377 (bind (x #t 0) (y #t 1))
378 (lexical #t #t box 1) (lexical #t #t box 0)
379 (call new-frame 0) (toplevel ref foo) (call call 0)
380 (call new-frame 0) (toplevel ref bar) (call call 0)
381 (bind (x #f 2) (y #f 3)) (lexical #t #f set 3) (lexical #t #f set 2)
382 (lexical #t #f ref 2) (lexical #t #t set 0)
383 (lexical #t #f ref 3) (lexical #t #t set 1) (unbind)
384 (lexical #t #t ref 0) (lexical #t #t ref 1)
385 (call add 2) (call return 1) (unbind)))
387 ;; complex bindings in letrec* -> box and set! in order
388 (assert-tree-il->glil without-partial-evaluation
389 (letrec* (x y) (x1 y1) ((apply (toplevel foo)) (apply (toplevel bar)))
390 (apply (primitive +) (lexical x x1) (lexical y y1)))
391 (program () (std-prelude 0 2 #f) (label _)
392 (void) (void) ;; what are these?
393 (bind (x #t 0) (y #t 1))
394 (lexical #t #t box 1) (lexical #t #t box 0)
395 (call new-frame 0) (toplevel ref foo) (call call 0)
396 (lexical #t #t set 0)
397 (call new-frame 0) (toplevel ref bar) (call call 0)
398 (lexical #t #t set 1)
399 (lexical #t #t ref 0)
400 (lexical #t #t ref 1)
401 (call add 2) (call return 1) (unbind)))
403 ;; simple bindings in letrec* -> equivalent to letrec
404 (assert-tree-il->glil without-partial-evaluation
405 (letrec* (x y) (xx yy) ((const 1) (const 2))
407 (program () (std-prelude 0 1 #f) (label _)
409 (bind (y #f 0)) ;; X is removed, and Y is unboxed
410 (lexical #t #f set 0)
411 (lexical #t #f ref 0)
412 (call return 1) (unbind))))
414 (with-test-prefix "lambda"
415 (assert-tree-il->glil
417 (lambda-case (((x) #f #f #f () (y)) (const 2)) #f))
418 (program () (std-prelude 0 0 #f) (label _)
419 (program () (std-prelude 1 1 #f)
420 (bind (x #f 0)) (label _)
421 (const 2) (call return 1) (unbind))
424 (assert-tree-il->glil
426 (lambda-case (((x y) #f #f #f () (x1 y1))
429 (program () (std-prelude 0 0 #f) (label _)
430 (program () (std-prelude 2 2 #f)
431 (bind (x #f 0) (y #f 1)) (label _)
432 (const 2) (call return 1)
436 (assert-tree-il->glil
438 (lambda-case ((() #f x #f () (y)) (const 2))
440 (program () (std-prelude 0 0 #f) (label _)
441 (program () (opt-prelude 0 0 0 1 #f)
442 (bind (x #f 0)) (label _)
443 (const 2) (call return 1)
447 (assert-tree-il->glil
449 (lambda-case (((x) #f x1 #f () (y y1)) (const 2))
451 (program () (std-prelude 0 0 #f) (label _)
452 (program () (opt-prelude 1 0 1 2 #f)
453 (bind (x #f 0) (x1 #f 1)) (label _)
454 (const 2) (call return 1)
458 (assert-tree-il->glil
460 (lambda-case (((x) #f x1 #f () (y y1)) (lexical x y))
462 (program () (std-prelude 0 0 #f) (label _)
463 (program () (opt-prelude 1 0 1 2 #f)
464 (bind (x #f 0) (x1 #f 1)) (label _)
465 (lexical #t #f ref 0) (call return 1)
469 (assert-tree-il->glil
471 (lambda-case (((x) #f x1 #f () (y y1)) (lexical x1 y1))
473 (program () (std-prelude 0 0 #f) (label _)
474 (program () (opt-prelude 1 0 1 2 #f)
475 (bind (x #f 0) (x1 #f 1)) (label _)
476 (lexical #t #f ref 1) (call return 1)
480 (assert-tree-il->glil
482 (lambda-case (((x) #f #f #f () (x1))
484 (lambda-case (((y) #f #f #f () (y1))
488 (program () (std-prelude 0 0 #f) (label _)
489 (program () (std-prelude 1 1 #f)
490 (bind (x #f 0)) (label _)
491 (program () (std-prelude 1 1 #f)
492 (bind (y #f 0)) (label _)
493 (lexical #f #f ref 0) (call return 1)
495 (lexical #t #f ref 0)
496 (call make-closure 1)
501 (with-test-prefix "sequence"
502 (assert-tree-il->glil
503 (begin (begin (const 2) (const #f)) (const #t))
504 (program () (std-prelude 0 0 #f) (label _)
505 (const #t) (call return 1)))
507 (assert-tree-il->glil
508 ;; This gets simplified by `peval'.
509 (apply (primitive null?) (begin (const #f) (const 2)))
510 (program () (std-prelude 0 0 #f) (label _)
511 (const #f) (call return 1))))
513 (with-test-prefix "values"
514 (assert-tree-il->glil
515 (apply (primitive values)
516 (apply (primitive values) (const 1) (const 2)))
517 (program () (std-prelude 0 0 #f) (label _)
518 (const 1) (call return 1)))
520 (assert-tree-il->glil
521 (apply (primitive values)
522 (apply (primitive values) (const 1) (const 2))
524 (program () (std-prelude 0 0 #f) (label _)
525 (const 1) (const 3) (call return/values 2)))
527 (assert-tree-il->glil
529 (apply (primitive values) (const 1) (const 2)))
530 (program () (std-prelude 0 0 #f) (label _)
531 (const 1) (call return 1))))
533 ;; FIXME: binding info for or-hacked locals might bork the disassembler,
534 ;; and could be tightened in any case
535 (with-test-prefix "the or hack"
536 (assert-tree-il->glil without-partial-evaluation
537 (let (x) (y) ((const 1))
540 (let (a) (b) ((const 2))
542 (program () (std-prelude 0 1 #f) (label _)
543 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
544 (lexical #t #f ref 0) (branch br-if-not ,l1)
545 (lexical #t #f ref 0) (call return 1)
547 (const 2) (bind (a #f 0)) (lexical #t #f set 0)
548 (lexical #t #f ref 0) (call return 1)
553 ;; second bound var is unreferenced
554 (assert-tree-il->glil without-partial-evaluation
555 (let (x) (y) ((const 1))
558 (let (a) (b) ((const 2))
560 (program () (std-prelude 0 1 #f) (label _)
561 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
562 (lexical #t #f ref 0) (branch br-if-not ,l1)
563 (lexical #t #f ref 0) (call return 1)
565 (lexical #t #f ref 0) (call return 1)
569 (with-test-prefix "apply"
570 (assert-tree-il->glil
571 (apply (primitive @apply) (toplevel foo) (toplevel bar))
572 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (toplevel ref bar) (call tail-apply 2)))
573 (assert-tree-il->glil
574 (begin (apply (primitive @apply) (toplevel foo) (toplevel bar)) (void))
575 (program () (std-prelude 0 0 #f) (label _)
576 (call new-frame 0) (toplevel ref apply) (toplevel ref foo) (toplevel ref bar) (mv-call 2 ,l1)
577 (call drop 1) (branch br ,l2) (label ,l3) (mv-bind 0 #f)
579 (void) (call return 1))
580 (and (eq? l1 l3) (eq? l2 l4)))
581 (assert-tree-il->glil
582 (apply (toplevel foo) (apply (toplevel @apply) (toplevel bar) (toplevel baz)))
583 (program () (std-prelude 0 0 #f) (label _)
585 (call new-frame 0) (toplevel ref bar) (toplevel ref baz) (call apply 2)
586 (call tail-call 1))))
588 (with-test-prefix "call/cc"
589 (assert-tree-il->glil
590 (apply (primitive @call-with-current-continuation) (toplevel foo))
591 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (call tail-call/cc 1)))
592 (assert-tree-il->glil
593 (begin (apply (primitive @call-with-current-continuation) (toplevel foo)) (void))
594 (program () (std-prelude 0 0 #f) (label _)
595 (call new-frame 0) (toplevel ref call-with-current-continuation) (toplevel ref foo) (mv-call 1 ,l1)
596 (call drop 1) (branch br ,l2) (label ,l3) (mv-bind 0 #f)
598 (void) (call return 1))
599 (and (eq? l1 l3) (eq? l2 l4)))
600 (assert-tree-il->glil
601 (apply (toplevel foo)
602 (apply (toplevel @call-with-current-continuation) (toplevel bar)))
603 (program () (std-prelude 0 0 #f) (label _)
605 (toplevel ref bar) (call call/cc 1)
606 (call tail-call 1))))
609 (with-test-prefix "partial evaluation"
612 ;; First order, primitive.
613 (let ((x 1) (y 2)) (+ x y))
617 ;; First order, coalesced.
618 (cons 0 (cons 1 (cons 2 (list 3 4 5))))
619 (const (0 1 2 3 4 5)))
622 ;; First order, coalesced, mutability preserved.
624 (cons 0 (cons 1 (cons 2 (list 3 4 5)))))
626 ;; This must not be a constant.
627 (apply (primitive list)
628 (const 0) (const 1) (const 2) (const 3) (const 4) (const 5))))
631 ;; First order, mutability preserved.
633 (let loop ((i 3) (r '()))
636 (loop (1- i) (cons (cons i i) r)))))
638 (apply (primitive list)
639 (apply (primitive cons) (const 1) (const 1))
640 (apply (primitive cons) (const 2) (const 2))
641 (apply (primitive cons) (const 3) (const 3)))))
643 ;; FIXME: The test below fails.
645 ;; ;; Mutability preserved.
646 ;; ((lambda (x y z) (list x y z)) 1 2 3)
647 ;; (apply (primitive list) (const 1) (const 2) (const 3)))
650 ;; First order, evaluated.
656 (loop (1- i) (cons i r)))))
657 (define one (const 1)))
660 ;; First order, aliased primitive.
661 (let* ((x *) (y (x 1 2))) y)
665 ;; First order, shadowed primitive.
667 (define (+ x y) (pk x y))
673 (((x y) #f #f #f () (_ _))
674 (apply (toplevel pk) (lexical x _) (lexical y _))))))
675 (apply (toplevel +) (const 1) (const 2))))
678 ;; First-order, effects preserved.
683 (apply (toplevel do-something!))
687 ;; First order, residual bindings removed.
690 (apply (primitive *) (const 5) (toplevel z)))
693 ;; First order, with lambda.
695 (define (bar z) (* z z))
700 (((x) #f #f #f () (_))
701 (letrec* (bar) (_) ((lambda (_) . _))
702 (apply (primitive +) (lexical x _) (const 9))))))))
705 ;; First order, with lambda inlined & specialized twice.
706 (let ((f (lambda (x y)
712 (let (f) (_) ((lambda (_)
714 (((x y) #f #f #f () (_ _))
723 (apply (primitive +) ; (f 2 3)
728 (apply (primitive +) ; (f something 2)
735 ;; First order, with lambda inlined & specialized 3 times.
736 (let ((f (lambda (x y) (if (> x 0) y x))))
737 (+ (f -1 x) (f 2 y) (f z y)))
741 (((x y) #f #f #f () (_ _))
742 (if (apply (primitive >) (lexical x _) (const 0))
746 (const -1) ; (f -1 x)
747 (toplevel y) ; (f 2 y)
748 (apply (lexical f _) ; (f z y)
749 (toplevel z) (toplevel y)))))
752 ;; First order, conditional.
760 (((x) #f #f #f () (_))
761 (apply (toplevel display) (lexical x _))))))
764 ;; First order, recursive procedure.
765 (letrec ((fibo (lambda (n)
776 (f (* (car x) (cadr x))))
783 ;; Higher order with optional argument (default value).
784 ((lambda* (f x #:optional (y 0))
785 (+ y (f (* (car x) (cadr x)))))
792 ;; Higher order with optional argument (caller-supplied value).
793 ((lambda* (f x #:optional (y 0))
794 (+ y (f (* (car x) (cadr x)))))
802 ;; Higher order, mutually recursive procedures.
803 (letrec ((even? (lambda (x)
807 (not (even? (- x 1))))))
808 (and (even? 4) (odd? 7)))
812 ;; Below are cases where constant propagation should bail out.
816 ;; Non-constant lexical is not propagated.
817 (let ((v (make-vector 6 #f)))
819 (vector-set! v n n)))
821 ((apply (toplevel make-vector) (const 6) (const #f)))
824 (((n) #f #f #f () (_))
825 (apply (toplevel vector-set!)
826 (lexical v _) (lexical n _) (lexical n _)))))))
829 ;; Mutable lexical is not propagated.
830 (let ((v (vector 1 2 3)))
834 ((apply (primitive vector) (const 1) (const 2) (const 3)))
841 ;; Lexical that is not provably pure is not inlined nor propagated.
842 (let* ((x (if (> p q) (frob!) (display 'chbouib)))
845 (let (x) (_) ((if (apply (primitive >) (toplevel p) (toplevel q))
846 (apply (toplevel frob!))
847 (apply (toplevel display) (const chbouib))))
848 (let (y) (_) ((apply (primitive *) (lexical x _) (const 2)))
849 (apply (primitive +) (lexical x _) (lexical x _)
850 (apply (primitive *) (lexical x _) (const 2))))))
853 ;; Procedure only called with non-constant args is not inlined.
854 (let* ((g (lambda (x y) (+ x y)))
855 (f (lambda (g x) (g x x))))
856 (+ (f g foo) (f g bar)))
860 (((x y) #f #f #f () (_ _))
861 (apply (primitive +) (lexical x _) (lexical y _))))))
865 (((g x) #f #f #f () (_ _))
866 (apply (lexical g _) (lexical x _) (lexical x _))))))
868 (apply (lexical g _) (toplevel foo) (toplevel foo))
869 (apply (lexical g _) (toplevel bar) (toplevel bar))))))
872 ;; Fresh objects are not turned into constants.
877 (let (x) (_) ((apply (primitive list) (const 1) (const 2) (const 3)))
878 (let (y) (_) ((apply (primitive cons) (const 0) (lexical x _)))
886 (let (x) (_) ((const 2))
888 (set! (lexical x _) (const 3))
897 (frob f) ; may mutate `x'
899 (letrec (x f) (_ _) ((const 0) _)
901 (apply (toplevel frob) (lexical f _))
906 (letrec ((f (lambda (x)
907 (set! f (lambda (_) x))
913 ;; Bindings possibly mutated.
914 (let ((x (make-foo)))
915 (frob! x) ; may mutate `x'
917 (let (x) (_) ((apply (toplevel make-foo)))
919 (apply (toplevel frob!) (lexical x _))
923 ;; Infinite recursion: `peval' gives up and leaves it as is.
924 (letrec ((f (lambda (x) (g (1- x))))
925 (g (lambda (x) (h (1+ x))))
926 (h (lambda (x) (f x))))
931 (with-test-prefix "tree-il-fold"
933 (pass-if "empty tree"
934 (let ((leaf? #f) (up? #f) (down? #f) (mark (list 'mark)))
936 (tree-il-fold (lambda (x y) (set! leaf? #t) y)
937 (lambda (x y) (set! down? #t) y)
938 (lambda (x y) (set! up? #t) y)
945 (pass-if "lambda and application"
946 (let* ((leaves '()) (ups '()) (downs '())
947 (result (tree-il-fold (lambda (x y)
948 (set! leaves (cons x leaves))
951 (set! downs (cons x downs))
954 (set! ups (cons x ups))
960 (((x y) #f #f #f () (x1 y1))
965 (and (equal? (map strip-source leaves)
966 (list (make-lexical-ref #f 'y 'y1)
967 (make-lexical-ref #f 'x 'x1)
968 (make-toplevel-ref #f '+)))
970 (equal? (reverse (map strip-source ups))
971 (map strip-source downs))))))
978 ;; Make sure we get English messages.
979 (setlocale LC_ALL "C")
981 (define (call-with-warnings thunk)
982 (let ((port (open-output-string)))
983 (with-fluids ((*current-warning-port* port)
984 (*current-warning-prefix* ""))
986 (let ((warnings (get-output-string port)))
987 (string-tokenize warnings
988 (char-set-complement (char-set #\newline))))))
990 (define %opts-w-unused
991 '(#:warnings (unused-variable)))
993 (define %opts-w-unused-toplevel
994 '(#:warnings (unused-toplevel)))
996 (define %opts-w-unbound
997 '(#:warnings (unbound-variable)))
999 (define %opts-w-arity
1000 '(#:warnings (arity-mismatch)))
1002 (define %opts-w-format
1003 '(#:warnings (format)))
1006 (with-test-prefix "warnings"
1008 (pass-if "unknown warning type"
1009 (let ((w (call-with-warnings
1011 (compile #t #:opts '(#:warnings (does-not-exist)))))))
1012 (and (= (length w) 1)
1013 (number? (string-contains (car w) "unknown warning")))))
1015 (with-test-prefix "unused-variable"
1018 (null? (call-with-warnings
1020 (compile '(lambda (x y) (+ x y))
1021 #:opts %opts-w-unused)))))
1023 (pass-if "let/unused"
1024 (let ((w (call-with-warnings
1026 (compile '(lambda (x)
1029 #:opts %opts-w-unused)))))
1030 (and (= (length w) 1)
1031 (number? (string-contains (car w) "unused variable `y'")))))
1033 (pass-if "shadowed variable"
1034 (let ((w (call-with-warnings
1036 (compile '(lambda (x)
1040 #:opts %opts-w-unused)))))
1041 (and (= (length w) 1)
1042 (number? (string-contains (car w) "unused variable `y'")))))
1045 (null? (call-with-warnings
1047 (compile '(lambda ()
1048 (letrec ((x (lambda () (y)))
1049 (y (lambda () (x))))
1051 #:opts %opts-w-unused)))))
1053 (pass-if "unused argument"
1054 ;; Unused arguments should not be reported.
1055 (null? (call-with-warnings
1057 (compile '(lambda (x y z) #t)
1058 #:opts %opts-w-unused)))))
1060 (pass-if "special variable names"
1061 (null? (call-with-warnings
1063 (compile '(lambda ()
1064 (let ((_ 'underscore)
1065 (#{gensym name}# 'ignore-me))
1068 #:opts %opts-w-unused))))))
1070 (with-test-prefix "unused-toplevel"
1072 (pass-if "used after definition"
1073 (null? (call-with-warnings
1075 (let ((in (open-input-string
1076 "(define foo 2) foo")))
1077 (read-and-compile in
1079 #:opts %opts-w-unused-toplevel))))))
1081 (pass-if "used before definition"
1082 (null? (call-with-warnings
1084 (let ((in (open-input-string
1085 "(define (bar) foo) (define foo 2) (bar)")))
1086 (read-and-compile in
1088 #:opts %opts-w-unused-toplevel))))))
1090 (pass-if "unused but public"
1091 (let ((in (open-input-string
1092 "(define-module (test-suite tree-il x) #:export (bar))
1093 (define (bar) #t)")))
1094 (null? (call-with-warnings
1096 (read-and-compile in
1098 #:opts %opts-w-unused-toplevel))))))
1100 (pass-if "unused but public (more)"
1101 (let ((in (open-input-string
1102 "(define-module (test-suite tree-il x) #:export (bar))
1103 (define (bar) (baz))
1104 (define (baz) (foo))
1105 (define (foo) #t)")))
1106 (null? (call-with-warnings
1108 (read-and-compile in
1110 #:opts %opts-w-unused-toplevel))))))
1112 (pass-if "unused but define-public"
1113 (null? (call-with-warnings
1115 (compile '(define-public foo 2)
1117 #:opts %opts-w-unused-toplevel)))))
1119 (pass-if "used by macro"
1120 ;; FIXME: See comment about macros at `unused-toplevel-analysis'.
1123 (null? (call-with-warnings
1125 (let ((in (open-input-string
1126 "(define (bar) 'foo)
1128 (syntax-rules () ((_) (bar))))")))
1129 (read-and-compile in
1131 #:opts %opts-w-unused-toplevel))))))
1134 (let ((w (call-with-warnings
1136 (compile '(define foo 2)
1138 #:opts %opts-w-unused-toplevel)))))
1139 (and (= (length w) 1)
1140 (number? (string-contains (car w)
1141 (format #f "top-level variable `~A'"
1144 (pass-if "unused recursive"
1145 (let ((w (call-with-warnings
1147 (compile '(define (foo) (foo))
1149 #:opts %opts-w-unused-toplevel)))))
1150 (and (= (length w) 1)
1151 (number? (string-contains (car w)
1152 (format #f "top-level variable `~A'"
1155 (pass-if "unused mutually recursive"
1156 (let* ((in (open-input-string
1157 "(define (foo) (bar)) (define (bar) (foo))"))
1158 (w (call-with-warnings
1160 (read-and-compile in
1162 #:opts %opts-w-unused-toplevel)))))
1163 (and (= (length w) 2)
1164 (number? (string-contains (car w)
1165 (format #f "top-level variable `~A'"
1167 (number? (string-contains (cadr w)
1168 (format #f "top-level variable `~A'"
1171 (pass-if "special variable names"
1172 (null? (call-with-warnings
1174 (compile '(define #{gensym name}# 'ignore-me)
1176 #:opts %opts-w-unused-toplevel))))))
1178 (with-test-prefix "unbound variable"
1181 (null? (call-with-warnings
1183 (compile '+ #:opts %opts-w-unbound)))))
1187 (w (call-with-warnings
1191 #:opts %opts-w-unbound)))))
1192 (and (= (length w) 1)
1193 (number? (string-contains (car w)
1194 (format #f "unbound variable `~A'"
1199 (w (call-with-warnings
1201 (compile `(set! ,v 7)
1203 #:opts %opts-w-unbound)))))
1204 (and (= (length w) 1)
1205 (number? (string-contains (car w)
1206 (format #f "unbound variable `~A'"
1209 (pass-if "module-local top-level is visible"
1210 (let ((m (make-module))
1212 (beautify-user-module! m)
1213 (compile `(define ,v 123)
1214 #:env m #:opts %opts-w-unbound)
1215 (null? (call-with-warnings
1220 #:opts %opts-w-unbound))))))
1222 (pass-if "module-local top-level is visible after"
1223 (let ((m (make-module))
1225 (beautify-user-module! m)
1226 (null? (call-with-warnings
1228 (let ((in (open-input-string
1231 (define chbouib 5)")))
1232 (read-and-compile in
1234 #:opts %opts-w-unbound)))))))
1236 (pass-if "optional arguments are visible"
1237 (null? (call-with-warnings
1239 (compile '(lambda* (x #:optional y z) (list x y z))
1240 #:opts %opts-w-unbound
1243 (pass-if "keyword arguments are visible"
1244 (null? (call-with-warnings
1246 (compile '(lambda* (x #:key y z) (list x y z))
1247 #:opts %opts-w-unbound
1250 (pass-if "GOOPS definitions are visible"
1251 (let ((m (make-module))
1253 (beautify-user-module! m)
1254 (module-use! m (resolve-interface '(oop goops)))
1255 (null? (call-with-warnings
1257 (let ((in (open-input-string
1258 "(define-class <foo> ()
1259 (bar #:getter foo-bar))
1260 (define z (foo-bar (make <foo>)))")))
1261 (read-and-compile in
1263 #:opts %opts-w-unbound))))))))
1265 (with-test-prefix "arity mismatch"
1268 (null? (call-with-warnings
1270 (compile '(cons 'a 'b) #:opts %opts-w-arity)))))
1272 (pass-if "direct application"
1273 (let ((w (call-with-warnings
1275 (compile '((lambda (x y) (or x y)) 1 2 3 4 5)
1276 #:opts %opts-w-arity
1278 (and (= (length w) 1)
1279 (number? (string-contains (car w)
1280 "wrong number of arguments to")))))
1282 (let ((w (call-with-warnings
1284 (compile '(let ((f (lambda (x y) (+ x y))))
1286 #:opts %opts-w-arity
1288 (and (= (length w) 1)
1289 (number? (string-contains (car w)
1290 "wrong number of arguments to")))))
1293 (let ((w (call-with-warnings
1295 (compile '(cons 1 2 3 4)
1296 #:opts %opts-w-arity
1298 (and (= (length w) 1)
1299 (number? (string-contains (car w)
1300 "wrong number of arguments to")))))
1302 (pass-if "alias to global"
1303 (let ((w (call-with-warnings
1305 (compile '(let ((f cons)) (f 1 2 3 4))
1306 #:opts %opts-w-arity
1308 (and (= (length w) 1)
1309 (number? (string-contains (car w)
1310 "wrong number of arguments to")))))
1312 (pass-if "alias to lexical to global"
1313 (let ((w (call-with-warnings
1315 (compile '(let ((f number?))
1318 #:opts %opts-w-arity
1320 (and (= (length w) 1)
1321 (number? (string-contains (car w)
1322 "wrong number of arguments to")))))
1324 (pass-if "alias to lexical"
1325 (let ((w (call-with-warnings
1327 (compile '(let ((f (lambda (x y z) (+ x y z))))
1330 #:opts %opts-w-arity
1332 (and (= (length w) 1)
1333 (number? (string-contains (car w)
1334 "wrong number of arguments to")))))
1337 (let ((w (call-with-warnings
1339 (compile '(letrec ((odd? (lambda (x) (even? (1- x))))
1344 #:opts %opts-w-arity
1346 (and (= (length w) 1)
1347 (number? (string-contains (car w)
1348 "wrong number of arguments to")))))
1350 (pass-if "case-lambda"
1351 (null? (call-with-warnings
1353 (compile '(let ((f (case-lambda
1360 #:opts %opts-w-arity
1363 (pass-if "case-lambda with wrong number of arguments"
1364 (let ((w (call-with-warnings
1366 (compile '(let ((f (case-lambda
1370 #:opts %opts-w-arity
1372 (and (= (length w) 1)
1373 (number? (string-contains (car w)
1374 "wrong number of arguments to")))))
1376 (pass-if "case-lambda*"
1377 (null? (call-with-warnings
1379 (compile '(let ((f (case-lambda*
1380 ((x #:optional y) 1)
1382 ((x y #:key z) 3))))
1387 #:opts %opts-w-arity
1390 (pass-if "case-lambda* with wrong arguments"
1391 (let ((w (call-with-warnings
1393 (compile '(let ((f (case-lambda*
1394 ((x #:optional y) 1)
1396 ((x y #:key z) 3))))
1399 #:opts %opts-w-arity
1401 (and (= (length w) 2)
1402 (null? (filter (lambda (w)
1406 w "wrong number of arguments to"))))
1409 (pass-if "local toplevel-defines"
1410 (let ((w (call-with-warnings
1412 (let ((in (open-input-string "
1413 (define (g x) (f x))
1415 (read-and-compile in
1416 #:opts %opts-w-arity
1417 #:to 'assembly))))))
1418 (and (= (length w) 1)
1419 (number? (string-contains (car w)
1420 "wrong number of arguments to")))))
1422 (pass-if "global toplevel alias"
1423 (let ((w (call-with-warnings
1425 (let ((in (open-input-string "
1427 (define (g) (f))")))
1428 (read-and-compile in
1429 #:opts %opts-w-arity
1430 #:to 'assembly))))))
1431 (and (= (length w) 1)
1432 (number? (string-contains (car w)
1433 "wrong number of arguments to")))))
1435 (pass-if "local toplevel overrides global"
1436 (null? (call-with-warnings
1438 (let ((in (open-input-string "
1440 (define (foo x) (cons))")))
1441 (read-and-compile in
1442 #:opts %opts-w-arity
1443 #:to 'assembly))))))
1445 (pass-if "keyword not passed and quiet"
1446 (null? (call-with-warnings
1448 (compile '(let ((f (lambda* (x #:key y) y)))
1450 #:opts %opts-w-arity
1453 (pass-if "keyword passed and quiet"
1454 (null? (call-with-warnings
1456 (compile '(let ((f (lambda* (x #:key y) y)))
1458 #:opts %opts-w-arity
1461 (pass-if "keyword passed to global and quiet"
1462 (null? (call-with-warnings
1464 (let ((in (open-input-string "
1465 (use-modules (system base compile))
1466 (compile '(+ 2 3) #:env (current-module))")))
1467 (read-and-compile in
1468 #:opts %opts-w-arity
1469 #:to 'assembly))))))
1471 (pass-if "extra keyword"
1472 (let ((w (call-with-warnings
1474 (compile '(let ((f (lambda* (x #:key y) y)))
1476 #:opts %opts-w-arity
1478 (and (= (length w) 1)
1479 (number? (string-contains (car w)
1480 "wrong number of arguments to")))))
1482 (pass-if "extra keywords allowed"
1483 (null? (call-with-warnings
1485 (compile '(let ((f (lambda* (x #:key y #:allow-other-keys)
1488 #:opts %opts-w-arity
1489 #:to 'assembly))))))
1491 (with-test-prefix "format"
1493 (pass-if "quiet (no args)"
1494 (null? (call-with-warnings
1496 (compile '(format #t "hey!")
1497 #:opts %opts-w-format
1500 (pass-if "quiet (1 arg)"
1501 (null? (call-with-warnings
1503 (compile '(format #t "hey ~A!" "you")
1504 #:opts %opts-w-format
1507 (pass-if "quiet (2 args)"
1508 (null? (call-with-warnings
1510 (compile '(format #t "~A ~A!" "hello" "world")
1511 #:opts %opts-w-format
1514 (pass-if "wrong port arg"
1515 (let ((w (call-with-warnings
1517 (compile '(format 10 "foo")
1518 #:opts %opts-w-format
1520 (and (= (length w) 1)
1521 (number? (string-contains (car w)
1522 "wrong port argument")))))
1524 (pass-if "non-literal format string"
1525 (let ((w (call-with-warnings
1527 (compile '(format #f fmt)
1528 #:opts %opts-w-format
1530 (and (= (length w) 1)
1531 (number? (string-contains (car w)
1532 "non-literal format string")))))
1534 (pass-if "non-literal format string using gettext"
1535 (null? (call-with-warnings
1537 (compile '(format #t (_ "~A ~A!") "hello" "world")
1538 #:opts %opts-w-format
1541 (pass-if "wrong format string"
1542 (let ((w (call-with-warnings
1544 (compile '(format #f 'not-a-string)
1545 #:opts %opts-w-format
1547 (and (= (length w) 1)
1548 (number? (string-contains (car w)
1549 "wrong format string")))))
1551 (pass-if "wrong number of args"
1552 (let ((w (call-with-warnings
1554 (compile '(format "shbweeb")
1555 #:opts %opts-w-format
1557 (and (= (length w) 1)
1558 (number? (string-contains (car w)
1559 "wrong number of arguments")))))
1561 (pass-if "~%, ~~, ~&, ~t, ~_, and ~\\n"
1562 (null? (call-with-warnings
1564 (compile '(format some-port "~&~3_~~ ~\n~12they~%")
1565 #:opts %opts-w-format
1568 (pass-if "one missing argument"
1569 (let ((w (call-with-warnings
1571 (compile '(format some-port "foo ~A~%")
1572 #:opts %opts-w-format
1574 (and (= (length w) 1)
1575 (number? (string-contains (car w)
1576 "expected 1, got 0")))))
1578 (pass-if "one missing argument, gettext"
1579 (let ((w (call-with-warnings
1581 (compile '(format some-port (_ "foo ~A~%"))
1582 #:opts %opts-w-format
1584 (and (= (length w) 1)
1585 (number? (string-contains (car w)
1586 "expected 1, got 0")))))
1588 (pass-if "two missing arguments"
1589 (let ((w (call-with-warnings
1591 (compile '(format #f "foo ~10,2f and bar ~S~%")
1592 #:opts %opts-w-format
1594 (and (= (length w) 1)
1595 (number? (string-contains (car w)
1596 "expected 2, got 0")))))
1598 (pass-if "one given, one missing argument"
1599 (let ((w (call-with-warnings
1601 (compile '(format #t "foo ~A and ~S~%" hey)
1602 #:opts %opts-w-format
1604 (and (= (length w) 1)
1605 (number? (string-contains (car w)
1606 "expected 2, got 1")))))
1608 (pass-if "too many arguments"
1609 (let ((w (call-with-warnings
1611 (compile '(format #t "foo ~A~%" 1 2)
1612 #:opts %opts-w-format
1614 (and (= (length w) 1)
1615 (number? (string-contains (car w)
1616 "expected 1, got 2")))))
1618 (with-test-prefix "conditionals"
1620 (null? (call-with-warnings
1622 (compile '(format #f "~A ~[foo~;bar~;baz~;~] ~10,2f"
1624 #:opts %opts-w-format
1627 (pass-if "literals with selector"
1628 (let ((w (call-with-warnings
1630 (compile '(format #f "~2[foo~;bar~;baz~;~] ~A"
1632 #:opts %opts-w-format
1634 (and (= (length w) 1)
1635 (number? (string-contains (car w)
1636 "expected 1, got 2")))))
1638 (pass-if "escapes (exact count)"
1639 (let ((w (call-with-warnings
1641 (compile '(format #f "~[~a~;~a~]")
1642 #:opts %opts-w-format
1644 (and (= (length w) 1)
1645 (number? (string-contains (car w)
1646 "expected 2, got 0")))))
1648 (pass-if "escapes with selector"
1649 (let ((w (call-with-warnings
1651 (compile '(format #f "~1[chbouib~;~a~]")
1652 #:opts %opts-w-format
1654 (and (= (length w) 1)
1655 (number? (string-contains (car w)
1656 "expected 1, got 0")))))
1658 (pass-if "escapes, range"
1659 (let ((w (call-with-warnings
1661 (compile '(format #f "~[chbouib~;~a~;~2*~a~]")
1662 #:opts %opts-w-format
1664 (and (= (length w) 1)
1665 (number? (string-contains (car w)
1666 "expected 1 to 4, got 0")))))
1669 (let ((w (call-with-warnings
1671 (compile '(format #f "~@[temperature=~d~]")
1672 #:opts %opts-w-format
1674 (and (= (length w) 1)
1675 (number? (string-contains (car w)
1676 "expected 1, got 0")))))
1679 (let ((w (call-with-warnings
1681 (compile '(format #f "~:[~[hey~;~a~;~va~]~;~3*~]")
1682 #:opts %opts-w-format
1684 (and (= (length w) 1)
1685 (number? (string-contains (car w)
1686 "expected 2 to 4, got 0")))))
1688 (pass-if "unterminated"
1689 (let ((w (call-with-warnings
1691 (compile '(format #f "~[unterminated")
1692 #:opts %opts-w-format
1694 (and (= (length w) 1)
1695 (number? (string-contains (car w)
1696 "unterminated conditional")))))
1698 (pass-if "unexpected ~;"
1699 (let ((w (call-with-warnings
1701 (compile '(format #f "foo~;bar")
1702 #:opts %opts-w-format
1704 (and (= (length w) 1)
1705 (number? (string-contains (car w)
1708 (pass-if "unexpected ~]"
1709 (let ((w (call-with-warnings
1711 (compile '(format #f "foo~]")
1712 #:opts %opts-w-format
1714 (and (= (length w) 1)
1715 (number? (string-contains (car w)
1719 (null? (call-with-warnings
1721 (compile '(format #f "~A ~{~S~} ~A"
1722 'hello '("ladies" "and")
1724 #:opts %opts-w-format
1727 (pass-if "~{...~}, too many args"
1728 (let ((w (call-with-warnings
1730 (compile '(format #f "~{~S~}" 1 2 3)
1731 #:opts %opts-w-format
1733 (and (= (length w) 1)
1734 (number? (string-contains (car w)
1735 "expected 1, got 3")))))
1738 (null? (call-with-warnings
1740 (compile '(format #f "~@{~S~}" 1 2 3)
1741 #:opts %opts-w-format
1744 (pass-if "~@{...~}, too few args"
1745 (let ((w (call-with-warnings
1747 (compile '(format #f "~A ~@{~S~}")
1748 #:opts %opts-w-format
1750 (and (= (length w) 1)
1751 (number? (string-contains (car w)
1752 "expected at least 1, got 0")))))
1754 (pass-if "unterminated ~{...~}"
1755 (let ((w (call-with-warnings
1757 (compile '(format #f "~{")
1758 #:opts %opts-w-format
1760 (and (= (length w) 1)
1761 (number? (string-contains (car w)
1765 (null? (call-with-warnings
1767 (compile '(format #f "~:@(~A ~A~)" 'foo 'bar)
1768 #:opts %opts-w-format
1772 (let ((w (call-with-warnings
1774 (compile '(format #f "~v_foo")
1775 #:opts %opts-w-format
1777 (and (= (length w) 1)
1778 (number? (string-contains (car w)
1779 "expected 1, got 0")))))
1781 (null? (call-with-warnings
1783 (compile '(format #f "~v:@y" 1 123)
1784 #:opts %opts-w-format
1789 (let ((w (call-with-warnings
1791 (compile '(format #f "~2*~a" 'a 'b)
1792 #:opts %opts-w-format
1794 (and (= (length w) 1)
1795 (number? (string-contains (car w)
1796 "expected 3, got 2")))))
1799 (null? (call-with-warnings
1801 (compile '(format #f "~?" "~d ~d" '(1 2))
1802 #:opts %opts-w-format
1805 (pass-if "complex 1"
1806 (let ((w (call-with-warnings
1808 (compile '(format #f
1809 "~4@S ~32S~@[;; ~1{~@?~}~]~@[~61t at ~a~]\n"
1811 #:opts %opts-w-format
1813 (and (= (length w) 1)
1814 (number? (string-contains (car w)
1815 "expected 4, got 6")))))
1817 (pass-if "complex 2"
1818 (let ((w (call-with-warnings
1820 (compile '(format #f
1821 "~:(~A~) Commands~:[~; [abbrev]~]:~2%"
1823 #:opts %opts-w-format
1825 (and (= (length w) 1)
1826 (number? (string-contains (car w)
1827 "expected 2, got 4")))))
1829 (pass-if "complex 3"
1830 (let ((w (call-with-warnings
1832 (compile '(format #f "~9@a~:[~*~3_~;~3d~] ~v:@y~%")
1833 #:opts %opts-w-format
1835 (and (= (length w) 1)
1836 (number? (string-contains (car w)
1837 "expected 5, got 0")))))
1839 (pass-if "ice-9 format"
1840 (let ((w (call-with-warnings
1842 (let ((in (open-input-string
1843 "(use-modules ((ice-9 format)
1844 #:renamer (symbol-prefix-proc 'i9-)))
1845 (i9-format #t \"yo! ~A\" 1 2)")))
1846 (read-and-compile in
1847 #:opts %opts-w-format
1848 #:to 'assembly))))))
1849 (and (= (length w) 1)
1850 (number? (string-contains (car w)
1851 "expected 1, got 2")))))
1853 (pass-if "not format"
1854 (null? (call-with-warnings
1856 (compile '(let ((format chbouib))
1857 (format #t "not ~A a format string"))
1858 #:opts %opts-w-format
1859 #:to 'assembly)))))))