Skip to content

Commit cf29215

Browse files
authored
support splat in the array syntax (#40)
- fixes #38
1 parent 4c495e6 commit cf29215

File tree

3 files changed

+109
-43
lines changed

3 files changed

+109
-43
lines changed

src/desugaring.jl

Lines changed: 46 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Lowering Pass 2 - syntax desugaring
1+
# Lowering Pass 2 - syntax desugaring
22

33
struct DesugaringContext{GraphType} <: AbstractLoweringContext
44
graph::GraphType
@@ -74,7 +74,7 @@ end
7474

7575
function check_no_parameters(ex::SyntaxTree, msg)
7676
i = find_parameters_ind(children(ex))
77-
if i > 0
77+
if i > 0
7878
throw(LoweringError(ex[i], msg))
7979
end
8080
end
@@ -523,7 +523,7 @@ function expand_compare_chain(ctx, ex)
523523
end
524524

525525
#-------------------------------------------------------------------------------
526-
# Expansion of array indexing
526+
# Expansion of array indexing
527527
function _arg_to_temp(ctx, stmts, ex, eq_is_kw=false)
528528
k = kind(ex)
529529
if is_effect_free(ex)
@@ -939,6 +939,29 @@ function expand_comprehension_to_loops(ctx, ex)
939939
]
940940
end
941941

942+
function expand_splat(ctx, ex, topfunc, args)
943+
return @ast ctx ex [K"call"
944+
"_apply_iterate"::K"core"
945+
"iterate"::K"top"
946+
topfunc
947+
expand_forms_2(ctx, _wrap_unsplatted_args(ctx, ex, args))...
948+
]
949+
end
950+
951+
function expand_array(ctx, ex, topfunc)
952+
args = children(ex)
953+
check_no_assignment(args)
954+
topfunc = @ast ctx ex topfunc::K"top"
955+
if any(kind(arg) == K"..." for arg in args)
956+
expand_splat(ctx, ex, topfunc, args)
957+
else
958+
@ast ctx ex [K"call"
959+
topfunc
960+
expand_forms_2(ctx, args)...
961+
]
962+
end
963+
end
964+
942965
#-------------------------------------------------------------------------------
943966
# Expansion of array concatenation notation `[a b ; c d]` etc
944967

@@ -1735,10 +1758,10 @@ function expand_ccall(ctx, ex)
17351758
if is_core_Any(raw_argt)
17361759
push!(unsafe_args, exarg)
17371760
else
1738-
cconverted_arg = emit_assign_tmp(sctx,
1761+
cconverted_arg = emit_assign_tmp(sctx,
17391762
@ast ctx argt [K"call"
17401763
"cconvert"::K"top"
1741-
argt
1764+
argt
17421765
exarg
17431766
]
17441767
)
@@ -1856,12 +1879,7 @@ function expand_call(ctx, ex)
18561879
end
18571880
if any(kind(arg) == K"..." for arg in args)
18581881
# Splatting, eg, `f(a, xs..., b)`
1859-
@ast ctx ex [K"call"
1860-
"_apply_iterate"::K"core"
1861-
"iterate"::K"top"
1862-
expand_forms_2(ctx, farg)
1863-
expand_forms_2(ctx, _wrap_unsplatted_args(ctx, ex, args))...
1864-
]
1882+
expand_splat(ctx, ex, expand_forms_2(ctx, farg), args)
18651883
elseif kind(farg) == K"Identifier" && farg.name_val == "include"
18661884
# world age special case
18671885
r = ssavar(ctx, ex)
@@ -1905,7 +1923,7 @@ function expand_dot(ctx, ex)
19051923
throw(LoweringError(rhs, "Unrecognized field access syntax"))
19061924
end
19071925
@ast ctx ex [K"call"
1908-
"getproperty"::K"top"
1926+
"getproperty"::K"top"
19091927
ex[1]
19101928
rhs
19111929
]
@@ -3092,7 +3110,7 @@ function expand_function_def(ctx, ex, docs, rewrite_call=identity, rewrite_body=
30923110
]
30933111
]
30943112
]
3095-
[K"removable"
3113+
[K"removable"
30963114
isnothing(bare_func_name) ? "nothing"::K"core" : bare_func_name
30973115
]
30983116
]
@@ -3131,7 +3149,7 @@ end
31313149

31323150
function expand_arrow(ctx, ex)
31333151
@chk numchildren(ex) == 2
3134-
expand_forms_2(ctx,
3152+
expand_forms_2(ctx,
31353153
@ast ctx ex [K"function"
31363154
expand_arrow_arglist(ctx, ex[1], string(kind(ex)))
31373155
ex[2]
@@ -3515,7 +3533,7 @@ function default_inner_constructors(ctx, srcref, global_struct_name,
35153533
[K"curly"
35163534
"Type"::K"core"
35173535
[K"curly"
3518-
global_struct_name
3536+
global_struct_name
35193537
typevar_names...
35203538
]
35213539
]
@@ -3570,7 +3588,7 @@ function default_outer_constructor(ctx, srcref, global_struct_name,
35703588
typevar_names, typevar_stmts, field_names, field_types)
35713589
@ast ctx srcref [K"function"
35723590
[K"where"
3573-
[K"call"
3591+
[K"call"
35743592
# We use `::Type{$global_struct_name}` here rather than just
35753593
# `struct_name` because global_struct_name is a binding to a
35763594
# type - we know we're not creating a new `Function` and
@@ -4189,7 +4207,7 @@ function expand_module(ctx, ex::SyntaxTree)
41894207
"x" ::K"Identifier"
41904208
]
41914209
[K"call"
4192-
"eval" ::K"core"
4210+
"eval" ::K"core"
41934211
modname ::K"Identifier"
41944212
"x" ::K"Identifier"
41954213
]
@@ -4216,11 +4234,11 @@ function expand_module(ctx, ex::SyntaxTree)
42164234
"x" ::K"Identifier"
42174235
]
42184236
[K"call"
4219-
"_call_latest" ::K"core"
4220-
"include" ::K"top"
4221-
"mapexpr" ::K"Identifier"
4222-
modname ::K"Identifier"
4223-
"x" ::K"Identifier"
4237+
"_call_latest" ::K"core"
4238+
"include" ::K"top"
4239+
"mapexpr" ::K"Identifier"
4240+
modname ::K"Identifier"
4241+
"x" ::K"Identifier"
42244242
]
42254243
]
42264244
]
@@ -4254,7 +4272,7 @@ end
42544272

42554273
"""
42564274
Lowering pass 2 - desugaring
4257-
4275+
42584276
This pass simplifies expressions by expanding complicated syntax sugar into a
42594277
small set of core syntactic forms. For example, field access syntax `a.b` is
42604278
expanded to a function call `getproperty(a, :b)`.
@@ -4377,7 +4395,7 @@ function expand_forms_2(ctx::DesugaringContext, ex::SyntaxTree, docs=nothing)
43774395
if numchildren(ex) == 1 && kind(ex[1]) == K"String"
43784396
ex[1]
43794397
else
4380-
@ast ctx ex [K"call"
4398+
@ast ctx ex [K"call"
43814399
"string"::K"top"
43824400
expand_forms_2(ctx, children(ex))...
43834401
]
@@ -4393,7 +4411,7 @@ function expand_forms_2(ctx::DesugaringContext, ex::SyntaxTree, docs=nothing)
43934411
elseif any_assignment(children(ex))
43944412
expand_forms_2(ctx, expand_named_tuple(ctx, ex, children(ex)))
43954413
else
4396-
expand_forms_2(ctx, @ast ctx ex [K"call"
4414+
expand_forms_2(ctx, @ast ctx ex [K"call"
43974415
"tuple"::K"core"
43984416
children(ex)...
43994417
])
@@ -4438,23 +4456,11 @@ function expand_forms_2(ctx::DesugaringContext, ex::SyntaxTree, docs=nothing)
44384456
]
44394457
elseif k == K"vect"
44404458
check_no_parameters(ex, "unexpected semicolon in array expression")
4441-
check_no_assignment(children(ex))
4442-
@ast ctx ex [K"call"
4443-
"vect"::K"top"
4444-
expand_forms_2(ctx, children(ex))...
4445-
]
4459+
expand_array(ctx, ex, "vect")
44464460
elseif k == K"hcat"
4447-
check_no_assignment(children(ex))
4448-
@ast ctx ex [K"call"
4449-
"hcat"::K"top"
4450-
expand_forms_2(ctx, children(ex))...
4451-
]
4461+
expand_array(ctx, ex, "hcat")
44524462
elseif k == K"typed_hcat"
4453-
check_no_assignment(children(ex))
4454-
@ast ctx ex [K"call"
4455-
"typed_hcat"::K"top"
4456-
expand_forms_2(ctx, children(ex))...
4457-
]
4463+
expand_array(ctx, ex, "typed_hcat")
44584464
elseif k == K"opaque_closure"
44594465
expand_forms_2(ctx, expand_opaque_closure(ctx, ex))
44604466
elseif k == K"vcat" || k == K"typed_vcat"
@@ -4513,4 +4519,3 @@ function expand_forms_2(ctx::MacroExpansionContext, ex::SyntaxTree)
45134519
ex1 = expand_forms_2(ctx1, reparent(ctx1, ex))
45144520
ctx1, ex1
45154521
end
4516-

test/arrays.jl

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using Test, JuliaLowering
2+
13
@testset "Array syntax" begin
24

35
test_mod = Module()
@@ -23,6 +25,22 @@ end
2325
Int[1.0 2.0 3.0]
2426
""") [1 2 3]
2527

28+
# splat with vect/hcat/typed_hcat
29+
@test JuliaLowering.include_string(test_mod, """
30+
let xs = [1,2,3]
31+
[0, xs...]
32+
end
33+
""") [0,1,2,3]
34+
@test JuliaLowering.include_string(test_mod, """
35+
let xs = [1,2,3]
36+
[0 xs...]
37+
end
38+
""") [0 1 2 3]
39+
@test JuliaLowering.include_string(test_mod, """
40+
let xs = [1,2,3]
41+
Int[0 xs...]
42+
end
43+
""") Int[0 1 2 3]
2644

2745
# vcat
2846
@test JuliaLowering.include_string(test_mod, """
@@ -127,4 +145,4 @@ let
127145
end
128146
""") == (3, 7, 2, 5)
129147

130-
end
148+
end # @testset "Array syntax" begin

test/arrays_ir.jl

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,29 @@
55
1 (call top.vect 10 20 30)
66
2 (return %₁)
77

8+
########################################
9+
# vect with splat
10+
[x, xs...]
11+
#---------------------
12+
1 TestMod.x
13+
2 (call core.tuple %₁)
14+
3 TestMod.xs
15+
4 (call core._apply_iterate top.iterate top.vect %%₃)
16+
5 (return %₄)
17+
18+
########################################
19+
# vect with splats
20+
[x, xs..., y, ys...]
21+
#---------------------
22+
1 TestMod.x
23+
2 (call core.tuple %₁)
24+
3 TestMod.xs
25+
4 TestMod.y
26+
5 (call core.tuple %₄)
27+
6 TestMod.ys
28+
7 (call core._apply_iterate top.iterate top.vect %%%%₆)
29+
8 (return %₇)
30+
831
########################################
932
# Error: vect syntax with parameters
1033
[10, 20; 30]
@@ -28,6 +51,16 @@ LoweringError:
2851
1 (call top.hcat 10 20 30)
2952
2 (return %₁)
3053

54+
########################################
55+
# hcat with splat
56+
[x xs...]
57+
#---------------------
58+
1 TestMod.x
59+
2 (call core.tuple %₁)
60+
3 TestMod.xs
61+
4 (call core._apply_iterate top.iterate top.hcat %%₃)
62+
5 (return %₄)
63+
3164
########################################
3265
# typed hcat syntax
3366
T[10 20 30]
@@ -36,6 +69,17 @@ T[10 20 30]
3669
2 (call top.typed_hcat %10 20 30)
3770
3 (return %₂)
3871

72+
########################################
73+
# typed hcat syntax with splat
74+
T[x xs...]
75+
#---------------------
76+
1 TestMod.T
77+
2 TestMod.x
78+
3 (call core.tuple %%₂)
79+
4 TestMod.xs
80+
5 (call core._apply_iterate top.iterate top.typed_hcat %%₄)
81+
6 (return %₅)
82+
3983
########################################
4084
# Error: hcat syntax with embedded assignments
4185
[10 20 a=40]
@@ -452,4 +496,3 @@ a[] = rhs
452496
2 TestMod.a
453497
3 (call top.setindex! %%₁)
454498
4 (return %₁)
455-

0 commit comments

Comments
 (0)