@@ -40,7 +40,7 @@ function _model_macro(mod, name, expr, isconnector)
40
40
:kwargs => Dict {Symbol, Dict} (),
41
41
:structural_parameters => Dict {Symbol, Dict} ()
42
42
)
43
- comps = Symbol[]
43
+ comps = Union{ Symbol, Expr} []
44
44
ext = Ref {Any} (nothing )
45
45
eqs = Expr[]
46
46
icon = Ref {Union{String, URI}} ()
745
745
746
746
# ## Parsing Components:
747
747
748
- function component_args! (a, b, expr, varexpr, kwargs)
748
+ function component_args! (a, b, varexpr, kwargs; index_name = nothing )
749
749
# Whenever `b` is a function call, skip the first arg aka the function name.
750
750
# Whenever it is a kwargs list, include it.
751
751
start = b. head == :call ? 2 : 1
@@ -754,73 +754,115 @@ function component_args!(a, b, expr, varexpr, kwargs)
754
754
arg isa LineNumberNode && continue
755
755
MLStyle. @match arg begin
756
756
x:: Symbol || Expr (:kw , x) => begin
757
- _v = _rename (a, x)
758
- b. args[i] = Expr (:kw , x, _v)
759
- push! (varexpr. args, :((@isdefined $ x) && ($ _v = $ x)))
760
- push! (kwargs, Expr (:kw , _v, nothing ))
761
- # dict[:kwargs][_v] = nothing
757
+ varname, _varname = _rename (a, x)
758
+ b. args[i] = Expr (:kw , x, _varname)
759
+ push! (varexpr. args, :((if $ varname != = nothing
760
+ $ _varname = $ varname
761
+ elseif @isdefined $ x
762
+ # Allow users to define a var in `structural_parameters` and set
763
+ # that as positional arg of subcomponents; it is useful for cases
764
+ # where it needs to be passed to multiple subcomponents.
765
+ $ _varname = $ x
766
+ end )))
767
+ push! (kwargs, Expr (:kw , varname, nothing ))
768
+ # dict[:kwargs][varname] = nothing
762
769
end
763
770
Expr (:parameters , x... ) => begin
764
- component_args! (a, arg, expr, varexpr, kwargs)
771
+ component_args! (a, arg, varexpr, kwargs)
765
772
end
766
773
Expr (:kw , x, y) => begin
767
- _v = _rename (a, x)
768
- b. args[i] = Expr (:kw , x, _v)
769
- push! (varexpr. args, :($ _v = $ _v === nothing ? $ y : $ _v))
770
- push! (kwargs, Expr (:kw , _v, nothing ))
771
- # dict[:kwargs][_v] = nothing
774
+ varname, _varname = _rename (a, x)
775
+ b. args[i] = Expr (:kw , x, _varname)
776
+ if isnothing (index_name)
777
+ push! (varexpr. args, :($ _varname = $ varname === nothing ? $ y : $ varname))
778
+ else
779
+ push! (varexpr. args,
780
+ :($ _varname = $ varname === nothing ? $ y : $ varname[$ index_name]))
781
+ end
782
+ push! (kwargs, Expr (:kw , varname, nothing ))
783
+ # dict[:kwargs][varname] = nothing
772
784
end
773
785
_ => error (" Could not parse $arg of component $a " )
774
786
end
775
787
end
776
788
end
777
789
778
- function _parse_components! (exprs, body, kwargs)
779
- expr = Expr (:block )
790
+ model_name (name, range) = Symbol .(name, :_ , collect (range))
791
+
792
+ function _parse_components! (body, kwargs)
793
+ local expr
780
794
varexpr = Expr (:block )
781
- # push!(exprs, varexpr)
782
- comps = Vector{Union{Symbol, Expr}}[]
795
+ comps = Vector{Union{Union{Expr, Symbol}, Expr}}[]
783
796
comp_names = []
784
797
785
- for arg in body. args
786
- arg isa LineNumberNode && continue
787
- MLStyle. @match arg begin
788
- Expr (:block ) => begin
789
- # TODO : Do we need this?
790
- error (" Multiple `@components` block detected within a single block" )
791
- end
792
- Expr (:(= ), a, b) => begin
793
- arg = deepcopy (arg)
794
- b = deepcopy (arg. args[2 ])
798
+ Base. remove_linenums! (body)
799
+ arg = body. args[end ]
800
+
801
+ MLStyle. @match arg begin
802
+ Expr (:(= ), a, Expr (:comprehension , Expr (:generator , b, Expr (:(= ), c, d)))) => begin
803
+ array_varexpr = Expr (:block )
795
804
796
- component_args! (a, b, expr, varexpr, kwargs)
805
+ push! (comp_names, :($ a... ))
806
+ push! (comps, [a, b. args[1 ], d])
807
+ b = deepcopy (b)
797
808
798
- arg. args[2 ] = b
799
- push! (expr. args, arg)
800
- push! (comp_names, a)
809
+ component_args! (a, b, array_varexpr, kwargs; index_name = c)
810
+
811
+ expr = _named_idxs (a, d, :($ c -> $ b); extra_args = array_varexpr)
812
+ end
813
+ Expr (:(= ), a, Expr (:comprehension , Expr (:generator , b, Expr (:filter , e, Expr (:(= ), c, d))))) => begin
814
+ error (" List comprehensions with conditional statements aren't supported." )
815
+ end
816
+ Expr (:(= ), a, Expr (:comprehension , Expr (:generator , b, Expr (:(= ), c, d), e... ))) => begin
817
+ # Note that `e` is of the form `Tuple{Expr(:(=), c, d)}`
818
+ error (" More than one index isn't supported while building component array" )
819
+ end
820
+ Expr (:block ) => begin
821
+ # TODO : Do we need this?
822
+ error (" Multiple `@components` block detected within a single block" )
823
+ end
824
+ Expr (:(= ), a, Expr (:for , Expr (:(= ), c, d), b)) => begin
825
+ Base. remove_linenums! (b)
826
+ array_varexpr = Expr (:block )
827
+ push! (array_varexpr. args, b. args[1 : (end - 1 )]. .. )
828
+ push! (comp_names, :($ a... ))
829
+ push! (comps, [a, b. args[end ]. args[1 ], d])
830
+ b = deepcopy (b)
831
+
832
+ component_args! (a, b. args[end ], array_varexpr, kwargs; index_name = c)
833
+
834
+ expr = _named_idxs (a, d, :($ c -> $ (b. args[end ])); extra_args = array_varexpr)
835
+ end
836
+ Expr (:(= ), a, b) => begin
837
+ arg = deepcopy (arg)
838
+ b = deepcopy (arg. args[2 ])
839
+
840
+ component_args! (a, b, varexpr, kwargs)
841
+
842
+ arg. args[2 ] = b
843
+ expr = :(@named $ arg)
844
+ push! (comp_names, a)
801
845
if (isa (b. args[1 ], Symbol) || Meta. isexpr (b. args[1 ], :.))
802
- push! (comps, [a, b. args[1 ]])
846
+ push! (comps, [a, b. args[1 ]])
803
847
end
804
- end
805
- _ => error (" Couldn't parse the component body: $arg " )
806
848
end
849
+ _ => error (" Couldn't parse the component body: $arg " )
807
850
end
851
+
808
852
return comp_names, comps, expr, varexpr
809
853
end
810
854
811
855
function push_conditional_component! (ifexpr, expr_vec, comp_names, varexpr)
812
856
blk = Expr (:block )
813
857
push! (blk. args, varexpr)
814
- push! (blk. args, :(@named begin
815
- $ (expr_vec. args... )
816
- end ))
858
+ push! (blk. args, expr_vec)
817
859
push! (blk. args, :($ push! (systems, $ (comp_names... ))))
818
860
push! (ifexpr. args, blk)
819
861
end
820
862
821
863
function handle_if_x! (mod, exprs, ifexpr, x, kwargs, condition = nothing )
822
864
push! (ifexpr. args, condition)
823
- comp_names, comps, expr_vec, varexpr = _parse_components! (ifexpr, x, kwargs)
865
+ comp_names, comps, expr_vec, varexpr = _parse_components! (x, kwargs)
824
866
push_conditional_component! (ifexpr, expr_vec, comp_names, varexpr)
825
867
comps
826
868
end
@@ -836,7 +878,7 @@ function handle_if_y!(exprs, ifexpr, y, kwargs)
836
878
push! (ifexpr. args, elseifexpr)
837
879
(comps... ,)
838
880
else
839
- comp_names, comps, expr_vec, varexpr = _parse_components! (exprs, y, kwargs)
881
+ comp_names, comps, expr_vec, varexpr = _parse_components! (y, kwargs)
840
882
push_conditional_component! (ifexpr, expr_vec, comp_names, varexpr)
841
883
comps
842
884
end
@@ -861,25 +903,23 @@ function parse_components!(exprs, cs, dict, compbody, kwargs)
861
903
Expr (:if , condition, x, y) => begin
862
904
handle_conditional_components (condition, dict, exprs, kwargs, x, y)
863
905
end
864
- Expr (:( = ), a, b) => begin
865
- comp_names, comps, expr_vec, varexpr = _parse_components! (exprs,
866
- :(begin
906
+ # Either the arg is top level component declaration or an invalid cause - both are handled by `_parse_components`
907
+ _ => begin
908
+ comp_names, comps, expr_vec, varexpr = _parse_components! ( :(begin
867
909
$ arg
868
910
end ),
869
911
kwargs)
870
912
push! (cs, comp_names... )
871
913
push! (dict[:components ], comps... )
872
- push! (exprs, varexpr, :(@named begin
873
- $ (expr_vec. args... )
874
- end ))
914
+ push! (exprs, varexpr, expr_vec)
875
915
end
876
- _ => error (" Couldn't parse the component body $compbody " )
877
916
end
878
917
end
879
918
end
880
919
881
920
function _rename (compname, varname)
882
921
compname = Symbol (compname, :__ , varname)
922
+ (compname, Symbol (:_ , compname))
883
923
end
884
924
885
925
# Handle top level branching
0 commit comments