%%%==============================================================================
%% Copyright 2023 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 1.3 (2023/06/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}[2022/06/01]
\RequirePackage{ expl3 }


\ProvidesExplPackage
    {starray}
    {2023/06/04}
    {1.3}
    {A structured array/hash of properties}

%%%%%%%
%%%
%%% Just an attempt of having my packages info in a regular way
%%% Idea being: { <pck-name> / pkg info } for each and all.
%%%
%%%%%%%
\keys_define:nn { starray / pkg info}
  {
     name        .code:n = starray ,
     prefix      .code:n = starray ,
     date        .code:n = 2023/06/04,
     version     .code:n = 1.3 ,
     description .code:n = A~structured~array/hash~of~properties
  }
\cs_if_exist:NF \__codedesc_pkg_info:nn 
  {
    \cs_new_protected:Npn \__codedesc_pkg_info:nn #1#2
      { \keys_set:nn {#1 / pkg info}{#2} }
  }
\cs_if_exist:NF \PkgInfo
  { \NewDocumentCommand \PkgInfo {mm} { \keys_set:nn {#1 / pkg info}{#2} } }
%%%%%%%
%%% End of cut-n-paste
%%%%%%%





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

\tl_new:N \l__starray_prefix_tl
%\tl_gset:Nn \l__starray_prefix_tl {l__starray_}


\keys_define:nn { starray }
  {
    prefix .tl_set:N          = \l__starray_prefix_tl ,
    prefix .value_required:n  = true ,
    prefix .initial:n         = l__starray_ ,
    prefix .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-err . 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 } 
      } ,
    msg-supress . usage:n = load ,
  
  
  }

\ProcessKeyOptions [ starray ]

%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% New variants of core expl3 primitives
%%%% expansion handling
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%

\cs_generate_variant:Nn \prop_item:Nn { ce , Ne }
\cs_generate_variant:Nn \tl_put_right:Nn {Ne}
\cs_generate_variant:Nn \tl_gput_right:Nn {Ne}
\cs_generate_variant:Nn \tl_set:Nn {Ne , ce}
\cs_generate_variant:Nn \tl_gset:Nn {Ne , ce} 

\cs_generate_variant:Nn \seq_put_right:Nn {ce}
\cs_generate_variant:Nn \seq_gput_right:Nn {ce}

\cs_generate_variant:Nn \int_to_Alph:n {e}

\cs_generate_variant:Nn \prop_put:Nnn {Nee , cee}
\cs_generate_variant:Nn \prop_gput:Nnn {Nee , cee}

\cs_generate_variant:Nn \prop_get:NnN { cnc , cec }

\prg_generate_conditional_variant:Nnn \prop_get:NnN { Nec } { F , T , TF}

\prg_generate_conditional_variant:Nnn \seq_if_in:Nn {ce} {TF}
\prg_generate_conditional_variant:Nnn \prop_if_in:Nn {ce} {TF}


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

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


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

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

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

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

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


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


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

\msg_new:nnnn {starray} {reference / iter}
  {
    (ID:#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~ ID:<#1>.
  }

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

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

    #3

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

    #3

    \iow_newline:
    definition's~end.
  }





\cs_new_protected:Npn \__starray_msg:nnnnn #1#2#3#4#5
  {
    \bool_gset_false:N \l__starray_rtn_bool

    \seq_gput_right:Nn \l__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_dispatch:
  {
    \seq_map_tokens:Nn \l__starray_msg_seq {  }
    \seq_clear:N \l__starray_msg_seq
  }

%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% Package Variables declaration
%%%%
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
% TODO variables declaration

\prop_new:N \l__starray_tmpA_prop

%%%%
%%%% 'general' (internal) returning bool
%%%%
\bool_new:N \l__starray_rtn_bool

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

%%%%
%%%% recursive/reentrant aware tmp variables.
%%%% this is clumsy and utterly ugly... 
%%%% a set of variables for each recursing level...
%%%%

\int_set:Nn \l_tmpa_int {9}
\tl_clear:N \l_tmpa_tl
\int_do_while:nNnn {\l_tmpa_int} > {0}
  {
    \tl_put_left:Nn \l_tmpa_tl {A}
    \prop_new:c { l__starray_tmp \l_tmpa_tl _hash_prop }
    \prop_new:c { l__starray_tmp \l_tmpa_tl _def_prop }
    \prop_new:c { l__starray_tmp \l_tmpa_tl _idx_prop }
    \int_new:c  { l__starray_tmp \l_tmpa_tl _int }
    \seq_new:c  { l__starray_tmp \l_tmpa_tl _seq }
    \tl_new:c   { l__starray_tmp \l_tmpa_tl _tl }
    \tl_new:c   { l__starray_tmp \l_tmpa_tl :A_tl }
    \tl_new:c   { l__starray_tmp \l_tmpa_tl :B_tl }
    \tl_new:c   { l__starray_tmp \l_tmpa_tl _idx_tl }
  
    \int_decr:N \l_tmpa_int
  }

\tl_new:N \l__starray_tmpa_tl
\tl_new:N \l__starray_tmpb_tl

\tl_new:N \l__starray_showcmd_tl

%%%%
%%%% (sub)structure returning tl.
%%%%
\tl_new:N \l__starray_tmpST_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


%%%%
%%%% parser returning variables
%%%%
\tl_new:N \l__starray_parsed_tl
\tl_new:N \l__starray_parsed_ref_tl
\tl_new:N \l__starray_parsed_ref_no_idx_ending_tl
\tl_new:N \l__starray_parsed_base_ref_tl
\tl_new:N \l__starray_parsed_root_ref_tl
  
\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

\tl_new:N \l__starray_parser_aux_tl %% when constructing parser ref, 1st <nothing> then dot .

\bool_new:N \l__starray_parser_OK_bool


%% big one, (g)put !!
%%%%
%%%% (g)put :: IF the effect shall be local or global
%%%%
\tl_new:N \l__starray_put_tl



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

%
%
\prg_new_conditional:Npnn \__starray_if_free:n #1 {p, T, F, TF}
  {
    \prop_if_exist:cTF {#1}
      { \prg_return_false: }
      { \prg_return_true: }
  }

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


\prg_new_conditional:Npnn \starray_if_exist:n #1 {p, T, F, TF}
  {
    \__starray_if_free:nTF {\l__starray_prefix_tl #1 _def_prop}
      { \prg_return_false: }
      { \prg_return_true: }
  }


\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_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 {\l__starray_prefix_tl #1 _def_prop}
      { \prg_return_true: }
      { \prg_return_false: }
  }


%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% starray \...._new declarations
%%%%
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%
%%% TODO: to add another property list mapping hash/idx -> iter
%%%       intend: \__starray_set_iter_hash !
%%%
% needs protection.
\cs_new_protected:Npn \__starray_base_new:nn #1#2
  {
    \int_new:c
      { \l__starray_prefix_tl #2 _cnt_int }
    \int_gzero:c
      { \l__starray_prefix_tl #2 _cnt_int }

    \int_new:c
      { \l__starray_prefix_tl #2 _iter_int }
    \int_gzero:c
      { \l__starray_prefix_tl #2 _iter_int }

    \prop_new:c { \l__starray_prefix_tl #2 _base_prop }

    \prop_gset_from_keyval:cn
      { \l__starray_prefix_tl #2 _base_prop }
      {
        def_ref = #1 ,
        is_starray  = \c_true_bool ,
      }

    \prop_gput:cno
      { \l__starray_prefix_tl #2 _base_prop }
      { cnt }
      { \use:c { \l__starray_prefix_tl #2 _cnt_int } }

    \prop_gput:cno
      { \l__starray_prefix_tl #2 _base_prop }
      { iter }
      { \use:c {\l__starray_prefix_tl #2 _iter_int} }

    \prop_gput:cnV
      { \l__starray_prefix_tl #2 _base_prop }
      { idx_hash }
      \c_empty_prop

    \prop_gput:cnV
      { \l__starray_prefix_tl #2 _base_prop }
      { iter_hash }
      \c_empty_prop
  }

\cs_generate_variant:Nn \__starray_base_new:nn { ee }


% needs protection.
\cs_new_protected:Npn \__starray_sub_base_new:nnn #1#2#3
  { \__starray_base_new:ee {#1.#3}{#2.#3} }


% needs protection.
\cs_new_protected:Npn \__starray_new:n #1
  {
    \prop_new:c
      { \l__starray_prefix_tl #1 _def_prop }

    \prop_gset_from_keyval:cn
      { \l__starray_prefix_tl #1 _def_prop }
      {
        is_starray = \c_true_bool ,
        def_ref   = #1
      }

    \prop_clear:N \l_tmpa_prop

    \prop_gput:cnV { \l__starray_prefix_tl #1 _def_prop } {@st_seq} \c_empty_seq

    \prop_gput:cnV
      { \l__starray_prefix_tl #1 _def_prop} {def} \l_tmpa_prop

  }

\cs_generate_variant:Nn \__starray_new:n { e }


%%%%%%%%%%%%%%%
%%%%
%%%% \starray_new
%%%%
%%%%%%%%%%%%%%%

% needs protection.
\cs_new_protected:Npn \starray_new:n #1
  {
    \__starray_if_free:nTF {\l__starray_prefix_tl #1 _def_prop}
      {
        \__starray_new:e {#1 }
        \__starray_base_new:ee {#1}{#1} % TODO: might be incomplete !!!
      }
      {
        \msg_warning:nnnn {starray} {strict / (re)define} {new:1} {#1}
      }
  }


% needs protection.
\prg_new_protected_conditional:Npnn \starray_new:n #1 {T, F, TF}
  {
    \__starray_if_free:nTF {\l__starray_prefix_tl #1 _def_prop}
      {
        \__starray_new:e {#1 }
        \__starray_base_new:ee {#1}{#1} % TODO: might be incomplete !!!
        \prg_return_true:
      }
      { \prg_return_false: }
  }

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

%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% get root reference (first term) assuming called as
%%%%    <st-ref> . \q_nil \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:w \l__starray_tmpa_tl . \q_nil \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:w #1 . #2 \q_stop { #1 }


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


% needs protection.
\cs_new_protected:Npn \__starray_def_prop:nnn #1#2#3
  {
    \prop_get:cnN {\l__starray_prefix_tl #1 _def_prop} {def} \l_tmpa_prop
    \prop_put:Nnn \l_tmpa_prop {#2} {#3}
    \prop_gput:cnV {\l__starray_prefix_tl #1 _def_prop} {def} \l_tmpa_prop
  }



%%%%%%%%%%%%%%%
%%%%
%%%% \starray_def_prop
%%%%
%%%%%%%%%%%%%%%

% needs protection, because of _p
\cs_new_protected:Npn \starray_def_prop:nnn #1#2#3
  {
    \__starray_if_valid:nTF {\l__starray_prefix_tl #1 _def_prop}
      { \__starray_def_prop:nnn  {#1} {#2} {#3} }
      {
        \msg_warning:nnxxx {starray}{reference / invalid-starray} 
          {addprop:1} {#1} {cannot~add~property:#2}
      }
  }


% needs protection, because of _p
\prg_new_protected_conditional:Npnn \starray_def_prop:nnn #1#2#3 {T, F, TF}
  {
    \__starray_if_valid:nTF {\l__starray_prefix_tl #1 _def_prop}
      {
        \__starray_def_prop:nnn  {#1} {#2} {#3}
        \prg_return_true:
      }
      { \prg_return_false: }
  }


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

% needs protection because of \seq_if...
\cs_new_protected:Npn \__starray_def_struct:nn #1#2
  {
    \prop_get:cnN {\l__starray_prefix_tl #1 _def_prop} {@st_seq} \l_tmpa_seq
    \seq_if_in:NnF \l_tmpa_seq {#2}
      {
        \seq_put_right:Nn \l_tmpa_seq {#2}
    
        \prop_gput:cnV {\l__starray_prefix_tl #1 _def_prop} {@st_seq} \l_tmpa_seq
    
        \__starray_new:e { #1 . #2}
      }
  }

\cs_generate_variant:Nn \__starray_def_struct:nn {ne}


%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% fixing struct _base for already instantiated terms
%%%%
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%TODO: recurse over 'terms' to fix a 'late addtion' (after being instantiated?)

\cs_new_protected:Npn \__starray_fix_terms_seq_aux:nnnn #1#2#3#4
  {
    \__starray_if_valid:eTF {\l__starray_prefix_tl #2 _ #3 . #4 _base_prop}
      {
       \__starray_fix_terms:nn {#1.#4}{#2_#3.#4}
      }
      {
       \__starray_base_new:ee {#1.#4}{#2_#3.#4}
      }
  }

\cs_new_protected:Npn \__starray_fix_terms_seq:nnnn #1#2#3#4
  {
    \prop_get:cnN
      {\l__starray_prefix_tl #2 _base_prop}
      {def_ref}
      \l_tmpa_tl
    \prop_get:cec
      {\l__starray_prefix_tl \l_tmpa_tl _def_prop}
      {@st_seq}
      {l__starray_tmp  A_seq}
    \seq_map_tokens:cn
      {l__starray_tmp  A_seq}
      {\__starray_fix_terms_seq_aux:nnnn {#1}{#2}{#4}}
  
  }

\cs_new_protected:Npn \__starray_fix_terms:nn #1#2
  {
    \group_begin:
      \prop_get:cnc
        {\l__starray_prefix_tl #2 _base_prop}
        {idx_hash}
        {l__starray_tmp  A_prop}
      \prop_if_empty:cF {l__starray_tmp  A_prop}
        {
          \prop_map_tokens:cn
            {l__starray_tmp  A_prop}
            {\__starray_fix_terms_seq:nnnn {#1}{#2}}
        }
    \group_end:
  }

\cs_generate_variant:Nn \__starray_fix_terms:nn {ee}



\cs_new_protected:Npn \starray_fix_terms:n #1
  {
    \tl_set:Ne \l_tmpb_tl {\__starray_get_root:w #1 . \q_nil \q_stop}
  
    \__starray_if_valid:nTF { \l__starray_prefix_tl \l_tmpb_tl _def_prop}
      {
        \__starray_fix_terms:ee {\l_tmpb_tl}{\l_tmpb_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_valid:nTF { \l__starray_prefix_tl #1 _def_prop}
      {
        \__starray_def_struct:nn  {#1} {#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_valid:nTF { \l__starray_prefix_tl #1 _def_prop}
      {
        \__starray_def_struct:nn  {#1} {#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 should 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:Ne \l__starray_tmpST_tl { #1 }
            \prg_return_true:
          } % dot struct, OK
          {
            \prg_return_false:
          } %% possible syntax ERR (dot, but no struct!)
      }
  }


\cs_new_protected:Npn \__starray_def_from_keyval_parse:nnn #1#2#3
  {
    \group_begin:
      \__starray_def_from_keyval_testdot:wTF #2 . \q_nil \q_stop
        {
          \tl_set:ce {l__starray_tmp A _tl} {#1 . \l__starray_tmpST_tl}
          \__starray_def_struct:ne {#1} {\l__starray_tmpST_tl}
          \keyval_parse:nnn
            {\__starray_def_from_keyval_parse:en  {\tl_use:c {l__starray_tmp A _tl}}}
            {\__starray_def_from_keyval_parse:enn {\tl_use:c {l__starray_tmp A _tl}}}
            {#3}
        }
        {
          \__starray_def_prop:nnn {#1} {#2} {#3}
        }
    \group_end:
  }

\cs_generate_variant:Nn \__starray_def_from_keyval_parse:nnn {enn}


\cs_new_protected:Npn \__starray_def_from_keyval_parse:nn #1#2
  {
    \__starray_def_prop:nnn {#1} {#2} {}
  }

\cs_generate_variant:Nn \__starray_def_from_keyval_parse:nn {en}



%%%%%%%%%%%%%%%
%%%%
%%%% \starray_def_from_keyval
%%%%
%%%%%%%%%%%%%%%

\cs_new_protected:Npn \starray_def_from_keyval:nn #1#2
  {
    \__starray_if_valid:nTF { \l__starray_prefix_tl #1 _def_prop}
      {
        \keyval_parse:nnn
          {\__starray_def_from_keyval_parse:en  {#1}}
          {\__starray_def_from_keyval_parse:enn {#1}}
          { #2 }
      }
      {
        \msg_warning:nnxxx {starray}{reference / invalid-starray} 
          {addkeyval:1} {#1} {cannot~add:#2}
      }
  }

\cs_generate_variant:Nn \starray_def_from_keyval:nn {ne , ee}


\prg_new_protected_conditional:Npnn \starray_def_from_keyval:nn #1#2 {T, F, TF}
  {
    \__starray_if_valid:nTF { \l__starray_prefix_tl #1 _def_prop}
      {
        \keyval_parse:nnn
          {\__starray_def_from_keyval_parse:en  {#1}}
          {\__starray_def_from_keyval_parse:enn {#1}}
          { #2 }
        \prg_return_true:
      }
      { \prg_return_false: }
  }


%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% adding terms
%%%%
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%
%%% TODO: to add {_iter_from_hash} property {hash} -> iter (integer!)
%%%
%%%

\cs_new_protected:Npn \__starray_new_term:nn #1#2
  {
    \int_gincr:N
        {\prop_item:cn {\l__starray_prefix_tl #1 _base_prop} {cnt} }

    \int_gset_eq:NN
       {\prop_item:cn {\l__starray_prefix_tl #1 _base_prop} {iter} }
       {\prop_item:cn {\l__starray_prefix_tl #1 _base_prop} {cnt} }


    % idx_hash Update.
    \prop_get:cnN {\l__starray_prefix_tl #1 _base_prop} {idx_hash} \l_tmpa_prop
    \prop_get:cnN {\l__starray_prefix_tl #1 _base_prop} {iter_hash} \l_tmpb_prop

    \prop_put:Nee \l_tmpa_prop
      { \int_use:N  \prop_item:cn {\l__starray_prefix_tl #1 _base_prop} {cnt}  }
      { \int_to_Alph:e { \prop_item:cn {\l__starray_prefix_tl #1 _base_prop} {cnt} }  }

    \prop_put:Nee \l_tmpb_prop
      { \int_use:N  \prop_item:cn {\l__starray_prefix_tl #1 _base_prop} {cnt}  }
      { \int_use:N  \prop_item:cn {\l__starray_prefix_tl #1 _base_prop} {cnt}  }

    \tl_if_blank:nF {#2}
      {
        \prop_put:Nee \l_tmpa_prop
          { #2  }
          { \int_to_Alph:e { \prop_item:cn {\l__starray_prefix_tl #1 _base_prop} {cnt} }  }
        \prop_put:Nee \l_tmpb_prop
          { #2  }
          { \int_use:N  \prop_item:cn {\l__starray_prefix_tl #1 _base_prop} {cnt} }  
      }

    \prop_gput:cnV  {\l__starray_prefix_tl #1 _base_prop} {idx_hash} \l_tmpa_prop

    \prop_gput:cnV  {\l__starray_prefix_tl #1 _base_prop} {iter_hash} \l_tmpb_prop

    % creating the 'new property list' (aka. term)
    \tl_set:Ne \l_tmpa_tl
      { \int_to_Alph:e {  \prop_item:cn {\l__starray_prefix_tl #1 _base_prop} {cnt} }  }

    \prop_new:c
      { \l__starray_prefix_tl #1 _ \l_tmpa_tl _term_prop }

    \prop_get:cnN {\l__starray_prefix_tl #1 _base_prop} {def_ref} \l_tmpb_tl

    \prop_get:cnN {\l__starray_prefix_tl \l_tmpb_tl _def_prop} {def} \l_tmpa_prop

    \prop_gset_eq:cN { \l__starray_prefix_tl #1 _ \l_tmpa_tl _term_prop } \l_tmpa_prop

    \prop_get:cnN {\l__starray_prefix_tl \l_tmpb_tl _def_prop} {@st_seq} \l_tmpa_seq

% map over 'all sub-starrays parts of def_ref -> st_seq (those starting with a dot, @st_seq)
    \seq_map_tokens:Nn
      \l_tmpa_seq
      {
        \__starray_sub_base_new:nnn
          { \l_tmpb_tl }{ #1 _ \l_tmpa_tl }
      }
  }


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

\cs_new_protected:Npn \starray_new_term:nn #1#2
  {
    \__starray_parser:nnTF {\c__starray_no_idx_ending_bool}{#1}
      {
        \__starray_new_term:nn
          {\l__starray_parsed_ref_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:nnTF {\c__starray_no_idx_ending_bool}{#1}
      {
        \__starray_new_term:nn
          {\l__starray_parsed_ref_tl }
          {#2}
        \prg_return_true:
      }
      { \prg_return_false: }
  }


%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% changing iterator value (recursing over sub-structures)
%%%%
%%%% NOTE: since iterator change 'can' be just local, 'temp vars' are recursive aware.
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%

\cs_new_protected:Npn \__starray_incr_iter:n #1
  {
    \int_compare:nNnTF
      {\prop_item:cn {\l__starray_prefix_tl #1 _base_prop} {iter}} <
      {\prop_item:cn {\l__starray_prefix_tl #1 _base_prop} {cnt}}
      {
        \int_gincr:N { \prop_item:cn {\l__starray_prefix_tl #1 _base_prop} {iter} }
      }
      {
        % TODO: validade _rtn_bool for end user???
        \bool_set_false:N \l__starray_rtn_bool
      }
  }

\prg_new_protected_conditional:Npnn \__starray_set_iter:nn #1#2 {T , F , TF}
  {
    \int_compare:nNnTF {#1} > {\prop_item:cn {\l__starray_prefix_tl #2 _base_prop} {cnt}}
      {
        \int_gset_eq:NN
          { \prop_item:cn {\l__starray_prefix_tl #2 _base_prop} {iter} }
          { \prop_item:cn {\l__starray_prefix_tl #2 _base_prop} {cnt} }
        \prg_return_false:
      }
      {
        \int_gset:Nn
          { \prop_item:cn {\l__starray_prefix_tl #2 _base_prop} {iter} }
          { #1 }
        \prg_return_true:
      }
  }

\prg_generate_conditional_variant:Nnn \__starray_set_iter:nn {ne} {T , F , TF}

\cs_new_protected:Npn \__starray_set_sub_iter:nnn #1#2#3
  {
    \prop_get:cnN {\l__starray_prefix_tl #2#3 _base_prop} {idx_hash} \l_tmpa_prop
  
    \prop_get:NecT \l_tmpa_prop
      { \int_use:N \prop_item:cn {\l__starray_prefix_tl #2#3 _base_prop} {iter} }
      { l__starray_tmp #1 A_tl }
      {
        \prop_get:cnN 
          {\l__starray_prefix_tl #2#3 _base_prop} 
          {def_ref} 
          \l_tmpa_tl
  
        \prop_get:cnc 
          { \l__starray_prefix_tl \l_tmpa_tl _def_prop } 
          { @st_seq } 
          {l__starray_tmp #1 A_seq }
  
        \seq_if_empty:cF {l__starray_tmp #1 A_seq }
          {
            \seq_map_variable:cNn
              { l__starray_tmp #1 A_seq }
              \l_tmpb_tl
              {
                \__starray_set_iter:neTF 
                  { 1 }
                  { #2#3 _ \tl_use:c {l__starray_tmp #1 A_tl} . \l_tmpb_tl }
                  {}
                  {}
  
                \__starray_set_sub_iter:nne
                  { #1 A }
                  { #2#3 _ \tl_use:c {l__starray_tmp #1 A_tl} . }
                  { \l_tmpb_tl }
              }
          }
      }
  }

\cs_generate_variant:Nn \__starray_set_sub_iter:nnn {nne}


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

\cs_new_protected:Npn \starray_set_iter:nn #1#2
  {
    \__starray_parser:nnTF {\c__starray_no_idx_ending_bool}{#1}
      {
        \int_compare:nNnTF {#2} < {1}
          { 
            \__starray_set_iter:nnTF {1}{\l__starray_parsed_ref_tl} 
              {} {}
          }
          { 
            \__starray_set_iter:nnTF {#2}{\l__starray_parsed_ref_tl} 
              {} {}
          }
        \__starray_set_sub_iter:nnn {}{\l__starray_parsed_ref_tl}{}
      }
      {
        \__starray_msg_dispatch:
        \msg_warning:nnnn {starray} {syntax /  iter} {iter:1} {#1}
      } % returns nothing by default
  }



\prg_new_protected_conditional:Npnn \starray_set_iter:nn #1#2 {T, F, TF}
  {
    \bool_set_true:N \l__starray_rtn_bool

    \__starray_parser:nnTF {\c__starray_no_idx_ending_bool}{#1}
      {
        \int_compare:nNnTF {#2} < {1}
          { 
            \bool_set_false:N \l__starray_rtn_bool
            \__starray_set_iter:nnTF {1}{\l__starray_parsed_ref_tl} 
              {}
              {}
          }
          { 
            \__starray_set_iter:nnTF {#2}{\l__starray_parsed_ref_tl} 
              {}
              {\bool_set_false:N \l__starray_rtn_bool}
          }
        \__starray_set_sub_iter:nnn {}{\l__starray_parsed_ref_tl}{}
        \bool_if:NTF \l__starray_rtn_bool
          {\prg_return_true:}
          {\prg_return_false:}
      }
      { 
        \bool_set_false:N \l__starray_rtn_bool
        \seq_clear:N \l__starray_msg_seq
        \prg_return_false: 
      }
  }


%%%%%%%%%%%%%%%
%%%%
%%%% \starray_reset_iter
%%%%
%%%%%%%%%%%%%%%

\cs_new_protected:Npn \starray_reset_iter:n #1
  {
    \__starray_parser:nnTF {\c__starray_no_idx_ending_bool}{#1}
      {
        \__starray_set_iter:nnTF {1}{\l__starray_parsed_ref_tl} {}{}
        \__starray_set_sub_iter:nnn {}{\l__starray_parsed_ref_tl}{}
      }
      {
        \__starray_msg_dispatch:
        \msg_warning:nnnn {starray} {syntax /  iter} {iter:4} {#1}
      } % returns nothing by default
  }


\prg_new_protected_conditional:Npnn \starray_reset_iter:n #1 {T, F, TF}
  {
    \bool_set_true:N \l__starray_rtn_bool
  
    \__starray_parser:nnTF {\c__starray_no_idx_ending_bool}{#1}
      {
        \__starray_set_iter:nnTF {1}{\l__starray_parsed_ref_tl} {}{\bool_set_false:N \l__starray_rtn_bool} %% TODO: verify logic !@!!
        \__starray_set_sub_iter:nnn {}{\l__starray_parsed_ref_tl}{}
        \bool_if:NTF \l__starray_rtn_bool
          {\prg_return_true:}
          {\prg_return_false:}
      }
      { 
        \seq_clear:N \l__starray_msg_seq
        \prg_return_false: 
      }
  }


%%%%%%%%%%%%%%%
%%%%
%%%% \starray_next_iter
%%%%
%%%%%%%%%%%%%%%

\cs_new_protected:Npn \starray_next_iter:n #1
  {
    \bool_set_true:N \l__starray_rtn_bool
    \seq_clear:N \l__starray_msg_seq

    \__starray_parser:nnTF {\c__starray_no_idx_ending_bool}{#1}
      {
        \__starray_incr_iter:n {\l__starray_parsed_ref_tl}
        \__starray_set_sub_iter:nnn {}{\l__starray_parsed_ref_tl}{}
      }
      {
        \__starray_msg_dispatch:
        \bool_set_false:N \l__starray_rtn_bool
        \msg_warning:nnnn {starray} {syntax /  iter} {iter:5} {#1}
      } % returns nothing by default
  }



\prg_new_protected_conditional:Npnn \starray_next_iter:n #1 {T, F, TF}
  {
    \bool_set_true:N \l__starray_rtn_bool
    \seq_clear:N \l__starray_msg_seq
  
    \__starray_parser:nnTF {\c__starray_no_idx_ending_bool}{#1}
      {
        \__starray_incr_iter:n {\l__starray_parsed_ref_tl}
        \__starray_set_sub_iter:nnn {}{\l__starray_parsed_ref_tl}{}
        \bool_if:NTF \l__starray_rtn_bool
          {\prg_return_true:}
          {\prg_return_false:}
      }
      { 
        \bool_set_false:N \l__starray_rtn_bool
        \prg_return_false: 
      }
  }

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


\cs_new:Npn \__starray_get_prop:nn #1#2
  {
    \prop_item:cn {\l__starray_prefix_tl #1 _term_prop}{#2}
  }

\cs_generate_variant:Nn \__starray_get_prop:nn {ee}


%%%%%%%%%%%%%%%
%%%%
%%%% \starray_get_prop
%%%%
%%%%%%%%%%%%%%%

\cs_new_protected:Npn \starray_get_prop:nn #1#2
  {
    \__starray_parser:nnTF {\c__starray_idx_ending_bool}{#1}
    {
      \__starray_get_prop:ee {\l__starray_parsed_ref_tl}{#2}
    }
    {
      \__starray_msg_dispatch:
      \msg_warning:nnnn {starray} {syntax /  prop} {get:1} {#1}
    } % returns nothing by default
  }
  
  
%%%%%%%%%%%%%%%%
%%%
%%% WARNING: This is uses the 'last parsed term'.
%%%
%%%%%%%%%%%%%%%%  
\cs_new:Npn \starray_parsed_get_prop:n #1
  {
    \__starray_get_prop:ee {\l__starray_parsed_ref_tl}{#1}
  }  

\cs_new_protected:Npn \starray_get_prop:nnN #1#2#3
  {
    \__starray_parser:nnTF {\c__starray_idx_ending_bool}{#1}
      {
        \prop_get:cnNF 
          {\l__starray_prefix_tl \l__starray_parsed_ref_tl _term_prop} {#2} #3
          { \tl_set:Nn #3 {} }
      }
      {
        \tl_set:Nn #3 {}
        \__starray_msg_dispatch:
        \msg_warning:nnnn {starray} {syntax /  prop} 
          {get:1} {#1}
      } % returns nothing by default
  }


\prg_new_protected_conditional:Npnn \starray_get_prop:nnN #1#2#3 {T, F, TF}
  {
    \__starray_parser:nnTF {\c__starray_idx_ending_bool}{#1}
      {
        \prop_get:cnNTF 
          {\l__starray_prefix_tl \l__starray_parsed_ref_tl _term_prop} 
          {#2} 
          #3
          {
            \prg_return_true:
          }
          {
            \tl_set:Nn #3 {}
            \prg_return_false:
          }
      }
      {
        \tl_set:Nn #3 {}
        \seq_clear:N \l__starray_msg_seq
        \prg_return_false:
      } % returns nothing by default
  }



\prg_new_protected_conditional:Npnn \starray_if_in:nn #1#2 {T, F, TF}
  {
    \__starray_parser:nnTF {\c__starray_idx_ending_bool} {#1}
      {
        \prop_if_in:cnTF 
          { \l__starray_prefix_tl \l__starray_parsed_ref_tl _term_prop } 
          {#2}
          { \prg_return_true: }
          { \prg_return_false: }
      }
      {
        \seq_clear:N \l__starray_msg_seq
        \prg_return_false:
      } % returns nothing by default
  }

%%%%%%%%%%%%%%%%
%%%
%%% WARNING: This is uses the 'last parsed term'.
%%%
%%%%%%%%%%%%%%%%
\prg_new_conditional:Npnn \starray_parsed_if_in:n #1 {p, T, F, TF}
  {
    \prop_if_in:cnTF 
      { \l__starray_prefix_tl \l__starray_parsed_ref_tl _term_prop } 
      {#1}
      { \prg_return_true: }
      { \prg_return_false: }
  }


\cs_new_protected:Npn \starray_get_cnt:n #1
  {
    \__starray_parser:nnTF {\c__starray_no_idx_ending_bool}{#1}
      {
        \int_use:N 
          \prop_item:cn { \l__starray_prefix_tl \l__starray_parsed_ref_tl _base_prop } {cnt}
      }
      {
        \__starray_msg_dispatch:
        \msg_warning:nnnn {starray} {syntax /  prop} {get:XX} {#1}
      } % returns nothing by default
  }


%%%%%%%%%%%%%%%%
%%%
%%% WARNING: This uses the 'last parsed term'.
%%%         It will leave cnt directly in the input stream
%%%%%%%%%%%%%%%%
\cs_new:Npn \starray_parsed_get_cnt:
  {
    \int_use:N
      \prop_item:cn { \l__starray_prefix_tl \l__starray_parsed_ref_no_idx_ending_tl _base_prop } {cnt}
  }
   

\cs_new_protected:Npn \starray_get_cnt:nN #1#2
  {
    \__starray_parser:nnTF {\c__starray_no_idx_ending_bool}{#1}
      {
        \int_set_eq:NN 
          #2 
          \prop_item:cn { \l__starray_prefix_tl \l__starray_parsed_ref_tl _base_prop } {cnt}
      }
      {
        \__starray_msg_dispatch:
        \msg_warning:nnnn {starray} {syntax /  prop} 
          {get:XX} {#1}
      } % returns nothing by default
  }

\prg_new_protected_conditional:Npnn \starray_get_cnt:nN #1#2  {T, F, TF}
  {
    \__starray_parser:nnTF {\c__starray_no_idx_ending_bool}{#1}
      {
        \int_set_eq:NN 
          #2 
          \prop_item:cn { \l__starray_prefix_tl \l__starray_parsed_ref_tl _base_prop } {cnt}
        \prg_return_true:
      }
    {
      \seq_clear:N \l__starray_msg_seq
      \prg_return_false:
    } % returns nothing by default
  }

\cs_new_protected:Npn \starray_get_iter:n #1
  {
    \__starray_parser:nnTF {\c__starray_no_idx_ending_bool}{#1}
      {
        \int_use:N 
          \prop_item:cn { \l__starray_prefix_tl \l__starray_parsed_ref_tl _base_prop } {iter}
      }
      {
        \__starray_msg_dispatch:
        \msg_warning:nnnn {starray} {syntax /  prop} 
          {get:XX} {#1}
      } % returns nothing by default
  }


%%%%%%%%%%%%%%%%
%%%
%%% WARNING: This uses the 'last parsed term'.
%%%         It will leave current iter directly in the input stream
%%%%%%%%%%%%%%%%
\cs_new:Npn \starray_parsed_get_iter:
  {
    \int_use:N 
      \prop_item:cn { \l__starray_prefix_tl \l__starray_parsed_ref_no_idx_ending_tl _base_prop } {iter}
  }


\cs_new_protected:Npn \starray_get_iter:nN #1#2
  {
    \__starray_parser:nnTF {\c__starray_no_idx_ending_bool}{#1}
    {
      \int_set_eq:NN 
        #2 
        \prop_item:cn { \l__starray_prefix_tl \l__starray_parsed_ref_tl _base_prop } {iter}
    }
    {
      \__starray_msg_dispatch:
      \msg_warning:nnnn {starray} {syntax /  prop} 
        {get:XX} {#1}
    } % returns nothing by default
  }

\prg_new_protected_conditional:Npnn \starray_get_iter:nN #1#2 {T, F, TF}
  {
    \__starray_parser:nnTF {\c__starray_no_idx_ending_bool}{#1}
    {
      \int_set_eq:NN 
        #2 
        \prop_item:cn { \l__starray_prefix_tl \l__starray_parsed_ref_tl _base_prop } {iter}
      \prg_return_true:
    }
    {
      \seq_clear:N \l__starray_msg_seq
      \prg_return_false:
    } % returns nothing by default
  }





\cs_new_protected:Npn \__starray_set_prop:nnn #1#2#3
  {
    \l__starray_put_tl {\l__starray_prefix_tl #1 _term_prop}{#2}{#3}
  }


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

\cs_new_protected:Npn \starray_set_prop:nnn #1#2#3
  {
    \tl_set:Nn \l__starray_put_tl \prop_put:cnn
    \__starray_parser:nnTF {\c__starray_idx_ending_bool}{#1}
      {
        \__starray_set_prop:nnn {\l__starray_parsed_ref_tl}{#2}{#3}
      }
      {
        \__starray_msg_dispatch:
        \msg_warning:nnnn {starray} {syntax /  prop} 
          {set:1} {#1}
      } % returns nothing by default
  }

\cs_generate_variant:Nn \starray_set_prop:nnn {nnV}

\cs_new_protected:Npn \starray_gset_prop:nnn #1#2#3
  {
    \tl_set:Nn \l__starray_put_tl \prop_gput:cnn
    \__starray_parser:nnTF {\c__starray_idx_ending_bool}{#1}
      {
        \__starray_set_prop:nnn {\l__starray_parsed_ref_tl}{#2}{#3}
      }
      {
        \__starray_msg_dispatch:
        \msg_warning:nnnn {starray} {syntax /  prop} 
          {set:1} {#1}
      } % returns nothing by default
  }

\cs_generate_variant:Nn \starray_gset_prop:nnn {nnV}


\prg_new_protected_conditional:Npnn \starray_set_prop:nnn #1#2#3 {T, F, TF}
  {
    \tl_set:Nn \l__starray_put_tl \prop_put:cnn
    \__starray_parser:nnTF {\c__starray_idx_ending_bool}{#1}
      {
        \__starray_set_prop:nnn {\l__starray_parsed_ref_tl}{#2}{#3}
        \prg_return_true:
      }
      { 
        \seq_clear:N \l__starray_msg_seq
        \prg_return_false: 
      }
  }

\prg_generate_conditional_variant:Nnn \starray_set_prop:nnn { nnV } { p , T, F , TF }

\prg_new_protected_conditional:Npnn \starray_gset_prop:nnn #1#2#3 {T, F, TF}
  {
    \tl_set:Nn \l__starray_put_tl \prop_gput:cnn
    \__starray_parser:nnTF {\c__starray_idx_ending_bool}{#1}
      {
        \__starray_set_prop:nnn {\l__starray_parsed_ref_tl}{#2}{#3}
        \prg_return_true:
      }
      { 
        \seq_clear:N \l__starray_msg_seq
        \prg_return_false: 
      }
  }


\prg_generate_conditional_variant:Nnn \starray_gset_prop:nnn { nnV } { p , T, F , TF }


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

%
% 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 ] #3 \q_stop { TF}
  {
    \quark_if_nil:nTF {#3}
      { \prg_return_false: } %% syntax ERR
      {
        \tl_set:cn {l__starray_tmp #1 :A_tl} {#2}
        \prg_return_true:
      }
  }


%
% 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}
  {
    \__starray_set_parse_end:wTF  {#1}#2 ] \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 [ #3 \q_stop { TF}
  {
    \quark_if_nil:nTF {#3}
      {               % no 'term' ref, just array_name (current/iter term)
        \tl_clear:c {l__starray_tmp #1 :A_tl}
        \prg_return_true:
      }
      {
        \tl_set:cn {l__starray_tmp #1 :B_tl}{#2}
        \__starray_set_parse_aux:wTF {#1}#3 \q_stop
          {\prg_return_true:}
          {\prg_return_false:}
      }
  }



\cs_new:Npn \__starray_set_from_keyval_parse:nnnn #1#2#3#4
  {
    \__starray_set_prop:nnn {#3}{#4}{}
  }

\cs_generate_variant:Nn \__starray_set_from_keyval_parse:nnnn {neen}

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

%%% what a mess. :(
%%% #1 => tmp series A, AA, AAA
%%% #2 => no_idx_ending ref 
%%% #3 => idx_ending ref !!!
%%% #4 => prop/struct(key from keyval)
%%% #5 => val/keyval (val from keyval)
%%%
\cs_new:Npn \__starray_set_from_keyval_parse:nnnnn #1#2#3#4#5
  {
    \tl_clear:c {l__starray_tmp #1 _tl}

    \__starray_set_parse_begin:wTF {#1}#4 [ \q_nil \q_stop
      {
        \tl_if_blank:eTF {\tl_use:c{l__starray_tmp #1 :A_tl}}
          {
          %
          % what should be here: 
          %  get #2_base_prop -> _def_prop -> @st_seq
          % _base_prop comes from (parser) _no_idx_ending_tl
          %
          % from there #3.<#4> => {}{...} 'next #2'
          %    #3.<#4>_[<#4>] (idx construct from #4) 'next #3'
          %
            \prop_get:cnc
              {\l__starray_prefix_tl #2 _base_prop}
              {def_ref}
              {l__starray_tmp #1 _def_prop}
            
            \prop_get:cnc 
              {\l__starray_prefix_tl \tl_use:c {l__starray_tmp #1 _def_prop} _def_prop}
              {@st_seq}
              {l__starray_tmp #1 _seq}
              
            \seq_if_in:cnTF {l__starray_tmp #1 _seq}{#4}
              { 
                \prop_get:cnc
                  { \l__starray_prefix_tl #3 .#4 _base_prop }
                  { idx_hash }
                  { l__starray_tmp #1 _hash_prop }
                \prop_get:cnc
                  { \l__starray_prefix_tl #3 .#4 _base_prop }
                  { iter }
                  { l__starray_tmp #1 _int }
                \int_compare:nNnTF {\int_use:c {l__starray_tmp #1 _int}} < {1}
                  {
                    \__starray_msg:nnnnn {reference / iter}
                      {setkeyval:2}{#2.#4}{-0-}{~(not~instantiated)}
                    % invalid iter / not instantiated
                  }
                  {
                    \tl_set:ce
                      { l__starray_tmp #1 _tl }
                      { #3.#4 _ \int_to_Alph:e {\int_use:c {l__starray_tmp #1 _int}} }

                    \keyval_parse:nnn
                      {
                        \__starray_set_from_keyval_parse:neen
                          { #1 A }
                          { #3.#4 }
                          { \tl_use:c { l__starray_tmp #1 _tl } }
                      }
                      {
                        \__starray_set_from_keyval_parse:neenn
                          { #1 A }
                          { #3.#4 }
                          { \tl_use:c { l__starray_tmp #1 _tl } }
                      }
                      { #5 }

                  }
              }
              {
                \__starray_set_prop:nnn {#3}{#4}{#5}
              }
          }
          {
            \prop_get:cnc
              {\l__starray_prefix_tl #2 _base_prop}
              {def_ref}
              {l__starray_tmp #1 _def_prop}
            
            \prop_get:cnc 
              {\l__starray_prefix_tl \tl_use:c {l__starray_tmp #1 _def_prop} _def_prop}
              {@st_seq}
              {l__starray_tmp #1 _seq}

            \seq_if_in:ceTF 
              { l__starray_tmp #1 _seq }  { \tl_use:c{l__starray_tmp #1 :B_tl} }
              {
                \prop_get:cnc
                  { \l__starray_prefix_tl #3. \tl_use:c{l__starray_tmp #1 :B_tl} _base_prop }
                  { idx_hash }
                  { l__starray_tmp #1 _hash_prop }
                \tl_set:ce
                  { l__starray_tmp #1 _idx_tl }
                  {
                    #3 . \tl_use:c{l__starray_tmp #1 :B_tl} _
                    \prop_item:ce
                      { l__starray_tmp #1 _hash_prop }
                      { \tl_use:c{ l__starray_tmp #1 :A_tl } }
                  }
                \tl_put_left:cn { l__starray_tmp #1 :B_tl } { #3 . }
                \prop_if_in:ceTF 
                  { l__starray_tmp #1 _hash_prop }
                  { \tl_use:c{l__starray_tmp #1 :A_tl}}
                  {
                    \keyval_parse:nnn
                      {
                        \__starray_set_from_keyval_parse:neen
                        { #1 A }
                        { \tl_use:c{l__starray_tmp #1 :B_tl} }
                        { \tl_use:c { l__starray_tmp #1 _idx_tl } }
                      }
                      {
                        \__starray_set_from_keyval_parse:neenn
                        { #1 A }
                        { \tl_use:c{l__starray_tmp #1 :B_tl} }
                        { \tl_use:c { l__starray_tmp #1 _idx_tl } }
                      }
                      { #5 }

                  }
                  {
                    \__starray_msg:nneee {reference / iter}
                      {setkeyval:3} {#2.#4} {\tl_use:c{l__starray_tmp #1 :A_tl}} {}
                    % invalid hash
                  }
              }
              {
                \__starray_msg:nneee {syntax / structure-ref}
                  {setkeyval:4} {#2.#4} {\tl_use:c{l__starray_tmp #1 :B_tl}} {}
                % invalid ref / not a substructure
              }
          }
      }
      {
        \__starray_msg:nnnnn {syntax / term}
          {setkeyval:5}{#4}{}{}
        % invalid ref/syntax
      }
  }

\cs_generate_variant:Nn \__starray_set_from_keyval_parse:nnnnn {neenn}


%%%%%%%%%%%%%%%
%%%%
%%%% \starray_set_from_keyval
%%%%
%%%%%%%%%%%%%%%

\tl_new:N \l__starray_from_keyval_orgref_tl

\cs_new_protected:Npn \__starray_set_from_keyval:nn #1#2
  {
    \bool_set_true:N \l__starray_rtn_bool
    
    %%% just in case, for msg_err messages
    \tl_set:Nn \l__starray_from_keyval_orgref_tl {#1}
    
    \__starray_parser:nnTF {\c__starray_idx_ending_bool}{#1}
    {
      \keyval_parse:nnn
        {\__starray_set_from_keyval_parse:neen  {A}{\l__starray_parsed_ref_no_idx_ending_tl}{\l__starray_parsed_ref_tl}}
        {\__starray_set_from_keyval_parse:neenn {A}{\l__starray_parsed_ref_no_idx_ending_tl}{\l__starray_parsed_ref_tl}}
        { #2 }
      \bool_if:NF \l__starray_rtn_bool
        { \__starray_msg_dispatch: }
    }
    {
      \__starray_msg_dispatch:
      \msg_warning:nnnn {starray} {syntax /  prop} 
        {setkeyval:1} {#1}
    } % returns nothing by default
  }


\cs_new_protected:Npn \starray_set_from_keyval:nn #1#2
  {
    \tl_set:Nn \l__starray_put_tl \prop_put:cnn
    \__starray_set_from_keyval:nn {#1}{#2}
  }

\cs_new_protected:Npn \starray_gset_from_keyval:nn #1#2
  {
    \tl_set:Nn \l__starray_put_tl \prop_gput:cnn
    \__starray_set_from_keyval:nn {#1}{#2}
  }

%%%
%%% small surprise, it was possible to _protected it... TODO: further test it.
%%%
\cs_new_protected:Npn \__starray_set_from_keyvalTF:nn #1#2
  {
    \bool_set_true:N \l__starray_rtn_bool
    
    %%% just in case, for msg_err messages
    \tl_set:Nn \l__starray_from_keyval_orgref_tl {#1}
    
    \__starray_parser:nnTF {\c__starray_idx_ending_bool}{#1}
      {
        \keyval_parse:nnn
          {\__starray_set_from_keyval_parse:neen  {A}{\l__starray_parsed_ref_no_idx_ending_tl}{\l__starray_parsed_ref_tl}}
          {\__starray_set_from_keyval_parse:neenn {A}{\l__starray_parsed_ref_no_idx_ending_tl}{\l__starray_parsed_ref_tl}}
          { #2 }
        \bool_if:NTF \l__starray_rtn_bool
          {\prg_return_true:}
          {\prg_return_false:}
      }
      { \prg_return_false: }
  }
  
\prg_new_protected_conditional:Npnn \starray_set_from_keyval:nn #1#2 {T, F, TF}
  {
    \tl_set:Nn \l__starray_put_tl \prop_put:cnn
    \__starray_set_from_keyvalTF:nn {#1}{#2}
  }
  
\prg_new_protected_conditional:Npnn \starray_gset_from_keyval:nn #1#2 {T, F, TF}
  {
    \tl_set:Nn \l__starray_put_tl \prop_gput:cnn
    \__starray_set_from_keyvalTF:nn {#1}{#2}
  }


%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% starray ref/address parser using quarks
%%%% could be done with seq_split and regex but
%%%% would have been even more cumbersome
%%%%
%%%% <starray_ref> := <array_ref> [ . <starray_ref> ]
%%%% <array_ref>   := <array_name> [ <term_ref> ]
%%%% <term_ref>    := \[ <number/hash> \]
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%

%%%
%%% \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}
        \prg_return_true:
      }
  }


%%%
%%% \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:}
  }


%%%
%%% \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:}
      }
  }


%  verify #2 before going for #1 . . .
%  if #2 isn't empty test for it, return true/false
%  if #2 is empty, test if #1 is valid, return true/false
\prg_new_protected_conditional:Npnn \__starray_if_valid_idx:nn #1#2 {T, F, TF}
  {
    \prop_get:cnN {\l__starray_prefix_tl \l__starray_parsed_ref_tl _base_prop} {idx_hash} \l_tmpa_prop

    \tl_if_blank:nTF {#2}
      {
        \tl_put_right:Ne \l__starray_parsed_ref_tl
          {  _  \prop_item:Ne \l_tmpa_prop {#1} }
      }
      {
        \tl_put_right:Ne \l__starray_parsed_ref_tl
          {  _  \prop_item:Ne \l_tmpa_prop {#2} }
      }

    \prop_if_exist:cTF { \l__starray_prefix_tl \l__starray_parsed_ref_tl _term_prop }
      {\prg_return_true:}
      {\prg_return_false:}
  }

\prg_generate_conditional_variant:Nnn \__starray_if_valid_idx:nn {ee} {T, F, TF}


%%%
%%% small surprise, it was possible to _protected this... TODO: further test it.
%%%
\cs_new_protected:Npn \__starray_ref_parse:w #1 . #2 \q_stop
  {
    \tl_put_right:Ne \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_parser_aux_tl \l__starray_parsed_term_tl }
        \tl_put_right:Ne \l__starray_parsed_base_ref_tl 
          { \l__starray_parser_aux_tl \l__starray_parsed_term_tl }
        \tl_set:Nn \l__starray_parser_aux_tl { . }

        \__starray_if_valid:eTF 
          {\l__starray_prefix_tl \l__starray_parsed_ref_tl _base_prop}
          {
            \quark_if_nil:nTF {#2}
            {       % this is the last one
              \tl_set:Ne 
                \l__starray_parsed_ref_no_idx_ending_tl 
                {\l__starray_parsed_ref_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:nneee {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
                \__starray_if_valid_idx:eeTF
                  {
                    \int_use:N 
                      \prop_item:cn
                        {\l__starray_prefix_tl \l__starray_parsed_ref_tl _base_prop}
                        {iter}
                  }
                  {
                    \l__starray_parsed_idx_tl
                  }
                  { }      % done, finish, ok
                  {
                    \bool_set_false:N \l__starray_parser_OK_bool
                    \__starray_msg:nneee {syntax / ref-syntax-err} {parser:2} 
                      {\l__starray_parsing_term_tl} 
                      {invalid~index~\l__starray_parsed_idx_tl} 
                      {}
                  }
              }
            }
            {                       
              \__starray_if_valid_idx:eeTF
                {
                  \int_use:N 
                    \prop_item:cn 
                      {\l__starray_prefix_tl \l__starray_parsed_ref_tl _base_prop} 
                      {iter}
                }
                {
                  \l__starray_parsed_idx_tl
                }
                {
                  \__starray_ref_parse:w #2 \q_stop
                }      % recurse next term
                {
                  \bool_set_false:N \l__starray_parser_OK_bool
                  \__starray_msg:nneee {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:nneee {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:nneee {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_ref_no_idx_ending_tl
%%%%                       \l__starray_parsed_base_ref_tl
%%%%                       \l__starray_parsed_root_ref_tl
%%%% parser 'false' returns:
%%%%                       
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%

\prg_new_protected_conditional:Npnn \__starray_parser:nn #1#2 {T, F, TF}
  {
    \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_tl
    \tl_clear:N \l__starray_parsed_ref_tl
    \tl_clear:N \l__starray_parsed_ref_no_idx_ending_tl
    \tl_clear:N \l__starray_parsed_base_ref_tl
    \tl_clear:N \l__starray_parsed_root_ref_tl

    \tl_set:Nn \l__starray_parser_aux_tl {}
    
    \tl_set:Nn \l__starray_parsing_term_tl {#2}

    \__starray_ref_parse:w #2 .\q_nil\q_stop

    \bool_if:NTF \l__starray_parser_OK_bool
      {
        \tl_set:Ne \l__starray_parsed_root_ref_tl
          { \__starray_get_root:w \l__starray_parsed_base_ref_tl .\q_nil\q_stop }
        \prg_return_true:
      }
      {
        \prg_return_false:
      }
  }


\prg_new_protected_conditional:Npnn \starray_term_syntax:n #1 {T, F, TF}
  {
    \__starray_parser:nnTF {\c__starray_idx_ending_bool}{#1}
      {\prg_return_true:}
      {
        \seq_clear:N \l__starray_msg_seq
        \prg_return_false:
      }
  }
  
\cs_new:Npn \starray_term_syntax:n #1
  {
    \__starray_parser:nnTF {\c__starray_idx_ending_bool}{#1}
      {}
      {}  
  }  

%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% \..show_def commands
%%%%
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% Note to self: 
%%%% \l__starray_showcmd_tl could be an extra param as well
%%%% (more tokens jungling around...)
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%


\cs_new_protected:Npn \__starray_show_def_item:nnn #1#2#3
  {
    \tl_gput_right:Nn \l__starray_tmpa_tl
    {
      \l__starray_showcmd_tl > #1 \use:nnn { ~ } { ~ } { ~ }
      \tl_to_str:n { {#2} }
      \use:nn { ~ } { ~ } => \use:nn { ~ } { ~ }
      \tl_to_str:n { {#3} }
    }
  }

\cs_new_protected:Npn \__starray_show_def:nnn #1#2#3
  {
    \group_begin:
      \tl_gput_right:Nn \l__starray_tmpa_tl
      {
        \l__starray_showcmd_tl > #1
        \tl_to_str:n {{#3} ~ struct}
        \use:nn { ~ } { ~ } =>
      }
  
      \prop_get:cnc 
        {\l__starray_prefix_tl #2#3 _def_prop} 
        {def} 
        {l__starray_tmp A _def_prop}
  
      \prop_get:cnc 
        { \l__starray_prefix_tl #2#3 _def_prop } 
        { @st_seq } 
        {l__starray_tmp A _seq }
  
      \prop_map_tokens:cn 
        {l__starray_tmp A _def_prop} 
        {\__starray_show_def_item:nnn {#1}}
  
      \seq_if_empty:cF { l__starray_tmp A _seq }
        {
          \seq_map_tokens:cn
          { l__starray_tmp A _seq }
          { \__starray_show_def:nnn  { #1 \use:nnn { ~ } { ~ } { ~ }} { #2#3. }  }
        }
    \group_end:
  }

%%%%%%%%%%%%%%%
%%%%
%%%% \starray_show_def
%%%%
%%%%%%%%%%%%%%%

\cs_new_protected:Npn \starray_show_def:n #1
  {
    \tl_clear:N \l__starray_tmpa_tl
    \tl_set:Nn \l__starray_showcmd_tl \iow_newline:
    \__starray_show_def:nnn {}{}{#1}

    \msg_show:nnxxx {starray}{info / show}
      { show~def }
      { The~ starray~ <#1> ~is~defined~as~follow: }
      { \tl_use:N \l__starray_tmpa_tl }
  }

\cs_new_protected:Npn \starray_show_def_in_text:n #1
  {
    \tl_clear:N \l__starray_tmpa_tl
    \tl_set:Nn \l__starray_showcmd_tl \par
    \__starray_show_def:nnn {}{}{#1}
  
    \tl_use:N \l__starray_tmpa_tl
  }



%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% \..show_terms commands
%%%%
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%
%%%%
%%%% Note to self: 
%%%% \l__starray_showcmd_tl could be an extra param as well
%%%% (more tokens jungling around...)
%%%%
%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%


\cs_new_protected:Npn \__starray_show_term_item:nnnnn #1#2#3#4#5
  {
    \group_begin:
      \tl_gput_right:Nn \l__starray_tmpa_tl
        {
          \l__starray_showcmd_tl > #1
          \tl_to_str:n { {#3[#4]} ~ (idx: ~ #5)}
          \use:nn { ~ } { ~ } =>
        }
  
      \prop_map_tokens:cn 
        {\l__starray_prefix_tl #2 #3 _ #5 _term_prop} 
        {\__starray_show_def_item:nnn {#1 }}
  
      \prop_get:cnN 
        { \l__starray_prefix_tl #2 #3 _base_prop } 
        { def_ref } 
        \l_tmpa_tl
  
      \prop_get:cnc 
        { \l__starray_prefix_tl \l_tmpa_tl _def_prop } 
        { @st_seq } 
        {l__starray_tmp A _seq }
  
      \seq_if_empty:cTF { l__starray_tmp A _seq }
        {}
        {
          \seq_map_tokens:cn
            { l__starray_tmp A _seq }
            { \__starray_show_terms:nen { #1 \use:nnn { ~ } { ~ } { ~ }} { #2  #3_#5. }  }
        }
    \group_end:
  }



\cs_new_protected:Npn \__starray_show_terms:nnn #1#2#3
  {
    \group_begin:
      \prop_get:cnc 
        {\l__starray_prefix_tl #2 #3 _base_prop} 
        {idx_hash} 
        {l__starray_tmp A _idx_prop}
  
      \prop_map_tokens:cn
        {l__starray_tmp A _idx_prop}
        {\__starray_show_term_item:nnnnn {#1}{#2}{#3}}
    \group_end:
  }

\cs_generate_variant:Nn \__starray_show_terms:nnn {nen}

%%%%%%%%%%%%%%%
%%%%
%%%% \starray_show_terms
%%%%
%%%%%%%%%%%%%%%

\cs_new_protected:Npn \starray_show_terms:n #1
  {
    \tl_clear:N \l__starray_tmpa_tl
    \tl_set:Nn \l__starray_showcmd_tl \iow_newline:
    \__starray_show_terms:nnn {}{}{#1}

    \msg_show:nnxxx {starray}{info / show}
      { show~terms }
      { The~ starray~ <#1> ~has~the~following~terms: }
      { \tl_use:N \l__starray_tmpa_tl }
  }

\cs_new_protected:Npn \starray_show_terms_in_text:n #1
  {
    \tl_clear:N \l__starray_tmpa_tl
    \tl_set:Nn \l__starray_showcmd_tl \par
    \__starray_show_terms:nnn {}{}{#1}
  
     \tl_use:N \l__starray_tmpa_tl
  }


