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 parameter list"))
62 (define exception:bad-formal
63 (cons 'syntax-error "Bad formal"))
64 (define exception:duplicate-formal
65 (cons 'syntax-error "Duplicate formal"))
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 (with-test-prefix "unmemoization"
134 ;; FIXME. I have no idea why, but the expander is filling in (if #f
135 ;; #f) as the second arm of the if, if the second arm is missing. I
136 ;; thought I made it not do that. But in the meantime, let's adapt,
137 ;; since that's not what we're testing.
139 (pass-if "normal begin"
140 (let ((foo (lambda () (if (= 1 1) (begin (+ 1) (+ 2)) #f))))
141 (equal? (procedure-source foo)
142 '(lambda () (if (= 1 1) (begin (+ 1) (+ 2)) #f)))))
144 (pass-if "redundant nested begin"
145 (let ((foo (lambda () (if (= 1 1) (begin (+ 1) (begin (+ 2) (+ 3))) #f))))
146 (foo) ; make sure, memoization has been performed
147 (equal? (procedure-source foo)
148 '(lambda () (if (= 1 1) (begin (+ 1) (begin (+ 2) (+ 3))) #f)))))
150 (pass-if "redundant begin at start of body"
151 (let ((foo (lambda () (begin (+ 1) (+ 2))))) ; should be optimized
152 (foo) ; make sure, memoization has been performed
153 (equal? (procedure-source foo)
154 '(lambda () (begin (+ 1) (+ 2)))))))
156 (pass-if-exception "illegal (begin)"
157 exception:generic-syncase-error
158 (eval '(begin (if #t (begin)) #t) (interaction-environment))))
160 (define-syntax matches?
162 ((_ (op arg ...) pat) (let ((x (op arg ...)))
165 ((_ x (a . b)) (and (pair? x)
167 (matches? (cdr x) b)))
169 ((_ x pat) (equal? x 'pat))))
171 (with-test-prefix "lambda"
173 (with-test-prefix "unmemoization"
175 (pass-if "normal lambda"
176 (let ((foo (lambda () (lambda (x y) (+ x y)))))
177 (matches? (procedure-source foo)
178 (lambda () (lambda (_ _) (+ _ _))))))
180 (pass-if "lambda with documentation"
181 (let ((foo (lambda () (lambda (x y) "docstring" (+ x y)))))
182 (matches? (procedure-source foo)
183 (lambda () (lambda (_ _) "docstring" (+ _ _)))))))
185 (with-test-prefix "bad formals"
187 (pass-if-exception "(lambda)"
190 (interaction-environment)))
192 (pass-if-exception "(lambda . \"foo\")"
194 (eval '(lambda . "foo")
195 (interaction-environment)))
197 (pass-if-exception "(lambda \"foo\")"
199 (eval '(lambda "foo")
200 (interaction-environment)))
202 (pass-if-exception "(lambda \"foo\" #f)"
203 exception:bad-formals
204 (eval '(lambda "foo" #f)
205 (interaction-environment)))
207 (pass-if-exception "(lambda (x 1) 2)"
208 exception:bad-formals
209 (eval '(lambda (x 1) 2)
210 (interaction-environment)))
212 (pass-if-exception "(lambda (1 x) 2)"
213 exception:bad-formals
214 (eval '(lambda (1 x) 2)
215 (interaction-environment)))
217 (pass-if-exception "(lambda (x \"a\") 2)"
218 exception:bad-formals
219 (eval '(lambda (x "a") 2)
220 (interaction-environment)))
222 (pass-if-exception "(lambda (\"a\" x) 2)"
223 exception:bad-formals
224 (eval '(lambda ("a" x) 2)
225 (interaction-environment))))
227 (with-test-prefix "duplicate formals"
230 (pass-if-exception "(lambda (x x) 1)"
231 exception:bad-formals
232 (eval '(lambda (x x) 1)
233 (interaction-environment)))
236 (pass-if-exception "(lambda (x x x) 1)"
237 exception:bad-formals
238 (eval '(lambda (x x x) 1)
239 (interaction-environment))))
241 (with-test-prefix "bad body"
243 (pass-if-exception "(lambda ())"
246 (interaction-environment)))))
248 (with-test-prefix "let"
250 (with-test-prefix "unmemoization"
252 (pass-if "normal let"
253 (let ((foo (lambda () (let ((i 1) (j 2)) (+ i j)))))
254 (matches? (procedure-source foo)
255 (lambda () (let ((_ 1) (_ 2)) (+ _ _)))))))
257 (with-test-prefix "bindings"
259 (pass-if-exception "late binding"
260 exception:unbound-var
261 (let ((x 1) (y x)) y)))
263 (with-test-prefix "bad bindings"
265 (pass-if-exception "(let)"
268 (interaction-environment)))
270 (pass-if-exception "(let 1)"
273 (interaction-environment)))
275 (pass-if-exception "(let (x))"
278 (interaction-environment)))
280 (pass-if-exception "(let ((x)))"
283 (interaction-environment)))
285 (pass-if-exception "(let (x) 1)"
288 (interaction-environment)))
290 (pass-if-exception "(let ((x)) 3)"
293 (interaction-environment)))
295 (pass-if-exception "(let ((x 1) y) x)"
297 (eval '(let ((x 1) y) x)
298 (interaction-environment)))
300 (pass-if-exception "(let ((1 2)) 3)"
302 (eval '(let ((1 2)) 3)
303 (interaction-environment))))
305 (with-test-prefix "duplicate bindings"
307 (pass-if-exception "(let ((x 1) (x 2)) x)"
308 exception:duplicate-binding
309 (eval '(let ((x 1) (x 2)) x)
310 (interaction-environment))))
312 (with-test-prefix "bad body"
314 (pass-if-exception "(let ())"
317 (interaction-environment)))
319 (pass-if-exception "(let ((x 1)))"
322 (interaction-environment)))))
324 (with-test-prefix "named let"
326 (with-test-prefix "initializers"
328 (pass-if "evaluated in outer environment"
330 (eqv? (let f ((n (f 1))) n) -1))))
332 (with-test-prefix "bad bindings"
334 (pass-if-exception "(let x (y))"
337 (interaction-environment))))
339 (with-test-prefix "bad body"
341 (pass-if-exception "(let x ())"
344 (interaction-environment)))
346 (pass-if-exception "(let x ((y 1)))"
348 (eval '(let x ((y 1)))
349 (interaction-environment)))))
351 (with-test-prefix "let*"
353 (with-test-prefix "unmemoization"
355 (pass-if "normal let*"
356 (let ((foo (lambda () (let* ((x 1) (y 2)) (+ x y)))))
357 (matches? (procedure-source foo)
358 (lambda () (let ((_ 1)) (let ((_ 2)) (+ _ _)))))))
360 (pass-if "let* without bindings"
361 (let ((foo (lambda () (let ((x 1) (y 2))
363 (and (= x 1) (= y 2)))))))
364 (matches? (procedure-source foo)
365 (lambda () (let ((_ 1) (_ 2))
366 (if (= _ 1) (= _ 2) #f)))))))
368 (with-test-prefix "bindings"
370 (pass-if "(let* ((x 1) (x 2)) ...)"
374 (pass-if "(let* ((x 1) (x x)) ...)"
378 (pass-if "(let ((x 1) (y 2)) (let* () ...))"
381 (and (= x 1) (= y 2))))))
383 (with-test-prefix "bad bindings"
385 (pass-if-exception "(let*)"
386 exception:generic-syncase-error
388 (interaction-environment)))
390 (pass-if-exception "(let* 1)"
391 exception:generic-syncase-error
393 (interaction-environment)))
395 (pass-if-exception "(let* (x))"
396 exception:generic-syncase-error
398 (interaction-environment)))
400 (pass-if-exception "(let* (x) 1)"
401 exception:generic-syncase-error
403 (interaction-environment)))
405 (pass-if-exception "(let* ((x)) 3)"
406 exception:generic-syncase-error
407 (eval '(let* ((x)) 3)
408 (interaction-environment)))
410 (pass-if-exception "(let* ((x 1) y) x)"
411 exception:generic-syncase-error
412 (eval '(let* ((x 1) y) x)
413 (interaction-environment)))
415 (pass-if-exception "(let* x ())"
416 exception:generic-syncase-error
418 (interaction-environment)))
420 (pass-if-exception "(let* x (y))"
421 exception:generic-syncase-error
423 (interaction-environment)))
425 (pass-if-exception "(let* ((1 2)) 3)"
426 exception:generic-syncase-error
427 (eval '(let* ((1 2)) 3)
428 (interaction-environment))))
430 (with-test-prefix "bad body"
432 (pass-if-exception "(let* ())"
433 exception:generic-syncase-error
435 (interaction-environment)))
437 (pass-if-exception "(let* ((x 1)))"
438 exception:generic-syncase-error
439 (eval '(let* ((x 1)))
440 (interaction-environment)))))
442 (with-test-prefix "letrec"
444 (with-test-prefix "unmemoization"
446 (pass-if "normal letrec"
447 (let ((foo (lambda () (letrec ((i 1) (j 2)) (+ i j)))))
448 (matches? (procedure-source foo)
449 (lambda () (letrec ((_ 1) (_ 2)) (+ _ _)))))))
451 (with-test-prefix "bindings"
453 (pass-if-exception "initial bindings are undefined"
454 exception:used-before-defined
456 (letrec ((x 1) (y x)) y))))
458 (with-test-prefix "bad bindings"
460 (pass-if-exception "(letrec)"
463 (interaction-environment)))
465 (pass-if-exception "(letrec 1)"
468 (interaction-environment)))
470 (pass-if-exception "(letrec (x))"
473 (interaction-environment)))
475 (pass-if-exception "(letrec (x) 1)"
477 (eval '(letrec (x) 1)
478 (interaction-environment)))
480 (pass-if-exception "(letrec ((x)) 3)"
482 (eval '(letrec ((x)) 3)
483 (interaction-environment)))
485 (pass-if-exception "(letrec ((x 1) y) x)"
487 (eval '(letrec ((x 1) y) x)
488 (interaction-environment)))
490 (pass-if-exception "(letrec x ())"
493 (interaction-environment)))
495 (pass-if-exception "(letrec x (y))"
497 (eval '(letrec x (y))
498 (interaction-environment)))
500 (pass-if-exception "(letrec ((1 2)) 3)"
502 (eval '(letrec ((1 2)) 3)
503 (interaction-environment))))
505 (with-test-prefix "duplicate bindings"
507 (pass-if-exception "(letrec ((x 1) (x 2)) x)"
508 exception:duplicate-binding
509 (eval '(letrec ((x 1) (x 2)) x)
510 (interaction-environment))))
512 (with-test-prefix "bad body"
514 (pass-if-exception "(letrec ())"
517 (interaction-environment)))
519 (pass-if-exception "(letrec ((x 1)))"
521 (eval '(letrec ((x 1)))
522 (interaction-environment)))))
524 (with-test-prefix "if"
526 (with-test-prefix "unmemoization"
529 (let ((foo (lambda (x) (if x (+ 1) (+ 2)))))
530 (foo #t) ; make sure, memoization has been performed
531 (foo #f) ; make sure, memoization has been performed
532 (matches? (procedure-source foo)
533 (lambda (_) (if _ (+ 1) (+ 2))))))
535 (expect-fail "if without else"
536 (let ((foo (lambda (x) (if x (+ 1)))))
537 (foo #t) ; make sure, memoization has been performed
538 (foo #f) ; make sure, memoization has been performed
539 (equal? (procedure-source foo)
540 '(lambda (x) (if x (+ 1))))))
542 (expect-fail "if #f without else"
543 (let ((foo (lambda () (if #f #f))))
544 (foo) ; make sure, memoization has been performed
545 (equal? (procedure-source foo)
546 `(lambda () (if #f #f))))))
548 (with-test-prefix "missing or extra expressions"
550 (pass-if-exception "(if)"
551 exception:generic-syncase-error
553 (interaction-environment)))
555 (pass-if-exception "(if 1 2 3 4)"
556 exception:generic-syncase-error
558 (interaction-environment)))))
560 (with-test-prefix "cond"
562 (with-test-prefix "cond is hygienic"
564 (pass-if "bound 'else is handled correctly"
565 (eq? (let ((else 'ok)) (cond (else))) 'ok))
567 (with-test-prefix "bound '=> is handled correctly"
571 (eq? (cond (#t => 'ok)) 'ok)))
575 (eq? (cond (else =>)) 'foo)))
577 (pass-if "else => identity"
579 (eq? (cond (else => identity)) identity)))))
581 (with-test-prefix "SRFI-61"
583 (pass-if "always available"
584 (cond-expand (srfi-61 #t) (else #f)))
586 (pass-if "single value consequent"
587 (eq? 'ok (cond (#t identity => (lambda (x) 'ok)) (else #f))))
589 (pass-if "single value alternate"
590 (eq? 'ok (cond (#t not => (lambda (x) #f)) (else 'ok))))
592 (pass-if-exception "doesn't affect standard =>"
593 exception:wrong-num-args
594 (cond ((values 1 2) => (lambda (x y) #t))))
596 (pass-if "multiple values consequent"
597 (equal? '(2 1) (cond ((values 1 2)
599 (and (= 1 one) (= 2 two))) =>
600 (lambda (one two) (list two one)))
603 (pass-if "multiple values alternate"
604 (eq? 'ok (cond ((values 2 3 4)
605 (lambda args (equal? '(1 2 3) args)) =>
609 (pass-if "zero values"
610 (eq? 'ok (cond ((values) (lambda () #t) => (lambda () 'ok))
613 (pass-if "bound => is handled correctly"
615 (eq? 'ok (cond (#t identity =>) (else #f)))))
617 (pass-if-exception "missing recipient"
618 '(syntax-error . "cond: wrong number of receiver expressions")
619 (cond (#t identity =>)))
621 (pass-if-exception "extra recipient"
622 '(syntax-error . "cond: wrong number of receiver expressions")
623 (cond (#t identity => identity identity))))
625 (with-test-prefix "unmemoization"
627 ;; FIXME: the (if #f #f) is a hack!
628 (pass-if "normal clauses"
629 (let ((foo (lambda () (cond ((= x 1) 'bar) ((= x 2) 'baz)))))
630 (equal? (procedure-source foo)
631 '(lambda () (if (= x 1) 'bar (if (= x 2) 'baz (if #f #f)))))))
634 (let ((foo (lambda () (cond (else 'bar)))))
635 (equal? (procedure-source foo)
638 ;; FIXME: the (if #f #f) is a hack!
640 (let ((foo (lambda () (cond (#t => identity)))))
641 (matches? (procedure-source foo)
642 (lambda () (let ((_ #t))
643 (if _ (identity _) (if #f #f))))))))
645 (with-test-prefix "bad or missing clauses"
647 (pass-if-exception "(cond)"
648 exception:generic-syncase-error
650 (interaction-environment)))
652 (pass-if-exception "(cond #t)"
653 exception:generic-syncase-error
655 (interaction-environment)))
657 (pass-if-exception "(cond 1)"
658 exception:generic-syncase-error
660 (interaction-environment)))
662 (pass-if-exception "(cond 1 2)"
663 exception:generic-syncase-error
665 (interaction-environment)))
667 (pass-if-exception "(cond 1 2 3)"
668 exception:generic-syncase-error
670 (interaction-environment)))
672 (pass-if-exception "(cond 1 2 3 4)"
673 exception:generic-syncase-error
674 (eval '(cond 1 2 3 4)
675 (interaction-environment)))
677 (pass-if-exception "(cond ())"
678 exception:generic-syncase-error
680 (interaction-environment)))
682 (pass-if-exception "(cond () 1)"
683 exception:generic-syncase-error
685 (interaction-environment)))
687 (pass-if-exception "(cond (1) 1)"
688 exception:generic-syncase-error
690 (interaction-environment))))
692 (with-test-prefix "wrong number of arguments"
694 (pass-if-exception "=> (lambda (x y) #t)"
695 exception:wrong-num-args
696 (cond (1 => (lambda (x y) #t))))))
698 (with-test-prefix "case"
700 (pass-if "clause with empty labels list"
701 (case 1 (() #f) (else #t)))
703 (with-test-prefix "case is hygienic"
705 (pass-if-exception "bound 'else is handled correctly"
706 exception:generic-syncase-error
707 (eval '(let ((else #f)) (case 1 (else #f)))
708 (interaction-environment))))
710 (with-test-prefix "unmemoization"
712 (pass-if "normal clauses"
713 (let ((foo (lambda (x) (case x ((1) 'bar) ((2) 'baz) (else 'foobar)))))
714 (matches? (procedure-source foo)
716 (if ((@@ (guile) memv) _ '(1))
718 (if ((@@ (guile) memv) _ '(2))
722 (pass-if "empty labels"
723 (let ((foo (lambda (x) (case x ((1) 'bar) (() 'baz) (else 'foobar)))))
724 (matches? (procedure-source foo)
726 (if ((@@ (guile) memv) _ '(1))
728 (if ((@@ (guile) memv) _ '())
732 (with-test-prefix "bad or missing clauses"
734 (pass-if-exception "(case)"
735 exception:generic-syncase-error
737 (interaction-environment)))
739 (pass-if-exception "(case . \"foo\")"
740 exception:generic-syncase-error
741 (eval '(case . "foo")
742 (interaction-environment)))
744 (pass-if-exception "(case 1)"
745 exception:generic-syncase-error
747 (interaction-environment)))
749 (pass-if-exception "(case 1 . \"foo\")"
750 exception:generic-syncase-error
751 (eval '(case 1 . "foo")
752 (interaction-environment)))
754 (pass-if-exception "(case 1 \"foo\")"
755 exception:generic-syncase-error
756 (eval '(case 1 "foo")
757 (interaction-environment)))
759 (pass-if-exception "(case 1 ())"
760 exception:generic-syncase-error
762 (interaction-environment)))
764 (pass-if-exception "(case 1 (\"foo\"))"
765 exception:generic-syncase-error
766 (eval '(case 1 ("foo"))
767 (interaction-environment)))
769 (pass-if-exception "(case 1 (\"foo\" \"bar\"))"
770 exception:generic-syncase-error
771 (eval '(case 1 ("foo" "bar"))
772 (interaction-environment)))
774 (pass-if-exception "(case 1 ((2) \"bar\") . \"foo\")"
775 exception:generic-syncase-error
776 (eval '(case 1 ((2) "bar") . "foo")
777 (interaction-environment)))
779 (pass-if-exception "(case 1 ((2) \"bar\") (else))"
780 exception:generic-syncase-error
781 (eval '(case 1 ((2) "bar") (else))
782 (interaction-environment)))
784 (pass-if-exception "(case 1 (else #f) . \"foo\")"
785 exception:generic-syncase-error
786 (eval '(case 1 (else #f) . "foo")
787 (interaction-environment)))
789 (pass-if-exception "(case 1 (else #f) ((1) #t))"
790 exception:generic-syncase-error
791 (eval '(case 1 (else #f) ((1) #t))
792 (interaction-environment)))))
794 (with-test-prefix "top-level define"
796 (pass-if "redefinition"
797 (let ((m (make-module)))
798 (beautify-user-module! m)
800 ;; The previous value of `round' must still be visible at the time the
801 ;; new `round' is defined. According to R5RS (Section 5.2.1), `define'
802 ;; should behave like `set!' in this case (except that in the case of
803 ;; Guile, we respect module boundaries).
804 (eval '(define round round) m)
805 (eq? (module-ref m 'round) round)))
807 (with-test-prefix "unmemoization"
809 (pass-if "definition unmemoized without prior execution"
810 (primitive-eval '(begin
811 (define (blub) (cons ('(1 . 2)) 2))
813 (procedure-source blub)
814 '(lambda () (cons ('(1 . 2)) 2))))))
817 (pass-if "definition with documentation unmemoized without prior execution"
818 (primitive-eval '(begin
819 (define (blub) "Comment" (cons ('(1 . 2)) 2))
821 (procedure-source blub)
822 '(lambda () "Comment" (cons ('(1 . 2)) 2)))))))
824 (with-test-prefix "missing or extra expressions"
826 (pass-if-exception "(define)"
827 exception:generic-syncase-error
829 (interaction-environment)))))
831 (with-test-prefix "internal define"
833 (pass-if "internal defines become letrec"
834 (eval '(let ((a identity) (b identity) (c identity))
835 (define (a x) (if (= x 0) 'a (b (- x 1))))
836 (define (b x) (if (= x 0) 'b (c (- x 1))))
837 (define (c x) (if (= x 0) 'c (a (- x 1))))
838 (and (eq? 'a (a 0) (a 3))
840 (eq? 'c (a 2) (a 5))))
841 (interaction-environment)))
843 (pass-if "binding is created before expression is evaluated"
844 ;; Internal defines are equivalent to `letrec' (R5RS, Section 5.2.2).
851 (interaction-environment))
854 (pass-if "internal defines with begin"
856 (eval '(let ((a identity) (b identity) (c identity))
857 (define (a x) (if (= x 0) 'a (b (- x 1))))
859 (define (b x) (if (= x 0) 'b (c (- x 1)))))
860 (define (c x) (if (= x 0) 'c (a (- x 1))))
861 (and (eq? 'a (a 0) (a 3))
863 (eq? 'c (a 2) (a 5))))
864 (interaction-environment))))
866 (pass-if "internal defines with empty begin"
868 (eval '(let ((a identity) (b identity) (c identity))
869 (define (a x) (if (= x 0) 'a (b (- x 1))))
871 (define (b x) (if (= x 0) 'b (c (- x 1))))
872 (define (c x) (if (= x 0) 'c (a (- x 1))))
873 (and (eq? 'a (a 0) (a 3))
875 (eq? 'c (a 2) (a 5))))
876 (interaction-environment))))
878 (pass-if "internal defines with macro application"
881 (defmacro my-define forms
882 (cons 'define forms))
883 (let ((a identity) (b identity) (c identity))
884 (define (a x) (if (= x 0) 'a (b (- x 1))))
885 (my-define (b x) (if (= x 0) 'b (c (- x 1))))
886 (define (c x) (if (= x 0) 'c (a (- x 1))))
887 (and (eq? 'a (a 0) (a 3))
889 (eq? 'c (a 2) (a 5)))))
890 (interaction-environment))))
892 (pass-if-exception "missing body expression"
893 exception:missing-body-expr
894 (eval '(let () (define x #t))
895 (interaction-environment)))
897 (pass-if "unmemoization"
898 (primitive-eval '(begin
905 (procedure-source foo)
906 (lambda () (letrec ((_ (lambda () (quote ok)))) (_))))))))
908 (with-test-prefix "set!"
910 (with-test-prefix "unmemoization"
912 (pass-if "normal set!"
913 (let ((foo (lambda (x) (set! x (+ 1 x)))))
914 (foo 1) ; make sure, memoization has been performed
915 (matches? (procedure-source foo)
916 (lambda (_) (set! _ (+ 1 _)))))))
918 (with-test-prefix "missing or extra expressions"
920 (pass-if-exception "(set!)"
923 (interaction-environment)))
925 (pass-if-exception "(set! 1)"
928 (interaction-environment)))
930 (pass-if-exception "(set! 1 2 3)"
933 (interaction-environment))))
935 (with-test-prefix "bad variable"
937 (pass-if-exception "(set! \"\" #t)"
940 (interaction-environment)))
942 (pass-if-exception "(set! 1 #t)"
945 (interaction-environment)))
947 (pass-if-exception "(set! #t #f)"
950 (interaction-environment)))
952 (pass-if-exception "(set! #f #t)"
955 (interaction-environment)))
957 (pass-if-exception "(set! #\\space #f)"
959 (eval '(set! #\space #f)
960 (interaction-environment)))))
962 (with-test-prefix "quote"
964 (with-test-prefix "missing or extra expression"
966 (pass-if-exception "(quote)"
969 (interaction-environment)))
971 (pass-if-exception "(quote a b)"
974 (interaction-environment)))))
976 (with-test-prefix "while"
978 (define (unreachable)
979 (error "unreachable code has been reached!"))
981 ;; Return a new procedure COND which when called (COND) will return #t the
982 ;; first N times, then #f, then any further call is an error. N=0 is
983 ;; allowed, in which case #f is returned by the first call.
984 (define (make-iterations-cond n)
987 (error "oops, condition re-tested after giving false"))
996 (pass-if-exception "too few args" exception:wrong-num-args
997 (eval '(while) (interaction-environment)))
999 (with-test-prefix "empty body"
1003 (eval `(letrec ((make-iterations-cond
1007 (error "oops, condition re-tested after giving false"))
1014 (let ((cond (make-iterations-cond ,n)))
1017 (interaction-environment)))))
1019 (pass-if "initially false"
1024 (with-test-prefix "iterations"
1028 (let ((cond (make-iterations-cond n))
1034 (with-test-prefix "break"
1036 (pass-if-exception "too many args" exception:wrong-num-args
1039 (interaction-environment)))
1041 (with-test-prefix "from cond"
1052 (let ((cond (make-iterations-cond n))
1062 (with-test-prefix "from body"
1072 (let ((cond (make-iterations-cond n))
1082 (pass-if "from nested"
1084 (let ((outer-break break))
1091 (pass-if "from recursive"
1092 (let ((outer-break #f))
1097 (set! outer-break break)
1103 (error "broke only from inner loop")))
1107 (with-test-prefix "continue"
1109 (pass-if-exception "too many args" exception:wrong-num-args
1112 (interaction-environment)))
1114 (with-test-prefix "from cond"
1118 (let ((cond (make-iterations-cond n))
1129 (with-test-prefix "from body"
1133 (let ((cond (make-iterations-cond n))
1141 (pass-if "from nested"
1142 (let ((cond (make-iterations-cond 3)))
1144 (let ((outer-continue continue))
1150 (pass-if "from recursive"
1151 (let ((outer-continue #f))
1153 (let ((cond (make-iterations-cond 3))
1156 (if (and (not first)
1158 (error "continued only to inner loop"))
1163 (set! outer-continue continue)