Skip to content

Commit cb8d7ec

Browse files
committed
Always use 2-argument eval
1 parent 53ca7b4 commit cb8d7ec

File tree

3 files changed

+98
-55
lines changed

3 files changed

+98
-55
lines changed

src/APITools.jl

Lines changed: 80 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -80,23 +80,28 @@ const _cur_mod = V6_COMPAT ? :( current_module() ) : :( @__MODULE__ )
8080
"""
8181
macro api(cmd::Symbol)
8282
cmd == :init && return _api_init()
83-
cmd == :freeze && return _api_freeze()
83+
cmd == :freeze && return esc(_api_freeze())
8484
cmd == :list && return _api_list()
8585
error("@api unrecognized command: $cmd")
8686
end
8787

88+
function _api_display(api, chain)
89+
show(api)
90+
println()
91+
show(chain)
92+
println()
93+
end
94+
8895
function _api_display(mod)
89-
if isdefined(mod, :__api__)
90-
show(eval(mod, :__api__))
91-
show(eval(mod, :__chain__))
92-
end
93-
if isdefined(mod, :__tmp_api__)
94-
show(eval(mod, :__tmp_api__))
95-
show(eval(mod, :__tmp_chain__))
96-
end
96+
isdefined(mod, :__api__) &&
97+
_api_display(eval(mod, :__api__), eval(mod, :__chain__))
98+
isdefined(mod, :__tmp_api__) &&
99+
_api_display(eval(mod, :__tmp_api__), eval(mod, :__tmp_chain__))
97100
nothing
98101
end
99102

103+
_api_freeze(mod, api, chain) = APIList(push!(chain, API(mod, api)))
104+
100105
_api_init() =
101106
quote
102107
export @api, APITools
@@ -105,14 +110,13 @@ _api_init() =
105110
end
106111

107112
_api_freeze() =
108-
esc(quote
109-
const __api__ = APITools.API($_cur_mod, __tmp_api__)
110-
push!(__tmp_chain__, __api__)
111-
const __chain__ = APITools.APIList(__tmp_chain__)
112-
__tmp_chain__ = _tmp_api__ = nothing
113-
end)
113+
quote
114+
global const __chain__ = APITools._api_freeze($_cur_mod, __tmp_api__, __tmp_chain__)
115+
global const __api__ = __chain__[end]
116+
__tmp_chain__ = __tmp_api__ = nothing
117+
end
114118

115-
_api_list(mod = _cur_mod) = :( _api_display($mod) )
119+
_api_list(mod = _cur_mod) = :( APITools._api_display($mod) )
116120

117121
const _cmduse = (:use, :test, :extend, :export)
118122
const _cmdadd =
@@ -121,30 +125,43 @@ const _cmdadd =
121125
@static V6_COMPAT && (const _ff = findfirst)
122126
@static V6_COMPAT || (_ff(lst, val) = coalesce(findfirst(isequal(val), lst), 0))
123127

124-
_add_def!(deflst, explst, sym) = (push!(deflst, sym); push!(explst, esc(:(function $sym end))))
125-
126-
"""Conditionally define functions, or import from Base"""
127-
function _maybe_public(exprs)
128-
implst = Symbol[]
129-
deflst = Symbol[]
130-
explst = isdefined(eval(_cur_mod), :__tmp_api__) ? Expr[] : Expr[_api_init()]
131-
for ex in exprs
132-
if isa(ex, Expr) && ex.head == :tuple
133-
for sym in ex.args
134-
isa(sym, Symbol) || error("@api $grp: $sym not a Symbol")
135-
isdefined(Base, sym) ? push!(implst, sym) : _add_def!(deflst, explst, sym)
136-
end
137-
elseif isa(ex, Symbol)
138-
isdefined(Base, ex) ? push!(implst, ex) : _add_def!(deflst, explst, ex)
139-
else
140-
error("@api $grp: syntax error $ex")
141-
end
128+
function _add_def!(deflst, implst, explst, sym)
129+
if isdefined(Base, sym)
130+
push!(implst, sym)
131+
else
132+
push!(deflst, sym)
133+
push!(explst, esc(:(function $sym end)))
142134
end
143-
isempty(deflst) || push!(explst, esc(:( append!(__tmp_api__.public, $deflst))))
144-
Expr(:toplevel, _add_symbols(:base, implst)..., explst...)
145135
end
146136

137+
"""Add symbols"""
147138
function _add_symbols(grp, exprs)
139+
print("_add_symbols($grp, $exprs)")
140+
outlst = Expr[:(isdefined($_cur_mod, :__tmp_api__) || APITools._api_init())]
141+
println(" => ", outlst)
142+
outlst = Expr[]
143+
if grp == :maybe_public
144+
implst = Symbol[]
145+
deflst = Symbol[]
146+
for ex in exprs
147+
if isa(ex, Expr) && ex.head == :tuple
148+
for sym in ex.args
149+
isa(sym, Symbol) || error("@api $grp: $sym not a Symbol")
150+
_add_def!(deflst, implst, outlst, sym)
151+
end
152+
elseif isa(ex, Symbol)
153+
_add_def!(deflst, implst, outlst, ex)
154+
else
155+
error("@api $grp: syntax error $ex")
156+
end
157+
end
158+
isempty(deflst) ||
159+
push!(outlst, Expr(:call, :push!,
160+
Expr(:., :__tmp_api__, QuoteNode(:public)),
161+
QuoteNode.(deflst)...))
162+
exprs = implst
163+
grp = :base
164+
end
148165
symbols = Symbol[]
149166
for ex in exprs
150167
if isa(ex, Expr) && ex.head == :tuple
@@ -155,46 +172,52 @@ function _add_symbols(grp, exprs)
155172
error("@api $grp: syntax error $ex")
156173
end
157174
end
158-
lst = isdefined(eval(_cur_mod), :__tmp_api__) ? Expr[] : Expr[_api_init()]
175+
println("symbols: ", symbols)
159176
if grp == :base
160177
syms = SymList(symbols)
161178
expr = "APITools._make_list($(QuoteNode(:import)), $(QuoteNode(:Base)), $syms)"
162-
push!(lst, :(eval($_cur_mod, $(Meta.parse(expr)))))
179+
push!(outlst, esc(:(eval($_cur_mod, $(Meta.parse(expr))))))
163180
end
164-
Expr(:toplevel, lst..., esc(:( append!(__tmp_api__.$grp, $symbols) )))
181+
push!(outlst, Expr(:call, :push!,
182+
Expr(:., :__tmp_api__, QuoteNode(grp)), QuoteNode.(symbols)...))
183+
println(outlst)
184+
outlst
165185
end
166186

167-
function _make_modules(exprs)
187+
function _make_modules(cmd, exprs)
168188
uselst = Expr[]
169189
modlst = Symbol[]
170190
for ex in exprs
171191
if isa(ex, Expr) && ex.head == :tuple
172192
append!(modlst, ex.args)
173-
for sym in ex.args ; push!(uselst, :(using $sym)) ; end
193+
for sym in ex.args ; push!(uselst, :(import $sym)) ; end
174194
elseif isa(ex, Symbol)
175195
push!(modlst, ex)
176-
push!(uselst, :(using $ex))
196+
push!(uselst, :(import $ex))
177197
else
178198
error("@api $cmd: syntax error $ex")
179199
end
180200
end
181201
uselst, modlst
182202
end
183203

184-
macro api(cmd::Symbol, exprs...)
204+
function _api(cmd, exprs)
185205
ind = _ff(_cmdadd, cmd)
186-
ind == 0 || return cmd == :maybe_public ? _maybe_public(exprs) : _add_symbols(cmd, exprs)
206+
ind == 0 || return esc(Expr(:toplevel, _add_symbols(cmd, exprs), nothing))
187207

188208
ind = _ff(_cmduse, cmd)
189209

190-
lst, modules = _make_modules(exprs)
210+
lst, modules = _make_modules(cmd, exprs)
191211

192212
cmd == :export &&
193213
return esc(Expr(:toplevel, lst...,
194-
[:(eval(Expr( :export, $mod.__api__.$grp... )))
195-
for mod in modules, grp in (:define_module, :define_public, :public)]...))
214+
[:(eval($_cur_mod, Expr( :export, $mod.__api__.$grp... )))
215+
for mod in modules, grp in (:define_module, :define_public, :public)]...,
216+
nothing))
196217
cmd == :list &&
197-
return Expr(:toplevel, [:(eval(Expr(:call, :_api_display, $mod))) for mod in modules]...)
218+
return Expr(:toplevel,
219+
[:(eval($_cur_mod, APITools._api_display($mod))) for mod in modules]...,
220+
nothing)
198221

199222
for mod in modules
200223
push!(lst, _make_module_exprs(mod))
@@ -209,7 +232,8 @@ macro api(cmd::Symbol, exprs...)
209232
grplst = (:define_public, :define_develop)
210233
# should add unique modules to __tmp_chain__
211234
for mod in modules
212-
push!(lst, :(in($mod.__api__, __tmp_chain__) || push!(__tmp_chain__, $mod.__api__)))
235+
push!(lst,
236+
esc(:(in($mod.__api__, __tmp_chain__) || push!(__tmp_chain__, $mod.__api__))))
213237
end
214238
for mod in modules, grp in (:base, :public, :develop)
215239
push!(lst, _make_exprs(:import, mod, grp))
@@ -220,19 +244,21 @@ macro api(cmd::Symbol, exprs...)
220244
for mod in modules, grp in grplst
221245
push!(lst, _make_exprs(:using, mod, grp))
222246
end
223-
esc(Expr(:toplevel, lst...))
247+
esc(Expr(:toplevel, lst..., nothing))
224248
end
225249

250+
macro api(cmd::Symbol, exprs...) ; _api(cmd, exprs) ; end
251+
226252
# We need Expr(:toplevel, (Expr($cmd, $mod, $sym) for sym in $mod.__api__.$grp)...)
227253

228254
function _make_module_list(mod, lst)
229255
isempty(lst) && return nothing
230256
length(lst) == 1 ? :(import $mod.$(lst[1])) :
231-
Expr(:toplevel, [:(import $mod.$nam) for nam in lst]...)
257+
Expr(:toplevel, [:(import $mod.$nam) for nam in lst]..., nothing)
232258
end
233259

234260
_make_module_exprs(mod) =
235-
:(eval($(Meta.parse("APITools._make_module_list($(QuoteNode(mod)), $mod.__api__.define_module)"))))
261+
:(eval($_cur_mod, $(Meta.parse("APITools._make_module_list($(QuoteNode(mod)), $mod.__api__.define_module)"))))
236262

237263
function _make_list(cmd, mod, lst)
238264
isempty(lst) && return nothing
@@ -246,7 +272,8 @@ end
246272

247273
function _make_exprs(cmd, mod, grp)
248274
from = QuoteNode(grp == :base ? :Base : mod)
249-
:(eval($(Meta.parse("APITools._make_list($(QuoteNode(cmd)), $from, $mod.__api__.$grp)"))))
275+
:(eval($_cur_mod,
276+
$(Meta.parse("APITools._make_list($(QuoteNode(cmd)), $from, $mod.__api__.$grp)"))))
250277
end
251278

252279
end # module APITools

test/APITest.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
module APITest
22
using APITools
3+
34
@api init
5+
46
@api base nextind, getindex, setindex!
7+
8+
println(__tmp_api__)
9+
510
@api public myfunc
611
@api define_public Foo
712

@@ -11,5 +16,10 @@ function myfunc end
1116
myfunc(::Integer) = 1
1217
myfunc(::String) = 2
1318

19+
#println(__tmp_api__)
20+
21+
#println(macroexpand( :( @api freeze ) ))
22+
1423
@api freeze
24+
1525
end # module APITest

test/runtests.jl

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
using APITools
55

6-
@static VERSION < v"0.7.0-DEV" ? (using Base.Test) : (using Test)
6+
@static V6_COMPAT ? (using Base.Test) : (using Test)
77

88
@def testcase begin
99
myname = "Scott Paul Jones"
@@ -19,7 +19,13 @@ push!(LOAD_PATH, @__DIR__)
1919

2020
@api init
2121

22-
@api extend APITest
22+
import APITest: myfunc
23+
24+
macroexpand( :( @api extend APITest ) )
25+
26+
@api list
27+
28+
@api list APITest
2329

2430
myfunc(::AbstractFloat) = 3
2531

0 commit comments

Comments
 (0)