[latex3-commits] [git/LaTeX3-latex3-latex3] gh844: Implement \seq_put_item:Nnn(TF) (see #844) (374a07c4f)

Bruno Le Floch blflatex at gmail.com
Wed Apr 28 08:12:36 CEST 2021


Repository : https://github.com/latex3/latex3
On branch  : gh844
Link       : https://github.com/latex3/latex3/commit/374a07c4fa5c3c896fc9c1f314e19075773bdefe

>---------------------------------------------------------------

commit 374a07c4fa5c3c896fc9c1f314e19075773bdefe
Author: Bruno Le Floch <blflatex at gmail.com>
Date:   Tue Apr 27 23:31:53 2021 +0200

    Implement \seq_put_item:Nnn(TF) (see #844)


>---------------------------------------------------------------

374a07c4fa5c3c896fc9c1f314e19075773bdefe
 l3kernel/CHANGELOG.md           |   1 +
 l3kernel/l3candidates.dtx       | 135 ++++++++++++++++++++++++++++++++++++++++
 l3kernel/testfiles/m3seq005.lvt |  37 +++++++++++
 l3kernel/testfiles/m3seq005.tlg | 121 +++++++++++++++++++++++++++++++++++
 4 files changed, 294 insertions(+)

diff --git a/l3kernel/CHANGELOG.md b/l3kernel/CHANGELOG.md
index 5d399c474..0a219856d 100644
--- a/l3kernel/CHANGELOG.md
+++ b/l3kernel/CHANGELOG.md
@@ -12,6 +12,7 @@ this project uses date-based 'snapshot' version identifiers.
 - `\tracingstacklevels`
 - Color export in comma-separated format
 - `\ur{...}` escape in `l3regex` to compose regexes
+- `\seq_put_item:Nnn(TF)` to change an entry of a sequence
 
 ### Changed
 - Breaking change: use prevailing catcodes instead of string in
diff --git a/l3kernel/l3candidates.dtx b/l3kernel/l3candidates.dtx
index 165a4c70c..381f9779a 100644
--- a/l3kernel/l3candidates.dtx
+++ b/l3kernel/l3candidates.dtx
@@ -434,6 +434,24 @@
 %   mappings.
 % \end{function}
 %
+% \begin{function}[added = 2021-04-28, noTF]
+%   {\seq_put_item:Nnn, \seq_put_item:cnn, \seq_gput_item:Nnn, \seq_gput_item:cnn}
+%   \begin{syntax}
+%     \cs{seq_put_item:Nnn} \meta{seq~var} \Arg{intexpr} \Arg{item}
+%     \cs{seq_put_item:NnnTF} \meta{seq~var} \Arg{intexpr} \Arg{item} \Arg{true code} \Arg{false code}
+%   \end{syntax}
+%   Removes the item of \meta{sequence} at the position given by
+%   evaluating the \meta{integer expression} and replaces it by
+%   \meta{item}.  Items are indexed from $1$ on the left/top of the
+%   \meta{sequence}, or from $-1$ on the right/bottom.  If the
+%   \meta{integer expression} is zero or is larger (in absolute value)
+%   than the number of items in the sequence, the \meta{sequence} is not
+%   modified.  In these cases, \cs{seq_put_item:Nnn} raises an error
+%   while \cs{seq_put_item:NnnTF} runs the \meta{false code}.  In cases
+%   where the assignment was successful, \meta{true code} is run
+%   afterwards.
+% \end{function}
+%
 % \section{Additions to \pkg{l3sys}}
 %
 % \begin{variable}[added = 2018-05-02]{\c_sys_engine_version_str}
@@ -1126,6 +1144,123 @@
 %    \end{macrocode}
 % \end{macro}
 %
+%
+% \begin{macro}{\@@_int_eval:w}
+%   Useful to more quickly go through items.
+%    \begin{macrocode}
+\cs_new_eq:NN \@@_int_eval:w \tex_numexpr:D
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[noTF]{\seq_put_item:Nnn, \seq_put_item:cnn, \seq_gput_item:Nnn, \seq_gput_item:cnn}
+% \begin{macro}{\@@_put_item:NnnNN, \@@_put_item:nnNNNN, \@@_put_item_false:nnNNNN, \@@_put_item:nNnnNNNN}
+% \begin{macro}[rEXP]{\@@_put_item:wn, \@@_put_item_end:w}
+%   The conditionals are distinguished from the |Nnn| versions by the
+%   last argument \cs{use_ii:nn} vs \cs{use_i:nn}.
+%    \begin{macrocode}
+\cs_new_protected:Npn \seq_put_item:Nnn #1#2#3
+  { \@@_put_item:NnnNN #1 {#2} {#3} \__kernel_tl_set:Nx \use_i:nn }
+\cs_new_protected:Npn \seq_gput_item:Nnn #1#2#3
+  { \@@_put_item:NnnNN #1 {#2} {#3} \__kernel_tl_gset:Nx \use_i:nn }
+\cs_generate_variant:Nn \seq_put_item:Nnn { c }
+\cs_generate_variant:Nn \seq_gput_item:Nnn { c }
+\prg_new_protected_conditional:Npnn \seq_put_item:Nnn #1#2#3 { TF , T , F }
+  { \@@_put_item:NnnNN #1 {#2} {#3} \__kernel_tl_set:Nx \use_ii:nn }
+\prg_new_protected_conditional:Npnn \seq_gput_item:Nnn #1#2#3 { TF , T , F }
+  { \@@_put_item:NnnNN #1 {#2} {#3} \__kernel_tl_gset:Nx \use_ii:nn }
+\prg_generate_conditional_variant:Nnn \seq_put_item:Nnn { c } { TF , T , F }
+\prg_generate_conditional_variant:Nnn \seq_gput_item:Nnn { c } { TF , T , F }
+%    \end{macrocode}
+%   Save the item to be stored and evaluate the position and the sequence
+%   length only once.  Then depending on the sign of the position, check
+%   that it is not bigger than the length (in absolute value) nor zero.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_put_item:NnnNN #1#2#3
+  {
+    \tl_set:Nn \l_@@_internal_a_tl { \@@_item:n {#3} }
+    \exp_args:Nff \@@_put_item:nnNNNN
+      { \int_eval:n {#2} } { \seq_count:N #1 } #1 \use_none:nn
+  }
+\cs_new_protected:Npn \@@_put_item:nnNNNN #1#2
+  {
+    \int_compare:nNnTF {#1} > 0
+      { \int_compare:nNnF {#1} > {#2} { \@@_put_item:nNnnNNNN { #1 - 1 } } }
+      {
+        \int_compare:nNnF {#1} < {-#2}
+          {
+            \int_compare:nNnF {#1} = 0
+              { \@@_put_item:nNnnNNNN { #2 + #1 } }
+          }
+      }
+    \@@_put_item_false:nnNNNN {#1} {#2}
+  }
+%    \end{macrocode}
+%   If the position is not ok, \cs{@@_put_item_false:nnNNNN} calls an
+%   error or returns \texttt{false} (depending on the \cs{use_i:nn} vs
+%   \cs{use_ii:nn} argument mentioned above).
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_put_item_false:nnNNNN #1#2#3#4#5#6
+  {
+    #6
+      {
+        \__kernel_msg_error:nnxxx { seq } { item-too-large }
+          { \token_to_str:N #3 } {#2} {#1}
+      }
+      { \prg_return_false: }
+  }
+\__kernel_msg_new:nnnn { seq } { item-too-large }
+  { Sequence~'#1'~does~not~have~an~item~#3 }
+  {
+    An~attempt~was~made~to~push~or~pop~the~item~at~position~#3~
+    of~'#1',~but~this~
+    \int_compare:nTF { #3 = 0 }
+      { position~does~not~exist. }
+      { sequence~only~has~#2~item \int_compare:nF { #2 = 1 } {s}. }
+  }
+%    \end{macrocode}
+%   If the position is ok, \cs{@@_put_item:nNnnNNNN} makes the assignment
+%   and returns \texttt{true} (in the case of conditionnals).  Here |#1|
+%   is an integer expression (position minus one), it needs to be
+%   evaluated.  The sequence |#5| starts with \cs{s_@@} (even if empty),
+%   which stops the integer expression and is absorbed by it.  The
+%   \cs{if_meaning:w} test is slightly faster than an integer test (but
+%   only works when testing against zero, hence the offset we chose in
+%   the position).  When we are done skipping items, insert the saved
+%   item \cs{l_@@_internal_a_tl}.  For |put| functions the last argument
+%   of \cs{@@_put_item_end:w} is \cs{use_none:nn} and it absorbs the
+%   item |#2| that we are removing: this is only useful for the |pop|
+%   functions.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_put_item:nNnnNNNN #1#2#3#4#5#6#7#8
+  {
+    #7 #5
+      {
+        \s_@@
+        \exp_after:wN \@@_put_item:wn
+        \int_value:w \@@_int_eval:w #1
+        #5 \s_@@_stop #6
+      }
+    #8 { } { \prg_return_true: }
+  }
+\cs_new:Npn \@@_put_item:wn #1 \@@_item:n #2
+  {
+    \if_meaning:w 0 #1 \@@_put_item_end:w \fi:
+    \exp_not:n { \@@_item:n {#2} }
+    \exp_after:wN \@@_put_item:wn
+    \int_value:w \@@_int_eval:w #1 - 1 \s_@@
+  }
+\cs_new:Npn \@@_put_item_end:w #1 \exp_not:n #2 #3 \s_@@ #4 \s_@@_stop #5
+  {
+    #1
+    \exp_not:o \l_@@_internal_a_tl
+    \exp_not:n {#4}
+    #5 #2
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
 % \subsection{Additions to \pkg{l3sys}}
 %
 %    \begin{macrocode}
diff --git a/l3kernel/testfiles/m3seq005.lvt b/l3kernel/testfiles/m3seq005.lvt
index 1067e252a..35b93c065 100644
--- a/l3kernel/testfiles/m3seq005.lvt
+++ b/l3kernel/testfiles/m3seq005.lvt
@@ -53,4 +53,41 @@
   \test:f { \seq_item:Nn \l_foo_seq {-4} }
 }
 
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\TEST { seq_put_item:Nnn }
+  {
+    \seq_clear:N \l_tmpa_seq
+    \seq_put_item:Nnn \l_tmpa_seq { 0 } { a }
+    \seq_put_item:cnn { l_tmpa_seq } { 1 } { a }
+    \seq_put_item:Nnn \l_tmpa_seq { 1+2-4 } { a }
+    \seq_put_item:cnnTF { l_tmpa_seq } { 0 } { a } { \TRUE } { \FALSE }
+    \seq_put_item:NnnTF \l_tmpa_seq { 12+3-4 } { a } { \TRUE } { \FALSE }
+    \seq_put_item:cnnTF { l_tmpa_seq } { -11 } { a } { \TRUE } { \FALSE }
+    %
+    \SEPARATOR
+    \seq_put_right:Nn \l_tmpa_seq { \AAA }
+    \seq_put_item:cnn { l_tmpa_seq } { 0 } { a } \seq_show:N \l_tmpa_seq
+    \group_begin:
+      \seq_put_item:Nnn \l_tmpa_seq { 1 } { a } \seq_show:N \l_tmpa_seq
+      \seq_put_item:cnn { l_tmpa_seq } { 2 } { a } \seq_show:N \l_tmpa_seq
+      \seq_put_item:Nnn \l_tmpa_seq { 1+2-4 } { \xy } \seq_show:N \l_tmpa_seq
+    \group_end:
+    \seq_put_item:cnnTF { l_tmpa_seq } { 0 } { # } { \TRUE } { \FALSE } \seq_show:N \l_tmpa_seq
+    \seq_put_item:NnnTF \l_tmpa_seq { 2+3-4 } { { \aa } } { \TRUE } { \FALSE } \seq_show:N \l_tmpa_seq
+    \seq_put_item:cnnTF { l_tmpa_seq } { -1 } { } { \TRUE } { \FALSE } \seq_show:N \l_tmpa_seq
+    %
+    \SEPARATOR
+    \seq_gset_split:Nnn \g_tmpa_seq { } { { \AAA } { \B\B } { { } } { # } }
+    \seq_gput_item:cnn { g_tmpa_seq } { 0 } { a } \seq_show:N \g_tmpa_seq
+    \seq_gput_item:Nnn \g_tmpa_seq { 1 } { \aaa } \seq_show:N \g_tmpa_seq
+    \group_begin:
+      \seq_gput_item:cnn { g_tmpa_seq } { 1+2-5 } { \ccc } \seq_show:N \g_tmpa_seq
+      \seq_gput_item:NnnTF \g_tmpa_seq { 0 } { a } { \TRUE } { \FALSE } \seq_show:N \g_tmpa_seq
+      \seq_gput_item:cnnTF { g_tmpa_seq } { -1 } { #\par } { \TRUE } { \FALSE } \seq_show:N \g_tmpa_seq
+    \group_end:
+    \seq_gput_item:NnnTF \g_tmpa_seq { 5 } { #\par } { \TRUE } { \FALSE } \seq_show:N \g_tmpa_seq
+  }
+
 \END
diff --git a/l3kernel/testfiles/m3seq005.tlg b/l3kernel/testfiles/m3seq005.tlg
index 04414d7e1..a6f025ae5 100644
--- a/l3kernel/testfiles/m3seq005.tlg
+++ b/l3kernel/testfiles/m3seq005.tlg
@@ -23,3 +23,124 @@ TEST 2: seq_item:Nn
 |\scan_stop: |
 ||
 ============================================================
+============================================================
+TEST 3: seq_put_item:Nnn
+============================================================
+! LaTeX3 Error: Sequence '\l_tmpa_seq' does not have an item 0
+For immediate help type H <return>.
+ ...                                              
+l. ...  }
+An attempt was made to push or pop the item at position 0 of '\l_tmpa_seq',
+but this position does not exist.
+! LaTeX3 Error: Sequence '\l_tmpa_seq' does not have an item 1
+For immediate help type H <return>.
+ ...                                              
+l. ...  }
+An attempt was made to push or pop the item at position 1 of '\l_tmpa_seq',
+but this sequence only has 0 items.
+! LaTeX3 Error: Sequence '\l_tmpa_seq' does not have an item -1
+For immediate help type H <return>.
+ ...                                              
+l. ...  }
+An attempt was made to push or pop the item at position -1 of '\l_tmpa_seq',
+but this sequence only has 0 items.
+FALSE
+FALSE
+FALSE
+============================================================
+! LaTeX3 Error: Sequence '\l_tmpa_seq' does not have an item 0
+For immediate help type H <return>.
+ ...                                              
+l. ...  }
+An attempt was made to push or pop the item at position 0 of '\l_tmpa_seq',
+but this position does not exist.
+The sequence \l_tmpa_seq contains the items (without outer braces):
+>  {\AAA }.
+<recently read> }
+l. ...  }
+The sequence \l_tmpa_seq contains the items (without outer braces):
+>  {a}.
+<recently read> }
+l. ...  }
+! LaTeX3 Error: Sequence '\l_tmpa_seq' does not have an item 2
+For immediate help type H <return>.
+ ...                                              
+l. ...  }
+An attempt was made to push or pop the item at position 2 of '\l_tmpa_seq',
+but this sequence only has 1 item.
+The sequence \l_tmpa_seq contains the items (without outer braces):
+>  {a}.
+<recently read> }
+l. ...  }
+The sequence \l_tmpa_seq contains the items (without outer braces):
+>  {\xy }.
+<recently read> }
+l. ...  }
+FALSE
+The sequence \l_tmpa_seq contains the items (without outer braces):
+>  {\AAA }.
+<recently read> }
+l. ...  }
+TRUE
+The sequence \l_tmpa_seq contains the items (without outer braces):
+>  {{\aa }}.
+<recently read> }
+l. ...  }
+TRUE
+The sequence \l_tmpa_seq contains the items (without outer braces):
+>  {}.
+<recently read> }
+l. ...  }
+============================================================
+! LaTeX3 Error: Sequence '\g_tmpa_seq' does not have an item 0
+For immediate help type H <return>.
+ ...                                              
+l. ...  }
+An attempt was made to push or pop the item at position 0 of '\g_tmpa_seq',
+but this position does not exist.
+The sequence \g_tmpa_seq contains the items (without outer braces):
+>  {\AAA }
+>  {\B \B }
+>  {{}}
+>  {##}.
+<recently read> }
+l. ...  }
+The sequence \g_tmpa_seq contains the items (without outer braces):
+>  {\aaa }
+>  {\B \B }
+>  {{}}
+>  {##}.
+<recently read> }
+l. ...  }
+The sequence \g_tmpa_seq contains the items (without outer braces):
+>  {\aaa }
+>  {\B \B }
+>  {\ccc }
+>  {##}.
+<recently read> }
+l. ...  }
+FALSE
+The sequence \g_tmpa_seq contains the items (without outer braces):
+>  {\aaa }
+>  {\B \B }
+>  {\ccc }
+>  {##}.
+<recently read> }
+l. ...  }
+TRUE
+The sequence \g_tmpa_seq contains the items (without outer braces):
+>  {\aaa }
+>  {\B \B }
+>  {\ccc }
+>  {##\par }.
+<recently read> }
+l. ...  }
+FALSE
+The sequence \g_tmpa_seq contains the items (without outer braces):
+>  {\aaa }
+>  {\B \B }
+>  {\ccc }
+>  {##\par }.
+<recently read> }
+l. ...  }
+============================================================





More information about the latex3-commits mailing list.