diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/expl3/l3seq.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/expl3/l3seq.dtx | 1921 |
1 files changed, 1156 insertions, 765 deletions
diff --git a/Master/texmf-dist/source/latex/expl3/l3seq.dtx b/Master/texmf-dist/source/latex/expl3/l3seq.dtx index f9d6f82e283..6e5c536616d 100644 --- a/Master/texmf-dist/source/latex/expl3/l3seq.dtx +++ b/Master/texmf-dist/source/latex/expl3/l3seq.dtx @@ -1,5 +1,7 @@ -% \iffalse -%% File: l3seq.dtx Copyright (C) 1990-2010 LaTeX3 project +% \iffalse meta-comment +% +%% File: l3seq.dtx Copyright (C) 1990-2011 by +%% The LaTeX3 Project <latex-team@latex-project.org> %% %% It may be distributed and/or modified under the conditions of the %% LaTeX Project Public License (LPPL), either version 1.3c of this @@ -8,7 +10,7 @@ %% %% http://www.latex-project.org/lppl.txt %% -%% This file is part of the ``expl3 bundle'' (The Work in LPPL) +%% 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. @@ -28,413 +30,607 @@ %% 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 LaTeX Project Team. +%% prior consultation with the LaTeX3 Project. %% %% ----------------------------------------------------------------------- % %<*driver|package> \RequirePackage{l3names} +\GetIdInfo$Id: l3seq.dtx 2245 2011-04-21 19:45:31Z joseph $ + {The LaTeX3 kernel: sequences and stacks} %</driver|package> -%\fi -\GetIdInfo$Id: l3seq.dtx 1879 2010-03-29 17:48:38Z mittelba $ - {L3 Experimental sequences and stacks} -%\iffalse %<*driver> -%\fi -\ProvidesFile{\filename.\filenameext} - [\filedate\space v\fileversion\space\filedescription] -%\iffalse \documentclass[full]{l3doc} +\usepackage{csquotes} \begin{document} -\DocInput{\filename.\filenameext} + \DocInput{\jobname.dtx} \end{document} %</driver> % \fi % +% \GetFileInfo{\jobname.sty} +% +% \title{^^A +% \fileinfo +% \thanks{This file describes v\fileversion, last revised \filedate.}^^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 \filedate} % -% \title{The \textsf{l3seq} package\thanks{This file -% has version number \fileversion, last -% revised \filedate.}\\ -% Sequences} -% \author{\Team} -% \date{\filedate} % \maketitle % % \begin{documentation} % -% \LaTeX3 implements a data type called `sequences'. These are special -% token lists that can be accessed via special function on the `left'. -% Appending tokens is possible at both ends. Appended token lists can be -% accessed only as a union. The token lists that form the individual -% items of a sequence might contain any tokens except two internal -% functions that are used to structure sequences (see section internal -% functions below). It is also possible to map functions on such -% sequences so that they are executed for every item on the sequence. -% -% All functions that return items from a sequence in some \m{tl var.}~assume -% that the \m{tl var.}~is local. See remarks below if you need a global -% returned value. -% -% The defined functions are not orthogonal in the sense that every -% possible variation possible is actually available. If you need a new -% variant use the expansion functions described in the package -% \texttt{l3expan} to build it. -% -% Adding items to the left of a sequence can currently be done with -% either something like "\seq_put_left:Nn" or with a ``stack'' function -% like "\seq_push:Nn" which has the same effect. Maybe one should -% therefore remove the ``left'' functions totally. -% -% \section{Functions for creating/initialising sequences} -% -% \begin{function}{ \seq_new:N | -% \seq_new:c } -% \begin{syntax} -% "\seq_new:N" <sequence> -% \end{syntax} -% Defines <sequence> to be a variable of type "seq". -% \end{function} -% -% \begin{function}{ \seq_clear:N | -% \seq_clear:c | -% \seq_gclear:N | -% \seq_gclear:c } -% \begin{syntax} -% "\seq_clear:N" <sequence> -% \end{syntax} -% These functions locally or globally clear <sequence>. -% \end{function} -% -% \begin{function}{ \seq_clear_new:N | -% \seq_clear_new:c | -% \seq_gclear_new:N | -% \seq_gclear_new:c } -% \begin{syntax} -% "\seq_clear_new:N" <sequence> -% \end{syntax} -% These functions locally or globally clear <sequence> if it exists or -% otherwise allocates it. -% \end{function} -% -% \begin{function}{ \seq_set_eq:NN | -% \seq_set_eq:cN | -% \seq_set_eq:Nc | -% \seq_set_eq:cc } -% \begin{syntax} -% "\seq_set_eq:NN" <seq1> <seq2> -% \end{syntax} -% Function that locally makes <seq1> identical to <seq2>. -% \end{function} -% -% \begin{function}{ \seq_gset_eq:NN | -% \seq_gset_eq:cN | -% \seq_gset_eq:Nc | -% \seq_gset_eq:cc } -% \begin{syntax} -% "\seq_gset_eq:NN" <seq1> <seq2> -% \end{syntax} -% Function that globally makes <seq1> identical to <seq2>. -% \end{function} -% -% \begin{function}{% -% \seq_concat:NNN | -% \seq_concat:ccc | -% \seq_gconcat:NNN | -% \seq_gconcat:ccc | -% } -% \begin{syntax} -% "\seq_concat:NNN" <seq1> <seq2> <seq3> -% "\seq_gconcat:NNN" <seq1> <seq2> <seq3> -% \end{syntax} -% Function that conatenates <seq2> and <seq3> and locally or globally assigns the -% result to <seq1>. -% \end{function} -% -% \section{Adding data to sequences} -% -% \begin{function}{% -% \seq_put_left:Nn | -% \seq_put_left:NV | -% \seq_put_left:No | -% \seq_put_left:Nx | -% \seq_put_left:cn | -% \seq_put_left:cV | -% \seq_put_left:co | +% \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} -% "\seq_put_left:Nn" <sequence> <token list> -% \end{syntax} -% Locally appends <token list> as a single item to the left -% of <sequence>. <token list> might get expanded before -% appending according to the variant. -% \end{function} -% -% \begin{function}{% -% \seq_put_right:Nn | -% \seq_put_right:NV | -% \seq_put_right:No | -% \seq_put_right:Nx | -% \seq_put_right:cn | -% \seq_put_right:cV | -% \seq_put_right:co | +% \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} -% "\seq_put_right:Nn" <sequence> <token list> -% \end{syntax} -% Locally appends <token list> as a single item to the right -% of <sequence>. <token list> might get expanded before -% appending according to the variant. -% \end{function} -% -% \begin{function}{% -% \seq_gput_left:Nn | -% \seq_gput_left:NV | -% \seq_gput_left:No | -% \seq_gput_left:Nx | -% \seq_gput_left:cn | -% \seq_gput_left:cV | -% \seq_gput_left:co | +% \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} -% "\seq_gput_left:Nn" <sequence> <token list> -% \end{syntax} -% Globally appends <token list> as a single item to the left -% of <sequence>. -% \end{function} -% -% \begin{function}{% -% \seq_gput_right:Nn | -% \seq_gput_right:NV | -% \seq_gput_right:No | -% \seq_gput_right:Nx | -% \seq_gput_right:cn | -% \seq_gput_right:cV | -% \seq_gput_right:co | +% \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} -% "\seq_gput_right:Nn" <sequence> <token list> -% \end{syntax} -% Globally appends <token list> as a single item to the right -% of <sequence>. +% \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} % -% \section{Working with sequences} +% \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_get:NN | -% \seq_get:cN | -% } -% \begin{syntax} -% "\seq_get:NN" <sequence> <tl var.> -% \end{syntax} -% Functions that locally assign the left-most item of <sequence> to the -% token list variable <tl var.>. Item is not removed from <sequence>! If you -% need a global return value you need to code something like this: -% \begin{quote} -% "\seq_get:NN" <sequence> "\l_tmpa_tl" \\ -% "\tl_gset_eq:NN" <global tl var.> "\l_tmpa_tl" -% \end{quote} -% But if this kind of construction is used often enough a separate -% function should be provided. -% \end{function} -% -% -% \begin{function}{\seq_map_variable:NNn | -% \seq_map_variable:cNn -% } -% \begin{syntax} -% "\seq_map_variable:NNn" <sequence> <tl var.> \Arg{code using tl var.} -% \end{syntax} -% Every element in <sequence> is assigned to <tl var.> and then <code -% using tl var.> is executed. The operation is not expandable which means -% that it can't be used within write operations etc. However, this -% function can be nested which the others can't. -% \end{function} -% -% \begin{function}{ \seq_map_function:NN | -% \seq_map_function:cN } -% \begin{syntax} -% "\seq_map_function:NN" <sequence> <function> -% \end{syntax} -% This function applies <function> (which must be a function with one -% argument) to every item of <sequence>. <function> is not executed -% within a sub-group so that side effects can be achieved locally. The -% operation is not expandable which means that it can't be used within -% write operations etc. -% -% In the current implementation the next functions are more efficient and -% should be preferred. -% \end{function} -% -% \begin{function}{\seq_map_inline:Nn | -% \seq_map_inline:cn -% } -% \begin{syntax} -% "\seq_map_inline:Nn" <sequence> \Arg{inline function} -% \end{syntax} -% Applies <inline function> (which should be the direct coding for a -% function with one argument (i.e.\ use "#1" as the place holder for -% this argument)) to every item of <sequence>. <inline function> is not -% executed within a sub-group so that side effects can be achieved locally. -% The operation is not expandable which means that it can't be used -% within write operations etc. -% \end{function} -% -% \begin{function}{ \seq_map_break: | \seq_map_break:n } -% These functions are used to break out of a mapping function at the point -% of execution. (Please do not put `|\q_stop|' inside a <seq> that uses -% these functions.) -% \end{function} -% -% \begin{function}{ \seq_show:N | -% \seq_show:c } -% \begin{syntax} -% "\seq_show:N" <sequence> -% \end{syntax} -% Function that pauses the compilation and displays <seq> in the terminal -% output and in the log file. (Usually used for diagnostic purposes.) -% \end{function} -% -% \begin{function}{ \seq_display:N | -% \seq_display:c } -% \begin{syntax} -% "\seq_display:N" <sequence> -% \end{syntax} -% As with "\seq_show:N" but pretty prints the output one line per element. -% \end{function} -% -% \begin{function}{ \seq_remove_duplicates:N | -% \seq_gremove_duplicates:N } -% \begin{syntax} -% "\seq_gremove_duplicates:N" <seq> -% \end{syntax} -% Function that removes any duplicate entries in <seq>. -% \end{function} -% -% \section{Predicates and conditionals} -% -% \begin{function}{ \seq_if_empty_p:N / (EXP) | -% \seq_if_empty_p:c / (EXP) } -% \begin{syntax} -% "\seq_if_empty_p:N" <sequence> -% \end{syntax} -% This predicate returns `true' if <sequence> is `empty' i.e., doesn't -% contain any items. Note that this is `false' even if the <sequence> only -% contains a single empty item. -% \end{function} -% -% \begin{function}{ \seq_if_empty:N / (TF) | -% \seq_if_empty:c / (TF) } -% \begin{syntax} -% "\seq_if_empty:NTF" <sequence> \Arg{true code} \Arg{false code} -% \end{syntax} -% Set of conditionals that test whether or not a particular <sequence> -% is empty and if so executes either <true code> or <false code>. -% \end{function} -% -% \begin{function}{ \seq_if_in:Nn / (TF) | -% \seq_if_in:NV / (TF) | -% \seq_if_in:cn / (TF) | -% \seq_if_in:cV / (TF) | -% \seq_if_in:co / (TF) | -% \seq_if_in:cx / (TF) } -% \begin{syntax} -% "\seq_if_in:NnTF" <sequence> \Arg{item} \Arg{true code} \Arg{false code} -% \end{syntax} -% Functions that test if <item> is in <sequence>. Depending on the result -% either <true code> or <false code> is executed. -% \end{function} -% -% \section{Internal functions} -% -% \begin{function}{\seq_if_empty_err:N} -% \begin{syntax} -% "\seq_if_empty_err:N" <sequence> -% \end{syntax} -% Signals an \LaTeX3 error if <sequence> is empty. -% \end{function} -% -% \begin{function}{\seq_pop_aux:nnNN} -% \begin{syntax} -% "\seq_pop_aux:nnNN" <assign1> <assign2> <sequence> <tl var.> -% \end{syntax} -% Function that assigns the left-most item of <sequence> to <tl var.> using -% <assign1> and assigns the tail to <sequence> using <assign2>. This -% function could be used to implement a global return function. -% \end{function} -% -% \begin{function}{% -% \seq_get_aux:w | -% \seq_pop_aux:w | -% \seq_put_aux:Nnn | -% \seq_put_aux:w | +% \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 storesitin 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 +% 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 +% 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} +% +% \subsection{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). The +% branching versions then leave either \meta{true code} or +% \meta{false code} in the input stream, as appropriate to the truth of +% the test and the variant of the function chosen. The logical truth of +% the test is left in the input stream by the predicate version. +% \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 % } -% Functions used to implement put and get operations. They are not for -% meant for direct use. -% \end{function} -% -% \begin{function}{ \seq_elt:w | -% \seq_elt_end: } -% Functions (usually used as constants) that separates items within a -% sequence. They might get special meaning during mapping operations and -% are not supposed to show up as tokens within an item appended to a -% sequence. -% \end{function} -% -% \section{Functions for `Sequence Stacks'} -% -% Special sequences in \LaTeX3 are `stacks' with their usual operations -% of `push', `pop', and `top'. They are internally implemented as -% sequences and share some of the functions (like "\seq_new:N" etc.) -% -% \begin{function}{% -% \seq_push:Nn | -% \seq_push:NV | -% \seq_push:No | -% \seq_push:cn | -% \seq_gpush:Nn | -% \seq_gpush:NV | -% \seq_gpush:No | -% \seq_gpush:Nv | -% \seq_gpush:cn | +% \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}. +% Either the \meta{true code} or \meta{false code} is left in the input +% stream, as appropriate to the truth of the test and the variant of the +% function +% chosen. +% \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} -% "\seq_push:Nn" <stack> \Arg{token list} -% \end{syntax} -% Locally or globally pushes <token list> as a single item onto the -% <stack>. -% \end{function} -% -% \begin{function}{% -% \seq_pop:NN | -% \seq_pop:cN | -% \seq_gpop:NN | -% \seq_gpop:cN | +% \begin{syntax} +% \cs{seq_map_variable:Nn} \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. One variable mapping may be +% nested inside another. +% \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 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 { <tokens> } } +% { +% % Do something useful +% } +% } +% \end{verbatim} +% Use outside of a \cs{seq_map_\ldots} scenario will lead 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} +% +% \subsection{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 the marker 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} -% "\seq_pop:NN" <stack> <tl var.> -% \end{syntax} -% Functions that assign the top item of <stack> to <tl var.> -% and removes it from <stack>! +% \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_top:NN | -% \seq_top:cN | +% \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} -% "\seq_top:NN" <stack> <tl var.> -% \end{syntax} -% Functions that locally assign the top item of <stack> to the <tl var.>. -% Item is \emph{not} removed from <stack>! +% \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} % % \end{documentation} % % \begin{implementation} % -% \section{\pkg{l3seq} implementation} +% \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} +% +% \section{Sequence implementation} +% +% \TestFiles{m3seq002,m3seq003} +% +% \begin{macrocode} +%<*initex|package> +% \end{macrocode} % % \begin{macrocode} %<*package> @@ -444,40 +640,53 @@ %</package> % \end{macrocode} % -% A sequence is a control sequence whose top-level expansion is of the -% form `|\seq_elt:w| \m{text$\sb1$} |\seq_elt_end:| \ldots{} -% |\seq_elt:w| \meta{text$\sb{n}$} \ldots'. We use explicit delimiters -% instead of braces around \m{text} to allow efficient searching for -% an item in the sequence. -% -% \begin{macro}{\seq_elt:w} -% \begin{macro}{\seq_elt_end:} -% We allocate the delimiters and make them errors if executed. +% A sequence is a control sequence whose top-level expansion is of +% the form \enquote{\cs{seq_item:n} \marg{item$_1$} +% \ldots \cs{seq_item:n} \marg{item$_n$}}. 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 which 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} -%<*initex|package> -\cs_new:Npn \seq_elt:w {\ERROR} -\cs_new:Npn \seq_elt_end: {\ERROR} +\cs_new:Npn \seq_item:n + { + \seq_use_error: + \use_none:n + } % \end{macrocode} % \end{macro} +% +% \begin{macro}[aux]{\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{macro} % -% \subsection{Allocating and initialisation} +% \subsection{Allocation and initialisation} % -% \begin{macro}{\seq_new:N} -% \begin{macro}{\seq_new:c} -% Sequences are implemented using token lists. +% \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} -% \end{macro} % -% \begin{macro}{\seq_clear:N} -% \begin{macro}{\seq_clear:c} -% \begin{macro}{\seq_gclear:N} -% \begin{macro}{\seq_gclear:c} -% Clearing a sequence is the same as clearing a token list. +% \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 @@ -486,14 +695,12 @@ % \end{macrocode} % \end{macro} % \end{macro} -% \end{macro} -% \end{macro} % -% \begin{macro}{\seq_clear_new:N} -% \begin{macro}{\seq_clear_new:c} -% \begin{macro}{\seq_gclear_new:N} -% \begin{macro}{\seq_gclear_new:c} -% Clearing a sequence is the same as clearing a token list. +% \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 simply 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 @@ -502,499 +709,683 @@ % \end{macrocode} % \end{macro} % \end{macro} -% \end{macro} -% \end{macro} -% -% \begin{macro}{\seq_set_eq:NN} -% \begin{macro}{\seq_set_eq:Nc} -% \begin{macro}{\seq_set_eq:cN} -% \begin{macro}{\seq_set_eq:cc} -% We can set one "seq" equal to another. -% \begin{macrocode} -\cs_new_eq:NN \seq_set_eq:NN \cs_set_eq:NN -\cs_new_eq:NN \seq_set_eq:cN \cs_set_eq:cN -\cs_new_eq:NN \seq_set_eq:Nc \cs_set_eq:Nc -\cs_new_eq:NN \seq_set_eq:cc \cs_set_eq:cc +% +% \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 simply 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} -% \end{macro} -% \end{macro} % -% \begin{macro}{\seq_gset_eq:NN} -% \begin{macro}{\seq_gset_eq:cN} -% \begin{macro}{\seq_gset_eq:Nc} -% \begin{macro}{\seq_gset_eq:cc} -% And of course globally which seems to be needed far more -% often.\footnote{To save a bit of space these functions could be made -% identical to those from the tl or clist module.} +% \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_eq:NN \seq_gset_eq:NN \cs_gset_eq:NN -\cs_new_eq:NN \seq_gset_eq:cN \cs_gset_eq:cN -\cs_new_eq:NN \seq_gset_eq:Nc \cs_gset_eq:Nc -\cs_new_eq:NN \seq_gset_eq:cc \cs_gset_eq:cc +\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} -% \end{macro} -% \end{macro} % -% \begin{macro}{\seq_concat:NNN,\seq_concat:ccc} -% |\seq_concat:NNN| \m{seq~1} \m{seq~2} \m{seq~3} will locally -% assign \m{seq~1} the concatenation of \m{seq~2} and \m{seq~3}. +% \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_nopar:Npn \seq_concat:NNN #1#2#3 { - \tl_set:Nx #1 { \exp_not:V #2 \exp_not:V #3 } -} -\cs_generate_variant:Nn \seq_concat:NNN {ccc} +\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_gconcat:NNN,\seq_gconcat:ccc} -% |\seq_gconcat:NNN| \m{seq~1} \m{seq~2} \m{seq~3} will globally -% assign \m{seq~1} the concatenation of \m{seq~2} and \m{seq~3}. +% \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_nopar:Npn \seq_gconcat:NNN #1#2#3 { - \tl_gset:Nx #1 { \exp_not:V #2 \exp_not:V #3 } -} -\cs_generate_variant:Nn \seq_gconcat:NNN {ccc} +\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{Predicates and conditionals} +% \subsection{Breaking sequence functions} % -% \begin{macro}{\seq_if_empty_p:N,\seq_if_empty_p:c} -% \begin{macro}[TF]{\seq_if_empty:N,\seq_if_empty:c} -% A predicate which evaluates to |\c_true_bool| iff the sequence is empty. +% \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} -\prg_new_eq_conditional:NNn \seq_if_empty:N \tl_if_empty:N {p,TF,T,F} -\prg_new_eq_conditional:NNn \seq_if_empty:c \tl_if_empty:c {p,TF,T,F} +\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_if_empty_err:N} -% Signals an error if the sequence is empty. +% \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_nopar:Npn \seq_if_empty_err:N #1 { - \if_meaning:w #1 \c_empty_tl +\cs_new_eq:NN \seq_map_break: \seq_break: +\cs_new_eq:NN \seq_map_break:n \seq_break:n % \end{macrocode} -% As I said before, I don't think we need to provide checks for this -% kind of error, since it is a severe internal macro package error -% that can not be produced by the user directly. Can it? So the -% next line of code should be probably removed. -% (Will: I have no idea what this comment means.) +% \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} - \tl_clear:N \l_kernel_testa_tl % catch prefixes - \msg_kernel_bug:x {Empty~sequence~`\token_to_str:N#1'} - \fi: -} +\cs_new_eq:NN \seq_break_point:n \use:n % \end{macrocode} % \end{macro} % -% \begin{macro}[TF]{\seq_if_in:Nn,\seq_if_in:NV,\seq_if_in:cn, -% \seq_if_in:cV,\seq_if_in:co,\seq_if_in:cx} -% |\seq_if_in:NnTF| \m{seq}\m{item} \m{true~case} \m{false~case} -% will check whether \m{item} is in \m{seq} and then either execute -% the \m{true~case} or the \m{false~case}. \m{true~case} and -% \m{false~case} may contain incomplete |\if_charcode:w| -% statements. -% -% Note that |##2| in the definition below for "\seq_tmp:w" contains -% exactly one token which we can compare with |\q_no_value|. +% \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} -\prg_new_protected_conditional:Nnn \seq_if_in:Nn {TF,T,F} { - \cs_set:Npn \seq_tmp:w ##1 \seq_elt:w #2 \seq_elt_end: ##2##3 \q_stop { - \if_meaning:w \q_no_value ##2 - \prg_return_false: \else: \prg_return_true: \fi: +\cs_new_protected_nopar:Npn \seq_if_empty_err_break:N #1 + { + \tex_ifx:D #1 \c_empty_tl + \msg_kernel_bug:x { Empty~sequence~\token_to_str:N #1 } + \exp_after:wN \seq_break: + \tex_fi:D } - \exp_after:wN \seq_tmp:w #1 \seq_elt:w #2 \seq_elt_end: \q_no_value \q_stop -} -% \end{macrocode} -% \begin{macrocode} -\cs_generate_variant:Nn \seq_if_in:NnTF { NV, cV, co, c, cx} -\cs_generate_variant:Nn \seq_if_in:NnT { NV, cV, co, c, cx} -\cs_generate_variant:Nn \seq_if_in:NnF { NV, cV, co, c, cx} % \end{macrocode} % \end{macro} % -% \subsection{Getting data out} +% \subsection{Mapping to sequences} % -% \begin{macro}{\seq_get:NN} -% \begin{macro}{\seq_get:cN} -% \begin{macro}{\seq_get_aux:w} -% |\seq_get:NN |\meta{sequence}\meta{cmd} defines \meta{cmd} to be the -% left-most element of \meta{sequence}. +% \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_protected_nopar:Npn \seq_get:NN #1 { - \seq_if_empty_err:N #1 - \exp_after:wN \seq_get_aux:w #1 \q_stop -} -\cs_new_protected:Npn \seq_get_aux:w \seq_elt:w #1 \seq_elt_end: #2 \q_stop #3 { - \tl_set:Nn #3 {#1} -} -\cs_generate_variant:Nn \seq_get:NN {c} +\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} -% \end{macro} % -% \begin{macro}{\seq_pop_aux:nnNN} -% \begin{macro}{\seq_pop_aux:w} -% |\seq_pop_aux:nnNN| \meta{def$\sb1$} \meta{def$\sb2$} \meta{sequence} -% \meta{cmd} assigns the left_most element of \meta{sequence} to -% \meta{cmd} using \meta{def$\sb2$}, and assigns the tail of -% \meta{sequence} to \meta{sequence} using \meta{def$\sb1$}. +% \begin{macro}[aux]{\g_seq_nesting_depth_int} +% A counter to keep track of nested functions. % \begin{macrocode} -\cs_new_protected:Npn \seq_pop_aux:nnNN #1#2#3 { - \seq_if_empty_err:N #3 - \exp_after:wN \seq_pop_aux:w #3 \q_stop #1#2#3 -} -\cs_new_protected:Npn \seq_pop_aux:w - \seq_elt:w #1 \seq_elt_end: #2\q_stop #3#4#5#6 { - #3 #5 {#2} - #4 #6 {#1} -} +\int_new:N \g_seq_nesting_depth_int % \end{macrocode} % \end{macro} -% \end{macro} % -% \begin{macro}{\seq_show:N} -% \begin{macro}{\seq_show:c} +% \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_eq:NN \seq_show:N \tl_show:N -\cs_new_eq:NN \seq_show:c \tl_show:c +\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_display:N} -% \begin{macro}{\seq_display:c} +% \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_nopar:Npn \seq_display:N #1 { - \iow_term:x { Sequence~\token_to_str:N #1~contains~ - the~elements~(without~outer~braces): } - \toks_clear:N \l_tmpa_toks - \seq_map_inline:Nn #1 { - \toks_if_empty:NF \l_tmpa_toks { - \toks_put_right:Nx \l_tmpa_toks {^^J>~} - } - \toks_put_right:Nx \l_tmpa_toks { - \c_space_tl \iow_char:N \{ \exp_not:n {##1} \iow_char:N \} - } +\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: } } - \toks_show:N \l_tmpa_toks -} -\cs_generate_variant:Nn \seq_display:N {c} +\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} % -% \subsection{Putting data in} +% The same functions as for sequences, but with the correct naming. % -% \begin{macro}{\seq_put_aux:Nnn} -% \begin{macro}{\seq_put_aux:w} -% |\seq_put_aux:Nnn| \meta{sequence} \meta{left} \meta{right} adds the -% elements specified by \meta{left} to the left of \meta{sequence}, and -% those specified by \meta{right} to the right. +% \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_protected:Npn \seq_put_aux:Nnn #1 { - \exp_after:wN \seq_put_aux:w #1 \q_stop #1 -} -\cs_new_protected:Npn \seq_put_aux:w #1\q_stop #2#3#4 { \tl_set:Nn #2 {#3#1#4} } +\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_put_left:Nn} -% \begin{macro}{\seq_put_left:NV} -% \begin{macro}{\seq_put_left:No} -% \begin{macro}{\seq_put_left:Nx} -% \begin{macro}{\seq_put_left:cn} -% \begin{macro}{\seq_put_left:cV} -% \begin{macro}{\seq_put_left:co} -% \begin{macro}{\seq_put_right:Nn} -% \begin{macro}{\seq_put_right:No} -% \begin{macro}{\seq_put_right:NV} -% \begin{macro}{\seq_put_right:Nx} -% \begin{macro}{\seq_put_right:cn} -% \begin{macro}{\seq_put_right:cV} -% \begin{macro}{\seq_put_right:co} -% Here are the usual operations for adding to the left and right. -% \begin{macrocode} -\cs_new_protected:Npn \seq_put_left:Nn #1#2 { - \seq_put_aux:Nnn #1 {\seq_elt:w #2\seq_elt_end:} {} -} -% \end{macrocode} -% We can't put in a |\prg_do_nothing:| instead of |{}| above since this argument -% is passed literally (and we would end up with many |\prg_do_nothing:|s inside -% the sequences). -% \begin{macrocode} -\cs_generate_variant:Nn \seq_put_left:Nn {NV,No,Nx,c,cV,co} -% \end{macrocode} +% \begin{macro}{\seq_get_left:NN, \seq_get_left:cN} +% \UnitTested +% \begin{macro}[aux]{\seq_get_left_aux:Nw} +% 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:Npn \seq_put_right:Nn #1#2{ - \seq_put_aux:Nnn #1{}{\seq_elt:w #2\seq_elt_end:}} -% \end{macrocode} -% \begin{macrocode} -\cs_generate_variant:Nn \seq_put_right:Nn {NV,No,Nx,c,cV,co} +\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:Nw #1 \q_stop #2 + \seq_break_point:n { } + } +\cs_new_protected:Npn \seq_get_left_aux:Nw \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} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \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:Nw} +% 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:Nw #2 \q_stop #1#2#3 + \seq_break_point:n { } + } +\cs_new_protected:Npn \seq_pop_left_aux:Nw \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_gput_left:Nn} -% \begin{macro}{\seq_gput_left:NV} -% \begin{macro}{\seq_gput_left:No} -% \begin{macro}{\seq_gput_left:Nx} -% \begin{macro}{\seq_gput_left:cn} -% \begin{macro}{\seq_gput_left:cV} -% \begin{macro}{\seq_gput_left:co} -% \begin{macro}{\seq_gput_right:Nn} -% \begin{macro}{\seq_gput_right:NV} -% \begin{macro}{\seq_gput_right:No} -% \begin{macro}{\seq_gput_right:Nx} -% \begin{macro}{\seq_gput_right:cn} -% \begin{macro}{\seq_gput_right:cV} -% \begin{macro}{\seq_gput_right:co} -% \begin{macrocode} -\cs_new_protected:Npn \seq_gput_left:Nn { -%<*check> - \pref_global_chk: -%</check> -%<*!check> - \pref_global:D -%</!check> - \seq_put_left:Nn -} -% \end{macrocode} +% \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:Npn \seq_gput_right:Nn { -%<*check> - \pref_global_chk: -%</check> -%<*!check> - \pref_global:D -%</!check> - \seq_put_right:Nn +\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} -% \begin{macrocode} -\cs_generate_variant:Nn \seq_gput_left:Nn {NV,No,Nx,c,cV,co} -% \end{macrocode} -% \begin{macrocode} -\cs_generate_variant:Nn \seq_gput_right:Nn {NV,No,Nx,c,cV,co} -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} % \end{macro} % \end{macro} % \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% \end{macro} -% -% -% \subsection{Mapping} % -% \begin{macro}{\seq_map_variable:NNn} -% \begin{macro}{\seq_map_variable:cNn} -% \begin{macro}[aux]{\seq_map_variable_aux:Nnw} -% Nothing spectacular here. +% \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_get_right_aux:NNN, \seq_get_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 |{ \tex_iffalse:D } \tex_fi:D| \ldots |\tex_iffalse:D { \tex_fi:D }| +% 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{tex_iffalse:D} +% 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:Npn \seq_map_variable_aux:Nnw #1#2 \seq_elt:w #3 \seq_elt_end: { - \tl_set:Nn #1 {#3} - \quark_if_nil:NT #1 \seq_map_break: - #2 - \seq_map_variable_aux:Nnw #1{#2} -} -\cs_new_protected:Npn \seq_map_variable:NNn #1#2#3 { - \tl_set:Nn #2 {\seq_map_variable_aux:Nnw #2{#3}} - \exp_after:wN #2 #1 \seq_elt:w \q_nil\seq_elt_end: \q_stop -} -\cs_generate_variant:Nn \seq_map_variable:NNn {c} +\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 { \tex_iffalse:D } \tex_fi:D + \exp_after:wN \exp_after:wN \exp_after:wN \seq_get_right_loop:nn + \exp_after:wN \use_none:n #2 + { + \tex_iffalse:D { \tex_fi:D } + \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} % -% \begin{macro}{\seq_map_break:} -% \begin{macro}{\seq_map_break:n} -% Terminate a mapping function at the point of execution. The latter -% takes an argument to be executed after cleaning up the map. +% \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_map_break: \use_none_delimit_by_q_stop:w -\cs_new_eq:NN \seq_map_break:n \use_i_delimit_by_q_stop:nw +\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{Sequence conditionals} % -% \begin{macro}{\seq_map_function:NN} -% \begin{macro}{\seq_map_function:cN} -% |\seq_map_function:NN| \meta{sequence} \meta{cmd} applies \meta{cmd} to each -% element of \meta{sequence}, from left to right. Since we don't have -% braces, this implementation is not very efficient. It might be -% better to say that \meta{cmd} must be a function with one argument -% that is delimited by |\seq_elt_end:|. +% \begin{macro}[pTF]{\seq_if_empty:N, \seq_if_empty:c} +% \UnitTested +% Simple copies from the token list variable material. % \begin{macrocode} -\cs_new_protected_nopar:Npn \seq_map_function:NN #1#2 { - \cs_set:Npn \seq_elt:w ##1 \seq_elt_end: {#2{##1}} - #1 \use_none:n \q_stop - \cs_set_eq:NN \seq_elt:w \ERROR -} -\cs_generate_variant:Nn \seq_map_function:NN {c} +\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} -% \end{macro} % -% \begin{macro}{\seq_map_inline:Nn} -% \begin{macro}{\seq_map_inline:cn} -% When no braces are used, this version of mapping seems more -% natural. +% \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} -\cs_new_protected_nopar:Npn \seq_map_inline:Nn #1#2 { - \cs_set:Npn \seq_elt:w ##1 \seq_elt_end: {#2} - #1 \use_none:n \q_stop - \cs_set_eq:NN \seq_elt:w \ERROR -} -\cs_generate_variant:Nn \seq_map_inline:Nn {c} +\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} + \tex_ifx:D \l_seq_tmpa_tl \l_seq_tmpb_tl + \exp_after:wN \seq_if_in_aux: + \tex_fi:D + } + #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{Manipulation} +% \subsection{Modifying sequences} % -% \begin{macro}[aux]{\l_clist_remove_clist} -% A common scratch space for the removal routines. +% \begin{macro}[aux]{\l_seq_remove_seq} +% An internal sequence for the removal routines. % \begin{macrocode} \seq_new:N \l_seq_remove_seq % \end{macrocode} -% \end{macro} +% \end{macro} % -% \begin{macro}[aux]{\seq_remove_duplicates_aux:NN} -% \begin{macro}[aux]{\seq_remove_duplicates_aux:n} -% \begin{macro}{\seq_remove_duplicates:N} -% \begin{macro}{\seq_gremove_duplicates:N} -% Copied from "\clist_remove_duplicates". +% \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_aux:NN #1#2 { - \seq_clear:N \l_seq_remove_seq - \seq_map_function:NN #2 \seq_remove_duplicates_aux:n - #1 #2 \l_seq_remove_seq -} -\cs_new_protected:Npn \seq_remove_duplicates_aux:n #1 { - \seq_if_in:NnF \l_seq_remove_seq {#1} { - \seq_put_right:Nn \l_seq_remove_seq {#1} +\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 } -} -% \end{macrocode} -% \begin{macrocode} -\cs_new_protected_nopar:Npn \seq_remove_duplicates:N { - \seq_remove_duplicates_aux:NN \seq_set_eq:NN -} -\cs_new_protected_nopar:Npn \seq_gremove_duplicates:N { - \seq_remove_duplicates_aux:NN \seq_gset_eq:NN -} +\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} -% \end{macro} -% -% \subsection{Sequence stacks} -% -% \begin{macro}{\seq_push:Nn} -% \begin{macro}{\seq_push:NV} -% \begin{macro}{\seq_push:No} -% \begin{macro}{\seq_push:cn} -% \begin{macro}{\seq_pop:NN} -% \begin{macro}{\seq_pop:cN} -% Since sequences can be used as stacks, we ought to have both -% `push' and `pop'. In most cases they are nothing more then new -% names for old functions. -% \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:No \seq_put_left:No -\cs_new_eq:NN \seq_push:cn \seq_put_left:cn -\cs_new_protected_nopar:Npn \seq_pop:NN { \seq_pop_aux:nnNN \tl_set:Nn \tl_set:Nn } -\cs_generate_variant:Nn \seq_pop:NN {c} -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} % \end{macro} % \end{macro} % \end{macro} % -% \begin{macro}{\seq_gpush:Nn} -% \begin{macro}{\seq_gpush:NV} -% \begin{macro}{\seq_gpush:No} -% \begin{macro}{\seq_gpush:cn} -% \begin{macro}{\seq_gpush:Nv} -% \begin{macro}{\seq_gpop:NN} -% \begin{macro}{\seq_gpop:cN} -% I don't agree with Denys that one needs only local stacks, -% actually I believe that one will probably need the functions -% here more often. In case of |\seq_gpop:NN| the value is -% nevertheless returned locally. +% \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_eq:NN \seq_gpush:Nn \seq_gput_left:Nn -\cs_new_protected_nopar:Npn \seq_gpop:NN { \seq_pop_aux:nnNN \tl_gset:Nn \tl_set:Nn } -\cs_generate_variant:Nn \seq_gpush:Nn {NV,No,c,Nv} -\cs_generate_variant:Nn \seq_gpop:NN {c} +\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} + { + \tex_iffalse:D { \tex_fi:D } + \tl_set:Nn \l_seq_tmpb_tl {##1} + #1 #2 + { \tex_iffalse:D } \tex_fi:D + \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} +% +% \section{Viewing sequences} +% +% \begin{macro}[aux]{\l_seq_show_tl} +% Used to store the material for display. +% \begin{macrocode} +\tl_new:N \l_seq_show_tl +% \end{macrocode} % \end{macro} +% +% \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} % -% \begin{macro}{\seq_top:NN} -% \begin{macro}{\seq_top:cN} -% Looking at the top element of the stack without removing it is -% done with this operation. +% \subsection{Depreciated 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:NN -\cs_new_eq:NN \seq_top:cN \seq_get:cN +\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} -% \end{macro} -% % +% \begin{macro}{\seq_display:N, \seq_display:c} +% An older name for \cs{seq_show:N}. % \begin{macrocode} -%</initex|package> +\cs_new_eq:NN \seq_display:N \seq_show:N +\cs_new_eq:NN \seq_display:c \seq_show:c % \end{macrocode} +% \end{macro} % -% Show token usage: % \begin{macrocode} -%<*showmemory> -%\showMemUsage -%</showmemory> +%</initex|package> % \end{macrocode} % % \end{implementation} -% \PrintIndex % -% \endinput +% \PrintIndex
\ No newline at end of file |