[latex3-commits] [l3svn] r5867 - Revamp l3check. Only parts of l3basics and l3expan so far
noreply at latex-project.org
noreply at latex-project.org
Wed Aug 19 04:39:15 CEST 2015
Author: bruno
Date: 2015-08-19 04:39:15 +0200 (Wed, 19 Aug 2015)
New Revision: 5867
Modified:
trunk/l3trial/l3check/l3check.dtx
Log:
Revamp l3check. Only parts of l3basics and l3expan so far
This new l3check actually finds some bugs in l3regex, for
instance, since it detects functions which are _nopar but
have arguments. I'll fix these l3regex bugs later. Not too
many false positives.
Modified: trunk/l3trial/l3check/l3check.dtx
===================================================================
--- trunk/l3trial/l3check/l3check.dtx 2015-08-18 18:47:32 UTC (rev 5866)
+++ trunk/l3trial/l3check/l3check.dtx 2015-08-19 02:39:15 UTC (rev 5867)
@@ -1,6 +1,6 @@
% \iffalse
%
-%% File l3check.dtx (C) Copyright 2012,2014 The LaTeX3 Project
+%% File l3check.dtx (C) Copyright 2012,2014,2015 The 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
@@ -71,19 +71,19 @@
%
% \section{Checks made in \texttt{l3kernel}}
%
-% The \pkg{l3check} package redefines some of the \LaTeX3 internals to
-% look for potential errors in the code, such as calling a token list
-% function with a sequence argument. Those checks come with a
+% The \pkg{l3check} package redefines some of the \pkg{expl3} internals to
+% look for potential errors in the code, such as calling a sequence function
+% with a token list argument. Those checks come with a
% performance penalty and are thus disabled by default; they are
% activated using \cs{check_on:n}.
%
-% The list of checks that are performed is as follows:
+% The (incomplete) list of checks that are performed is as follows:
% \begin{itemize}
% \item \pkg{l3expan} |N|-type and |V|-type arguments must be single
% tokens; |o| and |f|-type expansion should not be called on
% arguments that do not expand.
-% \item \pkg{l3tl} when a \enquote{tl~var} argument is expected, the
-% name is checked to end with |_tl|.
+% \item \pkg{l3tl} when a \enquote{tl~var} argument is expected, it
+% is checked to be a non-long parameterless macro.
% \end{itemize}
%
% \section{Turning checks on and off}
@@ -95,8 +95,10 @@
% Turns checking on globally for functions in each of the
% \meta{modules}, given as a comma list. This comes with a large
% performance penalty, thus should only be used for testing purposes.
-% The special module \texttt{l3kernel} is recognized and turns on
-% checking for all modules in the \pkg{l3kernel} bundle.
+% At present, the following modules are supported: |exp|, |tl|. The
+% special module \texttt{l3kernel} is recognized and turns on
+% checking for all modules in the \pkg{l3kernel} bundle. Checks are
+% turned on locally.
% \end{function}
%
% \begin{function}{\check_off:n}
@@ -105,10 +107,8 @@
% \end{syntax}
% Turns checking off globally for functions in each of the
% \meta{modules}, given as a comma list. Note that this function
-% keeps the performance penalty of \cs{check_on:n}, and simply
-% silences error messages. The special module \texttt{l3kernel} is
-% recognized and turns off checking for all modules in the
-% \pkg{l3kernel} bundle.
+% simply silences error messages, hence the performance penalty of
+% \cs{check_on:n} remains. Checks are turned off locally.
% \end{function}
%
% \section{Defining checks}
@@ -118,43 +118,106 @@
% \cs{check_new:nn} \Arg{module} \Arg{code}
% \end{syntax}
% Defines the action of \cs{check_on:n} \Arg{module} to be the
-% \meta{code}. Note that |#| does not need to be duplicated within
+% \meta{code}. Note that |#| does not need to be doubled within
% the \meta{code}.
% \end{function}
%
-% \section{Internal commands}
-%
-% \begin{function}[EXP, pTF]{\__check_if_on:n}
+% \begin{function}{\check_patch:Nn, \check_patch:cn}
% \begin{syntax}
-% \cs{__check_if_on:nTF} \Arg{module} \Arg{true code} \Arg{false code}
-% \cs{__check_if_on_p:n} \Arg{module}
+% \cs{check_patch:Nn} \meta{function} \Arg{replacement text}
% \end{syntax}
-% Returns \texttt{true} if the \meta{module}'s checks are currently
-% on, \texttt{false} otherwise, including if the \meta{module} does
-% not exist or has no checks. This is meant to be used in the
-% \meta{module}'s checking code (defined with \cs{check_new:nn}), to
-% determine whether to raise errors or not.
+% Redefine the \meta{function}. The \meta{function} will take
+% parameters according to its signature, which must consist
+% exclusively of |N| or |n|, and expand to the \meta{replacement
+% text}, followed by a copy of the original function. For instance,
+% \begin{quote}
+% \cs{check_patch:Nn} \cs{tl_set:Nn} |{| \cs{check_defined:N} |#1| |}|
+% \end{quote}
+% redefines \cs{tl_set:Nn} to check that its first argument exists
+% before performing its initial duty. Since the letter in the
+% signature of \cs{tl_set:Nn} is |N|, the code automatically checks
+% that indeed the first argument given is a single token. When
+% patching an expandable \meta{function}, the \meta{replacement text}
+% must be expandable and expand to nothing, as it otherwise
+% interferes with the expandable \meta{function}.
% \end{function}
%
-% \begin{function}{\__check_patch_protected:Npnn}
-% \begin{function}{\__check_patch:Npnn}
+% \begin{function}{\check_patch:Npnn, \check_patch:cpnn}
% \begin{syntax}
-% \cs{__check_patch_protected:Npnn} \meta{function} \meta{parameters_1} \Arg{parameters_2} \Arg{replacement text}
+% \cs{check_patch:Npnn} \meta{function} \meta{parameters_1} \Arg{parameters_2} \Arg{replacement text}
% \end{syntax}
% Redefine the \meta{function}. The \meta{function} will take the
% \meta{parameters} and expand to the \meta{replacement text},
-% followed by a copy of the original function acting on the
-% \meta{parameters_2}, which should be identical to the
-% \meta{parameters_1}, but wrapped within braces. For instance,
+% followed by a copy of the original function followed by the
+% \meta{parameters_2}, which should normally be identical to the
+% \meta{parameters_1}, but with parameters |#1|, |#2|, \ldots{}
+% wrapped in braces (except for single-token parameters |N| and |V|).
+% For instance,
% \begin{quote}
-% \cs{__check_patch_protected:Npnn} \cs{tl_set:Nn} |#1| |{ #1 }| \\
-% |{| \cs{__cs_chk_exist:N} |#1| |}|
+% \cs{check_patch:Npnn} \cs{tl_set:Nn} |#1| |#2| |{ #1 {#2} }| \\
+% |{| \\
+% \cs{check_is_N:n} |{| |#1| |}| \\
+% \cs{check_defined:N} |#1| \\
+% |}|
% \end{quote}
-% redefines \cs{tl_set:Nn} to check that its first argument exists
-% before performing its initial duty.
+% redefines \cs{tl_set:Nn} to check that its first argument is a
+% single token and that it exists, before performing its initial
+% duty. Contrarily to \cs{check_patch:Nn}, the check that |#1| is a
+% single token must be put here by hand. When patching an expandable
+% \meta{function}, the \meta{replacement text} must be expandable and
+% expand to nothing, as it otherwise interferes with the expandable
+% \meta{function}.
% \end{function}
+%
+% \section{Helpers for defining checks}
+%
+% \begin{function}{\check_is_defined:N}
+% ^^A todo: complete this section
% \end{function}
%
+% \section{Internal functions}
+%
+% \begin{function}[EXP, pTF]{\@@_if_on:n}
+% \begin{syntax}
+% \cs{@@_if_on:nTF} \Arg{module} \Arg{true code} \Arg{false code}
+% \cs{@@_if_on_p:n} \Arg{module}
+% \end{syntax}
+% Returns \texttt{true} if the \meta{module}'s checks are currently
+% on, \texttt{false} otherwise, including if the \meta{module} does
+% not exist or has no checks. This is used by \cs{check_patch:Nn}
+% and other functions in the \meta{module}'s checking code (defined
+% with \cs{check_new:nn}), to determine whether to raise errors or
+% not.
+% \end{function}
+%
+% ^^A todo: add more errors to \cs{@@_split_name:Nnnn}.
+% \begin{macro}[int, EXP]{\@@_split_name:Nnnn}
+% \begin{syntax}
+% \cs{@@_split_name:Nnnn} \meta{control sequence}
+% \Arg{code for function}
+% \Arg{code for variable}
+% \Arg{code for other}
+% \end{syntax}
+% Expands to one of the three \meta{code}, followed by brace groups
+% containing different informations depending on the case. There are
+% many cases, checked in the following order until one matches.
+% \begin{itemize}
+% \item If the name contains a colon and is not |\:|, it is an
+% \pkg{expl3} function, and the \meta{signature} is what follows
+% the last colon. Then \meta{code for function} \Arg{signature}
+% is left in the input stream.
+% \item If the name contains an underscore, and is not |\_|, it is
+% an \pkg{expl3} variable. Its first character must be a letter
+% among |clgqs|, and the next |_|. If the first character is |q|
+% or |s| (quark or scan mark), the \meta{type} is empty.
+% Otherwise the \meta{type} is the part after the last |_|. Then
+% \meta{code for variable} \Arg{scope} \Arg{type} is left in the
+% input stream.
+% \item Otherwise the control sequence is not known to \pkg{expl3},
+% and \meta{code for other} is left in the input stream.
+% \end{itemize}
+% \end{macro}
+%
% \end{documentation}
%
% \begin{implementation}
@@ -178,681 +241,1015 @@
%
% \subsection{Infrastructure}
%
-% ^^A todo: also check that modules exist in \cs{check_on/off:n}?
+% \subsubsection{Variables, variants and copied primitives}
%
-% \begin{variable}{\l_@@_module_tl}
-% Holds the name of the module for which we are currently defining the
-% checking code, both within the definition of \cs{check_new:nn}, and
-% when its second argument is used within a \cs{check_on:n} call.
+% \begin{macro}[aux]{\@@_tmp:w}
+% Used for defining other commands.
% \begin{macrocode}
+\cs_new_eq:NN \@@_tmp:w ?
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[aux]{\@@_exp_args:Nc}
+% Copy \cs{exp_args:Nc} with no check, to use in situations where the
+% check should be omitted.
+% \begin{macrocode}
+\cs_new_eq:NN \@@_exp_args:Nc \exp_args:Nc
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\tl_if_in:ffTF, \str_case:fnF, \tl_if_empty:fTF}
+% Just a variant we need.
+% \begin{macrocode}
+\cs_generate_variant:Nn \tl_if_in:nnTF { ff }
+\cs_generate_variant:Nn \str_case:nnF { f }
+\cs_generate_variant:Nn \tl_if_empty:nTF { f }
+\cs_generate_variant:Nn \tl_if_empty:nT { f }
+\cs_generate_variant:Nn \tl_if_empty:nF { f }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int, EXP]{\@@_exp:w, \@@_exp_stop:}
+% Trigger and stop one-step expansion.
+% \begin{macrocode}
+\cs_new_eq:NN \@@_exp:w \tex_romannumeral:D
+\cs_new_eq:NN \@@_exp_stop: \c_zero
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{variable}[int]{\l_@@_module_tl}
+% Holds the name of the module for which we are currently defining
+% the checking code. This is used by \cs{check_patch:Nn} to make
+% commands aware of what module the patch belongs to, so that
+% \cs{check_off:n} will correctly turn that check off.
+% \begin{macrocode}
\tl_new:N \l_@@_module_tl
% \end{macrocode}
% \end{variable}
%
-% \subsubsection{User commands}
+% \begin{variable}[int]{\l_@@_parm_int, \l_@@_parm_tl, \l_@@_parm_braced_tl}
+% \begin{variable}[int]{\l_@@_extra_code_tl}
+% Used in \cs{check_patch:Nn} to construct the parameter text for use
+% in \cs{check_patch:Npnn}. The \cs{l_@@_extra_code_tl} token list
+% contains code that checks that |N|-type arguments really are single
+% tokens.
+% \begin{macrocode}
+\int_new:N \l_@@_parm_int
+\tl_new:N \l_@@_parm_tl
+\tl_new:N \l_@@_parm_braced_tl
+\tl_new:N \l_@@_extra_code_tl
+% \end{macrocode}
+% \end{variable}
+% \end{variable}
%
-% \begin{macro}{\check_new:nn}
-% This function does not accept a comma-delimited list of modules,
-% only single modules, so we check and refuse that. If the module
-% |#1| already has a checking code defined, raise an error, but
-% replace the code by the new code. Store the \meta{code} |#2| in a
-% control sequence.
+% \begin{macro}{\@@_error:nn, \@@_error:nnn}
+% \begin{macro}[EXP]{\@@_error_exp:nn, \@@_error_exp:nnn}
+% Wrappers around errors, expandable or not.
% \begin{macrocode}
-\cs_new_protected:Npn \check_new:nn #1#2
+\cs_new_nopar:Npn \@@_error:nn
+ { \msg_error:nnn { check } }
+\cs_new_nopar:Npn \@@_error:nnn
+ { \msg_error:nnnn { check } }
+\cs_new_nopar:Npn \@@_error_exp:nn
+ { \msg_expandable_error:nnn { check } }
+\cs_new_nopar:Npn \@@_error_exp:nnn
+ { \msg_expandable_error:nnnn { check } }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_warning:nn, \@@_warning:nnn}
+% \begin{macro}[EXP]{\@@_warning_exp:nn, \@@_warning_exp:nnn}
+% A wrapper around warnings, expandable or not.
+% \begin{macrocode}
+\cs_new_nopar:Npn \@@_warning:nn
+ { \msg_warning:nnn { check } }
+\cs_new_nopar:Npn \@@_warning:nnn
+ { \msg_warning:nnnn { check } }
+\cs_new_nopar:Npn \@@_warning_exp:nn
{
- \tl_set:Nx \l_@@_module_tl { \tl_to_str:n {#1} }
- \tl_if_in:NnTF \l_@@_module_tl { , }
+ \cs_if_exist_use:NF
+ \msg_expandable_warning:nnn
+ \msg_expandable_error:nnn
+ { check }
+ }
+\cs_new_nopar:Npn \@@_warning_exp:nnn
+ {
+ \cs_if_exist_use:NF
+ \msg_expandable_warning:nnnn
+ \msg_expandable_error:nnnn
+ { check }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% ^^A todo: deal with active chars!
+%
+% \begin{macro}[int]{\@@_split_name:Nnnn}
+% \begin{macro}[int, EXP]{\@@_split_name_exp:Nnnn}
+% \begin{macro}[aux, EXP]
+% {
+% \@@_split_name_aux:w , \@@_split_name_colon:w ,
+% \@@_split_name_underscore:w , \@@_split_name_space:w ,
+% \@@_split_name_func:w , \@@_split_name_func_end:w ,
+% \@@_split_name_var:nNw , \@@_split_name_var_end:nNw ,
+% }
+% Two variants are provided so that the correct type of errors
+% (expandable or not) is used. Expands to |#2| \Arg{signature} if
+% the name contains a colon and is not |\:|. Expands to |#3|
+% \Arg{scope} \Arg{type} if the name contains an underscore and is
+% not |\_|. Expands to |#4| otherwise.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_split_name:Nnnn #1
+ {
+ \exp_after:wN \exp_after:wN
+ \exp_after:wN \@@_split_name_aux:w
+ \cs_to_str:N #1 \q_stop
+ \@@_warning:nnn
+ \@@_error:nnn
+ }
+\cs_new:Npn \@@_split_name_exp:Nnnn #1
+ {
+ \exp_after:wN \exp_after:wN
+ \exp_after:wN \@@_split_name_aux:w
+ \cs_to_str:N #1 \q_stop
+ \@@_warning_exp:nnn
+ \@@_error_exp:nnn
+ }
+\cs_gset:Npn \@@_tmp:w #1#2
+ {
+ \cs_new:Npn \@@_split_name_aux:w ##1 \q_stop ##2 ##3
{
- \__msg_kernel_error:nnxx { check } { multiple-modules }
- { \token_to_str:N \check_new:nn } { \l_@@_module_tl }
- }
- {
- \cs_if_exist:cT { @@_module_ \l_@@_module_tl : }
+ \tl_if_single:nTF {##1}
+ { \use_iii:nnn }
{
- \__msg_kernel_error:nnx { check } { module-exists }
- { \l_@@_module_tl }
- \cs_undefine:c { @@_module_ \l_@@_module_tl : }
+ \tl_if_empty:oTF { \@@_split_name_colon:w ##1 #1 }
+ {
+ \tl_if_empty:oTF { \@@_split_name_underscore:w ##1 #2 }
+ { \use_iii:nnn }
+ {
+ \tl_if_empty:oF { \@@_split_name_space:w ##1 ~ }
+ { ##2 { bad-var-name } {##1} { } }
+ \tl_if_head_eq_charcode:fNF
+ { \str_tail:n {##1} } #2
+ { ##2 { bad-var-name } {##1} { } }
+ \str_case:fnF { \str_head:n {##1} }
+ { l { } g { } c { } q { } s { } }
+ { ##2 { bad-var-name } {##1} { } }
+ \@@_split_name_var:Nw { } ##1
+ \q_mark \@@_split_name_var:Nw #2
+ \q_mark \@@_split_name_var_end:Nw \q_stop
+ }
+ }
+ {
+ \tl_if_empty:oF { \@@_split_name_space:w ##1 ~ }
+ { ##2 { bad-func-name } {##1} { } }
+ \@@_split_name_func:w \q_mark ##1
+ \q_mark \@@_split_name_func:w #1
+ \q_mark \@@_split_name_func_end:w \q_stop
+ }
}
- \cs_new_protected_nopar:cpx { @@_module_ \l_@@_module_tl : }
- { \exp_not:n {#2} }
}
+ \cs_new:Npn \@@_split_name_colon:w ##1 #1 { }
+ \cs_new:Npn \@@_split_name_underscore:w ##1 #2 { }
+ \cs_new:Npn \@@_split_name_space:w ##1 ~ { }
+ \cs_new:Npn \@@_split_name_func:w ##1 \q_mark ##2 #1 ##3 \q_mark ##4
+ { ##4 ##2 \q_mark ##3 \q_mark ##4 }
+ \cs_new:Npn \@@_split_name_func_end:w ##1 \q_mark ##2 \q_stop ##3##4##5
+ { ##3 {##1} }
+ \cs_new:Npn \@@_split_name_var:Nw ##1##2 #2 ##3 #2 ##4 \q_mark ##5
+ { ##5 ##1 ##3 #2 ##4 \q_mark ##5 }
+ \cs_new:Npn \@@_split_name_var_end:Nw ##1##2 #2 ##3 \q_stop ##4##5##6
+ { ##5 {##1} {##2} }
}
+\exp_after:wN \@@_tmp:w \tl_to_str:n { : _ }
% \end{macrocode}
% \end{macro}
+% \end{macro}
%
-% \begin{macro}[EXP, pTF]{\@@_if_on:n}
+% \begin{macro}[int, EXP, pTF]{\@@_if_tl_macro:N}
+% Test if the variable is a non-long, non-protected macro with no argument.
+% \begin{macrocode}
+\prg_new_conditional:Npnn \@@_if_tl_macro:N #1 { p , T , F , TF }
+ {
+ \tl_if_empty:fTF
+ {
+ \token_get_prefix_spec:N #1
+ \token_get_arg_spec:N #1
+ }
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Turning on/off checks}
+%
+% \begin{macro}[int, EXP, pTF]{\@@_if_on:n}
% This test is to be used within the second argument of
% \cs{check_new:nn}. It is for instance inserted by
-% \cs{@@_patch:Npnn}. It would be cleaner to use
+% \cs{check_patch:Npnn}. It would be cleaner to use
% \cs{cs_if_exist_use:cF}, but this function uses expansion, which
% leads to an infinite recursion when \pkg{l3expan} functions are
% checking and call this test.
% \begin{macrocode}
\prg_new_conditional:Npnn \@@_if_on:n #1 { p , T , F , TF }
{
- \exp_after:wN \if_meaning:w
- \cs:w @@_if_module_#1_on_return: \cs_end:
- \scan_stop:
+ \exp_after:wN \if_meaning:w \cs:w @@_return_#1: \cs_end: \scan_stop:
\prg_return_false:
\else:
- \cs:w @@_if_module_#1_on_return: \cs_end:
+ \cs:w @@_return_#1: \cs_end:
\fi:
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[int]{\check_on:n}
-% The argument is turned to a string (paranoia), then loop over
-% \meta{modules} in the argument. If the \texttt{return} function for
-% that \meta{module} is already defined, the checking code was loaded
-% already, so we simply set it to \texttt{true}. Otherwise, load the
-% checking code if it exists, and define the \texttt{return} function.
-% Note that \cs{l_@@_module_tl} holds the name of the \meta{module}
-% whose code is loaded. This allow \cs{@@_patch:Npnn} commands
-% appearing in that checking code to insert the correct
-% \enquote{\texttt{if_on}} tests.
+% \begin{macro}{\check_on:n, \check_off:n}
+% The argument is turned to a string (paranoia), then we loop over
+% \meta{modules} in the argument. If
+% |\__check_module_|\meta{module}|:N| is defined, use it with
+% \cs{prg_return_true:}|/false:| as its argument, otherwise it is an
+% error. This function is initially defined to patch commands of the
+% given \meta{module} with the appropriate checking code and to
+% redefine itself to do much less. In subsequent calls, it just sets
+% |\__check_return_|\meta{module}|:| equal to its argument
+% \cs{prg_return_true:}|/false:|.
% \begin{macrocode}
\cs_new_protected:Npn \check_on:n #1
{
- \exp_args:No \clist_map_variable:nNn
- { \tl_to_str:n {#1} }
- \l_@@_module_tl
+ \exp_args:No \clist_map_inline:nn { \tl_to_str:n {#1} }
{
- \cs_if_exist:cTF
- { @@_if_module_ \l_@@_module_tl _on_return: }
- {
- \cs_gset_eq:cN
- { @@_if_module_ \l_@@_module_tl _on_return: }
- \prg_return_true:
- }
- {
- \cs_if_exist:cT { @@_module_ \l_@@_module_tl : }
- {
- \cs_new_eq:cN
- { @@_if_module_ \l_@@_module_tl _on_return: }
- \prg_return_true:
- \use:c { @@_module_ \l_@@_module_tl : }
- }
- }
+ \cs_if_exist_use:cTF { @@_module_##1 :N }
+ { \prg_return_true: }
+ { \msg_error:nnn { check } { module-unknown } {##1} }
}
}
+\cs_new_protected:Npn \check_off:n #1
+ {
+ \exp_args:No \clist_map_inline:nn { \tl_to_str:n {#1} }
+ {
+ \cs_if_exist_use:cTF { @@_module_##1 :N }
+ { \prg_return_false: }
+ { \msg_error:nnn { check } { module-unknown } {##1} }
+ }
+ }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[int]{\check_off:n}
-% For each \meta{module} in the argument, if the \texttt{return}
-% function for that \meta{module} is defined, set it to
-% \texttt{false}.
+% \begin{macro}{\check_new:nn}
+% \begin{macro}[int]{\@@_new:nn, \@@_module_first_use:n}
+% This function does not accept a comma-delimited list of modules,
+% only single modules, so we check and refuse that. If the module
+% |#1| already has a checking code defined, raise an error and stop.
+% Store the \meta{code} |#2| in a control sequence (using an
+% \texttt{x}-expanding assignment and \cs{exp_not:n} to avoid issues
+% with |#|), with some code before and after it. In its original
+% definition given here, |\__check_module_|\meta{module}|:N| will do
+% nothing if its argument is \cs{prg_return_false:} because turning
+% off checking that has never been turne on is a no-op. When given
+% \cs{prg_return_true:} for the first time, this function is
+% redefined by the auxiliary \cs{@@_module_first_use:n} to do very
+% little (simply set the \texttt{return} function). The same
+% auxiliary defines the \texttt{return} function globally to
+% \texttt{false} so that there is no checking outside the current
+% group, but locally to \texttt{true} to have checking in the current
+% group. Finally, \cs{l_@@_module_tl} is defined so that it can be
+% used in the patch code, such as for \cs{check_patch:Nn}.
% \begin{macrocode}
-\cs_new_protected:Npn \check_off:n #1
+\cs_new_protected:Npn \check_new:nn #1
+ { \exp_args:No \@@_new:nn { \tl_to_str:n {#1} } }
+\cs_new_protected:Npn \@@_new:nn #1#2
{
- \exp_args:No \clist_map_inline:nn
- { \tl_to_str:n {#1} }
+ \tl_if_in:nnTF {#1} { , }
{
- \cs_if_exist:cT { @@_if_module_##1_on_return: }
+ \msg_error:nnxx { check } { multiple-modules }
+ { \token_to_str:N \check_new:nn } {#1}
+ }
+ {
+ \cs_if_exist:cTF { @@_module_#1:N }
+ { \msg_error:nnn { check } { module-exists } {#1} }
{
- \cs_gset_eq:cN { @@_if_module_##1_on_return: }
- \prg_return_false:
+ \cs_new_protected:cpx { @@_module_#1:N } ##1
+ {
+ \exp_not:N \token_if_eq_meaning:NNF
+ \exp_not:N \prg_return_false:
+ ##1
+ {
+ \exp_not:N \@@_module_first_use:n {#1}
+ \exp_not:n {#2}
+ }
+ }
}
}
}
+\cs_new_protected:Npn \@@_module_first_use:n #1
+ {
+ \cs_gset_protected_nopar:cpx { @@_module_#1:N }
+ { \exp_not:N \cs_set_eq:NN \exp_not:c { @@_return_#1: } }
+ \cs_new_eq:cN { @@_return_#1: } \prg_return_false:
+ \cs_set_eq:cN { @@_return_#1: } \prg_return_true:
+ \tl_set:Nn \l_@@_module_tl {#1}
+ }
% \end{macrocode}
% \end{macro}
+% \end{macro}
%
-% \subsubsection{Patching commands, errors and warnings}
+% ^^A todo: document, keep list up to date.
+% \begin{macro}[int]{\@@_module_l3kernel:N}
+% A special case that cannot be covered by other means.
+% \begin{macrocode}
+\cs_new_protected:cpn { @@_module_l3kernel:N } #1
+ {
+ \clist_map_inline:Nn \c_@@_kernel_modules_clist
+ { \use:c { @@_module_##1:N } #1 }
+ }
+\clist_const:Nn \c_@@_kernel_modules_clist { cs , expan } % , tl , seq }
+% \end{macrocode}
+% \end{macro}
%
-% \begin{macro}[int]{\@@_patch_protected:Npnn, \@@_patch:Npnn}
-% \begin{macro}[aux]{\@@_patch_aux:NnNNnnn}
+% \subsubsection{Patching commands}
+%
+% \begin{macro}[int]{\check_patch:Npnn, \check_patch:cpnn}
+% \begin{macro}[aux]{\@@_patch:NnNnnn, \@@_patch:NoNnnn}
+% \begin{macro}[aux]{\@@_patch_exp:NnNnnn, \@@_patch_exp:NoNnnn}
% The current code of |#1| is copied into a private control sequence,
-% whose name we build and pass to the auxiliary.
+% whose name we build and pass to the auxiliary. Distinguish the
+% case of protected and of expandable commands, by looking for
+% |protected| in the macro's prefix spec. This distinction is used
+% to redefine |#1| to be a protected or an expandable macro, but also
+% to make sure that the redefinition of expandable macros does not
+% alter their expansion properties. Namely, it is important for some
+% macros that |o|-expanding them twice fully expands them, so the
+% redefined macro uses \cs{@@_exp:w} and \cs{@@_exp_stop:} to make
+% sure that its second expansion is the same as the second expansion
+% of the original macro.
+%
+% We use \cs{@@_exp_args:Nc}, a copy of \cs{exp_args:Nc}, because we
+% are building a previously not-defined control sequence.
% \begin{macrocode}
-\cs_new_protected:Npn \@@_patch_protected:Npnn #1#2#
+\cs_new_protected:Npn \check_patch:Npnn #1#2#
{
- \exp_args:Nco \@@_patch_aux:NnNNnnn
- { @@_patched_ \cs_to_str:N #1 }
- { \l_@@_module_tl }
- \cs_gset_protected:Npn
- #1 {#2}
+ \token_if_macro:NTF #1
+ {
+ \tl_if_in:ffTF
+ { \token_get_prefix_spec:N #1 }
+ { \tl_to_str:n { protected } }
+ { \@@_exp_args:Nc \@@_patch:NoNnnn }
+ { \@@_exp_args:Nc \@@_patch_exp:NoNnnn }
+ { @@_patched_ \cs_to_str:N #1 }
+ { \l_@@_module_tl }
+ #1
+ {#2}
+ }
+ { \msg_error:nnnnnn { check } { patch-non-macro } {#1} {#2} }
}
-\cs_new:Npn \@@_patch:Npnn #1#2#
+\cs_generate_variant:Nn \check_patch:Npnn { c }
+\cs_new_protected:Npn \@@_patch:NnNnnn #1#2#3#4#5#6
{
- \exp_args:Nco \@@_patch_aux:NnNNnnn
- { @@_patched_ \cs_to_str:N #1 }
- { \l_@@_module_tl }
- \cs_gset:Npn
- #1 {#2}
+ \cs_new_eq:NN #1 #3
+ \cs_gset_protected:Npn #3 #4
+ {
+ \@@_if_on:nT {#2} { \if_false: { \fi: #6 \if_false: } \fi: }
+ #1 #5
+ }
}
-\cs_new:Npn \@@_patch_aux:NnNNnnn #1#2#3#4#5#6#7
+\cs_generate_variant:Nn \@@_patch:NnNnnn { No }
+\cs_new_protected:Npn \@@_patch_exp:NnNnnn #1#2#3#4#5#6
{
- \cs_new_eq:NN #1 #4
- #3 #4 #5
+ \cs_new_eq:NN #1 #3
+ \cs_gset:Npn #3 #4
{
- \@@_if_on:nT {#2} { \if_false: { \fi: #7 \if_false: } \fi: }
- #1 #6
+ \@@_exp:w
+ \@@_if_on:nT {#2} { \if_false: { \fi: #6 \if_false: } \fi: }
+ \exp_after:wN \exp_after:wN \exp_after:wN \@@_exp_stop:
+ #1 #5
}
}
+\cs_generate_variant:Nn \@@_patch_exp:NnNnnn { No }
% \end{macrocode}
% \end{macro}
% \end{macro}
-%
-% \begin{macro}{\@@_error:nn, \@@_error:nnn}
-% \begin{macro}[EXP]{\@@_expandable_error:nn, \@@_expandable_error:nnn}
-% Wrappers around errors, expandable or not.
-% \begin{macrocode}
-\cs_new_nopar:Npn \@@_error:nn
- { \__msg_kernel_error:nnn { check } }
-\cs_new_nopar:Npn \@@_error:nnn
- { \__msg_kernel_error:nnnn { check } }
-\cs_new_nopar:Npn \@@_expandable_error:nn
- { \__msg_kernel_expandable_error:nnn { check } }
-\cs_new_nopar:Npn \@@_expandable_error:nnn
- { \__msg_kernel_expandable_error:nnnn { check } }
-% \end{macrocode}
% \end{macro}
-% \end{macro}
%
-% \begin{macro}{\@@_warning:nn, \@@_warning:nnn}
-% \begin{macro}[EXP]{\@@_expandable_warning:nn, \@@_expandable_warning:nnn}
-% A wrapper around warnings, expandable or not.
+% ^^A todo: instead of \@@_if_on:nT {#2} use \cs:w @@_if_on_#2:T \cs_end: already as a single token.
+%
+% \begin{macro}[int]{\check_patch:Nn, \check_patch:cn}
+% \begin{macro}[aux]{\@@_patch_parm:Nnn, \@@_patch_parm:nNn, \@@_patch_parm:VNn}
+% Find the signature (with appropriate errors if that is not found),
+% then construct the parameter text for \cs{check_patch:Npnn}, both
+% braced and not braced. At the same time, fill the
+% \cs{l_@@_extra_code_tl} variable with code that checks |N|-type
+% arguments.
% \begin{macrocode}
-\cs_new_nopar:Npn \@@_warning:nn
- { \__msg_kernel_warning:nnn { check } }
-\cs_new_nopar:Npn \@@_warning:nnn
- { \__msg_kernel_warning:nnnn { check } }
-\cs_new_nopar:Npn \@@_expandable_warning:nn
+\cs_new_protected:Npn \check_patch:Nn #1#2
{
- \cs_if_exist_use:NF
- \__msg_kernel_expandable_warning:nnn
- \__msg_kernel_expandable_error:nnn
- { check }
+ \@@_split_name:Nnnn #1
+ { \@@_patch_parm:Nnn #1 {#2} }
+ { \use_i:nnn { \@@_error:nn { patch-var } {#1} } }
+ { \@@_error:nn { patch-non-expl } {#1} }
}
-\cs_new_nopar:Npn \@@_expandable_warning:nnn
+\cs_generate_variant:Nn \check_patch:Nn { c }
+\cs_new_protected:Npn \@@_patch_parm:Nnn #1#2#3
{
- \cs_if_exist_use:NF
- \__msg_kernel_expandable_warning:nnnn
- \__msg_kernel_expandable_error:nnnn
- { check }
+ \int_zero:N \l_@@_parm_int
+ \tl_clear:N \l_@@_parm_tl
+ \tl_clear:N \l_@@_parm_braced_tl
+ \tl_clear:N \l_@@_extra_code_tl
+ \tl_map_inline:nn {#3}
+ {
+ \int_incr:N \l_@@_parm_int
+ \@@_patch_parm:VNn \l_@@_parm_int ##1 {#3}
+ }
+ \use:x
+ {
+ \exp_not:N \check_patch:Npnn
+ \exp_not:N #1
+ \exp_not:V \l_@@_parm_tl
+ { \exp_not:V \l_@@_parm_braced_tl }
+ {
+ \exp_not:V \l_@@_extra_code_tl
+ \exp_not:n {#2}
+ }
+ }
}
+\cs_new_protected:Npn \@@_patch_parm:nNn #1#2#3
+ {
+ \str_case:nnTF {#2}
+ {
+ n { \tl_put_right:Nn \l_@@_parm_braced_tl { { ## #1 } } }
+ N
+ {
+ \tl_put_right:Nn \l_@@_parm_braced_tl { ## #1 }
+ \tl_put_right:Nn \l_@@_extra_code_tl { \check_is_N:n { ## #1 } }
+ }
+ }
+ { \tl_put_right:Nn \l_@@_parm_tl { ## #1 } }
+ {
+ \tl_map_break:n
+ { \@@_error:nn { patch-non-base } {#3} }
+ }
+ }
+\cs_generate_variant:Nn \@@_patch_parm:nNn { V }
% \end{macrocode}
% \end{macro}
% \end{macro}
%
-% \subsubsection{Helpers}
+% \subsubsection{Checks that can be made}
%
-% \begin{macro}[int]{\@@_tl_set:Nn, \@@_tl_gset:Nn}
-% We copy those functions to avoid their type checking turned on by
-% \cs{check_on:n} |{ l3tl }|. The copies may act on any tokens.
+% ^^A todo: document
+%
+% \begin{macro}{\check_is_N:n}
+% \begin{macro}[EXP]{\check_is_N_exp:n}
+% \begin{macro}[aux, EXP]{\@@_if_N_type:nF}
+% Those functions check if a token list is a single |N|-type token.
+% We cannot safely use some of the built-in \LaTeX{} functions since
+% the token list may contain \cs{q_stop}.
% \begin{macrocode}
- % \cs_new_eq:NN \@@_tl_set:Nn \tl_set:Nn
- % \cs_new_eq:NN \@@_tl_gset:Nn \tl_gset:Nn
+\cs_new_protected:Npn \check_is_N:n #1
+ {
+ \@@_if_N_type:nF {#1}
+ { \@@_error:nn { is-not-N-type } {#1} }
+ }
+\cs_new:Npn \@@_N_type_exp:n #1
+ {
+ \@@_if_N_type:nF {#1}
+ { \@@_error_exp:nn { is-not-N-type } {#1} }
+ }
+\prg_new_conditional:Npnn \@@_if_N_type:n #1 { F , TF }
+ {
+ \tl_if_blank:nTF {#1}
+ { \prg_return_false: }
+ {
+ \tl_if_single_token:nTF {#1}
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+ }
% \end{macrocode}
% \end{macro}
+% \end{macro}
+% \end{macro}
%
-% \begin{variable}{\q_@@}
-% \begin{macro}[int]{\@@_tl_head:w, \@@_tl_head:n}
-% Safe copies of \cs{tl_head:n} functions.
+% \begin{macro}{\check_is_function:N}
+% \begin{macro}[EXP]{\check_is_function_exp:N}
% \begin{macrocode}
-\quark_new:N \q_@@
-\cs_new:Npn \@@_tl_head:w #1#2 \q_@@ {#1}
-\cs_new:Npn \@@_tl_head:n #1
- { \etex_unexpanded:D \exp_after:wN { \@@_tl_head:w #1 { } \q_@@ } }
+\cs_new_protected:Npn \check_is_function:N #1
+ {
+ \@@_split_name:Nnnn #1
+ { \use_none:n }
+ { \use_i:nnn { \@@_error:nnn { is-not } { function } {#1} } }
+ { }
+ }
+\cs_new:Npn \check_is_function_exp:N #1
+ {
+ \@@_split_name_exp:Nnnn #1
+ { \use_none:n }
+ { \use_i:nnn { \@@_error_exp:nnn { is-not } { function } {#1} } }
+ { }
+ }
% \end{macrocode}
% \end{macro}
-% \end{variable}
+% \end{macro}
%
-% \begin{macro}[EXP, int]{\@@_variable_get_scope:N}
-% \begin{macro}[EXP, aux]{\@@_variable_get_scope_aux:w}
+% \begin{macro}{\check_is_variable:N}
+% \begin{macro}[EXP]{\check_is_variable_exp:N}
% \begin{macrocode}
-\group_begin:
- \char_set_catcode_other:n { `* }
- \char_set_lccode:nn { `* } { `_ }
- \tl_to_lowercase:n
- {
- \group_end:
- \cs_new:Npn \@@_variable_get_scope:N #1
- {
- \exp_after:wN \exp_after:wN
- \exp_after:wN \@@_variable_get_scope_aux:w
- \cs_to_str:N #1 * \q_stop
- }
- \cs_new:Npn \@@_variable_get_scope_aux:w #1 * #2 \q_stop {#1}
- }
+\cs_new_protected:Npn \check_is_variable:N #1
+ {
+ \@@_split_name:Nnnn #1
+ { \use_i:nn { \@@_error:nnn { is-not } { variable } {#1} } }
+ { \use_none:nn }
+ { }
+ }
+\cs_new:Npn \check_is_variable_exp:N #1
+ {
+ \@@_split_name_exp:Nnnn #1
+ { \use_i:nn { \@@_error_exp:nnn { is-not } { variable } {#1} } }
+ { \use_none:nn }
+ { }
+ }
% \end{macrocode}
% \end{macro}
% \end{macro}
%
-% \begin{macro}[EXP, int]{\@@_variable_get_type:N}
-% \begin{macro}[EXP, aux]
-% {\@@_variable_get_type_aux:ww, \@@_variable_get_type_end:ww}
+% \begin{macro}{\check_is_local_variable:N}
+% \begin{macro}[EXP]{\check_is_local_variable_exp:N}
% \begin{macrocode}
- % \group_begin:
- % \char_set_catcode_other:n { `* }
- % \char_set_lccode:nn { `* } { `_ }
- % \tl_to_lowercase:n
- % {
- % \group_end:
- % \cs_new:Npn \@@_variable_get_type:N #1
- % {
- % \exp_after:wN \exp_after:wN
- % \exp_after:wN \@@_variable_get_type_aux:ww
- % \exp_after:wN \exp_after:wN
- % \exp_after:wN *
- % \cs_to_str:N #1 * { \q_stop \@@_variable_get_type_end:ww } *
- % }
- % \cs_new:Npn \@@_variable_get_type_aux:ww #1 * #2 *
- % {
- % \use_none_delimit_by_q_stop:w #2 #1 \q_stop
- % \@@_variable_get_type_aux:ww #2 *
- % }
- % }
- % \cs_new:Npn \@@_variable_get_type_end:ww #1 \q_stop #2#3#4#5 {#1}
+\cs_new_protected_nopar:Npn \check_is_local_variable:N
+ { \@@_is_scope_variable:NNN l \@@_error:nnn }
+\cs_new_protected_nopar:Npn \check_is_global_variable:N
+ { \@@_is_scope_variable:NNN g \@@_error:nnn }
+\cs_new_nopar:Npn \check_is_local_variable_exp:N
+ { \@@_is_scope_variable:NNN l \@@_error_exp:nnn }
+\cs_new_nopar:Npn \check_is_global_variable_exp:N
+ { \@@_is_scope_variable:NNN g \@@_error_exp:nnn }
+\cs_new:Npn \@@_is_scope_variable:NNN #1#2#3
+ {
+ \@@_split_name:Nnnn #3
+ { \use_i:nn { #2 { is-not } { variable } {#3} } }
+ { \@@_is_scope_variable:NNNnn #1#2#3 }
+ { }
+ }
+\cs_new:Npn \@@_is_scope_variable:NNNnn #1#2#3#4#5
+ {
+ \str_if_eq:nnF {#1} {#4}
+ { #2 { is-not-scope } {#1} {#3} }
+ }
% \end{macrocode}
% \end{macro}
% \end{macro}
%
-% \begin{macro}[pTF]{\@@_variable_if_tl:N}
-% \begin{macro}[int, EXP]{\@@_variable_if_tl_return:N}
-% \begin{macro}[aux, EXP]{\@@_variable_if_tl_aux:w}
-%
+% \begin{macro}[EXP]{\check_signature:N}
+% Expands to \cs{scan_stop:} or to the signature of a function.
% \begin{macrocode}
-\prg_new_conditional:Npnn \@@_variable_if_tl:N #1 { p , T , F , TF }
- { \@@_variable_if_tl_return:N #1 }
-\group_begin:
-\char_set_catcode_other:N M
-\char_set_catcode_other:N A
-\char_set_catcode_other:N C
-\char_set_catcode_other:N R
-\char_set_catcode_other:N O
-\tl_to_lowercase:n
+\cs_new:Npn \check_signature:N #1
{
- \group_end:
- \cs_new:Npn \@@_variable_if_tl_return:N #1
- {
- \exp_after:wN \__tl_if_empty_return:o \exp_after:wN
- {
- \exp_after:wN \@@_variable_if_tl_aux:w
- \token_to_meaning:N #1 MACRO \q_stop
- }
- }
- \cs_new:Npn \@@_variable_if_tl_aux:w #1 MACRO #2 \q_stop { #1 }
+ \@@_split_name_exp:Nnnn #1
+ { \use:n }
+ { \use_i:nnn \scan_stop: }
+ { \scan_stop: }
}
% \end{macrocode}
% \end{macro}
-% \end{macro}
-% \end{macro}
%
-% \begin{macro}[int, EXP]{\@@_variable_if_seq_return:N}
+% \begin{macro}
+% {
+% \check_signature_is_base:N,
+% \check_signature_should_be_empty:N,
+% \check_signature_should_be_nonempty:N
+% }
+% \begin{macro}[aux]{\@@_signature_is_base:N}
% \begin{macrocode}
-\cs_new:Npn \@@_variable_if_seq_return:N #1
+\cs_new_protected:Npn \check_signature_is_base:N #1
{
- \cs_if_exist:NTF #1
+ \exp_last_unbraced:Nf \@@_signature_is_base:N
+ { \check_signature:N #1 } \q_recursion_tail \q_recursion_stop
+ }
+\cs_new_protected:Npn \@@_signature_is_base:N #1
+ {
+ \token_if_eq_charcode:NNTF N #1
+ { \@@_signature_is_base:N }
{
- \@@_variable_if_tl:NTF #1
+ \token_if_eq_charcode:NNTF n #1
+ { \@@_signature_is_base:N }
{
- \exp_after:wN \@@_variable_if_seq_return_aux:nn
- #1 \q_recursion_tail \q_recursion_tail \q_recursion_stop
+ \quark_if_recursion_tail_stop_do:Nn #1 { \prg_return_true: }
+ \use_i_delimit_by_q_recursion_stop:nw { \prg_return_false: }
}
- { \prg_return_false: }
}
- { \prg_return_false: }
}
-\cs_new:Npn \@@_variable_if_seq_return_aux:nn #1#2
+\cs_new_protected:Npn \check_signature_should_be_empty:N #1
{
- \quark_if_recursion_tail_stop_do:nn {#1} { \prg_return_true: }
- \quark_if_recursion_tail_stop_do:nn {#2} { \prg_return_false: }
- \str_if_eq:nnTF {#1} { \s__seq }
- { \@@_variable_if_seq_return_aux:nn }
- { \@@_variable_if_seq_return_aux:nn ? \q_recursion_tail }
+ \tl_if_empty:fF { \check_signature:N #1 }
+ { \@@_warning:nn { arg-nopar } {#1} }
}
+\cs_new_protected:Npn \check_signature_should_be_nonempty:N #1
+ {
+ \tl_if_empty:fT { \check_signature:N #1 }
+ { \@@_warning:nn { par-noarg } {#1} }
+ }
% \end{macrocode}
% \end{macro}
+% \end{macro}
%
-% \subsubsection{Common tests}
-%
-% \begin{macro}[EXP, int]{\@@_N_type_expandable:n}
-% \begin{macro}[int]{\@@_N_type:n}
-% \begin{macro}[aux, EXP]{\@@_if_N_type:nF, \@@_if_N_type:nTF}
-% Those functions check if a token list is a single |N|-type token.
-% We cannot safely use some of the built-in \LaTeX{} functions since
-% the token list may contain \cs{q_stop}.
+% \begin{macro}[EXP, aux]{\@@_is_name_type:NnN, \@@_is_name_type_aux:NnNnn}
% \begin{macrocode}
-\prg_new_conditional:Npnn \@@_if_N_type:n #1 { F , TF }
+\cs_new:Npn \@@_is_name_type:NnN #1#2#3
{
- \str_if_eq_x:nnTF
- { \exp_after:wN \exp_not:n \exp_after:wN { \use:n #1 { } } }
- { \exp_not:n { #1 { } } }
- {
- \str_if_eq_x:nnTF { \exp_not:n {#1} } { \@@_tl_head:n {#1} }
- { \prg_return_true: }
- { \prg_return_false: }
- }
- { \prg_return_false: }
+ \@@_split_name:Nnnn #1
+ { \use_i:nn { #3 { is-not } {#2} {#1} } }
+ { \@@_is_name_type_aux:NnNnn #1#2#3 }
+ { }
}
-\cs_new_protected:Npn \@@_N_type:n #1
- {
- \@@_if_N_type:nF {#1}
- { \@@_error:nn { not-N-type } {#1} }
- }
-\cs_new:Npn \@@_N_type_expandable:n #1
- {
- \@@_if_N_type:nF {#1}
- { \@@_expandable_error:nn { not-N-type } {#1} }
- }
+\cs_new:Npn \@@_is_name_type_aux:NnNnn #1#2#3#4#5
+ { \str_if_eq:nnF {#5} {#2} { #3 { is-not } {#2} {#1} } }
% \end{macrocode}
% \end{macro}
-% \end{macro}
-% \end{macro}
%
-% \begin{macro}[EXP, int]{\@@_cs_exist_expandable:n}
-% \begin{macro}[int]{\@@_cs_exist:n}
-% Check that the argument is a single existing token.
+% \begin{macro}{\check_is_defined:N}
+% \begin{macro}[EXP]{\check_is_defined_exp:N, \check_is_defined_exp:c}
+% Do not use \cs{exp_args:Nc} (nor \cs{cs_generate_variant:Nn} for
+% the |c| variant in order to avoid infinite loop since the redefined
+% |c|-expansion calls this function.
% \begin{macrocode}
-\cs_new_protected:Npn \@@_cs_exist:n #1
+\cs_new_protected:Npn \check_is_defined:N #1
{
- \@@_if_N_type:nTF {#1}
- { \cs_if_exist:NF #1 { \@@_error:nn { unknown-cs } {#1} } }
- { \@@_error:nn { not-N-type } {#1} }
+ \cs_if_exist:NF #1
+ { \@@_error:nn { is-not-defined } {#1} }
}
-\cs_new:Npn \@@_cs_exist_expandable:n #1
+\cs_new:Npn \check_is_defined_exp:N #1
{
- \@@_if_N_type:nTF {#1}
- {
- \cs_if_exist:NF #1
- { \@@_expandable_error:nn { unknown-cs } {#1} }
- }
- { \@@_expandable_error:nn { not-N-type } {#1} }
+ \cs_if_exist:NF #1
+ { \@@_error_exp:nn { is-not-defined } {#1} }
}
+\cs_new:Npn \check_is_defined_exp:c #1
+ { \exp_after:wN \check_is_defined_exp:N \cs:w #1 \cs_end: }
% \end{macrocode}
% \end{macro}
% \end{macro}
%
-% \begin{macro}[EXP, int]
-% {\@@_variable_type_expandable:nn, \@@_variable_type_only_expandable:nn}
-% \begin{macro}[int]{\@@_variable_type:nn, \@@_variable_type_only:nn}
-% \begin{macro}[aux, EXP]{\@@_if_variable_type:NnF}
-% Those functions check if the token list |#1| is a single |N|-type
-% token with type |#2|.
+% \begin{macro}{\check_is_tl:N, \check_is_defined_tl:N}
+% \begin{macro}[EXP]{\check_is_tl_exp:N, \check_is_defined_tl_exp:N}
+% \begin{macro}[EXP, aux]{\@@_is_tl_aux:NN}
% \begin{macrocode}
-\prg_new_conditional:Npnn \@@_if_variable_type:Nn #1#2 { F }
- { \cs:w @@_variable_if_ #2 _return:N \cs_end: #1 }
-\cs_new:Npn \@@_variable_type_aux:NNNnn #1#2#3#4#5
+\cs_new_protected:Npn \check_is_defined_tl:N #1
{
- \@@_if_N_type:nTF {#4}
- {
- \cs_if_exist:NTF #4
- {
- \@@_if_variable_type:NnF #4 {#5}
- { #1 { wrong-type } {#4} {#5} }
- }
- { #2 { non-declared-variable } {#4} }
- }
- { #3 { not-N-type } {#4} }
+ \cs_if_exist:NTF #1
+ { \@@_is_tl_aux:NN #1 \@@_error:nnn }
+ { \@@_error:nn { is-not-defined } {#1} }
}
-\cs_new_protected_nopar:Npn \@@_variable_type:nn
+\cs_new:Npn \check_is_defined_tl_exp:N #1
{
- \@@_variable_type_aux:NNNnn
- \@@_warning:nnn \@@_error:nn \@@_error:nn
+ \cs_if_exist:NTF #1
+ { \@@_is_tl_aux:NN #1 \@@_error_exp:nnn }
+ { \@@_error_exp:nn { is-not-defined } {#1} }
}
-\cs_new_protected_nopar:Npn \@@_variable_type_only:nn
+\cs_new_protected:Npn \check_is_tl:N #1
{
- \@@_variable_type_aux:NNNnn
- \@@_warning:nnn \use_none:nn \@@_error:nn
+ \cs_if_exist:NTF #1
+ { \@@_is_tl_aux:NN #1 \@@_error:nnn }
+ { \@@_is_name_type:NnN #1 { tl } \@@_error:nnn }
}
-\cs_new_nopar:Npn \@@_variable_type_expandable:nn
+\cs_new:Npn \check_is_tl_exp:N #1
{
- \@@_variable_type_aux:NNNnn
- \@@_expandable_warning:nnn
- \@@_expandable_error:nn
- \@@_expandable_error:nn
+ \cs_if_exist:NTF #1
+ { \@@_is_tl_aux:NN #1 \@@_error_exp:nnn }
+ { \@@_is_name_type:NnN #1 { tl } \@@_error_exp:nnn }
}
-\cs_new_nopar:Npn \@@_variable_type_only_expandable:nn
- {
- \@@_variable_type_aux:NNNnn
- \@@_expandable_warning:nnn
- \use_none:nn
- \@@_expandable_error:nn
- }
+\cs_new:Npn \@@_is_tl_aux:NN #1#2
+ { \@@_if_tl_macro:NF #1 { #2 { is-not } { tl } {#1} } }
% \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
-% \begin{macro}[EXP, int]{\@@_variable_scope_type_expandable:nnn}
-% \begin{macro}[int]
-% {\@@_variable_scope_type:nnn, \@@_variable_scope_type_only:nnn}
-% \begin{macro}[aux, EXP]{\@@_if_variable_scope:NnF}
-% Those functions check if the token list |#1| is a single |N|-type
-% token with scope |#2| and type |#3|.
+% ^^A todo: consolidate into \check_is_type:Nn #1 { seq }, combine internals with tl too, building them with \cs:w \cs_end:
+% \begin{macro}{\check_is_seq:N, \check_is_defined_seq:N}
+% \begin{macro}[EXP]{\check_is_seq_exp:N, \check_is_defined_seq_exp:N}
+% ^^A todo: doc auxiliaries
% \begin{macrocode}
-\prg_new_conditional:Npnn \@@_if_variable_scope:Nn #1#2 { F }
+\cs_new_protected:Npn \check_is_defined_seq:N #1
{
- \__str_if_eq_x_return:nn
- { \@@_variable_get_scope:N #1 } {#2}
+ \cs_if_exist:NTF #1
+ { \@@_is_seq_aux:NN #1 \@@_error:nn }
+ { \@@_error:nn { is-not-defined } {#1} }
}
-\cs_new:Npn \@@_variable_scope_type_aux:NNNNnnn #1#2#3#4#5#6#7
+\cs_new:Npn \check_is_defined_seq_exp:N #1
{
- \@@_if_N_type:nTF {#5}
+ \cs_if_exist:NTF #1
+ { \@@_is_seq_aux:NN #1 \@@_error_exp:nnn }
+ { \@@_error_exp:nn { is-not-defined } {#1} }
+ }
+\cs_new_protected:Npn \check_is_seq:N #1
+ {
+ \cs_if_exist:NTF #1
+ { \@@_is_seq_aux:NN #1 \@@_error:nnn }
+ { \@@_is_name_type:NnN #1 { seq } \@@_error:nnn }
+ }
+\cs_new:Npn \check_is_seq_exp:N #1
+ {
+ \cs_if_exist:NTF #1
+ { \@@_is_seq_aux:NN #1 \@@_error_exp:nnn }
+ { \@@_is_name_type:NnN #1 { seq } \@@_error_exp:nnn }
+ }
+\cs_new:Npn \@@_is_seq_aux:NN #1#2
+ { \@@_if_seq:NF #1 { #2 { is-not } { seq } {#1} } }
+\prg_new_conditional:Npnn \@@_if_seq:N #1 { F }
+ {
+ \@@_if_tl_macro:NTF #1
{
- \cs_if_exist:NTF #5
+ \exp_args:No \tl_if_empty:oTF
+ { \exp_after:wN \@@_if_seq_aux:w #1 \q_recursion_tail }
{
- \@@_if_variable_type:NnF #5 {#7}
- { #1 { wrong-type } {#5} {#7} }
+ \exp_after:wN \@@_if_seq_aux:N
+ #1 \q_recursion_tail \q_recursion_tail
+ \q_recursion_tail \q_recursion_stop
}
- { #2 { non-declared-variable } {#5} }
- \@@_if_variable_scope:NnF #5 {#6}
- { #3 { wrong-scope } {#5} {#6} }
+ { \prg_return_false: }
}
- { #4 { not-N-type } {#5} }
+ { \prg_return_false: }
}
-\cs_new_protected_nopar:Npn \@@_variable_scope_type:nnn
+\cs_new:Npn \@@_if_seq_aux:w #1 \q_recursion_tail { }
+\cs_new:Npn \@@_if_seq_aux:N #1
{
- \@@_variable_scope_type_aux:NNNNnnn
- \@@_warning:nnn
- \@@_error:nn
- \@@_warning:nnn
- \@@_error:nn
+ \str_if_eq:nnTF {#1} { \s__seq }
+ { \@@_if_seq_loop:nn }
+ { \@@_if_seq_break:Nw \prg_return_false: }
}
-\cs_new_protected_nopar:Npn \@@_variable_scope_type_only:nnn
+\cs_new:Npn \@@_if_seq_break:Nw
+ #1 #2 \q_recursion_tail \q_recursion_stop {#1}
+\cs_new:Npn \@@_if_seq_loop:nn #1#2
{
- \@@_variable_scope_type_aux:NNNNnnn
- \@@_warning:nnn
- \use_none:nn
- \@@_warning:nnn
- \@@_error:nn
+ \quark_if_recursion_tail_stop_do:nn {#1} { \prg_return_true: }
+ \quark_if_recursion_tail_stop_do:nn {#2} { \prg_return_false: }
+ \tl_if_single:nF {#1}
+ { \@@_if_seq_break:Nw \prg_return_false: }
+ \str_if_eq:nnF {#1} { \__seq_item:n }
+ { \@@_if_seq_break:Nw \prg_return_false: }
+ \@@_if_seq_loop:nn
}
-\cs_new_nopar:Npn \@@_variable_scope_type_expandable:nnn
- {
- \@@_variable_scope_type_aux:NNNNnnn
- \@@_expandable_warning:nnn
- \@@_expandable_error:nn
- \@@_expandable_warning:nnn
- \@@_expandable_error:nn
- }
% \end{macrocode}
% \end{macro}
% \end{macro}
-% \end{macro}
%
% \subsubsection{General messages}
%
-%
+% ^^A todo: more informative error saying what the variable is if it has the wrong type.
% \begin{macrocode}
-\__msg_kernel_new:nnn { check } { multiple-modules }
+\msg_new:nnn { check } { is-not-defined }
+ { Assertion~failed:~'#1'~is~not~defined. }
+\msg_new:nnn { check } { is-not-N-type }
+ { Assertion~failed:~'#1'~is~not~a~single~N-type~token. }
+\msg_new:nnn { check } { is-not-scope }
+ {
+ Assertion~failed:~'#2'~is~not~a~
+ \str_case:nnF {#1}
+ {
+ { l } { local }
+ { g } { global }
+ } {#1} ~
+ variable~(starting~with~'#1_').
+ }
+\msg_new:nnn { check } { is-not }
+ {
+ Assertion~failed:~'#2'~is~not~a~
+ \str_case:nnF {#1}
+ {
+ { function } { function }
+ { variable } { variable }
+ { tl } { token~list }
+ { seq } { sequence }
+ }
+ {#1} .
+ }
+\msg_new:nnn { check } { patch-var }
+ { Only~functions~can~be~patched.~'#1'~is~a~variable }
+\msg_new:nnn { check } { patch-non-expl }
+ { Use~'\iow_char:N\\check_patch:Npnn',~not~'\iow_char:N\\check_patch:Nn'~to~patch~'#1' }
+\msg_new:nnn { check } { patch-non-base }
+ { Cannot~patch~'#1'~with~'\iow_char:N\\check_patch:Nn':~it~is~not~a~base~function! }
+\msg_new:nnn { check } { patch-non-macro }
+ { Cannot~patch~'#1':~it~is~not~a~macro! }
+\msg_new:nnn { check } { bad-var-name }
+ { Variable~name~'#1'~does~not~follow~expl3~conventions }
+\msg_new:nnn { check } { bad-func-name }
+ { Function~name~'#1'~does~not~follow~expl3~conventions }
+\msg_new:nnn { check } { multiple-modules }
{ The~function~#1~expects~a~single~module,~not~'#2'. }
-\__msg_kernel_new:nnn { check } { module-exists }
+\msg_new:nnn { check } { module-exists }
{ The~checking~code~for~module~'#1'~is~already~defined. }
+\msg_new:nnn { check } { module-unknown }
+ { No~checking~code~defined~for~module~'#1'. }
% \end{macrocode}
%
+% ^^A todo: consolidate below with above.
% \begin{macrocode}
-\__msg_kernel_new:nnn { check } { not-N-type }
- { Non~N~argument~#1 }
-\__msg_kernel_new:nnn { check } { unknown-cs }
- { Unknown~command~#1 }
-\__msg_kernel_new:nnn { check } { wrong-scope }
- { Variable~#1 should~start~with~'#2_' }
-\__msg_kernel_new:nnn { check } { wrong-type }
- { Got~#1 instead~of~a~#2~variable }
+\msg_new:nnnn { check } { non-declared-variable }
+ {
+ The~variable~\tl_trim_spaces:n{#1}~has~not~been~declared~
+ \msg_line_context:.
+ }
+ {
+ Checking~is~active,~and~you~have~tried~do~so~something~like: \\
+ \ \ \tl_set:Nn ~ \tl_trim_spaces:n {#1} ~ \{ ~ ... ~ \} \\
+ without~first~having: \\
+ \ \ \tl_new:N ~ \tl_trim_spaces:n {#1} \\
+ \\
+ LaTeX~will~create~the~variable~and~continue.
+ }
+\msg_new:nnn { check } { par-noarg }
+ { The~function~'#1'~takes~no~argument~but~is~not~defined~to~be~"_nopar".~This~is~unusual. }
+\msg_new:nnn { check } { arg-nopar }
+ { The~function~'#1'~is~"_nopar"~but~takes~arguments.~This~is~risky. }
+\msg_new:nnn { check } { set-eq-undef }
+ { The~function~'#1'~was~set~equal~to~'#2',~but~that~is~not~defined. }
+\msg_new:nnn { check } { no-expansion }
+ { Redundant~#1-expansion~of~'#2' }
+\msg_new:nnn { check } { internal }
+ { Internal~error:~#1!! }
% \end{macrocode}
%
% \subsection{\texttt{l3kernel}}
%
-% Start recording the code. This ends after all the sections on
-% specific modules.
+% ^^A todo: worry about drivers?
+%
+% The following is based on file \texttt{expl3-code} at revision 5859 or so.
+%
+% Difficulty with \cs{int_gdecr:N} being defined as \cs{tex_global:D}
+% \cs{int_decr:N}. Same for \cs{cs_gset_eq:NN} and \cs{cs_new_eq:NN}
+% defined in terms of \cs{cs_set_eq:NN}. Same for \cs{int_gadd:Nn},
+% \cs{int_gsub:Nn}, \cs{int_gset:Nn},
+% |(dim/skip/muskip)_(gzero:N/gset:Nn/gset_eq:NN/gadd:Nn/gsub:Nn)|,
+% \cs{box_gset_eq:NN}, \cs{box_gset_eq_clear:NN},
+% \cs{box_get_to_last:N}, \cs{hbox_gset:Nn}, \cs{hbox_gset_to_wd:Nnn},
+% \cs{hbox_gset:Nw}, \cs{vbox_gset:Nn}, \cs{vbox_gset_top:Nn},
+% \cs{vbox_gset_to_ht:Nnn}, \cs{vbox_gset:Nw}.
+%
+% \subsubsection{\pkg{l3basics}}
+%
% \begin{macrocode}
-\check_new:nn { l3kernel }
+\check_new:nn { cs }
{
% \end{macrocode}
%
-% \subsubsection{\pkg{l3basics}}
+% We could change \cs{group_begin:}, \cs{group_end:},
+% \cs{group_insert_after:N}, but do not.
%
-% Functions which we might want to hook into: \cs{group_begin:},
-% \cs{group_end:}, \cs{group_insert_after:N}.
-%
-% The $48$ assignment functions: |set|, |gset|, |new|; |protected| or
-% not, |nopar| or not, |n| or |x|, with |p| or not. Of course, this
-% automatically extends to the |c| variants. We could
+% Let us do |\cs_(set/gset/new)(/_protected)(/_nopar):N(/p)(n/x)|, $48$
+% assignment functions. First clean them up a bit, since some are
+% defined as \cs{tex_global:D} followed by others.
+% \begin{macrocode}
+ \cs_set_protected_nopar:Npn \cs_set_nopar:Npn { \tex_def:D }
+ \cs_set_protected_nopar:Npn \cs_set_nopar:Npx { \tex_edef:D }
+ \cs_set_protected_nopar:Npn \cs_gset_nopar:Npn { \tex_gdef:D }
+ \cs_set_protected_nopar:Npn \cs_gset_nopar:Npx { \tex_xdef:D }
+ \cs_set_protected_nopar:Npn \cs_set:Npn { \tex_long:D \tex_def:D }
+ \cs_set_protected_nopar:Npn \cs_set:Npx { \tex_long:D \tex_edef:D }
+ \cs_set_protected_nopar:Npn \cs_gset:Npn { \tex_long:D \tex_gdef:D }
+ \cs_set_protected_nopar:Npn \cs_gset:Npx { \tex_long:D \tex_xdef:D }
+ \cs_set_protected_nopar:Npn \cs_set_protected_nopar:Npn { \etex_protected:D \tex_def:D }
+ \cs_set_protected_nopar:Npn \cs_set_protected_nopar:Npx { \etex_protected:D \tex_edef:D }
+ \cs_set_protected_nopar:Npn \cs_gset_protected_nopar:Npn { \etex_protected:D \tex_gdef:D }
+ \cs_set_protected_nopar:Npn \cs_gset_protected_nopar:Npx { \etex_protected:D \tex_xdef:D }
+ \cs_set_protected_nopar:Npn \cs_set_protected:Npn { \etex_protected:D \tex_long:D \tex_def:D }
+ \cs_set_protected_nopar:Npn \cs_set_protected:Npx { \etex_protected:D \tex_long:D \tex_edef:D }
+ \cs_set_protected_nopar:Npn \cs_gset_protected:Npn { \etex_protected:D \tex_long:D \tex_gdef:D }
+ \cs_set_protected_nopar:Npn \cs_gset_protected:Npx { \etex_protected:D \tex_long:D \tex_xdef:D }
+% \end{macrocode}
+% The plan is eventually to
% \begin{itemize}
% \item check that \enquote{nopar} is used properly;
% \item list any undefined token appearing in any cs definition, in
% particular variants;
+% \item detect what parts are arguments of what and detect e.g.,
+% brace groups used as N-type arguments, etc.
% \item perhaps detect functions from the \enquote{msg} module, and
% check that the corresponding message exists.
% \end{itemize}
-%
-% \begin{macro}{\cs_set_eq:NN, \cs_gset_eq:NN, \cs_new_eq:NN}
-% The $3$ copying functions (extending automatically to the |c|
-% variants) expect their argument to be defined, unless it is exactly
-% \cs{scan_stop:}, \cs{tex_undefined:D}, or \cs{tex_relax:D}.
+% For now, just check that the first argument is a single token, is a
+% function, and for the |:Nn|/|:Nx| defining functions, check that the
+% signature is right. Additionally, have a warning when trying to
+% define a long macro with no parameter or a non-long macro with
+% parameters. Note that we do not touch the \enquote{new} functions as
+% they call the \enquote{gset} functions internally (otherwise we would
+% get two warnings/errors).
% \begin{macrocode}
- % \tl_map_inline:nn { \cs_set_eq:NN , \cs_gset_eq:NN , \cs_new_eq:NN }
- % {
- % \@@_patch_protected:Npnn #1 ##1##2 { ##1 ##2 }
- % {
- % \str_case:nnF {##2}
- % {
- % { \tex_undefined:D } { }
- % { \scan_stop: } { }
- % { \tex_relax:D } { }
- % }
- % { \@@_cs_exist:n {##2} }
- % }
- % }
+ \group_begin:
+ \cs_set:Npn \check_tmp:w #1#2#3
+ {
+ \check_patch:cpnn { cs_ #1 #2 :Np #3 }
+ ##1 ##2 ## { ##1 ##2 }
+ {
+ \check_is_N:n {##1}
+ % \check_is_function:N ##1 % ^^A todo: reinstate when more is done
+ \tl_if_empty:nT {##2} { \@@_warning:nn { par-noarg } {##1} }
+ }
+ \check_patch:cpnn { cs_ #1 #2 _nopar:Np #3 }
+ ##1 ##2 ## { ##1 ##2 }
+ {
+ \check_is_N:n {##1}
+ % \check_is_function:N ##1 % ^^A todo: reinstate when more is done
+ \tl_if_empty:nF {##2} { \@@_warning:nn { arg-nopar } {##1} }
+ }
+ \check_patch:cpnn { cs_ #1 #2 :N #3 }
+ ##1 { ##1 }
+ {
+ \check_is_N:n {##1}
+ \check_is_function:N ##1
+ \check_signature_is_base:N ##1
+ \check_signature_should_be_nonempty:N ##1
+ }
+ \check_patch:cpnn { cs_ #1 #2 _nopar:N #3 }
+ ##1 ##2 ## { ##1 ##2 }
+ {
+ \check_is_N:n {##1}
+ \check_is_function:N ##1
+ \check_signature_is_base:N ##1
+ \check_signature_should_be_empty:N ##1
+ }
+ }
+ \tl_map_inline:nn { {set} {gset} }
+ {
+ \tl_map_inline:nn { { } {_protected} }
+ {
+ \tl_map_inline:nn { n x }
+ { \check_tmp:w {#1} {##1} {####1} }
+ }
+ }
+ \group_end:
% \end{macrocode}
-% \end{macro}
%
-% \begin{macro}{\__cs_check_exists:N}
-% We already check if the commands exist, so no need to keep the
-% \pkg{l3kernel} check. We also redefine the message to remove a
-% space: |#1| will contain a trailing space in our case.
+% The second argument of |\cs_(set/gset/new)_eq:NN| should be defined,
+% except if it is \cs{scan_stop:}, \cs{tex_relax:D} or
+% \cs{tex_undefined:D}, in which case that was probably the point.
+% Also redefine the |:Nc|, |:cN| and |:cc| variants to avoid using
+% actual |c|-expansion, since the resulting control sequences are often
+% undefined.
% \begin{macrocode}
- \cs_gset_eq:NN \__cs_check_exists:N \use_none:n
- \__msg_kernel_set:nnnn { check } { non-declared-variable }
+ \tl_map_inline:nn { {set} {gset} {new} }
{
- The~variable~\tl_trim_spaces:n{#1}~has~not~been~declared~
- \msg_line_context:.
+ \check_patch:cn { cs_#1_eq:NN }
+ {
+ \cs_if_exist:NF ##2
+ {
+ \str_case:nnF {##2}
+ {
+ \tex_undefined:D { }
+ \tex_relax:D { }
+ \scan_stop: { }
+ }
+ { \@@_warning:nnn { set-eq-undef } {##1} {##2} }
+ }
+ }
+ \cs_gset_protected:cpx { cs_#1_eq:cN } ##1
+ {
+ \exp_not:N \exp_after:wN \exp_not:c { cs_#1_eq:NN }
+ \exp_not:N \cs:w ##1 \cs_end:
+ }
+ \cs_gset_protected:cpx { cs_#1_eq:Nc } ##1##2
+ {
+ \exp_not:N \exp_after:wN \exp_not:c { cs_#1_eq:NN }
+ \exp_not:N \exp_after:wN ##1
+ \exp_not:N \cs:w ##2 \cs_end:
+ }
+ \cs_gset_protected:cpx { cs_#1_eq:cc } ##1##2
+ {
+ \exp_not:N \exp_after:wN \exp_not:c { cs_#1_eq:NN }
+ \exp_not:N \cs:w ##1 \exp_not:N \exp_after:wN \cs_end:
+ \exp_not:N \cs:w ##2 \cs_end:
+ }
}
- {
- Checking~is~active,~and~you~have~tried~do~so~something~like: \\
- \ \ \tl_set:Nn ~ \tl_trim_spaces:n {#1} ~ \{ ~ ... ~ \} \\
- without~first~having: \\
- \ \ \tl_new:N ~ \tl_trim_spaces:n {#1} \\
- \\
- LaTeX~will~create~the~variable~and~continue.
- }
% \end{macrocode}
-% \end{macro}
%
-% \subsubsection{\pkg{l3expan}}
-%
-% The \cs{cs_generate_variant:Nn} function should be altered, to check
-% that it is only doing sensible replacements in the arg spec.
-%
-% We could want to also do something about
-% \cs{exp_last_two_unbraced:Noo}.
-%
-% \begin{macro}[EXP]{\use:c}
-% \begin{macro}[aux, EXP]{\@@_cs_use:N}
-% Add to \cs{use:c} a check that the control sequence thus constructed
-% is defined. We need the \texttt{align_safe} functions in case |#1|
-% is one of the alignment primitives.
+% \begin{macro}{\__cs_check_exists:N}
+% Since \pkg{l3check} adds a check that the commands exist, no need
+% to keep the \pkg{l3kernel} check.
% \begin{macrocode}
- \cs_gset_nopar:Npn \use:c
- {
- \group_align_safe_begin:
- \exp_args:Nc \@@_cs_use:N
- }
- \cs_new:Npn \@@_cs_use:N #1
- {
- \cs_if_exist:NF #1
- { \@@_expandable_error:nn { unknown-cs } {#1} }
- \group_align_safe_end:
- #1
- }
+ \cs_gset_eq:NN \__cs_check_exists:N \use_none:n
% \end{macrocode}
% \end{macro}
-% \end{macro}
%
-% \begin{macro}[EXP]{\::N, \::V, \::V_unbraced}
-% Two of the expansion types expect a single token. Otherwise, raise
-% an error.
+% ^^A todo:
+% |\prg_(set/new)(/_protected)_conditional:N(/p)nn|,
+% |\prg_(/g)set_eq_conditional:NNn|,
+% |\cs_to_str:N|, |\cs_if_(exist/free)(/_p):(N/c)(T/F/TF)|,
+% |\cs_if_exist_use:(N/c)(/T/F/TF)|,
+% \cs{iow_log:x} \cs{iow_term:x},
+% |\cs_undefine:(N/c)|,
+% \cs{cs_generate_from_arg_count:NNnn},
+% \cs{cs_if_eq:NN}(TF), |\cs_(show/log):N|
+%
% \begin{macrocode}
- \@@_patch:Npnn \::N #1 \::: #2#3 { {#1} \::: {#2} {#3} }
- { \@@_N_type_expandable:n {#3} }
- \@@_patch:Npnn \::V #1 \::: #2#3 { {#1} \::: {#2} {#3} }
- { \@@_N_type_expandable:n {#3} }
- \@@_patch:Npnn \::V_unbraced \::: #1#2 { \::: {#1} {#2} }
- { \@@_N_type_expandable:n {#2} }
+ }
% \end{macrocode}
-% \end{macro}
%
-% \begin{macro}[EXP]{\::o, \::f, \::o_unbraced, \::f_unbraced}
-% \begin{macro}[aux, EXP]{\@@_if_head_is_expandable:nF}
-% These functions expand an argument, once or fully. If the argument
-% does not expand at all under the specified expansion type, warn the
-% user.
+% \subsubsection{\pkg{l3expan}}
+%
% \begin{macrocode}
- \prg_new_conditional:Npnn \@@_if_head_is_expandable:n #1 { F }
- {
- \str_if_eq_x:nnTF
- { \exp_after:wN \exp_not:n \exp_after:wN { \use:n #1 { } } }
- { \exp_not:n { #1 { } } }
- {
- \exp_after:wN \token_if_expandable:NTF
- \@@_tl_head:w #1 \q_@@
- { \prg_return_true: }
- { \prg_return_false: }
- }
- { \prg_return_false: }
- }
- \@@_patch:Npnn \::o #1 \::: #2#3 { {#1} \::: {#2} {#3} }
- {
- \@@_if_head_is_expandable:nF {#3}
- { \@@_expandable_warning:nn { no-expansion } {#3} }
- }
- \@@_patch:Npnn \::f #1 \::: #2#3 { {#1} \::: {#2} {#3} }
- {
- \tl_if_head_eq_catcode:nNF {#3} \c_space_token
- {
- \@@_if_head_is_expandable:nF {#3}
- { \@@_expandable_warning:nn { no-expansion } {#3} }
- }
- }
- \@@_patch:Npnn \::o_unbraced \::: #1#2 { \::: {#1} {#2} }
- {
- \@@_if_head_is_expandable:nF {#2}
- { \@@_expandable_warning:nn { no-expansion } {#2} }
- }
- \@@_patch:Npnn \::f_unbraced \::: #1#2 { \::: {#1} {#2} }
- {
- \tl_if_head_eq_catcode:nNF {#2} \c_space_token
- {
- \@@_if_head_is_expandable:nF {#2}
- { \@@_expandable_warning:nn { no-expansion } {#2} }
- }
- }
+\check_new:nn { expan }
+ {
% \end{macrocode}
-% \end{macro}
-% \end{macro}
%
% \begin{macro}[EXP]
% {
@@ -870,8 +1267,9 @@
% }
% Remove hand-tuning, to make sure that our modified \cs{::N},
% \cs{::V}, \cs{::o} and \cs{::f} are called. We need to base
-% \cs{exp_not:c} on the |N| variant, because the |n| variant is a
-% primitive, which does not accept unbraced arguments.
+% \cs{exp_not:c} on \cs{exp_not:N} and not \cs{exp_not:n}
+% because the |n| variant is a primitive, which does not
+% accept unbraced arguments.
% \begin{macrocode}
\cs_gset_nopar:Npn \exp_not:o { \exp_args:No \exp_not:n }
\cs_gset_nopar:Npn \exp_not:c { \exp_args:Nc \exp_not:N }
@@ -911,52 +1309,415 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\cs_show:c}
-% Now that we've removed hand-tuning from \cs{exp_args:Nc}, the output
-% of \cs{cs_show:c} becomes ugly. We fix that by redefining the
-% function to use \cs{cs:w} directly.
+% ^^A todo: we may need \group_align_safe_begin:/end: in case |#1| is an alignment primitive!
+% \begin{macro}[EXP]{\use:c}
+% Remove some more fine-tuning.
% \begin{macrocode}
- \cs_gset_protected:Npn \cs_show:c #1
- {
- \group_begin:
- \exp_after:wN
- \group_end:
- \exp_after:wN \cs_show:N \cs:w #1 \cs_end:
- }
+ \cs_gset_nopar:Npn \use:c { \exp_args:Nc \use:n }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\__msg_show_variable:n}
-% The internal \pkg{l3msg} function responsible for showing variables
-% is also redefined there to use the expansion underlying
-% \cs{exp_args:Nf} directly, for a better output.
+% \begin{macro}[EXP]{\::o, \::f, \::o_unbraced, \::f_unbraced}
+% \begin{macro}[aux, EXP]{\@@_if_head_is_expandable:nF}
+% These functions expand an argument, once or fully. If the argument
+% does not expand at all under the specified expansion type, warn the
+% user.
% \begin{macrocode}
- \cs_gset_protected:Npn \__msg_show_variable:n #1
+ \prg_new_conditional:Npnn \@@_if_head_is_expandable:n #1 { F }
{
- \tl_set:Nn \l__msg_internal_tl {#1}
- \tl_if_empty:NTF \l__msg_internal_tl
- { \etex_showtokens:D \exp_after:wN { } }
+ \tl_if_head_is_N_type:nTF {#1}
{
- \etex_showtokens:D \exp_after:wN
- {
- \tex_romannumeral:D -`0
- \exp_after:wN \exp_after:wN
- \exp_after:wN \__msg_show_variable:w
- \exp_after:wN \l__msg_internal_tl
- }
+ \exp_after:wN \tl_head:n
+ \exp_after:wN { \@@_if_head_is_expandable_aux:n #1 }
}
+ { \prg_return_false: }
}
+ \cs_new:Npn \@@_if_head_is_expandable_aux:n #1
+ {
+ {
+ \token_if_expandable:NTF #1
+ { \prg_return_true: }
+ { \prg_return_false: }
+ }
+ }
+ \check_patch:Npnn \::o #1 \::: #2#3 { {#1} \::: {#2} {#3} }
+ {
+ \@@_if_head_is_expandable:nF {#3}
+ { \@@_warning_exp:nnn { no-expansion } { o } {#3} }
+ }
+ \check_patch:Npnn \::f #1 \::: #2#3 { {#1} \::: {#2} {#3} }
+ {
+ \tl_if_head_eq_catcode:nNF {#3} \c_space_token
+ {
+ \@@_if_head_is_expandable:nF {#3}
+ { \@@_warning_exp:nnn { no-expansion } { f } {#3} }
+ }
+ }
+ \check_patch:Npnn \::o_unbraced \::: #1#2 { \::: {#1} {#2} }
+ {
+ \@@_if_head_is_expandable:nF {#2}
+ { \@@_warning_exp:nnn { no-expansion } { o } {#2} }
+ }
+ \check_patch:Npnn \::f_unbraced \::: #1#2 { \::: {#1} {#2} }
+ {
+ \tl_if_head_eq_catcode:nNF {#2} \c_space_token
+ {
+ \@@_if_head_is_expandable:nF {#2}
+ { \@@_warning_exp:nnn { no-expansion } { f } {#2} }
+ }
+ }
% \end{macrocode}
% \end{macro}
+% \end{macro}
%
-% Messages.
+% ^^A todo: check that first arg of \exp_args:N... is indeed N!
+%
+% \begin{macro}[EXP]{\::N}
+% Check that this is a single token.
% \begin{macrocode}
- \__msg_kernel_new:nnn { check } { no-expansion }
- { Redundant~expansion~in~#1 }
+ \check_patch:Npnn \::N #1 \::: #2#3 { {#1} \::: {#2} {#3} }
+ { \check_is_N:n {#3} }
% \end{macrocode}
+% \end{macro}
%
+% \begin{macro}[EXP]{\::c}
+% \begin{macrocode}
+ \check_patch:Npnn \::c #1 \::: #2#3 { {#1} \::: {#2} {#3} }
+ { \check_is_defined_exp:c {#3} }
+% \end{macrocode}
+% \end{macro}
+%
+% ^^A todo:
+% \cs{::V}, \cs{::v}, \cs{::x}
+% |\::(V/v/x)_unbraced|,
+% |\exp_last_two_unbraced:Noo|,
+%
+% ^^A todo: extra checks for \cs{cs_generate_variant:Nn}.
+% \begin{macrocode}
+ \check_patch:Nn \cs_generate_variant:Nn
+ {
+ \check_is_function:N #1
+ \check_is_defined:N #1
+ }
+% \end{macrocode}
+%
+% ^^A todo: move somewhere sensible, find better solution
+%
+% Fix back a few commands, double checking that their original
+% definition is still what it was when this code was written. Well, we
+% do not check \cs{__char_set_catcode:Nn}'s definition, because it
+% includes |^^@|, which is a can of worms.
+% \begin{macrocode}
+ \group_begin:
+ \cs_set:Npn \check_tmp:w #1#2 \q_mark #3 ~ #4 \q_stop #5#6#7#8
+ {
+ \scan_stop: \scan_stop: \fi:
+ \exp_not:N \q_mark
+ \exp_not:N \q_stop
+ \exp_not:N #6
+ \exp_not:c { #7 : #8 #1 #3 }
+ }
+ \cs_if_eq:NNTF \check_tmp:w \__cs_generate_variant_loop_end:nwwwNNnn
+ {
+ \cs_gset:Npn \__cs_generate_variant_loop_end:nwwwNNnn #1#2 \q_mark #3 ~ #4 \q_stop #5#6#7#8
+ {
+ \scan_stop: \scan_stop: \fi:
+ \exp_not:N \q_mark
+ \exp_not:N \q_stop
+ \exp_not:N #6
+ \exp_after:wN \exp_not:N \cs:w #7 : #8 #1 #3 \cs_end:
+ }
+ }
+ { \@@_error:nn { internal } { Cannot~patch~\__cs_generate_variant_loop_end:nwwwNNnn } }
+ \cs_set_protected:Npn \check_tmp:w #1#2#3#4#5
+ {
+ \tex_catcode:D `#1 = \__int_eval:w #2 \__int_eval_end:
+ #3 { \tex_catcode:D `#1 / \c_two } = \c_six
+ {
+ \group_begin: \exp_args:NNc \group_end:
+ \__char_set_catcode:NNN {#1} #4 #5
+ }
+ }
+ \cs_if_eq:NNTF \check_tmp:w \__char_set_catcode:NnNNN
+ {
+ \cs_gset_protected:Npn \__char_set_catcode:NnNNN #1#2#3#4#5
+ {
+ \tex_catcode:D `#1 = \__int_eval:w #2 \__int_eval_end:
+ #3 { \tex_catcode:D `#1 / \c_two } = \c_six
+ {
+ \group_begin: \exp_after:wN \group_end:
+ \exp_after:wN \__char_set_catcode:NNN \cs:w #1 \cs_end: #4 #5
+ }
+ }
+ }
+ { \@@_error:nn { internal } { Cannot~patch~\__char_set_catcode:NnNNN } }
+ \tl_if_exist:cT { @sanitize }
+ {
+ \use:x
+ {
+ \exp_not:n { \cs_gset_protected:Npn \__char_set_catcode:Nn #1#2 }
+ {
+ \exp_not:n { \cs_set_eq:NN \exp_args:Nc \@@_exp_args:Nc }
+ \exp_not:o { \__char_set_catcode:Nn {#1} {#2} }
+ \exp_not:n { \cs_set_nopar:Npn \exp_args:Nc { \::c \::: } }
+ }
+ }
+ }
+ \group_end:
+% \end{macrocode}
+% We do not redefine \cs{exp_args:cc} because
+% \cs{prg_new_conditional:Npnn} and its friends use that function to
+% generate new control sequences.
+%
+% The |c| variants of all \enquote{defining} commands should use
+% \cs{@@_exp_args:Nc} and not \cs{exp_args:Nc} for their first
+% argument, so that the existence check is omitted. Also for
+% \texttt{show} commands.
+% \begin{macrocode}
+ \group_begin:
+ \cs_set_protected:Npn \check_tmp:w #1#2
+ {
+ \exp_after:wN \cs_gset_protected_nopar:Npx \cs:w #1 : c #2 \cs_end:
+ {
+ \exp_not:N \@@_exp_args:Nc
+ \exp_not:c { #1 : N#2 }
+ }
+ }
+ \tl_map_inline:nn { {set} {gset} {new} }
+ {
+ \tl_map_inline:nn { { } { _protected } { _nopar } { _protected_nopar } }
+ {
+ \tl_map_inline:nn { n x }
+ { \check_tmp:w { cs_#1##1 } { p ####1 } }
+ }
+ }
+ \tl_map_inline:nn { {tl} {clist} {seq} {prop} {int} {dim} {skip} {muskip} }
+ {
+ \check_tmp:w { #1_new } { }
+ \check_tmp:w { #1_show } { }
+ \check_tmp:w { #1_log } { }
+ \check_tmp:w { #1_if_exist_p } { }
+ \check_tmp:w { #1_if_exist } { TF }
+ \check_tmp:w { #1_if_exist } { T }
+ \check_tmp:w { #1_if_exist } { F }
+ }
+ \tl_map_inline:nn { {tl} {clist} {seq} {prop} }
+ {
+ \check_tmp:w { #1_clear_new } { }
+ \check_tmp:w { #1_gclear_new } { }
+ }
+ \tl_map_inline:nn { {int} {dim} {skip} {muskip} }
+ {
+ \check_tmp:w { #1_zero_new } { }
+ \check_tmp:w { #1_gzero_new } { }
+ \check_tmp:w { #1_const } { n }
+ }
+ \check_tmp:w { tl_const } { n }
+ \check_tmp:w { tl_const } { x }
+ \check_tmp:w { clist_const } { n }
+ \check_tmp:w { tl_concat } { NN }
+ \check_tmp:w { clist_concat } { NN }
+ \check_tmp:w { seq_concat } { NN }
+ \group_end:
+% \end{macrocode}
+%
+% \begin{macrocode}
+ }
+% \end{macrocode}
+%
% \subsubsection{\pkg{l3tl}}
%
+% ^^A todo: everything below
+% \cs{tl_new:N}, \cs{tl_const:Nn}/Nx, \cs{tl_clear:N}/gclear,
+% \cs{tl_clear_new:N}/gclear, |\tl_(set/gset)_eq:(N/c)(N/c)|,
+% \cs{tl_concat:NNN}/gconcat, |\tl_if_exist:(N/c)(T/F/TF//p)|,
+% |\tl_(set/gset):(Nn/No/Nx)|,
+% |\tl_(put/gput)_(left/right):N(n/V/o/x)|,
+% |\tl_(set/gset)_rescan:Nnn|, |\tl_(/g)replace_(once/all):Nnn|
+% |\tl_if_(empty/single):N|(TF), \cs{tl_if_eq:NN}(TF),
+% \cs{tl_if_in:Nn}(TF), |\tl_map_function:NN|, |\tl_map_inline:Nn|,
+% |\tl_map_variable:NNn|, |\tl_(to_str/use/count/head/tail):N|,
+% |\tl_(g/)trim_spaces:N|, |\tl_(g/)reverse:N|,
+% |\tl_if_head_eq_(charcode/catcode/meaning):nN|(TF), |\tl_item:Nn|,
+% |\tl_(show/log):N|, |\tl_(g/)set_from_file(/_x):Nnn|
+%
+% Remove the \cs{l at expl@check at declarations@bool} loop business since it
+% would be covered by \pkg{l3check}.
+%
+% |(tl/str/int/dim)_case:(N/n)n|(TF) count brace groups.
+%
+% \subsubsection{\pkg{l3seq}}
+%
+% \cs{seq_new:N} should also check name of var.
+%
+% |\seq_(g/)clear(/_new):N|, |\seq_(g/)set_eq:(N/c)(N/c)|,
+% |\seq_if_(exist/empty):(N/c)|(TF), |\seq_(g/)remove_duplicates:N|,
+% |\seq_if_in:Nn|(TF), |\seq_item:Nn|, |\seq_count:N|,
+% |\seq_use:Nn(/nn)|, |\seq_map_function:NN|,
+% |\seq_mapthread_function:NNN|, |\seq_map_inline:Nn|,
+% |\seq_map_variable:NNn|, |\seq_(show/log):N|
+%
+% The following abuse |\tl_(g/)set:N(n/x/f)|:
+% |\seq_(g/)set_from_clist:N(N/n)|,
+% |\seq_(g/)set_split:Nnn|,
+% |\seq_(g/)concat:NNN|,
+% |\seq_(g/)(put_left/put_right/push):Nn|,
+% |\seq_(g/)reverse:N|,
+% |\seq_(get/pop/gpop)_(left/right):NN|(TF),
+% |\seq_(get/pop/gpop):NN|(TF),
+% |\seq_(g/)set_(filter/map):NNn|
+%
+% The following abuses it more: |\seq_(g/)remove_all:Nn| (interrupting
+% assignment and starting it again).
+%
+% \subsubsection{\pkg{l3int}}
+%
+% In principle we could make integer expressions a bit more robust by
+% adding a bunch of parentheses.
+%
+% |\int_(show/log):N|, \cs{int_new:N}, |\int_(g/)(zero/incr/decr):N|, |\int_(g/)zero_new:N|, \cs{int_const:Nn},
+% |\int_(g/)set_eq:NN|, |\int_if_exist:N|(TF), |\int_(g/)(add/sub/set):Nn|,
+% |\int_compare:nNn|(TF), |\int_(while/until)_do:nNnn|, |\int_do_(while/until):nNnn|,
+% |\int_step_function:nnnN|, |\int_step_variable:nnnNn|
+%
+% Would be nice to change but cannot because of expansion: |\int_use:N|.
+%
+% Deprecated: |\int_(to/from)_(binary/hexadecimal/octal):n|.
+%
+% \subsubsection{\pkg{l3quark}}
+%
+% \cs{quark_new:N} abuses \cs{tl_const:Nn}.
+%
+% \cs{quark_if_recursion_tail_stop:N}, \cs{quark_if_recursion_tail_stop_do:Nn},
+% |\quark_if_(nil/no_value):N|(TF)
+%
+% \subsubsection{\pkg{l3prg}}
+%
+% \cs{bool_new:N}, |\bool_(g/)set_(true/false):N|,
+% |\bool_(g/)set_eq:(N/c)(N/c)|, |\bool_(g/)set:Nn|, |\bool_if:N|(TF),
+% |\bool_(show/log):N|, |\bool_if_exist:(N/c)(TF)|, |\bool_(while_do/until_do/do_while/do_until):Nn|
+%
+% Deprecated: |\scan_align_safe_stop:|
+%
+% \subsubsection{\pkg{l3clist}}
+%
+% |\clist_new:(N/c)|, |\clist_const:Nn| abuses |\tl_const:Nx|, |\clist_(g/)clear:(N/c)|, |\clist_(g/)clear_new:(N/c)|,
+% |\clist_(g/)set_eq:(N/c)(N/c)|, |\clist_(g/)set_from_seq:NN| abuses |\tl_(g/)set:N?|, |\clist_(g/)concat:NNN| abuses |\tl_(g/)set:Nx|,
+% |\clist_if_exist:(N/c)|(TF), |\clist_(g/)set:Nn| abuses |\tl_(g/)set:Nx|, |\clist_(g/)put_(left/right):Nn| just N-type, |\clist_(get/pop/gpop):NN|(TF) abuse |\tl_(g/)set:N(n/x)|, |\clist_(g/)push:Nn|, |\clist_(g/)remove_duplicates:N|, |\clist_(g/)remove_all:Nn|, |\clist_(g/)reverse:N|, |\clist_if_in:Nn|(TF), |\clist_map_function:(N/n)N|, |\clist_map_inline:Nn|, |\clist_map_variable:(N/n)Nn|, |\clist_count:N|, |\clist_use:Nn(/nn)|, |\clist_item:Nn|, |\clist_(show/log):N|
+%
+% \subsubsection{\pkg{l3token}}
+%
+% ^^A todo: the internal \__peek_get_prefix_arg_replacement:wN is misnamed: __peek should be __token
+%
+% |\char_set_catcode_(escape/group_begin/group_end/math_toggle/alignment/end_line/parameter/math_superscript/math_subscript/ignore/space/letter/other/active/comment/invalid):N|,
+% |\token_if_(group_begin/group_end/math_toggle/alignment/parameter/math_superscript/math_subscript/space/letter/other/active/macro/cs/expandable/primitive/chardef/mathchardef/(dim/int/muskip/skip/toks)_register/(protected/long/protected_long)_macro):N|(TF),
+% |\peek_(catcode/charcode/meaning)(/_remove)(/_ignore_spaces):N|(TF),
+% |\token_new:Nn|, |\token_if_eq_(meaning/catcode/charcode):NN|(TF),
+% |\peek_(g/)after:Nw|,
+% |\token_get_(prefix/arg/replacement)_spec:N|,
+% |\char_(g/)set_active:Np(n/x)|, |\char_(g/)set_active_eq:NN|,
+%
+% \subsubsection{\pkg{l3prop}}
+%
+% |\prop_new:N|, |\prop_(g/)clear:N|, |\prop_(g/)clear_new:N|,
+% |\prop_(g/)set_eq:(N/c)(N/c)|, |\prop_item:Nn|,
+% |\prop_if_exist:(N/c)|(TF), |\prop_if_empty:N|(TF),
+% |\prop_if_in:Nn|(TF), |\prop_map_function:NN|, |\prop_map_tokens:Nn|,
+% |\prop_map_inline:Nn|, |\prop_(show/log):N|
+%
+% The following abuse |\tl_set:Nn| et al: |\prop_(g/)remove:Nn|, |\prop_(get/pop/gpop):NnN|(TF), |\prop_(g/)put(/_if_new):Nnn|
+%
+% |\prop_get:(N/c)n| (deprecated!)
+%
+% \subsubsection{\pkg{l3msg}}
+%
+% |\msg_(new/set/gset):nnn(/n)|?
+%
+% \subsubsection{\pkg{l3file}}
+%
+% ^^A todo: should \file_add_path:nN be renamed to \file_get_path:nN ?
+%
+% |\file_add_path:nN|, |\io(r/w)_new:N|, |\io(r/w)_open:Nn|,
+% |\ior_open:Nn|(TF), |\io(r/w)_close:N|, |\ior_get(/_str):NN|,
+% |\iow_(now/shipout/shipout_x):Nn| (special case |\c_(log/term)_iow|?),
+% |\iow_char:N|, |\iow_wrap:nnnN|,
+% |\ior_(str_/)map_inline:Nn|,
+%
+% \subsubsection{\pkg{l3skip}}
+%
+% |(dim/skip/muskip)_new:N|
+% |(dim/skip/muskip)_(g/)zero:N|
+% |(dim/skip/muskip)_(g/)zero_new:N|
+% |(dim/skip/muskip)_if_exist:(N/c)|
+% |(dim/skip/muskip)_const:Nn| abuses new and gset
+% |(dim/skip/muskip)_(g/)(set/add/sub):Nn|
+% |(dim/skip/muskip)_(g/)set_eq:NN|
+% |dim_abs:N|
+% |dim_compare:nNn|(TF)
+% |dim_(while_do/until_do/do_while/do_until):nNnn|
+% |(dim/skip/muskip)_(show/log):(N/c)|
+% |skip_(horizontal/vertical):N|
+% |\skip_split_finite_else_action:nnNN| % ^^A todo: rename?
+%
+% Would be nice to change but cannot because of expansion: |(dim/skip/muskip)_use:N|.
+%
+% \subsubsection{\pkg{l3keys}}
+% ^^A todo: add checking of args of key properties such as |.tl_set:N|
+%
+% |\keyval_parse:NNn|, |\keys_set_known:nnN|, |\keys_set_filter:nnnN|,
+%
+% |\keys_(show/log):nn|, |\keys_set:nn|, |\keys_set_known:nn(/N)|,
+% |\keys_set_filter:nnnN|, |\keys_set_groups:nnn|, could check the
+% module is known due to |\keys_define:nn|, \emph{i.e.}, that at least
+% one key is known for this module.
+%
+% \subsubsection{\pkg{l3fp}}
+%
+% |\fp_flag_on:n| must not use \cs{exp_args:Nc}.
+% |\fp_function:Nn|, |\fp_new_function:Npn|, |\fp_if_exist:(N/c)|(TF),
+% |\fp_compare:nNn|(TF), |\fp_(do_until/do_while/until_do/while_do):nNnn|
+% |\fp_to_(scientific/decimal/tl/dim/int):N|, |\fp_use:N|,
+%
+% |\fp_new:N|, |\fp_(set/gset/const):Nn| abuses |\tl_(set/gset/const):Nx|
+% |\fp_(g/)set_eq:NN|, |\fp_(g/)zero(/_new):N|, |\fp_(show/log):N|,
+%
+% |\fp_(g/)set_from_dim:Nn| (deprecated!)
+%
+% \subsubsection{\pkg{l3box}}
+%
+% |\box_new:N|, |\box_(g/)clear(/_new):N|,
+% |\box_(g/)set_eq(/_clear):NN|, |\box_if_exist:(N/c)|(TF)
+% |\box_(ht/dp/wd):N|, |\box_set_(dp/ht/wd):Nn|, |\box_use(/_clear):N|,
+% |\box_if_(horizontal/vertical/empty):N|(TF),
+% |\box_(g/)set_to_last:N|, |\box_(show/log):N(/nn)|,
+% |\hbox_(g/)set(:Nw/:Nn/_to_wd:Nnn)|, |\hbox_unpack(/_clear):N|,
+% |\vbox_set(:Nw/:Nn/_top:Nn/_to_ht:Nnn)|, |\vbox_unpack(/_clear):N|,
+% |\vbox_set_split_to_ht:NNn|,
+% |\box_rotate:Nn|, |\box_resize(/_to_wd_and_ht):Nnn|,
+% |\box_resize_to_(ht/ht_plus_dp/wd):Nn|, |\box_scale:Nnn|,
+% |\box_clip:N|, |\box_(trim/viewport):Nnnnn|,
+%
+% \subsubsection{\pkg{l3coffins}}
+%
+% |\coffin_if_exist:N|(TF), |\coffin_clear:N|, |\coffin_new:N|,
+% |\hcoffin_set(:Nn/:Nw)|, |\vcoffin_set(:Nnn/:Nnw)|,
+% |\coffin_set_eq:NN|, |\coffin_(dp/ht/wd):(N/c)|,
+% |\coffin_set_(horizontal/vertical)_pole:Nnn|,
+% |\coffin_(join/attach/attach_mark):NnnNnnnn|,
+% |\coffin_typeset:Nnnnn|, |\coffin_mark_handle:Nnnn|,
+% |\coffin_display_handles:Nn|, |\coffin_(show/log)_structure:N|,
+% |\coffin_rotate:Nn|, |\coffin_(resize/scale):Nnn|
+%
+% \subsubsection{pkg{l3color}}
+%
+% Alter |\color_group_begin:| if we decide to do something with |\group_begin:|.
+%
+% ^^A todo: inconsistency between \ior_str_map_inline and \ior_get_str
+%
+% ^^A todo: also provide \tl_set_from_file:Nnn as \file_contents_get:nnN ?
+%
+% \subsubsection{More stuff we could do}
+%
% \begin{itemize}
% \item We could check for a scope of \texttt{l} or \texttt{g} in
% \cs{tl_new:N}.
@@ -996,14 +1757,14 @@
% Protected functions whose first argument is a token list which may
% be undefined.
% \begin{macrocode}
- \@@_patch_protected:Npnn \tl_new:N #1 { {#1} }
- { \@@_variable_type_only:nn {#1} { tl } }
- \@@_patch_protected:Npnn \tl_show:N #1 { {#1} }
- { \@@_variable_type_only:nn {#1} { tl } }
- \@@_patch_protected:Npnn \tl_const:Nn #1 { {#1} }
- { \@@_variable_scope_type_only:nnn {#1} { c } { tl } }
- \@@_patch_protected:Npnn \tl_const:Nx #1 { {#1} }
- { \@@_variable_scope_type_only:nnn {#1} { c } { tl } }
+ % \@@_patch_protected:Npnn \tl_new:N #1 { {#1} }
+ % { \@@_variable_type_only:nn {#1} { tl } }
+ % \@@_patch_protected:Npnn \tl_show:N #1 { {#1} }
+ % { \@@_variable_type_only:nn {#1} { tl } }
+ % \@@_patch_protected:Npnn \tl_const:Nn #1 { {#1} }
+ % { \@@_variable_scope_type_only:nnn {#1} { c } { tl } }
+ % \@@_patch_protected:Npnn \tl_const:Nx #1 { {#1} }
+ % { \@@_variable_scope_type_only:nnn {#1} { c } { tl } }
% \end{macrocode}
% \end{macro}
%
@@ -1011,12 +1772,12 @@
% Expandable test whose first argument is a token list which may be
% undefined.
% \begin{macrocode}
- \tl_map_inline:nn
- { \tl_if_exist:NTF \tl_if_exist:NT \tl_if_exist:NF \tl_if_exist_p:N }
- {
- \@@_patch:Npnn #1 ##1 { {##1} }
- { \@@_variable_type_only_expandable:nn {##1} { tl } }
- }
+ % \tl_map_inline:nn
+ % { \tl_if_exist:NTF \tl_if_exist:NT \tl_if_exist:NF \tl_if_exist_p:N }
+ % {
+ % \@@_patch:Npnn #1 ##1 { {##1} }
+ % { \@@_variable_type_only_exp:nn {##1} { tl } }
+ % }
% \end{macrocode}
% \end{macro}
%
@@ -1033,19 +1794,19 @@
% }
% Protected functions whose first argument is a defined, local token list.
% \begin{macrocode}
- \tl_map_inline:nn
- {
- \tl_set:Nn \tl_set:No \tl_set:Nx
- \tl_put_left:Nn \tl_put_left:NV \tl_put_left:No \tl_put_left:Nx
- \tl_put_right:Nn \tl_put_right:NV \tl_put_right:No \tl_put_right:Nx
- \tl_set_rescan:Nnn
- \tl_replace_once:Nnn \tl_replace_all:Nnn
- \tl_trim_spaces:N \tl_reverse:N
- }
- {
- \@@_patch_protected:Npnn #1 ##1 { {##1} }
- { \@@_variable_scope_type:nnn {##1} { l } { tl } }
- }
+ % \tl_map_inline:nn
+ % {
+ % \tl_set:Nn \tl_set:No \tl_set:Nx
+ % \tl_put_left:Nn \tl_put_left:NV \tl_put_left:No \tl_put_left:Nx
+ % \tl_put_right:Nn \tl_put_right:NV \tl_put_right:No \tl_put_right:Nx
+ % \tl_set_rescan:Nnn
+ % \tl_replace_once:Nnn \tl_replace_all:Nnn
+ % \tl_trim_spaces:N \tl_reverse:N
+ % }
+ % {
+ % \@@_patch_protected:Npnn #1 ##1 { {##1} }
+ % { \@@_variable_scope_type:nnn {##1} { l } { tl } }
+ % }
% \end{macrocode}
% \end{macro}
%
@@ -1062,21 +1823,21 @@
% }
% Protected functions whose first argument is a defined, global token list.
% \begin{macrocode}
- \tl_map_inline:nn
- {
- \tl_gset:Nn \tl_gset:No \tl_gset:Nx
- \tl_gput_left:Nn \tl_gput_left:NV
- \tl_gput_left:No \tl_gput_left:Nx
- \tl_gput_right:Nn \tl_gput_right:NV
- \tl_gput_right:No \tl_gput_right:Nx
- \tl_gset_rescan:Nnn
- \tl_greplace_once:Nnn \tl_greplace_all:Nnn
- \tl_gtrim_spaces:N \tl_greverse:N
- }
- {
- \@@_patch_protected:Npnn #1 ##1 { {##1} }
- { \@@_variable_scope_type:nnn {##1} { g } { tl } }
- }
+ % \tl_map_inline:nn
+ % {
+ % \tl_gset:Nn \tl_gset:No \tl_gset:Nx
+ % \tl_gput_left:Nn \tl_gput_left:NV
+ % \tl_gput_left:No \tl_gput_left:Nx
+ % \tl_gput_right:Nn \tl_gput_right:NV
+ % \tl_gput_right:No \tl_gput_right:Nx
+ % \tl_gset_rescan:Nnn
+ % \tl_greplace_once:Nnn \tl_greplace_all:Nnn
+ % \tl_gtrim_spaces:N \tl_greverse:N
+ % }
+ % {
+ % \@@_patch_protected:Npnn #1 ##1 { {##1} }
+ % { \@@_variable_scope_type:nnn {##1} { g } { tl } }
+ % }
% \end{macrocode}
% \end{macro}
%
@@ -1086,16 +1847,16 @@
% list. Importantly, |#1| and |#2| are not braced in the first |n|
% argument of \cs{@@_patch_protected:Npnn}.
% \begin{macrocode}
- \@@_patch_protected:Npnn \tl_set_eq:NN #1#2 { #1 #2 }
- {
- \@@_variable_scope_type:nnn {#1} { l } { tl }
- \@@_variable_type:nn {#2} { tl }
- }
- \@@_patch_protected:Npnn \tl_gset_eq:NN #1#2 { #1 #2 }
- {
- \@@_variable_scope_type:nnn {#1} { g } { tl }
- \@@_variable_type:nn {#2} { tl }
- }
+ % \@@_patch_protected:Npnn \tl_set_eq:NN #1#2 { #1 #2 }
+ % {
+ % \@@_variable_scope_type:nnn {#1} { l } { tl }
+ % \@@_variable_type:nn {#2} { tl }
+ % }
+ % \@@_patch_protected:Npnn \tl_gset_eq:NN #1#2 { #1 #2 }
+ % {
+ % \@@_variable_scope_type:nnn {#1} { g } { tl }
+ % \@@_variable_type:nn {#2} { tl }
+ % }
% \end{macrocode}
% \end{macro}
%
@@ -1103,18 +1864,18 @@
% Protected functions whose three arguments are defined token lists,
% with a first argument local or global depending on the function.
% \begin{macrocode}
- \@@_patch_protected:Npnn \tl_concat:NNN #1#2#3 { {#1} {#2} {#3} }
- {
- \@@_variable_scope_type:nnn {#1} { l } { tl }
- \@@_variable_type:nn {#2} { tl }
- \@@_variable_type:nn {#3} { tl }
- }
- \@@_patch_protected:Npnn \tl_gconcat:NNN #1#2#3 { {#1} {#2} {#3} }
- {
- \@@_variable_scope_type:nnn {#1} { g } { tl }
- \@@_variable_type:nn {#2} { tl }
- \@@_variable_type:nn {#3} { tl }
- }
+ % \@@_patch_protected:Npnn \tl_concat:NNN #1#2#3 { {#1} {#2} {#3} }
+ % {
+ % \@@_variable_scope_type:nnn {#1} { l } { tl }
+ % \@@_variable_type:nn {#2} { tl }
+ % \@@_variable_type:nn {#3} { tl }
+ % }
+ % \@@_patch_protected:Npnn \tl_gconcat:NNN #1#2#3 { {#1} {#2} {#3} }
+ % {
+ % \@@_variable_scope_type:nnn {#1} { g } { tl }
+ % \@@_variable_type:nn {#2} { tl }
+ % \@@_variable_type:nn {#3} { tl }
+ % }
% \end{macrocode}
% \end{macro}
%
@@ -1125,15 +1886,15 @@
% }
% Protected functions whose first argument is a defined token list.
% \begin{macrocode}
- \tl_map_inline:nn
- {
- \tl_map_inline:Nn \tl_map_variable:NNn
- \tl_if_in:NnTF \tl_if_in:NnT \tl_if_in:NnF
- }
- {
- \@@_patch_protected:Npnn #1 ##1 { {##1} }
- { \@@_variable_type:nn {##1} { tl } }
- }
+ % \tl_map_inline:nn
+ % {
+ % \tl_map_inline:Nn \tl_map_variable:NNn
+ % \tl_if_in:NnTF \tl_if_in:NnT \tl_if_in:NnF
+ % }
+ % {
+ % \@@_patch_protected:Npnn #1 ##1 { {##1} }
+ % { \@@_variable_type:nn {##1} { tl } }
+ % }
% \end{macrocode}
% \end{macro}
%
@@ -1141,18 +1902,18 @@
% \begin{macro}[EXP]{\tl_map_function:NN, \tl_head:N, \tl_tail:N}
% Expandable functions whose first argument is a defined token list.
% \begin{macrocode}
- \tl_map_inline:nn
- {
- \tl_if_empty_p:N \tl_if_empty:NTF
- \tl_if_empty:NT \tl_if_empty:NF
- \tl_if_single_p:N \tl_if_single:NTF
- \tl_if_single:NT \tl_if_single:NF
- \tl_map_function:NN \tl_head:N \tl_tail:N
- }
- {
- \@@_patch:Npnn #1 ##1 { {##1} }
- { \@@_variable_type_expandable:nn {##1} { tl } }
- }
+ % \tl_map_inline:nn
+ % {
+ % \tl_if_empty_p:N \tl_if_empty:NTF
+ % \tl_if_empty:NT \tl_if_empty:NF
+ % \tl_if_single_p:N \tl_if_single:NTF
+ % \tl_if_single:NT \tl_if_single:NF
+ % \tl_map_function:NN \tl_head:N \tl_tail:N
+ % }
+ % {
+ % \@@_patch:Npnn #1 ##1 { {##1} }
+ % { \@@_variable_type_exp:nn {##1} { tl } }
+ % }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -1160,15 +1921,15 @@
% \begin{macro}[EXP, pTF]{\tl_if_eq:NN}
% Expandable functions whose two arguments are defined token lists.
% \begin{macrocode}
- \tl_map_inline:nn
- { \tl_if_eq_p:NN \tl_if_eq:NNTF \tl_if_eq:NNT \tl_if_eq:NNF }
- {
- \@@_patch:Npnn #1 ##1##2 { {##1} {##2} }
- {
- \@@_variable_type_expandable:nn {##1} { tl }
- \@@_variable_type_expandable:nn {##2} { tl }
- }
- }
+ % \tl_map_inline:nn
+ % { \tl_if_eq_p:NN \tl_if_eq:NNTF \tl_if_eq:NNT \tl_if_eq:NNF }
+ % {
+ % \@@_patch:Npnn #1 ##1##2 { {##1} {##2} }
+ % {
+ % \@@_variable_type_exp:nn {##1} { tl }
+ % \@@_variable_type_exp:nn {##2} { tl }
+ % }
+ % }
% \end{macrocode}
% \end{macro}
%
@@ -1176,10 +1937,10 @@
% \begin{macro}{\tl_map_variable:nNn}
% An expandable and a protected functions whose second argument is defined.
% \begin{macrocode}
- \@@_patch:Npnn \tl_map_function:nN #1#2 { {#1} {#2} }
- { \@@_cs_exist_expandable:n {#2} }
- \@@_patch_protected:Npnn \tl_map_variable:nNn #1#2 { {#1} {#2} }
- { \@@_cs_exist:n {#2} }
+ % \@@_patch:Npnn \tl_map_function:nN #1#2 { {#1} {#2} }
+ % { \@@_cs_exist_exp:n {#2} }
+ % \@@_patch_protected:Npnn \tl_map_variable:nNn #1#2 { {#1} {#2} }
+ % { \@@_cs_exist:n {#2} }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -1188,18 +1949,16 @@
% We need to redefine that one from scratch, since it may be expected
% to expand in two steps.
% \begin{macrocode}
- \cs_gset:Npn \tl_to_str:N #1
- {
- \etex_detokenize:D
- \@@_if_on:nT { l3tl }
- { \@@_variable_type_expandable:nn {#1} { tl } }
- \exp_after:wN {#1}
- }
+ % \cs_gset:Npn \tl_to_str:N #1
+ % {
+ % \etex_detokenize:D
+ % \@@_if_on:nT { l3tl }
+ % { \@@_variable_type_exp:nn {#1} { tl } }
+ % \exp_after:wN {#1}
+ % }
% \end{macrocode}
% \end{macro}
%
-% \subsubsection{\pkg{l3seq}}
-%
% \begin{itemize}
% \item The \cs{seq_if_exist:NTF} conditionals should also have a type
% check, and their |c| variant should be a true variant.
@@ -1209,10 +1968,10 @@
% Protected functions whose first argument is a sequence which may be
% undefined.
% \begin{macrocode}
- \@@_patch_protected:Npnn \seq_new:N #1 { {#1} }
- { \@@_variable_type_only:nn {#1} { seq } }
- \@@_patch_protected:Npnn \seq_show:N #1 { {#1} }
- { \@@_variable_type_only:nn {#1} { seq } }
+ % \@@_patch_protected:Npnn \seq_new:N #1 { {#1} }
+ % { \@@_variable_type_only:nn {#1} { seq } }
+ % \@@_patch_protected:Npnn \seq_show:N #1 { {#1} }
+ % { \@@_variable_type_only:nn {#1} { seq } }
% \end{macrocode}
% \end{macro}
%
@@ -1220,12 +1979,12 @@
% Expandable test whose first argument is a sequence which may be
% undefined.
% \begin{macrocode}
- \tl_map_inline:nn
- { \seq_if_exist:NTF \seq_if_exist:NT \seq_if_exist:NF \seq_if_exist_p:N }
- {
- \@@_patch:Npnn #1 ##1 { {##1} }
- { \@@_variable_type_only_expandable:nn {##1} { seq } }
- }
+ % \tl_map_inline:nn
+ % { \seq_if_exist:NTF \seq_if_exist:NT \seq_if_exist:NF \seq_if_exist_p:N }
+ % {
+ % \@@_patch:Npnn #1 ##1 { {##1} }
+ % { \@@_variable_type_only_exp:nn {##1} { seq } }
+ % }
% \end{macrocode}
% \end{macro}
%
@@ -1237,16 +1996,16 @@
% }
% Protected functions whose first argument is a defined, local sequence.
% \begin{macrocode}
- \tl_map_inline:nn
- {
- \seq_set_split:Nnn
- \seq_put_left:Nn \seq_put_right:Nn \seq_push:Nn
- \seq_remove_duplicates:N \seq_remove_all:Nn
- }
- {
- \@@_patch_protected:Npnn #1 ##1 { {##1} }
- { \@@_variable_scope_type:nnn {##1} { l } { seq } }
- }
+ % \tl_map_inline:nn
+ % {
+ % \seq_set_split:Nnn
+ % \seq_put_left:Nn \seq_put_right:Nn \seq_push:Nn
+ % \seq_remove_duplicates:N \seq_remove_all:Nn
+ % }
+ % {
+ % \@@_patch_protected:Npnn #1 ##1 { {##1} }
+ % { \@@_variable_scope_type:nnn {##1} { l } { seq } }
+ % }
% \end{macrocode}
% \end{macro}
%
@@ -1258,48 +2017,48 @@
% }
% Check that arguments are defined, have the right type and scope.
% \begin{macrocode}
- \tl_map_inline:nn
- {
- \seq_gset_split:Nnn
- \seq_gput_left:Nn \seq_gput_right:Nn \seq_gpush:Nn
- \seq_gremove_duplicates:N \seq_gremove_all:Nn
- }
- {
- \@@_patch_protected:Npnn #1 ##1 { {##1} }
- { \@@_variable_scope_type:nnn {##1} { g } { seq } }
- }
+ % \tl_map_inline:nn
+ % {
+ % \seq_gset_split:Nnn
+ % \seq_gput_left:Nn \seq_gput_right:Nn \seq_gpush:Nn
+ % \seq_gremove_duplicates:N \seq_gremove_all:Nn
+ % }
+ % {
+ % \@@_patch_protected:Npnn #1 ##1 { {##1} }
+ % { \@@_variable_scope_type:nnn {##1} { g } { seq } }
+ % }
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\seq_set_eq:NN, \seq_gset_eq:NN}
% \begin{macrocode}
- \@@_patch_protected:Npnn \seq_set_eq:NN #1#2 { #1 #2 }
- {
- \@@_variable_scope_type:nnn {#1} { l } { seq }
- \@@_variable_type:nn {#2} { seq }
- }
- \@@_patch_protected:Npnn \seq_gset_eq:NN #1#2 { #1 #2 }
- {
- \@@_variable_scope_type:nnn {#1} { g } { seq }
- \@@_variable_type:nn {#2} { seq }
- }
+ % \@@_patch_protected:Npnn \seq_set_eq:NN #1#2 { #1 #2 }
+ % {
+ % \@@_variable_scope_type:nnn {#1} { l } { seq }
+ % \@@_variable_type:nn {#2} { seq }
+ % }
+ % \@@_patch_protected:Npnn \seq_gset_eq:NN #1#2 { #1 #2 }
+ % {
+ % \@@_variable_scope_type:nnn {#1} { g } { seq }
+ % \@@_variable_type:nn {#2} { seq }
+ % }
% \end{macrocode}
% \end{macro}
%
% \begin{macro}{\seq_concat:NNN, \seq_gconcat:NNN}
% \begin{macrocode}
- \@@_patch_protected:Npnn \seq_concat:NNN #1#2#3 { {#1} {#2} {#3} }
- {
- \@@_variable_scope_type:nnn {#1} { l } { seq }
- \@@_variable_type:nn {#2} { seq }
- \@@_variable_type:nn {#3} { seq }
- }
- \@@_patch_protected:Npnn \seq_gconcat:NNN #1#2#3 { {#1} {#2} {#3} }
- {
- \@@_variable_scope_type:nnn {#1} { g } { seq }
- \@@_variable_type:nn {#2} { seq }
- \@@_variable_type:nn {#3} { seq }
- }
+ % \@@_patch_protected:Npnn \seq_concat:NNN #1#2#3 { {#1} {#2} {#3} }
+ % {
+ % \@@_variable_scope_type:nnn {#1} { l } { seq }
+ % \@@_variable_type:nn {#2} { seq }
+ % \@@_variable_type:nn {#3} { seq }
+ % }
+ % \@@_patch_protected:Npnn \seq_gconcat:NNN #1#2#3 { {#1} {#2} {#3} }
+ % {
+ % \@@_variable_scope_type:nnn {#1} { g } { seq }
+ % \@@_variable_type:nn {#2} { seq }
+ % \@@_variable_type:nn {#3} { seq }
+ % }
% \end{macrocode}
% \end{macro}
%
@@ -1355,17 +2114,6 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\seq_clear:N, \seq_gclear:N}
-% Clearing a sequence should be done by setting it equal to the empty
-% sequence, not a simple copy of the \cs{tl_clear:N} function anymore.
-% \begin{macrocode}
- \cs_gset_protected:Npn \seq_clear:N #1
- { \seq_set_eq:NN #1 \c_empty_seq }
- \cs_gset_protected:Npn \seq_gclear:N #1
- { \seq_gset_eq:NN #1 \c_empty_seq }
-% \end{macrocode}
-% \end{macro}
-%
% \begin{macro}
% {
% \seq_map_inline:Nn,
@@ -1373,36 +2121,36 @@
% }
% Protected functions whose first argument is a defined sequence.
% \begin{macrocode}
- \tl_map_inline:nn
- { \seq_map_inline:Nn \seq_if_in:NnTF \seq_if_in:NnT \seq_if_in:NnF }
- {
- \@@_patch_protected:Npnn #1 ##1 { {##1} }
- { \@@_variable_type:nn {##1} { seq } }
- }
+ % \tl_map_inline:nn
+ % { \seq_map_inline:Nn \seq_if_in:NnTF \seq_if_in:NnT \seq_if_in:NnF }
+ % {
+ % \@@_patch_protected:Npnn #1 ##1 { {##1} }
+ % { \@@_variable_type:nn {##1} { seq } }
+ % }
% \end{macrocode}
% \end{macro}
%
% \begin{macro}[EXP, pTF]{\seq_if_empty:N, \seq_if_eq:NN}
% For these two tests, we check the type, expandably.
% \begin{macrocode}
- \tl_map_inline:nn
- {
- \seq_if_empty_p:N \seq_if_empty:NTF
- \seq_if_empty:NT \seq_if_empty:NF
- }
- {
- \@@_patch:Npnn #1 ##1 { {##1} }
- { \@@_variable_type_expandable:nn {##1} { seq } }
- }
- \tl_map_inline:nn
- { \seq_if_eq_p:NN \seq_if_eq:NNTF \seq_if_eq:NNT \seq_if_eq:NNF }
- {
- \@@_patch:Npnn #1 ##1##2 { {##1} {##2} }
- {
- \@@_variable_type_expandable:nn {##1} { seq }
- \@@_variable_type_expandable:nn {##2} { seq }
- }
- }
+ % \tl_map_inline:nn
+ % {
+ % \seq_if_empty_p:N \seq_if_empty:NTF
+ % \seq_if_empty:NT \seq_if_empty:NF
+ % }
+ % {
+ % \@@_patch:Npnn #1 ##1 { {##1} }
+ % { \@@_variable_type_exp:nn {##1} { seq } }
+ % }
+ % \tl_map_inline:nn
+ % { \seq_if_eq_p:NN \seq_if_eq:NNTF \seq_if_eq:NNT \seq_if_eq:NNF }
+ % {
+ % \@@_patch:Npnn #1 ##1##2 { {##1} {##2} }
+ % {
+ % \@@_variable_type_exp:nn {##1} { seq }
+ % \@@_variable_type_exp:nn {##2} { seq }
+ % }
+ % }
% \end{macrocode}
% \end{macro}
%
@@ -1451,80 +2199,75 @@
% Since the \cs{seq_map_variable:NNn} needs the same checks as the
% |get| functions, we patch it here too.
% \begin{macrocode}
- \tl_map_inline:nn
- {
- \seq_map_variable:NNn
- \seq_get_left:NN \seq_get_left:NNT
- \seq_get_left:NNF \seq_get_left:NNTF
- \seq_get_right:NN \seq_get_right:NNT
- \seq_get_right:NNF \seq_get_right:NNTF
- \seq_get:NN \seq_get:NNT \seq_get:NNF \seq_get:NNTF
- }
- {
- \@@_patch_protected:Npnn #1 ##1##2 { {##1} {##2} }
- {
- \@@_variable_type:nn {##1} { seq }
- \@@_variable_type:nn {##2} { tl }
- }
- }
- \tl_map_inline:nn
- {
- \seq_pop_left:NN \seq_pop_left:NNT
- \seq_pop_left:NNF \seq_pop_left:NNTF
- \seq_pop_right:NN \seq_pop_right:NNT
- \seq_pop_right:NNF \seq_pop_right:NNTF
- \seq_pop:NN \seq_pop:NNT \seq_pop:NNF \seq_pop:NNTF
- }
- {
- \@@_patch_protected:Npnn #1 ##1##2 { {##1} {##2} }
- {
- \@@_variable_scope_type:nnn {##1} { l } { seq }
- \@@_variable_type:nn {##2} { tl }
- }
- }
- \tl_map_inline:nn
- {
- \seq_gpop_left:NN \seq_gpop_left:NNT
- \seq_gpop_left:NNF \seq_gpop_left:NNTF
- \seq_gpop_right:NN \seq_gpop_right:NNT
- \seq_gpop_right:NNF \seq_gpop_right:NNTF
- \seq_gpop:NN \seq_gpop:NNT \seq_gpop:NNF \seq_gpop:NNTF
- }
- {
- \@@_patch_protected:Npnn #1 ##1##2 { {##1} {##2} }
- {
- \@@_variable_scope_type:nnn {##1} { g } { seq }
- \@@_variable_type:nn {##2} { tl }
- }
- }
+ % \tl_map_inline:nn
+ % {
+ % \seq_map_variable:NNn
+ % \seq_get_left:NN \seq_get_left:NNT
+ % \seq_get_left:NNF \seq_get_left:NNTF
+ % \seq_get_right:NN \seq_get_right:NNT
+ % \seq_get_right:NNF \seq_get_right:NNTF
+ % \seq_get:NN \seq_get:NNT \seq_get:NNF \seq_get:NNTF
+ % }
+ % {
+ % \@@_patch_protected:Npnn #1 ##1##2 { {##1} {##2} }
+ % {
+ % \@@_variable_type:nn {##1} { seq }
+ % \@@_variable_type:nn {##2} { tl }
+ % }
+ % }
+ % \tl_map_inline:nn
+ % {
+ % \seq_pop_left:NN \seq_pop_left:NNT
+ % \seq_pop_left:NNF \seq_pop_left:NNTF
+ % \seq_pop_right:NN \seq_pop_right:NNT
+ % \seq_pop_right:NNF \seq_pop_right:NNTF
+ % \seq_pop:NN \seq_pop:NNT \seq_pop:NNF \seq_pop:NNTF
+ % }
+ % {
+ % \@@_patch_protected:Npnn #1 ##1##2 { {##1} {##2} }
+ % {
+ % \@@_variable_scope_type:nnn {##1} { l } { seq }
+ % \@@_variable_type:nn {##2} { tl }
+ % }
+ % }
+ % \tl_map_inline:nn
+ % {
+ % \seq_gpop_left:NN \seq_gpop_left:NNT
+ % \seq_gpop_left:NNF \seq_gpop_left:NNTF
+ % \seq_gpop_right:NN \seq_gpop_right:NNT
+ % \seq_gpop_right:NNF \seq_gpop_right:NNTF
+ % \seq_gpop:NN \seq_gpop:NNT \seq_gpop:NNF \seq_gpop:NNTF
+ % }
+ % {
+ % \@@_patch_protected:Npnn #1 ##1##2 { {##1} {##2} }
+ % {
+ % \@@_variable_scope_type:nnn {##1} { g } { seq }
+ % \@@_variable_type:nn {##2} { tl }
+ % }
+ % }
% \end{macrocode}
% \end{macro}
%
% \begin{macro}[EXP]{\seq_map_function:NN}
% Check that |#1| is a |seq| and |#2| is defined.
% \begin{macrocode}
- \@@_patch:Npnn \seq_map_function:NN #1#2 { {#1} {#2} }
- {
- \@@_variable_type_expandable:nn {#1} { seq }
- \@@_cs_exist_expandable:n {#2}
- }
+ % \@@_patch:Npnn \seq_map_function:NN #1#2 { {#1} {#2} }
+ % {
+ % \@@_variable_type_exp:nn {#1} { seq }
+ % \@@_cs_exist_exp:n {#2}
+ % }
% \end{macrocode}
% \end{macro}
%
-% \subsubsection{\pkg{l3int}}
+% \subsection{Let us go!}
%
-% \subsubsection{\pkg{l3quark}}
-%
-% \subsubsection{\pkg{l3prg}}
-%
-%
% \begin{macrocode}
- }
\check_on:n { l3kernel }
% \end{macrocode}
%
% \subsection{\texttt{l3kernel} test files failures}
%
+% Note: this section has not been updated recently.
% \begin{itemize}
% \item \file{m3basics002}: \cs{prg_new_conditional:Npnn} with an
% unknown or empty condition leads to \cs{use:c} with undefined
More information about the latex3-commits
mailing list