Skip to content

Commit 75535ac

Browse files
authored
Merge pull request #140 from tkf/anonymous-splitdef
Support anonymous function in splitdef/combinedef
2 parents 0cf0f7c + 8c003bc commit 75535ac

File tree

2 files changed

+84
-32
lines changed

2 files changed

+84
-32
lines changed

src/utils.jl

+70-32
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ isshortdef(ex) = (@capture(ex, (fcall_ = body_)) &&
226226

227227
function longdef1(ex)
228228
if @capture(ex, (arg_ -> body_))
229-
@q function ($arg,) $(body.args...) end
229+
Expr(:function, arg isa Symbol ? :($arg,) : arg, body)
230230
elseif isshortdef(ex)
231231
@assert @capture(ex, (fcall_ = body_))
232232
Expr(:function, fcall, body)
@@ -289,14 +289,31 @@ function splitdef(fdef)
289289
function (fcall_ | fcall_) body_ end),
290290
"Not a function definition: $fdef")
291291
fcall_nowhere, whereparams = gatherwheres(fcall)
292-
@assert(@capture(fcall_nowhere, ((func_(args__; kwargs__)) |
293-
(func_(args__; kwargs__)::rtype_) |
294-
(func_(args__)) |
295-
(func_(args__)::rtype_))),
296-
error_msg)
297-
@assert(@capture(func, (fname_{params__} | fname_)), error_msg)
298-
di = Dict(:name=>fname, :args=>args,
299-
:kwargs=>(kwargs===nothing ? [] : kwargs), :body=>body)
292+
func = args = kwargs = rtype = nothing
293+
if @capture(fcall_nowhere, ((func_(args__; kwargs__)) |
294+
(func_(args__; kwargs__)::rtype_) |
295+
(func_(args__)) |
296+
(func_(args__)::rtype_)))
297+
elseif isexpr(fcall_nowhere, :tuple)
298+
if length(fcall_nowhere.args) > 1 && isexpr(fcall_nowhere.args[1], :parameters)
299+
args = fcall_nowhere.args[2:end]
300+
kwargs = fcall_nowhere.args[1].args
301+
else
302+
args = fcall_nowhere.args
303+
end
304+
elseif isexpr(fcall_nowhere, :(::))
305+
args = Any[fcall_nowhere]
306+
else
307+
throw(ArgumentError(error_msg))
308+
end
309+
if func !== nothing
310+
@assert(@capture(func, (fname_{params__} | fname_)), error_msg)
311+
di = Dict(:name=>fname, :args=>args,
312+
:kwargs=>(kwargs===nothing ? [] : kwargs), :body=>body)
313+
else
314+
params = nothing
315+
di = Dict(:args=>args, :kwargs=>(kwargs===nothing ? [] : kwargs), :body=>body)
316+
end
300317
if rtype !== nothing; di[:rtype] = rtype end
301318
if whereparams !== nothing; di[:whereparams] = whereparams end
302319
if params !== nothing; di[:params] = params end
@@ -313,33 +330,54 @@ function combinedef(dict::Dict)
313330
params = get(dict, :params, [])
314331
wparams = get(dict, :whereparams, [])
315332
body = block(dict[:body])
316-
name = dict[:name]
317-
name_param = isempty(params) ? name : :($name{$(params...)})
318-
# We need the `if` to handle parametric inner/outer constructors like
319-
# SomeType{X}(x::X) where X = SomeType{X}(x, x+2)
320-
if isempty(wparams)
321-
if rtype==nothing
322-
@q(function $name_param($(dict[:args]...);
323-
$(dict[:kwargs]...))
324-
$(body.args...)
325-
end)
333+
if haskey(dict, :name)
334+
name = dict[:name]
335+
name_param = isempty(params) ? name : :($name{$(params...)})
336+
# We need the `if` to handle parametric inner/outer constructors like
337+
# SomeType{X}(x::X) where X = SomeType{X}(x, x+2)
338+
if isempty(wparams)
339+
if rtype==nothing
340+
@q(function $name_param($(dict[:args]...);
341+
$(dict[:kwargs]...))
342+
$(body.args...)
343+
end)
344+
else
345+
@q(function $name_param($(dict[:args]...);
346+
$(dict[:kwargs]...))::$rtype
347+
$(body.args...)
348+
end)
349+
end
326350
else
327-
@q(function $name_param($(dict[:args]...);
328-
$(dict[:kwargs]...))::$rtype
329-
$(body.args...)
330-
end)
351+
if rtype==nothing
352+
@q(function $name_param($(dict[:args]...);
353+
$(dict[:kwargs]...)) where {$(wparams...)}
354+
$(body.args...)
355+
end)
356+
else
357+
@q(function $name_param($(dict[:args]...);
358+
$(dict[:kwargs]...))::$rtype where {$(wparams...)}
359+
$(body.args...)
360+
end)
361+
end
331362
end
332363
else
333-
if rtype==nothing
334-
@q(function $name_param($(dict[:args]...);
335-
$(dict[:kwargs]...)) where {$(wparams...)}
336-
$(body.args...)
337-
end)
364+
if isempty(dict[:kwargs])
365+
arg = :($(dict[:args]...),)
366+
else
367+
arg = Expr(:tuple, Expr(:parameters, dict[:kwargs]...), dict[:args]...)
368+
end
369+
if isempty(wparams)
370+
if rtype==nothing
371+
@q($arg -> $body)
372+
else
373+
@q(($arg::$rtype) -> $body)
374+
end
338375
else
339-
@q(function $name_param($(dict[:args]...);
340-
$(dict[:kwargs]...))::$rtype where {$(wparams...)}
341-
$(body.args...)
342-
end)
376+
if rtype==nothing
377+
@q(($arg where {$(wparams...)}) -> $body)
378+
else
379+
@q(($arg::$rtype where {$(wparams...)}) -> $body)
380+
end
343381
end
344382
end
345383
end

test/split.jl

+14
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,20 @@ let
5454
# Parametric outer constructor
5555
@splitcombine Foo{A}(a::A) where A = Foo{A, A}(a,a)
5656
@test Foo{Int}(2) == Foo{Int, Int}(2, 2)
57+
58+
@test (@splitcombine x -> x + 2)(10) === 12
59+
@test (@splitcombine (a, b=2; c=3, d=4) -> a+b+c+d)(1; d=10) === 16
60+
@test (@splitcombine ((a, b)::Tuple{Int,Int} -> a + b))((1, 2)) == 3
61+
@test (@splitcombine ((a::T) where {T}) -> T)([]) === Vector{Any}
62+
@test (@splitcombine ((x::T, y::Vector{U}) where T <: U where U) -> (T, U))(1, Number[2.0]) ==
63+
(Int, Number)
64+
@test (@splitcombine () -> @zeroarg)() == 1
65+
@test (@splitcombine () -> @onearg 1)() == 2
66+
@test (@splitcombine function (x) x + 2 end)(10) === 12
67+
@test (@splitcombine function (a::T) where {T} T end)([]) === Vector{Any}
68+
@test (@splitcombine function (x::T, y::Vector{U}) where T <: U where U
69+
(T, U)
70+
end)(1, Number[2.0]) == (Int, Number)
5771
end
5872

5973
@testset "combinestructdef, splitstructdef" begin

0 commit comments

Comments
 (0)