Skip to content

Commit cd8d650

Browse files
committed
feat: parse constants in @mtkmodel
Allows `@constants` in the `@mtkmodel`; this works similar to the `@constants`; and in addition, a type check is added to the assigned value.
1 parent 8436903 commit cd8d650

File tree

1 file changed

+48
-6
lines changed

1 file changed

+48
-6
lines changed

src/systems/model_parsing.jl

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ end
3636
function _model_macro(mod, name, expr, isconnector)
3737
exprs = Expr(:block)
3838
dict = Dict{Symbol, Any}(
39+
:constants => Dict{Symbol, Dict}(),
3940
:kwargs => Dict{Symbol, Dict}(),
4041
:structural_parameters => Dict{Symbol, Dict}()
4142
)
@@ -347,6 +348,8 @@ function parse_model!(exprs, comps, ext, eqs, icon, vs, ps, sps,
347348
parse_structural_parameters!(exprs, sps, dict, mod, body, kwargs)
348349
elseif mname == Symbol("@equations")
349350
parse_equations!(exprs, eqs, dict, body)
351+
elseif mname == Symbol("@constants")
352+
parse_constants!(exprs, dict, body, mod)
350353
elseif mname == Symbol("@icon")
351354
isassigned(icon) && error("This model has more than one icon.")
352355
parse_icon!(body, dict, icon, mod)
@@ -355,13 +358,53 @@ function parse_model!(exprs, comps, ext, eqs, icon, vs, ps, sps,
355358
end
356359
end
357360

361+
function parse_constants!(exprs, dict, body, mod)
362+
Base.remove_linenums!(body)
363+
for arg in body.args
364+
MLStyle.@match arg begin
365+
Expr(:(=), Expr(:(::), a, type), Expr(:tuple, b, metadata)) || Expr(:(=), Expr(:(::), a, type), b) => begin
366+
type = getfield(mod, type)
367+
b = _type_check!(get_var(mod, b), a, type, :constants)
368+
constant = first(@constants $a::type = b)
369+
push!(exprs, :($a = $constant))
370+
dict[:constants][a] = Dict(:value => b, :type => type)
371+
if @isdefined metadata
372+
for data in metadata.args
373+
dict[:constants][a][data.args[1]] = data.args[2]
374+
end
375+
end
376+
end
377+
Expr(:(=), a, Expr(:tuple, b, metadata)) => begin
378+
constant = first(@constants $a = b)
379+
push!(exprs, :($a = $constant))
380+
dict[:constants][a] = Dict{Symbol, Any}(:value => get_var(mod, b))
381+
for data in metadata.args
382+
dict[:constants][a][data.args[1]] = data.args[2]
383+
end
384+
end
385+
Expr(:(=), a, b) => begin
386+
constant = first(@constants $a = b)
387+
push!(exprs, :($a = $constant))
388+
dict[:constants][a] = Dict(:value => get_var(mod, b))
389+
end
390+
_ => error("""Malformed constant definition `$arg`. Please use the following syntax:
391+
```
392+
@constants begin
393+
var = value, [description = "This is an example constant."]
394+
end
395+
```
396+
""")
397+
end
398+
end
399+
end
400+
358401
function parse_structural_parameters!(exprs, sps, dict, mod, body, kwargs)
359402
Base.remove_linenums!(body)
360403
for arg in body.args
361404
MLStyle.@match arg begin
362405
Expr(:(=), Expr(:(::), a, type), b) => begin
363-
type = Core.eval(mod, type)
364-
b = _type_check!(Core.eval(mod, b), a, type, :structural_parameters)
406+
type = getfield(mod, type)
407+
b = _type_check!(get_var(mod, b), a, type, :structural_parameters)
365408
push!(sps, a)
366409
push!(kwargs, Expr(:kw, Expr(:(::), a, type), b))
367410
dict[:structural_parameters][a] = dict[:kwargs][a] = Dict(
@@ -922,16 +965,15 @@ function parse_conditional_model_statements(comps, dict, eqs, exprs, kwargs, mod
922965
end))
923966
end
924967

925-
function _type_check!(val, a, type, varclass)
968+
function _type_check!(val, a, type, class)
926969
if val isa type
927970
return val
928971
else
929972
try
930973
return convert(type, val)
931-
catch
932-
(e)
974+
catch e
933975
throw(TypeError(Symbol("`@mtkmodel`"),
934-
"`$varclass`, while assigning to `$a`", type, typeof(val)))
976+
"`$class`, while assigning to `$a`", type, typeof(val)))
935977
end
936978
end
937979
end

0 commit comments

Comments
 (0)