Skip to content

Commit ced4ffb

Browse files
committed
Change AST for iterations to use iteration kind
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
1 parent bd29025 commit ced4ffb

File tree

5 files changed

+89
-76
lines changed

5 files changed

+89
-76
lines changed

docs/src/reference.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ class of tokenization errors and lets the parser deal with them.
7676
* 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)
7777
* 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)
7878
* 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.
8080

8181
## More detail on tree differences
8282

@@ -90,8 +90,10 @@ mean
9090

9191
```
9292
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
9597
```
9698

9799
so the `xy` prefix is in the *body* of the innermost for loop. Following this,
@@ -112,27 +114,25 @@ source order.
112114

113115
However, our green tree is strictly source-ordered, so we must deviate from the
114116
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
117119
distinguish flattened iterators. The nested flattens and generators of `Expr`
118120
forms are reconstructed later. In this form the tree structure resembles the
119121
source much more closely. For example, `(xy for x in xs for y in ys)` is parsed as
120122

121123
```
122124
(generator
123125
xy
124-
(= x xs)
125-
(= y ys))
126+
(iteration x xs)
127+
(iteration y ys))
126128
```
127129

128130
And the cartesian iteration `(xy for x in xs, y in ys)` is parsed as
129131

130132
```
131133
(generator
132134
xy
133-
(cartesian_iterator
134-
(= x xs)
135-
(= y ys)))
135+
(iteration x xs y ys))
136136
```
137137

138138
### Whitespace trivia inside strings

src/expr.jl

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,22 @@ function _extract_do_lambda!(args)
193193
end
194194
end
195195

196+
function _convert_iteration(wrap_iters::Function, ex)
197+
if @isexpr(ex, :iteration)
198+
if length(ex.args) == 2
199+
wrap_iters(false, Expr(:(=), ex.args[1], ex.args[2]))
200+
else
201+
blk_args = []
202+
for i = 1:2:length(ex.args)
203+
push!(blk_args, Expr(:(=), ex.args[i], ex.args[i+1]))
204+
end
205+
wrap_iters(true, blk_args)
206+
end
207+
else
208+
wrap_iters(false, ex)
209+
end
210+
end
211+
196212
# Convert internal node of the JuliaSyntax parse tree to an Expr
197213
function _internal_node_to_Expr(source, srcrange, head, childranges, childheads, args)
198214
k = kind(head)
@@ -296,9 +312,8 @@ function _internal_node_to_Expr(source, srcrange, head, childranges, childheads,
296312
# Move parameters blocks to args[2]
297313
_reorder_parameters!(args, 2)
298314
elseif k == K"for"
299-
a1 = args[1]
300-
if @isexpr(a1, :cartesian_iterator)
301-
args[1] = Expr(:block, a1.args...)
315+
args[1] = _convert_iteration(args[1]) do is_multi_iter, iter
316+
is_multi_iter ? Expr(:block, iter...) : iter
302317
end
303318
# Add extra line number node for the `end` of the block. This may seem
304319
# useless but it affects code coverage.
@@ -356,10 +371,9 @@ function _internal_node_to_Expr(source, srcrange, head, childranges, childheads,
356371
gen = args[1]
357372
for j = length(args):-1:2
358373
aj = args[j]
359-
if @isexpr(aj, :cartesian_iterator)
360-
gen = Expr(:generator, gen, aj.args...)
361-
else
362-
gen = Expr(:generator, gen, aj)
374+
gen = _convert_iteration(args[j]) do is_multi_iter, iter
375+
is_multi_iter ? Expr(:generator, gen, iter...) :
376+
Expr(:generator, gen, iter)
363377
end
364378
if j < length(args)
365379
# Additional `for`s flatten the inner generator
@@ -371,10 +385,12 @@ function _internal_node_to_Expr(source, srcrange, head, childranges, childheads,
371385
@assert length(args) == 2
372386
iterspec = args[1]
373387
outargs = Any[args[2]]
374-
if @isexpr(iterspec, :cartesian_iterator)
375-
append!(outargs, iterspec.args)
376-
else
377-
push!(outargs, iterspec)
388+
_convert_iteration(args[1]) do is_multi_iter, iter
389+
if is_multi_iter
390+
append!(outargs, iter)
391+
else
392+
push!(outargs, iter)
393+
end
378394
end
379395
args = outargs
380396
elseif k == K"nrow" || k == K"ncat"

src/kinds.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -912,7 +912,7 @@ const _kind_names =
912912
# Comprehensions
913913
"generator"
914914
"filter"
915-
"cartesian_iterator"
915+
"iteration"
916916
"comprehension"
917917
"typed_comprehension"
918918
# Container for a single statement/atom plus any trivia and errors

src/parser.jl

Lines changed: 20 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,7 +1075,7 @@ function parse_where_chain(ps0::ParseState, mark)
10751075
# x where {T,S} ==> (where x (braces T S))
10761076
# Also various nonsensical forms permitted
10771077
# x where {T S} ==> (where x (bracescat (row T S)))
1078-
# x where {y for y in ys} ==> (where x (braces (generator y (= y ys))))
1078+
# x where {y for y in ys} ==> (where x (braces (generator y (iteration y ys))))
10791079
m = position(ps)
10801080
bump(ps, TRIVIA_FLAG)
10811081
ckind, cflags = parse_cat(ps, K"}", ps.end_symbol)
@@ -1577,7 +1577,7 @@ function parse_call_chain(ps::ParseState, mark, is_macrocall=false)
15771577
# T[x y] ==> (typed_hcat T x y)
15781578
# T[x ; y] ==> (typed_vcat T x y)
15791579
# T[a b; c d] ==> (typed_vcat T (row a b) (row c d))
1580-
# T[x for x in xs] ==> (typed_comprehension T (generator x (= x xs)))
1580+
# T[x for x in xs] ==> (typed_comprehension T (generator x (iteration x xs)))
15811581
#v1.8: T[a ; b ;; c ; d] ==> (typed_ncat-2 T (nrow-1 a b) (nrow-1 c d))
15821582
outk = ckind == K"vect" ? K"ref" :
15831583
ckind == K"hcat" ? K"typed_hcat" :
@@ -1797,8 +1797,8 @@ function parse_resword(ps::ParseState)
17971797
bump_closing_token(ps, K"end")
17981798
emit(ps, mark, K"while")
17991799
elseif word == K"for"
1800-
# for x in xs end ==> (for (= x xs) (block))
1801-
# for x in xs, y in ys \n a \n end ==> (for (cartesian_iterator (= x xs) (= y ys)) (block a))
1800+
# for x in xs end ==> (for (iteration x xs) (block))
1801+
# for x in xs, y in ys \n a \n end ==> (for (iteration x xs y ys) (block a))
18021802
bump(ps, TRIVIA_FLAG)
18031803
parse_iteration_specs(ps)
18041804
parse_block(ps)
@@ -2620,11 +2620,11 @@ function parse_iteration_spec(ps::ParseState)
26202620
if peek_behind(ps).orig_kind == K"outer"
26212621
if peek_skip_newline_in_gen(ps) in KSet"= in ∈"
26222622
# Not outer keyword
2623-
# outer = rhs ==> (= outer rhs)
2624-
# outer <| x = rhs ==> (= (call-i outer <| x) rhs)
2623+
# outer = rhs ==> (iteration outer rhs)
2624+
# outer <| x = rhs ==> (iteration (call-i outer <| x) rhs)
26252625
else
2626-
# outer i = rhs ==> (= (outer i) rhs)
2627-
# outer (x,y) = rhs ==> (= (outer (tuple-p x y)) rhs)
2626+
# outer i = rhs ==> (iteration (outer i) rhs)
2627+
# outer (x,y) = rhs ==> (iteration (outer (tuple-p x y)) rhs)
26282628
reset_node!(ps, position(ps), kind=K"outer", flags=TRIVIA_FLAG)
26292629
parse_pipe_lt(ps)
26302630
emit(ps, mark, K"outer")
@@ -2640,17 +2640,14 @@ function parse_iteration_spec(ps::ParseState)
26402640
end
26412641
# Or try parse_pipe_lt ???
26422642
end
2643-
emit(ps, mark, K"=")
26442643
end
26452644

26462645
# Parse an iteration spec, or a comma separate list of such for for loops and
26472646
# generators
26482647
function parse_iteration_specs(ps::ParseState)
26492648
mark = position(ps)
26502649
n_iters = parse_comma_separated(ps, parse_iteration_spec)
2651-
if n_iters > 1
2652-
emit(ps, mark, K"cartesian_iterator")
2653-
end
2650+
emit(ps, mark, K"iteration")
26542651
end
26552652

26562653
# flisp: parse-space-separated-exprs
@@ -2700,27 +2697,27 @@ end
27002697
# Parse generators
27012698
#
27022699
# We represent generators quite differently from `Expr`:
2703-
# * Cartesian products of iterators are grouped within cartesian_iterator
2700+
# * Iteration variables and their iterators are grouped within K"iteration"
27042701
# nodes, as in the short form of `for` loops.
27052702
# * The `generator` kind is used for both cartesian and flattened generators
27062703
#
2707-
# (x for a in as for b in bs) ==> (parens (generator x (= a as) (= b bs)))
2708-
# (x for a in as, b in bs) ==> (parens (generator x (cartesian_iterator (= a as) (= b bs))))
2709-
# (x for a in as, b in bs if z) ==> (parens (generator x (filter (cartesian_iterator (= a as) (= b bs)) z)))
2704+
# (x for a in as for b in bs) ==> (parens (generator x (iteration a as) (iteration b bs)))
2705+
# (x for a in as, b in bs) ==> (parens (generator x (iteration a as b bs)))
2706+
# (x for a in as, b in bs if z) ==> (parens (generator x (filter (iteration a as b bs) z)))
27102707
#
27112708
# flisp: parse-generator
27122709
function parse_generator(ps::ParseState, mark)
27132710
while (t = peek_token(ps); kind(t) == K"for")
27142711
if !preceding_whitespace(t)
2715-
# ((x)for x in xs) ==> (parens (generator (parens x) (error) (= x xs)))
2712+
# ((x)for x in xs) ==> (parens (generator (parens x) (error) (iteration x xs)))
27162713
bump_invisible(ps, K"error", TRIVIA_FLAG,
27172714
error="Expected space before `for` in generator")
27182715
end
27192716
bump(ps, TRIVIA_FLAG)
27202717
iter_mark = position(ps)
27212718
parse_iteration_specs(ps)
27222719
if peek(ps) == K"if"
2723-
# (x for a in as if z) ==> (parens (generator x (filter (= a as) z)))
2720+
# (x for a in as if z) ==> (parens (generator x (filter (iteration a as) z)))
27242721
bump(ps, TRIVIA_FLAG)
27252722
parse_cond(ps)
27262723
emit(ps, iter_mark, K"filter")
@@ -2731,7 +2728,7 @@ end
27312728

27322729
# flisp: parse-comprehension
27332730
function parse_comprehension(ps::ParseState, mark, closer)
2734-
# [x for a in as] ==> (comprehension (generator x a in as))
2731+
# [x for a in as] ==> (comprehension (generator x (iteration a as)))
27352732
ps = ParseState(ps, whitespace_newline=true,
27362733
space_sensitive=false,
27372734
end_symbol=false)
@@ -2981,8 +2978,8 @@ function parse_cat(ps::ParseState, closer, end_is_symbol)
29812978
# [x ==> (vect x (error-t))
29822979
parse_vect(ps, closer)
29832980
elseif k == K"for"
2984-
# [x for a in as] ==> (comprehension (generator x (= a as)))
2985-
# [x \n\n for a in as] ==> (comprehension (generator x (= a as)))
2981+
# [x for a in as] ==> (comprehension (generator x (iteration a as)))
2982+
# [x \n\n for a in as] ==> (comprehension (generator x (iteration a as)))
29862983
parse_comprehension(ps, mark, closer)
29872984
else
29882985
# [x y] ==> (hcat x y)
@@ -3138,8 +3135,8 @@ function parse_brackets(after_parse::Function,
31383135
continue
31393136
elseif k == K"for"
31403137
# Generator syntax
3141-
# (x for a in as) ==> (parens (generator x (= a as)))
3142-
# (x \n\n for a in as) ==> (parens (generator x (= a as)))
3138+
# (x for a in as) ==> (parens (generator x (iteration a as)))
3139+
# (x \n\n for a in as) ==> (parens (generator x (iteration a as)))
31433140
parse_generator(ps, mark)
31443141
else
31453142
# Error - recovery done when consuming closing_kind

test/parser.jl

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ tests = [
299299
"x where \n {T}" => "(where x (braces T))"
300300
"x where {T,S}" => "(where x (braces T S))"
301301
"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))))"
303303
"x where T" => "(where x T)"
304304
"x where \n T" => "(where x T)"
305305
"x where T<:S" => "(where x (<: T S))"
@@ -388,7 +388,7 @@ tests = [
388388
"T[x y]" => "(typed_hcat T x y)"
389389
"T[x ; y]" => "(typed_vcat T x y)"
390390
"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)))"
392392
((v=v"1.8",), "T[a ; b ;; c ; d]") => "(typed_ncat-2 T (nrow-1 a b) (nrow-1 c d))"
393393

394394
# Dotted forms
@@ -460,8 +460,8 @@ tests = [
460460
"while cond body end" => "(while cond (block body))"
461461
"while x < y \n a \n b \n end" => "(while (call-i x < y) (block a b))"
462462
# 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 xs y ys) (block a))"
465465
# let
466466
"let x=1\n end" => "(let (block (= x 1)) (block))"
467467
"let x=1 ; end" => "(let (block (= x 1)) (block))"
@@ -669,16 +669,16 @@ tests = [
669669
"import A..." => "(import (importpath A ..))"
670670
"import A; B" => "(import (importpath A))"
671671
],
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)"
682682
],
683683
JuliaSyntax.parse_paren => [
684684
# Tuple syntax with commas
@@ -706,8 +706,8 @@ tests = [
706706
"(x)" => "(parens x)"
707707
"(a...)" => "(parens (... a))"
708708
# 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)))"
711711
# Range parsing in parens
712712
"(1:\n2)" => "(parens (call-i 1 : 2))"
713713
"(1:2)" => "(parens (call-i 1 : 2))"
@@ -775,19 +775,19 @@ tests = [
775775
"[x \n, ]" => "(vect x)"
776776
"[x" => "(vect x (error-t))"
777777
"[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)))"
780780
# 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 as b bs)))"
783+
"(x for a in as, b in bs if z)" => "(parens (generator x (filter (iteration a as b bs) z)))"
784+
"(x for a in as, b in bs for c in cs, d in ds)" => "(parens (generator x (iteration a as b bs) (iteration c cs d 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)))"
791791
# parse_vect
792792
"[x, y]" => "(vect x y)"
793793
"[x, y]" => "(vect x y)"
@@ -875,8 +875,8 @@ tests = [
875875
"\"hi\$(\"ho\")\"" => "(string \"hi\" (parens (string \"ho\")))"
876876
"\"\$(x,y)\"" => "(string (parens (error x y)))"
877877
"\"\$(x;y)\"" => "(string (parens (error x y)))"
878-
"\"\$(x for y in z)\"" => "(string (parens (error (generator x (= y z)))))"
879-
"\"\$((x for y in z))\"" => "(string (parens (parens (generator x (= y z)))))"
878+
"\"\$(x for y in z)\"" => "(string (parens (error (generator x (iteration y z)))))"
879+
"\"\$((x for y in z))\"" => "(string (parens (parens (generator x (iteration y z)))))"
880880
"\"\$(xs...)\"" => "(string (parens (... xs)))"
881881
"\"a \$foo b\"" => "(string \"a \" foo \" b\")"
882882
"\"\$var\"" => "(string var)"
@@ -995,7 +995,7 @@ parsestmt_test_specs = [
995995
":+'y'" => "(juxtapose (call-post (quote-: +) ') (call-post y '))"
996996
# unary subtype ops and newlines
997997
"a +\n\n<:" => "(call-i a + <:)"
998-
"for\n\n<:" => "(for (= <: (error (error-t))) (block (error)) (error-t))"
998+
"for\n\n<:" => "(for (iteration <: (error (error-t))) (block (error)) (error-t))"
999999
# Empty character consumes trailing ' delimiter (ideally this could be
10001000
# tested above but we don't require the input stream to be consumed in the
10011001
# unit tests there.

0 commit comments

Comments
 (0)