@@ -10,6 +10,8 @@ Licensed under MIT License, see LICENSE.md
10
10
"""
11
11
module APITools
12
12
13
+ const debug = Ref (false )
14
+
13
15
const V6_COMPAT = VERSION < v " 0.7.0-DEV"
14
16
const BIG_ENDIAN = (ENDIAN_BOM == 0x01020304 )
15
17
@@ -35,9 +37,9 @@ struct TMP_API <: AbstractAPI
35
37
base:: SymSet
36
38
public:: SymSet
37
39
develop:: SymSet
38
- define_public :: SymSet
39
- define_develop :: SymSet
40
- define_module :: SymSet
40
+ public! :: SymSet
41
+ develop! :: SymSet
42
+ modules :: SymSet
41
43
42
44
TMP_API (mod:: Module ) = new (mod, SymSet (), SymSet (), SymSet (), SymSet (), SymSet (), SymSet ())
43
45
end
@@ -49,19 +51,18 @@ struct API <: AbstractAPI
49
51
base:: SymList
50
52
public:: SymList
51
53
develop:: SymList
52
- define_public :: SymList
53
- define_develop :: SymList
54
- define_module :: SymList
54
+ public! :: SymList
55
+ develop! :: SymList
56
+ modules :: SymList
55
57
end
56
58
57
59
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))
60
+ API (api. mod, SymList (api. base), SymList (api. public), SymList (api. develop),
61
+ SymList (api. public!), SymList (api. develop!), SymList (api. modules))
61
62
62
63
function Base. show (io:: IO , api:: AbstractAPI )
63
64
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 )
65
66
syms = getfield (api, fld)
66
67
isempty (syms) || println (fld, " : " , syms)
67
68
end
@@ -77,22 +78,21 @@ cur_mod() = ccall(:jl_get_current_module, Ref{Module}, ())
77
78
78
79
* @api list <modules>... # list API(s) of given modules (or current if none given)
79
80
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
82
83
* @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
84
85
85
86
* @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
86
89
* @api public <names...> # Add functions that are part of the public API
87
90
* @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
91
92
"""
92
93
macro api (cmd:: Symbol )
93
94
mod = @static V6_COMPAT ? current_module () : __module__
94
95
cmd == :list ? _api_list (mod) :
95
- cmd == :init ? _api_init (mod) :
96
96
cmd == :freeze ? _api_freeze (mod) :
97
97
error (" @api unrecognized command: $cmd " )
98
98
end
@@ -108,12 +108,6 @@ function _api_list(mod::Module)
108
108
nothing
109
109
end
110
110
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
-
117
111
function _api_freeze (mod:: Module )
118
112
ex = :( global const __api__ = APITools. API (__tmp_api__) ; __tmp_api__ = nothing )
119
113
isdefined (mod, :__tmp_api__ ) && eval (mod, :( __tmp_api__ != = nothing ) ) && eval (mod, ex)
@@ -122,36 +116,46 @@ end
122
116
123
117
const _cmduse = (:use , :test , :extend , :export , :list )
124
118
const _cmdadd =
125
- (:define_module , :define_public , :define_develop , :public , :develop , :base , :maybe_public )
119
+ (:modules , :public , :develop , :public! , :develop! , :base , :base! )
126
120
127
121
@static V6_COMPAT && (const _ff = findfirst)
128
122
@static V6_COMPAT || (_ff (lst, val) = coalesce (findfirst (isequal (val), lst), 0 ))
129
123
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
131
133
if isdefined (Base, sym)
132
- eval (curmod, :(push! (__tmp_api__. base, $ (QuoteNode (sym)))))
133
134
eval (curmod, :(import Base.$ sym ))
135
+ eval (curmod, :(push! (__tmp_api__. base, $ (QuoteNode (sym)))))
134
136
else
135
- eval (curmod, :(push! (__tmp_api__. public, $ (QuoteNode (sym)))))
136
137
eval (curmod, :(function $ sym end ))
138
+ eval (curmod, :(push! (__tmp_api__. public!, $ (QuoteNode (sym)))))
137
139
end
138
140
end
139
141
140
142
""" Add symbols"""
141
143
function _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!
145
152
for ex in exprs
146
153
if isa (ex, Expr) && ex. head == :tuple
147
154
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)
150
156
end
151
- elseif isa (ex, Symbol)
152
- _add_def! (curmod, ex)
153
157
else
154
- error ( " @api $ grp: syntax error $ex " )
158
+ _add_def! (curmod, grp, ex )
155
159
end
156
160
end
157
161
else
@@ -161,6 +165,8 @@ function _add_symbols(curmod, grp, exprs)
161
165
push! (symbols, ex. args... )
162
166
elseif isa (ex, Symbol)
163
167
push! (symbols, ex)
168
+ elseif isa (ex, AbstractString)
169
+ push! (symbols, Symbol (ex))
164
170
else
165
171
error (" @api $grp : syntax error $ex " )
166
172
end
@@ -174,15 +180,61 @@ function _add_symbols(curmod, grp, exprs)
174
180
eval (curmod, :( push! (__tmp_api__.$ grp, $ (QuoteNode (sym)) )))
175
181
end
176
182
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
177
217
nothing
178
218
end
179
219
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
+
180
231
function _api (curmod:: Module , cmd:: Symbol , exprs)
181
232
ind = _ff (_cmdadd, cmd)
182
233
ind == 0 || return _add_symbols (curmod, cmd, exprs)
183
234
184
235
_ff (_cmduse, cmd) == 0 && error (" Syntax error: @api $cmd $exprs " )
185
236
237
+ debug[] && print (" _api($curmod , $cmd , $exprs )" )
186
238
modules = SymSet ()
187
239
for ex in exprs
188
240
if isa (ex, Expr) && ex. head == :tuple
@@ -195,61 +247,22 @@ function _api(curmod::Module, cmd::Symbol, exprs)
195
247
error (" @api $cmd : syntax error $ex " )
196
248
end
197
249
end
250
+ debug[] && println (" => $modules " )
198
251
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)
208
254
209
255
for nam in modules
210
256
mod = eval (curmod, nam)
211
- for sym in getfield (eval (mod, :__api__ ), :define_module )
257
+ for sym in getfield (eval (mod, :__api__ ), :modules )
212
258
eval (curmod, :(using $ nam.$ sym))
213
259
end
214
260
end
215
261
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
-
236
262
# Be nice and set up standard Test
237
263
cmd == :test && eval (curmod, V6_COMPAT ? :(using Base. Test) : :(using Test))
238
264
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)
253
266
end
254
267
255
268
@static V6_COMPAT || (_dot_name (nam) = Expr (:., nam))
@@ -258,16 +271,18 @@ function _do_list(curmod, cmd, api, mod, grp)
258
271
lst = getfield (api, grp)
259
272
isempty (lst) && return
260
273
@static if V6_COMPAT
261
- length (lst) == 1 && return eval (curmod, Expr (cmd, mod, lst[1 ]))
262
274
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)
264
278
end
265
279
else
266
280
exp = Expr (cmd, Expr (:(:), _dot_name (mod), _dot_name .(lst)... ))
267
- println (exp)
281
+ debug[] && println (" V7: $cmd , $mod , $mod , $ exp" )
268
282
try
269
283
eval (curmod, exp)
270
284
catch ex
285
+ println (" APITools: Error evaluating $exp " )
271
286
dump (exp)
272
287
println (sprint (showerror, ex, catch_backtrace ()))
273
288
end
0 commit comments