% !TEX program = pdflatex
% !TEX ext =  --interaction=nonstopmode --enable-etex
% !BIB program = none
%%%==============================================================================
%% 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 {1.9b} {2025/02/14}
%%
%% The list of files that compose this work can be found in the README.md file at
%% https://ctan.org/pkg/starray
%%
%%%==============================================================================
\documentclass[10pt]{article}
\RequirePackage[verbose,a4paper,marginparwidth=27.5mm,top=2.5cm,bottom=1.5cm,hmargin={40mm,20mm},marginparsep=2.5mm,columnsep=10mm,asymmetric]{geometry}
%\RequirePackage[verbose,a4paper,marginparwidth=27.5mm,top=2.5cm,bottom=1.5cm,hmargin={45mm,25mm},marginparsep=2.5mm,columnsep=10mm,asymmetric]{geometry}
\usepackage{codedescribe}
\usepackage{starray}
\RequirePackage[inline]{enumitem}
\SetEnumitemKey{miditemsep}{parsep=0ex,itemsep=0.4ex}

\RequirePackage[hidelinks,hypertexnames=false]{hyperref}
\begin{document}
\tstitle{
  author={Alceu Frigeri\footnote{\tsverb{https://github.com/alceu-frigeri/starray}}},
  date={\tsdate},
  title={The starray Package\break Version \PkgInfo{starray}{version}}
  }
  
\begin{typesetabstract}

This package implements vector like 'structures', alike 'C' and other programming languages. 
It's based on \tsobj[pkg]{expl3} and aimed at 'package writers', and not end users. The provided 'functions' are similar the ones provided for property (or sequence, or token) lists. Most of the provided functions have a companion 'branching version'.

\end{typesetabstract}

\tableofcontents

\section{Introduction}
The main idea is to have an array like syntax when setting/recovering structured information, e.g. \tsmacro{\starray_get_prop:nn} {student[2].work[3].reviewer[4] , name} where ''student'' is the starray root, ''work'' is a sub-structure (an array in itself), ''reviewer'' is a sub-structure of ''work'' and so on, \tsobj[marg]{name} being a property of ''reviewer''. Moreover one can iterate over the structure, for instance \tsmacro{\starray_get_prop:nn}{student.work.reviewer,name} is also a possible reference in which one is using ''student's'', ''work's'' and ''reviewer's'' iterators.

Internally, a \tsobj[pkg]{starray} is stored as a collection of property lists. Each \tsobj[pkg]{starray} can contain a list of property pairs (key/value as in any \tsobj[pkg]{expl3} property lists) and a list of sub-structures. Each sub-structure, at it's turn, can also contain a list of property pairs and a list of sub-structures. 

The construction/definition of a \tsobj[pkg]{starray} can be done piecewise (a property/sub-structure a time) or with a keyval interface or both, either way, one has to first ''create a root starray'' (\tsmacro{\starray_new:n}{}), define it's elements (properties and sub-structures), then instantiate them ''as needed''. An instance of a \tsobj[pkg]{starray} (or one of it's sub-structures) is referred, in this text, as a ''term''.

Finally, almost all defined functions have a branching version, as per \tsobj[pkg]{expl3}: \tsobj[code]{T,F,TF} (note: no \tsobj{_p} variants, see below). For simplicity, in the text bellow only the \underline{\textsl{TF}} variant is described, as in \tsobj[code]{\starray_new:nTF}, keep in mind that all 3 variants are defined, e.g. \tsobj[code]{\starray_new:nT,\starray_new:nF,\starray_new:nTF}.

\begin{tsremark}[Note:]
 Could it be implemented with a single property list? It sure could, but at a cost: 
\begin{enumerate*}   \item complexity;    \item access time.   \end{enumerate*}
The current implementation, albeit also complex, tries to reach a balance between inherent structure complexity, number of used/defined auxiliary property lists and access time.
\end{tsremark}

\begin{tsremark}[\color{red}Important:]
 \textsl{Expandability}, unfortunately most/all defined functions are not ''fully expandable'', in particular, most conditional/branching functions aren't, with just a few exceptions (marked with a star \ding{72}, as per \tsobj[pkg]{expl3} documentation convention).
 
\end{tsremark}


\section{Package Options}\label{pack:options}
The package options (\tsobj[key]{key}\,=\tsobj[value]{value}) are:
\begin{describelist}{option}
\describe{prefix}{(default: \tsobj[value]{\detokenize{l__starray_}} ). Set the \tsobj[key]{prefix} used when declaring the property lists associated with any \tsobj[pkg]{starray}.}

\describe{msg-err}{ 
By default, the \tsobj[pkg]{starray} package only generates ''warnings'', with \tsobj[option]{msg-err} one can choose which cases will generate ''package error'' messages. There are 3 message classes: 1. \tsobj[value]{strict} relates to \tsmacro{\starray_new:n}{} cases (\tsobj[pkg]{starray} creation); 2. \tsobj[value]{syntax} relates to ''term syntax'' errors (student.work.reviewer in the above examples); finally 3. \tsobj[value]{reference} relates to cases whereas the syntax is correct but referring to non-existent terms/properties. }

\begin{describelist*}{value}
\describe{none}{ (default) no package message will raise an error.}
\describe{strict}{ will raise an error on \tsobj[value]{strict} case alone.}
\describe{syntax}{ will raise an error on \tsobj[value]{strict} and \tsobj[value]{syntax} cases.}
\describe{reference}{ will raise an error on \tsobj[value]{strict}, \tsobj[value]{syntax} and \tsobj[value]{reference} cases.}
\describe{all}{ will raise an error on all cases.}
\end{describelist*}

\describe{msg-suppress}{ ditto, to suppress classes of messages:}
\begin{describelist*}{value}
\describe{none}{ (default) no package message will be suppressed.}
\describe{reference}{ only \tsobj[value]{reference} level messages will be suppressed.}
\describe{syntax}{ \tsobj[value]{reference} and \tsobj[value]{syntax} level messages will be suppressed.}
\describe{strict}{ \tsobj[value]{reference}, \tsobj[value]{syntax} and \tsobj[value]{strict} level messages will be suppressed.}
\describe{all}{ all messages will be suppressed.}
\end{describelist*}
\end{describelist}

\section{Creating a starray}\label{pack:new}
\begin{codedescribe}{\starray_new:n,\starray_new:nTF}
\begin{codesyntax}%
\tsmacro{\starray_new:n}{starray}
\tsmacro{\starray_new:nTF}{starray,if-true,if-false}
\end{codesyntax}
Creates a new \tsobj[marg]{starray} or raises a warning  if the name is already taken. The declaration (and associated property lists) is global. The given name is referred (in this text) as the \tsobj[marg]{starray-root} or just \tsobj[marg]{root}. 
\end{codedescribe}
\begin{tsremark}
  A warning is raised (see \ref{pack:options}) if the name is already taken. The branching version doesn't raise any warning.
\end{tsremark}

\subsection{Conditionals}\label{conditionals:exist}
\begin{codedescribe}[code,EXP,new=2023/05/20,update=2024/03/28]{\starray_if_exist_p:n,\starray_if_exist:nTF,\starray_if_valid_p:n,\starray_if_valid:nTF}
\begin{codesyntax}%
\tsmacro{\starray_if_exist_p:n}{starray}
\tsmacro{\starray_if_exist:nTF}{starray,if-true,if-false}
\tsmacro{\starray_if_valid_p:n}{starray}
\tsmacro{\starray_if_valid:nTF}{starray,if-true,if-false}
\end{codesyntax}
\tsobj{\starray_if_exist:nTF} only tests if \tsobj[marg]{starray} (the base property) is defined. It doesn't verifies if it really is a  \tsobj[pkg]{starray}. \tsobj{\starray_if_valid:nTF} is functionally equivalent since release 1.9. See \tsobj{\starray_term_syntax:nTF}, section \ref{conditionals:terms}, for a more reliable validity test.
\end{codedescribe}
\begin{tsremark}
The predicate versions, \tsobj{_p}, expand to either \tsobj{\prg_return_true:} or \tsobj{\prg_return_false:}
\end{tsremark}

\section{Defining and initialising a starray structure}\label{pack:def}

\begin{codedescribe}{\starray_def_prop:nnn,\starray_def_prop:nnnTF}
\begin{codesyntax}%
\tsmacro{\starray_def_prop:nnn}{starray-ref,prop-key,initial-value}
\tsmacro{\starray_def_prop:nnnTF}{starray-ref,prop-key,initial-value,if-true,if-false}
\end{codesyntax}
Adds an entry, \tsobj[marg]{prop-key}, to the \tsobj[marg]{starray-ref} (see \ref{pack:ref}) definition and set its initial value. If \tsobj[marg]{prop-key} is already present its initial value is updated. Both \tsobj[marg]{prop-key} and \tsobj[marg]{initial-value} may contain any \tsobj[marg]{balanced text}. \tsobj[marg]{prop-key} is an (\tsobj[pkg]{expl3}) property list \tsobj[marg]{key} meaning that category codes are ignored.

The definition/assignment of a \tsobj[marg]{prop-key} to a \tsobj[marg]{starray-ref} is global.
\end{codedescribe}

\begin{tsremark}
A warning is raised (see \ref{pack:options}) in case of a \tsobj[marg]{starray-ref} syntax/reference error. The branching version doesn't raise any warning.
\end{tsremark}

\begin{codedescribe}{\starray_def_structure:nn,\starray_def_structure:nnTF}
\begin{codesyntax}%
\tsmacro{\starray_def_struct:nn}{starray-ref,struct-name}
\tsmacro{\starray_def_struct:nnTF}{starray-ref,struct-name,if-true,if-false}
\end{codesyntax}
Adds a sub-structure (a \tsobj[pkg]{starray} in itself) to \tsobj[marg]{starray-ref} (see \ref{pack:ref}). If \tsobj[marg]{struct-name} is already present nothing happens. The definition/assignment of a \tsobj[marg]{struct-name} to a \tsobj[marg]{starray-ref} is global.
\end{codedescribe}


\begin{tsremark}
Do not use a dot when defining a (sub-)structure name, it might seems to work but it will breaks further down (see \ref{pack:ref}).
\end{tsremark}


\begin{tsremark}[Note 2:]
A warning is raised (see \ref{pack:options}) in case of a \tsobj[marg]{starray-ref} syntax error. The branching version doesn't raise any warning.
\end{tsremark}

\begin{codedescribe}{\starray_def_from_keyval:nn,\starray_def_from_keyval:nnTF}
\begin{codesyntax}%
\tsmacro{\starray_def_from_keyval:nn}{starray-ref,keyval-lst}
\tsmacro{\starray_def_from_keyval:nnTF}{starray-ref,keyval-lst,if-true,if-false}
\end{codesyntax}

Adds a set of \tsobj[marg]{keys} / \tsobj[marg]{values} and/or \tsobj[marg]{structures} to \tsobj[marg]{starray-ref} (see \ref{pack:ref}). The \tsobj[marg]{keyval-lst} is pretty straightforward, 
the construction \tsobj[key]{\tsobj[marg]{key} . struct} denotes a nested structure :
\end{codedescribe}

\begin{codestore}[keyval.demo]
\starray_def_from_keyval:nn {root.substructure} 
  {
    keyA = valA ,
    keyB = valB ,
    subZ . struct = 
      {
        keyZA = valZA ,
        keyZB = valZB ,
      }
    subY . struct =
      {
        keyYA = valYA ,
        keyYB = valYB ,
        subYYY . struct =
          {
            keyYYYa = valYYYa ,
            keyYYYb = valYYYb 
          }
      }
  }
\end{codestore}

\tscode*[codeprefix=~]{keyval.demo}

The definitions/assignments  to \tsobj[marg]{starray-ref} are all global.

\begin{tsremark}
The non-branching version raises a warning (see \ref{pack:options}) in case of a \tsobj[marg]{starray-ref} syntax error. The branching version doesn't raise any warning. Also note that, syntax errors on the \tsobj[marg]{keyval-lst} might raise low level (\TeX) errors.
\end{tsremark}

\subsection{Fixing an ill-instantiated starray}\label{pack:def-fix}

When instantiating (see \ref{pack:instantiate}) a \tsobj[pkg]{starray}, the associated structured will be constructed based on it's ''current definition'' (see \ref{pack:def}). A problem that migh arise, when one extends the definition of an already instantiated \tsobj[pkg]{starray}  (better said, if one adds a sub-structure), is a \textsl{quark loop} (from \tsobj[pkg]{l3quark}). To avoid a \textsl{quark loop} it is necessary to ''fix'' the structure of already instantiated terms.

\begin{codedescribe}{\starray_fix_terms:n}
\begin{codesyntax}%
\tsmacro{\starray_fix_terms:n}{starray-ref}
\end{codesyntax}
\end{codedescribe}
The sole purpose of this function is to ''fix'' the already instantiated terms of a \tsobj[pkg]{starray}. Note, this can be an expensive operation depending on the number of terms (it has to craw over all the terms of an instantiated \tsobj[pkg]{starray} adding any missing sub-structure references), but one doesn't need to run it ''right away'' it is possible to add a bunch of sub-structures and than run this just once.


\section{Instantiating starray terms}\label{pack:instantiate}

\begin{codedescribe}{\starray_new_term:n,\starray_new_term:nn,\starray_new_term:nTF,\starray_new_term:nnTF}
\begin{codesyntax}%
\tsmacro{\starray_new_term:n}{starray-ref}
\tsmacro{\starray_new_term:nn}{starray-ref,hash}
\tsmacro{\starray_new_term:nTF}{starray-ref,if-true,if-false}
\tsmacro{\starray_new_term:nnTF}{starray-ref,hash,if-true,if-false}
\end{codesyntax}
\end{codedescribe}
This create a new \textsl{term} (in fact a property list) of the (sub-)struture referenced by \tsobj[marg]{starray-ref}. Note that the newly created \textsl{term} will have all properties (key/values) as defined by the associated \tsmacro{\starray_prop_def:nn}{starray-ref}, with the respective ''initial values''. For instance, given the following 

\begin{codestore}[store-env=keyval.demo2]
\starray_new:n {st-root}

\starray_def_from_keyval:nn {st-root} 
  {
    keyA = valA ,
    keyB = valB ,
    subZ . struct = 
      {
        keyZA = valZA ,
        keyZB = valZB ,
      }
    subY . struct =
      {
        keyYA = valYA ,
        keyYB = valYB ,
        subYYY . struct =
          {
            keyYYYa = valYYYa ,
            keyYYYb = valYYYb 
          }
      }
  }
  
\starray_new_term:n {st-root}
\starray_new_term:n {st-root.subZ}
\starray_new_term:n {st-root.subZ}
\starray_new_term:n {st-root.subY}
\starray_new_term:nn {st-root}{hash-A}
\starray_new_term:n {st-root.subZ}
\end{codestore}

\tscode*[codeprefix=~]{keyval.demo2}

One will have created 6 \textsl{terms}:
\begin{enumerate}[miditemsep]
\item 2 \tsobj[marg]{st-root} \textsl{terms}
  \begin{enumerate}[miditemsep]
  \item the first one with index 1 and
  \begin{enumerate}[miditemsep]
    \item 2 sub-structures \tsobj[marg]{subZ} (indexes 1 and 2)
    \item 1 sub-structure \tsobj[marg]{subY} (index 1)
  \end{enumerate}
  \item the second one with indexes 2 and ''hash-A'' and
  \begin{enumerate}[miditemsep]
    \item 1 sub-structure \tsobj[marg]{subZ} (index 1)
  \end{enumerate}
  \end{enumerate}
\end{enumerate}

Note that, in the above example, it was used the ''implicit'' indexing (aka. iterator, see \ref{pack:ref}). Also note that no \textsl{term} of kind \tsobj[marg]{subYYY} was created.
\begin{tsremark}
A warning is raised (see \ref{pack:options}) in case of a \tsobj[marg]{starray-ref} syntax error. The branching version doesn't raise any warning.
\end{tsremark}

\subsection{referencing terms}\label{pack:ref}

When typing a \tsobj[marg]{starray-ref} there are 3 cases to consider:
\begin{enumerate}[miditemsep]
  \item structure definition
  \item term instantiation
  \item getting/setting a property 
\end{enumerate}

The first case is the simplest one, in which, one (starting by \tsobj[marg]{starray-root} will use a construct like \tsobj[marg]{starray-root}.\tsobj[marg]{sub-struct}.\tsobj[marg]{sub-struct}\ldots 
For example, an equivalent construct to the one shown in \ref{pack:instantiate} :

\begin{codestore}[store-env=demo3]
\starray_new:n {st-root}

\starray_def_struct:nn {st-root}{subZ}

\starray_def_prop:nnn {st-root}{keyA}{valA}
\starray_def_prop:nnn {st-root}{keyB}{valB}

\starray_def_prop:nnn {st-root.subZ}{keyZA}{valZA}
\starray_def_prop:nnn {st-root.subZ}{keyZB}{valZB}

\starray_def_struct:nn {st-root}{subY}
\starray_def_prop:nnn {st-root.subY}{keyYA}{valYA}
\starray_def_prop:nnn {st-root.subY}{keyYB}{valYB}

\starray_def_struct:nn {st-root.subY}{subYYY}
\starray_def_prop:nnn {st-root.subY.subYYY}{keyYYYA}{valYYYA}
\starray_def_prop:nnn {st-root.subY.subYYY}{keyYYYB}{valYYYB}
  
\end{codestore}

\tscode*[codeprefix=~]{demo3}

Note that, all it's needed in order to be able to use \tsobj[marg]{starray-root}.\tsobj[marg]{sub-A} is that \tsobj[marg]{sub-A} is an already declared sub-structure of \tsobj[marg]{starray-root}. The property definitions can be made in any order.

In all other cases, term instantiation, getting/setting a property, one has to address/reference a specific instance/term, implicitly (using iterators) or explicitly using indexes.
The general form, of a \tsobj[marg]{starray-ref}, is: \par
\tsobj[marg]{starray-root}\tsobj[oarg]{idx}.\tsobj[marg]{sub-A}\tsobj[oarg]{idxA}.\tsobj[marg]{sub-B}\tsobj[oarg]{idxB} \par
In the case of term instantiation the last \tsobj[marg]{sub-} cannot be indexed, after all one is creating a new term/index. Moreover, all \tsobj[oarg]{idx} are optional like:\par
\tsobj[marg]{starray-root}.\tsobj[marg]{sub-A}\tsobj[oarg]{idxA}.\tsobj[marg]{sub-B} \par
in which case, one is using the ''iterator'' of \tsobj[marg]{starray-root} and \tsobj[marg]{sub-B} (more later, but keep in mind the \tsobj[marg]{sub-B} iterator is the \tsobj[marg]{sub-B} associated with the \tsobj[marg]{sub-A}\tsobj[oarg]{idxA}).

Since one has to explicitly instantiate all (sub)terms of a starray, one can end with a highly asymmetric structure. Starting at the \tsobj[marg]{starray-root} one has a first counter (representing, indexing the root structure terms), then for all sub-strutures of \tsobj[marg]{starray-root} one will have an additional counter for every term of \tsobj[marg]{starray-root} !

So, for example:
\begin{codestore}[store-env=demo4]
\starray_new:n {st-root}
\starray_def_struct:nn {st-root}{subZ}
\starray_def_struct:nn {st-root}{subY}
\starray_def_struct:nn {st-root.subY}{subYYY}

\starray_new_term:n {st-root}
\starray_new_term:n {st-root.subZ}
\starray_new_term:n {st-root.subZ}
\starray_new_term:n {st-root.subY}
\starray_new_term:n {st-root.subY}
\starray_new_term:n {st-root.subY.subYYY}
\starray_new_term:n {st-root.subY}

\starray_new_term:n {st-root}
\starray_new_term:n {st-root.subZ}
\starray_new_term:n {st-root.subZ}
\starray_new_term:n {st-root.subY}
\end{codestore}

\tscode*[codeprefix=~]{demo4}

One has a single \tsobj[marg]{st-root} iterator (pointing to one of the 3 \tsobj[marg]{st-root} terms), then 3 ''\tsobj[marg]{subZ} iterators'', in fact, one \tsobj[marg]{subZ} iterator for each \tsobj[marg]{st-root} term.
Likewise there are 3 ''\tsobj[marg]{subY} iterators'' and 4 (four) ''\tsobj[marg]{subYYY} iterators'' one for each instance of \tsobj[marg]{subY}.

Every time a new term is created/instantiated, the corresponding iterator will points to it, which allows the notation used in this last example, keep in mind that one could instead, using explicit indexes:

\begin{codestore}[store-env=demo5]
\starray_new:n {st-root}
\starray_def_struct:nn {st-root}{subZ}
\starray_def_struct:nn {st-root}{subY}
\starray_def_struct:nn {st-root.subY}{subYYY}

\starray_new_term:n {st-root}
\starray_new_term:n {st-root[1].subZ}
\starray_new_term:n {st-root[1].subZ}
\starray_new_term:n {st-root[1].subY}
\starray_new_term:n {st-root[1].subY}
\starray_new_term:n {st-root[1].subY[2].subYYY}
\starray_new_term:n {st-root[1].subY}

\starray_new_term:n {st-root}
\starray_new_term:n {st-root[2].subZ}
\starray_new_term:n {st-root[2].subZ}
\starray_new_term:n {st-root[2].subY}
\end{codestore}

\tscode*[codeprefix=~]{demo5}

Finally, observe that, when creating a new term, one has the option to assign a ''hash'' to it, in which case that term can be referred to using an iterator, the explicit index or the hash:

\begin{codestore}[store-env=demo6]
\starray_new:n {st-root}
\starray_def_struct:nn {st-root}{subZ}
\starray_def_struct:nn {st-root}{subY}
\starray_def_struct:nn {st-root.subY}{subYYY}

\starray_new_term:nn {st-root}{hash-A}
\starray_new_term:n {st-root.subZ}
\starray_new_term:n {st-root[1].subZ}
\starray_new_term:n {st-root[hash-A].subZ}
\end{codestore}
\tscode*[codeprefix=~]{demo6}
 
Will create 3 \tsobj[marg]{subZ} terms associated with the first (index = 1) \tsobj[marg]{st-root}.


\subsection{iterators}\label{pack:iter}

\begin{codedescribe}{\starray_set_iter:nn,\starray_set_iter:nnTF,\starray_reset_iter:nn,\starray_reset_iter:nnTF,\starray_next_iter:nn,\starray_next_iter:nnTF}
\begin{codesyntax}%
\tsmacro{\starray_set_iter:nn}{starray-ref,int-val}
\tsmacro{\starray_set_iter:nTF}{starray-ref,int-val,if-true,if-false}
\tsmacro{\starray_reset_iter:nn}{starray-ref}
\tsmacro{\starray_reset_iter:nTF}{starray-ref,if-true,if-false}
\tsmacro{\starray_next_iter:nn}{starray-ref}
\tsmacro{\starray_next_iter:nTF}{starray-ref,if-true,if-false}
\end{codesyntax}
\end{codedescribe}
Those functions allows to \tsmacro{set}{} an iterator to a given \tsobj[marg]{int-val}, \tsmacro{reset}{} it (i.e. assign 1 to the iterator), or increase the iterator by one. An iterator might have a value between 1 and the number of instantiated terms (if the given (sub-)structure was already instantiated). If the (sub-)structure hasn't been instantiated yet, the iterator will always end being set to 0. The branching versions allows to catch those cases, like trying to set a value past its maximum, or a value smaller than one.

\begin{tsremark}[Important:]
Please observe that, when setting/resetting/incrementing the  iterator of a (sub-)structure, all ''descending'' iterators will be also be reset.
\end{tsremark}
\begin{tsremark}
A warning is raised (see \ref{pack:options}) in case of a \tsobj[marg]{starray-ref} syntax error. The branching version doesn't raise any warning.
\end{tsremark}


\begin{codestore}[store-env=demo7]
\starray_new:n {st-root}
\starray_def_struct:nn {st-root}{subZ}
\starray_def_struct:nn {st-root}{subY}
\starray_def_struct:nn {st-root.subY}{subYYY}

\starray_new_term:n {st-root}
\starray_new_term:n {st-root.subZ}
\starray_new_term:n {st-root.subZ}
\starray_new_term:n {st-root.subY}
\starray_new_term:n {st-root.subY.subYYY}
\starray_new_term:n {st-root.subY.subYYY}
\starray_new_term:n {st-root.subY}
\starray_new_term:n {st-root.subY.subYYY}
\starray_new_term:n {st-root.subY.subYYY}
\starray_new_term:n {st-root}
\starray_new_term:n {st-root.subZ}
\starray_new_term:n {st-root.subZ}
\starray_new_term:n {st-root.subY}
\starray_new_term:n {st-root.subY.subYYY}
\starray_new_term:n {st-root.subY.subYYY}
\starray_new_term:n {st-root.subY}
\starray_new_term:n {st-root.subY.subYYY}
\starray_new_term:n {st-root.subY.subYYY}

\starray_set_prop:nnn {st-root.subY.subYYY}{key}{val}
\starray_set_prop:nnn {st-root[2].subY[2].subYYY[2]}{key}{val}

\starray_reset_iter:n {st-root[2].subY}

\starray_set_prop:nnn {st-root.subY.subYYY}{key}{val}
\starray_set_prop:nnn {st-root[2].subY[1].subYYY[1]}{key}{val}
\end{codestore}

\tscode*[codeprefix=~]{demo7}

Before the reset \tsobj[marg]{st-root.subY.subYYY} was equivalent to \tsobj[marg]{st-root[2].subY[2]. subYYY[2]}, given that each iterator was pointing to the ''last term'', since the reset was of the \tsobj[marg]{subY} iterator, only it and the descending ones (in this example just \tsobj[marg]{subYYY}) where reseted, and therefore \tsobj[marg]{st-root.subY.subYYY} was then equivalent to \tsobj[marg]{st-root[2].subY[1].subYYY[1]}



\begin{codedescribe}[code,new=2023/11/04]{\starray_set_iter_from_hash:nn,\starray_set_iter_from_hash:nnTF}
\begin{codesyntax}%
\tsmacro{\starray_set_iter_from_hash:nn}{starray-ref,hash}
\tsmacro{\starray_set_iter_from_hash:nnTF}{starray-ref,hash,if-true,if-false}
\end{codesyntax}
\end{codedescribe}
\tsmacro{\starray_set_iter_from_hash:nn}{starray-ref,hash} will set iter based on the \tsobj[meta]{hash} used when instantiating a term (see \ref{pack:instantiate} ).
\begin{tsremark}
A warning is raised (see \ref{pack:options}) in case of a \tsobj[marg]{starray-ref} syntax error or invalid \tsobj[meta]{hash}. The branching version doesn't raise any warning.
\end{tsremark}


\begin{codedescribe}{\starray_get_iter:n,\starray_get_iter:nN,\starray_get_iter:nNTF}
\begin{codesyntax}%
\tsmacro{\starray_get_iter:n}{starray-ref}
\tsmacro{\starray_get_iter:nN}{starray-ref,int-var}
\tsmacro{\starray_get_iter:nNTF}{starray-ref,int-var,if-true,if-false}
\end{codesyntax}
\end{codedescribe}
\tsmacro{\starray_get_iter:n}{starray-ref} will type in the current value of a given iterator, whilst the other two functions will save it's value in a integer variable (\tsobj[pkg]{expl3}).
\begin{tsremark}
A warning is raised (see \ref{pack:options}) in case of a \tsobj[marg]{starray-ref} syntax error. The branching version doesn't raise any warning.
\end{tsremark}

\begin{codedescribe}[code,EXP,new=2023/05/20]{\starray_parsed_get_iter:}
\begin{codesyntax}%
\tsobj{\starray_parsed_get_iter:}{}
\end{codesyntax}
\tsobj{\starray_parsed_get_iter:} will place in the current iterator's value,  using \tsobj{\int_use:N}, of the last parsed term in the input stream.
\end{codedescribe}
\begin{tsremark}[\color{red}Warning:]
This can be used after any command which 'parses a term', for instance \tsobj{\starray_term_syntax:n}, see section \ref{conditionals:terms}, but it only makes sense (and returns a reliable/meaningful result) IF the last parser operation was successfully executed.
\end{tsremark}

\begin{codedescribe}[code,EXP,new=2023/11/28]{\starray_parsed_get_iter:NN}
\begin{codesyntax}%
\tsmacro{\starray_parsed_get_iter:NN}{parsed-refA,parsed-refB}
\end{codesyntax}
\tsobj{\starray_parsed_get_iter:} will place in the current iterator's value associated with \tsobj[marg]{parsed-refA,parsed-refB},  using \tsobj{\int_use:N}, in the input stream.
\end{codedescribe}
\begin{tsremark}[\color{red}Warning:]
\tsobj[marg]{parsed-refA,parsed-refB} are the values returned by \tsobj{\starray_term_syntax:nNN}.
\end{tsremark}


\begin{codedescribe}{\starray_get_cnt:n,\starray_get_cnt:nN,\starray_get_cnt:nNTF}
\begin{codesyntax}%
\tsmacro{\starray_get_cnt:n}{starray-ref}
\tsmacro{\starray_get_cnt:nN}{starray-ref,integer}
\tsmacro{\starray_get_cnt:nNTF}{starray-ref,integer,if-true,if-false}
\end{codesyntax}
\end{codedescribe}
\tsmacro{\starray_get_cnt:n}{starray-ref} will type in the current number of terms of a given (sub-)structure, whilst the other two functions will save it's value in a integer variable (\tsobj[pkg]{expl3}).
\begin{tsremark}
A warning is raised (see \ref{pack:options}) in case of a \tsobj[marg]{starray-ref} syntax error. The branching version doesn't raise any warning.
\end{tsremark}

\begin{codedescribe}[code,EXP,new=2023/05/20]{\starray_parsed_get_cnt:}
\begin{codesyntax}%
\tsobj{\starray_parsed_get_cnt:}{}
\end{codesyntax}
\tsobj{\starray_parsed_get_cnt:} will place the current number of terms, using \tsobj{\int_use:N}, of the last parsed term, in the input stream.
\end{codedescribe}
\begin{tsremark}[\color{red}Warning:]
This can be used after any command which 'parses a term', for instance \tsobj{\starray_term_syntax:n}, see section \ref{conditionals:terms}, but it only makes sense (and returns a reliable/meaningful result) IF the last parser operation was successfully executed.
\end{tsremark}

\begin{codedescribe}[code,EXP,new=2023/11/28]{\starray_parsed_get_cnt:NN}
\begin{codesyntax}%
\tsmacro{\starray_parsed_get_cnt:NN}{parsed-refA,parsed-refB}
\end{codesyntax}
\tsobj{\starray_parsed_get_cnt:} will place in the current number of terms associated with \tsobj[marg]{parsed-refA,parsed-refB},  using \tsobj{\int_use:N}, in the input stream.
\end{codedescribe}
\begin{tsremark}[\color{red}Warning:]
\tsobj[marg]{parsed-refA,parsed-refB} are the values returned by \tsobj{\starray_term_syntax:nNN}.
\end{tsremark}


\begin{codedescribe}[code,new=2023/11/04]{\starray_iterate_over:nn,\starray_iterate_over:nnTF}
\begin{codesyntax}%
\tsmacro{\starray_iterate_over:nn}{starray-ref,code}
\tsmacro{\starray_iterate_over:nnTF}{starray-ref,code,if-true,if-false}
\end{codesyntax}
\tsobj{\starray_iterate_over:nn} will reset the \tsobj[marg]{starray-ref} iterator, and then execute \tsobj[marg]{code} for each valid value of \tsobj{iter}. At the loop's end, the \tsobj[marg]{starray-ref} iterator will point to the last element of it. The \tsobj[marg]{if-true} is executed, at the loop's end if there is no syntax error, and the referenced structure was properly instantiated. Similarly \tsobj[marg]{if-false} is only execute if a syntax error is detected or the referenced structure wasn't properly instantiated
\end{codedescribe}
\begin{tsremark}
\tsobj{\starray_iterate_over:nn} Creates a local group, so that one can recurse over sub-structures. Be aware, then, that \tsobj[marg]{code} is executed in said local group.
\end{tsremark}
\begin{tsremark}
A warning is raised (see \ref{pack:options}) in case of a \tsobj[marg]{starray-ref} syntax error or the structure wasn't yet instantiated. The branching version doesn't raise any warning.
\end{tsremark}



\section{Changing and recovering starray properties}\label{pack:get/set}

\begin{codedescribe}{\starray_set_prop:nnn,\starray_set_prop:nnV,\starray_set_prop:nnnTF,\starray_set_prop:nnVTF,\starray_gset_prop:nnn,\starray_gset_prop:nnV,\starray_gset_prop:nnnTF,\starray_gset_prop:nnVTF}
\begin{codesyntax}%
\tsmacro{\starray_set_prop:nnn}{starray-ref,prop-key,value}
\tsmacro{\starray_set_prop:nnV}{starray-ref,prop-key,value}
\tsmacro{\starray_set_prop:nnnTF}{starray-ref,prop-key,value,if-true,if-false}
\tsmacro{\starray_set_prop:nnVTF}{starray-ref,prop-key,value,if-true,if-false}
\tsmacro{\starray_gset_prop:nnn}{starray-ref,prop-key,value}
\tsmacro{\starray_gset_prop:nnV}{starray-ref,prop-key,value}
\tsmacro{\starray_gset_prop:nnnTF}{starray-ref,prop-key,value,if-true,if-false}
\tsmacro{\starray_gset_prop:nnVTF}{starray-ref,prop-key,value,if-true,if-false}
\end{codesyntax}
\end{codedescribe}
Those are the functions that allow to (g)set (change) the value of a term's property. If the \tsobj[marg]{prop-key} isn't already present it will be added just for that term \tsobj[marg]{starray-ref}. The \tsobj[parg]{nnV} variants allow to save any variable like a token list, property list, etc...
\begin{tsremark}
A warning is raised (see \ref{pack:options}) in case of a \tsobj[marg]{starray-ref} syntax error. The branching version doesn't raise any warning.
\end{tsremark}

\begin{codedescribe}{\starray_set_from_keyval:nn,\starray_set_from_keyval:nnTF,\starray_gset_from_keyval:nn,\starray_gset_from_keyval:nnTF}
\begin{codesyntax}%
\tsmacro{\starray_set_from_keyval:nnn}{starray-ref,keyval-lst}
\tsmacro{\starray_set_from_keyval:nnnTF}{starray-ref,keyval-lst,if-true,if-false}
\tsmacro{\starray_gset_from_keyval:nnn}{starray-ref,keyval-lst}
\tsmacro{\starray_gset_from_keyval:nnnTF}{starray-ref,keyval-lst,if-true,if-false}
\end{codesyntax}
\end{codedescribe}

it is possible to set a collection of properties using a key/val syntax, similar to the one used to define a \tsobj[pkg]{starray} from keyvals (see \ref{pack:def}), with a few distinctions:
\begin{enumerate}
  \item when referring a (sub-)structure one can either explicitly use an index, or
  \item  implicitly use it's iterator 
  \item if a given key isn't already presented it will be added only to the given term
\end{enumerate}

 Note that, in the following example, TWO iterators are being used, the one for \tsobj[marg]{st-root} and then \tsobj[marg]{subY}.

\begin{codestore}[store-env=keyval.demo8]
\starray_set_from_keyval:nn {st-root} 
  {
    keyA = valA ,
    keyB = valB ,
    subZ[2] = 
      {
        keyZA = valZA ,
        keyZB = valZB ,
      }
    subY  =
      {
        keyYA = valYA ,
        keyYB = valYB ,
        subYYY[1] =
          {
            keyYYYa = valYYYa ,
            keyYYYb = valYYYb 
          }
      }
  }  
\end{codestore}

\tscode*[codeprefix=~]{keyval.demo8}

Also note that the above example is fully equivalent to:

\begin{codestore}[store-env=keyval.demo9]
\starray_set_prop:nnn {st-root} {keyA} {valA}
\starray_set_prop:nnn {st-root} {keyB} {valB}
\starray_set_prop:nnn {st-root.subZ[2]} {keyZA} {valZA}
\starray_set_prop:nnn {st-root.subZ[2]} {keyZB} {valZB}
\starray_set_prop:nnn {st-root.subY} {keyYA} {valYA}
\starray_set_prop:nnn {st-root.subY} {keyYB} {valYB}
\starray_set_prop:nnn {st-root.subY.subYYY[1} {keyYYYa} {valYYYa}
\starray_set_prop:nnn {st-root.subY.subYYY[1} {keyYYYb} {valYYYb}
\end{codestore}

\tscode*[codeprefix=~]{keyval.demo9}

\begin{codedescribe}{\starray_get_prop:nn,\starray_get_prop:nnN,\starray_get_prop:nnNTF}
\begin{codesyntax}%
\tsmacro{\starray_get_prop:nn}{starray-ref,key}
\tsmacro{\starray_get_prop:nnN}{starray-ref,key,tl-var}
\tsmacro{\starray_get_prop:nnNTF}{starray-ref,key,tl-var,if-true,if-false}
\end{codesyntax}
\tsmacro{\starray_get_prop:nn}{starray-ref,key} places the value of \tsobj[marg]{key} in the input stream.
\tsmacro{\starray_get_prop:nnN}{starray-ref,key,tl-var} recovers the value of \tsobj[marg]{key} and places it in \tsobj[marg]{tl-var} (a token list variable), this is specially useful in conjunction with \tsobj{\starray_set_prop:nnV}, whilst the \tsobj{\starray_get_prop:nnNTF} version branches accordly.
\end{codedescribe}
\begin{tsremark}
In case of a syntax error, or \tsobj[marg]{key} doesn't exist, an empty value is left in the stream (or \tsobj[marg]{tl-var}).
\end{tsremark}
\begin{tsremark}
A warning is raised (see \ref{pack:options}) in case of a \tsobj[marg]{starray-ref} syntax error. The branching version doesn't raise any warning.
\end{tsremark}


\begin{codedescribe}[code,EXP,new=2023/05/20]{\starray_parsed_get_prop:n}
\begin{codesyntax}%
\tsmacro{\starray_parsed_get_prop:n}{key}
\end{codesyntax}
\tsmacro{\starray_parsed_get_prop:n}{key} places the value of \tsobj[marg]{key}, if it exists, from the last parsed term, in the input stream. 
\end{codedescribe}
\begin{tsremark}[\color{red}Warning:]
This can be used after any command which 'parses a term', for instance \tsobj{\starray_term_syntax:n}, see section \ref{conditionals:terms}, but it only makes sense (and returns a reliable/meaningful result) IF the last parser operation was successfully executed.
\end{tsremark}


\begin{codedescribe}[code,EXP,new=2023/11/28]{\starray_parsed_get_prop:NNn}
\begin{codesyntax}%
\tsmacro{\starray_parsed_get_prop:NNn}{parsed-refA,parsed-refB,key}
\end{codesyntax}
\tsobj{\starray_parsed_get_prop:NNn} places the value of \tsobj[marg]{key}, if it exists, associated with \tsobj[marg]{parsed-refA,parsed-refB}.
\end{codedescribe}
\begin{tsremark}[\color{red}Warning:]
\tsobj[marg]{parsed-refA,parsed-refB} should be the values returned by \tsobj{\starray_term_syntax:nNN}.
\end{tsremark}


\section{Additional Commands and Conditionals}\label{conditionals:terms}

\begin{codedescribe}{\starray_if_in:nnTF}
\begin{codesyntax}%
\tsmacro{\starray_if_in:nnTF}{starray-ref,key,if-true,if-false}
\end{codesyntax}
The \tsmacro{\starray_if_in:nnTF}{starray-ref,key,\ldots,\ldots} tests if a given \tsobj[marg]{key} is present.
\end{codedescribe}

\begin{codedescribe}[code,new=2023/05/20]{\starray_term_syntax:n,\starray_term_syntax:nTF}
\begin{codesyntax}%
\tsmacro{\starray_term_syntax:n}{starray-ref}
\tsmacro{\starray_term_syntax:nTF}{starray-ref,if-true,if-false}
\end{codesyntax}
This will just parse  a \tsobj[marg]{starray-ref} reference, and set interval variables so that commands like \tsobj{\starray_parsed_} can be used.
\end{codedescribe}
\begin{tsremark}[\color{red}Warning:]
The main idea is to allow some expandable commands, but be aware that all \tsobj{\starray_} commands that use a \tsobj[marg]{starray-ref} use the very same parser variables. In case one needs are more permanent/resilient \tsobj[pkg]{starray} reference, one should use the \tsobj{\starray_term_syntax:nNN} variant.
\end{tsremark}
\begin{tsremark}
A warning is raised (see \ref{pack:options}) in case of a \tsobj[marg]{starray-ref} syntax error. The branching version doesn't raise any warning.
\end{tsremark}

\begin{codedescribe}[code,new=2023/11/28]{\starray_term_syntax:nNN,\starray_term_syntax:nNNTF}
\begin{codesyntax}%
\tsmacro{\starray_term_syntax:nNN}{starray-ref,parsed-refA,parsed-refB}
\tsmacro{\starray_term_syntax:nNNTF}{starray-ref,parsed-refA,parsed-refB,if-true,if-false}
\end{codesyntax}
Similar to the ones above (\tsobj{\starray_term_syntax:n}). \tsobj[marg]{parsed-refA,parsed-refB} (assumed to be two token list vars, \tsobj[meta]{tl-var}) will receive two 'internal references' that can be used in commands like \tsobj{\starray_parsed_...:NN} which expects such 'references', without having to worry about using another \tsobj{\starray_} command.
\end{codedescribe}
\begin{tsremark}
Once correctly parsed, \tsobj[marg]{parsed-refA,parsed-refB} can be used at 'any time' (by those few \tsobj{\starray_parsed_...:NN} associated commands).\end{tsremark}
\begin{tsremark}
A warning is raised (see \ref{pack:options}) in case of a \tsobj[marg]{starray-ref} syntax error (in which case \tsobj[marg]{parsed-refA,parsed-refB} will not hold a valid value). The branching version doesn't raise any warning.
\end{tsremark}


\begin{codedescribe}[code,EXP,new=2023/05/20]{\starray_parsed_if_in_p:n,\starray_parsed_if_in:nTF}
\begin{codesyntax}%
\tsmacro{\starray_parsed_if_in_p:nTF}{key}
\tsmacro{\starray_parsed_if_in:nTF}{key,if-true,if-false}
\end{codesyntax}
This will test if the given \tsobj[key]{key} is present in the "last parsed term". 
\end{codedescribe}
\begin{tsremark}
The predicate version, \tsobj{_p}, expands to either \tsobj{\prg_return_true:} or \tsobj{\prg_return_false:}.
\end{tsremark}
\begin{tsremark}[\color{red}Warning:]
This can be used after any command which 'parses a term', for instance \tsobj{\starray_term_syntax:n}, but it only makes sense (and returns a reliable/meaningful result) IF the last parser operation was successfully executed.
\end{tsremark}


\begin{codedescribe}[code,EXP,new=2023/11/28]{\starray_parsed_if_in_p:NNn,\starray_parsed_if_in:NNnTF}
\begin{codesyntax}%
\tsmacro{\starray_parsed_if_in_p:nTF}{parsed-refA,parsed-refB,key}
\tsmacro{\starray_parsed_if_in:nTF}{parsed-refA,parsed-refB,key,if-true,if-false}
\end{codesyntax}
This will test if the given \tsobj[key]{key} is present/associated with \tsobj[marg]{parsed-refA,parsed-refB}.
\end{codedescribe}
\begin{tsremark}
The predicate version, \tsobj{_p}, expands to either \tsobj{\prg_return_true:} or \tsobj{\prg_return_false:}.
\end{tsremark}
\begin{tsremark}[\color{red}Warning:]
\tsobj[marg]{parsed-refA,parsed-refB} should be the values returned by \tsobj{\starray_term_syntax:nNN}.
\end{tsremark}

\begin{codedescribe}[code,new=2024/03/10]{\starray_get_unique_id:nN,\starray_get_unique_id:nNTF}
\begin{codesyntax}%
\tsmacro{\starray_get_unique_id:nN}{starray-ref,tl-var}
\tsmacro{\starray_get_unique_id:nNTF}{starray-ref,tl-var}
\end{codesyntax}
\end{codedescribe}
Gets an 'unique ID' for a given \tsobj[marg]{starray-ref} \emph{term}, it should help defining/creating uniquely identified auxiliary structures, like auxiliary property or sequence lists, since one can't (better said shouldn't, as per l3kernel) store an anonymous property/sequence list using V-expansion. 
\begin{tsremark}
A warning is raised (see \ref{pack:options}) in case of a \tsobj[marg]{starray-ref} syntax error. The branching version doesn't raise any warning.
\end{tsremark}



\section{Showing (debugging) starrays }\label{pack:show}

\begin{codedescribe}{\starray_show_def:n,\starray_show_def_in_text:n}
\begin{codesyntax}%
\tsmacro{\starray_show_def:n}{starray-ref}
\tsmacro{\starray_show_def_in_text:n}{starray-ref}
\end{codesyntax}
\end{codedescribe}
Displays the \tsobj[marg]{starray} structure definition and initial property values in the terminal or directly in text.


\begin{codedescribe}{\starray_show_terms:n,\starray_show_terms_in_text:n}
\begin{codesyntax}%
\tsmacro{\starray_show_terms:n}{starray-ref}
\tsmacro{\starray_show_terms_in_text:n}{starray-ref}
\end{codesyntax}
\end{codedescribe}
Displays the \tsobj[marg]{starray} instantiated terms and current  property values in the terminal or directly in text.



\end{document}
