Skip to content

Commit bc0033a

Browse files
authored
Merge pull request #2246 from ven-k/vkb/boost-connector
Add support for parameters, equations... for `@connector`s
2 parents 74fb734 + 820684b commit bc0033a

File tree

2 files changed

+80
-78
lines changed

2 files changed

+80
-78
lines changed

src/systems/model_parsing.jl

Lines changed: 41 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -6,58 +6,64 @@ end
66
(m::Model)(args...; kw...) = m.f(args...; kw...)
77

88
for f in (:connector, :mtkmodel)
9+
isconnector = f == :connector ? true : false
910
@eval begin
1011
macro $f(name::Symbol, body)
11-
esc($(Symbol(f, :_macro))(__module__, name, body))
12+
esc($(:_model_macro)(__module__, name, body, $isconnector))
1213
end
1314
end
1415
end
1516

16-
@inline is_kwarg(::Symbol) = false
17-
@inline is_kwarg(e::Expr) = (e.head == :parameters)
18-
19-
function connector_macro(mod, name, body)
20-
if !Meta.isexpr(body, :block)
21-
err = """
22-
connector body must be a block! It should be in the form of
23-
```
24-
@connector Pin begin
25-
v(t) = 1
26-
(i(t) = 1), [connect = Flow]
27-
end
28-
```
29-
"""
30-
error(err)
31-
end
32-
vs = []
33-
kwargs = []
34-
icon = Ref{Union{String, URI}}()
17+
function _model_macro(mod, name, expr, isconnector)
18+
exprs = Expr(:block)
3519
dict = Dict{Symbol, Any}()
3620
dict[:kwargs] = Dict{Symbol, Any}()
37-
expr = Expr(:block)
38-
for arg in body.args
21+
comps = Symbol[]
22+
ext = Ref{Any}(nothing)
23+
eqs = Expr[]
24+
icon = Ref{Union{String, URI}}()
25+
vs = []
26+
ps = []
27+
kwargs = []
28+
29+
for arg in expr.args
3930
arg isa LineNumberNode && continue
40-
if arg.head == :macrocall && arg.args[1] == Symbol("@icon")
41-
parse_icon!(icon, dict, dict, arg.args[end])
42-
continue
31+
if arg.head == :macrocall
32+
parse_model!(exprs.args, comps, ext, eqs, icon, vs, ps,
33+
dict, mod, arg, kwargs)
34+
elseif arg.head == :block
35+
push!(exprs.args, arg)
36+
elseif isconnector
37+
# Connectors can have variables listed without `@variables` prefix or
38+
# begin block.
39+
parse_variable_arg!(exprs, vs, dict, mod, arg, :variables, kwargs)
40+
else
41+
error("$arg is not valid syntax. Expected a macro call.")
4342
end
44-
parse_variable_arg!(expr, vs, dict, mod, arg, :variables, kwargs)
4543
end
44+
4645
iv = get(dict, :independent_variable, nothing)
4746
if iv === nothing
48-
error("$name doesn't have a independent variable")
47+
iv = dict[:independent_variable] = variable(:t)
4948
end
50-
gui_metadata = isassigned(icon) ? GUIMetadata(GlobalRef(mod, name), icon[]) :
49+
50+
gui_metadata = isassigned(icon) > 0 ? GUIMetadata(GlobalRef(mod, name), icon[]) :
5151
GUIMetadata(GlobalRef(mod, name))
5252

53-
quote
54-
$name = $Model((; name, $(kwargs...)) -> begin
55-
$expr
56-
var"#___sys___" = $ODESystem($(Equation[]), $iv, [$(vs...)], $([]);
57-
name, gui_metadata = $gui_metadata)
58-
$Setfield.@set!(var"#___sys___".connector_type=$connector_type(var"#___sys___"))
59-
end, $dict, true)
53+
sys = :($ODESystem($Equation[$(eqs...)], $iv, [$(vs...)], [$(ps...)];
54+
name, systems = [$(comps...)], gui_metadata = $gui_metadata))
55+
56+
if ext[] === nothing
57+
push!(exprs.args, :(var"#___sys___" = $sys))
58+
else
59+
push!(exprs.args, :(var"#___sys___" = $extend($sys, $(ext[]))))
6060
end
61+
62+
isconnector && push!(exprs.args,
63+
:($Setfield.@set!(var"#___sys___".connector_type=$connector_type(var"#___sys___"))))
64+
65+
f = :($(Symbol(:__, name, :__))(; name, $(kwargs...)) = $exprs)
66+
:($name = $Model($f, $dict, $isconnector))
6167
end
6268

6369
function parse_variable_def!(dict, mod, arg, varclass, kwargs, def = nothing)
@@ -207,48 +213,6 @@ function get_var(mod::Module, b)
207213
end
208214
end
209215

210-
function mtkmodel_macro(mod, name, expr)
211-
exprs = Expr(:block)
212-
dict = Dict{Symbol, Any}()
213-
dict[:kwargs] = Dict{Symbol, Any}()
214-
comps = Symbol[]
215-
ext = Ref{Any}(nothing)
216-
eqs = Expr[]
217-
icon = Ref{Union{String, URI}}()
218-
vs = []
219-
ps = []
220-
kwargs = []
221-
222-
for arg in expr.args
223-
arg isa LineNumberNode && continue
224-
if arg.head == :macrocall
225-
parse_model!(exprs.args, comps, ext, eqs, icon, vs, ps,
226-
dict, mod, arg, kwargs)
227-
elseif arg.head == :block
228-
push!(exprs.args, arg)
229-
else
230-
error("$arg is not valid syntax. Expected a macro call.")
231-
end
232-
end
233-
iv = get(dict, :independent_variable, nothing)
234-
if iv === nothing
235-
iv = dict[:independent_variable] = variable(:t)
236-
end
237-
238-
gui_metadata = isassigned(icon) > 0 ? GUIMetadata(GlobalRef(mod, name), icon[]) :
239-
GUIMetadata(GlobalRef(mod, name))
240-
241-
sys = :($ODESystem($Equation[$(eqs...)], $iv, [$(vs...)], [$(ps...)];
242-
systems = [$(comps...)], name, gui_metadata = $gui_metadata)) #, defaults = $defaults))
243-
if ext[] === nothing
244-
push!(exprs.args, sys)
245-
else
246-
push!(exprs.args, :($extend($sys, $(ext[]))))
247-
end
248-
249-
:($name = $Model((; name, $(kwargs...)) -> $exprs, $dict, false))
250-
end
251-
252216
function parse_model!(exprs, comps, ext, eqs, icon, vs, ps, dict,
253217
mod, arg, kwargs)
254218
mname = arg.args[1]

test/model_parsing.jl

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
using ModelingToolkit, Test
2-
using ModelingToolkit: get_gui_metadata, VariableDescription, getdefault
2+
using ModelingToolkit: get_gui_metadata, VariableDescription, getdefault, RegularConnector
33
using URIs: URI
44
using Distributions
55
using Unitful
@@ -233,3 +233,41 @@ end
233233
for (k, v) in metadata
234234
@test MockMeta.structure[:variables][:m][k] == v
235235
end
236+
237+
@testset "Connector with parameters, equations..." begin
238+
@connector A begin
239+
@extend (e,) = extended_e = E()
240+
@icon "pin.png"
241+
@parameters begin
242+
p
243+
end
244+
@variables begin
245+
v(t)
246+
end
247+
@components begin
248+
cc = C()
249+
end
250+
@equations begin
251+
e ~ 0
252+
end
253+
end
254+
255+
@connector C begin
256+
c(t)
257+
end
258+
259+
@connector E begin
260+
e(t)
261+
end
262+
263+
@named aa = A()
264+
@test aa.connector_type == RegularConnector()
265+
266+
@test A.isconnector == true
267+
268+
@test A.structure[:parameters] == Dict(:p => Dict())
269+
@test A.structure[:extend] == [[:e], :extended_e, :E]
270+
@test A.structure[:equations] == ["e ~ 0"]
271+
@test A.structure[:kwargs] == Dict(:p => nothing, :v => nothing)
272+
@test A.structure[:components] == [[:cc, :C]]
273+
end

0 commit comments

Comments
 (0)