@@ -45,6 +45,7 @@ function _model_macro(mod, name, expr, isconnector)
45
45
icon = Ref {Union{String, URI}} ()
46
46
ps, sps, vs, = [], [], []
47
47
kwargs = Set ()
48
+ where_types = Expr[]
48
49
49
50
push! (exprs. args, :(variables = []))
50
51
push! (exprs. args, :(parameters = []))
@@ -55,25 +56,28 @@ function _model_macro(mod, name, expr, isconnector)
55
56
for arg in expr. args
56
57
if arg. head == :macrocall
57
58
parse_model! (exprs. args, comps, ext, eqs, icon, vs, ps,
58
- sps, dict, mod, arg, kwargs)
59
+ sps, dict, mod, arg, kwargs, where_types )
59
60
elseif arg. head == :block
60
61
push! (exprs. args, arg)
61
62
elseif arg. head == :if
62
63
MLStyle. @match arg begin
63
64
Expr (:if , condition, x) => begin
64
65
parse_conditional_model_statements (comps, dict, eqs, exprs, kwargs,
65
- mod, ps, vs, parse_top_level_branch (condition, x. args)... )
66
+ mod, ps, vs, where_types,
67
+ parse_top_level_branch (condition, x. args)... )
66
68
end
67
69
Expr (:if , condition, x, y) => begin
68
70
parse_conditional_model_statements (comps, dict, eqs, exprs, kwargs,
69
- mod, ps, vs, parse_top_level_branch (condition, x. args, y)... )
71
+ mod, ps, vs, where_types,
72
+ parse_top_level_branch (condition, x. args, y)... )
70
73
end
71
74
_ => error (" Got an invalid argument: $arg " )
72
75
end
73
76
elseif isconnector
74
77
# Connectors can have variables listed without `@variables` prefix or
75
78
# begin block.
76
- parse_variable_arg! (exprs. args, vs, dict, mod, arg, :variables , kwargs)
79
+ parse_variable_arg! (
80
+ exprs. args, vs, dict, mod, arg, :variables , kwargs, where_types)
77
81
else
78
82
error (" $arg is not valid syntax. Expected a macro call." )
79
83
end
@@ -104,11 +108,40 @@ function _model_macro(mod, name, expr, isconnector)
104
108
isconnector && push! (exprs. args,
105
109
:($ Setfield. @set! (var"#___sys___" . connector_type= $ connector_type (var"#___sys___" ))))
106
110
107
- f = :($ (Symbol (:__ , name, :__ ))(; name, $ (kwargs... )) = $ exprs)
111
+ f = if length (where_types) == 0
112
+ :($ (Symbol (:__ , name, :__ ))(; name, $ (kwargs... )) = $ exprs)
113
+ else
114
+ f_with_where = Expr (:where )
115
+ push! (f_with_where. args,
116
+ :($ (Symbol (:__ , name, :__ ))(; name, $ (kwargs... ))), where_types... )
117
+ :($ f_with_where = $ exprs)
118
+ end
108
119
:($ name = $ Model ($ f, $ dict, $ isconnector))
109
120
end
110
121
111
- function parse_variable_def! (dict, mod, arg, varclass, kwargs;
122
+ function update_kwargs_and_metadata! (dict, kwargs, a, def, indices, type, var,
123
+ varclass, where_types)
124
+ if indices isa Nothing
125
+ push! (kwargs, Expr (:kw , Expr (:(:: ), a, Union{Nothing, type}), nothing ))
126
+ dict[:kwargs ][getname (var)] = Dict (:value => def, :type => type)
127
+ else
128
+ vartype = gensym (:T )
129
+ push! (kwargs,
130
+ Expr (:kw ,
131
+ Expr (:(:: ), a,
132
+ Expr (:curly , :Union , :Nothing , Expr (:curly , :AbstractArray , vartype))),
133
+ nothing ))
134
+ push! (where_types, :($ vartype <: $type ))
135
+ dict[:kwargs ][getname (var)] = Dict (:value => def, :type => AbstractArray{type})
136
+ end
137
+ if dict[varclass] isa Vector
138
+ dict[varclass][1 ][getname (var)][:type ] = AbstractArray{type}
139
+ else
140
+ dict[varclass][getname (var)][:type ] = type
141
+ end
142
+ end
143
+
144
+ function parse_variable_def! (dict, mod, arg, varclass, kwargs, where_types;
112
145
def = nothing , indices:: Union{Vector{UnitRange{Int}}, Nothing} = nothing ,
113
146
type:: Type = Real)
114
147
metatypes = [(:connection_type , VariableConnectType),
@@ -128,40 +161,31 @@ function parse_variable_def!(dict, mod, arg, varclass, kwargs;
128
161
arg isa LineNumberNode && return
129
162
MLStyle. @match arg begin
130
163
a:: Symbol => begin
131
- if type isa Nothing
132
- push! (kwargs, Expr (:kw , a, nothing ))
133
- else
134
- push! (kwargs, Expr (:kw , Expr (:(:: ), a, Union{Nothing, type}), nothing ))
135
- end
136
164
var = generate_var! (dict, a, varclass; indices, type)
137
- dict[:kwargs ][getname (var)] = Dict (:value => def, :type => type)
165
+ update_kwargs_and_metadata! (dict, kwargs, a, def, indices, type, var,
166
+ varclass, where_types)
138
167
(var, def)
139
168
end
140
169
Expr (:(:: ), a, type) => begin
141
- type = Core. eval (mod, type)
142
- _type_check! (a, type)
143
- parse_variable_def! (dict, mod, a, varclass, kwargs; def, type)
170
+ type = getfield (mod, type)
171
+ parse_variable_def! (dict, mod, a, varclass, kwargs, where_types; def, type)
144
172
end
145
173
Expr (:(:: ), Expr (:call , a, b), type) => begin
146
- type = Core . eval (mod, type)
147
- def = _type_check! (def, a, type)
148
- parse_variable_def! (dict, mod, a, varclass, kwargs; def, type)
174
+ type = getfield (mod, type)
175
+ def = _type_check! (def, a, type, varclass )
176
+ parse_variable_def! (dict, mod, a, varclass, kwargs, where_types ; def, type)
149
177
end
150
178
Expr (:call , a, b) => begin
151
- if type isa Nothing
152
- push! (kwargs, Expr (:kw , a, nothing ))
153
- else
154
- push! (kwargs, Expr (:kw , Expr (:(:: ), a, Union{Nothing, type}), nothing ))
155
- end
156
179
var = generate_var! (dict, a, b, varclass; indices, type)
157
- type != = nothing && (dict[varclass][ getname (var)][ :type ] = type)
158
- dict[ :kwargs ][ getname (var)] = Dict ( :value => def, :type => type )
180
+ update_kwargs_and_metadata! (dict, kwargs, a, def, indices, type, var,
181
+ varclass, where_types )
159
182
(var, def)
160
183
end
161
184
Expr (:(= ), a, b) => begin
162
185
Base. remove_linenums! (b)
163
186
def, meta = parse_default (mod, b)
164
- var, def = parse_variable_def! (dict, mod, a, varclass, kwargs; def, type)
187
+ var, def = parse_variable_def! (
188
+ dict, mod, a, varclass, kwargs, where_types; def, type)
165
189
if dict[varclass] isa Vector
166
190
dict[varclass][1 ][getname (var)][:default ] = def
167
191
else
@@ -183,7 +207,8 @@ function parse_variable_def!(dict, mod, arg, varclass, kwargs;
183
207
(var, def)
184
208
end
185
209
Expr (:tuple , a, b) => begin
186
- var, def = parse_variable_def! (dict, mod, a, varclass, kwargs; type)
210
+ var, def = parse_variable_def! (
211
+ dict, mod, a, varclass, kwargs, where_types; type)
187
212
meta = parse_metadata (mod, b)
188
213
if meta != = nothing
189
214
for (type, key) in metatypes
@@ -202,7 +227,7 @@ function parse_variable_def!(dict, mod, arg, varclass, kwargs;
202
227
end
203
228
Expr (:ref , a, b... ) => begin
204
229
indices = map (i -> UnitRange (i. args[2 ], i. args[end ]), b)
205
- parse_variable_def! (dict, mod, a, varclass, kwargs;
230
+ parse_variable_def! (dict, mod, a, varclass, kwargs, where_types ;
206
231
def, indices, type)
207
232
end
208
233
_ => error (" $arg cannot be parsed" )
@@ -307,17 +332,17 @@ function get_var(mod::Module, b)
307
332
end
308
333
309
334
function parse_model! (exprs, comps, ext, eqs, icon, vs, ps, sps,
310
- dict, mod, arg, kwargs)
335
+ dict, mod, arg, kwargs, where_types )
311
336
mname = arg. args[1 ]
312
337
body = arg. args[end ]
313
338
if mname == Symbol (" @components" )
314
339
parse_components! (exprs, comps, dict, body, kwargs)
315
340
elseif mname == Symbol (" @extend" )
316
341
parse_extend! (exprs, ext, dict, mod, body, kwargs)
317
342
elseif mname == Symbol (" @variables" )
318
- parse_variables! (exprs, vs, dict, mod, body, :variables , kwargs)
343
+ parse_variables! (exprs, vs, dict, mod, body, :variables , kwargs, where_types )
319
344
elseif mname == Symbol (" @parameters" )
320
- parse_variables! (exprs, ps, dict, mod, body, :parameters , kwargs)
345
+ parse_variables! (exprs, ps, dict, mod, body, :parameters , kwargs, where_types )
321
346
elseif mname == Symbol (" @structural_parameters" )
322
347
parse_structural_parameters! (exprs, sps, dict, mod, body, kwargs)
323
348
elseif mname == Symbol (" @equations" )
@@ -336,7 +361,7 @@ function parse_structural_parameters!(exprs, sps, dict, mod, body, kwargs)
336
361
MLStyle. @match arg begin
337
362
Expr (:(= ), Expr (:(:: ), a, type), b) => begin
338
363
type = Core. eval (mod, type)
339
- b = _type_check! (Core. eval (mod, b), a, type)
364
+ b = _type_check! (Core. eval (mod, b), a, type, :structural_parameters )
340
365
push! (sps, a)
341
366
push! (kwargs, Expr (:kw , Expr (:(:: ), a, type), b))
342
367
dict[:structural_parameters ][a] = dict[:kwargs ][a] = Dict (
@@ -454,25 +479,27 @@ function parse_extend!(exprs, ext, dict, mod, body, kwargs)
454
479
return nothing
455
480
end
456
481
457
- function parse_variable_arg! (exprs, vs, dict, mod, arg, varclass, kwargs)
458
- name, ex = parse_variable_arg (dict, mod, arg, varclass, kwargs)
482
+ function parse_variable_arg! (exprs, vs, dict, mod, arg, varclass, kwargs, where_types )
483
+ name, ex = parse_variable_arg (dict, mod, arg, varclass, kwargs, where_types )
459
484
push! (vs, name)
460
485
push! (exprs, ex)
461
486
end
462
487
463
- function parse_variable_arg (dict, mod, arg, varclass, kwargs)
464
- vv, def = parse_variable_def! (dict, mod, arg, varclass, kwargs)
488
+ function parse_variable_arg (dict, mod, arg, varclass, kwargs, where_types )
489
+ vv, def = parse_variable_def! (dict, mod, arg, varclass, kwargs, where_types )
465
490
name = getname (vv)
466
491
return vv isa Num ? name : :($ name... ),
467
492
:($ name = $ name === nothing ? $ setdefault ($ vv, $ def) : $ setdefault ($ vv, $ name))
468
493
end
469
494
470
- function handle_conditional_vars! (arg, conditional_branch, mod, varclass, kwargs)
495
+ function handle_conditional_vars! (
496
+ arg, conditional_branch, mod, varclass, kwargs, where_types)
471
497
conditional_dict = Dict (:kwargs => Dict (),
472
498
:parameters => Any[Dict {Symbol, Dict{Symbol, Any}} ()],
473
499
:variables => Any[Dict {Symbol, Dict{Symbol, Any}} ()])
474
500
for _arg in arg. args
475
- name, ex = parse_variable_arg (conditional_dict, mod, _arg, varclass, kwargs)
501
+ name, ex = parse_variable_arg (
502
+ conditional_dict, mod, _arg, varclass, kwargs, where_types)
476
503
push! (conditional_branch. args, ex)
477
504
push! (conditional_branch. args, :(push! ($ varclass, $ name)))
478
505
end
@@ -530,7 +557,7 @@ function push_conditional_dict!(dict, condition, conditional_dict,
530
557
end
531
558
end
532
559
533
- function parse_variables! (exprs, vs, dict, mod, body, varclass, kwargs)
560
+ function parse_variables! (exprs, vs, dict, mod, body, varclass, kwargs, where_types )
534
561
expr = Expr (:block )
535
562
push! (exprs, expr)
536
563
for arg in body. args
@@ -542,7 +569,8 @@ function parse_variables!(exprs, vs, dict, mod, body, varclass, kwargs)
542
569
conditional_expr. args[2 ],
543
570
mod,
544
571
varclass,
545
- kwargs)
572
+ kwargs,
573
+ where_types)
546
574
push! (expr. args, conditional_expr)
547
575
push_conditional_dict! (dict, condition, conditional_dict, nothing , varclass)
548
576
end
@@ -552,12 +580,13 @@ function parse_variables!(exprs, vs, dict, mod, body, varclass, kwargs)
552
580
conditional_expr. args[2 ],
553
581
mod,
554
582
varclass,
555
- kwargs)
583
+ kwargs,
584
+ where_types)
556
585
conditional_y_expr, conditional_y_tuple = handle_y_vars (y,
557
586
conditional_dict,
558
587
mod,
559
588
varclass,
560
- kwargs)
589
+ kwargs, where_types )
561
590
push! (conditional_expr. args, conditional_y_expr)
562
591
push! (expr. args, conditional_expr)
563
592
push_conditional_dict! (dict,
@@ -566,25 +595,28 @@ function parse_variables!(exprs, vs, dict, mod, body, varclass, kwargs)
566
595
conditional_y_tuple,
567
596
varclass)
568
597
end
569
- _ => parse_variable_arg! (exprs, vs, dict, mod, arg, varclass, kwargs)
598
+ _ => parse_variable_arg! (
599
+ exprs, vs, dict, mod, arg, varclass, kwargs, where_types)
570
600
end
571
601
end
572
602
end
573
603
574
- function handle_y_vars (y, dict, mod, varclass, kwargs)
604
+ function handle_y_vars (y, dict, mod, varclass, kwargs, where_types )
575
605
conditional_dict = if Meta. isexpr (y, :elseif )
576
606
conditional_y_expr = Expr (:elseif , y. args[1 ], Expr (:block ))
577
607
conditional_dict = handle_conditional_vars! (y. args[2 ],
578
608
conditional_y_expr. args[2 ],
579
609
mod,
580
610
varclass,
581
- kwargs)
582
- _y_expr, _conditional_dict = handle_y_vars (y. args[end ], dict, mod, varclass, kwargs)
611
+ kwargs,
612
+ where_types)
613
+ _y_expr, _conditional_dict = handle_y_vars (
614
+ y. args[end ], dict, mod, varclass, kwargs, where_types)
583
615
push! (conditional_y_expr. args, _y_expr)
584
616
(:elseif , y. args[1 ], conditional_dict, _conditional_dict)
585
617
else
586
618
conditional_y_expr = Expr (:block )
587
- handle_conditional_vars! (y, conditional_y_expr, mod, varclass, kwargs)
619
+ handle_conditional_vars! (y, conditional_y_expr, mod, varclass, kwargs, where_types )
588
620
end
589
621
conditional_y_expr, conditional_dict
590
622
end
@@ -865,18 +897,18 @@ function parse_top_level_branch(condition, x, y = nothing, branch = :if)
865
897
end
866
898
867
899
function parse_conditional_model_statements (comps, dict, eqs, exprs, kwargs, mod,
868
- ps, vs, component_blk, equations_blk, parameter_blk, variable_blk)
900
+ ps, vs, where_types, component_blk, equations_blk, parameter_blk, variable_blk)
869
901
parameter_blk != = nothing &&
870
902
parse_variables! (
871
903
exprs. args, ps, dict, mod, :(begin
872
904
$ parameter_blk
873
- end ), :parameters , kwargs)
905
+ end ), :parameters , kwargs, where_types )
874
906
875
907
variable_blk != = nothing &&
876
908
parse_variables! (
877
909
exprs. args, vs, dict, mod, :(begin
878
910
$ variable_blk
879
- end ), :variables , kwargs)
911
+ end ), :variables , kwargs, where_types )
880
912
881
913
component_blk != = nothing &&
882
914
parse_components! (exprs. args,
@@ -890,8 +922,7 @@ function parse_conditional_model_statements(comps, dict, eqs, exprs, kwargs, mod
890
922
end ))
891
923
end
892
924
893
- _type_check! (a, type) = return
894
- function _type_check! (val, a, type)
925
+ function _type_check! (val, a, type, varclass)
895
926
if val isa type
896
927
return val
897
928
else
@@ -900,7 +931,7 @@ function _type_check!(val, a, type)
900
931
catch
901
932
(e)
902
933
throw (TypeError (Symbol (" `@mtkmodel`" ),
903
- " `@structural_parameters `, while assigning to `$a `" , type, typeof (val)))
934
+ " `$varclass `, while assigning to `$a `" , type, typeof (val)))
904
935
end
905
936
end
906
937
end
0 commit comments