Skip to content

Commit eb191ac

Browse files
committed
add comprehension filters (fixes #550) and nested loops (fixes #4867)
this also uses the new lowering for typed comprehensions, allowing all comprehensions on unknown-length iterables (fixes #1457)
1 parent b01d528 commit eb191ac

File tree

2 files changed

+73
-37
lines changed

2 files changed

+73
-37
lines changed

src/julia-parser.scm

+14-6
Original file line numberDiff line numberDiff line change
@@ -1511,22 +1511,30 @@
15111511
(else
15121512
(error "missing separator in array expression")))))))
15131513

1514+
(define (parse-generator s first)
1515+
(let ((iters (parse-comma-separated-iters s)))
1516+
(let ((iters (if (eq? (peek-token s) 'if)
1517+
(begin (take-token s)
1518+
(list `(filter ,(parse-cond s) ,@iters)))
1519+
iters)))
1520+
(if (eq? (peek-token s) 'for)
1521+
(begin (take-token s)
1522+
`(flatten (generator ,(parse-generator s first) ,@iters)))
1523+
`(generator ,first ,@iters)))))
1524+
15141525
(define (parse-comprehension s first closer)
1515-
(let ((r (parse-comma-separated-iters s)))
1526+
(let ((gen (parse-generator s first)))
15161527
(if (not (eqv? (require-token s) closer))
15171528
(error (string "expected \"" closer "\""))
15181529
(take-token s))
1519-
`(comprehension ,first ,@r)))
1530+
`(comprehension ,gen)))
15201531

15211532
(define (parse-dict-comprehension s first closer)
15221533
(let ((c (parse-comprehension s first closer)))
1523-
(if (dict-literal? (cadr c))
1534+
(if (dict-literal? (cadr (cadr c)))
15241535
`(dict_comprehension ,@(cdr c))
15251536
(error "invalid dict comprehension"))))
15261537

1527-
(define (parse-generator s first)
1528-
`(generator ,first ,@(parse-comma-separated-iters s)))
1529-
15301538
(define (parse-matrix s first closer gotnewline)
15311539
(define (fix head v) (cons head (reverse v)))
15321540
(define (update-outer v outer)

src/julia-syntax.scm

+59-31
Original file line numberDiff line numberDiff line change
@@ -1524,6 +1524,26 @@
15241524
(define (syntactic-op-to-call e)
15251525
`(call ,(car e) ,(expand-forms (cadr e)) ,(expand-forms (caddr e))))
15261526

1527+
;; wrap `expr` in a function appropriate for consuming values from given ranges
1528+
(define (func-for-generator-ranges expr range-exprs)
1529+
(let* ((vars (map cadr range-exprs))
1530+
(argname (if (and (length= vars 1) (symbol? (car vars)))
1531+
(car vars)
1532+
(gensy)))
1533+
(splat (cond ((eq? argname (car vars)) '())
1534+
((length= vars 1)
1535+
`(,@(map (lambda (v) `(local ,v)) (lhs-vars (car vars)))
1536+
(= ,(car vars) ,argname)))
1537+
(else
1538+
`(,@(map (lambda (v) `(local ,v)) (lhs-vars `(tuple ,@vars)))
1539+
(= (tuple ,@vars) ,argname))))))
1540+
(if (and (null? splat)
1541+
(length= expr 3) (eq? (car expr) 'call)
1542+
(eq? (caddr expr) argname)
1543+
(not (expr-contains-eq argname (cadr expr))))
1544+
(cadr expr) ;; eta reduce `x->f(x)` => `f`
1545+
`(-> ,argname (block ,@splat ,expr)))))
1546+
15271547
;; table mapping expression head to a function expanding that form
15281548
(define expand-table
15291549
(table
@@ -1958,52 +1978,60 @@
19581978

19591979
'generator
19601980
(lambda (e)
1961-
(let ((expr (cadr e))
1962-
(vars (map cadr (cddr e)))
1963-
(ranges (map caddr (cddr e))))
1964-
(let* ((argname (if (and (length= vars 1) (symbol? (car vars)))
1965-
(car vars)
1966-
(gensy)))
1967-
(splat (cond ((eq? argname (car vars)) '())
1968-
((length= vars 1)
1969-
`(,@(map (lambda (v) `(local ,v)) (lhs-vars (car vars)))
1970-
(= ,(car vars) ,argname)))
1971-
(else
1972-
`(,@(map (lambda (v) `(local ,v)) (lhs-vars `(tuple ,@vars)))
1973-
(= (tuple ,@vars) ,argname))))))
1974-
(expand-forms
1975-
`(call (top Generator)
1976-
,(if (and (null? splat)
1977-
(length= expr 3) (eq? (car expr) 'call)
1978-
(eq? (caddr expr) argname)
1979-
(not (expr-contains-eq argname (cadr expr))))
1980-
(cadr expr) ;; eta reduce `x->f(x)` => `f`
1981-
`(-> ,argname (block ,@splat ,expr)))
1982-
,(if (length= ranges 1)
1981+
(let* ((expr (cadr e))
1982+
(filt? (eq? (car (caddr e)) 'filter))
1983+
(range-exprs (if filt? (cddr (caddr e)) (cddr e)))
1984+
(ranges (map caddr range-exprs))
1985+
(iter (if (length= ranges 1)
19831986
(car ranges)
1984-
`(call (top product) ,@ranges)))))))
1987+
`(call (top product) ,@ranges)))
1988+
(iter (if filt?
1989+
`(call (top Filter)
1990+
,(func-for-generator-ranges (cadr (caddr e)) range-exprs)
1991+
,iter)
1992+
iter)))
1993+
(expand-forms
1994+
`(call (top Generator)
1995+
,(func-for-generator-ranges expr range-exprs)
1996+
,iter))))
1997+
1998+
'flatten
1999+
(lambda (e) `(call (top Flatten) ,(expand-forms (cadr e))))
19852000

19862001
'comprehension
19872002
(lambda (e)
1988-
(if (any (lambda (x) (eq? x ':)) (cddr e))
1989-
(error "comprehension syntax with `:` ranges has been removed"))
1990-
(expand-forms `(call (top collect) (generator ,(cadr e) ,@(cddr e)))))
2003+
(if (length> e 2)
2004+
;; backwards compat for macros that generate :comprehension exprs
2005+
(expand-forms `(comprehension (generator ,@(cdr e))))
2006+
(begin (if (and (eq? (caadr e) 'generator)
2007+
(any (lambda (x) (eq? x ':)) (cddr (cadr e))))
2008+
(error "comprehension syntax with `:` ranges has been removed"))
2009+
(expand-forms `(call (top collect) ,(cadr e))))))
19912010

19922011
'typed_comprehension
19932012
(lambda (e)
1994-
(if (any (lambda (x) (eq? x ':)) (cdddr e))
1995-
(error "comprehension syntax with `:` ranges has been removed"))
1996-
(expand-forms (lower-comprehension (cadr e) (caddr e) (cdddr e))))
2013+
(expand-forms
2014+
(or (and (eq? (caaddr e) 'generator)
2015+
(let ((ranges (cddr (caddr e))))
2016+
(if (any (lambda (x) (eq? x ':)) ranges)
2017+
(error "comprehension syntax with `:` ranges has been removed"))
2018+
(and (every (lambda (x) (and (pair? x) (eq? (car x) '=)
2019+
(pair? (caddr x)) (eq? (car (caddr x)) ':)))
2020+
ranges)
2021+
;; TODO: this is a hack to lower simple comprehensions to loops very
2022+
;; early, to greatly reduce the # of functions and load on the compiler
2023+
(lower-comprehension (cadr e) (cadr (caddr e)) ranges))))
2024+
`(call (top collect) ,(cadr e) ,(caddr e)))))
19972025

19982026
'dict_comprehension
19992027
(lambda (e)
20002028
(syntax-deprecation #f "[a=>b for (a,b) in c]" "Dict(a=>b for (a,b) in c)")
2001-
(expand-forms `(call (top Dict) (generator ,(cadr e) ,@(cddr e)))))
2029+
(expand-forms `(call (top Dict) ,(cadr e))))
20022030

20032031
'typed_dict_comprehension
20042032
(lambda (e) (expand-forms
20052033
`(call (call (core apply_type) (top Dict) ,@(cdr (cadr e)))
2006-
(generator ,(caddr e) ,@(cdddr e)))))))
2034+
,(caddr e))))))
20072035

20082036
(define (lower-comprehension atype expr ranges)
20092037
(let ((result (make-ssavalue))

0 commit comments

Comments
 (0)