%%%==============================================================================
%% Copyright 2023-present by Alceu Frigeri
%%
%% This work may be distributed and/or modified under the conditions of
%%
%% * The [LaTeX Project Public License](http://www.latex-project.org/lppl.txt),
%%   version 1.3c (or later), and/or
%% * The [GNU Affero General Public License](https://www.gnu.org/licenses/agpl-3.0.html),
%%   version 3 (or later)
%%
%% This work has the LPPL maintenance status *maintained*.
%%
%% The Current Maintainer of this work is Alceu Frigeri
%%
%% This is version {2.1a} {2026/07/04} 
%%
%% The list of files that compose this work can be found in the README.md file at
%% https://ctan.org/pkg/starray
%%
%%%==============================================================================
\NeedsTeXFormat{LaTeX2e}[2026/06/01]

%%%%%%%
%%%
%%% Just an attempt at having my package's info in a regular way
%%%   \pkginfograb_set:nn {<pkg-name>} { props } sets package info
%%%
%%%   \pkginfograbProvidesExplPackage {<pkg-name>} { props } sets package info
%%%     and calls \ProvidesExplPackage
%%%
%%%%%%%
\RequirePackage{pkginfograb}
\pkginfograbProvidesExplPackage {starray}
  {
     name        = {starray} ,
     prefix      = {starray} ,
     date        = {2026/07/04},
     version     = {2.1a} ,
     description = {A structured array/hash of properties}
  }
%%%%%%%
%%% End of cut-n-paste
%%%%%%%



%%%%%%%%%%%%%%%%%%%
%%%%
%%%%  New package
%%%%
%%%%%%%%%%%%%%%%%%%

\bool_new:N \l__starray_NNnames_bool
\bool_new:N \l__starray_NNnames_warn_bool

\keys_define:nn { starray }
  {
%    prefix .tl_set:N          =  g__starray_prfix_  ,
%    prefix .value_required:n  = true ,
%    prefix .initial:n         = l__starray_ ,
%    prefix .usage:n           = load ,
  
    NN~names . usage:n = load ,
    NN~names .choice: ,
    NN~names / none .code:n = 
      { 
        \bool_set_false:N \l__starray_NNnames_bool
      },
    NN~names / no~warnings .code:n = 
      {
        \bool_set_true:N \l__starray_NNnames_bool
        \bool_set_false:N \l__starray_NNnames_warn_bool      
      } ,
    NN~names / strict .code:n = 
      {
        \bool_set_true:N \l__starray_NNnames_bool
        \bool_set_true:N \l__starray_NNnames_warn_bool      
      } ,

    íter~cascade .usage:n = load ,
    iter~cascade .bool_set:N = \l__starray_cascade_bool ,
    iter~cascade .value_forbidden:n = true ,

    msg-err .usage:n = load ,
    msg-err .choice: ,
    msg-err / none .code:n = { },
    msg-err / default .code:n = {} ,
    msg-err / strict .code:n = 
      {
        \msg_redirect_module:nnn { starray / strict } { warning } { error }
      } ,
    msg-err / syntax .code:n = 
      {
        \msg_redirect_module:nnn { starray / strict } { warning } { error }
        \msg_redirect_module:nnn { starray / syntax } { warning } { error }
      } ,
    msg-err / reference .code:n = 
      {
        \msg_redirect_module:nnn { starray / strict } { warning } { error }
        \msg_redirect_module:nnn { starray / syntax } { warning } { error }
        \msg_redirect_module:nnn { starray / reference } { warning } { error }
      } ,
    msg-err / all .code:n = 
      {
        \msg_redirect_module:nnn { starray } { warning } { error } 
      } ,
  
    msg-supress .usage:n = load ,
    msg-supress .choice: ,
    msg-supress / none .code:n = {} ,
    msg-supress / reference .code:n = 
      {
        \msg_redirect_module:nnn { starray / reference } { warning } { none }
      } ,
    msg-supress / syntax .code:n = 
      {
        \msg_redirect_module:nnn { starray / strict } { warning } { none }
        \msg_redirect_module:nnn { starray / syntax } { warning } { none }
      } ,
    msg-supress / strict .code:n = 
      {
        \msg_redirect_module:nnn { starray / strict } { warning } { none }
        \msg_redirect_module:nnn { starray / syntax } { warning } { none }
        \msg_redirect_module:nnn { starray / reference } { warning } { none }
      } ,
    msg-supress / all .code:n = 
      {
        \msg_redirect_module:nnn { starray } { warning } { none } 
      } ,
    
    parsed~ check .usage:n = load ,
    parsed~ check .bool_set:N = \l__starray_parsed_check_bool ,
    parsed~ check .value_forbidden:n = true ,
  
  }

\ProcessKeyOptions [ starray ]

%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% New variants of core expl3 primitives
%%%% expansion handling
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
\cs_generate_variant:Nn \keyval_parse:nnn { ee }
\cs_generate_variant:Nn \prg_new_conditional:Nnn { c }
\cs_generate_variant:Nn \prg_new_conditional:Npnn { c }
    %% This is just for debugging. Otherwise, not needed
\cs_generate_variant:Nn \tl_show:n { e }


%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% Package error/warning messages
%%%% #1 'ID' (code identifier)
%%%% #2 / #3 / #4  further fields (as needed)
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%

\msg_new:nnnn { starray } { strict / Expl }
  {
    Expl~ version~ too~ old.~ Update~ needed!
  }
  {
    Expl~ version~ too~ old.~ Update~ needed!
  }

\msg_new:nnnn { starray } { strict / (re)define }
  {
    (#1)~'#2'~already~defined!
  }
  {
    You~tried~to~(re)define~'#2'.
    ~Error~Code: (#1).
  }

\msg_new:nnnn { starray } { strict / not defined }
  {
    (#1)~'#2'~isn't~defined!
  }
  {
    You~tried~to~use~a~non~defined~'#2'.
    ~Error~Code: (#1).
  }

\msg_new:nnnn { starray } { syntax / ref-syntax-err }
  {
    (#1)~term~reference~'#2'~--~'#3'.
  }
  {
    Your~term~'#2'~contains~a~syntax~error:~'#3'.
    ~Error~ Code: (#1).
  }

\msg_new:nnnn { starray } { syntax / keyval-term }
  {
    (#1)~term~reference~'#2'~error~'#3'.
  }
  {
    Your~term~'#2'~contains~a~syntax~error:~'#3'.
    ~Error~ Code: (#1).
  }

\msg_new:nnnn { starray } { syntax /  term }
  {
    (#1)~'#2'~isn't~a~valid~term~ref.
  }
  {
    Invalid~term~reference:~'#2'.
    ~Error~ Code: (#1).
  }

\msg_new:nnnn { starray } { syntax /  parsed }
  {
    (#1)~Can't~ call~ #2~ after~a~ failed~ \starray_term_parser:
  }
  {
    You~ called~ #2~ after~ a~ failed~ call~ to~ \starray_term_parser:
    ~Error~ Code: (#1).
  }
  

\msg_new:nnnn { starray } { syntax /  structure-ref }
  {
    (#1)~'#3'~isn't~a~sub-structure~of~'#2'.
  }
  {
    '#2' ~doesn't~have~a~sub-structure~named:~'#3'.
    ~Error~ Code: (#1).
  }

\msg_new:nnnn { starray } { syntax /  iter }
  {
    (#1)~cannot~set~iter. ~invalid~'#2'. 
  }
  {
    cannot~set~iter.~ invalid '#2'.
    ~Error~ Code: (#1).
  }


\msg_new:nnnn { starray } { syntax /  prop }
  {
    (#1)~cannot~get/set~property~from~'#2'.
  }
  {
    You~have~referenced~an~invalid~structure~'#2'.
    ~Error~ Code: (#1).
  }


\msg_new:nnnn { starray } { reference /  keyval }
  {
    (#1)~key~'#2'~ignored.
  }
  {
    You~referenced~a~key~without~setting~it's~value. ~Key~ignored.
  }

\msg_new:nnnn { starray } { reference / invalid-starray }  %%%$$
  {
    (#1)~'#2'~invalid~starray.
    \tl_if_blank:nTF { #3 }
      {~#3 }
      {}
  }
  {
    '#2'~isn't~a~starray.
    \tl_if_blank:nTF { #3 }
      {~#3 }
      {}
    ~Error~ Code: (#1).
  }

\msg_new:nnnn { starray } { reference / iter }
  {
    (#1)~invalid~iter~(#3)~from~'#2'
    \str_if_empty:nTF { #4 }
      {}
      { #4 }
    .
  }
  {
    Invalid~iter~(#3)~from~ '#2'.~You~might~have~tried~to~use/set/reset~an~iter~of
    ~an~ill~instantiated~structured.
    ~Error~ Code: (#1).
  }

\msg_new:nnnn { starray } { reference / prop } %%%$$
  {
    (#1)~cannot~get/set~property~'#3'~from~'#2'.
  }
  {
    '#3'~isn't~a~property~of~'#2'.
    ~Error~ Code: (#1).
  }

\msg_new:nnnn { starray } { info / show }
  {
    \iow_newline:(#1)\iow_newline:~ #2 \iow_newline:

    #3

    \iow_newline:
    definition's~end.
  }
  {
    \iow_newline:(#1)\iow_newline:~ #2 \iow_newline:

    #3

    \iow_newline:
    definition's~end.
  }

%%%%% 
%%%%%
%% Making this as short as possible (less than 60 chars)
%% so \msg_expandable_error: might be used.
%%%%%
\msg_new:nnnn { starray } { strict / deprecate } 
  {
    (#1)~'#2'~has ~ been ~ deprecated.
  }
  {
    The ~ command~'#2'~has ~ been ~ deprecated. ~
    Use~'#3'~ instead.
    ~Error~ Code: (#1).
  }


\IfExplAtLeastTF{ 2024-03-14 }{}{ \msg_warning:nn { starray } { strict / Expl } }


\cs_new_protected:Npn \__starray_msg:nnnnn #1#2#3#4#5
  {
    \__starray_set_rtn_false:

    \seq_gput_right:Nn \g__starray_msg_seq
      {
        \msg_warning:nnnnnn
          { starray }{ #1 } { #2 }{ #3 }{ #4 }{ #5 }
      }
  }
%\cs_generate_variant:Nn \__starray_msg:nnnnn { nneee , neeee }


\cs_new_protected:Npn \__starray_msg:nnnn #1#2#3#4
  {
    \__starray_set_rtn_false:

    \seq_gput_right:Nn \g__starray_msg_seq
      {
        \msg_warning:nnnnn
          { starray }{ #1 } { #2 }{ #3 }{ #4 }
      }
  }
\cs_generate_variant:Nn \__starray_msg:nnnn { nnee }


\cs_new_protected:Npn \__starray_msg_dispatch:
  {
    \seq_map_inline:Nn \g__starray_msg_seq { ##1 }
    \seq_gclear:N \g__starray_msg_seq
  }

\cs_new_protected:Npn \__starray_msg_clear:
  {
    \seq_gclear:N \g__starray_msg_seq
  }

%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% Package Variables declaration
%%%%
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%

%%%%
%%%% 'general' (internal) returning bool
%%%%
\cs_new:Npn \__starray_set_rtn_true:
  { \cs_set_eq:NN \__starray_rtn: \prg_return_true: }
\cs_new:Npn \__starray_set_rtn_false:
  { \cs_set_eq:NN \__starray_rtn: \prg_return_false: }

%%%%
%%%% sequence of 'error mensages' (stacked).
%%%%
\seq_new:N \g__starray_msg_seq

\tl_new:N  \l__starray_tmpa_tl  % to replace \l_tmpa_tl  % new_term
\tl_new:N  \l__starray_tmpb_tl % to replace \l_tmpb_tl   % fix terms+set iter from hash+if valid idx+set from keyval

\tl_new:N \l__starray_parser_tmp_A_tl
\tl_new:N \l__starray_parser_tmp_B_tl

\tl_new:N \l__starray_show_tmp_tl

\tl_new:N \l__starray_tmp_term_st_tl


%%%%
%%%% (sub)structure returning tl.
%%%%
\tl_new:N \l__starray_keyval_tmpb_tl
\tl_new:N \l__starray_keyval_tmpa_tl

%%%%
%%%% parser related ones
%%%%
\bool_const:Nn \c__starray_no_idx_ending_bool { \c_true_bool }
\bool_const:Nn \c__starray_idx_ending_bool    { \c_false_bool }

      
\tl_new:N \l__starray_from_keyval_orgref_tl

%%%%
%%%% parser returning variables
%%%%
\tl_new:N \l__starray_parsed_tl
\tl_new:N \l__starray_parsed_ref_tl

\tl_new:N \l__starray_parsed_base_st_tl
\tl_new:N \l__starray_parsed_term_st_tl

\tl_new:N   \g__starray_parsed_saved_base_st_tl 
\tl_new:N   \g__starray_parsed_saved_term_st_tl 
\bool_new:N \g__starray_parsed_bool
  
\tl_new:N \l__starray_parsing_term_tl 

%%%%
%%%% parser 'internal' variables
%%%%
\bool_new:N \l__starray_parser_no_idx_ending_bool

\tl_new:N \l__starray_parsed_term_tl
\tl_new:N \l__starray_parsed_idx_tl

\bool_new:N \l__starray_parser_OK_bool


%%%%
%%%% for cs/prg generating commands
%%%%
\tl_new:N \l__starray_csuse_tmp_tl

%%%%
%%%% scan mark for _base_st_tl, _term_st_tl and _ref_st_tl
%%%%
\scan_new:N \s__end

\tl_new:N \l__starray_duocmd_tmpa_tl
\tl_new:N \l__starray_duocmd_tmpb_tl


%% big one, (g)put !!
%%%%
%%%% (g)put :: IF the effect shall be local or global
%%%%
\cs_set_eq:NN \__starray_put:cnn \use_none:nnn


%%%%%%%%%
%%%
%%% This will create 4 variants
%%%                  This one is *NEVER* expandable
%%% { starray_ #cmd# : n #signature# } => standard one, expecting a starray-term-ref 
%%%                  This *might* be expandable (if base-code is)
%%% { starray_ uparsed_ #cmd# : N #signature# } => expecting an user given variable (from previous parsing)
%%%                  This *might* be expandable (if base-code (and if-parsed-bool-false, if checked) is)
%%% { starray_ parsed_ #cmd# : #signature# } => using *last* parsed term, with/without checking
%%%                  This *might* be expandable (if base-code (and if-parsed-bool-false, if checked) is)
%%% { starray_ iparsed_ #cmd# : #signature# } => using iterate over parsed term
%%%
%%%%%%%%%
%%%
%%% Regarding the base-code: it will 'get' two extra param BEFORE the ones in the signature
%%% nn#signature# (for example, signature:nN... real signature: nnnN #1#2#3#4
%%% whereas the first two parameters, nn, will (should) always be (o-expanded) '...term_st' and '...base_st'
%%%
%%% 'if-parser-failed' code shall expect a single parameter: starray-ref
%%%
%%% 'if-parsed-failed' code shall expect no parameter!
%%%
%%%%%%%%%
%%% #1 -> #cmd#      => base-name
%%% #2 -> #signature#
%%% #3 -> \c__starray_idx_ending_bool / \c__starray_no_idx_ending_bool
%%% #4 -> base-code                 % if expandable, the resulting commands *might* also be
%%% #5 -> if-parser-failed          % NB.: this will be in the F branch of \__starry_parser: *not* expandable
%%% #6 -> if-parsed-bool-false      % NB.: this will be in the F branch of a \bool_if: *might* be expandable
%%%%%%%%%
\cs_new_protected:Npn \__starray_cs_generate:nnNnnn #1#2#3#4
  {
    \int_case:nn { \tl_count:n { #2 } }
      {
        { 0 } { \tl_set:Nn \l__starray_csuse_tmp_tl {} }
        { 1 } { \tl_set:Nn \l__starray_csuse_tmp_tl { \use_none:n } }
        { 2 } { \tl_set:Nn \l__starray_csuse_tmp_tl { \use_none:nn } }
        { 3 } { \tl_set:Nn \l__starray_csuse_tmp_tl { \use_none:nnn } }
      }
      
    \cs_new:cn { __starray_parsed_ #1 : nn#2 }
      { #4 }
    
    \__starray_cs_generate:cVnnNnn 
      { __starray_parsed_ #1 : nn#2 } 
      \l__starray_csuse_tmp_tl
      { #1 }{ #2 } #3
  }

%%%%%%%%%
%%% #1 -> base
%%% #2 -> none
%%% #3 -> cmd radix
%%% #4 -> base signature
%%% #5 -> \c__starray_idx_ending_bool /  \c__starray_no_idx_ending_bool
%%% #6 -> in case  parser  err
%%% #7 -> in case *parsed* err
%%%%%%%%%
\cs_new_protected:Npn \__starray_cs_generate:NnnnNnn #1#2#3#4#5#6#7
  {
    \cs_new:cpn { starray_uparsed_ #3 : N#4 } ##1
      { \exp_last_unbraced:NV #1 ##1 }

    \bool_if:NTF \l__starray_NNnames_bool
      {
        \bool_if:NTF \l__starray_NNnames_warn_bool
          {
            \cs_new:cpn { starray_parsed_ #3 : NN#4 } ##1##2
              { 
                %%% Just in case 'this' is used in an expandable context
                \msg_expandable_error:nnnnn { starray } { strict / deprecate } { cs:01 }
                  {  starray_parsed_ #3 : NN#4 }
                  {  starray_uparsed_ #3 : N#4  }
                \exp_last_unbraced:NV #1 ##1
              }
          }
          {
            \cs_new:cpn { starray_parsed_ #3 : NN#4 } ##1##2
              { \exp_last_unbraced:NV #1 ##1 }
          }
      }
      {}
      

    \bool_if:NTF \l__starray_parsed_check_bool
      {
        \cs_new:cpn { starray_parsed_ #3 : #4 }
          { 
            \bool_if:NTF \g__starray_parsed_bool
              { \exp_args:Noo #1 \g__starray_parsed_saved_term_st_tl \g__starray_parsed_saved_base_st_tl }
              { #7 #2  }
          }      
      }
      {
        \cs_new:cpn { starray_parsed_ #3 : #4 }
          { \exp_args:Noo #1 \g__starray_parsed_saved_term_st_tl \g__starray_parsed_saved_base_st_tl }
      }
  
    \cs_new:cpn { starray_iparsed_ #3 : #4 }
      { \exp_args:Noo #1 \g__starray_iterate_term_st_tl \g__starray_iterate_base_st_tl }
      
    \cs_new:cpn { starray_ #3 : n#4 } ##1
      { 
        \__starray_parser:NeTF #5 { ##1 }
          { \exp_args:Noo #1 \l__starray_parsed_term_st_tl \l__starray_parsed_base_st_tl }
          { #6 #2 }
      }
  }
\cs_generate_variant:Nn \__starray_cs_generate:NnnnNnn { cV }


%%%%%%%%% WARNING: p variants.... might not be expandable !!!
%%%
%%% This will create 4 variants (x4 => p,T,F,TF)
%%%                  This will *NEVER* expandable
%%% { starray_ #cmd# : n #signature# { p,TF,T,F }} => standard one, expecting a starray-term-ref
%%%                  This *might* be expandable (if base-code and T/F code (that follows) also are)
%%% { starray_ uparsed_ #cmd# : N #signature# { p, TF,T,F }} => expecting an user given variables (from previous parsing)
%%%                  This *might* be expandable (if base-code and T/F code (that follows) also are... and (if-parsed-boold-false, if checked)
%%% { starray_ parsed_ #cmd# : #signature# { p,TF,T,F }} => using *last* parsed term, with/without checking
%%%                  This *might* be expandable (if base-code and T/F code (that follows) also are... and (if-parsed-boold-false, if checked)
%%% { starray_ iparsed_ #cmd# : #signature# { p,TF,T,F }} => using iterate over parsed term
%%%
%%% regarding the _p variants.. they will be ok iff #3 is expandable!
%%%
%%%%%%%%%
%%%
%%% Regarding the base-code: it will 'get' two extra param BEFORE the ones in the signature
%%% nn#signature# (for example, signature:nN... real signature: nnnN #1#2#3#4
%%% whereas the first two parameters, nn, will (should) always be (o-expanded) '...term_st' and '...base_st'
%%%
%%% 'if-parser-failed' code shall expect a single parameter: starray-ref
%%%
%%% 'if-parsed-failed' code shall expect no parameter!
%%%
%%% For all of them to be expandable, #3, #4 and #5 have also to be expandable.
%%%
%%%%%%%%%
%%% #1 -> #cmd#      => base-name
%%% #2 -> #signature#
%%% #3 -> \c__starray_idx_ending_bool /  \c__starray_no_idx_ending_bool
%%% #3=>4 -> base-code
%%% #4=>5 -> if-parser-failed
%%% #5=>6 -> if-parsed-bool-false
%%%%%%%%%
\tl_new:N \l__starray_useAa_tl
\tl_new:N \l__starray_useAb_tl
\tl_new:N \l__starray_useBa_tl
\tl_new:N \l__starray_useBb_tl

\cs_new_protected:Npn \__starray_prg_generate:nnNnnn #1#2#3#4#5#6
  {
    \int_case:nn { \tl_count:n { #2 } }  %%%% THOSE are for the "false" cases...(parameters not aboserbed by #signature#TF/_p/T/F cases)
      {
        { 0 } { 
              \tl_set:Nn \l__starray_useBa_tl { \use_ii:nn }    %% for the TF case
              \tl_set:Nn \l__starray_useBb_tl {}              %% for the _p case
              \tl_set:Nn \l__starray_useAa_tl { \use_none:n }   %% for the T case
              \tl_set:Nn \l__starray_useAb_tl { \use_i:n }      %% for the F case
            }
        { 1 } { 
              \tl_set:Nn \l__starray_useBa_tl { \use_iii:nnn } 
              \tl_set:Nn \l__starray_useBb_tl { \use_none:n } 
              \tl_set:Nn \l__starray_useAa_tl { \use_none:nn } 
              \tl_set:Nn \l__starray_useAb_tl { \use_ii:nn } 
            }
        { 2 } { 
              \tl_set:Nn \l__starray_useBa_tl { \use_iv:nnnn } 
              \tl_set:Nn \l__starray_useBb_tl { \use_none:nn } 
              \tl_set:Nn \l__starray_useAa_tl { \use_none:nnn } 
              \tl_set:Nn \l__starray_useAb_tl { \use_iii:nnn } 
            }
        { 3 } { 
              \tl_set:Nn \l__starray_useBa_tl { \use_v:nnnnn } 
              \tl_set:Nn \l__starray_useBb_tl { \use_none:nnn } 
              \tl_set:Nn \l__starray_useAa_tl { \use_none:nnnn } 
              \tl_set:Nn \l__starray_useAb_tl { \use_iv:nnnn } 
            }
      }
      
    %
    % the _p might be ok (expandable) ... depending on #4
    %
    \prg_new_conditional:cnn { __starray_parsed_ #1 : nn#2 } { p , T , F , TF }
      { #4 }

    \__starray_prg_generate_a:ccVVnnNnn
      { __starray_parsed_ #1 : nn#2 TF } { __starray_parsed_ #1 _p : nn#2 } 
      \l__starray_useBa_tl \l__starray_useBb_tl   
      { #1 }{ #2 }{ #3 }{ #5 }{ #6 }
    \__starray_prg_generate_b:ccVVnnNnn
      { __starray_parsed_ #1 : nn#2 T } { __starray_parsed_ #1 : nn#2 F }
      \l__starray_useAa_tl \l__starray_useAb_tl  
      { #1 }{ #2 }{ #3 }{ #5 }{ #6 }

  }

%%%%%%%%%
%%%
%%% if not expandable, better undefine them
%%%
%%%%%%%%%
\cs_new_protected:Npn \__starray_prg_undef_p:nn #1#2
  {
    \bool_if:NTF \l__starray_NNnames_bool
      { \cs_undefine:c { starray_parsed_ #1 _p: NN#2 } }
      {}
    
    \cs_undefine:c { __starray_parsed_ #1 _p: nn#2 }
    \cs_undefine:c { starray_uparsed_ #1 _p: N#2 }
    \cs_undefine:c { starray_parsed_ #1 _p: #2 }
  }

%%%%%%%%%
%%% #1 -> baseTF
%%% #2 -> base_p
%%% #3 -> noneA
%%% #4 -> none (for _p case)
%%% #5 -> cmd radix
%%% #6 -> base signature
%%% #7 -> \c__starray_idx_ending_bool /  \c__starray_no_idx_ending_bool
%%% #7=>8 -> in case  parser  err
%%% #8=>9 -> in case *parsed* err
%%%%%%%%%
\cs_new_protected:Npn \__starray_prg_generate_a:NNnnnnNnn #1#2#3#4#5#6#7#8#9
  {  
    \cs_new:cpn { starray_uparsed_ #5 : N#6 TF } ##1
      { \exp_last_unbraced:NV #1 ##1 }

    \cs_new:cpn { starray_uparsed_ #5 _p : N#6 } ##1
      { \exp_last_unbraced:NV #2 ##1 }


    \bool_if:NTF \l__starray_NNnames_bool
      {
        \bool_if:NTF \l__starray_NNnames_warn_bool
          {
            \cs_new:cpn { starray_parsed_ #5 : NN#6 TF } ##1##2
              { 
                \msg_warning:nnnnn { starray } { strict / deprecate } { prg:01 }
                  {  starray_parsed_ #5 : NN#6 TF }
                  {  starray_uparsed_ #5 : N#6 TF }
                \exp_last_unbraced:NV #1 ##1
              }
            \cs_new:cpn { starray_parsed_ #5 _p : NN#6 } ##1##2
              { 
                %%% Just in case 'this' is used in an expandable context
                \msg_expandable_error:nnnnn { starray } { strict / deprecate } { prg:02 }
                % This will certainly generate low level erros... :/
%                \msg_warning:nnnnn { starray } { strict / deprecate } { prg:02 }  
                  { \ starray_parsed_ #5 _p : NN#6 }
                  { \ starray_parsed_ #5 _p : N#6 }
                \exp_last_unbraced:NV #2 ##1
              }
          }
          {
            \cs_new:cpn { starray_parsed_ #5 : NN#6 TF } ##1##2
              { \exp_last_unbraced:NV #1 ##1 }
            \cs_new:cpn { starray_parsed_ #5 _p : NN#6 } ##1##2
              { \exp_last_unbraced:NV #2 ##1 }
          }
      }
      {}

    \bool_if:NTF \l__starray_parsed_check_bool
      {
        \cs_new:cpn { starray_parsed_ #5 : #6 TF }
          { 
            \bool_if:NTF \g__starray_parsed_bool
              { \exp_args:Noo #1 \g__starray_parsed_saved_term_st_tl \g__starray_parsed_saved_base_st_tl }
              { #9 #3 }  %%TODO... this should absorb N+2 and execute the last one...
          }
        \cs_new:cpn { starray_parsed_ #5 _p : #6 }
          { 
            \bool_if:NTF \g__starray_parsed_bool
              { \exp_args:Noo #2 \g__starray_parsed_saved_term_st_tl \g__starray_parsed_saved_base_st_tl }
              { #9 #4 }   %%TODO... hopefully this is correct... absorbs N tokens...execute none
          }
      }
      {
        \cs_new:cpn { starray_parsed_ #5 : #6 TF }
          { \exp_args:Noo #1 \g__starray_parsed_saved_term_st_tl \g__starray_parsed_saved_base_st_tl }
        \cs_new:cpn { starray_parsed_ #5 _p : #6 }
          { \exp_args:Noo #2 \g__starray_parsed_saved_term_st_tl \g__starray_parsed_saved_base_st_tl }
      }

    \cs_new:cpn { starray_iparsed_ #5 : #6 TF }
      { \exp_args:Noo #1 \g__starray_iterate_term_st_tl \g__starray_iterate_base_st_tl }
    \cs_new:cpn { starray_iparsed_ #5 _p : #6 }
      { \exp_args:Noo #2 \g__starray_iterate_term_st_tl \g__starray_iterate_base_st_tl }
  
    \cs_new:cpn { starray_ #5 : n#6 TF } ##1
      { 
        \__starray_parser:NeTF #7 { ##1 }
          { \exp_args:Noo #1 \l__starray_parsed_term_st_tl \l__starray_parsed_base_st_tl }
          { #8 #3 }  %%TODO... this should absorb N+2 and execute the last one...
      }

% for the record
% \__starray_parser isn't expandable
% *would it be...*
%
%    \cs_new:cpn { starray_ #5 _p : n#6 } ##1
%      { 
%        \__starray_parser:NeTF \c__starray_idx_ending_bool { ##1 }
%          { #2 \l__starray_parsed_term_st_tl \l__starray_parsed_base_st_tl }
%          { #7 #4 }
%      }
  
  }
\cs_generate_variant:Nn \__starray_prg_generate_a:NNnnnnNnn { ccVV }



%%%%%%%%%
%%% #1 -> baseT
%%% #2 -> baseF
%%% #3 -> noneA
%%% #4 -> noneB
%%% #5 -> cmd radix
%%% #6 -> base signature
%%% #7 -> \c__starray_idx_ending_bool /  \c__starray_no_idx_ending_bool
%%% #7=>8 -> in case  parser  err
%%% #8=>9 -> in case *parsed* err
%%%%%%%%%
\cs_new_protected:Npn \__starray_prg_generate_b:NNnnnnNnn #1#2#3#4#5#6#7#8#9
  {  
    \cs_new:cpn { starray_uparsed_ #5 : N#6 T } ##1
      { \exp_last_unbraced:NV #1 ##1 }
  
    \cs_new:cpn { starray_uparsed_ #5 : N#6 F } ##1
      { \exp_last_unbraced:NV #2 ##1 }

    \bool_if:NTF \l__starray_NNnames_bool
      {
        \bool_if:NTF \l__starray_NNnames_warn_bool
          {
            \cs_new:cpn { starray_parsed_ #5 : NN#6 T } ##1##2
              { 
                \msg_warning:nnnnn { starray } { strict / deprecate } { prg:03 }
                  {  starray_parsed_ #5 : NN#6 T }
                  {  starray_uparsed_ #5 : N#6 T }
                \exp_last_unbraced:NV #1 ##1
              }   
            \cs_new:cpn { starray_parsed_ #5 : NN#6 F } ##1##2
              { 
                \msg_warning:nnnnn { starray } { strict / deprecate } { prg:04 }
                  {  starray_parsed_ #5 : NN#6 F }
                  {  starray_uparsed_ #5 : N#6 F }
                \exp_last_unbraced:NV #2 ##1
              }
          }
          {
            \cs_new:cpn { starray_parsed_ #5 : NN#6 T } ##1##2
              { \exp_last_unbraced:NV #1 ##1  }
          
            \cs_new:cpn { starray_parsed_ #5 : NN#6 F } ##1##2
              { \exp_last_unbraced:NV #2 ##1  }
          }
      }
      {}


    \bool_if:NTF \l__starray_parsed_check_bool
      {
        \cs_new:cpn { starray_parsed_ #5 : #6 T }
          { 
            \bool_if:NTF \g__starray_parsed_bool
              { \exp_args:Noo #1 \g__starray_parsed_saved_term_st_tl \g__starray_parsed_saved_base_st_tl }
              { #9 #3 } %%TODO... this should absorb N+1 and execute none...
          }
        \cs_new:cpn { starray_parsed_ #5 : #6 F }
          { 
            \bool_if:NTF \g__starray_parsed_bool
              { \exp_args:Noo #2 \g__starray_parsed_saved_term_st_tl \g__starray_parsed_saved_base_st_tl }
              { #9 #4 } %%TODO... this should absorb N+1 and execute the last one...
          }
      }
      {
        \cs_new:cpn { starray_parsed_ #5 : #6 F }
          { \exp_args:Noo #1 \g__starray_parsed_saved_term_st_tl \g__starray_parsed_saved_base_st_tl }   
        \cs_new:cpn { starray_parsed_ #5 : #6 T }
          { \exp_args:Noo #2 \g__starray_parsed_saved_term_st_tl \g__starray_parsed_saved_base_st_tl }
      }
  
    \cs_new:cpn { starray_iparsed_ #5 : #6 F }
      { \exp_args:Noo #1 \g__starray_iterate_term_st_tl \g__starray_iterate_base_st_tl }   
    \cs_new:cpn { starray_iparsed_ #5 : #6 T }
      { \exp_args:Noo #2 \g__starray_iterate_term_st_tl \g__starray_iterate_base_st_tl }

    \cs_new:cpn { starray_ #5 : n#6 T } ##1
      { 
        \__starray_parser:NeTF #7 { ##1 }
          { \exp_args:Noo #1 \l__starray_parsed_term_st_tl \l__starray_parsed_base_st_tl }
          { #8 #3 }  %%TODO... this should absorb N+1 and execute none...
      }

    \cs_new:cpn { starray_ #5 : n#6 F } ##1
      { 
        \__starray_parser:NeTF #7 { ##1 }
          { \exp_args:Noo #2 \l__starray_parsed_term_st_tl \l__starray_parsed_base_st_tl }
          { #8 #4 }  %%TODO... this should absorb N+1 and execute the last one...
      }

  }
\cs_generate_variant:Nn \__starray_prg_generate_b:NNnnnnNnn { ccVV , ccee }



%%%%%%%%%
%%%
%%% This will create a pair
%%%                  *none* expandable
%%% #cmd:signature#    => cs,  expecting the #1 as a starray-ref
%%% #cmd:signature#TF  => prg, expecting the #1 as a starray-ref
%%%
%%%%%%%%%
%%%
%%% Regarding the base-code: #1 will always be treated as the starray-ref.
%%% \__starray_return_true: / \__starray_return_false: will be set as
%%%   *nothing* for the cs command
%%%   \prg_return_true: / \prg_return_false: for the prg command
%%%
%%% 'if-parser-failed' code can use all parameters 
%%%
%%%%%%%%%
%%% #1 -> #cmd:signature#           => base-name
%%% #2 -> \c__starray_idx_ending_bool / \c__starray_no_idx_ending_bool
%%% #3 -> base-code                 
%%% #4 -> if-parser-failed
%%%%%%%%%
\regex_const:Nn \c__starray_csa_regex { \c{ prg_return_true: }|\c{ prg_return_false: }}
\regex_const:Nn \c__starray_csb_regex { \c{ __starray_rtn: }}
\regex_const:Nn \c__starray_prg_regex { \c{ __starray_msg_dispatch: }}

\cs_new_protected:Npn \__starray_cs_prg_duo_generate:NNnn #1#2#3
  {
    
    \tl_set:Nn \l__starray_duocmd_tmpb_tl { #3 }
    \regex_replace_all:NnN \c__starray_prg_regex { \c{ __starray_msg_clear: }} \l__starray_duocmd_tmpb_tl

    \tl_set:Nn \l__starray_duocmd_tmpa_tl { #3 }
    \regex_replace_all:NnN \c__starray_csa_regex {} \l__starray_duocmd_tmpa_tl
    \regex_replace_all:NnNTF \c__starray_csb_regex {} \l__starray_duocmd_tmpa_tl
      { \tl_put_left:Nn  \l__starray_duocmd_tmpb_tl \__starray_set_rtn_true: }
      {}
    \__starray_cs_prg_duo_generate_a:NNVVn #1#2\l__starray_duocmd_tmpa_tl \l__starray_duocmd_tmpb_tl
  }

\cs_new_protected:Npn  \__starray_cs_prg_duo_generate_a:NNnnn #1#2#3#4#5
  {
    \prg_new_conditional:Nnn #1 { T , F , TF }
      {
        \__starray_parser:NeTF #2 { ##1 }
          { #4 }
          {
            \__starray_msg_clear:
            \prg_return_false:
          } % returns nothing by default
      }

    \cs_new:Nn #1
      {
        \__starray_parser:NeTF #2 { ##1 }
          { #3 }
          { 
            \__starray_msg_dispatch:
            #5 
          }
      }
  }
\cs_generate_variant:Nn \__starray_cs_prg_duo_generate_a:NNnnn { NNVV }


%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% Package conditionals
%%%%
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%


\prg_new_eq_conditional:NNn \__starray_if_exist:c \cs_if_exist:c { p, T, F, TF }

\prg_new_conditional:Npnn \starray_if_exist:n #1 { p, T, F, TF }
  {
    \__starray_if_exist:cTF { c__starray_prfix_.  #1 _base_ref_st_tl }
      \prg_return_true:
      \prg_return_false:
  }

%
% Note to self: One way would be to test the scan mark \s__end ... but cumbersome.
%
% DEPRECATED, unless some other (simple) test becomes available
%\prg_new_conditional:Npnn \__starray_if_valid:n #1 { p, T, F, TF }
%  {
%    \bool_lazy_and:nnTF { \prop_if_exist_p:c { #1 }} { \prop_item:cn { #1 } { is_starray }}
%      { \prg_return_true: }
%      { \prg_return_false: }
%  }

\prg_new_eq_conditional:NNn \__starray_if_valid:n \cs_if_exist:c { p, T, F, TF }

%\prg_generate_conditional_variant:Nnn \__starray_if_valid:n { e } { p, T, F, TF }


\prg_new_conditional:Npnn \starray_if_valid:n #1 { p, T, F, TF }
  {
    \__starray_if_valid:nTF { c__starray_prfix_.  #1 _ref_st_tl }
      \prg_return_true:
      \prg_return_false:
  }


\tl_const:Nn \c__starray_empty_hash_term_st_tl
  {
    \relax \relax \s__end
  }
  

%%%
%%% This will generate three main commands
%%%      \#cmd# : N #sig#  => idea being the 1st parameter will be a _st variable
%%%      \#cmd# : c #sig#  
%%%      \#cmd# : w #sig#  => the _st variable is already o-expanded
%%% Careful when calling this, the 3rd parameter has to convey a parameter list (add a space after each # )
%%%%%%%%%
%%% #1 -> #cmd#      => base-name
%%% #2 -> #signature#
%%% #3 -> parameter description (the 'p')
%%% #4 -> code                 % if expandable, the resulting commands will also be
%%%%%%%%%
\cs_new_protected:Npn \__starray_cs_wgen:nnnn #1#2#3#4
  {
    \cs_new:cpe { #1:N#2 } ##1
      {
        \exp_not:N \exp_last_unbraced:No \exp_not:c { #1:w#2 } ##1
      }
    \cs_generate_variant:cn { #1:N#2 } { c }
    
    \exp_last_unbraced:Nno \cs_new:cpn { #1:w#2 } #3
      { #4 }
  }


%%%
%%% This will generate three main conditional commands
%%%      \#cmd# : N #sig#TF  => (and c variant) idea being the 1st parameter will be a _st variable
%%%      \#cmd# : w #sig#TF  => the _st variable is already o-expanded
%%% Careful when calling this, the 3rd parameter has to convey a parameter list (add a space after each # )
%%%%%%%%%
%%% #1 -> #cmd#      => base-name
%%% #2 -> #signature#
%%% #3 -> parameter description (the 'p')
%%% #4 -> code                 % if expandable, the resulting commands will also be
%%%%%%%%%
\cs_new_protected:Npn \__starray_prg_wgen:nnnn #1#2#3#4
  {
    \cs_new:cpe { #1:N#2TF } ##1 
      {
        \exp_not:N \exp_last_unbraced:No \exp_not:c { #1:w#2TF } ##1
      }
    \cs_generate_variant:cn { #1:N#2TF } { c }

    \exp_last_unbraced:Nno \prg_new_conditional:cpnn { #1:w#2 } #3 { TF }
      { #4 }
  }

  
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% starray \...._new declarations
%%%%
%%%% Note: the \s__end allows to fast skip to the last iten, if not needed.
%%%%
%%%%%%%%%%%%%%%
\cs_new_protected:Npn \__starray_base_new:nn #1#2
  {
    \int_new:c
      { g__starray_prfix_.  #2 _base_cnt_int }
    \int_new:c
      { g__starray_prfix_.  #2 _base_iter_int }
    \prop_gclear_new_linked:c
      { g__starray_prfix_.  #2 _base_ihash_prop } %% will have { key/hash } => { \term_prop }{ infix-letter }{ i }{ infix }{ stkeys_seq }
      
    \tl_const:ce {  c__starray_prfix_.  #2 _base_st_tl } 
      {
        \exp_not:c { g__starray_prfix_.  #2 _base_ihash_prop }
        \exp_not:c { g__starray_prfix_.  #2 _base_iter_int }
        \exp_not:c { g__starray_prfix_.  #2 _base_cnt_int }
        \exp_not:c { g__starray_prfix_.  #1 _defkeys_prop }
        \exp_not:c { g__starray_prfix_.  #1 _defstkeys_seq }
        { #1 }{ #2 }
        \exp_not:N \s__end
      }
      
  }
%\cs_generate_variant:Nn \__starray_base_new:nn { e }

\cs_new_protected:Npn \__starray_sub_base_new:nnn #1#2#3
  { 
    \__starray_base_new:nn { #1.#3 }{ #2.#3 }
  }

\cs_new_protected:Npn \__starray_new:n #1
  {
    \prop_new_linked:c { g__starray_prfix_.  #1 _defkeys_prop }
    \seq_new:c { g__starray_prfix_.  #1 _defstkeys_seq }
    \tl_const:ce {  c__starray_prfix_.  #1 _ref_st_tl } 
      {
        \exp_not:c { g__starray_prfix_.  #1 _defkeys_prop }
        \exp_not:c { g__starray_prfix_.  #1 _defstkeys_seq }
        { #1 }
        \exp_not:N \s__end
      }
  }


%%%%%%%%%%%%%%%
%%%%
%%%% \starray_new
%%%%
%%%%%%%%%%%%%%%
\cs_new_protected:Npn \starray_new:n #1
  {
    \__starray_if_exist:cTF { c__starray_prfix_. #1 _ref_st_tl }
      {
        \msg_warning:nnnn { starray } { strict / (re)define } { new:1 } { #1 }
      }
      {
        \__starray_new:n { #1 }
        \__starray_base_new:nn { #1 }{ #1 } % TODO: might be incomplete !!!
      }
  }

\prg_new_protected_conditional:Npnn \starray_new:n #1 { T, F, TF }
  {
    \__starray_if_exist:cTF { c__starray_prfix_. #1 _ref_st_tl }
      { \prg_return_false: }
      {
        \__starray_new:n { #1 }
        \__starray_base_new:nn { #1 }{ #1 } % TODO: might be incomplete !!!
        \prg_return_true:
      }
  }

%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% starray ref parser
%%%%
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% get root reference (first term) assuming called as
%%%%   <tl-var> <st-ref> .  \q_stop
%%%% so that even if { ref } (has no dot, no idx) it will return 'the root ref'
%%%% e.g.: \tl_set:Ne \l__tmpb_tl { \__starray_get_root:nw \l__starray_tmpa_tl .  \q_stop }
%%%%
%%%% It will return the 'root ref' assuming that the ref is of form root.name.name (no [idx])
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%
%%% This one can't be protected... it is used in { e } expantion
%%% if protected, it results in a quark loop
%%% 
\cs_new:Npn \__starray_get_root:nw #1 . #2 \q_stop { #1 }
\cs_generate_variant:Nn \__starray_get_root:nw { V }

%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% set root reference (first term) assuming called as
%%%%   <tl-var> <st-ref> . \q_stop
%%%% so that even if { ref } (has no dot, no idx) it will return 'the root ref'
%%%% e.g.:  \__starray_set_root:Nnw \l__tmpb_tl \l__starray_tmpa_tl . \q_stop
%%%%
%%%% It will return the 'root ref' assuming that the ref is of form root.name.name (no [idx])
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
\cs_new_protected:Npn \__starray_set_root:Nnw #1 #2 . #3 \q_stop { \tl_set:Nn #1 { #2 } }
\cs_generate_variant:Nn \__starray_set_root:Nnw { Ne }


%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% adding property #3 (#4 being it's initial/default value)
%%%%    #1 prefix
%%%%    #2 starray
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%


%%% \c__starray...._ref_st_tl
%%%        \c{ -ref- _defkeys_prop }                  %% #1
%%%        \c{ -ref- _defstkeys_seq }                 %% #2
%%%        {-ref-}                                    %% #3
%%%    \s__end
%%%%%%
%%% \__starray_refst_def_prop:Nnn
%%% \__starray_refst_def_prop:cnn
%%% \__starray_refst_def_prop:wnn
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_refst_def_prop }{ nn }{ # 1 # 2 \s__end }
  { 
    \prop_gput:Nnn #1 
  }

%%%%%%%%%%%%%%%
%%%%
%%%% \starray_def_prop
%%%%
%%%%%%%%%%%%%%%
\cs_new_protected:Npn \starray_def_prop:nnn #1#2#3
  {
    \__starray_if_exist:cTF { c__starray_prfix_.  #1 _ref_st_tl }
      { 
        \__starray_refst_def_prop:cnn 
          { c__starray_prfix_.  #1 _ref_st_tl } { #2 } { #3 }
      }
      {
        \msg_warning:nnxxx { starray }{ reference / invalid-starray } 
          { addprop:1 } { #1 } { cannot~add~property:#2 }
      }
  }

\prg_new_protected_conditional:Npnn \starray_def_prop:nnn #1#2#3 { T, F, TF }
  {
    \__starray_if_exist:cTF { c__starray_prfix_.  #1 _ref_st_tl }
      {
        \__starray_refst_def_prop:cnn 
          { c__starray_prfix_.  #1 _ref_st_tl } { #2 } { #3 }
        
        \prg_return_true:
      }
      \prg_return_false:
  }


%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% adding struct array #2 to a starray
%%%%
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%

%%% \c__starray...._ref_st_tl
%%%        \c{ -ref- _defkeys_prop }                  %% #1
%%%        \c{ -ref- _defstkeys_seq }                 %% #2
%%%        {-ref-}                                    %% #3
%%%    \s__end
%%%%%%
%%% \__starray_refst_def_struct:Nn
%%% \__starray_refst_def_struct:cn
%%% \__starray_refst_def_struct:wn
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_refst_def_struct }{ n }{  # 1 # 2 # 3 \s__end # 4 }
  { 
    \seq_if_in:NnF #2 { #4 }
      {
        \seq_gput_right:Nn #2 { #4 } 
        \__starray_new:n { #3 . #4 }
      }
  }

%%%%%%
%%% \__starray_refst_keyval_def_struct:NnN
%%% \__starray_refst_keyval_def_struct:cnN
%%% \__starray_refst_keyval_def_struct:wnN
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_refst_keyval_def_struct }{ nN }{  # 1 # 2 # 3 \s__end # 4 # 5 }
  {
    \tl_set:Nn #5 { #3 }
    \seq_if_in:NnF #2 { #4 }
      {
        \seq_gput_right:Nn #2 { #4 } 
        \__starray_new:n { #3 . #4 }
      }
  }
\cs_generate_variant:Nn \__starray_refst_keyval_def_struct:NnN { Ne }  
  
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% fixing struct _base for already instantiated terms
%%%%
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%

%%% \c__starray_..._term_st_tl
%%%        \c{ -infix- _term_prop }                  %% #1
%%%        { -infix- }                               %% #2
%%%        { -val- }  %% iter's val for this entry   %% #3
%%%        { -idx- }                                 %% #4
%%%        \c{ -ref- _defstkeys_prop }                %% #5
%%%    \s__end
%%%%%%
%%% \__starray_termst_fix_terms:Nnn
%%% \__starray_termst_fix_terms:cnn
%%% \__starray_termst_fix_terms:wnn
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_termst_fix_terms }{ nn }{  # 1 # 2 # 3 \s__end # 4 # 5 }
  {
    \__starray_if_exist:cTF { c__starray_prfix_.  #2 . #5 _base_st_tl }
      {
        \__starray_basest_fix_terms:c 
          { c__starray_prfix_.  #2 . #5 _base_st_tl }
      }
      {
        \__starray_base_new:nn { #4 . #5 } { #2 . #5 }
      }
  }

%%% \c__starray_..._base_st_tl
%%%        \c{ -infix- _ihash_prop }                   %% #1
%%%        \c{ -infix- _base_iter_int }               %% #2
%%%        \c{ -infix- _base_cnt_int }                %% #3
%%%        \c{ -ref- _defkeys_prop }                   %% #4
%%%        \c{ -ref- _defstkeys_prop }                 %% #5
%%%        {-ref-}{-infix-}                           %% #6#7
%%%    \s__end
%%%%%%
%%% \__starray_basest_fix_terms:N
%%% \__starray_basest_fix_terms:c
%%% \__starray_basest_fix_terms:w
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_basest_fix_terms }{}{ # 1 # 2 # 3 # 4 # 5 # 6 # 7 \s__end }
  {
    \prop_if_empty:NF #1
      {
        \prop_map_inline:Nn #1
          { %%% ##1 will be idx/hash ##2 will be _term_st_tl
            \seq_map_inline:Nn #5  
              {  
                \__starray_termst_fix_terms:wnn
                  ##2 { #6 }{ ####1 }  
              }
          }
      }  
  }

\cs_new_protected:Npn \starray_fix_terms:n #1
  {
    \tl_set:Nn \l__starray_tmpb_tl { #1 }
    \__starray_set_root:New 
      \l__starray_tmpb_tl 
      \l__starray_tmpb_tl  .  \q_stop
  
    \__starray_if_exist:cTF {  c__starray_prfix_.  \l__starray_tmpb_tl _ref_st_tl }
      {
        \__starray_basest_fix_terms:c 
          {  c__starray_prfix_.  \l__starray_tmpb_tl _base_st_tl }
      }
      {
        \msg_warning:nnxxx { starray }{ reference / invalid-starray } 
          { fixterms:1 } { #1 } {}
      }
  }

%%%%%%%%%%%%%%%
%%%%
%%%% \starray_def_struct
%%%%
%%%%%%%%%%%%%%%
\cs_new_protected:Npn \starray_def_struct:nn #1#2
  {
    \__starray_if_exist:cTF {  c__starray_prfix_.  #1 _ref_st_tl }
      {
        \__starray_refst_def_struct:cn 
          { c__starray_prfix_.  #1 _ref_st_tl } { #2 }
      }
      {
        \msg_warning:nnxxx { starray }{ reference / invalid-starray } 
          { addstruct:1 } { #1 } { cannot~add~structure:#2 }
      }
  }


\prg_new_protected_conditional:Npnn \starray_def_struct:nn #1#2 { T, F, TF }
  {
    \__starray_if_exist:cTF {  c__starray_prfix_.  #1 _ref_st_tl }
      {
        \__starray_refst_def_struct:cn 
          { c__starray_prfix_.  #1 _ref_st_tl } { #2 }
        \prg_return_true:
      }
      { \prg_return_false: }
  }


%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% adding prop/struct from keyval
%%%%
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%


%\prg_new_conditional:Npnn \__starray_def_from_keyval_testdot_aux:w  #1 . \q_nil { TF }
%  {
%    \str_compare:nNnTF { #1 } = { struct }
%      { \prg_return_true: }
%      { \prg_return_false: }
%  }

%%% This expects 3 parameters the last two are being used by \str_compare:
\cs_new:Npn \__starray_def_from_keyval_testdot_aux:wTF  #1 . \q_nil
  {
    \str_compare:nNnTF { #1 } = { struct }
  }


%
% This can't be protected (\tl_set:Ne isn't expandable) but only the TF form matters.
%
\prg_new_conditional:Npnn \__starray_def_from_keyval_testdot:w  #1 . #2 \q_stop { TF }
  {
    \quark_if_nil:nTF { #2 }
      {
        \prg_return_false:
      } % no dot, OK
      {
        \__starray_def_from_keyval_testdot_aux:wTF #2
          {
            \tl_set:Nn \l__starray_keyval_tmpb_tl { #1 }
            \prg_return_true:
          } % dot struct, OK
          {
            \prg_return_false:
          } %% possible syntax ERR (dot, but not struct!)
      }
  }

\cs_new_protected:Npn \__starray_def_from_keyval_parse:Nnn #1#2#3
  {
      \__starray_def_from_keyval_testdot:wTF #2 . \q_nil \q_stop
        { 
          \__starray_refst_keyval_def_struct:NeN #1 
            \l__starray_keyval_tmpb_tl 
            \l__starray_keyval_tmpa_tl
          
          \keyval_parse:een 
            { 
              \exp_not:N \__starray_def_from_keyval_parse:Nn  
                \exp_not:c { c__starray_prfix_. \l__starray_keyval_tmpa_tl . \l__starray_keyval_tmpb_tl _ref_st_tl } 
            }
            { 
              \exp_not:N \__starray_def_from_keyval_parse:Nnn 
                \exp_not:c { c__starray_prfix_. \l__starray_keyval_tmpa_tl . \l__starray_keyval_tmpb_tl _ref_st_tl } 
            }
            { #3 }
        }
        { % #1 should be ..._ref_st_tl
          \__starray_refst_def_prop:Nnn #1 { #2 }{ #3 }
        }
  }

\cs_new_protected:Npn \__starray_def_from_keyval_parse:Nn #1#2
  { % #1 should be _ref_st_tl 
    \__starray_refst_def_prop:Nnn #1 { #2 }{}
  }



%%%%%%%%%%%%%%%
%%%%
%%%% \starray_def_from_keyval
%%%%
%%%%%%%%%%%%%%%
\cs_new_protected:Npn \starray_def_from_keyval:nn #1#2
  {
    \__starray_if_exist:cTF {  c__starray_prfix_.  #1 _ref_st_tl }
      { 
        \keyval_parse:een
          { \exp_not:N \__starray_def_from_keyval_parse:Nn  \exp_not:c { c__starray_prfix_.  #1 _ref_st_tl } }
          { \exp_not:N \__starray_def_from_keyval_parse:Nnn \exp_not:c { c__starray_prfix_.  #1 _ref_st_tl } }
          { #2 }
      }
      {
        \msg_warning:nnxxx { starray }{ reference / invalid-starray } 
          { addkeyval:1 } { #1 } { cannot~add:#2 }
      }
  }

\prg_new_protected_conditional:Npnn \starray_def_from_keyval:nn #1#2 { T, F, TF }
  {
    \__starray_if_exist:cTF { c__starray_prfix_.  #1 _ref_st_tl }
      { 
        \keyval_parse:een
          { \exp_not:N \__starray_def_from_keyval_parse:Nn  \exp_not:c { c__starray_prfix_.  #1 _ref_st_tl } }
          { \exp_not:N \__starray_def_from_keyval_parse:Nnn \exp_not:c { c__starray_prfix_.  #1 _ref_st_tl } }
          { #2 }
        \prg_return_true:
      }
      { \prg_return_false: }
  }


%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% adding terms
%%%%
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%

%%% \c__starray_..._base_st_tl
%%%        \c{ -infix- _ihash_prop }                   %% #1
%%%        \c{ -infix- _base_iter_int }               %% #2
%%%        \c{ -infix- _base_cnt_int }                %% #3
%%%        \c{ -ref- _defkeys_prop }                   %% #4
%%%        \c{ -ref- _defstkeys_prop }                 %% #5
%%%        {-ref-}{-infix-}                           %% #6#7
%%%    \s__end
%%%%%%
%%% \__starray_basest_new_term:Nn
%%% \__starray_basest_new_term:cn
%%% \__starray_basest_new_term:wn
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_basest_new_term }{ n }{ # 1 # 2 # 3 # 4 # 5 # 6 # 7\s__end # 8 }
  {
    \int_gincr:N #3

    \int_gset_eq:NN #2 #3

    \tl_set:Ne \l__starray_tmpa_tl
      { \int_to_Alph:n #3 }

    \prop_gput:Nee #1
      { \int_use:N #3 }
      {
        \exp_not:c {  g__starray_prfix_.  #7 _ \l__starray_tmpa_tl _term_prop }
        { #7 _ \l__starray_tmpa_tl }
        { \int_use:N #3 }
        { \l__starray_tmpa_tl }
        \exp_not:N #5
        \exp_not:N \s__end
      }
      
    \tl_if_blank:nF { #8 }
      {
        \prop_gput:Nee #1
          { #8 }
          {
            \exp_not:c {  g__starray_prfix_.  #7 _ \l__starray_tmpa_tl _term_prop }
            { #7 _ \l__starray_tmpa_tl }
            { \int_use:N #3 }
            { \l__starray_tmpa_tl }
            \exp_not:N #5
            \exp_not:N \s__end
          }
      }

   \prop_new_linked:c
      {  g__starray_prfix_.  #7 _ \l__starray_tmpa_tl _term_prop }
   \prop_gset_eq:cN
      {  g__starray_prfix_.  #7 _ \l__starray_tmpa_tl _term_prop }
      #4

% map over 'all sub-starrays parts of def_ref -> st_seq (those starting with a dot, @st_seq)
    \cs_set:Npe \__starray_sub_aux:n 
      {
        \exp_not:N \__starray_sub_base_new:nnn
          { #6 }{ #7 _ \l__starray_tmpa_tl }
      }
    \seq_map_inline:Nn #5
      { \__starray_sub_aux:n { ##1 } }
  }

%%%%%%%%%%%%%%%
%%%%
%%%% \starray_new_term
%%%%
%%%%%%%%%%%%%%%

\cs_new_protected:Npn \starray_new_term:nn #1#2
  {
    \__starray_parser:NeTF \c__starray_no_idx_ending_bool { #1 }
      {
        \__starray_basest_new_term:Nn
          \l__starray_parsed_base_st_tl { #2 }
      }
      {
        \__starray_msg_dispatch:
        \msg_warning:nnnn { starray }{ syntax /  term }{ addterm:2 }{ #1 }
      }
  }


\prg_new_protected_conditional:Npnn \starray_new_term:nn #1#2 { T, F, TF }
  {
    \__starray_parser:NeTF \c__starray_no_idx_ending_bool { #1 }
      {
        \__starray_basest_new_term:Nn
          \l__starray_parsed_base_st_tl { #2 }
        \prg_return_true:
      }
      { \prg_return_false: }
  }


%%% \c__starray_..._term_st_tl
%%%        \c{ -infix- _term_prop }                  %% #1
%%%        { -infix- }                               %% #2
%%%        { -val- }  %% iter's val for this entry   %% #3
%%%        { -idx- }                                 %% #4
%%%        \c{ -ref- _defstkeys_prop }                %% #5
%%%    \s__end
%%%%%%
%%% \__starray_termst_get_infix:NN
%%% \__starray_termst_get_infix:cN
%%% \__starray_termst_get_infix:wN
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_termst_get_infix }{ N }{ # 1 # 2 # 3 \s__end # 4 }
  { 
    \tl_set:Nn #4 { #2 } 
  }

%%%%%%%%
%%%%% \__starray_termst_get_iterx:NNN
%%%%% \__starray_termst_get_iterx:cNN
%%%%% \__starray_termst_get_iterx:wNN
%%%%%%%%
%%\__starray_cs_wgen:nnnn
%%  { __starray_termst_get_iterx }{ NN }{  # 1 # 2 # 3 # 4 \s__end # 5 # 6 }
%%  { 
%%    \tl_set:Nn #5 { #3 } 
%%    \tl_set:Nn #6 { #2 } 
%%  }

%%%%%%
%%% \__starray_termst_get_iterval:NN
%%% \__starray_termst_get_iterval:cN
%%% \__starray_termst_get_iterval:wN
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_termst_get_iterval }{ N }{  # 1 # 2 # 3 # 4 \s__end # 5 }
  { 
    \tl_set:Nn #5 { #3 } 
  }

\cs_new:Npn \__starray_cascade_aux:nN #1#2
  {
    \seq_map_inline:Nn #2
      {
        \__starray_basest_set_iter:cnTF 
          { c__starray_prfix_. #1 . ##1 _base_st_tl } { 1 }
          {} {}
      }
  }
\cs_generate_variant:Nn  \__starray_cascade_aux:nN { o }


\bool_if:NTF \l__starray_cascade_bool
  {
    \cs_new:Npn \__starray_iter_cascade:NNN #1#2#3
      {
        \prop_get:NeN #1 
          { \int_use:N #2 } \l__starray_tmp_term_st_tl
        
        \__starray_termst_get_infix:NN
          \l__starray_tmp_term_st_tl \l__starray_tmp_infix_tl 
          
        \__starray_cascade_aux:oN 
          \l__starray_tmp_infix_tl #3
      }
  }
  {
    \cs_new:Npn \__starray_iter_cascade:NNN #1#2#3
      { }
  }

%%% \c__starray_..._base_st_tl
%%%        \c{ -infix- _ihash_prop }                   %% #1
%%%        \c{ -infix- _base_iter_int }               %% #2
%%%        \c{ -infix- _base_cnt_int }                %% #3
%%%        \c{ -ref- _defkeys_prop }                   %% #4
%%%        \c{ -ref- _defstkeys_prop }                 %% #5
%%%        {-ref-}{-infix-}                           %% #6#7
%%%    \s__end
%%%%%%
%%% \__starray_basest_set_iter:NnTF
%%% \__starray_basest_set_iter:cnTF
%%% \__starray_basest_set_iter:wnTF
%%%%%%
\__starray_prg_wgen:nnnn
  { __starray_basest_set_iter }{ n }{ # 1 # 2 # 3 # 4 # 5 # 6 \s__end # 7 }
  {
    \int_compare:nNnTF { #7 } > { #3 }
      {
        \int_gset_eq:NN #2 #3  

        \int_compare:nNnTF #2 = \c_zero_int
          { }
          {
            \__starray_iter_cascade:NNN #1 #2 #5
          }

        \prg_return_false:
      }
      {
        \int_gset:Nn #2 { #7 }

        \__starray_iter_cascade:NNN #1 #2 #5

        \prg_return_true:
      }    
  }

%%%%%%
%%% \__starray_basest_incr_iter:NTF
%%% \__starray_basest_incr_iter:cTF
%%% \__starray_basest_incr_iter:wTF
%%%%%%
\__starray_prg_wgen:nnnn
  { __starray_basest_incr_iter }{}{ # 1 # 2 # 3 # 4 # 5 # 6 \s__end }
  {
    \int_compare:nNnTF { #2 } = { #3 }
      {
        \prg_return_false:
      }
      {
        \int_gincr:N #2

        \__starray_iter_cascade:NNN #1 #2 #5

        \prg_return_true:
      }    
  }

%%%%%%
%%% \__starray_basest_set_iter_from_hash:NnTF
%%% \__starray_basest_set_iter_from_hash:cnTF
%%% \__starray_basest_set_iter_from_hash:wnTF
%%%%%%
\__starray_prg_wgen:nnnn
  { __starray_basest_set_iter_from_hash }{ n }{ # 1 # 2 # 3 # 4 # 5 # 6 # 7 \s__end # 8 }
  {
    \prop_get:NeNTF #1 { #8 } \l__starray_tmp_term_st_tl
      {
        \__starray_termst_get_iterval:NN
          \l__starray_tmp_term_st_tl 
          \l__starray_tmpb_tl
        \int_gset:Nn #2 \l__starray_tmpb_tl

        \__starray_iter_cascade:NNN #1 #2 #5
        
        \prg_return_true:
      }
      {
        \prg_return_false:
      }
  }
\prg_generate_conditional_variant:Nnn \__starray_basest_set_iter_from_hash:Nn { Ne } { TF }


%%%%%%%%%%%%%%%
%%%%
%%%% \starray_set_iter
%%%%
%%%%%%%%%%%%%%%


%%%%%%%%%%%%%%%
%%% \starray_set_iter_from_hash:nn
%%% \starray_set_iter_from_hash:nnTF
%%%%%%%%%%%%%%%
\__starray_cs_prg_duo_generate:NNnn
  \starray_set_iter_from_hash:nn
  \c__starray_no_idx_ending_bool
  {
    \__starray_basest_set_iter_from_hash:NeTF
      \l__starray_parsed_base_st_tl { #2 }
      {}  
      { 
        \__starray_msg:nnnnn { reference /  iter } { iterhash:1 } { #1 }{ #2 }{-here-}
        \__starray_msg_dispatch:
        \__starray_set_rtn_false: 
      }
    \__starray_rtn:
  }
  {
        \msg_warning:nnnn { starray } { syntax /  iter } { iter:1 } { #1 }
  }
  




%%%%%%%%%%%%%%%
%%% \starray_set_iter:nn
%%% \starray_set_iter:nnTF
%%%%%%%%%%%%%%%
\__starray_cs_prg_duo_generate:NNnn
  \starray_set_iter:nn
  \c__starray_no_idx_ending_bool
  {
    \int_compare:nNnTF { #2 } < { 1 }
      { 
        \__starray_basest_set_iter:NnTF
          \l__starray_parsed_base_st_tl { 1 }
          {}{}

        \prg_return_false:
      }
      {
        \__starray_basest_set_iter:NnTF
          \l__starray_parsed_base_st_tl { #2 }
          {}  { \__starray_set_rtn_false: }

        \__starray_rtn:
      }
  }
  {
        \__starray_msg_dispatch:
        \msg_warning:nnnn { starray } { syntax /  iter } { iter:1 } { #1 }
  }




%%%%%%%%%%%%%%%
%%% \starray_reset_iter:n
%%% \starray_reset_iter:nTF
%%%%%%%%%%%%%%%
\__starray_cs_prg_duo_generate:NNnn
  \starray_reset_iter:n
  \c__starray_no_idx_ending_bool
  {
    \__starray_basest_set_iter:NnTF
      \l__starray_parsed_base_st_tl { 1 }
      {}  { \__starray_set_rtn_false: }

    \__starray_rtn:
  }
  {
        \msg_warning:nnnn { starray } { syntax /  iter } { iter:4 } { #1 }
  }

       

%%%%%%%%%%%%%%%
%%% \starray_next_iter:n
%%% \starray_next_iter:nTF
%%%%%%%%%%%%%%%
\__starray_cs_prg_duo_generate:NNnn
  \starray_next_iter:n
  \c__starray_no_idx_ending_bool
  {
    \__starray_basest_incr_iter:NTF
      \l__starray_parsed_base_st_tl
      {}  { \__starray_set_rtn_false: }

    \__starray_rtn:
  }
  {
        \msg_warning:nnnn { starray } { syntax /  iter } { iter:5 } { #1 }
  }


%%% \c__starray_..._base_st_tl
%%%        \c{ -infix- _ihash_prop }                   %% #1
%%%        \c{ -infix- _base_iter_int }               %% #2
%%%        \c{ -infix- _base_cnt_int }                %% #3
%%%        \c{ -ref- _defkeys_prop }                   %% #4
%%%        \c{ -ref- _defstkeys_prop }                 %% #5
%%%        {-ref-}{-infix-}                           %% #6#7
%%%    \s__end
%%%%%%
%%% \__starray_basest_get_term:NN
%%% \__starray_basest_get_term:cN
%%% \__starray_basest_get_term:wN
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_basest_get_term }{ N }{ # 1 # 2 # 3 \s__end # 4 }
  {
    \prop_get:NeN #1 { \int_use:N #2 } \l__starray_tmp_term_st_tl
    \tl_gset_eq:NN #4 \l__starray_tmp_term_st_tl
  }



\RequirePackage{ tokglobalstack }

\globalstack_csnew:n    { __starray_istack }
\cs_generate_variant:Nn \__starray_istack_gpush:n { e }

\cs_new_protected:Npn \__starray_istack_push:
  {
    \bool_if:NTF \g__starray_iterate_bool
      {
        \__starray_istack_gpush:e
          {
            \exp_not:N \tl_gset:Nn   \exp_not:N \g__starray_iterate_base_st_tl { \exp_not:o \g__starray_iterate_base_st_tl }
            \exp_not:N \tl_gset:Nn   \exp_not:N \g__starray_iterate_term_st_tl { \exp_not:o \g__starray_iterate_term_st_tl }
            \exp_not:N \bool_gset_true:N \exp_not:N \g__starray_iterate_bool
          }        
      }
      {
        \__starray_istack_gpush:e
          {
            \exp_not:N \tl_gset:Nn   \exp_not:N \g__starray_iterate_base_st_tl { \exp_not:o \g__starray_iterate_base_st_tl }
            \exp_not:N \tl_gset:Nn   \exp_not:N \g__starray_iterate_term_st_tl { \exp_not:o \g__starray_iterate_term_st_tl }
            \exp_not:N \bool_gset_false:N \exp_not:N \g__starray_iterate_bool
          }        
      }      
  }
\cs_set_eq:NN \__starray_istack_pop: \__starray_istack_gpop:

\bool_new:N \g__starray_iterate_bool
\tl_new:N   \g__starray_iterate_base_st_tl
\tl_new:N   \g__starray_iterate_term_st_tl


%%%%%%%%%%%%%%%
%%%
%%% \starray_iterate_over:nn
%%% \starray_iterate_over:nnTF
%%%
%%%%%%%%%%%%%%%
\__starray_cs_prg_duo_generate:NNnn
  \starray_iterate_over:nn
  \c__starray_no_idx_ending_bool
  {
    \__starray_istack_push:

    \tl_gset_eq:NN \g__starray_iterate_base_st_tl \l__starray_parsed_base_st_tl
    \bool_gset_true:N \g__starray_iterate_bool

    \__starray_basest_set_iter:NnTF
      \g__starray_iterate_base_st_tl { 1 }
      {
        \__starray_basest_get_term:NN
          \g__starray_iterate_base_st_tl
          \g__starray_iterate_term_st_tl
        \bool_do_while:Nn \g__starray_iterate_bool
          {
            #2

            \__starray_basest_incr_iter:NTF
              \g__starray_iterate_base_st_tl
              {
                \__starray_basest_get_term:NN
                  \g__starray_iterate_base_st_tl
                  \g__starray_iterate_term_st_tl
              }
              { 
                \bool_gset_false:N \g__starray_iterate_bool
              }
          }
          \__starray_msg_clear:  %% to clear the  "iter_incr" warning/error

          \__starray_set_rtn_true: 
      }  
      { 
        \__starray_msg:nnnn { syntax /  iter } { iter:6a } { #1 } {} 
        \__starray_msg_dispatch:

        \__starray_set_rtn_false: 
      }
    \__starray_istack_pop:
    \__starray_rtn:
  }
  {
        \msg_warning:nnnn { starray } { syntax /  iter } { iter:6 } { #1 }
  }



%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% set/get properties
%%%%
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%


%%% \c__starray_..._term_st_tl
%%%        \c{ -infix- _term_prop }                  %% #1
%%%        { -infix- }                               %% #2
%%%        { -val- }  %% iter's val for this entry   %% #3
%%%        { -idx- }                                 %% #4
%%%        \c{ -ref- _defstkeys_prop }                %% #5
%%%    \s__end
%%%%%%
%%% \__starray_termst_get_prop:Nn
%%% \__starray_termst_get_prop:cn
%%% \__starray_termst_get_prop:wn
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_termst_get_prop }{ n }{ # 1 # 2 \s__end # 3 }
  {
    \prop_item:Nn #1 { #3 }
  }

%%%%%%%%%%%%%%%
%%% \starray_get_prop:nn
%%% \starray_parsed_get_prop:Nn
%%% \starray_parsed_get_prop:n => checked/nocheck
%%%%%%%%%%%%%%%
\__starray_cs_generate:nnNnnn 
  { get_prop }{ n } \c__starray_idx_ending_bool
  {
    \__starray_termst_get_prop:wn #1 { #3 }
  }
  {
    \__starray_msg_dispatch:
    \msg_warning:nnnn { starray } { syntax /  prop } 
      { get:1 } { #1 }
  } % returns nothing by default
  {
    \msg_warning:nnnn { starray } { syntax /  parsed } 
      { parsed:1 } { \starray_parsed_get_prop:n }
  }
  

%%% \c__starray_..._term_st_tl
%%%        \c{ -infix- _term_prop }                  %% #1
%%%        { -infix- }                               %% #2
%%%        { -val- }  %% iter's val for this entry   %% #3
%%%        { -idx- }                                 %% #4
%%%        \c{ -ref- _defstkeys_prop }                %% #5
%%%    \s__end
%%%%%%
%%% \__starray_termst_get_prop:NnN
%%% \__starray_termst_get_prop:cnN
%%% \__starray_termst_get_prop:wnN
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_termst_get_prop }{ nN }{ # 1 # 2 \s__end # 3 # 4 }
  {
    \prop_get:NnNF #1 { #3 } #4
      { \tl_clear:N #4 }
  }

%%%%%%
%%% \__starray_termst_get_propTF:NnN
%%% \__starray_termst_get_propTF:cnN
%%% \__starray_termst_get_propTF:wnN
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_termst_get_propTF }{ nN }{ # 1 # 2 \s__end # 3 # 4 }
  {
    \prop_get:NnNTF #1 { #3 } #4
      { \prg_return_true: }
      { 
        \tl_clear:N #4
        \prg_return_false:
      }
  }


%%%%%%%%%%%%%%%
%%% \starray_get_prop:nnN
%%% \starray_parsed_get_prop:NNnN
%%% \starray_parsed_get_prop:nN => checked/nocheck
%%%%%%%%%%%%%%%
\__starray_cs_generate:nnNnnn 
  { get_prop }{ nN }  \c__starray_idx_ending_bool
  {
    \__starray_termst_get_prop:wnN #1
      { #3 } #4    
  }
  {
    \__starray_msg_dispatch:
    \msg_warning:nnnn { starray } { syntax /  prop } 
      { get:2 } { #1 }
  } % returns nothing by default
  {
    \msg_warning:nnnn { starray } { syntax /  parsed } 
      { parsed:2 } { \starray_parsed_get_prop:nN }
  }
  

%%%%%%%%%%%%%%%
%%%
%%% \starray_get_prop:nnN
%%% \starray_parsed_get_prop:NNnN
%%% \starray_parsed_get_prop:nN => checked/nocheck
%%%
%%%%%%%%%%%%%%%
\__starray_prg_generate:nnNnnn 
  { get_prop }{ nN } \c__starray_idx_ending_bool
  {
    \__starray_termst_get_propTF:wnN #1
      { #3 } #4    
  }
  { \__starray_msg_clear: }  %% This will be F case of \__starray_parser:NeTF, not expandable anyway
  { }                                   %% This will be F case of \bool_if:NTF

\__starray_prg_undef_p:nn { get_prop }{ nN }


%%% \c__starray_..._term_st_tl
%%%        \c{ -infix- _term_prop }                  %% #1
%%%        { -infix- }                               %% #2
%%%        { -val- }  %% iter's val for this entry   %% #3
%%%        { -idx- }                                 %% #4
%%%        \c{ -ref- _defstkeys_prop }                %% #5
%%%    \s__end
%%%%%%
%%% \__starray_termst_if_inTF:Nn
%%% \__starray_termst_if_inTF:cn
%%% \__starray_termst_if_inTF:wn
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_termst_if_inTF }{ n }{ # 1 # 2 \s__end # 3 }
  {
    \prop_if_in:NnTF #1 { #3 }
      \prg_return_true:
      \prg_return_false:
  }


%%%%%%%%%%%%%%%
%%% \starray_if_in:nnTF 
%%% \starray_parsed_if_in:NNnTF
%%% \starray_parsed_if_in:nNTF => checked/nocheck
%%%%%%%%%%%%%%%
\__starray_prg_generate:nnNnnn 
  { if_in }{ n } \c__starray_idx_ending_bool
  {
    \__starray_termst_if_inTF:wn #1 { #3 }
  }
  { \__starray_msg_clear:  } %% This will be F case of \__starray_parser:NeTF, not expandable anyway
  { }                                   %% This will be F case of \bool_if:NTF
  


%%% \c__starray_..._base_st_tl
%%%        \c{ -infix- _ihash_prop }                   %% #1
%%%        \c{ -infix- _base_iter_int }               %% #2
%%%        \c{ -infix- _base_cnt_int }                %% #3
%%%        \c{ -ref- _defkeys_prop }                   %% #4
%%%        \c{ -ref- _defstkeys_prop }                 %% #5
%%%        {-ref-}{-infix-}                           %% #6#7
%%%    \s__end
%%%%%%
%%% \__starray_basest_get_cnt:N
%%% \__starray_basest_get_cnt:c
%%% \__starray_basest_get_cnt:w
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_basest_get_cnt }{}{ # 1 # 2 # 3 # 4 \s__end }
  { \int_use:N #3 }

%%%%%%
%%% \__starray_basest_get_cnt:NN
%%% \__starray_basest_get_cnt:cN
%%% \__starray_basest_get_cnt:wN
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_basest_get_cnt }{ N }{ # 1 # 2 # 3 # 4 \s__end # 5 }
  { \int_set_eq:NN #5 #3 }

%%%%%%
%%% \__starray_basest_get_iter:N
%%% \__starray_basest_get_iter:c
%%% \__starray_basest_get_iter:w
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_basest_get_iter }{}{ # 1 # 2 # 3 \s__end }
  { \int_use:N #2 }

%%%%%%
%%% \__starray_basest_get_iter:NN
%%% \__starray_basest_get_iter:cN
%%% \__starray_basest_get_iter:wN
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_basest_get_iter }{ N }{ # 1 # 2 # 3 \s__end # 4 }
  { \int_set_eq:NN #4 #2 }


%%%%%%%%%%%%%%%
%%% \starray_get_cnt:n
%%% \starray_parsed_get_cnt:NN
%%% \starray_parsed_get_cnt: => checked/nocheck
%%%%%%%%%%%%%%%
\__starray_cs_generate:nnNnnn 
  { get_cnt }{}  \c__starray_no_idx_ending_bool
  {
    \__starray_basest_get_cnt:w #2 
  } 
  {
    \__starray_msg_dispatch:
    \msg_warning:nnnn { starray } { syntax /  prop } 
      { get:3 } { #1 }
  } % returns nothing by default
  {
    \msg_warning:nnnn { starray } { syntax /  parsed } 
      { parsed:3 } { \starray_parsed_get_cnt: }
  }
  

%%%%%%%%%%%%%%%
%%% \starray_get_cnt:nN
%%% \starray_parsed_get_cnt:NNN
%%% \starray_parsed_get_cnt:N => checked/nocheck
%%%%%%%%%%%%%%%
\__starray_cs_generate:nnNnnn 
  { get_cnt }{ N }  \c__starray_no_idx_ending_bool
  {
    \__starray_basest_get_cnt:wN #2 #3
  }
  {
    \__starray_msg_dispatch:
    \msg_warning:nnnn { starray } { syntax /  prop } 
      { get:4 } { #1 }
  } % returns nothing by default
  {
    \msg_warning:nnnn { starray } { syntax /  parsed } 
      { parsed:4 } { \starray_parsed_get_cnt:N }
  }
  


%%%%%%%%%%%%%%%
%%% \starray_get_cnt:nNTF
%%% \starray_parsed_get_cnt:NNNTF
%%% \starray_parsed_get_cnt:NTF => checked/nocheck
%%%%%%%%%%%%%%%
\__starray_prg_generate:nnNnnn 
  { get_cnt }{ N } \c__starray_no_idx_ending_bool
  {
    \__starray_basest_get_cnt:wN #2 #3
    \prg_return_true:
  }
  { \__starray_msg_clear:  }  %% This will be F case of \__starray_parser:NeTF, not expandable anyway
  { }                                    %% This will be F case of \bool_if:NTF

\__starray_prg_undef_p:nn { get_cnt }{ N }



%%%%%%%%%%%%%%%
%%%
%%% \starray_get_iter:n
%%% \starray_parsed_get_iter:NN
%%% \starray_parsed_get_iter: => checked/nocheck
%%%
%%%%%%%%%%%%%%%
\__starray_cs_generate:nnNnnn 
  { get_iter }{}  \c__starray_no_idx_ending_bool
  {
    \__starray_basest_get_iter:w #2
  }
  {
    \__starray_msg_dispatch:
    \msg_warning:nnnn { starray } { syntax /  prop } 
      { get:5 } { #1 }
  } % returns nothing by default
  {
    \msg_warning:nnnn { starray } { syntax /  parsed } 
      { parsed:5 } { \starray_parsed_get_iter: }
  }



%%%%%%%%%%%%%%%
%%% \starray_get_iter:nN
%%% \starray_parsed_get_iter:NNN
%%% \starray_parsed_get_iter:N => checked/nocheck
%%%%%%%%%%%%%%%
\__starray_cs_generate:nnNnnn 
  { get_iter }{ N }  \c__starray_no_idx_ending_bool
  {
    \__starray_basest_get_iter:wN #2 #3
  }
  {
    \__starray_msg_dispatch:
    \msg_warning:nnnn { starray } { syntax /  prop } 
      { get:6 } { #1 }
  } % returns nothing by default
  {
    \msg_warning:nnnn { starray } { syntax /  parsed } 
      { parsed:6 } { \starray_parsed_get_iter:N }
  }


%%%%%%%%%%%%%%% 
%%% \starray_get_iter:nnTF 
%%% \starray_parsed_get_iter:NNnTF
%%% \starray_parsed_get_iter:nNTF => checked/nocheck
%%%%%%%%%%%%%%%
\__starray_prg_generate:nnNnnn 
  { get_iter }{ N } \c__starray_no_idx_ending_bool
  {
    \__starray_basest_get_iter:wN #2 #3
    \prg_return_true:
  }
  { \__starray_msg_clear:  } %% This will be F case of \__starray_parser:NeTF, not expandable anyway
  { }                                   %% This will be F case of \bool_if:NTF

\__starray_prg_undef_p:nn
  { get_iter }{ N }



%%% \c__starray_..._term_st_tl
%%%        \c{ -infix- _term_prop }                  %% #1
%%%        { -infix- }                               %% #2
%%%        { -val- }  %% iter's val for this entry   %% #3
%%%        { -idx- }                                 %% #4
%%%        \c{ -ref- _defstkeys_prop }                %% #5
%%%    \s__end
%%%%%%
%%% \__starray_termst_get_unique_id:NN
%%% \__starray_termst_get_unique_id:cN
%%% \__starray_termst_get_unique_id:wN
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_termst_get_unique_id }{ N }{ # 1 # 2 # 3 \s__end # 4 }
  {
    \tl_set:Nn #4 { #2 }
  }

%%%%%%%%%%%%%%%
%%%
%%% \starray_get_unique_id:nN
%%% \starray_parsed_get_unique_id:NNN
%%% \starray_parsed_get_unique_id:N => checked/nocheck
%%%
%%%%%%%%%%%%%%%
\__starray_cs_generate:nnNnnn 
  { get_unique_id }{ N }  \c__starray_idx_ending_bool
  {
    \__starray_termst_get_unique_id:wN #1 #3
  }
  {
    \__starray_msg_dispatch:
    \msg_warning:nnnn { starray } { syntax /  prop } 
      { get:7 } { #1 }
  } % returns nothing by default
  {
    \msg_warning:nnnn { starray } { syntax /  parsed } 
      { parsed:7 } { \starray_parsed_get_unique_id:N }
  }


%%%%%%%%%%%%%%% 
%%%
%%% \starray_get_unique_id:nNTF 
%%% \starray_parsed_get_unique_id:NNNTF
%%% \starray_parsed_get_unique_id:NTF => checked/nocheck
%%%
%%%%%%%%%%%%%%%
\__starray_prg_generate:nnNnnn 
  { get_unique_id }{ N } \c__starray_idx_ending_bool
  {
    \__starray_termst_get_unique_id:wN #1 #3
    \prg_return_true:
  }
  { \__starray_msg_clear:  } %% This will be F case of \__starray_parser:NeTF, not expandable anyway
  { }                                   %% This will be F case of \bool_if:NTF

\__starray_prg_undef_p:nn
  { get_unique_id }{ N }


%%% \c__starray_..._term_st_tl
%%%        \c{ -infix- _term_prop }                  %% #1
%%%        { -infix- }                               %% #2
%%%        { -val- }  %% iter's val for this entry   %% #3
%%%        { -idx- }                                 %% #4
%%%        \c{ -ref- _defstkeys_prop }                %% #5
%%%    \s__end
%%%%%%
%%% \__starray_termst_set_prop:NNnn
%%% \__starray_termst_set_prop:cNnn
%%% \__starray_termst_set_prop:wNnn
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_termst_set_prop }{ Nnn }{ # 1 # 2 \s__end # 3 # 4 # 5 }
  { #3  %% this will be either \prop_put: or \prop_gput:
     #1 { #4 } { #5 } }


%%%%%%%%%%%%%%%
%%%%
%%%% \starray_set_prop
%%%%
%%%%%%%%%%%%%%%


%%%%%%%%%%%%%%%
%%% \starray_set_prop:nnn
%%% \starray_set_prop:nnnTF
%%%%%%%%%%%%%%%
\__starray_cs_prg_duo_generate:NNnn
  \starray_set_prop:nnn
  \c__starray_idx_ending_bool
  {
    \__starray_termst_set_prop:NNnn  
      \l__starray_parsed_term_st_tl 
      \prop_put:Nnn 
      { #2 }{ #3 }
    \prg_return_true:
  }
  {
        \msg_warning:nnnn { starray } { syntax /  prop } 
          { set:1 } { #1 }
  }
\cs_generate_variant:Nn \starray_set_prop:nnn { nnV }
\prg_generate_conditional_variant:Nnn \starray_set_prop:nnn { nnV } { T, F , TF } %%%

%%%%%%%%%%%%%%%
%%% \starray_gset_prop:nnn
%%% \starray_gset_prop:nnnTF
%%%%%%%%%%%%%%%
\__starray_cs_prg_duo_generate:NNnn
  \starray_gset_prop:nnn
  \c__starray_idx_ending_bool
  {
    \__starray_termst_set_prop:NNnn  
      \l__starray_parsed_term_st_tl 
      \prop_gput:Nnn 
      { #2 }{ #3 }
    \prg_return_true:
  }
  {
        \msg_warning:nnnn { starray } { syntax /  prop } 
          { set:1 } { #1 }
  }
\cs_generate_variant:Nn \starray_gset_prop:nnn { nnV }
\prg_generate_conditional_variant:Nnn \starray_gset_prop:nnn { nnV } { T, F , TF } %%%



%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% set/get properties (keyval)
%%%%
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%

\cs_new:Npn \__starray_set_parse_end_chk:w #1 ] \q_nil \q_stop
  {
    \tl_if_empty:nTF { #1 }
      \prg_return_true:
      \prg_return_false:  %% syntax ERR (something after  )
  }

%
% Not expandable. DO NOT generate a predicate version! 
% but, already a :w conditional anyway (internal)
%
\prg_new_conditional:Npnn \__starray_set_parse_end:w  #1 ] #2 \q_stop { TF }
  {
    \quark_if_nil:nTF { #2 }
      { \prg_return_false: } %% syntax ERR
      {
        \tl_set:Nn \l__starray_parser_tmp_A_tl { #1 }
        \__starray_set_parse_end_chk:w #2 \q_stop
      }
  }


%
% Not expandable. DO NOT generate a predicate version! 
% but, already a :w conditional anyway (internal)
%
%\prg_new_conditional:Npnn \__starray_set_parse_aux:w  #1#2 [ \q_nil \q_stop { TF }
\cs_new:Npn \__starray_set_parse_aux:wTF  #1 [ \q_nil \q_stop
  {
    \__starray_set_parse_end:wTF  #1 ] \q_nil\q_stop
%      { \prg_return_true: }
%      { \prg_return_false: }
  }


%
% Not expandable. DO NOT generate a predicate version! 
% but, already a :w conditional anyway (internal)
%
\prg_new_conditional:Npnn \__starray_set_parse_begin:w #1 [ #2 \q_stop { TF }
  {
    \tl_set:Nn \l__starray_parser_tmp_B_tl { #1 }
    \quark_if_nil:nTF { #2 }
      {               % no 'term' ref, just array_name (current/iter term)
        \tl_clear:N \l__starray_parser_tmp_A_tl
        \prg_return_true:
      }
      {
        \__starray_set_parse_aux:wTF #2 \q_stop
          \prg_return_true:
          \prg_return_false:
      }
  }


\cs_new:Npn \__starray_set_from_keyval_parse:n #1
  { }   % hanging key, no value set, silently ignored.


%%% \c__starray_..._base_st_tl
%%%        \c{ -infix- _ihash_prop }                   %% #1
%%%        \c{ -infix- _base_iter_int }               %% #2
%%%        \c{ -infix- _base_cnt_int }                %% #3
%%%        \c{ -ref- _defkeys_prop }                   %% #4
%%%        \c{ -ref- _defstkeys_prop }                 %% #5
%%%        {-ref-}{-infix-}                           %% #6#7
%%%    \s__end
%%%%%%
%%% \__starray_basest_set_from_keyval_parse:N
%%% \__starray_basest_set_from_keyval_parse:c
%%% \__starray_basest_set_from_keyval_parse:w
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_basest_set_from_keyval_parse }{ nn }{ # 1 # 2 # 3 \s__end # 4 # 5 }
  {
    \tl_if_blank:nTF { #4 }
      {
        \prop_get:NeNTF #1 { \int_use:N #2 } \l__starray_tmp_term_st_tl
          {
            \keyval_parse:een
              { \exp_not:N \__starray_set_from_keyval_parse:n   }
              { 
                \exp_not:N \__starray_termst_set_from_keyval_parse:wnn
                \exp_not:o \l__starray_tmp_term_st_tl 
              }  
              { #5 }
          }
          {%%err, non-instatiated
            \__starray_msg:nnee { reference / iter }
              { setkeyval:3 } {--} { #4 }
          }
      }
      {
        \prop_get:NnNTF #1 { #4 } \l__starray_tmp_term_st_tl
          {
            \keyval_parse:een
              { \exp_not:N \__starray_set_from_keyval_parse:n   }
              { 
                \exp_not:N \__starray_termst_set_from_keyval_parse:wnn
                \exp_not:o \l__starray_tmp_term_st_tl 
              }  
              { #5 }
          }
          {%%err, invalid hash
            \__starray_msg:nnee { reference / iter }
              { setkeyval:3 } {--} { #4 }
          }
      }
  }
\cs_generate_variant:Nn \__starray_basest_set_from_keyval_parse:Nnn { co }

%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% set from keyval
%%%%
%%%% NOTE: tmp variables are recursive aware.
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%

%%% \c__starray_..._term_st_tl
%%%        \c{ -infix- _term_prop }                  %% #1
%%%        { -infix- }                               %% #2
%%%        { -val- }  %% iter's val for this entry   %% #3
%%%        { -idx- }                                 %% #4
%%%        \c{ -ref- _defstkeys_prop }                %% #5
%%%    \s__end
%%% #6 => prop/struct(key from keyval)
%%% #7 => val/keyval (val from keyval)
%%%%%%
%%% \__starray_termst_set_from_keyval_parse:N
%%% \__starray_termst_set_from_keyval_parse:c
%%% \__starray_termst_set_from_keyval_parse:w
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_termst_set_from_keyval_parse }{ nn }{ # 1 # 2 # 3 # 4 # 5 \s__end # 6 # 7 }
  {
    \__starray_set_parse_begin:wTF #6 [ \q_nil \q_stop
      {
        \seq_if_in:NeTF #5 \l__starray_parser_tmp_B_tl
          {
            \__starray_basest_set_from_keyval_parse:con
              { c__starray_prfix_. #2 . \l__starray_parser_tmp_B_tl _base_st_tl } 
              \l__starray_parser_tmp_A_tl { #7 }
          }
          {
            \tl_if_empty:NTF \l__starray_parser_tmp_A_tl
              {
                \__starray_put:Nen #1 \l__starray_parser_tmp_B_tl { #7 }
              }
              {%%err  invalid ref / not a substructure
                \__starray_msg:nnee { syntax / structure-ref }
                  { setkeyval:4 } { #6 } { \l__starray_parser_tmp_B_tl }
              }
          }
      }
      {%%err invalid ref/syntax
        \__starray_msg:nnnn { syntax / term }
          { setkeyval:5 }{ #6 }{}
      }
  }
      
%%%%%%%%%%%%%%%
%%% \__starray_set_from_keyval:nn
%%% \__starray_set_from_keyval:nnTF
%%%%%%%%%%%%%%%
\__starray_cs_prg_duo_generate:NNnn
  \__starray_set_from_keyval:nn
  \c__starray_idx_ending_bool
  {
        %%% just in case, for msg_err messages
        \tl_set:Nn \l__starray_from_keyval_orgref_tl { #1 }
        
        \keyval_parse:een
          { \exp_not:N \__starray_set_from_keyval_parse:n   }
          { 
            \exp_not:N \__starray_termst_set_from_keyval_parse:wnn
            \exp_not:o \l__starray_parsed_term_st_tl 
          }
          { #2 }

        \__starray_msg_dispatch:
        \__starray_rtn:
  }
  {
      \msg_warning:nnnn { starray } { syntax /  prop } 
        { setkeyval:1 } { #1 }
  }


%\cs_new_protected:Npn \starray_set_from_keyval:nn #1#2
%  {
%    \cs_set_eq:NN \__starray_put:cnn \prop_put:cnn
%    \__starray_set_from_keyval:nn { #1 }{ #2 }
%  }
\cs_new_protected:Npn \starray_set_from_keyval:nn
  { 
    \cs_set_eq:NN \__starray_put:Nen \prop_put:Nen
    \__starray_set_from_keyval:nn
  }


%\cs_new_protected:Npn \starray_gset_from_keyval:nn #1#2
%  {
%    \cs_set_eq:NN \__starray_put:cnn \prop_gput:cnn
%    \__starray_set_from_keyval:nn { #1 }{ #2 }
%  }
\cs_new_protected:Npn \starray_gset_from_keyval:nn
  { 
    \cs_set_eq:NN \__starray_put:Nen \prop_gput:Nen
    \__starray_set_from_keyval:nn
  }

  
%%
%% TODO: Might be worth a bit (more) of optimization...
%% \cs_new_protected: \starray_set_from_keyval:nnTF (etc...) with the two parameters being implicit...
%%  
%\prg_new_protected_conditional:Npnn \starray_set_from_keyval:nn #1#2 { T, F, TF }
%  {
%    \cs_set_eq:NN \__starray_put:cnn \prop_put:cnn
%    \__starray_set_from_keyvalTF:nn { #1 }{ #2 }
%  }
\cs_new_protected:Npn \starray_set_from_keyval:nnT 
  { 
    \cs_set_eq:NN \__starray_put:Nen \prop_put:Nen
    \__starray_set_from_keyval:nnT
  }
\cs_new_protected:Npn \starray_set_from_keyval:nnF
  { 
    \cs_set_eq:NN \__starray_put:Nen \prop_put:Nen
    \__starray_set_from_keyval:nnF
  }
\cs_new_protected:Npn \starray_set_from_keyval:nnTF
  { 
    \cs_set_eq:NN \__starray_put:Nen \prop_put:Nen
    \__starray_set_from_keyval:nnTF
  }
  
%\prg_new_protected_conditional:Npnn \starray_gset_from_keyval:nn #1#2 { T, F, TF }
%  {
%    \cs_set_eq:NN \__starray_put:cnn \prop_gput:cnn
%    \__starray_set_from_keyvalTF:nn { #1 }{ #2 }
%  }
\cs_new_protected:Npn \starray_gset_from_keyval:nnT
  { 
    \cs_set_eq:NN \__starray_put:Nen \prop_gput:Nen
    \__starray_set_from_keyval:nnT
  }
\cs_new_protected:Npn \starray_gset_from_keyval:nnF
  { 
    \cs_set_eq:NN \__starray_put:Nen \prop_gput:Nen
    \__starray_set_from_keyval:nnF
  }
\cs_new_protected:Npn \starray_gset_from_keyval:nnTF 
  { 
    \cs_set_eq:NN \__starray_put:Nen \prop_gput:Nen
    \__starray_set_from_keyval:nnTF
  }


%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% starray ref/address parser using quarks
%%%% could be done with seq_split and regex but
%%%% would have been even more cumbersome (and slow)
%%%%
%%%% <starray_ref> := <array_ref> [ . <starray_ref> ]
%%%% <array_ref>   := <array_name> [ <term_ref> ]
%%%% <term_ref>    := \[ <number/hash> \]
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
\cs_new:Npn \__starray_term_parser_end_chk:w #1 ] \q_nil \q_stop
  {
    \tl_if_empty:nTF { #1 }
      \prg_return_true:
      \prg_return_false:  %% syntax ERR (something after  )
  }


%%%
%%% \tl_set: isn't expandable... but (internal) and only the TF variant is needed.
%%% :w macro anyway...
%%%
\prg_new_conditional:Npnn \__starray_term_parse_end:w  #1 ] #2 \q_stop { TF }
  {
    \quark_if_nil:nTF { #2 }
      { \prg_return_false: } %% syntax ERR
      {
        \tl_set:Nn \l__starray_parsed_idx_tl { #1 }
        \__starray_term_parser_end_chk:w #2 \q_stop
      }
  }


%%%
%%% \tl_set: isn't expandable (see above)... but (internal) and only the TF variant is needed.
%%% :w macro anyway...
%%%
%\prg_new_conditional:Npnn \__starray_term_parse_aux:w  #1 [ \q_nil \q_stop { TF }
%  {
%    \__starray_term_parse_end:wTF  #1 ] \q_nil\q_stop
%      { \prg_return_true: }
%      { \prg_return_false: }
%  }
\cs_new:Npn \__starray_term_parse_aux:wTF  #1 [ \q_nil \q_stop
  {
    \__starray_term_parse_end:wTF  #1 ] \q_nil\q_stop
  }


%%%
%%% \tl_set: isn't expandable (see above)... but (internal) and only the TF variant is needed.
%%% :w macro anyway...
%%%
\prg_new_conditional:Npnn \__starray_term_parse_begin:w #1 [ #2 \q_stop { TF }
  {
    \tl_set:Nn \l__starray_parsed_term_tl { #1 }

    \quark_if_nil:nTF { #2 }
      {               % no 'term' ref, just array_name (current/iter term)
        \tl_clear:N \l__starray_parsed_idx_tl
        \prg_return_true:
      }
      {
        \__starray_term_parse_aux:wTF #2 \q_stop
          \prg_return_true:
          \prg_return_false:
      }
  }


%%% \c__starray_..._base_st_tl
%%%        \c{ -infix- _ihash_prop }                   %% #1
%%%        \c{ -infix- _base_iter_int }               %% #2
%%%        \c{ -infix- _base_cnt_int }                %% #3
%%%        \c{ -ref- _defkeys_prop }                   %% #4
%%%        \c{ -ref- _defstkeys_prop }                 %% #5
%%%        {-ref-}{-infix-}                           %% #6#7
%%%    \s__end
%%%%%%
%%% \__starray_basest_if_valid_idx:Nn
%%% \__starray_basest_if_valid_idx:cn
%%% \__starray_basest_if_valid_idx:wn
%%%%%%
\__starray_prg_wgen:nnnn
  { __starray_basest_if_valid_idx }{ n }{ # 1 # 2 # 3 \s__end # 4 }
  {
    \tl_if_empty:NTF #4
      {
        \prop_get:NeNTF #1 { \int_use:N #2 } \l__starray_parsed_term_st_tl
          {
            \__starray_termst_get_infix:NN
              \l__starray_parsed_term_st_tl 
              \l__starray_tmpb_tl  
              
            \tl_set:Ne \l__starray_parsed_ref_tl { . \l__starray_tmpb_tl }
            \prg_return_true:
          }
          {
            \tl_set_eq:NN \l__starray_parsed_term_st_tl \c__starray_empty_hash_term_st_tl
            \prg_return_false:
          }
      }
      {
        \prop_get:NeNTF #1 { #4 } \l__starray_parsed_term_st_tl
          { 
            \__starray_termst_get_infix:NN
              \l__starray_parsed_term_st_tl 
              \l__starray_tmpb_tl  

            \tl_set:Ne \l__starray_parsed_ref_tl { . \l__starray_tmpb_tl }
            \prg_return_true:
          }
          {
            \tl_set_eq:NN \l__starray_parsed_term_st_tl \c__starray_empty_hash_term_st_tl
            \prg_return_false:
          }
      }
  }
  
  
%%%
%%% small surprise, it was possible to _protected this... TODO: further test it.
%%%
\cs_new_protected:Npn \__starray_ref_parse:nw #1 . #2 \q_stop
  {
    %% just if case, for _msg_
    \tl_put_right:Nn \l__starray_parsed_tl { #1 }

    \__starray_term_parse_begin:wTF #1 [ \q_nil \q_stop
      {                              % syntax ok so far.
                                     % TODO: verify instance validity hash/index
                                     % vars: \l__starray_parsed_term_tl
                                     %       \l__starray_parsed_idx_tl
        \tl_put_right:Ne \l__starray_parsed_ref_tl 
          { . \l__starray_parsed_term_tl }

        \__starray_if_exist:cTF 
          { c__starray_prfix_  \l__starray_parsed_ref_tl _base_st_tl }
          {
            \quark_if_nil:nTF { #2 }
            {       % this is the 'last one'
                
              \tl_set_eq:Nc
                \l__starray_parsed_base_st_tl { c__starray_prfix_  \l__starray_parsed_ref_tl _base_st_tl }
                                
              \bool_if:NTF \l__starray_parser_no_idx_ending_bool
              {                                  % assuming it is to add a term...
                \tl_if_empty:NTF \l__starray_parsed_idx_tl
                { }       % done. correct
                {
                  \bool_set_false:N \l__starray_parser_OK_bool
                  \__starray_msg:nnee { syntax / ref-syntax-err } { parser:1 } 
                    { \l__starray_parsing_term_tl } 
                    { invalid~index~\l__starray_parsed_idx_tl~(at~the~end)}              
                } % err !
              }
              { % assuming it is to set/get a property... _base_st_tl maps to \__starray_if_valid_idx:NNNNNnnTF 
                % This will set \l__starray_parsed_term_st_tl (if it exists)
                
                \__starray_basest_if_valid_idx:cnTF
                  { c__starray_prfix_  \l__starray_parsed_ref_tl _base_st_tl } \l__starray_parsed_idx_tl
                  { }      % done, finish, ok
                  {
                    \bool_set_false:N \l__starray_parser_OK_bool
                    \__starray_msg:nnee { syntax / ref-syntax-err } { parser:2 } 
                      { \l__starray_parsing_term_tl } 
                      { invalid~index~\l__starray_parsed_idx_tl }    
                  }
              }
            }
            {                       
              % assuming it is to set/get a property... _base_st_tl maps to \__starray_if_valid_idx:NNNNNnnTF 
              % This will set \l__starray_parsed_term_st_tl (if it exists)
              \__starray_basest_if_valid_idx:cnTF
                { c__starray_prfix_  \l__starray_parsed_ref_tl _base_st_tl } \l__starray_parsed_idx_tl
                {
                  \__starray_ref_parse:nw #2 \q_stop
                }      % recurse next term
                {
                  \bool_set_false:N \l__starray_parser_OK_bool
                  \__starray_msg:nnee { syntax / ref-syntax-err } { parser:3 } 
                    { \l__starray_parsing_term_tl } 
                    { invalid~index~\l__starray_parsed_idx_tl } 
                }
            }
          }
          {
            \bool_set_false:N \l__starray_parser_OK_bool
            \__starray_msg:nnee { syntax / ref-syntax-err } { parser:4 } 
              { \l__starray_parsing_term_tl } 
              { invalid~struct~\l__starray_parsed_ref_tl } 
          } % invalid/ref err.
      }
      {
        \bool_set_false:N \l__starray_parser_OK_bool
        \__starray_msg:nnee { syntax / ref-syntax-err } { parser:5 } 
          { \l__starray_parsing_term_tl } 
          { invalid~struct~#1~at~\l__starray_parsed_tl }         
      } % syntax/ref err.
  }

%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% parser 'true' returns:
%%%%                       \l__starray_parsed_ref_tl
%%%%
%%%%                       \l__starray_parsed_term_st_tl !!! IF there is one!
%%%%                       \l__starray_parsed_base_st_tl !!! always, if OK
%%%%
%%%% parser 'false' returns:
%%%%                       
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
\cs_new_protected:Npn \__starray_parser:NnTF #1#2 
  {
    \bool_set_eq:NN \l__starray_parser_no_idx_ending_bool #1
    \bool_set_true:N \l__starray_parser_OK_bool

    \tl_clear:N \l__starray_parsed_ref_tl

%%% This is just for error/warning messages    
    \tl_set:Nn \l__starray_parsing_term_tl { #2 }

    \__starray_ref_parse:nw #2 .\q_nil\q_stop

    \bool_if:NTF \l__starray_parser_OK_bool
  }
\cs_generate_variant:Nn \__starray_parser:NnTF { Ne }

\cs_new_protected:Npn \starray_term_parser:n #1
  {
    \__starray_parser:NeTF \c__starray_idx_ending_bool { #1 }
      {
        \tl_gset_eq:NN \g__starray_parsed_saved_term_st_tl \l__starray_parsed_term_st_tl
        \tl_gset_eq:NN \g__starray_parsed_saved_base_st_tl \l__starray_parsed_base_st_tl
        
        \bool_gset_true:N \g__starray_parsed_bool
      }
      {
        \bool_gset_false:N \g__starray_parsed_bool
        \__starray_msg_dispatch:
        \msg_warning:nnnn { starray } { syntax /  term } 
          { term parser:1 } { #1 }
      }  
  }
  
\cs_new_protected:Npn \starray_term_syntax:n
  {
    \msg_warning:nnnnn { starray } { strict / deprecate } { dep:01 }
      { \starray_term_syntax:n }
      { \starray_term_parser:n }
    \starray_term_parser:n
  }

\prg_new_protected_conditional:Npnn \starray_term_parser:n #1 { T, F, TF }
  {
    \__starray_parser:NeTF \c__starray_idx_ending_bool { #1 }
      {
        \tl_gset_eq:NN \g__starray_parsed_saved_term_st_tl \l__starray_parsed_term_st_tl
        \tl_gset_eq:NN \g__starray_parsed_saved_base_st_tl \l__starray_parsed_base_st_tl

        \bool_gset_true:N \g__starray_parsed_bool
        \prg_return_true:
      }
      {
        \bool_gset_false:N \g__starray_parsed_bool
        \__starray_msg_clear:
        \prg_return_false:
      }
  }
\cs_new_protected:Npn \starray_term_syntax:nTF
  {
    \msg_warning:nnnnn { starray } { strict / deprecate } { dep:03 }
      { \starray_term_syntax:nTF }
      { \starray_term_parser:nTF }
    \starray_term_parser:nTF
  }
\cs_new_protected:Npn \starray_term_syntax:nT
  {
    \msg_warning:nnnnn { starray } { strict / deprecate } { dep:04 }
      { \starray_term_syntax:nT }
      { \starray_term_parser:nT }
    \starray_term_parser:nT
  }
\cs_new_protected:Npn \starray_term_syntax:nF
  {
    \msg_warning:nnnnn { starray } { strict / deprecate } { dep:05 }
      { \starray_term_syntax:nF }
      { \starray_term_parser:nF }
    \starray_term_parser:nF
  }
  
\cs_new_protected:Npn \starray_term_parser:nN #1#2
  {
    \__starray_parser:NeTF \c__starray_idx_ending_bool { #1 }
      {
        \tl_gset:Ne #2 
          {
            { \exp_not:o \l__starray_parsed_term_st_tl }
            { \exp_not:o \l__starray_parsed_base_st_tl }
          }          
      }
      {
        \__starray_msg_dispatch:
        \msg_warning:nnnn { starray } { syntax /  term } 
          { term parser:2 } { #1 }
      }  
  }  
  
\cs_new_protected:Npn \starray_term_parser:nNN #1#2#3
  {
    \msg_warning:nnnnn { starray } { strict / deprecate } { dep:02a }
      { \starray_term_syntax:nNN }
      { \starray_term_parser:nN }
    \starray_term_parser:nN { #1 } #2 
  }  
  
\cs_new_protected:Npn \starray_term_syntax:nNN
  {
    \msg_warning:nnnnn { starray } { strict / deprecate } { dep:02 }
      { \starray_term_syntax:nNN }
      { \starray_term_parser:nNN }
    \starray_term_parser:nNN
  }
  
\prg_new_protected_conditional:Npnn \starray_term_parser:nN #1#2 { T, F, TF }
  {
    \__starray_parser:NeTF \c__starray_idx_ending_bool { #1 }
      {
        \tl_gset:Ne #2 
          {
            { \exp_not:o \l__starray_parsed_term_st_tl }
            { \exp_not:o \l__starray_parsed_base_st_tl }
          }
        \prg_return_true:
      }
      {
        \__starray_msg_clear:
        \prg_return_false:
      }  
  }  
  
\cs_new_protected:Npn \starray_term_parser:nNNTF #1#2#3
  {
    \msg_warning:nnnnn { starray } { strict / deprecate } { dep:06a }
      { \starray_term_parser:nNNTF }
      { \starray_term_parser:nNTF }
    \starray_term_parser:nNTF { #1 } #2 
  }
\cs_new_protected:Npn \starray_term_parser:nNNT #1#2#3
  {
    \msg_warning:nnnnn { starray } { strict / deprecate } { dep:07a }
      { \starray_term_parser:nNNT }
      { \starray_term_parser:nNT }
    \starray_term_parser:nNT { #1 } #2 
  }
\cs_new_protected:Npn \starray_term_parser:nNNF #1#2#3
  {
    \msg_warning:nnnnn { starray } { strict / deprecate } { dep:08a }
      { \starray_term_parser:nNNF }
      { \starray_term_parser:nNF }
    \starray_term_parser:nNF { #1 } #2 
  }

  
\cs_new_protected:Npn \starray_term_syntax:nNNTF
  {
    \msg_warning:nnnnn { starray } { strict / deprecate } { dep:06 }
      { \starray_term_syntax:nNNTF }
      { \starray_term_parser:nNNTF }
    \starray_term_parser:nNNTF
  }
\cs_new_protected:Npn \starray_term_syntax:nNNT
  {
    \msg_warning:nnnnn { starray } { strict / deprecate } { dep:07 }
      { \starray_term_syntax:nNNT }
      { \starray_term_parser:nNNT }
    \starray_term_parser:nNNT
  }
\cs_new_protected:Npn \starray_term_syntax:nNNF
  {
    \msg_warning:nnnnn { starray } { strict / deprecate } { dep:08 }
      { \starray_term_syntax:nNNF }
      { \starray_term_parser:nNNF }
    \starray_term_parser:nNNF
  }



%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% \..show_def commands
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%

%%% \c__starray...._ref_st_tl
%%%        \c{ -ref- _defkeys_prop }                  %% #1
%%%        \c{ -ref- _defstkeys_seq }                 %% #2
%%%        {-ref-}                                    %% #3
%%%    \s__end
%%%%%%
%%% \__starray_refst_show_def:Nnn
%%% \__starray_refst_show_def:cnn
%%% \__starray_refst_show_def:wnn
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_refst_show_def }{ nn }{  # 1 # 2 # 3 \s__end # 4 # 5 }
  {
      \tl_put_right:Nn \l__starray_show_tmp_tl
        {
          \__starray_show: > #4
          \tl_to_str:n {{ #5 }}
          \use:nn {~}{~} struct
          \use:nn {~}{~} =>
        }    
      \prop_map_inline:Nn  #1
        {
          \tl_put_right:Nn \l__starray_show_tmp_tl
            {
              \__starray_show: > #4 \use:nnn {~}{~}{~}
              \tl_to_str:n { { ##1 } }
              \use:nn {~}{~} => \use:nn {~}{~}
              \tl_to_str:n { { ##2 } }
            }          
        }
      \seq_map_inline:Nn #2
        {   
          \__starray_refst_show_def:cnn 
            { c__starray_prfix_. #3 . ##1 _ref_st_tl } 
            { #4 \use:nnn {~}{~}{~}} { ##1 }
        }
  }


%%%%%%%%%%%%%%%
%%%%
%%%% \starray_show_def
%%%%
%%%%%%%%%%%%%%%
\cs_new_protected:Npn \starray_show_def:n #1
  {
    \__starray_if_exist:cTF { c__starray_prfix_.  #1 _ref_st_tl }
      {
        \tl_clear:N \l__starray_show_tmp_tl
        \cs_set_eq:NN \__starray_show: \iow_newline:
        
        \__starray_refst_show_def:cnn 
          { c__starray_prfix_. #1 _ref_st_tl } 
          { } { #1 }
    
        \msg_show:nnxxx { starray }{ info / show }
          { show~def }
          { The~ starray~ <#1> ~is~defined~as~follow: }
          { \l__starray_show_tmp_tl }
      }
      {
        \msg_warning:nnnn { starray }{ strict / not defined }
          { show~def } { #1 }
      }
     
  }

\cs_new_protected:Npn \starray_show_def_in_text:n #1
  {
    \__starray_if_exist:cTF { c__starray_prfix_.  #1 _ref_st_tl }
      {
        \tl_clear:N \l__starray_show_tmp_tl
        \cs_set_eq:NN \__starray_show: \par
        
        \__starray_refst_show_def:cnn 
          { c__starray_prfix_. #1 _ref_st_tl } 
          { } { #1 }
    
        \l__starray_show_tmp_tl
      }
      {
        \msg_warning:nnnn { starray }{ strict / not defined }
          { show~def } { #1 }
      }
  }


%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% \..show_terms commands
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%

%%% \c__starray_..._term_st_tl
%%%        \c{ -infix- _term_prop }                  %% #1
%%%        { -infix- }                               %% #2
%%%        { -val- }  %% iter's val for this entry   %% #3
%%%        { -idx- }                                 %% #4
%%%        \c{ -ref- _defstkeys_prop }                %% #5
%%%    \s__end
%%%%%%
%%% \__starray_termst_show_item:NnnN
%%% \__starray_termst_show_item:cnnN
%%% \__starray_termst_show_item:wnnN
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_termst_show_item }{ nnN }{ # 1 # 2 # 3 # 4 # 5 \s__end # 6 # 7 # 8 }
  {
    \tl_put_right:Nn \l__starray_show_tmp_tl
      {
        \__starray_show: > #6
        \tl_to_str:n { { #7 } ~ (idx: ~ #4)}
        \use:nn {~}{~} =>
      }  

    \prop_map_inline:Nn #1
      {
        \tl_put_right:Nn \l__starray_show_tmp_tl
          {
            \__starray_show: > #6 \use:nnn {~}{~}{~}
            \tl_to_str:n { { ##1 } }
            \use:nn {~}{~} => ~ \tl_to_str:n { { ##2 } }
          }          
      }

    \seq_map_inline:Nn #8
      {
        \__starray_basest_show_terms:cnn
          { c__starray_prfix_. #2 . ##1 _base_st_tl } 
          { #6 \use:nnn {~}{~}{~}} { ##1 }
      }


  }

%%% \c__starray_..._base_st_tl
%%%        \c{ -infix- _ihash_prop }                   %% #1
%%%        \c{ -infix- _base_iter_int }               %% #2
%%%        \c{ -infix- _base_cnt_int }                %% #3
%%%        \c{ -ref- _defkeys_prop }                   %% #4
%%%        \c{ -ref- _defstkeys_prop }                 %% #5
%%%        {-ref-}{-infix-}                           %% #6#7
%%%    \s__end
%%%%%%
%%% \__starray_basest_show_terms:Nnn
%%% \__starray_basest_show_terms:cnn
%%% \__starray_basest_show_terms:wnn
%%%%%%
\__starray_cs_wgen:nnnn
  { __starray_basest_show_terms }{ nn }{ # 1 # 2 # 3 # 4 # 5 # 6 # 7 \s__end # 8 # 9 }
  {
    \prop_map_inline:Nn #1
      {
        \__starray_termst_show_item:wnnN
          ##2 { #8 } { #9[##1]} #5
      }
  }
  
%%%%%%%%%%%%%%%
%%%%
%%%% \starray_show_terms
%%%%
%%%%%%%%%%%%%%%
\cs_new_protected:Npn \starray_show_terms:n #1
  {
    \__starray_if_exist:cTF { c__starray_prfix_.  #1 _base_st_tl }
      {
        \tl_clear:N \l__starray_show_tmp_tl
        \cs_set_eq:NN \__starray_show: \iow_newline:
           
        \__starray_basest_show_terms:cnn
          { c__starray_prfix_. #1 _base_st_tl } 
          { } { #1 }
    
        \msg_show:nnxxx { starray }{ info / show }
          { show~terms }
          { The~ starray~ <#1> ~has~the~following~terms: }
          { \l__starray_show_tmp_tl }
      }
      {
        \msg_warning:nnnn { starray }{ strict / not defined }
          { show~terms } { #1 }
      }
  }


\cs_new_protected:Npn \starray_show_terms_in_text:n #1
  {
    \__starray_if_exist:cTF { c__starray_prfix_.  #1 _base_st_tl }
      {
        \tl_clear:N \l__starray_show_tmp_tl
        \cs_set_eq:NN \__starray_show: \par
        
        \__starray_basest_show_terms:cnn
          { c__starray_prfix_. #1 _base_st_tl } 
          { } { #1 }
      
         \l__starray_show_tmp_tl
      }
      {
        \msg_warning:nnnn { starray }{ strict / not defined }
          { show~terms } { #1 }
      }
  }


