Ticket #379: srfi-46.patch
File srfi-46.patch, 12.0 KB (added by , 14 years ago) |
---|
-
synrules.scm
diff --git a/synrules.scm b/synrules.scm index 0e5f66f..d2da55a 100644
a b 65 65 (define %and (r 'and)) 66 66 (define %car '##sys#car) 67 67 (define %cdr '##sys#cdr) 68 (define %length (r 'length)) 68 69 (define %vector? '##sys#vector?) 69 70 (define %vector-length '##sys#vector-length) 70 71 (define %vector-ref '##sys#vector-ref) 71 72 (define %vector->list '##sys#vector->list) 72 73 (define %list->vector '##sys#list->vector) 73 74 (define %>= '##sys#>=) 75 (define %> (r '>)) 74 76 (define %= '##sys#=) 75 77 (define %+ '##sys#+) 78 (define %- '-) 76 79 (define %i (r 'i)) 77 80 (define %compare (r 'compare)) 78 81 (define %cond (r 'cond)) … … 82 85 (define %equal? '##sys#equal?) 83 86 (define %input (r 'input)) 84 87 (define %l (r 'l)) 88 (define %len (r 'len)) 85 89 (define %lambda (r 'lambda)) 86 90 (define %let (r 'let)) 87 91 (define %let* (r 'let*)) … … 99 103 (define %temp (r 'temp)) 100 104 (define %syntax-error '##sys#syntax-error-hook) 101 105 (define %ellipsis (r ellipsis)) 106 (define %drop-right (r 'drop-right)) 107 (define %take-right (r 'take-right)) 102 108 103 109 (define (ellipsis? x) 104 110 (c x %ellipsis)) 105 111 106 112 (define (make-transformer rules) 107 113 `(,%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)))))) 109 132 (,%cond ,@(map process-rule rules) 110 133 (,%else 111 134 (##sys#syntax-rules-mismatch ,%input)))))) … … 116 139 (null? (cddr rule))) 117 140 (let ((pattern (cdar rule)) 118 141 (template (cadr rule))) 119 `((,%and ,@(process-match %tail pattern ))142 `((,%and ,@(process-match %tail pattern #f)) 120 143 (,%let* ,(process-pattern pattern 121 144 %tail 122 (lambda (x) x) )145 (lambda (x) x) #f) 123 146 ,(process-template template 124 147 0 125 (meta-variables pattern 0 '() )))))148 (meta-variables pattern 0 '() #f))))) 126 149 (##sys#syntax-error-hook "ill-formed syntax rule" rule))) 127 150 128 151 ;; Generate code to test whether input expression matches pattern 129 152 130 (define (process-match input pattern )153 (define (process-match input pattern seen-segment?) 131 154 (cond ((symbol? pattern) 132 155 (if (memq pattern subkeywords) 133 156 `((,%compare ,input (,%rename (##core#syntax ,pattern)))) 134 157 `())) 135 ((segment-pattern? pattern )136 (process-segment-match input (car pattern)))158 ((segment-pattern? pattern seen-segment?) 159 (process-segment-match input pattern)) 137 160 ((pair? pattern) 138 161 `((,%let ((,%temp ,input)) 139 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))))) 142 165 ((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))))) 144 170 ((or (null? pattern) (boolean? pattern) (char? pattern)) 145 171 `((,%eq? ,input ',pattern))) 146 172 (else 147 173 `((,%equal? ,input ',pattern))))) 148 174 149 175 (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 184 189 ;; Generate code to take apart the input expression 185 190 ;; This is pretty bad, but it seems to work (can't say why). 186 191 187 (define (process-pattern pattern path mapit )192 (define (process-pattern pattern path mapit seen-segment?) 188 193 (cond ((symbol? pattern) 189 194 (if (memq pattern subkeywords) 190 195 '() 191 196 (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)))) 200 213 ((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))) 203 216 ((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)) 220 219 (else '()))) 221 220 222 221 ;; Generate code to compose the output expression according to template … … 266 265 267 266 ;; Return an association list of (var . dim) 268 267 269 (define (meta-variables pattern dim vars )268 (define (meta-variables pattern dim vars seen-segment?) 270 269 (cond ((symbol? pattern) 271 270 (if (memq pattern subkeywords) 272 271 vars 273 272 (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)) 276 276 ((pair? pattern) 277 277 (meta-variables (car pattern) dim 278 (meta-variables (cdr pattern) dim vars )))278 (meta-variables (cdr pattern) dim vars #f) #f)) 279 279 ((vector? pattern) 280 (meta-variables (vector->list pattern) dim vars ))280 (meta-variables (vector->list pattern) dim vars #f)) 281 281 (else vars))) 282 282 283 283 ;; Return a list of meta-variables of given higher dim … … 303 303 (free-meta-variables (vector->list template) dim env free)) 304 304 (else free))) 305 305 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)))) 310 314 311 315 (define (segment-template? pattern) 312 316 (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 144 144 (bar foo)))) 145 145 ) 146 146 147 ;;; alternative ellipsis test 147 ;;; alternative ellipsis test (SRFI-46) 148 148 149 149 (define-syntax foo 150 150 (syntax-rules … … 166 166 167 167 (t 3 (inc 2)) 168 168 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 169 219 ;;; 170 220 171 221 (define-syntax usetmp