diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3prg.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3prg.dtx | 385 |
1 files changed, 130 insertions, 255 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx b/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx index b54376773d6..67af5299b7c 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3prg.dtx @@ -41,7 +41,7 @@ % }^^A % } % -% \date{Released 2017/07/15} +% \date{Released 2017/07/19} % % \maketitle % @@ -270,7 +270,7 @@ % Sets \meta{boolean_1} to the current value of \meta{boolean_2}. % \end{function} % -% \begin{function}[updated = 2012-07-08] +% \begin{function}[updated = 2017-07-15] % {\bool_set:Nn, \bool_set:cn, \bool_gset:Nn, \bool_gset:cn} % \begin{syntax} % \cs{bool_set:Nn} \meta{boolean} \Arg{boolexpr} @@ -296,7 +296,7 @@ % Displays the logical truth of the \meta{boolean} on the terminal. % \end{function} % -% \begin{function}[added = 2012-02-09, updated = 2015-08-07]{\bool_show:n} +% \begin{function}[added = 2012-02-09, updated = 2017-07-15]{\bool_show:n} % \begin{syntax} % \cs{bool_show:n} \Arg{boolean expression} % \end{syntax} @@ -311,7 +311,7 @@ % Writes the logical truth of the \meta{boolean} in the log file. % \end{function} % -% \begin{function}[added = 2014-08-22, updated = 2015-08-07]{\bool_log:n} +% \begin{function}[added = 2014-08-22, updated = 2017-07-15]{\bool_log:n} % \begin{syntax} % \cs{bool_log:n} \Arg{boolean expression} % \end{syntax} @@ -354,8 +354,7 @@ % \meta{true} or \meta{false}. It supports the logical operations And, % Or and Not as the well-known infix operators |&&| and \verb"||" and prefix~|!| % with their usual precedences (namely, |&&| binds more tightly than -% \verb"||"). In -% addition to this, parentheses can be used to isolate +% \verb"||"). In addition to this, parentheses can be used to isolate % sub-expressions. For example, % \begin{verbatim} % \int_compare_p:n { 1 = 1 } && @@ -368,18 +367,22 @@ % \end{verbatim} % is a valid boolean expression. % -% At present, the infix operators |&&| and \verb"||" perform lazy -% evaluation, but this will change in the near future. % Contrarily to some other programming languages, the operators |&&| and -% \verb"||" will evaluate both operands in all cases, even when the first +% \verb"||" evaluate both operands in all cases, even when the first % operand is enough to determine the result. This \enquote{eager} % evaluation should be contrasted with the \enquote{lazy} evaluation of % \cs[no-index]{bool_lazy_\ldots{}} functions. % % \begin{texnote} % The eager evaluation of boolean expressions is unfortunately -% necessary. Indeed, a lazy parser can get confused if |&&| and -% \verb"||" appear as (unbraced) arguments of some predicates. +% necessary in \TeX{}. Indeed, a lazy parser can get confused if |&&| +% or \verb"||" or parentheses appear as (unbraced) arguments of some +% predicates. For instance, the innocuous-looking expression below +% would break (in a lazy parser) if |#1| were a closing parenthesis +% and \cs[no-index]{l_tmpa_bool} were \texttt{true}. +% \begin{verbatim} +% ( \l_tmpa_bool || \token_if_eq_meaning_p:NN X #1 ) +% \end{verbatim} % \end{texnote} % % Minimal (lazy) evaluation can be obtained using the conditionals @@ -405,7 +408,7 @@ % line is expanded because its logical value is needed to determine the % result of \cs{bool_lazy_and_p:nn}. % -% \begin{function}[EXP, pTF, updated = 2012-07-08]{\bool_if:n} +% \begin{function}[EXP, pTF, updated = 2017-07-15]{\bool_if:n} % \begin{syntax} % \cs{bool_if_p:n} \Arg{boolean expression} % \cs{bool_if:nTF} \Arg{boolean expression} \Arg{true code} \Arg{false code} @@ -418,8 +421,8 @@ % |!| (\enquote{Not}) and parentheses. The logical Not applies to % the next predicate or group. % \end{function} -% -% \begin{function}[EXP, pTF, added = 2015-11-15]{\bool_lazy_all:n} +% +% \begin{function}[EXP, pTF, added = 2015-11-15, updated = 2017-07-15]{\bool_lazy_all:n} % \begin{syntax} % \cs{bool_lazy_all_p:n} \{ \Arg{boolexpr_1} \Arg{boolexpr_2} $\cdots$ \Arg{boolexpr_N} \} % \cs{bool_lazy_all:nTF} \{ \Arg{boolexpr_1} \Arg{boolexpr_2} $\cdots$ \Arg{boolexpr_N} \} \Arg{true code} \Arg{false code} @@ -433,7 +436,7 @@ % when there are only two \meta{boolean expressions}. % \end{function} % -% \begin{function}[EXP, pTF, added = 2015-11-15]{\bool_lazy_and:nn} +% \begin{function}[EXP, pTF, added = 2015-11-15, updated = 2017-07-15]{\bool_lazy_and:nn} % \begin{syntax} % \cs{bool_lazy_and_p:nn} \Arg{boolexpr_1} \Arg{boolexpr_2} % \cs{bool_lazy_and:nnTF} \Arg{boolexpr_1} \Arg{boolexpr_2} \Arg{true code} \Arg{false code} @@ -446,7 +449,7 @@ % than two \meta{boolean expressions}. % \end{function} % -% \begin{function}[EXP, pTF, added = 2015-11-15]{\bool_lazy_any:n} +% \begin{function}[EXP, pTF, added = 2015-11-15, updated = 2017-07-15]{\bool_lazy_any:n} % \begin{syntax} % \cs{bool_lazy_any_p:n} \{ \Arg{boolexpr_1} \Arg{boolexpr_2} $\cdots$ \Arg{boolexpr_N} \} % \cs{bool_lazy_any:nTF} \{ \Arg{boolexpr_1} \Arg{boolexpr_2} $\cdots$ \Arg{boolexpr_N} \} \Arg{true code} \Arg{false code} @@ -460,7 +463,7 @@ % when there are only two \meta{boolean expressions}. % \end{function} % -% \begin{function}[EXP, pTF, added = 2015-11-15]{\bool_lazy_or:nn} +% \begin{function}[EXP, pTF, added = 2015-11-15, updated = 2017-07-15]{\bool_lazy_or:nn} % \begin{syntax} % \cs{bool_lazy_or_p:nn} \Arg{boolexpr_1} \Arg{boolexpr_2} % \cs{bool_lazy_or:nnTF} \Arg{boolexpr_1} \Arg{boolexpr_2} \Arg{true code} \Arg{false code} @@ -473,7 +476,7 @@ % than two \meta{boolean expressions}. % \end{function} % -% \begin{function}[EXP, updated = 2012-07-08]{\bool_not_p:n} +% \begin{function}[EXP, updated = 2017-07-15]{\bool_not_p:n} % \begin{syntax} % \cs{bool_not_p:n} \Arg{boolean expression} % \end{syntax} @@ -481,7 +484,7 @@ % expression. % \end{function} % -% \begin{function}[EXP, updated = 2012-07-08]{\bool_xor_p:nn} +% \begin{function}[EXP, updated = 2017-07-15]{\bool_xor_p:nn} % \begin{syntax} % \cs{bool_xor_p:nn} \Arg{boolexpr_1} \Arg{boolexpr_2} % \end{syntax} @@ -538,7 +541,7 @@ % until the \meta{boolean} is \texttt{false}. % \end{function} % -% \begin{function}[rEXP, updated = 2012-07-08]{\bool_do_until:nn} +% \begin{function}[rEXP, updated = 2017-07-15]{\bool_do_until:nn} % \begin{syntax} % \cs{bool_do_until:nn} \Arg{boolean expression} \Arg{code} % \end{syntax} @@ -550,7 +553,7 @@ % \texttt{true}. % \end{function} % -% \begin{function}[rEXP, updated = 2012-07-08]{\bool_do_while:nn} +% \begin{function}[rEXP, updated = 2017-07-15]{\bool_do_while:nn} % \begin{syntax} % \cs{bool_do_while:nn} \Arg{boolean expression} \Arg{code} % \end{syntax} @@ -562,7 +565,7 @@ % \texttt{false}. % \end{function} % -% \begin{function}[rEXP, updated = 2012-07-08]{\bool_until_do:nn} +% \begin{function}[rEXP, updated = 2017-07-15]{\bool_until_do:nn} % \begin{syntax} % \cs{bool_until_do:nn} \Arg{boolean expression} \Arg{code} % \end{syntax} @@ -574,7 +577,7 @@ % then loops until the \meta{boolean expression} is \texttt{true}. % \end{function} % -% \begin{function}[rEXP, updated = 2012-07-08]{\bool_while_do:nn} +% \begin{function}[rEXP, updated = 2017-07-15]{\bool_while_do:nn} % \begin{syntax} % \cs{bool_while_do:nn} \Arg{boolean expression} \Arg{code} % \end{syntax} @@ -808,16 +811,16 @@ % make sure the boolean exists. This is needed because booleans are % not based on token lists nor on \TeX{} registers. % \begin{macrocode} -\__debug_patch:nnNw { \__chk_if_exist_var:N #1 } { } +\__debug_patch:nnNNpn { \__debug_chk_var_exist:N #1 } { } \cs_new_protected:Npn \bool_set_true:N #1 { \cs_set_eq:NN #1 \c_true_bool } -\__debug_patch:nnNw { \__chk_if_exist_var:N #1 } { } +\__debug_patch:nnNNpn { \__debug_chk_var_exist:N #1 } { } \cs_new_protected:Npn \bool_set_false:N #1 { \cs_set_eq:NN #1 \c_false_bool } -\__debug_patch:nnNw { \__chk_if_exist_var:N #1 } { } +\__debug_patch:nnNNpn { \__debug_chk_var_exist:N #1 } { } \cs_new_protected:Npn \bool_gset_true:N #1 { \cs_gset_eq:NN #1 \c_true_bool } -\__debug_patch:nnNw { \__chk_if_exist_var:N #1 } { } +\__debug_patch:nnNNpn { \__debug_chk_var_exist:N #1 } { } \cs_new_protected:Npn \bool_gset_false:N #1 { \cs_gset_eq:NN #1 \c_false_bool } \cs_generate_variant:Nn \bool_set_true:N { c } @@ -852,10 +855,10 @@ % argument the meaning \cs{c_true_bool} or \cs{c_false_bool}. % Again, we include some checking code. % \begin{macrocode} -\__debug_patch:nnNw { \__chk_if_exist_var:N #1 } { } +\__debug_patch:nnNNpn { \__debug_chk_var_exist:N #1 } { } \cs_new_protected:Npn \bool_set:Nn #1#2 { \tex_chardef:D #1 = \bool_if_p:n {#2} } -\__debug_patch:nnNw { \__chk_if_exist_var:N #1 } { } +\__debug_patch:nnNNpn { \__debug_chk_var_exist:N #1 } { } \cs_new_protected: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 } @@ -871,7 +874,7 @@ % \begin{macrocode} \prg_new_conditional:Npnn \bool_if:N #1 { p , T , F , TF } { - \if_meaning:w \c_true_bool #1 + \if_bool:N #1 \prg_return_true: \else: \prg_return_false: @@ -942,7 +945,8 @@ % input syntax somewhat similar to the one found in other programming % languages with |(| and |)| for grouping, |!| for logical % \enquote{Not}, |&&| for logical \enquote{And} and \verb"||" for -% logical \enquote{Or}. We shall use the terms Not, And, Or, Open and +% logical \enquote{Or}. However, they perform eager evaluation. +% We shall use the terms Not, And, Or, Open and % Close for these operations. % % Any expression is terminated by a Close operation. Evaluation @@ -951,9 +955,8 @@ % \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, remove the |!| and call a GetNotNext -% function, which eventually reverses the logic compared to -% GetNext. +% \item If a Not is seen, remove the |!| and call a GetNext +% function with the logic reversed. % \item If none of the above, reinsert the token found (this is % supposed to be a predicate function) in front of an Eval % function, which evaluates it to the boolean value \meta{true} or @@ -968,11 +971,11 @@ % 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}. +% seen, stop using the values of predicates within this +% sub-expression until the next Close. Then return \meta{false}. +% \item[\meta{true}Or] Current truth value is true, logical Or seen, +% stop using the values of predicates within this sub-expression +% until 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. @@ -981,15 +984,6 @@ % \item[\meta{false}Close] Current truth value is false, Close % seen, return \meta{false}. % \end{description} -% We introduce an additional Stop operation with the same -% semantics as the Close operation. -% \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. % \begin{macrocode} \prg_new_conditional:Npnn \bool_if:n #1 { T , F , TF } { @@ -1003,82 +997,40 @@ % \end{macro} % % \begin{macro}[EXP]{\bool_if_p:n} -% \begin{macro}[EXP, aux] -% { -% \@@_if_left_parentheses:wwwn , -% \@@_if_right_parentheses:wwwn , -% \@@_if_or:wwwn -% } -% First issue a \cs{group_align_safe_begin:} as we are using |&&| -% as syntax shorthand for the And operation and we need to hide it for -% \TeX{}. This is closed at the end of the expression parsing -% (see |S| below). -% -% Minimal (\enquote{short-circuit}) evaluation of boolean expressions -% requires skipping to the end of the current parenthesized group when -% \meta{true}\verb"||" is seen, but to the next \verb"||" or closing -% parenthesis when \meta{false}|&&| is seen. To avoid having separate -% functions for the two cases, we transform the boolean expression by -% doubling each parenthesis and adding parenthesis around each -% \verb"||". This ensures that |&&| binds tighter than \verb"||". -% -% The replacement is done in three passes, for left and right -% parentheses and for \verb"||". At each pass, the part of the -% expression that has been transformed is stored before \cs{q_nil}, -% the rest lies until the first \cs{q_mark}, followed by an empty -% brace group. A trailing marker ensures that the auxiliaries' -% delimited arguments do not run-away. As long as the delimiter -% matches inside the expression, material is moved before \cs{q_nil} -% and we continue. Afterwards, the trailing marker is taken as a -% delimiter, |#4| is the next auxiliary, immediately followed by a new -% \cs{q_nil} delimiter, which indicates that nothing has been treated -% at this pass. The last step calls \cs{@@_if_parse:NNNww} which -% cleans up and triggers the evaluation of the expression itself. +% First issue a \cs{group_align_safe_begin:} as we are using |&&| as +% syntax shorthand for the And operation and we need to hide it for +% \TeX{}. This group is closed after \cs{@@_get_next:NN} returns +% \cs{c_true_bool} or \cs{c_false_bool}. That function requires the +% trailing parenthesis to know where the expression ends. % \begin{macrocode} \cs_new:Npn \bool_if_p:n #1 { \group_align_safe_begin: - \@@_if_left_parentheses:wwwn \q_nil - #1 \q_mark { } - ( \q_mark { \@@_if_right_parentheses:wwwn \q_nil } - ) \q_mark { \@@_if_or:wwwn \q_nil } - || \q_mark \@@_if_parse:NNNww - \q_stop - } -\cs_new:Npn \@@_if_left_parentheses:wwwn #1 \q_nil #2 ( #3 \q_mark #4 - { #4 \@@_if_left_parentheses:wwwn #1 #2 (( \q_nil #3 \q_mark {#4} } -\cs_new:Npn \@@_if_right_parentheses:wwwn #1 \q_nil #2 ) #3 \q_mark #4 - { #4 \@@_if_right_parentheses:wwwn #1 #2 )) \q_nil #3 \q_mark {#4} } -\cs_new:Npn \@@_if_or:wwwn #1 \q_nil #2 || #3 \q_mark #4 - { #4 \@@_if_or:wwwn #1 #2 )||( \q_nil #3 \q_mark {#4} } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}[EXP, aux]{\@@_if_parse:NNNww} -% After removing extra tokens from the transformation phase, start -% evaluating. At the end, we need to finish the special -% \texttt{align_safe} group before finally -% returning a \cs{c_true_bool} or \cs{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} -\cs_new:Npn \@@_if_parse:NNNww #1#2#3#4 \q_mark #5 \q_stop - { - \__bool_get_next:NN \use_i:nn (( #4 )) S + \exp_after:wN + \group_align_safe_end: + \exp:w \exp_end_continue_f:w % ( + \@@_get_next:NN \use_i:nnnn #1 ) } % \end{macrocode} % \end{macro} % % \begin{macro}[aux]{\@@_get_next:NN} -% The GetNext operation. This is a switch: if what follows is neither -% |!| nor |(|, we assume it is a predicate. The first argument is -% \cs{use_ii:nn} if the logic must eventually be reversed (after a -% |!|), otherwise it is \cs{use_i:nn}. This function eventually -% expand to the truth value \cs{c_true_bool} or \cs{c_false_bool} of -% the expression which follows until the next unmatched closing -% parenthesis. +% The GetNext operation. Its first argument is \cs{use_i:nnnn}, +% \cs{use_ii:nnnn}, \cs{use_iii:nnnn}, or \cs{use_iv:nnnn} (we call +% these \enquote{states}). In the first state, this function +% eventually expand to the truth value \cs{c_true_bool} or +% \cs{c_false_bool} of the expression which follows until the next +% unmatched closing parenthesis. For instance +% \enquote{\cs{@@_get_next:NN} \cs{use_i:nnnn} \cs{c_true_bool} +% \texttt{\&\&} \cs{c_true_bool} \texttt{)}} (including the closing +% parenthesis) expands to \cs{c_true_bool}. In the second state +% (after a |!|) the logic is reversed. We call these two states +% \enquote{normal} and the next two \enquote{skipping}. In the third +% state (after \cs{c_true_bool}\verb"||") it always returns +% \cs{c_true_bool}. In the fourth state (after \cs{c_false_bool}|&&|) +% it always returns \cs{c_false_bool} and also stops when encountering +% \verb"||", not only parentheses. This code itself is a switch: if +% what follows is neither |!| nor |(|, we assume it is a predicate. % \begin{macrocode} \cs_new:Npn \@@_get_next:NN #1#2 { @@ -1094,23 +1046,31 @@ % \end{macro} % % \begin{macro}[aux]{\@@_!:Nw} -% The Not operation reverses the logic: discard the |!| token and call -% the GetNext operation with its first argument reversed. +% The Not operation reverses the logic: it discards the |!|~token and +% calls the GetNext operation with the appropriate first argument. +% Namely the first and second states are interchanged, but after +% \cs{c_true_bool}\verb"||" or \cs{c_false_bool}|&&| the |!|~is +% ignored. % \begin{macrocode} \cs_new:cpn { @@_!:Nw } #1#2 - { \exp_after:wN \@@_get_next:NN #1 \use_ii:nn \use_i:nn } + { + \exp_after:wN \@@_get_next:NN + #1 \use_ii:nnnn \use_i:nnnn \use_iii:nnnn \use_iv:nnnn + } % \end{macrocode} % \end{macro} % % \begin{macro}[aux]{\@@_(:Nw} -% The Open operation starts a sub-expression after discarding the -% token. This is done by calling GetNext, with a post-processing step -% which looks for And, Or or Close afterwards. +% The Open operation starts a sub-expression after discarding the open +% parenthesis. This is done by calling GetNext (which eventually +% discards the corresponding closing parenthesis), with a +% post-processing step which looks for And, Or or Close after the +% group. % \begin{macrocode} \cs_new:cpn { @@_(:Nw } #1#2 { \exp_after:wN \@@_choose:NNN \exp_after:wN #1 - \__int_value:w \@@_get_next:NN \use_i:nn + \__int_value:w \@@_get_next:NN \use_i:nnnn } % \end{macrocode} % \end{macro} @@ -1118,8 +1078,8 @@ % \begin{macro}[aux]{\@@_p:Nw} % If what follows GetNext is neither |!| nor |(|, evaluate the % predicate using the primitive \cs{__int_value:w}. The canonical -% true and false values have numerical values $1$ and $0$ -% respectively. Look for And, Or or Close afterwards. +% \texttt{true} and \texttt{false} values have numerical values $1$ +% and $0$ respectively. Look for And, Or or Close afterwards. % \begin{macrocode} \cs_new:cpn { @@_p:Nw } #1 { \exp_after:wN \@@_choose:NNN \exp_after:wN #1 \__int_value:w } @@ -1127,149 +1087,63 @@ % \end{macro} % % \begin{macro}[aux]{\@@_choose:NNN} -% Branching the eight-way switch. The arguments are 1: \cs{use_i:nn} -% or \cs{use_ii:nn}, 2: $0$ or $1$ encoding the current truth value, -% 3: the next operation, And, Or, Close or Stop. If |#1| is -% \cs{use_ii:nn}, the logic of |#2| must be reversed. +% \begin{macro}[aux]+\@@_)_0:+ +% \begin{macro}[aux]+\@@_)_1:+ +% \begin{macro}[aux]+\@@_)_2:+ +% \begin{macro}[aux]+\@@_&_0:+ +% \begin{macro}[aux]+\@@_&_1:+ +% \begin{macro}[aux]+\@@_&_2:+ +% \begin{macro}[aux]+\@@_|_0:+ +% \begin{macro}[aux]+\@@_|_1:+ +% \begin{macro}[aux]+\@@_|_2:+ +% The arguments are |#1|: a function such as \cs{use_i:nnnn}, |#2|: +% $0$ or $1$ encoding the current truth value, |#3|: the next +% operation, And, Or or Close. We distinguish three cases according +% to a combination of |#1| and |#2|. Case~2 is when |#1| is +% \cs{use_iii:nnnn} (state~3), namely after +% \cs{c_true_bool}~\verb"||". Case~1 is when |#1| is \cs{use_i:nnnn} +% and |#2| is \texttt{true} or when |#1| is \cs{use_ii:nnnn} and |#2| +% is \texttt{false}, for instance for |!|\cs{c_false_bool}. Case~0 +% includes the same with \texttt{true}/\texttt{false} interchanged and +% the case where |#1| is \cs{use_iv:nnnn} namely after +% \cs{c_false_bool}~|&&|. +% +% When seeing~|)| the current subexpression is done, leave the +% appropriate boolean. When seeing~|&| in case~0 go into state~4, +% equivalent to having seen \cs{c_false_bool}~|&&|. In case~1, namely +% when the argument is \texttt{true} and we are in a normal state +% continue in the normal state~1. In case~2, namely when skipping +% alternatives in an Or, continue in the same state. When +% seeing~\verb"|" in case~0, continue in a normal state; in particular +% stop skipping for \cs{c_false_bool}~|&&| because that binds more +% tightly than~\verb"||". In the other two cases start skipping for +% \cs{c_true_bool}~\verb"||". % \begin{macrocode} \cs_new:Npn \@@_choose:NNN #1#2#3 { \use:c { - @@_ #3 _ - #1 #2 { \if_meaning:w 0 #2 1 \else: 0 \fi: } - :w + @@_ \token_to_str:N #3 _ + #1 #2 { \if_meaning:w 0 #2 1 \else: 0 \fi: } 2 0 : } } +\cs_new:cpn { @@_)_0: } { \c_false_bool } +\cs_new:cpn { @@_)_1: } { \c_true_bool } +\cs_new:cpn { @@_)_2: } { \c_true_bool } +\cs_new:cpn { @@_&_0: } & { \@@_get_next:NN \use_iv:nnnn } +\cs_new:cpn { @@_&_1: } & { \@@_get_next:NN \use_i:nnnn } +\cs_new:cpn { @@_&_2: } & { \@@_get_next:NN \use_iii:nnnn } +\cs_new:cpn { @@_|_0: } | { \@@_get_next:NN \use_i:nnnn } +\cs_new:cpn { @@_|_1: } | { \@@_get_next:NN \use_iii:nnnn } +\cs_new:cpn { @@_|_2: } | { \@@_get_next:NN \use_iii:nnnn } % \end{macrocode} % \end{macro} -% -% \begin{macro}[aux] -% { -% \@@_)_0:w, -% \@@_)_1:w, -% \@@_S_0:w, -% \@@_S_1:w, -% } -% 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:cpn { @@_)_0:w } { \c_false_bool } -\cs_new:cpn { @@_)_1:w } { \c_true_bool } -\cs_new:cpn { @@_S_0:w } { \group_align_safe_end: \c_false_bool } -\cs_new:cpn { @@_S_1:w } { \group_align_safe_end: \c_true_bool } -% \end{macrocode} % \end{macro} -% -% \begin{macro}[aux]+\@@_&_1:w+ -% \begin{macro}[aux]+\@@_|_0:w+ -% Two cases where we simply continue scanning. We must remove the -% second |&| or \verb"|". -% \begin{macrocode} -\cs_new:cpn { @@_&_1:w } & { \@@_get_next:NN \use_i:nn } -\cs_new:cpn { @@_|_0:w } | { \@@_get_next:NN \use_i:nn } -% \end{macrocode} % \end{macro} % \end{macro} -% -% \begin{macro}[aux]+\@@_&_0:w+ -% \begin{macro}[aux]+\@@_|_1:w+ -% \begin{macro}[aux] -% { -% \@@_eval_skip_to_end_auxi:Nw, -% \@@_eval_skip_to_end_auxii:Nw, -% \@@_eval_skip_to_end_auxiii:Nw -% } -% When the truth value has already been decided, we have to throw away -% the remainder of the current group as we are doing minimal -% evaluation. This is slightly tricky as there are no braces so we -% have to play match the |()| manually. -% \begin{macrocode} -\cs_new:cpn { @@_&_0:w } & - { \@@_eval_skip_to_end_auxi:Nw \c_false_bool } -\cs_new:cpn { @@_|_1:w } | - { \@@_eval_skip_to_end_auxi:Nw \c_true_bool } -% \end{macrocode} -% There is always at least one |)| waiting, namely the outer -% one. However, we are facing the problem that there may be more than -% one that need to be finished off and we have to detect the correct -% number of them. Here is a complicated example showing how this is -% done. After evaluating the following, we realize we must skip -% everything after the first And. Note the extra Close at the end. -% \begin{quote} -% |\c_false_bool && ((abc) && xyz) && ((xyz) && (def)))| -% \end{quote} -% First read up to the first Close. This gives us the list we first -% read up until the first right parenthesis so we are looking at the -% token list -% \begin{quote} -% |((abc| -% \end{quote} -% This contains two Open markers so we must remove two groups. Since -% no evaluation of the contents is to be carried out, it doesn't -% matter how we remove the groups as long as we wind up with the -% correct result. We therefore first remove a |()| pair and what -% preceded the Open -- but leave the contents as it may contain Open -% tokens itself -- leaving -% \begin{quote} -% |(abc && xyz) && ((xyz) && (def)))| -% \end{quote} -% Another round of this gives us -% \begin{quote} -% |(abc && xyz| -% \end{quote} -% which still contains an Open so we remove another |()| pair, giving us -% \begin{quote} -% |abc && xyz && ((xyz) && (def)))| -% \end{quote} -% Again we read up to a Close and again find Open tokens: -% \begin{quote} -% |abc && xyz && ((xyz| -% \end{quote} -% Further reduction gives us -% \begin{quote} -% |(xyz && (def)))| -% \end{quote} -% and then -% \begin{quote} -% |(xyz && (def| -% \end{quote} -% with reduction to -% \begin{quote} -% |xyz && (def))| -% \end{quote} -% and ultimately we arrive at no Open tokens being skipped and we can -% finally close the group nicely. -% \begin{macrocode} -%% ( -\cs_new:Npn \@@_eval_skip_to_end_auxi:Nw #1#2 ) - { - \@@_eval_skip_to_end_auxii:Nw #1#2 ( % ) - \q_no_value \q_stop - {#2} - } -% \end{macrocode} -% If no right parenthesis, then |#3| is no_value and we are done, return -% the boolean |#1|. If there is, we need to grab a |()| pair and then -% recurse -% \begin{macrocode} -\cs_new:Npn \@@_eval_skip_to_end_auxii:Nw #1#2 ( #3#4 \q_stop #5 % ) - { - \quark_if_no_value:NTF #3 - {#1} - { \@@_eval_skip_to_end_auxiii:Nw #1 #5 } - } -% \end{macrocode} -% Keep the boolean, throw away anything up to the |(| as it is -% irrelevant, remove a |()| pair but remember to reinsert |#3| as it may -% contain |(| tokens! -% \begin{macrocode} -\cs_new:Npn \@@_eval_skip_to_end_auxiii:Nw #1#2 ( #3 ) - { % ( - \@@_eval_skip_to_end_auxi:Nw #1#3 ) - } -% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} % \end{macro} % \end{macro} % \end{macro} @@ -1510,6 +1384,7 @@ % pool. Also, it is considerably slower than what we use here so the % few extra csnames are well spent I would say. % \begin{macrocode} +\__debug_patch_args:nNNpn { { (#1) } } \cs_new:Npn \prg_replicate:nn #1 { \exp:w |