diff options
Diffstat (limited to 'macros/latex/required/l3kernel/l3int.dtx')
-rw-r--r-- | macros/latex/required/l3kernel/l3int.dtx | 229 |
1 files changed, 172 insertions, 57 deletions
diff --git a/macros/latex/required/l3kernel/l3int.dtx b/macros/latex/required/l3kernel/l3int.dtx index 45050964de..120a1b4630 100644 --- a/macros/latex/required/l3kernel/l3int.dtx +++ b/macros/latex/required/l3kernel/l3int.dtx @@ -2,7 +2,7 @@ % %% File: l3int.dtx % -% Copyright (C) 1990-2024 The LaTeX Project +% Copyright (C) 1990-2025 The LaTeX Project % % It may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this @@ -43,7 +43,7 @@ % }^^A % } % -% \date{Released 2024-05-27} +% \date{Released 2025-01-18} % % \maketitle % @@ -100,21 +100,6 @@ % restricted-expandable functions can both be used, and \cs{exp_not:n} % and its variants have no effect while \cs{exp_not:N} may incorrectly % interrupt the expression. -% \begin{texnote} -% Exactly two expansions are needed to evaluate \cs{int_eval:n}. -% The result is \emph{not} an \meta{internal integer}, and therefore -% should be terminated by a space if used in \cs{int_value:w} or in -% a \TeX{}-style integer assignment. -% -% As all \TeX{} integers, integer operands can also be: -% \tn{value}\Arg{\LaTeXe{} counter}; dimension or skip variables, -% converted to integers in~\texttt{sp}; the character code of some -% character given as \texttt{`}\meta{char} or -% \texttt{`\textbackslash}\meta{char}; octal numbers given as -% \texttt{'} followed by digits from \texttt{0} to \texttt{7}; or -% hexadecimal numbers given as |"| followed by digits and upper case -% letters from \texttt{A} to~\texttt{F}. -% \end{texnote} % % \begin{function}[EXP]{\int_eval:n} % \begin{syntax} @@ -277,11 +262,11 @@ % \begin{function}[EXP, pTF, added=2012-03-03] % {\int_if_exist:N, \int_if_exist:c} % \begin{syntax} -% \cs{int_if_exist_p:N} \meta{int} -% \cs{int_if_exist:NTF} \meta{int} \Arg{true code} \Arg{false code} +% \cs{int_if_exist_p:N} \meta{integer} +% \cs{int_if_exist:NTF} \meta{integer} \Arg{true code} \Arg{false code} % \end{syntax} -% Tests whether the \meta{int} is currently defined. This does not -% check that the \meta{int} really is an integer variable. +% Tests whether the \meta{integer} is currently defined. This does not +% check that the \meta{integer} really is an integer variable. % \end{function} % % \section{Setting and incrementing integers} @@ -310,7 +295,10 @@ % \end{function} % % \begin{function}[updated = 2011-10-22] -% {\int_set:Nn, \int_set:cn, \int_gset:Nn, \int_gset:cn} +% { +% \int_set:Nn, \int_set:cn, \int_set:NV, \int_set:cV, +% \int_gset:Nn, \int_gset:cn, \int_gset:NV, \int_gset:cV +% } % \begin{syntax} % \cs{int_set:Nn} \meta{integer} \Arg{int expr} % \end{syntax} @@ -319,6 +307,37 @@ % \cs{int_eval:n}). % \end{function} % +% \begin{function}[added = 2024-12-08] +% { +% \int_set_regex_count:Nnn, \int_set_regex_count:cnn, +% \int_set_regex_count:NNn, \int_set_regex_count:cNn, +% \int_gset_regex_count:Nnn, \int_gset_regex_count:cnn, +% \int_gset_regex_count:NNn, \int_gset_regex_count:cNn, +% } +% \begin{syntax} +% \cs{int_set_regex_count:Nnn} \meta{integer} \Arg{regex} \Arg{token list} +% \cs{int_set_regex_count:NNn} \meta{integer} \meta{regex~var} \Arg{token list} +% \end{syntax} +% Sets \meta{integer} equal to the number of times +% \meta{regular expression} appears in \meta{token list}. +% The search starts by finding the left-most longest match, +% respecting greedy and lazy (non-greedy) operators. Then the search +% starts again from the character following the last character +% of the previous match, until reaching the end of the token list. +% Infinite loops are prevented in the case where the regular expression +% can match an empty token list: then we count one match between each +% pair of characters. +% For instance, +% \begin{verbatim} +% \int_set_regex_count:Nnn \l_foo_int { (b+|c) } { abbababcbb } +% \end{verbatim} +% results in \cs[no-index]{l_foo_int} taking the value $5$. +% Theses are alternative names for \cs{regex_count:nnN} and friends, +% with arguments re-ordered for \meta{integer} setting; +% see \pkg{l3regex} chapter for more details of the \meta{regex} +% format. +% \end{function} +% % \begin{function}[updated = 2011-10-22] % {\int_sub:Nn, \int_sub:cn, \int_gsub:Nn, \int_gsub:cn} % \begin{syntax} @@ -426,7 +445,8 @@ % \end{syntax} % This function evaluates the \meta{test int expr} and % compares this in turn to each of the -% \meta{int expr cases}. If the two are equal then the +% \meta{int expr case}s until a match is found. +% If the two are equal then the % associated \meta{code} is left in the input stream % and other cases are discarded. If any of the % cases are matched, the \meta{true code} is also inserted into the @@ -445,6 +465,10 @@ % { No idea! } % \end{verbatim} % leaves \enquote{\texttt{Medium}} in the input stream. +% Since evaluation of the test expressions stops at the first +% successful case, the order of possible matches should normally +% be that the most likely are earlier: this will reduce the average +% steps required to complete expansion. % \end{function} % % \begin{function}[EXP,pTF]{\int_if_even:n, \int_if_odd:n} @@ -605,6 +629,32 @@ % $1$. These functions are provided as simple short-cuts for code clarity. % \end{function} % +% \begin{function}[added = 2025-01-13, rEXP] +% {\int_step_tokens:nn, \int_step_tokens:nnn, \int_step_tokens:nnnn} +% \begin{syntax} +% \cs{int_step_tokens:nn} \Arg{final value} \Arg{code} +% \cs{int_step_tokens:nnn} \Arg{initial value} \Arg{final value} \Arg{code} +% \cs{int_step_tokens:nnnn} \Arg{initial value} \Arg{step} \Arg{final value} \Arg{code} +% \end{syntax} +% This function works just like \cs{int_step_function:nnnN} but +% instead of mapping a single function to each stepped \meta{value} +% between \meta{initial value} and \meta{final value} this maps +% the multiple tokens in \meta{code}, so that it gets the current +% \meta{value} as a braced argument following it. For instance +% \begin{verbatim} +% \cs_set:Npn \my_product:nn #1#2 +% { $#1 \times #2 = \int_eval:n { #1 * #2 }$ \quad } +% \int_step_tokens:nnnn { 1 } { 1 } { 4 } { \my_product:nn { 2 } } +% \end{verbatim} +% would print +% \begin{quote} +% $2 \times 1 = 2$ \quad +% $2 \times 2 = 4$ \quad +% $2 \times 3 = 6$ \quad +% $2 \times 4 = 8$ \quad +% \end{quote} +% \end{function} +% % \begin{function}[added = 2012-06-04, updated = 2018-04-22] % {\int_step_inline:nn, \int_step_inline:nnn, \int_step_inline:nnnn} % \begin{syntax} @@ -1132,6 +1182,13 @@ % \end{macro} % \end{macro} % +% \begin{macro}{\@@_sep:} +% See comments in \texttt{l3fp-aux.dtx} for this idea. +% \begin{macrocode} +\cs_new_eq:NN \@@_sep: \tex_right:D +% \end{macrocode} +% \end{macro} +% % \begin{macro}[EXP]{\int_sign:n, \@@_sign:Nw} % See \cs{int_abs:n}. Evaluate the expression once (and when % debugging is enabled, check that the expression is well-formed), @@ -1143,10 +1200,10 @@ \cs_new:Npn \int_sign:n #1 { \int_value:w \exp_after:wN \@@_sign:Nw - \int_value:w \@@_eval:w #1 \@@_eval_end: ; + \int_value:w \@@_eval:w #1 \@@_eval_end: \@@_sep: \exp_stop_f: } -\cs_new:Npn \@@_sign:Nw #1#2 ; +\cs_new:Npn \@@_sign:Nw #1#2 \@@_sep: { \if_meaning:w 0 #1 0 @@ -1180,20 +1237,20 @@ \cs_new:Npn \int_max:nn #1#2 { \int_value:w \exp_after:wN \@@_maxmin:wwN - \int_value:w \@@_eval:w #1 \exp_after:wN ; - \int_value:w \@@_eval:w #2 ; + \int_value:w \@@_eval:w #1 \exp_after:wN \@@_sep: + \int_value:w \@@_eval:w #2 \@@_sep: > \exp_stop_f: } \cs_new:Npn \int_min:nn #1#2 { \int_value:w \exp_after:wN \@@_maxmin:wwN - \int_value:w \@@_eval:w #1 \exp_after:wN ; - \int_value:w \@@_eval:w #2 ; + \int_value:w \@@_eval:w #1 \exp_after:wN \@@_sep: + \int_value:w \@@_eval:w #2 \@@_sep: < \exp_stop_f: } -\cs_new:Npn \@@_maxmin:wwN #1 ; #2 ; #3 +\cs_new:Npn \@@_maxmin:wwN #1 \@@_sep: #2 \@@_sep: #3 { \if_int_compare:w #1 #3 #2 ~ #1 @@ -1233,11 +1290,11 @@ { \int_value:w \@@_eval:w \exp_after:wN \@@_div_truncate:NwNw - \int_value:w \@@_eval:w #1 \exp_after:wN ; - \int_value:w \@@_eval:w #2 ; + \int_value:w \@@_eval:w #1 \exp_after:wN \@@_sep: + \int_value:w \@@_eval:w #2 \@@_sep: \@@_eval_end: } -\cs_new:Npn \@@_div_truncate:NwNw #1#2; #3#4; +\cs_new:Npn \@@_div_truncate:NwNw #1#2 \@@_sep: #3#4 \@@_sep: { \if_meaning:w 0 #1 0 @@ -1261,12 +1318,12 @@ \cs_new:Npn \int_mod:nn #1#2 { \int_value:w \@@_eval:w \exp_after:wN \@@_mod:ww - \int_value:w \@@_eval:w #1 \exp_after:wN ; - \int_value:w \@@_eval:w #2 ; + \int_value:w \@@_eval:w #1 \exp_after:wN \@@_sep: + \int_value:w \@@_eval:w #2 \@@_sep: \@@_eval_end: } -\cs_new:Npn \@@_mod:ww #1; #2; - { #1 - ( \@@_div_truncate:NwNw #1 ; #2 ; ) * #2 } +\cs_new:Npn \@@_mod:ww #1 \@@_sep: #2 \@@_sep: + { #1 - ( \@@_div_truncate:NwNw #1 \@@_sep: #2 \@@_sep: ) * #2 } % \end{macrocode} % \end{macro} % \end{macro} @@ -1483,9 +1540,9 @@ % \end{macro} % \end{macro} % -% \begin{macro}{\int_set:Nn, \int_set:cn} +% \begin{macro}{\int_set:Nn, \int_set:cn, \int_set:NV, \int_set:cV} % \UnitTested -% \begin{macro}{\int_gset:Nn, \int_gset:cn} +% \begin{macro}{\int_gset:Nn, \int_gset:cn, \int_gset:NV, \int_gset:cV} % \UnitTested % As integers are register-based \TeX{} issues an error % if they are not defined. While the |=| sign is optional, this @@ -1496,8 +1553,47 @@ { #1 = \@@_eval:w #2 \@@_eval_end: } \cs_new_protected:Npn \int_gset:Nn #1#2 { \tex_global:D #1 = \@@_eval:w #2 \@@_eval_end: } -\cs_generate_variant:Nn \int_set:Nn { c } -\cs_generate_variant:Nn \int_gset:Nn { c } +\cs_generate_variant:Nn \int_set:Nn { NV , c , cV } +\cs_generate_variant:Nn \int_gset:Nn { NV , c , cV } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \int_set_regex_count:Nnn, \int_set_regex_count:cnn, +% \int_gset_regex_count:Nnn, \int_gset_regex_count:cnn +% } +% \begin{macro} +% { +% \int_set_regex_count:NNn, \int_set_regex_count:cNn, +% \int_gset_regex_count:NNn, \int_set_gregex_count:cNn +% } +% \begin{macrocode} +\cs_new_protected:Npn \int_set_regex_count:Nnn #1#2#3 + { \regex_count:nnN {#2} {#3} #1 } +\cs_generate_variant:Nn \int_set_regex_count:Nnn { c } +\cs_new_protected:Npn \int_gset_regex_count:Nnn #1#2#3 + { + \group_begin: + \int_set_eq:NN \l_@@_internal_a_int #1 + \regex_count:nnN {#2} {#3} \l_@@_internal_a_int + \int_gset_eq:NN #1 \l_@@_internal_a_int + \group_end: + } +\cs_generate_variant:Nn \int_gset_regex_count:Nnn { c } +\cs_new_protected:Npn \int_set_regex_count:NNn #1#2#3 + { \regex_count:NnN #2 {#3} #1 } +\cs_generate_variant:Nn \int_set_regex_count:Nnn { c } +\cs_new_protected:Npn \int_gset_regex_count:NNn #1#2#3 + { + \group_begin: + \int_set_eq:NN \l_@@_internal_a_int #1 + \regex_count:NnN #2 {#3} \l_@@_internal_a_int + \int_gset_eq:NN #1 \l_@@_internal_a_int + \group_end: + } +\cs_generate_variant:Nn \int_gset_regex_count:NNn { c } % \end{macrocode} % \end{macro} % \end{macro} @@ -1881,7 +1977,7 @@ % \subsection{Integer step functions} % % \begin{macro}{\int_step_function:nnnN} -% \begin{macro}{\@@_step:wwwN, \@@_step:NwnnN} +% \begin{macro}{\@@_step:w, \@@_step:Nw} % \begin{macro}{\int_step_function:nN} % \begin{macro}{\int_step_function:nnN} % Before all else, evaluate the initial value, step, and final value. @@ -1889,51 +1985,70 @@ % of the steps. After that, do the function for the start value then % step and loop around. It would be more symmetrical to test for a % step size of zero before checking the sign, but we optimize for the -% most frequent case (positive step). +% most frequent case (positive step). And since when we're doing the +% test the step size is the result of \cs{@@_eval:w} we know that only +% the value $0$ has a leading token |0| which we can use for a faster +% test than \cs{int_compare:nNnTF}. % \begin{macrocode} \cs_new:Npn \int_step_function:nnnN #1#2#3 { - \exp_after:wN \@@_step:wwwN - \int_value:w \@@_eval:w #1 \exp_after:wN ; - \int_value:w \@@_eval:w #2 \exp_after:wN ; - \int_value:w \@@_eval:w #3 ; + \exp_after:wN \@@_step:w + \int_value:w \@@_eval:w #1 \exp_after:wN \@@_sep: + \int_value:w \@@_eval:w #2 \exp_after:wN \@@_sep: + \int_value:w \@@_eval:w #3 \@@_sep: } -\cs_new:Npn \@@_step:wwwN #1; #2; #3; #4 +\cs_new:Npn \@@_step:w #1 \@@_sep: #2 \@@_sep: #3 \@@_sep: #4 { \int_compare:nNnTF {#2} > \c_zero_int - { \@@_step:NwnnN > } + { \@@_step:Nw > } { - \int_compare:nNnTF {#2} = \c_zero_int + \if_meaning:w 0 #2 + \exp_after:wN \use_ii:nn + \fi: + \use_none:n { \msg_expandable_error:nnn { kernel } { zero-step } {#4} \prg_break: } - { \@@_step:NwnnN < } + \@@_step:Nw < } - #1 ; {#2} {#3} #4 + #1 \@@_sep: {#2} {#3} {#4} \prg_break_point: } -\cs_new:Npn \@@_step:NwnnN #1#2 ; #3#4#5 +\cs_new:Npn \@@_step:Nw #1#2 \@@_sep: #3#4#5 { \if_int_compare:w #2 #1 #4 \exp_stop_f: \prg_break:n \fi: #5 {#2} - \exp_after:wN \@@_step:NwnnN + \exp_after:wN \@@_step:Nw \exp_after:wN #1 - \int_value:w \@@_eval:w #2 + #3 ; {#3} {#4} #5 + \int_value:w \@@_eval:w #2 + #3 \@@_sep: {#3} {#4} {#5} } \cs_new:Npn \int_step_function:nN - { \int_step_function:nnnN { 1 } { 1 } } + { \int_step_function:nnnN \c_one_int \c_one_int } \cs_new:Npn \int_step_function:nnN #1 - { \int_step_function:nnnN {#1} { 1 } } + { \int_step_function:nnnN {#1} \c_one_int } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % +% \begin{macro} +% {\int_step_tokens:nn, \int_step_tokens:nnn, \int_step_tokens:nnnn} +% Because the internals \cs{@@_step:wwwn} and \cs{@@_step:Nwnnn} are +% defined in such a way that they work with both a single token or a +% braced group of tokens these are really the same as the |function| +% variants. +% \begin{macrocode} +\cs_new_eq:NN \int_step_tokens:nn \int_step_function:nN +\cs_new_eq:NN \int_step_tokens:nnn \int_step_function:nnN +\cs_new_eq:NN \int_step_tokens:nnnn \int_step_function:nnnN +% \end{macrocode} +% \end{macro} +% % \begin{macro}{\int_step_inline:nn, \int_step_inline:nnn, \int_step_inline:nnnn} % \begin{macro}{\int_step_variable:nNn, \int_step_variable:nnNn, \int_step_variable:nnnNn} % \UnitTested |