Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion src/systems/model_parsing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ function _model_macro(mod, fullname::Union{Expr, Symbol}, expr, isconnector)
dict = Dict{Symbol, Any}(
:defaults => Dict{Symbol, Any}(),
:kwargs => Dict{Symbol, Dict}(),
:structural_parameters => Dict{Symbol, Dict}()
:structural_parameters => Dict{Symbol, Dict}(),
:metadata => Dict{Symbol, Any}()
)
comps = Union{Symbol, Expr}[]
ext = []
Expand Down Expand Up @@ -127,6 +128,7 @@ function _model_macro(mod, fullname::Union{Expr, Symbol}, expr, isconnector)

consolidate = get(dict, :consolidate, default_consolidate)
description = get(dict, :description, "")
model_meta = get(dict, :metadata, Dict{Symbol, Any}())

@inline pop_structure_dict!.(
Ref(dict), [:defaults, :kwargs, :structural_parameters])
Expand All @@ -145,6 +147,14 @@ function _model_macro(mod, fullname::Union{Expr, Symbol}, expr, isconnector)
isconnector && push!(exprs.args,
:($Setfield.@set!(var"#___sys___".connector_type=$connector_type(var"#___sys___"))))

meta_exprs = quote
for (k, v) in $model_meta
var"#___sys___" = setmetadata(var"#___sys___", $get_var($mod, k), v)
end
end
push!(exprs.args, meta_exprs)
push!(exprs.args, :(var"#___sys___"))

f = if length(where_types) == 0
:($(Symbol(:__, name, :__))(; name, $(kwargs...)) = $exprs)
else
Expand Down Expand Up @@ -678,6 +688,8 @@ function parse_model!(exprs, comps, ext, eqs, icon, vs, ps, sps, c_evts, d_evts,
parse_costs!(costs, dict, body)
elseif mname == Symbol("@consolidate")
parse_consolidate!(body, dict)
elseif mname == Symbol("@metadata")
parse_metadata_block!(body, dict, mod)
else
error("$mname is not handled.")
end
Expand Down Expand Up @@ -1254,6 +1266,21 @@ function parse_description!(body, dict)
end
end

function parse_metadata_block!(body, dict, mod)
Base.remove_linenums!(body)
for arg in body.args
MLStyle.@match arg begin
Expr(:(=), a, b) => begin
dict[:metadata][a] = get_var(mod, b)
end
Expr(:call, :(=>), a, b) => begin
dict[:metadata][a] = get_var(mod, b)
end
_ => error("Invalid metadata entry: $arg. Expected key = value or key => value format.")
end
end
end

### Parsing Components:

function component_args!(a, b, varexpr, kwargs; index_name = nothing)
Expand Down
44 changes: 44 additions & 0 deletions test/model_parsing.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1045,3 +1045,47 @@ end
@test Example.structure[:constraints] == ["(EvalAt(0.3))(x) ~ 3", "y ≲ 4"]
@test Example.structure[:costs] == ["x + y", "(EvalAt(1))(y) ^ 2"]
end

@testset "Model Level Metadata" begin
struct Author end
struct MyVersion end
struct License end
struct Category end
struct Tags end
struct MyBool end
struct NewInt end

@mtkmodel TestMetadataModel begin
@metadata begin
Author = "Test Author"
MyVersion = "1.0.0"
License = "MIT"
Category => "example"
Tags = ["test", "demo", "metadata"]
MyBool => false
NewInt => 1
end

@parameters begin
k = 1.0, [description = "Gain parameter"]
end

@variables begin
x(t), [description = "State variable"]
y(t), [description = "Output variable"]
end

@equations begin
D(x) ~ -k * x
y ~ x
end
end
@named test_model = TestMetadataModel()

struct UnknownMetaKey end
@test ModelingToolkit.getmetadata(test_model, Author, nothing) == "Test Author"
@test ModelingToolkit.getmetadata(test_model, MyVersion, nothing) == "1.0.0"
@test ModelingToolkit.getmetadata(test_model, UnknownMetaKey, nothing) === nothing
@test ModelingToolkit.getmetadata(test_model, MyBool, nothing) === false
@test ModelingToolkit.getmetadata(test_model, NewInt, nothing) === 1
end
Loading