@@ -22,15 +22,13 @@ function _model_macro(mod, name, expr, isconnector)
22
22
ext = Ref {Any} (nothing )
23
23
eqs = Expr[]
24
24
icon = Ref {Union{String, URI}} ()
25
- vs = []
26
- ps = []
27
- kwargs = []
25
+ kwargs, ps, sps, vs, = [], [], [], []
28
26
29
27
for arg in expr. args
30
28
arg isa LineNumberNode && continue
31
29
if arg. head == :macrocall
32
30
parse_model! (exprs. args, comps, ext, eqs, icon, vs, ps,
33
- dict, mod, arg, kwargs)
31
+ sps, dict, mod, arg, kwargs)
34
32
elseif arg. head == :block
35
33
push! (exprs. args, arg)
36
34
elseif isconnector
@@ -213,8 +211,8 @@ function get_var(mod::Module, b)
213
211
end
214
212
end
215
213
216
- function parse_model! (exprs, comps, ext, eqs, icon, vs, ps, dict ,
217
- mod, arg, kwargs)
214
+ function parse_model! (exprs, comps, ext, eqs, icon, vs, ps, sps ,
215
+ dict, mod, arg, kwargs)
218
216
mname = arg. args[1 ]
219
217
body = arg. args[end ]
220
218
if mname == Symbol (" @components" )
@@ -225,6 +223,8 @@ function parse_model!(exprs, comps, ext, eqs, icon, vs, ps, dict,
225
223
parse_variables! (exprs, vs, dict, mod, body, :variables , kwargs)
226
224
elseif mname == Symbol (" @parameters" )
227
225
parse_variables! (exprs, ps, dict, mod, body, :parameters , kwargs)
226
+ elseif mname == Symbol (" @structural_parameters" )
227
+ parse_structural_parameters! (exprs, sps, dict, mod, body, kwargs)
228
228
elseif mname == Symbol (" @equations" )
229
229
parse_equations! (exprs, eqs, dict, body)
230
230
elseif mname == Symbol (" @icon" )
@@ -234,9 +234,28 @@ function parse_model!(exprs, comps, ext, eqs, icon, vs, ps, dict,
234
234
end
235
235
end
236
236
237
+ function parse_structural_parameters! (exprs, sps, dict, mod, body, kwargs)
238
+ Base. remove_linenums! (body)
239
+ for arg in body. args
240
+ MLStyle. @match arg begin
241
+ Expr (:(= ), a, b) => begin
242
+ push! (sps, a)
243
+ push! (kwargs, Expr (:kw , a, b))
244
+ dict[:kwargs ][a] = b
245
+ end
246
+ a => begin
247
+ push! (sps, a)
248
+ push! (kwargs, a)
249
+ dict[:kwargs ][a] = nothing
250
+ end
251
+ end
252
+ end
253
+ end
254
+
237
255
function parse_components! (exprs, cs, dict, body, kwargs)
238
256
expr = Expr (:block )
239
- push! (exprs, expr)
257
+ varexpr = Expr (:block )
258
+ push! (exprs, varexpr)
240
259
comps = Vector{Symbol}[]
241
260
for arg in body. args
242
261
arg isa LineNumberNode && continue
@@ -247,23 +266,25 @@ function parse_components!(exprs, cs, dict, body, kwargs)
247
266
arg = deepcopy (arg)
248
267
b = deepcopy (arg. args[2 ])
249
268
250
- component_args! (a, b, expr, kwargs)
269
+ component_args! (a, b, dict, expr, varexpr , kwargs)
251
270
252
- push! (b. args, Expr (:kw , :name , Meta. quot (a)))
253
271
arg. args[2 ] = b
254
272
push! (expr. args, arg)
255
273
end
256
274
_ => error (" `@components` only takes assignment expressions. Got $arg " )
257
275
end
258
276
end
277
+
278
+ push! (exprs, :(@named $ expr))
279
+
259
280
dict[:components ] = comps
260
281
end
261
282
262
283
function _rename (compname, varname)
263
284
compname = Symbol (compname, :__ , varname)
264
285
end
265
286
266
- function component_args! (a, b, expr, kwargs)
287
+ function component_args! (a, b, dict, expr, varexpr , kwargs)
267
288
# Whenever `b` is a function call, skip the first arg aka the function name.
268
289
# Whenever it is a kwargs list, include it.
269
290
start = b. head == :call ? 2 : 1
@@ -274,15 +295,58 @@ function component_args!(a, b, expr, kwargs)
274
295
x:: Symbol || Expr (:kw , x) => begin
275
296
_v = _rename (a, x)
276
297
b. args[i] = Expr (:kw , x, _v)
298
+ push! (varexpr. args, :((@isdefined $ x) && ($ _v = $ x)))
277
299
push! (kwargs, Expr (:kw , _v, nothing ))
300
+ dict[:kwargs ][_v] = nothing
278
301
end
279
302
Expr (:parameters , x... ) => begin
280
- component_args! (a, arg, expr, kwargs)
303
+ component_args! (a, arg, dict, expr, varexpr , kwargs)
281
304
end
282
305
Expr (:kw , x, y) => begin
283
306
_v = _rename (a, x)
284
307
b. args[i] = Expr (:kw , x, _v)
285
- push! (kwargs, Expr (:kw , _v, y))
308
+ push! (varexpr. args, :($ _v = $ _v === nothing ? $ y : $ _v))
309
+ push! (kwargs, Expr (:kw , _v, nothing ))
310
+ dict[:kwargs ][_v] = nothing
311
+ end
312
+ _ => error (" Could not parse $arg of component $a " )
313
+ end
314
+ end
315
+ end
316
+
317
+ function extend_args! (a, b, dict, expr, kwargs, varexpr, has_param = false )
318
+ # Whenever `b` is a function call, skip the first arg aka the function name.
319
+ # Whenver it is a kwargs list, include it.
320
+ start = b. head == :call ? 2 : 1
321
+ for i in start: lastindex (b. args)
322
+ arg = b. args[i]
323
+ arg isa LineNumberNode && continue
324
+ MLStyle. @match arg begin
325
+ x:: Symbol => begin
326
+ if b. head != :parameters
327
+ if has_param
328
+ popat! (b. args, i)
329
+ push! (b. args[2 ]. args, x)
330
+ else
331
+ b. args[i] = Expr (:parameters , x)
332
+ end
333
+ end
334
+ push! (kwargs, Expr (:kw , x, nothing ))
335
+ dict[:kwargs ][x] = nothing
336
+ end
337
+ Expr (:kw , x) => begin
338
+ push! (kwargs, Expr (:kw , x, nothing ))
339
+ dict[:kwargs ][x] = nothing
340
+ end
341
+ Expr (:kw , x, y) => begin
342
+ b. args[i] = Expr (:kw , x, x)
343
+ push! (varexpr. args, :($ x = $ x === nothing ? $ y : $ x))
344
+ push! (kwargs, Expr (:kw , x, nothing ))
345
+ dict[:kwargs ][x] = nothing
346
+ end
347
+ Expr (:parameters , x... ) => begin
348
+ has_param = true
349
+ extend_args! (a, arg, dict, expr, kwargs, varexpr, has_param)
286
350
end
287
351
_ => error (" Could not parse $arg of component $a " )
288
352
end
291
355
292
356
function parse_extend! (exprs, ext, dict, body, kwargs)
293
357
expr = Expr (:block )
358
+ varexpr = Expr (:block )
359
+ push! (exprs, varexpr)
294
360
push! (exprs, expr)
295
361
body = deepcopy (body)
296
362
MLStyle. @match body begin
@@ -302,13 +368,15 @@ function parse_extend!(exprs, ext, dict, body, kwargs)
302
368
error (" `@extend` destructuring only takes an tuple as LHS. Got $body " )
303
369
end
304
370
a, b = b. args
305
- component_args ! (a, b, expr, kwargs)
371
+ extend_args ! (a, b, dict, expr, kwargs, varexpr )
306
372
vars, a, b
307
373
end
308
374
ext[] = a
309
375
push! (b. args, Expr (:kw , :name , Meta. quot (a)))
310
- dict[:extend ] = [Symbol .(vars. args), a, b. args[1 ]]
311
376
push! (expr. args, :($ a = $ b))
377
+
378
+ dict[:extend ] = [Symbol .(vars. args), a, b. args[1 ]]
379
+
312
380
if vars != = nothing
313
381
push! (expr. args, :(@unpack $ vars = $ a))
314
382
end
0 commit comments