Skip to content

Commit ac4dd25

Browse files
committed
feat: provision to enforce types in parameters, variables and structural_parameters in @mtkmodel
Check that specified default is of specified type. Add types to corresponding keyword arg.
1 parent a132efd commit ac4dd25

File tree

1 file changed

+55
-12
lines changed

1 file changed

+55
-12
lines changed

src/systems/model_parsing.jl

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ end
3535

3636
function _model_macro(mod, name, expr, isconnector)
3737
exprs = Expr(:block)
38-
dict = Dict{Symbol, Any}()
39-
dict[:kwargs] = Dict{Symbol, Any}()
38+
dict = Dict{Symbol, Any}(
39+
:kwargs => Dict{Symbol, Dict}(),
40+
)
4041
comps = Symbol[]
4142
ext = Ref{Any}(nothing)
4243
eqs = Expr[]
@@ -107,7 +108,8 @@ function _model_macro(mod, name, expr, isconnector)
107108
end
108109

109110
function parse_variable_def!(dict, mod, arg, varclass, kwargs;
110-
def = nothing, indices::Union{Vector{UnitRange{Int}}, Nothing} = nothing)
111+
def = nothing, indices::Union{Vector{UnitRange{Int}}, Nothing} = nothing,
112+
type::Union{Type, Nothing} = nothing)
111113
metatypes = [(:connection_type, VariableConnectType),
112114
(:description, VariableDescription),
113115
(:unit, VariableUnit),
@@ -127,15 +129,34 @@ function parse_variable_def!(dict, mod, arg, varclass, kwargs;
127129
arg isa LineNumberNode && return
128130
MLStyle.@match arg begin
129131
a::Symbol => begin
130-
push!(kwargs, Expr(:kw, a, nothing))
132+
if type isa Nothing
133+
push!(kwargs, Expr(:kw, a, nothing))
134+
else
135+
push!(kwargs, Expr(:kw, Expr(:(::), a, Union{Nothing, type}), nothing))
136+
end
131137
var = generate_var!(dict, a, varclass; indices)
132-
dict[:kwargs][getname(var)] = def
138+
dict[:kwargs][getname(var)] = Dict(:value => def, :type => type)
133139
(var, def)
134140
end
141+
Expr(:(::), a, type) => begin
142+
type = Core.eval(mod, type)
143+
_type_check!(a, type)
144+
parse_variable_def!(dict, mod, a, varclass, kwargs; def, type)
145+
end
146+
Expr(:(::), Expr(:call, a, b), type) => begin
147+
type = Core.eval(mod, type)
148+
def = _type_check!(def, a, type)
149+
parse_variable_def!(dict, mod, a, varclass, kwargs; def, type)
150+
end
135151
Expr(:call, a, b) => begin
136-
push!(kwargs, Expr(:kw, a, nothing))
152+
if type isa Nothing
153+
push!(kwargs, Expr(:kw, a, nothing))
154+
else
155+
push!(kwargs, Expr(:kw, Expr(:(::), a, Union{Nothing, type}), nothing))
156+
end
137157
var = generate_var!(dict, a, b, varclass; indices)
138-
dict[:kwargs][getname(var)] = def
158+
type !== nothing && (dict[varclass][getname(var)][:type] = type)
159+
dict[:kwargs][getname(var)] = Dict(:value => def, :type => type)
139160
(var, def)
140161
end
141162
Expr(:(=), a, b) => begin
@@ -306,15 +327,22 @@ function parse_structural_parameters!(exprs, sps, dict, mod, body, kwargs)
306327
Base.remove_linenums!(body)
307328
for arg in body.args
308329
MLStyle.@match arg begin
330+
Expr(:(=), Expr(:(::), a, type), b) => begin
331+
type = Core.eval(mod, type)
332+
b = _type_check!(Core.eval(mod, b), a, type)
333+
push!(sps, a)
334+
push!(kwargs, Expr(:kw, Expr(:(::), a, type), b))
335+
dict[:kwargs][a] = Dict(:value => b, :type => type)
336+
end
309337
Expr(:(=), a, b) => begin
310338
push!(sps, a)
311339
push!(kwargs, Expr(:kw, a, b))
312-
dict[:kwargs][a] = b
340+
dict[:kwargs][a] = Dict(:value => b)
313341
end
314342
a => begin
315343
push!(sps, a)
316344
push!(kwargs, a)
317-
dict[:kwargs][a] = nothing
345+
dict[:kwargs][a] = Dict(:value => nothing)
318346
end
319347
end
320348
end
@@ -338,17 +366,17 @@ function extend_args!(a, b, dict, expr, kwargs, varexpr, has_param = false)
338366
end
339367
end
340368
push!(kwargs, Expr(:kw, x, nothing))
341-
dict[:kwargs][x] = nothing
369+
dict[:kwargs][x] = Dict(:value => nothing)
342370
end
343371
Expr(:kw, x) => begin
344372
push!(kwargs, Expr(:kw, x, nothing))
345-
dict[:kwargs][x] = nothing
373+
dict[:kwargs][x] = Dict(:value => nothing)
346374
end
347375
Expr(:kw, x, y) => begin
348376
b.args[i] = Expr(:kw, x, x)
349377
push!(varexpr.args, :($x = $x === nothing ? $y : $x))
350378
push!(kwargs, Expr(:kw, x, nothing))
351-
dict[:kwargs][x] = nothing
379+
dict[:kwargs][x] = Dict(:value => nothing)
352380
end
353381
Expr(:parameters, x...) => begin
354382
has_param = true
@@ -853,3 +881,18 @@ function parse_conditional_model_statements(comps, dict, eqs, exprs, kwargs, mod
853881
$equations_blk
854882
end))
855883
end
884+
885+
_type_check!(a, type) = return
886+
function _type_check!(val, a, type)
887+
if val isa type
888+
return val
889+
else
890+
try
891+
return convert(type, val)
892+
catch
893+
(e)
894+
throw(TypeError(Symbol("`@mtkmodel`"),
895+
"`@structural_parameters`, while assigning to `$a`", type, typeof(val)))
896+
end
897+
end
898+
end

0 commit comments

Comments
 (0)