|
1506 | 1506 | after
|
1507 | 1507 | (cons R elts)))
|
1508 | 1508 | ((vararg? L)
|
| 1509 | + (if (any vararg? (cdr lhss)) |
| 1510 | + (error "multiple \"...\" on lhs of assignment")) |
1509 | 1511 | (if (null? (cdr lhss))
|
1510 | 1512 | (let ((temp (if (eventually-call? (cadr L)) (gensy) (make-ssavalue))))
|
1511 | 1513 | `(block ,@(reverse stmts)
|
1512 | 1514 | (= ,temp (tuple ,@rhss))
|
1513 | 1515 | ,@(reverse after)
|
1514 | 1516 | (= ,(cadr L) ,temp)
|
1515 | 1517 | (unnecessary (tuple ,@(reverse elts) (... ,temp)))))
|
1516 |
| - (error (string "invalid \"...\" on non-final assignment location \"" |
1517 |
| - (cadr L) "\"")))) |
| 1518 | + (let ((lhss- (reverse lhss)) |
| 1519 | + (rhss- (reverse rhss)) |
| 1520 | + (lhs-tail '()) |
| 1521 | + (rhs-tail '())) |
| 1522 | + (define (extract-tail) |
| 1523 | + (if (not (or (null? lhss-) (null? rhss-) |
| 1524 | + (vararg? (car lhss-)) (vararg? (car rhss-)))) |
| 1525 | + (begin |
| 1526 | + (set! lhs-tail (cons (car lhss-) lhs-tail)) |
| 1527 | + (set! rhs-tail (cons (car rhss-) rhs-tail)) |
| 1528 | + (set! lhss- (cdr lhss-)) |
| 1529 | + (set! rhss- (cdr rhss-)) |
| 1530 | + (extract-tail)))) |
| 1531 | + (extract-tail) |
| 1532 | + (let* ((temp (if (any (lambda (x) |
| 1533 | + (or (eventually-call? x) |
| 1534 | + (and (vararg? x) (eventually-call? (cadr x))))) |
| 1535 | + lhss-) |
| 1536 | + (gensy) |
| 1537 | + (make-ssavalue))) |
| 1538 | + (assigns (make-assignment temp `(tuple ,@(reverse rhss-)))) |
| 1539 | + (assigns (if (symbol? temp) |
| 1540 | + `((local-def ,temp) ,assigns) |
| 1541 | + (list assigns))) |
| 1542 | + (n (length lhss-)) |
| 1543 | + (st (gensy)) |
| 1544 | + (end (list after)) |
| 1545 | + (assigns (if (and (length= lhss- 1) (vararg? (car lhss-))) |
| 1546 | + (begin |
| 1547 | + (set-car! end |
| 1548 | + (cons `(= ,(cadar lhss-) ,temp) (car end))) |
| 1549 | + assigns) |
| 1550 | + (append (if (> n 0) |
| 1551 | + `(,@assigns (local ,st)) |
| 1552 | + assigns) |
| 1553 | + (destructure- 1 (reverse lhss-) temp |
| 1554 | + n st end))))) |
| 1555 | + (loop lhs-tail |
| 1556 | + (append (map (lambda (x) (if (vararg? x) (cadr x) x)) lhss-) assigned) |
| 1557 | + rhs-tail |
| 1558 | + (append (reverse assigns) stmts) |
| 1559 | + (car end) |
| 1560 | + (cons `(... ,temp) elts)))))) |
| 1561 | + |
1518 | 1562 | ((vararg? R)
|
1519 | 1563 | (let ((temp (make-ssavalue)))
|
1520 | 1564 | `(block ,@(reverse stmts)
|
|
2187 | 2231 | lhss)
|
2188 | 2232 | (unnecessary ,xx))))
|
2189 | 2233 |
|
| 2234 | +;; implement tuple destructuring, possibly with slurping |
| 2235 | +;; |
| 2236 | +;; `i`: index of the current lhs arg |
| 2237 | +;; `lhss`: remaining lhs args |
| 2238 | +;; `xx`: the rhs, already either an ssavalue or something simple |
| 2239 | +;; `st`: empty list if i=1, otherwise contains the iteration state |
| 2240 | +;; `n`: total nr of lhs args |
| 2241 | +;; `end`: car collects statements to be executed afterwards. |
| 2242 | +;; In general, actual assignments should only happen after |
| 2243 | +;; the whole iterater is desctructured (https://github.com/JuliaLang/julia/issues/40574) |
| 2244 | +(define (destructure- i lhss xx n st end) |
| 2245 | + (if (null? lhss) |
| 2246 | + '() |
| 2247 | + (let* ((lhs (car lhss)) |
| 2248 | + (lhs- (cond ((or (symbol? lhs) (ssavalue? lhs)) |
| 2249 | + lhs) |
| 2250 | + ((vararg? lhs) |
| 2251 | + (let ((lhs- (cadr lhs))) |
| 2252 | + (if (or (symbol? lhs-) (ssavalue? lhs-)) |
| 2253 | + lhs |
| 2254 | + `(|...| ,(if (eventually-call? lhs-) |
| 2255 | + (gensy) |
| 2256 | + (make-ssavalue)))))) |
| 2257 | + ;; can't use ssavalues if it's a function definition |
| 2258 | + ((eventually-call? lhs) (gensy)) |
| 2259 | + (else (make-ssavalue))))) |
| 2260 | + (if (and (vararg? lhs) (any vararg? (cdr lhss))) |
| 2261 | + (error "multiple \"...\" on lhs of assignment")) |
| 2262 | + (if (not (eq? lhs lhs-)) |
| 2263 | + (if (vararg? lhs) |
| 2264 | + (set-car! end (cons (expand-forms `(= ,(cadr lhs) ,(cadr lhs-))) (car end))) |
| 2265 | + (set-car! end (cons (expand-forms `(= ,lhs ,lhs-)) (car end))))) |
| 2266 | + (if (vararg? lhs-) |
| 2267 | + (if (= i n) |
| 2268 | + (if (underscore-symbol? (cadr lhs-)) |
| 2269 | + '() |
| 2270 | + (list (expand-forms |
| 2271 | + `(= ,(cadr lhs-) (call (top rest) ,xx ,@(if (eq? i 1) '() `(,st))))))) |
| 2272 | + (let ((tail (if (eventually-call? lhs) (gensy) (make-ssavalue)))) |
| 2273 | + (cons (expand-forms |
| 2274 | + (lower-tuple-assignment |
| 2275 | + (list (cadr lhs-) tail) |
| 2276 | + `(call (top split_rest) ,xx ,(- n i) ,@(if (eq? i 1) '() `(,st))))) |
| 2277 | + (destructure- 1 (cdr lhss) tail (- n i) st end)))) |
| 2278 | + (cons (expand-forms |
| 2279 | + (lower-tuple-assignment |
| 2280 | + (if (= i n) |
| 2281 | + (list lhs-) |
| 2282 | + (list lhs- st)) |
| 2283 | + `(call (top indexed_iterate) |
| 2284 | + ,xx ,i ,@(if (eq? i 1) '() `(,st))))) |
| 2285 | + (destructure- (+ i 1) (cdr lhss) xx n st end)))))) |
| 2286 | + |
2190 | 2287 | (define (expand-tuple-destruct lhss x)
|
2191 | 2288 | (define (sides-match? l r)
|
2192 | 2289 | ;; l and r either have equal lengths, or r has a trailing ...
|
|
2203 | 2300 | (tuple-to-assignments lhss x))
|
2204 | 2301 | ;; (a, b, ...) = other
|
2205 | 2302 | (begin
|
2206 |
| - ;; like memq, but if last element of lhss is (... sym), |
2207 |
| - ;; check against sym instead |
| 2303 | + ;; like memq, but if lhs is (... sym), check against sym instead |
2208 | 2304 | (define (in-lhs? x lhss)
|
2209 | 2305 | (if (null? lhss)
|
2210 | 2306 | #f
|
2211 | 2307 | (let ((l (car lhss)))
|
2212 | 2308 | (cond ((and (pair? l) (eq? (car l) '|...|))
|
2213 |
| - (if (null? (cdr lhss)) |
2214 |
| - (eq? (cadr l) x) |
2215 |
| - (error (string "invalid \"...\" on non-final assignment location \"" |
2216 |
| - (cadr l) "\"")))) |
| 2309 | + (eq? (cadr l) x)) |
2217 | 2310 | ((eq? l x) #t)
|
2218 | 2311 | (else (in-lhs? x (cdr lhss)))))))
|
2219 | 2312 | ;; in-lhs? also checks for invalid syntax, so always call it first
|
2220 | 2313 | (let* ((xx (maybe-ssavalue lhss x in-lhs?))
|
2221 | 2314 | (ini (if (eq? x xx) '() (list (sink-assignment xx (expand-forms x)))))
|
2222 | 2315 | (n (length lhss))
|
2223 |
| - ;; skip last assignment if it is an all-underscore vararg |
2224 |
| - (n (if (> n 0) |
2225 |
| - (let ((l (last lhss))) |
2226 |
| - (if (and (vararg? l) (underscore-symbol? (cadr l))) |
2227 |
| - (- n 1) |
2228 |
| - n)) |
2229 |
| - n)) |
2230 | 2316 | (st (gensy))
|
2231 |
| - (end '())) |
| 2317 | + (end (list (list)))) |
2232 | 2318 | `(block
|
2233 | 2319 | ,@(if (> n 0) `((local ,st)) '())
|
2234 | 2320 | ,@ini
|
2235 |
| - ,@(map (lambda (i lhs) |
2236 |
| - (let ((lhs- (cond ((or (symbol? lhs) (ssavalue? lhs)) |
2237 |
| - lhs) |
2238 |
| - ((vararg? lhs) |
2239 |
| - (let ((lhs- (cadr lhs))) |
2240 |
| - (if (or (symbol? lhs-) (ssavalue? lhs-)) |
2241 |
| - lhs |
2242 |
| - `(|...| ,(if (eventually-call? lhs-) |
2243 |
| - (gensy) |
2244 |
| - (make-ssavalue)))))) |
2245 |
| - ;; can't use ssavalues if it's a function definition |
2246 |
| - ((eventually-call? lhs) (gensy)) |
2247 |
| - (else (make-ssavalue))))) |
2248 |
| - (if (not (eq? lhs lhs-)) |
2249 |
| - (if (vararg? lhs) |
2250 |
| - (set! end (cons (expand-forms `(= ,(cadr lhs) ,(cadr lhs-))) end)) |
2251 |
| - (set! end (cons (expand-forms `(= ,lhs ,lhs-)) end)))) |
2252 |
| - (expand-forms |
2253 |
| - (if (vararg? lhs-) |
2254 |
| - `(= ,(cadr lhs-) (call (top rest) ,xx ,@(if (eq? i 0) '() `(,st)))) |
2255 |
| - (lower-tuple-assignment |
2256 |
| - (if (= i (- n 1)) |
2257 |
| - (list lhs-) |
2258 |
| - (list lhs- st)) |
2259 |
| - `(call (top indexed_iterate) |
2260 |
| - ,xx ,(+ i 1) ,@(if (eq? i 0) '() `(,st)))))))) |
2261 |
| - (iota n) |
2262 |
| - lhss) |
2263 |
| - ,@(reverse end) |
| 2321 | + ,@(destructure- 1 lhss xx n st end) |
| 2322 | + ,@(reverse (car end)) |
2264 | 2323 | (unnecessary ,xx))))))
|
2265 | 2324 |
|
2266 | 2325 | ;; move an assignment into the last statement of a block to keep more statements at top level
|
|
0 commit comments