@@ -22,15 +22,13 @@ function _model_macro(mod, name, expr, isconnector)
2222 ext = Ref {Any} (nothing )
2323 eqs = Expr[]
2424 icon = Ref {Union{String, URI}} ()
25- vs = []
26- ps = []
27- kwargs = []
25+ kwargs, ps, sps, vs, = [], [], [], []
2826
2927 for arg in expr. args
3028 arg isa LineNumberNode && continue
3129 if arg. head == :macrocall
3230 parse_model! (exprs. args, comps, ext, eqs, icon, vs, ps,
33- dict, mod, arg, kwargs)
31+ sps, dict, mod, arg, kwargs)
3432 elseif arg. head == :block
3533 push! (exprs. args, arg)
3634 elseif isconnector
@@ -213,8 +211,8 @@ function get_var(mod::Module, b)
213211 end
214212end
215213
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)
218216 mname = arg. args[1 ]
219217 body = arg. args[end ]
220218 if mname == Symbol (" @components" )
@@ -225,6 +223,8 @@ function parse_model!(exprs, comps, ext, eqs, icon, vs, ps, dict,
225223 parse_variables! (exprs, vs, dict, mod, body, :variables , kwargs)
226224 elseif mname == Symbol (" @parameters" )
227225 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)
228228 elseif mname == Symbol (" @equations" )
229229 parse_equations! (exprs, eqs, dict, body)
230230 elseif mname == Symbol (" @icon" )
@@ -234,9 +234,28 @@ function parse_model!(exprs, comps, ext, eqs, icon, vs, ps, dict,
234234 end
235235end
236236
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+
237255function parse_components! (exprs, cs, dict, body, kwargs)
238256 expr = Expr (:block )
239- push! (exprs, expr)
257+ varexpr = Expr (:block )
258+ push! (exprs, varexpr)
240259 comps = Vector{Symbol}[]
241260 for arg in body. args
242261 arg isa LineNumberNode && continue
@@ -247,23 +266,25 @@ function parse_components!(exprs, cs, dict, body, kwargs)
247266 arg = deepcopy (arg)
248267 b = deepcopy (arg. args[2 ])
249268
250- component_args! (a, b, expr, kwargs)
269+ component_args! (a, b, dict, expr, varexpr , kwargs)
251270
252- push! (b. args, Expr (:kw , :name , Meta. quot (a)))
253271 arg. args[2 ] = b
254272 push! (expr. args, arg)
255273 end
256274 _ => error (" `@components` only takes assignment expressions. Got $arg " )
257275 end
258276 end
277+
278+ push! (exprs, :(@named $ expr))
279+
259280 dict[:components ] = comps
260281end
261282
262283function _rename (compname, varname)
263284 compname = Symbol (compname, :__ , varname)
264285end
265286
266- function component_args! (a, b, expr, kwargs)
287+ function component_args! (a, b, dict, expr, varexpr , kwargs)
267288 # Whenever `b` is a function call, skip the first arg aka the function name.
268289 # Whenever it is a kwargs list, include it.
269290 start = b. head == :call ? 2 : 1
@@ -274,15 +295,58 @@ function component_args!(a, b, expr, kwargs)
274295 x:: Symbol || Expr (:kw , x) => begin
275296 _v = _rename (a, x)
276297 b. args[i] = Expr (:kw , x, _v)
298+ push! (varexpr. args, :((@isdefined $ x) && ($ _v = $ x)))
277299 push! (kwargs, Expr (:kw , _v, nothing ))
300+ dict[:kwargs ][_v] = nothing
278301 end
279302 Expr (:parameters , x... ) => begin
280- component_args! (a, arg, expr, kwargs)
303+ component_args! (a, arg, dict, expr, varexpr , kwargs)
281304 end
282305 Expr (:kw , x, y) => begin
283306 _v = _rename (a, x)
284307 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)
286350 end
287351 _ => error (" Could not parse $arg of component $a " )
288352 end
291355
292356function parse_extend! (exprs, ext, dict, body, kwargs)
293357 expr = Expr (:block )
358+ varexpr = Expr (:block )
359+ push! (exprs, varexpr)
294360 push! (exprs, expr)
295361 body = deepcopy (body)
296362 MLStyle. @match body begin
@@ -302,13 +368,15 @@ function parse_extend!(exprs, ext, dict, body, kwargs)
302368 error (" `@extend` destructuring only takes an tuple as LHS. Got $body " )
303369 end
304370 a, b = b. args
305- component_args ! (a, b, expr, kwargs)
371+ extend_args ! (a, b, dict, expr, kwargs, varexpr )
306372 vars, a, b
307373 end
308374 ext[] = a
309375 push! (b. args, Expr (:kw , :name , Meta. quot (a)))
310- dict[:extend ] = [Symbol .(vars. args), a, b. args[1 ]]
311376 push! (expr. args, :($ a = $ b))
377+
378+ dict[:extend ] = [Symbol .(vars. args), a, b. args[1 ]]
379+
312380 if vars != = nothing
313381 push! (expr. args, :(@unpack $ vars = $ a))
314382 end
0 commit comments