diff options
author | Karl Berry <karl@freefriends.org> | 2009-06-09 23:31:15 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2009-06-09 23:31:15 +0000 |
commit | 215b9a864d5829070bdc66ba736986eb72e5143e (patch) | |
tree | fe0882c81fc4ec945cee4b512f72eaa21ea5f791 /Master/texmf-dist/source/latex/expl3/l3prg.dtx | |
parent | df90ec06321940c2f066b05e12f1b5ab099105da (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.dtx | 1599 |
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 |