diff options
author | Karl Berry <karl@freefriends.org> | 2007-05-22 17:46:23 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2007-05-22 17:46:23 +0000 |
commit | f4eb27d3314d15838f674a3872000159d029f88b (patch) | |
tree | 6e9ab33c5a2d702912b4a969ade4e4e2ac586d62 /Master/texmf-dist/source/latex/expl3/l3clist.dtx | |
parent | 14af3f447439750920f754792b89f113d019076a (diff) |
update expl3
git-svn-id: svn://tug.org/texlive/trunk@4335 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/expl3/l3clist.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/expl3/l3clist.dtx | 1082 |
1 files changed, 1082 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/expl3/l3clist.dtx b/Master/texmf-dist/source/latex/expl3/l3clist.dtx new file mode 100644 index 00000000000..f8fdba275bb --- /dev/null +++ b/Master/texmf-dist/source/latex/expl3/l3clist.dtx @@ -0,0 +1,1082 @@ +% \iffalse +%% File: l3clist.dtx Copyright (C) 2005-2006 Frank Mittelbach, 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/cgi-bin/cvsweb.cgi/ +%% +%% 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 LaTeX Project Team. +%% +%% ----------------------------------------------------------------------- +% +%<package>\RequirePackage{l3names} +%<*dtx> +%\fi +\def\GetIdInfo$Id: #1.dtx #2 #3-#4-#5 #6 #7$#8{% + \def\fileversion{#2}% + \def\filedate{#3/#4/#5}% + \ProvidesFile{#1.dtx}[#3/#4/#5 v#2 #8]% +} +%\iffalse +%</dtx> +%\fi +\GetIdInfo$Id: l3clist.dtx 573 2006-08-21 20:59:37Z morten $ + {L3 Experimental comma separated lists} +% +% \iffalse +%<*driver> +\documentclass{l3doc} +\begin{document} +\DocInput{l3clist.dtx} +\end{document} +%</driver> +% \fi +% +% +% +% \title{The \textsf{l3clist} package\thanks{This file +% has version number \fileversion, last +% revised \filedate.}\\ +% Comma separated lists} +% \author{Frank Mittelbach} +% \date{\filedate} +% \maketitle +% +% +% +% \section{Comma lists} +% +% \LaTeX3 implements a data type called `clist (comma-lists)'. 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 comma-list might contain any tokens except for commas that +% are used to structure comma-lists (braces are need if commas are +% part of the value). It is also possible to map functions on such +% comma-lists so that they are executed for every item of the comma-list. +% +% All functions that return items from a comma-list in some \m{tlp} assume +% that the \m{tlp} 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 comma-list can currently be done with +% either something like "\clist_put_left:Nn" or with a ``stack'' function +% like "\clist_push:Nn" which has the same effect. Maybe one should +% therefore remove the ``left'' functions totally. +% +% \subsection{Functions} +% +% \begin{function}{% +% \clist_new:N | +% \clist_new:c | +% } +% \begin{syntax} +% "\clist_new:N" <comma-list> +% \end{syntax} +% Defines <comma-list> to be a variable of type clist. +% \end{function} +% +% \begin{function}{% +% \clist_clear:N | +% \clist_clear:c | +% \clist_gclear:N | +% \clist_gclear:c | +% } +% \begin{syntax} +% "\clist_clear:N" <comma-list> +% \end{syntax} +% These functions locally or globally clear <comma-list>. +% \end{function} +% +% \begin{function}{% +% \clist_put_left:Nn | +% \clist_put_left:No | +% \clist_put_left:Nx | +% \clist_put_left:cn | +% \clist_put_right:Nn | +% \clist_put_right:No | +% \clist_put_right:Nx | +% } +% \begin{syntax} +% "\clist_put_left:Nn" <comma-list> <token list> +% \end{syntax} +% Locally appends <token list> as a single item to the left +% or right of <comma-list>. <token list> might get expanded before +% appending. +% \end{function} +% +% \begin{function}{% +% \clist_gput_left:Nn | +% \clist_gput_right:Nn | +% \clist_gput_right:No | +% \clist_gput_right:cn | +% \clist_gput_right:co | +% \clist_gput_right:cc | +% } +% \begin{syntax} +% "\clist_gput_left:Nn" <comma-list> <token list> +% \end{syntax} +% Globally appends <token list> as a single item to the left +% or right of <comma-list>. +% \end{function} +% +% \begin{function}{% +% \clist_get:NN | +% \clist_get:cN | +% } +% \begin{syntax} +% "\clist_get:NN" <comma-list> <tlp> +% \end{syntax} +% Functions that locally assign the left-most item of <comma-list> to the +% token list pointer <tlp>. Item is not removed from <comma-list>! If you +% need a global return value you need to code something like this: +% \begin{quote} +% "\clist_get:NN" <comma-list> "\l_tmpa_tlp" \\ +% "\tlp_gset_eq:NN" <global tlp> "\l_tmpa_tlp" +% \end{quote} +% But if this kind of construction is used often enough a separate +% function should be provided. +% \end{function} +% +% \begin{function}{% +% \clist_set_eq:NN +% } +% \begin{syntax} +% "\clist_set_eq:NN" <clist1> <clist2> +% \end{syntax} +% Function that locally makes <clist1> identical to <clist2>. +% \end{function} +% +% +% \begin{function}{% +% \clist_gset_eq:NN | +% \clist_gset_eq:cN | +% \clist_gset_eq:Nc | +% \clist_gset_eq:cc +% } +% \begin{syntax} +% "\clist_gset_eq:NN" <clist1> <clist2> +% \end{syntax} +% Function that globally makes <clist1> identical to <clist2>. +% \end{function} +% +% +% \begin{function}{% +% \clist_concat:NNN | +% \clist_gconcat:NNN | +% \clist_gconcat:NNc | +% \clist_gconcat:ccc | +% } +% \begin{syntax} +% "\clist_gconcat:NNN" <clist1> <clist2> <clist3> +% \end{syntax} +% Function that concatenates <clist2> and <clist3> and globally assigns the +% result to <clist1>. +% \end{function} +% +% +% \begin{function}{% +% \clist_remove_duplicates:N | +% \clist_gremove_duplicates:N | +% } +% \begin{syntax} +% "\clist_gremove_duplicates:N" <clist> +% \end{syntax} +% Function that removes any duplicate entries in <clist>. +% \end{function} +% +% \begin{function}{% +% \clist_use:N | +% \clist_use:c +% } +% \begin{syntax} +% "\clist_use:N" <clist> +% \end{syntax} +% Function that inserts the <clist> into the processing stream. Mainly +% useful if one knows what the <clist> contains, e.g., for displaying +% the content of template parameters. +% \end{function} +% +% +% \subsection{Mapping functions} +% +% +% We provide three types of mapping functions, each with their own +% strengths. The "\clist_map_function:NN" is expandable whereas +% "\clist_map_inline:Nn" type uses "##1" as a placeholder for the +% current item in \m{clist}. Finally we have the +% "\clist_map_variable:NNn" type which uses a user-defined variable as +% placeholder. Both the |_inline| and |_variable| versions are nestable. +% +% +% \begin{function}{\clist_map_function:NN| +% \clist_map_function:cN| +% \clist_map_function:nN +% } +% \begin{syntax} +% "\clist_map_function:NN" <comma-list> <function> +% \end{syntax} +% This function applies <function> (which must be a function with one +% argument) to every item of <comma-list>. <function> is not executed +% within a sub-group so that side effects can be achieved locally. The +% operation is expandable which means that it can be used within write +% operations etc. +% \end{function} +% +% \begin{function}{\clist_map_inline:Nn | +% \clist_map_inline:cn | +% \clist_map_inline:nn | +% } +% \begin{syntax} +% "\clist_map_inline:Nn" <comma-list> "{" <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 placeholder for +% this argument)) to every item of <comma-list>. <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. These functions can be nested. +% \end{function} +% +% +% \begin{function}{\clist_map_variable:NNn | +% \clist_map_variable:cNn | +% \clist_map_variable:nNn | +% } +% \begin{syntax} +% "\clist_map_variable:NNn" <comma-list> <temp-var> "{" <action> "}" +% \end{syntax} +% Assigns <temp-var> to each element in <clist> and then executes +% <action> which should contain <temp-var>. As the +% operation performs an assignment, it is not expandable. +% \begin{texnote} +% These functions resemble the \LaTeXe{} function \tn{@for} but does +% not borrow the somewhat strange syntax. +% \end{texnote} +% \end{function} +% +% \begin{function}{% +% \clist_map_break:w | +% } +% \begin{syntax} +% "\clist_map_break:w" +% \end{syntax} +% For breaking out of a loop. To be used inside "TF" type functions as +% in the example below. +% \begin{verbatim} +% \def_new:Npn \test_function:n #1 { +% \int_compare:nNnTF {#1}> 3 {\clist_map_break:w}{``#1''} +% } +% \clist_map_function:nN {1,2,3,4,5,6,7,8}\test_function:n +% \end{verbatim} +% This would return "``1''``2''``3''". +% \end{function} +% +% +% \subsection{Predicates and conditionals} +% +% \begin{function}{\clist_if_empty_p:N} +% \begin{syntax} +% "\clist_if_empty_p:N" <comma-list> +% \end{syntax} +% This predicate returns `true' if <comma-list> is `empty' i.e., doesn't +% contain any tokens. +% \end{function} +% +% \begin{function}{% +% \clist_if_empty:NTF | +% \clist_if_empty:cTF | +% \clist_if_empty:NF | +% \clist_if_empty:cF | +% } +% \begin{syntax} +% "\clist_if_empty:NTF" <comma-list> "{" <true code> "}{" <false code> "}" +% \end{syntax} +% Set of conditionals that test whether or not a particular <comma-list> +% is empty and if so executes either <true code> or <false code>. +% \end{function} +% +% \begin{function}{% +% \clist_if_eq:NNTF | +% } +% \begin{syntax} +% "\clist_if_eq:NNTF" <comma-list1> <comma-list2> "{" <true code> +% "}{" <false code> "}" +% \end{syntax} +% Check if <comma-list1> and <comma-list2> are equal and execute +% either <true code> or <false code> accordingly. +% \end{function} +% +% \begin{function}{% +% \clist_if_in:NnTF | +% \clist_if_in:NoTF | +% \clist_if_in:cnTF | +% \clist_if_in:coTF | +% } +% \begin{syntax} +% "\clist_if_in:NnTF" <comma-list> "{" <item> "}{" <true code> "}{" +% <false code> "}" +% \end{syntax} +% Function that tests if <item> is in <comma-list>. Depending on the result +% either <true code> or <false code> is executed. +% \end{function} +% +% \subsection{Internal functions} +% +% \begin{function}{\clist_if_empty_err:N} +% \begin{syntax} +% "\clist_if_empty_err:N" <comma-list> +% \end{syntax} +% Signals an \LaTeX3 error if <comma-list> is empty. +% \end{function} +% +% \begin{function}{\clist_pop_aux:nnNN} +% \begin{syntax} +% "\clist_pop_aux:nnNN" <assign1> <assign2> <comma-list> <tlp> +% \end{syntax} +% Function that assigns the left-most item of <comma-list> to <tlp> using +% <assign1> and assigns the tail to <comma-list> using <assign2>. This +% function could be used to implement a global return function. +% \end{function} +% +% \begin{function}{% +% \clist_get_aux:w | +% \clist_pop_aux:w | +% \clist_pop_auxi:w | +% \clist_put_aux:NNnnNn | +% } +% \begin{syntax}\end{syntax} +% Functions used to implement put and get operations. They are not for +% meant for direct use. +% \end{function} +% +% +% +% \begin{function}{% +% \clist_map_function_aux:Nw | +% \clist_map_inline_aux:Nw | +% \clist_map_variable_aux:Nnw | +% } +% \begin{syntax}\end{syntax} +% Internal helper functions for the <clist> mapping functions. +% \end{function} +% +% +% \begin{function}{% +% \clist_concat_aux:NNNN | +% \clist_remove_duplicates_aux:NN | +% \clist_remove_duplicates_aux:n | +% \l_clist_remove_duplicates_clist | +% } +% \begin{syntax}\end{syntax} +% Functions that help concatenate <clist>s and remove duplicate +% elements from a <clist>. +% \end{function} +% +% +% +% \subsection{Comma list Stacks} +% +% Special comma-lists in \LaTeX3 are `stacks' with their usual operations +% of `push', `pop', and `top'. They are internally implemented as +% comma-lists and share some of the functions (like "\clist_new:N" etc.) +% +% +% \begin{function}{% +% \clist_push:Nn | +% \clist_push:No | +% \clist_push:cn | +% \clist_gpush:Nn | +% \clist_gpush:No | +% \clist_gpush:cn | +% } +% \begin{syntax} +% "\clist_push:Nn" <stack> "{" <token list> "}" +% \end{syntax} +% Locally or globally pushes <token list> as a single item onto the +% <stack>. <token list> might get expanded before the operation. +% \end{function} +% +% \begin{function}{% +% \clist_pop:NN | +% \clist_pop:cN | +% \clist_gpop:NN | +% \clist_gpop:cN | +% } +% \begin{syntax} +% "\clist_pop:NN" <stack> <tlp> +% \end{syntax} +% Functions that assign the top item of <stack> to the token +% list pointer <tlp> and removes it from <stack>! +% \end{function} +% +% \begin{function}{% +% \clist_top:NN | +% \clist_top:cN | +% } +% \begin{syntax} +% "\clist_top:NN" <stack> <tlp> +% \end{syntax} +% Functions that locally assign the top item of <stack> to the token +% list pointer <tlp>. Item is not removed from <stack>! +% \end{function} +% +% \StopEventually{} +% +% Use "clist" functions. +% +% +% \subsection {The Implementation} +% +% We start by ensuring that the required packages are loaded. +% \begin{macrocode} +%<*package> +\NeedsTeXFormat{LaTeX2e} +%<!check>\RequirePackage{l3prg,l3quark} +%<check>\RequirePackage{l3chk} +%</package> +%<*initex|package> +% \end{macrocode} +% +% +% \begin{macro}{\clist_new:N} +% \begin{macro}{\clist_new:c} +% Comma-Lists are implemented using token lists. +% \begin{macrocode} +\def_new:Npn \clist_new:N #1{\tlp_new:Nn #1{}} +\def_new:Npn \clist_new:c {\exp_args:Nc \clist_new:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_clear:N} +% \begin{macro}{\clist_clear:c} +% \begin{macro}{\clist_gclear:N} +% \begin{macro}{\clist_gclear:c} +% Clearing a comma-list is the same as clearing a token list. +% \begin{macrocode} +\let_new:NN \clist_clear:N \tlp_clear:N +\let_new:NN \clist_clear:c \tlp_clear:c +\let_new:NN \clist_gclear:N \tlp_gclear:N +\let_new:NN \clist_gclear:c \tlp_gclear:c +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\clist_set_eq:NN} +% We can set one \meta{clist} equal to another. +% \begin{macrocode} +\let_new:NN \clist_set_eq:NN \let:NN +% \end{macrocode} +% \end{macro} +% +% +% \begin{macro}{\clist_set_eq:NN} +% \begin{macro}{\clist_set_eq:cN} +% \begin{macro}{\clist_set_eq:Nc} +% \begin{macro}{\clist_set_eq:cc} +% An of course globally which seems to be needed far more often. +% \begin{macrocode} +\let_new:NN \clist_gset_eq:NN \glet:NN +\def_new:Npn \clist_gset_eq:cN {\exp_args:Nc \clist_gset_eq:NN} +\def_new:Npn \clist_gset_eq:Nc {\exp_args:NNc \clist_gset_eq:NN} +\def_new:Npn \clist_gset_eq:cc {\exp_args:Ncc \clist_gset_eq:NN} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\clist_if_empty_p:N} +% A predicate which evaluates to |\c_true| iff the comma-list is empty. +% \begin{macrocode} +\let_new:NN \clist_if_empty_p:N \tlp_if_empty_p:N +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\clist_if_empty:NTF} +% \begin{macro}{\clist_if_empty:NT} +% \begin{macro}{\clist_if_empty:NF} +% \begin{macro}{\clist_if_empty:cTF} +% \begin{macro}{\clist_if_empty:cT} +% \begin{macro}{\clist_if_empty:cF} +% |\clist_if_empty:NTF|\m{clist}\m{true~case}\m{false~case} will check +% whether the \m{clist} is empty and then select one of the other +% arguments. |\clist_if_empty:cTF| turns its first argument into a +% control comma-list to get the name of the comma-list. +% \begin{macrocode} +\def_test_function_new:npn {clist_if_empty:N}#1{\if_meaning:NN#1\c_empty_tlp} +\def_new:Npn \clist_if_empty:cTF {\exp_args:Nc\clist_if_empty:NTF} +\def_new:Npn \clist_if_empty:cT {\exp_args:Nc\clist_if_empty:NT} +\def_new:Npn \clist_if_empty:cF {\exp_args:Nc\clist_if_empty:NF} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\clist_if_empty_err:N} +% Signals an error if the comma-list is empty. +% \begin{macrocode} +\def_new:Npn \clist_if_empty_err:N #1{ + \if_meaning:NN#1\c_empty_tlp + \tlp_clear:N \l_testa_tlp % catch prefixes + \err_latex_bug:x{Empty~comma-list~`\token_to_string:N#1'} + \fi:} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\clist_if_eq:NNTF} +% As comma lists are token list pointers internally this is just an +% alias. +% \begin{macrocode} +\let_new:NN \clist_if_eq:NNTF \tlp_if_eq:NNTF +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\clist_get:NN} +% \begin{macro}{\clist_get:cN} +% |\clist_get:NN |\zz{comma-list}\zz{cmd} defines \zz{cmd} to be the +% left-most element of \zz{comma-list}. +% \begin{macrocode} +\def_new:Npn \clist_get:NN #1{ + \clist_if_empty_err:N #1 + \exp_after:NN\clist_get_aux:w #1,\q_stop} +% \end{macrocode} +% \begin{macrocode} +\def_new:Npn \clist_get_aux:w #1,#2\q_stop #3{\tlp_set:Nn #3{#1}} +% \end{macrocode} +% \begin{macrocode} +\def_new:Npn \clist_get:cN {\exp_args:Nc \clist_get:NN} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_pop_aux:nnNN} +% \begin{macro}{\clist_pop_aux:w} +% \begin{macro}{\clist_pop_auxi:w} +% |\clist_pop_aux:nnNN| \zz{def$\sb1$} \zz{def$\sb2$} \zz{comma-list} +% \zz{cmd} assigns the left-most element of \zz{comma-list} to +% \zz{cmd} using \zz{def$\sb2$}, and assigns the tail of +% \zz{comma-list} to \zz{comma-list} using \zz{def$\sb1$}. +% \begin{macrocode} +\def_new:Npn \clist_pop_aux:nnNN #1#2#3{ + \clist_if_empty_err:N #3 + \exp_after:NN\clist_pop_aux:w #3,\q_nil\q_stop #1#2#3} +% \end{macrocode} +% \begin{macrocode} +\def_new:Npn \clist_pop_aux:w #1,#2\q_stop #3#4#5#6{ + #4#6{#1} + #3#5{#2} +% \end{macrocode} +% If there was only one element in the original clist, it now contains +% only |\q_nil|. +% \begin{macrocode} + \quark_if_nil:NTF #5 + { #3#5{} } + { \clist_pop_auxi:w #2 #3#5 } +} +% \end{macrocode} +% \begin{macrocode} +\def_new:Npn\clist_pop_auxi:w #1,\q_nil #2#3 {#2#3{#1}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_put_aux:NNnnNn} +% The generic put function. +% \begin{macrocode} +\def_new:Npn \clist_put_aux:NNnnNn #1#2#3#4#5#6{ +% \end{macrocode} +% When adding we have to distinguish between an empty \meta{clist} +% and one that contains at least one item (otherwise we accumulate +% commas). +% \begin{macrocode} + \clist_if_empty:NTF#5 {#1 #5{#6}} +% \end{macrocode} +% MH says: Perhaps we should make sure that empty arguments don't get +% on the stack as that is probably a mistake. That's what I've +% implemented here. Since |\tlist_if_empty:nF| is expandable prefixes +% are still allowed. +% \begin{macrocode} + { \tlist_if_empty:nF {#6}{ #2 #5{#3#6#4} } } +} +% \end{macrocode} +% \end{macro} +% \begin{macro}{\clist_put_left:Nn} +% \begin{macro}{\clist_put_left:No} +% \begin{macro}{\clist_put_left:Nx} +% \begin{macro}{\clist_put_left:cn} +% The operations for adding to the left. +% \begin{macrocode} +\def_new:Npn \clist_put_left:Nn { + \clist_put_aux:NNnnNn \tlp_set:Nn \tlp_put_left:Nn {} , +} +\def_new:Npn \clist_put_left:cn {\exp_args:Nc \clist_put_left:Nn} +\def_new:Npn \clist_put_left:No {\exp_args:NNo\clist_put_left:Nn} +\def_new:Npn \clist_put_left:Nx {\exp_args:Nnx\clist_put_left:Nn} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \begin{macro}{\clist_gput_left:Nn} +% Global versions. +% \begin{macrocode} +\def_new:Npn \clist_gput_left:Nn { + \clist_put_aux:NNnnNn \tlp_gset:Nn \tlp_gput_left:Nn {} , +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\clist_put_right:Nn} +% \begin{macro}{\clist_put_right:cn} +% \begin{macro}{\clist_put_right:No} +% \begin{macro}{\clist_put_right:Nx} +% Adding something to the right side is almost the same. +% \begin{macrocode} +\def_new:Npn \clist_put_right:Nn { + \clist_put_aux:NNnnNn \tlp_set:Nn \tlp_put_right:Nn , {} +} +\def_new:Npn \clist_put_right:cn {\exp_args:Nc \clist_put_right:Nn} +\def_new:Npn \clist_put_right:No {\exp_args:Nno\clist_put_right:Nn} +\def_new:Npn \clist_put_right:Nx {\exp_args:Nnx\clist_put_right:Nn} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_gput_right:Nn} +% \begin{macro}{\clist_gput_right:No} +% \begin{macro}{\clist_gput_right:cn} +% \begin{macro}{\clist_gput_right:co} +% \begin{macro}{\clist_gput_right:cc} +% \begin{macro}{\clist_gput_right:NC} +% An here the global variants. +% \begin{macrocode} +\def_new:Npn \clist_gput_right:Nn { + \clist_put_aux:NNnnNn \tlp_set:Nn \tlp_put_right:Nn , {} +} +\def_new:Npn \clist_gput_right:No {\exp_args:NNo \clist_gput_right:Nn} +\def_new:Npn \clist_gput_right:cn {\exp_args:Nc \clist_gput_right:Nn} +\def_new:Npn \clist_gput_right:co {\exp_args:Nco \clist_gput_right:Nn} +\def_new:Npn \clist_gput_right:cc {\exp_args:Ncc \clist_gput_right:Nn} +% \end{macrocode} +% \begin{macrocode} +\def_new:Npn \clist_gput_right:NC {\exp_args:NNC \clist_gput_right:Nn} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_map_function:nN} +% \begin{macro}{\clist_map_function:cN} +% \begin{macro}{\clist_map_function:NN} +% |\clist_map_function:NN| \zz{comma-list} \zz{cmd} applies \zz{cmd} to each +% element of \zz{comma-list}, from left to right. +% \begin{macrocode} +\def_new:Npn \clist_map_function:NN #1#2{ + \clist_if_empty:NF #1 + { + \exp_after:NN \clist_map_function_aux:Nw + \exp_after:NN #2 #1 , \q_nil , \q_stop + } +} +\def_new:Npn \clist_map_function:cN{\exp_args:Nc\clist_map_function:NN} +\def_new:Npn \clist_map_function:nN #1#2{ + \tlist_if_empty:nF {#1} + { \clist_map_function_aux:Nw #2 #1 , \q_nil , \q_stop } +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_map_function_aux:Nw} +% The general loop. Tests if we hit the first stop marker and exits if +% we did. If we didn't, place the function "#1" in front of the +% element "#2", which is surrounded by braces. +% \begin{macrocode} +\def_new:Npn \clist_map_function_aux:Nw #1#2,{ + \quark_if_nil:nT{#2} \clist_map_break:w + #1{#2} + \clist_map_function_aux:Nw #1 +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\clist_map_break:w} +% The break statement is easy: Just gobble everything op to the last +% of the two stop markers "\q_stop" waiting at the end and close the +% "\if_..." we're in. Technically this should get an "w" specifier, +% but it doesn't take any arguments when you call it -- at least not +% any you would expect. +% \begin{macrocode} +\let_new:NN \clist_map_break:w \use_none_delimit_by_q_stop:w +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\clist_map_inline:Nn} +% \begin{macro}{\clist_map_inline:cn} +% \begin{macro}{\clist_map_inline:nn} +% The inline type is faster but not expandable. In order to make it +% nestable, we use a counter to keep track of the nesting level so +% that all of the functions called have distict names. A simpler +% approach would of course be to use grouping and thus the save +% stack but then you lose the ability to do things locally. +% \begin{macrocode} +\int_new:N \l_clist_inline_level_int +\def_new:Npn \clist_map_inline:Nn #1#2{ + \clist_if_empty:NF #1 + { + \int_incr:N \l_clist_inline_level_int + \def:cpn {clist_map_inline_ \int_use:N \l_clist_inline_level_int :n} + ##1{#2} +% \end{macrocode} +% Recall that the |E| in |\exp_args:NcE| means `single token expanded +% once and no braces added'. It is a lot more efficient to carry over +% the special function rather than constructing the same csname over +% and over again, so we just do it once. We reuse +% |\clist_map_function_aux:Nw| for the actual loop. +% \begin{macrocode} + \exp_args:NcE \clist_map_function_aux:Nw + {clist_map_inline_ \int_use:N \l_clist_inline_level_int :n} + #1 , \q_nil , \q_stop + \int_decr:N \l_clist_inline_level_int + } +} +\def_new:Npn \clist_map_inline:cn{\exp_args:Nc\clist_map_inline:Nn} +\def_new:Npn \clist_map_inline:nn #1#2{ + \tlist_if_empty:nF {#1} + { + \int_incr:N \l_clist_inline_level_int + \def:cpn {clist_map_inline_ \int_use:N \l_clist_inline_level_int :n} + ##1{#2} + \exp_args:Nc \clist_map_function_aux:Nw + {clist_map_inline_ \int_use:N \l_clist_inline_level_int :n} + #1 , \q_nil , \q_stop + \int_decr:N \l_clist_inline_level_int + } +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\clist_map_variable:nNn} +% \begin{macro}{\clist_map_variable:NNn} +% \begin{macro}{\clist_map_variable:cNn} +% |\clist_map:NNn| \zz{comma-list} \zz{temp} \zz{action} assigns +% \zz{temp} to each element and executes \zz{action}. +% \begin{macrocode} +\def_new:Npn \clist_map_variable:nNn #1#2#3{ + \tlist_if_empty:nF{#1} + { + \clist_map_variable_aux:Nnw #2 {#3} #1 , \q_nil , \q_stop + } +} +\def_new:Npn \clist_map_variable:NNn {\exp_args:No \clist_map_variable:nNn} +\def_new:Npn \clist_map_variable:cNn {\exp_args:Nc \clist_map_variable:NNn} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_map_variable_aux:Nnw} +% The general loop. Assign the temp variable |#1| to the current item +% |#3| and then check if that's the stop marker. If it is, break the +% loop. If not, execute the action |#2| and continue. +% \begin{macrocode} +\def_new:Npn \clist_map_variable_aux:Nnw #1#2#3,{ + \def:Npn #1{#3} + \quark_if_nil:NT #1 \clist_map_break:w + #2 \clist_map_variable_aux:Nnw #1{#2} +} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\clist_concat_aux:NNNN} +% \begin{macro}{\clist_concat:NNN} +% \begin{macro}{\clist_gconcat:NNN} +% \begin{macro}{\clist_gconcat:NNc} +% \begin{macro}{\clist_gconcat:ccc} +% |\clist_gconcat:NNN| \m{clist~1} \m{clist~2} \m{clist~3} will globally +% assign \m{clist~1} the concatenation of \m{clist~2} and +% \m{clist~3}. +% \begin{macrocode} +\def_new:Npn \clist_concat_aux:NNNN #1#2#3#4{ + \toks_set:No \l_tmpa_toks {#3} + \toks_set:No \l_tmpb_toks {#4} + #1 #2 { + \toks_use:N \l_tmpa_toks +% \end{macrocode} +% Again the situation is a bit more complicated because of the use +% of commas between items, so if either list is empty we have to avoid +% adding a comma. +% \begin{macrocode} + \toks_if_empty:NF \l_tmpa_toks {\toks_if_empty:NF \l_tmpb_toks ,} + \toks_use:N \l_tmpb_toks + } +} +\def_new:Npn \clist_concat:NNN {\clist_concat_aux:NNNN \tlp_set:Nx} +\def_new:Npn \clist_gconcat:NNN {\clist_concat_aux:NNNN \tlp_gset:Nx} +% \end{macrocode} +% And the usual versions. +% \begin{macrocode} +\def_new:Npn \clist_gconcat:NNc{\exp_args:Nnnc\clist_gconcat:NNN} +\def_new:Npn \clist_gconcat:ccc{\exp_args:Nccc\clist_gconcat:NNN} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\clist_remove_duplicates_aux:NN} +% \begin{macro}{\clist_remove_duplicates_aux:n} +% \begin{macro}{\clist_remove_duplicates:N} +% \begin{macro}{\clist_gremove_duplicates:N} +% Removing duplicate entries in a \meta{clist} is fairly straight +% forward. We use a temporary variable and then go through the list +% from left to right. For each element check if the element is +% already present in the list. +% \begin{macrocode} +\def:Npn \clist_remove_duplicates_aux:NN #1#2 { + \clist_clear:N \l_clist_remove_duplicates_clist + \clist_map_function:NN #2 \clist_remove_duplicates_aux:n + #1 #2 \l_clist_remove_duplicates_clist +} +\def:Npn \clist_remove_duplicates_aux:n #1 { + \clist_if_in:NnTF \l_clist_remove_duplicates_clist {#1} {} + {\clist_put_right:Nn \l_clist_remove_duplicates_clist {#1}} +} +% \end{macrocode} +% The high level functions are just for telling if it should be a +% local or global setting. +% \begin{macrocode} +\def_new:Npn \clist_remove_duplicates:N { + \clist_remove_duplicates_aux:NN \clist_set_eq:NN +} +\def_new:Npn \clist_gremove_duplicates:N { + \clist_remove_duplicates_aux:NN \clist_gset_eq:NN +} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\l_clist_remove_duplicates_clist} +% \begin{macrocode} +\clist_new:N \l_clist_remove_duplicates_clist +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\clist_use:N} +% \begin{macro}{\clist_use:c} +% Using a \meta{clist} is just executing it but\dots +% \begin{macrocode} +\def_new:Npn \clist_use:N #1 { + \if_meaning:NN #1 \scan_stop: +% \end{macrocode} +% \dots\ if \m{clist} equals |\scan_stop:| it is probably stemming +% from a |\cs:w ... \cd_end:| that was created by mistake somewhere. +% \begin{macrocode} + \err_latex_bug:x {Comma~list~ `\token_to_string:N #1'~ + has~ an~ erroneous~ structure!} + \else: + \exp_after:NN #1 + \fi: +} +\def_new:Npn \clist_use:c {\exp_args:Nc \clist_use:N} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\clist_if_in:NnTF} +% \begin{macro}{\clist_if_in:NoTF} +% \begin{macro}{\clist_if_in:cnTF} +% \begin{macro}{\clist_if_in:coTF} +% |\clist_if_in:NnTF| \m{clist}\m{item} \m{true~case} \m{false~case} +% will check whether \m{item} is in \m{clist} 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. +% \begin{macrocode} +\def_new:Npn \clist_if_in:NnTF #1#2{ + \def:Npn \tmp:w ##1 ,#2, ##2##3\q_stop{ + \if_meaning:NN\q_no_value##2 + \exp_after:NN\use_arg_ii:nn + \else: + \exp_after:NN\use_arg_i:nn + \fi: + } + \exp_after:NN \tmp:w + \exp_after:NN , #1, #2, \q_no_value \q_stop +} +\def_new:Npn \clist_if_in:NoTF {\exp_args:NNo \clist_if_in:NnTF} +\def_new:Npn \clist_if_in:coTF {\exp_args:Nco \clist_if_in:NnTF} +\def_new:Npn \clist_if_in:cnTF {\exp_args:Nc \clist_if_in:NnTF} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% +% \subsubsection{Stack operations} +% +% We build stacks from comma-lists, but here we put the +% specific functions together. +% +% +% \begin{macro}{\clist_push:Nn} +% \begin{macro}{\clist_push:No} +% \begin{macro}{\clist_push:cn} +% \begin{macro}{\clist_pop:NN} +% \begin{macro}{\clist_pop:cN} +% Since comma-lists 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} +\let_new:NN \clist_push:Nn \clist_put_left:Nn +\let_new:NN \clist_push:No \clist_put_left:No +\let_new:NN \clist_push:cn \clist_put_left:cn +\def_new:Npn \clist_pop:NN {\clist_pop_aux:nnNN \tlp_set:Nn \tlp_set:Nn} +\def_new:Npn \clist_pop:cN {\exp_args:Nc \clist_pop:NN} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% +% \begin{macro}{\clist_gpush:Nn} +% \begin{macro}{\clist_gpush:No} +% \begin{macro}{\clist_gpush:cn} +% \begin{macro}{\clist_gpop:NN} +% \begin{macro}{\clist_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 |\clist_gpop:NN| the value is +% nevertheless returned locally. +% \begin{macrocode} +\let_new:NN \clist_gpush:Nn \clist_gput_left:Nn +\def_new:Npn \clist_gpush:No {\exp_args:NNo \clist_gpush:Nn} +\def_new:Npn \clist_gpush:cn {\exp_args:Nc \clist_gpush:Nn} +\def_new:Npn \clist_gpop:NN {\clist_pop_aux:nnNN \tlp_gset:Nn \tlp_set:Nn} +\def_new:Npn \clist_gpop:cN {\exp_args:Nc \clist_gpop:NN} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% +% \begin{macro}{\clist_top:NN} +% \begin{macro}{\clist_top:cN} +% Looking at the top element of the stack without removing it is +% done with this operation. +% \begin{macrocode} +\let_new:NN \clist_top:NN \clist_get:NN +\let_new:NN \clist_top:cN \clist_get:cN +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% +% Show token usage: +% \begin{macrocode} +%</initex|package> +%<*showmemory> +%\showMemUsage +%</showmemory> +% \end{macrocode} +% +% +% +% \endinput +% +% $Log$ +% Revision 1.16 2006/07/30 15:45:46 morten +% Made \clist_map_inline:Nn and variants nestable plus a little cleanup. +% +% Revision 1.15 2006/03/20 18:26:34 braams +% Updated the copyright notice (2006) and demoted all implementation +% sections to subsections and so on to clean up the toc for source3.tex +% +% Revision 1.14 2006/01/04 01:32:09 morten +% Minor changes to code to reflect changes in l3tlp. +% +% Revision 1.13 2005/12/27 09:52:51 morten +% Minor changes plus changed RCS information retrieval +% +% Revision 1.12 2005/10/27 23:14:49 morten +% Improved loops. +% +% Revision 1.11 2005/04/12 16:45:22 morten +% Enabled put operations. Added function that removes duplicate entries (mostly for +% use after concatenating to clists) +% +% Revision 1.10 2005/04/12 13:22:13 morten +% Mostly cosmetic changes. \clist_gconcat:NNN reprogrammed using "proper" methods, \clist_put_right:Nn likewise. +% +% Revision 1.9 2005/03/22 23:26:54 morten +% Fix error message +% +% Revision 1.8 2005/03/16 22:36:43 braams +% Added the tweaks necessary to be able to load with initex +% +% Revision 1.7 2005/03/11 21:36:36 braams +% Fixed the use of RCS information; +% Fixed a few documentation typos; added \StopEventually +% Replaced \ifx by \if_meaning:NN, \c_if_empty_toks became \c_empty_toks +% but needs further work according to Morten +% |