1 ;;;; eval.test --- tests guile's evaluator -*- scheme -*-
2 ;;;; Copyright (C) 2000, 2001, 2006, 2007, 2009, 2010, 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
4 ;;;; This library is free software; you can redistribute it and/or
5 ;;;; modify it under the terms of the GNU Lesser General Public
6 ;;;; License as published by the Free Software Foundation; either
7 ;;;; version 3 of the License, or (at your option) any later version.
9 ;;;; This library is distributed in the hope that it will be useful,
10 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 ;;;; Lesser General Public License for more details.
14 ;;;; You should have received a copy of the GNU Lesser General Public
15 ;;;; License along with this library; if not, write to the Free Software
16 ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 (define-module (test-suite test-eval)
19 :use-module (test-suite lib)
20 :use-module ((srfi srfi-1) :select (unfold count))
21 :use-module ((system vm vm) :select (call-with-stack-overflow-handler))
22 :use-module ((system vm frame) :select (frame-call-representation))
23 :use-module (ice-9 documentation)
24 :use-module (ice-9 local-eval))
27 (define exception:bad-expression
28 (cons 'syntax-error "Bad expression"))
30 (define exception:failed-match
31 (cons 'syntax-error "failed to match any pattern"))
33 (define exception:not-a-list
34 (cons 'wrong-type-arg "Not a list"))
36 (define exception:wrong-length
37 (cons 'wrong-type-arg "wrong length"))
43 (define (documented? object)
44 (not (not (object-documentation object))))
51 (with-test-prefix "memoization"
53 (with-test-prefix "copy-tree"
55 (pass-if "(#t . #(#t))"
56 (let* ((foo (cons #t (vector #t)))
57 (bar (copy-tree foo)))
58 (vector-set! (cdr foo) 0 #f)
59 (equal? bar '(#t . #(#t)))))
61 (pass-if-exception "circular lists in forms"
62 exception:wrong-type-arg
63 (let ((foo (list #f)))
67 (pass-if "transparency"
69 (eval x (current-module))
70 (equal? '(begin 1) x))))
77 (with-test-prefix "evaluator"
79 (pass-if "definitions return #<unspecified>"
80 (eq? (primitive-eval '(define test-var 'foo))
83 (with-test-prefix "symbol lookup"
85 (with-test-prefix "top level"
87 (with-test-prefix "unbound"
89 (pass-if-exception "variable reference"
93 (pass-if-exception "procedure"
97 (with-test-prefix "parameter error"
99 ;; This is currently a bug in guile:
100 ;; Macros are accepted as function parameters.
101 ;; Functions that 'apply' macros are rewritten!!!
103 (pass-if-exception "macro as argument"
104 exception:failed-match
106 '(let ((f (lambda (p a b) (p a b))))
109 (pass-if-exception "passing macro as parameter"
110 exception:failed-match
112 '(let* ((f (lambda (p a b) (p a b)))
113 (foo (procedure-source f)))
115 (equal? (procedure-source f) foo))))
123 (with-test-prefix "call"
125 (with-test-prefix "wrong number of arguments"
127 (pass-if-exception "((lambda () #f) 1)"
128 exception:wrong-num-args
131 (pass-if-exception "((lambda (x) #f))"
132 exception:wrong-num-args
135 (pass-if-exception "((lambda (x) #f) 1 2)"
136 exception:wrong-num-args
137 ((lambda (x) #f) 1 2))
139 (pass-if-exception "((lambda (x y) #f))"
140 exception:wrong-num-args
143 (pass-if-exception "((lambda (x y) #f) 1)"
144 exception:wrong-num-args
145 ((lambda (x y) #f) 1))
147 (pass-if-exception "((lambda (x y) #f) 1 2 3)"
148 exception:wrong-num-args
149 ((lambda (x y) #f) 1 2 3))
151 (pass-if-exception "((lambda (x . rest) #f))"
152 exception:wrong-num-args
153 ((lambda (x . rest) #f)))
155 (pass-if-exception "((lambda (x y . rest) #f))"
156 exception:wrong-num-args
157 ((lambda (x y . rest) #f)))
159 (pass-if-exception "((lambda (x y . rest) #f) 1)"
160 exception:wrong-num-args
161 ((lambda (x y . rest) #f) 1))))
167 (with-test-prefix "apply"
169 (with-test-prefix "scm_tc7_subr_2o"
171 ;; prior to guile 1.6.9 and 1.8.1 this called the function with
172 ;; SCM_UNDEFINED, which in the case of make-vector resulted in
173 ;; wrong-type-arg, instead of the intended wrong-num-args
174 (pass-if-exception "0 args" exception:wrong-num-args
175 (apply make-vector '()))
178 (vector? (apply make-vector '(1))))
181 (vector? (apply make-vector '(1 2))))
183 ;; prior to guile 1.6.9 and 1.8.1 this error wasn't detected
184 (pass-if-exception "3 args" exception:wrong-num-args
185 (apply make-vector '(1 2 3)))))
191 (with-test-prefix "map"
193 ;; Is documentation available?
195 (expect-fail "documented?"
198 (with-test-prefix "argument error"
200 (with-test-prefix "non list argument"
203 (with-test-prefix "different length lists"
205 (pass-if-exception "first list empty"
206 exception:wrong-length
209 (pass-if-exception "second list empty"
210 exception:wrong-length
213 (pass-if-exception "first list shorter"
214 exception:wrong-length
217 (pass-if-exception "second list shorter"
218 exception:wrong-length
222 (with-test-prefix "for-each"
224 (pass-if-exception "1 arg, non-list, even number of elements"
226 (for-each values '(1 2 3 4 . 5)))
228 (pass-if-exception "1 arg, non-list, odd number of elements"
230 (for-each values '(1 2 3 . 4))))
233 ;;; define with procedure-name
236 ;; names are only set on top-level procedures (currently), so these can't be
239 (define foo-closure (lambda () "hello"))
240 (define bar-closure foo-closure)
241 ;; make sure that make-procedure-with-setter returns an anonymous
242 ;; procedure-with-setter by passing it an anonymous getter.
243 (define foo-pws (make-procedure-with-setter
245 (lambda (x y) (set-car! x y))))
246 (define bar-pws foo-pws)
248 (with-test-prefix "define set procedure-name"
251 (eq? 'foo-closure (procedure-name bar-closure)))
253 (expect-fail "procedure-with-setter" ; FIXME: `pass-if' when it's supported
254 (eq? 'foo-pws (procedure-name bar-pws))))
260 (with-test-prefix "promises"
262 (with-test-prefix "basic promise behaviour"
264 (pass-if "delay gives a promise"
265 (promise? (delay 1)))
267 (pass-if "force evaluates a promise"
268 (eqv? (force (delay (+ 1 2))) 3))
270 (pass-if "a forced promise is a promise"
271 (let ((p (delay (+ 1 2))))
275 (pass-if "forcing a forced promise works"
276 (let ((p (delay (+ 1 2))))
280 (pass-if "a promise is evaluated once"
287 (pass-if "a promise may call itself"
293 (if (> x 1) x (force p))))))
296 (pass-if "a promise carries its environment"
299 (set! p (delay (+ x 1))))
302 (pass-if "a forced promise does not reference its environment"
303 (let* ((g (make-guardian))
305 (let* ((x (cons #f #f)))
307 (set! p (delay (car x))))
310 (if (not (equal? (g) (cons #f #f)))
314 (with-test-prefix "extended promise behaviour"
316 (pass-if-exception "forcing a non-promise object is not supported"
317 exception:wrong-type-arg
320 (pass-if "unmemoizing a promise"
324 (with-throw-handler #t
326 (let ((f (lambda (g) (delay (g)))))
329 (set! stack (make-stack #t)))))
331 (%make-void-port "w"))
339 (define (stack->frames stack)
340 ;; Return the list of frames comprising STACK.
342 (>= i (stack-length stack)))
348 (define (make-tagged-trimmed-stack tag spec)
354 (with-throw-handler 'wrong-type-arg
355 (lambda () (substring 'wrong 'type 'arg))
356 (lambda _ (throw 'result (apply make-stack spec)))))
357 (lambda () (throw 'make-stack-failed))))
358 (lambda (key result) result)))
360 (define tag (make-prompt-tag "foo"))
362 (with-test-prefix "stacks"
363 (pass-if "stack involving a primitive"
364 ;; The primitive involving the error must appear exactly once on the
366 (let* ((stack (make-tagged-trimmed-stack tag '(#t)))
367 (frames (stack->frames stack))
368 (num (count (lambda (frame) (eq? (frame-procedure frame)
373 (pass-if "arguments of a primitive stack frame"
374 ;; Create a stack with two primitive frames and make sure the
375 ;; arguments are correct.
376 (let* ((stack (make-tagged-trimmed-stack tag '(#t)))
377 (call-list (map frame-call-representation (stack->frames stack))))
378 (and (equal? (car call-list) '(make-stack #t))
379 (pair? (member '(substring wrong type arg)
382 (pass-if "inner trim with prompt tag"
383 (let* ((stack (make-tagged-trimmed-stack tag `(#t ,tag)))
384 (frames (stack->frames stack)))
385 ;; the top frame on the stack is the lambda inside the 'catch, and the
386 ;; next frame is the (catch 'result ...)
387 (and (eq? (car (frame-call-representation (cadr frames)))
389 (eq? (car (frame-arguments (cadr frames)))
392 (pass-if "outer trim with prompt tag"
393 (let* ((stack (make-tagged-trimmed-stack tag `(#t 0 ,tag)))
394 (frames (stack->frames stack)))
395 ;; the top frame on the stack is the make-stack call, and the last
396 ;; frame is the (with-throw-handler 'wrong-type-arg ...)
397 (and (eq? (car (frame-call-representation (car frames)))
399 (eq? (car (frame-call-representation (car (last-pair frames))))
400 'with-throw-handler)))))
403 ;;; letrec init evaluation
406 (with-test-prefix "letrec init evaluation"
408 (pass-if "lots of inits calculated in correct order"
409 (equal? (letrec ((a 'a) (b 'b) (c 'c) (d 'd)
410 (e 'e) (f 'f) (g 'g) (h 'h)
411 (i 'i) (j 'j) (k 'k) (l 'l)
412 (m 'm) (n 'n) (o 'o) (p 'p)
413 (q 'q) (r 'r) (s 's) (t 't)
414 (u 'u) (v 'v) (w 'w) (x 'x)
416 (list a b c d e f g h i j k l m
417 n o p q r s t u v w x y z))
418 '(a b c d e f g h i j k l m
419 n o p q r s t u v w x y z))))
425 (with-test-prefix "values"
427 (pass-if "single value"
428 (equal? 1 (values 1)))
430 (pass-if "call-with-values"
431 (equal? (call-with-values (lambda () (values 1 2 3 4)) list)
435 (equal? (values 1 2 3 4) (values 1 2 3 4))))
438 ;;; stack overflow handling
441 (with-test-prefix "stack overflow handlers"
442 (define (trigger-overflow)
444 (error "not reached"))
446 (define (dynwind-test n)
449 (call-with-stack-overflow-handler n
451 (dynamic-wind (lambda () #t)
458 (pass-if-exception "limit should be number"
459 exception:wrong-type-arg
460 (call-with-stack-overflow-handler #t
461 trigger-overflow trigger-overflow))
463 (pass-if-exception "limit should be exact integer"
464 exception:wrong-type-arg
465 (call-with-stack-overflow-handler 2.0
466 trigger-overflow trigger-overflow))
468 (pass-if-exception "limit should be nonnegative"
469 exception:out-of-range
470 (call-with-stack-overflow-handler -1
471 trigger-overflow trigger-overflow))
473 (pass-if-exception "limit should be positive"
474 exception:out-of-range
475 (call-with-stack-overflow-handler 0
476 trigger-overflow trigger-overflow))
478 (pass-if-exception "limit should be within address space"
479 exception:out-of-range
480 (call-with-stack-overflow-handler (ash 1 64)
481 trigger-overflow trigger-overflow))
483 (pass-if "exception on overflow"
486 (call-with-stack-overflow-handler 10000
492 (pass-if "exception on overflow with dynwind"
493 ;; Try all limits between 1 and 200 words.
496 (and (dynwind-test n)
499 (pass-if-exception "overflow handler should return number"
500 exception:wrong-type-arg
501 (call-with-stack-overflow-handler 1000
504 (pass-if-exception "overflow handler should return exact integer"
505 exception:wrong-type-arg
506 (call-with-stack-overflow-handler 1000
509 (pass-if-exception "overflow handler should be nonnegative"
510 exception:out-of-range
511 (call-with-stack-overflow-handler 1000
514 (pass-if-exception "overflow handler should be positive"
515 exception:out-of-range
516 (call-with-stack-overflow-handler 1000
520 (letrec ((fac (lambda (n)
521 (if (zero? n) 1 (* n (fac (1- n)))))))
522 (pass-if-equal "overflow handler can allow recursion to continue"
524 (call-with-stack-overflow-handler 1
532 (with-test-prefix "docstrings"
534 (pass-if-equal "fixed closure"
536 (map procedure-documentation
537 (list (eval '(lambda (a b) "hello" (+ a b))
539 (eval '(lambda (a b) "world" (- a b))
542 (pass-if-equal "fixed closure with many args"
544 (procedure-documentation
545 (eval '(lambda (a b c d e f g h i j k)
550 (pass-if-equal "general closure"
552 (procedure-documentation
553 (eval '(lambda* (a b #:key k #:rest r)
562 (with-test-prefix "local evaluation"
564 (pass-if "local-eval"
566 (let* ((env1 (local-eval '(let ((x 1) (y 2) (z 3))
567 (define-syntax-rule (foo x) (quote x))
570 (env2 (local-eval '(let ((x 111) (a 'a))
571 (define-syntax-rule (bar x) (quote x))
574 (local-eval '(set! x 11) env1)
575 (local-eval '(set! y 22) env1)
576 (local-eval '(set! z 33) env2)
577 (and (equal? (local-eval '(list x y z) env1)
579 (equal? (local-eval '(list x y z a) env2)
582 (pass-if "local-compile"
584 (let* ((env1 (local-compile '(let ((x 1) (y 2) (z 3))
585 (define-syntax-rule (foo x) (quote x))
588 (env2 (local-compile '(let ((x 111) (a 'a))
589 (define-syntax-rule (bar x) (quote x))
592 (local-compile '(set! x 11) env1)
593 (local-compile '(set! y 22) env1)
594 (local-compile '(set! z 33) env2)
595 (and (equal? (local-compile '(list x y z) env1)
597 (equal? (local-compile '(list x y z a) env2)
600 (pass-if "the-environment within a macro"
601 (let ((module-a-name '(test module the-environment a))
602 (module-b-name '(test module the-environment b)))
603 (let ((module-a (resolve-module module-a-name))
604 (module-b (resolve-module module-b-name)))
605 (module-use! module-a (resolve-interface '(guile)))
606 (module-use! module-a (resolve-interface '(ice-9 local-eval)))
609 (define-syntax-rule (test)
613 (module-use! module-b (resolve-interface '(guile)))
614 (let ((env (local-eval `(let ((x 111) (y 222))
615 ((@@ ,module-a-name test)))
617 (equal? (local-eval '(list x y z) env)
620 (pass-if "capture pattern variables"
621 (let ((env (syntax-case #'(((a 1) (b 2) (c 3))
622 ((d 4) (e 5) (f 6))) ()
623 ((((k v) ...) ...) (the-environment)))))
624 (equal? (syntax->datum (local-eval '#'((k ... v ...) ...) env))
625 '((a b c 1 2 3) (d e f 4 5 6)))))
627 (pass-if "mixed primitive-eval, local-eval and local-compile"
629 (let* ((env1 (primitive-eval '(let ((x 1) (y 2) (z 3))
630 (define-syntax-rule (foo x) (quote x))
632 (env2 (local-eval '(let ((x 111) (a 'a))
633 (define-syntax-rule (bar x) (quote x))
636 (env3 (local-compile '(let ((y 222) (b 'b))
639 (local-eval '(set! x 11) env1)
640 (local-compile '(set! y 22) env2)
641 (local-eval '(set! z 33) env2)
642 (local-compile '(set! a (* y 2)) env3)
643 (and (equal? (local-compile '(list x y z) env1)
645 (equal? (local-eval '(list x y z a) env2)
647 (equal? (local-eval '(list x y z a b) env3)
648 '(111 222 33 444 b))))))
650 ;;; eval.test ends here