Ticket #379: srfi-46.patch

File srfi-46.patch, 12.0 KB (added by sjamaan, 14 years ago)

Full SRFI-46 support

  • synrules.scm

    diff --git a/synrules.scm b/synrules.scm
    index 0e5f66f..d2da55a 100644
    a b  
    6565  (define %and (r 'and))
    6666  (define %car '##sys#car)
    6767  (define %cdr '##sys#cdr)
     68  (define %length (r 'length))
    6869  (define %vector? '##sys#vector?)
    6970  (define %vector-length '##sys#vector-length)
    7071  (define %vector-ref '##sys#vector-ref)
    7172  (define %vector->list '##sys#vector->list)
    7273  (define %list->vector '##sys#list->vector)
    7374  (define %>= '##sys#>=)
     75  (define %> (r '>))
    7476  (define %= '##sys#=)
    7577  (define %+ '##sys#+)
     78  (define %- '-)
    7679  (define %i (r 'i))
    7780  (define %compare (r 'compare))
    7881  (define %cond (r 'cond))
     
    8285  (define %equal? '##sys#equal?)
    8386  (define %input (r 'input))
    8487  (define %l (r 'l))
     88  (define %len (r 'len))
    8589  (define %lambda (r 'lambda))
    8690  (define %let (r 'let))
    8791  (define %let* (r 'let*))
     
    99103  (define %temp (r 'temp))
    100104  (define %syntax-error '##sys#syntax-error-hook)
    101105  (define %ellipsis (r ellipsis))
     106  (define %drop-right (r 'drop-right))
     107  (define %take-right (r 'take-right))
    102108
    103109  (define (ellipsis? x)
    104110    (c x %ellipsis))
    105111
    106112  (define (make-transformer rules)
    107113    `(,%lambda (,%input ,%rename ,%compare)
    108                (,%let ((,%tail (,%cdr ,%input)))
     114               (,%let ((,%tail (,%cdr ,%input))
     115                       (,%drop-right
     116                         (,%lambda (,%input ,%temp)
     117                            (,%let ,%loop ((,%len (,%length ,%input))
     118                                           (,%input ,%input))
     119                               (,%cond
     120                                ((,%> ,%len ,%temp)
     121                                 (,%cons (,%car ,%input)
     122                                         (,%loop (,%- ,%len 1) (,%cdr ,%input))))
     123                                (,%else (,%quote ()))))))
     124                       (,%take-right
     125                         (,%lambda (,%input ,%temp)
     126                            (,%let ,%loop ((,%len (,%length ,%input))
     127                                           (,%input ,%input))
     128                               (,%cond
     129                                ((,%> ,%len ,%temp)
     130                                 (,%loop (,%- ,%len 1) (,%cdr ,%input)))
     131                                (,%else ,%input))))))
    109132                      (,%cond ,@(map process-rule rules)
    110133                              (,%else
    111134                               (##sys#syntax-rules-mismatch ,%input))))))
     
    116139             (null? (cddr rule)))
    117140        (let ((pattern (cdar rule))
    118141              (template (cadr rule)))
    119           `((,%and ,@(process-match %tail pattern))
     142          `((,%and ,@(process-match %tail pattern #f))
    120143            (,%let* ,(process-pattern pattern
    121144                                      %tail
    122                                       (lambda (x) x))
     145                                      (lambda (x) x) #f)
    123146                    ,(process-template template
    124147                                       0
    125                                        (meta-variables pattern 0 '())))))
     148                                       (meta-variables pattern 0 '() #f)))))
    126149        (##sys#syntax-error-hook "ill-formed syntax rule" rule)))
    127150
    128151  ;; Generate code to test whether input expression matches pattern
    129152
    130   (define (process-match input pattern)
     153  (define (process-match input pattern seen-segment?)
    131154    (cond ((symbol? pattern)
    132155           (if (memq pattern subkeywords)
    133156               `((,%compare ,input (,%rename (##core#syntax ,pattern))))
    134157               `()))
    135           ((segment-pattern? pattern)
    136            (process-segment-match input (car pattern)))
     158          ((segment-pattern? pattern seen-segment?)
     159           (process-segment-match input pattern))
    137160          ((pair? pattern)
    138161           `((,%let ((,%temp ,input))
    139                     (,%and (,%pair? ,%temp)
    140                            ,@(process-match `(,%car ,%temp) (car pattern))
    141                            ,@(process-match `(,%cdr ,%temp) (cdr pattern))))))
     162               (,%and (,%pair? ,%temp)
     163                      ,@(process-match `(,%car ,%temp) (car pattern) #f)
     164                      ,@(process-match `(,%cdr ,%temp) (cdr pattern) #f)))))
    142165          ((vector? pattern)
    143            (process-vector-match input pattern))
     166           `((,%let ((,%temp ,input))
     167              (,%and (,%vector? ,%temp)
     168                     ,@(process-match `(,%vector->list ,%temp)
     169                                      (vector->list pattern) #f)))))
    144170          ((or (null? pattern) (boolean? pattern) (char? pattern))
    145171           `((,%eq? ,input ',pattern)))
    146172          (else
    147173           `((,%equal? ,input ',pattern)))))
    148174
    149175  (define (process-segment-match input pattern)
    150     (let ((conjuncts (process-match `(,%car ,%l) pattern)))
    151       (if (null? conjuncts)
    152           `((,%list? ,input))           ;+++
    153           `((,%let ,%loop ((,%l ,input))
    154                    (,%or (,%null? ,%l)
    155                          (,%and (,%pair? ,%l)
    156                                 ,@conjuncts
    157                                 (,%loop (,%cdr ,%l)))))))))
    158 
    159    (define (process-vector-match input pattern)
    160      (let* ((len (vector-length pattern))
    161             (segment? (and (>= len 2)
    162                            (ellipsis? (vector-ref pattern (- len 1))))))
    163        `((,%let ((,%temp ,input))
    164           (,%and (,%vector? ,%temp)
    165                  ,(if segment?
    166                       `(,%>= (,%vector-length ,%temp) ,(- len 2))
    167                       `(,%= (,%vector-length ,%temp) ,len))
    168                  ,@(let lp ((i 0))
    169                      (cond
    170                       ((>= i len)
    171                        '())
    172                       ((and (= i (- len 2)) segment?)
    173                        `((,%let ,%loop ((,%i ,i))
    174                             (,%or (,%>= ,%i ,len)
    175                                   (,%and ,@(process-match
    176                                             `(,%vector-ref ,%temp ,%i)
    177                                             (vector-ref pattern (- len 2)))
    178                                          (,%loop (,%+ ,%i 1)))))))
    179                       (else
    180                        (append (process-match `(,%vector-ref ,%temp ,i)
    181                                               (vector-ref pattern i))
    182                                (lp (+ i 1)))))))))))
    183  
     176    (let ((conjuncts (process-match `(,%car ,%l) (car pattern) #f)))
     177      `((,%and (,%list? ,input) ; Can't ask for its length if not a proper list
     178               (,%let ((,%len (,%length ,input)))
     179                 (,%and (,%>= ,%len ,(length (cddr pattern)))
     180                        (,%let ,%loop ((,%l ,input)
     181                                       (,%len ,%len))
     182                           (,%cond
     183                             ((,%= ,%len ,(length (cddr pattern)))
     184                              ,@(process-match %l (cddr pattern) #t))
     185                             (,%else
     186                              (,%and ,@conjuncts
     187                                     (,%loop (,%cdr ,%l) (,%- ,%len 1))))))))))))
     188
    184189  ;; Generate code to take apart the input expression
    185190  ;; This is pretty bad, but it seems to work (can't say why).
    186191
    187   (define (process-pattern pattern path mapit)
     192  (define (process-pattern pattern path mapit seen-segment?)
    188193    (cond ((symbol? pattern)
    189194           (if (memq pattern subkeywords)
    190195               '()
    191196               (list (list pattern (mapit path)))))
    192           ((segment-pattern? pattern)
    193            (process-pattern (car pattern)
    194                             %temp
    195                             (lambda (x) ;temp is free in x
    196                               (mapit (if (eq? %temp x)
    197                                          path ;+++
    198                                          `(,%map1 (,%lambda (,%temp) ,x)
    199                                                   ,path))))))
     197          ((segment-pattern? pattern seen-segment?)
     198           (let* ((tail-length (length (cddr pattern)))
     199                  (%match (if (zero? tail-length) ; Simple segment?
     200                              path  ; No list traversing overhead at runtime!
     201                              `(,%drop-right ,path ,tail-length))))
     202             (append
     203              (process-pattern (car pattern)
     204                               %temp
     205                               (lambda (x) ;temp is free in x
     206                                 (mapit
     207                                  (if (eq? %temp x)
     208                                      %match ; Optimization: no map+lambda
     209                                      `(,%map1 (,%lambda (,%temp) ,x) ,%match))))
     210                               #f)
     211              (process-pattern (cddr pattern)
     212                               `(,%take-right ,path ,tail-length) mapit #t))))
    200213          ((pair? pattern)
    201            (append (process-pattern (car pattern) `(,%car ,path) mapit)
    202                    (process-pattern (cdr pattern) `(,%cdr ,path) mapit)))
     214           (append (process-pattern (car pattern) `(,%car ,path) mapit #f)
     215                   (process-pattern (cdr pattern) `(,%cdr ,path) mapit #f)))
    203216          ((vector? pattern)
    204            (let* ((len (vector-length pattern))
    205                   (segment? (and (>= len 2)
    206                                  (ellipsis? (vector-ref pattern (- len 1))))))
    207              (if segment?
    208                  (process-pattern (vector->list pattern)
    209                                   `(,%vector->list ,path)
    210                                   mapit)
    211                  (let lp ((i 0))
    212                    (cond
    213                     ((>= i len)
    214                      '())
    215                     (else
    216                      (append (process-pattern (vector-ref pattern i)
    217                                               `(,%vector-ref ,path ,i)
    218                                               mapit)
    219                              (lp (+ i 1)))))))))
     217           (process-pattern (vector->list pattern)
     218                            `(,%vector->list ,path) mapit #f))
    220219          (else '())))
    221220
    222221  ;; Generate code to compose the output expression according to template
     
    266265
    267266  ;; Return an association list of (var . dim)
    268267
    269   (define (meta-variables pattern dim vars)
     268  (define (meta-variables pattern dim vars seen-segment?)
    270269    (cond ((symbol? pattern)
    271270           (if (memq pattern subkeywords)
    272271               vars
    273272               (cons (cons pattern dim) vars)))
    274           ((segment-pattern? pattern)
    275            (meta-variables (car pattern) (+ dim 1) vars))
     273          ((segment-pattern? pattern seen-segment?)
     274           (meta-variables (car pattern) (+ dim 1)
     275                           (meta-variables (cddr pattern) dim vars #t) #f))
    276276          ((pair? pattern)
    277277           (meta-variables (car pattern) dim
    278                            (meta-variables (cdr pattern) dim vars)))
     278                           (meta-variables (cdr pattern) dim vars #f) #f))
    279279          ((vector? pattern)
    280            (meta-variables (vector->list pattern) dim vars))
     280           (meta-variables (vector->list pattern) dim vars #f))
    281281          (else vars)))
    282282
    283283  ;; Return a list of meta-variables of given higher dim
     
    303303           (free-meta-variables (vector->list template) dim env free))
    304304          (else free)))
    305305
    306   (define (segment-pattern? pattern)
    307     (and (segment-template? pattern)
    308          (or (null? (cddr pattern))
    309              (##sys#syntax-error-hook "segment matching not implemented" pattern))))
     306  (define (segment-pattern? p seen-segment?)
     307    (and (segment-template? p)
     308         (cond
     309          (seen-segment?
     310           (##sys#syntax-error-hook "Only one segment per level is allowed" p))
     311          ((not (list? p))              ; Improper list
     312           (##sys#syntax-error-hook "Cannot combine dotted tail and ellipsis" p))
     313          (else #t))))
    310314
    311315  (define (segment-template? pattern)
    312316    (and (pair? pattern)
  • tests/syntax-tests.scm

    diff --git a/tests/syntax-tests.scm b/tests/syntax-tests.scm
    index c210165..9fd644d 100644
    a b  
    144144      (bar foo))))
    145145)
    146146
    147 ;;; alternative ellipsis test
     147;;; alternative ellipsis test (SRFI-46)
    148148
    149149(define-syntax foo
    150150  (syntax-rules
     
    166166
    167167(t 3 (inc 2))
    168168
     169;;; Rest patterns after ellipsis (SRFI-46)
     170
     171(define-syntax foo
     172  (syntax-rules ()
     173    ((_ (a ... b) ... (c d))
     174     (list (list (list a ...) ... b ...) c d))
     175    ((_ #(a ... b) ... #(c d) #(e f))
     176     (list (list (vector a ...) ... b ...) c d e f))
     177    ((_ #(a ... b) ... #(c d))
     178     (list (list (vector a ...) ... b ...) c d))))
     179
     180(t '(() 1 2)
     181   (foo (1 2)))
     182
     183(t '(((1) 2) 3 4)
     184   (foo (1 2) (3 4)))
     185
     186(t '(((1 2) (4) 3 5) 6 7)
     187   (foo (1 2 3) (4 5) (6 7)))
     188
     189(t '(() 1 2)
     190   (foo #(1 2)))
     191
     192(t '((#() 1) 2 3)
     193   (foo #(1) #(2 3)))
     194
     195(t '((#(1 2) 3) 4 5)
     196   (foo #(1 2 3) #(4 5)))
     197
     198(t '((#(1 2) 3) 4 5 6 7)
     199   (foo #(1 2 3) #(4 5) #(6 7)))
     200
     201(t '(() 1 2 3 4)
     202   (foo #(1 2) #(3 4)))
     203
     204(t '((#(1) 2) 3 4 5 6)
     205   (foo #(1 2) #(3 4) #(5 6)))
     206
     207(t '((#(1 2) #(4) 3 5) 6 7 8 9)
     208   (foo #(1 2 3) #(4 5) #(6 7) #(8 9)))
     209
     210;;; Bug discovered during implementation of SRFI-46 rest patterns:
     211
     212(define-syntax foo
     213  (syntax-rules ()
     214    ((_ #((a) ...)) (list a ...))))
     215
     216(t '(1)
     217   (foo #((1))))
     218
    169219;;;
    170220
    171221(define-syntax usetmp