You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The `=` node which has traditionally been used for iteration
specifications in `for` loops and generators doesn't have normal
assignment semantics. Let's consider
for x in xs
body
end
which has been parsed as `(for (= x xs) (block body))`.
Problems:
* The iteration does create a binding for `x`, but not to the expression
on the right hand side of the `=`.
* The user may use `in` or `∈` in the source code rather than `=`.
The parser still uses a `=` node for consistency but this only
emphasizes that there's something a bit weird going on.
So this use of `=` is not assignment; merely assignment-like.
In this change, we use a new iteration kind instead of `=` so the `for`
loop parses as `(for (iteration x xs) (block body))` instead.
We also reuse `iteration` to replace the `cartesian_iteration` head -
cartesian iteration is just an iteration with an even number of children
greater than two. Being less specific here with the naming (omitting the
"cartesian") seems appropriate in trying to represent the surface
syntax; cartesian semantics come later in lowering and a macro may
decide to do something else with the iteration spec.
These changes are also used for generators.
After the changes we have tree structures such as
julia> parsestmt(SyntaxNode, "for i in is body end")
line:col│ tree │ file_name
1:1 │[for]
1:4 │ [iteration]
1:5 │ i
1:10 │ is
1:12 │ [block]
1:13 │ body
julia> parsestmt(SyntaxNode, "for i in is, j in js body end")
line:col│ tree │ file_name
1:1 │[for]
1:4 │ [iteration]
1:5 │ i
1:10 │ is
1:14 │ j
1:19 │ js
1:21 │ [block]
1:22 │ body
julia> parsestmt(SyntaxNode, "[a for i = is, j = js if z]")
line:col│ tree │ file_name
1:1 │[comprehension]
1:2 │ [generator]
1:2 │ a
1:7 │ [filter]
1:7 │ [iteration]
1:8 │ i
1:12 │ is
1:16 │ j
1:20 │ js
1:26 │ z
julia> parsestmt(SyntaxNode, "[a for i = is for j = js if z]")
line:col│ tree │ file_name
1:1 │[comprehension]
1:2 │ [generator]
1:2 │ a
1:7 │ [iteration]
1:8 │ i
1:12 │ is
1:18 │ [filter]
1:18 │ [iteration]
1:19 │ j
1:23 │ js
1:29 │ z
Copy file name to clipboardExpand all lines: docs/src/reference.md
+10-10Lines changed: 10 additions & 10 deletions
Original file line number
Diff line number
Diff line change
@@ -76,7 +76,7 @@ class of tokenization errors and lets the parser deal with them.
76
76
* Using `try catch else finally end` is parsed with `K"catch"``K"else"` and `K"finally"` children to avoid the awkwardness of the optional child nodes in the `Expr` representation (#234)
77
77
* The dotted import path syntax as in `import A.b.c` is parsed with a `K"importpath"` kind rather than `K"."`, because a bare `A.b.c` has a very different nested/quoted expression representation (#244)
78
78
* We use flags rather than child nodes to represent the difference between `struct` and `mutable struct`, `module` and `baremodule` (#220)
79
-
*Multiple iterations within the header of a `for`, as in `for a=as, b=bs body end` are represented with a `cartesian_iterator` head rather than a `block`, as these lists of iterators are neither semantically nor syntactically a sequence of statements. Unlike other uses of `block` (see also generators).
79
+
*Iterations are represented with the `iteration` head rather than `=`within the header of a `for`. Thus `for i=is ; body end` parses to `(for (iteration i is) (block body))`. Cartesian iteration as in `for a=as, b=bs body end` are represented with a longer `iteration` block rather than a `block` containing `=` because these lists of iterators are neither semantically nor syntactically a sequence of statements, unlike other uses of `block`. Generators also use the `iteration` head - see information on that below.
80
80
81
81
## More detail on tree differences
82
82
@@ -90,8 +90,10 @@ mean
90
90
91
91
```
92
92
for x in xs
93
-
for y in ys
94
-
push!(xy, collection)
93
+
for y in ys
94
+
push!(xy, collection)
95
+
end
96
+
end
95
97
```
96
98
97
99
so the `xy` prefix is in the *body* of the innermost for loop. Following this,
@@ -112,27 +114,25 @@ source order.
112
114
113
115
However, our green tree is strictly source-ordered, so we must deviate from the
114
116
Julia AST. We deal with this by grouping cartesian products of iterators
115
-
(separated by commas) within `cartesian_iterator` blocks as in `for` loops, and
116
-
use the presence of multiple iterator blocks rather than the `flatten` head to
117
+
(separated by commas) within `iteration` blocks as in `for` loops, and
118
+
use the length of the `iteration` block rather than the `flatten` head to
117
119
distinguish flattened iterators. The nested flattens and generators of `Expr`
118
120
forms are reconstructed later. In this form the tree structure resembles the
119
121
source much more closely. For example, `(xy for x in xs for y in ys)` is parsed as
120
122
121
123
```
122
124
(generator
123
125
xy
124
-
(= x xs)
125
-
(= y ys))
126
+
(iteration x xs)
127
+
(iteration y ys))
126
128
```
127
129
128
130
And the cartesian iteration `(xy for x in xs, y in ys)` is parsed as
Copy file name to clipboardExpand all lines: test/parser.jl
+31-31Lines changed: 31 additions & 31 deletions
Original file line number
Diff line number
Diff line change
@@ -299,7 +299,7 @@ tests = [
299
299
"x where \n {T}"=>"(where x (braces T))"
300
300
"x where {T,S}"=>"(where x (braces T S))"
301
301
"x where {T S}"=>"(where x (bracescat (row T S)))"
302
-
"x where {y for y in ys}"=>"(where x (braces (generator y (= y ys))))"
302
+
"x where {y for y in ys}"=>"(where x (braces (generator y (iteration y ys))))"
303
303
"x where T"=>"(where x T)"
304
304
"x where \n T"=>"(where x T)"
305
305
"x where T<:S"=>"(where x (<: T S))"
@@ -388,7 +388,7 @@ tests = [
388
388
"T[x y]"=>"(typed_hcat T x y)"
389
389
"T[x ; y]"=>"(typed_vcat T x y)"
390
390
"T[a b; c d]"=>"(typed_vcat T (row a b) (row c d))"
391
-
"T[x for x in xs]"=>"(typed_comprehension T (generator x (= x xs)))"
391
+
"T[x for x in xs]"=>"(typed_comprehension T (generator x (iteration x xs)))"
392
392
((v=v"1.8",), "T[a ; b ;; c ; d]") =>"(typed_ncat-2 T (nrow-1 a b) (nrow-1 c d))"
393
393
394
394
# Dotted forms
@@ -460,8 +460,8 @@ tests = [
460
460
"while cond body end"=>"(while cond (block body))"
461
461
"while x < y \n a \n b \n end"=>"(while (call-i x < y) (block a b))"
462
462
# for
463
-
"for x in xs end"=>"(for (= x xs) (block))"
464
-
"for x in xs, y in ys \n a \n end"=>"(for (cartesian_iterator (= x xs) (= y ys)) (block a))"
463
+
"for x in xs end"=>"(for (iteration x xs) (block))"
464
+
"for x in xs, y in ys \n a \n end"=>"(for (iteration x xsy ys) (block a))"
465
465
# let
466
466
"let x=1\n end"=>"(let (block (= x 1)) (block))"
467
467
"let x=1 ; end"=>"(let (block (= x 1)) (block))"
@@ -669,16 +669,16 @@ tests = [
669
669
"import A..."=>"(import (importpath A ..))"
670
670
"import A; B"=>"(import (importpath A))"
671
671
],
672
-
JuliaSyntax.parse_iteration_spec=> [
673
-
"i = rhs"=>"(= i rhs)"
674
-
"i in rhs"=>"(= i rhs)"
675
-
"i ∈ rhs"=>"(= i rhs)"
676
-
"i = 1:10"=>"(= i (call-i 1 : 10))"
677
-
"(i,j) in iter"=>"(= (tuple-p i j) iter)"
678
-
"outer = rhs"=>"(= outer rhs)"
679
-
"outer <| x = rhs"=>"(= (call-i outer <| x) rhs)"
680
-
"outer i = rhs"=>"(= (outer i) rhs)"
681
-
"outer (x,y) = rhs"=>"(= (outer (tuple-p x y)) rhs)"
672
+
JuliaSyntax.parse_iteration_specs=> [
673
+
"i = rhs"=>"(iteration i rhs)"
674
+
"i in rhs"=>"(iteration i rhs)"
675
+
"i ∈ rhs"=>"(iteration i rhs)"
676
+
"i = 1:10"=>"(iteration i (call-i 1 : 10))"
677
+
"(i,j) in iter"=>"(iteration (tuple-p i j) iter)"
678
+
"outer = rhs"=>"(iteration outer rhs)"
679
+
"outer <| x = rhs"=>"(iteration (call-i outer <| x) rhs)"
680
+
"outer i = rhs"=>"(iteration (outer i) rhs)"
681
+
"outer (x,y) = rhs"=>"(iteration (outer (tuple-p x y)) rhs)"
682
682
],
683
683
JuliaSyntax.parse_paren => [
684
684
# Tuple syntax with commas
@@ -706,8 +706,8 @@ tests = [
706
706
"(x)"=>"(parens x)"
707
707
"(a...)"=>"(parens (... a))"
708
708
# Generators
709
-
"(x for a in as)"=>"(parens (generator x (= a as)))"
710
-
"(x \n\n for a in as)"=>"(parens (generator x (= a as)))"
709
+
"(x for a in as)"=>"(parens (generator x (iteration a as)))"
710
+
"(x \n\n for a in as)"=>"(parens (generator x (iteration a as)))"
711
711
# Range parsing in parens
712
712
"(1:\n2)"=>"(parens (call-i 1 : 2))"
713
713
"(1:2)"=>"(parens (call-i 1 : 2))"
@@ -775,19 +775,19 @@ tests = [
775
775
"[x \n, ]"=>"(vect x)"
776
776
"[x"=>"(vect x (error-t))"
777
777
"[x \n\n ]"=>"(vect x)"
778
-
"[x for a in as]"=>"(comprehension (generator x (= a as)))"
779
-
"[x \n\n for a in as]"=>"(comprehension (generator x (= a as)))"
778
+
"[x for a in as]"=>"(comprehension (generator x (iteration a as)))"
779
+
"[x \n\n for a in as]"=>"(comprehension (generator x (iteration a as)))"
780
780
# parse_generator
781
-
"(x for a in as for b in bs)"=>"(parens (generator x (= a as) (= b bs)))"
782
-
"(x for a in as, b in bs)"=>"(parens (generator x (cartesian_iterator (= a as) (= b bs))))"
783
-
"(x for a in as, b in bs if z)"=>"(parens (generator x (filter (cartesian_iterator (= a as) (= b bs)) z)))"
784
-
"(x for a in as, b in bs for c in cs, d in ds)"=>"(parens (generator x (cartesian_iterator (= a as) (= b bs)) (cartesian_iterator (= c cs) (= d ds))))"
785
-
"(x for a in as for b in bs if z)"=>"(parens (generator x (= a as) (filter (= b bs) z)))"
786
-
"(x for a in as if z for b in bs)"=>"(parens (generator x (filter (= a as) z) (= b bs)))"
787
-
"[x for a = as for b = bs if cond1 for c = cs if cond2]"=>"(comprehension (generator x (= a as) (filter (= b bs) cond1) (filter (= c cs) cond2)))"
788
-
"[x for a = as if begin cond2 end]"=>"(comprehension (generator x (filter (= a as) (block cond2))))"
789
-
"[(x)for x in xs]"=>"(comprehension (generator (parens x) (error-t) (= x xs)))"
790
-
"(x for a in as if z)"=>"(parens (generator x (filter (= a as) z)))"
781
+
"(x for a in as for b in bs)"=>"(parens (generator x (iteration a as) (iteration b bs)))"
782
+
"(x for a in as, b in bs)"=>"(parens (generator x (iteration a asb bs)))"
783
+
"(x for a in as, b in bs if z)"=>"(parens (generator x (filter (iteration a asb bs) z)))"
784
+
"(x for a in as, b in bs for c in cs, d in ds)"=>"(parens (generator x (iteration a asb bs) (iteration c csd ds)))"
785
+
"(x for a in as for b in bs if z)"=>"(parens (generator x (iteration a as) (filter (iteration b bs) z)))"
786
+
"(x for a in as if z for b in bs)"=>"(parens (generator x (filter (iteration a as) z) (iteration b bs)))"
787
+
"[x for a = as for b = bs if cond1 for c = cs if cond2]"=>"(comprehension (generator x (iteration a as) (filter (iteration b bs) cond1) (filter (iteration c cs) cond2)))"
788
+
"[x for a = as if begin cond2 end]"=>"(comprehension (generator x (filter (iteration a as) (block cond2))))"
789
+
"[(x)for x in xs]"=>"(comprehension (generator (parens x) (error-t) (iteration x xs)))"
790
+
"(x for a in as if z)"=>"(parens (generator x (filter (iteration a as) z)))"
0 commit comments