@@ -10,6 +10,8 @@ Licensed under MIT License, see LICENSE.md
1010"""
1111module APITools
1212
13+ const debug = Ref (false )
14+
1315const V6_COMPAT = VERSION < v " 0.7.0-DEV"
1416const BIG_ENDIAN = (ENDIAN_BOM == 0x01020304 )
1517
@@ -35,9 +37,9 @@ struct TMP_API <: AbstractAPI
3537 base:: SymSet
3638 public:: SymSet
3739 develop:: SymSet
38- define_public :: SymSet
39- define_develop :: SymSet
40- define_module :: SymSet
40+ public! :: SymSet
41+ develop! :: SymSet
42+ modules :: SymSet
4143
4244 TMP_API (mod:: Module ) = new (mod, SymSet (), SymSet (), SymSet (), SymSet (), SymSet (), SymSet ())
4345end
@@ -49,19 +51,18 @@ struct API <: AbstractAPI
4951 base:: SymList
5052 public:: SymList
5153 develop:: SymList
52- define_public :: SymList
53- define_develop :: SymList
54- define_module :: SymList
54+ public! :: SymList
55+ develop! :: SymList
56+ modules :: SymList
5557end
5658
5759API (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))
60+ API (api. mod, SymList (api. base), SymList (api. public), SymList (api. develop),
61+ SymList (api. public!), SymList (api. develop!), SymList (api. modules))
6162
6263function Base. show (io:: IO , api:: AbstractAPI )
6364 println (io, " APITools.API: " , api. mod)
64- for fld in (:base , :public , :develop , :define_public , :define_develop , :define_module )
65+ for fld in (:base , :public , :develop , :public! , :develop! , :modules )
6566 syms = getfield (api, fld)
6667 isempty (syms) || println (fld, " : " , syms)
6768 end
@@ -77,22 +78,21 @@ cur_mod() = ccall(:jl_get_current_module, Ref{Module}, ())
7778
7879 * @api list <modules>... # list API(s) of given modules (or current if none given)
7980
80- * @api use <modules>... # use for normal use
81- * @api test <modules>... # using api and dev , for testing purposes
81+ * @api use <modules>... # use, without importing (i.e. can't extend)
82+ * @api test <modules>... # using public and develop APIs , for testing purposes
8283 * @api extend <modules>... # for development, imports api & dev, use api & dev definitions
83- * @api export <modules>... # export api symbols
84+ * @api export <modules>... # export public definitions
8485
8586 * @api base <names...> # Add functions from Base that are part of the API
87+ * @api public! <names...> # Add other symbols that are part of the public API (structs, consts)
88+ * @api develop! <names...> # Add other symbols that are part of the development API
8689 * @api public <names...> # Add functions that are part of the public API
8790 * @api develop <names...> # Add functions that are part of the development API
88- * @api define_public <names...> # Add other symbols that are part of the public API (structs, consts)
89- * @api define_develop <names...> # Add other symbols that are part of the development API
90- * @api define_module <names...> # Add submodule names that are part of the API
91+ * @api modules <names...> # Add submodule names that are part of the API
9192"""
9293macro api (cmd:: Symbol )
9394 mod = @static V6_COMPAT ? current_module () : __module__
9495 cmd == :list ? _api_list (mod) :
95- cmd == :init ? _api_init (mod) :
9696 cmd == :freeze ? _api_freeze (mod) :
9797 error (" @api unrecognized command: $cmd " )
9898end
@@ -108,12 +108,6 @@ function _api_list(mod::Module)
108108 nothing
109109end
110110
111- function _api_init (mod:: Module )
112- ex = :( export @api , APITools ; global __tmp_api__ = APITools. TMP_API ($ mod) )
113- isdefined (mod, :__tmp_api__ ) || eval (mod, ex)
114- nothing
115- end
116-
117111function _api_freeze (mod:: Module )
118112 ex = :( global const __api__ = APITools. API (__tmp_api__) ; __tmp_api__ = nothing )
119113 isdefined (mod, :__tmp_api__ ) && eval (mod, :( __tmp_api__ != = nothing ) ) && eval (mod, ex)
@@ -122,36 +116,46 @@ end
122116
123117const _cmduse = (:use , :test , :extend , :export , :list )
124118const _cmdadd =
125- (:define_module , :define_public , :define_develop , :public , :develop , :base , :maybe_public )
119+ (:modules , :public , :develop , :public! , :develop! , :base , :base! )
126120
127121@static V6_COMPAT && (const _ff = findfirst)
128122@static V6_COMPAT || (_ff (lst, val) = coalesce (findfirst (isequal (val), lst), 0 ))
129123
130- function _add_def! (curmod, sym)
124+ function _add_def! (curmod, grp, exp)
125+ debug[] && print (" _add_def!($curmod , $grp , $exp ::$(typeof (exp)) " )
126+ if isa (exp, Symbol)
127+ sym = exp
128+ elseif isa (exp, AbstractString)
129+ sym = Symbol (exp)
130+ else
131+ error (" @api $grp : syntax error $exp " )
132+ end
131133 if isdefined (Base, sym)
132- eval (curmod, :(push! (__tmp_api__. base, $ (QuoteNode (sym)))))
133134 eval (curmod, :(import Base.$ sym ))
135+ eval (curmod, :(push! (__tmp_api__. base, $ (QuoteNode (sym)))))
134136 else
135- eval (curmod, :(push! (__tmp_api__. public, $ (QuoteNode (sym)))))
136137 eval (curmod, :(function $ sym end ))
138+ eval (curmod, :(push! (__tmp_api__. public!, $ (QuoteNode (sym)))))
137139 end
138140end
139141
140142""" Add symbols"""
141143function _add_symbols (curmod, grp, exprs)
142- # print("_add_symbols($curmod, $grp, $exprs)", isdefined(curmod, :__tmp_api__))
143- _api_init (curmod)
144- if grp == :maybe_public
144+ if debug[]
145+ print (" _add_symbols($curmod , $grp , $exprs )" )
146+ isdefined (curmod, :__tmp_api__ ) && print (" => " , eval (curmod, :__tmp_api__ ))
147+ println ()
148+ end
149+ ex = :( export @api , APITools ; global __tmp_api__ = APITools. TMP_API ($ curmod) )
150+ isdefined (curmod, :__tmp_api__ ) || eval (curmod, ex)
151+ if grp == :base!
145152 for ex in exprs
146153 if isa (ex, Expr) && ex. head == :tuple
147154 for sym in ex. args
148- isa (sym, Symbol) || error (" @api $grp : $sym not a Symbol" )
149- _add_def! (curmod, sym)
155+ _add_def! (curmod, grp, sym)
150156 end
151- elseif isa (ex, Symbol)
152- _add_def! (curmod, ex)
153157 else
154- error ( " @api $ grp: syntax error $ex " )
158+ _add_def! (curmod, grp, ex )
155159 end
156160 end
157161 else
@@ -161,6 +165,8 @@ function _add_symbols(curmod, grp, exprs)
161165 push! (symbols, ex. args... )
162166 elseif isa (ex, Symbol)
163167 push! (symbols, ex)
168+ elseif isa (ex, AbstractString)
169+ push! (symbols, Symbol (ex))
164170 else
165171 error (" @api $grp : syntax error $ex " )
166172 end
@@ -174,15 +180,61 @@ function _add_symbols(curmod, grp, exprs)
174180 eval (curmod, :( push! (__tmp_api__.$ grp, $ (QuoteNode (sym)) )))
175181 end
176182 end
183+ debug[] && println (" after add symbols: " , eval (curmod, :__tmp_api__ ))
184+ nothing
185+ end
186+
187+ function _api_extend (curmod, modules)
188+ imp = :import
189+ use = :using
190+
191+ for nam in modules
192+ mod = eval (curmod, nam)
193+ if isdefined (mod, :__api__ )
194+ api = eval (mod, :__api__ )
195+ _do_list (curmod, imp, api, :Base , :base )
196+ _do_list (curmod, imp, api, nam, :public! )
197+ _do_list (curmod, imp, api, nam, :develop! )
198+ _do_list (curmod, use, api, nam, :public )
199+ _do_list (curmod, use, api, nam, :develop )
200+ else
201+ println (" API not found for module: $mod " )
202+ end
203+ end
204+
205+ nothing
206+ end
207+
208+ function _api_use (curmod, modules)
209+ for nam in modules
210+ mod = eval (curmod, nam)
211+ if isdefined (mod, :__api__ )
212+ api = eval (mod, :__api__ )
213+ _do_list (curmod, :using , api, nam, :public )
214+ _do_list (curmod, :using , api, nam, :public! )
215+ end
216+ end
177217 nothing
178218end
179219
220+ _api_export (curmod, modules) =
221+ esc (Expr (:toplevel ,
222+ [:(eval (Expr ( :export , $ mod. __api__.$ grp... )))
223+ for mod in modules, grp in (:modules , :public , :public! )]. .. ,
224+ nothing ))
225+
226+ _api_list (curmod, modules) =
227+ Expr (:toplevel ,
228+ [:(eval (APITools. _api_display ($ mod))) for mod in modules]. .. ,
229+ nothing )
230+
180231function _api (curmod:: Module , cmd:: Symbol , exprs)
181232 ind = _ff (_cmdadd, cmd)
182233 ind == 0 || return _add_symbols (curmod, cmd, exprs)
183234
184235 _ff (_cmduse, cmd) == 0 && error (" Syntax error: @api $cmd $exprs " )
185236
237+ debug[] && print (" _api($curmod , $cmd , $exprs )" )
186238 modules = SymSet ()
187239 for ex in exprs
188240 if isa (ex, Expr) && ex. head == :tuple
@@ -195,61 +247,22 @@ function _api(curmod::Module, cmd::Symbol, exprs)
195247 error (" @api $cmd : syntax error $ex " )
196248 end
197249 end
250+ debug[] && println (" => $modules " )
198251
199- cmd == :export &&
200- return esc (Expr (:toplevel ,
201- [:(eval (Expr ( :export , $ mod. __api__.$ grp... )))
202- for mod in modules, grp in (:define_module , :define_public , :public )]. .. ,
203- nothing ))
204- cmd == :list &&
205- return Expr (:toplevel ,
206- [:(eval (APITools. _api_display ($ mod))) for mod in modules]. .. ,
207- nothing )
252+ cmd == :export && return _api_export (curmod, modules)
253+ cmd == :list && return _api_list (curmod, modules)
208254
209255 for nam in modules
210256 mod = eval (curmod, nam)
211- for sym in getfield (eval (mod, :__api__ ), :define_module )
257+ for sym in getfield (eval (mod, :__api__ ), :modules )
212258 eval (curmod, :(using $ nam.$ sym))
213259 end
214260 end
215261
216- imp = :import
217- use = :using
218-
219- if cmd == :extend
220- for nam in modules
221- mod = eval (curmod, nam)
222- if isdefined (mod, :__api__ )
223- api = eval (mod, :__api__ )
224- _do_list (curmod, imp, api, :Base , :base )
225- _do_list (curmod, imp, api, nam, :public )
226- _do_list (curmod, imp, api, nam, :develop )
227- _do_list (curmod, use, api, nam, :define_public )
228- _do_list (curmod, use, api, nam, :define_develop )
229- else
230- println (" API not found for module: $mod " )
231- end
232- end
233- return nothing
234- end
235-
236262 # Be nice and set up standard Test
237263 cmd == :test && eval (curmod, V6_COMPAT ? :(using Base. Test) : :(using Test))
238264
239- for nam in modules
240- mod = eval (curmod, nam)
241- if isdefined (mod, :__api__ )
242- api = eval (mod, :__api__ )
243- _do_list (curmod, use, api, nam, :public )
244- _do_list (curmod, use, api, nam, :define_public )
245- if cmd == :test
246- _do_list (curmod, use, api, nam, :public )
247- _do_list (curmod, use, api, nam, :define_public )
248- end
249- end
250- end
251-
252- nothing
265+ cmd == :use ? _api_use (curmod, modules) : _api_extend (curmod, modules)
253266end
254267
255268@static V6_COMPAT || (_dot_name (nam) = Expr (:., nam))
@@ -258,16 +271,18 @@ function _do_list(curmod, cmd, api, mod, grp)
258271 lst = getfield (api, grp)
259272 isempty (lst) && return
260273 @static if V6_COMPAT
261- length (lst) == 1 && return eval (curmod, Expr (cmd, mod, lst[1 ]))
262274 for nam in lst
263- eval (curmod, Expr (cmd, mod, nam))
275+ exp = Expr (cmd, mod, nam)
276+ debug[] && println (" V6: $cmd , $mod , $mod , $exp " )
277+ eval (curmod, exp)
264278 end
265279 else
266280 exp = Expr (cmd, Expr (:(:), _dot_name (mod), _dot_name .(lst)... ))
267- println (exp)
281+ debug[] && println (" V7: $cmd , $mod , $mod , $ exp" )
268282 try
269283 eval (curmod, exp)
270284 catch ex
285+ println (" APITools: Error evaluating $exp " )
271286 dump (exp)
272287 println (sprint (showerror, ex, catch_backtrace ()))
273288 end
0 commit comments