%%%============================================================================== %% 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.2 (2023/05/20) %% %% 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/05/20} {1.2} {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 = 2023/05/20 , version .code:n = 1.2 , 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_redirect_module:nnn { starray } { warning } { none } }, 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_base_ref_tl \tl_new:N \l__starray_parsed_root_ref_tl \tl_new:N \l__starray_parsed_ref_no_idx_ending_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_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 %%%% %%%% %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% % 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 } \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 %%%% . \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 { % \bool_set_true:N \l__starray_rtn_bool \__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 %%%% %%%% %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% \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_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} } } \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_gput:cnV {\l__starray_prefix_tl #1 _base_prop} {idx_hash} \l_tmpa_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: should it be a potential 'warning' ??? \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:} } { \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:} } { \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_protected: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 {nnen} %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% %%%% %%%% set from keyval %%%% %%%% NOTE: tmp variables are recursive aware. %%%% %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% \cs_new_protected: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}} { \prop_get:cnc {\l__starray_prefix_tl #2 _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:nnen { #1 A } { #2.#4 } { \tl_use:c { l__starray_tmp #1 _tl } } } { \__starray_set_from_keyval_parse:nnenn { #1 A } { #2.#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 _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 } { #2 . } \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:nnen { #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:nnenn { #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 {nnenn} %%%%%%%%%%%%%%% %%%% %%%% \starray_set_from_keyval %%%% %%%%%%%%%%%%%%% \cs_new_protected:Npn \__starray_set_from_keyval:nn #1#2 { \bool_set_true:N \l__starray_rtn_bool \__starray_parser:nnTF {\c__starray_idx_ending_bool}{#1} { \keyval_parse:nnn {\__starray_set_from_keyval_parse:nnen {A}{#1}{\l__starray_parsed_ref_tl}} {\__starray_set_from_keyval_parse:nnenn {A}{#1}{\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 \__starray_parser:nnTF {\c__starray_idx_ending_bool}{#1} { \keyval_parse:nnn {\__starray_set_from_keyval_parse:nnen {A}{#1}{\l__starray_parsed_ref_tl}} {\__starray_set_from_keyval_parse:nnenn {A}{#1}{\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} { \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_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_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 }