%%%============================================================================== %% 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.11} {2025/10/26} %% %% 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} {2025/10/26} {1.11} {A structured array/hash of properties} %%%%%%% %%% %%% Just an attempt of having my packages info in a regular way %%% \pkginfograb_set:nn {} { props} for each and all. %%% %%%%%%% \RequirePackage{pkginfograb} \pkginfograb_set:nn { starray } { name = {starray} , prefix = {starray} , date = {2025/10/26}, version = {1.11} , description = {A~structured~array/hash~of~properties} } %%%%%%% %%% 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 , parsed~ check .usage:n = load , parsed~ check .bool_set:N = \l__starray_parsed_check_bool , parsed~ check .value_forbidden:n = true , } \ProcessKeyOptions [ starray ] %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% %%%% %%%% New variants of core expl3 primitives %%%% expansion handling %%%% %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% \cs_generate_variant:Nn \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 } %MARK:variant %\prg_generate_conditional_variant:Nnn \prop_get:NnN { Nec , cec , ceN , cnN } { F , T , TF} \prg_generate_conditional_variant:Nnn \prop_get:NnN { Nec , cec , ce , c } { 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 / parsed} { (ID:#1)~Can't~ call~ #2~ after~a~ failed~ \starray_term_parser: } { You~ called~ #2~ after~ a~ failed~ call~ to~ \starray_term_parser: ~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~structure~'#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. } \msg_new:nnnn {starray} {info / deprecate} %%%$$ { (ID:#1)~'#2'~has ~ been ~ deprecated~ use~'#3'~ instead. } { The ~ command~'#2'~has ~ been ~ deprecated. ~ Use~'#3'~ instead. ~Error~ Code~ ID:<#1>. } \IfExplAtLeastTF{2024-03-14}{}{\msg_warning:nn {starray} {strict / Expl} } \cs_new_protected:Npn \__starray_msg:nnnnn #1#2#3#4#5 { \__starray_set_rtn_false: \seq_gput_right:Nn \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 } \cs_new_protected:Npn \__starray_msg_clear: { \seq_clear:N \l__starray_msg_seq } %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% %%%% %%%% Package Variables declaration %%%% %%%% %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% % TODO variables declaration %\prop_new:N \l__starray_tmpA_prop %%%% %%%% 'general' (internal) returning bool %%%% \cs_new:Npn \__starray_set_rtn_true: { \cs_set_eq:NN \__starray_rtn: \prg_return_true: } \cs_new:Npn \__starray_set_rtn_false: { \cs_set_eq:NN \__starray_rtn: \prg_return_false: } %%%% %%%% sequence of 'error mensages' (stacked). %%%% \seq_new:N \l__starray_msg_seq %%%% %%%% recursive/reentrant aware tmp variables. %%%% this is clumsy and utterly ugly... %%%% a set of variables for each recursing level... %%%% \tl_new:N \l__starray_tmpa_tl % to replace \l_tmpa_tl \tl_new:N \l__starray_tmpb_tl % to replace \l_tmpb_tl \int_new:N \l__starray_tmpa_int % to replace \l_tmpa_int \int_set:Nn \l__starray_tmpa_int {9} \tl_clear:N \l__starray_tmpa_tl \int_do_while:nNnn {\l__starray_tmpa_int} > {0} { \tl_put_left:Nn \l__starray_tmpa_tl {A} \tl_new:c { l__starray_tmp \l__starray_tmpa_tl _tl } \tl_new:c { l__starray_tmp \l__starray_tmpa_tl :A_tl } \tl_new:c { l__starray_tmp \l__starray_tmpa_tl :B_tl } \tl_new:c { l__starray_tmp \l__starray_tmpa_tl _idx_tl } \int_decr:N \l__starray_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 \__starray_show: %%%% %%%% (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 %%%% \cs_set_eq:NN \__starray_put:cnn \relax %%%%%%%%% %%% %%% This will create 3 variants %%% This one is *NEVER* expandable %%% {starray_ #cmd# : n #signature# } => standard one, expecting a starray-term-ref %%% This *might* be expandable (if base-code is) %%% {starray_ parsed_ #cmd# : NN #signature# } => expecting two user given variables (from previous parsing) %%% This *might* be expandable (if base-code (and if-parsed-bool-false, if checked) is) %%% {starray_ parsed_ #cmd# : #signature# } => using *last* parsed term, with/without checking %%% %%%%%%%%% %%% %%% Regarding the base-code: it will 'get' two extra param BEFORE the ones in #signature# %%% NN#signature# (for example, signature:nN... real signature: NNnN #1#2#3#4 %%% whereas the first two parameters, NN, will (should) always be '...ref_tl' and '...ref_no_idx_ending_tl' %%% %%% 'if-parser-failed' code shall expect a single parameter: starray-ref %%% %%% 'if-parsed-failed' code shall expect no parameter! %%% %%%%%%%%% %%% %%% #1 -> #cmd# => base-name %%% #2 -> #signature# %%% #3 -> \c__starray_idx_ending_bool / \c__starray_no_idx_ending_bool %%% #4 -> base-code % if expandable, the resulting commands *might* also be %%% #5 -> if-parser-failed % NB.: this will be in the F branch of \__starry_parser: *not* expandable %%% #6 -> if-parsed-bool-false % NB.: this will be in the F branch of a \bool_if: *might* be expandable %%% %%%%%%%%% \cs_new_protected:Npn \__starray_cs_generate:nnNnnn #1#2#3#4 { \int_case:nn { \tl_count:n {#2} } { {0} { \tl_set:Nn \l__starray_use_tl {} } {1} { \tl_set:Nn \l__starray_use_tl {\use_none:n} } {2} { \tl_set:Nn \l__starray_use_tl {\use_none:nn} } {3} { \tl_set:Nn \l__starray_use_tl {\use_none:nnn} } } \cs_new:cn {starray_parsed_ #1 : NN#2} { #4 } \__starray_cs_generate:cVnnNnn {starray_parsed_ #1 : NN#2} \l__starray_use_tl {#1}{#2} #3 } %%%%%%%%% %%% %%% #1 -> base %%% #2 -> none %%% #3 -> cmd radix %%% #4 -> base signature %%% #5 -> \c__starray_idx_ending_bool / \c__starray_no_idx_ending_bool %%% #6 -> in case parser err %%% #7 -> in case *parsed* err %%%%%%%%% \cs_new_protected:Npn \__starray_cs_generate:NnnnNnn #1#2#3#4#5#6#7 { \bool_if:NTF \l__starray_parsed_check_bool { \cs_new:cpn {starray_parsed_ #3 : #4} { \bool_if:NTF \l__starray_parsed_bool { #1 \l__starray_parsed_saved_ref_tl \l__starray_parsed_saved_ref_no_idx_ending_tl} { #7 #2 } } } { \cs_new:cpn {starray_parsed_ #3 : #4} { #1 \l__starray_parsed_saved_ref_tl \l__starray_parsed_saved_ref_no_idx_ending_tl} } \cs_new:cpn {starray_ #3 : n#4} ##1 { \__starray_parser:nnTF {#5}{##1} { #1 \l__starray_parsed_ref_tl \l__starray_parsed_ref_no_idx_ending_tl} { #6 #2 } } } \cs_generate_variant:Nn \__starray_cs_generate:NnnnNnn {cV} \cs_generate_variant:Nn \prg_new_conditional:Nnn { c } % % Damit \use_none:nn..nn is wrong... should be \use_...:nn... (and execute the false branch!!! IF PRESENT !!!might be the last (...F), none (...T) or last (...TF)) % %%%%%%%%% WARNING: p variants.... might not be expandable !!! %%% %%% This will create 4 variants (x4 => p,T,F,TF) %%% This will *NEVER* expandable %%% {starray_ #cmd# : n #signature# {p,TF,T,F}} => standard one, expecting a starray-term-ref %%% This *might* be expandable (if base-code and T/F code (that follows) also are) %%% {starray_ parsed_ #cmd# : NN #signature# {p, TF,T,F}} => expecting two user given variables (from previous parsing) %%% This *might* be expandable (if base-code and T/F code (that follows) also are... and (if-parsed-boold-false, if checked) %%% {starray_ parsed_ #cmd# : #signature# {p,TF,T,F}} => using *last* parsed term, with/without checking %%% %%% regarding the _p variants.. they will be ok iff #3 is expandable! %%% %%%%%%%%% %%% %%% Regarding the base-code: it will 'get' two extra param BEFORE the ones in the signature %%% NN#signature# (for example, signature:nN... real signature: NNnN #1#2#3#4 %%% whereas the first two parameters, NN, will (should) always be '...ref_tl' and '...ref_no_idx_ending_tl' %%% %%% 'if-parser-failed' code shall expect a single parameter: starray-ref %%% %%% 'if-parsed-failed' code shall expect no parameter! %%% %%% For all of them to be expandable, #3, #4 and #5 have also to be expandable. %%% %%%%%%%%% %%% %%% #1 -> #cmd# => base-name %%% #2 -> #signature# %%% #3 -> \c__starray_idx_ending_bool / \c__starray_no_idx_ending_bool %%% #3=>4 -> base-code %%% #4=>5 -> if-parser-failed %%% #5=>6 -> if-parsed-bool-false %%% %%%%%%%%% \cs_new_protected:Npn \__starray_prg_generate:nnNnnn #1#2#3#4#5#6 { \int_case:nn { \tl_count:n {#2} } %%%% THOSE are for the "false" cases...(parameters not aboserbed by #signature#TF/_p/T/F cases) { {0} { \tl_set:Nn \l__starray_useBa_tl {\use_ii:nn} %% for the TF case \tl_set:Nn \l__starray_useBb_tl {} %% for the _p case \tl_set:Nn \l__starray_useAa_tl {\use_none:n} %% for the T case \tl_set:Nn \l__starray_useAb_tl {\use_i:n} %% for the F case } {1} { \tl_set:Nn \l__starray_useBa_tl {\use_iii:nnn} \tl_set:Nn \l__starray_useBb_tl {\use_none:n} \tl_set:Nn \l__starray_useAa_tl {\use_none:nn} \tl_set:Nn \l__starray_useAb_tl {\use_ii:nn} } {2} { \tl_set:Nn \l__starray_useBa_tl {\use_iv:nnnn} \tl_set:Nn \l__starray_useBb_tl {\use_none:nn} \tl_set:Nn \l__starray_useAa_tl {\use_none:nnn} \tl_set:Nn \l__starray_useAb_tl {\use_iii:nnn} } {3} { \tl_set:Nn \l__starray_useBa_tl {\use_v:nnnnn} \tl_set:Nn \l__starray_useBb_tl {\use_none:nnn} \tl_set:Nn \l__starray_useAa_tl {\use_none:nnnn} \tl_set:Nn \l__starray_useAb_tl {\use_iv:nnnn} } } % % the _p might be ok (expandable) ... depending on #4 % \prg_new_conditional:cnn {starray_parsed_ #1 : NN#2} {p , T , F , TF} { #4 } \__starray_prg_generate_a:ccVVnnNnn {starray_parsed_ #1 : NN#2 TF} {starray_parsed_ #1 _p : NN#2} \l__starray_useBa_tl \l__starray_useBb_tl {#1}{#2}{#3}{#5}{#6} \__starray_prg_generate_b:ccVVnnNnn {starray_parsed_ #1 : NN#2 T} {starray_parsed_ #1 : NN#2 F} \l__starray_useAa_tl \l__starray_useAb_tl {#1}{#2}{#3}{#5}{#6} } %%%%%%%%% %%% %%% if not expandable, better undefine them %%% %%%%%%%%% \cs_new_protected:Npn \__starray_prg_undef_p:nn #1#2 { \cs_undefine:c { starray_parsed_ #1 _p: NN#2 } \cs_undefine:c { starray_parsed_ #1 _p: #2 } } %%%%%%%%% %%% %%% #1 -> baseTF %%% #2 -> base_p %%% #3 -> noneA %%% #4 -> none (for _p case) %%% #5 -> cmd radix %%% #6 -> base signature %%% #7 -> \c__starray_idx_ending_bool / \c__starray_no_idx_ending_bool %%% #7=>8 -> in case parser err %%% #8=>9 -> in case *parsed* err %%%%%%%%% \cs_new_protected:Npn \__starray_prg_generate_a:NNnnnnNnn #1#2#3#4#5#6#7#8#9 { \bool_if:NTF \l__starray_parsed_check_bool { \cs_new_protected:cpn {starray_parsed_ #5 : #6 TF} { \bool_if:NTF \l__starray_parsed_bool { #1 \l__starray_parsed_saved_ref_tl \l__starray_parsed_saved_ref_no_idx_ending_tl} { #9 #3 } %%TODO... this should absorb N+2 and execute the last one... } \cs_new_protected:cpn {starray_parsed_ #5 _p : #6 } { \bool_if:NTF \l__starray_parsed_bool { #2 \l__starray_parsed_saved_ref_tl \l__starray_parsed_saved_ref_no_idx_ending_tl} { #9 #4 } %%TODO... hopefully this is correct... absorbs N tokens...execute none } } { \cs_new:cpn {starray_parsed_ #5 : #6 TF} { #1 \l__starray_parsed_saved_ref_tl \l__starray_parsed_saved_ref_no_idx_ending_tl} \cs_new:cpn {starray_parsed_ #5 _p : #6 } { #2 \l__starray_parsed_saved_ref_tl \l__starray_parsed_saved_ref_no_idx_ending_tl} } \cs_new:cpn {starray_ #5 : n#6 TF} ##1 { \__starray_parser:nnTF {#7}{##1} { #1 \l__starray_parsed_ref_tl \l__starray_parsed_ref_no_idx_ending_tl} { #8 #3 } %%TODO... this should absorb N+2 and execute the last one... } % for the record % \__starray_parser isn't expandable % *would it be...* % % \cs_new:cpn {starray_ #5 _p : n#6 T} ##1 % { % \__starray_parser:nnTF {\c__starray_idx_ending_bool}{##1} % { #2 \l__starray_parsed_ref_tl \l__starray_parsed_ref_no_idx_ending_tl} % { #7 #4 } % } } \cs_generate_variant:Nn \__starray_prg_generate_a:NNnnnnNnn {ccVV} %%%%%%%%% %%% %%% #1 -> baseT %%% #2 -> baseF %%% #3 -> noneA %%% #4 -> noneB %%% #5 -> cmd radix %%% #6 -> base signature %%% #7 -> \c__starray_idx_ending_bool / \c__starray_no_idx_ending_bool %%% #7=>8 -> in case parser err %%% #8=>9 -> in case *parsed* err %%%%%%%%% \cs_new_protected:Npn \__starray_prg_generate_b:NNnnnnNnn #1#2#3#4#5#6#7#8#9 { \bool_if:NTF \l__starray_parsed_check_bool { \cs_new:cpn {starray_parsed_ #5 : #6 T} { \bool_if:NTF \l__starray_parsed_bool { #1 \l__starray_parsed_saved_ref_tl \l__starray_parsed_saved_ref_no_idx_ending_tl} { #9 #3 } %%TODO... this should absorb N+1 and execute none... } \cs_new:cpn {starray_parsed_ #5 : #6 F} { \bool_if:NTF \l__starray_parsed_bool { #2 \l__starray_parsed_saved_ref_tl \l__starray_parsed_saved_ref_no_idx_ending_tl} { #9 #4 } %%TODO... this should absorb N+1 and execute the last one... } } { \cs_new:cpn {starray_parsed_ #5 : #6 F} { #1 \l__starray_parsed_saved_ref_tl \l__starray_parsed_saved_ref_no_idx_ending_tl} \cs_new:cpn {starray_parsed_ #5 : #6 T} { #2 \l__starray_parsed_saved_ref_tl \l__starray_parsed_saved_ref_no_idx_ending_tl} } \cs_new:cpn {starray_ #5 : n#6 T} ##1 { \__starray_parser:nnTF {#7}{##1} { #1 \l__starray_parsed_ref_tl \l__starray_parsed_ref_no_idx_ending_tl} { #8 #3 } %%TODO... this should absorb N+1 and execute none... } \cs_new:cpn {starray_ #5 : n#6 F} ##1 { \__starray_parser:nnTF {#7}{##1} { #2 \l__starray_parsed_ref_tl \l__starray_parsed_ref_no_idx_ending_tl} { #8 #4 } %%TODO... this should absorb N+1 and execute the last one... } } \cs_generate_variant:Nn \__starray_prg_generate_b:NNnnnnNnn {ccVV} %%%%%%%%% %%% %%% This will create a pair %%% *none* expandable %%% #cmd:signature# => cs, expecting the #1 as a starray-ref %%% #cmd:signature#TF => prg, expecting the #1 as a starray-ref %%% %%%%%%%%% %%% %%% Regarding the base-code: #1 will always be treated as the starray-ref. %%% \__starray_return_true: / \__starray_return_false: will be set as %%% as *nothing* for the cs command %%% \prg_return_true: / \prg_return_false: for the prg command %%% %%% 'if-parser-failed' code can use all parameters %%% %%%%%%%%% %%% %%% #1 -> #cmd:signature# => base-name %%% #2 -> \c__starray_idx_ending_bool / \c__starray_no_idx_ending_bool %%% #3 -> base-code %%% #4 -> if-parser-failed %%% %%%%%%%%% \regex_const:Nn \l__starray_csa_regex {\c{prg_return_true:}|\c{prg_return_false:}} \regex_const:Nn \l__starray_csb_regex {\c{__starray_rtn:}} \regex_const:Nn \l__starray_prg_regex {\c{__starray_msg_dispatch:}} \cs_new_protected:Npn \__starray_cs_prg_duo_generate:NNnn #1#2#3 { \tl_set:Nn \l__starray_cmdtmpb_tl {#3} \regex_replace_all:NnN \l__starray_prg_regex {\c{__starray_msg_clear:}} \l__starray_cmdtmpb_tl \tl_set:Nn \l__starray_cmdtmpa_tl {#3} \regex_replace_all:NnN \l__starray_csa_regex {} \l__starray_cmdtmpa_tl \regex_replace_all:NnNTF \l__starray_csb_regex {} \l__starray_cmdtmpa_tl {\tl_put_left:Nn \l__starray_cmdtmpb_tl \__starray_set_rtn_true:} {} \__starray_cs_prg_duo_generate_a:NNVVn #1#2\l__starray_cmdtmpa_tl \l__starray_cmdtmpb_tl } \cs_new_protected:Npn \__starray_cs_prg_duo_generate_a:NNnnn #1#2#3#4#5 { \prg_new_protected_conditional:Nnn #1 {T , F , TF} { \__starray_parser:nnTF #2 {##1} { #4 } { \__starray_msg_clear: \prg_return_false: } % returns nothing by default } \cs_new_protected:Nn #1 { \__starray_parser:nnTF #2 {##1} { #3 } { \__starray_msg_dispatch: #5 } } } \cs_generate_variant:Nn \__starray_cs_prg_duo_generate_a:NNnnn {NNVV} %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% %%%% %%%% Package conditionals %%%% %%%% %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% \prg_new_eq_conditional:NNn \__starray_if_exist:c \cs_if_exist:c {p, T, F, TF} %\prg_generate_conditional_variant:Nnn \__starray_if_exist:c {e} {p, T, F, TF} \prg_new_conditional:Npnn \starray_if_exist:n #1 {p, T, F, TF} { \__starray_if_exist:cTF {\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_gset: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:cTF {\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:cTF {\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} % } \cs_new_protected:Npn \__starray_def_prop:nnn #1 { \prop_gput:cnn {\l__starray_prefix_tl #1 _defkeys_prop} } %%%%%%%%%%%%%%% %%%% %%%% \starray_def_prop %%%% %%%%%%%%%%%%%%% % needs protection, because of _p \cs_new_protected:Npn \starray_def_prop:nnn #1#2#3 { \__starray_if_exist:cTF {\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:cTF {\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:cTF {\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__starray_tmpa_tl {\l__starray_prefix_tl #2 _base_defref_tl} \seq_map_inline:cn {\l__starray_prefix_tl \l__starray_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 {\l__starray_prefix_tl #2 _base_idxhash_prop} { \prop_map_inline:cn {\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__starray_tmpb_tl {\__starray_get_root:w #1 . \q_nil \q_stop} \__starray_if_exist:cTF { \l__starray_prefix_tl \l__starray_tmpb_tl _defref_tl} { \__starray_fix_terms:ee {\l__starray_tmpb_tl}{\l__starray_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:cTF { \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:cTF { \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 expects 3 parameters the last two are being used by \str_compare: \cs_new:Npn \__starray_def_from_keyval_testdot_aux:wTF #1 . \q_nil { \str_compare:nNnTF {#1} = {struct} } % % This 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:Vn \l__starray_tmpA_tl } { \__starray_def_from_keyval_parse:Vnn \l__starray_tmpA_tl } {#3} } { \__starray_def_prop:nnn {#1} {#2} {#3} } \group_end: } %MARK:variant %\cs_generate_variant:Nn \__starray_def_from_keyval_parse:nnn {enn} \cs_generate_variant:Nn \__starray_def_from_keyval_parse:nnn {e , V} \cs_new_protected:Npn \__starray_def_from_keyval_parse:nn #1#2 { \__starray_def_prop:nnn {#1} {#2} {} } %MARK:variant %\cs_generate_variant:Nn \__starray_def_from_keyval_parse:nn {en} \cs_generate_variant:Nn \__starray_def_from_keyval_parse:nn {e , V} %%%%%%%%%%%%%%% %%%% %%%% \starray_def_from_keyval %%%% %%%%%%%%%%%%%%% \cs_new_protected:Npn \starray_def_from_keyval:nn #1#2 { \__starray_if_exist:cTF { \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:cTF { \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} } } \tl_set:Ne \l__starray_tmp_A_tl { \exp_args:Nc \int_to_Alph:n {\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__starray_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__starray_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__starray_tmpb_tl _defstkeys_seq} { \__starray_sub_base_new:nnn { \l__starray_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} } { \__starray_set_rtn_false: } } \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__starray_tmpa_tl { \int_gset:cn { \l__starray_prefix_tl #1 _base_iter_int } { \l__starray_tmpa_tl } \prg_return_true: } { \prg_return_false: } } %%%%%%%%%%%%%%% %%% %%% \starray_set_iter_from_hash:nn %%% \starray_set_iter_from_hash:nnTF %%% %%%%%%%%%%%%%%% \__starray_cs_prg_duo_generate:NNnn \starray_set_iter_from_hash:nn \c__starray_no_idx_ending_bool { \__starray_set_iter_from_hash:nnTF {\l__starray_parsed_ref_tl}{#2} { \__starray_set_sub_iter:nnn {}{\l__starray_parsed_ref_tl}{} \prg_return_true: } { \__starray_msg:nnnnn {reference / iter} {iterhash:1} {#1}{#2} {} \__starray_msg_dispatch: \prg_return_false: } } { \msg_warning:nnnn {starray} {syntax / iter} {iter:1} {#1} } %%%%%%%%%%%%%%% %%% %%% \starray_set_iter:nn %%% \starray_set_iter:nnTF %%% %%%%%%%%%%%%%%% \__starray_cs_prg_duo_generate:NNnn \starray_set_iter:nn \c__starray_no_idx_ending_bool { \int_compare:nNnTF {#2} < {1} { \__starray_set_iter:nnTF {1}{\l__starray_parsed_ref_tl} {} {} \__starray_set_sub_iter:nnn {}{\l__starray_parsed_ref_tl}{} \prg_return_false: } { \__starray_set_iter:nnTF {#2}{\l__starray_parsed_ref_tl} {} { \__starray_set_rtn_false: } \__starray_set_sub_iter:nnn {}{\l__starray_parsed_ref_tl}{} \__starray_rtn: } } { \msg_warning:nnnn {starray} {syntax / iter} {iter:1} {#1} } %%%%%%%%%%%%%%% %%% %%% \starray_reset_iter:n %%% \starray_reset_iter:nTF %%% %%%%%%%%%%%%%%% \__starray_cs_prg_duo_generate:NNnn \starray_reset_iter:n \c__starray_no_idx_ending_bool { \__starray_set_iter:nnTF {1}{\l__starray_parsed_ref_tl} {}{\__starray_set_rtn_false:} \__starray_set_sub_iter:nnn {}{\l__starray_parsed_ref_tl}{} \__starray_rtn: } { \msg_warning:nnnn {starray} {syntax / iter} {iter:4} {#1} } \prg_new_protected_conditional:Npnn \__starray_reset_iter:N #1 {TF} { \__starray_set_rtn_true: \__starray_set_iter:nnTF {1}{#1} {}{\__starray_set_rtn_false:} %% TODO: verify logic !@!! \__starray_set_sub_iter:nnn {}{#1}{} \__starray_rtn: } \prg_generate_conditional_variant:Nnn \__starray_reset_iter:N {c} {TF} %%%%%%%%%%%%%%% %%% %%% \starray_next_iter:n %%% \starray_next_iter:nTF %%% %%%%%%%%%%%%%%% \__starray_cs_prg_duo_generate:NNnn \starray_next_iter:n \c__starray_no_idx_ending_bool { \__starray_incr_iter:n {\l__starray_parsed_ref_tl} \__starray_set_sub_iter:nnn {}{\l__starray_parsed_ref_tl}{} \__starray_rtn: } { \msg_warning:nnnn {starray} {syntax / iter} {iter:5} {#1} } \prg_new_protected_conditional:Npnn \__starray_next_iter:N #1 {TF} { \__starray_set_rtn_true: %% \__starray_msg_clear: \__starray_incr_iter:n {#1} \__starray_set_sub_iter:nnn {}{#1}{} \__starray_rtn: } \prg_generate_conditional_variant:Nnn \__starray_next_iter:N {c} {TF} %%%%%%%%%%%%%%% %%% %%% \starray_iterate_over:nn %%% \starray_iterate_over:nnTF %%% %%%%%%%%%%%%%%% \__starray_cs_prg_duo_generate:NNnn \starray_iterate_over:nn \c__starray_no_idx_ending_bool { \bool_if_exist:cF {g__starray_iterate_ #1 _bool} { \bool_new:c {g__starray_iterate_ #1 _bool} } \tl_if_exist:cF {g__starray_iterate_ #1 _ref_tl} { \tl_new:c {g__starray_iterate_ #1 _ref_tl} } \tl_gset_eq:cN {g__starray_iterate_ #1 _ref_tl} \l__starray_parsed_ref_tl \__starray_reset_iter:cTF {g__starray_iterate_ #1 _ref_tl} { \bool_gset_true:c {g__starray_iterate_ #1 _bool} \bool_do_while:cn {g__starray_iterate_ #1 _bool} { #2 \__starray_next_iter:cTF {g__starray_iterate_ #1 _ref_tl} { } { \bool_gset_false:c {g__starray_iterate_ #1 _bool} } } \prg_return_true: } { \__starray_msg:nnnnn {syntax / iter} {iter:6a} {#1} {} {} \__starray_msg_dispatch: \prg_return_false: } } { \msg_warning:nnnn {starray} {syntax / iter} {iter:6} {#1} } %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% %%%% %%%% set/get properties %%%% %%%% %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% %\cs_new:Npn \__starray_get_prop:nn #1#2 % { % \prop_item:cn {\l__starray_prefix_tl #1 _term_prop}{#2} % } \cs_new:Npn \__starray_get_prop:nn #1 { \prop_item:cn {\l__starray_prefix_tl #1 _term_prop} } \cs_generate_variant:Nn \__starray_get_prop:nn {ee , Ve} %%%%%%%%%%%%%%% %%% %%% \starray_get_prop:nn %%% \starray_parsed_get_prop:NNn %%% \starray_parsed_get_prop:n => checked/nocheck %%% %%%%%%%%%%%%%%% \__starray_cs_generate:nnNnnn {get_prop}{n} \c__starray_idx_ending_bool { \__starray_get_prop:Ve #1 {#3} } { \__starray_msg_dispatch: \msg_warning:nnnn {starray} {syntax / prop} {get:1} {#1} } % returns nothing by default { \msg_warning:nnnn {starray} {syntax / parsed} {parsed:1} {\starray_parsed_get_prop:n} } %%%%%%%%%%%%%%% %%% %%% \starray_get_prop:nnN %%% \starray_parsed_get_prop:NNnN %%% \starray_parsed_get_prop:nN => checked/nocheck %%% %%%%%%%%%%%%%%% \__starray_cs_generate:nnNnnn {get_prop}{nN} \c__starray_idx_ending_bool { \prop_get:cnNF {\l__starray_prefix_tl #1 _term_prop} {#3} #4 { \tl_clear:N #4 } } { \__starray_msg_dispatch: \msg_warning:nnnn {starray} {syntax / prop} {get:2} {#1} } % returns nothing by default { \msg_warning:nnnn {starray} {syntax / parsed} {parsed:2} {\starray_parsed_get_prop:nN} } %%%%%%%%%%%%%%% %%% %%% \starray_get_prop:nnN %%% \starray_parsed_get_prop:NNnN %%% \starray_parsed_get_prop:nN => checked/nocheck %%% %%%%%%%%%%%%%%% \__starray_prg_generate:nnNnnn {get_prop}{nN} \c__starray_idx_ending_bool { \prop_get:cnNTF { \l__starray_prefix_tl #1 _term_prop } { #3 } #4 { \prg_return_true: } { \tl_clear:N #4 \prg_return_false: } } { \__starray_msg_clear: } %% This will be F case of \__starray_parser:nnTF, not expandable anyway { } %% This will be F case of \bool_if:NTF \__starray_prg_undef_p:nn {get_prop}{nN} %%%%%%%%%%%%%%% and predicates %%% %%% \starray_if_in:nnTF %%% \starray_parsed_if_in:NNnTF %%% \starray_parsed_if_in:nNTF => checked/nocheck %%% %%%%%%%%%%%%%%% \__starray_prg_generate:nnNnnn {if_in}{n} \c__starray_idx_ending_bool { \prop_if_in:cnTF { \l__starray_prefix_tl #1 _term_prop } {#3} { \prg_return_true: } { \prg_return_false: } } { \__starray_msg_clear: } %% This will be F case of \__starray_parser:nnTF, not expandable anyway { } %% This will be F case of \bool_if:NTF %%%%%%%%%%%%%%% %%% %%% \starray_get_cnt:n %%% \starray_parsed_get_cnt:NN %%% \starray_parsed_get_cnt: => checked/nocheck %%% %%%%%%%%%%%%%%% \__starray_cs_generate:nnNnnn {get_cnt}{} \c__starray_no_idx_ending_bool { \int_use:c { \l__starray_prefix_tl #2 _base_cnt_int } } { \__starray_msg_dispatch: \msg_warning:nnnn {starray} {syntax / prop} {get:3} {#1} } % returns nothing by default { \msg_warning:nnnn {starray} {syntax / parsed} {parsed:3} {\starray_parsed_get_cnt:} } %%%%%%%%%%%%%%% %%% %%% \starray_get_cnt:nN %%% \starray_parsed_get_cnt:NNN %%% \starray_parsed_get_cnt:N => checked/nocheck %%% %%%%%%%%%%%%%%% \__starray_cs_generate:nnNnnn {get_cnt}{N} \c__starray_no_idx_ending_bool { \int_set_eq:Nc #3 { \l__starray_prefix_tl #2 _base_cnt_int } } { \__starray_msg_dispatch: \msg_warning:nnnn {starray} {syntax / prop} {get:4} {#1} } % returns nothing by default { \msg_warning:nnnn {starray} {syntax / parsed} {parsed:4} {\starray_parsed_get_cnt:N} } %%%%%%%%%%%%%%% %%% %%% \starray_get_cnt:nNTF %%% \starray_parsed_get_cnt:NNNTF %%% \starray_parsed_get_cnt:NTF => checked/nocheck %%% %%%%%%%%%%%%%%% \__starray_prg_generate:nnNnnn {get_cnt}{N} \c__starray_no_idx_ending_bool { \int_set_eq:Nc #3 { \l__starray_prefix_tl #2 _base_cnt_int } \prg_return_true: } { \__starray_msg_clear: } %% This will be F case of \__starray_parser:nnTF, not expandable anyway { } %% This will be F case of \bool_if:NTF \__starray_prg_undef_p:nn {get_cnt}{N} %%%%%%%%%%%%%%% %%% %%% \starray_get_iter:n %%% \starray_parsed_get_iter:NN %%% \starray_parsed_get_iter: => checked/nocheck %%% %%%%%%%%%%%%%%% \__starray_cs_generate:nnNnnn {get_iter}{} \c__starray_no_idx_ending_bool { \int_use:c { \l__starray_prefix_tl #2 _base_iter_int } } { \__starray_msg_dispatch: \msg_warning:nnnn {starray} {syntax / prop} {get:5} {#1} } % returns nothing by default { \msg_warning:nnnn {starray} {syntax / parsed} {parsed:5} {\starray_parsed_get_iter:} } %%%%%%%%%%%%%%% %%% %%% \starray_get_iter:nN %%% \starray_parsed_get_iter:NNN %%% \starray_parsed_get_iter:N => checked/nocheck %%% %%%%%%%%%%%%%%% \__starray_cs_generate:nnNnnn {get_iter}{N} \c__starray_no_idx_ending_bool { \int_set_eq:Nc #3 { \l__starray_prefix_tl #2 _base_iter_int } } { \__starray_msg_dispatch: \msg_warning:nnnn {starray} {syntax / prop} {get:6} {#1} } % returns nothing by default { \msg_warning:nnnn {starray} {syntax / parsed} {parsed:6} {\starray_parsed_get_iter:N} } %%%%%%%%%%%%%%% %%% %%% \starray_get_iter:nnTF %%% \starray_parsed_get_iter:NNnTF %%% \starray_parsed_get_iter:nNTF => checked/nocheck %%% %%%%%%%%%%%%%%% \__starray_prg_generate:nnNnnn {get_iter}{N} \c__starray_no_idx_ending_bool { \int_set_eq:Nc #3 { \l__starray_prefix_tl #2 _base_iter_int } \prg_return_true: } { \__starray_msg_clear: } %% This will be F case of \__starray_parser:nnTF, not expandable anyway { } %% This will be F case of \bool_if:NTF \__starray_prg_undef_p:nn {get_iter}{N} %%%%%%%%%%%%%%% %%% %%% \starray_get_unique_id:nN %%% \starray_parsed_get_unique_id:NNN %%% \starray_parsed_get_unique_id:N => checked/nocheck %%% %%%%%%%%%%%%%%% \__starray_cs_generate:nnNnnn {get_unique_id}{N} \c__starray_idx_ending_bool { \tl_set:NV #3 #1 } { \__starray_msg_dispatch: \msg_warning:nnnn {starray} {syntax / prop} {get:7} {#1} } % returns nothing by default { \msg_warning:nnnn {starray} {syntax / parsed} {parsed:7} {\starray_parsed_get_unique_id:N} } %%%%%%%%%%%%%%% %%% %%% \starray_get_unique_id:nNTF %%% \starray_parsed_get_unique_id:NNNTF %%% \starray_parsed_get_unique_id:NTF => checked/nocheck %%% %%%%%%%%%%%%%%% \__starray_prg_generate:nnNnnn {get_unique_id}{N} \c__starray_idx_ending_bool { \tl_set:NV #3 #1 \prg_return_true: } { \__starray_msg_clear: } %% This will be F case of \__starray_parser:nnTF, not expandable anyway { } %% This will be F case of \bool_if:NTF \__starray_prg_undef_p:nn {get_unique_id}{N} %%%%%%%%%%%%%%% %%%% %%%% \starray_set_prop %%%% %%%%%%%%%%%%%%% %\cs_new_protected:Npn \__starray_set_prop:nnn #1#2#3 % { % \__starray_put:cnn {\l__starray_prefix_tl #1 _term_prop}{#2}{#3} % } \cs_new_protected:Npn \__starray_set_prop:nnn #1 { \__starray_put:cnn {\l__starray_prefix_tl #1 _term_prop} } \cs_new_protected:Npn \__starray_set_prop:Nnnn #1#2 { #1 {\l__starray_prefix_tl #2 _term_prop} } %%%%%%%%%%%%%%% %%% %%% \starray_set_prop:nnn %%% \starray_set_prop:nnnTF %%% %%%%%%%%%%%%%%% \__starray_cs_prg_duo_generate:NNnn \starray_set_prop:nnn \c__starray_idx_ending_bool { \__starray_set_prop:Nnnn \prop_put:cnn \l__starray_parsed_ref_tl {#2}{#3} \prg_return_true: } { \msg_warning:nnnn {starray} {syntax / prop} {set:1} {#1} } \cs_generate_variant:Nn \starray_set_prop:nnn {nnV} \prg_generate_conditional_variant:Nnn \starray_set_prop:nnn { nnV } {T, F , TF } %%% %%%%%%%%%%%%%%% %%% %%% \starray_gset_prop:nnn %%% \starray_gset_prop:nnnTF %%% %%%%%%%%%%%%%%% \__starray_cs_prg_duo_generate:NNnn \starray_gset_prop:nnn \c__starray_idx_ending_bool { \__starray_set_prop:Nnnn \prop_gput:cnn \l__starray_parsed_ref_tl {#2}{#3} \prg_return_true: } { \msg_warning:nnnn {starray} {syntax / prop} {set:1} {#1} } \cs_generate_variant:Nn \starray_gset_prop:nnn {nnV} \prg_generate_conditional_variant:Nnn \starray_gset_prop:nnn { nnV } {T, F , TF } %%% %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% %%%% %%%% set/get properties (keyval) %%%% %%%% %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% % % 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} \cs_new:Npn \__starray_set_parse_aux:wTF #1#2 [ \q_nil \q_stop { \__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}{} } %MARK:variant %\cs_generate_variant:Nn \__starray_set_from_keyval_parse:nnnn {neen} \cs_generate_variant:Nn \__starray_set_from_keyval_parse:nnnn {nee , nVV , nvv} %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% %%%% %%%% 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 { \exp_args:Nv \tl_if_blank:nTF {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 { \l__starray_prefix_tl \tl_use:c {\l__starray_prefix_tl #2 _base_defref_tl} _defstkeys_seq} {#4} { \int_compare:nNnTF {\int_use:c { \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 { \l__starray_prefix_tl #3 .#4 _base_idxhash_prop } {\int_use:c { \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 { \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} _ \l__starray_tmp_D_tl } \tl_put_left:cn { l__starray_tmp #1 :B_tl } { #3 . } \keyval_parse:nnn { \__starray_set_from_keyval_parse:nvvn { #1 A } { l__starray_tmp #1 :B_tl } { l__starray_tmp #1 _idx_tl } } { \__starray_set_from_keyval_parse:nvvnn { #1 A } { l__starray_tmp #1 :B_tl } { 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 } } %MARK:variant %\cs_generate_variant:Nn \__starray_set_from_keyval_parse:nnnnn {neenn} \cs_generate_variant:Nn \__starray_set_from_keyval_parse:nnnnn {nee , nVV , nvv} %%%%%%%%%%%%%%% %%% %%% \__starray_set_from_keyval:nn %%% \__starray_set_from_keyval:nnTF %%% %%%%%%%%%%%%%%% \__starray_cs_prg_duo_generate:NNnn \__starray_set_from_keyval:nn \c__starray_idx_ending_bool { %%% just in case, for msg_err messages \tl_set:Nn \l__starray_from_keyval_orgref_tl {#1} \keyval_parse:nnn {\__starray_set_from_keyval_parse:nVVn {A}{\l__starray_parsed_ref_no_idx_ending_tl}{\l__starray_parsed_ref_tl}} {\__starray_set_from_keyval_parse:nVVnn {A}{\l__starray_parsed_ref_no_idx_ending_tl}{\l__starray_parsed_ref_tl}} { #2 } \__starray_msg_dispatch: \__starray_rtn: } { \msg_warning:nnnn {starray} {syntax / prop} {setkeyval:1} {#1} } %\cs_new_protected:Npn \starray_set_from_keyval:nn #1#2 % { % \cs_set_eq:NN \__starray_put:cnn \prop_put:cnn % \__starray_set_from_keyval:nn {#1}{#2} % } \cs_new_protected:Npn \starray_set_from_keyval:nn { \cs_set_eq:NN \__starray_put:cnn \prop_put:cnn \__starray_set_from_keyval:nn } %\cs_new_protected:Npn \starray_gset_from_keyval:nn #1#2 % { % \cs_set_eq:NN \__starray_put:cnn \prop_gput:cnn % \__starray_set_from_keyval:nn {#1}{#2} % } \cs_new_protected:Npn \starray_gset_from_keyval:nn { \cs_set_eq:NN \__starray_put:cnn \prop_gput:cnn \__starray_set_from_keyval:nn } %% %% TODO: Might be worth a bit (more) of optimization... %% \cs_new_protected: \starray_set_from_keyval:nnTF (etc...) with the two parameters being implicit... %% %\prg_new_protected_conditional:Npnn \starray_set_from_keyval:nn #1#2 {T, F, TF} % { % \cs_set_eq:NN \__starray_put:cnn \prop_put:cnn % \__starray_set_from_keyvalTF:nn {#1}{#2} % } \cs_new_protected:Npn \starray_set_from_keyval:nnT { \cs_set_eq:NN \__starray_put:cnn \prop_put:cnn \__starray_set_from_keyval:nnT } \cs_new_protected:Npn \starray_set_from_keyval:nnF { \cs_set_eq:NN \__starray_put:cnn \prop_put:cnn \__starray_set_from_keyval:nnF } \cs_new_protected:Npn \starray_set_from_keyval:nnTF { \cs_set_eq:NN \__starray_put:cnn \prop_put:cnn \__starray_set_from_keyval:nnTF } %\prg_new_protected_conditional:Npnn \starray_gset_from_keyval:nn #1#2 {T, F, TF} % { % \cs_set_eq:NN \__starray_put:cnn \prop_gput:cnn % \__starray_set_from_keyvalTF:nn {#1}{#2} % } \cs_new_protected:Npn \starray_gset_from_keyval:nnT { \cs_set_eq:NN \__starray_put:cnn \prop_gput:cnn \__starray_set_from_keyval:nnT } \cs_new_protected:Npn \starray_gset_from_keyval:nnF { \cs_set_eq:NN \__starray_put:cnn \prop_gput:cnn \__starray_set_from_keyval:nnF } \cs_new_protected:Npn \starray_gset_from_keyval:nnTF { \cs_set_eq:NN \__starray_put:cnn \prop_gput:cnn \__starray_set_from_keyval:nnTF } %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% %%%% %%%% starray ref/address parser using quarks %%%% could be done with seq_split and regex but %%%% would have been even more cumbersome %%%% %%%% := [ . ] %%%% := [ ] %%%% := \[ \] %%%% %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% %%% %%% \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:} % } \cs_new:Npn \__starray_term_parse_aux:wTF #1 [ \q_nil \q_stop { \__starray_term_parse_end:wTF #1 ] \q_nil\q_stop } %%% %%% \tl_set: isn't expandable (see above)... but (internal) and only the TF variant is needed. %%% :w macro anyway... %%% \prg_new_conditional:Npnn \__starray_term_parse_begin:w #1 [ #2 \q_stop { TF} { \tl_set:Nn \l__starray_parsed_term_tl {#1} \quark_if_nil:nTF {#2} { % no 'term' ref, just array_name (current/iter term) \tl_clear:N \l__starray_parsed_idx_tl \prg_return_true: } { \__starray_term_parse_aux:wTF #2 \q_stop {\prg_return_true:} {\prg_return_false:} } } %%% %%% 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, %%% \prop_if_exist:cTF , at the end, expects TF (should follow this) %%% %\prg_new_protected_conditional:Npnn \__starray_if_valid_idx:nn #1#2 {T, F, TF} \cs_new_protected:Npn \__starray_if_valid_idx:nnTF #1#2 { \tl_if_blank:nTF {#2} { \prop_get:ceNF {\l__starray_prefix_tl \l__starray_parsed_ref_tl _base_idxhash_prop} {#1} \l__starray_tmpa_tl { \tl_clear:N \l__starray_tmpa_tl } } { \prop_get:ceNF {\l__starray_prefix_tl \l__starray_parsed_ref_tl _base_idxhash_prop} {#2} \l__starray_tmpa_tl { \tl_clear:N \l__starray_tmpa_tl } } \tl_put_right:Ne \l__starray_parsed_ref_tl { _ \l__starray_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} \cs_generate_variant:Nn \__starray_if_valid_idx:nnTF {ee} %%% %%% 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:cTF {\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_clear:N \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: } } \tl_new:N \l__starray_parsed_saved_ref_tl \tl_new:N \l__starray_parsed_saved_ref_no_idx_ending_tl \bool_new:N \l__starray_parsed_bool \cs_new_protected:Npn \starray_term_parser:n #1 { \__starray_parser:nnTF {\c__starray_idx_ending_bool}{#1} { \tl_set:NV \l__starray_parsed_saved_ref_tl \l__starray_parsed_ref_tl \tl_set:NV \l__starray_parsed_saved_ref_no_idx_ending_tl \l__starray_parsed_ref_no_idx_ending_tl \bool_set_true:N \l__starray_parsed_bool } { \bool_set_false:N \l__starray_parsed_bool \__starray_msg_dispatch: \msg_warning:nnnn {starray} {syntax / term} {term parser:1} {#1} } } \cs_new_protected:Npn \starray_term_syntax:n { \msg_warning:nnnnn {starray} {info / deprecate} {dep:01} { \starray_term_syntax:n } { \starray_term_parser:n } \starray_term_parser:n } \prg_new_protected_conditional:Npnn \starray_term_parser:n #1 {T, F, TF} { \__starray_parser:nnTF {\c__starray_idx_ending_bool}{#1} { \tl_set:NV \l__starray_parsed_saved_ref_tl \l__starray_parsed_ref_tl \tl_set:NV \l__starray_parsed_saved_ref_no_idx_ending_tl \l__starray_parsed_ref_no_idx_ending_tl \bool_set_true:N \l__starray_parsed_bool \prg_return_true: } { \bool_set_false:N \l__starray_parsed_bool \__starray_msg_clear: \prg_return_false: } } \cs_new_protected:Npn \starray_term_syntax:nTF { \msg_warning:nnnnn {starray} {info / deprecate} {dep:03} { \starray_term_syntax:nTF } { \starray_term_parser:nTF } \starray_term_parser:nTF } \cs_new_protected:Npn \starray_term_syntax:nT { \msg_warning:nnnnn {starray} {info / deprecate} {dep:04} { \starray_term_syntax:nT } { \starray_term_parser:nT } \starray_term_parser:nT } \cs_new_protected:Npn \starray_term_syntax:nF { \msg_warning:nnnnn {starray} {info / deprecate} {dep:05} { \starray_term_syntax:nF } { \starray_term_parser:nF } \starray_term_parser:nF } \cs_new_protected:Npn \starray_term_parser: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 / term} {term parser:2} {#1} } } \cs_new_protected:Npn \starray_term_syntax:nNN { \msg_warning:nnnnn {starray} {info / deprecate} {dep:02} { \starray_term_syntax:nNN } { \starray_term_parser:nNN } \starray_term_parser:nNN } \prg_new_protected_conditional:Npnn \starray_term_parser:nNN #1#2#3 {T, F, TF} { \__starray_parser:nnTF {\c__starray_idx_ending_bool}{#1} { \tl_gset:NV #2 \l__starray_parsed_ref_tl \tl_gset:NV #3 \l__starray_parsed_ref_no_idx_ending_tl \prg_return_true: } { \__starray_msg_clear: \prg_return_false: } } \cs_new_protected:Npn \starray_term_syntax:nNNTF { \msg_warning:nnnnn {starray} {info / deprecate} {dep:06} { \starray_term_syntax:nNNTF } { \starray_term_parser:nNNTF } \starray_term_parser:nNNTF } \cs_new_protected:Npn \starray_term_syntax:nNNT { \msg_warning:nnnnn {starray} {info / deprecate} {dep:07} { \starray_term_syntax:nNNT } { \starray_term_parser:nNNT } \starray_term_parser:nNNT } \cs_new_protected:Npn \starray_term_syntax:nNNF { \msg_warning:nnnnn {starray} {info / deprecate} {dep:08} { \starray_term_syntax:nNNF } { \starray_term_parser:nNNF } \starray_term_parser:nNNF } %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% %%%% %%%% \..show_def commands %%%% %%%% %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% %%%% %%%% Note to self: %%%% \__starray_show: 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 { \__starray_show: > #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 { \__starray_show: > #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 \cs_set_eq:NN \__starray_show: \iow_newline: \__starray_show_def:nnn {}{}{#1} \msg_show:nnxxx {starray}{info / show} { show~def } { The~ starray~ <#1> ~is~defined~as~follow: } { \l__starray_tmp_B_tl } } \cs_new_protected:Npn \starray_show_def_in_text:n #1 { \tl_clear:N \l__starray_tmp_B_tl \cs_set_eq:NN \__starray_show: \par \__starray_show_def:nnn {}{}{#1} \l__starray_tmp_B_tl } %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% %%%% %%%% \..show_terms commands %%%% %%%% %%%%%%%%%%%%%%% %%%%%%%%%%%%%%% %%%% %%%% Note to self: %%%% \__starray_show: 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 { \__starray_show: > #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__starray_tmpa_tl {\l__starray_prefix_tl #2#3 _base_defref_tl} \seq_if_empty:cTF { \l__starray_prefix_tl \l__starray_tmpa_tl _defstkeys_seq } {} { \seq_map_inline:cn { \l__starray_prefix_tl \l__starray_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: } %MARK:variant %\cs_generate_variant:Nn \__starray_show_terms:nnn {nen} \cs_generate_variant:Nn \__starray_show_terms:nnn {ne} %%%%%%%%%%%%%%% %%%% %%%% \starray_show_terms %%%% %%%%%%%%%%%%%%% \cs_new_protected:Npn \starray_show_terms:n #1 { \tl_clear:N \l__starray_tmp_B_tl \cs_set_eq:NN \__starray_show: \iow_newline: \__starray_show_terms:nnn {}{}{#1} \msg_show:nnxxx {starray}{info / show} { show~terms } { The~ starray~ <#1> ~has~the~following~terms: } { \l__starray_tmp_B_tl } } \cs_new_protected:Npn \starray_show_terms_in_text:n #1 { \tl_clear:N \l__starray_tmp_B_tl \cs_set_eq:NN \__starray_show: \par \__starray_show_terms:nnn {}{}{#1} \l__starray_tmp_B_tl }