%%%============================================================================== %% 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.9} {2024/03/28} %% %% The list of files that compose this work can be found in the README.md file at %% https://ctan.org/pkg/starray %% %%%============================================================================== \NeedsTeXFormat{LaTeX2e}[2023/11/01] \ProvidesExplPackage {starray} {2024/03/28} {1.9} {A structured array/hash of properties} %%%%%%% %%% %%% Just an attempt of having my packages info in a regular way %%% Idea being: { / pkg info } for each and all. %%% %%%%%%% \keys_define:nn { starray / pkg info} { name .code:n = {starray} , prefix .code:n = {starray} , date .code:n = {2024/03/28}, version .code:n = {1.9} , description .code:n = {A~structured~array/hash~of~properties} } \cs_if_exist:NF \PkgInfo { \NewDocumentCommand \PkgInfo {mm} { \keys_set:nn {#1 / pkg info}{#2} } \NewDocumentCommand \PkgDescription {m} { \noindent Package~ \textbf{\PkgInfo{#1}{name}}~Version:~\PkgInfo{#1}{version}~ -~ \PkgInfo{#1}{date}\par \emph{\PkgInfo{#1}{description}}~\par } } %%%%%%% %%% 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 \int_gset:Nn {Ne} \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 , cec , ceN , cnN } { 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 / Expl} { Expl~ version~ too~ old.~ Update~ needed! } { Expl~ version~ too~ old.~ Update~ 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. } \IfExplAtLeastTF{2024-03-14}{}{\msg_warning:nn {starray} {strict / Expl} } \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_inline:Nn \l__starray_msg_seq { ##1 } \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} \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_tmp_A_tl \tl_new:N \l__starray_tmp_B_tl \tl_new:N \l__starray_tmp_C_tl \tl_new:N \l__starray_tmp_D_tl \tl_new:N \l__starray_showcmd_tl %%%% %%%% (sub)structure returning tl. %%%% \tl_new:N \l__starray_tmp_ST_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 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_eq_conditional:NNn \__starray_if_exist:n \cs_if_exist:c {p, T, F, TF} \prg_generate_conditional_variant:Nnn \__starray_if_exist:n {e} {p, T, F, TF} \prg_new_conditional:Npnn \starray_if_exist:n #1 {p, T, F, TF} { \__starray_if_exist:nTF {\l__starray_prefix_tl #1 _base_defref_tl} { \prg_return_true: } { \prg_return_false: } } % DEPRECATED, unless some other (simple) test become available %\prg_new_conditional:Npnn \__starray_if_valid:n #1 {p, T, F, TF} % { % \bool_lazy_and:nnTF {\prop_if_exist_p:c {#1}} {\prop_item:cn {#1} {is_starray}} % { \prg_return_true: } % { \prg_return_false: } % } \prg_new_eq_conditional:NNn \__starray_if_valid:n \cs_if_exist:c {p, T, F, TF} \prg_generate_conditional_variant:Nnn \__starray_if_valid:n {e} {p, T, F, TF} \prg_new_conditional:Npnn \starray_if_valid:n #1 {p, T, F, TF} { \__starray_if_valid:nTF {\l__starray_prefix_tl #1 _defref_tl} { \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 _base_cnt_int } \int_new:c { \l__starray_prefix_tl #2 _base_iter_int } \tl_new:c { \l__starray_prefix_tl #2 _base_defref_tl } \tl_set:cn { \l__starray_prefix_tl #2 _base_defref_tl } {#1} \prop_new_linked:c {\l__starray_prefix_tl #2 _base_idxhash_prop} \prop_new_linked:c {\l__starray_prefix_tl #2 _base_iterhash_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 { \tl_new:c { \l__starray_prefix_tl #1 _defref_tl } \tl_set:cn { \l__starray_prefix_tl #1 _defref_tl } {#1} \seq_new:c { \l__starray_prefix_tl #1 _defstkeys_seq } \prop_new_linked:c {\l__starray_prefix_tl #1 _defkeys_prop} } \cs_generate_variant:Nn \__starray_new:n { e } %%%%%%%%%%%%%%% %%%% %%%% \starray_new %%%% %%%%%%%%%%%%%%% % needs protection. \cs_new_protected:Npn \starray_new:n #1 { \__starray_if_exist:nTF {\l__starray_prefix_tl #1 _defref_tl} { \msg_warning:nnnn {starray} {strict / (re)define} {new:1} {#1} } { \__starray_new:e {#1 } \__starray_base_new:ee {#1}{#1} % TODO: might be incomplete !!! } } % needs protection. \prg_new_protected_conditional:Npnn \starray_new:n #1 {T, F, TF} { \__starray_if_exist:nTF {\l__starray_prefix_tl #1 _defref_tl} { \prg_return_false: } { \__starray_new:e {#1 } \__starray_base_new:ee {#1}{#1} % TODO: might be incomplete !!! \prg_return_true: } } %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% %%%% %%%% starray ref parser %%%% %%%% %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% %%%% %%%% get root reference (first term) assuming called as %%%% . \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_tmp_A_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_gput:cnn {\l__starray_prefix_tl #1 _defkeys_prop} {#2} {#3} } %%%%%%%%%%%%%%% %%%% %%%% \starray_def_prop %%%% %%%%%%%%%%%%%%% % needs protection, because of _p \cs_new_protected:Npn \starray_def_prop:nnn #1#2#3 { \__starray_if_exist:nTF {\l__starray_prefix_tl #1 _defref_tl} { \__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_exist:nTF {\l__starray_prefix_tl #1 _defref_tl} { \__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 { \seq_if_in:cnF {\l__starray_prefix_tl #1 _defstkeys_seq} {#2} { \seq_gput_right:cn {\l__starray_prefix_tl #1 _defstkeys_seq} {#2} \__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 addition' (after being instantiated?) \cs_new_protected:Npn \__starray_fix_terms_seq_aux:nnnn #1#2#3#4 { \__starray_if_exist:eTF {\l__starray_prefix_tl #2 _ #3 . #4 _base_defref_tl} { \__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 { \tl_set_eq:Nc \l_tmpa_tl {\l__starray_prefix_tl #2 _base_defref_tl} \seq_map_inline:cn {\tl_use:N \l__starray_prefix_tl \tl_use:N \l_tmpa_tl _defstkeys_seq} {\__starray_fix_terms_seq_aux:nnnn {#1}{#2}{#4}{##1} } } \cs_new_protected:Npn \__starray_fix_terms:nn #1#2 { \group_begin: \prop_if_empty:cF {\tl_use:N \l__starray_prefix_tl #2 _base_idxhash_prop} { \prop_map_inline:cn {\tl_use:N \l__starray_prefix_tl #2 _base_idxhash_prop} {\__starray_fix_terms_seq:nnnn {#1}{#2}{##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_exist:nTF { \l__starray_prefix_tl \l_tmpb_tl _defref_tl} { \__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_exist:nTF { \l__starray_prefix_tl #1 _defref_tl} { \__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_exist:nTF { \l__starray_prefix_tl #1 _defref_tl} { \__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_tmp_ST_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:Ne \l__starray_tmpA_tl {#1 . \l__starray_tmp_ST_tl} \__starray_def_struct:ne {#1} {\l__starray_tmp_ST_tl} \keyval_parse:nnn {\__starray_def_from_keyval_parse:en {\tl_use:N \l__starray_tmpA_tl}} {\__starray_def_from_keyval_parse:enn {\tl_use:N \l__starray_tmpA_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_exist:nTF { \l__starray_prefix_tl #1 _defref_tl} { \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_exist:nTF { \l__starray_prefix_tl #1 _defref_tl} { \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:c {\l__starray_prefix_tl #1 _base_cnt_int} \int_gset_eq:cc {\l__starray_prefix_tl #1 _base_iter_int} {\l__starray_prefix_tl #1 _base_cnt_int} \tl_set:Ne \l__starray_tmp_A_tl { \int_to_Alph:e {\int_use:c {\l__starray_prefix_tl #1 _base_cnt_int} } } \prop_put:cee {\l__starray_prefix_tl #1 _base_idxhash_prop} { \int_use:c {\l__starray_prefix_tl #1 _base_cnt_int} } { \l__starray_tmp_A_tl } \prop_put:cee {\l__starray_prefix_tl #1 _base_iterhash_prop} { \int_use:c {\l__starray_prefix_tl #1 _base_cnt_int} } { \int_use:c {\l__starray_prefix_tl #1 _base_cnt_int} } \tl_if_blank:nF {#2} { \prop_put:cee {\l__starray_prefix_tl #1 _base_idxhash_prop} { #2 } { \l__starray_tmp_A_tl } \prop_put:cee {\l__starray_prefix_tl #1 _base_iterhash_prop} { #2 } { \int_use:c {\l__starray_prefix_tl #1 _base_cnt_int} } } \prop_new_linked:c { \l__starray_prefix_tl #1 _ \l__starray_tmp_A_tl _term_prop } \tl_set_eq:Nc \l_tmpb_tl {\l__starray_prefix_tl #1 _base_defref_tl} \prop_gset_eq:cc { \l__starray_prefix_tl #1 _ \l__starray_tmp_A_tl _term_prop } {\l__starray_prefix_tl \l_tmpb_tl _defkeys_prop} %\prop_make_linked:c { \l__starray_prefix_tl #1 _ \l__starray_tmp_A_tl _term_prop } % map over 'all sub-starrays parts of def_ref -> st_seq (those starting with a dot, @st_seq) \seq_map_inline:cn {\l__starray_prefix_tl \l_tmpb_tl _defstkeys_seq} { \__starray_sub_base_new:nnn { \l_tmpb_tl }{ #1 _ \l__starray_tmp_A_tl } {##1} } } %%%%%%%%%%%%%%% %%%% %%%% \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 {\use:c {\l__starray_prefix_tl #1 _base_iter_int}} < {\use:c {\l__starray_prefix_tl #1 _base_cnt_int}} { \int_gincr:c {\l__starray_prefix_tl #1 _base_iter_int} } { % 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} > { \use:c {\l__starray_prefix_tl #2 _base_cnt_int} } { \int_gset_eq:cc {\l__starray_prefix_tl #2 _base_iter_int} {\l__starray_prefix_tl #2 _base_cnt_int} \prg_return_false: } { \int_gset:cn {\l__starray_prefix_tl #2 _base_iter_int} { #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:cecT {\l__starray_prefix_tl #2#3 _base_idxhash_prop} { \int_use:c {\l__starray_prefix_tl #2#3 _base_iter_int } } { l__starray_tmp #1 A_tl } { \tl_set_eq:Nc \l__starray_tmp_C_tl {\l__starray_prefix_tl #2#3 _base_defref_tl} \seq_if_empty:cF {\l__starray_prefix_tl \l__starray_tmp_C_tl _defstkeys_seq} { \seq_map_inline:cn {\l__starray_prefix_tl \l__starray_tmp_C_tl _defstkeys_seq} { \__starray_set_iter:neTF { 1 } { #2#3 _ \tl_use:c {l__starray_tmp #1 A_tl} . ##1 } {} {} \__starray_set_sub_iter:nne { #1 A } { #2#3 _ \tl_use:c {l__starray_tmp #1 A_tl} . } { ##1 } } } } } \cs_generate_variant:Nn \__starray_set_sub_iter:nnn {nne} %%%%%%%%%%%%%%% %%%% %%%% \starray_set_iter %%%% %%%%%%%%%%%%%%% \prg_new_protected_conditional:Npnn \__starray_set_iter_from_hash:nn #1#2 {T , F, TF} { \prop_get:cnNTF {\l__starray_prefix_tl #1 _base_iterhash_prop} {#2} \l_tmpa_tl { \int_gset:cn { \l__starray_prefix_tl #1 _base_iter_int } { \l_tmpa_tl } \prg_return_true: } { \prg_return_false: } } \cs_new_protected:Npn \starray_set_iter_from_hash:nn #1#2 { \__starray_parser:nnTF {\c__starray_no_idx_ending_bool}{#1} { \__starray_set_iter_from_hash:nnTF {\l__starray_parsed_ref_tl}{#2} { \__starray_set_sub_iter:nnn {}{\l__starray_parsed_ref_tl}{} } { \msg_warning:nnnn {starray} {reference / iter} {iterhash:1} {#1}{#2} } } { \__starray_msg_dispatch: \msg_warning:nnnn {starray} {syntax / iter} {iter:1} {#1} } % returns nothing by default } \prg_new_protected_conditional:Npnn \starray_set_iter_from_hash:nn #1#2 {T, F, TF} { \bool_set_true:N \l__starray_rtn_bool \__starray_parser:nnTF {\c__starray_no_idx_ending_bool}{#1} { \__starray_set_iter_from_hash:nnTF {\l__starray_parsed_ref_tl}{#2} { \__starray_set_sub_iter:nnn {}{\l__starray_parsed_ref_tl}{} \prg_return_true: } { \bool_set_false:N \l__starray_rtn_bool \prg_return_false: } } { \bool_set_false:N \l__starray_rtn_bool \seq_clear:N \l__starray_msg_seq \prg_return_false: } % returns nothing by default } \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: } } %%%%%%%%%%%%%%% %%%% %%%% \starray_iterate_over %%%% %%%%%%%%%%%%%%% \bool_new:N \l__starray_iterate_bool \cs_new_protected:Npn \starray_iterate_over:nn #1#2 { \bool_if_exist:cF {l__starray_iterate_ #1 _bool} { \bool_new:c {l__starray_iterate_ #1 _bool} } \starray_reset_iter:nTF {#1} { \bool_gset_true:c {l__starray_iterate_ #1 _bool} \bool_do_while:cn {l__starray_iterate_ #1 _bool} { #2 \starray_next_iter:nTF {#1} { \bool_gset_true:c {l__starray_iterate_ #1 _bool} } { \bool_gset_false:c {l__starray_iterate_ #1 _bool} } } } { \bool_set_false:N \l__starray_rtn_bool \msg_warning:nnnn {starray} {syntax / iter} {iter:6} {#1} } } \prg_new_protected_conditional:Npnn \starray_iterate_over:nn #1#2 {T, F, TF} { \bool_if_exist:cF {l__starray_iterate_#1_bool} {\bool_new:c {l__starray_iterate_#1_bool}} \starray_reset_iter:nTF {#1} { \bool_gset_true:c {l__starray_iterate_#1_bool} \bool_do_while:cn {l__starray_iterate_#1_bool} { #2 \starray_next_iter:nF {#1} %{\bool_gset_true:c {l__starray_iterate_#1_bool}} {\bool_gset_false:c {l__starray_iterate_#1_bool}} } \prg_return_true: } { \seq_clear:N \l__starray_msg_seq \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 uses the 'last parsed term'. %%% %%%%%%%%%%%%%%%% \cs_new:Npn \starray_parsed_get_prop:n #1 { \__starray_get_prop:ee {\l__starray_parsed_ref_tl}{#1} } %%%%%%%%%%%%%%%% %%% %%% WARNING: #1 should be \l__starray_parsed_ref_tl %%% #2 should be \l__starray_parsed_ref_no_idx_ending_tl %%% %%%%%%%%%%%%%%%% \cs_new:Npn \starray_parsed_get_prop:NNn #1#2#3 { \__starray_get_prop:ee {#1}{#3} } \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:2} {#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 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: } } %%%%%%%%%%%%%%%% %%% %%% WARNING: #1 should be \l__starray_parsed_ref_tl %%% #2 should be \l__starray_parsed_ref_no_idx_ending_tl %%% %%%%%%%%%%%%%%%% \prg_new_conditional:Npnn \starray_parsed_if_in:NNn #1#2#3 {p, T, F, TF} { \prop_if_in:cnTF { \l__starray_prefix_tl #1 _term_prop } {#3} { \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:c { \l__starray_prefix_tl \l__starray_parsed_ref_tl _base_cnt_int } } { \__starray_msg_dispatch: \msg_warning:nnnn {starray} {syntax / prop} {get:3} {#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:c { \l__starray_prefix_tl \l__starray_parsed_ref_no_idx_ending_tl _base_cnt_int } } %%%%%%%%%%%%%%%% %%% %%% WARNING: #1 should be \l__starray_parsed_ref_tl %%% #2 should be \l__starray_parsed_ref_no_idx_ending_tl %%% %%%%%%%%%%%%%%%% \cs_new:Npn \starray_parsed_get_cnt:NN #1#2 { \int_use:c { \l__starray_prefix_tl #2 _base_cnt_int } } \cs_new_protected:Npn \starray_get_cnt:nN #1#2 { \__starray_parser:nnTF {\c__starray_no_idx_ending_bool}{#1} { \int_set_eq:Nc #2 { \l__starray_prefix_tl \l__starray_parsed_ref_tl _base_cnt_int } } { \__starray_msg_dispatch: \msg_warning:nnnn {starray} {syntax / prop} {get:4} {#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:Nc #2 { \l__starray_prefix_tl \l__starray_parsed_ref_tl _base_cnt_int } \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:c { \l__starray_prefix_tl \l__starray_parsed_ref_tl _base_iter_int } } { \__starray_msg_dispatch: \msg_warning:nnnn {starray} {syntax / prop} {get:5} {#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:c { \l__starray_prefix_tl \l__starray_parsed_ref_no_idx_ending_tl _base_iter_int } } %%%%%%%%%%%%%%%% %%% %%% WARNING: #1 should be \l__starray_parsed_ref_tl %%% #2 should be \l__starray_parsed_ref_no_idx_ending_tl %%% %%%%%%%%%%%%%%%% \cs_new:Npn \starray_parsed_get_iter:NN #1#2 { \int_use:c { \l__starray_prefix_tl #2 _base_iter_int } } \cs_new_protected:Npn \starray_get_iter:nN #1#2 { \__starray_parser:nnTF {\c__starray_no_idx_ending_bool}{#1} { \int_set_eq:Nc #2 { \l__starray_prefix_tl \l__starray_parsed_ref_tl _base_iter_int } } { \__starray_msg_dispatch: \msg_warning:nnnn {starray} {syntax / prop} {get:6} {#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:Nc #2 { \l__starray_prefix_tl \l__starray_parsed_ref_tl _base_iter_int } \prg_return_true: } { \seq_clear:N \l__starray_msg_seq \prg_return_false: } % returns nothing by default } \cs_new_protected:Npn \starray_get_unique_id:nN #1#2 { \__starray_parser:nnTF {\c__starray_no_idx_ending_bool}{#1} { \int_set_eq:Ne #2 { \l__starray_parsed_ref_tl } } { \__starray_msg_dispatch: \msg_warning:nnnn {starray} {syntax / prop} {get:7} {#1} } % returns nothing by default } \prg_new_protected_conditional:Npnn \starray_get_unique_id:nN #1#2 {T, F, TF} { \__starray_parser:nnTF {\c__starray_idx_ending_bool}{#1} { \tl_set:Ne #2 { \l__starray_parsed_ref_tl } \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_new: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' % \seq_if_in:cnTF {\tl_use:N \l__starray_prefix_tl \tl_use:c {\l__starray_prefix_tl #2 _base_defref_tl} _defstkeys_seq} {#4} { \int_compare:nNnTF {\int_use:c { \tl_use:N \l__starray_prefix_tl #3 .#4 _base_iter_int }} < {1} { \__starray_msg:nnnnn {reference / iter} {setkeyval:2}{#2.#4}{-0-}{~(not~instantiated)} % invalid iter / not instantiated } { %%%% WARNING: is't sure it does exist? will result in a quark loop if not! \prop_get:cec { \tl_use:N \l__starray_prefix_tl #3 .#4 _base_idxhash_prop } {\int_use:c { \tl_use:N \l__starray_prefix_tl #3 .#4 _base_iter_int }} { l__starray_tmp #1 _tl } \keyval_parse:nnn { \__starray_set_from_keyval_parse:neen { #1 A } { #3.#4 } { #3.#4 _ \tl_use:c { l__starray_tmp #1 _tl } } } { \__starray_set_from_keyval_parse:neenn { #1 A } { #3.#4 } { #3.#4 _ \tl_use:c { l__starray_tmp #1 _tl } } } { #5 } } } { \__starray_set_prop:nnn {#3}{#4}{#5} } } { \seq_if_in:ceTF {\tl_use:N \l__starray_prefix_tl \tl_use:c {\l__starray_prefix_tl #2 _base_defref_tl} _defstkeys_seq} { \tl_use:c{l__starray_tmp #1 :B_tl} } { \prop_get:ceNTF { \l__starray_prefix_tl #3. \tl_use:c{l__starray_tmp #1 :B_tl} _base_idxhash_prop } { \tl_use:c{l__starray_tmp #1 :A_tl}} \l__starray_tmp_D_tl { %% here should be all the remaining code. 'everything fine so far'. \tl_set:ce { l__starray_tmp #1 _idx_tl } { #3 . \tl_use:c{l__starray_tmp #1 :B_tl} _ \tl_use:N \l__starray_tmp_D_tl } \tl_put_left:cn { l__starray_tmp #1 :B_tl } { #3 . } \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 } } { %% if we got here, it doesn't exist. wrong idx, \__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 %%%% %%%% := [ . ] %%%% := [ ] %%%% := \[ \] %%%% %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% %%% %%% \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} { \tl_if_blank:nTF {#2} { \prop_get:ceNF {\l__starray_prefix_tl \l__starray_parsed_ref_tl _base_idxhash_prop} {#1} \l_tmpa_tl { \tl_set:Nn \l_tmpa_tl {} } } { \prop_get:ceNF {\l__starray_prefix_tl \l__starray_parsed_ref_tl _base_idxhash_prop} {#2} \l_tmpa_tl { \tl_set:Nn \l_tmpa_tl {} } } \tl_put_right:Ne \l__starray_parsed_ref_tl { _ \l_tmpa_tl } \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_exist:eTF {\l__starray_prefix_tl \l__starray_parsed_ref_tl _base_defref_tl} { \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:c { \l__starray_prefix_tl \l__starray_parsed_ref_tl _base_iter_int } } { \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:c { \l__starray_prefix_tl \l__starray_parsed_ref_tl _base_iter_int } } { \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: } } \prg_new_protected_conditional:Npnn \starray_term_syntax:nNN #1#2#3 {T, F, TF} { \__starray_parser:nnTF {\c__starray_idx_ending_bool}{#1} { \tl_gset:Ne #2 {\l__starray_parsed_ref_tl} \tl_gset:Ne #3 {\l__starray_parsed_ref_no_idx_ending_tl} \prg_return_true: } { \seq_clear:N \l__starray_msg_seq \prg_return_false: } } \cs_new_protected:Npn \starray_term_syntax:n #1 { \__starray_parser:nnTF {\c__starray_idx_ending_bool}{#1} {} { \__starray_msg_dispatch: \msg_warning:nnnn {starray} {syntax / prop} {setkeyval:1} {#1} } } \cs_new_protected:Npn \starray_term_syntax:nNN #1#2#3 { \__starray_parser:nnTF {\c__starray_idx_ending_bool}{#1} { \tl_gset:Ne #2 {\l__starray_parsed_ref_tl} \tl_gset:Ne #3 {\l__starray_parsed_ref_no_idx_ending_tl} } { \__starray_msg_dispatch: \msg_warning:nnnn {starray} {syntax / prop} {setkeyval:1} {#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_tmp_B_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_tmp_B_tl { \l__starray_showcmd_tl > #1 \tl_to_str:n {{#3} ~ struct} \use:nn { ~ } { ~ } => } \prop_map_inline:cn {\l__starray_prefix_tl #2#3 _defkeys_prop} {\__starray_show_def_item:nnn {#1} {##1} {##2} } \seq_if_empty:cF { \l__starray_prefix_tl #2#3 _defstkeys_seq} { \seq_map_inline:cn { \l__starray_prefix_tl #2#3 _defstkeys_seq} { \__starray_show_def:nnn { #1 \use:nnn { ~ } { ~ } { ~ }} { #2#3. } {##1} } } \group_end: } %%%%%%%%%%%%%%% %%%% %%%% \starray_show_def %%%% %%%%%%%%%%%%%%% \cs_new_protected:Npn \starray_show_def:n #1 { \tl_clear:N \l__starray_tmp_B_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_tmp_B_tl } } \cs_new_protected:Npn \starray_show_def_in_text:n #1 { \tl_clear:N \l__starray_tmp_B_tl \tl_set:Nn \l__starray_showcmd_tl \par \__starray_show_def:nnn {}{}{#1} \tl_use:N \l__starray_tmp_B_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_tmp_B_tl { \l__starray_showcmd_tl > #1 \tl_to_str:n { {#3[#4]} ~ (idx: ~ #5)} \use:nn { ~ } { ~ } => } \prop_map_inline:cn {\l__starray_prefix_tl #2 #3 _ #5 _term_prop} {\__starray_show_def_item:nnn {#1 } {##1}{##2}} \tl_set_eq:Nc \l_tmpa_tl {\l__starray_prefix_tl #2#3 _base_defref_tl} \seq_if_empty:cTF { \l__starray_prefix_tl \l_tmpa_tl _defstkeys_seq } {} { \seq_map_inline:cn { \l__starray_prefix_tl \l_tmpa_tl _defstkeys_seq } { \__starray_show_terms:nen { #1 \use:nnn { ~ } { ~ } { ~ }} { #2 #3_#5. } {##1} } } \group_end: } \cs_new_protected:Npn \__starray_show_terms:nnn #1#2#3 { \group_begin: \prop_map_inline:cn {\l__starray_prefix_tl #2 #3 _base_idxhash_prop} {\__starray_show_term_item:nnnnn {#1}{#2}{#3}{##1}{##2}} \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_tmp_B_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_tmp_B_tl } } \cs_new_protected:Npn \starray_show_terms_in_text:n #1 { \tl_clear:N \l__starray_tmp_B_tl \tl_set:Nn \l__starray_showcmd_tl \par \__starray_show_terms:nnn {}{}{#1} \tl_use:N \l__starray_tmp_B_tl }