~ chicken-core (master) /tests/syntax-tests.scm
Trap1;;;; syntax-tests.scm - various macro tests23(import-for-syntax chicken.pretty-print)4(import chicken.gc chicken.pretty-print chicken.port)5(import (only (scheme base) call/cc))67(define-syntax t8 (syntax-rules ()9 ((_ r x)10 (let ((tmp x))11 (if (not (equal? r tmp))12 (error "test failed" r tmp 'x)13 (pp tmp))))))1415(define-syntax f16 (syntax-rules ()17 ((_ x)18 (let ((got-error #f))19 (handle-exceptions ex (set! got-error #t) x)20 (unless got-error21 (error "test returned, but should have failed" 'x) )))))2223(t 3 3)2425(f abc)26(f (t 3 4))2728;; test syntax-rules2930(define-syntax test31 (syntax-rules ()32 ((_ x form)33 (let ((tmp x))34 (if (number? tmp)35 form36 (error "not a number" tmp))))))3738(t 100 (test 2 100))394041;; Keywords are not symbols; don't attempt to bind them42(t 1 (let-syntax ((foo (syntax-rules () ((foo bar: qux) qux))))43 (foo bar: 1)))4445;; some basic contrived testing4647(define (fac n)48 (let-syntax ((m149 (er-macro-transformer50 (lambda (n r c)51 (pp `(M1: ,n))52 (list (r 'sub1) (cadr n))))))53 (define (sub1 . _) ; ref. transp.? (should not be used here)54 (error "argh.") )55 #;(print "fac: " n)56 (if (test n (zero? n))57 158 (* n (fac (m1 n))))))5960(t 3628800 (fac 10))6162;; letrec-syntax6364(t 3465(letrec-syntax ((foo (syntax-rules () ((_ x) (bar x))))66 (bar (syntax-rules () ((_ x) (+ x 1)))))67 (foo 33))68)6970;; letrec-values7172(t '(0 1 2 3 (4) (5 6))73 (letrec-values ((() (values))74 ((a) (values 0))75 ((b c) (values 1 2))76 ((d . e) (values 3 4))77 (f (values 5 6)))78 (list a b c d e f)))7980;; from r5rs:8182(t 4583(let ((x 5))84 (define foo (lambda (y) (bar x y)))85 (define bar (lambda (a b) (+ (* a b) a)))86 (foo (+ x 3)))87)8889;; an error, according to r5rs - here it treats foo as defining a toplevel binding9091#;(let-syntax92 ((foo (syntax-rules ()93 ((foo (proc args ...) body ...)94 (define proc95 (lambda (args ...)96 body ...))))))97 (let ((x 3))98 (foo (plus x y) (+ x y))99 (define foo x)100 (print (plus foo x))))101102(t 'now103(let-syntax ((when (syntax-rules ()104 ((when test stmt1 stmt2 ...)105 (if test106 (begin stmt1107 stmt2 ...))))))108 (let ((if #t))109 (when if (set! if 'now))110 if))111)112113(t 'outer114(let ((x 'outer))115 (let-syntax ((m (syntax-rules () ((m) x))))116 (let ((x 'inner))117 (m))))118)119120(t 7121(letrec-syntax122 ((my-or (syntax-rules ()123 ((my-or) #f)124 ((my-or e) e)125 ((my-or e1 e2 ...)126 (let ((temp e1))127 (if temp128 temp129 (my-or e2 ...)))))))130 (let ((x #f)131 (y 7)132 (temp 8)133 (let odd?)134 (if even?))135 (my-or x136 (let temp)137 (if y)138 y)))139)140141;; From Al* Petrofsky's "An Advanced Syntax-Rules Primer for the Mildly Insane"142(let ((a 1))143 (letrec-syntax144 ((foo (syntax-rules ()145 ((_ b)146 (bar a b))))147 (bar (syntax-rules ()148 ((_ c d)149 (cons c (let ((c 3))150 (list d c 'c)))))))151 (let ((a 2))152 (t '(1 2 3 a) (foo a)))))153154;; ER equivalent155(let ((a 1))156 (letrec-syntax157 ((foo (er-macro-transformer158 (lambda (x r c)159 `(,(r 'bar) ,(r 'a) ,(cadr x)))))160 (bar (er-macro-transformer161 (lambda (x r c)162 (let ((c (cadr x))163 (d (caddr x)))164 `(,(r 'cons) ,c165 (,(r 'let) ((,c 3))166 (,(r 'list) ,d ,c ',c))))))))167 (let ((a 2))168 (t '(1 2 3 a) (foo a)))))169170;; IR equivalent171(let ((a 1))172 (letrec-syntax173 ((foo (ir-macro-transformer174 (lambda (x i c)175 `(bar a ,(cadr x)))))176 (bar (ir-macro-transformer177 (lambda (x i c)178 (let ((c (cadr x))179 (d (caddr x)))180 `(cons ,c181 (let ((,c 3))182 (list ,d ,c ',c))))))))183 (let ((a 2))184 (t '(1 2 3 a) (foo a)))))185186;; Strip-syntax on vectors:187(let-syntax188 ((foo (syntax-rules ()189 ((_)190 '#(b)))))191 (t '#(b) (foo)))192193(define-syntax kw194 (syntax-rules (baz)195 ((_ baz) "baz")196 ((_ any) "no baz")))197198(t "baz" (kw baz))199(t "no baz" (kw xxx))200201(let ((baz 100))202 (t "no baz" (kw baz)))203204;; Optimisation to rewrite constants with =>, reported by Michele La Monaca205(t 2 (cond (1 2)))206(f (cond (1 => string-length)))207(t #t (cond (1 => odd?)))208209(t 'ok210(let ((=> #f))211 (cond (#t => 'ok)))212)213214(t 1 (let ((=> 1))215 (cond (#f 'false)216 (#t =>))))217218(t 3 (let ((=> 1))219 (cond (#f 'false)220 (#t => 2 3))))221222(t '(3 4)223(let ((foo 3))224 (let-syntax ((bar (syntax-rules () ((_ x) (list foo x)))))225 (let ((foo 4))226 (bar foo))))227)228229;;; strip-syntax cuts across multiple levels of syntax230;;; reported by Matthew Flatt231(define-syntax c232 (syntax-rules ()233 [(_)234 (let ([x 10])235 (let-syntax ([z (syntax-rules ()236 [(_) (quote x)])])237 (z)))]))238239(t "x" (symbol->string (c)))240241(define-syntax c2242 (syntax-rules ()243 [(_)244 (let ([x 10])245 (let-syntax ([z (syntax-rules ()246 [(_) (let-syntax ([w (syntax-rules ()247 [(_) (quote x)])])248 (w))])])249 (z)))]))250251(t "x" (symbol->string (c2)))252253;;; strip-syntax on renamed module identifiers, as well as core identifiers254(module foo (bar)255 (import scheme)256257 (define bar 1))258259(import foo)260261(define-syntax baz262 (er-macro-transformer263 (lambda (e r c)264 `',(strip-syntax (r 'bar)))))265266(t "bar" (symbol->string (baz bar)))267(t "bar" (symbol->string (baz void)))268269;; Fully qualified symbols are not mangled - these names are internal270;; and not documented, but shouldn't be messed with by the expander271272(t "foo#bar" (symbol->string 'foo#bar))273(t "foo#bar" (symbol->string (strip-syntax 'foo#bar)))274275(t "#!rest" (symbol->string '#!rest))276(t "#!rest" (symbol->string '|#!rest|))277(t "#!rest" (symbol->string (strip-syntax '#!rest)))278279;; Read-write invariance of "special" symbols280281(t '#!rest (with-input-from-string "#!rest" read))282(t '#!rest (with-input-from-string "|#!rest|" read))283(t "#!rest" (with-output-to-string (lambda () (write '#!rest))))284285;; Non-special symbols starting with shebang286(f (with-input-from-string "#!foo" read))287(t '|#!foo| (with-input-from-string "|#!foo|" read))288(t "|#!foo|" (with-output-to-string (lambda () (write '|#!foo|))))289290;; Namespaced symbols291(t "foo#bar" (with-output-to-string (lambda () (write 'foo#bar))))292(t "##foo#bar" (with-output-to-string (lambda () (write '##foo#bar))))293294;; These used to be treated specially, but now they just trigger an295;; "invalid sharp-sign read syntax" error.296(t "|#%foo|" (with-output-to-string (lambda () (write '|#%foo|))))297(f (with-input-from-string "#%foo" read))298299;;; alternative ellipsis test (SRFI-46)300301(define-syntax foo302 (syntax-rules303 ___ ()304 ((_ vals ___) (list '... vals ___))))305306(t '(... 1 2 3)307 (foo 1 2 3)308)309310(define-syntax defalias311 (syntax-rules ___ ()312 ((_ new old)313 (define-syntax new314 (syntax-rules ()315 ((_ args ...) (old args ...)))))))316317(defalias inc add1)318319(t 3 (inc 2))320321;;; Rest patterns after ellipsis (SRFI-46)322323(define-syntax foo324 (syntax-rules ()325 ((_ (a ... b) ... (c d))326 (list (list (list a ...) ... b ...) c d))327 ((_ #(a ... b) ... #(c d) #(e f))328 (list (list (vector a ...) ... b ...) c d e f))329 ((_ #(a ... b) ... #(c d))330 (list (list (vector a ...) ... b ...) c d))))331332(t '(() 1 2)333 (foo (1 2)))334335(t '(((1) 2) 3 4)336 (foo (1 2) (3 4)))337338(t '(((1 2) (4) 3 5) 6 7)339 (foo (1 2 3) (4 5) (6 7)))340341(t '(() 1 2)342 (foo #(1 2)))343344(t '((#() 1) 2 3)345 (foo #(1) #(2 3)))346347(t '((#(1 2) 3) 4 5)348 (foo #(1 2 3) #(4 5)))349350(t '((#(1 2) 3) 4 5 6 7)351 (foo #(1 2 3) #(4 5) #(6 7)))352353(t '(() 1 2 3 4)354 (foo #(1 2) #(3 4)))355356(t '((#(1) 2) 3 4 5 6)357 (foo #(1 2) #(3 4) #(5 6)))358359(t '((#(1 2) #(4) 3 5) 6 7 8 9)360 (foo #(1 2 3) #(4 5) #(6 7) #(8 9)))361362;;; Bug discovered during implementation of SRFI-46 rest patterns:363364(define-syntax foo365 (syntax-rules ()366 ((_ #((a) ...)) (list a ...))))367368(t '(1)369 (foo #((1))))370371;;;372373(define-syntax usetmp374 (syntax-rules ()375 ((_ var)376 (list var))))377378(define-syntax withtmp379 (syntax-rules ()380 ((_ val exp)381 (let ((tmp val))382 (exp tmp)))))383384(t '(99)385 (withtmp 99 usetmp)386)387388(t 7389(letrec-syntax390 ((my-or (syntax-rules ()391 ((my-or) #f)392 ((my-or e) e)393 ((my-or e1 e2 ...)394 (let ((temp e1))395 (if temp396 temp397 (my-or e2 ...)))))))398 (let ((x #f)399 (y 7)400 (temp 8)401 (let odd?)402 (if even?))403 (my-or x404 (let temp)405 (if y)406 y)))407)408409(define-syntax foo410 (syntax-rules ()411 ((_ #(a ...)) (list a ...))))412413(t '(1 2 3)414 (foo #(1 2 3))415)416417418(define-syntax loop419 (er-macro-transformer420 (lambda (x r c)421 (let ((body (cdr x)))422 `(,(r 'call/cc)423 (,(r 'lambda) (exit)424 (,(r 'let) ,(r 'f) () ,@body (,(r 'f)))))))))425426(let ((n 10))427 (loop428 (print* n " ")429 (set! n (sub1 n))430 (when (zero? n) (exit #f)))431 (newline))432433(define-syntax while0434 (syntax-rules ()435 ((_ t b ...)436 (loop (if (not t) (exit #f))437 b ...))))438439(f (while0 #f (print "no.")))440441(define-syntax while442 (er-macro-transformer443 (lambda (x r c)444 `(,(r 'loop)445 (,(r 'if) (,(r 'not) ,(cadr x)) (exit #f))446 ,@(cddr x)))))447448(let ((n 10))449 (while (not (zero? n))450 (print* n " ")451 (set! n (- n 1)) )452 (newline))453454;;; found by Jim Ursetto455456(let ((lambda 0)) (define (foo) 1) (foo))457458459;;; define-macro implementation (only usable in a module-free environment)460461(define-syntax define-macro462 (syntax-rules ()463 ((_ (name . llist) body ...)464 (define-syntax name465 (er-macro-transformer466 (lambda (x r c)467 (apply (lambda llist body ...) (strip-syntax (cdr x)))))))))468469(define-macro (loop . body)470 (let ((loop (gensym)))471 `(call/cc472 (lambda (exit)473 (let ,loop () ,@body (,loop))))))474475(let ((i 1))476 (loop (when (> i 10) (exit #f))477 (print* i " ")478 (set! i (add1 i))))479(newline)480481482;;;; exported macro would override original name (fixed in rev. 13351)483484(module xfoo (xbaz xbar)485 (import scheme)486 (define-syntax xbar487 (syntax-rules ()488 ((_ 1) (xbaz))489 ((_) 'xbar)))490 (define-syntax xbaz491 (syntax-rules ()492 ((_ 1) (xbar))493 ((_) 'xbazz))))494495(import xfoo)496(assert (eq? 'xbar (xbaz 1)))497(assert (eq? 'xbazz (xbar 1)))498(assert (eq? 'xbar (xbar)))499500501;;;; ellipsis pattern element wasn't matched - reported by Jim Ursetto (fixed rev. 13582)502503(define-syntax foo504 (syntax-rules ()505 ((_ (a b) ...)506 (list '(a b) ...))507 ((_ a ...)508 (list '(a) ...))))509510(assert (equal? (foo (1 2) (3 4) (5 6)) '((1 2) (3 4) (5 6))))511(assert (equal? (foo (1 2) (3) (5 6)) '(((1 2)) ((3)) ((5 6))))) ; failed512(assert (equal? (foo 1) '((1))))513514515;;; incorrect lookup for keyword variables in DSSSL llists516517(module broken-keyword-var ()518 (import scheme (chicken base))519 ((lambda (#!key string) (assert (not string))))) ; refered to R5RS `string'520521;;; Missing check for keyword and optional variable types in DSSSL llists522523(f (eval '(lambda (foo #!key (0 1)) x)))524(f (eval '(lambda (foo #!optional (0 1)) x)))525526;;; compiler didn't resolve expansion into local variable527;;; (reported by Alex Shinn, #15)528529(module unresolve-local (foo)530 (import scheme)531 (define (foo)532 (let ((qux 3))533 (let-syntax ((bar (syntax-rules () ((bar) qux))))534 (bar))))535536 (display (foo))537 (newline)538)539540541;;; incorrect expansion when assigning to something marked '##core#primitive (rev. 14613)542543(define x 99)544545(module primitive-assign ()546 (import scheme (chicken base))547 (let ((x 100)) (set! x 20) (assert (= x 20)))548 (set! setter 123))549550(assert (= x 99))551(assert (= 123 setter))552553554;;; prefixed import from `chicken' module with indirect reference to imported syntax555;;; (reported by Jack Trades)556557(module prefixed-self-reference1 (a b c)558 (import scheme (prefix chicken.base c:))559 (c:define-values (a b c) (values 1 2 3)) )560561(module prefixed-self-reference2 ()562 (import scheme (prefix (chicken base) c:) (prefix (chicken condition) c:))563 (c:define-values (a b c) (values 1 2 3))564 (c:print "ok")565 (c:condition-case566 (c:abort "ugh")567 (ex () (c:print "caught"))))568569(module prefixed-self-reference3 (a)570 ;; TODO: Switch this around when plain "chicken" has been removed571 (import (prefix scheme s.) (prefix (chicken condition) c.))572 (s.define (a x y)573 (c.condition-case (s.+ x y) ((exn) "not numbers")))574 )575576(module prefixed-self-reference4 (a)577 (import (prefix scheme s.))578 (s.define (a x y) (s.and x y)))579580581;;; canonicalization of body captures 'begin (reported by Abdulaziz Ghuloum)582583(let ((begin (lambda (x y) (bomb)))) 1 2)584585586;;; redefinition of defining forms587588(module m0001 (foo bar)589 (import (prefix scheme s:))590 (s:define-syntax foo (syntax-rules () ((_ x) (s:list x))))591 (s:define bar 99))592593(module m0002 ()594 (import scheme m0001 chicken.pretty-print)595 (pp (foo bar)))596597598;;; renaming of arbitrary structures599600(module m1 (s1 s2)601602 (import scheme)603604 (define-syntax s1 (syntax-rules () ((_ x) (list x))))605606 (define-syntax s2607 (er-macro-transformer608 (lambda (x r c)609 (r `(vector (s1 ,(cadr x))))))) ) ; without renaming the local version of `s1'610 ; below will be captured611612(import m1)613614(let-syntax ((s1 (syntax-rules () ((_ x) x))))615 (assert (equal? '#((99)) (s2 99))))616617;; IR macros618619(define-syntax loop2620 (ir-macro-transformer621 (lambda (x i c)622 (let ((body (cdr x)))623 `(call/cc624 (lambda (,(i 'exit))625 (let f () ,@body (f))))))))626627(let ((n 10))628 (loop2629 (print* n " ")630 (set! n (sub1 n))631 (when (zero? n) (exit #f)))632 (newline))633634(define-syntax while20635 (syntax-rules ()636 ((_ t b ...)637 (loop2 (if (not t) (exit #f))638 b ...))))639640(f (while20 #f (print "no.")))641642(define-syntax while2643 (ir-macro-transformer644 (lambda (x i c)645 `(loop646 (if (not ,(cadr x)) (,(i 'exit) #f))647 ,@(cddr x)))))648649(let ((n 10))650 (while2 (not (zero? n))651 (print* n " ")652 (set! n (- n 1)) )653 (newline))654655(module m2 (s3 s4)656657 (import scheme)658659 (define-syntax s3 (syntax-rules () ((_ x) (list x))))660661 (define-syntax s4662 (ir-macro-transformer663 (lambda (x r c)664 `(vector (s3 ,(cadr x)))))) ) ; without implicit renaming the local version665 ; of `s3' below would be captured666667(import m2)668669(let-syntax ((s3 (syntax-rules () ((_ x) x))))670 (t '#((99)) (s4 99)))671672(let ((vector list))673 (t '#((one)) (s4 'one)))674675(define-syntax nest-me676 (ir-macro-transformer677 (lambda (x i c)678 `(let ((,(i 'captured) 1))679 ,@(cdr x)))))680681(t '(1 #(1 #(1)))682 (nest-me (list captured683 (let ((captured 2)684 (let 'not-captured)685 (list vector))686 (nest-me (list captured687 (nest-me (list captured))))))))688689(define-syntax cond-test690 (ir-macro-transformer691 (lambda (x i c)692 (let lp ((exprs (cdr x)))693 (cond694 ((null? exprs) '(void))695 ((c (caar exprs) 'else)696 `(begin ,@(cdar exprs)))697 ((c (cadar exprs) '=>)698 `(let ((tmp ,(caar exprs)))699 (if tmp700 (,(caddar exprs) tmp)701 ,(lp (cdr exprs)))))702 ((c (cadar exprs) (i '==>)) ;; ==> is an Unhygienic variant of =>703 `(let ((tmp ,(caar exprs)))704 (if tmp705 (,(caddar exprs) tmp)706 ,(lp (cdr exprs)))))707 (else708 `(if ,(caar exprs)709 (begin ,@(cdar exprs))710 ,(lp (cdr exprs)))))))))711712(t 'yep713 (cond-test714 (#f 'false)715 (else 'yep)))716717(t 1718 (cond-test719 (#f 'false)720 (1 => (lambda (x) x))721 (else 'yep)))722723(let ((=> #f))724 (t 'a-procedure725 (cond-test726 (#f 'false)727 (1 => 'a-procedure)728 (else 'yep))))729730(let ((else #f))731 (t (void)732 (cond-test733 (#f 'false)734 (else 'nope))))735736(t 1737 (cond-test738 (#f 'false)739 (1 ==> (lambda (x) x))740 (else 'yep)))741742(let ((==> #f))743 (t 1744 (cond-test745 (#f 'false)746 (1 ==> (lambda (x) x))747 (else 'yep))))748749;; Undefined value (but no compiler error) on empty `else' clauses750(t (void) (cond (else)))751(t (void) (case 1 (else)))752753;; Literal quotation of a symbol, injected or not, should always result in that symbol754(module ir-se-test (run)755 (import scheme chicken.base)756 (define-syntax run757 (ir-macro-transformer758 (lambda (e i c)759 `(quote ,(i 'void))))))760761(import ir-se-test)762(t 'void (run))763764;;; local definitions765766(define-syntax s2767 (syntax-rules ()768 ((_) 1)))769770(define (f1) 3)771(define-values (v1 v2) (values 9 10))772(define-values (v3 . v4) (values 11 12))773(define-values v56 (values 13))774775(let ()776 (define-syntax s2777 (syntax-rules ()778 ((_) 2)))779 42780 (define-values (v1 v2) (values 1 2))781 (define-values (v3 . v4) (values 3 4))782 (define-values v56 (values 5 6))783 (define v56-again v56) ; ordering of assignments was broken #1274784 43785 (define (f1) 4)786 (define ((f2)) 4)787 (assert (= 4 (f1)))788 (assert (= 4 ((f2))))789 (assert (= 2 (s2)))790 (assert (= 1 v1))791 (assert (= 2 v2))792 (assert (= 3 v3))793 (assert (equal? (list 4) v4))794 (assert (equal? (list 5 6) v56))795 (assert (equal? (list 5 6) v56-again)))796797(assert (= 1 (s2)))798(assert (= 3 (f1)))799(assert (= 9 v1))800(assert (= 10 v2))801(assert (= 11 v3))802(assert (equal? (list 12) v4))803(assert (equal? (list 13) v56))804805;;; redefining definition forms (disabled, since we can not catch this error easily)806807#|808(module m0a () (import chicken.module) (reexport (only scheme define)))809(module m0b () (import chicken.module) (reexport (only scheme define-syntax)))810811(module m1 ()812(import (prefix scheme s:) (prefix m0b m:))813;(s:define m:define 1)814(s:define-syntax s:define-syntax (syntax-rules ()))815)816|#817818;;; Definitions of non-identifiers819820(f (eval '(define foo: 1)))821(f (eval '(define-syntax foo: (syntax-rules () ((_) 1)))))822(f (eval '(let foo: () 1)))823(f (eval '(let ((foo: 1)) 1)))824825826;;; Definitions in expression contexts are rejected (#1309)827828(f (eval '(+ 1 2 (begin (define x 3) x) 4)))829(f (eval '(+ 1 2 (begin (define-values (x y) (values 3 4)) x) 4)))830(f (eval '(display (define x 1))))831;; Some tests for nested but valid definition expressions:832(t 2 (eval '(begin (define x 1) 2)))833(t 2 (eval '(module _ () (import scheme) (define x 1) 2)))834(t 1 (eval '(let ()835 (define-record-type foo (make-foo bar) foo? (bar foo-bar))836 (foo-bar (make-foo 1)))))837838;; Nested begins inside definitions were not treated correctly839(t 3 (eval '(let () (begin 1 (begin 2 (define internal-def 3) internal-def)))))840;; Macros that expand to "define" should not cause a letrec barrier841(t 1 (eval '(let-syntax ((my-define (syntax-rules ()842 ((_ var val) (define var val)))))843 (let () (define (run-it) foo) (my-define foo 1) (run-it)))))844;; Begin should not cause a letrec barrier845(t 1 (eval '(let () (define (run-it) foo) (begin (define foo 1) (run-it)))))846(f (eval '(let () internal-def)))847848;;; renaming of keyword argument (#277)849850(define-syntax foo1851 (syntax-rules ()852 ((_ procname)853 (define (procname #!key (who "world"))854 (string-append "hello, " who)))))855856(foo1 bar)857858(assert (string=? "hello, XXX" (bar who: "XXX")))859860;;; DSSSL keyword arguments in various combinations with optional and rest args861;;; reported on IRC by R. Winkler862863(define (test-optional&rest x y #!optional z #!rest r)864 (list x y z r))865866(assert (equal? '(3 4 5 (6 7)) (test-optional&rest 3 4 5 6 7)))867868(define (test-optional&rest-cdrs x y #!optional z #!rest r)869 (list x y z (cdr (cdr r))))870871(assert (equal? '(3 4 5 ()) (test-optional&rest-cdrs 3 4 5 6 7)))872873(define (test-optional&key x y #!optional z #!key i (j 1))874 (list x y z i: i j: j))875876(assert (equal? '(3 4 5 i: 6 j: 7) (test-optional&key 3 4 5 i: 6 j: 7 8)))877;; Unfortunate but correct (missing optional arg)878(assert (equal? '(3 4 i: i: #f j: 1) (test-optional&key 3 4 i: 6 j: 7 8)))879880(define (test-key&rest x y #!rest r #!key i (j 1))881 (list x y i: i j: j r))882883(assert (equal? '(3 4 i: 5 j: 1 (i: 5 6 7)) (test-key&rest 3 4 i: 5 6 7)))884(assert (equal? '(3 4 i: 5 j: 6 (i: 5 j: 6 7 8))885 (test-key&rest 3 4 i: 5 j: 6 7 8)))886887(define (test-optional-key&rest x y #!optional z #!rest r #!key i (j 1))888 (list x y z i: i j: j r))889890(assert (equal? '(3 4 5 i: 6 j: 7 (i: 6 j: 7 8))891 (test-optional-key&rest 3 4 5 i: 6 j: 7 8)))892893;;; Miscellaneous DSSSL tests894895;; DSSSL annotations may each appear only once896(f (eval '(lambda (x #!optional o1 #!optional o2) 'foo)))897(f (eval '(lambda (x #!rest r1 #!rest r1) 'foo)))898(f (eval '(lambda (x #!key k1 #!key k2) 'foo)))899900;; DSSSL annotations must occur in order (optional, rest, key)901(f (eval '(lambda (x #!rest r1 #!optional o1) 'foo)))902(f (eval '(lambda (x #!key k1 #!optional o1) 'foo)))903(f (eval '(lambda (x #!key r1 #!rest k1) 'foo)))904905;; #!rest limited to 1 arg906(f (eval '(lambda (x #!rest r1 r2) 'foo)))907908;; list arguments invalid for required and rest parameters909(f (eval '(lambda ((x 0) #!rest r1) 'foo)))910(f (eval '(lambda (x #!rest (r1 0)) 'foo)))911912;; "optional" expansion should not rely on user imports (hygiene)913(t '(1 2)914 (eval '(module x ()915 (import (only scheme lambda list))916 ((lambda (x #!optional (y 0)) (list x y)) 1 2))))917918;; Dotted list syntax can be mixed in919(t '(1 2 3 4 (5 6))920 ((lambda (x y #!optional o1 o2 . r) (list x y o1 o2 r))921 1 2 3 4 5 6))922923;; More DSSSL hygiene issues, from #806924(module dsssl-extended-lambda-list-hygiene ()925 (import (prefix scheme s/))926 (s/define (foo #!optional bar #!rest qux #!key baz)927 (s/list bar baz qux)))928929;;; import not seen, if explicitly exported and renamed:930931(module rfoo (rbar rbaz)932(import scheme)933934(define (rbaz x)935 (display x)936 (newline) )937938(define-syntax rbar939 (syntax-rules ()940 ((_ x) (rbaz x))))941942)943944(import (prefix rfoo f:))945(f:rbar 1)946947;;; SRFI-2 (and-let*)948949(t 1 (and-let* ((a 1)) a))950(f (eval '(and-let* ((a 1 2 3)) a)))951(t 2 (and-let* ((a 1) (b (+ a 1))) b))952(t 3 (and-let* (((or #f #t))) 3))953(f (eval '(and-let* ((or #f #t)) 1)))954(t 4 (and-let* ((c 4) ((equal? 4 c))) c))955(t #f (and-let* ((c 4) ((equal? 5 c))) (error "not reached")))956(t #f (and-let* (((= 4 5)) ((error "not reached 1"))) (error "not reached 2")))957(t 'foo (and-let* (((= 4 4)) (a 'foo)) a))958(t #f (and-let* ((a #f) ((error "not reached 1"))) (error "not reached 2")))959960(t (and-let* () 1) 1)961(t (and-let* () 1 2) 2)962(t (and-let* () ) #t)963964(t (let ((x #f)) (and-let* (x))) #f)965(t (let ((x 1)) (and-let* (x))) 1)966(t (and-let* ((x #f)) ) #f)967(t (and-let* ((x 1)) ) 1)968(f (eval '(and-let* ( #f (x 1))) ))969(t (and-let* ( (#f) (x 1)) ) #f)970(f (eval '(and-let* (2 (x 1))) ))971(t (and-let* ( (2) (x 1)) ) 1)972(t (and-let* ( (x 1) (2)) ) 2)973(t (let ((x #f)) (and-let* (x) x)) #f)974(t (let ((x "")) (and-let* (x) x)) "")975(t (let ((x "")) (and-let* (x) )) "")976(t (let ((x 1)) (and-let* (x) (+ x 1))) 2)977(t (let ((x #f)) (and-let* (x) (+ x 1))) #f)978(t (let ((x 1)) (and-let* (((positive? x))) (+ x 1))) 2)979(t (let ((x 1)) (and-let* (((positive? x))) )) #t)980(t (let ((x 0)) (and-let* (((positive? x))) (+ x 1))) #f)981(t (let ((x 1)) (and-let* (((positive? x)) (x (+ x 1))) (+ x 1))) 3)982; The uniqueness of the bindings isn't enforced983(t (let ((x 1)) (and-let* (((positive? x)) (x (+ x 1)) (x (+ x 1))) (+ x 1))) 4)984985(t (let ((x 1)) (and-let* (x ((positive? x))) (+ x 1))) 2)986(t (let ((x 1)) (and-let* ( ((begin x)) ((positive? x))) (+ x 1))) 2)987(t (let ((x 0)) (and-let* (x ((positive? x))) (+ x 1))) #f)988(t (let ((x #f)) (and-let* (x ((positive? x))) (+ x 1))) #f)989(t (let ((x #f)) (and-let* ( ((begin x)) ((positive? x))) (+ x 1))) #f)990991(t (let ((x 1)) (and-let* (x (y (- x 1)) ((positive? y))) (/ x y))) #f)992(t (let ((x 0)) (and-let* (x (y (- x 1)) ((positive? y))) (/ x y))) #f)993(t (let ((x #f)) (and-let* (x (y (- x 1)) ((positive? y))) (/ x y))) #f)994(t (let ((x 3)) (and-let* (x (y (- x 1)) ((positive? y))) (/ x y))) 3/2)995996;;; SRFI-26997998;; Cut999(t '() ((cut list)))1000(t '() ((cut list <...>)))1001(t '(1) ((cut list 1)))1002(t '(1) ((cut list <>) 1))1003(t '(1) ((cut list <...>) 1))1004(t '(1 2) ((cut list 1 2)))1005(t '(1 2) ((cut list 1 <>) 2))1006(t '(1 2) ((cut list 1 <...>) 2))1007(t '(1 2 3 4) ((cut list 1 <...>) 2 3 4))1008(t '(1 2 3 4) ((cut list 1 <> 3 <>) 2 4))1009(t '(1 2 3 4 5 6) ((cut list 1 <> 3 <...>) 2 4 5 6))1010(t '(ok) (let* ((x 'wrong)1011 (y (cut list x)))1012 (set! x 'ok)1013 (y)))1014(t 2 (let ((a 0))1015 (map (cut + (begin (set! a (+ a 1)) a) <>)1016 '(1 2))1017 a))1018(f (eval '((cut + <...> 1) 1)))10191020;; Cute1021(t '() ((cute list)))1022(t '() ((cute list <...>)))1023(t '(1) ((cute list 1)))1024(t '(1) ((cute list <>) 1))1025(t '(1) ((cute list <...>) 1))1026(t '(1 2) ((cute list 1 2)))1027(t '(1 2) ((cute list 1 <>) 2))1028(t '(1 2) ((cute list 1 <...>) 2))1029(t '(1 2 3 4) ((cute list 1 <...>) 2 3 4))1030(t '(1 2 3 4) ((cute list 1 <> 3 <>) 2 4))1031(t '(1 2 3 4 5 6) ((cute list 1 <> 3 <...>) 2 4 5 6))1032(t 1 (let ((a 0))1033 (map (cute + (begin (set! a (+ a 1)) a) <>)1034 '(1 2))1035 a))1036(f (eval '((cute + <...> 1) 1)))10371038;;; (quasi-)quotation10391040(f (eval '(let ((a 1)) (unquote a))))1041(t 'unquote (quasiquote unquote))1042(f (eval '(quasiquote (a unquote . 1)))) ; "Bad syntax". Also ok: '(a unquote . 1)1043(t 'a (quasiquote a))1044(f (eval '(quasiquote a b)))1045(f (eval '(quote a b)))1046(f (eval '(quasiquote)))1047(f (eval '(quote)))1048(f (eval '(quasiquote . a)))1049(f (eval '(quote . a)))1050(t '(foo . 1) (let ((bar 1))1051 (quasiquote (foo . (unquote bar)))))1052(f (eval '(let ((a 1)1053 (b 2))1054 (quasiquote (unquote a b))))) ; > 1 arg10551056(t '(quasiquote (unquote a)) (quasiquote (quasiquote (unquote a))))1057(t '(quasiquote x y) (quasiquote (quasiquote x y)))10581059(t '(unquote-splicing a) (quasiquote (unquote-splicing a)))1060(t '(1 2) (let ((a (list 2))) (quasiquote (1 (unquote-splicing a)))))1061(f (eval '(let ((a 1)) ; a is not a list1062 (quasiquote (1 (unquote-splicing a) 2)))))1063(f (eval '(let ((a (list 1))1064 (b (list 2)))1065 (quasiquote (1 (unquote-splicing a b)))))) ; > 1 arg10661067;; level counting1068(define x (list 1 2))10691070;; Testing R5RS-compliance:1071(t '(quasiquote (unquote (1 2)))1072 (quasiquote (quasiquote (unquote (unquote x)))))1073(t '(quasiquote (unquote-splicing (1 2)))1074 (quasiquote (quasiquote (unquote-splicing (unquote x)))))1075(t '(quasiquote (unquote 1 2))1076 (quasiquote (quasiquote (unquote (unquote-splicing x)))))1077(t 'x1078 (quasiquote (unquote (quasiquote x))))1079(t '(quasiquote (unquote-splicing (quasiquote (unquote x))))1080 (quasiquote (quasiquote (unquote-splicing (quasiquote (unquote x))))))1081(t '(quasiquote (unquote (quasiquote (unquote-splicing x))))1082 (quasiquote (quasiquote (unquote (quasiquote (unquote-splicing x))))))1083(t '(quasiquote (unquote (quasiquote (unquote (1 2)))))1084 (quasiquote (quasiquote (unquote (quasiquote (unquote (unquote x)))))))10851086;; The following are explicitly left undefined by R5RS. For consistency1087;; we define any unquote-(splicing) or quasiquote that occurs in the CAR of1088;; a pair to decrease, respectively increase the level count by one.10891090(t '(quasiquote . #(1 (unquote x) 3)) ; cdr is not a pair1091 (quasiquote (quasiquote . #(1 (unquote x) 3))))1092(t '(quasiquote #(1 (unquote x) 3)) ; cdr is a list of one1093 (quasiquote (quasiquote #(1 (unquote x) 3))))1094(t '(quasiquote a #(1 (unquote x) 3) b) ; cdr is longer1095 (quasiquote (quasiquote a #(1 (unquote x) 3) b)))10961097(t '(quasiquote (unquote . #(1 (1 2) 3))) ; cdr is not a pair1098 (quasiquote (quasiquote (unquote . #(1 (unquote x) 3)))))1099(t '(quasiquote (unquote #(1 (1 2) 3))) ; cdr is a list of one1100 (quasiquote (quasiquote (unquote #(1 (unquote x) 3)))))1101(t '(quasiquote (unquote a #(1 (1 2) 3) b)) ; cdr is longer1102 (quasiquote (quasiquote (unquote a #(1 (unquote x) 3) b))))11031104(t '(quasiquote (unquote-splicing . #(1 (1 2) 3))) ; cdr is not a pair1105 (quasiquote (quasiquote (unquote-splicing . #(1 (unquote x) 3)))))1106(t '(quasiquote (unquote-splicing #(1 (1 2) 3))) ; cdr is a list of one1107 (quasiquote (quasiquote (unquote-splicing #(1 (unquote x) 3)))))1108(t '(quasiquote (unquote-splicing a #(1 (1 2) 3) b)) ; cdr is longer1109 (quasiquote (quasiquote (unquote-splicing a #(1 (unquote x) 3) b))))11101111(t 'quasiquote (quasiquote quasiquote))1112(t 'unquote (quasiquote unquote))1113(t 'unquote-splicing (quasiquote unquote-splicing))1114(t '(x quasiquote) (quasiquote (x quasiquote)))1115; (quasiquote (x unquote)) is identical to (quasiquote (x . (unquote)))....1116;; It's either this (error) or make all calls to unquote with more or less1117;; than one argument resolve to a literal unquote.1118(f (eval '(quasiquote (x unquote))))1119(t '(x unquote-splicing) (quasiquote (x unquote-splicing)))1120;; Let's internal defines properly compared to core define procedure when renamed1121(f (eval '(let-syntax ((foo (syntax-rules () ((_ x) (begin (define x 1))))))1122 (let () (foo a))1123 (print "1: " a))))11241125(t '(a 1) (letrec-syntax ((define (syntax-rules () ((_ x y) (list 'x y))))1126 (foo (syntax-rules () ((_ x) (define x 1)))))1127 (let () (foo a))))11281129(t '(1) (let-syntax ((define (syntax-rules () ((_ x) (list x)))))1130 (let () (define 1))))11311132;; Local override: not a macro1133(t '(1) (let ((define list)) (define 1)))11341135;; Toplevel (no SE)1136(define-syntax foo (syntax-rules () ((_ x) (begin (define x 1)))))1137(foo a)1138(t 1 a)113911401141;; ,@ in tail pos with circular object - found in trav2 benchmark and1142;; reported by syn:11431144(let ((a '(1)))1145 (set-cdr! a a)1146 `(1 ,@a))114711481149;; ##sys#alias-global-hook, when invoked via eval/meta, did resolve identifiers1150;; used during evaluation of an expander body in the wrong environment and mapped1151;; an identifier to something imported for the runtime environment11521153(module foonumbers (+)1154 (import (except scheme +) (only (chicken base) error))1155 (define (+ . _) (error "failed.")))11561157(import foonumbers)11581159(define-syntax foo1160 (er-macro-transformer1161 (lambda (x r c)1162 `(print ,(+ (cadr x) 1)))))11631164(foo 3)116511661167;; #578: import with specifier has no effect for internal modules on csi's top-level11681169(import srfi-4)1170(import (prefix srfi-4 other-))1171u8vector1172other-u8vector11731174(import (prefix scheme other-))1175eval1176other-eval117711781179;; #805: case-lambda is unhygienic (see 4706afb4 and bc5cc698)1180(module case-lambda-and-ensure-hygiene ()1181 (import (prefix (scheme case-lambda) c/) (prefix scheme s/))1182 (c/case-lambda ((a) a)))118311841185;; #816: compiler-syntax should obey hygiene in its rewrites1186(module foo ()1187 (import (prefix (only scheme map lambda list) ~))1188 (~map (~lambda (y) y) (~list 1)))11891190;; #852: renamed macros should not be returned as first-class1191;; objects in the interpreter1192(module renamed-macros (renamed-macro-not-firstclassed)1193 (import scheme chicken.base)1194 (define-syntax renamed-macro-not-firstclassed1195 (er-macro-transformer1196 (lambda (e r c)1197 `(,(r 'list) ,(r 'define))))))11981199(f (eval '(begin (import renamed-macros) (renamed-macro-not-firstclassed))))12001201;; #893: implicitly renamed variables shouldn't be resolved to core1202;; builtins (#%xyz), but go through a level of indirection, so1203;; strip-syntax can still access the original symbol.1204(module rename-builtins1205 (strip-syntax-on-*)1206 (import scheme chicken.base)1207 (define-syntax strip-syntax-on-*1208 (ir-macro-transformer1209 (lambda (e r c) '(quote *)))))12101211(import rename-builtins)1212(assert (eq? '* (strip-syntax-on-*)))12131214;; #1362: Double rename would cause "renamed" var to be restored to1215;; the original macro aliased name (resulting in a plain symbol)1216(let-syntax ((wrapper/should-do-nothing1217 (er-macro-transformer1218 (lambda (e r c)1219 (let* ((%x (r 'x))1220 (%%x (r %x)))1221 `(let ((,%x 1)1222 (,%%x 2))1223 ,(cadr e)))))))1224 (print (let ((x 1)) (wrapper/should-do-nothing x))))12251226;; Same net effect as above, but more complex by the use of IR macros.1227(letrec-syntax ((bind-pair1228 (ir-macro-transformer1229 (lambda (e i c)1230 (let* ((b (cadr e))1231 (exp (caddr e))1232 (body (cdddr e)))1233 `(let* ((x ,exp)1234 (,(car b) (car x))1235 (,(cadr b) (cdr x)))1236 ,@body)))))1237 (foo1238 (ir-macro-transformer1239 (lambda (e i c)1240 `(bind-pair (x y) (cons 'foo-car 'foo-cdr) y)))))1241 (assert (eq? 'second (bind-pair (x y) (cons 'first 'second) y)))1242 (assert (eq? 'foo-cdr (foo))))12431244;; #944: macro-renamed defines mismatch with the names recorded in module1245;; definitions, causing the module to be unresolvable.12461247(module foo ()1248 (import scheme)1249 (define-syntax bar1250 (syntax-rules ()1251 ((_) (begin (define req 1) (display req) (newline)))))1252 (bar))12531254;; The fix for the above bug causes the req to be defined at toplevel,1255;; unhygienically. The test below should probably be enabled and this1256;; behavior fixed. R5RS seems to allow the current behavior though (?),1257;; and some Schemes (at least Gauche) behave the same way. I think it's1258;; broken, since it's unhygienic.1259#;(module foo ()1260 (import scheme)1261 (define req 1)1262 (define-syntax bar1263 (syntax-rules ()1264 ((_) (begin (define req 2) (display req) (newline)))))1265 (bar)1266 (assert (eq? req 1)))126712681269;; Includes should be spliced into the surrounding body context:12701271(begin-for-syntax1272 (with-output-to-file "x.out" (cut pp '(define x 2))))12731274(let ()1275 (define x 1)1276 (include "x.out")1277 (t 2 x))12781279(let ()1280 (define x 1)1281 (let ()1282 (include "x.out"))1283 (t 1 x))12841285;; letrec vs. letrec*12861287;;XXX this fails - the optimizer substitutes "foo" for it's known constant value1288#;(t (void) (letrec ((foo 1)1289 (bar foo))1290 bar))12911292;; Obscure letrec issue #10681293(t 1 (letrec ((foo (lambda () 1))1294 (bar (let ((tmp (lambda (x) (if x (foo) (bar #t)))))1295 tmp)))1296 (bar #f)))12971298;; Deeper issue uncovered by fixing the above issue1299(t 1 (letrec ((bar (lambda (x) (if x 1 (bar bar)))))1300 (bar #f)))13011302;; Just to verify (this has always worked)1303(t 1 (letrec* ((foo (lambda () 1))1304 (bar (let ((tmp (lambda (x) (if x (foo) (bar #t)))))1305 tmp)))1306 (bar #f)))13071308(t 1 (letrec* ((foo 1)1309 (bar foo))1310 bar))131113121313;; This would crash in nasty ways (see #1493, reported by megane)1314(module self-redefinition (foo)1315 (import scheme (chicken base))13161317 (define-syntax foo1318 (ir-macro-transformer1319 (lambda (e i c)1320 (apply1321 (lambda (name)1322 `(begin1323 (define-syntax ,(strip-syntax name)1324 (syntax-rules () ((_ . _) 'new)))1325 'old))1326 (cdr e))))))13271328(import (rename self-redefinition (foo imported-foo)))1329(import (rename self-redefinition (foo reimported-foo)))13301331(t 'old (imported-foo imported-foo))1332(t 'new (imported-foo imported-foo))13331334;; Like any normal redefinition, the underlying exported identifier1335;; changes, and any other imports are simply aliases.1336;;(t 'old (reimported-foo reimported-foo))1337(t 'new (reimported-foo reimported-foo))13381339;; #11661340(module val-vs-syn1 *1341 (import scheme)1342 (define-syntax bar (syntax-rules () ((_) 'bar)))1343 (define (bar) 99)1344)13451346(module test-val-vs-syn1 ()1347 (import scheme (chicken base) val-vs-syn1)1348 (assert (eq? 99 (bar))))13491350(module val-vs-syn2 *1351 (import scheme)1352 (define (bar) 99)1353 (define-syntax bar (syntax-rules () ((_) 'bar)))1354)13551356(module test-val-vs-syn2 ()1357 (import scheme (chicken base) val-vs-syn2)1358 (assert (eq? 'bar (bar))))13591360(define begin -)1361(assert (eq? -1 (begin 0 1)))13621363;; #1736 - dotted pairs after ellipsis13641365(define-syntax match-ellipsis-and-dotted-tail11366 (syntax-rules ()1367 ((_ a ... . b)1368 '(a ... b))))13691370(t '(x y z) (match-ellipsis-and-dotted-tail1 x y . z))13711372(define-syntax match-ellipsis-and-dotted-tail21373 (syntax-rules ()1374 ((_ (a) ... . (b))1375 '(a ... b))))13761377(t '(x y z) (match-ellipsis-and-dotted-tail2 (x) (y) z))13781379;; from SRFI-46 document:1380(define-syntax fake-begin1381 (syntax-rules ()1382 ((fake-begin ?body ... ?tail)1383 (let* ((ignored ?body) ...) ?tail))))13841385(t 3 (fake-begin 1 2 3))13861387;; #179313881389(let ([x 'outer])1390 (define-syntax m1391 (syntax-rules ()1392 ((m a)1393 (let ([a 'inner]) x))))1394 (t 'outer (m x)))13951396; fails with error when compiled ("toplevel def. in non-toplevel context")1397#;(let ([x 'outer])1398 (define-syntax m1399 (syntax-rules ()1400 ((m a)1401 (begin1402 (define a 'inner)1403 x))))1404 (m x)1405 (t 'inner x))