@@ -26,37 +26,49 @@ macro def(name, definition)
2626 end
2727end
2828
29- struct TMP_API
30- base:: Vector{Symbol}
31- public:: Vector{Symbol}
32- develop:: Vector{Symbol}
33- define_public:: Vector{Symbol}
34- define_develop:: Vector{Symbol}
35- define_module:: Vector{Symbol}
36- TMP_API() = new(Symbol[], Symbol[], Symbol[], Symbol[], Symbol[], Symbol[])
29+ const SymSet = Set{Symbol}
30+
31+ abstract type AbstractAPI end
32+
33+ struct TMP_API <: AbstractAPI
34+ mod:: Module
35+ base:: SymSet
36+ public:: SymSet
37+ develop:: SymSet
38+ define_public:: SymSet
39+ define_develop:: SymSet
40+ define_module:: SymSet
41+
42+ TMP_API(mod:: Module ) = new(mod, SymSet(), SymSet(), SymSet(), SymSet(), SymSet(), SymSet())
3743end
3844
3945const SymList = Tuple{Vararg{Symbol}}
4046
41- struct API
47+ struct API <: AbstractAPI
4248 mod:: Module
4349 base:: SymList
4450 public:: SymList
4551 develop:: SymList
4652 define_public:: SymList
4753 define_develop:: SymList
4854 define_module:: SymList
49-
50- API(mod, api:: TMP_API ) =
51- new(mod,
52- SymList(api. base), SymList(api. public), SymList(api. develop),
53- SymList(api. define_public), SymList(api. define_develop), SymList(api. define_module))
5455end
5556
56- const APIList = Tuple{Vararg{API}}
57+ API(api:: TMP_API ) =
58+ API(api. mod, SymList(api. base), SymList(api. public),
59+ SymList(api. develop), SymList(api. define_public),
60+ SymList(api. define_develop), SymList(api. define_module))
5761
58- """ Expression to get current module"""
59- const _cur_mod = V6_COMPAT ? :( current_module() ) : :( @__MODULE__ )
62+ function Base. show(io:: IO , api:: AbstractAPI )
63+ println(io, " APITools.API: " , api. mod)
64+ for fld in (:base, :public, :develop, :define_public, :define_develop, :define_module)
65+ syms = getfield(api, fld)
66+ isempty(syms) || println(fld, " : " , syms)
67+ end
68+ end
69+
70+ """ Get current module"""
71+ cur_mod() = ccall(:jl_get_current_module, Ref{Module}, ())
6072
6173"""
6274@api <cmd> [<symbols>...]
@@ -79,44 +91,42 @@ const _cur_mod = V6_COMPAT ? :( current_module() ) : :( @__MODULE__ )
7991 * @api define_module <names...> # Add submodule names that are part of the API
8092"""
8193macro api(cmd:: Symbol )
82- cmd == :init && return _api_init()
83- cmd == :freeze && return esc(_api_freeze())
84- cmd == :list && return _api_list()
94+ mod = @static V6_COMPAT ? current_module() : __module__
95+ #=
96+ @static if V6_COMPAT
97+ println("api($mod, $cmd)")
98+ else
99+ println("api($__source__, $mod, $cmd)")
100+ end
101+ =#
102+ cmd == :list ? _api_list(mod) :
103+ cmd == :init ? _api_init(mod) :
104+ cmd == :freeze ? _api_freeze(mod) :
85105 error(" @api unrecognized command: $cmd " )
86106end
87107
88- function _api_display(api, chain )
108+ function _api_display(api:: AbstractAPI )
89109 show(api)
90110 println()
91- show(chain)
92- println()
93111end
94112
95- function _api_display(mod)
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__))
113+ function _api_list(mod:: Module )
114+ isdefined(mod, :__api__) && _api_display(eval(mod, :__api__))
115+ isdefined(mod, :__tmp_api__) && _api_display(eval(mod, :__tmp_api__))
100116 nothing
101117end
102118
103- _api_freeze(mod, api, chain) = APIList(push!(chain, API(mod, api)))
104-
105- _api_init() =
106- quote
107- export @api, APITools
108- global __tmp_api__ = APITools. TMP_API()
109- global __tmp_chain__ = APITools. API[]
110- end
111-
112- _api_freeze() =
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
119+ function _api_init(mod:: Module )
120+ ex = :( export @api, APITools ; global __tmp_api__ = APITools. TMP_API($ mod) )
121+ isdefined(mod, :__tmp_api__) || eval(mod, ex)
122+ nothing
123+ end
118124
119- _api_list(mod = _cur_mod) = :( APITools. _api_display($ mod) )
125+ function _api_freeze(mod:: Module )
126+ ex = :( global const __api__ = APITools. API(__tmp_api__) ; __tmp_api__ = nothing )
127+ isdefined(mod, :__tmp_api__) && eval(mod, :( __tmp_api__ != = nothing ) ) && eval(mod, ex)
128+ nothing
129+ end
120130
121131const _cmduse = (:use, :test, :extend, :export)
122132const _cmdadd =
@@ -125,102 +135,96 @@ const _cmdadd =
125135@static V6_COMPAT && (const _ff = findfirst)
126136@static V6_COMPAT || (_ff(lst, val) = coalesce(findfirst(isequal(val), lst), 0 ))
127137
128- function _add_def!(deflst, implst, explst , sym)
138+ function _add_def!(curmod , sym)
129139 if isdefined(Base, sym)
130- push!(implst, sym)
140+ eval(curmod, :(push!(__tmp_api__. base, $ (QuoteNode(sym)))))
141+ eval(curmod, :(import Base.$ sym ))
131142 else
132- push!(deflst, sym)
133- push!(explst, esc( :(function $ sym end ) ))
143+ eval(curmod, :( push!(__tmp_api__ . public, $ (QuoteNode( sym)))) )
144+ eval(curmod, :(function $ sym end ))
134145 end
135146end
136147
137148""" Add symbols"""
138- 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[]
149+ function _add_symbols(curmod, grp, exprs)
150+ # print("_add_symbols($curmod, $grp, $exprs)", isdefined(curmod, :__tmp_api__))
151+ _api_init(curmod)
143152 if grp == :maybe_public
144- implst = Symbol[]
145- deflst = Symbol[]
146153 for ex in exprs
147154 if isa(ex, Expr) && ex. head == :tuple
148155 for sym in ex. args
149156 isa(sym, Symbol) || error(" @api $grp : $sym not a Symbol" )
150- _add_def!(deflst, implst, outlst , sym)
157+ _add_def!(curmod , sym)
151158 end
152159 elseif isa(ex, Symbol)
153- _add_def!(deflst, implst, outlst , ex)
160+ _add_def!(curmod , ex)
154161 else
155162 error(" @api $grp : syntax error $ex " )
156163 end
157164 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
165- symbols = Symbol[]
166- for ex in exprs
167- if isa(ex, Expr) && ex. head == :tuple
168- append!(symbols, ex. args)
169- elseif isa(ex, Symbol)
170- push!(symbols, ex)
171- else
172- error(" @api $grp : syntax error $ex " )
165+ else
166+ symbols = SymSet()
167+ for ex in exprs
168+ if isa(ex, Expr) && ex. head == :tuple
169+ push!(symbols, ex. args... )
170+ elseif isa(ex, Symbol)
171+ push!(symbols, ex)
172+ else
173+ error(" @api $grp : syntax error $ex " )
174+ end
175+ end
176+ # println("symbols: ", symbols)
177+ if grp == :base
178+ for sym in symbols
179+ eval(curmod, :( import Base.$ sym ))
180+ end
181+ end
182+ for sym in symbols
183+ eval(curmod, :( push!(__tmp_api__.$ grp, $ (QuoteNode(sym)) )))
173184 end
174185 end
175- println(" symbols: " , symbols)
176- if grp == :base
177- syms = SymList(symbols)
178- expr = " APITools._make_list($(QuoteNode(:import)) , $(QuoteNode(:Base)) , $syms )"
179- push!(outlst, esc(:(eval($ _cur_mod, $ (Meta. parse(expr))))))
180- end
181- push!(outlst, Expr(:call, :push!,
182- Expr(:., :__tmp_api__, QuoteNode(grp)), QuoteNode.(symbols). .. ))
183- println(outlst)
184- outlst
186+ nothing
185187end
186188
187- function _make_modules(cmd, exprs)
188- uselst = Expr[]
189- modlst = Symbol[]
189+ function _make_modules(curmod, cmd, exprs)
190+ modlst = SymSet()
190191 for ex in exprs
191192 if isa(ex, Expr) && ex. head == :tuple
192- append !(modlst, ex. args)
193- for sym in ex. args ; push!(uselst , :(import $ sym)) ; end
193+ push !(modlst, ex. args... )
194+ for sym in ex. args ; eval(curmod , :(import $ sym)) ; end
194195 elseif isa(ex, Symbol)
195196 push!(modlst, ex)
196- push!(uselst , :(import $ ex))
197+ eval(curmod , :(import $ ex))
197198 else
198199 error(" @api $cmd : syntax error $ex " )
199200 end
200201 end
201- uselst, modlst
202+ modlst
202203end
203204
204- function _api(cmd, exprs)
205+ function _api(curmod:: Module , cmd:: Symbol , exprs)
206+ # println("api($curmod, $cmd, $exprs)")
205207 ind = _ff(_cmdadd, cmd)
206- ind == 0 || return esc(Expr(:toplevel, _add_symbols( cmd, exprs), nothing ) )
208+ ind == 0 || return _add_symbols(curmod, cmd, exprs)
207209
208210 ind = _ff(_cmduse, cmd)
209211
210- lst, modules = _make_modules(cmd, exprs)
212+ modules = _make_modules(curmod, cmd, exprs)
211213
212214 cmd == :export &&
213- return esc(Expr(:toplevel, lst ... ,
214- [:(eval($ _cur_mod, Expr( :export, $ mod. __api__.$ grp... )))
215+ return esc(Expr(:toplevel,
216+ [:(eval(Expr( :export, $ mod. __api__.$ grp... )))
215217 for mod in modules, grp in (:define_module, :define_public, :public)]. .. ,
216218 nothing ))
217219 cmd == :list &&
218220 return Expr(:toplevel,
219- [:(eval($ _cur_mod, APITools. _api_display($ mod))) for mod in modules]. .. ,
221+ [:(eval(APITools. _api_display($ mod))) for mod in modules]. .. ,
220222 nothing )
221223
224+ lst = Expr[]
222225 for mod in modules
223- push!(lst, _make_module_exprs(mod))
226+ exp = " APITools._make_module_list($(QuoteNode(mod)) , $mod .__api__.define_module)"
227+ push!(lst, :(eval($ (Meta. parse(exp)))))
224228 end
225229
226230 if cmd == :use
@@ -230,11 +234,6 @@ function _api(cmd, exprs)
230234 push!(lst, V6_COMPAT ? :(using Base. Test) : :(using Test))
231235 elseif cmd == :extend
232236 grplst = (:define_public, :define_develop)
233- # should add unique modules to __tmp_chain__
234- for mod in modules
235- push!(lst,
236- esc(:(in($ mod. __api__, __tmp_chain__) || push!(__tmp_chain__, $ mod. __api__))))
237- end
238237 for mod in modules, grp in (:base, :public, :develop)
239238 push!(lst, _make_exprs(:import, mod, grp))
240239 end
@@ -247,19 +246,18 @@ function _api(cmd, exprs)
247246 esc(Expr(:toplevel, lst... , nothing ))
248247end
249248
250- macro api(cmd:: Symbol , exprs... ) ; _api(cmd, exprs) ; end
251-
252- # We need Expr(:toplevel, (Expr($cmd, $mod, $sym) for sym in $mod.__api__.$grp)...)
249+ @static if V6_COMPAT
250+ macro api(cmd:: Symbol , exprs... ) ; _api(current_module(), cmd, exprs) ; end
251+ else
252+ macro api(cmd:: Symbol , exprs... ) ; _api(__module__, cmd, exprs) ; end
253+ end
253254
254255function _make_module_list(mod, lst)
255256 isempty(lst) && return nothing
256257 length(lst) == 1 ? :(import $ mod.$ (lst[1 ])) :
257258 Expr(:toplevel, [:(import $ mod.$ nam) for nam in lst]. .. , nothing )
258259end
259260
260- _make_module_exprs(mod) =
261- :(eval($ _cur_mod, $ (Meta. parse(" APITools._make_module_list($(QuoteNode(mod)) , $mod .__api__.define_module)" ))))
262-
263261function _make_list(cmd, mod, lst)
264262 isempty(lst) && return nothing
265263 @static if VERSION < v" 0.7.0-DEV"
272270
273271function _make_exprs(cmd, mod, grp)
274272 from = QuoteNode(grp == :base ? :Base : mod)
275- :(eval($ _cur_mod,
276- $ (Meta. parse(" APITools._make_list($(QuoteNode(cmd)) , $from , $mod .__api__.$grp )" ))))
273+ :(eval($ (Meta. parse(" APITools._make_list($(QuoteNode(cmd)) , $from , $mod .__api__.$grp )" ))))
277274end
278275
279276end # module APITools
0 commit comments