1 ;;;; syntax.test --- test suite for Guile's syntactic forms -*- scheme -*-
3 ;;;; Copyright (C) 2001,2003,2004, 2005, 2006 Free Software Foundation, Inc.
5 ;;;; This program is free software; you can redistribute it and/or modify
6 ;;;; it under the terms of the GNU General Public License as published by
7 ;;;; the Free Software Foundation; either version 2, or (at your option)
8 ;;;; any later version.
10 ;;;; This program 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
13 ;;;; GNU General Public License for more details.
15 ;;;; You should have received a copy of the GNU General Public License
16 ;;;; along with this software; see the file COPYING. If not, write to
17 ;;;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 ;;;; Boston, MA 02110-1301 USA
20 (define-module (test-suite test-syntax)
21 :use-module (test-suite lib))
24 (define exception:generic-syncase-error
25 (cons 'syntax-error "source expression failed to match"))
26 (define exception:unexpected-syntax
27 (cons 'syntax-error "unexpected syntax"))
29 (define exception:bad-expression
30 (cons 'syntax-error "Bad expression"))
32 (define exception:missing/extra-expr
33 (cons 'syntax-error "Missing or extra expression"))
34 (define exception:missing-expr
35 (cons 'syntax-error "Missing expression"))
36 (define exception:missing-body-expr
37 (cons 'syntax-error "no expressions in body"))
38 (define exception:extra-expr
39 (cons 'syntax-error "Extra expression"))
40 (define exception:illegal-empty-combination
41 (cons 'syntax-error "Illegal empty combination"))
43 (define exception:bad-lambda
44 '(syntax-error . "bad lambda"))
45 (define exception:bad-let
46 '(syntax-error . "bad let "))
47 (define exception:bad-letrec
48 '(syntax-error . "bad letrec "))
49 (define exception:bad-set!
50 '(syntax-error . "bad set!"))
51 (define exception:bad-quote
52 '(syntax-error . "quote: bad syntax"))
53 (define exception:bad-bindings
54 (cons 'syntax-error "Bad bindings"))
55 (define exception:bad-binding
56 (cons 'syntax-error "Bad binding"))
57 (define exception:duplicate-binding
58 (cons 'syntax-error "duplicate bound variable"))
59 (define exception:bad-body
60 (cons 'misc-error "^bad body"))
61 (define exception:bad-formals
62 '(syntax-error . "invalid parameter list"))
63 (define exception:bad-formal
64 (cons 'syntax-error "Bad formal"))
65 (define exception:duplicate-formal
66 (cons 'syntax-error "Duplicate formal"))
68 (define exception:missing-clauses
69 (cons 'syntax-error "Missing clauses"))
70 (define exception:misplaced-else-clause
71 (cons 'syntax-error "Misplaced else clause"))
72 (define exception:bad-case-clause
73 (cons 'syntax-error "Bad case clause"))
74 (define exception:bad-case-labels
75 (cons 'syntax-error "Bad case labels"))
76 (define exception:bad-cond-clause
77 (cons 'syntax-error "Bad cond clause"))
80 (with-test-prefix "expressions"
82 (with-test-prefix "Bad argument list"
84 (pass-if-exception "improper argument list of length 1"
85 exception:generic-syncase-error
86 (eval '(let ((foo (lambda (x y) #t)))
88 (interaction-environment)))
90 (pass-if-exception "improper argument list of length 2"
91 exception:generic-syncase-error
92 (eval '(let ((foo (lambda (x y) #t)))
94 (interaction-environment))))
96 (with-test-prefix "missing or extra expression"
99 ;; *Note:* In many dialects of Lisp, the empty combination, (),
100 ;; is a legitimate expression. In Scheme, combinations must
101 ;; have at least one subexpression, so () is not a syntactically
105 (pass-if-exception "empty parentheses \"()\""
106 exception:unexpected-syntax
108 (interaction-environment)))))
110 (with-test-prefix "quote"
113 (with-test-prefix "quasiquote"
115 (with-test-prefix "unquote"
117 (pass-if "repeated execution"
118 (let ((foo (let ((i 0)) (lambda () (set! i (+ i 1)) `(,i)))))
119 (and (equal? (foo) '(1)) (equal? (foo) '(2))))))
121 (with-test-prefix "unquote-splicing"
123 (pass-if-exception "extra arguments"
124 '(syntax-error . "unquote-splicing takes exactly one argument")
125 (eval '(quasiquote ((unquote-splicing (list 1 2) (list 3 4))))
126 (interaction-environment)))))
128 (with-test-prefix "begin"
130 (pass-if "legal (begin)"
131 (eval '(begin (begin) #t) (interaction-environment)))
133 (with-test-prefix "unmemoization"
135 ;; FIXME. I have no idea why, but the expander is filling in (if #f
136 ;; #f) as the second arm of the if, if the second arm is missing. I
137 ;; thought I made it not do that. But in the meantime, let's adapt,
138 ;; since that's not what we're testing.
140 (pass-if "normal begin"
141 (let ((foo (lambda () (if (= 1 1) (begin (+ 1) (+ 2)) #f))))
142 (equal? (procedure-source foo)
143 '(lambda () (if (= 1 1) (begin (+ 1) (+ 2)) #f)))))
145 (pass-if "redundant nested begin"
146 (let ((foo (lambda () (if (= 1 1) (begin (+ 1) (begin (+ 2) (+ 3))) #f))))
147 (foo) ; make sure, memoization has been performed
148 (equal? (procedure-source foo)
149 '(lambda () (if (= 1 1) (begin (+ 1) (begin (+ 2) (+ 3))) #f)))))
151 (pass-if "redundant begin at start of body"
152 (let ((foo (lambda () (begin (+ 1) (+ 2))))) ; should be optimized
153 (foo) ; make sure, memoization has been performed
154 (equal? (procedure-source foo)
155 '(lambda () (begin (+ 1) (+ 2)))))))
157 (pass-if-exception "illegal (begin)"
158 exception:generic-syncase-error
159 (eval '(begin (if #t (begin)) #t) (interaction-environment))))
161 (define-syntax matches?
163 ((_ (op arg ...) pat) (let ((x (op arg ...)))
166 ((_ x (a . b)) (and (pair? x)
168 (matches? (cdr x) b)))
170 ((_ x pat) (equal? x 'pat))))
172 (with-test-prefix "lambda"
174 (with-test-prefix "unmemoization"
176 (pass-if "normal lambda"
177 (let ((foo (lambda () (lambda (x y) (+ x y)))))
178 (matches? (procedure-source foo)
179 (lambda () (lambda (_ _) (+ _ _))))))
181 (pass-if "lambda with documentation"
182 (let ((foo (lambda () (lambda (x y) "docstring" (+ x y)))))
183 (matches? (procedure-source foo)
184 (lambda () (lambda (_ _) "docstring" (+ _ _)))))))
186 (with-test-prefix "bad formals"
188 (pass-if-exception "(lambda)"
191 (interaction-environment)))
193 (pass-if-exception "(lambda . \"foo\")"
195 (eval '(lambda . "foo")
196 (interaction-environment)))
198 (pass-if-exception "(lambda \"foo\")"
200 (eval '(lambda "foo")
201 (interaction-environment)))
203 (pass-if-exception "(lambda \"foo\" #f)"
204 exception:bad-formals
205 (eval '(lambda "foo" #f)
206 (interaction-environment)))
208 (pass-if-exception "(lambda (x 1) 2)"
209 exception:bad-formals
210 (eval '(lambda (x 1) 2)
211 (interaction-environment)))
213 (pass-if-exception "(lambda (1 x) 2)"
214 exception:bad-formals
215 (eval '(lambda (1 x) 2)
216 (interaction-environment)))
218 (pass-if-exception "(lambda (x \"a\") 2)"
219 exception:bad-formals
220 (eval '(lambda (x "a") 2)
221 (interaction-environment)))
223 (pass-if-exception "(lambda (\"a\" x) 2)"
224 exception:bad-formals
225 (eval '(lambda ("a" x) 2)
226 (interaction-environment))))
228 (with-test-prefix "duplicate formals"
231 (pass-if-exception "(lambda (x x) 1)"
232 exception:bad-formals
233 (eval '(lambda (x x) 1)
234 (interaction-environment)))
237 (pass-if-exception "(lambda (x x x) 1)"
238 exception:bad-formals
239 (eval '(lambda (x x x) 1)
240 (interaction-environment))))
242 (with-test-prefix "bad body"
244 (pass-if-exception "(lambda ())"
247 (interaction-environment)))))
249 (with-test-prefix "let"
251 (with-test-prefix "unmemoization"
253 (pass-if "normal let"
254 (let ((foo (lambda () (let ((i 1) (j 2)) (+ i j)))))
255 (matches? (procedure-source foo)
256 (lambda () (let ((_ 1) (_ 2)) (+ _ _)))))))
258 (with-test-prefix "bindings"
260 (pass-if-exception "late binding"
261 exception:unbound-var
262 (let ((x 1) (y x)) y)))
264 (with-test-prefix "bad bindings"
266 (pass-if-exception "(let)"
269 (interaction-environment)))
271 (pass-if-exception "(let 1)"
274 (interaction-environment)))
276 (pass-if-exception "(let (x))"
279 (interaction-environment)))
281 (pass-if-exception "(let ((x)))"
284 (interaction-environment)))
286 (pass-if-exception "(let (x) 1)"
289 (interaction-environment)))
291 (pass-if-exception "(let ((x)) 3)"
294 (interaction-environment)))
296 (pass-if-exception "(let ((x 1) y) x)"
298 (eval '(let ((x 1) y) x)
299 (interaction-environment)))
301 (pass-if-exception "(let ((1 2)) 3)"
303 (eval '(let ((1 2)) 3)
304 (interaction-environment))))
306 (with-test-prefix "duplicate bindings"
308 (pass-if-exception "(let ((x 1) (x 2)) x)"
309 exception:duplicate-binding
310 (eval '(let ((x 1) (x 2)) x)
311 (interaction-environment))))
313 (with-test-prefix "bad body"
315 (pass-if-exception "(let ())"
318 (interaction-environment)))
320 (pass-if-exception "(let ((x 1)))"
323 (interaction-environment)))))
325 (with-test-prefix "named let"
327 (with-test-prefix "initializers"
329 (pass-if "evaluated in outer environment"
331 (eqv? (let f ((n (f 1))) n) -1))))
333 (with-test-prefix "bad bindings"
335 (pass-if-exception "(let x (y))"
338 (interaction-environment))))
340 (with-test-prefix "bad body"
342 (pass-if-exception "(let x ())"
345 (interaction-environment)))
347 (pass-if-exception "(let x ((y 1)))"
349 (eval '(let x ((y 1)))
350 (interaction-environment)))))
352 (with-test-prefix "let*"
354 (with-test-prefix "unmemoization"
356 (pass-if "normal let*"
357 (let ((foo (lambda () (let* ((x 1) (y 2)) (+ x y)))))
358 (matches? (procedure-source foo)
359 (lambda () (let ((_ 1)) (let ((_ 2)) (+ _ _)))))))
361 (pass-if "let* without bindings"
362 (let ((foo (lambda () (let ((x 1) (y 2))
364 (and (= x 1) (= y 2)))))))
365 (matches? (procedure-source foo)
366 (lambda () (let ((_ 1) (_ 2))
367 (if (= _ 1) (= _ 2) #f)))))))
369 (with-test-prefix "bindings"
371 (pass-if "(let* ((x 1) (x 2)) ...)"
375 (pass-if "(let* ((x 1) (x x)) ...)"
379 (pass-if "(let ((x 1) (y 2)) (let* () ...))"
382 (and (= x 1) (= y 2))))))
384 (with-test-prefix "bad bindings"
386 (pass-if-exception "(let*)"
387 exception:generic-syncase-error
389 (interaction-environment)))
391 (pass-if-exception "(let* 1)"
392 exception:generic-syncase-error
394 (interaction-environment)))
396 (pass-if-exception "(let* (x))"
397 exception:generic-syncase-error
399 (interaction-environment)))
401 (pass-if-exception "(let* (x) 1)"
402 exception:generic-syncase-error
404 (interaction-environment)))
406 (pass-if-exception "(let* ((x)) 3)"
407 exception:generic-syncase-error
408 (eval '(let* ((x)) 3)
409 (interaction-environment)))
411 (pass-if-exception "(let* ((x 1) y) x)"
412 exception:generic-syncase-error
413 (eval '(let* ((x 1) y) x)
414 (interaction-environment)))
416 (pass-if-exception "(let* x ())"
417 exception:generic-syncase-error
419 (interaction-environment)))
421 (pass-if-exception "(let* x (y))"
422 exception:generic-syncase-error
424 (interaction-environment)))
426 (pass-if-exception "(let* ((1 2)) 3)"
427 exception:generic-syncase-error
428 (eval '(let* ((1 2)) 3)
429 (interaction-environment))))
431 (with-test-prefix "bad body"
433 (pass-if-exception "(let* ())"
434 exception:generic-syncase-error
436 (interaction-environment)))
438 (pass-if-exception "(let* ((x 1)))"
439 exception:generic-syncase-error
440 (eval '(let* ((x 1)))
441 (interaction-environment)))))
443 (with-test-prefix "letrec"
445 (with-test-prefix "unmemoization"
447 (pass-if "normal letrec"
448 (let ((foo (lambda () (letrec ((i 1) (j 2)) (+ i j)))))
449 (matches? (procedure-source foo)
450 (lambda () (letrec ((_ 1) (_ 2)) (+ _ _)))))))
452 (with-test-prefix "bindings"
454 (pass-if-exception "initial bindings are undefined"
455 exception:used-before-defined
457 (letrec ((x 1) (y x)) y))))
459 (with-test-prefix "bad bindings"
461 (pass-if-exception "(letrec)"
464 (interaction-environment)))
466 (pass-if-exception "(letrec 1)"
469 (interaction-environment)))
471 (pass-if-exception "(letrec (x))"
474 (interaction-environment)))
476 (pass-if-exception "(letrec (x) 1)"
478 (eval '(letrec (x) 1)
479 (interaction-environment)))
481 (pass-if-exception "(letrec ((x)) 3)"
483 (eval '(letrec ((x)) 3)
484 (interaction-environment)))
486 (pass-if-exception "(letrec ((x 1) y) x)"
488 (eval '(letrec ((x 1) y) x)
489 (interaction-environment)))
491 (pass-if-exception "(letrec x ())"
494 (interaction-environment)))
496 (pass-if-exception "(letrec x (y))"
498 (eval '(letrec x (y))
499 (interaction-environment)))
501 (pass-if-exception "(letrec ((1 2)) 3)"
503 (eval '(letrec ((1 2)) 3)
504 (interaction-environment))))
506 (with-test-prefix "duplicate bindings"
508 (pass-if-exception "(letrec ((x 1) (x 2)) x)"
509 exception:duplicate-binding
510 (eval '(letrec ((x 1) (x 2)) x)
511 (interaction-environment))))
513 (with-test-prefix "bad body"
515 (pass-if-exception "(letrec ())"
518 (interaction-environment)))
520 (pass-if-exception "(letrec ((x 1)))"
522 (eval '(letrec ((x 1)))
523 (interaction-environment)))))
525 (with-test-prefix "if"
527 (with-test-prefix "unmemoization"
530 (let ((foo (lambda (x) (if x (+ 1) (+ 2)))))
531 (foo #t) ; make sure, memoization has been performed
532 (foo #f) ; make sure, memoization has been performed
533 (matches? (procedure-source foo)
534 (lambda (_) (if _ (+ 1) (+ 2))))))
536 (expect-fail "if without else"
537 (let ((foo (lambda (x) (if x (+ 1)))))
538 (foo #t) ; make sure, memoization has been performed
539 (foo #f) ; make sure, memoization has been performed
540 (equal? (procedure-source foo)
541 '(lambda (x) (if x (+ 1))))))
543 (expect-fail "if #f without else"
544 (let ((foo (lambda () (if #f #f))))
545 (foo) ; make sure, memoization has been performed
546 (equal? (procedure-source foo)
547 `(lambda () (if #f #f))))))
549 (with-test-prefix "missing or extra expressions"
551 (pass-if-exception "(if)"
552 exception:generic-syncase-error
554 (interaction-environment)))
556 (pass-if-exception "(if 1 2 3 4)"
557 exception:generic-syncase-error
559 (interaction-environment)))))
561 (with-test-prefix "cond"
563 (with-test-prefix "cond is hygienic"
565 (pass-if "bound 'else is handled correctly"
566 (eq? (let ((else 'ok)) (cond (else))) 'ok))
568 (with-test-prefix "bound '=> is handled correctly"
572 (eq? (cond (#t => 'ok)) 'ok)))
576 (eq? (cond (else =>)) 'foo)))
578 (pass-if "else => identity"
580 (eq? (cond (else => identity)) identity)))))
582 (with-test-prefix "SRFI-61"
584 (pass-if "always available"
585 (cond-expand (srfi-61 #t) (else #f)))
587 (pass-if "single value consequent"
588 (eq? 'ok (cond (#t identity => (lambda (x) 'ok)) (else #f))))
590 (pass-if "single value alternate"
591 (eq? 'ok (cond (#t not => (lambda (x) #f)) (else 'ok))))
593 (pass-if-exception "doesn't affect standard =>"
594 exception:wrong-num-args
595 (cond ((values 1 2) => (lambda (x y) #t))))
597 (pass-if "multiple values consequent"
598 (equal? '(2 1) (cond ((values 1 2)
600 (and (= 1 one) (= 2 two))) =>
601 (lambda (one two) (list two one)))
604 (pass-if "multiple values alternate"
605 (eq? 'ok (cond ((values 2 3 4)
606 (lambda args (equal? '(1 2 3) args)) =>
610 (pass-if "zero values"
611 (eq? 'ok (cond ((values) (lambda () #t) => (lambda () 'ok))
614 (pass-if "bound => is handled correctly"
616 (eq? 'ok (cond (#t identity =>) (else #f)))))
618 (pass-if-exception "missing recipient"
619 '(syntax-error . "cond: wrong number of receiver expressions")
620 (cond (#t identity =>)))
622 (pass-if-exception "extra recipient"
623 '(syntax-error . "cond: wrong number of receiver expressions")
624 (cond (#t identity => identity identity))))
626 (with-test-prefix "unmemoization"
628 ;; FIXME: the (if #f #f) is a hack!
629 (pass-if "normal clauses"
630 (let ((foo (lambda () (cond ((= x 1) 'bar) ((= x 2) 'baz)))))
631 (equal? (procedure-source foo)
632 '(lambda () (if (= x 1) 'bar (if (= x 2) 'baz (if #f #f)))))))
635 (let ((foo (lambda () (cond (else 'bar)))))
636 (equal? (procedure-source foo)
639 ;; FIXME: the (if #f #f) is a hack!
641 (let ((foo (lambda () (cond (#t => identity)))))
642 (matches? (procedure-source foo)
643 (lambda () (let ((_ #t))
644 (if _ (identity _) (if #f #f))))))))
646 (with-test-prefix "bad or missing clauses"
648 (pass-if-exception "(cond)"
649 exception:generic-syncase-error
651 (interaction-environment)))
653 (pass-if-exception "(cond #t)"
654 exception:generic-syncase-error
656 (interaction-environment)))
658 (pass-if-exception "(cond 1)"
659 exception:generic-syncase-error
661 (interaction-environment)))
663 (pass-if-exception "(cond 1 2)"
664 exception:generic-syncase-error
666 (interaction-environment)))
668 (pass-if-exception "(cond 1 2 3)"
669 exception:generic-syncase-error
671 (interaction-environment)))
673 (pass-if-exception "(cond 1 2 3 4)"
674 exception:generic-syncase-error
675 (eval '(cond 1 2 3 4)
676 (interaction-environment)))
678 (pass-if-exception "(cond ())"
679 exception:generic-syncase-error
681 (interaction-environment)))
683 (pass-if-exception "(cond () 1)"
684 exception:generic-syncase-error
686 (interaction-environment)))
688 (pass-if-exception "(cond (1) 1)"
689 exception:generic-syncase-error
691 (interaction-environment))))
693 (with-test-prefix "wrong number of arguments"
695 (pass-if-exception "=> (lambda (x y) #t)"
696 exception:wrong-num-args
697 (cond (1 => (lambda (x y) #t))))))
699 (with-test-prefix "case"
701 (pass-if "clause with empty labels list"
702 (case 1 (() #f) (else #t)))
704 (with-test-prefix "case is hygienic"
706 (pass-if-exception "bound 'else is handled correctly"
707 exception:generic-syncase-error
708 (eval '(let ((else #f)) (case 1 (else #f)))
709 (interaction-environment))))
711 (with-test-prefix "unmemoization"
713 (pass-if "normal clauses"
714 (let ((foo (lambda (x) (case x ((1) 'bar) ((2) 'baz) (else 'foobar)))))
715 (matches? (procedure-source foo)
717 (if ((@@ (guile) memv) _ '(1))
719 (if ((@@ (guile) memv) _ '(2))
723 (pass-if "empty labels"
724 (let ((foo (lambda (x) (case x ((1) 'bar) (() 'baz) (else 'foobar)))))
725 (matches? (procedure-source foo)
727 (if ((@@ (guile) memv) _ '(1))
729 (if ((@@ (guile) memv) _ '())
733 (with-test-prefix "bad or missing clauses"
735 (pass-if-exception "(case)"
736 exception:generic-syncase-error
738 (interaction-environment)))
740 (pass-if-exception "(case . \"foo\")"
741 exception:generic-syncase-error
742 (eval '(case . "foo")
743 (interaction-environment)))
745 (pass-if-exception "(case 1)"
746 exception:generic-syncase-error
748 (interaction-environment)))
750 (pass-if-exception "(case 1 . \"foo\")"
751 exception:generic-syncase-error
752 (eval '(case 1 . "foo")
753 (interaction-environment)))
755 (pass-if-exception "(case 1 \"foo\")"
756 exception:generic-syncase-error
757 (eval '(case 1 "foo")
758 (interaction-environment)))
760 (pass-if-exception "(case 1 ())"
761 exception:generic-syncase-error
763 (interaction-environment)))
765 (pass-if-exception "(case 1 (\"foo\"))"
766 exception:generic-syncase-error
767 (eval '(case 1 ("foo"))
768 (interaction-environment)))
770 (pass-if-exception "(case 1 (\"foo\" \"bar\"))"
771 exception:generic-syncase-error
772 (eval '(case 1 ("foo" "bar"))
773 (interaction-environment)))
775 (pass-if-exception "(case 1 ((2) \"bar\") . \"foo\")"
776 exception:generic-syncase-error
777 (eval '(case 1 ((2) "bar") . "foo")
778 (interaction-environment)))
780 (pass-if-exception "(case 1 ((2) \"bar\") (else))"
781 exception:generic-syncase-error
782 (eval '(case 1 ((2) "bar") (else))
783 (interaction-environment)))
785 (pass-if-exception "(case 1 (else #f) . \"foo\")"
786 exception:generic-syncase-error
787 (eval '(case 1 (else #f) . "foo")
788 (interaction-environment)))
790 (pass-if-exception "(case 1 (else #f) ((1) #t))"
791 exception:generic-syncase-error
792 (eval '(case 1 (else #f) ((1) #t))
793 (interaction-environment)))))
795 (with-test-prefix "top-level define"
797 (pass-if "redefinition"
798 (let ((m (make-module)))
799 (beautify-user-module! m)
801 ;; The previous value of `round' must still be visible at the time the
802 ;; new `round' is defined. According to R5RS (Section 5.2.1), `define'
803 ;; should behave like `set!' in this case (except that in the case of
804 ;; Guile, we respect module boundaries).
805 (eval '(define round round) m)
806 (eq? (module-ref m 'round) round)))
808 (with-test-prefix "unmemoization"
810 (pass-if "definition unmemoized without prior execution"
812 (define (blub) (cons ('(1 . 2)) 2))
814 (procedure-source blub)
815 '(lambda () (cons ('(1 . 2)) 2))))
816 (interaction-environment)))
818 (pass-if "definition with documentation unmemoized without prior execution"
820 (define (blub) "Comment" (cons ('(1 . 2)) 2))
822 (procedure-source blub)
823 '(lambda () "Comment" (cons ('(1 . 2)) 2))))
824 (interaction-environment))))
826 (with-test-prefix "missing or extra expressions"
828 (pass-if-exception "(define)"
829 exception:generic-syncase-error
831 (interaction-environment)))))
833 (with-test-prefix "internal define"
835 (pass-if "internal defines become letrec"
836 (eval '(let ((a identity) (b identity) (c identity))
837 (define (a x) (if (= x 0) 'a (b (- x 1))))
838 (define (b x) (if (= x 0) 'b (c (- x 1))))
839 (define (c x) (if (= x 0) 'c (a (- x 1))))
840 (and (eq? 'a (a 0) (a 3))
842 (eq? 'c (a 2) (a 5))))
843 (interaction-environment)))
845 (pass-if "binding is created before expression is evaluated"
846 ;; Internal defines are equivalent to `letrec' (R5RS, Section 5.2.2).
853 (interaction-environment))
856 (pass-if "internal defines with begin"
858 (eval '(let ((a identity) (b identity) (c identity))
859 (define (a x) (if (= x 0) 'a (b (- x 1))))
861 (define (b x) (if (= x 0) 'b (c (- x 1)))))
862 (define (c x) (if (= x 0) 'c (a (- x 1))))
863 (and (eq? 'a (a 0) (a 3))
865 (eq? 'c (a 2) (a 5))))
866 (interaction-environment))))
868 (pass-if "internal defines with empty begin"
870 (eval '(let ((a identity) (b identity) (c identity))
871 (define (a x) (if (= x 0) 'a (b (- x 1))))
873 (define (b x) (if (= x 0) 'b (c (- x 1))))
874 (define (c x) (if (= x 0) 'c (a (- x 1))))
875 (and (eq? 'a (a 0) (a 3))
877 (eq? 'c (a 2) (a 5))))
878 (interaction-environment))))
880 (pass-if "internal defines with macro application"
883 (defmacro my-define forms
884 (cons 'define forms))
885 (let ((a identity) (b identity) (c identity))
886 (define (a x) (if (= x 0) 'a (b (- x 1))))
887 (my-define (b x) (if (= x 0) 'b (c (- x 1))))
888 (define (c x) (if (= x 0) 'c (a (- x 1))))
889 (and (eq? 'a (a 0) (a 3))
891 (eq? 'c (a 2) (a 5)))))
892 (interaction-environment))))
894 (pass-if-exception "missing body expression"
895 exception:missing-body-expr
896 (eval '(let () (define x #t))
897 (interaction-environment)))
899 (pass-if "unmemoization"
907 (procedure-source foo)
908 (lambda () (letrec ((_ (lambda () (quote ok)))) (_)))))
911 (with-test-prefix "set!"
913 (with-test-prefix "unmemoization"
915 (pass-if "normal set!"
916 (let ((foo (lambda (x) (set! x (+ 1 x)))))
917 (foo 1) ; make sure, memoization has been performed
918 (matches? (procedure-source foo)
919 (lambda (_) (set! _ (+ 1 _)))))))
921 (with-test-prefix "missing or extra expressions"
923 (pass-if-exception "(set!)"
926 (interaction-environment)))
928 (pass-if-exception "(set! 1)"
931 (interaction-environment)))
933 (pass-if-exception "(set! 1 2 3)"
936 (interaction-environment))))
938 (with-test-prefix "bad variable"
940 (pass-if-exception "(set! \"\" #t)"
943 (interaction-environment)))
945 (pass-if-exception "(set! 1 #t)"
948 (interaction-environment)))
950 (pass-if-exception "(set! #t #f)"
953 (interaction-environment)))
955 (pass-if-exception "(set! #f #t)"
958 (interaction-environment)))
960 (pass-if-exception "(set! #\\space #f)"
962 (eval '(set! #\space #f)
963 (interaction-environment)))))
965 (with-test-prefix "quote"
967 (with-test-prefix "missing or extra expression"
969 (pass-if-exception "(quote)"
972 (interaction-environment)))
974 (pass-if-exception "(quote a b)"
977 (interaction-environment)))))
979 (with-test-prefix "while"
981 (define (unreachable)
982 (error "unreachable code has been reached!"))
984 ;; Return a new procedure COND which when called (COND) will return #t the
985 ;; first N times, then #f, then any further call is an error. N=0 is
986 ;; allowed, in which case #f is returned by the first call.
987 (define (make-iterations-cond n)
990 (error "oops, condition re-tested after giving false"))
999 (pass-if-exception "too few args" exception:wrong-num-args
1000 (eval '(while) (interaction-environment)))
1002 (with-test-prefix "empty body"
1006 (eval `(letrec ((make-iterations-cond
1010 (error "oops, condition re-tested after giving false"))
1017 (let ((cond (make-iterations-cond ,n)))
1020 (interaction-environment)))))
1022 (pass-if "initially false"
1027 (with-test-prefix "iterations"
1031 (let ((cond (make-iterations-cond n))
1037 (with-test-prefix "break"
1039 (pass-if-exception "too many args" exception:wrong-num-args
1042 (interaction-environment)))
1044 (with-test-prefix "from cond"
1055 (let ((cond (make-iterations-cond n))
1065 (with-test-prefix "from body"
1075 (let ((cond (make-iterations-cond n))
1085 (pass-if "from nested"
1087 (let ((outer-break break))
1094 (pass-if "from recursive"
1095 (let ((outer-break #f))
1100 (set! outer-break break)
1106 (error "broke only from inner loop")))
1110 (with-test-prefix "continue"
1112 (pass-if-exception "too many args" exception:wrong-num-args
1115 (interaction-environment)))
1117 (with-test-prefix "from cond"
1121 (let ((cond (make-iterations-cond n))
1132 (with-test-prefix "from body"
1136 (let ((cond (make-iterations-cond n))
1144 (pass-if "from nested"
1145 (let ((cond (make-iterations-cond 3)))
1147 (let ((outer-continue continue))
1153 (pass-if "from recursive"
1154 (let ((outer-continue #f))
1156 (let ((cond (make-iterations-cond 3))
1159 (if (and (not first)
1161 (error "continued only to inner loop"))
1166 (set! outer-continue continue)