% \iffalse meta-comment % %% File: l3seq.dtx Copyright (C) 1990-2011 The LaTeX3 Project %% %% It 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 file is part of the "expl3 bundle" (The Work in LPPL) %% and all files in that bundle must be distributed together. %% %% The released version of this bundle is available from CTAN. %% %% ----------------------------------------------------------------------- %% %% The development version of the bundle can be found at %% %% http://www.latex-project.org/svnroot/experimental/trunk/ %% %% for those people who are interested. %% %%%%%%%%%%% %% NOTE: %% %%%%%%%%%%% %% %% Snapshots taken from the repository represent work in progress and may %% not work or may contain conflicting material! We therefore ask %% people _not_ to put them into distributions, archives, etc. without %% prior consultation with the LaTeX3 Project. %% %% ----------------------------------------------------------------------- % %<*driver|package> \RequirePackage{l3names} \GetIdInfo$Id: l3seq.dtx 2665 2011-08-25 22:15:27Z joseph $ {L3 Experimental sequences and stacks} % %<*driver> \documentclass[full]{l3doc} \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % % \title{^^A % The \pkg{l3seq} package\\ Sequences and stacks^^A % \thanks{This file describes v\ExplFileVersion, % last revised \ExplFileDate.}^^A % } % % \author{^^A % The \LaTeX3 Project\thanks % {^^A % E-mail: % \href{mailto:latex-team@latex-project.org} % {latex-team@latex-project.org}^^A % }^^A % } % % \date{Released \ExplFileDate} % % \maketitle % % \begin{documentation} % % \LaTeX3 implements a \enquote{sequence} data type, which contain % an ordered list of entries which may contain any \meta{balanced text}. % It is possible to map functions to sequences such that the function % is applied to every item in the sequence. % % Sequences are also used to implement stack functions in \LaTeX3. This % is achieved using a number of dedicated stack functions. % % \section{Creating and initialising sequences} % % \begin{function}{\seq_new:N, \seq_new:c} % \begin{syntax} % \cs{seq_new:N} \meta{sequence} % \end{syntax} % Creates a new \meta{sequence} or raises an error if the name is % already taken. The declaration is global. The \meta{sequence} will % initially contain no items. % \end{function} % % \begin{function}{\seq_clear:N, \seq_clear:c} % \begin{syntax} % \cs{seq_clear:N} \meta{sequence} % \end{syntax} % Clears all items from the \meta{sequence} within the scope of % the current \TeX{} group. % \end{function} % % \begin{function}{\seq_gclear:N, \seq_gclear:c} % \begin{syntax} % \cs{seq_gclear:N} \meta{sequence} % \end{syntax} % Clears all entries from the \meta{sequence} globally. % \end{function} % % \begin{function}{\seq_clear_new:N, \seq_clear_new:c} % \begin{syntax} % \cs{seq_clear_new:N} \meta{sequence} % \end{syntax} % If the \meta{sequence} already exists, clears it within the scope % of the current \TeX{} group. If the \meta{sequence} is not defined, % it will be created (using \cs{seq_new:N}). Thus the sequence is % guaranteed to be available and clear within the current \TeX{} % group. The \meta{sequence} will exist globally, but the content % outside of the current \TeX{} group is not specified. % \end{function} % % \begin{function}{\seq_gclear_new:N, \seq_gclear_new:c} % \begin{syntax} % \cs{seq_gclear_new:N} \meta{sequence} % \end{syntax} % If the \meta{sequence} already exists, clears it globally. If the % \meta{sequence} is not defined, it will be created (using % \cs{seq_new:N}). Thus the sequence is guaranteed to be available % and globally clear. % \end{function} % % \begin{function} % {\seq_set_eq:NN, \seq_set_eq:cN, \seq_set_eq:Nc, \seq_set_eq:cc} % \begin{syntax} % \cs{seq_set_eq:NN} \meta{sequence1} \meta{sequence2} % \end{syntax} % Sets the content of \meta{sequence1} equal to that of % \meta{sequence2}. This assignment is restricted to the current % \TeX{} group level. % \end{function} % % \begin{function} % {\seq_gset_eq:NN, \seq_gset_eq:cN, \seq_gset_eq:Nc, \seq_gset_eq:cc} % \begin{syntax} % \cs{seq_gset_eq:NN} \meta{sequence1} \meta{sequence2} % \end{syntax} % Sets the content of \meta{sequence1} equal to that of % \meta{sequence2}. This assignment is global and so is not % limited by the current \TeX{} group level. % \end{function} % % \begin{function}{\seq_concat:NNN, \seq_concat:ccc} % \begin{syntax} % \cs{seq_concat:NNN} \meta{sequence1} \meta{sequence2} \meta{sequence3} % \end{syntax} % Concatenates the content of \meta{sequence2} and \meta{sequence3} % together and saves the result in \meta{sequence1}. The items in % \meta{sequence2} will be placed at the left side of the new sequence. % This operation is local to the current \TeX{} group and will % remove any existing content in \meta{sequence1}. % \end{function} % % \begin{function}{\seq_gconcat:NNN, \seq_gconcat:ccc} % \begin{syntax} % \cs{seq_gconcat:NNN} \meta{sequence1} \meta{sequence2} \meta{sequence3} % \end{syntax} % Concatenates the content of \meta{sequence2} and \meta{sequence3} % together and saves the result in \meta{sequence1}. The items in % \meta{sequence2} will be placed at the left side of the new sequence. % This operation is global and will remove any existing content in % \meta{sequence1}. % \end{function} % % \section{Appending data to sequences} % % \begin{function}{ % \seq_put_left:Nn, \seq_put_left:NV, \seq_put_left:Nv, % \seq_put_left:No, \seq_put_left:Nx, % \seq_put_left:cn, \seq_put_left:cV, \seq_put_left:cv, % \seq_put_left:co, \seq_put_left:cx % } % \begin{syntax} % \cs{seq_put_left:Nn} \meta{sequence} \Arg{item} % \end{syntax} % Appends the \meta{item} to the left of the \meta{sequence}. % The assignment is restricted to the current \TeX{} group. % \end{function} % % \begin{function}{ % \seq_gput_left:Nn, \seq_gput_left:NV, \seq_gput_left:Nv, % \seq_gput_left:No, \seq_gput_left:Nx, % \seq_gput_left:cn, \seq_gput_left:cV, \seq_gput_left:cv, % \seq_gput_left:co, \seq_gput_left:cx % } % \begin{syntax} % \cs{seq_gput_left:Nn} \meta{sequence} \Arg{item} % \end{syntax} % Appends the \meta{item} to the left of the \meta{sequence}. % The assignment is global. % \end{function} % % \begin{function}{ % \seq_put_right:Nn, \seq_put_right:NV, \seq_put_right:Nv, % \seq_put_right:No, \seq_put_right:Nx, % \seq_put_right:cn, \seq_put_right:cV, \seq_put_right:cv, % \seq_put_right:co, \seq_put_right:cx % } % \begin{syntax} % \cs{seq_put_right:Nn} \meta{sequence} \Arg{item} % \end{syntax} % Appends the \meta{item} to the right of the \meta{sequence}. % The assignment is restricted to the current \TeX{} group. % \end{function} % % \begin{function}{ % \seq_gput_right:Nn, \seq_gput_right:NV, \seq_gput_right:Nv, % \seq_gput_right:No, \seq_gput_right:Nx, % \seq_gput_right:cn, \seq_gput_right:cV, \seq_gput_right:cv, % \seq_gput_right:co, \seq_gput_right:cx % } % \begin{syntax} % \cs{seq_gput_right:Nn} \meta{sequence} \Arg{item} % \end{syntax} % Appends the \meta{item} to the right of the \meta{sequence}. % The assignment is global. % \end{function} % % \section{Recovering items from sequences} % % Items can be recovered from either the left or the right of sequences. % For implementation reasons, the actions at the left of the sequence are % faster than those acting on the right. These functions all assign the % recovered material locally, \emph{i.e.}~setting the % \meta{token list variable} used with \cs{tl_set:Nn} and \emph{never} % \cs{tl_gset:Nn}. % % \begin{function}{\seq_get_left:NN, \seq_get_left:cN} % \begin{syntax} % \cs{seq_get_left:NN} \meta{sequence} \meta{token list variable} % \end{syntax} % Stores the left-most item from a \meta{sequence} in the % \meta{token list variable} without removing it from the % \meta{sequence}. The \meta{token list variable} is assigned locally. % If \meta{sequence} is empty an error will be raised. % \end{function} % % \begin{function}{\seq_get_right:NN, \seq_get_right:cN} % \begin{syntax} % \cs{seq_get_right:NN} \meta{sequence} \meta{token list variable} % \end{syntax} % Stores the right-most item from a \meta{sequence} in the % \meta{token list variable} without removing it from the % \meta{sequence}. The \meta{token list variable} is assigned locally. % If \meta{sequence} is empty an error will be raised. % \end{function} % % \begin{function}{\seq_pop_left:NN, \seq_pop_left:cN} % \begin{syntax} % \cs{seq_pop_left:NN} \meta{sequence} \meta{token list variable} % \end{syntax} % Pops the left-most item from a \meta{sequence} into the % \meta{token list variable}, \emph{i.e.}~removes the item from the % sequence and stores it in the \meta{token list variable}. % Both of the variables are assigned locally. If \meta{sequence} is % empty an error will be raised. % \end{function} % % \begin{function}{\seq_gpop_left:NN, \seq_gpop_left:cN} % \begin{syntax} % \cs{seq_gpop_left:NN} \meta{sequence} \meta{token list variable} % \end{syntax} % Pops the left-most item from a \meta{sequence} into the % \meta{token list variable}, \emph{i.e.}~removes the item from the % sequence and stores it in the \meta{token list variable}. % The \meta{sequence} is modified globally, while the assignment of % the \meta{token list variable} is local. % If \meta{sequence} is empty an error will be raised. % \end{function} % % \begin{function}{\seq_pop_right:NN, \seq_pop_right:cN} % \begin{syntax} % \cs{seq_pop_right:NN} \meta{sequence} \meta{token list variable} % \end{syntax} % Pops the right-most item from a \meta{sequence} into the % \meta{token list variable}, \emph{i.e.}~removes the item from the % sequence and stores it in in the \meta{token list variable}. % Both of the variables are assigned locally. If \meta{sequence} is % empty an error will be raised. % \end{function} % % \begin{function}{\seq_gpop_right:NN, \seq_gpop_right:cN} % \begin{syntax} % \cs{seq_gpop_right:NN} \meta{sequence} \meta{token list variable} % \end{syntax} % Pops the right-most item from a \meta{sequence} into the % \meta{token list variable}, \emph{i.e.}~removes the item from the % sequence and stores it in the \meta{token list variable}. % The \meta{sequence} is modified globally, while the assignment of % the \meta{token list variable} is local. % If \meta{sequence} is empty an error will be raised. % \end{function} % % \section{Modifying sequences} % % While sequences are normally used as ordered lists, it may be % necessary to modify the content. The functions here may be used % to update sequences, while retaining the order of the unaffected % entries. % % \begin{function}{\seq_remove_duplicates:N, \seq_remove_duplicates:c} % \begin{syntax} % \cs{seq_remove_duplicates:N} \meta{sequence} % \end{syntax} % Removes duplicate items from the \meta{sequence}, leaving the % left most copy of each item in the \meta{sequence}. The \meta{item} % comparison takes place on a token basis, as for \cs{tl_if_eq:nn(TF)}. % The removal is local to the current \TeX{} group. % \begin{texnote} % This function iterates through every item in the \meta{sequence} and % does a comparison with the \meta{items} already checked. It is therefore % relatively slow with large sequences. % \end{texnote} % \end{function} % % \begin{function}{\seq_gremove_duplicates:N, \seq_gremove_duplicates:c} % \begin{syntax} % \cs{seq_gremove_duplicates:N} \meta{sequence} % \end{syntax} % Removes duplicate items from the \meta{sequence}, leaving the % left most copy of each item in the \meta{sequence}. The \meta{item} % comparison takes place on a token basis, as for \cs{tl_if_eq:nn(TF)}. % The removal is applied globally. % \begin{texnote} % This function iterates through every item in the \meta{sequence} and % does a comparison with the \meta{items} already checked. It is therefore % relatively slow with large sequences. % \end{texnote} % \end{function} % % \begin{function}{\seq_remove_all:Nn, \seq_remove_all:cn} % \begin{syntax} % \cs{seq_remove_all:Nn} \meta{sequence} \Arg{item} % \end{syntax} % Removes every occurrence of \meta{item} from the \meta{sequence}. % The \meta{item} comparison takes place on a token basis, as for % \cs{tl_if_eq:nn(TF)}. The removal is local to the current \TeX{} group. % \end{function} % % \begin{function}{\seq_gremove_all:Nn, \seq_gremove_all:cn} % \begin{syntax} % \cs{seq_gremove_all:Nn} \meta{sequence} \Arg{item} % \end{syntax} % Removes each occurrence of \meta{item} from the \meta{sequence}. % The \meta{item} comparison takes place on a token basis, as for % \cs{tl_if_eq:nn(TF)}. The removal is applied globally. % \end{function} % % \section{Sequence conditionals} % % \begin{function}[EXP,pTF]{\seq_if_empty:N, \seq_if_empty:c} % \begin{syntax} % \cs{seq_if_empty_p:N} \meta{sequence} % \cs{seq_if_empty:NTF} \meta{sequence} \Arg{true code} \Arg{false code} % \end{syntax} % Tests if the \meta{sequence} is empty (containing no items). % \end{function} % % \begin{function}[TF]{ % \seq_if_in:Nn, \seq_if_in:NV, \seq_if_in:Nv, \seq_if_in:No, \seq_if_in:Nx, % \seq_if_in:cn, \seq_if_in:cV, \seq_if_in:cv, \seq_if_in:co, \seq_if_in:cx % } % \begin{syntax} % \cs{seq_if_in:NnTF} \meta{sequence} \Arg{item} % ~~\Arg{true code} \Arg{false code} % \end{syntax} % Tests if the \meta{item} is present in the \meta{sequence}. % \end{function} % % \section{Mapping to sequences} % % \begin{function}[EXP]{\seq_map_function:NN, \seq_map_function:cN} % \begin{syntax} % \cs{seq_map_function:NN} \meta{sequence} \meta{function} % \end{syntax} % Applies \meta{function} to every \meta{item} stored in the % \meta{sequence}. The \meta{function} will receive one argument for % each iteration. The \meta{items} are returned from left to right. % The function \cs{seq_map_inline:Nn} is in general more efficient % than \cs{seq_map_function:NN}. % One mapping may be nested inside another. % \end{function} % % \begin{function}{\seq_map_inline:Nn, \seq_map_inline:cn} % \begin{syntax} % \cs{seq_map_inline:Nn} \meta{sequence} \Arg{inline function} % \end{syntax} % Applies \meta{inline function} to every \meta{item} stored % within the \meta{sequence}. The \meta{inline function} should % consist of code which will receive the \meta{item} as |#1|. % One in line mapping can be nested inside another. The \meta{items} % are returned from left to right. % \end{function} % % \begin{function}{ % \seq_map_variable:NNn, \seq_map_variable:Ncn, % \seq_map_variable:cNn, \seq_map_variable:ccn % } % \begin{syntax} % \cs{seq_map_variable:NNn} \meta{sequence} % ~~\meta{tl~var.} \Arg{function using tl~var.} % \end{syntax} % Stores each entry in the \meta{sequence} in turn in the % \meta{tl~var.}\ and applies the \meta{function using tl~var.} % The \meta{function} will usually consist of code making use of % the \meta{tl~var.}, but this is not enforced. One variable % mapping can be nested inside another. The \meta{items} % are returned from left to right. % \end{function} % % \begin{function}[EXP]{\seq_map_break:} % \begin{syntax} % \cs{seq_map_break:} % \end{syntax} % Used to terminate a \cs{seq_map_\ldots} function before all % entries in the \meta{sequence} have been processed. This will % normally take place within a conditional statement, for example % \begin{verbatim} % \seq_map_inline:Nn \l_my_seq % { % \str_if_eq:nnTF { #1 } { bingo } % { \seq_map_break: } % { % % Do something useful % } % } % \end{verbatim} % Use outside of a \cs{seq_map_\ldots} scenario will lead to low % level \TeX{} errors. % \begin{texnote} % When the mapping is broken, additional tokens may be inserted by the % internal macro \cs{seq_break_point:n} before further items are taken % from the input stream. This will depend on the design of the mapping % function. % \end{texnote} % \end{function} % % \begin{function}[EXP]{\seq_map_break:n} % \begin{syntax} % \cs{seq_map_break:n} \Arg{tokens} % \end{syntax} % Used to terminate a \cs{seq_map_\ldots} function before all % entries in the \meta{sequence} have been processed, inserting % the \meta{tokens} after the mapping has ended. This will % normally take place within a conditional statement, for example % \begin{verbatim} % \seq_map_inline:Nn \l_my_seq % { % \str_if_eq:nnTF { #1 } { bingo } % { \seq_map_break:n { } } % { % % Do something useful % } % } % \end{verbatim} % Use outside of a \cs{seq_map_\ldots} scenario will lead to low % level \TeX{} errors. % \begin{texnote} % When the mapping is broken, additional tokens may be inserted by the % internal macro \cs{seq_break_point:n} before the \meta{tokens} are % inserted into the input stream. % This will depend on the design of the mapping function. % \end{texnote} % \end{function} % % \section{Sequences as stacks} % % Sequences can be used as stacks, where data is pushed to and popped % from the top of the sequence. (The left of a sequence is the top, for % performance reasons.) The stack functions for sequences are not % intended to be mixed with the general ordered data functions detailed % in the previous section: a sequence should either be used as an % ordered data type or as a stack, but not in both ways. % % \begin{function}{\seq_get:NN, \seq_get:cN} % \begin{syntax} % \cs{seq_get:NN} \meta{sequence} \meta{token list variable} % \end{syntax} % Reads the top item from a \meta{sequence} into the % \meta{token list variable} without removing it from the % \meta{sequence}. The \meta{token list variable} is assigned locally. % If \meta{sequence} is empty an error will be raised. % \end{function} % % \begin{function}{\seq_pop:NN, \seq_pop:cN} % \begin{syntax} % \cs{seq_pop:NN} \meta{sequence} \meta{token list variable} % \end{syntax} % Pops the top item from a \meta{sequence} into the % \meta{token list variable}. Both of the variables are assigned % locally. If \meta{sequence} is empty an error will be raised. % \end{function} % % \begin{function}{\seq_gpop:NN, \seq_gpop:cN} % \begin{syntax} % \cs{seq_gpop:NN} \meta{sequence} \meta{token list variable} % \end{syntax} % Pops the top item from a \meta{sequence} into the % \meta{token list variable}. The \meta{sequence} is modified globally, % while the \meta{token list variable} is assigned locally. If % \meta{sequence} is empty an error will be raised. % \end{function} % % \begin{function} % { % \seq_push:Nn, \seq_push:NV, \seq_push:Nv, \seq_push:No, \seq_push:Nx, % seq_push:cn, \seq_push:cV, \seq_push:cv, \seq_push:co, \seq_push:cx % } % \begin{syntax} % \cs{seq_push:Nn} \meta{sequence} \Arg{item} % \end{syntax} % Adds the \Arg{item} to the top of the \meta{sequence}. % The assignment is restricted to the current \TeX{} group. % \end{function} % % \begin{function} % { % \seq_gpush:Nn, \seq_gpush:NV, \seq_gpush:Nv, % \seq_gpush:No, \seq_gpush:Nx, % \seq_gpush:cn, \seq_gpush:cV, \seq_gpush:cv, % \seq_gpush:co, \seq_gpush:cx % } % \begin{syntax} % \cs{seq_gpush:Nn} \meta{sequence} \Arg{item} % \end{syntax} % Pushes the \meta{item} onto the end of the top of the % \meta{sequence}. The assignment is global. % \end{function} % % \section{Viewing sequences} % % \begin{function}{\seq_show:N, \seq_show:c} % \begin{syntax} % \cs{seq_show:N} \meta{sequence} % \end{syntax} % Displays the entries in the \meta{sequence} in the terminal. % \end{function} % % \section{Experimental sequence functions} % % This section contains functions which may or may not be retained, depending % on how useful they are found to be. % % \begin{function}[TF]{\seq_get_left:NN, \seq_get_left:cN} % \begin{syntax} % \cs{seq_get_left:NNTF} \meta{sequence} \meta{token list variable} % ~~\Arg{true code} \Arg{false code} % \end{syntax} % If the \meta{sequence} is empty, leaves the \meta{false code} in the % input stream and leaves the \meta{token list variable} unchanged. If the % \meta{sequence} is non-empty, stores the left-most item from a % \meta{sequence} % in the \meta{token list variable} without removing it from a % \meta{sequence}. % The \meta{token list variable} is assigned locally. % \end{function} % % \begin{function}[TF]{\seq_get_right:NN, \seq_get_right:cN} % \begin{syntax} % \cs{seq_get_right:NNTF} \meta{sequence} \meta{token list variable} % ~~\Arg{true code} \Arg{false code} % \end{syntax} % If the \meta{sequence} is empty, leaves the \meta{false code} in the % input stream and leaves the \meta{token list variable} unchanged. If the % \meta{sequence} is non-empty, stores the right-most item from a % \meta{sequence} % in the \meta{token list variable} without removing it from a % \meta{sequence}. % The \meta{token list variable} is assigned locally. % \end{function} % % \begin{function}[TF]{\seq_pop_left:NN, \seq_pop_left:cN} % \begin{syntax} % \cs{seq_pop_left:NNTF} \meta{sequence} \meta{token list variable} % ~~\Arg{true code} \Arg{false code} % \end{syntax} % If the \meta{sequence} is empty, leaves the \meta{false code} in the % input stream and leaves the \meta{token list variable} unchanged. If the % \meta{sequence} is non-empty, pops the left-most item from a % \meta{sequence} % in the \meta{token list variable}, \emph{i.e.}~removes the item from a % \meta{sequence}. % Both the \meta{sequence} and the \meta{token list variable} are assigned % locally. % \end{function} % % \begin{function}[TF]{\seq_gpop_left:NN, \seq_gpop_left:cN} % \begin{syntax} % \cs{seq_gpop_left:NNTF} \meta{sequence} \meta{token list variable} % ~~\Arg{true code} \Arg{false code} % \end{syntax} % If the \meta{sequence} is empty, leaves the \meta{false code} in the % input stream and leaves the \meta{token list variable} unchanged. If the % \meta{sequence} is non-empty, pops the left-most item from a \meta{sequence} % in the \meta{token list variable}, \emph{i.e.}~removes the item from a % \meta{sequence}. % The \meta{sequence} is modified globally, while the \meta{token list variable} % is assigned locally. % \end{function} % % \begin{function}[TF]{\seq_pop_right:NN, \seq_pop_right:cN} % \begin{syntax} % \cs{seq_pop_right:NNTF} \meta{sequence} \meta{token list variable} % ~~\Arg{true code} \Arg{false code} % \end{syntax} % If the \meta{sequence} is empty, leaves the \meta{false code} in the % input stream and leaves the \meta{token list variable} unchanged. If the % \meta{sequence} is non-empty, pops the right-most item from a \meta{sequence} % in the \meta{token list variable}, \emph{i.e.}~removes the item from a % \meta{sequence}. % Both the \meta{sequence} and the \meta{token list variable} are assigned % locally. % \end{function} % % \begin{function}[TF]{\seq_gpop_right:NN, \seq_gpop_right:cN} % \begin{syntax} % \cs{seq_gpop_right:NNTF} \meta{sequence} \meta{token list variable} % ~~\Arg{true code} \Arg{false code} % \end{syntax} % If the \meta{sequence} is empty, leaves the \meta{false code} in the % input stream and leaves the \meta{token list variable} unchanged. If the % \meta{sequence} is non-empty, pops the right-most item from a \meta{sequence} % in the \meta{token list variable}, \emph{i.e.}~removes the item from a % \meta{sequence}. % The \meta{sequence} is modified globally, while the \meta{token list variable} % is assigned locally. % \end{function} % % \begin{function}[EXP]{\seq_length:N, \seq_length:c} % \begin{syntax} % \cs{seq_length:N} \meta{sequence} % \end{syntax} % Leaves the number of items in the \meta{sequence} in the input % stream as an \meta{integer denotation}. The total number of items % in a \meta{sequence} will include those which are empty and duplicates, % \emph{i.e.}~every item in a \meta{sequence} is unique. % \end{function} % % \begin{function}[EXP]{\seq_item:Nn, \seq_item:cn} % \begin{syntax} % \cs{seq_item:Nn} \meta{sequence} \Arg{integer expression} % \end{syntax} % Indexing items in the \meta{sequence} from $0$ at the top (left), this % function will evaluate the \meta{integer expression} and leave the % appropriate item from the sequence in the input stream. If the % \meta{integer expression} is negative, indexing occurs from the % bottom (right) of the sequence. When the \meta{integer expression} % is larger than the number of items in the \meta{sequence} (as % calculated by \cs{seq_length:N}) then the function will expand to % nothing. % \end{function} % % \begin{function}[EXP]{\seq_use:N, \seq_use:c} % \begin{syntax} % \cs{seq_use:N} \meta{sequence} % \end{syntax} % Places each \meta{item} in the \meta{sequence} in turn in the input stream. % This occurs in an expandable fashion, and is implemented as a mapping. % This means that the process may be prematurely terminated using % \cs{seq_map_break:} or \cs{seq_map_break:n}. The \meta{items} in the % \meta{sequence} will be used from left (top) to right (bottom). % \end{function} % % \begin{function}[EXP] % { % \seq_mapthread_function:NNN, \seq_mapthread_function:NcN, % \seq_mapthread_function:cNN, \seq_mapthread_function:ccN % } % \begin{syntax} % \cs{seq_mapthread_function:NNN} \meta{seq1} \meta{seq2} \meta{function} % \end{syntax} % Applies \meta{function} to every pair of items % \meta{seq1-item}--\meta{seq2-item} from the two sequences, returning % items from both sequences from left to right. The \meta{function} will % receive two \texttt{n}-type arguments for each iteration. The mapping % will terminate when % the end of either sequence is reached (\emph{i.e.}~whichever sequence has % fewer items determines how many iterations % occur). % \end{function} % % \begin{function} % { % \seq_set_from_clist:NN, \seq_set_from_clist:cN, % \seq_set_from_clist:Nc, \seq_set_from_clist:cc, % \seq_set_from_clist:Nn, \seq_set_from_clist:cn % } % \begin{syntax} % \cs{seq_set_from_clist:NN} \meta{sequence} \meta{comma-list} % \end{syntax} % Sets the \meta{sequence} within the current \TeX{} group to be equal % to the content of the \meta{comma-list}. % \end{function} % % \begin{function} % { % \seq_gset_from_clist:NN, \seq_gset_from_clist:cN, % \seq_gset_from_clist:Nc, \seq_gset_from_clist:cc, % \seq_gset_from_clist:Nn, \seq_gset_from_clist:cn % } % \begin{syntax} % \cs{seq_gset_from_clist:NN} \meta{sequence} \meta{comma-list} % \end{syntax} % Sets the \meta{sequence} globally to equal to the content of the % \meta{comma-list}. % \end{function} % % \begin{function}{\seq_set_reverse:N,\seq_gset_reverse:N} % \begin{syntax} % \cs{seq_set_reverse:N} \meta{sequence} % \end{syntax} % Reverses the order of items in the \meta{sequence}, and % assigns the result to \meta{sequence}, locally or globally % according to the variant chosen. % \end{function} % % \begin{function} % {\seq_set_split:Nnn,\seq_gset_split:Nnn} % \begin{syntax} % \cs{seq_set_split:Nnn} \meta{sequence} % ~~\Arg{delimiter} \Arg{token list} % \end{syntax} % This function splits the \meta{token list} into \meta{items} % separated by \meta{delimiter}, ignoring all explicit space % characters from both sides of each \meta{item}, then removing % one set of outer braces if any. The result is assigned to % \meta{sequence}, locally or globally according to the function % chosen. The \meta{delimiter} may not contain |{|, |}| or |#| % (assuming \TeX{}'s normal category code r\'egime). % \end{function} % % \section{Internal sequence functions} % % \begin{function}{\seq_if_empty_err_break:N} % \begin{syntax} % \cs{seq_if_empty_err_break:N} \meta{sequence} % \end{syntax} % Tests if the \meta{sequence} is empty, and if so issues an error % message before skipping over any tokens up to \cs{seq_break_point:n}. % This function is used to avoid more serious errors which would % otherwise occur if some internal functions were applied to an % empty \meta{sequence}. % \end{function} % % \begin{function}[EXP]{\seq_item:n} % \begin{syntax} % \cs{seq_item:n} \meta{item} % \end{syntax} % The internal token used to begin each sequence entry. If expanded % outside of a mapping or manipulation function, an error will be % raised. The definition should always be set globally. % \end{function} % % \begin{function}{\seq_push_item_def:n, \seq_push_item_def:x} % \begin{syntax} % \cs{seq_push_item_def:n} \Arg{code} % \end{syntax} % Saves the definition of \cs{seq_item:n} and redefines it to % accept one parameter and expand to \meta{code}. This function % should always be balanced by use of \cs{seq_pop_item_def:}. % \end{function} % % \begin{function}{\seq_pop_item_def:} % \begin{syntax} % \cs{seq_pop_item_def:} % \end{syntax} % Restores the definition of \cs{seq_item:n} most recently saved by % \cs{seq_push_item_def:n}. This function should always be used in % a balanced pair with \cs{seq_push_item_def:n}. % \end{function} % % \begin{function}[EXP]{\seq_break:} % \begin{syntax} % \cs{seq_break:} % \end{syntax} % Used to terminate sequence functions by gobbling all tokens % up to \cs{seq_break_point:n}. This function is a copy of % \cs{seq_map_break:}, but is used in situations which are % not mappings. % \end{function} % % \begin{function}[EXP]{\seq_break:n} % \begin{syntax} % \cs{seq_break:n} \Arg{tokens} % \end{syntax} % Used to terminate sequence functions by gobbling all tokens % up to \cs{seq_break_point:n}, then inserting the \meta{tokens} % before continuing reading the input stream. This function is a copy % of \cs{seq_map_break:n}, but is used in situations which are % not mappings. % \end{function} % % \begin{function}[EXP]{\seq_break_point:n} % \begin{syntax} % \cs{seq_break_point:n} \meta{tokens} % \end{syntax} % Used to mark the end of a recursion or mapping: the functions % \cs{seq_map_break:} and \cs{seq_map_break:n} use this to break out % of the loop. After the loop ends, the \meta{tokens} are inserted into % the input stream. This occurs even if the the break functions are % \emph{not} applied: \cs{seq_break_point:n} is functionally-equivalent % in these cases to \cs{use:n}. % \end{function} % % \end{documentation} % % \begin{implementation} % % \section{\pkg{l3seq} implementation} % % \TestFiles{m3seq002,m3seq003} % % \begin{macrocode} %<*initex|package> % \end{macrocode} % % \begin{macrocode} %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} \package_check_loaded_expl: % % \end{macrocode} % % A sequence is a control sequence whose top-level expansion is of % the form \enquote{\cs{seq_item:n} \marg{item$_0$} % \ldots \cs{seq_item:n} \marg{item$_{n-1}$}}. An earlier implementation % used the structure \enquote{\cs{seq_elt:w} \meta{item$_1$} % \cs{seq_elt_end:} \ldots \cs{seq_elt:w} \meta{item$_n$} % \cs{seq_elt_end:}}. This allows rapid searching using a delimited % function, but is not suitable for items containing |{|, |}| and |#| % tokens, and also leads to the loss of surrounding braces % around items. % % \begin{macro}[int]{\seq_item:n} % The delimiter is always defined, but when used incorrectly simply % removes its argument and hits an undefined control sequence to % raise an error. % \begin{macrocode} \cs_new:Npn \seq_item:n { \msg_expandable_error:n { A~sequence~was~used~incorrectly. } \use_none:n } % \end{macrocode} % \end{macro} % % \begin{variable}{\l_seq_tmpa_tl, \l_seq_tmpb_tl} % Scratch space for various internal uses. % \begin{macrocode} \tl_new:N \l_seq_tmpa_tl \tl_new:N \l_seq_tmpb_tl % \end{macrocode} % \end{variable} % % \subsection{Allocation and initialisation} % % \begin{macro}{\seq_new:N,\seq_new:c} % \UnitTested % Internally, sequences are just token lists. % \begin{macrocode} \cs_new_eq:NN \seq_new:N \tl_new:N \cs_new_eq:NN \seq_new:c \tl_new:c % \end{macrocode} % \end{macro} % % \begin{macro}{\seq_clear:N, \seq_clear:c} % \UnitTested % \begin{macro}{\seq_gclear:N, \seq_gclear:c} % \UnitTested % Clearing sequences is just the same as clearing token lists. % \begin{macrocode} \cs_new_eq:NN \seq_clear:N \tl_clear:N \cs_new_eq:NN \seq_clear:c \tl_clear:c \cs_new_eq:NN \seq_gclear:N \tl_gclear:N \cs_new_eq:NN \seq_gclear:c \tl_gclear:c % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\seq_clear_new:N, \seq_clear_new:c} % \UnitTested % \begin{macro}{\seq_gclear_new:N, \seq_gclear_new:c} % \UnitTested % Once again a copy from the token list functions. % \begin{macrocode} \cs_new_eq:NN \seq_clear_new:N \tl_clear_new:N \cs_new_eq:NN \seq_clear_new:c \tl_clear_new:c \cs_new_eq:NN \seq_gclear_new:N \tl_gclear_new:N \cs_new_eq:NN \seq_gclear_new:c \tl_gclear_new:c % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\seq_set_eq:NN, \seq_set_eq:cN, \seq_set_eq:Nc, \seq_set_eq:cc} % \UnitTested % \begin{macro} % {\seq_gset_eq:NN, \seq_gset_eq:cN, \seq_gset_eq:Nc, \seq_gset_eq:cc} % \UnitTested % Once again, these are simple copies from the token list functions. % \begin{macrocode} \cs_new_eq:NN \seq_set_eq:NN \tl_set_eq:NN \cs_new_eq:NN \seq_set_eq:Nc \tl_set_eq:Nc \cs_new_eq:NN \seq_set_eq:cN \tl_set_eq:cN \cs_new_eq:NN \seq_set_eq:cc \tl_set_eq:cc \cs_new_eq:NN \seq_gset_eq:NN \tl_gset_eq:NN \cs_new_eq:NN \seq_gset_eq:Nc \tl_gset_eq:Nc \cs_new_eq:NN \seq_gset_eq:cN \tl_gset_eq:cN \cs_new_eq:NN \seq_gset_eq:cc \tl_gset_eq:cc % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\seq_concat:NNN, \seq_concat:ccc} % \UnitTested % \begin{macro}{\seq_gconcat:NNN, \seq_gconcat:ccc} % \UnitTested % Concatenating sequences is easy. % \begin{macrocode} \cs_new_protected_nopar:Npn \seq_concat:NNN #1#2#3 { \tl_set:Nx #1 { \exp_not:o {#2} \exp_not:o {#3} } } \cs_new_protected_nopar:Npn \seq_gconcat:NNN #1#2#3 { \tl_gset:Nx #1 { \exp_not:o {#2} \exp_not:o {#3} } } \cs_generate_variant:Nn \seq_concat:NNN { ccc } \cs_generate_variant:Nn \seq_gconcat:NNN { ccc } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Appending data to either end} % % \begin{macro}{ % \seq_put_left:Nn, \seq_put_left:NV, \seq_put_left:Nv, % \seq_put_left:No, \seq_put_left:Nx, % \seq_put_left:cn, \seq_put_left:cV, \seq_put_left:cv, % \seq_put_left:co, \seq_put_left:cx % } % \UnitTested % \begin{macro}{ % \seq_put_right:Nn, \seq_put_right:NV, \seq_put_right:Nv, % \seq_put_right:No, \seq_put_right:Nx, % \seq_put_right:cn, \seq_put_right:cV, \seq_put_right:cv, % \seq_put_right:co, \seq_put_right:cx % } % \UnitTested % The code here is just a wrapper for adding to token lists. % \begin{macrocode} \cs_new_protected:Npn \seq_put_left:Nn #1#2 { \tl_put_left:Nn #1 { \seq_item:n {#2} } } \cs_new_protected:Npn \seq_put_right:Nn #1#2 { \tl_put_right:Nn #1 { \seq_item:n {#2} } } \cs_generate_variant:Nn \seq_put_left:Nn { NV , Nv , No , Nx } \cs_generate_variant:Nn \seq_put_left:Nn { c , cV , cv , co , cx } \cs_generate_variant:Nn \seq_put_right:Nn { NV , Nv , No , Nx } \cs_generate_variant:Nn \seq_put_right:Nn { c , cV , cv , co , cx } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{ % \seq_gput_left:Nn, \seq_gput_left:NV, \seq_gput_left:Nv, % \seq_gput_left:No, \seq_gput_left:Nx, % \seq_gput_left:cn, \seq_gput_left:cV, \seq_gput_left:cv, % \seq_gput_left:co, \seq_gput_left:cx % } % \begin{macro}{ % \seq_gput_right:Nn, \seq_gput_right:NV, \seq_gput_right:Nv, % \seq_gput_right:No, \seq_gput_right:Nx, % \seq_gput_right:cn, \seq_gput_right:cV,\seq_gput_right:cv, % \seq_gput_right:co, \seq_gput_right:cx % } % The same for global addition. % \begin{macrocode} \cs_new_protected:Npn \seq_gput_left:Nn #1#2 { \tl_gput_left:Nn #1 { \seq_item:n {#2} } } \cs_new_protected:Npn \seq_gput_right:Nn #1#2 { \tl_gput_right:Nn #1 { \seq_item:n {#2} } } \cs_generate_variant:Nn \seq_gput_left:Nn { NV , Nv , No , Nx } \cs_generate_variant:Nn \seq_gput_left:Nn { c , cV , cv , co , cx } \cs_generate_variant:Nn \seq_gput_right:Nn { NV , Nv , No , Nx } \cs_generate_variant:Nn \seq_gput_right:Nn { c , cV , cv , co , cx } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Modifying sequences} % % \begin{variable}{\l_seq_remove_seq} % An internal sequence for the removal routines. % \begin{macrocode} \seq_new:N \l_seq_remove_seq % \end{macrocode} % \end{variable} % % \begin{macro}{\seq_remove_duplicates:N, \seq_remove_duplicates:c} % \UnitTested % \begin{macro}{\seq_gremove_duplicates:N, \seq_gremove_duplicates:c} % \UnitTested % \begin{macro}[aux]{\seq_remove_duplicates_aux:NN} % Removing duplicates means making a new list then copying it. % \begin{macrocode} \cs_new_protected:Npn \seq_remove_duplicates:N { \seq_remove_duplicates_aux:NN \seq_set_eq:NN } \cs_new_protected:Npn \seq_gremove_duplicates:N { \seq_remove_duplicates_aux:NN \seq_gset_eq:NN } \cs_new_protected:Npn \seq_remove_duplicates_aux:NN #1#2 { \seq_clear:N \l_seq_remove_seq \seq_map_inline:Nn #2 { \seq_if_in:NnF \l_seq_remove_seq {##1} { \seq_put_right:Nn \l_seq_remove_seq {##1} } } #1 #2 \l_seq_remove_seq } \cs_generate_variant:Nn \seq_remove_duplicates:N { c } \cs_generate_variant:Nn \seq_gremove_duplicates:N { c } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\seq_remove_all:Nn, \seq_remove_all:cn} % \UnitTested % \begin{macro}{\seq_gremove_all:Nn, \seq_gremove_all:cn} % \UnitTested % \begin{macro}[aux]{\seq_remove_all_aux:NNn} % The idea of the code here is to avoid a relatively expensive addition of % items one at a time to an intermediate sequence. % The approach taken is therefore similar to % that in \cs{seq_pop_right_aux_ii:NNN}, using a \enquote{flexible} % \texttt{x}-type expansion to do most of the work. As \cs{tl_if_eq:nnT} % is not expandable, a two-part strategy is needed. First, the % \texttt{x}-type expansion uses \cs{str_if_eq:nnT} to find potential % matches. If one is found, the expansion is halted and the necessary % set up takes place to use the \cs{tl_if_eq:NNT} test. The \texttt{x}-type % is started again, including all of the items copied already. This will % happen repeatedly until the entire sequence has been scanned. The code % is set up to avoid needing and intermediate scratch list: the lead-off % \texttt{x}-type expansion (|#1 #2 {#2}|) will ensure that nothing is % lost. % \begin{macrocode} \cs_new_protected:Npn \seq_remove_all:Nn { \seq_remove_all_aux:NNn \tl_set:Nx } \cs_new_protected:Npn \seq_gremove_all:Nn { \seq_remove_all_aux:NNn \tl_gset:Nx } \cs_new_protected:Npn \seq_remove_all_aux:NNn #1#2#3 { \seq_push_item_def:n { \str_if_eq:nnT {##1} {#3} { \if_false: { \fi: } \tl_set:Nn \l_seq_tmpb_tl {##1} #1 #2 { \if_false: } \fi: \exp_not:o {#2} \tl_if_eq:NNT \l_seq_tmpa_tl \l_seq_tmpb_tl { \use_none:nn } } \exp_not:n { \seq_item:n {##1} } } \tl_set:Nn \l_seq_tmpa_tl {#3} #1 #2 {#2} \seq_pop_item_def: } \cs_generate_variant:Nn \seq_remove_all:Nn { c } \cs_generate_variant:Nn \seq_gremove_all:Nn { c } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Sequence conditionals} % % \begin{macro}[pTF]{\seq_if_empty:N, \seq_if_empty:c} % \UnitTested % Simple copies from the token list variable material. % \begin{macrocode} \prg_new_eq_conditional:NNn \seq_if_empty:N \tl_if_empty:N { p , T , F , TF } \prg_new_eq_conditional:NNn \seq_if_empty:c \tl_if_empty:c { p , T , F , TF } % \end{macrocode} % \end{macro} % % \begin{macro}[TF]{ % \seq_if_in:Nn, \seq_if_in:NV, \seq_if_in:Nv, \seq_if_in:No, \seq_if_in:Nx, % \seq_if_in:cn, \seq_if_in:cV, \seq_if_in:cv, \seq_if_in:co, \seq_if_in:cx % } % \UnitTested % \begin{macro}[aux]{\seq_if_in_aux:} % The approach here is to define \cs{seq_item:n} to compare its % argument with the test sequence. If the two items are equal, the % mapping is terminated and \cs{prg_return_true:} is inserted. On the % other hand, if there is no match then the loop will break returning % \cs{prg_return_false:}. In either case, \cs{seq_break_point:n} % ensures that the group ends before the logical value is returned. % Everything is inside a group so that \cs{seq_item:n} is preserved % in nested situations. % \begin{macrocode} \prg_new_protected_conditional:Npnn \seq_if_in:Nn #1#2 { T , F , TF } { \group_begin: \tl_set:Nn \l_seq_tmpa_tl {#2} \cs_set_protected:Npn \seq_item:n ##1 { \tl_set:Nn \l_seq_tmpb_tl {##1} \if_meaning:w \l_seq_tmpa_tl \l_seq_tmpb_tl \exp_after:wN \seq_if_in_aux: \fi: } #1 \seq_break:n { \prg_return_false: } \seq_break_point:n { \group_end: } } \cs_new_nopar:Npn \seq_if_in_aux: { \seq_break:n { \prg_return_true: } } \cs_generate_variant:Nn \seq_if_in:NnT { NV , Nv , No , Nx } \cs_generate_variant:Nn \seq_if_in:NnT { c , cV , cv , co , cx } \cs_generate_variant:Nn \seq_if_in:NnF { NV , Nv , No , Nx } \cs_generate_variant:Nn \seq_if_in:NnF { c , cV , cv , co , cx } \cs_generate_variant:Nn \seq_if_in:NnTF { NV , Nv , No , Nx } \cs_generate_variant:Nn \seq_if_in:NnTF { c , cV , cv , co , cx } % \end{macrocode} % \end{macro} % \end{macro} % % \subsection{Recovering data from sequences} % % \begin{macro}{\seq_get_left:NN, \seq_get_left:cN} % \UnitTested % \begin{macro}[aux]{\seq_get_left_aux:NnwN} % Getting an item from the left of a sequence is pretty easy: just % trim off the first item after removing the \cs{seq_item:n} at % the start. % \begin{macrocode} \cs_new_protected_nopar:Npn \seq_get_left:NN #1#2 { \seq_if_empty_err_break:N #1 \exp_after:wN \seq_get_left_aux:NnwN #1 \q_stop #2 \seq_break_point:n { } } \cs_new_protected:Npn \seq_get_left_aux:NnwN \seq_item:n #1#2 \q_stop #3 { \tl_set:Nn #3 {#1} } \cs_generate_variant:Nn \seq_get_left:NN { c } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\seq_pop_left:NN, \seq_pop_left:cN} % \UnitTested % \begin{macro}{\seq_gpop_left:NN, \seq_gpop_left:cN} % \UnitTested % \begin{macro}[aux]{\seq_pop_left_aux:NNN} % \begin{macro}[aux]{\seq_pop_left_aux:NnwNNN} % The approach to popping an item is pretty similar to that to get % an item, with the only difference being that the sequence itself has % to be redefined. This makes it more sensible to use an auxiliary % function for the local and global cases. % \begin{macrocode} \cs_new_protected_nopar:Npn \seq_pop_left:NN { \seq_pop_left_aux:NNN \tl_set:Nn } \cs_new_protected_nopar:Npn \seq_gpop_left:NN { \seq_pop_left_aux:NNN \tl_gset:Nn } \cs_new_protected_nopar:Npn \seq_pop_left_aux:NNN #1#2#3 { \seq_if_empty_err_break:N #2 \exp_after:wN \seq_pop_left_aux:NnwNNN #2 \q_stop #1#2#3 \seq_break_point:n { } } \cs_new_protected:Npn \seq_pop_left_aux:NnwNNN \seq_item:n #1#2 \q_stop #3#4#5 { #3 #4 {#2} \tl_set:Nn #5 {#1} } \cs_generate_variant:Nn \seq_pop_left:NN { c } \cs_generate_variant:Nn \seq_gpop_left:NN { c } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\seq_get_right:NN, \seq_get_right:cN} % \UnitTested % \begin{macro}[aux]{\seq_get_right_aux:NN} % \begin{macro}[aux]{\seq_get_right_loop:nn} % The idea here is to remove the very first \cs{seq_item:n} from the % sequence, leaving a token list starting with the first braced entry. % Two arguments at a time are then grabbed: apart from the right-hand end of % the sequence, this will be a brace group followed by \cs{seq_item:n}. The % set up code means that these all disappear. At the end of the sequence, % the assignment is placed in front of the very last entry in the sequence, % before a tidying-up step takes place to remove the loop and reset the % meaning of \cs{seq_item:n}. % \begin{macrocode} \cs_new_protected_nopar:Npn \seq_get_right:NN #1#2 { \seq_if_empty_err_break:N #1 \seq_get_right_aux:NN #1#2 \seq_break_point:n { } } \cs_new_protected_nopar:Npn \seq_get_right_aux:NN #1#2 { \seq_push_item_def:n { } \exp_after:wN \exp_after:wN \exp_after:wN \seq_get_right_loop:nn \exp_after:wN \use_none:n #1 { \tl_set:Nn #2 } { } { \seq_pop_item_def: \seq_break: } } \cs_new:Npn \seq_get_right_loop:nn #1#2 { #2 {#1} \seq_get_right_loop:nn } \cs_generate_variant:Nn \seq_get_right:NN { c } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\seq_pop_right:NN, \seq_pop_right:cN} % \UnitTested % \begin{macro}{\seq_gpop_right:NN, \seq_gpop_right:cN} % \UnitTested % \begin{macro}[aux]{\seq_pop_right_aux:NNN, \seq_pop_right_aux_ii:NNN} % The approach to popping from the right is a bit more involved, but does % use some of the same ideas as getting from the right. What is needed is a % \enquote{flexible length} way to set a token list variable. This is % supplied by the |{ \if_false:} \fi:| \ldots % |\if_false: { \fi: }| construct. Using an \texttt{x}-type % expansion and a \enquote{non-expanding} definition for \cs{seq_item:n}, % the left-most $n - 1$ entries in a sequence of $n$ items will be stored % back in the sequence. That needs a loop of unknown length, hence using the % strange \cs{if_false:} way of including brackets. When the last item % of the sequence is reached, the closing bracket for the assignment is % inserted, and |\tl_set:Nn #3| is inserted in front of the final entry. % This therefore does the pop assignment, then a final loop clears up the % code. % \begin{macrocode} \cs_new_protected_nopar:Npn \seq_pop_right:NN { \seq_pop_right_aux:NNN \tl_set:Nx } \cs_new_protected_nopar:Npn \seq_gpop_right:NN { \seq_pop_right_aux:NNN \tl_gset:Nx } \cs_new_protected_nopar:Npn \seq_pop_right_aux:NNN #1#2#3 { \seq_if_empty_err_break:N #2 \seq_pop_right_aux_ii:NNN #1 #2 #3 \seq_break_point:n { } } \cs_new_protected_nopar:Npn \seq_pop_right_aux_ii:NNN #1#2#3 { \seq_push_item_def:n { \exp_not:n { \seq_item:n {##1} } } #1 #2 { \if_false: } \fi: \exp_after:wN \exp_after:wN \exp_after:wN \seq_get_right_loop:nn \exp_after:wN \use_none:n #2 { \if_false: { \fi: } \tl_set:Nn #3 } { } { \seq_pop_item_def: \seq_break: } } \cs_generate_variant:Nn \seq_pop_right:NN { c } \cs_generate_variant:Nn \seq_gpop_right:NN { c } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Mapping to sequences} % % \begin{macro}[int]{\seq_break:} % \begin{macro}[int]{\seq_break:n} % To break a function, the special token \cs{seq_break_point:n} is % used to find the end of the code. Any ending code is then inserted % before the return value of \cs{seq_map_break:n} is inserted. % \begin{macrocode} \cs_new:Npn \seq_break: #1 \seq_break_point:n #2 {#2} \cs_new:Npn \seq_break:n #1#2 \seq_break_point:n #3 { #3 #1 } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\seq_map_break:} % \UnitTested % \begin{macro}{\seq_map_break:n} % \UnitTested % Semantically-logical copies of the break functions for use inside % mappings. % \begin{macrocode} \cs_new_eq:NN \seq_map_break: \seq_break: \cs_new_eq:NN \seq_map_break:n \seq_break:n % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[int]{\seq_break_point:n} % Normally, the marker token will not be executed, but if it is then % the end code is simply inserted. % \begin{macrocode} \cs_new_eq:NN \seq_break_point:n \use:n % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\seq_if_empty_err_break:N} % A function to check that sequences really have some content. This % is optimised for speed, hence the direct primitive use. % \begin{macrocode} \cs_new_protected_nopar:Npn \seq_if_empty_err_break:N #1 { \if_meaning:w #1 \c_empty_tl \msg_kernel_error:nnx { seq } { empty-sequence } { \token_to_str:N #1 } \exp_after:wN \seq_break: \fi: } % \end{macrocode} % \end{macro} % % \begin{macro}{\seq_map_function:NN, \seq_map_function:cN} % \UnitTested % \begin{macro}[aux]{\seq_map_function_aux:NNn} % The idea here is to apply the code of |#2| to each item in the % sequence without altering the definition of \cs{seq_item:n}. This % is done as by noting that every odd token in the sequence must be % \cs{seq_item:n}, which can be gobbled by \cs{use_none:n}. At the end of % the loop, |#2| is instead |? \seq_map_break:|, which therefore breaks the % loop without needing to do a (relatively-expensive) quark test. % \begin{macrocode} \cs_new:Npn \seq_map_function:NN #1#2 { \exp_after:wN \seq_map_function_aux:NNn \exp_after:wN #2 #1 { ? \seq_map_break: } { } \seq_break_point:n { } } \cs_new:Npn \seq_map_function_aux:NNn #1#2#3 { \use_none:n #2 #1 {#3} \seq_map_function_aux:NNn #1 } \cs_generate_variant:Nn \seq_map_function:NN { c } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{variable}{\g_seq_nesting_depth_int} % A counter to keep track of nested functions: defined in \pkg{l3int}. % \end{variable} % % \begin{macro}[int]{\seq_push_item_def:n, \seq_push_item_def:x} % \begin{macro}[aux]{\seq_push_item_def_aux:} % \begin{macro}[int]{\seq_pop_item_def:} % The definition of \cs{seq_item:n} needs to be saved and restored at % various points within the mapping and manipulation code. That is handled % here: as always, this approach uses global assignments. % \begin{macrocode} \cs_new_protected:Npn \seq_push_item_def:n { \seq_push_item_def_aux: \cs_gset:Npn \seq_item:n ##1 } \cs_new_protected:Npn \seq_push_item_def:x { \seq_push_item_def_aux: \cs_gset:Npx \seq_item:n ##1 } \cs_new_protected:Npn \seq_push_item_def_aux: { \cs_gset_eq:cN { seq_item_ \int_use:N \g_seq_nesting_depth_int :n } \seq_item:n \int_gincr:N \g_seq_nesting_depth_int } \cs_new_protected_nopar:Npn \seq_pop_item_def: { \int_gdecr:N \g_seq_nesting_depth_int \cs_gset_eq:Nc \seq_item:n { seq_item_ \int_use:N \g_seq_nesting_depth_int :n } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\seq_map_inline:Nn, \seq_map_inline:cn} % \UnitTested % The idea here is that \cs{seq_item:n} is already \enquote{applied} to % each item in a sequence, and so an in-line mapping is just a case of % redefining \cs{seq_item:n}. % \begin{macrocode} \cs_new_protected:Npn \seq_map_inline:Nn #1#2 { \seq_push_item_def:n {#2} #1 \seq_break_point:n { \seq_pop_item_def: } } \cs_generate_variant:Nn \seq_map_inline:Nn { c } % \end{macrocode} % \end{macro} % % \begin{macro} % { % \seq_map_variable:NNn,\seq_map_variable:Ncn, % \seq_map_variable:cNn,\seq_map_variable:ccn % } % \UnitTested % This is just a specialised version of the in-line mapping function, % using an \texttt{x}-type expansion for the code set up so that the % number of |#| tokens required is as expected. % \begin{macrocode} \cs_new_protected:Npn \seq_map_variable:NNn #1#2#3 { \seq_push_item_def:x { \tl_set:Nn \exp_not:N #2 {##1} \exp_not:n {#3} } #1 \seq_break_point:n { \seq_pop_item_def: } } \cs_generate_variant:Nn \seq_map_variable:NNn { Nc } \cs_generate_variant:Nn \seq_map_variable:NNn { c , cc } % \end{macrocode} % \end{macro} % % \subsection{Sequence stacks} % % The same functions as for sequences, but with the correct naming. % % \begin{macro}{ % \seq_push:Nn, \seq_push:NV, \seq_push:Nv, \seq_push:No, \seq_push:Nx, % \seq_push:cn, \seq_push:cV, \seq_push:cV, \seq_push:co, \seq_push:cx % } % \UnitTested % \begin{macro}{ % \seq_gpush:Nn, \seq_gpush:NV, \seq_gpush:Nv, \seq_gpush:No, \seq_gpush:Nx, % \seq_gpush:cn, \seq_gpush:cV, \seq_gpush:cv, \seq_gpush:co, \seq_gpush:cx % } % \UnitTested % Pushing to a sequence is the same as adding on the left. % \begin{macrocode} \cs_new_eq:NN \seq_push:Nn \seq_put_left:Nn \cs_new_eq:NN \seq_push:NV \seq_put_left:NV \cs_new_eq:NN \seq_push:Nv \seq_put_left:Nv \cs_new_eq:NN \seq_push:No \seq_put_left:No \cs_new_eq:NN \seq_push:Nx \seq_put_left:Nx \cs_new_eq:NN \seq_push:cn \seq_put_left:cn \cs_new_eq:NN \seq_push:cV \seq_put_left:cV \cs_new_eq:NN \seq_push:cv \seq_put_left:cv \cs_new_eq:NN \seq_push:co \seq_put_left:co \cs_new_eq:NN \seq_push:cx \seq_put_left:cx \cs_new_eq:NN \seq_gpush:Nn \seq_gput_left:Nn \cs_new_eq:NN \seq_gpush:NV \seq_gput_left:NV \cs_new_eq:NN \seq_gpush:Nv \seq_gput_left:Nv \cs_new_eq:NN \seq_gpush:No \seq_gput_left:No \cs_new_eq:NN \seq_gpush:Nx \seq_gput_left:Nx \cs_new_eq:NN \seq_gpush:cn \seq_gput_left:cn \cs_new_eq:NN \seq_gpush:cV \seq_gput_left:cV \cs_new_eq:NN \seq_gpush:cv \seq_gput_left:cv \cs_new_eq:NN \seq_gpush:co \seq_gput_left:co \cs_new_eq:NN \seq_gpush:cx \seq_gput_left:cx % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\seq_get:NN, \seq_get:cN} % \UnitTested % \begin{macro}{\seq_pop:NN, \seq_pop:cN} % \UnitTested % \begin{macro}{\seq_gpop:NN, \seq_gpop:cN} % \UnitTested % In most cases, getting items from the stack does not need to specify % that this is from the left. So alias are provided. % \begin{macrocode} \cs_new_eq:NN \seq_get:NN \seq_get_left:NN \cs_new_eq:NN \seq_get:cN \seq_get_left:cN \cs_new_eq:NN \seq_pop:NN \seq_pop_left:NN \cs_new_eq:NN \seq_pop:cN \seq_pop_left:cN \cs_new_eq:NN \seq_gpop:NN \seq_gpop_left:NN \cs_new_eq:NN \seq_gpop:cN \seq_gpop_left:cN % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Viewing sequences} % % \begin{variable}{\l_seq_show_tl} % Used to store the material for display. % \begin{macrocode} \tl_new:N \l_seq_show_tl % \end{macrocode} % \end{variable} % % \begin{macro}{\seq_show:N, \seq_show:c} % \UnitTested % \begin{macro}[aux]{\seq_show_aux:n} % \begin{macro}[aux]{\seq_show_aux:w} % The aim of the mapping here is to create a token list containing the % formatted sequence. The very first item needs the new line and \verb*|> | % removing, which is achieved using a \texttt{w}-type auxiliary. To avoid % a low-level \TeX{} error if there is an empty sequence, a simple test is % used to keep the output \enquote{clean}. % \begin{macrocode} \cs_new_protected_nopar:Npn \seq_show:N #1 { \seq_if_empty:NTF #1 { \iow_term:x { Sequence~\token_to_str:N #1 \c_space_tl is~empty } \tl_show:n { } } { \iow_term:x { Sequence~\token_to_str:N #1 \c_space_tl contains~the~items~(without~outer~braces): } \tl_set:Nx \l_seq_show_tl { \seq_map_function:NN #1 \seq_show_aux:n } \etex_showtokens:D \exp_after:wN \exp_after:wN \exp_after:wN { \exp_after:wN \seq_show_aux:w \l_seq_show_tl } } } \cs_new:Npn \seq_show_aux:n #1 { \iow_newline: > \c_space_tl \c_space_tl \iow_char:N \{ \exp_not:n {#1} \iow_char:N \} } \cs_new:Npn \seq_show_aux:w #1 > ~ { } \cs_generate_variant:Nn \seq_show:N { c } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Experimental functions} % % \begin{macro}[aux]{\seq_if_empty_break_return_false:N} % The name says it all: of the sequence is empty, returns logical % \texttt{false}. % \begin{macrocode} \cs_new_nopar:Npn \seq_if_empty_break_return_false:N #1 { \if_meaning:w #1 \c_empty_tl \prg_return_false: \exp_after:wN \seq_break: \fi: } % \end{macrocode} % \end{macro} % % \begin{macro}[TF]{\seq_get_left:NN, \seq_get_left:cN} % \begin{macro}[TF]{\seq_get_right:NN, \seq_get_right:cN} % Getting from the left or right with a check on the results. % \begin{macrocode} \prg_new_protected_conditional:Npnn \seq_get_left:NN #1 #2 { T , F , TF } { \seq_if_empty_break_return_false:N #1 \exp_after:wN \seq_get_left_aux:Nw #1 \q_stop #2 \prg_return_true: \seq_break: \seq_break_point:n { } } \prg_new_protected_conditional:Npnn \seq_get_right:NN #1#2 { T , F , TF } { \seq_if_empty_break_return_false:N #1 \seq_get_right_aux:NN #1#2 \prg_return_true: \seq_break: \seq_break_point:n { } } \cs_generate_variant:Nn \seq_get_left:NNT { c } \cs_generate_variant:Nn \seq_get_left:NNF { c } \cs_generate_variant:Nn \seq_get_left:NNTF { c } \cs_generate_variant:Nn \seq_get_right:NNT { c } \cs_generate_variant:Nn \seq_get_right:NNF { c } \cs_generate_variant:Nn \seq_get_right:NNTF { c } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[TF]{\seq_pop_left:NN, \seq_pop_left:cN} % \begin{macro}[TF]{\seq_gpop_left:NN, \seq_gpop_left:cN} % \begin{macro}[TF]{\seq_pop_right:NN, \seq_pop_right:cN} % \begin{macro}[TF]{\seq_gpop_right:NN, \seq_gpop_right:cN} % More or less the same for popping. % \begin{macrocode} \prg_new_protected_conditional:Npnn \seq_pop_left:NN #1#2 { T , F , TF } { \seq_if_empty_break_return_false:N #1 \exp_after:wN \seq_pop_left_aux:NnwNNN #1 \q_stop \tl_set:Nn #1#2 \prg_return_true: \seq_break: \seq_break_point:n { } } \prg_new_protected_conditional:Npnn \seq_gpop_left:NN #1#2 { T , F , TF } { \seq_if_empty_break_return_false:N #1 \exp_after:wN \seq_pop_left_aux:NnwNNN #1 \q_stop \tl_gset:Nn #1#2 \prg_return_true: \seq_break: \seq_break_point:n { } } \prg_new_protected_conditional:Npnn \seq_pop_right:NN #1#2 { T , F , TF } { \seq_if_empty_break_return_false:N #1 \seq_pop_right_aux_ii:NNN \tl_set:Nx #1 #2 \prg_return_true: \seq_break: \seq_break_point:n { } } \prg_new_protected_conditional:Npnn \seq_gpop_right:NN #1#2 { T , F , TF } { \seq_if_empty_break_return_false:N #1 \seq_pop_right_aux_ii:NNN \tl_gset:Nx #1 #2 \prg_return_true: \seq_break: \seq_break_point:n { } } \cs_generate_variant:Nn \seq_pop_left:NNT { c } \cs_generate_variant:Nn \seq_pop_left:NNF { c } \cs_generate_variant:Nn \seq_pop_left:NNTF { c } \cs_generate_variant:Nn \seq_gpop_left:NNT { c } \cs_generate_variant:Nn \seq_gpop_left:NNF { c } \cs_generate_variant:Nn \seq_gpop_left:NNTF { c } \cs_generate_variant:Nn \seq_pop_right:NNT { c } \cs_generate_variant:Nn \seq_pop_right:NNF { c } \cs_generate_variant:Nn \seq_pop_right:NNTF { c } \cs_generate_variant:Nn \seq_gpop_right:NNT { c } \cs_generate_variant:Nn \seq_gpop_right:NNF { c } \cs_generate_variant:Nn \seq_gpop_right:NNTF { c } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\seq_length:N, \seq_length:c} % \begin{macro}[aux]{\seq_length_aux:n} % Counting the items in a sequence is done using the same approach as for % other length functions: turn each entry into a \texttt{+1} then use % integer evaluation to actually do the mathematics. % \begin{macrocode} \cs_new:Npn \seq_length:N #1 { \int_eval:n { 0 \seq_map_function:NN #1 \seq_length_aux:n } } \cs_new:Npn \seq_length_aux:n #1 { +1 } \cs_generate_variant:Nn \seq_length:N { c } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\seq_item:Nn, \seq_item:cn} % \begin{macro}[aux]{\seq_item_aux:nnn} % The idea here is to find the offset of the item from the left, then use % a loop to grab the correct item. If the resulting offset is too large, % then the stop code |{ ? \seq_break } { }| will be used by the auxiliary, % terminating the loop and returning nothing at all. % \begin{macrocode} \cs_new_nopar:Npn \seq_item:Nn #1#2 { \exp_last_unbraced:Nfo \seq_item_aux:nnn { \int_eval:n { \int_compare:nNnT {#2} < \c_zero { \seq_length:N #1 + } #2 } } #1 { ? \seq_break: } { } \seq_break_point:n { } } \cs_new_nopar:Npn \seq_item_aux:nnn #1#2#3 { \use_none:n #2 \int_compare:nNnTF {#1} = \c_zero { \seq_break:n {#3} } { \exp_args:Nf \seq_item_aux:nnn { #1 - 1 } } } \cs_generate_variant:Nn \seq_item:Nn { c } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\seq_use:N, \seq_use:c} % A simple short cut for a mapping. % \begin{macrocode} \cs_new_nopar:Npn \seq_use:N #1 { \seq_map_function:NN #1 \use:n } \cs_generate_variant:Nn \seq_use:N { c } % \end{macrocode} % \end{macro} % % \begin{macro} % { % \seq_mapthread_function:NNN, \seq_mapthread_function:NcN, % \seq_mapthread_function:cNN, \seq_mapthread_function:ccN % } % \begin{macro}[aux]{\seq_mapthread_function_aux:NN} % \begin{macro}[aux]{\seq_mapthread_function_aux:Nnnwnn} % The idea here is to first expand both of the sequences, adding the usual % |{ ? \seq_break: } { }| to the end of each on. This is most conveniently % done in two steps using an auxiliary function. The mapping then throws % away the first token of |#2| and |#5|, which for items in the sequences % will both be \cs{seq_item:n}. The function to be mapped will then be % applied to the two entries. When the code hits the end of one of the % sequences, the break material will stop the entire loop and tidy up. This % avoids needing to find the length of the two sequences, or worrying about % which is longer. % \begin{macrocode} \cs_new_nopar:Npn \seq_mapthread_function:NNN #1#2#3 { \exp_after:wN \seq_mapthread_function_aux:NN \exp_after:wN #3 \exp_after:wN #1 #2 { ? \seq_break: } { } \seq_break_point:n { } } \cs_new_nopar:Npn \seq_mapthread_function_aux:NN #1#2 { \exp_after:wN \seq_mapthread_function_aux:Nnnwnn \exp_after:wN #1 #2 { ? \seq_break: } { } \q_stop } \cs_new:Npn \seq_mapthread_function_aux:Nnnwnn #1#2#3#4 \q_stop #5#6 { \use_none:n #2 \use_none:n #5 #1 {#3} {#6} \seq_mapthread_function_aux:Nnnwnn #1 #4 \q_stop } \cs_generate_variant:Nn \seq_mapthread_function:NNN { Nc } \cs_generate_variant:Nn \seq_mapthread_function:NNN { c , cc } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro} % { % \seq_set_from_clist:NN, \seq_set_from_clist:cN, % \seq_set_from_clist:Nc, \seq_set_from_clist:cc, % \seq_set_from_clist:Nn, \seq_set_from_clist:cn % } % \begin{macro} % { % \seq_gset_from_clist:NN, \seq_gset_from_clist:cN, % \seq_gset_from_clist:Nc, \seq_gset_from_clist:cc, % \seq_gset_from_clist:Nn, \seq_gset_from_clist:cn % } % \begin{macro}[aux]{\seq_wrap_item:n} % Setting a sequence from a comma-separated list is done using a simple % mapping. % \begin{macrocode} \cs_new_protected:Npn \seq_set_from_clist:NN #1#2 { \tl_set:Nx #1 { \clist_map_function:NN #2 \seq_wrap_item:n } } \cs_new_protected:Npn \seq_set_from_clist:Nn #1#2 { \tl_set:Nx #1 { \clist_map_function:nN {#2} \seq_wrap_item:n } } \cs_new_protected:Npn \seq_gset_from_clist:NN #1#2 { \tl_gset:Nx #1 { \clist_map_function:NN #2 \seq_wrap_item:n } } \cs_new_protected:Npn \seq_gset_from_clist:Nn #1#2 { \tl_gset:Nx #1 { \clist_map_function:nN {#2} \seq_wrap_item:n } } \cs_new:Npn \seq_wrap_item:n #1 { \exp_not:n { \seq_item:n {#1} } } \cs_generate_variant:Nn \seq_set_from_clist:NN { Nc } \cs_generate_variant:Nn \seq_set_from_clist:NN { c , cc } \cs_generate_variant:Nn \seq_set_from_clist:Nn { c } \cs_generate_variant:Nn \seq_gset_from_clist:NN { Nc } \cs_generate_variant:Nn \seq_gset_from_clist:NN { c , cc } \cs_generate_variant:Nn \seq_gset_from_clist:Nn { c } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\seq_set_reverse:N,\seq_gset_reverse:N} % Define \cs{seq_item:n} to place its argument after a marker, % \cs{prg_do_nothing:}. Then x-expand the sequence. % \begin{macrocode} \cs_new_protected_nopar:Npn \seq_tmp:w { \msg_expandable_error:n { There~is~a~bug~in~LaTeX3! } } \cs_new_protected_nopar:Npn \seq_set_reverse:N { \seq_reverse_aux:NN \tl_set:Nx } \cs_new_protected_nopar:Npn \seq_gset_reverse:N { \seq_reverse_aux:NN \tl_gset:Nx } \cs_new_protected_nopar:Npn \seq_reverse_aux:NN #1 #2 { \cs_set_eq:NN \seq_tmp:w \seq_item:n \cs_set_eq:NN \seq_item:n \seq_reverse_aux_item:w #1 #2 { #2 \prg_do_nothing: } \cs_set_eq:NN \seq_item:n \seq_tmp:w } \cs_new:Npn \seq_reverse_aux_item:w #1 #2 \prg_do_nothing: { #2 \prg_do_nothing: \exp_not:n { \seq_item:n {#1} } } % \end{macrocode} % \end{macro} % % \begin{macro}{\seq_set_split:Nnn,\seq_gset_split:Nnn} % \begin{macro}[aux]{\seq_set_split_aux:NNnn} % \begin{macro}[aux] % { % \seq_set_split_aux_i:w, \seq_set_split_aux_ii:w, % \seq_set_split_aux_end: % } % The goal is to split a given token list at a marker, % strip spaces from each item, and remove one set of % outer braces if after removing leading and trailing % spaces the item is enclosed within braces. After % \cs{tl_replace_all:Nnn}, the token list \cs{l_seq_tmpa_tl} % is a repetition of the pattern % \cs{seq_set_split_aux_i:w} \cs{prg_do_nothing:} % \meta{item with spaces} \cs{seq_set_split_aux_end:}. % Then, \texttt{x}-expansion causes \cs{seq_set_split_aux_i:w} % to trim spaces, and leaves its result as % \cs{seq_set_split_aux_ii:w} \meta{trimmed item} % \cs{seq_set_split_aux_end:}. This is then converted % to the \pkg{l3seq} internal structure by another % \texttt{x}-expansion. In the first step, we insert % \cs{prg_do_nothing:} to avoid losing braces too early: % that would cause space trimming to act within those % lost braces. The second step is solely there to strip % braces which are outermost after space trimming. % \begin{macrocode} \cs_new_protected_nopar:Npn \seq_set_split:Nnn { \seq_set_split_aux:NNnn \tl_set:Nx } \cs_new_protected_nopar:Npn \seq_gset_split:Nnn { \seq_set_split_aux:NNnn \tl_gset:Nx } \cs_new_protected_nopar:Npn \seq_set_split_aux:NNnn #1 #2 #3 #4 { \tl_if_empty:nTF {#4} { #1 #2 { } } { \tl_set:Nn \l_seq_tmpa_tl { \seq_set_split_aux_i:w \prg_do_nothing: #4 \seq_set_split_aux_end: } \tl_replace_all:Nnn \l_seq_tmpa_tl { #3 } { \seq_set_split_aux_end: \seq_set_split_aux_i:w \prg_do_nothing: } \tl_set:Nx \l_seq_tmpa_tl { \l_seq_tmpa_tl } #1 #2 { \l_seq_tmpa_tl } } } \cs_new:Npn \seq_set_split_aux_i:w #1 \seq_set_split_aux_end: { \exp_not:N \seq_set_split_aux_ii:w \exp_args:No \tl_trim_spaces:n {#1} \exp_not:N \seq_set_split_aux_end: } \cs_new:Npn \seq_set_split_aux_ii:w #1 \seq_set_split_aux_end: { \exp_not:n { \seq_item:n {#1} } } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Deprecated interfaces} % % A few functions which are no longer documented: these were moved % here on or before 2011-04-20, and will be removed entirely by % 2011-07-20. % % \begin{macro}{\seq_top:NN, \seq_top:cN} % These are old stack functions. % \begin{macrocode} \cs_new_eq:NN \seq_top:NN \seq_get_left:NN \cs_new_eq:NN \seq_top:cN \seq_get_left:cN % \end{macrocode} % \end{macro} % % \begin{macro}{\seq_display:N, \seq_display:c} % An older name for \cs{seq_show:N}. % \begin{macrocode} \cs_new_eq:NN \seq_display:N \seq_show:N \cs_new_eq:NN \seq_display:c \seq_show:c % \end{macrocode} % \end{macro} % % \begin{macrocode} % % \end{macrocode} % % \end{implementation} % % \PrintIndex