~ chicken-r7rs (master) 691b067f9f719fbab10c6ea8cb5d9e3b35a76691


commit 691b067f9f719fbab10c6ea8cb5d9e3b35a76691
Author:     Peter Bex <peter@more-magic.net>
AuthorDate: Sat Jun 15 16:11:40 2013 +0000
Commit:     Evan Hanson <evhan@foldling.org>
CommitDate: Sat Jun 15 16:11:40 2013 +0000

    Implement syntax-rules in r7rs egg

diff --git a/r7rs.scm b/r7rs.scm
index 980f23b..b423eec 100644
--- a/r7rs.scm
+++ b/r7rs.scm
@@ -1,10 +1,10 @@
 (module r7rs (define-library)
 
-  (import scheme)			;XXX except ...
+  (import (except scheme syntax-rules))		;XXX except ...
   (import chicken)			;XXX except ...
   (import numbers)
   (import scheme.base)
-  (include "scheme.base-interface.scm") 
+  (include "scheme.base-interface.scm")
 
   (begin-for-syntax
    (require-library r7rs-compile-time numbers))
diff --git a/r7rs.setup b/r7rs.setup
index 1f2585f..2c65b9d 100644
--- a/r7rs.setup
+++ b/r7rs.setup
@@ -1,13 +1,14 @@
+;; -*- Scheme -*-
 (use make)
 
-
 (define scheme-modules
   '("base" "process-context"))		;XXX
 
 (make (("r7rs-compile-time.so" ("r7rs-compile-time.scm" "r7rs-compile-time-module.scm")
 	(compile -s -O3 -d1 r7rs-compile-time-module.scm -J -o r7rs-compile-time.so)
 	(compile -s -O3 -d0 r7rs-compile-time.import.scm))
-       ("scheme.base.so" ("scheme.base.scm" "scheme.base-interface.scm")
+       ("scheme.base.so" ("scheme.base.scm" "scheme.base-interface.scm"
+                          "synrules.scm")
 	(compile -s -O3 -d1 scheme.base.scm -J)
 	(compile -s -O3 -d0 scheme.base.import.scm)))
   '("r7rs-compile-time.so" "scheme.base.so"))
diff --git a/scheme.base-interface.scm b/scheme.base-interface.scm
index d6805da..42e450d 100644
--- a/scheme.base-interface.scm
+++ b/scheme.base-interface.scm
@@ -38,7 +38,9 @@
   current-input-port current-output-port current-error-port
   define
   define-record-type
+  |#
   define-syntax
+  #|
   define-values
   denominator numerator
   do
@@ -78,7 +80,7 @@
   |#
   import
   #|
-  ;; import-for-syntax   XXX should we?
+  ;; import-for-syntax   XXX should we?  Probably not, it's not in r7rs...
   include include-ci
   |#
   input-port-open? output-port-open?
@@ -90,8 +92,10 @@
   let let*
   letrec letrec*
   let-values let*-values
+  |#
   let-syntax
   letrec-syntax
+  #|
   library                    ; for "cond-expand"
   list
   list-copy
@@ -161,7 +165,9 @@
   symbol=?
   symbol?
   syntax-error
-  ;syntax-rules   XXX???
+  |#
+  syntax-rules
+  #|
   textual-port?
   truncate
   truncate-quotient truncate-remainder
diff --git a/scheme.base.scm b/scheme.base.scm
index b2c2b90..0eae03c 100644
--- a/scheme.base.scm
+++ b/scheme.base.scm
@@ -1,6 +1,6 @@
 (module scheme.base ()
 
-(import (except scheme cond-expand))
+(import (except scheme syntax-rules cond-expand))
 (import (except chicken with-exception-handler raise))
 
 (include "scheme.base-interface.scm")
@@ -95,6 +95,10 @@
                   (lambda ()
                     (apply values args))))))))))))))
 
+;;;
+;;; 5.4. Syntax definitions
+;;;
+(include "synrules.scm")
 
 ;;;
 ;;; 6.11. Exceptions
diff --git a/synrules.scm b/synrules.scm
new file mode 100644
index 0000000..f8cf331
--- /dev/null
+++ b/synrules.scm
@@ -0,0 +1,324 @@
+;;
+;; This is a slightly modified copy of core syntax-rules, enhanced
+;; with underscore "wildcard" patterns and the ellipsis (... ...)
+;; "quoting" mechanism from R7RS.
+;;
+;; Copyright (c) 1993-2001 by Richard Kelsey and Jonathan Rees.
+;; All rights reserved.
+
+;; Redistribution and use in source and binary forms, with or without
+;; modification, are permitted provided that the following conditions
+;; are met:
+;; 1. Redistributions of source code must retain the above copyright
+;;    notice, this list of conditions and the following disclaimer.
+;; 2. Redistributions in binary form must reproduce the above copyright
+;;    notice, this list of conditions and the following disclaimer in the
+;;    documentation and/or other materials provided with the distribution.
+;; 3. The name of the authors may not be used to endorse or promote products
+;;    derived from this software without specific prior written permission.
+
+;; THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
+;; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+;; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+;; IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+;; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+;; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+;; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+;; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+; The syntax-rules macro (new in R5RS)
+
+;;; [Hacked slightly by Taylor R. Campbell to make it work in his
+;;; macro expander `riaxpander'.]
+
+;; [Hacked even more by Felix L. Winkelmann to make it work in his
+;; Hi-Lo expander]
+
+; Example:
+;
+; (define-syntax or
+;   (syntax-rules ()
+;     ((or)          #f)
+;     ((or e)        e)
+;     ((or e1 e ...) (let ((temp e1))
+;		       (if temp temp (or e ...))))))
+
+
+(define-syntax syntax-rules
+  (er-macro-transformer
+   (lambda (exp r c)
+     (##sys#check-syntax 'syntax-rules exp '#(_ 2))
+     (let ((subkeywords (cadr exp))
+           (rules (cddr exp))
+           (ellipsis '...))
+       (when (symbol? subkeywords)
+         (##sys#check-syntax 'syntax-rules exp '(_ _ list . #(_ 0)))
+         (set! ellipsis subkeywords)
+         (set! subkeywords (car rules))
+         (set! rules (cdr rules)))
+       (process-syntax-rules ellipsis rules subkeywords r c)))))
+
+(begin-for-syntax
+ (define (process-syntax-rules ellipsis rules subkeywords r c)
+
+   (define %append '##sys#append)
+   (define %apply '##sys#apply)
+   (define %and (r 'and))
+   (define %car '##sys#car)
+   (define %cdr '##sys#cdr)
+   (define %length '##sys#length)
+   (define %vector? '##sys#vector?)
+   (define %vector->list '##sys#vector->list)
+   (define %list->vector '##sys#list->vector)
+   (define %>= '##sys#>=)
+   (define %= '##sys#=)
+   (define %+ '##sys#+)
+   (define %compare (r 'compare))
+   (define %cond (r 'cond))
+   (define %cons '##sys#cons)
+   (define %else (r 'else))
+   (define %eq? '##sys#eq?)
+   (define %equal? '##sys#equal?)
+   (define %input (r 'input))
+   (define %l (r 'l))
+   (define %len (r 'len))
+   (define %lambda (r 'lambda))
+   (define %let (r 'let))
+   (define %let* (r 'let*))
+   (define %list? '##sys#list?)
+   (define %loop (r 'loop))
+   (define %map1 '##sys#map)
+   (define %map '##sys#map-n)
+   (define %pair? '##sys#pair?)
+   (define %quote (r 'quote))
+   (define %rename (r 'rename))
+   (define %tail (r 'tail))
+   (define %temp (r 'temp))
+   (define %syntax-error '##sys#syntax-error-hook)
+   (define %ellipsis (r ellipsis))
+
+   (define (ellipsis? x)
+     (c x %ellipsis))
+
+   ;; R7RS support: underscore matches anything
+   (define (underscore? x)
+     (c x (r '_)))
+
+   (define (make-transformer rules)
+     `(##sys#er-transformer
+       (,%lambda (,%input ,%rename ,%compare)
+                 (,%let ((,%tail (,%cdr ,%input)))
+                        (,%cond ,@(map process-rule rules)
+                                (,%else
+                                 (,%syntax-error "no rule matches form" ,%input)))))))
+
+   (define (process-rule rule)
+     (if (and (pair? rule)
+              (pair? (cdr rule))
+              (null? (cddr rule)))
+         (let ((pattern (cdar rule))
+               (template (cadr rule)))
+           `((,%and ,@(process-match %tail pattern #f ellipsis?))
+             (,%let* ,(process-pattern pattern
+                                       %tail
+                                       (lambda (x) x) #f ellipsis?)
+                     ,(process-template template
+                                        0
+                                        ellipsis?
+                                        (meta-variables pattern 0 ellipsis? '() #f)))))
+         (%syntax-error "ill-formed syntax rule" rule)))
+
+   ;; Generate code to test whether input expression matches pattern
+
+   (define (process-match input pattern seen-segment? el?)
+     (cond ((symbol? pattern)
+            (if (memq pattern subkeywords)
+                `((,%compare ,input (,%rename (##core#syntax ,pattern))))
+                `()))
+           ((segment-pattern? pattern seen-segment? el?)
+            (process-segment-match input pattern el?))
+           ((pair? pattern)
+            `((,%let ((,%temp ,input))
+                     (,%and (,%pair? ,%temp)
+                            ,@(process-match `(,%car ,%temp) (car pattern) #f el?)
+                            ,@(process-match `(,%cdr ,%temp) (cdr pattern) #f el?)))))
+           ((vector? pattern)
+            `((,%let ((,%temp ,input))
+                     (,%and (,%vector? ,%temp)
+                            ,@(process-match `(,%vector->list ,%temp)
+                                             (vector->list pattern) #f el?)))))
+           ((or (null? pattern) (boolean? pattern) (char? pattern))
+            `((,%eq? ,input ',pattern)))
+           (else
+            `((,%equal? ,input ',pattern)))))
+
+   (define (process-segment-match input pattern el?)
+     (let ((conjuncts (process-match `(,%car ,%l) (car pattern) #f el?)))
+       `((,%and (,%list? ,input) ; Can't ask for its length if not a proper list
+                (,%let ((,%len (,%length ,input)))
+                       (,%and (,%>= ,%len ,(length (cddr pattern)))
+                              (,%let ,%loop ((,%l ,input)
+                                             (,%len ,%len))
+                                     (,%cond
+                                      ((,%= ,%len ,(length (cddr pattern)))
+                                       ,@(process-match %l (cddr pattern) #t el?))
+                                      (,%else
+                                       (,%and ,@conjuncts
+                                              (,%loop (,%cdr ,%l) (,%+ ,%len -1))))))))))))
+
+   ;; Generate code to take apart the input expression
+   ;; This is pretty bad, but it seems to work (can't say why).
+
+   (define (process-pattern pattern path mapit seen-segment? el?)
+     (cond ((symbol? pattern)
+            (if (or (memq pattern subkeywords) (underscore? pattern))
+                '()
+                (list (list pattern (mapit path)))))
+           ((segment-pattern? pattern seen-segment? el?)
+            (let* ((tail-length (length (cddr pattern)))
+                   (%match (if (zero? tail-length) ; Simple segment?
+                               path ; No list traversing overhead at runtime!
+                               `(##sys#drop-right ,path ,tail-length))))
+              (append
+               (process-pattern (car pattern)
+                                %temp
+                                (lambda (x) ;temp is free in x
+                                  (mapit
+                                   (if (eq? %temp x)
+                                       %match ; Optimization: no map+lambda
+                                       `(,%map1 (,%lambda (,%temp) ,x) ,%match))))
+                                #f el?)
+               (process-pattern (cddr pattern)
+                                `(##sys#take-right ,path ,tail-length)
+                                mapit #t el?))))
+           ((pair? pattern)
+            (append (process-pattern (car pattern) `(,%car ,path) mapit #f el?)
+                    (process-pattern (cdr pattern) `(,%cdr ,path) mapit #f el?)))
+           ((vector? pattern)
+            (process-pattern (vector->list pattern)
+                             `(,%vector->list ,path) mapit #f el?))
+           (else '())))
+
+   ;; Generate code to compose the output expression according to template
+
+   (define (process-template template dim el? env)
+     (cond ((symbol? template)
+            (let ((probe (assq template env)))
+              (if probe
+                  (if (<= (cdr probe) dim)
+                      template
+                      (%syntax-error "template dimension error (too few ellipses?)"
+                                     template))
+                  `(,%rename (##core#syntax ,template)))))
+           ((ellipsis-escaped-pattern? template el?)
+            (if (or (not (pair? (cdr template))) (pair? (cddr template)))
+                (%syntax-error "Invalid escaped ellipsis template" template)
+                (process-template (cadr template) dim (lambda _ #f) env)))
+           ((segment-template? template el?)
+            (let* ((depth (segment-depth template el?))
+                   (seg-dim (+ dim depth))
+                   (vars
+                    (free-meta-variables (car template) seg-dim el? env '())))
+              (if (null? vars)
+                  (%syntax-error "too many ellipses" template)
+                  (let* ((x (process-template (car template) seg-dim el? env))
+                         (gen (if (and (pair? vars)
+                                       (null? (cdr vars))
+                                       (symbol? x)
+                                       (eq? x (car vars)))
+                                  x	;+++
+                                  `(,%map (,%lambda ,vars ,x)
+                                          ,@vars)))
+                         (gen (do ((d depth (- d 1))
+                                   (gen gen `(,%apply ,%append ,gen)))
+                                  ((= d 1)
+                                   gen)))
+                         (tail (segment-tail template el?)))
+                    (if (null? tail)
+                        gen		;+++
+                        `(,%append ,gen ,(process-template tail dim el? env)))))))
+           ((pair? template)
+            `(,%cons ,(process-template (car template) dim el? env)
+                     ,(process-template (cdr template) dim el? env)))
+           ((vector? template)
+            `(,%list->vector
+              ,(process-template (vector->list template) dim el? env)))
+           (else
+            `(,%quote ,template))))
+
+   ;; Return an association list of (var . dim)
+
+   (define (meta-variables pattern dim el? vars seen-segment?)
+     (cond ((symbol? pattern)
+            (if (or (memq pattern subkeywords) (underscore? pattern))
+                vars
+                (cons (cons pattern dim) vars)))
+           ((segment-pattern? pattern seen-segment? el?)
+            (meta-variables (car pattern) (+ dim 1) el?
+                            (meta-variables (cddr pattern) dim el? vars #t) #f))
+           ((pair? pattern)
+            (meta-variables (car pattern) dim el?
+                            (meta-variables (cdr pattern) dim el? vars #f) #f))
+           ((vector? pattern)
+            (meta-variables (vector->list pattern) dim el? vars #f))
+           (else vars)))
+
+   ;; Return a list of meta-variables of given higher dim
+
+   (define (free-meta-variables template dim el? env free)
+     (cond ((symbol? template)
+            (if (and (not (memq template free))
+                     (let ((probe (assq template env)))
+                       (and probe (>= (cdr probe) dim))))
+                (cons template free)
+                free))
+           ((segment-template? template el?)
+            (free-meta-variables (car template)
+                                 dim el? env
+                                 (free-meta-variables (cddr template)
+                                                      dim el? env free)))
+           ((pair? template)
+            (free-meta-variables (car template)
+                                 dim el? env
+                                 (free-meta-variables (cdr template)
+                                                      dim el? env free)))
+           ((vector? template)
+            (free-meta-variables (vector->list template) dim el? env free))
+           (else free)))
+
+   (define (ellipsis-escaped-pattern? pattern el?)
+     (and (pair? pattern) (el? (car pattern))))
+  
+   (define (segment-pattern? p seen-segment? el?)
+     (and (segment-template? p el?)
+          (cond
+           (seen-segment?
+            (%syntax-error "Only one segment per level is allowed" p))
+           ((not (list? p))             ; Improper list
+            (%syntax-error "Cannot combine dotted tail and ellipsis" p))
+           (else #t))))
+
+   (define (segment-template? pattern el?)
+     (and (pair? pattern)
+          (pair? (cdr pattern))
+          (el? (cadr pattern))))
+
+   ;; Count the number of `...'s in PATTERN.
+
+   (define (segment-depth pattern el?)
+     (if (segment-template? pattern el?)
+         (+ 1 (segment-depth (cdr pattern) el?))
+         0))
+
+   ;; Get whatever is after the `...'s in PATTERN.
+
+   (define (segment-tail pattern el?)
+     (let loop ((pattern (cdr pattern)))
+       (if (and (pair? pattern)
+                (el? (car pattern)))
+           (loop (cdr pattern))
+           pattern)))
+
+   (make-transformer rules)))
diff --git a/tests/run.scm b/tests/run.scm
index 9201b30..f5e48b7 100644
--- a/tests/run.scm
+++ b/tests/run.scm
@@ -1,5 +1,10 @@
 (use r7rs test)
 
+;; XXX: This seems to be necessary in order to get the syntax-rules
+;; from r7rs rather than the built-in CHICKEN one.  I'm not sure if
+;; that's correct or not...
+(import-for-syntax r7rs)
+
 (define (read-from-string s)
   (with-input-from-string s read))
 
@@ -116,6 +121,276 @@
       (test-assert "It's ok to close input ports that are already closed"
                    (close-port the-string-port)))))
 
+;; This is for later. We can't define it inside a group because that
+;; would make it locally scoped (as a letrec rewrite), which breaks
+;; the syntax-rules underscore tests.  Very subtle (and annoying), this!
+(define (_) 'underscore-procedure)
+(define ___ 'triple-underscore-literal)
+
+(test-group "syntax-rules"
+  (test "let-syntax w/ basic syntax-rules"
+        100
+        (let-syntax ((foo (syntax-rules ()
+                            ((_ x form)
+                             (let ((tmp x))
+                               (if (number? tmp)
+                                   form
+                                   (error "not a number" tmp)))))))
+          (foo 2 100)))
+  (let-syntax ((foo (syntax-rules ()
+                      ((_ #(a ...)) (list a ...)))))
+    (test "Basic matching of vectors"
+          '(1 2 3) (foo #(1 2 3))))
+  ;; ellipsis pattern element wasn't matched - reported by Jim Ursetto (fixed rev. 13582)
+  (let-syntax ((foo (syntax-rules ()
+                      ((_ (a b) ...)
+                       (list 'first '(a b) ...))
+                      ((_ a ...)
+                       (list 'second '(a) ...)))))
+    (test "Basic ellipsis match"
+          '(first (1 2) (3 4) (5 6)) (foo (1 2) (3 4) (5 6)))
+    (test "Ellipsis match of length 1 does not match length 2"
+          '(second (1)) (foo 1))
+    (test "Ellipsis match of lists with mismatched lengths (used to fail)"
+          '(second ((1 2)) ((3)) ((5 6))) (foo (1 2) (3) (5 6))))
+
+  (test "letrec-syntax"
+        34
+        (letrec-syntax ((foo (syntax-rules () ((_ x) (bar x))))
+                        (bar (syntax-rules () ((_ x) (+ x 1)))))
+          (foo 33)))
+  (test "Basic hygienic rename of syntactic keywords"
+        'now
+        (let-syntax ((when (syntax-rules ()
+                             ((when test stmt1 stmt2 ...)
+                              (if test
+                                  (begin stmt1
+                                         stmt2 ...))))))
+          (let ((if #t))
+            (when if (set! if 'now))
+            if)))
+  (test "Basic hygienic rename of shadowed outer let"
+        'outer
+        (let ((x 'outer))
+          (let-syntax ((m (syntax-rules () ((m) x))))
+            (let ((x 'inner))
+              (m)))))
+  (test "Simple recursive letrec expansion"
+        7
+        (letrec-syntax
+            ((my-or (syntax-rules ()
+                      ((my-or) #f)
+                      ((my-or e) e)
+                      ((my-or e1 e2 ...)
+                       (let ((temp e1))
+                         (if temp
+                             temp
+                             (my-or e2 ...)))))))
+          (let ((x #f)
+                (y 7)
+                (temp 8)
+                (let odd?)
+                (if even?))
+            (my-or x
+                   (let temp)
+                   (if y)
+                   y))))
+  ;; From Al* Petrofsky's "An Advanced Syntax-Rules Primer for the Mildly Insane"
+  (let ((a 1))
+    (letrec-syntax
+        ((foo (syntax-rules ()
+                ((_ b)
+                 (bar a b))))
+         (bar (syntax-rules ()
+                ((_ c d)
+                 (cons c (let ((c 3))
+                           (list d c 'c)))))))
+      (let ((a 2))
+        (test "Al* Petrofsky torture test" '(1 2 3 a) (foo a)))))
+  (let-syntax
+      ((foo (syntax-rules ()
+              ((_)
+               '#(b)))))
+    (test "Quoted symbols inside vectors are stripped of syntactic info"
+          '#(b) (foo)))
+  (let-syntax ((kw (syntax-rules (baz)
+                     ((_ baz) "baz")
+                     ((_ any) "no baz"))))
+    (test "syntax-rules keywords match" "baz" (kw baz))
+    (test "syntax-rules keywords no match" "no baz" (kw xxx))
+    (let ((baz 100))
+      (test "keyword loses meaning if shadowed" "no baz" (kw baz))))
+  (test "keyword also loses meaning for builtins (from R7RS section 4.3.2)"
+        'ok
+        (let ((=> #f))
+          (cond (#t => 'ok))))
+  (test "Nested identifier shadowing works correctly"
+        '(3 4)
+        (let ((foo 3))
+          (let-syntax ((bar (syntax-rules () ((_ x) (list foo x)))))
+            (let ((foo 4))
+              (bar foo)))))
+  (let-syntax ((c (syntax-rules ()
+                    ((_)
+                     (let ((x 10))
+                       (let-syntax ((z (syntax-rules ()
+                                         ((_) (quote x)))))
+                         (z))))))
+               (c2 (syntax-rules ()
+                     ((_)
+                      (let ((x 10))
+                        (let-syntax
+                            ((z (syntax-rules ()
+                                  ((_) (let-syntax
+                                           ((w (syntax-rules ()
+                                                 ((_) (quote x)))))
+                                         (w))))))
+                          (z)))))))
+    ;; Reported by Matthew Flatt
+    (test "strip-syntax cuts across three levels of syntax"
+          "x" (symbol->string (c)))
+    (test "strip-syntax cuts across four levels of syntax"
+          "x" (symbol->string (c2))))
+  (let-syntax ((foo (syntax-rules 
+                        ___ () 
+                        ((_ vals ___) (list '... vals ___)))))
+    (test "Alternative ellipsis (from SRFI-46)"
+          '(... 1 2 3) (foo 1 2 3)))
+  (let-syntax ((let-alias (syntax-rules
+                              ___ ()
+                              ((_ new old code ___)
+                               (let-syntax
+                                   ((new
+                                     (syntax-rules ()
+                                       ((_ args ...) (old args ...)))))
+                                 code ___)))))
+    (let-alias inc (lambda (x) (+ 1 x))
+               (test "Ellipsis rules are reset in new macro expansion phase"
+                     3 (inc 2))))
+  (let-syntax ((foo (syntax-rules ()
+                      ((_ (a ... b) ... (c d))
+                       (list (list (list a ...) ... b ...) c d))
+                      ((_ #(a ... b) ... #(c d) #(e f))
+                       (list (list (vector a ...) ... b ...) c d e f))
+                      ((_ #(a ... b) ... #(c d))
+                       (list (list (vector a ...) ... b ...) c d)))))
+    (test-group "rest patterns after ellipsis (SRFI-46 smoke test)"
+      (test '(() 1 2) (foo (1 2)))
+      (test '(((1) 2) 3 4) (foo (1 2) (3 4)))
+      (test '(((1 2) (4) 3 5) 6 7)
+            (foo (1 2 3) (4 5) (6 7)))
+      (test '(() 1 2)
+            (foo #(1 2)))
+      (test '((#() 1) 2 3)
+            (foo #(1) #(2 3)))
+      (test '((#(1 2) 3) 4 5)
+            (foo #(1 2 3) #(4 5)))
+      (test '((#(1 2) 3) 4 5 6 7)
+            (foo #(1 2 3) #(4 5) #(6 7)))
+      (test '(() 1 2 3 4)
+            (foo #(1 2) #(3 4)))
+      (test '((#(1) 2) 3 4 5 6)
+            (foo #(1 2) #(3 4) #(5 6)))
+      (test '((#(1 2) #(4) 3 5) 6 7 8 9)
+            (foo #(1 2 3) #(4 5) #(6 7) #(8 9)))))
+  (let-syntax ((foo (syntax-rules ()
+                      ((_ #((a) ...)) (list a ...)))))
+    (test "Bug discovered during implementation of rest patterns"
+          '(1)
+          (foo #((1)))))
+  ;; R7RS: (<ellipsis> <template>) is like <template>, ignoring
+  ;; occurrances of <ellipsis> inside the template.
+  (let-syntax ((be-like-begin
+                (syntax-rules ()
+                  ((be-like-begin name)
+                   (define-syntax name
+                     (syntax-rules ()
+                       ((name expr (... ...))
+                        (begin expr (... ...)))))))))
+    (be-like-begin sequence)
+    (test "be-like-begin from R7RS 4.3.2 (nested ellipsis are not expanded)"
+          4 (sequence 1 2 3 4)))
+  (let-syntax ((ignore-underscores
+                (syntax-rules ()
+                  ((_ _ _ _) (_)))))
+    (test "underscores are ignored in patterns"
+          'underscore-procedure (ignore-underscores _ b c)))
+
+  (test-group "undefined behaviours: mixing keywords, ellipsis and underscores"
+    (test-group "underscore as keyword literal"
+      (define-syntax match-literal-underscores ; for eval
+        (syntax-rules (_)
+          ((x a _ c) (_))
+          ((x _ b c) 1)))
+      (test-error "Missing literal underscore keyword causes syntax-error"
+                  (eval '(match-literal-underscores d e f)))
+      (test "Literal underscore matches"
+            1 (match-literal-underscores _ h i))
+      (test "Literal underscore matches even if it refers to toplevel binding"
+            'underscore-procedure (match-literal-underscores g _ i)))
+    
+    (test-group "underscore as ellipsis"
+     ;; It's undefined what this should do.  Logically, it should be
+     ;; possible to bind _ as an ellipsis identifier.
+     (define-syntax match-ellipsis-underscores ; for eval
+       (syntax-rules _ () ((x a _ c) (list a _ c))))
+     (test-error "No rule matching if prefix is omitted"
+                 (eval '(match-ellipsis-underscores)))
+     (test "Only prefix is supplied"
+           '(1) (match-ellipsis-underscores 1))
+     (test "Ellipsis does its work if multiple arguments given"
+           '(1 2 3 4 5 6) (match-ellipsis-underscores 1 2 3 4 5 6)))
+
+    (test-group "underscore as ellipsis mixed with underscore literal"
+      ;; Even more undefined behaviour: mixing literals and ellipsis identifiers
+      ;; Currently, ellipsis identifiers have precedence over the other two.
+      (define-syntax match-ellipsis-and-literals-underscores ; for eval
+        (syntax-rules _ (_) ((x a _ c) (list a _ c))))
+      (test-error "No rule matching if prefix is omitted"
+                  (eval '(match-ellipsis-and-literals-underscores)))
+      (test '(1) (match-ellipsis-and-literals-underscores 1))
+      (test '(1 2 3) (match-ellipsis-and-literals-underscores 1 2 3))
+      (test '(1 2 3 4 5 6) (match-ellipsis-and-literals-underscores 1 2 3 4 5 6)))
+
+    (test-group "\"custom\" ellipsis and literal of the same identifier"
+      ;; This is similar to the above, but maybe a little simpler because
+      ;; it does not use reserved names:
+      (define-syntax match-ellipsis-literals
+        (syntax-rules ___ (___)
+                      ((_ x ___) (list x ___))))
+      (test "Ellipsis as literals"
+            '(1) (match-ellipsis-literals 1))
+      (test "Ellipsis as literals multiple args"
+            '(1 2) (match-ellipsis-literals 1 2))
+      (test "Toplevel binding of the same name as ellipsis"
+            '(1 triple-underscore-literal) (match-ellipsis-literals 1 ___))))
+
+  (letrec-syntax ((usetmp
+                   (syntax-rules ()
+                     ((_ var) 
+                      (list var))))
+                  (withtmp
+                   (syntax-rules ()
+                     ((_ val exp)
+                      (let ((tmp val))
+                        (exp tmp))))))
+    (test "Passing a macro as argument to macro"
+          '(99)
+          (withtmp 99 usetmp)))
+
+  ;; renaming of keyword argument (#277)
+  (let-syntax ((let-hello-proc
+                (syntax-rules ()
+                  ((_ procname code ...)
+                   (let ((procname (lambda (#!key (who "world"))
+                                     (string-append "hello, " who))))
+                     code ...)))))
+    (let-hello-proc bar
+         ;; This is not R7RS, but R7RS should not interfere with other
+         ;; CHICKEN features!
+         (test "DSSSL keyword arguments aren't renamed (not R7RS)"
+               "hello, XXX" (bar who: "XXX")))))
+
 (test-end "r7rs tests")
 
 (test-exit)
Trap