summaryrefslogtreecommitdiff
path: root/macros/latex/required/l3kernel/l3int.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/required/l3kernel/l3int.dtx')
-rw-r--r--macros/latex/required/l3kernel/l3int.dtx229
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