1;;;; eval.test --- tests guile's evaluator -*- scheme -*- 2;;;; Copyright (C) 2000-2001,2003-2015,2017,2019,2020 3;;;; Free Software Foundation, Inc. 4;;;; 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. 9;;;; 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. 14;;;; 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 18 19(define-module (test-suite test-eval) 20 :use-module (test-suite lib) 21 :use-module ((srfi srfi-1) :select (unfold count)) 22 :use-module ((system vm vm) :select (call-with-stack-overflow-handler)) 23 :use-module ((system vm frame) :select (frame-call-representation)) 24 :use-module (ice-9 documentation) 25 :use-module (ice-9 local-eval)) 26 27 28(define exception:bad-expression 29 (cons 'syntax-error "Bad expression")) 30 31(define exception:failed-match 32 (cons 'syntax-error "failed to match any pattern")) 33 34(define exception:not-a-list 35 (cons 'wrong-type-arg "Not a list")) 36 37(define exception:wrong-length 38 (cons 'wrong-type-arg "wrong length")) 39 40;;; 41;;; miscellaneous 42;;; 43 44(define (documented? object) 45 (not (not (object-documentation object)))) 46 47 48;;; 49;;; memoization 50;;; 51 52(with-test-prefix "memoization" 53 (pass-if "transparency" 54 (let ((x '(begin 1))) 55 (eval x (current-module)) 56 (equal? '(begin 1) x)))) 57 58 59;;; 60;;; eval 61;;; 62 63(with-test-prefix "evaluator" 64 65 (pass-if "definitions return #<unspecified>" 66 (eq? (primitive-eval '(define test-var 'foo)) 67 (if #f #f))) 68 69 (with-test-prefix "symbol lookup" 70 71 (with-test-prefix "top level" 72 73 (with-test-prefix "unbound" 74 75 (pass-if-exception "variable reference" 76 exception:unbound-var 77 x) 78 79 (pass-if-exception "procedure" 80 exception:unbound-var 81 (x))))) 82 83 (with-test-prefix "parameter error" 84 85 ;; This is currently a bug in guile: 86 ;; Macros are accepted as function parameters. 87 ;; Functions that 'apply' macros are rewritten!!! 88 89 (pass-if-exception "macro as argument" 90 exception:failed-match 91 (primitive-eval 92 '(let ((f (lambda (p a b) (p a b)))) 93 (f and #t #t)))) 94 95 (pass-if-exception "passing macro as parameter" 96 exception:failed-match 97 (primitive-eval 98 '(let* ((f (lambda (p a b) (p a b))) 99 (foo (procedure-source f))) 100 (f and #t #t) 101 (equal? (procedure-source f) foo)))) 102 103 )) 104 105;;; 106;;; call 107;;; 108 109(with-test-prefix "call" 110 111 (with-test-prefix "wrong number of arguments" 112 113 (pass-if-exception "((lambda () #f) 1)" 114 exception:wrong-num-args 115 ((lambda () #f) 1)) 116 117 (pass-if-exception "((lambda (x) #f))" 118 exception:wrong-num-args 119 ((lambda (x) #f))) 120 121 (pass-if-exception "((lambda (x) #f) 1 2)" 122 exception:wrong-num-args 123 ((lambda (x) #f) 1 2)) 124 125 (pass-if-exception "((lambda (x y) #f))" 126 exception:wrong-num-args 127 ((lambda (x y) #f))) 128 129 (pass-if-exception "((lambda (x y) #f) 1)" 130 exception:wrong-num-args 131 ((lambda (x y) #f) 1)) 132 133 (pass-if-exception "((lambda (x y) #f) 1 2 3)" 134 exception:wrong-num-args 135 ((lambda (x y) #f) 1 2 3)) 136 137 (pass-if-exception "((lambda (x . rest) #f))" 138 exception:wrong-num-args 139 ((lambda (x . rest) #f))) 140 141 (pass-if-exception "((lambda (x y . rest) #f))" 142 exception:wrong-num-args 143 ((lambda (x y . rest) #f))) 144 145 (pass-if-exception "((lambda (x y . rest) #f) 1)" 146 exception:wrong-num-args 147 ((lambda (x y . rest) #f) 1)))) 148 149;;; 150;;; apply 151;;; 152 153(with-test-prefix "apply" 154 155 (with-test-prefix "scm_tc7_subr_2o" 156 157 ;; prior to guile 1.6.9 and 1.8.1 this called the function with 158 ;; SCM_UNDEFINED, which in the case of make-vector resulted in 159 ;; wrong-type-arg, instead of the intended wrong-num-args 160 (pass-if-exception "0 args" exception:wrong-num-args 161 (apply make-vector '())) 162 163 (pass-if "1 arg" 164 (vector? (apply make-vector '(1)))) 165 166 (pass-if "2 args" 167 (vector? (apply make-vector '(1 2)))) 168 169 ;; prior to guile 1.6.9 and 1.8.1 this error wasn't detected 170 (pass-if-exception "3 args" exception:wrong-num-args 171 (apply make-vector '(1 2 3))))) 172 173;;; 174;;; map 175;;; 176 177(with-test-prefix "map" 178 179 ;; Is documentation available? 180 181 (expect-fail "documented?" 182 (documented? map)) 183 184 (with-test-prefix "argument error" 185 186 (with-test-prefix "non list argument" 187 #t) 188 189 (with-test-prefix "different length lists" 190 191 (pass-if-exception "first list empty" 192 exception:wrong-length 193 (map + '() '(1))) 194 195 (pass-if-exception "second list empty" 196 exception:wrong-length 197 (map + '(1) '())) 198 199 (pass-if-exception "first list shorter" 200 exception:wrong-length 201 (map + '(1) '(2 3))) 202 203 (pass-if-exception "second list shorter" 204 exception:wrong-length 205 (map + '(1 2) '(3))) 206 ))) 207 208(with-test-prefix "for-each" 209 210 (pass-if-exception "1 arg, non-list, even number of elements" 211 exception:not-a-list 212 (for-each values '(1 2 3 4 . 5))) 213 214 (pass-if-exception "1 arg, non-list, odd number of elements" 215 exception:not-a-list 216 (for-each values '(1 2 3 . 4)))) 217 218;;; 219;;; define with procedure-name 220;;; 221 222;; names are only set on top-level procedures (currently), so these can't be 223;; hidden in a let 224;; 225(define foo-closure (lambda () "hello")) 226(define bar-closure foo-closure) 227;; make sure that make-procedure-with-setter returns an anonymous 228;; procedure-with-setter by passing it an anonymous getter. 229(define foo-pws (make-procedure-with-setter 230 (lambda (x) (car x)) 231 (lambda (x y) (set-car! x y)))) 232(define bar-pws foo-pws) 233 234(with-test-prefix "define set procedure-name" 235 236 (pass-if "closure" 237 (eq? 'foo-closure (procedure-name bar-closure))) 238 239 (expect-fail "procedure-with-setter" ; FIXME: `pass-if' when it's supported 240 (eq? 'foo-pws (procedure-name bar-pws)))) 241 242;;; 243;;; promises 244;;; 245 246(with-test-prefix "promises" 247 248 (with-test-prefix "basic promise behaviour" 249 250 (pass-if "delay gives a promise" 251 (promise? (delay 1))) 252 253 (pass-if "force evaluates a promise" 254 (eqv? (force (delay (+ 1 2))) 3)) 255 256 (pass-if "a forced promise is a promise" 257 (let ((p (delay (+ 1 2)))) 258 (force p) 259 (promise? p))) 260 261 (pass-if "forcing a forced promise works" 262 (let ((p (delay (+ 1 2)))) 263 (force p) 264 (eqv? (force p) 3))) 265 266 (pass-if "a promise is evaluated once" 267 (let* ((x 1) 268 (p (delay (+ x 1)))) 269 (force p) 270 (set! x (+ x 1)) 271 (eqv? (force p) 2))) 272 273 (pass-if "a promise may call itself" 274 (define p 275 (let ((x 0)) 276 (delay 277 (begin 278 (set! x (+ x 1)) 279 (if (> x 1) x (force p)))))) 280 (eqv? (force p) 2)) 281 282 (pass-if "a promise carries its environment" 283 (let* ((x 1) (p #f)) 284 (let* ((x 2)) 285 (set! p (delay (+ x 1)))) 286 (eqv? (force p) 3))) 287 288 (pass-if "a forced promise does not reference its environment" 289 (let* ((g (make-guardian)) 290 (p #f)) 291 (let* ((x (cons #f #f))) 292 (g x) 293 (set! p (delay (car x)))) 294 (force p) 295 (gc) 296 ;; Though this test works reliably when running just eval.test, 297 ;; it often does the unresolved case when running the full 298 ;; suite. Adding this extra gc makes the full-suite behavior 299 ;; pass more reliably. 300 (gc) 301 (if (not (equal? (g) (cons #f #f))) 302 (throw 'unresolved) 303 #t)))) 304 305 (with-test-prefix "extended promise behaviour" 306 307 (pass-if-exception "forcing a non-promise object is not supported" 308 exception:wrong-type-arg 309 (force 1)) 310 311 (pass-if "unmemoizing a promise" 312 (display-backtrace 313 (let ((stack #f)) 314 (false-if-exception 315 (with-throw-handler #t 316 (lambda () 317 (let ((f (lambda (g) (delay (g))))) 318 (force (f error)))) 319 (lambda _ 320 (set! stack (make-stack #t))))) 321 stack) 322 (%make-void-port "w")) 323 #t))) 324 325 326;;; 327;;; stacks 328;;; 329 330(define (stack->frames stack) 331 ;; Return the list of frames comprising STACK. 332 (unfold (lambda (i) 333 (>= i (stack-length stack))) 334 (lambda (i) 335 (stack-ref stack i)) 336 1+ 337 0)) 338 339(define (make-tagged-trimmed-stack tag spec) 340 (catch 'result 341 (lambda () 342 (call-with-prompt 343 tag 344 (lambda () 345 (with-throw-handler 'wrong-type-arg 346 (lambda () (substring 'wrong 'type 'arg)) 347 (lambda _ (throw 'result (apply make-stack spec))))) 348 (lambda () (throw 'make-stack-failed)))) 349 (lambda (key result) result))) 350 351(define tag (make-prompt-tag "foo")) 352 353(with-test-prefix "stacks" 354 (pass-if "stack involving a primitive" 355 ;; The primitive involving the error must appear exactly once on the 356 ;; stack. 357 (let* ((stack (make-tagged-trimmed-stack tag '(#t))) 358 (frames (stack->frames stack)) 359 (num (count (lambda (frame) (eq? (frame-procedure-name frame) 360 'substring)) 361 frames))) 362 (= num 1))) 363 364 (pass-if "arguments of a primitive stack frame" 365 ;; Create a stack with two primitive frames and make sure the 366 ;; arguments are correct. 367 (let* ((stack (make-tagged-trimmed-stack tag '(#t))) 368 (call-list (map frame-call-representation (stack->frames stack)))) 369 (and (equal? (car call-list) '(make-stack #t)) 370 (pair? (member '(substring wrong type arg) 371 (cdr call-list)))))) 372 373 (pass-if "inner trim with prompt tag" 374 (let* ((stack (make-tagged-trimmed-stack tag `(#t ,tag))) 375 (frames (stack->frames stack))) 376 ;; the top frame on the stack is the body of the catch, and the 377 ;; next frame is the with-exception-handler corresponding to the 378 ;; (catch 'result ...) 379 (eq? (car (frame-call-representation (cadr frames))) 380 'with-exception-handler))) 381 382 (pass-if "outer trim with prompt tag" 383 (let* ((stack (make-tagged-trimmed-stack tag `(#t 0 ,tag))) 384 (frames (stack->frames stack))) 385 ;; the top frame on the stack is the make-stack call, and the last 386 ;; frame is the (with-throw-handler 'wrong-type-arg ...) 387 (and (eq? (car (frame-call-representation (car frames))) 388 'make-stack) 389 (eq? (car (frame-call-representation (car (last-pair frames)))) 390 'with-exception-handler))))) 391 392;;; 393;;; letrec init evaluation 394;;; 395 396(with-test-prefix "letrec init evaluation" 397 398 (pass-if "lots of inits calculated in correct order" 399 (equal? (letrec ((a 'a) (b 'b) (c 'c) (d 'd) 400 (e 'e) (f 'f) (g 'g) (h 'h) 401 (i 'i) (j 'j) (k 'k) (l 'l) 402 (m 'm) (n 'n) (o 'o) (p 'p) 403 (q 'q) (r 'r) (s 's) (t 't) 404 (u 'u) (v 'v) (w 'w) (x 'x) 405 (y 'y) (z 'z)) 406 (list a b c d e f g h i j k l m 407 n o p q r s t u v w x y z)) 408 '(a b c d e f g h i j k l m 409 n o p q r s t u v w x y z)))) 410 411;;; 412;;; values 413;;; 414 415(with-test-prefix "values" 416 417 (pass-if "single value" 418 (equal? 1 (values 1))) 419 420 (pass-if "call-with-values" 421 (equal? (call-with-values (lambda () (values 1 2 3 4)) list) 422 '(1 2 3 4))) 423 424 (pass-if "equal?" 425 (equal? (values 1 2 3 4) (values 1 2 3 4)))) 426 427;;; 428;;; stack overflow handling 429;;; 430 431(with-test-prefix "stack overflow handlers" 432 (define (trigger-overflow) 433 (trigger-overflow) 434 (error "not reached")) 435 436 (define (dynwind-test n) 437 (catch 'foo 438 (lambda () 439 (call-with-stack-overflow-handler n 440 (lambda () 441 (dynamic-wind (lambda () #t) 442 trigger-overflow 443 trigger-overflow)) 444 (lambda () 445 (throw 'foo)))) 446 (lambda _ #t))) 447 448 (pass-if-exception "limit should be number" 449 exception:wrong-type-arg 450 (call-with-stack-overflow-handler #t 451 trigger-overflow trigger-overflow)) 452 453 (pass-if-exception "limit should be exact integer" 454 exception:wrong-type-arg 455 (call-with-stack-overflow-handler 2.0 456 trigger-overflow trigger-overflow)) 457 458 (pass-if-exception "limit should be nonnegative" 459 exception:out-of-range 460 (call-with-stack-overflow-handler -1 461 trigger-overflow trigger-overflow)) 462 463 (pass-if-exception "limit should be positive" 464 exception:out-of-range 465 (call-with-stack-overflow-handler 0 466 trigger-overflow trigger-overflow)) 467 468 (pass-if-exception "limit should be within address space" 469 exception:out-of-range 470 (call-with-stack-overflow-handler (ash 1 64) 471 trigger-overflow trigger-overflow)) 472 473 (pass-if "exception on overflow" 474 (catch 'foo 475 (lambda () 476 (call-with-stack-overflow-handler 10000 477 trigger-overflow 478 (lambda () 479 (throw 'foo)))) 480 (lambda _ #t))) 481 482 (pass-if "exception on overflow with dynwind" 483 ;; Try all limits between 1 and 200 words. 484 (let lp ((n 1)) 485 (or (= n 200) 486 (and (dynwind-test n) 487 (lp (1+ n)))))) 488 489 (pass-if-exception "overflow handler should return number" 490 exception:wrong-type-arg 491 (call-with-stack-overflow-handler 1000 492 trigger-overflow 493 (lambda () #t))) 494 (pass-if-exception "overflow handler should return exact integer" 495 exception:wrong-type-arg 496 (call-with-stack-overflow-handler 1000 497 trigger-overflow 498 (lambda () 2.0))) 499 (pass-if-exception "overflow handler should be nonnegative" 500 exception:out-of-range 501 (call-with-stack-overflow-handler 1000 502 trigger-overflow 503 (lambda () -1))) 504 (pass-if-exception "overflow handler should be positive" 505 exception:out-of-range 506 (call-with-stack-overflow-handler 1000 507 trigger-overflow 508 (lambda () 0))) 509 510 (letrec ((fac (lambda (n) 511 (if (zero? n) 1 (* n (fac (1- n))))))) 512 (pass-if-equal "overflow handler can allow recursion to continue" 513 (fac 10) 514 (call-with-stack-overflow-handler 1 515 (lambda () (fac 10)) 516 (lambda () 1))))) 517 518;;; 519;;; docstrings 520;;; 521 522(with-test-prefix "docstrings" 523 524 (pass-if-equal "fixed closure" 525 '("hello" "world") 526 (map procedure-documentation 527 (list (eval '(lambda (a b) "hello" (+ a b)) 528 (current-module)) 529 (eval '(lambda (a b) "world" (- a b)) 530 (current-module))))) 531 532 (pass-if-equal "fixed closure with many args" 533 "So many args." 534 (procedure-documentation 535 (eval '(lambda (a b c d e f g h i j k) 536 "So many args." 537 (+ a b)) 538 (current-module)))) 539 540 (pass-if-equal "general closure" 541 "How general." 542 (procedure-documentation 543 (eval '(lambda* (a b #:key k #:rest r) 544 "How general." 545 (+ a b)) 546 (current-module))))) 547 548;;; 549;;; local-eval 550;;; 551 552(with-test-prefix "local evaluation" 553 554 (pass-if "local-eval" 555 556 (let* ((env1 (local-eval '(let ((x 1) (y 2) (z 3)) 557 (define-syntax-rule (foo x) (quote x)) 558 (the-environment)) 559 (current-module))) 560 (env2 (local-eval '(let ((x 111) (a 'a)) 561 (define-syntax-rule (bar x) (quote x)) 562 (the-environment)) 563 env1))) 564 (local-eval '(set! x 11) env1) 565 (local-eval '(set! y 22) env1) 566 (local-eval '(set! z 33) env2) 567 (and (equal? (local-eval '(list x y z) env1) 568 '(11 22 33)) 569 (equal? (local-eval '(list x y z a) env2) 570 '(111 22 33 a))))) 571 572 (pass-if "local-compile" 573 574 (let* ((env1 (local-compile '(let ((x 1) (y 2) (z 3)) 575 (define-syntax-rule (foo x) (quote x)) 576 (the-environment)) 577 (current-module))) 578 (env2 (local-compile '(let ((x 111) (a 'a)) 579 (define-syntax-rule (bar x) (quote x)) 580 (the-environment)) 581 env1))) 582 (local-compile '(set! x 11) env1) 583 (local-compile '(set! y 22) env1) 584 (local-compile '(set! z 33) env2) 585 (and (equal? (local-compile '(list x y z) env1) 586 '(11 22 33)) 587 (equal? (local-compile '(list x y z a) env2) 588 '(111 22 33 a))))) 589 590 (pass-if "the-environment within a macro" 591 (let ((module-a-name '(test module the-environment a)) 592 (module-b-name '(test module the-environment b))) 593 (let ((module-a (resolve-module module-a-name)) 594 (module-b (resolve-module module-b-name))) 595 (module-use! module-a (resolve-interface '(guile))) 596 (module-use! module-a (resolve-interface '(ice-9 local-eval))) 597 (eval '(begin 598 (define z 3) 599 (define-syntax-rule (test) 600 (let ((x 1) (y 2)) 601 (the-environment)))) 602 module-a) 603 (module-use! module-b (resolve-interface '(guile))) 604 (let ((env (local-eval `(let ((x 111) (y 222)) 605 ((@@ ,module-a-name test))) 606 module-b))) 607 (equal? (local-eval '(list x y z) env) 608 '(1 2 3)))))) 609 610 (pass-if "capture pattern variables" 611 (let ((env (syntax-case #'(((a 1) (b 2) (c 3)) 612 ((d 4) (e 5) (f 6))) () 613 ((((k v) ...) ...) (the-environment))))) 614 (equal? (syntax->datum (local-eval '#'((k ... v ...) ...) env)) 615 '((a b c 1 2 3) (d e f 4 5 6))))) 616 617 (pass-if "mixed primitive-eval, local-eval and local-compile" 618 619 (let* ((env1 (primitive-eval '(let ((x 1) (y 2) (z 3)) 620 (define-syntax-rule (foo x) (quote x)) 621 (the-environment)))) 622 (env2 (local-eval '(let ((x 111) (a 'a)) 623 (define-syntax-rule (bar x) (quote x)) 624 (the-environment)) 625 env1)) 626 (env3 (local-compile '(let ((y 222) (b 'b)) 627 (the-environment)) 628 env2))) 629 (local-eval '(set! x 11) env1) 630 (local-compile '(set! y 22) env2) 631 (local-eval '(set! z 33) env2) 632 (local-compile '(set! a (* y 2)) env3) 633 (and (equal? (local-compile '(list x y z) env1) 634 '(11 22 33)) 635 (equal? (local-eval '(list x y z a) env2) 636 '(111 22 33 444)) 637 (equal? (local-eval '(list x y z a b) env3) 638 '(111 222 33 444 b)))))) 639 640;;; eval.test ends here 641