[latex3-commits] [git/LaTeX3-latex3-latex3] scan-quark: Add \__kernel_quark_conditional_generate:NNnn for branching quark conditionals (233b7d0b6)

PhelypeOleinik tex.phelype at gmail.com
Thu Mar 19 15:50:35 CET 2020


Repository : https://github.com/latex3/latex3
On branch  : scan-quark
Link       : https://github.com/latex3/latex3/commit/233b7d0b634eb7e5baf06deaaf9a5b775ecd06b7

>---------------------------------------------------------------

commit 233b7d0b634eb7e5baf06deaaf9a5b775ecd06b7
Author: PhelypeOleinik <tex.phelype at gmail.com>
Date:   Thu Mar 19 11:50:35 2020 -0300

    Add \__kernel_quark_conditional_generate:NNnn for branching quark conditionals


>---------------------------------------------------------------

233b7d0b634eb7e5baf06deaaf9a5b775ecd06b7
 l3kernel/l3quark.dtx | 301 ++++++++++++++++++++++++++++++++-------------------
 1 file changed, 188 insertions(+), 113 deletions(-)

diff --git a/l3kernel/l3quark.dtx b/l3kernel/l3quark.dtx
index 166d2e4be..61db72192 100644
--- a/l3kernel/l3quark.dtx
+++ b/l3kernel/l3quark.dtx
@@ -486,8 +486,95 @@
 % \end{macro}
 % \end{macro}
 %
+% \begin{macro}[pTF]{\quark_if_nil:N}
+% \UnitTested
+% \begin{macro}[pTF]{\quark_if_no_value:N, \quark_if_no_value:c}
+% \UnitTested
+%   Here we test if we found a special quark as the first argument.
+%   We better start with \cs{q_no_value} as the first argument since
+%   the whole thing may otherwise loop if |#1| is wrongly given
+%   a string like |aabc| instead of a single token.\footnote{It may
+%   still loop in special circumstances however!}
+%    \begin{macrocode}
+\prg_new_conditional:Npnn \quark_if_nil:N #1 { p, T , F , TF }
+  {
+    \if_meaning:w \q_nil #1
+      \prg_return_true:
+    \else:
+      \prg_return_false:
+    \fi:
+  }
+\prg_new_conditional:Npnn \quark_if_no_value:N #1 { p, T , F , TF }
+  {
+    \if_meaning:w \q_no_value #1
+      \prg_return_true:
+    \else:
+      \prg_return_false:
+    \fi:
+  }
+\prg_generate_conditional_variant:Nnn \quark_if_no_value:N
+  { c } { p , T , F , TF }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[pTF]{\quark_if_nil:n, \quark_if_nil:V, \quark_if_nil:o}
+% \UnitTested
+% \begin{macro}[pTF]{\quark_if_no_value:n}
+% \UnitTested
+% \begin{macro}{\@@_if_nil:w, \@@_if_no_value:w}
+% \begin{macro}[EXP]{\@@_if_empty_if:o}
+%   Let us explain |\quark_if_nil:n(TF)|.  Expanding \cs{@@_if_nil:w}
+%   once is safe thanks to the trailing \cs{q_nil} |??!|.  The result of
+%   expanding once is empty if and only if both delimited arguments |#1|
+%   and~|#2| are empty and |#3|~is delimited by the last tokens~|?!|.
+%   Thanks to the leading~|{}|, the argument~|#1| is empty if and only
+%   if the argument of \cs{quark_if_nil:n} starts with \cs{q_nil}.  The
+%   argument~|#2| is empty if and only if this \cs{q_nil} is followed
+%   immediately by~|?| or by~|{}?|, coming either from the trailing
+%   tokens in the definition of \cs{quark_if_nil:n}, or from its
+%   argument.  In the first case, \cs{@@_if_nil:w} is followed by
+%   |{}\q_nil| |{}?| |!\q_nil|~|??!|, hence |#3|~is delimited by the
+%   final~|?!|, and the test returns \texttt{true} as wanted.  In the
+%   second case, the result is not empty since the first~|?!| in the
+%   definition of \cs{quark_if_nil:n} stop~|#3|. The auxiliary here
+%   is the same as \cs{__tl_if_empty_if:o}, with the same comments
+%   applying.
+%    \begin{macrocode}
+\prg_new_conditional:Npnn \quark_if_nil:n #1 { p, T , F , TF }
+  {
+    \@@_if_empty_if:o
+      { \@@_if_nil:w {} #1 {} ? ! \q_nil ? ? ! }
+      \prg_return_true:
+    \else:
+      \prg_return_false:
+    \fi:
+  }
+\cs_new:Npn \@@_if_nil:w #1 \q_nil #2 ? #3 ? ! { #1 #2 }
+\prg_new_conditional:Npnn \quark_if_no_value:n #1 { p, T , F , TF }
+  {
+    \@@_if_empty_if:o
+      { \@@_if_no_value:w {} #1 {} ? ! \q_no_value ? ? ! }
+      \prg_return_true:
+    \else:
+      \prg_return_false:
+    \fi:
+  }
+\cs_new:Npn \@@_if_no_value:w #1 \q_no_value #2 ? #3 ? ! { #1 #2 }
+\prg_generate_conditional_variant:Nnn \quark_if_nil:n
+  { V , o } { p , TF , T , F }
+\cs_new:Npn \@@_if_empty_if:o #1
+  {
+    \exp_after:wN \if_meaning:w \exp_after:wN \q_nil
+      \__kernel_tl_to_str:w \exp_after:wN {#1} \q_nil
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
 % \begin{macro}{\__kernel_quark_test_generate:NNNn}
-% \begin{macro}{\@@_test_generate_aux:nnNN, \@@_test_generate_choose:nN }
 %   The function \cs{__kernel_quark_test_generate:NNNn} defines |#1|
 %   in a similar way as \cs[no-index]{quark_if_recursion_tail_stop(_do):(N|n)(n)}.
 %   using |#2| (as \cs{q_recursion_tail}) as the test quark and |#3|
@@ -506,25 +593,46 @@
 %     \item[\texttt{:NN}:~] defines \cs{quark_if_recursion_tail_break:NN}
 %   \end{description}
 %   Any other signature causes an error, as does a function without signature.
+%
+% \begin{macro}{\__kernel_quark_conditional_generate:NNnn}
+%   Similar to \cs{__kernel_quark_test_generate:NNNn}, but defines
+%   quark branching conditionals like \cs{quark_if_nil:nTF}
+%   using |#2| as the test quark, |#3| as the name-space to define
+%   auxiliaries, and |#4| is the list of conditional variants to define.
+%
+%   There are only two cases here:
+%   \begin{description}
+%     \item[\texttt{:n}:~] defines \cs[no-index]{quark_if_nil:n(TF)}
+%     \item[\texttt{:N}:~] defines \cs[no-index]{quark_if_nil:N(TF)}
+%   \end{description}
+%   Any other signature causes an error, as does a function without signature.
+%
+% \begin{macro}{\@@_test_generate_aux:nnNN, \@@_test_generate_choose:nN }
 %    \begin{macrocode}
 \cs_new_protected:Npn \__kernel_quark_test_generate:NNNn #1
   {
     \exp_last_unbraced:Nf \@@_test_generate_aux:nnNN
       \cs_split_function:N #1
-      #1
+      #1 { test }
+  }
+\cs_new_protected:Npn \__kernel_quark_conditional_generate:NNnn #1
+  {
+    \exp_last_unbraced:Nf \@@_test_generate_aux:nnNN
+      \cs_split_function:N #1
+      #1 { conditional }
   }
 \cs_new_protected:Npn \@@_test_generate_aux:nnNN #1 #2 #3 #4
   {
     \reverse_if:N \tex_ifodd:D #3
       \__kernel_msg_error:nnx { kernel } { missing-colon }
         { \token_to_str:N #4 }
-      \exp_after:wN \use_none:nnnnn
+      \exp_after:wN \use_none:nnnnnn
     \fi:
     \use:n { \@@_test_generate_choose:nN {#2} #4 }
   }
-\cs_new_protected:Npn \@@_test_generate_choose:nN #1 #2
+\cs_new_protected:Npn \@@_test_generate_choose:nN #1 #2 #3
   {
-    \cs_if_exist_use:cTF { @@_test_generate_#1:NNNn } {#2}
+    \cs_if_exist_use:cTF { @@_#3_generate_#1:NNNn } {#2}
       {
         \__kernel_msg_error:nnxx { kernel } { invalid-quark-function }
           { \token_to_str:N #2 } {#1}
@@ -534,6 +642,7 @@
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
+% \end{macro}
 %
 % \begin{macro}{
 %     \@@_test_generate_n:NNNn, \@@_test_generate_nn:NNNn,
@@ -543,39 +652,39 @@
 %   These macros implement the six possibilities mentioned above, passing
 %   the right arguments to \cs{@@_test_generate_aux_do:nNNnnnn},
 %   which defines some auxiliaries, and then to
-%   \cs{@@_test_generate_define_tl:NNNNn} (|:n(n)| variants) or to
-%   \cs{@@_test_generate_define_ifx:NNNNn} (|:N(n)|) which define the
+%   \cs{@@_test_generate_define_tl:nNNNNN} (|:n(n)| variants) or to
+%   \cs{@@_test_generate_define_ifx:nNNNNN} (|:N(n)|) which define the
 %   main conditionals.
 %    \begin{macrocode}
 \cs_new_protected:Npn \@@_test_generate_n:NNNn #1 #2 #3 #4
   {
     \@@_test_generate_aux_do:nNNnnnn {#4} #2 #3 { none } { } { } { }
-      \@@_test_generate_define_tl:NNNNn #1 { }
+      \@@_test_generate_define_tl:nNNNNN #1 { }
   }
 \cs_new_protected:Npn \@@_test_generate_nn:NNNn #1 #2 #3 #4
   {
     \@@_test_generate_aux_do:nNNnnnn {#4} #2 #3 { i } { n } {##1} {##2}
-      \@@_test_generate_define_tl:NNNNn #1 { \use_none:n }
+      \@@_test_generate_define_tl:nNNNNN #1 { \use_none:n }
   }
 \cs_new_protected:Npn \@@_test_generate_nN:NNNn #1 #2 #3 #4
   {
     \@@_test_generate_aux_do:nNNnnnn {#4} #2 #3 { i } { n } {##1} {##2}
-      \@@_test_generate_define_break_tl:NNNNn #1 { }
+      \@@_test_generate_define_break_tl:nNNNNN #1 { }
   }
 \cs_new_protected:Npn \@@_test_generate_N:NNNn #1 #2 #3 #4
   {
     \@@_test_generate_aux_do:nNNnnnn {#4} #2 #3 { none } { } { } { }
-      \@@_test_generate_define_ifx:NNNNn #1 { }
+      \@@_test_generate_define_ifx:nNNNNN #1 { }
   }
 \cs_new_protected:Npn \@@_test_generate_Nn:NNNn #1 #2 #3 #4
   {
     \@@_test_generate_aux_do:nNNnnnn {#4} #2 #3 { i } { n } {##1} {##2}
-      \@@_test_generate_define_ifx:NNNNn #1 { \use_none:n }
+      \@@_test_generate_define_ifx:nNNNNN #1 { \use_none:n }
   }
 \cs_new_protected:Npn \@@_test_generate_NN:NNNn #1 #2 #3 #4
   {
     \@@_test_generate_aux_do:nNNnnnn {#4} #2 #3 { i } { n } {##1} {##2}
-      \@@_test_generate_define_break_ifx:NNNNn #1 { }
+      \@@_test_generate_define_break_ifx:nNNNNN #1 { }
   }
 %    \end{macrocode}
 % \end{macro}
@@ -586,8 +695,8 @@
 %   }
 %   \cs{@@_test_generate_aux_do:nNNnnnn} makes the conrol sequence names
 %   which will be used by \cs{@@_test_define_aux:NNNnnN}, and then later
-%   by \cs{@@_test_generate_define_tl:NNNNn} or
-%   \cs{@@_test_generate_define_ifx:NNNNn}. The control sequences defined
+%   by \cs{@@_test_generate_define_tl:nNNNNN} or
+%   \cs{@@_test_generate_define_ifx:nNNNNN}. The control sequences defined
 %   here are analogous to \cs{@@_if_recursion_tail:w} and to
 %   \cs[no-index]{use_(none|i)_delimit_by_q_recursion_stop:(|n)w}.
 %
@@ -621,17 +730,17 @@
 % \end{macro}
 %
 % \begin{macro}{
-%     \@@_test_generate_define_tl:NNNNn,
-%     \@@_test_generate_define_ifx:NNNNn
+%     \@@_test_generate_define_tl:nNNNNN,
+%     \@@_test_generate_define_ifx:nNNNNN
 %   }
 % \begin{macro}{
-%     \@@_test_generate_define_break_tl:NNNNn,
-%     \@@_test_generate_define_break_ifx:NNNNn
+%     \@@_test_generate_define_break_tl:nNNNNN,
+%     \@@_test_generate_define_break_ifx:nNNNNN
 %   }
 %   Finally, these two macros define the main conditional function using
 %   what's been set up before.
 %    \begin{macrocode}
-\cs_new_protected:Npn \@@_test_generate_define_tl:NNNNn #1 #2 #3 #4 #5 #6
+\cs_new_protected:Npn \@@_test_generate_define_tl:nNNNNN #1 #2 #3 #4 #5 #6
   {
     \cs_new:Npn #5 #1
       {
@@ -640,7 +749,7 @@
           {#3} {#6}
       }
   }
-\cs_new_protected:Npn \@@_test_generate_define_ifx:NNNNn #1 #2 #3 #4 #5 #6
+\cs_new_protected:Npn \@@_test_generate_define_ifx:nNNNNN #1 #2 #3 #4 #5 #6
   {
     \cs_new:Npx #5 #1
       {
@@ -651,14 +760,68 @@
         \exp_not:N \fi:
       }
   }
-\cs_new_protected:Npn \@@_test_generate_define_break_tl:NNNNn #1 #2 #3
-  { \@@_test_generate_define_tl:NNNNn {##1##2} #2 {##2} }
-\cs_new_protected:Npn \@@_test_generate_define_break_ifx:NNNNn #1 #2 #3
-  { \@@_test_generate_define_ifx:NNNNn {##1##2} #2 {##2} }
+\cs_new_protected:Npn \@@_test_generate_define_break_tl:nNNNNN #1 #2 #3
+  { \@@_test_generate_define_tl:nNNNNN {##1##2} #2 {##2} }
+\cs_new_protected:Npn \@@_test_generate_define_break_ifx:nNNNNN #1 #2 #3
+  { \@@_test_generate_define_ifx:nNNNNN {##1##2} #2 {##2} }
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
 %
+% \begin{macro}{
+%     \@@_conditional_generate_n:NNNn,
+%     \@@_conditional_generate_N:NNNn,
+%   }
+%   These macros implement the two possibilities for branching quark
+%   conditionals, passing
+%   the right arguments to \cs{@@_conditional_generate_aux_do:nN},
+%   which defines some auxiliaries, and then to
+%   \cs{@@_conditional_generate_define:nNNNNn} which defines the
+%   main conditionals.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_conditional_generate_n:NNNn #1 #2 #3
+  {
+    \@@_conditional_generate_aux_do:nN {#3} #2
+      \@@_conditional_generate_define:nNNNNn #1 \use_i:nn
+  }
+\cs_new_protected:Npn \@@_conditional_generate_N:NNNn #1 #2 #3
+  {
+    \@@_conditional_generate_aux_do:nN {#3} #2
+      \@@_conditional_generate_define:nNNNNn #1 \use_ii:nn
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{
+%     \@@_conditional_generate_aux_do:nN,
+%     \@@_conditional_define_aux:NN,
+%     \@@_conditional_generate_define:nNNNNn
+%   }
+%   Similar to the previous macros, but branching conditionals only require
+%   one auxiliary, so we take a shortcut.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_conditional_generate_aux_do:nN #1 #2
+  {
+    \exp_args:Nc \@@_conditional_define_aux:NN
+      { #1 _if_ \@@_get_name:N #2 :w } #2
+  }
+\cs_new_protected:Npn \@@_conditional_define_aux:NN #1 #2 #3
+  {
+    \cs_gset:Npn #1  ##1 #2 ##2 ? ##3 ?! { ##1 ##2 }
+    #3 {##1} #1 #2
+  }
+\cs_new_protected:Npn \@@_conditional_generate_define:nNNNNn #1 #2 #3 #4 #5 #6
+  {
+    \exp_args:Nno \use:n { \prg_new_conditional:Npnn #4 #1 {#6} }
+      {
+        #5 { \@@_if_empty_if:o { #2 {} ##1 {} ?! #3 ??! } }
+           { \if_meaning:w #3 ##1 }
+        \prg_return_true: \else: \prg_return_false: \fi:
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
 % \begin{macro}[EXP]{\@@_get_name:N}
 % \begin{macro}[EXP]{
 %     \@@_get_name_aux:w,
@@ -696,94 +859,6 @@
 % \end{macro}
 % \end{macro}
 %
-% \begin{macro}[pTF]{\quark_if_nil:N}
-% \UnitTested
-% \begin{macro}[pTF]{\quark_if_no_value:N, \quark_if_no_value:c}
-% \UnitTested
-%   Here we test if we found a special quark as the first argument.
-%   We better start with \cs{q_no_value} as the first argument since
-%   the whole thing may otherwise loop if |#1| is wrongly given
-%   a string like |aabc| instead of a single token.\footnote{It may
-%   still loop in special circumstances however!}
-%    \begin{macrocode}
-\prg_new_conditional:Npnn \quark_if_nil:N #1 { p, T , F , TF }
-  {
-    \if_meaning:w \q_nil #1
-      \prg_return_true:
-    \else:
-      \prg_return_false:
-    \fi:
-  }
-\prg_new_conditional:Npnn \quark_if_no_value:N #1 { p, T , F , TF }
-  {
-    \if_meaning:w \q_no_value #1
-      \prg_return_true:
-    \else:
-      \prg_return_false:
-    \fi:
-  }
-\prg_generate_conditional_variant:Nnn \quark_if_no_value:N
-  { c } { p , T , F , TF }
-%    \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[pTF]{\quark_if_nil:n, \quark_if_nil:V, \quark_if_nil:o}
-% \UnitTested
-% \begin{macro}[pTF]{\quark_if_no_value:n}
-% \UnitTested
-% \begin{macro}{\@@_if_nil:w, \@@_if_no_value:w}
-% \begin{macro}[EXP]{\@@_if_empty_if:o}
-%   Let us explain |\quark_if_nil:n(TF)|.  Expanding \cs{@@_if_nil:w}
-%   once is safe thanks to the trailing \cs{q_nil} |??!|.  The result of
-%   expanding once is empty if and only if both delimited arguments |#1|
-%   and~|#2| are empty and |#3|~is delimited by the last tokens~|?!|.
-%   Thanks to the leading~|{}|, the argument~|#1| is empty if and only
-%   if the argument of \cs{quark_if_nil:n} starts with \cs{q_nil}.  The
-%   argument~|#2| is empty if and only if this \cs{q_nil} is followed
-%   immediately by~|?| or by~|{}?|, coming either from the trailing
-%   tokens in the definition of \cs{quark_if_nil:n}, or from its
-%   argument.  In the first case, \cs{@@_if_nil:w} is followed by
-%   |{}\q_nil| |{}?| |!\q_nil|~|??!|, hence |#3|~is delimited by the
-%   final~|?!|, and the test returns \texttt{true} as wanted.  In the
-%   second case, the result is not empty since the first~|?!| in the
-%   definition of \cs{quark_if_nil:n} stop~|#3|. The auxiliary here
-%   is the same as \cs{__tl_if_empty_if:o}, with the same comments
-%   applying.
-%    \begin{macrocode}
-\prg_new_conditional:Npnn \quark_if_nil:n #1 { p, T , F , TF }
-  {
-    \@@_if_empty_if:o
-      { \@@_if_nil:w {} #1 {} ? ! \q_nil ? ? ! }
-      \prg_return_true:
-    \else:
-      \prg_return_false:
-    \fi:
-  }
-\cs_new:Npn \@@_if_nil:w #1 \q_nil #2 ? #3 ? ! { #1 #2 }
-\prg_new_conditional:Npnn \quark_if_no_value:n #1 { p, T , F , TF }
-  {
-    \@@_if_empty_if:o
-      { \@@_if_no_value:w {} #1 {} ? ! \q_no_value ? ? ! }
-      \prg_return_true:
-    \else:
-      \prg_return_false:
-    \fi:
-  }
-\cs_new:Npn \@@_if_no_value:w #1 \q_no_value #2 ? #3 ? ! { #1 #2 }
-\prg_generate_conditional_variant:Nnn \quark_if_nil:n
-  { V , o } { p , TF , T , F }
-\cs_new:Npn \@@_if_empty_if:o #1
-  {
-    \exp_after:wN \if_meaning:w \exp_after:wN \q_nil
-      \__kernel_tl_to_str:w \exp_after:wN {#1} \q_nil
-  }
-%    \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
 % \subsection{Scan marks}
 %
 %    \begin{macrocode}





More information about the latex3-commits mailing list.