summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/expl3/l3prg.dtx
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2009-06-09 23:31:15 +0000
committerKarl Berry <karl@freefriends.org>2009-06-09 23:31:15 +0000
commit215b9a864d5829070bdc66ba736986eb72e5143e (patch)
treefe0882c81fc4ec945cee4b512f72eaa21ea5f791 /Master/texmf-dist/source/latex/expl3/l3prg.dtx
parentdf90ec06321940c2f066b05e12f1b5ab099105da (diff)
expl3 1407 (9jun09)
git-svn-id: svn://tug.org/texlive/trunk@13686 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/expl3/l3prg.dtx')
-rw-r--r--Master/texmf-dist/source/latex/expl3/l3prg.dtx1599
1 files changed, 910 insertions, 689 deletions
diff --git a/Master/texmf-dist/source/latex/expl3/l3prg.dtx b/Master/texmf-dist/source/latex/expl3/l3prg.dtx
index b99caf822d7..ca50697fd0f 100644
--- a/Master/texmf-dist/source/latex/expl3/l3prg.dtx
+++ b/Master/texmf-dist/source/latex/expl3/l3prg.dtx
@@ -1,5 +1,5 @@
% \iffalse
-%% File: l3prg.dtx Copyright (C) 2005-2006 LaTeX3 project
+%% File: l3prg.dtx Copyright (C) 2005-2009 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
@@ -17,7 +17,7 @@
%%
%% The development version of the bundle can be found at
%%
-%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/
+%% http://www.latex-project.org/svnroot/experimental/trunk/
%%
%% for those people who are interested.
%%
@@ -36,7 +36,7 @@
\RequirePackage{l3names}
%</driver|package>
%\fi
-\GetIdInfo$Id: l3prg.dtx 768 2008-08-05 19:45:06Z morten $
+\GetIdInfo$Id: l3prg.dtx 1365 2009-05-31 17:26:17Z mittelba $
{L3 Experimental control structures}
%\iffalse
%<*driver>
@@ -44,9 +44,9 @@
\ProvidesFile{\filename.\filenameext}
[\filedate\space v\fileversion\space\filedescription]
%\iffalse
-\documentclass{l3doc}
+\documentclass[full]{l3doc}
\begin{document}
-\DocInput{\filename.\filenameext}
+\DocInput{l3prg.dtx}
\end{document}
%</driver>
% \fi
@@ -60,167 +60,121 @@
% \date{\filedate}
% \maketitle
%
+% \begin{documentation}
%
-% \section{Control structures}
+% \section{Conditionals and logical operations}
%
-% \subsection{Choosing modes}
+% 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, e.g., text as input in a function comparing integers.
%
-% \begin{function}{\mode_if_vertical_p:|
-% \mode_if_vertical:TF |
-% \mode_if_vertical:T |
-% \mode_if_vertical:F
-% }
-% \begin{syntax}
-% "\mode_if_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_if_horizontal_p:|
-% \mode_if_horizontal:TF |
-% \mode_if_horizontal:T |
-% \mode_if_horizontal:F
-% }
-% \begin{syntax}
-% "\mode_if_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_if_inner_p:|
-% \mode_if_inner:TF|
-% \mode_if_inner:T|
-% \mode_if_inner:F
-% }
-% \begin{syntax}
-% "\mode_if_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_if_math:TF|
-% \mode_if_math:T|
-% \mode_if_math:F|
-% }
-% \begin{syntax}
-% "\mode_if_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}
+%
%
+% \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
%
-% \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}
+% \section{Defining a set of conditional functions}
%
-% \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.
+% \begin{function}{ \prg_return_true: |
+% \prg_return_false: }
+% These functions exit conditional processing when used in
+% conjunction with the generating functions listed below.
% \end{function}
%
+% \begin{function}{%
+% \prg_set_conditional:Nnn |
+% \prg_set_conditional:Npnn |
+% \prg_new_conditional:Nnn |
+% \prg_new_conditional:Npnn |
+% \prg_set_protected_conditional:Nnn |
+% \prg_set_protected_conditional:Npnn |
+% \prg_new_protected_conditional:Nnn |
+% \prg_new_protected_conditional:Npnn |
+% }
+% \begin{syntax}
+% "\prg_set_conditional:Nnn" <test> <conds> <code>
+% "\prg_set_conditional:Npnn" <test> <param> <conds> <code>
+% \end{syntax}
+% This defines a conditional \meta{base function} which upon
+% evaluation using |\prg_return_true:| and |\prg_return_false:| to
+% finish branches,
+% returns a state. Currently the states are either \meta{true} or
+% \meta{false} although this can change as more states may be
+% introduced, say an \meta{error} state. \meta{conds} is a comma
+% separated list possibly consisting of |p| for denoting a predicate function
+% returning the boolean \meta{true} or \meta{false} values and |TF|,
+% |T| and |F| for the functions that act on the tokens following in
+% the input stream. The |:Nnn| form implicitly determines the number
+% of arguments from the function being defined whereas the |:Npnn|
+% form expects a primitive parameter text.
+%
+% An example can easily clarify matters here:
+% \begin{verbatim}
+% \prg_set_conditional:Nnn \foo_if_bar:NN {p,TF,T} {
+% \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}
%
%
-% \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".
%
+% \section{The boolean data type}
%
% 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. Parsing "\iffalse"
-% and "\iftrue" tokens can be quite tricky at times so the easiest is to
-% simply 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 |\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}
+% connected to conditional processing 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_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, etc.\ which can then be used on
+% both the boolean type and predicate functions.
+%
+% All conditonal "\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 |
@@ -230,7 +184,7 @@
% "\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".
+% boolean is actually just either "\c_true_bool" or "\c_false_bool".
% \end{function}
%
% \begin{function}{%
@@ -246,7 +200,7 @@
% \begin{syntax}
% "\bool_gset_false:N" <bool>
% \end{syntax}
-% Set <bool> either true or false. We can also do this globally.
+% Set <bool> either <true> or <false>. We can also do this globally.
% \end{function}
%
%
@@ -268,120 +222,145 @@
% \end{function}
%
% \begin{function}{%
-% \bool_if:NTF |
-% \bool_if:NT |
-% \bool_if:NF |
-% \bool_if_p:N |
+% \bool_if_p:N / (EXP) |
+% \bool_if:N / (TF)(EXP) |
+% \bool_if_p:c / (EXP) |
+% \bool_if:c / (TF)(EXP) |
%
% }
% \begin{syntax}
-% "\bool_if:NTF" <bool> "{"\m{true}"}" "{"\m{false}"}" \\
+% "\bool_if:NTF" <bool> \Arg{true} \Arg{false} \\
% "\bool_if_p:N" <bool>
% \end{syntax}
-% Test the truth value of the boolean and execute the \m{true} or
+% Test the truth value of <bool> and execute the \m{true} or
% \m{false} code. "\bool_if_p:N" is a predicate function for use in
-% "\if:w" tests.
+% "\if_predicate:w" tests or "\bool_if:nTF"-type functions described below.
% \end{function}
%
% \begin{function}{%
-% \bool_whiledo:NT |
-% \bool_whiledo:NF |
-% \bool_dowhile:NT |
-% \bool_dowhile:NF |
+% \bool_while_do:Nn |
+% \bool_while_do:cn |
+% \bool_until_do:Nn |
+% \bool_until_do:cn |
+% \bool_do_while:Nn |
+% \bool_do_while:cn |
+% \bool_do_until:Nn |
+% \bool_do_until:cn |
%
% }
% \begin{syntax}
-% "\bool_whiledo:NT" <bool> "{"\m{true}"}" \\
-% "\bool_whiledo:NF" <bool> "{"\m{false}"}" \\
+% "\bool_while_do:Nn" <bool> \Arg{code} \\
+% "\bool_until_do:Nn" <bool> \Arg{code} \\
% \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
+% The `while' versions execute <code> as long as the boolean is
+% true and the `until' versions execute <code> as long as the
+% boolean is false. The "while_do" functions execute the body after
+% testing the boolean and the "do_while" 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}
+% \section{Boolean expressions}
%
-% 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.
+% 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 "&&", "||" and "!". In
+% addition to this, parentheses can be used to isolate
+% sub-expressions. For example,
+% \begin{verbatim}
+% \intexpr_compare_p:n {1=1} &&
+% (
+% \intexpr_compare_p:n {2=3} ||
+% \intexpr_compare_p:n {4=4} ||
+% \intexpr_compare_p:n {1=\error} % is skipped
+% ) &&
+% !(\intexpr_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 anymore, the remainding tests within the current group
+% are skipped.
%
% \begin{function}{%
-% \predicate_p:n |
-% \predicate:nTF |
-% \predicate:nT |
-% \predicate:nF |
+% \bool_if_p:n / (EXP) |
+% \bool_if:n / (TF)(EXP) |
% }
% \begin{syntax}
-% "\predicate:nTF" "{"<list of predicates>"}" "{"<true>"}"
-% "{"<false>"}"
+% "\bool_if:nTF" \Arg{boolean expression} \Arg{true}
+% \Arg{false}
% \end{syntax}
-% The functions evaluate the truth value of \m{list of predicates}
+% The functions evaluate the truth value of \m{boolean expression}
% where each predicate is separated by \verb+&&+ or \verb+||+
-% denoting logical And and Or functions. Minimal evaluation is
-% carried out so that whenever a truth value cannot be changed
-% anymore, the remainding tests are not carried out. Hence
+% denoting logical `And' and `Or' functions. "(" and ")" denote
+% grouping of sub-expressions while "!" is used to as a prefix to
+% either negate a single expression or a group. Hence
% \begin{verbatim}
-% \predicate_p:n{
-% \int_compare_p:nNn 1=1 &&
-% \predicate_p:n {
-% \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=2
+% \bool_if_p:n{
+% \intexpr_compare_p:n {1=1} &&
+% (
+% \intexpr_compare_p:n {2=3} ||
+% \intexpr_compare_p:n {4=4} ||
+% \intexpr_compare_p:n {1=\error} % is skipped
+% ) &&
+% !(\intexpr_compare_p:n {2=4})
% }
% \end{verbatim}
-% returns \meta{true}.
+% from above returns \meta{true}.
+%
+% Logical operators take higher precedence the later in the predicate they
+% appear. ``<x> "||" <y> "&&" <z>'' is interpreted as the equivalent of
+% ``<x> \textsc{or} [~<y> \textsc{and} <z>~]'' (but now we have grouping
+% you shouldn't write this sort of thing, anyway).
% \end{function}
%
%
%
+% \begin{function}{ \bool_not_p:n / (EXP) }
+% \begin{syntax}
+% "\bool_not_p:n" \Arg{boolean expression}
+% \end{syntax}
+% Longhand for writing "!("\meta{boolean expression}")" within a boolean
+% expression. Might not stick around.
+% \end{function}
%
-% \begin{function}{%
-% \predicate_not_p:n |
-% }
+% \begin{function}{ \bool_xor_p:nn / (EXP) }
% \begin{syntax}
-% "\predicate_not_p:n" "{"<list of predicates>"}"
+% "\bool_xor_p:nn" \Arg{boolean expression} \Arg{boolean expression}
% \end{syntax}
-% "\predicate_not_p:n"
-% reverses the truth value of its argument. Thus
-% \begin{quote}
-% "\prg_if_predicate_not_p:n {\prg_if_predicate_not_p:n {\c_true}}"
-% \end{quote}
-% ultimately returns \m{true}.
+% Implements an `exclusive or' operation between two boolean
+% expressions. There is no infix operation for this.
% \end{function}
%
-% \subsubsection{Case switches}
+% \begin{function}{\bool_set:Nn |\bool_set:cn |\bool_gset:Nn |\bool_gset:cn}
+% \begin{syntax}
+% "\bool_set:Nn" <bool> \Arg{boolean expression}
+% \end{syntax}
+% Sets <bool> to the logical outcome of evaluating <boolean expression>.
+% \end{function}
%
%
-% \begin{function}{
-% \prg_case_int:nnn |
+% \section{Case switches}
%
-% }
+%
+% \begin{function}{ \prg_case_int:nnn / (EXP) }
% \begin{syntax}
-% "\prg_case_int:nnn" "{"<integer expr>"}" "{"
-% " {"\m{integer expr$\sb 1$}"}""{"\m{code$\sb 1$}"}""{"\m{integer expr$\sb 2$}"}""{"\m{code$\sb 2$}"}"\\
-% " ...""{"\m{integer expr$\sb n$}"}""{"\m{code$\sb n$}"}"\\
-% "}" "{"\m{else case}"}"
+% "\prg_case_int:nnn" \Arg{integer expr} "{"
+% ~~\Arg{integer expr 1} \Arg{code 1}\\
+% ~~\Arg{integer expr 2} \Arg{code 2}\\
+% ~~\dots\\
+% ~~\Arg{integer expr\,$\sb n$} \Arg{code\,$\sb n$}\\
+% "}" \Arg{else case}
% \end{syntax}
% This function evaluates the first \meta{integer expr} and then compares it
% to the values found in the list. Thus the expression
% \begin{verbatim}
-% \prg_case:nnn{2*5}{
+% \prg_case_int:nnn{2*5}{
% {5}{Small} {4+6}{Medium} {-2*10}{Negative}
% }{Other}
% \end{verbatim}
@@ -396,29 +375,27 @@
% from within the function are left over.
% \end{function}
%
-% \begin{function}{
-% \prg_case_dim:nnn |
-%
-% }
+% \begin{function}{ \prg_case_dim:nnn / (EXP) }
% \begin{syntax}
-% "\prg_case_int:nnn" "{"<dim expr>"}" "{"
-% " {"\m{dim expr$\sb 1$}"}""{"\m{code$\sb 1$}"}""{"\m{dim expr$\sb 2$}"}""{"\m{code$\sb 2$}"}"\\
-% " ...""{"\m{dim expr$\sb n$}"}""{"\m{code$\sb n$}"}"\\
-% "}" "{"\m{else case}"}"
+% "\prg_case_int:nnn" \Arg{dim expr} "{"\\
+% ~~\Arg{dim expr 1} \Arg{code 1}\\
+% ~~\Arg{dim expr 2} \Arg{code 2}\\
+% ~~"..."\\
+% ~~\Arg{dim expr\,$\sb n$} \Arg{code\,$\sb n$}\\
+% "}" \Arg{else case}
% \end{syntax}
% This function works just like |\prg_case_int:nnn| except it works
% for \meta{dim} registers.
% \end{function}
%
-% \begin{function}{
-% \prg_case_str:nnn |
-%
-% }
+% \begin{function}{ \prg_case_str:nnn / (EXP) }
% \begin{syntax}
-% "\prg_case_str:nnn" "{"<string>"}" "{"
-% " {"\m{string$\sb 1$}"}""{"\m{code$\sb 1$}"}""{"\m{string$\sb 2$}"}""{"\m{code$\sb 2$}"}"\\
-% " ...""{"\m{string$\sb n$}"}""{"\m{code$\sb n$}"}"\\
-% "}" "{"\m{else case}"}"
+% "\prg_case_str:nnn" \Arg{string} "{" \\
+% ~~\Arg{string 1} \Arg{code 1}\\
+% ~~\Arg{string 2} \Arg{code 2}\\
+% ~~"..."\\
+% ~~\Arg{string\,$\sb n$} \Arg{code,$\sb n$}\\
+% "}" \Arg{else case}
% \end{syntax}
% This function works just like |\prg_case_int:nnn| except it
% compares strings. Each string is evaluated fully using \texttt{x}
@@ -429,45 +406,169 @@
% \texttt{f} style expansion can take place cleanly, i.e., no tokens
% from within the function are left over.
% \end{function}
-%
-% \subsubsection{Generic loops}
%
+% \begin{function}{ \prg_case_tl:Nnn / (EXP) }
+% \begin{syntax}
+% "\prg_case_tl:Nnn" <tl var.> "{"
+% ~~<tl var.\ 1> \Arg{code 1} <tl var.\ 2> \Arg{code 2} "..." <tl var.\,$\sb n$> \Arg{code\,$\sb n$}\\
+% "}" \Arg{else case}
+% \end{syntax}
+% This function works just like |\prg_case_int:nnn| except it
+% compares token list variables.
%
-% \begin{function}{
-% \prg_whiledo:nT |
-% \prg_whiledo:nF |
-% \prg_dowhile:nT |
-% \prg_dowhile:nF |
+% The function is expandable\footnote{Provided you use pdfTeX v1.30 or
+% later} and is written in such a way that
+% \texttt{f} style expansion can take place cleanly, i.e., no tokens
+% from within the function are left over.
+% \end{function}
+%
+% \section{Generic loops}
%
-% }
+%
+% \begin{function}{ \bool_while_do:nn |
+% \bool_until_do:nn |
+% \bool_do_while:nn |
+% \bool_do_until:nn }
% \begin{syntax}
-% "\prg_whiledo:nT" "{"<test>"}" "{"\m{true}"}" \\
-% "\prg_whiledo:nF" "{"<test>"}" "{"\m{false}"}"
+% "\bool_while_do:nn" \Arg{boolean expression} \Arg{code} \\
+% "\bool_until_do:nn" \Arg{boolean expression} \Arg{code}
% \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|.
+% The `while' versions execute the code as long as <boolean
+% expression> is true and the `until' versions execute <code> as long
+% as <boolean expression> is false. The "while_do" functions execute
+% the body after testing the boolean and the "do_while" functions
+% executes the body first and then tests the boolean.
% \end{function}
%
-% \subsection{Sorting}
+% \section{Choosing modes}
+%
+% \begin{function}{ \mode_if_vertical_p: / (EXP)|
+% \mode_if_vertical: / (TF)(EXP) }
+% \begin{syntax}
+% "\mode_if_vertical:TF" \Arg{true code} \Arg{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_if_horizontal_p: / (EXP)|
+% \mode_if_horizontal: / (TF)(EXP) }
+% \begin{syntax}
+% "\mode_if_horizontal:TF" \Arg{true code} \Arg{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_if_inner_p: / (EXP)|
+% \mode_if_inner: / (TF)(EXP) }
+% \begin{syntax}
+% "\mode_if_inner:TF" \Arg{true code} \Arg{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_if_math_p: /(EXP) |
+% \mode_if_math: / (TF)(EXP) }
+% \begin{syntax}
+% "\mode_if_math:TF" \Arg{true code} \Arg{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}
+%
+%
+% \section{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}
+%
+%
+% \section{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 / (EXP) }
+% \begin{syntax}
+% "\prg_replicate:nn" \Arg{number} \Arg{arg}
+% \end{syntax}
+% Creates <number> copies of <arg>. Note that it is expandable.
+% \end{function}
+%
+%
+% \begin{function}{\prg_stepwise_function:nnnN / (EXP) }
+% \begin{syntax}
+% "\prg_stepwise_function:nnnN" \Arg{start} \Arg{step}
+% \Arg{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.
+% \end{function}
+%
+% \begin{function}{\prg_stepwise_inline:nnnn}
+% \begin{syntax}
+% "\prg_stepwise_inline:nnnn" \Arg{start} \Arg{step} \Arg{end}
+% \Arg{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" \Arg{start} \Arg{step} \Arg{end}
+% <temp-var> \Arg{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}
+%
+% \section{Sorting}
%
%
% \begin{function}{
% \prg_quicksort:n |
% }
% \begin{syntax}
-% "\prg_quicksort:n" "{" "{"<element~1>"}" "{"<element~2>"}"
-% \dots\space "{"<element~n>"}" "}"
+% "\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 |\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
+% items are given as argument to the function
% |\prg_quicksort_function:n| which the programmer also controls.
% \end{function}
%
@@ -476,14 +577,14 @@
% \prg_quicksort_compare:nnTF
% }
% \begin{syntax}
-% "\prg_quicksort_function:n" "{"<element>"}" \\
-% "\prg_quicksort_compare:nnTF" "{"<element 1>"}" "{"<element 2>"}"\\
+% "\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}
-% |\def:NNn\prg_quicksort_function:n 1{{#1}}|\\
-% |\def:NNn\prg_quicksort_compare:nnTF 2{\num_compare:nNnTF{#1}>{#2}}|
+% |\cs_set_nopar:Nn\prg_quicksort_function:n {{#1}}|\\
+% |\cs_set_nopar:Nn\prg_quicksort_compare:nnTF {\intexpr_compare:nNnTF{#1}>{#2}}|
% \end{quote}
% Then the function call
% \begin{quote}
@@ -493,89 +594,94 @@
% 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 }|
+% |\cs_set_nopar:Nn\prg_quicksort_compare:nnTF {|\\
+% | \intexpr_compare:nNnTF{\tl_compare:nn{#1}{#2}}>\c_zero }|
% \end{quote}
%
% \end{function}
%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3prg} implementation}
+%
+% \subsection{Variables}
%
-% \StopEventually{}
+% \begin{function}{ \l_tmpa_bool | \g_tmpa_bool }
+% Reserved booleans.
+% \end{function}
%
-% \subsection{The Implementation}
+% \begin{variable}{\g_prg_inline_level_int}
+% Global variable to track the nesting of the stepwise inline loop.
+% \end{variable}
%
+% \subsection{Module code}
%
% We start by ensuring that the required packages are loaded.
% \begin{macrocode}
%<*package>
\ProvidesExplPackage
{\filename}{\filedate}{\fileversion}{\filedescription}
-\RequirePackage{l3quark}
-\RequirePackage{l3toks}
-\RequirePackage{l3int}
+\package_check_loaded_expl:
%</package>
%<*initex|package>
% \end{macrocode}
%
-%
-% \subsubsection{Choosing modes}
+% \subsection{Choosing modes}
%
% \begin{macro}{\mode_if_vertical_p:}
-% \begin{macro}{\mode_if_vertical:TF}
-% \begin{macro}{\mode_if_vertical:T}
-% \begin{macro}{\mode_if_vertical:F}
-% For testing vertical mode.
+% \begin{macro}[TF]{\mode_if_vertical:}
+% 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}
-\def_new:Npn \mode_if_vertical_p: {
- \if_mode_vertical: \c_true \else: \c_false\fi:}
-\def_test_function_new:npn{mode_if_vertical:}{\if_mode_vertical:}
+\prg_set_conditional:Npnn \mode_if_vertical: {p,TF,T,F}{
+ \if_mode_vertical:
+ \prg_return_true: \else: \prg_return_false: \fi:
+}
% \end{macrocode}
% \end{macro}
% \end{macro}
-% \end{macro}
-% \end{macro}
%
% \begin{macro}{\mode_if_horizontal_p:}
-% \begin{macro}{\mode_if_horizontal:TF}
-% \begin{macro}{\mode_if_horizontal:T}
-% \begin{macro}{\mode_if_horizontal:F}
+% \begin{macro}[TF]{\mode_if_horizontal:}
% For testing horizontal mode.
% \begin{macrocode}
-\def_new:Npn \mode_if_horizontal_p: {
- \if_mode_horizontal: \c_true \else: \c_false\fi:}
-\def_test_function_new:npn{mode_if_horizontal:}{\if_mode_horizontal:}
+\prg_set_conditional:Npnn \mode_if_horizontal: {p,TF,T,F}{
+ \if_mode_horizontal:
+ \prg_return_true: \else: \prg_return_false: \fi:
+}
% \end{macrocode}
% \end{macro}
% \end{macro}
-% \end{macro}
-% \end{macro}
%
% \begin{macro}{\mode_if_inner_p:}
-% \begin{macro}{\mode_if_inner:TF}
-% \begin{macro}{\mode_if_inner:T}
-% \begin{macro}{\mode_if_inner:F}
+% \begin{macro}[TF]{\mode_if_inner:}
% For testing inner mode.
% \begin{macrocode}
-\def_new:Npn \mode_if_inner_p: {
- \if_mode_inner: \c_true \else: \c_false\fi:}
-\def_test_function_new:npn{mode_if_inner:}{\if_mode_inner:}
+\prg_set_conditional:Npnn \mode_if_inner: {p,TF,T,F}{
+ \if_mode_inner:
+ \prg_return_true: \else: \prg_return_false: \fi:
+}
% \end{macrocode}
% \end{macro}
% \end{macro}
-% \end{macro}
-% \end{macro}
%
-% \begin{macro}{\mode_if_math:TF}
-% \begin{macro}{\mode_if_math:T}
-% \begin{macro}{\mode_if_math:F}
+% \begin{macro}{\mode_if_math_p:}
+% \begin{macro}[TF]{\mode_if_math:}
% For testing math mode. Uses the kern-save |\scan_align_safe_stop:|.
% \begin{macrocode}
-\def_test_function_new:npn{mode_if_math:} {
- \scan_align_safe_stop: \if_mode_math: }
+\prg_set_conditional:Npnn \mode_if_math: {p,TF,T,F}{
+ \scan_align_safe_stop: \if_mode_math:
+ \prg_return_true: \else: \prg_return_false: \fi:
+}
% \end{macrocode}
% \end{macro}
% \end{macro}
-% \end{macro}
%
% \paragraph{Alignment safe grouping and scanning}
%
@@ -583,7 +689,7 @@
% \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
+% 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
@@ -599,9 +705,9 @@
% by using code documented only in Appendix~D of
% \emph{The \TeX book}\dots
% \begin{macrocode}
-\def_new:Npn \group_align_safe_begin: {
+\cs_new_nopar:Npn \group_align_safe_begin: {
\if_false:{\fi:\if_num:w`}=\c_zero\fi:}
-\def_new:Npn \group_align_safe_end: {\if_num:w`{=\c_zero}\fi:}
+\cs_new_nopar:Npn \group_align_safe_end: {\if_num:w`{=\c_zero}\fi:}
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -625,12 +731,12 @@
% 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
+\cs_new_nopar:Npn \scan_align_safe_stop: {
+ \intexpr_compare:nNnT \etex_currentgrouptype:D = \c_six
{
- \num_compare:nNnF \etex_lastnodetype:D = \c_zero
+ \intexpr_compare:nNnF \etex_lastnodetype:D = \c_zero
{
- \num_compare:nNnF \etex_lastnodetype:D = \c_seven
+ \intexpr_compare:nNnF \etex_lastnodetype:D = \c_seven
\scan_stop:
}
}
@@ -638,11 +744,10 @@
% \end{macrocode}
% \end{macro}
%
-% \subsubsection{Making $n$ copies}
+% \subsection{Producing $n$ copies}
%
% \begin{macro}{\prg_replicate:nn}
-% \begin{macro}{\prg_replicate_aux:N}
-% \begin{macro}{\prg_replicate_first_aux:N}
+% \begin{macro}[aux]{\prg_replicate_aux:N,\prg_replicate_first_aux:N}
% This function uses a cascading csname technique by David Kastrup
% (who else :-)
%
@@ -660,7 +765,7 @@
% 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.
+% creating is simply "\prg_do_nothing:" 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
@@ -672,104 +777,102 @@
% 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_new_nopar:Npn \prg_replicate:nn #1{
+ \cs:w prg_do_nothing:
+ \exp_after:wN\prg_replicate_first_aux:N
+ \tex_romannumeral:D -`\q \intexpr_eval:n{#1} \cs_end:
\cs_end:
}
-\def_new:Npn \prg_replicate_aux:N#1{
+\cs_new_nopar: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_new_nopar: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_new_nopar:Npn \prg_replicate_ :n #1{}% no, this is not a typo!
+\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}
-\def_long_new:cpn {prg_replicate_4:n}#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}
-\def_long_new:cpn {prg_replicate_5:n}#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}
-\def_long_new:cpn {prg_replicate_6:n}#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}
-\def_long_new:cpn {prg_replicate_7:n}#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}
-\def_long_new:cpn {prg_replicate_8:n}#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}
-\def_long_new:cpn {prg_replicate_9:n}#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}
-\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}
+\cs_new:cpn {prg_replicate_first_0:n}#1{\cs_end: }
+\cs_new:cpn {prg_replicate_first_1:n}#1{\cs_end: #1}
+\cs_new:cpn {prg_replicate_first_2:n}#1{\cs_end: #1#1}
+\cs_new:cpn {prg_replicate_first_3:n}#1{\cs_end: #1#1#1}
+\cs_new:cpn {prg_replicate_first_4:n}#1{\cs_end: #1#1#1#1}
+\cs_new:cpn {prg_replicate_first_5:n}#1{\cs_end: #1#1#1#1#1}
+\cs_new:cpn {prg_replicate_first_6:n}#1{\cs_end: #1#1#1#1#1#1}
+\cs_new:cpn {prg_replicate_first_7:n}#1{\cs_end: #1#1#1#1#1#1#1}
+\cs_new:cpn {prg_replicate_first_8:n}#1{\cs_end: #1#1#1#1#1#1#1#1}
+\cs_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}
+% \begin{macro}[aux]{\prg_stepwise_function_incr:nnnN,
+% \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}
+\cs_new:Npn \prg_stepwise_function:nnnN #1#2{
+ \intexpr_compare:nNnTF{#2}<\c_zero
+ {\exp_args:Nf\prg_stepwise_function_decr:nnnN }
+ {\exp_args:Nf\prg_stepwise_function_incr:nnnN }
+ {\intexpr_eval:n{#1}}{#2}
}
-\def_long_new:NNn \prg_stepwise_function_incr:nnnN 4{
- \num_compare:nNnF {#1}>{#3}
+\cs_new:Npn \prg_stepwise_function_incr:nnnN #1#2#3#4{
+ \intexpr_compare:nNnF {#1}>{#3}
{
#4{#1}
- \exp_args:No \prg_stepwise_function_incr:nnnN
- {\int_use:N\int_eval:n{#1 + #2}}
+ \exp_args:Nf \prg_stepwise_function_incr:nnnN
+ {\intexpr_eval:n{#1 + #2}}
{#2}{#3}{#4}
}
}
-\def_long_new:NNn \prg_stepwise_function_decr:nnnN 4{
- \num_compare:nNnF {#1}<{#3}
+\cs_new:Npn \prg_stepwise_function_decr:nnnN #1#2#3#4{
+ \intexpr_compare:nNnF {#1}<{#3}
{
#4{#1}
- \exp_args:No \prg_stepwise_function_decr:nnnN
- {\int_use:N\int_eval:n{#1 + #2}}
+ \exp_args:Nf \prg_stepwise_function_decr:nnnN
+ {\intexpr_eval:n{#1 + #2}}
{#2}{#3}{#4}
}
}
% \end{macrocode}
% \end{macro}
% \end{macro}
-% \end{macro}
%
% \begin{macro}{\g_prg_inline_level_int}
% \begin{macro}{\prg_stepwise_inline:nnnn}
-% \begin{macro}{\prg_stepwise_inline_decr:nnnn}
-% \begin{macro}{\prg_stepwise_inline_incr:nnnn}
+% \begin{macro}[aux]{\prg_stepwise_inline_decr:nnnn,
+% \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
@@ -777,76 +880,74 @@
% when we maintain our own stack.
% \begin{macrocode}
\int_new:N\g_prg_inline_level_int
-\def_long_new:NNn\prg_stepwise_inline:nnnn 4{
+\cs_new:Npn\prg_stepwise_inline:nnnn #1#2#3#4{
\int_gincr:N \g_prg_inline_level_int
- \gdef:cpn{prg_stepwise_inline_\int_use:N\g_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 }
+ \cs_gset_nopar:cpn{prg_stepwise_inline_\int_use:N\g_prg_inline_level_int :n}##1{#4}
+ \intexpr_compare:nNnTF {#2}<\c_zero
+ {\exp_args:Ncf \prg_stepwise_inline_decr:Nnnn }
+ {\exp_args:Ncf \prg_stepwise_inline_incr:Nnnn }
{prg_stepwise_inline_\int_use:N\g_prg_inline_level_int :n}
- {\int_use:N\int_eval:n{#1}} {#2} {#3}
+ {\intexpr_eval:n{#1}} {#2} {#3}
\int_gdecr:N \g_prg_inline_level_int
}
-\def_long_new:NNn \prg_stepwise_inline_incr:Nnnn 4{
- \num_compare:nNnF {#2}>{#4}
+\cs_new:Npn \prg_stepwise_inline_incr:Nnnn #1#2#3#4{
+ \intexpr_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}
+ \exp_args:NNf \prg_stepwise_inline_incr:Nnnn #1
+ {\intexpr_eval:n{#2 + #3}} {#3}{#4}
}
}
-\def_long_new:NNn \prg_stepwise_inline_decr:Nnnn 4{
- \num_compare:nNnF {#2}<{#4}
+\cs_new:Npn \prg_stepwise_inline_decr:Nnnn #1#2#3#4{
+ \intexpr_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}
+ \exp_args:NNf \prg_stepwise_inline_decr:Nnnn #1
+ {\intexpr_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}
+% \begin{macro}[aux]{\prg_stepwise_variable_decr:nnnNn,
+% \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}
+\cs_new:Npn \prg_stepwise_variable:nnnNn #1#2 {
+ \intexpr_compare:nNnTF {#2}<\c_zero
+ {\exp_args:Nf\prg_stepwise_variable_decr:nnnNn}
+ {\exp_args:Nf\prg_stepwise_variable_incr:nnnNn}
+ {\intexpr_eval:n{#1}}{#2}
}
-\def_long_new:NNn \prg_stepwise_variable_incr:nnnNn 5 {
- \num_compare:nNnF {#1}>{#3}
+\cs_new:Npn \prg_stepwise_variable_incr:nnnNn #1#2#3#4#5 {
+ \intexpr_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}
+ \cs_set_nopar:Npn #4{#1} #5
+ \exp_args:Nf \prg_stepwise_variable_incr:nnnNn
+ {\intexpr_eval:n{#1 + #2}}{#2}{#3}#4{#5}
}
}
-\def_long_new:NNn \prg_stepwise_variable_decr:nnnNn 5 {
- \num_compare:nNnF {#1}<{#3}
+\cs_new:Npn \prg_stepwise_variable_decr:nnnNn #1#2#3#4#5 {
+ \intexpr_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}
+ \cs_set_nopar:Npn #4{#1} #5
+ \exp_args:Nf \prg_stepwise_variable_decr:nnnNn
+ {\intexpr_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|.
+% \subsection{Booleans}
+% For normal booleans we set them to either "\c_true_bool" or "\c_false_bool"
+% and then use "\if_bool:N" to choose the right branch. The functions
+% return either the TF, T, or F case \emph{after} ending the |\if_bool:N|.
% We only define the |N| versions here as the |c| versions can easily
% be constructed with the expansion module.
%
@@ -862,16 +963,16 @@
% \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 }
+\cs_new_nopar:Npn \bool_new:N #1 { \cs_new_eq:NN #1 \c_false_bool }
+\cs_new_nopar:Npn \bool_new:c #1 { \cs_new_eq:cN {#1} \c_false_bool }
+\cs_new_nopar:Npn \bool_set_true:N #1 { \cs_set_eq:NN #1 \c_true_bool }
+\cs_new_nopar:Npn \bool_set_true:c #1 { \cs_set_eq:cN {#1} \c_true_bool }
+\cs_new_nopar:Npn \bool_set_false:N #1 { \cs_set_eq:NN #1 \c_false_bool }
+\cs_new_nopar:Npn \bool_set_false:c #1 { \cs_set_eq:cN {#1} \c_false_bool }
+\cs_new_nopar:Npn \bool_gset_true:N #1 { \cs_gset_eq:NN #1 \c_true_bool }
+\cs_new_nopar:Npn \bool_gset_true:c #1 { \cs_gset_eq:cN {#1} \c_true_bool }
+\cs_new_nopar:Npn \bool_gset_false:N #1 { \cs_gset_eq:NN #1 \c_false_bool }
+\cs_new_nopar:Npn \bool_gset_false:c #1 { \cs_gset_eq:cN {#1} \c_false_bool }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -894,14 +995,14 @@
% \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
+\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}
% \end{macro}
@@ -922,217 +1023,225 @@
% \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{macro}{\bool_if_p:N,\bool_if_p:c}
+% \begin{macro}[TF]{\bool_if:N,\bool_if:c}
+% Straight forward here. We could optimize here if we wanted to as
+% the boolean can just be input directly.
% \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}
+\prg_set_conditional:Npnn \bool_if:N #1 {p,TF,T,F}{
+ \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:NTF {c}
+\cs_generate_variant:Nn \bool_if:NT {c}
+\cs_generate_variant:Nn \bool_if:NF {c}
% \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}
+% \begin{macro}{\bool_while_do:Nn}
+% \begin{macro}{\bool_while_do:cn}
+% \begin{macro}{\bool_until_do:Nn}
+% \begin{macro}{\bool_until_do:cn}
% 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
+% statement. The `while' version executes the code as long as the
+% boolean is true; the `until' version executes the code 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}}
+\cs_new:Npn \bool_while_do:Nn #1 #2 {
+ \bool_if:NT #1 {#2 \bool_while_do:Nn #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}}
+\cs_generate_variant:Nn \bool_while_do:Nn {c}
+% \end{macrocode}
+%
+% \begin{macrocode}
+\cs_new:Npn \bool_until_do:Nn #1 #2 {
+ \bool_if:NF #1 {#2 \bool_until_do:Nn #1 {#2}}
}
-\def_new:Npn \bool_whiledo:cF{\exp_args:Nc\bool_whiledo:NF}
+\cs_generate_variant:Nn \bool_until_do:Nn {c}
% \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}
+% \begin{macro}{\bool_do_while:Nn}
+% \begin{macro}{\bool_do_while:cn}
+% \begin{macro}{\bool_do_until:Nn}
+% \begin{macro}{\bool_do_until:cn}
% 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}}
+\cs_new:Npn \bool_do_while:Nn #1 #2 {
+ #2 \bool_if:NT #1 {\bool_do_while:Nn #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}
+\cs_generate_variant:Nn \bool_do_while:Nn {c}
% \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:
+\cs_new:Npn \bool_do_until:Nn #1 #2 {
+ #2 \bool_if:NF #1 {\bool_do_until:Nn #1 {#2}}
}
-\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}
+\cs_generate_variant:Nn \bool_do_until:Nn {c}
% \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}{\predicate_p:n}
-% \begin{macro}{\predicate:nTF}
-% \begin{macro}{\predicate:nT}
-% \begin{macro}{\predicate:nF}
-% \begin{macro}{\predicate_auxi:NN}
-% \begin{macro}{\predicate_auxii:NNN}
-% \begin{macro}{\predicate_88_0:w}^^A% fix!
-% \begin{macro}{\predicate_88_1:w}^^A% fix!
-% \begin{macro}{\predicate_II_0:w}^^A% fix!
-% \begin{macro}{\predicate_II_1:w}^^A fix!
-% \begin{macro}{\predicate_02_0:w}
-% \begin{macro}{\predicate_02_1:w}
-%
+%
+%
+% \subsection{Parsing boolean expressions}
+%
+% \begin{macro}{\bool_if_p:n}
+% \begin{macro}[TF]{\bool_if:n}
+% \begin{macro}[aux]{\bool_get_next:N, \bool_cleanup:N, \bool_choose:NN}
+% \begin{macro}[aux]{\bool_!:w}
+% \begin{macro}[aux]{\bool_(:w}
+% \begin{macro}[aux]{\bool_p:w}
+% \begin{macro}[aux]{\bool_8_1:w}
+% \begin{macro}[aux]{\bool_I_1:w}
+% \begin{macro}[aux]{\bool_8_0:w}
+% \begin{macro}[aux]{\bool_I_0:w}
+% \begin{macro}[aux]{\bool_)_0:w}
+% \begin{macro}[aux]{\bool_)_1:w}
+% \begin{macro}[aux]{\bool_S_0:w}
+% \begin{macro}[aux]{\bool_S_1:w}
+%
% 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. The function evaluates predicates from
-% left to right, expanding them to 00 and 01 resp., which leads to
-% six different situations of tokens in the input stream:
-% \begin{itemize}
-% \item[\texttt{00\&\&}] Current truth value is true, logical And
-% seen, continue to see if next is also true.
-% \item[\texttt{01\&\&}] Current truth value is false, logical And
-% seen, break the scanning and return \meta{false}.
-% \item[\texttt{00\char`\|\char`\|}] Current truth value is true,
-% logical Or seen, break the scanning and return \meta{true}.
-% \item[\texttt{01\char`\|\char`\|}] Current truth value is false,
-% logical Or seen, continue to see if a later predicate is true.
-% \item[\texttt{0002}] Current truth value is true, end marker
+% programming languages with "(" and ")" for grouping, "!" for
+% logical `Not', "&&" for logical `And' and "||" for logical
+% "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[\texttt{0102}] Current truth value is false, end marker
+% \item[\meta{false}Close] Current truth value is false, Close
% seen, return \meta{false}.
-% \end{itemize}
-% To accomplish this we pre-expand the predicate list using |f|
-% type expansion which leads to |00| or |01|, possibly with a
-% sequence of unfinished |\else: \c_false \fi:| or similar after
-% it, which we remove using the same trick. We also carry over the
-% truth value of the evaluated predicate. The expansion stops when
-% it sees the end marker or \verb+&&+ or \verb+||+ (assuming these
-% are not active characters at the programming level).
+% \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 "\tex_number: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}
-\def_long_new:Npn \predicate_p:n #1{
- \group_align_safe_begin:
- \exp_after:NN \predicate_auxi:NN
- \int_to_roman:w-`\q #1 02\scan_stop:
+\cs_set:Npn \bool_if_p:n #1{
+ \group_align_safe_begin:
+ \bool_get_next:N ( #1 )S
}
-\def_long_test_function_new:npn {predicate:n}#1{
- \group_align_safe_begin:
- \if:w \exp_after:NN \predicate_auxi:NN
- \int_to_roman:w-`\q #1 02\scan_stop:
+% \end{macrocode}
+% The GetNext operation. We make it a switch: If not a "!" or "(", we
+% assume it is a predicate.
+% \begin{macrocode}
+\cs_set:Npn \bool_get_next:N #1{
+ \use:c {
+ bool_
+ \if_meaning:w !#1 ! \else: \if_meaning:w (#1 ( \else: p \fi: \fi:
+ :w
+ } #1
}
-\def_new:Npn \predicate_auxi:NN 0 #1{
- \exp_after:NN \predicate_auxii:NNN \exp_after:NN #1
- \int_to_roman:w-`\q
+% \end{macrocode}
+% The Not operation. Discard the token read and reverse the truth
+% value of the next expression using "\intexpr_if_even_p:n".
+% \begin{macrocode}
+\cs_set:cpn {bool_!:w}#1{
+ \exp_after:wN \intexpr_if_even_p:n \tex_number:D \bool_get_next:N
}
% \end{macrocode}
-% After removing trailing conditionals we call a macro for the case we
-% are in (see list above).
+% The Open operation. Discard the token read and start a
+% sub-expression.
% \begin{macrocode}
-\def_new:Npn \predicate_auxii:NNN #1#2#3{
- \cs_use:c{predicate_#2#3_#1:w} }
-\def_new:cpn{predicate_&&_0:w}{
- \exp_after:NN \predicate_auxi:NN\int_to_roman:w-`\q
+\cs_set:cpn {bool_(:w}#1{
+ \exp_after:wN \bool_cleanup:N \tex_number:D \bool_get_next:N
}
-\def_long_new:cpn{predicate_&&_1:w} #1 02\scan_stop:{
- \group_align_safe_end: 01}
-\def_long_new:cpn{predicate_||_0:w} #1 02\scan_stop:{
- \group_align_safe_end: 00}
-\def_new:cpn{predicate_||_1:w}{
- \exp_after:NN \predicate_auxi:NN\int_to_roman:w-`\q
+% \end{macrocode}
+% Otherwise just evaluate the predicate and look for And, Or or Close
+% afterward.
+% \begin{macrocode}
+\cs_set:cpn {bool_p:w}{\exp_after:wN \bool_cleanup:N \tex_number:D }
+% \end{macrocode}
+% This cleanup function can be omitted once predicates return their
+% true/false booleans outside the conditionals.
+% \begin{macrocode}
+\cs_new_nopar:Npn \bool_cleanup:N #1{
+ \exp_after:wN \bool_choose:NN \exp_after:wN #1
+ \int_to_roman:w-`\q
}
-\def_new:cpn{predicate_02_0:w}\scan_stop:{ \group_align_safe_end: 00 }
-\def_new:cpn{predicate_02_1:w}\scan_stop:{ \group_align_safe_end: 01 }
+% \end{macrocode}
+% Branching the six way switch.
+% \begin{macrocode}
+\cs_new_nopar:Npn \bool_choose:NN #1#2{ \use:c{bool_#2_#1:w} }
+% \end{macrocode}
+% Continues scanning. Must remove the second "&" or "|".
+% \begin{macrocode}
+\cs_new_nopar:cpn{bool_&_1:w}&{\bool_get_next:N}
+\cs_new_nopar:cpn{bool_|_0: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_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_set:cpn{bool_&_0:w}&{\bool_eval_skip_to_end:Nw \c_false_bool}
+\cs_set:cpn{bool_|_1:w}|{\bool_eval_skip_to_end:Nw \c_true_bool}
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -1146,61 +1255,197 @@
% \end{macro}
% \end{macro}
% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\bool_eval_skip_to_end:Nw,
+% \bool_eval_skip_to_end_aux:Nw,\bool_eval_skip_to_end_auxii:Nw}
+% 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.
%
+% This whole operation could be made a lot simpler if we were allowed
+% to do simple pattern matching. With a new enough pdf\TeX\ one can do
+% that sort of thing to test for existence of particular tokens.
+% \begin{macrocode}
+\cs_set:Npn \bool_eval_skip_to_end:Nw #1#2){
+ \bool_eval_skip_to_end_aux:Nw #1 #2(\q_no_value\q_nil{#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_set:Npn \bool_eval_skip_to_end_aux:Nw #1#2(#3#4\q_nil#5{
+ \quark_if_no_value:NTF #3
+ { #1 }
+ { \bool_eval_skip_to_end_auxii: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_set:Npn \bool_eval_skip_to_end_auxii:Nw #1#2(#3){
+ \bool_eval_skip_to_end:Nw #1#3 )
+}
+% \end{macrocode}
+% \end{macro}
%
-% \begin{macro}{\predicate_not_p:n}
-% The "not" variant just reverses the outcome of |\predicate_p:n|.
+% \begin{macro}{\bool_set:Nn,\bool_set:cn,\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}
-\def_long_new:Npn \predicate_not_p:n #1{
- \if:w \predicate_p:n{#1} \c_false \else: \c_true \fi:
+\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}{\bool_not_p:n}
+% 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}
%
-% \subsubsection{Case switch}
+% \begin{macro}{\bool_xor_p:nn}
+% 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 {
+ \intexpr_compare:nNnTF {\bool_if_p:n { #1 }} = {\bool_if_p:n { #2 }}
+ {\c_false_bool}{\c_true_bool}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+\prg_set_conditional:Npnn \bool_if:n #1 {TF,T,F}{
+ \if_predicate:w \bool_if_p:n{#1}
+ \prg_return_true: \else: \prg_return_false: \fi:
+}
+% \end{macrocode}
+%
+% \begin{macro}{\bool_while_do:nn,\bool_until_do:nn}
+% \begin{macro}{\bool_do_while:nn,\bool_do_until:nn}
+% \begin{arguments}
+% \item Predicate test
+% \item Code to execute
+% \end{arguments}
+% \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_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} }
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Case switch}
%
% \begin{macro}{\prg_case_int:nnn}
-% \begin{macro}{\prg_case_int_aux:nnn}
+% \begin{macro}[aux]{\prg_case_int_aux:nnn}
% This case switch is in reality quite simple. It takes three arguments:
% \begin{enumerate}
% \item An integer expression you wish to find.
-% \item A list of pairs of "{"\meta{integer
-% expr}"}""{"\meta{code}"}". The list can be as long as is desired
+% \item A list of pairs of \Arg{integer expr} \Arg{code}.
+% The list can be as long as is desired
% and \meta{integer expr} can be negative.
% \item The code to be executed if the value wasn't found.
% \end{enumerate}
% We don't need the else case here yet, so leave it dangling in the
% input stream.
% \begin{macrocode}
-\def_long:Npn \prg_case_int:nnn #1 #2 {
+\cs_new:Npn \prg_case_int:nnn #1 #2 {
% \end{macrocode}
% We will be parsing on |#1| for each step so we might as well
% evaluate it first in case it is complicated.
% \begin{macrocode}
- \exp_args:No \prg_case_int_aux:nnn {\num_value:w \int_eval:n{#1}} #2
+ \exp_args:Nf \prg_case_int_aux:nnn { \intexpr_eval:n{#1}} #2
% \end{macrocode}
% The \texttt{?} below is just so there are enough arguments when we
% reach the end. And it made you look.~\texttt{;-)}
% \begin{macrocode}
\q_recursion_tail ? \q_recursion_stop
}
-\def_long_new:Npn \prg_case_int_aux:nnn #1#2#3{
+\cs_new:Npn \prg_case_int_aux:nnn #1#2#3{
% \end{macrocode}
% If we reach the end, return the else case. We just remove braces.
% \begin{macrocode}
- \quark_if_recursion_tail_stop_do:nn{#2}{\use_arg_i:n}
+ \quark_if_recursion_tail_stop_do:nn{#2}{\use:n}
% \end{macrocode}
% Otherwise we compare (which evaluates |#2| for us)
% \begin{macrocode}
- \num_compare:nNnTF{#1}={#2}
+ \intexpr_compare:nNnTF{#1}={#2}
% \end{macrocode}
% If true, we want to remove the remainder of the list, the else case
-% and then execute the code specified. Why not use |#3\use_none:n|?
-% Because if we are doing |f| style expansion, we will get
-% leftovers. If the test was false, we try the next pair, carrying the
-% |#1|.
+% and then execute the code specified. |\prg_end_case:nw {#3}| does
+% just that in one go. This means |f| style expansion works the way
+% one wants it to work.
% \begin{macrocode}
- { \use_arg_i_delimit_by_q_recursion_stop:nw {\use_arg_i:nn{#3}} }
+ { \prg_end_case:nw {#3} }
{ \prg_case_int_aux:nnn {#1}}
}
% \end{macrocode}
@@ -1208,17 +1453,17 @@
% \end{macro}
%
% \begin{macro}{\prg_case_dim:nnn}
-% \begin{macro}{\prg_case_dim_aux:nnn}
+% \begin{macro}[aux]{\prg_case_dim_aux:nnn}
% Same as |\prg_case_dim:nnn| except it is for \meta{dim} registers.
% \begin{macrocode}
-\def_long:Npn \prg_case_dim:nnn #1 #2 {
+\cs_new:Npn \prg_case_dim:nnn #1 #2 {
\exp_args:No \prg_case_dim_aux:nnn {\dim_use:N \dim_eval:n{#1}} #2
\q_recursion_tail ? \q_recursion_stop
}
-\def_long_new:Npn \prg_case_dim_aux:nnn #1#2#3{
- \quark_if_recursion_tail_stop_do:nn{#2}{\use_arg_i:n}
+\cs_new:Npn \prg_case_dim_aux:nnn #1#2#3{
+ \quark_if_recursion_tail_stop_do:nn{#2}{\use:n}
\dim_compare:nNnTF{#1}={#2}
- { \use_arg_i_delimit_by_q_recursion_stop:nw {\use_arg_i:nn{#3}} }
+ { \prg_end_case:nw {#3} }
{ \prg_case_dim_aux:nnn {#1}}
}
% \end{macrocode}
@@ -1226,27 +1471,56 @@
% \end{macro}
%
% \begin{macro}{\prg_case_str:nnn}
-% \begin{macro}{\prg_case_str_aux:nnn}
+% \begin{macro}[aux]{\prg_case_str_aux:nnn}
% Same as |\prg_case_dim:nnn| except it is for strings.
% \begin{macrocode}
-\def_long:Npn \prg_case_str:nnn #1 #2 {
+\cs_new:Npn \prg_case_str:nnn #1 #2 {
\prg_case_str_aux:nnn {#1} #2
\q_recursion_tail ? \q_recursion_stop
}
-\def_long_new:Npn \prg_case_str_aux:nnn #1#2#3{
- \quark_if_recursion_tail_stop_do:nn{#2}{\use_arg_i:n}
- \tlist_if_eq:xxTF{#1}{#2}
- { \use_arg_i_delimit_by_q_recursion_stop:nw {\use_arg_i:nn{#3}} }
+\cs_new:Npn \prg_case_str_aux:nnn #1#2#3{
+ \quark_if_recursion_tail_stop_do:nn{#2}{\use:n}
+ \tl_if_eq:xxTF{#1}{#2}
+ { \prg_end_case:nw {#3} }
{ \prg_case_str_aux:nnn {#1}}
}
% \end{macrocode}
% \end{macro}
% \end{macro}
%
-% \subsubsection{Sorting}
+% \begin{macro}{\prg_case_tl:Nnn}
+% \begin{macro}[aux]{\prg_case_tl_aux:NNn}
+% Same as |\prg_case_dim:nnn| except it is for token list variables.
+% \begin{macrocode}
+\cs_new:Npn \prg_case_tl:Nnn #1 #2 {
+ \prg_case_tl_aux:NNn #1 #2
+ \q_recursion_tail ? \q_recursion_stop
+}
+\cs_new:Npn \prg_case_tl_aux:NNn #1#2#3{
+ \quark_if_recursion_tail_stop_do:Nn #2{\use:n}
+ \tl_if_eq:NNTF #1 #2
+ { \prg_end_case:nw {#3} }
+ { \prg_case_tl_aux:NNn #1}
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+%
+% \begin{macro}[aux]{\prg_end_case:nw}
+% Ending a case switch is always performed the same way so we
+% optimize for this. |#1| is the code to execute, |#2| the
+% remainder, and |#3| the dangling else case.
+% \begin{macrocode}
+\cs_new:Npn \prg_end_case:nw #1#2\q_recursion_stop#3{#1}
+% \end{macrocode}
+% \end{macro}
+
%
+% \subsection{Sorting}
%
-% \begin{macro}{\prg_define_quicksort:nnn}
+%
+% \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
@@ -1263,37 +1537,37 @@
% 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
+% is a token list variable, so one additionally has to define
% \begin{quote}
-% |\def:Npn \seq_quicksort:N{\exp_args:No\seq_quicksort:n}|
+% |\cs_set_nopar: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.
+% initial list and then the braced list afterwards.
% \begin{macrocode}
-\def_new:NNn \prg_define_quicksort:nnn 3 {
- \def_long:cNx{#1_quicksort:n}1{
+\cs_new_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}
}
- \def_long:cNx{#1_quicksort_braced:n}1{
+ \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
}
- \def_long:cpx {#1_quicksort_start_partition:w} #2 ##1 #3{
+ \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}{}{}
}
- \def_long:cNx {#1_quicksort_start_partition_braced:n} 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}
- \def_long:cpx {#1_quicksort_do_partition_i:nnnw} ##1##2##3 #2 ##4 #3 {
+ \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}
@@ -1302,7 +1576,7 @@
}
{##1}{##2}{##3}{##4}
}
- \def_long:cNx {#1_quicksort_do_partition_i_braced:nnnn} 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}
@@ -1311,7 +1585,7 @@
}
{##1}{##2}{##3}{##4}
}
- \def_long:cpx {#1_quicksort_do_partition_ii:nnnw} ##1##2##3 #2 ##4 #3 {
+ \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}
@@ -1320,7 +1594,7 @@
}
{##1}{##2}{##3}{##4}
}
- \def_long:cNx {#1_quicksort_do_partition_ii_braced:nnnn} 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}
@@ -1333,26 +1607,26 @@
% 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{
+ \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}}
- \def_long:cNx {#1_quicksort_partition_less_ii:nnnn} 4{
+ \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}}}
- \def_long:cNx {#1_quicksort_partition_greater_i:nnnn} 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}}
- \def_long:cNx {#1_quicksort_partition_greater_ii:nnnn} 4{
+ \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}}
- \def_long:cNx {#1_quicksort_partition_less_i_braced:nnnn} 4{
+ \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}}
- \def_long:cNx {#1_quicksort_partition_less_ii_braced:nnnn} 4{
+ \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}}}
- \def_long:cNx {#1_quicksort_partition_greater_i_braced:nnnn} 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}}
- \def_long:cNx {#1_quicksort_partition_greater_ii_braced:nnnn} 4{
+ \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}
- \def_long:cpx {#1_do_quicksort_braced:nnnnw} ##1##2##3##4\q_stop {
+ \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}
@@ -1374,77 +1648,24 @@
% \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
+\cs_set:Npn \prg_quicksort_function:n {\ERROR}
+\cs_set:Npn \prg_quicksort_compare:nnTF {\ERROR}
% \end{macrocode}
% \end{macro}
% \end{macro}
%
-%
% That's it (for now).
% \begin{macrocode}
%</initex|package>
+% \end{macrocode}
+%
+% \begin{macrocode}
%<*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
+% \end{implementation}
+% \PrintIndex
%
+% \endinput