Skip to content

Commit ff71696

Browse files
committed
More robust parsing
1 parent 5f2cfd7 commit ff71696

File tree

1 file changed

+39
-26
lines changed

1 file changed

+39
-26
lines changed

src/systems/connectors.jl

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ macro connector(expr)
1111
end
1212

1313
macro connector(name::Symbol, body)
14-
esc(connector_macro((@__MODULE__), name, body))
14+
esc(connector_macro(__module__, name, body))
1515
end
1616

1717
struct Model{F, S}
@@ -51,7 +51,7 @@ end
5151

5252
function parse_variable_def!(dict, mod, arg, varclass)
5353
MLStyle.@match arg begin
54-
::Symbol => generate_var(arg, varclass)
54+
::Symbol => generate_var!(dict, arg, varclass)
5555
Expr(:call, a, b) => generate_var!(dict, a, set_iv!(dict, b), varclass)
5656
Expr(:(=), a, b) => begin
5757
var = parse_variable_def!(dict, mod, a, varclass)
@@ -71,9 +71,23 @@ function parse_variable_def!(dict, mod, arg, varclass)
7171
end
7272
end
7373

74-
generate_var(a) = Symbolics.variable(a)
74+
function generate_var(a, varclass)
75+
var = Symbolics.variable(a)
76+
if varclass == :parameters
77+
var = toparam(var)
78+
end
79+
var
80+
end
81+
function generate_var!(dict, a, varclass)
82+
var = generate_var(a, :variables)
83+
vd = get!(dict, varclass) do
84+
Dict{Symbol, Dict{Symbol, Any}}()
85+
end
86+
vd[a] = Dict{Symbol, Any}()
87+
var
88+
end
7589
function generate_var!(dict, a, b, varclass)
76-
iv = generate_var(b)
90+
iv = generate_var(b, :variables)
7791
prev_iv = get!(dict, :independent_variable) do
7892
iv
7993
end
@@ -101,6 +115,7 @@ function parse_default(mod, a)
101115
a = Base.remove_linenums!(deepcopy(a))
102116
MLStyle.@match a begin
103117
Expr(:block, a) => get_var(mod, a)
118+
::Symbol => get_var(mod, a)
104119
_ => error("Cannot parse default $a")
105120
end
106121
end
@@ -121,49 +136,53 @@ function get_var(mod::Module, b)
121136
b isa Symbol ? getproperty(mod, b) : b
122137
end
123138
macro model(name::Symbol, expr)
124-
esc(model_macro(@__MODULE__, name, expr))
139+
esc(model_macro(__module__, name, expr))
125140
end
126141
function model_macro(mod, name, expr)
127142
exprs = Expr(:block)
128143
dict = Dict{Symbol, Any}()
144+
comps = Symbol[]
145+
vs = Symbol[]
146+
ps = Symbol[]
147+
eqs = Expr[]
129148
for arg in expr.args
130149
arg isa LineNumberNode && continue
131150
arg.head == :macrocall || error("$arg is not valid syntax. Expected a macro call.")
132-
parse_model!(exprs.args, dict, mod, arg)
151+
parse_model!(exprs.args, comps, eqs, vs, ps, dict, mod, arg)
133152
end
134153
iv = get(dict, :independent_variable, nothing)
135154
if iv === nothing
136-
error("$name doesn't have a independent variable")
155+
iv = dict[:independent_variable] = variable(:t)
137156
end
138157
push!(exprs.args,
139-
:($ODESystem(var"#___eqs___", $iv, var"#___vs___", $([]);
140-
systems = var"#___comps___", name)))
158+
:($ODESystem($Equation[$(eqs...)], $iv, [$(vs...)], [$(ps...)];
159+
systems = [$(comps...)], name)))
141160
:($name = $Model((; name) -> $exprs, $dict))
142161
end
143-
function parse_model!(exprs, dict, mod, arg)
162+
function parse_model!(exprs, comps, eqs, vs, ps, dict, mod, arg)
144163
mname = arg.args[1]
145-
vs = Num[]
146164
body = arg.args[end]
147165
if mname == Symbol("@components")
148-
parse_components!(exprs, dict, body)
166+
parse_components!(exprs, comps, dict, body)
149167
elseif mname == Symbol("@variables")
150168
parse_variables!(exprs, vs, dict, mod, body, :variables)
169+
elseif mname == Symbol("@parameters")
170+
parse_variables!(exprs, ps, dict, mod, body, :parameters)
151171
elseif mname == Symbol("@equations")
152-
parse_equations!(exprs, dict, body)
172+
parse_equations!(exprs, eqs, dict, body)
153173
else
154174
error("$mname is not handled.")
155175
end
156176
end
157-
function parse_components!(exprs, dict, body)
177+
function parse_components!(exprs, cs, dict, body)
158178
expr = Expr(:block)
159179
push!(exprs, expr)
160180
comps = Pair{String, String}[]
161-
names = Symbol[]
162181
for arg in body.args
163182
arg isa LineNumberNode && continue
164183
MLStyle.@match arg begin
165184
Expr(:(=), a, b) => begin
166-
push!(names, a)
185+
push!(cs, a)
167186
arg = deepcopy(arg)
168187
b = deepcopy(arg.args[2])
169188
push!(b.args, Expr(:kw, :name, Meta.quot(a)))
@@ -174,32 +193,26 @@ function parse_components!(exprs, dict, body)
174193
_ => error("`@components` only takes assignment expressions. Got $arg")
175194
end
176195
end
177-
push!(expr.args, :(var"#___comps___" = [$(names...)]))
178196
dict[:components] = comps
179197
end
180198
function parse_variables!(exprs, vs, dict, mod, body, varclass)
181199
expr = Expr(:block)
182200
push!(exprs, expr)
183-
names = Symbol[]
184201
for arg in body.args
185202
arg isa LineNumberNode && continue
186203
v = Num(parse_variable_def!(dict, mod, arg, varclass))
187-
push!(vs, v)
188204
name = getname(v)
189-
push!(names, name)
205+
push!(vs, name)
190206
push!(expr.args, :($name = $v))
191207
end
192-
push!(expr.args, :(var"#___vs___" = [$(names...)]))
193208
end
194-
function parse_equations!(exprs, dict, body)
195-
eqs = :(Equation[])
209+
function parse_equations!(exprs, eqs, dict, body)
196210
for arg in body.args
197211
arg isa LineNumberNode && continue
198-
push!(eqs.args, arg)
212+
push!(eqs, arg)
199213
end
200214
# TODO: does this work with TOML?
201-
dict[:equations] = readable_code.(@view eqs.args[2:end])
202-
push!(exprs, :(var"#___eqs___" = $eqs))
215+
dict[:equations] = readable_code.(eqs)
203216
end
204217

205218
abstract type AbstractConnectorType end

0 commit comments

Comments
 (0)