[latex3-commits] [git/LaTeX3-latex3-latex3] scan-quark: Enhance \__kernel_quark_test_generate:NNNn (1955297ea)
PhelypeOleinik
tex.phelype at gmail.com
Thu Mar 12 03:29:01 CET 2020
Repository : https://github.com/latex3/latex3
On branch : scan-quark
Link : https://github.com/latex3/latex3/commit/1955297ea18733197d7ae974909b2f63505d3730
>---------------------------------------------------------------
commit 1955297ea18733197d7ae974909b2f63505d3730
Author: PhelypeOleinik <tex.phelype at gmail.com>
Date: Wed Mar 11 23:29:01 2020 -0300
Enhance \__kernel_quark_test_generate:NNNn
>---------------------------------------------------------------
1955297ea18733197d7ae974909b2f63505d3730
l3kernel/l3msg.dtx | 9 +++
l3kernel/l3quark.dtx | 203 +++++++++++++++++++++++++++++++++++++++++----------
2 files changed, 173 insertions(+), 39 deletions(-)
diff --git a/l3kernel/l3msg.dtx b/l3kernel/l3msg.dtx
index 68264ca6d..c244d06fa 100644
--- a/l3kernel/l3msg.dtx
+++ b/l3kernel/l3msg.dtx
@@ -1798,6 +1798,15 @@
\__kernel_msg_new:nnnn { kernel } { quote-in-shell }
{ Quotes~in~shell~command~'#1'. }
{ Shell~commands~cannot~contain~quotes~("). }
+\__kernel_msg_new:nnnn { kernel } { invalid-quark-function }
+ { Quark~test~function~'#1'~is~invalid. }
+ {
+ \c__msg_coding_error_text_tl
+ LaTeX~has~been~asked~to~create~quark~test~function~'#1'~
+ with~signature~'#2',~but~that~signature~is~not~valid.
+ }
+\__kernel_msg_new:nnn { kernel } { invalid-quark }
+ { Invalid~quark~variable~'#1'. }
\__kernel_msg_new:nnnn { kernel } { scanmark-already-defined }
{ Scan~mark~#1~already~defined. }
{
diff --git a/l3kernel/l3quark.dtx b/l3kernel/l3quark.dtx
index fe37c251c..1c6214475 100644
--- a/l3kernel/l3quark.dtx
+++ b/l3kernel/l3quark.dtx
@@ -464,60 +464,185 @@
% \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|
+% (as \cs{q_recursion_stop}) as the delimiter quark. |#4| is the name-space
+% to be used (for example |__quark|).
+%
+% There are four possible function types which this funciton can define,
+% and which is defined depends on the signature of the function being
+% defined:
+% \begin{description}
+% \item[\texttt{:n}:~] defines \cs{quark_if_recursion_tail_stop:n}
+% \item[\texttt{:nn}:~] defines \cs{quark_if_recursion_tail_stop_do:nn}
+% \item[\texttt{:N}:~] defines \cs{quark_if_recursion_tail_stop:N}
+% \item[\texttt{:Nn}:~] defines \cs{quark_if_recursion_tail_stop_do:Nn}
+% \end{description}
+% Any other signature causes an error, as does a function without signature.
+% \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
+ }
+\cs_new_protected:Npn \@@_test_generate_aux:nnNN #1 #2 #3 #4
+ {
+ \reverse_if:N \if_int_odd:w #3
+ \__kernel_msg_error:nnx { kernel } { missing-colon }
+ { \token_to_str:N #4 }
+ \exp_after:wN \use_none:nnnnn
+ \fi:
+ \use:n { \@@_test_generate_choose:nN {#2} #4 }
+ }
+\cs_new_protected:Npn \@@_test_generate_choose:nN #1 #2
+ {
+ \cs_if_exist_use:cTF { @@_test_generate_#1:NNNn } {#2}
+ {
+ \__kernel_msg_error:nnxx { kernel } { invalid-quark-function }
+ { \token_to_str:N #2 } {#1}
+ \use_none:nnn
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
% \begin{macro}{
-% \__kernel_quark_new_recursion_tail_stop:n,
-% \__kernel_quark_new_recursion_tail_stop_do:n,
+% \@@_test_generate_n:NNNn, \@@_test_generate_nn:NNNn,
+% \@@_test_generate_N:NNNn, \@@_test_generate_Nn:NNNn,
% }
+% These macros implement the four 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
+% 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 { }
+ }
+\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 }
+ }
+\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 { }
+ }
+\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 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{
+% \@@_test_generate_aux_do:nNNnnnn,
+% \@@_test_define_aux:NNNnnN
+% }
+% \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
+% here are analogous to \cs{@@_if_recursion_tail:w} and to
+% \cs[no-index]{use_(none|i)_delimit_by_q_recursion_stop:(|n)w}.
+%
+% The name is composed by the name-space and the name of the quarks.
+% Suppose \cs{__kernel_quark_test_generate:NNNn} was used with:
+% \begin{verbatim}
+% \__kernel_quark_test_generate:NNNn \__test_quark_tail:n
+% \q__test_tail \q__test_stop { __test }
+% \end{verbatim}
+% then the first auxiliary will be \cs[no-index]{__test_if_test_tail:w},
+% and the second one will be
+% \cs[no-index]{__test_use_none_delimit_by_q_test_stop:w}.
+%
+% Note that the actual quarks are \emph{not} defined here. They should
+% be defined separately using \cs{quark_new:N}.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_test_generate_aux_do:nNNnnnn #1 #2 #3 #4 #5
+ {
+ \exp_args:Ncc \@@_test_define_aux:NNNnnN
+ { #1 _if_ \@@_get_name:N #2 :w }
+ { #1 _use_ #4 _delimit_by_q_ \@@_get_name:N #3 : #5 w }
+ #2 #3
+ }
+\cs_new_protected:Npn \@@_test_define_aux:NNNnnN #1 #2 #3 #4 #5 #6 #7
+ {
+ \cs_gset:Npn #1 ##1 #3 ##2 ? ##3 ?! { ##1 ##2 }
+ \cs_gset:Npn #2 ##1 #6 #4 {#5}
+ #7 #1 #2 #3
+ }
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}{
-% \@@_new_recursion_tail_auxi:nnNNn,
-% \@@_new_recursion_tail_auxii:NNNNNN,
+% \@@_test_generate_define_tl:NNNNn,
+% \@@_test_generate_define_ifx:NNNNn
% }
-% Basically the same as above, but generic so that it is possible to
-% define \cs[no-index]{quark_if_recursion_tail...} functions on-the-fly,
-% for each module which needs them.
-%
-% \cs{__kernel_quark_new_recursion_tail_stop:n}|{ __mod }| defines the
-% top-level \cs[no-index]{__mod_quark_if_recursion_tail_stop:n}, and
-% the auxiliaries \cs[no-index]{__mod_quark_if_recursion_tail:w} and
-% \cs[no-index]{__mod_use_none_delimit_by_q_recursion_stop:w}.
-%
-% \cs{__kernel_quark_new_recursion_tail_stop_do:n}|{ __mod }| defines the
-% top-level \cs[no-index]{__mod_quark_if_recursion_tail_stop_do:nn}, and
-% the auxiliaries \cs[no-index]{__mod_quark_if_recursion_tail:w} and
-% \cs[no-index]{__mod_use_i_delimit_by_q_recursion_stop:nw}.
-%
-% In either case, the corresponding \cs[no-index]{q__mod_recursion_tail}
-% and \cs[no-index]{q__mod_recursion_stop} have to be manually defined.
+% Finally, these two macros define the main conditional function using
+% what's been set up before.
% \begin{macrocode}
-\cs_new_protected:Npn \__kernel_quark_new_recursion_tail_stop:n #1
+\cs_new_protected:Npn \@@_test_generate_define_tl:NNNNn #1 #2 #3 #4 #5
{
- \@@_new_recursion_tail_auxi:nnNNn {#1} { stop:n }
- \use_none_delimit_by_q_recursion_stop:w \use_none:n { }
+ \cs_new:Npn #4 ##1
+ {
+ \tl_if_empty:oTF
+ { #1 {} ##1 {} ?! #3 ??! }
+ {#2} {#5}
+ }
}
-\cs_new_protected:Npn \__kernel_quark_new_recursion_tail_stop_do:n #1
+\cs_new_protected:Npn \@@_test_generate_define_ifx:NNNNn #1 #2 #3 #4 #5
{
- \@@_new_recursion_tail_auxi:nnNNn {#1} { stop_do:nn }
- \use_i_delimit_by_q_recursion_stop:nw \use:n { \use_none:n }
+ \cs_new:Npx #4 ##1
+ {
+ \exp_not:N \if_meaning:w \exp_not:N #3 ##1
+ \exp_not:n { \exp_after:wN #2 }
+ \tl_if_empty:nF {#5}
+ { \exp_not:n { \else: \exp_after:wN #5 } }
+ \exp_not:N \fi:
+ }
}
-\cs_new_protected:Npn \@@_new_recursion_tail_auxi:nnNNn #1 #2 #3
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_get_name:N}
+% \begin{macro}{
+% \@@_get_name_aux:w,
+% \@@_remove_underscore:w, \@@_remove_underscore_end:w
+% }
+% \cs{@@_get_name:N} takes a quark and removes the leading |q| and
+% possibly |_|, so that \cs{@@_get_name:N}\cs{q__test_tail} expands
+% to |test_tail|.
+% \begin{macrocode}
+\cs_new:Npn \@@_get_name:N #1
+ { \exp_last_unbraced:Nf \@@_get_name_aux:w { \cs_to_str:N #1 } \s_@@ }
+\cs_new:Npn \@@_get_name_aux:w #1 #2 \s_@@
{
- \use:x
+ \str_if_eq:nnTF {#1} { q }
+ { \@@_remove_underscore:w #2 \s_@@ }
{
- \@@_new_recursion_tail_auxii:NNNNNNn
- \exp_not:c { #1_quark_if_recursion_tail_#2 }
- \exp_not:c { #1_quark_if_recursion_tail:w }
- \exp_not:c { q #1 _recursion_tail }
- \exp_not:c { q #1 _recursion_stop }
- \exp_not:c { #1_\cs_to_str:N #3 }
+ \__kernel_msg_expandable_error:nnf
+ { kernel } { invalid-quark } { \c_backslash_str #1 #2 }
}
}
-\cs_new_protected:Npn \@@_new_recursion_tail_auxii:NNNNNNn #1 #2 #3 #4 #5 #6 #7
+\cs_new:Npn \@@_remove_underscore:w #1 #2 \s_@@
{
- \cs_new:Npn #1 ##1
- { \tl_if_empty:oTF { #2 {} ##1 {} ?! #3 ??! } {#5} {#7} }
- \cs_gset:Npn #2 ##1 #3 ##2 ? ##3 ?! { ##1 ##2 }
- \use:e { \cs_gset:Npn \exp_not:N #5 ##1 #6 {##2} \exp_not:N #4 { #6{##1} } }
+ \str_if_eq:nnTF {#1} { _ }
+ { \@@_remove_underscore:w }
+ { \@@_remove_underscore_end:w #1 }
+ #2 \s_@@
}
+\cs_new:Npn \@@_remove_underscore_end:w #1 \s_@@ {#1}
% \end{macrocode}
% \end{macro}
% \end{macro}
More information about the latex3-commits
mailing list.