@@ -180,6 +180,16 @@ function update_kwargs_and_metadata!(dict, kwargs, a, def, indices, type, var,
180180    end 
181181end 
182182
183+ function  unit_handled_variable_value (mod, y, varname)
184+     meta =  parse_metadata (mod, y)
185+     varval =  if  meta isa  Nothing ||  get (meta, VariableUnit, nothing ) isa  Nothing
186+         varname
187+     else 
188+         :($ convert_units ($ (meta[VariableUnit]), $ varname))
189+     end 
190+     return  varval
191+ end 
192+ 
183193function  parse_variable_def! (dict, mod, arg, varclass, kwargs, where_types;
184194        def =  nothing , indices:: Union{Vector{UnitRange{Int}}, Nothing}  =  nothing ,
185195        type:: Type  =  Real, meta =  Dict {DataType, Expr} ())
@@ -222,6 +232,66 @@ function parse_variable_def!(dict, mod, arg, varclass, kwargs, where_types;
222232                varclass, where_types, meta)
223233            return  var, def, Dict ()
224234        end 
235+         Expr (:tuple , Expr (:(:: ), Expr (:ref , a, b... ), type), y) ||  Expr (:tuple , Expr (:ref , a, b... ), y) =>  begin 
236+             (@isdefined  type) ||  (type =  Real)
237+             varname =  Meta. isexpr (a, :call ) ?  a. args[1 ] :  a
238+             push! (kwargs, Expr (:kw , varname, nothing ))
239+             varval =  unit_handled_variable_value (mod, y, varname)
240+             if  varclass ==  :parameters 
241+                 var =  :($ varname =  $ first (@parameters  $ a[$ (b... )]:: $type  =  ($ varval, $ y)))
242+             else 
243+                 var =  :($ varname =  $ first (@variables  $ a[$ (b... )]:: $type  =  ($ varval, $ y)))
244+             end 
245+             # TODO : update `dict` aka `Model.structure` with the metadata
246+             (:($ varname... ), var), nothing , Dict ()
247+         end 
248+         Expr (:(= ), Expr (:(:: ), Expr (:ref , a, b... ), type), y) ||  Expr (:(= ), Expr (:ref , a, b... ), y) =>  begin 
249+             (@isdefined  type) ||  (type =  Real)
250+             varname =  Meta. isexpr (a, :call ) ?  a. args[1 ] :  a
251+             if  Meta. isexpr (y, :tuple )
252+                 varval =  unit_handled_variable_value (mod, y, varname)
253+                 val, y =  (y. args[1 ], y. args[2 : end ])
254+                 push! (kwargs, Expr (:kw , varname, nothing ))
255+                 if  varclass ==  :parameters 
256+                     var =  :($ varname =  $ varname ===  nothing  ?  $ val :  $ varname;
257+                     $ varname =  $ first (@parameters  $ a[$ (b... )]:: $type  =  (
258+                         $ varval, $ (y... ))))
259+                 else 
260+                     var =  :($ varname =  $ varname ===  nothing  ?  $ val :  $ varname;
261+                     $ varname =  $ first (@variables  $ a[$ (b... )]:: $type  =  (
262+                         $ varval, $ (y... ))))
263+                 end 
264+             else 
265+                 push! (kwargs, Expr (:kw , varname, nothing ))
266+                 if  varclass ==  :parameters 
267+                     var =  :($ varname =  $ varname ===  nothing  ?  $ y :  $ varname;
268+                     $ varname =  $ first (@parameters  $ a[$ (b... )]:: $type  =  $ varname))
269+                 else 
270+                     var =  :($ varname =  $ varname ===  nothing  ?  $ y :  $ varname;
271+                     $ varname =  $ first (@variables  $ a[$ (b... )]:: $type  =  $ varname))
272+                 end 
273+             end 
274+             # TODO : update `dict`` aka `Model.structure` with the metadata
275+             (:($ varname... ), var), nothing , Dict ()
276+         end 
277+         Expr (:(:: ), Expr (:ref , a, b... ), type) ||  Expr (:ref , a, b... ) =>  begin 
278+             (@isdefined  type) ||  (type =  Real)
279+             varname =  a isa  Expr &&  a. head ==  :call  ?  a. args[1 ] :  a
280+             push! (kwargs, Expr (:kw , varname, nothing ))
281+             if  varclass ==  :parameters 
282+                 var =  :($ varname =  $ first (@parameters  $ a[$ (b... )]:: $type  =  $ varname))
283+             elseif  varclass ==  :variables 
284+                 var =  :($ varname =  $ first (@variables  $ a[$ (b... )]:: $type  =  $ varname))
285+             else 
286+                 throw (" Symbolic array with arbitrary length is not handled for $varclass .
287+                     Please open an issue with an example."  )
288+             end 
289+             dict[varclass] =  get! (dict, varclass) do 
290+                 Dict {Symbol, Dict{Symbol, Any}} ()
291+             end 
292+             #  dict[:kwargs][varname] = dict[varclass][varname] = Dict(:size => b)
293+             (:($ varname... ), var), nothing , Dict ()
294+         end 
225295        Expr (:(= ), a, b) =>  begin 
226296            Base. remove_linenums! (b)
227297            def, meta =  parse_default (mod, b)
@@ -268,11 +338,6 @@ function parse_variable_def!(dict, mod, arg, varclass, kwargs, where_types;
268338            end 
269339            return  var, def, Dict ()
270340        end 
271-         Expr (:ref , a, b... ) =>  begin 
272-             indices =  map (i ->  UnitRange (i. args[2 ], i. args[end ]), b)
273-             parse_variable_def! (dict, mod, a, varclass, kwargs, where_types;
274-                 def, indices, type, meta)
275-         end 
276341        _ =>  error (" $arg  cannot be parsed" 
277342    end 
278343end 
@@ -380,14 +445,23 @@ function parse_default(mod, a)
380445    end 
381446end 
382447
383- function  parse_metadata (mod, a)
448+ function  parse_metadata (mod, a:: Expr )
384449    MLStyle. @match  a begin 
385-         Expr (:vect , eles... ) =>  Dict (parse_metadata (mod, e) for  e in  eles)
450+         Expr (:vect , b... ) =>  Dict (parse_metadata (mod, m) for  m in  b)
451+         Expr (:tuple , a, b... ) =>  parse_metadata (mod, b)
386452        Expr (:(= ), a, b) =>  Symbolics. option_to_metadata_type (Val (a)) =>  get_var (mod, b)
387453        _ =>  error (" Cannot parse metadata $a " 
388454    end 
389455end 
390456
457+ function  parse_metadata (mod, metadata:: AbstractArray )
458+     ret =  Dict ()
459+     for  m in  metadata
460+         merge! (ret, parse_metadata (mod, m))
461+     end 
462+     ret
463+ end 
464+ 
391465function  _set_var_metadata! (metadata_with_exprs, a, m, v:: Expr )
392466    push! (metadata_with_exprs, m =>  v)
393467    a
@@ -645,6 +719,7 @@ function parse_variable_arg!(exprs, vs, dict, mod, arg, varclass, kwargs, where_
645719end 
646720
647721function  convert_units (varunits:: DynamicQuantities.Quantity , value)
722+     value isa  Nothing &&  return  nothing 
648723    DynamicQuantities. ustrip (DynamicQuantities. uconvert (
649724        DynamicQuantities. SymbolicUnits. as_quantity (varunits), value))
650725end 
@@ -656,6 +731,7 @@ function convert_units(
656731end 
657732
658733function  convert_units (varunits:: Unitful.FreeUnits , value)
734+     value isa  Nothing &&  return  nothing 
659735    Unitful. ustrip (varunits, value)
660736end 
661737
@@ -674,47 +750,50 @@ end
674750function  parse_variable_arg (dict, mod, arg, varclass, kwargs, where_types)
675751    vv, def, metadata_with_exprs =  parse_variable_def! (
676752        dict, mod, arg, varclass, kwargs, where_types)
677-     name =  getname (vv)
678- 
679-     varexpr =  if  haskey (metadata_with_exprs, VariableUnit)
680-         unit =  metadata_with_exprs[VariableUnit]
681-         quote 
682-             $ name =  if  $ name ===  nothing 
683-                 $ setdefault ($ vv, $ def)
684-             else 
685-                 try 
686-                     $ setdefault ($ vv, $ convert_units ($ unit, $ name))
687-                 catch  e
688-                     if  isa (e, $ (DynamicQuantities. DimensionError)) || 
689-                        isa (e, $ (Unitful. DimensionError))
690-                         error (" Unable to convert units for \' " *  string (:($$ vv)) *  " \' " 
691-                     elseif  isa (e, MethodError)
692-                         error (" No or invalid units provided for \' " *  string (:($$ vv)) * 
693-                               " \' " 
694-                     else 
695-                         rethrow (e)
753+     if  ! (vv isa  Tuple)
754+         name =  getname (vv)
755+         varexpr =  if  haskey (metadata_with_exprs, VariableUnit)
756+             unit =  metadata_with_exprs[VariableUnit]
757+             quote 
758+                 $ name =  if  $ name ===  nothing 
759+                     $ setdefault ($ vv, $ def)
760+                 else 
761+                     try 
762+                         $ setdefault ($ vv, $ convert_units ($ unit, $ name))
763+                     catch  e
764+                         if  isa (e, $ (DynamicQuantities. DimensionError)) || 
765+                            isa (e, $ (Unitful. DimensionError))
766+                             error (" Unable to convert units for \' " *  string (:($$ vv)) *  " \' " 
767+                         elseif  isa (e, MethodError)
768+                             error (" No or invalid units provided for \' " *  string (:($$ vv)) * 
769+                                   " \' " 
770+                         else 
771+                             rethrow (e)
772+                         end 
696773                    end 
697774                end 
698775            end 
699-         end 
700-     else 
701-         quote 
702-             $ name  =   if   $ name  ===   nothing 
703-                 $ setdefault ( $ vv,  $ def) 
704-             else 
705-                 $ setdefault ( $ vv,  $ name) 
776+         else 
777+              quote 
778+                  $ name  =   if   $ name  ===   nothing 
779+                      $ setdefault ( $ vv,  $ def) 
780+                 else 
781+                      $ setdefault ( $ vv,  $ name) 
782+                 end 
706783            end 
707784        end 
708-     end 
709785
710-     metadata_expr =  Expr (:block )
711-     for  (k, v) in  metadata_with_exprs
712-         push! (metadata_expr. args,
713-             :($ name =  $ wrap ($ set_scalar_metadata ($ unwrap ($ name), $ k, $ v))))
714-     end 
786+          metadata_expr =  Expr (:block )
787+          for  (k, v) in  metadata_with_exprs
788+              push! (metadata_expr. args,
789+                  :($ name =  $ wrap ($ set_scalar_metadata ($ unwrap ($ name), $ k, $ v))))
790+          end 
715791
716-     push! (varexpr. args, metadata_expr)
717-     return  vv isa  Num ?  name :  :($ name... ), varexpr
792+         push! (varexpr. args, metadata_expr)
793+         return  vv isa  Num ?  name :  :($ name... ), varexpr
794+     else 
795+         return  vv
796+     end 
718797end 
719798
720799function  handle_conditional_vars! (
0 commit comments