[latex3-commits] [git/LaTeX3-latex3-latex3] gh795: Copying xparse (expandable) commands (792c59afd)
PhelypeOleinik
phelype.oleinik at latex-project.org
Fri Jan 15 02:54:12 CET 2021
Repository : https://github.com/latex3/latex3
On branch : gh795
Link : https://github.com/latex3/latex3/commit/792c59afd11b5d0c4b402ae9ca591e8f735482ce
>---------------------------------------------------------------
commit 792c59afd11b5d0c4b402ae9ca591e8f735482ce
Author: PhelypeOleinik <phelype.oleinik at latex-project.org>
Date: Thu Jan 14 22:54:12 2021 -0300
Copying xparse (expandable) commands
part of #795... phew!
>---------------------------------------------------------------
792c59afd11b5d0c4b402ae9ca591e8f735482ce
l3packages/xparse/xparse.dtx | 208 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 208 insertions(+)
diff --git a/l3packages/xparse/xparse.dtx b/l3packages/xparse/xparse.dtx
index ec04c4ca0..3d316cd6a 100644
--- a/l3packages/xparse/xparse.dtx
+++ b/l3packages/xparse/xparse.dtx
@@ -4340,6 +4340,214 @@
% \end{macrocode}
% \end{macro}
%
+% \subsubsection{Expandable commands}
+%
+% \begin{macro}{\@@_expandable_cmd_set_eq:NN}
+% \begin{macro}{\@@_replace_cmd_name:N}
+% Copying an expandable command, on the other hand, is a \emph{lot}
+% more work. A non-expandable command uses \pkg{xparse}'s macros to
+% look ahead and grab the arguments to the command, but an expandable
+% command can't use much of that, since it all requires assignments
+% based on the command's signature, so an expandable command carries
+% its argument-grabbing code with itself, along with a bunch of
+% auxiliaries. An expandable code contains
+% \begin{itemize}
+% \item the top-level macro \cs[no-index]{\meta{name}}
+% \item the actual code in \cs[no-index]{\meta{name} code}
+% \item an auxiliary \cs[no-index]{\meta{name}}\verb*| |
+% \item possibly another auxiliary \cs[no-index]{\meta{name}}\verb*| |
+% \item possibly defaults to the optional arguments in
+% \cs[no-index]{\meta{name} defaults}
+% \item up to 9 auxiliaries \cs[no-index]{\meta{name} (arg \meta{num})}
+% \end{itemize}
+% all of which must be copied, and their \meta{name} replaced by
+% \meta{new name} in the new command.
+%
+% We start by defining shorthands, as before, and a function to quickly
+% replace a leading \meta{name} (possibly with a leading backslash)
+% by \meta{new name} in a \cs{string}ified control sequence.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_expandable_cmd_set_eq:NN #1 #2
+ {
+ \tl_set:Nx \l_@@_tmpa_tl { \cs_to_str:N #1 ~ }
+ \tl_set:Nx \l_@@_tmpb_tl { \cs_to_str:N #2 ~ }
+ \use:e
+ {
+ \cs_set:Npn \exp_not:N \@@_replace_cmd_name:w ##1 \l_@@_tmpb_tl
+ { \l_@@_tmpa_tl }
+ }
+% \end{macrocode}
+% Here is the hardest part: copy the top-level command and replace
+% every occurrence of \meta{name} by \meta{new name} inside it. The
+% argument |##1| here is \pkg{xparse}'s \cs{@@_start_expandable:nNNNNn}
+% and the command signature: these are just passed through. |##2| is
+% (possibly) the auxiliary \cs[no-index]{\meta{name}}\verb*| | or
+% just \cs[no-index]{\meta{name}}\verb*| |; \cs{@@_replace_cmd_name:N}
+% figures that out easily. |##3| is either |?| or
+% \cs[no-index]{\meta{name} defaults}.
+%
+% |##4| is the actual argument parsing code. It is a list of up to
+% nine \cs[no-index]{@@_expandable_grab_\meta{type}:w} \meta{parameters}.
+% We'll iterate over that list with \cs{@@_expandable_signature_copy:w}
+% which will take care of the copying.
+% \begin{macrocode}
+ \use:e
+ {
+ \cs_set_protected:Npn \exp_not:N \@@_tmp:w
+ ##1 \exp_not:c { \l_@@_tmpb_tl }
+ ##2 \exp_not:c { \l_@@_tmpb_tl code } ##3 ##4
+ }
+ {
+ \cs_set_nopar:Npx #1
+ {
+ \exp_not:n {##1} \exp_not:c { \l_@@_tmpa_tl }
+ \exp_not:c { \@@_replace_cmd_name:N ##2 }
+ \exp_not:c { \l_@@_tmpa_tl code }
+ \token_if_eq_charcode:NNTF ? ##3
+ {##3} { \exp_not:c { \l_@@_tmpa_tl defaults } }
+ {
+ \@@_expandable_signature_copy:w
+ ##4 \q_recursion_tail \q_recursion_stop
+ }
+ }
+ }
+ \exp_after:wN \@@_tmp:w #2
+% \end{macrocode}
+% After that is done, just copy the code of the command and the
+% auxiliaries. Not all are defined, so we check if they exist first.
+% \begin{macrocode}
+ \cs_set_eq:cc { \l_@@_tmpa_tl code } { \l_@@_tmpb_tl code }
+ \cs_set_eq:cc { \l_@@_tmpa_tl } { \l_@@_tmpb_tl }
+ \cs_if_exist:cT { \l_@@_tmpb_tl \c_space_tl }
+ {
+ \cs_set_eq:cc { \l_@@_tmpa_tl \c_space_tl }
+ { \l_@@_tmpb_tl \c_space_tl }
+ }
+ \cs_if_exist:cT { \l_@@_tmpb_tl defaults }
+ {
+ \cs_set_eq:cc { \l_@@_tmpa_tl defaults }
+ { \l_@@_tmpb_tl defaults }
+ }
+ \int_step_inline:nn { 9 }
+ {
+ \cs_if_exist:cT { \l_@@_tmpb_tl (arg~##1) }
+ {
+ \cs_set_eq:cc { \l_@@_tmpa_tl (arg~##1) }
+ { \l_@@_tmpb_tl (arg~##1) }
+ }
+ }
+ }
+% \end{macrocode}
+%
+% This auxiliary will replace the old command name with the new one.
+% It should be used inside a \cs{csname}\ldots\cs{endcsname}.
+% \begin{macrocode}
+\cs_new:Npn \@@_replace_cmd_name:N
+ { \exp_after:wN \@@_replace_cmd_name:w \token_to_str:N }
+\cs_new_eq:NN \@@_replace_cmd_name:w ?
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_expandable_signature_copy:w}
+% \begin{macro}{\@@_expandable_copy_type:w}
+% \begin{macro}{
+% \@@_expandable_signature_copy_D:w,
+% \@@_expandable_signature_copy_D_alt:w,
+% \@@_expandable_signature_copy_E:w,
+% \@@_expandable_signature_copy_m:w,
+% \@@_expandable_signature_copy_m_long:w,
+% \@@_expandable_signature_copy_R:w,
+% \@@_expandable_signature_copy_R_alt:w,
+% \@@_expandable_signature_copy_t:w,
+% \@@_expandable_signature_copy_u:w,
+% }
+% Now we'll loop over the list of argument parsers of the expandable
+% command, and rewrite them to use the \meta{new name}. This command
+% will take the next token, which should be an
+% \cs[no-index]{@@_expandable_grab_\meta{type}:w}, then
+% \cs{@@_expandable_copy_type:w} will figure out what the \meta{type}
+% is, and execute the proper
+% \cs[no-index]{@@_expandable_signature_copy_\meta{type}:w}. Each of
+% these will take the \meta{parameters} relevant to the type, and
+% rewrite them accordingly for the new command, leaving them unexpanded.
+% \begin{macrocode}
+\cs_new:Npn \@@_expandable_signature_copy:w #1
+ {
+ \quark_if_recursion_tail_stop:N #1
+ \exp_after:wN \@@_expandable_copy_type:w \token_to_str:N #1 \s_@@
+ }
+\use:e
+ {
+ \cs_new:Npn \exp_not:N \@@_expandable_copy_type:w #1
+ \tl_to_str:n { grab_ } #2 \c_colon_str #3 \s_@@
+ { \exp_not:N \use:c { @@_expandable_signature_copy_#2:w } }
+ }
+\cs_new:Npn \@@_expandable_signature_copy_D:w #1 #2 #3
+ {
+ \exp_not:N \@@_expandable_grab_D:w
+ \exp_not:c { \@@_replace_cmd_name:N #1 }
+ \exp_not:N #2 \exp_not:N #3
+ \@@_expandable_signature_copy:w
+ }
+\cs_new:Npn \@@_expandable_signature_copy_D_alt:w #1 #2
+ {
+ \exp_not:N \@@_expandable_grab_D_alt:w
+ \exp_not:c { \@@_replace_cmd_name:N #1 }
+ \exp_not:N #2
+ \@@_expandable_signature_copy:w
+ }
+\cs_new:Npn \@@_expandable_signature_copy_E:w #1 #2
+ {
+ \exp_not:N \@@_expandable_grab_E:w
+ \exp_not:n { {#1} {#2} }
+ \@@_expandable_signature_copy:w
+ }
+\cs_new:Npn \@@_expandable_signature_copy_m:w
+ {
+ \exp_not:N \@@_expandable_grab_m:w
+ \@@_expandable_signature_copy:w
+ }
+\cs_new:Npn \@@_expandable_signature_copy_m_long:w
+ {
+ \exp_not:N \@@_expandable_grab_m_long:w
+ \@@_expandable_signature_copy:w
+ }
+\cs_new:Npn \@@_expandable_signature_copy_R:w #1 #2 #3
+ {
+ \exp_not:N \@@_expandable_grab_R:w
+ \exp_not:c { \@@_replace_cmd_name:N #1 }
+ \exp_not:N #2 \exp_not:N #3
+ \@@_expandable_signature_copy:w
+ }
+\cs_new:Npn \@@_expandable_signature_copy_R_alt:w #1 #2
+ {
+ \exp_not:N \@@_expandable_grab_R_alt:w
+ \exp_not:c { \@@_replace_cmd_name:N #1 }
+ \exp_not:N #2
+ \@@_expandable_signature_copy:w
+ }
+\cs_new:Npn \@@_expandable_signature_copy_t:w #1 #2
+ {
+ \exp_not:N \@@_expandable_grab_t:w
+ \exp_not:N #1 \exp_not:N #2
+ \@@_expandable_signature_copy:w
+ }
+%</core>
+%<*package>
+\cs_new:Npn \@@_expandable_signature_copy_u:w #1
+ {
+ \exp_not:N \@@_expandable_grab_u:w
+ \exp_not:N #1
+ \@@_expandable_signature_copy:w
+ }
+%</package>
+%<*core>
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
% \subsection{Argument processors}
%
% \begin{macro}{\@@_bool_reverse:N}
More information about the latex3-commits
mailing list.