summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2011-07-31 18:27:06 +0000
committerKarl Berry <karl@freefriends.org>2011-07-31 18:27:06 +0000
commitdac945b204407dae96f70ec228206516093156d7 (patch)
tree02ca182689947e45dec95e17ba08b503c959bd17 /Master/texmf-dist/source/latex/l3kernel/l3prg.dtx
parentc1840548792cfbc7c9f746da1d53d89b94406e72 (diff)
l3kernel (5jun11)
git-svn-id: svn://tug.org/texlive/trunk@23282 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3prg.dtx')
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3prg.dtx2046
1 files changed, 2046 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx b/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx
new file mode 100644
index 00000000000..b4cf9368f2a
--- /dev/null
+++ b/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx
@@ -0,0 +1,2046 @@
+% \iffalse meta-comment
+%
+%% File: l3prg.dtx Copyright (C) 2005-2011 The LaTeX3 Project
+%%
+%% It may be distributed and/or modified under the conditions of the
+%% LaTeX Project Public License (LPPL), either version 1.3c of this
+%% license or (at your option) any later version. The latest version
+%% of this license is in the file
+%%
+%% http://www.latex-project.org/lppl.txt
+%%
+%% This file is part of the "expl3 bundle" (The Work in LPPL)
+%% and all files in that bundle must be distributed together.
+%%
+%% The released version of this bundle is available from CTAN.
+%%
+%% -----------------------------------------------------------------------
+%%
+%% The development version of the bundle can be found at
+%%
+%% http://www.latex-project.org/svnroot/experimental/trunk/
+%%
+%% for those people who are interested.
+%%
+%%%%%%%%%%%
+%% NOTE: %%
+%%%%%%%%%%%
+%%
+%% Snapshots taken from the repository represent work in progress and may
+%% not work or may contain conflicting material! We therefore ask
+%% people _not_ to put them into distributions, archives, etc. without
+%% prior consultation with the LaTeX3 Project.
+%%
+%% -----------------------------------------------------------------------
+%
+%<*driver|package>
+\RequirePackage{l3names}
+\GetIdInfo$Id: l3prg.dtx 2495 2011-07-06 16:57:08Z bruno $
+ {L3 Experimental control structures}
+%</driver|package>
+%<*driver>
+\documentclass[full]{l3doc}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \pkg{l3prg} package\\ Control structures^^A
+% \thanks{This file describes v\ExplFileVersion,
+% last revised \ExplFileDate.}^^A
+% }
+%
+% \author{^^A
+% The \LaTeX3 Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Released \ExplFileDate}
+%
+% \maketitle
+%
+% \begin{documentation}
+%
+% Conditional processing in \LaTeX3 is defined as something that
+% performs a series of tests, possibly involving assignments and
+% calling other functions that do not read further ahead in the input
+% stream. After processing the input, a \emph{state} is returned. The
+% typical states returned are \meta{true} and \meta{false} but other
+% states are possible, say an \meta{error} state for erroneous
+% input, \emph{e.g.}, text as input in a function comparing integers.
+%
+% \LaTeX3 has two primary forms of conditional flow processing based
+% on these states. One type is predicate functions that turn the
+% returned state into a boolean \meta{true} or \meta{false}. For
+% example, the function |\cs_if_free_p:N| checks whether the control
+% sequence given as its argument is free and then returns the boolean
+% \meta{true} or \meta{false} values to be used in testing with
+% |\if_predicate:w| or in functions to be described below. The other type
+% is the kind of functions choosing a particular argument from the
+% input stream based on the result of the testing as in
+% |\cs_if_free:NTF| which also takes one argument (the |N|) and then
+% executes either \meta{true} or \meta{false} depending on the
+% result. Important to note here is that the arguments are executed
+% after exiting the underlying |\if...\fi:| structure
+%
+% \section{Defining a set of conditional functions}
+%
+% \begin{function}
+% {
+% \prg_new_conditional:Npnn, \prg_set_conditional:Npnn,
+% \prg_new_conditional:Nnn, \prg_set_conditional:Nnn
+% }
+% \begin{syntax}
+% \cs{prg_set_conditional:Npnn} \cs{\meta{name}:\meta{arg spec}}
+% ~~\meta{parameters} \Arg{conditions} \Arg{code}
+% \cs{prg_set_conditional:Nnn} \cs{\meta{name}:\meta{arg spec}}
+% ~~\Arg{conditions} \Arg{code}
+% \end{syntax}
+% These functions creates a family of conditionals using the same
+% \Arg{code} to perform the test created. The \texttt{new} version will
+% check for existing definitions (\emph{cf.}~\cs{cs_new:Npn}) whereas
+% the \texttt{set} version will not (\emph{cf.}~\cs{cs_set:Npn}). The
+% conditionals created are depended on the comma-separated list of
+% \meta{conditions}, which should be one or more of \texttt{p},
+% \texttt{T}, \texttt{F} and \texttt{TF}. The conditionals are then
+% defined in the obvious way as:
+% \begin{itemize}
+% \item \cs{\meta{name}_p:\meta{arg spec}}, a predicate function
+% which will supply either a logical \texttt{true} or
+% logical \texttt{false}. This function is intended for use
+% in cases where one or more logical tests are combined to
+% lead to a final outcome.
+% \item \cs{\meta{name}:\meta{arg spec}T}, a function with one
+% more argument than the original \meta{arg spec} demands. The
+% \meta{true branch} code in this additional argument will be
+% left on the input stream only if the test is \texttt{true}.
+% \item \cs{\meta{name}:\meta{arg spec}F}, a function with one
+% more argument than the original \meta{arg spec} demands. The
+% \meta{false branch} code in this additional argument will be
+% left on the input stream only if the test is \texttt{false}.
+% \item \cs{\meta{name}:\meta{arg spec}TF} , a function with two
+% more argument than the original \meta{arg spec} demands. The
+% \meta{true branch} code in the first additional argument will
+% be left on the input stream if the test is \texttt{true}, while
+% the \meta{false branch} code in the second argument will be
+% left on the input stream if the test is \texttt{false}.
+% \end{itemize}
+% The \meta{code} of the test may use \meta{parameters} as specified
+% by the second argument to \cs{prg_set_conditional:Npnn}: this should
+% match the \meta{argument specification} but this is not enforced.
+% The |Nnn| versions infer the number of arguments from the argument
+% specification given (\emph{cf.}~\cs{cs_new:Nn}, \emph{etc.}).
+% Within the \meta{code}, the functions \cs{prg_return_true:} and
+% \cs{prg_return_false:} are used to indicate the logical outcomes of
+% the test. If \meta{code} is expandable then
+% \cs{prg_set_conditional:Npnn} will generate a family of conditionals
+% which are also expandable. All of the functions are created globally.
+%
+% An example can easily clarify matters here:
+% \begin{verbatim}
+% \prg_set_conditional:Nnn \foo_if_bar:NN { p , T , TF }
+% {
+% \if_meaning:w \l_tmpa_tl #1
+% \prg_return_true:
+% \else:
+% \if_meaning:w \l_tmpa_tl #2
+% \prg_return_true:
+% \else:
+% \prg_return_false:
+% \fi:
+% \fi:
+% }
+% \end{verbatim}
+% This defines the function |\foo_if_bar_p:NN|, |\foo_if_bar:NNTF|,
+% |\foo_if_bar:NNT| but not |\foo_if_bar:NNF| (because |F| is missing from
+% the \meta{conds} list). The return statements
+% take care of resolving the remaining |\else:| and |\fi:| before
+% returning the state. There must be a return statement for each
+% branch, failing to do so will result in an error if that branch is
+% executed.
+% \end{function}
+%
+% \begin{function}
+% {
+% \prg_new_protected_conditional:Npnn, \prg_set_protected_conditional:Npnn,
+% \prg_new_protected_conditional:Nnn, \prg_set_protected_conditional:Nnn
+% }
+% \begin{syntax}
+% \cs{prg_set_protected_conditional:Npnn}
+% ~~\cs{\meta{name}:\meta{arg spec}} \meta{parameters}
+% ~~\meta{conditions} \Arg{code}
+% \cs{prg_set_protected_conditional:Nnn}
+% ~~\cs{\meta{name}:\meta{arg spec}} \meta{conditions} \Arg{code}
+% \end{syntax}
+% These functions creates a family of conditionals using the same
+% \Arg{code} to perform the test created. The \texttt{new} version will
+% check for existing definitions (\emph{cf.}~\cs{cs_new:Npn}) whereas
+% the \texttt{set} version will not (\emph{cf.}~\cs{cs_set:Npn}). The
+% conditionals created are depended on the comma-separated list of
+% \meta{conditions}, which should be one or more of \texttt{T},
+% \texttt{F} and \texttt{TF}. The conditionals are then defined in the
+% obvious way as:
+% \begin{itemize}
+% \item \cs{\meta{name}:\meta{arg spec}T}, a function with one
+% more argument than the original \meta{arg spec} demands. The
+% \meta{true branch} code in this additional argument will be
+% left on the input stream only if the test is \texttt{true}.
+% \item \cs{\meta{name}:\meta{arg spec}F}, a function with one
+% more argument than the original \meta{arg spec} demands. The
+% \meta{false branch} code in this additional argument will be
+% left on the input stream only if the test is \texttt{false}.
+% \item \cs{\meta{name}:\meta{arg spec}TF} , a function with two
+% more argument than the original \meta{arg spec} demands. The
+% \meta{true branch} code in the first additional argument will
+% be left on the input stream if the test is \texttt{true}, while
+% the \meta{false branch} code in the second argument will be
+% left on the input stream if the test is \texttt{false}.
+% \end{itemize}
+% The \meta{code} of the test may use \meta{parameters} as specified
+% by the second argument to \cs{prg_set_conditional:Npn}: this should
+% match the \meta{argument specification} but this is not enforced.
+% The |Nnn| versions infer the number of arguments from the argument
+% specification given (\emph{cf.}~\cs{cs_new:Nn}, \emph{etc.}).
+% Within the \meta{code}, the functions \cs{prg_return_true:} and
+% \cs{prg_return_false:} are used to indicate the logical outcomes of
+% the test. \cs{prg_set_protected_conditional:Npn} will generate
+% a family of protected conditional functions, and so \meta{code}
+% does not need to be expandable. All of the functions are created
+% globally.
+%\end{function}
+%
+% \begin{function}{\prg_new_eq_conditional:NN, \prg_set_eq_conditional:NN}
+% \begin{syntax}
+% \cs{prg_new_eq_conditional:NN}
+% ~~\cs{\meta{name1}:\meta{arg spec1}} \cs{\meta{name2}:\meta{arg spec2}}
+% \end{syntax}
+% These will set the definitions of the functions
+% \begin{itemize}
+% \item \cs{\meta{name1}_p:\meta{arg spec1}}
+% \item \cs{\meta{name1}:\meta{arg spec1}T}
+% \item \cs{\meta{name1}:\meta{arg spec1}F}
+% \item \cs{\meta{name1}:\meta{arg spec1}TF}
+% \end{itemize}
+% equal to those for
+% \begin{itemize}
+% \item \cs{\meta{name2}_p:\meta{arg spec2}}
+% \item \cs{\meta{name2}:\meta{arg spec2}T}
+% \item \cs{\meta{name2}:\meta{arg spec2}F}
+% \item \cs{\meta{name2}:\meta{arg spec2}TF}
+% \end{itemize}
+% In most cases, the two \meta{arg specs} will be identical, although
+% this is not enforced. In the case of the \texttt{new} function, a
+% check is made for any existing definitions for \meta{name1}. The
+% functions are set globally.
+% \end{function}
+%
+% \begin{function}[EXP]{\prg_return_true:, \prg_return_false:}
+% \begin{syntax}
+% \cs{prg_return_true:}
+% \cs{prg_return_false:}
+% \end{syntax}
+% These functions define the logical state at the end of a conditional.
+% As such, they should appear within the code for a conditional
+% statement generated by \cs{prg_set_conditional:Npnn}, \emph{etc}.
+% \end{function}
+%
+% \section{The boolean data type}
+%
+% This section describes a boolean data type which is closely
+% connected to conditional processing as sometimes you want to
+% execute some code depending on the value of a switch
+% (\emph{e.g.},~draft/final) and other times you perhaps want to use it as a
+% predicate function in an |\if_predicate:w| test. The problem of the
+% primitive |\if_false:| and |\if_true:| tokens is that it is not
+% always safe to pass them around as they may interfere with scanning
+% for termination of primitive conditional processing. Therefore, we
+% employ two canonical booleans: |\c_true_bool| or
+% |\c_false_bool|. Besides preventing problems as described above, it
+% also allows us to implement a simple boolean parser supporting the
+% logical operations And, Or, Not, \emph{etc.}\ which can then be used on
+% both the boolean type and predicate functions.
+%
+% All conditional |\bool_| functions are expandable and expect the
+% input to also be fully expandable (which will generally mean being
+% constructed from predicate functions, possibly nested).
+%
+% \begin{function}{\bool_new:N, \bool_new:c}
+% \begin{syntax}
+% \cs{bool_new:N} \meta{boolean}
+% \end{syntax}
+% Creates a new \meta{boolean} or raises an error if the
+% name is already taken. The declaration is global. The
+% \meta{boolean} will initially be \texttt{false}.
+% \end{function}
+%
+% \begin{function}{\bool_set_false:N, \bool_set_false:c}
+% \begin{syntax}
+% \cs{bool_set_false:N} \meta{boolean}
+% \end{syntax}
+% Sets \meta{boolean} logically \texttt{false} within the current
+% \TeX{} group.
+% \end{function}
+%
+% \begin{function}{\bool_gset_false:N, \bool_gset_false:c}
+% \begin{syntax}
+% \cs{bool_sget_false:N} \meta{boolean}
+% \end{syntax}
+% Sets \meta{boolean} logically \texttt{false} globally.
+% \end{function}
+%
+% \begin{function}{\bool_set_true:N, \bool_set_true:c}
+% \begin{syntax}
+% \cs{bool_set_true:N} \meta{boolean}
+% \end{syntax}
+% Sets \meta{boolean} logically \texttt{true} within the current
+% \TeX{} group.
+% \end{function}
+%
+% \begin{function}{\bool_gset_true:N, \bool_gset_true:c}
+% \begin{syntax}
+% \cs{bool_gset_true:N} \meta{boolean}
+% \end{syntax}
+% Sets \meta{boolean} logically \texttt{true} globally.
+% \end{function}
+%
+% \begin{function}
+% {\bool_set_eq:NN, \bool_set_eq:cN, \bool_set_eq:Nc, \bool_set_eq:cc}
+% \begin{syntax}
+% \cs{bool_set_eq:NN} \meta{boolean1} \meta{boolean2}
+% \end{syntax}
+% Sets the content of \meta{boolean1} equal to that of \meta{boolean2}.
+% This assignment is restricted to the current \TeX{} group level.
+% \end{function}
+%
+% \begin{function}
+% {\bool_gset_eq:NN, \bool_gset_eq:cN, \bool_gset_eq:Nc, \bool_gset_eq:cc}
+% \begin{syntax}
+% \cs{bool_gset_eq:NN} \meta{boolean1} \meta{boolean2}
+% \end{syntax}
+% Sets the content of \meta{boolean1} equal to that of \meta{boolean2}.
+% This assignment is global and so is not limited by the current
+% \TeX{} group level.
+% \end{function}
+%
+% \begin{function}{\bool_set:Nn, \bool_set:cn}
+% \begin{syntax}
+% \cs{bool_set:Nn} \meta{boolean} \Arg{boolexpr}
+% \end{syntax}
+% Evaluates the \meta{boolean expression} as described for
+% \cs{bool_if:n(TF)}, and sets the \meta{boolean} variable to
+% the logical truth of this evaluation. This assignment is local.
+% \end{function}
+%
+% \begin{function}{\bool_gset:Nn, \bool_gset:cn}
+% \begin{syntax}
+% \cs{bool_gset:Nn} \meta{boolean} \Arg{boolexpr}
+% \end{syntax}
+% Evaluates the \meta{boolean expression} as described for
+% \cs{bool_if:n(TF)}, and sets the \meta{boolean} variable to
+% the logical truth of this evaluation. This assignment is global.
+% \end{function}
+%
+% \begin{function}[EXP,pTF]{\bool_if:N, \bool_if:c}
+% \begin{syntax}
+% \cs{bool_if_p:N} \Arg{boolean}
+% \cs{bool_if:NTF} \Arg{boolean} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% Tests the current truth of \meta{boolean}, and continues expansion
+% based on this result. 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{variable}{\l_tmpa_bool}
+% A scratch boolean for local assignment. It is never used by
+% the kernel code, and so is safe for use with any \LaTeX3-defined
+% function. However, it may be overwritten by other non-kernel
+% code and so should only be used for short-term storage.
+% \end{variable}
+%
+% \begin{variable}{\g_tmpa_bool}
+% A scratch boolean for global assignment. It is never used by
+% the kernel code, and so is safe for use with any \LaTeX3-defined
+% function. However, it may be overwritten by other non-kernel
+% code and so should only be used for short-term storage.
+% \end{variable}
+%
+% \section{Boolean expressions}
+%
+% As we have a boolean datatype and predicate functions returning
+% boolean \meta{true} or \meta{false} values, it seems only fitting
+% that we also provide a parser for \meta{boolean expressions}.
+%
+% A boolean expression is an expression which given input in the form
+% of predicate functions and boolean variables, return boolean
+% \meta{true} or \meta{false}. It supports the logical operations And,
+% Or and Not as the well-known infix operators |&&|, \verb"||" and |!|. In
+% addition to this, parentheses can be used to isolate
+% sub-expressions. For example,
+% \begin{verbatim}
+% \int_compare_p:n { 1 = 1 } &&
+% (
+% \int_compare_p:n { 2 = 3 } ||
+% \int_compare_p:n { 4 = 4 } ||
+% \int_compare_p:n { 1 = \error } % is skipped
+% ) &&
+% ! ( \int_compare_p:n { 2 = 4 } )
+% \end{verbatim}
+% is a valid boolean expression. Note that minimal evaluation is
+% carried out whenever possible so that whenever a truth value cannot
+% be changed any more, the remaining tests within the current group
+% are skipped.
+%
+% \begin{function}[EXP,pTF]{\bool_if:n}
+% \begin{syntax}
+% \cs{bool_if_p:n} \Arg{boolean expression}
+% \cs{bool_if:nTF} \Arg{boolean expression} \Arg{true code}
+% ~~\Arg{false code}
+% \end{syntax}
+% Tests the current truth of \meta{boolean expression}, and
+% continues expansion based on this result. The
+% \meta{boolean expression} should consist of a series of predicates
+% or boolean variables with the logical relationship between these
+% defined using |&&| (\enquote{And}), \verb"||" (\enquote{Or}),
+% |!| (\enquote{Not}) and parentheses. Minimal evaluation is used
+% in the processing, so that once a result is defined there is
+% not further expansion of the tests. For example
+% \begin{verbatim}
+% \bool_if_p:n
+% {
+% \int_compare_p:nNn { 1 } = { 1 }
+% &&
+% (
+% \int_compare_p:nNn { 2 } = { 3 } ||
+% \int_compare_p:nNn { 4 } = { 4 } ||
+% \int_compare_p:nNn { 1 } = { \error } % is skipped
+% )
+% &&
+% ! ( \int_compare_p:nNn { 2 } = { 4 } )
+% }
+% \end{verbatim}
+% will be \texttt{true} and will not evaluate
+% |\int_compare_p:nNn { 1 } = { \error }|. The logical Not applies to
+% the next single predicate or group. As shown above, this means that
+% any predicates requiring an argument have to be given within
+% parentheses. 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}[EXP]{\bool_not_p:n}
+% \begin{syntax}
+% \cs{bool_not_p:n} \Arg{boolean expression}
+% \end{syntax}
+% Function version of |!(|\meta{boolean expression}|)| within a boolean
+% expression.
+% \end{function}
+%
+% \begin{function}[EXP]{\bool_xor_p:nn}
+% \begin{syntax}
+% \cs{bool_xor_p:nn} \Arg{boolexpr1} \Arg{boolexpr1}
+% \end{syntax}
+% Implements an \enquote{exclusive or} operation between two boolean
+% expressions. There is no infix operation for this logical
+% operator.
+% \end{function}
+%
+% \section{Logical loops}
+%
+% Loops using either boolean expressions or stored boolean values.
+%
+% \begin{function}[EXP]{\bool_until_do:Nn, \bool_until_do:cn}
+% \begin{syntax}
+% \cs{bool_until_do:Nn} \Arg{boolean} \Arg{code}
+% \end{syntax}
+% This function firsts checks the logical value of the \meta{boolean}.
+% If it is \texttt{false} the \meta{code} is placed in the input stream
+% and expanded. After the completion of the \meta{code} the truth
+% of the \meta{boolean} is re-evaluated. The process will then loop
+% until the \meta{boolean} is \texttt{true}.
+% \end{function}
+%
+% \begin{function}[EXP]{\bool_while_do:Nn, \bool_while_do:cn}
+% \begin{syntax}
+% \cs{bool_while_do:Nn} \Arg{boolean} \Arg{code}
+% \end{syntax}
+% This function firsts checks the logical value of the \meta{boolean}.
+% If it is \texttt{true} the \meta{code} is placed in the input stream
+% and expanded. After the completion of the \meta{code} the truth
+% of the \meta{boolean} is re-evaluated. The process will then loop
+% until the \meta{boolean} is \texttt{false}.
+% \end{function}
+%
+% \begin{function}[EXP]{\bool_until_do:nn}
+% \begin{syntax}
+% \cs{bool_until_do:nn} \Arg{boolean expression} \Arg{code}
+% \end{syntax}
+% This function firsts checks the logical value of the
+% \meta{boolean expression} (as described for \cs{bool_if:nTF}).
+% If it is \texttt{false} the \meta{code} is placed in the input stream
+% and expanded. After the completion of the \meta{code} the truth
+% of the \meta{boolean expression} is re-evaluated. The process will
+% then loop until the \meta{boolean expression} is \texttt{true}.
+% \end{function}
+%
+% \begin{function}[EXP]{\bool_while_do:nn}
+% \begin{syntax}
+% \cs{bool_while_do:nn} \Arg{boolean expression} \Arg{code}
+% \end{syntax}
+% This function firsts checks the logical value of the
+% \meta{boolean expression} (as described for \cs{bool_if:nTF}).
+% If it is \texttt{true} the \meta{code} is placed in the input stream
+% and expanded. After the completion of the \meta{code} the truth
+% of the \meta{boolean expression} is re-evaluated. The process will
+% then loop until the \meta{boolean expression} is \texttt{false}.
+% \end{function}
+%
+% \section{Switching by case}
+%
+% For cases where a number of cases need to be considered a family of
+% case-selecting functions are available.
+%
+% \begin{function}[EXP]{\prg_case_int:nnn}
+% \begin{syntax}
+% \cs{prg_case_int:nnn}
+% ~~\Arg{test integer expression}
+% ~~|{|
+% ~~~~\Arg{intexpr case1} \Arg{code case1}
+% ~~~~\Arg{intexpr case2} \Arg{code case2}
+% ~~~~\ldots
+% ~~~~\Arg{intexpr case$_n$} \Arg{code case$_n$}
+% ~~|}|
+% ~~\Arg{else case}
+% \end{syntax}
+% This function evaluates the \meta{test integer expression} and
+% compares this in turn to each of the
+% \meta{integer expression cases}. If the two are equal then the
+% associated \meta{code} is left in the input stream. If none of
+% the tests are \texttt{true} then the \texttt{else code} will be
+% left in the input stream. For example
+% \begin{verbatim}
+% \prg_case_int:nnn
+% { 2 * 5 }
+% {
+% { 5 } { Small }
+% { 4 + 6 } { Medium }
+% { -2 * 10 } { Negative }
+% }
+% { No idea! }
+% \end{verbatim}
+% will leave \enquote{\texttt{Medium}} in the input stream.
+% \end{function}
+%
+% \begin{function}[EXP]{\prg_case_dim:nnn}
+% \begin{syntax}
+% \cs{prg_case_dim:nnn}
+% ~~\Arg{test dimension expression}
+% ~~|{|
+% ~~~~\Arg{dimexpr case1} \Arg{code case1}
+% ~~~~\Arg{dimexpr case2} \Arg{code case2}
+% ~~~~\ldots
+% ~~~~\Arg{dimexpr case$_n$} \Arg{code case$_n$}
+% ~~|}|
+% ~~\Arg{else case}
+% \end{syntax}
+% This function evaluates the \meta{test dimension expression} and
+% compares this in turn to each of the
+% \meta{dimension expression cases}. If the two are equal then the
+% associated \meta{code} is left in the input stream. If none of
+% the tests are \texttt{true} then the \texttt{else code} will be
+% left in the input stream.
+% \end{function}
+%
+% \begin{function}[EXP]
+% {\prg_case_str:nnn, \prg_case_str:onn, \prg_case_str:xxn}
+% \begin{syntax}
+% \cs{prg_case_str:nnn}
+% ~~\Arg{test string}
+% ~~|{|
+% ~~~~\Arg{string case1} \Arg{code case1}
+% ~~~~\Arg{string case2} \Arg{code case2}
+% ~~~~\ldots
+% ~~~~\Arg{string case$_n$} \Arg{code case$_n$}
+% ~~|}|
+% ~~\Arg{else case}
+% \end{syntax}
+% This function compares the \meta{test string} in turn with each
+% of the \meta{string cases}. If the two are equal (as described for
+% \cs{str_if_eq:nnTF} then the
+% associated \meta{code} is left in the input stream. If none of
+% the tests are \texttt{true} then the \texttt{else code} will be
+% left in the input stream. The |xx| variant is fully expandable,
+% in the same way as the underlying \cs{str_if_eq:xxTF} test.
+% \end{function}
+%
+% \begin{function}[EXP]{\prg_case_tl:Nnn, \prg_case_tl:cnn}
+% \begin{syntax}
+% \cs{prg_case_tl:Nnn}
+% ~~\meta{test token list variable}
+% ~~"{"
+% ~~~~\meta{token list variable case1} \Arg{code case1}
+% ~~~~\meta{token list variable case2} \Arg{code case2}
+% ~~~~\ldots
+% ~~~~\meta{token list variable case$_n$} \Arg{code case$_n$}
+% ~~"}"
+% ~~\Arg{else case}
+% \end{syntax}
+% This function compares the \meta{test token list variable} in turn
+% with each of the \meta{token list variable cases}. If the two
+% are equal (as described for
+% \cs{tl_if_eq:nnTF}
+% then the associated \meta{code} is left in the input
+% stream. If none of the tests are \texttt{true} then the
+% \texttt{else code} will be left in the input stream.
+% \end{function}
+%
+% \section{Producing $n$ copies}
+%
+% \begin{function}[EXP]{\prg_replicate:nn}
+% \begin{syntax}
+% \cs{prg_replicate:nn} \Arg{integer expression} \Arg{tokens}
+% \end{syntax}
+% Evaluates the \meta{integer expression} (which should be
+% zero or positive) and creates the resulting number of copies
+% of the \meta{tokens}. The function is both expandable and safe for
+% nesting. It yields its result after two expansion steps.
+% \end{function}
+%
+% \begin{function}[EXP]{\prg_stepwise_function:nnnN}
+% \begin{syntax}
+% \cs{prg_stepwise_function:nnnN} \Arg{initial value} \Arg{step}
+% ~~\Arg{final value} \meta{function}
+% \end{syntax}
+% This function first evaluates the \meta{initial value}, \meta{step}
+% and \meta{final value}, all of which should be integer expressions.
+% The \meta{function} is then placed in front of each \meta{value}
+% from the \meta{initial value} to the \meta{final value} in turn
+% (using \meta{step} between each \meta{value}). Thus \meta{function}
+% should absorb one numerical argument. For example
+% \begin{verbatim}
+% \cs_set_nopar:Npn \my_func:n #1 { I~saw~#1 \\ }
+% \prg_stepwise_function:nnnN { 1 } { 5 } { 1 } \my_func:n
+% \end{verbatim}
+% would print
+% \begin{quote}
+% I saw 1 \\
+% I saw 2 \\
+% I saw 3 \\
+% I saw 4 \\
+% I saw 5 \\
+% \end{quote}
+% \end{function}
+%
+% \begin{function}{\prg_stepwise_inline:nnnn}
+% \begin{syntax}
+% \cs{prg_stepwise_inline:nnnn} \Arg{initial value} \Arg{step}
+% ~~\Arg{final value} \Arg{code}
+% \end{syntax}
+% This function first evaluates the \meta{initial value}, \meta{step}
+% and \meta{final value}, all of which should be integer expressions.
+% The \meta{code} is then placed in front of each \meta{value}
+% from the \meta{initial value} to the \meta{final value} in turn
+% (using \meta{step} between each \meta{value}). Thus the \meta{code}
+% should define a function of one argument (|#1|).
+% \end{function}
+%
+% \begin{function}{\prg_stepwise_variable:nnnn}
+% \begin{syntax}
+% \cs{prg_stepwise_inline:nnnn} \Arg{initial value} \Arg{step}
+% ~~\Arg{final value} \meta{tl~var} \Arg{code}
+% \end{syntax}
+% This function first evaluates the \meta{initial value}, \meta{step}
+% and \meta{final value}, all of which should be integer expressions.
+% The \meta{code} is inserted into the input stream, with the
+% \meta{tl~var} defined as the current \meta{value}. Thus the
+% \meta{code} should make use of the \meta{tl~var}.
+% \end{function}
+%
+% \section{Detecting \TeX{}'s mode}
+%
+% \begin{function}[EXP,pTF]{\mode_if_horizontal:}
+% \begin{syntax}
+% \cs{mode_if_horizontal_p:}
+% \cs{mode_if_horizontal:TF} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% Detects if \TeX{} is currently in horizontal mode. 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}[EXP,pTF]{\mode_if_inner:}
+% \begin{syntax}
+% \cs{mode_if_inner_p:}
+% \cs{mode_if_inner:TF} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% Detects if \TeX{} is currently in inner mode. 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}[EXP,TF]{\mode_if_math:}
+% \begin{syntax}
+% \cs{mode_if_math:TF} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% Detects if \TeX{} is currently in maths mode. 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.
+% \end{function}
+%
+% \begin{function}[EXP,pTF]{\mode_if_vertical:}
+% \begin{syntax}
+% \cs{mode_if_vertical_p:}
+% \cs{mode_if_vertical:TF} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% Detects if \TeX{} is currently in vertical mode. 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}
+%
+% \section{Internal programming functions}
+%
+% \begin{function}[EXP]{\group_align_safe_begin:, \group_align_safe_end:}
+% \begin{syntax}
+% \cs{group_align_safe_begin:}
+% \ldots
+% \cs{group_align_safe_end:}
+% \end{syntax}
+% These functions are used to enclose material in a \TeX{} alignment
+% environment within a specially-constructed group. This group is
+% designed in such a way that it does not add brace groups to the
+% output but does act as a group for the |&| token inside
+% \cs{tex_halign:D}. This is necessary to allow grabbing of tokens
+% for testing purposes, as \TeX{} uses group level to determine the
+% effect of alignment tokens. Without the special grouping, the use of
+% a function such as \cs{peek_after:Nw} will result in a forbidden
+% comparison of the internal \cs{endtemplate} token, yielding a
+% fatal error. Each \cs{group_align_safe_begin:} must be matched by a
+% \cs{group_align_safe_end:}, although this does not have to occur
+% within the same function.
+% \end{function}
+%
+% \begin{function}{\scan_align_safe_stop:}
+% \begin{syntax}
+% \cs{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}[EXP]{\prg_variable_get_scope:N}
+% \begin{syntax}
+% \cs{prg_variable_get_scope:N} \meta{variable}
+% \end{syntax}
+% Returns the scope (\texttt{g} for global, blank otherwise) for the
+% \meta{variable}.
+% \end{function}
+%
+% \begin{function}[EXP]{\prg_variable_get_type:N}
+% \begin{syntax}
+% \cs{prg_variable_get_type:N} \meta{variable}
+% \end{syntax}
+% Returns the type of \meta{variable} (\texttt{tl}, \texttt{int},
+% \emph{etc.})
+% \end{function}
+%
+% \section{Experimental programmings functions}
+%
+% \begin{function}{\prg_quicksort:n}
+% \begin{syntax}
+% \cs{prg_quicksort:n} |{| \Arg{item~1} \Arg{item~2} \dots \Arg{item~n} |}|
+% \end{syntax}
+% Performs a quicksort on the token list. The comparisons are
+% performed by the function \cs{prg_quicksort_compare:nnTF} which is up
+% to the programmer to define. When the sorting process is over, all
+% items are given as argument to the function
+% \cs{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" \Arg{element} \\
+% "\prg_quicksort_compare:nnTF" \Arg{element 1} \Arg{element 2}\\
+% \end{syntax}
+% The two functions the programmer must define before calling
+% |\prg_quicksort:n|. As an example we could define
+% \begin{quote}
+% |\cs_set_nopar:Npn\prg_quicksort_function:n #1{{#1}}|\\
+% |\cs_set_nopar:Npn\prg_quicksort_compare:nnTF #1#2#3#4 {\int_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}
+% |\cs_set_nopar:Npn\prg_quicksort_compare:nnTF #1#2 {|\\
+% | \int_compare:nNnTF{\tl_compare:nn{#1}{#2}}>\c_zero }|
+% \end{quote}
+%
+% \end{function}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3prg} implementation}
+%
+% \TestFiles{m3prg001.lvt,m3prg002.lvt,m3prg003.lvt}
+%%
+% \begin{macrocode}
+%<*initex|package>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*package>
+\ProvidesExplPackage
+ {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
+\package_check_loaded_expl:
+%</package>
+% \end{macrocode}
+%
+% \subsection{Defining a set of conditional functions}
+%
+% \begin{macro}
+% {
+% \prg_set_conditional:Npnn,
+% \prg_new_conditional:Npnn,
+% \prg_set_protected_conditional:Npnn,
+% \prg_new_protected_conditional:Npnn
+% }
+% \begin{macro}
+% {
+% \prg_set_conditional:Nnn,
+% \prg_new_conditional:Nnn,
+% \prg_set_protected_conditional:Nnn,
+% \prg_new_protected_conditional:Nnn
+% }
+% \begin{macro}{\prg_set_eq_conditional:NNn, \prg_new_eq_conditional:NNn}
+% \begin{macro}{\prg_return_true:}
+% \TestMissing
+% {This function is implicitly tested with all other conditionals!}
+% \begin{macro}{\prg_return_false:}
+% \TestMissing
+% {This function is also implicitly tested with all other conditionals!}
+% These are all defined in \pkg{l3basics}, as they are needed
+% \enquote{early}. This is just a reminder that that is the case!
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{The boolean data type}
+%
+% \begin{macro}{\bool_new:N, \bool_new:c}
+% \UnitTested
+% Boolean variables have to be initiated when they are created. Other
+% than that there is not much to say here.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \bool_new:N #1 { \cs_new_eq:NN #1 \c_false_bool }
+\cs_generate_variant:Nn \bool_new:N { c }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \bool_set_true:N, \bool_set_true:c,
+% \bool_gset_true:N, \bool_gset_true:c,
+% \bool_set_false:N, \bool_set_false:c,
+% \bool_gset_false:N, \bool_gset_false:c
+% }
+% \UnitTested
+% Setting is already pretty easy.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \bool_set_true:N #1
+ { \cs_set_eq:NN #1 \c_true_bool }
+\cs_new_protected_nopar:Npn \bool_set_false:N #1
+ { \cs_set_eq:NN #1 \c_false_bool }
+\cs_new_protected_nopar:Npn \bool_gset_true:N #1
+ { \cs_gset_eq:NN #1 \c_true_bool }
+\cs_new_protected_nopar:Npn \bool_gset_false:N #1
+ { \cs_gset_eq:NN #1 \c_false_bool }
+\cs_generate_variant:Nn \bool_set_true:N { c }
+\cs_generate_variant:Nn \bool_set_false:N { c }
+\cs_generate_variant:Nn \bool_gset_true:N { c }
+\cs_generate_variant:Nn \bool_gset_false:N { c }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \bool_set_eq:NN, \bool_set_eq:cN,
+% \bool_set_eq:Nc, \bool_set_eq:cc,
+% \bool_gset_eq:NN, \bool_gset_eq:cN,
+% \bool_gset_eq:Nc, \bool_gset_eq:cc
+% }
+% \UnitTested
+% The usual copy code.
+% \begin{macrocode}
+\cs_new_eq:NN \bool_set_eq:NN \cs_set_eq:NN
+\cs_new_eq:NN \bool_set_eq:Nc \cs_set_eq:Nc
+\cs_new_eq:NN \bool_set_eq:cN \cs_set_eq:cN
+\cs_new_eq:NN \bool_set_eq:cc \cs_set_eq:cc
+\cs_new_eq:NN \bool_gset_eq:NN \cs_gset_eq:NN
+\cs_new_eq:NN \bool_gset_eq:Nc \cs_gset_eq:Nc
+\cs_new_eq:NN \bool_gset_eq:cN \cs_gset_eq:cN
+\cs_new_eq:NN \bool_gset_eq:cc \cs_gset_eq:cc
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\bool_set:Nn,\bool_set:cn}
+% \begin{macro}{\bool_gset:Nn,\bool_gset:cn}
+% This function evaluates a boolean expression and assigns the first
+% argument the meaning |\c_true_bool| or |\c_false_bool|.
+% \begin{macrocode}
+\cs_new:Npn \bool_set:Nn #1#2
+ { \tex_chardef:D #1 = \bool_if_p:n {#2} }
+\cs_new:Npn \bool_gset:Nn #1#2
+ { \tex_global:D \tex_chardef:D #1 = \bool_if_p:n {#2} }
+\cs_generate_variant:Nn \bool_set:Nn { c }
+\cs_generate_variant:Nn \bool_gset:Nn { c }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[pTF]{\bool_if:N, \bool_if:c}
+% \UnitTested
+% Straight forward here. We could optimize here if we wanted to as
+% the boolean can just be input directly.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \bool_if:N #1 { p , T , F , TF }
+ {
+ \if_bool:N #1
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+\cs_generate_variant:Nn \bool_if_p:N { c }
+\cs_generate_variant:Nn \bool_if:NT { c }
+\cs_generate_variant:Nn \bool_if:NF { c }
+\cs_generate_variant:Nn \bool_if:NTF { c }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{variable}{\l_tmpa_bool, \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{variable}
+%
+% \subsection{Boolean expressions}
+%
+% \begin{macro}[pTF]{\bool_if:n}
+% \UnitTested
+% \begin{macro}[aux]{\bool_get_next:N}
+% \begin{macro}[aux]{\bool_cleanup:N}
+% \begin{macro}[aux]{\bool_choose:NN}
+% \begin{macro}[aux]
+% {
+% bool_!:w,
+% \bool_Not:w,
+% \bool_Not:w,
+% \bool_(:w,
+% \bool_p:w,
+% \bool_8_1:w,
+% \bool_I_1:w,
+% \bool_8_0:w,
+% \bool_I_0:w,
+% \bool_)_0:w,
+% \bool_)_1:w,
+% \bool_S_0:w,
+% \bool_S_1:w
+% }
+% \begin{macro}[aux]
+% {
+% \bool_eval_skip_to_end:Nw, \bool_eval_skip_to_end_aux:Nw,
+% \bool_eval_skip_to_end_aux_ii:Nw
+% }
+% Evaluating the truth value of a list of predicates is done using
+% an input syntax somewhat similar to the one found in other
+% programming languages with |(| and |)| for grouping, |!| for
+% logical \enquote{Not}, |&&| for logical \enquote{And} and \verb"||"
+% for logical \enquote{Or}. We shall use the terms Not, And, Or, Open and
+% Close for these operations.
+%
+% Any expression is terminated by a Close operation. Evaluation
+% happens from left to right in the following manner using a GetNext
+% function:
+% \begin{itemize}
+% \item If an Open is seen, start evaluating a new expression using
+% the Eval function and call GetNext again.
+% \item If a Not is seen, insert a negating function (if-even in
+% this case) and call GetNext.
+% \item If none of the above, start evaluating a new expression by
+% reinserting the token found (this is supposed to be a predicate
+% function) in front of Eval.
+% \end{itemize}
+% The Eval function then contains a post-processing operation which
+% grabs the instruction following the predicate. This is either And,
+% Or or Close. In each case the truth value is used to determine
+% where to go next. The following situations can arise:
+% \begin{description}
+% \item[\meta{true}And] Current truth value is true, logical And
+% seen, continue with GetNext to examine truth value of next
+% boolean (sub-)expression.
+% \item[\meta{false}And] Current truth value is false, logical And
+% seen, stop evaluating the predicates within this sub-expression
+% and break to the nearest Close. Then return \meta{false}.
+% \item[\meta{true}Or] Current truth value is true, logical Or
+% seen, stop evaluating the predicates within this sub-expression
+% and break to the nearest Close. Then return \meta{true}.
+% \item[\meta{false}Or] Current truth value is false, logical Or
+% seen, continue with GetNext to examine truth value of next
+% boolean (sub-)expression.
+% \item[\meta{true}Close] Current truth value is true, Close
+% seen, return \meta{true}.
+% \item[\meta{false}Close] Current truth value is false, Close
+% seen, return \meta{false}.
+% \end{description}
+% We introduce an additional Stop operation with the following
+% semantics:
+% \begin{description}
+% \item[\meta{true}Stop] Current truth value is true, return
+% \meta{true}.
+% \item[\meta{false}Stop] Current truth value is false, return
+% \meta{false}.
+% \end{description}
+% The reasons for this follow below.
+%
+% Now for how these works in practice. The canonical true and false
+% values have numerical values $1$ and $0$ respectively. We evaluate
+% this using the primitive |\int_value:w:D| operation. First we
+% issue a |\group_align_safe_begin:| as we are using |&&| as syntax
+% shorthand for the And operation and we need to hide it for \TeX{}.
+% We also need to finish this special group before finally
+% returning a |\c_true_bool| or |\c_false_bool| as there might
+% otherwise be something left in front in the input stream. For
+% this we call the Stop operation, denoted simply by a |S|
+% following the last Close operation.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \bool_if:n #1 { T , F , TF }
+ {
+ \if_predicate:w \bool_if_p:n {#1}
+ \prg_return_true:
+ \else:
+ \prg_return_false:
+ \fi:
+ }
+\cs_new:Npn \bool_if_p:n #1
+ {
+ \group_align_safe_begin:
+ \bool_get_next:N ( #1 ) S
+ }
+% \end{macrocode}
+% The GetNext operation. We make it a switch: If not a |!| or |(|, we
+% assume it is a predicate.
+% \begin{macrocode}
+\cs_new:Npn \bool_get_next:N #1
+ {
+ \use:c
+ {
+ bool_
+ \if_meaning:w !#1 ! \else: \if_meaning:w (#1 ( \else: p \fi: \fi:
+ :w
+ }
+ #1
+ }
+% \end{macrocode}
+% This variant gets called when a Not has just been entered.
+% It (eventually) results in a reversal of the logic of the directly
+% following material.
+% \begin{macrocode}
+\cs_new:Npn \bool_get_not_next:N #1
+ {
+ \use:c
+ {
+ bool_not_
+ \if_meaning:w !#1 ! \else: \if_meaning:w (#1 ( \else: p \fi: \fi:
+ :w
+ }
+ #1
+ }
+% \end{macrocode}
+% We need these later on to nullify the unity operation |!!|.
+% \begin{macrocode}
+\cs_new:Npn \bool_get_next:NN #1#2 { \bool_get_next:N #2 }
+\cs_new:Npn \bool_get_not_next:NN #1#2 { \bool_get_not_next:N #2 }
+% \end{macrocode}
+% The Not operation. Discard the token read and reverse the truth
+% value of the next expression if there
+% are brackets; otherwise
+% if we're coming up to a |!| then we don't need to reverse anything
+% (but we then want to continue scanning ahead in case some fool has written
+% |!!(...)|);
+% otherwise we have a boolean that we can reverse here and now.
+% \begin{macrocode}
+\cs_new:cpn { bool_!:w } #1#2
+ {
+ \if_meaning:w ( #2
+ \exp_after:wN \bool_Not:w
+ \else:
+ \if_meaning:w ! #2
+ \exp_after:wN \exp_after:wN \exp_after:wN \bool_get_next:NN
+ \else:
+ \exp_after:wN \exp_after:wN \exp_after:wN \bool_Not:N
+ \fi:
+ \fi:
+ #2
+ }
+% \end{macrocode}
+% Variant called when already inside a Not.
+% Essentially the opposite of the above.
+% \begin{macrocode}
+\cs_new:cpn { bool_not_!:w } #1#2
+ {
+ \if_meaning:w ( #2
+ \exp_after:wN \bool_not_Not:w
+ \else:
+ \if_meaning:w ! #2
+ \exp_after:wN \exp_after:wN \exp_after:wN \bool_get_not_next:NN
+ \else:
+ \exp_after:wN \exp_after:wN \exp_after:wN \bool_not_Not:N
+ \fi:
+ \fi:
+ #2
+ }
+% \end{macrocode}
+% These occur when processing |!(...)|. The idea is to use a variant
+% of |\bool_get_next:N| that finishes its parsing with a logic reversal.
+% Of course, the double logic reversal gets us back to where we started.
+% \begin{macrocode}
+\cs_new:Npn \bool_Not:w { \exp_after:wN \int_value:w \bool_get_not_next:N }
+\cs_new:Npn \bool_not_Not:w { \exp_after:wN \int_value:w \bool_get_next:N }
+% \end{macrocode}
+% These occur when processing |!<bool>| and can be evaluated directly.
+% \begin{macrocode}
+\cs_new:Npn \bool_Not:N #1
+ {
+ \exp_after:wN \bool_p:w
+ \if_meaning:w #1 \c_true_bool
+ \c_false_bool
+ \else:
+ \c_true_bool
+ \fi:
+ }
+\cs_new:Npn \bool_not_Not:N #1
+ {
+ \exp_after:wN \bool_p:w
+ \if_meaning:w #1 \c_true_bool
+ \c_true_bool
+ \else:
+ \c_false_bool
+ \fi:
+ }
+% \end{macrocode}
+% The Open operation. Discard the token read and start a
+% sub-expression.
+% |\bool_get_next:N| continues building up the logical expressions as usual;
+% |\bool_not_cleanup:N| is what reverses the logic if we're inside |!(...)|.
+% \begin{macrocode}
+\cs_new:cpn { bool_(:w } #1
+ { \exp_after:wN \bool_cleanup:N \int_value:w \bool_get_next:N }
+\cs_new:cpn { bool_not_(:w } #1
+ { \exp_after:wN \bool_not_cleanup:N \int_value:w \bool_get_next:N }
+% \end{macrocode}
+% Otherwise just evaluate the predicate and look for And, Or or Close
+% afterwards.
+% \begin{macrocode}
+\cs_new:cpn { bool_p:w } { \exp_after:wN \bool_cleanup:N \int_value:w }
+\cs_new:cpn { bool_not_p:w } {\exp_after:wN \bool_not_cleanup:N \int_value:w }
+% \end{macrocode}
+% This cleanup function can be omitted once predicates return their
+% true/false booleans outside the conditionals.
+% \begin{macrocode}
+\cs_new:Npn \bool_cleanup:N #1
+ {
+ \exp_after:wN \bool_choose:NN \exp_after:wN #1
+ \int_to_roman:w - `\q
+ }
+\cs_new:Npn \bool_not_cleanup:N #1
+ {
+ \exp_after:wN \bool_not_choose:NN \exp_after:wN #1
+ \int_to_roman:w - `\q
+ }
+% \end{macrocode}
+% Branching the six way switch.
+% Reversals should be reasonably straightforward.
+% \begin{macrocode}
+\cs_new_nopar:Npn \bool_choose:NN #1#2 { \use:c { bool_ #2 _ #1 :w } }
+\cs_new_nopar:Npn \bool_not_choose:NN #1#2 { \use:c { bool_not_ #2 _ #1 :w } }
+% \end{macrocode}
+% Continues scanning. Must remove the second "&" or \verb"|".
+% \begin{macrocode}
+\cs_new_nopar:cpn { bool_&_1:w } & { \bool_get_next:N }
+\cs_new_nopar:cpn { bool_|_0:w } | { \bool_get_next:N }
+\cs_new_nopar:cpn { bool_not_&_0:w } & { \bool_get_next:N }
+\cs_new_nopar:cpn { bool_not_|_1:w } | { \bool_get_next:N }
+% \end{macrocode}
+% Closing a group is just about returning the result. The Stop
+% operation is similar except it closes the special alignment group
+% before returning the boolean.
+% \begin{macrocode}
+\cs_new_nopar:cpn { bool_)_0:w } { \c_false_bool }
+\cs_new_nopar:cpn { bool_)_1:w } { \c_true_bool }
+\cs_new_nopar:cpn { bool_not_)_0:w } { \c_true_bool }
+\cs_new_nopar:cpn { bool_not_)_1:w } { \c_false_bool }
+\cs_new_nopar:cpn { bool_S_0:w } { \group_align_safe_end: \c_false_bool }
+\cs_new_nopar:cpn { bool_S_1:w } { \group_align_safe_end: \c_true_bool }
+% \end{macrocode}
+% When the truth value has already been decided, we have to throw away
+% the remainder of the current group as we are doing minimal
+% evaluation. This is slightly tricky as there are no braces so we
+% have to play match the |()| manually.
+% \begin{macrocode}
+\cs_new_nopar:cpn { bool_&_0:w } & { \bool_eval_skip_to_end:Nw \c_false_bool }
+\cs_new_nopar:cpn { bool_|_1:w } | { \bool_eval_skip_to_end:Nw \c_true_bool }
+\cs_new_nopar:cpn { bool_not_&_1:w } &
+ { \bool_eval_skip_to_end:Nw \c_false_bool }
+\cs_new_nopar:cpn { bool_not_|_0:w } |
+ { \bool_eval_skip_to_end:Nw \c_true_bool }
+% \end{macrocode}
+% There is always at least one |)| waiting, namely the outer
+% one. However, we are facing the problem that there may be more than
+% one that need to be finished off and we have to detect the correct
+% number of them. Here is a complicated example showing how this is
+% done. After evaluating the following, we realize we must skip
+% everything after the first And. Note the extra Close at the end.
+% \begin{quote}
+% |\c_false_bool && ((abc) && xyz) && ((xyz) && (def)))|
+% \end{quote}
+% First read up to the first Close. This gives us the list we first
+% read up until the first right parenthesis so we are looking at the
+% token list
+% \begin{quote}
+% |((abc|
+% \end{quote}
+% This contains two Open markers so we must remove two groups. Since
+% no evaluation of the contents is to be carried out, it doesn't
+% matter how we remove the groups as long as we wind up with the
+% correct result. We therefore first remove a |()| pair and what
+% preceded the Open -- but leave the contents as it may contain Open
+% tokens itself -- leaving
+% \begin{quote}
+% |(abc && xyz) && ((xyz) && (def)))|
+% \end{quote}
+% Another round of this gives us
+% \begin{quote}
+% |(abc && xyz|
+% \end{quote}
+% which still contains an Open so we remove another |()| pair, giving us
+% \begin{quote}
+% |abc && xyz && ((xyz) && (def)))|
+% \end{quote}
+% Again we read up to a Close and again find Open tokens:
+% \begin{quote}
+% |abc && xyz && ((xyz|
+% \end{quote}
+% Further reduction gives us
+% \begin{quote}
+% |(xyz && (def)))|
+% \end{quote}
+% and then
+% \begin{quote}
+% |(xyz && (def|
+% \end{quote}
+% with reduction to
+% \begin{quote}
+% |xyz && (def))|
+% \end{quote}
+% and ultimately we arrive at no Open tokens being skipped and we can
+% finally close the group nicely.
+% \begin{macrocode}
+%% (
+\cs_new:Npn \bool_eval_skip_to_end:Nw #1#2 )
+ {
+ \bool_eval_skip_to_end_aux:Nw #1#2 ( % )
+ \q_no_value \q_stop
+ {#2}
+ }
+% \end{macrocode}
+% If no right parenthesis, then |#3| is no_value and we are done, return
+% the boolean |#1|. If there is, we need to grab a |()| pair and then
+% recurse
+% \begin{macrocode}
+\cs_new:Npn \bool_eval_skip_to_end_aux:Nw #1#2 ( #3#4 \q_stop #5 % )
+ {
+ \quark_if_no_value:NTF #3
+ {#1}
+ { \bool_eval_skip_to_end_aux_ii:Nw #1 #5 }
+ }
+% \end{macrocode}
+% Keep the boolean, throw away anything up to the |(| as it is
+% irrelevant, remove a |()| pair but remember to reinsert |#3| as it may
+% contain |(| tokens!
+% \begin{macrocode}
+\cs_new:Npn \bool_eval_skip_to_end_aux_ii:Nw #1#2 ( #3 )
+ { % (
+ \bool_eval_skip_to_end:Nw #1#3 )
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\bool_not_p:n}
+% \UnitTested
+% The Not variant just reverses the outcome of |\bool_if_p:n|. Can
+% be optimized but this is nice and simple and according to the
+% implementation plan. Not even particularly useful to have it when
+% the infix notation is easier to use.
+% \begin{macrocode}
+\cs_new:Npn \bool_not_p:n #1 { \bool_if_p:n { ! ( #1 ) } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\bool_xor_p:nn}
+% \UnitTested
+% Exclusive or. If the boolean expressions have same truth value,
+% return false, otherwise return true.
+% \begin{macrocode}
+\cs_new:Npn \bool_xor_p:nn #1#2
+ {
+ \int_compare:nNnTF { \bool_if_p:n {#1} } = { \bool_if_p:n {#2} }
+ \c_false_bool
+ \c_true_bool
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Logical loops}
+%
+% \begin{macro}{\bool_while_do:Nn,\bool_while_do:cn}
+% \UnitTested
+% \begin{macro}{\bool_until_do:Nn,\bool_until_do:cn}
+% \UnitTested
+% A |while| loop where the boolean is tested before executing the
+% statement. The \enquote{while} version executes the code as long as the
+% boolean is true; the \enquote{until} version executes the code as
+% long as the boolean is false.
+% \begin{macrocode}
+\cs_new:Npn \bool_while_do:Nn #1#2
+ { \bool_if:NT #1 { #2 \bool_while_do:Nn #1 {#2} } }
+\cs_new:Npn \bool_until_do:Nn #1#2
+ { \bool_if:NF #1 { #2 \bool_until_do:Nn #1 {#2} } }
+\cs_generate_variant:Nn \bool_while_do:Nn { c }
+\cs_generate_variant:Nn \bool_until_do:Nn { c }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\bool_do_while:Nn,\bool_do_while:cn}
+% \UnitTested
+% \begin{macro}{\bool_do_until:Nn,\bool_do_until:cn}
+% \UnitTested
+% 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}
+\cs_new:Npn \bool_do_while:Nn #1#2
+ { #2 \bool_if:NT #1 { \bool_do_while:Nn #1 {#2} } }
+\cs_new:Npn \bool_do_until:Nn #1#2
+ { #2 \bool_if:NF #1 { \bool_do_until:Nn #1 {#2} } }
+\cs_generate_variant:Nn \bool_do_while:Nn { c }
+\cs_generate_variant:Nn \bool_do_until:Nn { c }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \bool_while_do:nn, \bool_do_while:nn ,
+% \bool_until_do:nn, \bool_do_until:nn
+% }
+% \UnitTested
+% Loop functions with the test either before or after the first body
+% expansion.
+% \begin{macrocode}
+\cs_new:Npn \bool_while_do:nn #1#2
+ {
+ \bool_if:nT {#1}
+ {
+ #2
+ \bool_while_do:nn {#1} {#2}
+ }
+ }
+\cs_new:Npn \bool_do_while:nn #1#2
+ {
+ #2
+ \bool_if:nT {#1} { \bool_do_while:nn {#1} {#2} }
+ }
+\cs_new:Npn \bool_until_do:nn #1#2
+ {
+ \bool_if:nF {#1}
+ {
+ #2
+ \bool_until_do:nn {#1} {#2}
+ }
+ }
+\cs_new:Npn \bool_do_until:nn #1#2
+ {
+ #2
+ \bool_if:nF {#1} { \bool_do_until:nn {#1} {#2} }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Switching by case}
+%
+% A family of functions to select one case of a number: the same ideas
+% are used for a number of different situations.
+%
+% \begin{macro}[aux]{\prg_case_end:nw}
+% In all cases the end statement is the same. Here, |#1| will be the
+% code needed, |#2| the other cases to throw away, including the
+% \enquote{else} case.
+% \begin{macrocode}
+\cs_new_eq:NN \prg_case_end:nw \use_i_delimit_by_q_recursion_stop:nw
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\prg_case_int:nnn}
+% \UnitTested
+% \begin{macro}[aux]{\prg_case_int_aux:nnn,\prg_case_int_aux:nw}
+% For integer cases, the first task to fully expand the check
+% condition. After that, a loop is started to compare each possible
+% value and stop if the test is true. The tested value is put at the
+% end to ensure that there is necessarily a match, which will fire the
+% \enquote{else} pathway.
+% \begin{macrocode}
+\cs_new:Npn \prg_case_int:nnn #1
+ { \exp_args:Nf \prg_case_int_aux:nnn { \int_eval:n {#1} } }
+\cs_new:Npn \prg_case_int_aux:nnn #1 #2 #3
+ { \prg_case_int_aux:nw {#1} #2 {#1} {#3} \q_recursion_stop }
+\cs_new:Npn \prg_case_int_aux:nw #1#2#3
+ {
+ \int_compare:nNnTF {#1} = {#2}
+ { \prg_case_end:nw {#3} }
+ { \prg_case_int_aux:nw {#1} }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\prg_case_dim:nnn}
+% \UnitTested
+% \begin{macro}[aux]{\prg_case_dim_aux:nnn,\prg_case_dim_aux:nw}
+% The dimension function is the same, just a change of calculation
+% method.
+% \begin{macrocode}
+\cs_new:Npn \prg_case_dim:nnn #1
+ { \exp_args:Nf \prg_case_dim_aux:nnn { \dim_eval:n {#1} } }
+\cs_new:Npn \prg_case_dim_aux:nnn #1 #2 #3
+ { \prg_case_dim_aux:nw {#1} #2 {#1} {#3} \q_recursion_stop }
+\cs_new:Npn \prg_case_dim_aux:nw #1#2#3
+ {
+ \dim_compare:nNnTF {#1} = {#2}
+ { \prg_case_end:nw {#3} }
+ { \prg_case_dim_aux:nw {#1} }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\prg_case_str:nnn, \prg_case_str:onn, \prg_case_str:xxn}
+% \UnitTested
+% \begin{macro}[aux]{\prg_case_str_aux:nw, \prg_case_str_x_aux:nw}
+% No calculations for strings, otherwise no surprises.
+% \begin{macrocode}
+\cs_new:Npn \prg_case_str:nnn #1#2#3
+ { \prg_case_str_aux:nw {#1} #2 {#1} {#3} \q_recursion_stop }
+\cs_new:Npn \prg_case_str_aux:nw #1#2#3
+ {
+ \str_if_eq:nnTF {#1} {#2}
+ { \prg_case_end:nw {#3} }
+ { \prg_case_str_aux:nw {#1} }
+ }
+\cs_generate_variant:Nn \prg_case_str:nnn { o }
+\cs_new:Npn \prg_case_str:xxn #1#2#3
+ { \prg_case_str_x_aux:nw {#1} #2 {#1} {#3} \q_recursion_stop }
+\cs_new:Npn \prg_case_str_x_aux:nw #1#2#3
+ {
+ \str_if_eq:xxTF {#1} {#2}
+ { \prg_case_end:nw {#3} }
+ { \prg_case_str_aux:nw {#1} }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\prg_case_tl:Nnn, \prg_case_tl:cnn}
+% \UnitTested
+% \begin{macro}[aux]{\prg_case_tl_aux:Nw}
+% Similar again, but this time with some variants.
+% \begin{macrocode}
+\cs_new:Npn \prg_case_tl:Nnn #1#2#3
+ { \prg_case_tl_aux:Nw #1 #2 #1 {#3} \q_recursion_stop }
+\cs_new:Npn \prg_case_tl_aux:Nw #1#2#3
+ {
+ \tl_if_eq:NNTF #1 #2
+ { \prg_case_end:nw {#3} }
+ { \prg_case_tl_aux:Nw #1 }
+ }
+\cs_generate_variant:Nn \prg_case_tl:Nnn { c }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Producing $n$ copies}
+%
+% \begin{macro}{\prg_replicate:nn}
+% \UnitTested
+% \begin{macro}[aux]{\prg_replicate_aux:N, \prg_replicate_first_aux:N}
+% \begin{macro}[aux]{\prg_replicate_}
+% \begin{macro}[aux]
+% {
+% \prg_replicate_0:n,
+% \prg_replicate_1:n,
+% \prg_replicate_2:n,
+% \prg_replicate_3:n,
+% \prg_replicate_4:n,
+% \prg_replicate_5:n,
+% \prg_replicate_6:n,
+% \prg_replicate_7:n,
+% \prg_replicate_8:n,
+% \prg_replicate_9:n
+% }
+% \begin{macro}[aux]
+% {
+% \prg_replicate_first_-:n,
+% \prg_replicate_first_0:n,
+% \prg_replicate_first_1:n,
+% \prg_replicate_first_2:n,
+% \prg_replicate_first_3:n,
+% \prg_replicate_first_4:n,
+% \prg_replicate_first_5:n,
+% \prg_replicate_first_6:n,
+% \prg_replicate_first_7:n,
+% \prg_replicate_first_8:n,
+% \prg_replicate_first_9: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. These functions also close the expansion of
+% \cs{int_to_roman:w}, which ensures that \cs{prg_replicate:nn} only
+% requires two steps of expansion.
+%
+% 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, and if
+% necessary, it is possible to write
+% |\prg_replicate:nn{1000}{\prg_replicate:nn{1000}{|\meta{code}|}}|. An
+% alternative approach is to create a string of |m|'s with
+% \cs{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}
+\cs_new_nopar:Npn \prg_replicate:nn #1
+ {
+ \int_to_roman:w
+ \exp_after:wN \prg_replicate_first_aux:N
+ \int_value:w \int_eval:w #1 \int_eval_end:
+ \cs_end:
+ }
+\cs_new_nopar:Npn \prg_replicate_aux:N #1
+ { \cs:w prg_replicate_#1 :n \prg_replicate_aux:N }
+\cs_new_nopar:Npn \prg_replicate_first_aux:N #1
+ { \cs:w prg_replicate_first_ #1 :n \prg_replicate_aux:N }
+% \end{macrocode}
+% \end{macro}
+% Then comes all the functions that do the hard work of inserting all
+% the copies.
+% \begin{macrocode}
+\cs_new_nopar:Npn \prg_replicate_ :n #1 { \cs_end: }
+\cs_new:cpn { prg_replicate_0:n } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} }
+\cs_new:cpn { prg_replicate_1:n } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1 }
+\cs_new:cpn { prg_replicate_2:n } #1 { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1 }
+\cs_new:cpn { prg_replicate_3:n } #1
+ { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1 }
+\cs_new:cpn { prg_replicate_4:n } #1
+ { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1#1 }
+\cs_new:cpn { prg_replicate_5:n } #1
+ { \cs_end: {#1#1#1#1#1#1#1#1#1#1} #1#1#1#1#1 }
+\cs_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 }
+\cs_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 }
+\cs_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 }
+\cs_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}
+\cs_new:cpn { prg_replicate_first_-:n } #1 { \c_zero \negative_replication }
+\cs_new:cpn { prg_replicate_first_0:n } #1 { \c_zero }
+\cs_new:cpn { prg_replicate_first_1:n } #1 { \c_zero #1 }
+\cs_new:cpn { prg_replicate_first_2:n } #1 { \c_zero #1#1 }
+\cs_new:cpn { prg_replicate_first_3:n } #1 { \c_zero #1#1#1 }
+\cs_new:cpn { prg_replicate_first_4:n } #1 { \c_zero #1#1#1#1 }
+\cs_new:cpn { prg_replicate_first_5:n } #1 { \c_zero #1#1#1#1#1 }
+\cs_new:cpn { prg_replicate_first_6:n } #1 { \c_zero #1#1#1#1#1#1 }
+\cs_new:cpn { prg_replicate_first_7:n } #1 { \c_zero #1#1#1#1#1#1#1 }
+\cs_new:cpn { prg_replicate_first_8:n } #1 { \c_zero #1#1#1#1#1#1#1#1 }
+\cs_new:cpn { prg_replicate_first_9:n } #1 { \c_zero #1#1#1#1#1#1#1#1#1 }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\prg_stepwise_function:nnnN}
+% \begin{macro}[aux]
+% {\prg_stepwise_function_incr:nnnN, \prg_stepwise_function_decr:nnnN}
+% Repeating a function by steps fist needs a check on the direction
+% of the steps. After that, do the function for the start value
+% then step and loop around.
+% \begin{macrocode}
+\cs_new:Npn \prg_stepwise_function:nnnN #1#2
+ {
+ \int_compare:nNnTF {#2} > { 0 }
+ { \exp_args:Nf \prg_stepwise_function_incr:nnnN }
+ { \exp_args:Nf \prg_stepwise_function_decr:nnnN }
+ { \int_eval:n {#1} } {#2}
+ }
+\cs_new:Npn \prg_stepwise_function_incr:nnnN #1#2#3#4
+ {
+ \int_compare:nNnF {#1} > {#3}
+ {
+ #4 {#1}
+ \exp_args:Nf \prg_stepwise_function_incr:nnnN
+ { \int_eval:n { #1 + #2 } } {#2} {#3} #4
+ }
+ }
+\cs_new:Npn \prg_stepwise_function_decr:nnnN #1#2#3#4
+ {
+ \int_compare:nNnF {#1} < {#3}
+ {
+ #4 {#1}
+ \exp_args:Nf \prg_stepwise_function_decr:nnnN
+ { \int_eval:n { #1 + #2 } } {#2} {#3} #4
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%\begin{macro}[aux]{\g_prg_stepwise_level_int}
+% For nesting, the usual approach of using a counter.
+% \begin{macrocode}
+\int_new:N \g_prg_stepwise_level_int
+% \end{macrocode}
+%\end{macro}
+%
+%\begin{macro}{\prg_stepwise_inline:nnnn}
+%\begin{macro}[aux]
+% {\prg_stepwise_inline_incr:Nnnn, \prg_stepwise_inline_decr:Nnnn}
+% The approach here is similar but with a global integer required
+% to make the nesting safe (as seen in other in line functions).
+% \begin{macrocode}
+\cs_new_protected:Npn \prg_stepwise_inline:nnnn #1#2#3#4
+ {
+ \int_gincr:N \g_prg_stepwise_level_int
+ \cs_gset_nopar:cpn
+ { g_prg_stepwise_ \int_use:N \g_prg_stepwise_level_int :n }
+ ##1 {#4}
+ \int_compare:nNnTF {#2} > { 0 }
+ { \exp_args:Ncf \prg_stepwise_inline_incr:Nnnn }
+ { \exp_args:Ncf \prg_stepwise_inline_decr:Nnnn }
+ { g_prg_stepwise_ \int_use:N \g_prg_stepwise_level_int :n }
+ { \int_eval:n {#1} } {#2} {#3}
+ \int_gdecr:N \g_prg_stepwise_level_int
+ }
+\cs_new_protected:Npn \prg_stepwise_inline_incr:Nnnn #1#2#3#4
+ {
+ \int_compare:nNnF {#2} > {#4}
+ {
+ #1 {#2}
+ \exp_args:NNf \prg_stepwise_inline_incr:Nnnn #1
+ { \int_eval:n { #2 + #3 } } {#3} {#4}
+ }
+ }
+\cs_new_protected:Npn \prg_stepwise_inline_decr:Nnnn #1#2#3#4
+ {
+ \int_compare:nNnF {#2} < {#4}
+ {
+ #1 {#2}
+ \exp_args:NNf \prg_stepwise_inline_decr:Nnnn #1
+ { \int_eval:n { #2 + #3 } } {#3} {#4}
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\prg_stepwise_variable:nnnNn}
+% \UnitTested
+% A wrapper for the above.
+% \begin{macrocode}
+\cs_new_protected:Npn \prg_stepwise_variable:nnnNn #1#2#3#4#5
+ {
+ \prg_stepwise_inline:nnnn {#1} {#2} {#3}
+ {
+ \tl_set:Nn #4 {##1}
+ #5
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Detecting \TeX{}'s mode}
+%
+% \begin{macro}[pTF]{\mode_if_vertical:}
+% \UnitTested
+% For testing vertical mode. Strikes me here on the bus with David,
+% that as long as we are just talking about returning true and
+% false states, we can just use the primitive conditionals for this
+% and gobbling the |\c_zero| in the input stream. However this
+% requires knowledge of the implementation so we keep things nice
+% and clean and use the return statements.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \mode_if_vertical: { p , T , F , TF }
+ { \if_mode_vertical: \prg_return_true: \else: \prg_return_false: \fi: }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[pTF]{\mode_if_horizontal:}
+% \UnitTested
+% For testing horizontal mode.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \mode_if_horizontal: { p , T , F , TF }
+ { \if_mode_horizontal: \prg_return_true: \else: \prg_return_false: \fi: }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[pTF]{\mode_if_inner:}
+% \UnitTested
+% For testing inner mode.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \mode_if_inner: { p , T , F , TF }
+ { \if_mode_inner: \prg_return_true: \else: \prg_return_false: \fi: }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[pTF]{\mode_if_math:}
+% \UnitTested
+% For testing math mode: without \cs{} things go wrong in alignments.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \mode_if_math: { p , T , F , TF }
+ {
+ \scan_align_safe_stop:
+ \if_mode_math: \prg_return_true: \else: \prg_return_false: \fi:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Internal programming functions}
+%
+% \begin{macro}[int]{\group_align_safe_begin:, \group_align_safe_end:}
+% \TeX{}'s alignment structures present many problems. As Knuth says
+% himself in \emph{\TeX : The Program}: \enquote{It's sort of a miracle
+% whenever \cs{halign} or \cs{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 |&|$_4$ 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}
+\cs_new_nopar:Npn \group_align_safe_begin:
+ { \if_false: { \fi: \if_int_compare:w `} = \c_zero \fi: }
+\cs_new_nopar:Npn \group_align_safe_end:
+ { \if_int_compare:w `{ = \c_zero } \fi: }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\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 \cs{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, \emph{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 if an only
+% if 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}
+\cs_new_nopar:Npn \scan_align_safe_stop:
+ {
+ \int_compare:nNnT \etex_currentgrouptype:D = \c_six
+ {
+ \int_compare:nNnF \etex_lastnodetype:D = \c_zero
+ { \int_compare:nNnF \etex_lastnodetype:D = \c_seven { \scan_stop: } }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\prg_variable_get_scope:N}
+% \begin{macro}[aux]{\prg_variable_get_scope_aux:w}
+% \begin{macro}[int]{\prg_variable_get_type:N}
+% \begin{macro}[aux]{\prg_variable_get_type:w}
+% Expandable functions to find the type of a variable, and to
+% return \texttt{g} if the variable is global. The trick for
+% \cs{prg_variable_get_scope:N} is the same as that in
+% \cs{cs_split_function:NN}, but it can be simplified as the
+% requirements here are less complex.
+% \begin{macrocode}
+\group_begin:
+ \tex_lccode:D `\& = `\g \scan_stop:
+ \tex_catcode:D `\& = \c_twelve
+\tl_to_lowercase:n
+ {
+ \group_end:
+ \cs_new_nopar:Npn \prg_variable_get_scope:N #1
+ {
+ \exp_last_unbraced:Nf \prg_variable_get_scope_aux:w
+ { \cs_to_str:N #1 \exp_stop_f: \q_stop }
+ }
+ \cs_new_nopar:Npn \prg_variable_get_scope_aux:w #1#2 \q_stop
+ { \token_if_eq_meaning:NNT & #1 { g } }
+ }
+\group_begin:
+ \tex_lccode:D `\& = `\_ \scan_stop:
+ \tex_catcode:D `\& = \c_twelve
+\tl_to_lowercase:n
+ {
+ \group_end:
+ \cs_new_nopar:Npn \prg_variable_get_type:N #1
+ {
+ \exp_after:wN \prg_variable_get_type_aux:w
+ \token_to_str:N #1 & a \q_stop
+ }
+ \cs_new_nopar:Npn \prg_variable_get_type_aux:w #1 & #2#3 \q_stop
+ {
+ \token_if_eq_meaning:NNTF a #2
+ {#1}
+ { \prg_variable_get_type_aux:w #2#3 \q_stop }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Experimental programmings functions}
+%
+%
+% \begin{macro}[aux]{\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 variable, so one additionally has to define
+% \begin{quote}
+% |\cs_set_nopar:Npn \seq_quicksort:N{\exp_args:No\seq_quicksort:n}|
+% \end{quote}
+%
+%
+% For details on the implementation see \enquote{Sorting in \TeX{}'s Mouth}
+% by Bernd Raichle. Firstly we define the function for parsing the
+% initial list and then the braced list afterwards.
+% \begin{macrocode}
+\cs_new_protected_nopar:Npn \prg_define_quicksort:nnn #1#2#3 {
+ \cs_set:cpx{#1_quicksort:n}##1{
+ \exp_not:c{#1_quicksort_start_partition:w} ##1
+ \exp_not:n{#2\q_nil#3\q_stop}
+ }
+ \cs_set:cpx{#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
+ }
+ \cs_set: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}{}{}
+ }
+ \cs_set:cpx {#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}
+ \cs_set: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}
+ }
+ \cs_set:cpx {#1_quicksort_do_partition_i_braced:nnnn} ##1##2##3##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}
+ }
+ \cs_set: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}
+ }
+ \cs_set:cpx {#1_quicksort_do_partition_ii_braced:nnnn} ##1##2##3##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}
+ \cs_set:cpx {#1_quicksort_partition_less_i:nnnn} ##1##2##3##4{
+ \exp_not:c{#1_quicksort_do_partition_i:nnnw}{##1}{##2}{{##4}##3}}
+ \cs_set:cpx {#1_quicksort_partition_less_ii:nnnn} ##1##2##3##4{
+ \exp_not:c{#1_quicksort_do_partition_ii:nnnw}{##1}{##2}{##3{##4}}}
+ \cs_set:cpx {#1_quicksort_partition_greater_i:nnnn} ##1##2##3##4{
+ \exp_not:c{#1_quicksort_do_partition_i:nnnw}{##1}{{##4}##2}{##3}}
+ \cs_set:cpx {#1_quicksort_partition_greater_ii:nnnn} ##1##2##3##4{
+ \exp_not:c{#1_quicksort_do_partition_ii:nnnw}{##1}{##2{##4}}{##3}}
+ \cs_set:cpx {#1_quicksort_partition_less_i_braced:nnnn} ##1##2##3##4{
+ \exp_not:c{#1_quicksort_do_partition_i_braced:nnnn}{##1}{##2}{{##4}##3}}
+ \cs_set:cpx {#1_quicksort_partition_less_ii_braced:nnnn} ##1##2##3##4{
+ \exp_not:c{#1_quicksort_do_partition_ii_braced:nnnn}{##1}{##2}{##3{##4}}}
+ \cs_set:cpx {#1_quicksort_partition_greater_i_braced:nnnn} ##1##2##3##4{
+ \exp_not:c{#1_quicksort_do_partition_i_braced:nnnn}{##1}{{##4}##2}{##3}}
+ \cs_set:cpx {#1_quicksort_partition_greater_ii_braced:nnnn} ##1##2##3##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}
+ \cs_set: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}
+% \UnitTested
+% 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}
+% \UnitTested
+% \begin{macro}{\prg_quicksort_compare:nnTF}
+% \UnitTested
+% \begin{macrocode}
+\cs_set:Npn \prg_quicksort_function:n {\ERROR}
+\cs_set:Npn \prg_quicksort_compare:nnTF {\ERROR}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Deprecated functions}
+%
+% These were depreciated on 2011-05-27 and will be removed entirely by
+% 2011-08-31.
+%
+% \begin{macro}{\prg_new_map_functions:Nn}
+% \begin{macro}{\prg_set_map_functions:Nn}
+% As we have restructured the structured variables, these are no
+% longer needed.
+% \begin{macrocode}
+\cs_new_protected:Npn \prg_new_map_functions:Nn #1#2 { \deprectiated }
+\cs_new_protected:Npn \prg_set_map_functions:Nn #1#2 { \deprectiated }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macrocode}
+%</initex|package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex \ No newline at end of file