Commit | Line | Data |
---|---|---|
08c608e1 DH |
1 | ;;;; syntax.test --- test suite for Guile's syntactic forms -*- scheme -*- |
2 | ;;;; | |
6e7d5622 | 3 | ;;;; Copyright (C) 2001,2003,2004, 2005, 2006 Free Software Foundation, Inc. |
08c608e1 DH |
4 | ;;;; |
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. | |
9 | ;;;; | |
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. | |
14 | ;;;; | |
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 | |
92205699 MV |
17 | ;;;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
18 | ;;;; Boston, MA 02110-1301 USA | |
08c608e1 | 19 | |
8aa28a91 DH |
20 | (define-module (test-suite test-syntax) |
21 | :use-module (test-suite lib)) | |
08c608e1 | 22 | |
2a6f7afe | 23 | |
40b36cfb | 24 | (define exception:generic-syncase-error |
02604212 | 25 | (cons 'syntax-error "source expression failed to match")) |
40b36cfb AW |
26 | (define exception:unexpected-syntax |
27 | (cons 'syntax-error "unexpected syntax")) | |
28 | ||
2a6f7afe DH |
29 | (define exception:bad-expression |
30 | (cons 'syntax-error "Bad expression")) | |
cc56ba80 | 31 | |
21628685 | 32 | (define exception:missing/extra-expr |
89bff2fc | 33 | (cons 'syntax-error "Missing or extra expression")) |
cc56ba80 DH |
34 | (define exception:missing-expr |
35 | (cons 'syntax-error "Missing expression")) | |
ced8edb0 DH |
36 | (define exception:missing-body-expr |
37 | (cons 'syntax-error "Missing body expression")) | |
cc56ba80 DH |
38 | (define exception:extra-expr |
39 | (cons 'syntax-error "Extra expression")) | |
89bff2fc DH |
40 | (define exception:illegal-empty-combination |
41 | (cons 'syntax-error "Illegal empty combination")) | |
cc56ba80 | 42 | |
dc1eed52 AW |
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 ")) | |
08c608e1 | 49 | (define exception:bad-bindings |
d6754c23 DH |
50 | (cons 'syntax-error "Bad bindings")) |
51 | (define exception:bad-binding | |
52 | (cons 'syntax-error "Bad binding")) | |
53 | (define exception:duplicate-binding | |
dc1eed52 | 54 | (cons 'syntax-error "duplicate bound variable")) |
08c608e1 DH |
55 | (define exception:bad-body |
56 | (cons 'misc-error "^bad body")) | |
57 | (define exception:bad-formals | |
dc1eed52 | 58 | '(syntax-error . "invalid parameter list")) |
03a3e941 DH |
59 | (define exception:bad-formal |
60 | (cons 'syntax-error "Bad formal")) | |
61 | (define exception:duplicate-formal | |
62 | (cons 'syntax-error "Duplicate formal")) | |
cc56ba80 | 63 | |
2a6f7afe DH |
64 | (define exception:missing-clauses |
65 | (cons 'syntax-error "Missing clauses")) | |
609a8b86 DH |
66 | (define exception:misplaced-else-clause |
67 | (cons 'syntax-error "Misplaced else clause")) | |
2a6f7afe DH |
68 | (define exception:bad-case-clause |
69 | (cons 'syntax-error "Bad case clause")) | |
2a6f7afe DH |
70 | (define exception:bad-case-labels |
71 | (cons 'syntax-error "Bad case labels")) | |
609a8b86 DH |
72 | (define exception:bad-cond-clause |
73 | (cons 'syntax-error "Bad cond clause")) | |
cc56ba80 | 74 | |
08c608e1 DH |
75 | |
76 | (with-test-prefix "expressions" | |
77 | ||
d6e04e7c DH |
78 | (with-test-prefix "Bad argument list" |
79 | ||
80 | (pass-if-exception "improper argument list of length 1" | |
40b36cfb | 81 | exception:generic-syncase-error |
d6e04e7c DH |
82 | (eval '(let ((foo (lambda (x y) #t))) |
83 | (foo . 1)) | |
84 | (interaction-environment))) | |
85 | ||
86 | (pass-if-exception "improper argument list of length 2" | |
40b36cfb | 87 | exception:generic-syncase-error |
d6e04e7c DH |
88 | (eval '(let ((foo (lambda (x y) #t))) |
89 | (foo 1 . 2)) | |
90 | (interaction-environment)))) | |
91 | ||
08c608e1 DH |
92 | (with-test-prefix "missing or extra expression" |
93 | ||
94 | ;; R5RS says: | |
95 | ;; *Note:* In many dialects of Lisp, the empty combination, (), | |
96 | ;; is a legitimate expression. In Scheme, combinations must | |
97 | ;; have at least one subexpression, so () is not a syntactically | |
98 | ;; valid expression. | |
1c54a87c MV |
99 | |
100 | ;; Fixed on 2001-3-3 | |
101 | (pass-if-exception "empty parentheses \"()\"" | |
40b36cfb | 102 | exception:unexpected-syntax |
d6e04e7c DH |
103 | (eval '() |
104 | (interaction-environment))))) | |
08c608e1 | 105 | |
7171f1ab DH |
106 | (with-test-prefix "quote" |
107 | #t) | |
108 | ||
109 | (with-test-prefix "quasiquote" | |
110 | ||
111 | (with-test-prefix "unquote" | |
112 | ||
113 | (pass-if "repeated execution" | |
114 | (let ((foo (let ((i 0)) (lambda () (set! i (+ i 1)) `(,i))))) | |
115 | (and (equal? (foo) '(1)) (equal? (foo) '(2)))))) | |
116 | ||
117 | (with-test-prefix "unquote-splicing" | |
118 | ||
119 | (pass-if-exception "extra arguments" | |
02604212 AW |
120 | '(syntax-error . "unquote-splicing takes exactly one argument") |
121 | (eval '(quasiquote ((unquote-splicing (list 1 2) (list 3 4)))) | |
122 | (interaction-environment))))) | |
7171f1ab DH |
123 | |
124 | (with-test-prefix "begin" | |
125 | ||
126 | (pass-if "legal (begin)" | |
ce09ee19 | 127 | (eval '(begin (begin) #t) (interaction-environment))) |
7171f1ab | 128 | |
aa498d0c DH |
129 | (with-test-prefix "unmemoization" |
130 | ||
02604212 AW |
131 | ;; FIXME. I have no idea why, but the expander is filling in (if #f |
132 | ;; #f) as the second arm of the if, if the second arm is missing. I | |
133 | ;; thought I made it not do that. But in the meantime, let's adapt, | |
134 | ;; since that's not what we're testing. | |
135 | ||
aa498d0c | 136 | (pass-if "normal begin" |
02604212 | 137 | (let ((foo (lambda () (if (= 1 1) (begin (+ 1) (+ 2)) #f)))) |
aa498d0c | 138 | (equal? (procedure-source foo) |
02604212 | 139 | '(lambda () (if (= 1 1) (begin (+ 1) (+ 2)) #f))))) |
aa498d0c DH |
140 | |
141 | (pass-if "redundant nested begin" | |
02604212 | 142 | (let ((foo (lambda () (if (= 1 1) (begin (+ 1) (begin (+ 2) (+ 3))) #f)))) |
aa498d0c DH |
143 | (foo) ; make sure, memoization has been performed |
144 | (equal? (procedure-source foo) | |
02604212 | 145 | '(lambda () (if (= 1 1) (begin (+ 1) (begin (+ 2) (+ 3))) #f))))) |
aa498d0c DH |
146 | |
147 | (pass-if "redundant begin at start of body" | |
148 | (let ((foo (lambda () (begin (+ 1) (+ 2))))) ; should be optimized | |
149 | (foo) ; make sure, memoization has been performed | |
150 | (equal? (procedure-source foo) | |
151 | '(lambda () (begin (+ 1) (+ 2))))))) | |
152 | ||
02604212 AW |
153 | (pass-if-exception "illegal (begin)" |
154 | exception:generic-syncase-error | |
ce09ee19 | 155 | (eval '(begin (if #t (begin)) #t) (interaction-environment)))) |
7171f1ab | 156 | |
02604212 AW |
157 | (define-syntax matches? |
158 | (syntax-rules (_) | |
159 | ((_ (op arg ...) pat) (let ((x (op arg ...))) | |
160 | (matches? x pat))) | |
161 | ((_ x ()) (null? x)) | |
162 | ((_ x (a . b)) (and (pair? x) | |
163 | (matches? (car x) a) | |
164 | (matches? (cdr x) b))) | |
165 | ((_ x _) #t) | |
166 | ((_ x pat) (equal? x 'pat)))) | |
167 | ||
08c608e1 DH |
168 | (with-test-prefix "lambda" |
169 | ||
aa498d0c DH |
170 | (with-test-prefix "unmemoization" |
171 | ||
172 | (pass-if "normal lambda" | |
173 | (let ((foo (lambda () (lambda (x y) (+ x y))))) | |
02604212 AW |
174 | (matches? (procedure-source foo) |
175 | (lambda () (lambda (_ _) (+ _ _)))))) | |
aa498d0c DH |
176 | |
177 | (pass-if "lambda with documentation" | |
178 | (let ((foo (lambda () (lambda (x y) "docstring" (+ x y))))) | |
02604212 AW |
179 | (matches? (procedure-source foo) |
180 | (lambda () (lambda (_ _) "docstring" (+ _ _))))))) | |
aa498d0c | 181 | |
08c608e1 DH |
182 | (with-test-prefix "bad formals" |
183 | ||
ea6c2147 | 184 | (pass-if-exception "(lambda)" |
dc1eed52 | 185 | exception:bad-lambda |
d6e04e7c DH |
186 | (eval '(lambda) |
187 | (interaction-environment))) | |
ea6c2147 DH |
188 | |
189 | (pass-if-exception "(lambda . \"foo\")" | |
dc1eed52 | 190 | exception:bad-lambda |
d6e04e7c DH |
191 | (eval '(lambda . "foo") |
192 | (interaction-environment))) | |
ea6c2147 | 193 | |
ea6c2147 | 194 | (pass-if-exception "(lambda \"foo\")" |
dc1eed52 | 195 | exception:bad-lambda |
d6e04e7c DH |
196 | (eval '(lambda "foo") |
197 | (interaction-environment))) | |
ea6c2147 DH |
198 | |
199 | (pass-if-exception "(lambda \"foo\" #f)" | |
200 | exception:bad-formals | |
4dce3c96 DH |
201 | (eval '(lambda "foo" #f) |
202 | (interaction-environment))) | |
ea6c2147 DH |
203 | |
204 | (pass-if-exception "(lambda (x 1) 2)" | |
dc1eed52 | 205 | exception:bad-formals |
d6e04e7c DH |
206 | (eval '(lambda (x 1) 2) |
207 | (interaction-environment))) | |
08c608e1 DH |
208 | |
209 | (pass-if-exception "(lambda (1 x) 2)" | |
dc1eed52 | 210 | exception:bad-formals |
d6e04e7c DH |
211 | (eval '(lambda (1 x) 2) |
212 | (interaction-environment))) | |
08c608e1 DH |
213 | |
214 | (pass-if-exception "(lambda (x \"a\") 2)" | |
dc1eed52 | 215 | exception:bad-formals |
d6e04e7c DH |
216 | (eval '(lambda (x "a") 2) |
217 | (interaction-environment))) | |
08c608e1 DH |
218 | |
219 | (pass-if-exception "(lambda (\"a\" x) 2)" | |
dc1eed52 | 220 | exception:bad-formals |
d6e04e7c DH |
221 | (eval '(lambda ("a" x) 2) |
222 | (interaction-environment)))) | |
08c608e1 | 223 | |
1c54a87c MV |
224 | (with-test-prefix "duplicate formals" |
225 | ||
226 | ;; Fixed on 2001-3-3 | |
227 | (pass-if-exception "(lambda (x x) 1)" | |
dc1eed52 | 228 | exception:bad-formals |
d6e04e7c DH |
229 | (eval '(lambda (x x) 1) |
230 | (interaction-environment))) | |
08c608e1 | 231 | |
1c54a87c MV |
232 | ;; Fixed on 2001-3-3 |
233 | (pass-if-exception "(lambda (x x x) 1)" | |
dc1eed52 | 234 | exception:bad-formals |
d6e04e7c DH |
235 | (eval '(lambda (x x x) 1) |
236 | (interaction-environment)))) | |
7171f1ab DH |
237 | |
238 | (with-test-prefix "bad body" | |
239 | ||
240 | (pass-if-exception "(lambda ())" | |
dc1eed52 | 241 | exception:bad-lambda |
d6e04e7c DH |
242 | (eval '(lambda ()) |
243 | (interaction-environment))))) | |
08c608e1 DH |
244 | |
245 | (with-test-prefix "let" | |
246 | ||
aa498d0c DH |
247 | (with-test-prefix "unmemoization" |
248 | ||
249 | (pass-if "normal let" | |
250 | (let ((foo (lambda () (let ((i 1) (j 2)) (+ i j))))) | |
dc1eed52 AW |
251 | (matches? (procedure-source foo) |
252 | (lambda () (let ((_ 1) (_ 2)) (+ _ _))))))) | |
aa498d0c | 253 | |
08c608e1 DH |
254 | (with-test-prefix "bindings" |
255 | ||
256 | (pass-if-exception "late binding" | |
257 | exception:unbound-var | |
258 | (let ((x 1) (y x)) y))) | |
259 | ||
7171f1ab | 260 | (with-test-prefix "bad bindings" |
08c608e1 | 261 | |
08c608e1 | 262 | (pass-if-exception "(let)" |
dc1eed52 | 263 | exception:bad-let |
d6e04e7c DH |
264 | (eval '(let) |
265 | (interaction-environment))) | |
08c608e1 | 266 | |
08c608e1 | 267 | (pass-if-exception "(let 1)" |
dc1eed52 | 268 | exception:bad-let |
d6e04e7c DH |
269 | (eval '(let 1) |
270 | (interaction-environment))) | |
08c608e1 | 271 | |
08c608e1 | 272 | (pass-if-exception "(let (x))" |
dc1eed52 | 273 | exception:bad-let |
d6e04e7c DH |
274 | (eval '(let (x)) |
275 | (interaction-environment))) | |
08c608e1 | 276 | |
7171f1ab | 277 | (pass-if-exception "(let ((x)))" |
dc1eed52 | 278 | exception:bad-let |
d6e04e7c DH |
279 | (eval '(let ((x))) |
280 | (interaction-environment))) | |
08c608e1 DH |
281 | |
282 | (pass-if-exception "(let (x) 1)" | |
dc1eed52 | 283 | exception:bad-let |
d6e04e7c DH |
284 | (eval '(let (x) 1) |
285 | (interaction-environment))) | |
08c608e1 DH |
286 | |
287 | (pass-if-exception "(let ((x)) 3)" | |
dc1eed52 | 288 | exception:bad-let |
d6e04e7c DH |
289 | (eval '(let ((x)) 3) |
290 | (interaction-environment))) | |
08c608e1 DH |
291 | |
292 | (pass-if-exception "(let ((x 1) y) x)" | |
dc1eed52 | 293 | exception:bad-let |
d6e04e7c DH |
294 | (eval '(let ((x 1) y) x) |
295 | (interaction-environment))) | |
08c608e1 DH |
296 | |
297 | (pass-if-exception "(let ((1 2)) 3)" | |
dc1eed52 | 298 | exception:bad-let |
4dce3c96 DH |
299 | (eval '(let ((1 2)) 3) |
300 | (interaction-environment)))) | |
08c608e1 | 301 | |
c0ed1605 MV |
302 | (with-test-prefix "duplicate bindings" |
303 | ||
304 | (pass-if-exception "(let ((x 1) (x 2)) x)" | |
d6754c23 | 305 | exception:duplicate-binding |
d6e04e7c DH |
306 | (eval '(let ((x 1) (x 2)) x) |
307 | (interaction-environment)))) | |
7171f1ab DH |
308 | |
309 | (with-test-prefix "bad body" | |
310 | ||
311 | (pass-if-exception "(let ())" | |
dc1eed52 | 312 | exception:bad-let |
d6e04e7c DH |
313 | (eval '(let ()) |
314 | (interaction-environment))) | |
7171f1ab DH |
315 | |
316 | (pass-if-exception "(let ((x 1)))" | |
dc1eed52 | 317 | exception:bad-let |
d6e04e7c DH |
318 | (eval '(let ((x 1))) |
319 | (interaction-environment))))) | |
08c608e1 DH |
320 | |
321 | (with-test-prefix "named let" | |
322 | ||
7171f1ab DH |
323 | (with-test-prefix "initializers" |
324 | ||
325 | (pass-if "evaluated in outer environment" | |
326 | (let ((f -)) | |
327 | (eqv? (let f ((n (f 1))) n) -1)))) | |
328 | ||
329 | (with-test-prefix "bad bindings" | |
330 | ||
331 | (pass-if-exception "(let x (y))" | |
dc1eed52 | 332 | exception:bad-let |
d6e04e7c DH |
333 | (eval '(let x (y)) |
334 | (interaction-environment)))) | |
7171f1ab | 335 | |
08c608e1 DH |
336 | (with-test-prefix "bad body" |
337 | ||
338 | (pass-if-exception "(let x ())" | |
dc1eed52 | 339 | exception:bad-let |
d6e04e7c DH |
340 | (eval '(let x ()) |
341 | (interaction-environment))) | |
08c608e1 DH |
342 | |
343 | (pass-if-exception "(let x ((y 1)))" | |
dc1eed52 | 344 | exception:bad-let |
d6e04e7c DH |
345 | (eval '(let x ((y 1))) |
346 | (interaction-environment))))) | |
08c608e1 DH |
347 | |
348 | (with-test-prefix "let*" | |
349 | ||
aa498d0c DH |
350 | (with-test-prefix "unmemoization" |
351 | ||
352 | (pass-if "normal let*" | |
353 | (let ((foo (lambda () (let* ((x 1) (y 2)) (+ x y))))) | |
dc1eed52 AW |
354 | (matches? (procedure-source foo) |
355 | (lambda () (let ((_ 1)) (let ((_ 2)) (+ _ _))))))) | |
aa498d0c DH |
356 | |
357 | (pass-if "let* without bindings" | |
358 | (let ((foo (lambda () (let ((x 1) (y 2)) | |
359 | (let* () | |
360 | (and (= x 1) (= y 2))))))) | |
dc1eed52 AW |
361 | (matches? (procedure-source foo) |
362 | (lambda () (let ((_ 1) (_ 2)) | |
363 | (if (= _ 1) (= _ 2) #f))))))) | |
aa498d0c | 364 | |
e1a7b2ce DH |
365 | (with-test-prefix "bindings" |
366 | ||
367 | (pass-if "(let* ((x 1) (x 2)) ...)" | |
368 | (let* ((x 1) (x 2)) | |
369 | (= x 2))) | |
370 | ||
371 | (pass-if "(let* ((x 1) (x x)) ...)" | |
372 | (let* ((x 1) (x x)) | |
aa498d0c DH |
373 | (= x 1))) |
374 | ||
375 | (pass-if "(let ((x 1) (y 2)) (let* () ...))" | |
376 | (let ((x 1) (y 2)) | |
377 | (let* () | |
378 | (and (= x 1) (= y 2)))))) | |
e1a7b2ce | 379 | |
7171f1ab | 380 | (with-test-prefix "bad bindings" |
08c608e1 | 381 | |
08c608e1 | 382 | (pass-if-exception "(let*)" |
dc1eed52 | 383 | exception:generic-syncase-error |
d6e04e7c DH |
384 | (eval '(let*) |
385 | (interaction-environment))) | |
08c608e1 | 386 | |
08c608e1 | 387 | (pass-if-exception "(let* 1)" |
dc1eed52 | 388 | exception:generic-syncase-error |
d6e04e7c DH |
389 | (eval '(let* 1) |
390 | (interaction-environment))) | |
08c608e1 | 391 | |
08c608e1 | 392 | (pass-if-exception "(let* (x))" |
dc1eed52 | 393 | exception:generic-syncase-error |
d6e04e7c DH |
394 | (eval '(let* (x)) |
395 | (interaction-environment))) | |
08c608e1 DH |
396 | |
397 | (pass-if-exception "(let* (x) 1)" | |
dc1eed52 | 398 | exception:generic-syncase-error |
d6e04e7c DH |
399 | (eval '(let* (x) 1) |
400 | (interaction-environment))) | |
08c608e1 DH |
401 | |
402 | (pass-if-exception "(let* ((x)) 3)" | |
dc1eed52 | 403 | exception:generic-syncase-error |
d6e04e7c DH |
404 | (eval '(let* ((x)) 3) |
405 | (interaction-environment))) | |
08c608e1 DH |
406 | |
407 | (pass-if-exception "(let* ((x 1) y) x)" | |
dc1eed52 | 408 | exception:generic-syncase-error |
d6e04e7c DH |
409 | (eval '(let* ((x 1) y) x) |
410 | (interaction-environment))) | |
08c608e1 DH |
411 | |
412 | (pass-if-exception "(let* x ())" | |
dc1eed52 | 413 | exception:generic-syncase-error |
4dce3c96 DH |
414 | (eval '(let* x ()) |
415 | (interaction-environment))) | |
08c608e1 DH |
416 | |
417 | (pass-if-exception "(let* x (y))" | |
dc1eed52 | 418 | exception:generic-syncase-error |
4dce3c96 DH |
419 | (eval '(let* x (y)) |
420 | (interaction-environment))) | |
08c608e1 DH |
421 | |
422 | (pass-if-exception "(let* ((1 2)) 3)" | |
dc1eed52 | 423 | exception:generic-syncase-error |
4dce3c96 DH |
424 | (eval '(let* ((1 2)) 3) |
425 | (interaction-environment)))) | |
7171f1ab DH |
426 | |
427 | (with-test-prefix "bad body" | |
428 | ||
429 | (pass-if-exception "(let* ())" | |
dc1eed52 | 430 | exception:generic-syncase-error |
d6e04e7c DH |
431 | (eval '(let* ()) |
432 | (interaction-environment))) | |
7171f1ab DH |
433 | |
434 | (pass-if-exception "(let* ((x 1)))" | |
dc1eed52 | 435 | exception:generic-syncase-error |
d6e04e7c DH |
436 | (eval '(let* ((x 1))) |
437 | (interaction-environment))))) | |
08c608e1 DH |
438 | |
439 | (with-test-prefix "letrec" | |
440 | ||
aa498d0c DH |
441 | (with-test-prefix "unmemoization" |
442 | ||
443 | (pass-if "normal letrec" | |
444 | (let ((foo (lambda () (letrec ((i 1) (j 2)) (+ i j))))) | |
dc1eed52 AW |
445 | (matches? (procedure-source foo) |
446 | (lambda () (letrec ((_ 1) (_ 2)) (+ _ _))))))) | |
aa498d0c | 447 | |
08c608e1 DH |
448 | (with-test-prefix "bindings" |
449 | ||
450 | (pass-if-exception "initial bindings are undefined" | |
0ac46745 | 451 | exception:used-before-defined |
08c608e1 DH |
452 | (let ((x 1)) |
453 | (letrec ((x 1) (y x)) y)))) | |
454 | ||
7171f1ab | 455 | (with-test-prefix "bad bindings" |
08c608e1 | 456 | |
08c608e1 | 457 | (pass-if-exception "(letrec)" |
dc1eed52 | 458 | exception:bad-letrec |
d6e04e7c DH |
459 | (eval '(letrec) |
460 | (interaction-environment))) | |
08c608e1 | 461 | |
08c608e1 | 462 | (pass-if-exception "(letrec 1)" |
dc1eed52 | 463 | exception:bad-letrec |
d6e04e7c DH |
464 | (eval '(letrec 1) |
465 | (interaction-environment))) | |
08c608e1 | 466 | |
08c608e1 | 467 | (pass-if-exception "(letrec (x))" |
dc1eed52 | 468 | exception:bad-letrec |
d6e04e7c DH |
469 | (eval '(letrec (x)) |
470 | (interaction-environment))) | |
08c608e1 DH |
471 | |
472 | (pass-if-exception "(letrec (x) 1)" | |
dc1eed52 | 473 | exception:bad-letrec |
d6e04e7c DH |
474 | (eval '(letrec (x) 1) |
475 | (interaction-environment))) | |
08c608e1 DH |
476 | |
477 | (pass-if-exception "(letrec ((x)) 3)" | |
dc1eed52 | 478 | exception:bad-letrec |
d6e04e7c DH |
479 | (eval '(letrec ((x)) 3) |
480 | (interaction-environment))) | |
08c608e1 DH |
481 | |
482 | (pass-if-exception "(letrec ((x 1) y) x)" | |
dc1eed52 | 483 | exception:bad-letrec |
d6e04e7c DH |
484 | (eval '(letrec ((x 1) y) x) |
485 | (interaction-environment))) | |
08c608e1 DH |
486 | |
487 | (pass-if-exception "(letrec x ())" | |
dc1eed52 | 488 | exception:bad-letrec |
4dce3c96 DH |
489 | (eval '(letrec x ()) |
490 | (interaction-environment))) | |
08c608e1 DH |
491 | |
492 | (pass-if-exception "(letrec x (y))" | |
dc1eed52 | 493 | exception:bad-letrec |
4dce3c96 DH |
494 | (eval '(letrec x (y)) |
495 | (interaction-environment))) | |
08c608e1 DH |
496 | |
497 | (pass-if-exception "(letrec ((1 2)) 3)" | |
dc1eed52 | 498 | exception:bad-letrec |
4dce3c96 DH |
499 | (eval '(letrec ((1 2)) 3) |
500 | (interaction-environment)))) | |
08c608e1 | 501 | |
c0ed1605 MV |
502 | (with-test-prefix "duplicate bindings" |
503 | ||
504 | (pass-if-exception "(letrec ((x 1) (x 2)) x)" | |
d6754c23 | 505 | exception:duplicate-binding |
d6e04e7c DH |
506 | (eval '(letrec ((x 1) (x 2)) x) |
507 | (interaction-environment)))) | |
7171f1ab DH |
508 | |
509 | (with-test-prefix "bad body" | |
510 | ||
511 | (pass-if-exception "(letrec ())" | |
dc1eed52 | 512 | exception:bad-letrec |
d6e04e7c DH |
513 | (eval '(letrec ()) |
514 | (interaction-environment))) | |
7171f1ab DH |
515 | |
516 | (pass-if-exception "(letrec ((x 1)))" | |
dc1eed52 | 517 | exception:bad-letrec |
d6e04e7c DH |
518 | (eval '(letrec ((x 1))) |
519 | (interaction-environment))))) | |
08c608e1 DH |
520 | |
521 | (with-test-prefix "if" | |
522 | ||
aa498d0c DH |
523 | (with-test-prefix "unmemoization" |
524 | ||
525 | (pass-if "normal if" | |
526 | (let ((foo (lambda (x) (if x (+ 1) (+ 2))))) | |
527 | (foo #t) ; make sure, memoization has been performed | |
528 | (foo #f) ; make sure, memoization has been performed | |
dc1eed52 AW |
529 | (matches? (procedure-source foo) |
530 | (lambda (_) (if _ (+ 1) (+ 2)))))) | |
aa498d0c | 531 | |
dc1eed52 | 532 | (expect-fail "if without else" |
aa498d0c DH |
533 | (let ((foo (lambda (x) (if x (+ 1))))) |
534 | (foo #t) ; make sure, memoization has been performed | |
535 | (foo #f) ; make sure, memoization has been performed | |
536 | (equal? (procedure-source foo) | |
537 | '(lambda (x) (if x (+ 1)))))) | |
538 | ||
dc1eed52 | 539 | (expect-fail "if #f without else" |
aa498d0c DH |
540 | (let ((foo (lambda () (if #f #f)))) |
541 | (foo) ; make sure, memoization has been performed | |
542 | (equal? (procedure-source foo) | |
543 | `(lambda () (if #f #f)))))) | |
544 | ||
08c608e1 DH |
545 | (with-test-prefix "missing or extra expressions" |
546 | ||
547 | (pass-if-exception "(if)" | |
dc1eed52 | 548 | exception:generic-syncase-error |
4dce3c96 DH |
549 | (eval '(if) |
550 | (interaction-environment))) | |
08c608e1 DH |
551 | |
552 | (pass-if-exception "(if 1 2 3 4)" | |
dc1eed52 | 553 | exception:generic-syncase-error |
4dce3c96 DH |
554 | (eval '(if 1 2 3 4) |
555 | (interaction-environment))))) | |
08c608e1 DH |
556 | |
557 | (with-test-prefix "cond" | |
558 | ||
aa498d0c DH |
559 | (with-test-prefix "cond is hygienic" |
560 | ||
561 | (pass-if "bound 'else is handled correctly" | |
562 | (eq? (let ((else 'ok)) (cond (else))) 'ok)) | |
563 | ||
564 | (with-test-prefix "bound '=> is handled correctly" | |
565 | ||
566 | (pass-if "#t => 'ok" | |
567 | (let ((=> 'foo)) | |
568 | (eq? (cond (#t => 'ok)) 'ok))) | |
569 | ||
570 | (pass-if "else =>" | |
571 | (let ((=> 'foo)) | |
572 | (eq? (cond (else =>)) 'foo))) | |
573 | ||
574 | (pass-if "else => identity" | |
575 | (let ((=> 'foo)) | |
576 | (eq? (cond (else => identity)) identity))))) | |
577 | ||
9ee0f678 LC |
578 | (with-test-prefix "SRFI-61" |
579 | ||
580 | (pass-if "always available" | |
581 | (cond-expand (srfi-61 #t) (else #f))) | |
582 | ||
583 | (pass-if "single value consequent" | |
584 | (eq? 'ok (cond (#t identity => (lambda (x) 'ok)) (else #f)))) | |
585 | ||
586 | (pass-if "single value alternate" | |
587 | (eq? 'ok (cond (#t not => (lambda (x) #f)) (else 'ok)))) | |
588 | ||
589 | (pass-if-exception "doesn't affect standard =>" | |
590 | exception:wrong-num-args | |
591 | (cond ((values 1 2) => (lambda (x y) #t)))) | |
592 | ||
593 | (pass-if "multiple values consequent" | |
594 | (equal? '(2 1) (cond ((values 1 2) | |
595 | (lambda (one two) | |
596 | (and (= 1 one) (= 2 two))) => | |
597 | (lambda (one two) (list two one))) | |
598 | (else #f)))) | |
599 | ||
600 | (pass-if "multiple values alternate" | |
601 | (eq? 'ok (cond ((values 2 3 4) | |
602 | (lambda args (equal? '(1 2 3) args)) => | |
603 | (lambda (x y z) #f)) | |
604 | (else 'ok)))) | |
605 | ||
606 | (pass-if "zero values" | |
607 | (eq? 'ok (cond ((values) (lambda () #t) => (lambda () 'ok)) | |
608 | (else #f)))) | |
609 | ||
610 | (pass-if "bound => is handled correctly" | |
611 | (let ((=> 'ok)) | |
612 | (eq? 'ok (cond (#t identity =>) (else #f))))) | |
613 | ||
614 | (pass-if-exception "missing recipient" | |
dc1eed52 | 615 | '(syntax-error . "cond: wrong number of receiver expressions") |
9ee0f678 LC |
616 | (cond (#t identity =>))) |
617 | ||
618 | (pass-if-exception "extra recipient" | |
dc1eed52 | 619 | '(syntax-error . "cond: wrong number of receiver expressions") |
9ee0f678 LC |
620 | (cond (#t identity => identity identity)))) |
621 | ||
aa498d0c DH |
622 | (with-test-prefix "unmemoization" |
623 | ||
dc1eed52 | 624 | ;; FIXME: the (if #f #f) is a hack! |
aa498d0c | 625 | (pass-if "normal clauses" |
dc1eed52 | 626 | (let ((foo (lambda () (cond ((= x 1) 'bar) ((= x 2) 'baz))))) |
aa498d0c | 627 | (equal? (procedure-source foo) |
dc1eed52 | 628 | '(lambda () (if (= x 1) 'bar (if (= x 2) 'baz (if #f #f))))))) |
aa498d0c DH |
629 | |
630 | (pass-if "else" | |
631 | (let ((foo (lambda () (cond (else 'bar))))) | |
aa498d0c | 632 | (equal? (procedure-source foo) |
dc1eed52 | 633 | '(lambda () 'bar)))) |
aa498d0c | 634 | |
dc1eed52 | 635 | ;; FIXME: the (if #f #f) is a hack! |
aa498d0c DH |
636 | (pass-if "=>" |
637 | (let ((foo (lambda () (cond (#t => identity))))) | |
dc1eed52 AW |
638 | (matches? (procedure-source foo) |
639 | (lambda () (let ((_ #t)) | |
640 | (if _ (identity _) (if #f #f)))))))) | |
aa498d0c | 641 | |
08c608e1 DH |
642 | (with-test-prefix "bad or missing clauses" |
643 | ||
644 | (pass-if-exception "(cond)" | |
dc1eed52 | 645 | exception:generic-syncase-error |
d6e04e7c DH |
646 | (eval '(cond) |
647 | (interaction-environment))) | |
08c608e1 DH |
648 | |
649 | (pass-if-exception "(cond #t)" | |
dc1eed52 | 650 | exception:generic-syncase-error |
d6e04e7c DH |
651 | (eval '(cond #t) |
652 | (interaction-environment))) | |
08c608e1 DH |
653 | |
654 | (pass-if-exception "(cond 1)" | |
dc1eed52 | 655 | exception:generic-syncase-error |
d6e04e7c DH |
656 | (eval '(cond 1) |
657 | (interaction-environment))) | |
08c608e1 DH |
658 | |
659 | (pass-if-exception "(cond 1 2)" | |
dc1eed52 | 660 | exception:generic-syncase-error |
d6e04e7c DH |
661 | (eval '(cond 1 2) |
662 | (interaction-environment))) | |
08c608e1 DH |
663 | |
664 | (pass-if-exception "(cond 1 2 3)" | |
dc1eed52 | 665 | exception:generic-syncase-error |
d6e04e7c DH |
666 | (eval '(cond 1 2 3) |
667 | (interaction-environment))) | |
08c608e1 DH |
668 | |
669 | (pass-if-exception "(cond 1 2 3 4)" | |
dc1eed52 | 670 | exception:generic-syncase-error |
d6e04e7c DH |
671 | (eval '(cond 1 2 3 4) |
672 | (interaction-environment))) | |
08c608e1 DH |
673 | |
674 | (pass-if-exception "(cond ())" | |
dc1eed52 | 675 | exception:generic-syncase-error |
d6e04e7c DH |
676 | (eval '(cond ()) |
677 | (interaction-environment))) | |
08c608e1 DH |
678 | |
679 | (pass-if-exception "(cond () 1)" | |
dc1eed52 | 680 | exception:generic-syncase-error |
d6e04e7c DH |
681 | (eval '(cond () 1) |
682 | (interaction-environment))) | |
08c608e1 DH |
683 | |
684 | (pass-if-exception "(cond (1) 1)" | |
dc1eed52 | 685 | exception:generic-syncase-error |
d6e04e7c | 686 | (eval '(cond (1) 1) |
aa498d0c | 687 | (interaction-environment)))) |
b461abe7 | 688 | |
d6e04e7c | 689 | (with-test-prefix "wrong number of arguments" |
08c608e1 | 690 | |
d6e04e7c DH |
691 | (pass-if-exception "=> (lambda (x y) #t)" |
692 | exception:wrong-num-args | |
693 | (cond (1 => (lambda (x y) #t)))))) | |
08c608e1 | 694 | |
27a22666 DH |
695 | (with-test-prefix "case" |
696 | ||
58a2510b DH |
697 | (pass-if "clause with empty labels list" |
698 | (case 1 (() #f) (else #t))) | |
699 | ||
2a6f7afe DH |
700 | (with-test-prefix "case is hygienic" |
701 | ||
702 | (pass-if-exception "bound 'else is handled correctly" | |
dc1eed52 | 703 | exception:generic-syncase-error |
2a6f7afe DH |
704 | (eval '(let ((else #f)) (case 1 (else #f))) |
705 | (interaction-environment)))) | |
706 | ||
aa498d0c DH |
707 | (with-test-prefix "unmemoization" |
708 | ||
709 | (pass-if "normal clauses" | |
710 | (let ((foo (lambda (x) (case x ((1) 'bar) ((2) 'baz) (else 'foobar))))) | |
dc1eed52 AW |
711 | (matches? (procedure-source foo) |
712 | (lambda (_) | |
713 | (if ((@@ (guile) memv) _ '(1)) | |
714 | 'bar | |
715 | (if ((@@ (guile) memv) _ '(2)) | |
716 | 'baz | |
717 | 'foobar)))))) | |
aa498d0c DH |
718 | |
719 | (pass-if "empty labels" | |
720 | (let ((foo (lambda (x) (case x ((1) 'bar) (() 'baz) (else 'foobar))))) | |
dc1eed52 AW |
721 | (matches? (procedure-source foo) |
722 | (lambda (_) | |
723 | (if ((@@ (guile) memv) _ '(1)) | |
724 | 'bar | |
725 | (if ((@@ (guile) memv) _ '()) | |
726 | 'baz | |
727 | 'foobar))))))) | |
aa498d0c | 728 | |
27a22666 DH |
729 | (with-test-prefix "bad or missing clauses" |
730 | ||
731 | (pass-if-exception "(case)" | |
dc1eed52 | 732 | exception:generic-syncase-error |
d6e04e7c DH |
733 | (eval '(case) |
734 | (interaction-environment))) | |
27a22666 | 735 | |
27a22666 | 736 | (pass-if-exception "(case . \"foo\")" |
dc1eed52 | 737 | exception:generic-syncase-error |
d6e04e7c DH |
738 | (eval '(case . "foo") |
739 | (interaction-environment))) | |
27a22666 DH |
740 | |
741 | (pass-if-exception "(case 1)" | |
dc1eed52 | 742 | exception:generic-syncase-error |
d6e04e7c DH |
743 | (eval '(case 1) |
744 | (interaction-environment))) | |
27a22666 | 745 | |
27a22666 | 746 | (pass-if-exception "(case 1 . \"foo\")" |
dc1eed52 | 747 | exception:generic-syncase-error |
d6e04e7c DH |
748 | (eval '(case 1 . "foo") |
749 | (interaction-environment))) | |
27a22666 DH |
750 | |
751 | (pass-if-exception "(case 1 \"foo\")" | |
dc1eed52 | 752 | exception:generic-syncase-error |
d6e04e7c DH |
753 | (eval '(case 1 "foo") |
754 | (interaction-environment))) | |
27a22666 DH |
755 | |
756 | (pass-if-exception "(case 1 ())" | |
dc1eed52 | 757 | exception:generic-syncase-error |
d6e04e7c DH |
758 | (eval '(case 1 ()) |
759 | (interaction-environment))) | |
27a22666 DH |
760 | |
761 | (pass-if-exception "(case 1 (\"foo\"))" | |
dc1eed52 | 762 | exception:generic-syncase-error |
d6e04e7c DH |
763 | (eval '(case 1 ("foo")) |
764 | (interaction-environment))) | |
27a22666 DH |
765 | |
766 | (pass-if-exception "(case 1 (\"foo\" \"bar\"))" | |
dc1eed52 | 767 | exception:generic-syncase-error |
d6e04e7c DH |
768 | (eval '(case 1 ("foo" "bar")) |
769 | (interaction-environment))) | |
27a22666 | 770 | |
27a22666 | 771 | (pass-if-exception "(case 1 ((2) \"bar\") . \"foo\")" |
dc1eed52 | 772 | exception:generic-syncase-error |
d6e04e7c DH |
773 | (eval '(case 1 ((2) "bar") . "foo") |
774 | (interaction-environment))) | |
27a22666 | 775 | |
d6e04e7c | 776 | (pass-if-exception "(case 1 ((2) \"bar\") (else))" |
dc1eed52 | 777 | exception:generic-syncase-error |
d6e04e7c DH |
778 | (eval '(case 1 ((2) "bar") (else)) |
779 | (interaction-environment))) | |
27a22666 | 780 | |
27a22666 | 781 | (pass-if-exception "(case 1 (else #f) . \"foo\")" |
dc1eed52 | 782 | exception:generic-syncase-error |
d6e04e7c DH |
783 | (eval '(case 1 (else #f) . "foo") |
784 | (interaction-environment))) | |
27a22666 DH |
785 | |
786 | (pass-if-exception "(case 1 (else #f) ((1) #t))" | |
dc1eed52 | 787 | exception:generic-syncase-error |
d6e04e7c DH |
788 | (eval '(case 1 (else #f) ((1) #t)) |
789 | (interaction-environment))))) | |
27a22666 | 790 | |
ced8edb0 | 791 | (with-test-prefix "top-level define" |
08c608e1 | 792 | |
3dcf3373 LC |
793 | (pass-if "redefinition" |
794 | (let ((m (make-module))) | |
795 | (beautify-user-module! m) | |
796 | ||
797 | ;; The previous value of `round' must still be visible at the time the | |
798 | ;; new `round' is defined. According to R5RS (Section 5.2.1), `define' | |
799 | ;; should behave like `set!' in this case (except that in the case of | |
800 | ;; Guile, we respect module boundaries). | |
801 | (eval '(define round round) m) | |
802 | (eq? (module-ref m 'round) round))) | |
36245b66 | 803 | |
7171f1ab DH |
804 | (with-test-prefix "currying" |
805 | ||
806 | (pass-if "(define ((foo)) #f)" | |
ced8edb0 DH |
807 | (eval '(begin |
808 | (define ((foo)) #t) | |
809 | ((foo))) | |
810 | (interaction-environment)))) | |
7171f1ab | 811 | |
c454c4e6 DH |
812 | (with-test-prefix "unmemoization" |
813 | ||
814 | (pass-if "definition unmemoized without prior execution" | |
815 | (eval '(begin | |
816 | (define (blub) (cons ('(1 . 2)) 2)) | |
817 | (equal? | |
818 | (procedure-source blub) | |
819 | '(lambda () (cons ('(1 . 2)) 2)))) | |
820 | (interaction-environment))) | |
821 | ||
822 | (pass-if "definition with documentation unmemoized without prior execution" | |
823 | (eval '(begin | |
824 | (define (blub) "Comment" (cons ('(1 . 2)) 2)) | |
825 | (equal? | |
826 | (procedure-source blub) | |
827 | '(lambda () "Comment" (cons ('(1 . 2)) 2)))) | |
828 | (interaction-environment)))) | |
829 | ||
08c608e1 DH |
830 | (with-test-prefix "missing or extra expressions" |
831 | ||
832 | (pass-if-exception "(define)" | |
cc56ba80 | 833 | exception:missing-expr |
d6e04e7c DH |
834 | (eval '(define) |
835 | (interaction-environment))))) | |
08c608e1 | 836 | |
ced8edb0 DH |
837 | (with-test-prefix "internal define" |
838 | ||
839 | (pass-if "internal defines become letrec" | |
840 | (eval '(let ((a identity) (b identity) (c identity)) | |
841 | (define (a x) (if (= x 0) 'a (b (- x 1)))) | |
842 | (define (b x) (if (= x 0) 'b (c (- x 1)))) | |
843 | (define (c x) (if (= x 0) 'c (a (- x 1)))) | |
844 | (and (eq? 'a (a 0) (a 3)) | |
845 | (eq? 'b (a 1) (a 4)) | |
846 | (eq? 'c (a 2) (a 5)))) | |
847 | (interaction-environment))) | |
848 | ||
3dcf3373 LC |
849 | (pass-if "binding is created before expression is evaluated" |
850 | ;; Internal defines are equivalent to `letrec' (R5RS, Section 5.2.2). | |
851 | (= (eval '(let () | |
852 | (define foo | |
853 | (begin | |
854 | (set! foo 1) | |
855 | (+ foo 1))) | |
856 | foo) | |
857 | (interaction-environment)) | |
858 | 2)) | |
859 | ||
c86c440b | 860 | (pass-if "internal defines with begin" |
ced8edb0 DH |
861 | (false-if-exception |
862 | (eval '(let ((a identity) (b identity) (c identity)) | |
863 | (define (a x) (if (= x 0) 'a (b (- x 1)))) | |
864 | (begin | |
865 | (define (b x) (if (= x 0) 'b (c (- x 1))))) | |
866 | (define (c x) (if (= x 0) 'c (a (- x 1)))) | |
867 | (and (eq? 'a (a 0) (a 3)) | |
868 | (eq? 'b (a 1) (a 4)) | |
869 | (eq? 'c (a 2) (a 5)))) | |
870 | (interaction-environment)))) | |
871 | ||
c86c440b | 872 | (pass-if "internal defines with empty begin" |
ced8edb0 DH |
873 | (false-if-exception |
874 | (eval '(let ((a identity) (b identity) (c identity)) | |
875 | (define (a x) (if (= x 0) 'a (b (- x 1)))) | |
876 | (begin) | |
877 | (define (b x) (if (= x 0) 'b (c (- x 1)))) | |
878 | (define (c x) (if (= x 0) 'c (a (- x 1)))) | |
879 | (and (eq? 'a (a 0) (a 3)) | |
880 | (eq? 'b (a 1) (a 4)) | |
881 | (eq? 'c (a 2) (a 5)))) | |
882 | (interaction-environment)))) | |
883 | ||
c3d94801 | 884 | (pass-if "internal defines with macro application" |
560434b3 DH |
885 | (false-if-exception |
886 | (eval '(begin | |
c3d94801 | 887 | (defmacro my-define forms |
560434b3 | 888 | (cons 'define forms)) |
c3d94801 DH |
889 | (let ((a identity) (b identity) (c identity)) |
890 | (define (a x) (if (= x 0) 'a (b (- x 1)))) | |
891 | (my-define (b x) (if (= x 0) 'b (c (- x 1)))) | |
892 | (define (c x) (if (= x 0) 'c (a (- x 1)))) | |
893 | (and (eq? 'a (a 0) (a 3)) | |
894 | (eq? 'b (a 1) (a 4)) | |
895 | (eq? 'c (a 2) (a 5))))) | |
560434b3 DH |
896 | (interaction-environment)))) |
897 | ||
ced8edb0 DH |
898 | (pass-if-exception "missing body expression" |
899 | exception:missing-body-expr | |
900 | (eval '(let () (define x #t)) | |
a264c013 DH |
901 | (interaction-environment))) |
902 | ||
903 | (pass-if "unmemoization" | |
904 | (eval '(begin | |
905 | (define (foo) | |
906 | (define (bar) | |
907 | 'ok) | |
908 | (bar)) | |
909 | (foo) | |
910 | (equal? | |
911 | (procedure-source foo) | |
912 | '(lambda () (letrec ((bar (lambda () (quote ok)))) (bar))))) | |
ced8edb0 DH |
913 | (interaction-environment)))) |
914 | ||
aa498d0c DH |
915 | (with-test-prefix "do" |
916 | ||
917 | (with-test-prefix "unmemoization" | |
918 | ||
919 | (pass-if "normal case" | |
920 | (let ((foo (lambda () (do ((i 1 (+ i 1)) (j 2)) | |
921 | ((> i 9) (+ i j)) | |
922 | (identity i))))) | |
923 | (foo) ; make sure, memoization has been performed | |
924 | (equal? (procedure-source foo) | |
925 | '(lambda () (do ((i 1 (+ i 1)) (j 2)) | |
926 | ((> i 9) (+ i j)) | |
927 | (identity i)))))) | |
928 | ||
929 | (pass-if "reduced case" | |
930 | (let ((foo (lambda () (do ((i 1 (+ i 1)) (j 2 j)) ; redundant step for j | |
931 | ((> i 9) (+ i j)) | |
932 | (identity i))))) | |
933 | (foo) ; make sure, memoization has been performed | |
934 | (equal? (procedure-source foo) | |
935 | '(lambda () (do ((i 1 (+ i 1)) (j 2)) ; no redundancy here | |
936 | ((> i 9) (+ i j)) | |
937 | (identity i)))))))) | |
938 | ||
08c608e1 DH |
939 | (with-test-prefix "set!" |
940 | ||
aa498d0c DH |
941 | (with-test-prefix "unmemoization" |
942 | ||
943 | (pass-if "normal set!" | |
944 | (let ((foo (lambda (x) (set! x (+ 1 x))))) | |
945 | (foo 1) ; make sure, memoization has been performed | |
946 | (equal? (procedure-source foo) | |
947 | '(lambda (x) (set! x (+ 1 x))))))) | |
948 | ||
08c608e1 DH |
949 | (with-test-prefix "missing or extra expressions" |
950 | ||
951 | (pass-if-exception "(set!)" | |
da48db62 | 952 | exception:missing/extra-expr |
4dce3c96 DH |
953 | (eval '(set!) |
954 | (interaction-environment))) | |
08c608e1 DH |
955 | |
956 | (pass-if-exception "(set! 1)" | |
da48db62 | 957 | exception:missing/extra-expr |
4dce3c96 DH |
958 | (eval '(set! 1) |
959 | (interaction-environment))) | |
08c608e1 DH |
960 | |
961 | (pass-if-exception "(set! 1 2 3)" | |
da48db62 | 962 | exception:missing/extra-expr |
4dce3c96 DH |
963 | (eval '(set! 1 2 3) |
964 | (interaction-environment)))) | |
08c608e1 DH |
965 | |
966 | (with-test-prefix "bad variable" | |
967 | ||
968 | (pass-if-exception "(set! \"\" #t)" | |
da48db62 | 969 | exception:bad-variable |
4dce3c96 DH |
970 | (eval '(set! "" #t) |
971 | (interaction-environment))) | |
08c608e1 DH |
972 | |
973 | (pass-if-exception "(set! 1 #t)" | |
da48db62 | 974 | exception:bad-variable |
4dce3c96 DH |
975 | (eval '(set! 1 #t) |
976 | (interaction-environment))) | |
08c608e1 DH |
977 | |
978 | (pass-if-exception "(set! #t #f)" | |
da48db62 | 979 | exception:bad-variable |
4dce3c96 DH |
980 | (eval '(set! #t #f) |
981 | (interaction-environment))) | |
08c608e1 DH |
982 | |
983 | (pass-if-exception "(set! #f #t)" | |
da48db62 | 984 | exception:bad-variable |
4dce3c96 DH |
985 | (eval '(set! #f #t) |
986 | (interaction-environment))) | |
08c608e1 | 987 | |
96dfea7d | 988 | (pass-if-exception "(set! #\\space #f)" |
da48db62 | 989 | exception:bad-variable |
4dce3c96 DH |
990 | (eval '(set! #\space #f) |
991 | (interaction-environment))))) | |
08c608e1 | 992 | |
08c608e1 DH |
993 | (with-test-prefix "quote" |
994 | ||
995 | (with-test-prefix "missing or extra expression" | |
996 | ||
997 | (pass-if-exception "(quote)" | |
998 | exception:missing/extra-expr | |
4dce3c96 DH |
999 | (eval '(quote) |
1000 | (interaction-environment))) | |
08c608e1 DH |
1001 | |
1002 | (pass-if-exception "(quote a b)" | |
1003 | exception:missing/extra-expr | |
4dce3c96 DH |
1004 | (eval '(quote a b) |
1005 | (interaction-environment))))) | |
2798ba71 KR |
1006 | |
1007 | (with-test-prefix "while" | |
1008 | ||
1009 | (define (unreachable) | |
1010 | (error "unreachable code has been reached!")) | |
1011 | ||
2798ba71 KR |
1012 | ;; Return a new procedure COND which when called (COND) will return #t the |
1013 | ;; first N times, then #f, then any further call is an error. N=0 is | |
1014 | ;; allowed, in which case #f is returned by the first call. | |
1015 | (define (make-iterations-cond n) | |
1016 | (lambda () | |
1017 | (cond ((not n) | |
1018 | (error "oops, condition re-tested after giving false")) | |
1019 | ((= 0 n) | |
1020 | (set! n #f) | |
1021 | #f) | |
1022 | (else | |
1023 | (set! n (1- n)) | |
1024 | #t)))) | |
1025 | ||
1026 | ||
1027 | (pass-if-exception "too few args" exception:wrong-num-args | |
d6e04e7c | 1028 | (eval '(while) (interaction-environment))) |
2798ba71 KR |
1029 | |
1030 | (with-test-prefix "empty body" | |
1031 | (do ((n 0 (1+ n))) | |
1032 | ((> n 5)) | |
1033 | (pass-if n | |
ce09ee19 AW |
1034 | (eval `(letrec ((make-iterations-cond |
1035 | (lambda (n) | |
1036 | (lambda () | |
1037 | (cond ((not n) | |
1038 | (error "oops, condition re-tested after giving false")) | |
1039 | ((= 0 n) | |
1040 | (set! n #f) | |
1041 | #f) | |
1042 | (else | |
1043 | (set! n (1- n)) | |
1044 | #t)))))) | |
1045 | (let ((cond (make-iterations-cond ,n))) | |
1046 | (while (cond)) | |
1047 | #t)) | |
1048 | (interaction-environment))))) | |
2798ba71 KR |
1049 | |
1050 | (pass-if "initially false" | |
1051 | (while #f | |
1052 | (unreachable)) | |
1053 | #t) | |
1054 | ||
1055 | (with-test-prefix "in empty environment" | |
d6e04e7c DH |
1056 | |
1057 | ;; an environment with no bindings at all | |
1058 | (define empty-environment | |
1059 | (make-module 1)) | |
2ebe323a KR |
1060 | |
1061 | ;; these tests are 'unresolved because to work with ice-9 syncase it was | |
1062 | ;; necessary to drop the unquote from `do' in the implementation, and | |
1063 | ;; unfortunately that makes `while' depend on its evaluation environment | |
d6e04e7c | 1064 | |
2798ba71 | 1065 | (pass-if "empty body" |
2ebe323a | 1066 | (throw 'unresolved) |
2798ba71 KR |
1067 | (eval `(,while #f) |
1068 | empty-environment) | |
1069 | #t) | |
1070 | ||
1071 | (pass-if "initially false" | |
2ebe323a | 1072 | (throw 'unresolved) |
2798ba71 KR |
1073 | (eval `(,while #f |
1074 | #f) | |
1075 | empty-environment) | |
1076 | #t) | |
1077 | ||
1078 | (pass-if "iterating" | |
2ebe323a | 1079 | (throw 'unresolved) |
2798ba71 KR |
1080 | (let ((cond (make-iterations-cond 3))) |
1081 | (eval `(,while (,cond) | |
1082 | 123 456) | |
1083 | empty-environment)) | |
1084 | #t)) | |
1085 | ||
1086 | (with-test-prefix "iterations" | |
1087 | (do ((n 0 (1+ n))) | |
1088 | ((> n 5)) | |
1089 | (pass-if n | |
1090 | (let ((cond (make-iterations-cond n)) | |
1091 | (i 0)) | |
1092 | (while (cond) | |
1093 | (set! i (1+ i))) | |
1094 | (= i n))))) | |
1095 | ||
1096 | (with-test-prefix "break" | |
1097 | ||
1098 | (pass-if-exception "too many args" exception:wrong-num-args | |
1099 | (while #t | |
1100 | (break 1))) | |
1101 | ||
1102 | (with-test-prefix "from cond" | |
1103 | (pass-if "first" | |
1104 | (while (begin | |
1105 | (break) | |
1106 | (unreachable)) | |
1107 | (unreachable)) | |
1108 | #t) | |
1109 | ||
1110 | (do ((n 0 (1+ n))) | |
1111 | ((> n 5)) | |
1112 | (pass-if n | |
1113 | (let ((cond (make-iterations-cond n)) | |
1114 | (i 0)) | |
1115 | (while (if (cond) | |
1116 | #t | |
1117 | (begin | |
1118 | (break) | |
1119 | (unreachable))) | |
1120 | (set! i (1+ i))) | |
1121 | (= i n))))) | |
1122 | ||
1123 | (with-test-prefix "from body" | |
1124 | (pass-if "first" | |
1125 | (while #t | |
1126 | (break) | |
1127 | (unreachable)) | |
1128 | #t) | |
1129 | ||
1130 | (do ((n 0 (1+ n))) | |
1131 | ((> n 5)) | |
1132 | (pass-if n | |
1133 | (let ((cond (make-iterations-cond n)) | |
1134 | (i 0)) | |
1135 | (while #t | |
1136 | (if (not (cond)) | |
1137 | (begin | |
1138 | (break) | |
1139 | (unreachable))) | |
1140 | (set! i (1+ i))) | |
1141 | (= i n))))) | |
1142 | ||
1143 | (pass-if "from nested" | |
1144 | (while #t | |
1145 | (let ((outer-break break)) | |
1146 | (while #t | |
1147 | (outer-break) | |
1148 | (unreachable))) | |
1149 | (unreachable)) | |
cc08aafd KR |
1150 | #t) |
1151 | ||
1152 | (pass-if "from recursive" | |
1153 | (let ((outer-break #f)) | |
1154 | (define (r n) | |
1155 | (while #t | |
1156 | (if (eq? n 'outer) | |
1157 | (begin | |
1158 | (set! outer-break break) | |
1159 | (r 'inner)) | |
1160 | (begin | |
1161 | (outer-break) | |
1162 | (unreachable)))) | |
1163 | (if (eq? n 'inner) | |
1164 | (error "broke only from inner loop"))) | |
1165 | (r 'outer)) | |
2798ba71 KR |
1166 | #t)) |
1167 | ||
1168 | (with-test-prefix "continue" | |
1169 | ||
1170 | (pass-if-exception "too many args" exception:wrong-num-args | |
1171 | (while #t | |
1172 | (continue 1))) | |
1173 | ||
1174 | (with-test-prefix "from cond" | |
1175 | (do ((n 0 (1+ n))) | |
1176 | ((> n 5)) | |
1177 | (pass-if n | |
1178 | (let ((cond (make-iterations-cond n)) | |
1179 | (i 0)) | |
1180 | (while (if (cond) | |
1181 | (begin | |
1182 | (set! i (1+ i)) | |
1183 | (continue) | |
1184 | (unreachable)) | |
1185 | #f) | |
1186 | (unreachable)) | |
1187 | (= i n))))) | |
1188 | ||
1189 | (with-test-prefix "from body" | |
1190 | (do ((n 0 (1+ n))) | |
1191 | ((> n 5)) | |
1192 | (pass-if n | |
1193 | (let ((cond (make-iterations-cond n)) | |
1194 | (i 0)) | |
1195 | (while (cond) | |
1196 | (set! i (1+ i)) | |
1197 | (continue) | |
1198 | (unreachable)) | |
1199 | (= i n))))) | |
1200 | ||
1201 | (pass-if "from nested" | |
1202 | (let ((cond (make-iterations-cond 3))) | |
1203 | (while (cond) | |
1204 | (let ((outer-continue continue)) | |
1205 | (while #t | |
1206 | (outer-continue) | |
1207 | (unreachable))))) | |
cc08aafd KR |
1208 | #t) |
1209 | ||
1210 | (pass-if "from recursive" | |
1211 | (let ((outer-continue #f)) | |
1212 | (define (r n) | |
1213 | (let ((cond (make-iterations-cond 3)) | |
1214 | (first #t)) | |
1215 | (while (begin | |
1216 | (if (and (not first) | |
1217 | (eq? n 'inner)) | |
1218 | (error "continued only to inner loop")) | |
1219 | (cond)) | |
1220 | (set! first #f) | |
1221 | (if (eq? n 'outer) | |
1222 | (begin | |
1223 | (set! outer-continue continue) | |
1224 | (r 'inner)) | |
1225 | (begin | |
1226 | (outer-continue) | |
1227 | (unreachable)))))) | |
1228 | (r 'outer)) | |
2798ba71 | 1229 | #t))) |