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 tree-il primitives)
27 #:use-module (language glil)
28 #:use-module (srfi srfi-13))
30 ;; Of course, the GLIL that is emitted depends on the source info of the
31 ;; input. Here we're not concerned about that, so we strip source
32 ;; information from the incoming tree-il.
34 (define (strip-source x)
35 (post-order! (lambda (x) (set! (tree-il-src x) #f))
38 (define-syntax assert-tree-il->glil
39 (syntax-rules (with-partial-evaluation without-partial-evaluation
41 ((_ with-partial-evaluation in pat test ...)
42 (assert-tree-il->glil with-options (#:partial-eval? #t)
44 ((_ without-partial-evaluation in pat test ...)
45 (assert-tree-il->glil with-options (#:partial-eval? #f)
47 ((_ with-options opts in pat test ...)
50 (let ((glil (unparse-glil
51 (compile (strip-source (parse-tree-il exp))
52 #:from 'tree-il #:to 'glil
55 (pat (guard test ...) #t)
58 (assert-tree-il->glil with-partial-evaluation
61 (define-syntax pass-if-tree-il->scheme
64 (assert-scheme->tree-il->scheme in pat #t))
67 (pmatch (tree-il->scheme
68 (compile 'in #:from 'scheme #:to 'tree-il))
69 (pat (guard guard-exp) #t)
73 ;; The partial evaluator.
74 (@@ (language tree-il optimize) peval))
76 (define-syntax pass-if-peval
77 (syntax-rules (resolve-primitives)
80 (compile 'in #:from 'scheme #:to 'tree-il)))
81 ((_ resolve-primitives in pat)
85 (compile 'in #:from 'scheme #:to 'tree-il)
89 (let ((evaled (unparse-tree-il (peval code))))
92 (_ (pk 'peval-mismatch)
93 ((@ (ice-9 pretty-print) pretty-print)
96 ((@ (ice-9 pretty-print) pretty-print)
99 ((@ (ice-9 pretty-print) pretty-print)
105 (with-test-prefix "tree-il->scheme"
106 (pass-if-tree-il->scheme
107 (case-lambda ((a) a) ((b c) (list b c)))
108 (case-lambda ((,a) ,a1) ((,b ,c) (list ,b1 ,c1)))
109 (and (eq? a a1) (eq? b b1) (eq? c c1))))
111 (with-test-prefix "void"
112 (assert-tree-il->glil
114 (program () (std-prelude 0 0 #f) (label _) (void) (call return 1)))
115 (assert-tree-il->glil
116 (begin (void) (const 1))
117 (program () (std-prelude 0 0 #f) (label _) (const 1) (call return 1)))
118 (assert-tree-il->glil
119 (apply (primitive +) (void) (const 1))
120 (program () (std-prelude 0 0 #f) (label _) (void) (call add1 1) (call return 1))))
122 (with-test-prefix "application"
123 (assert-tree-il->glil
124 (apply (toplevel foo) (const 1))
125 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (const 1) (call tail-call 1)))
126 (assert-tree-il->glil
127 (begin (apply (toplevel foo) (const 1)) (void))
128 (program () (std-prelude 0 0 #f) (label _) (call new-frame 0) (toplevel ref foo) (const 1) (mv-call 1 ,l1)
129 (call drop 1) (branch br ,l2)
130 (label ,l3) (mv-bind 0 #f)
132 (void) (call return 1))
133 (and (eq? l1 l3) (eq? l2 l4)))
134 (assert-tree-il->glil
135 (apply (toplevel foo) (apply (toplevel bar)))
136 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (call new-frame 0) (toplevel ref bar) (call call 0)
137 (call tail-call 1))))
139 (with-test-prefix "conditional"
140 (assert-tree-il->glil
141 (if (toplevel foo) (const 1) (const 2))
142 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (branch br-if-not ,l1)
143 (const 1) (call return 1)
144 (label ,l2) (const 2) (call return 1))
147 (assert-tree-il->glil without-partial-evaluation
148 (begin (if (toplevel foo) (const 1) (const 2)) (const #f))
149 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (branch br-if-not ,l1) (branch br ,l2)
150 (label ,l3) (label ,l4) (const #f) (call return 1))
151 (eq? l1 l3) (eq? l2 l4))
153 (assert-tree-il->glil
154 (apply (primitive null?) (if (toplevel foo) (const 1) (const 2)))
155 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (branch br-if-not ,l1)
156 (const 1) (branch br ,l2)
157 (label ,l3) (const 2) (label ,l4)
158 (call null? 1) (call return 1))
159 (eq? l1 l3) (eq? l2 l4)))
161 (with-test-prefix "primitive-ref"
162 (assert-tree-il->glil
164 (program () (std-prelude 0 0 #f) (label _) (toplevel ref +) (call return 1)))
166 (assert-tree-il->glil
167 (begin (primitive +) (const #f))
168 (program () (std-prelude 0 0 #f) (label _) (const #f) (call return 1)))
170 (assert-tree-il->glil
171 (apply (primitive null?) (primitive +))
172 (program () (std-prelude 0 0 #f) (label _) (toplevel ref +) (call null? 1)
175 (with-test-prefix "lexical refs"
176 (assert-tree-il->glil without-partial-evaluation
177 (let (x) (y) ((const 1)) (lexical x y))
178 (program () (std-prelude 0 1 #f) (label _)
179 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
180 (lexical #t #f ref 0) (call return 1)
183 (assert-tree-il->glil without-partial-evaluation
184 (let (x) (y) ((const 1)) (begin (lexical x y) (const #f)))
185 (program () (std-prelude 0 1 #f) (label _)
186 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
187 (const #f) (call return 1)
190 (assert-tree-il->glil without-partial-evaluation
191 (let (x) (y) ((const 1)) (apply (primitive null?) (lexical x y)))
192 (program () (std-prelude 0 1 #f) (label _)
193 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
194 (lexical #t #f ref 0) (call null? 1) (call return 1)
197 (with-test-prefix "lexical sets"
198 (assert-tree-il->glil
199 ;; unreferenced sets may be optimized away -- make sure they are ref'd
200 (let (x) (y) ((const 1))
201 (set! (lexical x y) (apply (primitive 1+) (lexical x y))))
202 (program () (std-prelude 0 1 #f) (label _)
203 (const 1) (bind (x #t 0)) (lexical #t #t box 0)
204 (lexical #t #t ref 0) (call add1 1) (lexical #t #t set 0)
205 (void) (call return 1)
208 (assert-tree-il->glil
209 (let (x) (y) ((const 1))
210 (begin (set! (lexical x y) (apply (primitive 1+) (lexical x y)))
212 (program () (std-prelude 0 1 #f) (label _)
213 (const 1) (bind (x #t 0)) (lexical #t #t box 0)
214 (lexical #t #t ref 0) (call add1 1) (lexical #t #t set 0)
215 (lexical #t #t ref 0) (call return 1)
218 (assert-tree-il->glil
219 (let (x) (y) ((const 1))
220 (apply (primitive null?)
221 (set! (lexical x y) (apply (primitive 1+) (lexical x y)))))
222 (program () (std-prelude 0 1 #f) (label _)
223 (const 1) (bind (x #t 0)) (lexical #t #t box 0)
224 (lexical #t #t ref 0) (call add1 1) (lexical #t #t set 0) (void)
225 (call null? 1) (call return 1)
228 (with-test-prefix "module refs"
229 (assert-tree-il->glil
231 (program () (std-prelude 0 0 #f) (label _)
232 (module public ref (foo) bar)
235 (assert-tree-il->glil
236 (begin (@ (foo) bar) (const #f))
237 (program () (std-prelude 0 0 #f) (label _)
238 (module public ref (foo) bar) (call drop 1)
239 (const #f) (call return 1)))
241 (assert-tree-il->glil
242 (apply (primitive null?) (@ (foo) bar))
243 (program () (std-prelude 0 0 #f) (label _)
244 (module public ref (foo) bar)
245 (call null? 1) (call return 1)))
247 (assert-tree-il->glil
249 (program () (std-prelude 0 0 #f) (label _)
250 (module private ref (foo) bar)
253 (assert-tree-il->glil
254 (begin (@@ (foo) bar) (const #f))
255 (program () (std-prelude 0 0 #f) (label _)
256 (module private ref (foo) bar) (call drop 1)
257 (const #f) (call return 1)))
259 (assert-tree-il->glil
260 (apply (primitive null?) (@@ (foo) bar))
261 (program () (std-prelude 0 0 #f) (label _)
262 (module private ref (foo) bar)
263 (call null? 1) (call return 1))))
265 (with-test-prefix "module sets"
266 (assert-tree-il->glil
267 (set! (@ (foo) bar) (const 2))
268 (program () (std-prelude 0 0 #f) (label _)
269 (const 2) (module public set (foo) bar)
270 (void) (call return 1)))
272 (assert-tree-il->glil
273 (begin (set! (@ (foo) bar) (const 2)) (const #f))
274 (program () (std-prelude 0 0 #f) (label _)
275 (const 2) (module public set (foo) bar)
276 (const #f) (call return 1)))
278 (assert-tree-il->glil
279 (apply (primitive null?) (set! (@ (foo) bar) (const 2)))
280 (program () (std-prelude 0 0 #f) (label _)
281 (const 2) (module public set (foo) bar)
282 (void) (call null? 1) (call return 1)))
284 (assert-tree-il->glil
285 (set! (@@ (foo) bar) (const 2))
286 (program () (std-prelude 0 0 #f) (label _)
287 (const 2) (module private set (foo) bar)
288 (void) (call return 1)))
290 (assert-tree-il->glil
291 (begin (set! (@@ (foo) bar) (const 2)) (const #f))
292 (program () (std-prelude 0 0 #f) (label _)
293 (const 2) (module private set (foo) bar)
294 (const #f) (call return 1)))
296 (assert-tree-il->glil
297 (apply (primitive null?) (set! (@@ (foo) bar) (const 2)))
298 (program () (std-prelude 0 0 #f) (label _)
299 (const 2) (module private set (foo) bar)
300 (void) (call null? 1) (call return 1))))
302 (with-test-prefix "toplevel refs"
303 (assert-tree-il->glil
305 (program () (std-prelude 0 0 #f) (label _)
309 (assert-tree-il->glil without-partial-evaluation
310 (begin (toplevel bar) (const #f))
311 (program () (std-prelude 0 0 #f) (label _)
312 (toplevel ref bar) (call drop 1)
313 (const #f) (call return 1)))
315 (assert-tree-il->glil
316 (apply (primitive null?) (toplevel bar))
317 (program () (std-prelude 0 0 #f) (label _)
319 (call null? 1) (call return 1))))
321 (with-test-prefix "toplevel sets"
322 (assert-tree-il->glil
323 (set! (toplevel bar) (const 2))
324 (program () (std-prelude 0 0 #f) (label _)
325 (const 2) (toplevel set bar)
326 (void) (call return 1)))
328 (assert-tree-il->glil
329 (begin (set! (toplevel bar) (const 2)) (const #f))
330 (program () (std-prelude 0 0 #f) (label _)
331 (const 2) (toplevel set bar)
332 (const #f) (call return 1)))
334 (assert-tree-il->glil
335 (apply (primitive null?) (set! (toplevel bar) (const 2)))
336 (program () (std-prelude 0 0 #f) (label _)
337 (const 2) (toplevel set bar)
338 (void) (call null? 1) (call return 1))))
340 (with-test-prefix "toplevel defines"
341 (assert-tree-il->glil
342 (define bar (const 2))
343 (program () (std-prelude 0 0 #f) (label _)
344 (const 2) (toplevel define bar)
345 (void) (call return 1)))
347 (assert-tree-il->glil
348 (begin (define bar (const 2)) (const #f))
349 (program () (std-prelude 0 0 #f) (label _)
350 (const 2) (toplevel define bar)
351 (const #f) (call return 1)))
353 (assert-tree-il->glil
354 (apply (primitive null?) (define bar (const 2)))
355 (program () (std-prelude 0 0 #f) (label _)
356 (const 2) (toplevel define bar)
357 (void) (call null? 1) (call return 1))))
359 (with-test-prefix "constants"
360 (assert-tree-il->glil
362 (program () (std-prelude 0 0 #f) (label _)
363 (const 2) (call return 1)))
365 (assert-tree-il->glil
366 (begin (const 2) (const #f))
367 (program () (std-prelude 0 0 #f) (label _)
368 (const #f) (call return 1)))
370 (assert-tree-il->glil
371 ;; This gets simplified by `peval'.
372 (apply (primitive null?) (const 2))
373 (program () (std-prelude 0 0 #f) (label _)
374 (const #f) (call return 1))))
376 (with-test-prefix "letrec"
377 ;; simple bindings -> let
378 (assert-tree-il->glil without-partial-evaluation
379 (letrec (x y) (x1 y1) ((const 10) (const 20))
380 (apply (toplevel foo) (lexical x x1) (lexical y y1)))
381 (program () (std-prelude 0 2 #f) (label _)
382 (const 10) (const 20)
383 (bind (x #f 0) (y #f 1))
384 (lexical #t #f set 1) (lexical #t #f set 0)
386 (lexical #t #f ref 0) (lexical #t #f ref 1)
390 ;; complex bindings -> box and set! within let
391 (assert-tree-il->glil without-partial-evaluation
392 (letrec (x y) (x1 y1) ((apply (toplevel foo)) (apply (toplevel bar)))
393 (apply (primitive +) (lexical x x1) (lexical y y1)))
394 (program () (std-prelude 0 4 #f) (label _)
395 (void) (void) ;; what are these?
396 (bind (x #t 0) (y #t 1))
397 (lexical #t #t box 1) (lexical #t #t box 0)
398 (call new-frame 0) (toplevel ref foo) (call call 0)
399 (call new-frame 0) (toplevel ref bar) (call call 0)
400 (bind (x #f 2) (y #f 3)) (lexical #t #f set 3) (lexical #t #f set 2)
401 (lexical #t #f ref 2) (lexical #t #t set 0)
402 (lexical #t #f ref 3) (lexical #t #t set 1) (unbind)
403 (lexical #t #t ref 0) (lexical #t #t ref 1)
404 (call add 2) (call return 1) (unbind)))
406 ;; complex bindings in letrec* -> box and set! in order
407 (assert-tree-il->glil without-partial-evaluation
408 (letrec* (x y) (x1 y1) ((apply (toplevel foo)) (apply (toplevel bar)))
409 (apply (primitive +) (lexical x x1) (lexical y y1)))
410 (program () (std-prelude 0 2 #f) (label _)
411 (void) (void) ;; what are these?
412 (bind (x #t 0) (y #t 1))
413 (lexical #t #t box 1) (lexical #t #t box 0)
414 (call new-frame 0) (toplevel ref foo) (call call 0)
415 (lexical #t #t set 0)
416 (call new-frame 0) (toplevel ref bar) (call call 0)
417 (lexical #t #t set 1)
418 (lexical #t #t ref 0)
419 (lexical #t #t ref 1)
420 (call add 2) (call return 1) (unbind)))
422 ;; simple bindings in letrec* -> equivalent to letrec
423 (assert-tree-il->glil without-partial-evaluation
424 (letrec* (x y) (xx yy) ((const 1) (const 2))
426 (program () (std-prelude 0 1 #f) (label _)
428 (bind (y #f 0)) ;; X is removed, and Y is unboxed
429 (lexical #t #f set 0)
430 (lexical #t #f ref 0)
431 (call return 1) (unbind))))
433 (with-test-prefix "lambda"
434 (assert-tree-il->glil
436 (lambda-case (((x) #f #f #f () (y)) (const 2)) #f))
437 (program () (std-prelude 0 0 #f) (label _)
438 (program () (std-prelude 1 1 #f)
439 (bind (x #f 0)) (label _)
440 (const 2) (call return 1) (unbind))
443 (assert-tree-il->glil
445 (lambda-case (((x y) #f #f #f () (x1 y1))
448 (program () (std-prelude 0 0 #f) (label _)
449 (program () (std-prelude 2 2 #f)
450 (bind (x #f 0) (y #f 1)) (label _)
451 (const 2) (call return 1)
455 (assert-tree-il->glil
457 (lambda-case ((() #f x #f () (y)) (const 2))
459 (program () (std-prelude 0 0 #f) (label _)
460 (program () (opt-prelude 0 0 0 1 #f)
461 (bind (x #f 0)) (label _)
462 (const 2) (call return 1)
466 (assert-tree-il->glil
468 (lambda-case (((x) #f x1 #f () (y y1)) (const 2))
470 (program () (std-prelude 0 0 #f) (label _)
471 (program () (opt-prelude 1 0 1 2 #f)
472 (bind (x #f 0) (x1 #f 1)) (label _)
473 (const 2) (call return 1)
477 (assert-tree-il->glil
479 (lambda-case (((x) #f x1 #f () (y y1)) (lexical x y))
481 (program () (std-prelude 0 0 #f) (label _)
482 (program () (opt-prelude 1 0 1 2 #f)
483 (bind (x #f 0) (x1 #f 1)) (label _)
484 (lexical #t #f ref 0) (call return 1)
488 (assert-tree-il->glil
490 (lambda-case (((x) #f x1 #f () (y y1)) (lexical x1 y1))
492 (program () (std-prelude 0 0 #f) (label _)
493 (program () (opt-prelude 1 0 1 2 #f)
494 (bind (x #f 0) (x1 #f 1)) (label _)
495 (lexical #t #f ref 1) (call return 1)
499 (assert-tree-il->glil
501 (lambda-case (((x) #f #f #f () (x1))
503 (lambda-case (((y) #f #f #f () (y1))
507 (program () (std-prelude 0 0 #f) (label _)
508 (program () (std-prelude 1 1 #f)
509 (bind (x #f 0)) (label _)
510 (program () (std-prelude 1 1 #f)
511 (bind (y #f 0)) (label _)
512 (lexical #f #f ref 0) (call return 1)
514 (lexical #t #f ref 0)
515 (call make-closure 1)
520 (with-test-prefix "sequence"
521 (assert-tree-il->glil
522 (begin (begin (const 2) (const #f)) (const #t))
523 (program () (std-prelude 0 0 #f) (label _)
524 (const #t) (call return 1)))
526 (assert-tree-il->glil
527 ;; This gets simplified by `peval'.
528 (apply (primitive null?) (begin (const #f) (const 2)))
529 (program () (std-prelude 0 0 #f) (label _)
530 (const #f) (call return 1))))
532 (with-test-prefix "values"
533 (assert-tree-il->glil
534 (apply (primitive values)
535 (apply (primitive values) (const 1) (const 2)))
536 (program () (std-prelude 0 0 #f) (label _)
537 (const 1) (call return 1)))
539 (assert-tree-il->glil
540 (apply (primitive values)
541 (apply (primitive values) (const 1) (const 2))
543 (program () (std-prelude 0 0 #f) (label _)
544 (const 1) (const 3) (call return/values 2)))
546 (assert-tree-il->glil
548 (apply (primitive values) (const 1) (const 2)))
549 (program () (std-prelude 0 0 #f) (label _)
550 (const 1) (call return 1))))
552 ;; FIXME: binding info for or-hacked locals might bork the disassembler,
553 ;; and could be tightened in any case
554 (with-test-prefix "the or hack"
555 (assert-tree-il->glil without-partial-evaluation
556 (let (x) (y) ((const 1))
559 (let (a) (b) ((const 2))
561 (program () (std-prelude 0 1 #f) (label _)
562 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
563 (lexical #t #f ref 0) (branch br-if-not ,l1)
564 (lexical #t #f ref 0) (call return 1)
566 (const 2) (bind (a #f 0)) (lexical #t #f set 0)
567 (lexical #t #f ref 0) (call return 1)
572 ;; second bound var is unreferenced
573 (assert-tree-il->glil without-partial-evaluation
574 (let (x) (y) ((const 1))
577 (let (a) (b) ((const 2))
579 (program () (std-prelude 0 1 #f) (label _)
580 (const 1) (bind (x #f 0)) (lexical #t #f set 0)
581 (lexical #t #f ref 0) (branch br-if-not ,l1)
582 (lexical #t #f ref 0) (call return 1)
584 (lexical #t #f ref 0) (call return 1)
588 (with-test-prefix "apply"
589 (assert-tree-il->glil
590 (apply (primitive @apply) (toplevel foo) (toplevel bar))
591 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (toplevel ref bar) (call tail-apply 2)))
592 (assert-tree-il->glil
593 (begin (apply (primitive @apply) (toplevel foo) (toplevel bar)) (void))
594 (program () (std-prelude 0 0 #f) (label _)
595 (call new-frame 0) (toplevel ref apply) (toplevel ref foo) (toplevel ref bar) (mv-call 2 ,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) (apply (toplevel @apply) (toplevel bar) (toplevel baz)))
602 (program () (std-prelude 0 0 #f) (label _)
604 (call new-frame 0) (toplevel ref bar) (toplevel ref baz) (call apply 2)
605 (call tail-call 1))))
607 (with-test-prefix "call/cc"
608 (assert-tree-il->glil
609 (apply (primitive @call-with-current-continuation) (toplevel foo))
610 (program () (std-prelude 0 0 #f) (label _) (toplevel ref foo) (call tail-call/cc 1)))
611 (assert-tree-il->glil
612 (begin (apply (primitive @call-with-current-continuation) (toplevel foo)) (void))
613 (program () (std-prelude 0 0 #f) (label _)
614 (call new-frame 0) (toplevel ref call-with-current-continuation) (toplevel ref foo) (mv-call 1 ,l1)
615 (call drop 1) (branch br ,l2) (label ,l3) (mv-bind 0 #f)
617 (void) (call return 1))
618 (and (eq? l1 l3) (eq? l2 l4)))
619 (assert-tree-il->glil
620 (apply (toplevel foo)
621 (apply (toplevel @call-with-current-continuation) (toplevel bar)))
622 (program () (std-prelude 0 0 #f) (label _)
624 (toplevel ref bar) (call call/cc 1)
625 (call tail-call 1))))
628 (with-test-prefix "partial evaluation"
631 ;; First order, primitive.
632 (let ((x 1) (y 2)) (+ x y))
636 ;; First order, thunk.
638 (let ((f (lambda () (+ x y))))
642 (pass-if-peval resolve-primitives
643 ;; First order, let-values (requires primitive expansion for
644 ;; `call-with-values'.)
647 (lambda () (if (zero? x) (values 1 2) (values 3 4)))
653 ;; First order, coalesced.
654 (cons 0 (cons 1 (cons 2 (list 3 4 5))))
655 (const (0 1 2 3 4 5)))
658 ;; First order, coalesced, mutability preserved.
660 (cons 0 (cons 1 (cons 2 (list 3 4 5)))))
662 ;; This must not be a constant.
663 (apply (primitive list)
664 (const 0) (const 1) (const 2) (const 3) (const 4) (const 5))))
667 ;; First order, mutability preserved.
669 (let loop ((i 3) (r '()))
672 (loop (1- i) (cons (cons i i) r)))))
674 (apply (primitive list)
675 (apply (primitive cons) (const 1) (const 1))
676 (apply (primitive cons) (const 2) (const 2))
677 (apply (primitive cons) (const 3) (const 3)))))
680 ;; Mutability preserved.
682 ((lambda (x y z) (list x y z)) 1 2 3))
684 (apply (primitive list) (const 1) (const 2) (const 3))))
687 ;; Don't propagate effect-free expressions that operate on mutable
693 (let (x) (_) ((apply (primitive list) (const 1)))
694 (let (y) (_) ((apply (primitive car) (lexical x _)))
696 (apply (toplevel set-car!) (lexical x _) (const 0))
700 ;; Don't propagate effect-free expressions that operate on objects we
705 (let (y) (_) ((apply (primitive car) (toplevel x)))
707 (apply (toplevel set-car!) (toplevel x) (const 0))
711 ;; First order, evaluated.
717 (loop (1- i) (cons i r)))))
718 (define one (const 1)))
721 ;; First order, aliased primitive.
722 (let* ((x *) (y (x 1 2))) y)
726 ;; First order, shadowed primitive.
728 (define (+ x y) (pk x y))
734 (((x y) #f #f #f () (_ _))
735 (apply (toplevel pk) (lexical x _) (lexical y _))))))
736 (apply (toplevel +) (const 1) (const 2))))
739 ;; First-order, effects preserved.
744 (apply (toplevel do-something!))
748 ;; First order, residual bindings removed.
751 (apply (primitive *) (const 5) (toplevel z)))
754 ;; First order, with lambda.
756 (define (bar z) (* z z))
761 (((x) #f #f #f () (_))
762 (letrec* (bar) (_) ((lambda (_) . _))
763 (apply (primitive +) (lexical x _) (const 9))))))))
766 ;; First order, with lambda inlined & specialized twice.
767 (let ((f (lambda (x y)
773 (let (f) (_) ((lambda (_)
775 (((x y) #f #f #f () (_ _))
784 (apply (primitive +) ; (f 2 3)
789 (apply (lexical f _) ; (f something 2)
790 ;; This arg is not const, so the lambda does not
791 ;; fold. We will fix this in the future when we
792 ;; inline lambda to `let'. That will offer the
793 ;; possibility of creating a lexical binding for
794 ;; `something', to preserve the order of effects.
799 ;; First order, with lambda inlined & specialized 3 times.
800 (let ((f (lambda (x y) (if (> x 0) y x))))
809 (((x y) #f #f #f () (_ _))
810 (if (apply (primitive >) (lexical x _) (const 0))
814 (const -1) ; (f -1 0)
816 (apply (lexical f _) ; (f -1 y)
817 (const -1) (toplevel y))
818 (apply (lexical f _) ; (f 2 y)
819 (const 2) (toplevel y))
820 (apply (lexical f _) ; (f z y)
821 (toplevel z) (toplevel y)))))
824 ;; First order, conditional.
832 (((x) #f #f #f () (_))
833 (apply (toplevel display) (lexical x _))))))
836 ;; First order, recursive procedure.
837 (letrec ((fibo (lambda (n)
846 ;; Don't propagate toplevel references, as intervening expressions
847 ;; could alter their bindings.
851 (let (x) (_) ((toplevel top))
853 (apply (toplevel foo))
859 (f (* (car x) (cadr x))))
866 ;; Higher order with optional argument (default value).
867 ((lambda* (f x #:optional (y 0))
868 (+ y (f (* (car x) (cadr x)))))
875 ;; Higher order with optional argument (caller-supplied value).
876 ((lambda* (f x #:optional (y 0))
877 (+ y (f (* (car x) (cadr x)))))
886 ((lambda (f) (f x)) (lambda (x) x))
889 (((x) #f #f #f () (_))
895 ;; <https://lists.gnu.org/archive/html/bug-guile/2011-09/msg00019.html>.
896 (let ((fold (lambda (f g) (f (g top)))))
897 (fold 1+ (lambda (x) x)))
899 (apply (primitive 1+)
902 (((x) #f #f #f () (_))
907 ;; Procedure not inlined when residual code contains recursive calls.
908 ;; <http://debbugs.gnu.org/9542>
909 (letrec ((fold (lambda (f x3 b null? car cdr)
912 (f (car x3) (fold f (cdr x3) b null? car cdr))))))
913 (fold * x 1 zero? (lambda (x1) x1) (lambda (x2) (- x2 1))))
914 (letrec (fold) (_) (_)
915 (apply (lexical fold _)
922 (((x1) #f #f #f () (_))
926 (((x2) #f #f #f () (_))
927 (apply (primitive -) (lexical x2 _) (const 1))))))))
929 (pass-if "inlined lambdas are alpha-renamed"
930 ;; In this example, `make-adder' is inlined more than once; thus,
931 ;; they should use different gensyms for their arguments, because
932 ;; the various optimization passes assume uniquely-named variables.
935 ;; <https://lists.gnu.org/archive/html/bug-guile/2011-09/msg00019.html> and
936 ;; <https://lists.gnu.org/archive/html/bug-guile/2011-09/msg00029.html>.
937 (pmatch (unparse-tree-il
940 (lambda (x) (lambda (y) (+ x y)))))
941 (cons (make-adder 1) (make-adder 2)))
943 ((let (make-adder) (_) (_)
944 (apply (primitive cons)
947 (((y) #f #f #f () (,gensym1))
950 (lexical y ,ref1)))))
953 (((y) #f #f #f () (,gensym2))
956 (lexical y ,ref2)))))))
957 (and (eq? gensym1 ref1)
959 (not (eq? gensym1 gensym2))))
963 ;; Higher order, mutually recursive procedures.
964 (letrec ((even? (lambda (x)
968 (not (even? (- x 1))))))
969 (and (even? 4) (odd? 7)))
973 ;; Below are cases where constant propagation should bail out.
977 ;; Non-constant lexical is not propagated.
978 (let ((v (make-vector 6 #f)))
980 (vector-set! v n n)))
982 ((apply (toplevel make-vector) (const 6) (const #f)))
985 (((n) #f #f #f () (_))
986 (apply (toplevel vector-set!)
987 (lexical v _) (lexical n _) (lexical n _)))))))
990 ;; Mutable lexical is not propagated.
991 (let ((v (vector 1 2 3)))
995 ((apply (primitive vector) (const 1) (const 2) (const 3)))
1002 ;; Lexical that is not provably pure is not inlined nor propagated.
1003 (let* ((x (if (> p q) (frob!) (display 'chbouib)))
1006 (let (x) (_) ((if (apply (primitive >) (toplevel p) (toplevel q))
1007 (apply (toplevel frob!))
1008 (apply (toplevel display) (const chbouib))))
1009 (apply (primitive +) (lexical x _) (lexical x _)
1010 (apply (primitive *) (lexical x _) (const 2)))))
1013 ;; Non-constant arguments not propagated to lambdas.
1023 (((x y z) #f #f #f () (_ _ _))
1025 (apply (toplevel vector-set!)
1026 (lexical x _) (const 0) (const 0))
1027 (apply (toplevel set-car!)
1028 (lexical y _) (const 0))
1029 (apply (toplevel set-cdr!)
1030 (lexical z _) (const ()))))))
1031 (apply (primitive vector) (const 1) (const 2) (const 3))
1032 (apply (toplevel make-list) (const 10))
1033 (apply (primitive list) (const 1) (const 2) (const 3))))
1036 ;; Procedure only called with dynamic args is not inlined.
1037 (let ((foo top-foo) (bar top-bar))
1038 (let* ((g (lambda (x y) (+ x y)))
1039 (f (lambda (g x) (g x x))))
1040 (+ (f g foo) (f g bar))))
1041 (let (foo bar) (_ _) ((toplevel top-foo) (toplevel top-bar))
1045 (((x y) #f #f #f () (_ _))
1046 (apply (primitive +) (lexical x _) (lexical y _))))))
1050 (((g x) #f #f #f () (_ _))
1051 (apply (lexical g _) (lexical x _) (lexical x _))))))
1052 (apply (primitive +)
1053 (apply (lexical g _) (lexical foo _) (lexical foo _))
1054 (apply (lexical g _) (lexical bar _) (lexical bar _)))))))
1057 ;; Fresh objects are not turned into constants.
1062 (let (x) (_) ((apply (primitive list) (const 1) (const 2) (const 3)))
1063 (let (y) (_) ((apply (primitive cons) (const 0) (lexical x _)))
1067 ;; Bindings mutated.
1071 (let (x) (_) ((const 2))
1073 (set! (lexical x _) (const 3))
1077 ;; Bindings mutated.
1082 (frob f) ; may mutate `x'
1084 (letrec (x f) (_ _) ((const 0) _)
1086 (apply (toplevel frob) (lexical f _))
1090 ;; Bindings mutated.
1091 (letrec ((f (lambda (x)
1092 (set! f (lambda (_) x))
1098 ;; Bindings possibly mutated.
1099 (let ((x (make-foo)))
1100 (frob! x) ; may mutate `x'
1102 (let (x) (_) ((apply (toplevel make-foo)))
1104 (apply (toplevel frob!) (lexical x _))
1108 ;; Inlining stops at recursive calls with dynamic arguments.
1110 (if (< x 0) x (loop (1- x))))
1111 (letrec (loop) (_) ((lambda (_)
1113 (((x) #f #f #f () (_))
1115 (apply (lexical loop _)
1116 (apply (primitive 1-)
1117 (lexical x _))))))))
1118 (apply (lexical loop _) (toplevel x))))
1121 ;; Recursion on the 2nd argument is fully evaluated.
1123 (let loop ((x x) (y 10))
1127 (let (x) (_) ((apply (toplevel top)))
1128 (letrec (loop) (_) (_)
1129 (apply (toplevel foo) (lexical x _) (const 0)))))
1132 ;; Inlining aborted when residual code contains recursive calls.
1133 ;; <http://debbugs.gnu.org/9542>
1134 (let loop ((x x) (y 0))
1136 (loop (1+ x) (1+ y))
1137 (if (< x 0) x (loop (1- x)))))
1138 (letrec (loop) (_) ((lambda (_)
1140 (((x y) #f #f #f () (_ _))
1141 (if (apply (primitive >)
1142 (lexical y _) (const 0))
1144 (apply (lexical loop _) (toplevel x) (const 0))))
1147 ;; Infinite recursion: `peval' gives up and leaves it as is.
1148 (letrec ((f (lambda (x) (g (1- x))))
1149 (g (lambda (x) (h (1+ x))))
1150 (h (lambda (x) (f x))))
1155 (with-test-prefix "tree-il-fold"
1157 (pass-if "empty tree"
1158 (let ((leaf? #f) (up? #f) (down? #f) (mark (list 'mark)))
1160 (tree-il-fold (lambda (x y) (set! leaf? #t) y)
1161 (lambda (x y) (set! down? #t) y)
1162 (lambda (x y) (set! up? #t) y)
1169 (pass-if "lambda and application"
1170 (let* ((leaves '()) (ups '()) (downs '())
1171 (result (tree-il-fold (lambda (x y)
1172 (set! leaves (cons x leaves))
1175 (set! downs (cons x downs))
1178 (set! ups (cons x ups))
1184 (((x y) #f #f #f () (x1 y1))
1189 (and (equal? (map strip-source leaves)
1190 (list (make-lexical-ref #f 'y 'y1)
1191 (make-lexical-ref #f 'x 'x1)
1192 (make-toplevel-ref #f '+)))
1193 (= (length downs) 3)
1194 (equal? (reverse (map strip-source ups))
1195 (map strip-source downs))))))
1202 ;; Make sure we get English messages.
1203 (setlocale LC_ALL "C")
1205 (define (call-with-warnings thunk)
1206 (let ((port (open-output-string)))
1207 (with-fluids ((*current-warning-port* port)
1208 (*current-warning-prefix* ""))
1210 (let ((warnings (get-output-string port)))
1211 (string-tokenize warnings
1212 (char-set-complement (char-set #\newline))))))
1214 (define %opts-w-unused
1215 '(#:warnings (unused-variable)))
1217 (define %opts-w-unused-toplevel
1218 '(#:warnings (unused-toplevel)))
1220 (define %opts-w-unbound
1221 '(#:warnings (unbound-variable)))
1223 (define %opts-w-arity
1224 '(#:warnings (arity-mismatch)))
1226 (define %opts-w-format
1227 '(#:warnings (format)))
1230 (with-test-prefix "warnings"
1232 (pass-if "unknown warning type"
1233 (let ((w (call-with-warnings
1235 (compile #t #:opts '(#:warnings (does-not-exist)))))))
1236 (and (= (length w) 1)
1237 (number? (string-contains (car w) "unknown warning")))))
1239 (with-test-prefix "unused-variable"
1242 (null? (call-with-warnings
1244 (compile '(lambda (x y) (+ x y))
1245 #:opts %opts-w-unused)))))
1247 (pass-if "let/unused"
1248 (let ((w (call-with-warnings
1250 (compile '(lambda (x)
1253 #:opts %opts-w-unused)))))
1254 (and (= (length w) 1)
1255 (number? (string-contains (car w) "unused variable `y'")))))
1257 (pass-if "shadowed variable"
1258 (let ((w (call-with-warnings
1260 (compile '(lambda (x)
1264 #:opts %opts-w-unused)))))
1265 (and (= (length w) 1)
1266 (number? (string-contains (car w) "unused variable `y'")))))
1269 (null? (call-with-warnings
1271 (compile '(lambda ()
1272 (letrec ((x (lambda () (y)))
1273 (y (lambda () (x))))
1275 #:opts %opts-w-unused)))))
1277 (pass-if "unused argument"
1278 ;; Unused arguments should not be reported.
1279 (null? (call-with-warnings
1281 (compile '(lambda (x y z) #t)
1282 #:opts %opts-w-unused)))))
1284 (pass-if "special variable names"
1285 (null? (call-with-warnings
1287 (compile '(lambda ()
1288 (let ((_ 'underscore)
1289 (#{gensym name}# 'ignore-me))
1292 #:opts %opts-w-unused))))))
1294 (with-test-prefix "unused-toplevel"
1296 (pass-if "used after definition"
1297 (null? (call-with-warnings
1299 (let ((in (open-input-string
1300 "(define foo 2) foo")))
1301 (read-and-compile in
1303 #:opts %opts-w-unused-toplevel))))))
1305 (pass-if "used before definition"
1306 (null? (call-with-warnings
1308 (let ((in (open-input-string
1309 "(define (bar) foo) (define foo 2) (bar)")))
1310 (read-and-compile in
1312 #:opts %opts-w-unused-toplevel))))))
1314 (pass-if "unused but public"
1315 (let ((in (open-input-string
1316 "(define-module (test-suite tree-il x) #:export (bar))
1317 (define (bar) #t)")))
1318 (null? (call-with-warnings
1320 (read-and-compile in
1322 #:opts %opts-w-unused-toplevel))))))
1324 (pass-if "unused but public (more)"
1325 (let ((in (open-input-string
1326 "(define-module (test-suite tree-il x) #:export (bar))
1327 (define (bar) (baz))
1328 (define (baz) (foo))
1329 (define (foo) #t)")))
1330 (null? (call-with-warnings
1332 (read-and-compile in
1334 #:opts %opts-w-unused-toplevel))))))
1336 (pass-if "unused but define-public"
1337 (null? (call-with-warnings
1339 (compile '(define-public foo 2)
1341 #:opts %opts-w-unused-toplevel)))))
1343 (pass-if "used by macro"
1344 ;; FIXME: See comment about macros at `unused-toplevel-analysis'.
1347 (null? (call-with-warnings
1349 (let ((in (open-input-string
1350 "(define (bar) 'foo)
1352 (syntax-rules () ((_) (bar))))")))
1353 (read-and-compile in
1355 #:opts %opts-w-unused-toplevel))))))
1358 (let ((w (call-with-warnings
1360 (compile '(define foo 2)
1362 #:opts %opts-w-unused-toplevel)))))
1363 (and (= (length w) 1)
1364 (number? (string-contains (car w)
1365 (format #f "top-level variable `~A'"
1368 (pass-if "unused recursive"
1369 (let ((w (call-with-warnings
1371 (compile '(define (foo) (foo))
1373 #:opts %opts-w-unused-toplevel)))))
1374 (and (= (length w) 1)
1375 (number? (string-contains (car w)
1376 (format #f "top-level variable `~A'"
1379 (pass-if "unused mutually recursive"
1380 (let* ((in (open-input-string
1381 "(define (foo) (bar)) (define (bar) (foo))"))
1382 (w (call-with-warnings
1384 (read-and-compile in
1386 #:opts %opts-w-unused-toplevel)))))
1387 (and (= (length w) 2)
1388 (number? (string-contains (car w)
1389 (format #f "top-level variable `~A'"
1391 (number? (string-contains (cadr w)
1392 (format #f "top-level variable `~A'"
1395 (pass-if "special variable names"
1396 (null? (call-with-warnings
1398 (compile '(define #{gensym name}# 'ignore-me)
1400 #:opts %opts-w-unused-toplevel))))))
1402 (with-test-prefix "unbound variable"
1405 (null? (call-with-warnings
1407 (compile '+ #:opts %opts-w-unbound)))))
1411 (w (call-with-warnings
1415 #:opts %opts-w-unbound)))))
1416 (and (= (length w) 1)
1417 (number? (string-contains (car w)
1418 (format #f "unbound variable `~A'"
1423 (w (call-with-warnings
1425 (compile `(set! ,v 7)
1427 #:opts %opts-w-unbound)))))
1428 (and (= (length w) 1)
1429 (number? (string-contains (car w)
1430 (format #f "unbound variable `~A'"
1433 (pass-if "module-local top-level is visible"
1434 (let ((m (make-module))
1436 (beautify-user-module! m)
1437 (compile `(define ,v 123)
1438 #:env m #:opts %opts-w-unbound)
1439 (null? (call-with-warnings
1444 #:opts %opts-w-unbound))))))
1446 (pass-if "module-local top-level is visible after"
1447 (let ((m (make-module))
1449 (beautify-user-module! m)
1450 (null? (call-with-warnings
1452 (let ((in (open-input-string
1455 (define chbouib 5)")))
1456 (read-and-compile in
1458 #:opts %opts-w-unbound)))))))
1460 (pass-if "optional arguments are visible"
1461 (null? (call-with-warnings
1463 (compile '(lambda* (x #:optional y z) (list x y z))
1464 #:opts %opts-w-unbound
1467 (pass-if "keyword arguments are visible"
1468 (null? (call-with-warnings
1470 (compile '(lambda* (x #:key y z) (list x y z))
1471 #:opts %opts-w-unbound
1474 (pass-if "GOOPS definitions are visible"
1475 (let ((m (make-module))
1477 (beautify-user-module! m)
1478 (module-use! m (resolve-interface '(oop goops)))
1479 (null? (call-with-warnings
1481 (let ((in (open-input-string
1482 "(define-class <foo> ()
1483 (bar #:getter foo-bar))
1484 (define z (foo-bar (make <foo>)))")))
1485 (read-and-compile in
1487 #:opts %opts-w-unbound))))))))
1489 (with-test-prefix "arity mismatch"
1492 (null? (call-with-warnings
1494 (compile '(cons 'a 'b) #:opts %opts-w-arity)))))
1496 (pass-if "direct application"
1497 (let ((w (call-with-warnings
1499 (compile '((lambda (x y) (or x y)) 1 2 3 4 5)
1500 #:opts %opts-w-arity
1502 (and (= (length w) 1)
1503 (number? (string-contains (car w)
1504 "wrong number of arguments to")))))
1506 (let ((w (call-with-warnings
1508 (compile '(let ((f (lambda (x y) (+ x y))))
1510 #:opts %opts-w-arity
1512 (and (= (length w) 1)
1513 (number? (string-contains (car w)
1514 "wrong number of arguments to")))))
1517 (let ((w (call-with-warnings
1519 (compile '(cons 1 2 3 4)
1520 #:opts %opts-w-arity
1522 (and (= (length w) 1)
1523 (number? (string-contains (car w)
1524 "wrong number of arguments to")))))
1526 (pass-if "alias to global"
1527 (let ((w (call-with-warnings
1529 (compile '(let ((f cons)) (f 1 2 3 4))
1530 #:opts %opts-w-arity
1532 (and (= (length w) 1)
1533 (number? (string-contains (car w)
1534 "wrong number of arguments to")))))
1536 (pass-if "alias to lexical to global"
1537 (let ((w (call-with-warnings
1539 (compile '(let ((f number?))
1542 #:opts %opts-w-arity
1544 (and (= (length w) 1)
1545 (number? (string-contains (car w)
1546 "wrong number of arguments to")))))
1548 (pass-if "alias to lexical"
1549 (let ((w (call-with-warnings
1551 (compile '(let ((f (lambda (x y z) (+ x y z))))
1554 #:opts %opts-w-arity
1556 (and (= (length w) 1)
1557 (number? (string-contains (car w)
1558 "wrong number of arguments to")))))
1561 (let ((w (call-with-warnings
1563 (compile '(letrec ((odd? (lambda (x) (even? (1- x))))
1568 #:opts %opts-w-arity
1570 (and (= (length w) 1)
1571 (number? (string-contains (car w)
1572 "wrong number of arguments to")))))
1574 (pass-if "case-lambda"
1575 (null? (call-with-warnings
1577 (compile '(let ((f (case-lambda
1584 #:opts %opts-w-arity
1587 (pass-if "case-lambda with wrong number of arguments"
1588 (let ((w (call-with-warnings
1590 (compile '(let ((f (case-lambda
1594 #:opts %opts-w-arity
1596 (and (= (length w) 1)
1597 (number? (string-contains (car w)
1598 "wrong number of arguments to")))))
1600 (pass-if "case-lambda*"
1601 (null? (call-with-warnings
1603 (compile '(let ((f (case-lambda*
1604 ((x #:optional y) 1)
1606 ((x y #:key z) 3))))
1611 #:opts %opts-w-arity
1614 (pass-if "case-lambda* with wrong arguments"
1615 (let ((w (call-with-warnings
1617 (compile '(let ((f (case-lambda*
1618 ((x #:optional y) 1)
1620 ((x y #:key z) 3))))
1623 #:opts %opts-w-arity
1625 (and (= (length w) 2)
1626 (null? (filter (lambda (w)
1630 w "wrong number of arguments to"))))
1633 (pass-if "local toplevel-defines"
1634 (let ((w (call-with-warnings
1636 (let ((in (open-input-string "
1637 (define (g x) (f x))
1639 (read-and-compile in
1640 #:opts %opts-w-arity
1641 #:to 'assembly))))))
1642 (and (= (length w) 1)
1643 (number? (string-contains (car w)
1644 "wrong number of arguments to")))))
1646 (pass-if "global toplevel alias"
1647 (let ((w (call-with-warnings
1649 (let ((in (open-input-string "
1651 (define (g) (f))")))
1652 (read-and-compile in
1653 #:opts %opts-w-arity
1654 #:to 'assembly))))))
1655 (and (= (length w) 1)
1656 (number? (string-contains (car w)
1657 "wrong number of arguments to")))))
1659 (pass-if "local toplevel overrides global"
1660 (null? (call-with-warnings
1662 (let ((in (open-input-string "
1664 (define (foo x) (cons))")))
1665 (read-and-compile in
1666 #:opts %opts-w-arity
1667 #:to 'assembly))))))
1669 (pass-if "keyword not passed and quiet"
1670 (null? (call-with-warnings
1672 (compile '(let ((f (lambda* (x #:key y) y)))
1674 #:opts %opts-w-arity
1677 (pass-if "keyword passed and quiet"
1678 (null? (call-with-warnings
1680 (compile '(let ((f (lambda* (x #:key y) y)))
1682 #:opts %opts-w-arity
1685 (pass-if "keyword passed to global and quiet"
1686 (null? (call-with-warnings
1688 (let ((in (open-input-string "
1689 (use-modules (system base compile))
1690 (compile '(+ 2 3) #:env (current-module))")))
1691 (read-and-compile in
1692 #:opts %opts-w-arity
1693 #:to 'assembly))))))
1695 (pass-if "extra keyword"
1696 (let ((w (call-with-warnings
1698 (compile '(let ((f (lambda* (x #:key y) y)))
1700 #:opts %opts-w-arity
1702 (and (= (length w) 1)
1703 (number? (string-contains (car w)
1704 "wrong number of arguments to")))))
1706 (pass-if "extra keywords allowed"
1707 (null? (call-with-warnings
1709 (compile '(let ((f (lambda* (x #:key y #:allow-other-keys)
1712 #:opts %opts-w-arity
1713 #:to 'assembly))))))
1715 (with-test-prefix "format"
1717 (pass-if "quiet (no args)"
1718 (null? (call-with-warnings
1720 (compile '(format #t "hey!")
1721 #:opts %opts-w-format
1724 (pass-if "quiet (1 arg)"
1725 (null? (call-with-warnings
1727 (compile '(format #t "hey ~A!" "you")
1728 #:opts %opts-w-format
1731 (pass-if "quiet (2 args)"
1732 (null? (call-with-warnings
1734 (compile '(format #t "~A ~A!" "hello" "world")
1735 #:opts %opts-w-format
1738 (pass-if "wrong port arg"
1739 (let ((w (call-with-warnings
1741 (compile '(format 10 "foo")
1742 #:opts %opts-w-format
1744 (and (= (length w) 1)
1745 (number? (string-contains (car w)
1746 "wrong port argument")))))
1748 (pass-if "non-literal format string"
1749 (let ((w (call-with-warnings
1751 (compile '(format #f fmt)
1752 #:opts %opts-w-format
1754 (and (= (length w) 1)
1755 (number? (string-contains (car w)
1756 "non-literal format string")))))
1758 (pass-if "non-literal format string using gettext"
1759 (null? (call-with-warnings
1761 (compile '(format #t (_ "~A ~A!") "hello" "world")
1762 #:opts %opts-w-format
1765 (pass-if "wrong format string"
1766 (let ((w (call-with-warnings
1768 (compile '(format #f 'not-a-string)
1769 #:opts %opts-w-format
1771 (and (= (length w) 1)
1772 (number? (string-contains (car w)
1773 "wrong format string")))))
1775 (pass-if "wrong number of args"
1776 (let ((w (call-with-warnings
1778 (compile '(format "shbweeb")
1779 #:opts %opts-w-format
1781 (and (= (length w) 1)
1782 (number? (string-contains (car w)
1783 "wrong number of arguments")))))
1785 (pass-if "~%, ~~, ~&, ~t, ~_, and ~\\n"
1786 (null? (call-with-warnings
1788 (compile '(format some-port "~&~3_~~ ~\n~12they~%")
1789 #:opts %opts-w-format
1792 (pass-if "one missing argument"
1793 (let ((w (call-with-warnings
1795 (compile '(format some-port "foo ~A~%")
1796 #:opts %opts-w-format
1798 (and (= (length w) 1)
1799 (number? (string-contains (car w)
1800 "expected 1, got 0")))))
1802 (pass-if "one missing argument, gettext"
1803 (let ((w (call-with-warnings
1805 (compile '(format some-port (_ "foo ~A~%"))
1806 #:opts %opts-w-format
1808 (and (= (length w) 1)
1809 (number? (string-contains (car w)
1810 "expected 1, got 0")))))
1812 (pass-if "two missing arguments"
1813 (let ((w (call-with-warnings
1815 (compile '(format #f "foo ~10,2f and bar ~S~%")
1816 #:opts %opts-w-format
1818 (and (= (length w) 1)
1819 (number? (string-contains (car w)
1820 "expected 2, got 0")))))
1822 (pass-if "one given, one missing argument"
1823 (let ((w (call-with-warnings
1825 (compile '(format #t "foo ~A and ~S~%" hey)
1826 #:opts %opts-w-format
1828 (and (= (length w) 1)
1829 (number? (string-contains (car w)
1830 "expected 2, got 1")))))
1832 (pass-if "too many arguments"
1833 (let ((w (call-with-warnings
1835 (compile '(format #t "foo ~A~%" 1 2)
1836 #:opts %opts-w-format
1838 (and (= (length w) 1)
1839 (number? (string-contains (car w)
1840 "expected 1, got 2")))))
1842 (with-test-prefix "conditionals"
1844 (null? (call-with-warnings
1846 (compile '(format #f "~A ~[foo~;bar~;baz~;~] ~10,2f"
1848 #:opts %opts-w-format
1851 (pass-if "literals with selector"
1852 (let ((w (call-with-warnings
1854 (compile '(format #f "~2[foo~;bar~;baz~;~] ~A"
1856 #:opts %opts-w-format
1858 (and (= (length w) 1)
1859 (number? (string-contains (car w)
1860 "expected 1, got 2")))))
1862 (pass-if "escapes (exact count)"
1863 (let ((w (call-with-warnings
1865 (compile '(format #f "~[~a~;~a~]")
1866 #:opts %opts-w-format
1868 (and (= (length w) 1)
1869 (number? (string-contains (car w)
1870 "expected 2, got 0")))))
1872 (pass-if "escapes with selector"
1873 (let ((w (call-with-warnings
1875 (compile '(format #f "~1[chbouib~;~a~]")
1876 #:opts %opts-w-format
1878 (and (= (length w) 1)
1879 (number? (string-contains (car w)
1880 "expected 1, got 0")))))
1882 (pass-if "escapes, range"
1883 (let ((w (call-with-warnings
1885 (compile '(format #f "~[chbouib~;~a~;~2*~a~]")
1886 #:opts %opts-w-format
1888 (and (= (length w) 1)
1889 (number? (string-contains (car w)
1890 "expected 1 to 4, got 0")))))
1893 (let ((w (call-with-warnings
1895 (compile '(format #f "~@[temperature=~d~]")
1896 #:opts %opts-w-format
1898 (and (= (length w) 1)
1899 (number? (string-contains (car w)
1900 "expected 1, got 0")))))
1903 (let ((w (call-with-warnings
1905 (compile '(format #f "~:[~[hey~;~a~;~va~]~;~3*~]")
1906 #:opts %opts-w-format
1908 (and (= (length w) 1)
1909 (number? (string-contains (car w)
1910 "expected 2 to 4, got 0")))))
1912 (pass-if "unterminated"
1913 (let ((w (call-with-warnings
1915 (compile '(format #f "~[unterminated")
1916 #:opts %opts-w-format
1918 (and (= (length w) 1)
1919 (number? (string-contains (car w)
1920 "unterminated conditional")))))
1922 (pass-if "unexpected ~;"
1923 (let ((w (call-with-warnings
1925 (compile '(format #f "foo~;bar")
1926 #:opts %opts-w-format
1928 (and (= (length w) 1)
1929 (number? (string-contains (car w)
1932 (pass-if "unexpected ~]"
1933 (let ((w (call-with-warnings
1935 (compile '(format #f "foo~]")
1936 #:opts %opts-w-format
1938 (and (= (length w) 1)
1939 (number? (string-contains (car w)
1943 (null? (call-with-warnings
1945 (compile '(format #f "~A ~{~S~} ~A"
1946 'hello '("ladies" "and")
1948 #:opts %opts-w-format
1951 (pass-if "~{...~}, too many args"
1952 (let ((w (call-with-warnings
1954 (compile '(format #f "~{~S~}" 1 2 3)
1955 #:opts %opts-w-format
1957 (and (= (length w) 1)
1958 (number? (string-contains (car w)
1959 "expected 1, got 3")))))
1962 (null? (call-with-warnings
1964 (compile '(format #f "~@{~S~}" 1 2 3)
1965 #:opts %opts-w-format
1968 (pass-if "~@{...~}, too few args"
1969 (let ((w (call-with-warnings
1971 (compile '(format #f "~A ~@{~S~}")
1972 #:opts %opts-w-format
1974 (and (= (length w) 1)
1975 (number? (string-contains (car w)
1976 "expected at least 1, got 0")))))
1978 (pass-if "unterminated ~{...~}"
1979 (let ((w (call-with-warnings
1981 (compile '(format #f "~{")
1982 #:opts %opts-w-format
1984 (and (= (length w) 1)
1985 (number? (string-contains (car w)
1989 (null? (call-with-warnings
1991 (compile '(format #f "~:@(~A ~A~)" 'foo 'bar)
1992 #:opts %opts-w-format
1996 (let ((w (call-with-warnings
1998 (compile '(format #f "~v_foo")
1999 #:opts %opts-w-format
2001 (and (= (length w) 1)
2002 (number? (string-contains (car w)
2003 "expected 1, got 0")))))
2005 (null? (call-with-warnings
2007 (compile '(format #f "~v:@y" 1 123)
2008 #:opts %opts-w-format
2013 (let ((w (call-with-warnings
2015 (compile '(format #f "~2*~a" 'a 'b)
2016 #:opts %opts-w-format
2018 (and (= (length w) 1)
2019 (number? (string-contains (car w)
2020 "expected 3, got 2")))))
2023 (null? (call-with-warnings
2025 (compile '(format #f "~?" "~d ~d" '(1 2))
2026 #:opts %opts-w-format
2029 (pass-if "complex 1"
2030 (let ((w (call-with-warnings
2032 (compile '(format #f
2033 "~4@S ~32S~@[;; ~1{~@?~}~]~@[~61t at ~a~]\n"
2035 #:opts %opts-w-format
2037 (and (= (length w) 1)
2038 (number? (string-contains (car w)
2039 "expected 4, got 6")))))
2041 (pass-if "complex 2"
2042 (let ((w (call-with-warnings
2044 (compile '(format #f
2045 "~:(~A~) Commands~:[~; [abbrev]~]:~2%"
2047 #:opts %opts-w-format
2049 (and (= (length w) 1)
2050 (number? (string-contains (car w)
2051 "expected 2, got 4")))))
2053 (pass-if "complex 3"
2054 (let ((w (call-with-warnings
2056 (compile '(format #f "~9@a~:[~*~3_~;~3d~] ~v:@y~%")
2057 #:opts %opts-w-format
2059 (and (= (length w) 1)
2060 (number? (string-contains (car w)
2061 "expected 5, got 0")))))
2063 (pass-if "ice-9 format"
2064 (let ((w (call-with-warnings
2066 (let ((in (open-input-string
2067 "(use-modules ((ice-9 format)
2068 #:renamer (symbol-prefix-proc 'i9-)))
2069 (i9-format #t \"yo! ~A\" 1 2)")))
2070 (read-and-compile in
2071 #:opts %opts-w-format
2072 #:to 'assembly))))))
2073 (and (= (length w) 1)
2074 (number? (string-contains (car w)
2075 "expected 1, got 2")))))
2077 (pass-if "not format"
2078 (null? (call-with-warnings
2080 (compile '(let ((format chbouib))
2081 (format #t "not ~A a format string"))
2082 #:opts %opts-w-format
2083 #:to 'assembly)))))))