1 ;;;; syntax.test --- test suite for Guile's syntactic forms -*- scheme -*-
3 ;;;; Copyright (C) 2001,2003,2004, 2005, 2006, 2009 Free Software Foundation, Inc.
5 ;;;; This library is free software; you can redistribute it and/or
6 ;;;; modify it under the terms of the GNU Lesser General Public
7 ;;;; License as published by the Free Software Foundation; either
8 ;;;; version 3 of the License, or (at your option) any later version.
10 ;;;; This library is distributed in the hope that it will be useful,
11 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 ;;;; Lesser General Public License for more details.
15 ;;;; You should have received a copy of the GNU Lesser General Public
16 ;;;; License along with this library; if not, write to the Free Software
17 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 (define-module (test-suite test-syntax)
20 :use-module (test-suite lib))
23 (define exception:generic-syncase-error
24 (cons 'syntax-error "source expression failed to match"))
25 (define exception:unexpected-syntax
26 (cons 'syntax-error "unexpected syntax"))
28 (define exception:bad-expression
29 (cons 'syntax-error "Bad expression"))
31 (define exception:missing/extra-expr
32 (cons 'syntax-error "Missing or extra expression"))
33 (define exception:missing-expr
34 (cons 'syntax-error "Missing expression"))
35 (define exception:missing-body-expr
36 (cons 'syntax-error "no expressions in body"))
37 (define exception:extra-expr
38 (cons 'syntax-error "Extra expression"))
39 (define exception:illegal-empty-combination
40 (cons 'syntax-error "Illegal empty combination"))
42 (define exception:bad-lambda
43 '(syntax-error . "bad lambda"))
44 (define exception:bad-let
45 '(syntax-error . "bad let "))
46 (define exception:bad-letrec
47 '(syntax-error . "bad letrec "))
48 (define exception:bad-set!
49 '(syntax-error . "bad set!"))
50 (define exception:bad-quote
51 '(syntax-error . "quote: bad syntax"))
52 (define exception:bad-bindings
53 (cons 'syntax-error "Bad bindings"))
54 (define exception:bad-binding
55 (cons 'syntax-error "Bad binding"))
56 (define exception:duplicate-binding
57 (cons 'syntax-error "duplicate bound variable"))
58 (define exception:bad-body
59 (cons 'misc-error "^bad body"))
60 (define exception:bad-formals
61 '(syntax-error . "invalid argument list"))
62 (define exception:bad-formal
63 (cons 'syntax-error "Bad formal"))
64 (define exception:duplicate-formals
65 (cons 'syntax-error "duplicate identifier in argument list"))
67 (define exception:missing-clauses
68 (cons 'syntax-error "Missing clauses"))
69 (define exception:misplaced-else-clause
70 (cons 'syntax-error "Misplaced else clause"))
71 (define exception:bad-case-clause
72 (cons 'syntax-error "Bad case clause"))
73 (define exception:bad-case-labels
74 (cons 'syntax-error "Bad case labels"))
75 (define exception:bad-cond-clause
76 (cons 'syntax-error "Bad cond clause"))
79 (with-test-prefix "expressions"
81 (with-test-prefix "Bad argument list"
83 (pass-if-exception "improper argument list of length 1"
84 exception:generic-syncase-error
85 (eval '(let ((foo (lambda (x y) #t)))
87 (interaction-environment)))
89 (pass-if-exception "improper argument list of length 2"
90 exception:generic-syncase-error
91 (eval '(let ((foo (lambda (x y) #t)))
93 (interaction-environment))))
95 (with-test-prefix "missing or extra expression"
98 ;; *Note:* In many dialects of Lisp, the empty combination, (),
99 ;; is a legitimate expression. In Scheme, combinations must
100 ;; have at least one subexpression, so () is not a syntactically
104 (pass-if-exception "empty parentheses \"()\""
105 exception:unexpected-syntax
107 (interaction-environment)))))
109 (with-test-prefix "quote"
112 (with-test-prefix "quasiquote"
114 (with-test-prefix "unquote"
116 (pass-if "repeated execution"
117 (let ((foo (let ((i 0)) (lambda () (set! i (+ i 1)) `(,i)))))
118 (and (equal? (foo) '(1)) (equal? (foo) '(2))))))
120 (with-test-prefix "unquote-splicing"
122 (pass-if-exception "extra arguments"
123 '(syntax-error . "unquote-splicing takes exactly one argument")
124 (eval '(quasiquote ((unquote-splicing (list 1 2) (list 3 4))))
125 (interaction-environment)))))
127 (with-test-prefix "begin"
129 (pass-if "legal (begin)"
130 (eval '(begin (begin) #t) (interaction-environment)))
132 (pass-if-exception "illegal (begin)"
133 exception:generic-syncase-error
134 (eval '(begin (if #t (begin)) #t) (interaction-environment))))
136 (define-syntax matches?
138 ((_ (op arg ...) pat) (let ((x (op arg ...)))
141 ((_ x (a . b)) (and (pair? x)
143 (matches? (cdr x) b)))
145 ((_ x pat) (equal? x 'pat))))
147 (with-test-prefix "lambda"
149 (with-test-prefix "bad formals"
151 (pass-if-exception "(lambda)"
154 (interaction-environment)))
156 (pass-if-exception "(lambda . \"foo\")"
158 (eval '(lambda . "foo")
159 (interaction-environment)))
161 (pass-if-exception "(lambda \"foo\")"
163 (eval '(lambda "foo")
164 (interaction-environment)))
166 (pass-if-exception "(lambda \"foo\" #f)"
167 exception:bad-formals
168 (eval '(lambda "foo" #f)
169 (interaction-environment)))
171 (pass-if-exception "(lambda (x 1) 2)"
172 exception:bad-formals
173 (eval '(lambda (x 1) 2)
174 (interaction-environment)))
176 (pass-if-exception "(lambda (1 x) 2)"
177 exception:bad-formals
178 (eval '(lambda (1 x) 2)
179 (interaction-environment)))
181 (pass-if-exception "(lambda (x \"a\") 2)"
182 exception:bad-formals
183 (eval '(lambda (x "a") 2)
184 (interaction-environment)))
186 (pass-if-exception "(lambda (\"a\" x) 2)"
187 exception:bad-formals
188 (eval '(lambda ("a" x) 2)
189 (interaction-environment))))
191 (with-test-prefix "duplicate formals"
194 (pass-if-exception "(lambda (x x) 1)"
195 exception:duplicate-formals
196 (eval '(lambda (x x) 1)
197 (interaction-environment)))
200 (pass-if-exception "(lambda (x x x) 1)"
201 exception:duplicate-formals
202 (eval '(lambda (x x x) 1)
203 (interaction-environment))))
205 (with-test-prefix "bad body"
207 (pass-if-exception "(lambda ())"
210 (interaction-environment)))))
212 (with-test-prefix "let"
214 (with-test-prefix "bindings"
216 (pass-if-exception "late binding"
217 exception:unbound-var
218 (let ((x 1) (y x)) y)))
220 (with-test-prefix "bad bindings"
222 (pass-if-exception "(let)"
225 (interaction-environment)))
227 (pass-if-exception "(let 1)"
230 (interaction-environment)))
232 (pass-if-exception "(let (x))"
235 (interaction-environment)))
237 (pass-if-exception "(let ((x)))"
240 (interaction-environment)))
242 (pass-if-exception "(let (x) 1)"
245 (interaction-environment)))
247 (pass-if-exception "(let ((x)) 3)"
250 (interaction-environment)))
252 (pass-if-exception "(let ((x 1) y) x)"
254 (eval '(let ((x 1) y) x)
255 (interaction-environment)))
257 (pass-if-exception "(let ((1 2)) 3)"
259 (eval '(let ((1 2)) 3)
260 (interaction-environment))))
262 (with-test-prefix "duplicate bindings"
264 (pass-if-exception "(let ((x 1) (x 2)) x)"
265 exception:duplicate-binding
266 (eval '(let ((x 1) (x 2)) x)
267 (interaction-environment))))
269 (with-test-prefix "bad body"
271 (pass-if-exception "(let ())"
274 (interaction-environment)))
276 (pass-if-exception "(let ((x 1)))"
279 (interaction-environment)))))
281 (with-test-prefix "named let"
283 (with-test-prefix "initializers"
285 (pass-if "evaluated in outer environment"
287 (eqv? (let f ((n (f 1))) n) -1))))
289 (with-test-prefix "bad bindings"
291 (pass-if-exception "(let x (y))"
294 (interaction-environment))))
296 (with-test-prefix "bad body"
298 (pass-if-exception "(let x ())"
301 (interaction-environment)))
303 (pass-if-exception "(let x ((y 1)))"
305 (eval '(let x ((y 1)))
306 (interaction-environment)))))
308 (with-test-prefix "let*"
310 (with-test-prefix "bindings"
312 (pass-if "(let* ((x 1) (x 2)) ...)"
316 (pass-if "(let* ((x 1) (x x)) ...)"
320 (pass-if "(let ((x 1) (y 2)) (let* () ...))"
323 (and (= x 1) (= y 2))))))
325 (with-test-prefix "bad bindings"
327 (pass-if-exception "(let*)"
328 exception:generic-syncase-error
330 (interaction-environment)))
332 (pass-if-exception "(let* 1)"
333 exception:generic-syncase-error
335 (interaction-environment)))
337 (pass-if-exception "(let* (x))"
338 exception:generic-syncase-error
340 (interaction-environment)))
342 (pass-if-exception "(let* (x) 1)"
343 exception:generic-syncase-error
345 (interaction-environment)))
347 (pass-if-exception "(let* ((x)) 3)"
348 exception:generic-syncase-error
349 (eval '(let* ((x)) 3)
350 (interaction-environment)))
352 (pass-if-exception "(let* ((x 1) y) x)"
353 exception:generic-syncase-error
354 (eval '(let* ((x 1) y) x)
355 (interaction-environment)))
357 (pass-if-exception "(let* x ())"
358 exception:generic-syncase-error
360 (interaction-environment)))
362 (pass-if-exception "(let* x (y))"
363 exception:generic-syncase-error
365 (interaction-environment)))
367 (pass-if-exception "(let* ((1 2)) 3)"
368 exception:generic-syncase-error
369 (eval '(let* ((1 2)) 3)
370 (interaction-environment))))
372 (with-test-prefix "bad body"
374 (pass-if-exception "(let* ())"
375 exception:generic-syncase-error
377 (interaction-environment)))
379 (pass-if-exception "(let* ((x 1)))"
380 exception:generic-syncase-error
381 (eval '(let* ((x 1)))
382 (interaction-environment)))))
384 (with-test-prefix "letrec"
386 (with-test-prefix "bindings"
388 (pass-if-exception "initial bindings are undefined"
389 exception:used-before-defined
391 ;; FIXME: the memoizer does initialize the var to undefined, but
392 ;; the Scheme evaluator has no way of checking what's an
393 ;; undefined value. Not sure how to do this.
395 (letrec ((x 1) (y x)) y))))
397 (with-test-prefix "bad bindings"
399 (pass-if-exception "(letrec)"
402 (interaction-environment)))
404 (pass-if-exception "(letrec 1)"
407 (interaction-environment)))
409 (pass-if-exception "(letrec (x))"
412 (interaction-environment)))
414 (pass-if-exception "(letrec (x) 1)"
416 (eval '(letrec (x) 1)
417 (interaction-environment)))
419 (pass-if-exception "(letrec ((x)) 3)"
421 (eval '(letrec ((x)) 3)
422 (interaction-environment)))
424 (pass-if-exception "(letrec ((x 1) y) x)"
426 (eval '(letrec ((x 1) y) x)
427 (interaction-environment)))
429 (pass-if-exception "(letrec x ())"
432 (interaction-environment)))
434 (pass-if-exception "(letrec x (y))"
436 (eval '(letrec x (y))
437 (interaction-environment)))
439 (pass-if-exception "(letrec ((1 2)) 3)"
441 (eval '(letrec ((1 2)) 3)
442 (interaction-environment))))
444 (with-test-prefix "duplicate bindings"
446 (pass-if-exception "(letrec ((x 1) (x 2)) x)"
447 exception:duplicate-binding
448 (eval '(letrec ((x 1) (x 2)) x)
449 (interaction-environment))))
451 (with-test-prefix "bad body"
453 (pass-if-exception "(letrec ())"
456 (interaction-environment)))
458 (pass-if-exception "(letrec ((x 1)))"
460 (eval '(letrec ((x 1)))
461 (interaction-environment)))))
463 (with-test-prefix "if"
465 (with-test-prefix "missing or extra expressions"
467 (pass-if-exception "(if)"
468 exception:generic-syncase-error
470 (interaction-environment)))
472 (pass-if-exception "(if 1 2 3 4)"
473 exception:generic-syncase-error
475 (interaction-environment)))))
477 (with-test-prefix "cond"
479 (with-test-prefix "cond is hygienic"
481 (pass-if "bound 'else is handled correctly"
482 (eq? (let ((else 'ok)) (cond (else))) 'ok))
484 (with-test-prefix "bound '=> is handled correctly"
488 (eq? (cond (#t => 'ok)) 'ok)))
492 (eq? (cond (else =>)) 'foo)))
494 (pass-if "else => identity"
496 (eq? (cond (else => identity)) identity)))))
498 (with-test-prefix "SRFI-61"
500 (pass-if "always available"
501 (cond-expand (srfi-61 #t) (else #f)))
503 (pass-if "single value consequent"
504 (eq? 'ok (cond (#t identity => (lambda (x) 'ok)) (else #f))))
506 (pass-if "single value alternate"
507 (eq? 'ok (cond (#t not => (lambda (x) #f)) (else 'ok))))
509 (pass-if-exception "doesn't affect standard =>"
510 exception:wrong-num-args
511 (cond ((values 1 2) => (lambda (x y) #t))))
513 (pass-if "multiple values consequent"
514 (equal? '(2 1) (cond ((values 1 2)
516 (and (= 1 one) (= 2 two))) =>
517 (lambda (one two) (list two one)))
520 (pass-if "multiple values alternate"
521 (eq? 'ok (cond ((values 2 3 4)
522 (lambda args (equal? '(1 2 3) args)) =>
526 (pass-if "zero values"
527 (eq? 'ok (cond ((values) (lambda () #t) => (lambda () 'ok))
530 (pass-if "bound => is handled correctly"
532 (eq? 'ok (cond (#t identity =>) (else #f)))))
534 (pass-if-exception "missing recipient"
535 '(syntax-error . "cond: wrong number of receiver expressions")
536 (cond (#t identity =>)))
538 (pass-if-exception "extra recipient"
539 '(syntax-error . "cond: wrong number of receiver expressions")
540 (cond (#t identity => identity identity))))
542 (with-test-prefix "bad or missing clauses"
544 (pass-if-exception "(cond)"
545 exception:generic-syncase-error
547 (interaction-environment)))
549 (pass-if-exception "(cond #t)"
550 exception:generic-syncase-error
552 (interaction-environment)))
554 (pass-if-exception "(cond 1)"
555 exception:generic-syncase-error
557 (interaction-environment)))
559 (pass-if-exception "(cond 1 2)"
560 exception:generic-syncase-error
562 (interaction-environment)))
564 (pass-if-exception "(cond 1 2 3)"
565 exception:generic-syncase-error
567 (interaction-environment)))
569 (pass-if-exception "(cond 1 2 3 4)"
570 exception:generic-syncase-error
571 (eval '(cond 1 2 3 4)
572 (interaction-environment)))
574 (pass-if-exception "(cond ())"
575 exception:generic-syncase-error
577 (interaction-environment)))
579 (pass-if-exception "(cond () 1)"
580 exception:generic-syncase-error
582 (interaction-environment)))
584 (pass-if-exception "(cond (1) 1)"
585 exception:generic-syncase-error
587 (interaction-environment))))
589 (with-test-prefix "wrong number of arguments"
591 (pass-if-exception "=> (lambda (x y) #t)"
592 exception:wrong-num-args
593 (cond (1 => (lambda (x y) #t))))))
595 (with-test-prefix "case"
597 (pass-if "clause with empty labels list"
598 (case 1 (() #f) (else #t)))
600 (with-test-prefix "case is hygienic"
602 (pass-if-exception "bound 'else is handled correctly"
603 exception:generic-syncase-error
604 (eval '(let ((else #f)) (case 1 (else #f)))
605 (interaction-environment))))
607 (with-test-prefix "bad or missing clauses"
609 (pass-if-exception "(case)"
610 exception:generic-syncase-error
612 (interaction-environment)))
614 (pass-if-exception "(case . \"foo\")"
615 exception:generic-syncase-error
616 (eval '(case . "foo")
617 (interaction-environment)))
619 (pass-if-exception "(case 1)"
620 exception:generic-syncase-error
622 (interaction-environment)))
624 (pass-if-exception "(case 1 . \"foo\")"
625 exception:generic-syncase-error
626 (eval '(case 1 . "foo")
627 (interaction-environment)))
629 (pass-if-exception "(case 1 \"foo\")"
630 exception:generic-syncase-error
631 (eval '(case 1 "foo")
632 (interaction-environment)))
634 (pass-if-exception "(case 1 ())"
635 exception:generic-syncase-error
637 (interaction-environment)))
639 (pass-if-exception "(case 1 (\"foo\"))"
640 exception:generic-syncase-error
641 (eval '(case 1 ("foo"))
642 (interaction-environment)))
644 (pass-if-exception "(case 1 (\"foo\" \"bar\"))"
645 exception:generic-syncase-error
646 (eval '(case 1 ("foo" "bar"))
647 (interaction-environment)))
649 (pass-if-exception "(case 1 ((2) \"bar\") . \"foo\")"
650 exception:generic-syncase-error
651 (eval '(case 1 ((2) "bar") . "foo")
652 (interaction-environment)))
654 (pass-if-exception "(case 1 ((2) \"bar\") (else))"
655 exception:generic-syncase-error
656 (eval '(case 1 ((2) "bar") (else))
657 (interaction-environment)))
659 (pass-if-exception "(case 1 (else #f) . \"foo\")"
660 exception:generic-syncase-error
661 (eval '(case 1 (else #f) . "foo")
662 (interaction-environment)))
664 (pass-if-exception "(case 1 (else #f) ((1) #t))"
665 exception:generic-syncase-error
666 (eval '(case 1 (else #f) ((1) #t))
667 (interaction-environment)))))
669 (with-test-prefix "top-level define"
671 (pass-if "redefinition"
672 (let ((m (make-module)))
673 (beautify-user-module! m)
675 ;; The previous value of `round' must still be visible at the time the
676 ;; new `round' is defined. According to R5RS (Section 5.2.1), `define'
677 ;; should behave like `set!' in this case (except that in the case of
678 ;; Guile, we respect module boundaries).
679 (eval '(define round round) m)
680 (eq? (module-ref m 'round) round)))
682 (with-test-prefix "missing or extra expressions"
684 (pass-if-exception "(define)"
685 exception:generic-syncase-error
687 (interaction-environment)))))
689 (with-test-prefix "internal define"
691 (pass-if "internal defines become letrec"
692 (eval '(let ((a identity) (b identity) (c identity))
693 (define (a x) (if (= x 0) 'a (b (- x 1))))
694 (define (b x) (if (= x 0) 'b (c (- x 1))))
695 (define (c x) (if (= x 0) 'c (a (- x 1))))
696 (and (eq? 'a (a 0) (a 3))
698 (eq? 'c (a 2) (a 5))))
699 (interaction-environment)))
701 (pass-if "binding is created before expression is evaluated"
702 ;; Internal defines are equivalent to `letrec' (R5RS, Section 5.2.2).
709 (interaction-environment))
712 (pass-if "internal defines with begin"
714 (eval '(let ((a identity) (b identity) (c identity))
715 (define (a x) (if (= x 0) 'a (b (- x 1))))
717 (define (b x) (if (= x 0) 'b (c (- x 1)))))
718 (define (c x) (if (= x 0) 'c (a (- x 1))))
719 (and (eq? 'a (a 0) (a 3))
721 (eq? 'c (a 2) (a 5))))
722 (interaction-environment))))
724 (pass-if "internal defines with empty begin"
726 (eval '(let ((a identity) (b identity) (c identity))
727 (define (a x) (if (= x 0) 'a (b (- x 1))))
729 (define (b x) (if (= x 0) 'b (c (- x 1))))
730 (define (c x) (if (= x 0) 'c (a (- x 1))))
731 (and (eq? 'a (a 0) (a 3))
733 (eq? 'c (a 2) (a 5))))
734 (interaction-environment))))
736 (pass-if "internal defines with macro application"
739 (defmacro my-define forms
740 (cons 'define forms))
741 (let ((a identity) (b identity) (c identity))
742 (define (a x) (if (= x 0) 'a (b (- x 1))))
743 (my-define (b x) (if (= x 0) 'b (c (- x 1))))
744 (define (c x) (if (= x 0) 'c (a (- x 1))))
745 (and (eq? 'a (a 0) (a 3))
747 (eq? 'c (a 2) (a 5)))))
748 (interaction-environment))))
750 (pass-if-exception "missing body expression"
751 exception:missing-body-expr
752 (eval '(let () (define x #t))
753 (interaction-environment))))
755 (with-test-prefix "set!"
757 (with-test-prefix "missing or extra expressions"
759 (pass-if-exception "(set!)"
762 (interaction-environment)))
764 (pass-if-exception "(set! 1)"
767 (interaction-environment)))
769 (pass-if-exception "(set! 1 2 3)"
772 (interaction-environment))))
774 (with-test-prefix "bad variable"
776 (pass-if-exception "(set! \"\" #t)"
779 (interaction-environment)))
781 (pass-if-exception "(set! 1 #t)"
784 (interaction-environment)))
786 (pass-if-exception "(set! #t #f)"
789 (interaction-environment)))
791 (pass-if-exception "(set! #f #t)"
794 (interaction-environment)))
796 (pass-if-exception "(set! #\\space #f)"
798 (eval '(set! #\space #f)
799 (interaction-environment)))))
801 (with-test-prefix "quote"
803 (with-test-prefix "missing or extra expression"
805 (pass-if-exception "(quote)"
808 (interaction-environment)))
810 (pass-if-exception "(quote a b)"
813 (interaction-environment)))))
815 (with-test-prefix "while"
817 (define (unreachable)
818 (error "unreachable code has been reached!"))
820 ;; Return a new procedure COND which when called (COND) will return #t the
821 ;; first N times, then #f, then any further call is an error. N=0 is
822 ;; allowed, in which case #f is returned by the first call.
823 (define (make-iterations-cond n)
826 (error "oops, condition re-tested after giving false"))
835 (pass-if-exception "too few args" exception:wrong-num-args
836 (eval '(while) (interaction-environment)))
838 (with-test-prefix "empty body"
842 (eval `(letrec ((make-iterations-cond
846 (error "oops, condition re-tested after giving false"))
853 (let ((cond (make-iterations-cond ,n)))
856 (interaction-environment)))))
858 (pass-if "initially false"
863 (with-test-prefix "iterations"
867 (let ((cond (make-iterations-cond n))
873 (with-test-prefix "break"
875 (pass-if-exception "too many args" exception:wrong-num-args
878 (interaction-environment)))
880 (with-test-prefix "from cond"
891 (let ((cond (make-iterations-cond n))
901 (with-test-prefix "from body"
911 (let ((cond (make-iterations-cond n))
921 (pass-if "from nested"
923 (let ((outer-break break))
930 (pass-if "from recursive"
931 (let ((outer-break #f))
936 (set! outer-break break)
942 (error "broke only from inner loop")))
946 (with-test-prefix "continue"
948 (pass-if-exception "too many args" exception:wrong-num-args
951 (interaction-environment)))
953 (with-test-prefix "from cond"
957 (let ((cond (make-iterations-cond n))
968 (with-test-prefix "from body"
972 (let ((cond (make-iterations-cond n))
980 (pass-if "from nested"
981 (let ((cond (make-iterations-cond 3)))
983 (let ((outer-continue continue))
989 (pass-if "from recursive"
990 (let ((outer-continue #f))
992 (let ((cond (make-iterations-cond 3))
997 (error "continued only to inner loop"))
1002 (set! outer-continue continue)