Skip to content

Commit 2b7648c

Browse files
committed
WIP: Switch to using ExprTools
Docs need revision yet
1 parent 1d9e8f6 commit 2b7648c

File tree

4 files changed

+7
-139
lines changed

4 files changed

+7
-139
lines changed

Project.toml

+2
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ version = "0.5.3"
44

55
[deps]
66
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
7+
ExprTools = "e2ba6199-217a-4e67-a87a-7c52f15ade04"
78
Markdown = "d6f4376e-aef5-505a-96c1-9c027394607a"
89
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
910

1011
[compat]
1112
DataStructures = "0.17"
13+
ExprTools = "0.1"
1214
julia = "1"
1315

1416
[extras]

src/MacroTools.jl

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
module MacroTools
22

33
using DataStructures, Markdown, Random
4-
export @match, @capture
4+
using ExprTools: splitdef, combinedef
5+
6+
export @match, @capture, splitdef
57

68
include("match/match.jl")
79
include("match/types.jl")

src/utils.jl

+1-84
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export @esc, isexpr, isline, iscall, rmlines, unblock, block, inexpr, namify, isdef,
2-
longdef, shortdef, @expand, makeif, prettify, splitdef, splitarg
2+
longdef, shortdef, @expand, makeif, prettify, splitarg
33

44
"""
55
assoc!(d, k, v)
@@ -261,89 +261,6 @@ function gatherwheres(ex)
261261
end
262262
end
263263

264-
""" splitdef(fdef)
265-
266-
Match any function definition
267-
268-
```julia
269-
function name{params}(args; kwargs)::rtype where {whereparams}
270-
body
271-
end
272-
```
273-
274-
and return `Dict(:name=>..., :args=>..., etc.)`. The definition can be rebuilt by
275-
calling `MacroTools.combinedef(dict)`, or explicitly with
276-
277-
```
278-
rtype = get(dict, :rtype, :Any)
279-
all_params = [get(dict, :params, [])..., get(dict, :whereparams, [])...]
280-
:(function \$(dict[:name]){\$(all_params...)}(\$(dict[:args]...);
281-
\$(dict[:kwargs]...))::\$rtype
282-
\$(dict[:body])
283-
end)
284-
```
285-
"""
286-
function splitdef(fdef)
287-
error_msg = "Not a function definition: $(repr(fdef))"
288-
@assert(@capture(longdef1(fdef),
289-
function (fcall_ | fcall_) body_ end),
290-
"Not a function definition: $fdef")
291-
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)
300-
if rtype !== nothing; di[:rtype] = rtype end
301-
if whereparams !== nothing; di[:whereparams] = whereparams end
302-
if params !== nothing; di[:params] = params end
303-
di
304-
end
305-
306-
"""
307-
combinedef(dict::Dict)
308-
309-
`combinedef` is the inverse of `splitdef`. It takes a splitdef-like Dict
310-
and returns a function definition. """
311-
function combinedef(dict::Dict)
312-
rtype = get(dict, :rtype, nothing)
313-
params = get(dict, :params, [])
314-
wparams = get(dict, :whereparams, [])
315-
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)
326-
else
327-
@q(function $name_param($(dict[:args]...);
328-
$(dict[:kwargs]...))::$rtype
329-
$(body.args...)
330-
end)
331-
end
332-
else
333-
if rtype==nothing
334-
@q(function $name_param($(dict[:args]...);
335-
$(dict[:kwargs]...)) where {$(wparams...)}
336-
$(body.args...)
337-
end)
338-
else
339-
@q(function $name_param($(dict[:args]...);
340-
$(dict[:kwargs]...))::$rtype where {$(wparams...)}
341-
$(body.args...)
342-
end)
343-
end
344-
end
345-
end
346-
347264
"""
348265
combinearg(arg_name, arg_type, is_splat, default)
349266

test/split.jl

+1-54
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,8 @@
11
using MacroTools: splitstructdef, combinestructdef
22

3-
macro nothing_macro()
4-
end
3+
macro nothing_macro() end
54
@test @expand(@nothing_macro) === nothing
65

7-
macro splitcombine(fundef) # should be a no-op
8-
dict = splitdef(fundef)
9-
esc(MacroTools.combinedef(dict))
10-
end
11-
12-
# Macros for testing that splitcombine doesn't break
13-
# macrocalls in bodies
14-
macro zeroarg()
15-
:(1)
16-
end
17-
macro onearg(x)
18-
:(1+$(esc(x)))
19-
end
20-
21-
let
22-
# Ideally we'd compare the result against :(function f(x)::Int 10 end),
23-
# but it fails because of :line and :block differences
24-
@test longdef(:(f(x)::Int = 10)).head == :function
25-
@test longdef(:(f(x::T) where U where T = 2)).head == :function
26-
@test shortdef(:(function f(x)::Int 10 end)).head != :function
27-
@test map(splitarg, (:(f(a=2, x::Int=nothing, y, args...))).args[2:end]) ==
28-
[(:a, :Any, false, 2), (:x, :Int, false, :nothing),
29-
(:y, :Any, false, nothing), (:args, :Any, true, nothing)]
30-
@test splitarg(:(::Int)) == (nothing, :Int, false, nothing)
31-
32-
@splitcombine foo(x) = x+2
33-
@test foo(10) == 12
34-
@splitcombine add(a, b=2; c=3, d=4)::Float64 = a+b+c+d
35-
@test add(1; d=10) === 16.0
36-
@splitcombine fparam(a::T) where {T} = T
37-
@test fparam([]) == Vector{Any}
38-
struct Orange end
39-
@splitcombine (::Orange)(x) = x+2
40-
@test Orange()(10) == 12
41-
@splitcombine fwhere(a::T) where T = T
42-
@test fwhere(10) == Int
43-
@splitcombine manywhere(x::T, y::Vector{U}) where T <: U where U = (T, U)
44-
@test manywhere(1, Number[2.0]) == (Int, Number)
45-
@splitcombine fmacro0() = @zeroarg
46-
@test fmacro0() == 1
47-
@splitcombine fmacro1() = @onearg 1
48-
@test fmacro1() == 2
49-
50-
struct Foo{A, B}
51-
a::A
52-
b::B
53-
end
54-
# Parametric outer constructor
55-
@splitcombine Foo{A}(a::A) where A = Foo{A, A}(a,a)
56-
@test Foo{Int}(2) == Foo{Int, Int}(2, 2)
57-
end
58-
596
@testset "combinestructdef, splitstructdef" begin
607
ex = :(struct S end)
618
@test ex |> splitstructdef |> combinestructdef |> Base.remove_linenums! ==

0 commit comments

Comments
 (0)