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, thunk.
619 (let ((f (lambda () (+ x y))))
624 ;; First order, coalesced.
625 (cons 0 (cons 1 (cons 2 (list 3 4 5))))
626 (const (0 1 2 3 4 5)))
629 ;; First order, coalesced, mutability preserved.
631 (cons 0 (cons 1 (cons 2 (list 3 4 5)))))
633 ;; This must not be a constant.
634 (apply (primitive list)
635 (const 0) (const 1) (const 2) (const 3) (const 4) (const 5))))
638 ;; First order, mutability preserved.
640 (let loop ((i 3) (r '()))
643 (loop (1- i) (cons (cons i i) r)))))
645 (apply (primitive list)
646 (apply (primitive cons) (const 1) (const 1))
647 (apply (primitive cons) (const 2) (const 2))
648 (apply (primitive cons) (const 3) (const 3)))))
651 ;; Mutability preserved.
653 ((lambda (x y z) (list x y z)) 1 2 3))
655 (apply (primitive list) (const 1) (const 2) (const 3))))
658 ;; First order, evaluated.
664 (loop (1- i) (cons i r)))))
665 (define one (const 1)))
668 ;; First order, aliased primitive.
669 (let* ((x *) (y (x 1 2))) y)
673 ;; First order, shadowed primitive.
675 (define (+ x y) (pk x y))
681 (((x y) #f #f #f () (_ _))
682 (apply (toplevel pk) (lexical x _) (lexical y _))))))
683 (apply (toplevel +) (const 1) (const 2))))
686 ;; First-order, effects preserved.
691 (apply (toplevel do-something!))
695 ;; First order, residual bindings removed.
698 (apply (primitive *) (const 5) (toplevel z)))
701 ;; First order, with lambda.
703 (define (bar z) (* z z))
708 (((x) #f #f #f () (_))
709 (letrec* (bar) (_) ((lambda (_) . _))
710 (apply (primitive +) (lexical x _) (const 9))))))))
713 ;; First order, with lambda inlined & specialized twice.
714 (let ((f (lambda (x y)
720 (let (f) (_) ((lambda (_)
722 (((x y) #f #f #f () (_ _))
731 (apply (primitive +) ; (f 2 3)
736 (apply (primitive +) ; (f something 2)
743 ;; First order, with lambda inlined & specialized 3 times.
744 (let ((f (lambda (x y) (if (> x 0) y x))))
745 (+ (f -1 x) (f 2 y) (f z y)))
749 (((x y) #f #f #f () (_ _))
750 (if (apply (primitive >) (lexical x _) (const 0))
754 (const -1) ; (f -1 x)
755 (toplevel y) ; (f 2 y)
756 (apply (lexical f _) ; (f z y)
757 (toplevel z) (toplevel y)))))
760 ;; First order, conditional.
768 (((x) #f #f #f () (_))
769 (apply (toplevel display) (lexical x _))))))
772 ;; First order, recursive procedure.
773 (letrec ((fibo (lambda (n)
784 (f (* (car x) (cadr x))))
791 ;; Higher order with optional argument (default value).
792 ((lambda* (f x #:optional (y 0))
793 (+ y (f (* (car x) (cadr x)))))
800 ;; Higher order with optional argument (caller-supplied value).
801 ((lambda* (f x #:optional (y 0))
802 (+ y (f (* (car x) (cadr x)))))
811 ((lambda (f) (f x)) (lambda (x) x))
814 (((x) #f #f #f () (_))
820 ;; <https://lists.gnu.org/archive/html/bug-guile/2011-09/msg00019.html>.
821 (let ((fold (lambda (f g) (f (g top)))))
822 (fold 1+ (lambda (x) x)))
824 (apply (primitive 1+)
827 (((x) #f #f #f () (_))
832 ;; Higher order, mutually recursive procedures.
833 (letrec ((even? (lambda (x)
837 (not (even? (- x 1))))))
838 (and (even? 4) (odd? 7)))
842 ;; Below are cases where constant propagation should bail out.
846 ;; Non-constant lexical is not propagated.
847 (let ((v (make-vector 6 #f)))
849 (vector-set! v n n)))
851 ((apply (toplevel make-vector) (const 6) (const #f)))
854 (((n) #f #f #f () (_))
855 (apply (toplevel vector-set!)
856 (lexical v _) (lexical n _) (lexical n _)))))))
859 ;; Mutable lexical is not propagated.
860 (let ((v (vector 1 2 3)))
864 ((apply (primitive vector) (const 1) (const 2) (const 3)))
871 ;; Lexical that is not provably pure is not inlined nor propagated.
872 (let* ((x (if (> p q) (frob!) (display 'chbouib)))
875 (let (x) (_) ((if (apply (primitive >) (toplevel p) (toplevel q))
876 (apply (toplevel frob!))
877 (apply (toplevel display) (const chbouib))))
878 (let (y) (_) ((apply (primitive *) (lexical x _) (const 2)))
879 (apply (primitive +) (lexical x _) (lexical x _)
880 (apply (primitive *) (lexical x _) (const 2))))))
883 ;; Non-constant arguments not propagated to lambdas.
893 (((x y z) #f #f #f () (_ _ _))
895 (apply (toplevel vector-set!)
896 (lexical x _) (const 0) (const 0))
897 (apply (toplevel set-car!)
898 (lexical y _) (const 0))
899 (apply (toplevel set-cdr!)
900 (lexical z _) (const ()))))))
901 (apply (primitive vector) (const 1) (const 2) (const 3))
902 (apply (toplevel make-list) (const 10))
903 (apply (primitive list) (const 1) (const 2) (const 3))))
906 ;; Procedure only called with dynamic args is not inlined.
907 (let* ((g (lambda (x y) (+ x y)))
908 (f (lambda (g x) (g x x))))
909 (+ (f g foo) (f g bar)))
913 (((x y) #f #f #f () (_ _))
914 (apply (primitive +) (lexical x _) (lexical y _))))))
918 (((g x) #f #f #f () (_ _))
919 (apply (lexical g _) (lexical x _) (lexical x _))))))
921 (apply (lexical g _) (toplevel foo) (toplevel foo))
922 (apply (lexical g _) (toplevel bar) (toplevel bar))))))
925 ;; Fresh objects are not turned into constants.
930 (let (x) (_) ((apply (primitive list) (const 1) (const 2) (const 3)))
931 (let (y) (_) ((apply (primitive cons) (const 0) (lexical x _)))
939 (let (x) (_) ((const 2))
941 (set! (lexical x _) (const 3))
950 (frob f) ; may mutate `x'
952 (letrec (x f) (_ _) ((const 0) _)
954 (apply (toplevel frob) (lexical f _))
959 (letrec ((f (lambda (x)
960 (set! f (lambda (_) x))
966 ;; Bindings possibly mutated.
967 (let ((x (make-foo)))
968 (frob! x) ; may mutate `x'
970 (let (x) (_) ((apply (toplevel make-foo)))
972 (apply (toplevel frob!) (lexical x _))
976 ;; Inlining stops at recursive calls with dynamic arguments.
978 (if (< x 0) x (loop (1- x))))
979 (letrec (loop) (_) ((lambda (_)
981 (((x) #f #f #f () (_))
983 (apply (lexical loop _)
984 (apply (primitive 1-)
986 (apply (lexical loop _) (toplevel x))))
989 ;; Inlining stops at recursive calls (mixed static/dynamic arguments).
990 (let loop ((x x) (y 0))
993 (if (< x 0) x (loop (1- x)))))
994 (letrec (loop) (_) ((lambda (_)
996 (((x y) #f #f #f () (_ _))
997 (if (apply (primitive >)
998 (lexical y _) (const 0))
1000 ;; call to (loop x 0) is inlined & specialized
1001 (if (apply (primitive <) (toplevel x) (const 0))
1003 (apply (lexical loop _)
1004 (apply (primitive 1-) (toplevel x))))))
1007 ;; Infinite recursion: `peval' gives up and leaves it as is.
1008 (letrec ((f (lambda (x) (g (1- x))))
1009 (g (lambda (x) (h (1+ x))))
1010 (h (lambda (x) (f x))))
1015 (with-test-prefix "tree-il-fold"
1017 (pass-if "empty tree"
1018 (let ((leaf? #f) (up? #f) (down? #f) (mark (list 'mark)))
1020 (tree-il-fold (lambda (x y) (set! leaf? #t) y)
1021 (lambda (x y) (set! down? #t) y)
1022 (lambda (x y) (set! up? #t) y)
1029 (pass-if "lambda and application"
1030 (let* ((leaves '()) (ups '()) (downs '())
1031 (result (tree-il-fold (lambda (x y)
1032 (set! leaves (cons x leaves))
1035 (set! downs (cons x downs))
1038 (set! ups (cons x ups))
1044 (((x y) #f #f #f () (x1 y1))
1049 (and (equal? (map strip-source leaves)
1050 (list (make-lexical-ref #f 'y 'y1)
1051 (make-lexical-ref #f 'x 'x1)
1052 (make-toplevel-ref #f '+)))
1053 (= (length downs) 3)
1054 (equal? (reverse (map strip-source ups))
1055 (map strip-source downs))))))
1062 ;; Make sure we get English messages.
1063 (setlocale LC_ALL "C")
1065 (define (call-with-warnings thunk)
1066 (let ((port (open-output-string)))
1067 (with-fluids ((*current-warning-port* port)
1068 (*current-warning-prefix* ""))
1070 (let ((warnings (get-output-string port)))
1071 (string-tokenize warnings
1072 (char-set-complement (char-set #\newline))))))
1074 (define %opts-w-unused
1075 '(#:warnings (unused-variable)))
1077 (define %opts-w-unused-toplevel
1078 '(#:warnings (unused-toplevel)))
1080 (define %opts-w-unbound
1081 '(#:warnings (unbound-variable)))
1083 (define %opts-w-arity
1084 '(#:warnings (arity-mismatch)))
1086 (define %opts-w-format
1087 '(#:warnings (format)))
1090 (with-test-prefix "warnings"
1092 (pass-if "unknown warning type"
1093 (let ((w (call-with-warnings
1095 (compile #t #:opts '(#:warnings (does-not-exist)))))))
1096 (and (= (length w) 1)
1097 (number? (string-contains (car w) "unknown warning")))))
1099 (with-test-prefix "unused-variable"
1102 (null? (call-with-warnings
1104 (compile '(lambda (x y) (+ x y))
1105 #:opts %opts-w-unused)))))
1107 (pass-if "let/unused"
1108 (let ((w (call-with-warnings
1110 (compile '(lambda (x)
1113 #:opts %opts-w-unused)))))
1114 (and (= (length w) 1)
1115 (number? (string-contains (car w) "unused variable `y'")))))
1117 (pass-if "shadowed variable"
1118 (let ((w (call-with-warnings
1120 (compile '(lambda (x)
1124 #:opts %opts-w-unused)))))
1125 (and (= (length w) 1)
1126 (number? (string-contains (car w) "unused variable `y'")))))
1129 (null? (call-with-warnings
1131 (compile '(lambda ()
1132 (letrec ((x (lambda () (y)))
1133 (y (lambda () (x))))
1135 #:opts %opts-w-unused)))))
1137 (pass-if "unused argument"
1138 ;; Unused arguments should not be reported.
1139 (null? (call-with-warnings
1141 (compile '(lambda (x y z) #t)
1142 #:opts %opts-w-unused)))))
1144 (pass-if "special variable names"
1145 (null? (call-with-warnings
1147 (compile '(lambda ()
1148 (let ((_ 'underscore)
1149 (#{gensym name}# 'ignore-me))
1152 #:opts %opts-w-unused))))))
1154 (with-test-prefix "unused-toplevel"
1156 (pass-if "used after definition"
1157 (null? (call-with-warnings
1159 (let ((in (open-input-string
1160 "(define foo 2) foo")))
1161 (read-and-compile in
1163 #:opts %opts-w-unused-toplevel))))))
1165 (pass-if "used before definition"
1166 (null? (call-with-warnings
1168 (let ((in (open-input-string
1169 "(define (bar) foo) (define foo 2) (bar)")))
1170 (read-and-compile in
1172 #:opts %opts-w-unused-toplevel))))))
1174 (pass-if "unused but public"
1175 (let ((in (open-input-string
1176 "(define-module (test-suite tree-il x) #:export (bar))
1177 (define (bar) #t)")))
1178 (null? (call-with-warnings
1180 (read-and-compile in
1182 #:opts %opts-w-unused-toplevel))))))
1184 (pass-if "unused but public (more)"
1185 (let ((in (open-input-string
1186 "(define-module (test-suite tree-il x) #:export (bar))
1187 (define (bar) (baz))
1188 (define (baz) (foo))
1189 (define (foo) #t)")))
1190 (null? (call-with-warnings
1192 (read-and-compile in
1194 #:opts %opts-w-unused-toplevel))))))
1196 (pass-if "unused but define-public"
1197 (null? (call-with-warnings
1199 (compile '(define-public foo 2)
1201 #:opts %opts-w-unused-toplevel)))))
1203 (pass-if "used by macro"
1204 ;; FIXME: See comment about macros at `unused-toplevel-analysis'.
1207 (null? (call-with-warnings
1209 (let ((in (open-input-string
1210 "(define (bar) 'foo)
1212 (syntax-rules () ((_) (bar))))")))
1213 (read-and-compile in
1215 #:opts %opts-w-unused-toplevel))))))
1218 (let ((w (call-with-warnings
1220 (compile '(define foo 2)
1222 #:opts %opts-w-unused-toplevel)))))
1223 (and (= (length w) 1)
1224 (number? (string-contains (car w)
1225 (format #f "top-level variable `~A'"
1228 (pass-if "unused recursive"
1229 (let ((w (call-with-warnings
1231 (compile '(define (foo) (foo))
1233 #:opts %opts-w-unused-toplevel)))))
1234 (and (= (length w) 1)
1235 (number? (string-contains (car w)
1236 (format #f "top-level variable `~A'"
1239 (pass-if "unused mutually recursive"
1240 (let* ((in (open-input-string
1241 "(define (foo) (bar)) (define (bar) (foo))"))
1242 (w (call-with-warnings
1244 (read-and-compile in
1246 #:opts %opts-w-unused-toplevel)))))
1247 (and (= (length w) 2)
1248 (number? (string-contains (car w)
1249 (format #f "top-level variable `~A'"
1251 (number? (string-contains (cadr w)
1252 (format #f "top-level variable `~A'"
1255 (pass-if "special variable names"
1256 (null? (call-with-warnings
1258 (compile '(define #{gensym name}# 'ignore-me)
1260 #:opts %opts-w-unused-toplevel))))))
1262 (with-test-prefix "unbound variable"
1265 (null? (call-with-warnings
1267 (compile '+ #:opts %opts-w-unbound)))))
1271 (w (call-with-warnings
1275 #:opts %opts-w-unbound)))))
1276 (and (= (length w) 1)
1277 (number? (string-contains (car w)
1278 (format #f "unbound variable `~A'"
1283 (w (call-with-warnings
1285 (compile `(set! ,v 7)
1287 #:opts %opts-w-unbound)))))
1288 (and (= (length w) 1)
1289 (number? (string-contains (car w)
1290 (format #f "unbound variable `~A'"
1293 (pass-if "module-local top-level is visible"
1294 (let ((m (make-module))
1296 (beautify-user-module! m)
1297 (compile `(define ,v 123)
1298 #:env m #:opts %opts-w-unbound)
1299 (null? (call-with-warnings
1304 #:opts %opts-w-unbound))))))
1306 (pass-if "module-local top-level is visible after"
1307 (let ((m (make-module))
1309 (beautify-user-module! m)
1310 (null? (call-with-warnings
1312 (let ((in (open-input-string
1315 (define chbouib 5)")))
1316 (read-and-compile in
1318 #:opts %opts-w-unbound)))))))
1320 (pass-if "optional arguments are visible"
1321 (null? (call-with-warnings
1323 (compile '(lambda* (x #:optional y z) (list x y z))
1324 #:opts %opts-w-unbound
1327 (pass-if "keyword arguments are visible"
1328 (null? (call-with-warnings
1330 (compile '(lambda* (x #:key y z) (list x y z))
1331 #:opts %opts-w-unbound
1334 (pass-if "GOOPS definitions are visible"
1335 (let ((m (make-module))
1337 (beautify-user-module! m)
1338 (module-use! m (resolve-interface '(oop goops)))
1339 (null? (call-with-warnings
1341 (let ((in (open-input-string
1342 "(define-class <foo> ()
1343 (bar #:getter foo-bar))
1344 (define z (foo-bar (make <foo>)))")))
1345 (read-and-compile in
1347 #:opts %opts-w-unbound))))))))
1349 (with-test-prefix "arity mismatch"
1352 (null? (call-with-warnings
1354 (compile '(cons 'a 'b) #:opts %opts-w-arity)))))
1356 (pass-if "direct application"
1357 (let ((w (call-with-warnings
1359 (compile '((lambda (x y) (or x y)) 1 2 3 4 5)
1360 #:opts %opts-w-arity
1362 (and (= (length w) 1)
1363 (number? (string-contains (car w)
1364 "wrong number of arguments to")))))
1366 (let ((w (call-with-warnings
1368 (compile '(let ((f (lambda (x y) (+ x y))))
1370 #:opts %opts-w-arity
1372 (and (= (length w) 1)
1373 (number? (string-contains (car w)
1374 "wrong number of arguments to")))))
1377 (let ((w (call-with-warnings
1379 (compile '(cons 1 2 3 4)
1380 #:opts %opts-w-arity
1382 (and (= (length w) 1)
1383 (number? (string-contains (car w)
1384 "wrong number of arguments to")))))
1386 (pass-if "alias to global"
1387 (let ((w (call-with-warnings
1389 (compile '(let ((f cons)) (f 1 2 3 4))
1390 #:opts %opts-w-arity
1392 (and (= (length w) 1)
1393 (number? (string-contains (car w)
1394 "wrong number of arguments to")))))
1396 (pass-if "alias to lexical to global"
1397 (let ((w (call-with-warnings
1399 (compile '(let ((f number?))
1402 #:opts %opts-w-arity
1404 (and (= (length w) 1)
1405 (number? (string-contains (car w)
1406 "wrong number of arguments to")))))
1408 (pass-if "alias to lexical"
1409 (let ((w (call-with-warnings
1411 (compile '(let ((f (lambda (x y z) (+ x y z))))
1414 #:opts %opts-w-arity
1416 (and (= (length w) 1)
1417 (number? (string-contains (car w)
1418 "wrong number of arguments to")))))
1421 (let ((w (call-with-warnings
1423 (compile '(letrec ((odd? (lambda (x) (even? (1- x))))
1428 #:opts %opts-w-arity
1430 (and (= (length w) 1)
1431 (number? (string-contains (car w)
1432 "wrong number of arguments to")))))
1434 (pass-if "case-lambda"
1435 (null? (call-with-warnings
1437 (compile '(let ((f (case-lambda
1444 #:opts %opts-w-arity
1447 (pass-if "case-lambda with wrong number of arguments"
1448 (let ((w (call-with-warnings
1450 (compile '(let ((f (case-lambda
1454 #:opts %opts-w-arity
1456 (and (= (length w) 1)
1457 (number? (string-contains (car w)
1458 "wrong number of arguments to")))))
1460 (pass-if "case-lambda*"
1461 (null? (call-with-warnings
1463 (compile '(let ((f (case-lambda*
1464 ((x #:optional y) 1)
1466 ((x y #:key z) 3))))
1471 #:opts %opts-w-arity
1474 (pass-if "case-lambda* with wrong arguments"
1475 (let ((w (call-with-warnings
1477 (compile '(let ((f (case-lambda*
1478 ((x #:optional y) 1)
1480 ((x y #:key z) 3))))
1483 #:opts %opts-w-arity
1485 (and (= (length w) 2)
1486 (null? (filter (lambda (w)
1490 w "wrong number of arguments to"))))
1493 (pass-if "local toplevel-defines"
1494 (let ((w (call-with-warnings
1496 (let ((in (open-input-string "
1497 (define (g x) (f x))
1499 (read-and-compile in
1500 #:opts %opts-w-arity
1501 #:to 'assembly))))))
1502 (and (= (length w) 1)
1503 (number? (string-contains (car w)
1504 "wrong number of arguments to")))))
1506 (pass-if "global toplevel alias"
1507 (let ((w (call-with-warnings
1509 (let ((in (open-input-string "
1511 (define (g) (f))")))
1512 (read-and-compile in
1513 #:opts %opts-w-arity
1514 #:to 'assembly))))))
1515 (and (= (length w) 1)
1516 (number? (string-contains (car w)
1517 "wrong number of arguments to")))))
1519 (pass-if "local toplevel overrides global"
1520 (null? (call-with-warnings
1522 (let ((in (open-input-string "
1524 (define (foo x) (cons))")))
1525 (read-and-compile in
1526 #:opts %opts-w-arity
1527 #:to 'assembly))))))
1529 (pass-if "keyword not passed and quiet"
1530 (null? (call-with-warnings
1532 (compile '(let ((f (lambda* (x #:key y) y)))
1534 #:opts %opts-w-arity
1537 (pass-if "keyword passed and quiet"
1538 (null? (call-with-warnings
1540 (compile '(let ((f (lambda* (x #:key y) y)))
1542 #:opts %opts-w-arity
1545 (pass-if "keyword passed to global and quiet"
1546 (null? (call-with-warnings
1548 (let ((in (open-input-string "
1549 (use-modules (system base compile))
1550 (compile '(+ 2 3) #:env (current-module))")))
1551 (read-and-compile in
1552 #:opts %opts-w-arity
1553 #:to 'assembly))))))
1555 (pass-if "extra keyword"
1556 (let ((w (call-with-warnings
1558 (compile '(let ((f (lambda* (x #:key y) y)))
1560 #:opts %opts-w-arity
1562 (and (= (length w) 1)
1563 (number? (string-contains (car w)
1564 "wrong number of arguments to")))))
1566 (pass-if "extra keywords allowed"
1567 (null? (call-with-warnings
1569 (compile '(let ((f (lambda* (x #:key y #:allow-other-keys)
1572 #:opts %opts-w-arity
1573 #:to 'assembly))))))
1575 (with-test-prefix "format"
1577 (pass-if "quiet (no args)"
1578 (null? (call-with-warnings
1580 (compile '(format #t "hey!")
1581 #:opts %opts-w-format
1584 (pass-if "quiet (1 arg)"
1585 (null? (call-with-warnings
1587 (compile '(format #t "hey ~A!" "you")
1588 #:opts %opts-w-format
1591 (pass-if "quiet (2 args)"
1592 (null? (call-with-warnings
1594 (compile '(format #t "~A ~A!" "hello" "world")
1595 #:opts %opts-w-format
1598 (pass-if "wrong port arg"
1599 (let ((w (call-with-warnings
1601 (compile '(format 10 "foo")
1602 #:opts %opts-w-format
1604 (and (= (length w) 1)
1605 (number? (string-contains (car w)
1606 "wrong port argument")))))
1608 (pass-if "non-literal format string"
1609 (let ((w (call-with-warnings
1611 (compile '(format #f fmt)
1612 #:opts %opts-w-format
1614 (and (= (length w) 1)
1615 (number? (string-contains (car w)
1616 "non-literal format string")))))
1618 (pass-if "non-literal format string using gettext"
1619 (null? (call-with-warnings
1621 (compile '(format #t (_ "~A ~A!") "hello" "world")
1622 #:opts %opts-w-format
1625 (pass-if "wrong format string"
1626 (let ((w (call-with-warnings
1628 (compile '(format #f 'not-a-string)
1629 #:opts %opts-w-format
1631 (and (= (length w) 1)
1632 (number? (string-contains (car w)
1633 "wrong format string")))))
1635 (pass-if "wrong number of args"
1636 (let ((w (call-with-warnings
1638 (compile '(format "shbweeb")
1639 #:opts %opts-w-format
1641 (and (= (length w) 1)
1642 (number? (string-contains (car w)
1643 "wrong number of arguments")))))
1645 (pass-if "~%, ~~, ~&, ~t, ~_, and ~\\n"
1646 (null? (call-with-warnings
1648 (compile '(format some-port "~&~3_~~ ~\n~12they~%")
1649 #:opts %opts-w-format
1652 (pass-if "one missing argument"
1653 (let ((w (call-with-warnings
1655 (compile '(format some-port "foo ~A~%")
1656 #:opts %opts-w-format
1658 (and (= (length w) 1)
1659 (number? (string-contains (car w)
1660 "expected 1, got 0")))))
1662 (pass-if "one missing argument, gettext"
1663 (let ((w (call-with-warnings
1665 (compile '(format some-port (_ "foo ~A~%"))
1666 #:opts %opts-w-format
1668 (and (= (length w) 1)
1669 (number? (string-contains (car w)
1670 "expected 1, got 0")))))
1672 (pass-if "two missing arguments"
1673 (let ((w (call-with-warnings
1675 (compile '(format #f "foo ~10,2f and bar ~S~%")
1676 #:opts %opts-w-format
1678 (and (= (length w) 1)
1679 (number? (string-contains (car w)
1680 "expected 2, got 0")))))
1682 (pass-if "one given, one missing argument"
1683 (let ((w (call-with-warnings
1685 (compile '(format #t "foo ~A and ~S~%" hey)
1686 #:opts %opts-w-format
1688 (and (= (length w) 1)
1689 (number? (string-contains (car w)
1690 "expected 2, got 1")))))
1692 (pass-if "too many arguments"
1693 (let ((w (call-with-warnings
1695 (compile '(format #t "foo ~A~%" 1 2)
1696 #:opts %opts-w-format
1698 (and (= (length w) 1)
1699 (number? (string-contains (car w)
1700 "expected 1, got 2")))))
1702 (with-test-prefix "conditionals"
1704 (null? (call-with-warnings
1706 (compile '(format #f "~A ~[foo~;bar~;baz~;~] ~10,2f"
1708 #:opts %opts-w-format
1711 (pass-if "literals with selector"
1712 (let ((w (call-with-warnings
1714 (compile '(format #f "~2[foo~;bar~;baz~;~] ~A"
1716 #:opts %opts-w-format
1718 (and (= (length w) 1)
1719 (number? (string-contains (car w)
1720 "expected 1, got 2")))))
1722 (pass-if "escapes (exact count)"
1723 (let ((w (call-with-warnings
1725 (compile '(format #f "~[~a~;~a~]")
1726 #:opts %opts-w-format
1728 (and (= (length w) 1)
1729 (number? (string-contains (car w)
1730 "expected 2, got 0")))))
1732 (pass-if "escapes with selector"
1733 (let ((w (call-with-warnings
1735 (compile '(format #f "~1[chbouib~;~a~]")
1736 #:opts %opts-w-format
1738 (and (= (length w) 1)
1739 (number? (string-contains (car w)
1740 "expected 1, got 0")))))
1742 (pass-if "escapes, range"
1743 (let ((w (call-with-warnings
1745 (compile '(format #f "~[chbouib~;~a~;~2*~a~]")
1746 #:opts %opts-w-format
1748 (and (= (length w) 1)
1749 (number? (string-contains (car w)
1750 "expected 1 to 4, got 0")))))
1753 (let ((w (call-with-warnings
1755 (compile '(format #f "~@[temperature=~d~]")
1756 #:opts %opts-w-format
1758 (and (= (length w) 1)
1759 (number? (string-contains (car w)
1760 "expected 1, got 0")))))
1763 (let ((w (call-with-warnings
1765 (compile '(format #f "~:[~[hey~;~a~;~va~]~;~3*~]")
1766 #:opts %opts-w-format
1768 (and (= (length w) 1)
1769 (number? (string-contains (car w)
1770 "expected 2 to 4, got 0")))))
1772 (pass-if "unterminated"
1773 (let ((w (call-with-warnings
1775 (compile '(format #f "~[unterminated")
1776 #:opts %opts-w-format
1778 (and (= (length w) 1)
1779 (number? (string-contains (car w)
1780 "unterminated conditional")))))
1782 (pass-if "unexpected ~;"
1783 (let ((w (call-with-warnings
1785 (compile '(format #f "foo~;bar")
1786 #:opts %opts-w-format
1788 (and (= (length w) 1)
1789 (number? (string-contains (car w)
1792 (pass-if "unexpected ~]"
1793 (let ((w (call-with-warnings
1795 (compile '(format #f "foo~]")
1796 #:opts %opts-w-format
1798 (and (= (length w) 1)
1799 (number? (string-contains (car w)
1803 (null? (call-with-warnings
1805 (compile '(format #f "~A ~{~S~} ~A"
1806 'hello '("ladies" "and")
1808 #:opts %opts-w-format
1811 (pass-if "~{...~}, too many args"
1812 (let ((w (call-with-warnings
1814 (compile '(format #f "~{~S~}" 1 2 3)
1815 #:opts %opts-w-format
1817 (and (= (length w) 1)
1818 (number? (string-contains (car w)
1819 "expected 1, got 3")))))
1822 (null? (call-with-warnings
1824 (compile '(format #f "~@{~S~}" 1 2 3)
1825 #:opts %opts-w-format
1828 (pass-if "~@{...~}, too few args"
1829 (let ((w (call-with-warnings
1831 (compile '(format #f "~A ~@{~S~}")
1832 #:opts %opts-w-format
1834 (and (= (length w) 1)
1835 (number? (string-contains (car w)
1836 "expected at least 1, got 0")))))
1838 (pass-if "unterminated ~{...~}"
1839 (let ((w (call-with-warnings
1841 (compile '(format #f "~{")
1842 #:opts %opts-w-format
1844 (and (= (length w) 1)
1845 (number? (string-contains (car w)
1849 (null? (call-with-warnings
1851 (compile '(format #f "~:@(~A ~A~)" 'foo 'bar)
1852 #:opts %opts-w-format
1856 (let ((w (call-with-warnings
1858 (compile '(format #f "~v_foo")
1859 #:opts %opts-w-format
1861 (and (= (length w) 1)
1862 (number? (string-contains (car w)
1863 "expected 1, got 0")))))
1865 (null? (call-with-warnings
1867 (compile '(format #f "~v:@y" 1 123)
1868 #:opts %opts-w-format
1873 (let ((w (call-with-warnings
1875 (compile '(format #f "~2*~a" 'a 'b)
1876 #:opts %opts-w-format
1878 (and (= (length w) 1)
1879 (number? (string-contains (car w)
1880 "expected 3, got 2")))))
1883 (null? (call-with-warnings
1885 (compile '(format #f "~?" "~d ~d" '(1 2))
1886 #:opts %opts-w-format
1889 (pass-if "complex 1"
1890 (let ((w (call-with-warnings
1892 (compile '(format #f
1893 "~4@S ~32S~@[;; ~1{~@?~}~]~@[~61t at ~a~]\n"
1895 #:opts %opts-w-format
1897 (and (= (length w) 1)
1898 (number? (string-contains (car w)
1899 "expected 4, got 6")))))
1901 (pass-if "complex 2"
1902 (let ((w (call-with-warnings
1904 (compile '(format #f
1905 "~:(~A~) Commands~:[~; [abbrev]~]:~2%"
1907 #:opts %opts-w-format
1909 (and (= (length w) 1)
1910 (number? (string-contains (car w)
1911 "expected 2, got 4")))))
1913 (pass-if "complex 3"
1914 (let ((w (call-with-warnings
1916 (compile '(format #f "~9@a~:[~*~3_~;~3d~] ~v:@y~%")
1917 #:opts %opts-w-format
1919 (and (= (length w) 1)
1920 (number? (string-contains (car w)
1921 "expected 5, got 0")))))
1923 (pass-if "ice-9 format"
1924 (let ((w (call-with-warnings
1926 (let ((in (open-input-string
1927 "(use-modules ((ice-9 format)
1928 #:renamer (symbol-prefix-proc 'i9-)))
1929 (i9-format #t \"yo! ~A\" 1 2)")))
1930 (read-and-compile in
1931 #:opts %opts-w-format
1932 #:to 'assembly))))))
1933 (and (= (length w) 1)
1934 (number? (string-contains (car w)
1935 "expected 1, got 2")))))
1937 (pass-if "not format"
1938 (null? (call-with-warnings
1940 (compile '(let ((format chbouib))
1941 (format #t "not ~A a format string"))
1942 #:opts %opts-w-format
1943 #:to 'assembly)))))))