summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/precattl/precattl.sty
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2022-07-08 03:02:08 +0000
committerNorbert Preining <norbert@preining.info>2022-07-08 03:02:08 +0000
commitc600912bde983d6a04c7ce42321d50d4c7c1a50b (patch)
tree77d96e38d7a6f78e62a322188625aae9b5846f3a /macros/latex/contrib/precattl/precattl.sty
parentc925207bc17a56bf94a6e3d156db27042965136d (diff)
CTAN sync 202207080302
Diffstat (limited to 'macros/latex/contrib/precattl/precattl.sty')
-rw-r--r--macros/latex/contrib/precattl/precattl.sty424
1 files changed, 424 insertions, 0 deletions
diff --git a/macros/latex/contrib/precattl/precattl.sty b/macros/latex/contrib/precattl/precattl.sty
new file mode 100644
index 0000000000..da5d3faf60
--- /dev/null
+++ b/macros/latex/contrib/precattl/precattl.sty
@@ -0,0 +1,424 @@
+% File: precattl.sty
+% Copyright 2022 user202729
+%
+% This work may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this license or
+% (at your option) any later version. The latest version of this license is in
+% the file:
+%
+% http://www.latex-project.org/lppl.txt
+%
+% This work has the LPPL maintenance status `maintained'.
+%
+% The Current Maintainer of this work is user202729.
+
+\ProvidesExplPackage{precattl}{2022/07/07}{0.0.0}{Prepare special catcodes from token list}
+
+
+% ======== this part is inlined from execinside.sty. It's a bit messy yes, maybe will fix when the 2 LaTeX3 bugs on \peek_analysis_map_inline are fixed
+%
+
+\cs_generate_variant:Nn \EI_append:n {x}
+\cs_generate_variant:Nn \int_compare:nNnTF {VNnTF}
+\cs_generate_variant:Nn \tl_set:Nn {Nx}
+\cs_generate_variant:Nn \int_compare:nNnT {VNnT}
+\cs_generate_variant:Nn \cs_if_exist_use:NT {cT}
+
+% ======== define handler functions.
+% a few things it can do:
+% • \tl_build_gput_right:Nn to \_EIresult (content being put there must be wrapped in \unexpanded i.e. x-expand to the desired result
+
+\cs_set_protected:Npn \EI_append_raw:n #1 {
+ \tl_build_gput_right:Nn \_EIresult {#1}
+}
+
+\cs_set_protected:Npn \EI_append:n #1 {
+ \EI_append_raw:n {\exp_not:n {#1}}
+}
+
+\int_new:N \_EIbalance_level
+\int_new:N \_EIcollecting_balanced
+
+% handler can call this to collect following tokens in the input stream as argument.
+% #1: the function to pass argument in. (arguments are passed as brace-hack-included)
+% #2: number of arguments
+\cs_set_protected:Npn \EI_collect_arg:Nn #1 #2 {
+ \int_set:Nn \_EIcollecting_balanced {#2}
+ \int_zero:N \_EIbalance_level
+ \tl_build_gbegin:N \_EIbalanced_content
+ \tl_build_gput_right:Nn \_EIbalanced_content {\noexpand #1}
+}
+
+\cs_set_protected:Npn \EIhandler_EIexpand {
+ \EI_collect_arg:Nn \EI_append:x {1}
+}
+
+\cs_set_protected:Npn \EIhandler_EIexecute {
+ \EI_collect_arg:Nn \use:n {1}
+}
+
+\cs_set_protected:Npn \execinsideprepare:n #1 {
+ \tl_build_gbegin:N \_EIresult
+ \int_zero:N \_EIcollecting_balanced
+
+ \tl_analysis_map_inline:nn {#1} {
+ % reminder: ##1: token, ##2: char code (int), ##3: cat code (hex digit)
+
+ \int_compare:nNnTF \_EIcollecting_balanced > 0 {
+ % collecting content.
+
+ \tl_build_gput_right:Nn \_EIbalanced_content {##1}
+ \int_case:nn {"##3} {
+ {1} { \int_incr:N \_EIbalance_level }
+ {2} { \int_decr:N \_EIbalance_level }
+ }
+
+ % we check this every time instead of only after egroup tokens...
+ % so that if there's exactly one token to be collected it's still correctly passed through
+ % disadvantage: function might get a space
+ \int_compare:nNnT \_EIbalance_level = 0 {
+ % done, call handler function and revert to normal mode.
+
+ \int_decr:N \_EIcollecting_balanced
+ \int_compare:nNnT \_EIcollecting_balanced = 0 {
+ \tl_build_gend:N \_EIbalanced_content
+ \tl_set:Nx \_EIbalanced_content {\_EIbalanced_content}
+ %\pretty:V \_EIbalanced_content
+ \_EIbalanced_content % ← the handler function is embedded in here
+ %\pretty:n {done}
+ }
+ }
+ } {
+ \let \_EIprocessed \c_false_bool
+
+ % check for \EIexecute etc. and handle accordingly.
+ \int_compare:nNnT {##2} = {-1} {
+ \cs_if_exist_use:cT {
+ EIhandler_ \expandafter \cs_to_str:N ##1
+ } {
+ \let \_EIprocessed \c_true_bool
+ }
+ }
+
+ % if not, just append to result.
+ \bool_if:NF \_EIprocessed {
+ \tl_build_gput_right:Nn \_EIresult {##1}
+ }
+ }
+ }
+
+ \tl_build_gend:N \_EIresult
+ \tl_set:Nx \_EIresult {\_EIresult}
+}
+
+\cs_set_protected:Npn \execinside:n #1 {
+ \execinsideprepare:n {#1}
+ \_EIresult
+}
+\let\execinside\execinside:n % normal-catcode alias
+
+\cs_set_protected:Npn \execinside_set:Nn #1 #2 {
+ \execinsideprepare:n {#2}
+ \let #1 \_EIresult
+}
+\let\execinsideSet\execinside_set:Nn
+
+\cs_set_protected:Npn \execinside_gset:Nn #1 #2 {
+ \execinsideprepare:n {#2}
+ \global \let #1 \_EIresult
+}
+\let\execinsideGset\execinside_gset:Nn
+
+
+%% ======== temporary patch for expl3 bug https://github.com/latex3/latex3/issues/1109
+%% okay maybe no need, still use old \tl_analysis implementation
+%
+%% #1: some explicit char with char 32 and cat X
+%% #2: the original explicit char
+%\cs_new_protected:Npn \__broken_tl_peek_analysis_char:nN #1#2
+% {
+% \cs_set_protected:Npn \__tl_tmp:w ##1 #1 ##2 ##3 \scan_stop:
+% { \exp_args:No \l__tl_peek_code_tl { \int_value:w `#2 } ##2 }
+% \exp_after:wN \__tl_tmp:w \c__tl_peek_catcodes_tl \scan_stop:
+% }
+%
+%% only patch in this particular condition.
+%\ifx \__tl_peek_analysis_char:nN \__broken_tl_peek_analysis_char:nN
+% \cs_set_protected:Npn \__tl_peek_analysis_char:nN #1#2
+% {
+% \pretty:n {#1, #2}
+% \token_if_parameter:NTF #1 {
+% \exp_args:No \l__tl_peek_code_tl { \int_value:w `#2 } 6
+% } {
+% \cs_set_protected:Npn \__tl_tmp:w ##1 #1 ##2 ##3 \scan_stop:
+% { \exp_args:No \l__tl_peek_code_tl { \int_value:w `#2 } ##2 }
+% \exp_after:wN \__tl_tmp:w \c__tl_peek_catcodes_tl \scan_stop:
+% }
+% }
+%\fi
+
+% ========
+
+
+\cs_generate_variant:Nn \exp_args:NN {Nc}
+\cs_generate_variant:Nn \EI_append:n {x}
+\cs_generate_variant:Nn \exp_args:Nn {No}
+\cs_generate_variant:Nn \EI_append:n {o}
+\cs_generate_variant:Nn \tl_put_right:Nn {Nx}
+\cs_generate_variant:Nn \use:nn {nV}
+\cs_generate_variant:Nn \execinside_set:Nn {NV}
+
+
+\def \_precattlappend_space #1 {
+ \begingroup
+ \lccode `\ =#1
+ \lowercase{
+ \endgroup \EI_append:n {~}
+ }
+}
+\def \_precattlappend_begin #1 {
+ \begingroup
+ \lccode `\{=#1
+ \lowercase{\endgroup \EI_append_raw:n { \iftrue { \else } \fi }}
+}
+\def \_precattlappend_end #1 {
+ \begingroup
+ \lccode `\}=#1
+ \lowercase{\endgroup \EI_append_raw:n { \iffalse { \else } \fi }}
+}
+
+%\def \_precattldo_special_cC #1 { \exp_args:Nc \EI_append:n {#1} }
+\def \_precattldo_special_cC #1 { \EI_append_raw:n {\exp_not:c {#1}} } % do this to handle \outer tokens. but in the x-expansion step below need to wrap in a group level to avoid defining control sequences as \relax.
+
+\def \_precattldo_special_cB #1 { \str_map_inline:nn {#1} { \_precattlappend_begin {`##1} } }
+\def \_precattldo_special_cE #1 { \str_map_inline:nn {#1} { \_precattlappend_end {`##1} } }
+\def \_precattldo_special_cM #1 { \str_map_inline:nn {#1} { \EI_append:x {\char_generate:nn {`##1} {3}} } }
+\def \_precattldo_special_cT #1 { \str_map_inline:nn {#1} { \EI_append:x {\char_generate:nn {`##1} {4}} } }
+\def \_precattldo_special_cP #1 { \str_map_inline:nn {#1} { \exp_args:No \EI_append:o {\char_generate:nn {`##1} {6}} } }
+\def \_precattldo_special_cU #1 { \str_map_inline:nn {#1} { \EI_append:x {\char_generate:nn {`##1} {7}} } }
+\def \_precattldo_special_cD #1 { \str_map_inline:nn {#1} { \EI_append:x {\char_generate:nn {`##1} {8}} } }
+\def \_precattldo_special_cS #1 { \str_map_inline:nn {#1} { \_precattlappend_space {`##1} } }
+\def \_precattldo_special_cL #1 { \str_map_inline:nn {#1} { \EI_append:x {\char_generate:nn {`##1} {11}} } }
+\def \_precattldo_special_cO #1 { \str_map_inline:nn {#1} { \EI_append:x {\char_generate:nn {`##1} {12}} } }
+\def \_precattldo_special_cA #1 { \str_map_inline:nn {#1} {
+ %\exp_args:No \EI_append:o {\char_generate:nn {`##1} {13}}
+ \EI_append_raw:n {\expandafter \expandafter \expandafter \noexpand \char_generate:nn {`##1} {13}} % handle outer token
+} }
+
+
+
+\def \_precattldo_special #1 #2 {
+ % given #1 e.g. \cO, #2 e.g. {abc}, append <abc> in detokenized catcode to EI.
+ \begingroup
+ \escapechar=-1
+
+ % let \_precattltmp be the concatenation of \string of all tokens within #2.
+ \def \_precattltmp {}
+ \tl_analysis_map_inline:nn {#2} {
+ \tl_put_right:Nx \_precattltmp {\expandafter \string ##1}
+ }
+
+ % then pass it to the specific handler.
+ \exp_args:NNV
+ \endgroup
+ #1 \_precattltmp
+}
+
+
+\def \_precattldo_special_cC_outer { \_precattldo_special\_precattldo_special_cC }
+\def \_precattldo_special_cB_outer { \_precattldo_special\_precattldo_special_cB }
+\def \_precattldo_special_cE_outer { \_precattldo_special\_precattldo_special_cE }
+\def \_precattldo_special_cM_outer { \_precattldo_special\_precattldo_special_cM }
+\def \_precattldo_special_cT_outer { \_precattldo_special\_precattldo_special_cT }
+\def \_precattldo_special_cP_outer { \_precattldo_special\_precattldo_special_cP }
+\def \_precattldo_special_cU_outer { \_precattldo_special\_precattldo_special_cU }
+\def \_precattldo_special_cD_outer { \_precattldo_special\_precattldo_special_cD }
+\def \_precattldo_special_cS_outer { \_precattldo_special\_precattldo_special_cS }
+\def \_precattldo_special_cL_outer { \_precattldo_special\_precattldo_special_cL }
+\def \_precattldo_special_cO_outer { \_precattldo_special\_precattldo_special_cO }
+\def \_precattldo_special_cA_outer { \_precattldo_special\_precattldo_special_cA }
+
+\def \_precattl_tmp_help #1 {
+ \def \_precattl_do_frozen_relax { \EI_append:n {#1} }
+ % #1 here will be substituted by the frozen relax
+}
+\expandafter \_precattl_tmp_help \ifnum0=0\fi
+\let \_precattl_tmp_help \undefined
+
+
+
+\def \precattl_prepare:n #1 {
+ \begingroup
+ \let \EIhandler_EIexpand \undefined
+ \let \EIhandler_EIexecute \undefined
+ \def \EIhandler_cC { \EI_collect_arg:Nn \_precattldo_special_cC_outer 1 }
+ \def \EIhandler_cB { \EI_collect_arg:Nn \_precattldo_special_cB_outer 1 }
+ \def \EIhandler_cE { \EI_collect_arg:Nn \_precattldo_special_cE_outer 1 }
+ \def \EIhandler_cM { \EI_collect_arg:Nn \_precattldo_special_cM_outer 1 }
+ \def \EIhandler_cT { \EI_collect_arg:Nn \_precattldo_special_cT_outer 1 }
+ \def \EIhandler_cP { \EI_collect_arg:Nn \_precattldo_special_cP_outer 1 }
+ \def \EIhandler_cU { \EI_collect_arg:Nn \_precattldo_special_cU_outer 1 }
+ \def \EIhandler_cD { \EI_collect_arg:Nn \_precattldo_special_cD_outer 1 }
+ \def \EIhandler_cS { \EI_collect_arg:Nn \_precattldo_special_cS_outer 1 }
+ \def \EIhandler_cL { \EI_collect_arg:Nn \_precattldo_special_cL_outer 1 }
+ \def \EIhandler_cO { \EI_collect_arg:Nn \_precattldo_special_cO_outer 1 }
+ \def \EIhandler_cA { \EI_collect_arg:Nn \_precattldo_special_cA_outer 1 }
+ \let \EIhandler_cFrozenRelax \_precattl_do_frozen_relax
+ \execinside_gset:Nn \_precattlvalueg {#1}
+ \endgroup
+}
+
+\def \precattl_set:Nn #1 #2 {
+ \precattl_prepare:n {#2}
+ \tl_set_eq:NN #1 \_precattlvalueg
+}
+
+
+
+
+
+
+\cs_new_protected:Npn \__resume_peek: {
+ \peek_analysis_map_inline:n {
+ \__process {##1} {##2} {##3}
+ }
+}
+
+\def \__help:NN #1 #2 {
+ \def #1 { \peek_analysis_map_break:n { \_precattldo_special #2 } }
+}
+\cs_generate_variant:Nn \__help:NN {cc}
+\str_map_inline:nn {CBEMTPUDSLOA} {
+ \__help:cc {__special c #1} {__special c #1 _continue: }
+}
+
+\def \__help:NN #1 #2 {
+ \def #1 { \peek_analysis_map_break:n { #2 } }
+}
+
+\str_map_inline:nn {BEMTPUDSLOA} {
+ \__help:cc {__special c #1} {__special c #1 _continue: }
+}
+
+
+\def \__help:n #1 {
+ \def \__specialcFrozenRelax {
+ \tl_build_gput_right:Nn \__result { #1 }
+ }
+ % #1 here will be substituted by the frozen relax
+}
+\expandafter \__help:n \ifnum0=0\fi
+\let \__help:n \undefined
+
+
+
+% ======== define \__specialcB_continue:, etc.
+
+\def \__help:Nn #1 #2 {
+ \def #1 ##1 {
+ \tl_analysis_map_inline:nn {##1} {
+ \str_map_inline:xn {\expandafter\string####1} {
+ \tl_build_gput_right:Nn \__result {
+ \char_generate:nn {`########1} {#2}
+ }
+ }
+ }
+ \__resume_peek:
+ }
+}
+\__help:Nn \__specialcB_continue: {1}
+\__help:Nn \__specialcE_continue: {2}
+\__help:Nn \__specialcM_continue: {3}
+\__help:Nn \__specialcT_continue: {4}
+\__help:Nn \__specialcU_continue: {7}
+\__help:Nn \__specialcD_continue: {8}
+\__help:Nn \__specialcS_continue: {10}
+\__help:Nn \__specialcL_continue: {11}
+\__help:Nn \__specialcO_continue: {12}
+
+
+\def \__specialcC_continue: #1 {
+ \begingroup
+ \exp_args:NNo \tl_build_gput_right:Nn \__result {\expandafter \noexpand \csname #1 \endcsname}
+ \endgroup
+ \__resume_peek:
+}
+\def \__specialcA_continue: #1 {
+ \tl_analysis_map_inline:nn {#1} {
+ \str_map_inline:xn {\expandafter\string##1} {
+ \tl_build_gput_right:Nn \__result {
+ \expandafter \expandafter \expandafter \noexpand \char_generate:nn {`####1} {13}
+ }
+ }
+ }
+ \__resume_peek:
+}
+\def \__specialcP_continue: #1 {
+ \tl_analysis_map_inline:nn {#1} {
+ \str_map_inline:xn {\expandafter\string##1} {
+ \tl_build_gput_right:Nn \__result {
+ ######## \char_generate:nn {`####1} {6}
+ %## \char_generate:nn {`#1} {6}
+ }
+ }
+ }
+ \__resume_peek:
+}
+
+% ========
+
+\cs_new_protected:Npn \__process #1 #2 #3 {
+ \token_if_eq_meaning:NNTF #3 0 {
+
+ %\ifcsname __special \expandafter \cs_to_str:N #1 \endcsname
+ % \csname __special \expandafter \cs_to_str:N #1 \expandafter \endcsname
+ %\else
+ % \tl_build_gput_right:Nn \__result {#1}
+ %\fi
+
+ \ifcsname __special \expandafter \cs_to_str:N #1 \endcsname
+ \expandafter \use_i:nn
+ \else
+ \expandafter \use_ii:nn
+ \fi
+ {\csname __special \expandafter \cs_to_str:N #1 \endcsname}
+ {\tl_build_gput_right:Nn \__result {#1}}
+ }
+ {
+ \tl_build_gput_right:Nn \__result {#1}
+ }
+}
+
+
+
+\def \_precattl_tmp_help #1 {
+ \def \_precattl_do_frozen_relax { \EI_append:n {#1} }
+ % #1 here will be substituted by the frozen relax
+}
+\expandafter \_precattl_tmp_help \ifnum0=0\fi
+\let \_precattl_tmp_help \undefined
+
+
+\def \precattl_setx:Nn #1 #2 {
+ \begingroup
+ \escapechar=-1~
+ \tl_build_gbegin:N \__result
+ \cs_set_protected:Npn \__special__stop {
+ \tl_build_gend:N \__result
+ \endgroup
+ \tl_set:Nx #1 {\__result}
+ \peek_analysis_map_break:
+ }
+ \__resume_peek:
+ #2
+ \__stop
+}
+\let\precattlSet\precattl_set:Nn
+
+\def \precattl_exec:n #1 {
+ \precattl_prepare:n {#1}
+ \_precattlvalueg
+ %\precattl_set:Nn \__tmp {#1}
+ %\__tmp
+}
+\let\precattlExec\precattl_exec:n