summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/expl3/l3prg.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/expl3/l3prg.dtx')
-rw-r--r--Master/texmf-dist/source/latex/expl3/l3prg.dtx1374
1 files changed, 1374 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/expl3/l3prg.dtx b/Master/texmf-dist/source/latex/expl3/l3prg.dtx
new file mode 100644
index 00000000000..43e2e77448a
--- /dev/null
+++ b/Master/texmf-dist/source/latex/expl3/l3prg.dtx
@@ -0,0 +1,1374 @@
+% \iffalse
+%% File: l3prg.dtx Copyright (C) 2005-2006 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: l3prg.dtx 574 2006-08-21 23:30:10Z morten $
+ {L3 Experimental control structures}
+%
+% \iffalse
+%<*driver>
+\documentclass{l3doc}
+
+\begin{document}
+\DocInput{l3prg.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{The \textsf{l3prg} package\thanks{This file
+% has version number \fileversion, last
+% revised \filedate.}\\
+% Program control structures}
+% \author{\Team}
+% \date{\filedate}
+% \maketitle
+%
+%
+% \section{Control structures}
+%
+% \subsection{Choosing modes}
+%
+% \begin{function}{\mode_vertical_p:|
+% \mode_vertical:TF |
+% \mode_vertical:T |
+% \mode_vertical:F
+% }
+% \begin{syntax}
+% "\mode_vertical:TF" "{"<true code>"}" "{"<false code>"}"
+% \end{syntax}
+% Determines if \TeX{} is in vertical mode or not and executes either
+% <true code> or <false code> accordingly.
+% \end{function}
+%
+% \begin{function}{\mode_horizontal_p:|
+% \mode_horizontal:TF |
+% \mode_horizontal:T |
+% \mode_horizontal:F
+% }
+% \begin{syntax}
+% "\mode_horizontal:TF" "{"<true code>"}" "{"<false code>"}"
+% \end{syntax}
+% Determines if \TeX{} is in horizontal mode or not and executes either
+% <true code> or <false code> accordingly.
+% \end{function}
+%
+%
+% \begin{function}{
+% \mode_inner_p:|
+% \mode_inner:TF|
+% \mode_inner:T|
+% \mode_inner:F
+% }
+% \begin{syntax}
+% "\mode_inner:TF" "{"<true code>"}" "{"<false code>"}"
+% \end{syntax}
+% Determines if \TeX{} is in inner mode or not and executes either
+% <true code> or <false code> accordingly.
+% \end{function}
+%
+% \begin{function}{
+% \mode_math:TF|
+% \mode_math:T|
+% \mode_math:F|
+% }
+% \begin{syntax}
+% "\mode_math:TF" "{"<true code>"}" "{"<false code>"}"
+% \end{syntax}
+% Determines if \TeX{} is in math mode or not and executes either
+% <true code> or <false code> accordingly.
+% \begin{texnote}
+% This version will choose the right branch even at the beginning of
+% an alignment cell.
+% \end{texnote}
+% \end{function}
+%
+%
+% \subsubsection{Alignment safe grouping and scanning}
+%
+% \begin{function}{\scan_align_safe_stop:}
+% \begin{syntax}
+% "\scan_align_safe_stop:"
+% \end{syntax}
+% This function gets \TeX{} on the right track inside an alignment
+% cell but without destroying any kerning.
+% \end{function}
+%
+%
+% \begin{function}{\group_align_safe_begin:|
+% \group_align_safe_end:}
+% \begin{syntax}
+% "\group_align_safe_begin:" <...> "\group_align_safe_end:"
+% \end{syntax}
+% Encloses <...> inside a group but is safe inside an alignment cell.
+% See the implementation of |\peek_token_generic:NNTF| for an
+% application.
+% \end{function}
+%
+%
+% \subsection{Producing $n$ copies}
+%
+% There are often several different requirements for producing
+% multiple copies of something. Sometimes one might want to produce a
+% number of identical copies of a sequence of tokens whereas at other
+% times the goal is to simulate a for loop as known from most real
+% programming languages.
+%
+% \begin{function}{\prg_replicate:nn }
+% \begin{syntax}
+% "\prg_replicate:nn" "{" <number> "}" "{" <arg> "}"
+% \end{syntax}
+% Creates <number> copies of <arg>. Expandable.
+% \end{function}
+%
+%
+% \begin{function}{\prg_stepwise_function:nnnN}
+% \begin{syntax}
+% "\prg_stepwise_function:nnnN" "{"<start>"}" "{"<step>"}"
+% "{"<end>"}" <function>
+% \end{syntax}
+% This function performs <action> once for each step starting at
+% <start> and ending once <end> is passed. <function> is placed
+% directly in front of a brace group holding the current number so it
+% should usually be a function taking one argument. The
+% |\prg_stepwise_function:nnnN| function is expandable.
+% \end{function}
+%
+% \begin{function}{\prg_stepwise_inline:nnnn}
+% \begin{syntax}
+% "\prg_stepwise_inline:nnnn" "{"<start>"}" "{"<step>"}" "{"<end>"}"
+% "{"<action>"}"
+% \end{syntax}
+% Same as |\prg_stepwise_function:nnnN| except here <action> is
+% performed each time with |##1| as a placeholder for the number
+% currently being tested. This function is not expandable and it is
+% nestable.
+% \end{function}
+%
+% \begin{function}{\prg_stepwise_variable:nnnNn}
+% \begin{syntax}
+% "\prg_stepwise_variable:nnnn" "{"<start>"}" "{"<step>"}" "{"<end>"}"
+% <temp-var> "{"<action>"}"
+% \end{syntax}
+% Same as |\prg_stepwise_inline:nnnn| except here the current value is
+% stored in <temp-var> and the programmer can use it in <action>. This
+% function is not expandable.
+% \end{function}
+%
+%
+%
+% \subsection{Conditionals and logical operations}
+%
+%
+% \LaTeX3 has two primary forms of conditional flow processing. The
+% one type deals with the truth value of a test directly as in
+% "\cs_free:NTF" where you test if a control sequence was undefined
+% and then execute either the \m{true} or \m{false} part depending on
+% the result and after exiting the underlying "\if...\fi:" structure.
+% The second type has to do with predicate functions like
+% "\cs_free_p:N" which return either "\c_true" or "\c_false" to be
+% used in testing with "\if:w".
+%
+%
+% This section describes a boolean data type which is closely
+% connected to both parts as sometimes you want to execute some code
+% depending on the value of a switch (e.g.,~draft/final) and other
+% times you perhaps want to use it as a predicate function in an
+% "\if:w" test. Here \TeX's original concept with "\iffalse" and
+% "\iftrue" is a little difficult to handle so the easiest is simply
+% to let a boolean either be "\c_true" or "\c_false". This also means
+% we get the logical operations And, Or, and Not which can then be
+% used on both the boolean type and predicate functions. All
+% functions by the name |\prg_if_predicate_| are expandable and
+% expect the input to also be fully expandable. More generic
+% constructs do not contain |predicate| in their names.
+%
+%
+% \subsubsection{The boolean data type}
+%
+% \begin{function}{%
+% \bool_new:N |
+% \bool_new:c |
+% }
+% \begin{syntax}
+% "\bool_new:N" <bool>
+% \end{syntax}
+% Define a new boolean variable. The initial value is <false>. A
+% boolean is actually just either "\c_true" or "\c_false".
+% \end{function}
+%
+% \begin{function}{%
+% \bool_set_true:N |
+% \bool_set_true:c |
+% \bool_set_false:N |
+% \bool_set_false:c |
+% \bool_gset_true:N |
+% \bool_gset_true:c |
+% \bool_gset_false:N |
+% \bool_gset_false:c |
+% }
+% \begin{syntax}
+% "\bool_gset_false:N" <bool>
+% \end{syntax}
+% Set <bool> either true or false. We can also do this globally.
+% \end{function}
+%
+%
+% \begin{function}{%
+% \bool_set_eq:NN |
+% \bool_set_eq:Nc |
+% \bool_set_eq:cN |
+% \bool_set_eq:cc |
+% \bool_gset_eq:NN |
+% \bool_gset_eq:Nc |
+% \bool_gset_eq:cN |
+% \bool_gset_eq:cc |
+%
+% }
+% \begin{syntax}
+% "\bool_set_eq:NN" <bool1> <bool2>
+% \end{syntax}
+% Set <bool1> equal to the value of <bool2>.
+% \end{function}
+%
+% \begin{function}{%
+% \bool_if:NTF |
+% \bool_if:NT |
+% \bool_if:NF |
+% \bool_if_p:N |
+%
+% }
+% \begin{syntax}
+% "\bool_if:NTF" <bool> "{"\m{true}"}" "{"\m{false}"}" \\
+% "\bool_if_p:N" <bool>
+% \end{syntax}
+% Test the truth value of the boolean and execute the \m{true} or
+% \m{false} code. "\bool_if_p:N" is a predicate function for use in
+% "\if:w" tests.
+% \end{function}
+%
+% \begin{function}{%
+% \bool_whiledo:NT |
+% \bool_whiledo:NF |
+% \bool_dowhile:NT |
+% \bool_dowhile:NF |
+%
+% }
+% \begin{syntax}
+% "\bool_whiledo:NT" <bool> "{"\m{true}"}" \\
+% "\bool_whiledo:NF" <bool> "{"\m{false}"}" \\
+% \end{syntax}
+% The "T" versions execute the \m{true} code as long as the boolean is
+% true and the "F" versions execute the \m{false} code as long as the
+% boolean is false. The "whiledo" functions execute the body after
+% testing the boolean and the "dowhile" functions executes the body
+% first and then tests the boolean.
+% \end{function}
+%
+%
+% \begin{function}{%
+% \l_tmpa_bool |
+% \g_tmpa_bool |
+%
+% }
+% \begin{syntax}
+% \end{syntax}
+% Reserved booleans.
+% \end{function}
+%
+% \subsubsection{Logical operations}
+%
+% Somewhat related to the subject of conditional flow processing is
+% logical operators as these deal with \m{true} and \m{false}
+% statements which is precisely what the predicate functions return.
+%
+%
+% \begin{function}{%
+% \prg_if_predicate:nTF |
+% \prg_if_predicate:nT |
+% \prg_if_predicate:nF |
+% }
+% \begin{syntax}
+% "\prg_if_predicate:nTF" "{"<predicate>"}" "{"<true>"}" "{"<false>"}" \\
+% \end{syntax}
+% The first argument can either be a predicate function like
+% "\cs_free_p:N \foo" or one of the logic tests below.
+% \end{function}
+%
+%
+%
+%
+% \begin{function}{%
+% \prg_if_predicate_ors_p:n |
+% \prg_if_predicate_or_p:nn |
+% \prg_if_predicate_ands_p:n |
+% \prg_if_predicate_and_p:nn |
+% \prg_if_predicate_not_p:n |
+% }
+% \begin{syntax}
+% "\prg_if_predicate_ors_p:n" "{"<predicate> <predicate> ..."}" \\
+% "\prg_if_predicate_or_p:nn" "{"<predicate>"}" "{"<predicate>"}" \\
+% "\prg_if_predicate_ands_p:n" "{"<predicate> <predicate> ..."}" \\
+% "\prg_if_predicate_and_p:nn" "{"<predicate>"}" "{"<predicate>"}" \\
+% "\prg_if_predicate_not_p:n" "{"<predicate>"}"
+% \end{syntax}
+% "\prg_if_predicate_or_p:nn" compares the outcome of two predicate
+% functions (or other logic tests) and if either turns out to be
+% \m{true} returns \m{true} itself. "\prg_if_predicate_and_p:nn"
+% works in a similar way but requires both outcomes to be \m{true} in
+% order for it to return \m{true} itself. "\prg_if_predicate_not_p:n"
+% reverses the truth value of a predicate test or a logic
+% operation. Thus
+% \begin{quote}
+% "\prg_if_predicate_not_p:n {\prg_if_predicate_not_p:n {\c_true}}"
+% \end{quote}
+% ultimately returns \m{true}. The argument of the functions
+% "\prg_if_predicate_ors_p:n" and "\prg_if_predicate_ands_p:n" take a
+% list of predicate functions (and their arguments) and return either
+% \m{true} or \m{false}.
+% \end{function}
+%
+% \subsubsection{Generic loops}
+%
+%
+% \begin{function}{
+% \prg_whiledo:nT |
+% \prg_whiledo:nF |
+% \prg_dowhile:nT |
+% \prg_dowhile:nF |
+%
+% }
+% \begin{syntax}
+% "\prg_whiledo:nT" "{"<test>"}" "{"\m{true}"}" \\
+% "\prg_whiledo:nF" "{"<test>"}" "{"\m{false}"}"
+% \end{syntax}
+% The "T" versions execute the \m{true} code as long as <test> is
+% true and the "F" versions execute the \m{false} code as long as
+% <test> is false. The "whiledo" functions execute the body after
+% testing the boolean and the "dowhile" functions executes the body
+% first and then tests the boolean. For the "T" versions, <test>
+% should end with a function executing only the \meta{true} code for
+% some test such as |\tlp_if_eq:NNT|. Similarly the "F" types should
+% end with |\tlp_if_eq:NNF|.
+% \end{function}
+%
+% \subsection{Sorting}
+%
+%
+% \begin{function}{
+% \prg_quicksort:n |
+% }
+% \begin{syntax}
+% "\prg_quicksort:n" "{" "{"<element~1>"}" "{"<element~2>"}"
+% \dots\space "{"<element~n>"}" "}"
+% \end{syntax}
+% Performs a Quicksort on the token list. The comparisons are
+% performed by the function |\prg_quicksort_compare:nnTF| which is up
+% to the programmer to define. When the sorting process is over, all
+% elements are given as argument to the function
+% |\prg_quicksort_function:n| which the programmer also controls.
+% \end{function}
+%
+% \begin{function}{
+% \prg_quicksort_function:n |
+% \prg_quicksort_compare:nnTF
+% }
+% \begin{syntax}
+% "\prg_quicksort_function:n" "{"<element>"}" \\
+% "\prg_quicksort_compare:nnTF" "{"<element 1>"}" "{"<element 2>"}"\\
+% \end{syntax}
+% The two functions the programmer must define before calling
+% |\prg_quicksort:n|. As an example we could define
+% \begin{quote}
+% |\def:NNn\prg_quicksort_function:n 1{{#1}}|\\
+% |\def:NNn\prg_quicksort_compare:nnTF 2{\num_compare:nNnTF{#1}>{#2}}|
+% \end{quote}
+% Then the function call
+% \begin{quote}
+% |\prg_quicksort:n {876234520}|
+% \end{quote}
+% would return |{0}{2}{2}{3}{4}{5}{6}{7}{8}|. An alternative example
+% where one sorts a list of words, |\prg_quicksort_compare:nnTF| could
+% be defined as
+% \begin{quote}
+% |\def:NNn\prg_quicksort_compare:nnTF 2{|\\
+% | \num_compare:nNnTF{\tlist_compare:nn{#1}{#2}}>\c_zero }|
+% \end{quote}
+%
+% \end{function}
+%
+%
+% \StopEventually{}
+%
+% \subsection{The Implementation}
+%
+%
+% We start by ensuring that the required packages are loaded.
+% \begin{macrocode}
+%<*package>
+\RequirePackage{l3quark}
+\RequirePackage{l3toks}
+\RequirePackage{l3int}
+%</package>
+%<*initex|package>
+% \end{macrocode}
+%
+%
+% \subsubsection{Choosing modes}
+%
+% \begin{macro}{\mode_vertical_p:}
+% \begin{macro}{\mode_vertical:TF}
+% \begin{macro}{\mode_vertical:T}
+% \begin{macro}{\mode_vertical:F}
+% For testing vertical mode.
+% \begin{macrocode}
+\def_new:Npn \mode_vertical_p: {
+ \if_mode_vertical: \c_true \else: \c_false\fi:}
+\def_test_function_new:npn{mode_vertical:}{\if_mode_vertical:}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\mode_horizontal_p:}
+% \begin{macro}{\mode_horizontal:TF}
+% \begin{macro}{\mode_horizontal:T}
+% \begin{macro}{\mode_horizontal:F}
+% For testing horizontal mode.
+% \begin{macrocode}
+\def_new:Npn \mode_horizontal_p: {
+ \if_mode_horizontal: \c_true \else: \c_false\fi:}
+\def_test_function_new:npn{mode_horizontal:}{\if_mode_horizontal:}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\mode_inner_p:}
+% \begin{macro}{\mode_inner:TF}
+% \begin{macro}{\mode_inner:T}
+% \begin{macro}{\mode_inner:F}
+% For testing inner mode.
+% \begin{macrocode}
+\def_new:Npn \mode_inner_p: {
+ \if_mode_inner: \c_true \else: \c_false\fi:}
+\def_test_function_new:npn{mode_inner:}{\if_mode_inner:}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\mode_math:TF}
+% \begin{macro}{\mode_math:T}
+% \begin{macro}{\mode_math:F}
+% For testing math mode. Uses the kern-save |\scan_align_safe_stop:|.
+% \begin{macrocode}
+\def_test_function_new:npn{mode_math:} {
+ \scan_align_safe_stop: \if_mode_math: }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \paragraph{Alignment safe grouping and scanning}
+%
+%
+% \begin{macro}{\group_align_safe_begin:}
+% \begin{macro}{\group_align_safe_end:}
+% \TeX's alignment structures present many problems. As Knuth says
+% himself in \emph{\TeX: The Program}: ``It's sort of a miracle
+% whenever |\halign| or |\valign| work, [\ldots]'' One problem relates
+% to commands that internally issues a |\cr| but also peek ahead for
+% the next character for use in, say, an optional argument. If the
+% next token happens to be a |&| with category code~4 we will get some
+% sort of weird error message because the underlying
+% |\tex_futurelet:D| will store the token at the end of the alignment
+% template. This could be a |&|$\sb4$ giving a message like
+% |! Misplaced \cr.| or even worse: it could be the |\endtemplate|
+% token causing even more trouble! To solve this we have to open a
+% special group so that \TeX{} still thinks it's on safe ground but at
+% the same time we don't want to introduce any brace group that may
+% find its way to the output. The following functions help with this
+% by using code documented only in Appendix~D of
+% \emph{The \TeX book}\dots
+% \begin{macrocode}
+\def_new:Npn \group_align_safe_begin: {\if_false:{\fi:\if_num:w0=`}\fi:}
+\def_new:Npn \group_align_safe_end: {\if_num:w0=`{\fi:\if_false:}\fi:}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%
+% \begin{macro}{\scan_align_safe_stop:}
+% When \TeX{} is in the beginning of an align cell (right after the
+% |\cr|) it is in a somewhat strange mode as it is looking ahead to
+% find an |\tex_omit:D| or |\tex_noalign:D| and hasn't looked at the
+% preamble yet. Thus an |\tex_ifmmode:D| test will always fail unless
+% we insert |\scan_stop:| to stop \TeX's scanning ahead. On the other
+% hand we don't want to insert a |\scan_stop:| every time as that will
+% destroy kerning between letters\footnote{Unless we enforce an extra
+% pass with an appropriate value of \texttt{\string\pretolerance}.}
+% Unfortunately there is no way to detect if we're in the beginning of
+% an alignment cell as they have different characteristics depending
+% on column number etc. However we \emph{can} detect if we're in an
+% alignment cell by checking the current group type and we can also
+% check if the previous node was a character or ligature. What is done
+% here is that |\scan_stop:| is only inserted iff a)~we're in the
+% outer part of an alignment cell and b)~the last node \emph{wasn't} a
+% char node or a ligature node.
+% \begin{macrocode}
+\def_new:Npn \scan_align_safe_stop: {
+ \num_compare:nNnT \etex_currentgrouptype:D = \c_six
+ {
+ \num_compare:nNnF \etex_lastnodetype:D = \c_zero
+ {
+ \num_compare:nNnF \etex_lastnodetype:D = \c_seven
+ \scan_stop:
+ }
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Making $n$ copies}
+%
+% \begin{macro}{\prg_replicate:nn}
+% \begin{macro}{\prg_replicate_aux:N}
+% \begin{macro}{\prg_replicate_first_aux:N}
+% This function uses a cascading csname technique by David Kastrup
+% (who else :-)
+%
+% The idea is to make the input "25" result in first adding five, and
+% then 20 copies of the code to be replicated. The technique uses
+% cascading csnames which means that we start building several csnames
+% so we end up with a list of functions to be called in reverse
+% order. This is important here (and other places) because it means
+% that we can for instance make the function that inserts five copies
+% of something to also hand down ten to the next function in
+% line. This is exactly what happens here: in the example with "25"
+% then the next function is the one that inserts two copies but it
+% sees the ten copies handed down by the previous function. In order
+% to avoid the last function to insert say, 100 copies of the original
+% argument just to gobble them again we define separate functions to
+% be inserted first. Finally we must ensure that the cascade comes to
+% a peaceful end so we make it so that the original csname \TeX{} is
+% creating is simply "\use_noop:" expanding to nothing.
+%
+% This function has one flaw though: Since it constantly passes down
+% ten copies of its previous argument it will severely affect the main
+% memory once you start demanding hundreds of thousands of copies. Now
+% I don't think this is a real limitation for any ordinary use. An
+% alternative approach is to create a string of "m"'s with
+% "\int_to_roman:w" which can be done with just four macros but that
+% method has its own problems since it can exhaust the string
+% pool. Also, it is considerably slower than what we use here so the
+% few extra csnames are well spent I would say.
+% \begin{macrocode}
+\def_new:Npn \prg_replicate:nn #1{
+ \cs:w use_noop:
+ \exp_after:NN\prg_replicate_first_aux:N
+ \int_use:N \int_eval:n{#1} \cs_end:
+ \cs_end:
+}
+\def_new:Npn \prg_replicate_aux:N#1{
+ \cs:w prg_replicate_#1:n\prg_replicate_aux:N
+}
+\def_new:Npn \prg_replicate_first_aux:N#1{
+ \cs:w prg_replicate_first_#1:n\prg_replicate_aux:N
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% Then comes all the functions that do the hard work of inserting all
+% the copies.
+% \begin{macrocode}
+\def_new:Npn \prg_replicate_ :n #1{}% no, this is not a typo!
+\def_long_new:cpn {prg_replicate_0:n}#1{\cs_end:{#1#1#1#1#1#1#1#1#1#1}}
+\def_long_new:cpn {prg_replicate_1:n}#1{\cs_end:{#1#1#1#1#1#1#1#1#1#1}#1}
+\def_long_new:cpn {prg_replicate_2:n}#1{\cs_end:{#1#1#1#1#1#1#1#1#1#1}#1#1}
+\def_long_new:cpn {prg_replicate_3:n}#1{
+ \cs_end:{#1#1#1#1#1#1#1#1#1#1}#1#1#1}
+\def_long_new:cpn {prg_replicate_4:n}#1{
+ \cs_end:{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1}
+\def_long_new:cpn {prg_replicate_5:n}#1{
+ \cs_end:{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1#1}
+\def_long_new:cpn {prg_replicate_6:n}#1{
+ \cs_end:{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1#1#1}
+\def_long_new:cpn {prg_replicate_7:n}#1{
+ \cs_end:{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1#1#1#1}
+\def_long_new:cpn {prg_replicate_8:n}#1{
+ \cs_end:{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1#1#1#1#1}
+\def_long_new:cpn {prg_replicate_9:n}#1{
+ \cs_end:{#1#1#1#1#1#1#1#1#1#1}#1#1#1#1#1#1#1#1#1}
+% \end{macrocode}
+% Users shouldn't ask for something to be replicated once or even
+% not at all but\dots
+% \begin{macrocode}
+\def_long_new:cpn {prg_replicate_first_0:n}#1{\cs_end: }
+\def_long_new:cpn {prg_replicate_first_1:n}#1{\cs_end: #1}
+\def_long_new:cpn {prg_replicate_first_2:n}#1{\cs_end: #1#1}
+\def_long_new:cpn {prg_replicate_first_3:n}#1{\cs_end: #1#1#1}
+\def_long_new:cpn {prg_replicate_first_4:n}#1{\cs_end: #1#1#1#1}
+\def_long_new:cpn {prg_replicate_first_5:n}#1{\cs_end: #1#1#1#1#1}
+\def_long_new:cpn {prg_replicate_first_6:n}#1{\cs_end: #1#1#1#1#1#1}
+\def_long_new:cpn {prg_replicate_first_7:n}#1{\cs_end: #1#1#1#1#1#1#1}
+\def_long_new:cpn {prg_replicate_first_8:n}#1{\cs_end: #1#1#1#1#1#1#1#1}
+\def_long_new:cpn {prg_replicate_first_9:n}#1{\cs_end: #1#1#1#1#1#1#1#1#1}
+% \end{macrocode}
+%
+%
+%
+%
+% \begin{macro}{\prg_stepwise_function:nnnN}
+% \begin{macro}{\prg_stepwise_function_incr:nnnN}
+% \begin{macro}{\prg_stepwise_function_decr:nnnN}
+% A stepwise function. Firstly we check the direction of the steps
+% |#2| since that will depend on which test we should use. If the
+% step is positive we use a greater than test, otherwise a less than
+% test. If the test comes out true exit, otherwise perform |#4|,
+% add the step to |#1| and try again with this new value of |#1|.
+% \begin{macrocode}
+\def_long_new:NNn \prg_stepwise_function:nnnN 2{
+ \num_compare:nNnTF{#2}<\c_zero
+ {\exp_args:No\prg_stepwise_function_decr:nnnN }
+ {\exp_args:No\prg_stepwise_function_incr:nnnN }
+ {\int_use:N\int_eval:n{#1}}{#2}
+}
+\def_long_new:NNn \prg_stepwise_function_incr:nnnN 4{
+ \num_compare:nNnF {#1}>{#3}
+ {
+ #4{#1}
+ \exp_args:No \prg_stepwise_function_incr:nnnN
+ {\int_use:N\int_eval:n{#1 + #2}}
+ {#2}{#3}{#4}
+ }
+}
+\def_long_new:NNn \prg_stepwise_function_decr:nnnN 4{
+ \num_compare:nNnF {#1}<{#3}
+ {
+ #4{#1}
+ \exp_args:No \prg_stepwise_function_decr:nnnN
+ {\int_use:N\int_eval:n{#1 + #2}}
+ {#2}{#3}{#4}
+ }
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\l_prg_inline_level_int}
+% \begin{macro}{\prg_stepwise_inline:nnnn}
+% \begin{macro}{\prg_stepwise_inline_decr:nnnn}
+% \begin{macro}{\prg_stepwise_inline_incr:nnnn}
+% This function uses the same approach as for instance
+% |\clist_map_inline:Nn| to allow arbitrary nesting. First construct
+% the special function and then call an auxiliary one which just
+% carries the newly constructed csname.
+% \begin{macrocode}
+\int_new:N\l_prg_inline_level_int
+\def_long_new:NNn\prg_stepwise_inline:nnnn 4{
+ \int_incr:N \l_prg_inline_level_int
+ \def:cpn{prg_stepwise_inline_\int_use:N\l_prg_inline_level_int :n}##1{#4}
+ \num_compare:nNnTF {#2}<\c_zero
+ {\exp_args:Nco \prg_stepwise_inline_decr:Nnnn }
+ {\exp_args:Nco \prg_stepwise_inline_incr:Nnnn }
+ {prg_stepwise_inline_\int_use:N\l_prg_inline_level_int :n}
+ {\int_use:N\int_eval:n{#1}} {#2} {#3}
+ \int_decr:N \l_prg_inline_level_int
+}
+\def_long_new:NNn \prg_stepwise_inline_incr:Nnnn 4{
+ \num_compare:nNnF {#2}>{#4}
+ {
+ #1{#2}
+ \exp_args:NNo \prg_stepwise_inline_incr:Nnnn #1
+ {\int_use:N\int_eval:n{#2 + #3}} {#3}{#4}
+ }
+}
+\def_long_new:NNn \prg_stepwise_inline_decr:Nnnn 4{
+ \num_compare:nNnF {#2}<{#4}
+ {
+ #1{#2}
+ \exp_args:NNo \prg_stepwise_inline_decr:Nnnn #1
+ {\int_use:N\int_eval:n{#2 + #3}} {#3}{#4}
+ }
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\prg_stepwise_variable:nnnNn}
+% \begin{macro}{\prg_stepwise_variable_decr:nnnNn}
+% \begin{macro}{\prg_stepwise_variable_incr:nnnNn}
+% Almost the same as above. Just store the value in |#4| and execute
+% |#5|.
+% \begin{macrocode}
+\def_long_new:NNn \prg_stepwise_variable:nnnNn 2 {
+ \num_compare:nNnTF {#2}<\c_zero
+ {\exp_args:No\prg_stepwise_variable_decr:nnnNn}
+ {\exp_args:No\prg_stepwise_variable_incr:nnnNn}
+ {\int_use:N\int_eval:n{#1}}{#2}
+}
+\def_long_new:NNn \prg_stepwise_variable_incr:nnnNn 5 {
+ \num_compare:nNnF {#1}>{#3}
+ {
+ \def:Npn #4{#1} #5
+ \exp_args:No \prg_stepwise_variable_incr:nnnNn
+ {\int_use:N\int_eval:n{#1 + #2}}{#2}{#3}#4{#5}
+ }
+}
+\def_long_new:NNn \prg_stepwise_variable_decr:nnnNn 5 {
+ \num_compare:nNnF {#1}<{#3}
+ {
+ \def:Npn #4{#1} #5
+ \exp_args:No \prg_stepwise_variable_decr:nnnNn
+ {\int_use:N\int_eval:n{#1 + #2}}{#2}{#3}#4{#5}
+ }
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+%
+% \subsubsection{Booleans}
+% For normal booleans we set them to either "\c_true" or "\c_false"
+% and then use "\if:w" to choose the right branch. The functions
+% return either the TF, T, or F case \emph{after} ending the |\if:w|.
+% We only define the |N| versions here as the |c| versions can easily
+% be constructed with the expansion module.
+%
+% \begin{macro}{\bool_new:N}
+% \begin{macro}{\bool_new:c}
+% \begin{macro}{\bool_set_true:N}
+% \begin{macro}{\bool_set_true:c}
+% \begin{macro}{\bool_set_false:N}
+% \begin{macro}{\bool_set_false:c}
+% \begin{macro}{\bool_gset_true:N}
+% \begin{macro}{\bool_gset_true:c}
+% \begin{macro}{\bool_gset_false:N}
+% \begin{macro}{\bool_gset_false:c}
+% Defining and setting a boolean is easy.
+% \begin{macrocode}
+\def_new:Npn \bool_new:N #1 { \let_new:NN #1 \c_false }
+\def_new:Npn \bool_new:c #1 { \let_new:cN #1 \c_false }
+\def_new:Npn \bool_set_true:N #1 { \let:NN #1 \c_true }
+\def_new:Npn \bool_set_true:c #1 { \let:cN #1 \c_true }
+\def_new:Npn \bool_set_false:N #1 { \let:NN #1 \c_false }
+\def_new:Npn \bool_set_false:c #1 { \let:cN #1 \c_false }
+\def_new:Npn \bool_gset_true:N #1 { \glet:NN #1 \c_true }
+\def_new:Npn \bool_gset_true:c #1 { \glet:cN #1 \c_true }
+\def_new:Npn \bool_gset_false:N #1 { \glet:NN #1 \c_false }
+\def_new:Npn \bool_gset_false:c #1 { \glet:cN #1 \c_false }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\bool_set_eq:NN}
+% \begin{macro}{\bool_set_eq:Nc}
+% \begin{macro}{\bool_set_eq:cN}
+% \begin{macro}{\bool_set_eq:cc}
+% \begin{macro}{\bool_gset_eq:NN}
+% \begin{macro}{\bool_gset_eq:Nc}
+% \begin{macro}{\bool_gset_eq:cN}
+% \begin{macro}{\bool_gset_eq:cc}
+% Setting a boolean to another is also pretty easy.
+% \begin{macrocode}
+\let_new:NN \bool_set_eq:NN \let:NN
+\let_new:NN \bool_set_eq:Nc \let:Nc
+\let_new:NN \bool_set_eq:cN \let:cN
+\let_new:NN \bool_set_eq:cc \let:cc
+\let_new:NN \bool_gset_eq:NN \glet:NN
+\let_new:NN \bool_gset_eq:Nc \glet:Nc
+\let_new:NN \bool_gset_eq:cN \glet:cN
+\let_new:NN \bool_gset_eq:cc \glet:cc
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\l_tmpa_bool}
+% \begin{macro}{\g_tmpa_bool}
+% A few booleans just if you need them.
+% \begin{macrocode}
+\bool_new:N \l_tmpa_bool
+\bool_new:N \g_tmpa_bool
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\bool_if:NTF}
+% \begin{macro}{\bool_if:NT}
+% \begin{macro}{\bool_if:NF}
+% \begin{macro}{\bool_if:cTF}
+% \begin{macro}{\bool_if:cT}
+% \begin{macro}{\bool_if:cF}
+% Straight forward here.
+% \begin{macrocode}
+\def_test_function_new:npn{bool_if:N}#1{\if:w #1}
+\def_new:Npn \bool_if:cTF{\exp_args:Nc\bool_if:NTF}
+\def_new:Npn \bool_if:cT{\exp_args:Nc\bool_if:NT}
+\def_new:Npn \bool_if:cF{\exp_args:Nc\bool_if:NF}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\bool_if_p:N}
+% \begin{macro}{\bool_if_p:c}
+% We also make a predicate function for the "bool" data type but since
+% we use "\c_true" and "\c_false" it's rather simple\dots{}
+% Not that there's anything wrong in simplicity -- on the contrary!
+% \begin{macrocode}
+\def_new:Npn \bool_if_p:N #1 { #1 }
+\let_new:NN \bool_if_p:c \cs_use:c
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%
+% \begin{macro}{\bool_whiledo:NT}
+% \begin{macro}{\bool_whiledo:cT}
+% \begin{macro}{\bool_whiledo:NF}
+% \begin{macro}{\bool_whiledo:cF}
+% A "while" loop where the boolean is tested before executing the
+% statement. The "NT" version executes the "T" part as long as the
+% boolean is true while the "NF" version executes the "F" part as
+% long as the boolean is false.
+% \begin{macrocode}
+\def_long_new:Npn \bool_whiledo:NT #1 #2 {
+ \bool_if:NT #1 {#2 \bool_whiledo:NT #1 {#2}}
+}
+\def_new:Npn \bool_whiledo:cT{\exp_args:Nc\bool_whiledo:NT}
+\def_long_new:Npn \bool_whiledo:NF #1 #2 {
+ \bool_if:NF #1 {#2 \bool_whiledo:NF #1 {#2}}
+}
+\def_new:Npn \bool_whiledo:cF{\exp_args:Nc\bool_whiledo:NF}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\bool_dowhile:NT}
+% \begin{macro}{\bool_dowhile:cT}
+% \begin{macro}{\bool_dowhile:NF}
+% \begin{macro}{\bool_dowhile:cF}
+% A "do-while" loop where the body is performed at least once and the
+% boolean is tested after executing the body. Otherwise identical to
+% the above functions.
+% \begin{macrocode}
+\def_long_new:Npn \bool_dowhile:NT #1 #2 {
+ #2 \bool_if:NT #1 {\bool_dowhile:NT #1 {#2}}
+}
+\def_new:Npn \bool_dowhile:cT{\exp_args:Nc\bool_dowhile:NT}
+\def_long_new:Npn \bool_dowhile:NF #1 #2 {
+ #2 \bool_if:NF #1 {\bool_dowhile:NF #1 {#2}}
+}
+\def_new:Npn \bool_dowhiledo:cF{\exp_args:Nc\bool_dowhile:cF}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\bool_double_if:NNnnnn}
+% \begin{macro}{\bool_double_if:cNnnnn}
+% \begin{macro}{\bool_double_if:Ncnnnn}
+% \begin{macro}{\bool_double_if:ccnnnn}
+% Execute |#3| iff TT, |#4| iff TF, |#5| iff FT and |#6| iff
+% FF. The name isn't that great but I'll have to think about
+% that. Ideally it should be something with |TF| since only one of
+% the cases is executed but we haven't got any naming scheme for
+% this kind of thing so for now I'll just stick to simple |nnnn|.
+% \begin{macrocode}
+\def_new:Npn \bool_double_if:NNnnnn#1#2{
+ \if_case:w \num_eval:w #1\scan_stop:
+ \if_case:w \num_eval:w #2\scan_stop:
+ \exp_after:NN\exp_after:NN\exp_after:NN \use_arg_i:nnnn
+ \else:
+ \exp_after:NN\exp_after:NN\exp_after:NN \use_arg_ii:nnnn
+ \fi:
+ \else:
+ \if_case:w \num_eval:w #2\scan_stop:
+ \exp_after:NN\exp_after:NN\exp_after:NN \use_arg_iii:nnnn
+ \else:
+ \exp_after:NN\exp_after:NN\exp_after:NN \use_arg_iv:nnnn
+ \fi:
+ \fi:
+}
+\def_new:Npn \bool_double_if:cNnnnn{\exp_args:Nc\bool_double_if:NNnnnn}
+\def_new:Npn \bool_double_if:Ncnnnn{\exp_args:NNc\bool_double_if:NNnnnn}
+\def_new:Npn \bool_double_if:ccnnnn{\exp_args:Ncc\bool_double_if:NNnnnn}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \subsubsection{Generic testing}
+%
+% \begin{macro}{\prg_whiledo:nT}
+% \begin{macro}{\prg_whiledo:nF}
+% \begin{macro}{\prg_dowhile:nT}
+% \begin{macro}{\prg_dowhile:nF}
+% We provide these four generic while loops. |#1| is a test function
+% and for the |T| functions it should be a test function ending with
+% just the true case. Similar for the |F| types.
+% \begin{macrocode}
+\def_long_new:Npn \prg_whiledo:nT #1#2{
+ #1 {#2 \prg_whiledo:nT {#1}{#2}}
+}
+\def_long_new:Npn \prg_whiledo:nF #1#2{
+ #1 {#2 \prg_whiledo:nF {#1}{#2}}
+}
+\def_long_new:Npn \prg_dowhile:nT #1#2{
+ #2 #1 {\prg_dowhile:nT {#1}{#2}}
+}
+\def_long_new:Npn \prg_dowhile:nF #1#2{
+ #2 #1 {\prg_dowhile:nF {#1}{#2}}
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\prg_if_predicate:nTF}
+% \begin{macro}{\prg_if_predicate:nT}
+% \begin{macro}{\prg_if_predicate:nF}
+% As the boolean type is actually a predicate function, the next ones
+% are just aliases.
+% \begin{macrocode}
+\let_new:NN \prg_if_predicate:nTF \bool_if:NTF
+\let_new:NN \prg_if_predicate:nT \bool_if:NT
+\let_new:NN \prg_if_predicate:nF \bool_if:NF
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+%
+% \begin{macro}{\prg_if_predicate_or_p:nn}
+% \begin{macro}{\prg_if_predicate_and_p:nn}
+% \begin{macro}{\prg_if_predicate_not_p:n}
+% The logic operations require a little more work. The idea is to have
+% the end result of the logic "and" and "or" functions return "00" and
+% "01" resp.\ to be used in an "\if:w" test. The arguments of the
+% functions are always something expanding to "\c_true" or "\c_false"
+% which is usually resulting from a predicate function or from another
+% logical operation. All the functions start with a "0" and depending
+% on the results of the tests return either "0" or "1" to the input
+% stream to form a new true or false statement.
+%
+% The comments in the following is mostly to convince myseld of the
+% validity of the code.
+% \begin{macrocode}
+\def_new:Npn \prg_if_predicate_or_p:nn #1#2{
+% \end{macrocode}
+% Form a number of the input which is one of "0000", "0001", "0100", or
+% "0101". If the truth value of both tests are false we get the "0101"
+% else we get a number less than that. So we check if the number formed
+% is less than $101$.
+% \begin{macrocode}
+ \if_num:w #1#2<\c_hundred_one
+% \end{macrocode}
+% If it is we put a "\c_true" back into the input stream.
+% \begin{macrocode}
+ \c_true
+ \else:
+% \end{macrocode}
+% Otherwise we insert "\c_false".
+% \begin{macrocode}
+ \c_false
+ \fi:
+}
+% \end{macrocode}
+% The "and" function is a little different. Again we can have input of
+% the types "0000", "0001", "0100", or "0101". As we require both
+% values to be \m{true} in order to continue we simply check if the
+% number formed by the input is "0" or not and then put the
+% corresponding "0" or "1" back in the input stream as above. We could
+% use "\if_num:w" for this test as well but that'll require us to read
+% the additional "=\c_zero" which runs a little slower than using
+% "\if_case:w" directly, so we use the latter.
+% \begin{macrocode}
+\def_new:Npn \prg_if_predicate_and_p:nn #1#2{
+ \if_case:w #1#2 ~
+ \c_true
+ \else:
+ \c_false
+ \fi:
+}
+% \end{macrocode}
+% The "not" function checks a single truth value and reverses it. Here
+% we either get a "00" or "01". If the input equals "0" we put a "1"
+% in the input stream, else we put a "0". Again we use "\if_case:w"
+% because it's slightly faster.
+% \begin{macrocode}
+\def_new:Npn \prg_if_predicate_not_p:n #1{
+ \if_case:w #1 ~
+ \c_false
+ \or:
+ \c_true
+ \fi:
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+%
+% \begin{macro}{\prg_if_predicate_ors_p:n}
+% \begin{macro}{\prg_if_predicate_ands_p:n}
+% \begin{macro}{\prg_if_predicate_andor_aux:NNN}
+% \begin{macro}{\prg_if_predicate_andor_break:NNN }
+% For longer lists of predicates we can't rely on such structures
+% as above. The "\prg_if_predicate_ands_p:n" would have been easy to
+% program as simply
+% \begin{verbatim}
+% \def_new:Npn \prg_if_predicate_and_p:n #1 {
+% 0\tex_ifcase:D #1 ~ \exp_after:NN 0 \else: \exp_after:NN 1 \fi:
+% }
+% \end{verbatim}
+% but this would fail with a "! Number too big." in case we were
+% testing six predicate functions where the first was false. This
+% would mean we would have to first convert the string from binary
+% into numerical and then check. While challenging and interesting
+% in itself (See \textsf{binhex}) it still imposes a restriction of
+% 15 predicate functions\footnote{We would probably never hit that
+% limit but why create a restriction when we can avoid it?} and we
+% haven't dealt with the "or" case either.
+%
+% The solution below expands a predicate function until |\c_false| or
+% |\c_true| are seen and expanded to |01| or |00| respectively. If
+% we're testing the logical AND operation, all predicate functions
+% must return \meta{true}; if they don't we can exit and return
+% \meta{false}. In an OR operation, we just need one predicate
+% function to return \meta{true}, the rest don't matter. Since every
+% expansion in the internal loop results in a result of either |00|
+% or |01|, we can test against this number to decide what to do.
+%
+% First up is the top level functions.
+% \begin{macrocode}
+\def_long_new:Npn \prg_if_predicate_ands_p:n #1{
+ \exp_after:NN \prg_if_predicate_andor_aux:NNN \exp_after:NN \c_true
+ \int_to_roman:w -`0 #1 \scan_stop: \scan_stop:
+}
+\def_long_new:Npn \prg_if_predicate_ors_p:n #1{
+ \exp_after:NN \prg_if_predicate_andor_aux:NNN \exp_after:NN \c_false
+ \int_to_roman:w -`0 #1 \scan_stop: \scan_stop:
+}
+% \end{macrocode}
+% When we reach the inner loop we have already expanded all tokens in
+% the first predicate function as far as possible. This means that
+% either are arguments |#2| and |#3| \emph{both} |\scan_stop:| or else
+% |#2| is |0| and |#3| is |0| if the predicate returned \meta{true} or
+% |1| if it returned \meta{false}. If we reached the end we return
+% \meta{true} for the AND function and \meta{false} for the OR
+% function. If |#3| is |0| and we are doing the OR test, we want to
+% exit and return \meta{true}. If |#3| is |0| and we are in the AND
+% test we must continue to check the remaining predicate functions. If
+% |#3| is |1| and we are in the OR test we continue in case a later
+% predicate function returns \meta{true}. Finally, if |#3| is |1| and
+% we are in the AND test we can exit and return \meta{false} before
+% deciding what to do.
+% \begin{macrocode}
+\def_new:Npn \prg_if_predicate_andor_aux:NNN #1#2#3{
+ \token_if_eq_meaning:NNTF \scan_stop: #2
+ { #1 }
+ {
+ \int_compare:nNnTF #3 = #1
+ { \exp_after:NN \prg_if_predicate_andor_aux:NNN }
+ { \exp_after:NN \prg_if_predicate_andor_break:NNN }
+ \exp_after:NN #1 \int_to_roman:w -`0
+ }
+}
+% \end{macrocode}
+% The break loop is called when we know what the final outcome
+% is. However we keep expanding because a)~we don't know which tokens
+% we might have left dangling ahead and b)~it also provides error
+% checking on the remaining predicate functions. |#1| is \meta{false}
+% for the OR function and \meta{true} for the AND function so we
+% reverse them here.
+% \begin{macrocode}
+\def_new:Npn \prg_if_predicate_andor_break:NNN #1#2#3{
+ \token_if_eq_meaning:NNTF \scan_stop: #2
+ { \if:w #1\c_false\else:\c_true\fi: }
+ {
+ \exp_after:NN \prg_if_predicate_andor_break:NNN \exp_after:NN #1
+ \int_to_roman:w -`0
+ }
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsubsection{Sorting}
+%
+%
+% \begin{macro}{\prg_define_quicksort:nnn}
+% |#1| is the name, |#2| and |#3| are the tokens enclosing the
+% argument. For the somewhat strange \meta{clist} type which doesn't
+% enclose the items but uses a separator we define it by hand
+% afterwards. When doing the first pass, the algorithm wraps all
+% elements in braces and then uses a generic quicksort which works
+% on token lists.
+%
+% As an example
+% \begin{quote}
+% |\prg_define_quicksort:nnn{seq}{\seq_elt:w}{\seq_elt_end:w}|
+% \end{quote}
+% defines the user function |\seq_quicksort:n| and furthermore
+% expects to use the two functions |\seq_quicksort_compare:nnTF|
+% which compares the items and |\seq_quicksort_function:n| which is
+% placed before each sorted item. It is up to the programmer to
+% define these functions when needed. For the |seq| type a sequence
+% is a token list pointer, so one additionally has to define
+% \begin{quote}
+% |\def:Npn \seq_quicksort:N{\exp_args:No\seq_quicksort:n}|
+% \end{quote}
+%
+%
+% For details on the implementation see ``Sorting in \TeX's Mouth''
+% by Bernd Raichle. Firstly we define the function for parsing the
+% ininital list and then the braced list afterwards.
+% \begin{macrocode}
+\def_new:NNn \prg_define_quicksort:nnn 3 {
+ \def_long:cNx{#1_quicksort:n}1{
+ \exp_not:c{#1_quicksort_start_partition:w} ##1
+ \exp_not:n{#2\q_nil#3\q_stop}
+ }
+ \def_long:cNx{#1_quicksort_braced:n}1{
+ \exp_not:c{#1_quicksort_start_partition_braced:n} ##1
+ \exp_not:N\q_nil\exp_not:N\q_stop
+ }
+ \def_long:cpx {#1_quicksort_start_partition:w} #2 ##1 #3{
+ \exp_not:N \quark_if_nil:nT {##1}\exp_not:N \use_none_delimit_by_q_stop:w
+ \exp_not:c{#1_quicksort_do_partition_i:nnnw} {##1}{}{}
+ }
+ \def_long:cNx {#1_quicksort_start_partition_braced:n} 1 {
+ \exp_not:N \quark_if_nil:nT {##1}\exp_not:N \use_none_delimit_by_q_stop:w
+ \exp_not:c{#1_quicksort_do_partition_i_braced:nnnn} {##1}{}{}
+ }
+% \end{macrocode}
+% Now for doing the partitions.
+% \begin{macrocode}
+ \def_long:cpx {#1_quicksort_do_partition_i:nnnw} ##1##2##3 #2 ##4 #3 {
+ \exp_not:N \quark_if_nil:nTF {##4} \exp_not:c {#1_do_quicksort_braced:nnnnw}
+ {
+ \exp_not:c{#1_quicksort_compare:nnTF}{##1}{##4}
+ \exp_not:c{#1_quicksort_partition_greater_ii:nnnn}
+ \exp_not:c{#1_quicksort_partition_less_ii:nnnn}
+ }
+ {##1}{##2}{##3}{##4}
+ }
+ \def_long:cNx {#1_quicksort_do_partition_i_braced:nnnn} 4 {
+ \exp_not:N \quark_if_nil:nTF {##4} \exp_not:c {#1_do_quicksort_braced:nnnnw}
+ {
+ \exp_not:c{#1_quicksort_compare:nnTF}{##1}{##4}
+ \exp_not:c{#1_quicksort_partition_greater_ii_braced:nnnn}
+ \exp_not:c{#1_quicksort_partition_less_ii_braced:nnnn}
+ }
+ {##1}{##2}{##3}{##4}
+ }
+ \def_long:cpx {#1_quicksort_do_partition_ii:nnnw} ##1##2##3 #2 ##4 #3 {
+ \exp_not:N \quark_if_nil:nTF {##4} \exp_not:c {#1_do_quicksort_braced:nnnnw}
+ {
+ \exp_not:c{#1_quicksort_compare:nnTF}{##4}{##1}
+ \exp_not:c{#1_quicksort_partition_less_i:nnnn}
+ \exp_not:c{#1_quicksort_partition_greater_i:nnnn}
+ }
+ {##1}{##2}{##3}{##4}
+ }
+ \def_long:cNx {#1_quicksort_do_partition_ii_braced:nnnn} 4 {
+ \exp_not:N \quark_if_nil:nTF {##4} \exp_not:c {#1_do_quicksort_braced:nnnnw}
+ {
+ \exp_not:c{#1_quicksort_compare:nnTF}{##4}{##1}
+ \exp_not:c{#1_quicksort_partition_less_i_braced:nnnn}
+ \exp_not:c{#1_quicksort_partition_greater_i_braced:nnnn}
+ }
+ {##1}{##2}{##3}{##4}
+ }
+% \end{macrocode}
+% This part of the code handles the two branches in each
+% sorting. Again we will also have to do it braced.
+% \begin{macrocode}
+ \def_long:cNx {#1_quicksort_partition_less_i:nnnn} 4{
+ \exp_not:c{#1_quicksort_do_partition_i:nnnw}{##1}{##2}{{##4}##3}}
+ \def_long:cNx {#1_quicksort_partition_less_ii:nnnn} 4{
+ \exp_not:c{#1_quicksort_do_partition_ii:nnnw}{##1}{##2}{##3{##4}}}
+ \def_long:cNx {#1_quicksort_partition_greater_i:nnnn} 4{
+ \exp_not:c{#1_quicksort_do_partition_i:nnnw}{##1}{{##4}##2}{##3}}
+ \def_long:cNx {#1_quicksort_partition_greater_ii:nnnn} 4{
+ \exp_not:c{#1_quicksort_do_partition_ii:nnnw}{##1}{##2{##4}}{##3}}
+ \def_long:cNx {#1_quicksort_partition_less_i_braced:nnnn} 4{
+ \exp_not:c{#1_quicksort_do_partition_i_braced:nnnn}{##1}{##2}{{##4}##3}}
+ \def_long:cNx {#1_quicksort_partition_less_ii_braced:nnnn} 4{
+ \exp_not:c{#1_quicksort_do_partition_ii_braced:nnnn}{##1}{##2}{##3{##4}}}
+ \def_long:cNx {#1_quicksort_partition_greater_i_braced:nnnn} 4{
+ \exp_not:c{#1_quicksort_do_partition_i_braced:nnnn}{##1}{{##4}##2}{##3}}
+ \def_long:cNx {#1_quicksort_partition_greater_ii_braced:nnnn} 4{
+ \exp_not:c{#1_quicksort_do_partition_ii_braced:nnnn}{##1}{##2{##4}}{##3}}
+% \end{macrocode}
+% Finally, the big kahuna! This is where the sub-lists are sorted.
+% \begin{macrocode}
+ \def_long:cpx {#1_do_quicksort_braced:nnnnw} ##1##2##3##4\q_stop {
+ \exp_not:c{#1_quicksort_braced:n}{##2}
+ \exp_not:c{#1_quicksort_function:n}{##1}
+ \exp_not:c{#1_quicksort_braced:n}{##3}
+ }
+}
+% \end{macrocode}
+% \end{macro}
+%
+%
+% \begin{macro}{\prg_quicksort:n}
+% A simple version. Sorts a list of tokens, uses the function
+% |\prg_quicksort_compare:nnTF| to compare items, and places the
+% function |\prg_quicksort_function:n| in front of each of them.
+% \begin{macrocode}
+\prg_define_quicksort:nnn {prg}{}{}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\prg_quicksort_function:n}
+% \begin{macro}{\prg_quicksort_compare:nnTF}
+% \begin{macrocode}
+\let:NN \prg_quicksort_function:n \ERROR
+\let:NN \prg_quicksort_compare:nnTF \ERROR
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%
+% That's it (for now).
+% \begin{macrocode}
+%</initex|package>
+%<*showmemory>
+\showMemUsage
+%</showmemory>
+% \end{macrocode}
+%
+% \endinput
+%
+% $Log$
+% Revision 1.19 2006/08/08 10:26:09 morten
+% Fixed bugs in stepwise functions
+%
+% Revision 1.18 2006/07/30 14:41:28 morten
+% Added stepwise functions (loops going from i to k with step of j) plus quicksort.
+%
+% Revision 1.17 2006/07/06 14:57:13 morten
+% Moved code in the `miscellaneus' section to l3basics.
+%
+% Revision 1.16 2006/06/03 18:55:12 morten
+% Added special double boolean switches.
+%
+% Revision 1.15 2006/03/20 18:26:38 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/19 22:31:56 morten
+% Added \bool_set_eq:NN functions plus made function collection
+% complete.
+%
+% Revision 1.13 2006/01/04 00:58:17 morten
+% Added generic loops. Changed some names plus syntax for some of the
+% logical operations. Added code for defining functions with specified
+% number of arguments.
+%
+% Revision 1.12 2005/12/27 10:01:55 morten
+% Changed RCS information retrieval. Moved tlist code to l3tlp. Added
+% code for inserting n copies of something. Changed \bool_while to
+% \bool_whiledo.
+%
+% Revision 1.11 2005/04/25 15:01:59 morten
+% Fixed some names. Improved \peek_char_generic:NNTF to not use token registers.
+%
+% Revision 1.10 2005/04/23 14:36:12 morten
+% Changed \c_left|right_brace_token to \c_group_begin_token and
+% \c_group_end_token. Fixed definitions of \tlist_if_head_XXX functions.
+% Added example for PR/3080.
+%
+% Revision 1.9 2005/04/09 21:08:43 morten
+% Documentation blunders fixed
+%
+% Revision 1.8 2005/04/06 21:27:15 morten
+% More tlist functions, Moved \engine_aleph:TF to l3basics, new peek-ahead functions, definitions of implicit characters.
+%
+% Revision 1.7 2005/03/26 21:11:14 morten
+% Fix typo in \scan_align_safe_stop:
+%
+% Revision 1.6 2005/03/22 23:23:30 morten
+% Moved \tlist_ functions from l3basics. Added align-safe versions of important functions. Reorganized documentation slightly.
+%
+% Revision 1.5 2005/03/16 22:36:10 braams
+% Added the tweaks necessary to be able to load with initex
+%
+% Revision 1.4 2005/03/11 21:28:20 braams
+% Fixed the use of RCS information; added \StopEventually
+%