@@ -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