diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3basics.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3basics.dtx | 1343 |
1 files changed, 764 insertions, 579 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx b/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx index f6be95ab725..549ec6de6f8 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx @@ -35,8 +35,8 @@ % %<*driver|package> \RequirePackage{l3names} -\GetIdInfo$Id: l3basics.dtx 3491 2012-03-04 06:13:18Z bruno $ - {L3 Experimental basic definitions} +\GetIdInfo$Id: l3basics.dtx 3987 2012-07-15 21:57:39Z joseph $ + {L3 Basic definitions} %</driver|package> %<*driver> \documentclass[full]{l3doc} @@ -155,36 +155,36 @@ % for the formal parameters (|#1|, |#2|, \ldots). % \begin{description} % \item[\texttt{new}] -% Create a new function with the \texttt{new} primitives, +% Create a new function with the \texttt{new} scope, % such as \cs{cs_new:Npn}. The definition is global and will result in % an error if it is already defined. % \item[\texttt{set}] -% Create a new function with the \texttt{set} primitives, +% Create a new function with the \texttt{set} scope, % such as \cs{cs_set:Npn}. The definition is restricted to the current % \TeX{} group and will not result in an error if the function is already % defined. % \item[\texttt{gset}] -% Create a new function with the \texttt{gset} primitives, +% Create a new function with the \texttt{gset} scope, % such as \cs{cs_gset:Npn}. The definition is global and % will not result in an error if the function is already defined. % \end{description} % -% Within each set of primitives there are different ways to define a function. +% Within each set of scope there are different ways to define a function. % The differences depend on restrictions on the actual parameters and % the expandability of the resulting function. % \begin{description} % \item[\texttt{nopar}] -% Create a new function with the \texttt{nopar} primitives, +% Create a new function with the \texttt{nopar} restriction, % such as \cs{cs_set_nopar:Npn}. The parameter may not contain % \cs{par} tokens. % \item[\texttt{protected}] -% Create a new function with the \texttt{protected} primitives, +% Create a new function with the \texttt{protected} restriction, % such as \cs{cs_set_protected:Npn}. The parameter may contain % \cs{par} tokens but the function will not expand within an % \texttt{x}-type expansion. % \end{description} % -% \subsection{Defining new functions using primitive parameter text} +% \subsection{Defining new functions using parameter text} % % \begin{function}{\cs_new:Npn, \cs_new:cpn, \cs_new:Npx, \cs_new:cpx} % \begin{syntax} @@ -613,11 +613,11 @@ % \begin{function} % {\cs_new_eq:NN, \cs_new_eq:Nc, \cs_new_eq:cN, \cs_new_eq:cc} % \begin{syntax} -% \cs{cs_new_eq:NN} \meta{cs 1} \meta{cs 2} -% \cs{cs_new_eq:NN} \meta{cs 1} \meta{token} +% \cs{cs_new_eq:NN} \meta{cs_1} \meta{cs_2} +% \cs{cs_new_eq:NN} \meta{cs_1} \meta{token} % \end{syntax} -% Globally creates \meta{control sequence 1} and sets it to have the same -% meaning as \meta{control sequence 2} or <token>. +% Globally creates \meta{control sequence_1} and sets it to have the same +% meaning as \meta{control sequence_2} or <token>. % The second control sequence may % subsequently be altered without affecting the copy. % \end{function} @@ -625,28 +625,28 @@ % \begin{function} % {\cs_set_eq:NN, \cs_set_eq:Nc, \cs_set_eq:cN, \cs_set_eq:cc} % \begin{syntax} -% \cs{cs_set_eq:NN} \meta{cs 1} \meta{cs 2} -% \cs{cs_set_eq:NN} \meta{cs 1} \meta{token} +% \cs{cs_set_eq:NN} \meta{cs_1} \meta{cs_2} +% \cs{cs_set_eq:NN} \meta{cs_1} \meta{token} % \end{syntax} -% Sets \meta{control sequence 1} to have the same meaning as -% \meta{control sequence 2} (or <token>). +% Sets \meta{control sequence_1} to have the same meaning as +% \meta{control sequence_2} (or <token>). % The second control sequence may subsequently be % altered without affecting the copy. The assignment of a meaning -% to the \meta{control sequence 1} is restricted to the current +% to the \meta{control sequence_1} is restricted to the current % \TeX{} group level. % \end{function} % % \begin{function} % {\cs_gset_eq:NN, \cs_gset_eq:Nc, \cs_gset_eq:cN, \cs_gset_eq:cc} % \begin{syntax} -% \cs{cs_gset_eq:NN} \meta{cs 1} \meta{cs 2} -% \cs{cs_gset_eq:NN} \meta{cs 1} \meta{token} +% \cs{cs_gset_eq:NN} \meta{cs_1} \meta{cs_2} +% \cs{cs_gset_eq:NN} \meta{cs_1} \meta{token} % \end{syntax} -% Globally sets \meta{control sequence 1} to have the same meaning as -% \meta{control sequence 2} (or <token>). +% Globally sets \meta{control sequence_1} to have the same meaning as +% \meta{control sequence_2} (or <token>). % The second control sequence may subsequently be % altered without affecting the copy. The assignment of a meaning to -% the \meta{control sequence 1} is \emph{not} restricted to the current +% the \meta{control sequence_1} is \emph{not} restricted to the current % \TeX{} group level: the assignment is global. % \end{function} % @@ -938,56 +938,6 @@ % in the input stream for further processing. % \end{function} % -% \subsection{Decomposing control sequences} -% -% \begin{function}[EXP]{\cs_get_arg_count_from_signature:N} -% \begin{syntax} -% \cs{cs_get_arg_count_from_signature:N} \meta{function} -% \end{syntax} -% Splits the \meta{function} into the \meta{name} (\emph{i.e.}~the part -% before the colon) and the \meta{signature} (\emph{i.e.}~after the colon). -% The \meta{number} of tokens in the \meta{signature} is then left in -% the input stream. If there was no \meta{signature} then the result is -% the marker value $-1$. -% \end{function} -% -% \begin{function}[EXP]{\cs_get_function_name:N} -% \begin{syntax} -% \cs{cs_get_function_name:N} \meta{function} -% \end{syntax} -% Splits the \meta{function} into the \meta{name} (\emph{i.e.}~the part -% before the colon) and the \meta{signature} (\emph{i.e.}~after the colon). -% The \meta{name} is then left in the input stream without the escape -% character present made up of tokens with category code $12$ -% (other). -% \end{function} -% -% \begin{function}[EXP]{\cs_get_function_signature:N} -% \begin{syntax} -% \cs{cs_get_function_signature:N} \meta{function} -% \end{syntax} -% Splits the \meta{function} into the \meta{name} (\emph{i.e.}~the part -% before the colon) and the \meta{signature} (\emph{i.e.}~after the colon). -% The \meta{signature} is then left in the input stream made up of -% tokens with category code $12$ (other). -% \end{function} -% -% \begin{function}[EXP]{\cs_split_function:NN} -% \begin{syntax} -% \cs{cs_split_function:NN} \meta{function} \meta{processor} -% \end{syntax} -% Splits the \meta{function} into the \meta{name} (\emph{i.e.}~the part -% before the colon) and the \meta{signature} (\emph{i.e.}~after the colon). -% This information is then placed in the input stream after the -% \meta{processor} function in three parts: the \meta{name}, the -% \meta{signature} and a logic token indicating if a colon was found -% (to differentiate variables from function names). The \meta{name} -% will not include the escape character, and both the \meta{name} and -% \meta{signature} are made up of tokens with category code $12$ -% (other). The \meta{processor} should be a function with argument -% specification \texttt{:nnN} (plus any trailing arguments needed). -% \end{function} -% % \section{Predicates and conditionals} % \label{sec:predicates} % @@ -1031,7 +981,7 @@ % are expandable and have names that end with |_p| in the % description part. For example, % \begin{quote} -% |\cs_if_free_p:N| +% \cs{cs_if_free_p:N} % \end{quote} % would be a predicate function for the same type of test as the % conditional described above. It would return \enquote{true} if its @@ -1100,7 +1050,7 @@ % \begin{function}[EXP,pTF] % { % \str_if_eq:nn, \str_if_eq:Vn, \str_if_eq:on, \str_if_eq:no, -% \str_if_eq:nV, \str_if_eq:VV, \str_if_eq:xx +% \str_if_eq:nV, \str_if_eq:VV % } % \begin{syntax} % \cs{str_if_eq_p:nn} \Arg{tl_1} \Arg{tl_2} @@ -1110,11 +1060,63 @@ % basis, and is \texttt{true} if the two lists contain the same % characters in the same order. Thus for example % \begin{verbatim} -% \str_if_eq_p:xx { abc } { \tl_to_str:n { abc } } +% \str_if_eq_p:no { abc } { \tl_to_str:n { abc } } +% \end{verbatim} +% is logically \texttt{true}. +% \end{function} +% +% \begin{function}[EXP,pTF, added = 2012-06-05]{\str_if_eq_x:nn} +% \begin{syntax} +% \cs{str_if_eq_x_p:nn} \Arg{tl_1} \Arg{tl_2} +% \cs{str_if_eq_x:nnTF} \Arg{tl_1} \Arg{tl_2} \Arg{true code} \Arg{false code} +% \end{syntax} +% Compares the full expansion of two \meta{token lists} on a character by +% character basis, and is \texttt{true} if the two lists contain the same +% characters in the same order. Thus for example +% \begin{verbatim} +% \str_if_eq_x_p:nn { abc } { \tl_to_str:n { abc } } % \end{verbatim} -% is logically \texttt{true}. All versions of these functions are fully -% expandable (including those involving an \texttt{x}-type -% expansion). +% is logically \texttt{true}. +% \end{function} +% +% \begin{function}[added = 2012-06-03, EXP]{\str_case:nnn, \str_case:onn} +% \begin{syntax} +% \cs{str_case:nnn} \Arg{test string} \\ +% ~~|{| \\ +% ~~~~\Arg{string case_1} \Arg{code case_1} \\ +% ~~~~\Arg{string case_2} \Arg{code case_2} \\ +% ~~~~\ldots \\ +% ~~~~\Arg{string case_n} \Arg{code case_n} \\ +% ~~|}| \\ +% ~~\Arg{else code} +% \end{syntax} +% This function compares the \meta{test string} in turn with each +% of the \meta{string cases}. If the two are equal (as described for +% \cs{str_if_eq:nnTF} then the +% associated \meta{code} is left in the input stream. If none of +% the tests are \texttt{true} then the \texttt{else code} will be +% left in the input stream. +% \end{function} +% +% \begin{function}[added = 2012-06-05, EXP]{\str_case_x:nnn} +% \begin{syntax} +% \cs{str_case_x:nnn} \Arg{test string} \\ +% ~~|{| \\ +% ~~~~\Arg{string case_1} \Arg{code case_1} \\ +% ~~~~\Arg{string case_2} \Arg{code case_2} \\ +% ~~~~\ldots \\ +% ~~~~\Arg{string case_n} \Arg{code case_n} \\ +% ~~|}| \\ +% ~~\Arg{else code} +% \end{syntax} +% This function comapres the full expansion of the \meta{test string} +% in turn with the full expansion of the \meta{string cases}. If the two +% full expansions are equal (as described for \cs{str_if_eq:nnTF} then the +% associated \meta{code} is left in the input stream. If none of the tests +% are \texttt{true} then the \texttt{else code} will be left in the input +% stream. The \meta{test string} is expanded in each comparison, and must +% always yield the same result: for example, random numbers should +% not be used within this string. % \end{function} % % \subsection{Engine-specific conditionals} @@ -1146,7 +1148,7 @@ % expand whatever comes after them and others don't. Hence the names % for these underlying functions will often contain a |:w| part but % higher level functions are often available. See for instance -% |\int_compare_p:nNn| which is a wrapper for |\if_num:w|. +% \cs{int_compare_p:nNn} which is a wrapper for \cs{if_int_compare:w}. % % Certain conditionals deal with specific data types like boxes and % fonts and are described there. The ones described below are either @@ -1167,7 +1169,7 @@ % for more. % \begin{texnote} % These are equivalent to their corresponding \TeX\ primitive -% conditionals; |\reverse_if:N| is \eTeX's |\unless|. +% conditionals; \cs{reverse_if:N} is \eTeX's \tn{unless}. % \end{texnote} % \end{function} % @@ -1180,7 +1182,7 @@ % <arg_1> and <arg_2> could be functions, variables, tokens; in all cases the % \emph{unexpanded} definitions are compared. % \begin{texnote} -% This is \TeX{}'s |\ifx|. +% This is \TeX{}'s \tn{ifx}. % \end{texnote} % \end{function} % @@ -1223,45 +1225,105 @@ % % \section{Internal kernel functions} % -% \begin{function}{\chk_if_exist_cs:N, \chk_if_exist_cs:c} +% \begin{function}{\__chk_if_exist_cs:N, \__chk_if_exist_cs:c} % \begin{syntax} -% \cs{chk_if_exist_cs:N} \meta{cs} +% \cs{__chk_if_exist_cs:N} \meta{cs} % \end{syntax} % This function checks that \meta{cs} exists according to the % criteria for \cs{cs_if_exist_p:N}, and if not raises a kernel-level % error. % \end{function} % -% \begin{function}{\chk_if_free_cs:N, \chk_if_free_cs:c} +% \begin{function}{\__chk_if_free_cs:N, \__chk_if_free_cs:c} % \begin{syntax} -% \cs{chk_if_free_cs:N} \meta{cs} +% \cs{__chk_if_free_cs:N} \meta{cs} % \end{syntax} % This function checks that \meta{cs} is free according to the % criteria for \cs{cs_if_free_p:N}, and if not raises a kernel-level % error. % \end{function} % -% \section{Experimental functions} +% \begin{function}[EXP]{\__cs_count_signature:N, \__cs_count_signature:c} +% \begin{syntax} +% \cs{__cs_count_signature:N} \meta{function} +% \end{syntax} +% Splits the \meta{function} into the \meta{name} (\emph{i.e.}~the part +% before the colon) and the \meta{signature} (\emph{i.e.}~after the colon). +% The \meta{number} of tokens in the \meta{signature} is then left in +% the input stream. If there was no \meta{signature} then the result is +% the marker value $-1$. +% \end{function} % -% \begin{function}[EXP,TF,added=2011-10-10] -% {\cs_if_exist_use:N, \cs_if_exist_use:c} +% \begin{function}[EXP]{\__cs_split_function:NN} % \begin{syntax} -% \cs{cs_if_exist_use:NTF} \meta{control sequence} \Arg{true code} \Arg{false code} +% \cs{__cs_split_function:NN} \meta{function} \meta{processor} % \end{syntax} -% If the \meta{control sequence} exists, leave it in the input stream, -% followed by the \meta{true code} (unbraced). Otherwise, leave the -% \meta{false} code in the input stream. For example, -% \begin{verbatim} -% \cs_set:Npn \mypkg_use_character:N #1 -% { \cs_if_exist_use:cF { mypkg_#1:n } { \mypkg_default:N #1 } } -% \end{verbatim} -% calls the function |\mypkg_#1:n| if it exists, and falls back to -% a default action otherwise. This could also be done (more slowly) -% using \cs{prg_case_str:xxn}. -% \begin{texnote} -% The \texttt{c} variants do not introduce the \meta{control sequence} -% in the hash table if it is not there. -% \end{texnote} +% Splits the \meta{function} into the \meta{name} (\emph{i.e.}~the part +% before the colon) and the \meta{signature} (\emph{i.e.}~after the colon). +% This information is then placed in the input stream after the +% \meta{processor} function in three parts: the \meta{name}, the +% \meta{signature} and a logic token indicating if a colon was found +% (to differentiate variables from function names). The \meta{name} +% will not include the escape character, and both the \meta{name} and +% \meta{signature} are made up of tokens with category code $12$ +% (other). The \meta{processor} should be a function with argument +% specification \texttt{:nnN} (plus any trailing arguments needed). +% \end{function} +% +% \begin{function}[EXP]{\__cs_get_function_name:N} +% \begin{syntax} +% \cs{__cs_get_function_name:N} \meta{function} +% \end{syntax} +% Splits the \meta{function} into the \meta{name} (\emph{i.e.}~the part +% before the colon) and the \meta{signature} (\emph{i.e.}~after the colon). +% The \meta{name} is then left in the input stream without the escape +% character present made up of tokens with category code $12$ +% (other). +% \end{function} +% +% \begin{function}[EXP]{\__cs_get_function_signature:N} +% \begin{syntax} +% \cs{__cs_get_function_signature:N} \meta{function} +% \end{syntax} +% Splits the \meta{function} into the \meta{name} (\emph{i.e.}~the part +% before the colon) and the \meta{signature} (\emph{i.e.}~after the colon). +% The \meta{signature} is then left in the input stream made up of +% tokens with category code $12$ (other). +% \end{function} +% +% \begin{function}{\__cs_tmp:w} +% Function used for various short-term usages, for instance defining +% functions whose definition involves tokens which are hard to insert +% normally (spaces, charactes with category other). +% \end{function} +% +% \begin{function}{\__kernel_register_show:N, \__kernel_register_show:c} +% \begin{syntax} +% \cs{\__kernel_register_show:N} \meta{register} +% \end{syntax} +% Used to show the contents of a \TeX{} register at the terminal, formatted +% such that internal parts of the mechanism are not visible. +% \end{function} +% +% \begin{function}{\__prg_case_end:nw} +% \begin{syntax} +% \cs{__prg_case_end:nw} \Arg{code} \meta{tokens} \cs{q_recursion_stop} +% \end{syntax} +% Used to terminate case statements (\cs{int_case:nnn}, \emph{etc.}) +% by removing trailing \meta{tokens} and the end marker +% \cs{q_recursion_stop}, and inserting the \meta{code} for the successful +% case. +% \end{function} +% +% \begin{function}{\__str_if_eq_x_return:nn} +% \begin{syntax} +% \cs{__str_if_eq_x_return:nn} \Arg{tl_1} \Arg{tl_2} +% \end{syntax} +% Compares the full expansion of two \meta{token lists} on a character by +% character basis, and is \texttt{true} if the two lists contain the same +% characters in the same order. Either \cs{prg_return_true:} or +% \cs{prg_return_false:} is then left in the input stream. This is a version +% of \cs{str_if_eq_x:nn(TF)} coded for speed. % \end{function} % % \end{documentation} @@ -1278,7 +1340,7 @@ %<*package> \ProvidesExplPackage {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} -\package_check_loaded_expl: +\__expl_package_check: %</package> % \end{macrocode} % @@ -1370,11 +1432,11 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}[EXP]{\if_int_compare:w, \int_to_roman:w} +% \begin{macro}[EXP]{\if_int_compare:w, \__int_to_roman:w} % For integers. % \begin{macrocode} \tex_let:D \if_int_compare:w \tex_ifnum:D -\tex_let:D \int_to_roman:w \tex_romannumeral:D +\tex_let:D \__int_to_roman:w \tex_romannumeral:D % \end{macrocode} % \end{macro} % @@ -1385,15 +1447,6 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}{\tex_global:D, \tex_long:D, \etex_protected:D} -% Three prefixes for assignments. -% \begin{macrocode} -\tex_let:D \tex_global:D \tex_global:D -\tex_let:D \tex_long:D \tex_long:D -\tex_let:D \tex_protected:D \etex_protected:D -% \end{macrocode} -% \end{macro} -% % \begin{macro}[EXP]{\exp_args:Nc} % Discussed in \pkg{l3expan}, but needed much earlier. % \begin{macrocode} @@ -1403,15 +1456,16 @@ % % \begin{macro}[EXP]{\token_to_str:c, \cs_meaning:c} % \begin{macro}{\cs_show:c} -% A small number of variants by hand. Some of the necessary functions +% A small number of variants defined by hand. +% Some of the necessary functions % (\cs{use_i:nn}, \cs{use_ii:nn}, and \cs{exp_args:NNc}) are not % defined at that point yet, but will be defined before those variants % are used. The \cs{cs_meaning:c} command must check for an undefined % control sequence to avoid defining it mistakenly. The % \cs{cs_show:c} command is \enquote{protected} because its action is % not expandable. Also, the conversion of its argument to a control -% sequence is done within a group to avoid converting it to -% \tn{relax}. +% sequence is done within a group to avoid showing \tn{relax} for +% undefined control sequences. % \begin{macrocode} \tex_def:D \token_to_str:c { \exp_args:Nc \token_to_str:N } \tex_long:D \tex_def:D \cs_meaning:c #1 @@ -1424,7 +1478,7 @@ { \exp_args:Nc \cs_meaning:N {#1} } { \tl_to_str:n {undefined} } } -\tex_protected:D \tex_def:D \cs_show:c +\etex_protected:D \tex_def:D \cs_show:c { \group_begin: \exp_args:NNc \group_end: \cs_show:N } % \end{macrocode} % \end{macro} @@ -1434,17 +1488,17 @@ % % \begin{variable}{\c_minus_one, \c_zero, \c_sixteen} % \begin{variable}{\c_six, \c_seven, \c_twelve} -% We need the constants |\c_minus_one| and |\c_sixteen| now for -% writing information to the log and the terminal and |\c_zero| +% We need the constants \cs{c_minus_one} and \cs{c_sixteen} now for +% writing information to the log and the terminal and \cs{c_zero} % which is used by some functions in the \textsf{l3alloc} module. The % rest are defined in the \textsf{l3int} module -- at least for the -% ones that can be defined with |\tex_chardef:D| or -% |\tex_mathchardef:D|. For other constants the \textsf{l3int} module is +% ones that can be defined with \cs{tex_chardef:D} or +% \cs{tex_mathchardef:D}. For other constants the \textsf{l3int} module is % required but it can't be used until the allocation has been set % up properly! The actual allocation mechanism is in % \textsf{l3alloc} and as \TeX{} wants to reserve count registers % 0--9, the first available one is~10 so we use that for -% |\c_minus_one|. +% \cs{c_minus_one}. % \begin{macrocode} %<*package> \tex_let:D \c_minus_one \m@ne @@ -1453,18 +1507,18 @@ \tex_countdef:D \c_minus_one = 10 ~ \c_minus_one = -1 ~ %</initex> -\tex_chardef:D \c_sixteen = 16~ -\tex_chardef:D \c_zero = 0~ -\tex_chardef:D \c_six = 6~ -\tex_chardef:D \c_seven = 7~ -\tex_chardef:D \c_twelve = 12~ +\tex_chardef:D \c_sixteen = 16 ~ +\tex_chardef:D \c_zero = 0 ~ +\tex_chardef:D \c_six = 6 ~ +\tex_chardef:D \c_seven = 7 ~ +\tex_chardef:D \c_twelve = 12 ~ % \end{macrocode} % \end{variable} % \end{variable} % % \begin{variable}{\c_max_register_int} % This is here as this particular integer is needed both in package -% mode and to bootstrap \pkg{l3alloc}. +% mode and to bootstrap \pkg{l3alloc}, and is documented in \pkg{l3int}. % \begin{macrocode} \etex_ifdefined:D \luatex_luatexversion:D \tex_chardef:D \c_max_register_int = 65 535 ~ @@ -1486,24 +1540,24 @@ % \cs_set_protected_nopar:Npn , \cs_set_protected_nopar:Npx , % \cs_set_protected:Npn , \cs_set_protected:Npx % } -% All assignment functions in \LaTeX3 should be naturally robust; +% All assignment functions in \LaTeX3 should be naturally protected; % after all, the \TeX{} primitives for assignments are and it can be % a cause of problems if others aren't. % \begin{macrocode} \tex_let:D \cs_set_nopar:Npn \tex_def:D \tex_let:D \cs_set_nopar:Npx \tex_edef:D -\tex_protected:D \cs_set_nopar:Npn \cs_set:Npn +\etex_protected:D \cs_set_nopar:Npn \cs_set:Npn { \tex_long:D \cs_set_nopar:Npn } -\tex_protected:D \cs_set_nopar:Npn \cs_set:Npx +\etex_protected:D \cs_set_nopar:Npn \cs_set:Npx { \tex_long:D \cs_set_nopar:Npx } -\tex_protected:D \cs_set_nopar:Npn \cs_set_protected_nopar:Npn - { \tex_protected:D \cs_set_nopar:Npn } -\tex_protected:D \cs_set_nopar:Npn \cs_set_protected_nopar:Npx - { \tex_protected:D \cs_set_nopar:Npx } +\etex_protected:D \cs_set_nopar:Npn \cs_set_protected_nopar:Npn + { \etex_protected:D \cs_set_nopar:Npn } +\etex_protected:D \cs_set_nopar:Npn \cs_set_protected_nopar:Npx + { \etex_protected:D \cs_set_nopar:Npx } \cs_set_protected_nopar:Npn \cs_set_protected:Npn - { \tex_protected:D \tex_long:D \cs_set_nopar:Npn } + { \etex_protected:D \tex_long:D \cs_set_nopar:Npn } \cs_set_protected_nopar:Npn \cs_set_protected:Npx - { \tex_protected:D \tex_long:D \cs_set_nopar:Npx } + { \etex_protected:D \tex_long:D \cs_set_nopar:Npx } % \end{macrocode} % \end{macro} % @@ -1523,13 +1577,13 @@ \cs_set_protected_nopar:Npn \cs_gset:Npx { \tex_long:D \cs_gset_nopar:Npx } \cs_set_protected_nopar:Npn \cs_gset_protected_nopar:Npn - { \tex_protected:D \cs_gset_nopar:Npn } + { \etex_protected:D \cs_gset_nopar:Npn } \cs_set_protected_nopar:Npn \cs_gset_protected_nopar:Npx - { \tex_protected:D \cs_gset_nopar:Npx } + { \etex_protected:D \cs_gset_nopar:Npx } \cs_set_protected_nopar:Npn \cs_gset_protected:Npn - { \tex_protected:D \tex_long:D \cs_gset_nopar:Npn } + { \etex_protected:D \tex_long:D \cs_gset_nopar:Npn } \cs_set_protected_nopar:Npn \cs_gset_protected:Npx - { \tex_protected:D \tex_long:D \cs_gset_nopar:Npx } + { \etex_protected:D \tex_long:D \cs_gset_nopar:Npx } % \end{macrocode} % \end{macro} % @@ -1544,18 +1598,18 @@ % % \begin{macro}{\use:x} % Fully expands its argument and passes it to the input stream. Uses -% the reserved \cs{l_exp_internal_tl} which will be set up in \pkg{l3expan}. +% the reserved \cs{l__exp_internal_tl} which will be set up in \pkg{l3expan}. % \begin{macrocode} \cs_set_protected:Npn \use:x #1 { - \cs_set_nopar:Npx \l_exp_internal_tl {#1} - \l_exp_internal_tl + \cs_set_nopar:Npx \l__exp_internal_tl {#1} + \l__exp_internal_tl } % \end{macrocode} % \end{macro} % % \begin{macro}[EXP]{\use:n, \use:nn, \use:nnn, \use:nnnn} -% These macro grabs its arguments and returns it back to the input +% These macros grab their arguments and returns them back to the input % (with outer braces removed). % \begin{macrocode} \cs_set:Npn \use:n #1 {#1} @@ -1663,20 +1717,25 @@ % testing and processing must return the \meta{state} this leaves % \TeX{} in. Therefore, a simple user interface could be something like % \begin{verbatim} -% \if_meaning:w #1#2 \prg_return_true: \else: -% \if_meaning:w #1#3 \prg_return_true: \else: -% \prg_return_false: -% \fi: \fi: +% \if_meaning:w #1#2 +% \prg_return_true: +% \else: +% \if_meaning:w #1#3 +% \prg_return_true: +% \else: +% \prg_return_false: +% \fi: +% \fi: % \end{verbatim} % Usually, a \TeX{} programmer would have to insert a number of -% |\exp_after:wN|s to ensure the state value is returned at exactly +% \cs{exp_after:wN}s to ensure the state value is returned at exactly % the point where the last conditional is finished. However, that % obscures the code and forces the \TeX{} programmer to prove that % he/she knows the $2^{n}-1$ table. We therefore provide the simpler % interface. % % \begin{macro}[EXP]{\prg_return_true:, \prg_return_false:} -% The idea here is that \cs{int_to_roman:w} will expand fully any +% The idea here is that \cs{__int_to_roman:w} will expand fully any % \cs{else:} and the \cs{fi:} that are waiting to be discarded, % before reaching the \cs{c_zero} which will leave the expansion null. % The code can then leave either the first or second argument in the @@ -1685,9 +1744,9 @@ % to see this. % \begin{macrocode} \cs_set_nopar:Npn \prg_return_true: - { \exp_after:wN \use_i:nn \int_to_roman:w } + { \exp_after:wN \use_i:nn \__int_to_roman:w } \cs_set_nopar:Npn \prg_return_false: - { \exp_after:wN \use_ii:nn \int_to_roman:w} + { \exp_after:wN \use_ii:nn \__int_to_roman:w} % \end{macrocode} % An extended state space could be implemented by including a more % elaborate function in place of \cs{use_i:nn}/\cs{use_ii:nn}. Provided @@ -1701,29 +1760,29 @@ % \prg_set_protected_conditional:Npnn , % \prg_new_protected_conditional:Npnn , % } -% \begin{macro}[aux]{\prg_generate_conditional_parm_aux:NNpnn} +% \begin{macro}[aux]{\__prg_generate_conditional_parm:nnNpnn} % The user functions for the types using parameter text from the % programmer. The various functions only differ by which function is % used for the assignment. For those |Npnn| type functions, we must % grab the parameter text, reading everything up to a left brace % before continuing. Then split the base function into name and % signature, and feed \Arg{name} \Arg{signature} \meta{boolean} -% \meta{defining~function} |{parm}| \Arg{parameters} |{TF,...}| +% \Arg{set~or~new} \Arg{maybe~protected} \Arg{parameters} |{TF,...}| % \Arg{code} to the auxiliary function responsible for defining all % conditionals. % \begin{macrocode} \cs_set_protected_nopar:Npn \prg_set_conditional:Npnn - { \prg_generate_conditional_parm_aux:NNpnn \cs_set:Npn } + { \__prg_generate_conditional_parm:nnNpnn { set } { } } \cs_set_protected_nopar:Npn \prg_new_conditional:Npnn - { \prg_generate_conditional_parm_aux:NNpnn \cs_new:Npn } + { \__prg_generate_conditional_parm:nnNpnn { new } { } } \cs_set_protected_nopar:Npn \prg_set_protected_conditional:Npnn - { \prg_generate_conditional_parm_aux:NNpnn \cs_set_protected:Npn } + { \__prg_generate_conditional_parm:nnNpnn { set } { _protected } } \cs_set_protected_nopar:Npn \prg_new_protected_conditional:Npnn - { \prg_generate_conditional_parm_aux:NNpnn \cs_new_protected:Npn } -\cs_set_protected:Npn \prg_generate_conditional_parm_aux:NNpnn #1#2#3# + { \__prg_generate_conditional_parm:nnNpnn { new } { _protected } } +\cs_set_protected:Npn \__prg_generate_conditional_parm:nnNpnn #1#2#3#4# { - \cs_split_function:NN #2 \prg_generate_conditional_aux:nnNNnnnn - #1 { parm } {#3} + \__cs_split_function:NN #3 \__prg_generate_conditional:nnNnnnnn + {#1} {#2} {#4} } % \end{macrocode} % \end{macro} @@ -1736,204 +1795,248 @@ % \prg_set_protected_conditional:Nnn , % \prg_new_protected_conditional:Nnn , % } -% \begin{macro}[aux]{\prg_generate_conditional_count_aux:NNnn} +% \begin{macro}[aux] +% { +% \__prg_generate_conditional_count:nnNnn , +% \__prg_generate_conditional_count:nnNnnnn +% } % The user functions for the types automatically inserting the correct % parameter text based on the signature. The various functions only -% differ by which function is used for the assignment. For those |Nnn| -% type functions, we calculate the number of arguments. Then split the -% base function into name and signature, and feed \Arg{name} -% \Arg{signature} \meta{boolean} \meta{defining~function} |{count}| -% \Arg{arg~count} |{TF,...}| \Arg{code} to the auxiliary function -% responsible for defining all conditionals. +% differ by which function is used for the assignment. Split the base +% function into name and signature. The second auxiliary generates +% the parameter text from the number of letters in the signature. +% Then feed \Arg{name} \Arg{signature} \meta{boolean} \Arg{set~or~new} +% \Arg{maybe~protected} \Arg{parameters} |{TF,...}| \Arg{code} to the +% auxiliary function responsible for defining all conditionals. If +% the \meta{signature} has more than $9$ letters, the definition is +% aborted since \TeX{} macros have at most $9$ arguments. The +% erroneous case where the function name contains no colon is captured +% later. % \begin{macrocode} \cs_set_protected_nopar:Npn \prg_set_conditional:Nnn - { \prg_generate_conditional_count_aux:NNnn \cs_set:Npn } + { \__prg_generate_conditional_count:nnNnn { set } { } } \cs_set_protected_nopar:Npn \prg_new_conditional:Nnn - { \prg_generate_conditional_count_aux:NNnn \cs_new:Npn } + { \__prg_generate_conditional_count:nnNnn { new } { } } \cs_set_protected_nopar:Npn \prg_set_protected_conditional:Nnn - { \prg_generate_conditional_count_aux:NNnn \cs_set_protected:Npn } + { \__prg_generate_conditional_count:nnNnn { set } { _protected } } \cs_set_protected_nopar:Npn \prg_new_protected_conditional:Nnn - { \prg_generate_conditional_count_aux:NNnn \cs_new_protected:Npn } -\cs_set_protected:Npn \prg_generate_conditional_count_aux:NNnn #1#2 + { \__prg_generate_conditional_count:nnNnn { new } { _protected } } +\cs_set_protected:Npn \__prg_generate_conditional_count:nnNnn #1#2#3 + { + \__cs_split_function:NN #3 \__prg_generate_conditional_count:nnNnnnn + {#1} {#2} + } +\cs_set_protected:Npn \__prg_generate_conditional_count:nnNnnnn #1#2#3#4#5 { - \exp_args:Nnf \use:n + \__cs_parm_from_arg_count:nnF + { \__prg_generate_conditional:nnNnnnnn {#1} {#2} #3 {#4} {#5} } + { \tl_count:n {#2} } { - \cs_split_function:NN #2 \prg_generate_conditional_aux:nnNNnnnn - #1 { count } + \__msg_kernel_error:nnxx { kernel } { bad-number-of-arguments } + { \token_to_str:c { #1 : #2 } } + { \tl_count:n {#2} } + \use_none:nn } - { \cs_get_arg_count_from_signature:N #2 } } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}{\prg_set_eq_conditional:NNn,\prg_new_eq_conditional:NNn} -% The obvious setting-equal functions. -% \begin{macrocode} -\cs_set_protected:Npn \prg_set_eq_conditional:NNn #1#2#3 - { \prg_set_eq_conditional_aux:NNNn \cs_set_eq:cc #1#2 {#3} } -\cs_set_protected:Npn \prg_new_eq_conditional:NNn #1#2#3 - { \prg_set_eq_conditional_aux:NNNn \cs_new_eq:cc #1#2 {#3} } -% \end{macrocode} -% \end{macro} -% % \begin{macro}[aux] % { -% \prg_generate_conditional_aux:nnNNnnnn, -% \prg_generate_conditional_aux:nnw +% \__prg_generate_conditional:nnNnnnnn, +% \__prg_generate_conditional:nnnnnnw % } % The workhorse here is going through a list of desired forms, \emph{i.e.}, % |p|, |TF|, |T| and |F|. The first three arguments come from splitting up % the base form of the conditional, which gives the name, signature % and a boolean to signal whether or not there was a colon in the -% name. For the time being, we do not use this piece of information -% but could well throw an error. The fourth argument is how to -% define this function, the fifth is the text |parm| or |count| for -% which version to use to define the functions, the sixth is the -% parameters to use (possibly empty) or number of arguments, the -% seventh is the list of forms to define, the eight is the +% name. In the absence of a colon, we throw an error and don't define +% any conditional. The fourth and fifth arguments build up the +% defining function. The sixth is the parameters to use (possibly +% empty), the seventh is the list of forms to define, the eigth is the % replacement text which we will augment when defining the forms. % \begin{macrocode} -\cs_set_protected:Npn \prg_generate_conditional_aux:nnNNnnnn #1#2#3#4#5#6#7#8 +\cs_set_protected:Npn \__prg_generate_conditional:nnNnnnnn #1#2#3#4#5#6#7#8 { - \prg_generate_conditional_aux:nnw {#5} - { - #4 {#1} {#2} {#6} {#8} - } - #7 , ? , \q_recursion_stop + \if_meaning:w \c_true_bool #3 + \exp_after:wN \use_i:nn + \else: + \exp_after:wN \use_ii:nn + \fi: + { + \__prg_generate_conditional:nnnnnnw + {#4} {#5} {#1} {#2} {#6} {#8} + #7 , , \q_recursion_stop + } + { + \__msg_kernel_error:nnx { kernel } { missing-colon } + { \token_to_str:c {#1} } + } } % \end{macrocode} -% Looping through the list of desired forms. First is the text |parm| -% or |count|, second is five arguments packed together and third is -% the form. Use text and form to call the correct type. +% Looping through the list of desired forms. First are six arguments +% and seventh is the form. Use the form to call the +% correct type. If the form does not exist, the \cs{use:c} +% construction results in \tn{relax}, and the error message is +% displayed, then \cs{use_none:nnnnnnn} cleans up. Otherwise, the +% error message is removed by the variant form. % \begin{macrocode} -\cs_set_protected:Npn \prg_generate_conditional_aux:nnw #1#2#3 , +\cs_set_protected:Npn \__prg_generate_conditional:nnnnnnw #1#2#3#4#5#6#7 , { - \if:w ?#3 + \if_catcode:w \scan_stop: \etex_detokenize:D {#7} \scan_stop: \exp_after:wN \use_none_delimit_by_q_recursion_stop:w \fi: - \use:c { prg_generate_#3_form_#1:Nnnnn } #2 - \prg_generate_conditional_aux:nnw {#1} {#2} + \use:c { __prg_generate_ \etex_detokenize:D {#7} _form:wnnnnnn } + \__msg_kernel_error:nnxx + { kernel } { conditional-form-unknown } + { \tl_to_str:n {#7} } { \token_to_str:c { #3 : #4 } } + \use_none:nnnnnnn + \q_stop + {#1} {#2} {#3} {#4} {#5} {#6} + \__prg_generate_conditional:nnnnnnw {#1} {#2} {#3} {#4} {#5} {#6} } % \end{macrocode} % \end{macro} % % \begin{macro}[aux] % { -% \prg_generate_p_form_parm:Nnnnn, -% \prg_generate_TF_form_parm:Nnnnn, -% \prg_generate_T_form_parm:Nnnnn, -% \prg_generate_F_form_parm:Nnnnn +% \__prg_generate_p_form:wnnnnnn, +% \__prg_generate_TF_form:wnnnnnn, +% \__prg_generate_T_form:wnnnnnn, +% \__prg_generate_F_form:wnnnnnn % } -% How to generate the various forms. The |parm| types here takes the -% following arguments: 1: how to define (an N-type), 2: name, 3: -% signature, 4: parameter text (or empty), 5: replacement. Remember that -% the logic-returning functions expect two arguments to be present after -% \cs{c_zero}: notice the construction of the different variants -% relies on this, and that the |TF| variant will be slightly faster -% than the |T| version. -% \begin{macrocode} -\cs_set_protected:Npn \prg_generate_p_form_parm:Nnnnn #1#2#3#4#5 +% How to generate the various forms. Those functions take the +% following arguments: 1: \texttt{set} or \texttt{new}, 2: empty or +% \texttt{\_protected}, 3: function name 4: signature, 5: parameter +% text (or empty), 6: replacement. Remember that the logic-returning +% functions expect two arguments to be present after \cs{c_zero}: +% notice the construction of the different variants relies on this, +% and that the |TF| variant will be slightly faster than the |T| +% version. The |p| form is only valid for expandable tests, we check +% for that by making sure that the second argument is empty. +% \begin{macrocode} +\cs_set_protected:Npn \__prg_generate_p_form:wnnnnnn #1 \q_stop #2#3#4#5#6#7 { - \exp_args:Nc #1 { #2 _p: #3 } #4 + \if_meaning:w \scan_stop: #3 \scan_stop: + \exp_after:wN \use_i:nn + \else: + \exp_after:wN \use_ii:nn + \fi: { - #5 \c_zero - \c_true_bool \c_false_bool + \exp_args:Nc \exp_args:Nc { cs_ #2 #3 :Npn } { #4 _p: #5 } #6 + { #7 \c_zero \c_true_bool \c_false_bool } } - } -\cs_set_protected:Npn \prg_generate_T_form_parm:Nnnnn #1#2#3#4#5 - { - \exp_args:Nc #1 { #2 : #3 T } #4 { - #5 \c_zero - \use:n \use_none:n + \__msg_kernel_error:nnx { kernel } { protected-predicate } + { \token_to_str:c { #4 _p: #5 } } } } -\cs_set_protected:Npn \prg_generate_F_form_parm:Nnnnn #1#2#3#4#5 +\cs_set_protected:Npn \__prg_generate_T_form:wnnnnnn #1 \q_stop #2#3#4#5#6#7 { - \exp_args:Nc #1 { #2 : #3 F } #4 - { - #5 \c_zero - { } - } + \exp_args:Nc \exp_args:Nc { cs_ #2 #3 :Npn } { #4 : #5 T } #6 + { #7 \c_zero \use:n \use_none:n } } -\cs_set_protected:Npn \prg_generate_TF_form_parm:Nnnnn #1#2#3#4#5 +\cs_set_protected:Npn \__prg_generate_F_form:wnnnnnn #1 \q_stop #2#3#4#5#6#7 { - \exp_args:Nc #1 { #2 : #3 TF } #4 - { #5 \c_zero } + \exp_args:Nc \exp_args:Nc { cs_ #2 #3 :Npn } { #4 : #5 F } #6 + { #7 \c_zero { } } + } +\cs_set_protected:Npn \__prg_generate_TF_form:wnnnnnn #1 \q_stop #2#3#4#5#6#7 + { + \exp_args:Nc \exp_args:Nc { cs_ #2 #3 :Npn } { #4 : #5 TF } #6 + { #7 \c_zero } } % \end{macrocode} % \end{macro} % -% \begin{macro}[aux] -% { -% \prg_generate_p_form_count:Nnnnn, -% \prg_generate_TF_form_count:Nnnnn, -% \prg_generate_T_form_count:Nnnnn, -% \prg_generate_F_form_count:Nnnnn -% } -% The |count| form is similar, but of course requires a number rather -% than a primitive argument specification. +% \begin{macro}{\prg_set_eq_conditional:NNn,\prg_new_eq_conditional:NNn} +% The setting-equal functions. Split the base function to be copied, +% and feed a first auxiliary \Arg{name} \Arg{signature} \meta{boolean} +% \meta{copying~function} \meta{new~function} \Arg{conditions}. % \begin{macrocode} -\cs_set_protected:Npn \prg_generate_p_form_count:Nnnnn #1#2#3#4#5 +\cs_set_protected:Npn \prg_set_eq_conditional:NNn #1#2 { - \cs_generate_from_arg_count:cNnn { #2 _p: #3 } #1 {#4} - { - #5 \c_zero - \c_true_bool \c_false_bool - } + \__cs_split_function:NN #2 \__prg_set_eq_conditional:nnNNNn + \cs_set_eq:cc #1 } -\cs_set_protected:Npn \prg_generate_T_form_count:Nnnnn #1#2#3#4#5 +\cs_set_protected:Npn \prg_new_eq_conditional:NNn #1#2 { - \cs_generate_from_arg_count:cNnn { #2 : #3 T } #1 {#4} - { - #5 \c_zero - \use:n \use_none:n - } - } -\cs_set_protected:Npn \prg_generate_F_form_count:Nnnnn #1#2#3#4#5 - { - \cs_generate_from_arg_count:cNnn { #2 : #3 F } #1 {#4} - { - #5 \c_zero - { } - } - } -\cs_set_protected:Npn \prg_generate_TF_form_count:Nnnnn #1#2#3#4#5 - { - \cs_generate_from_arg_count:cNnn { #2 : #3 TF } #1 {#4} - { #5 \c_zero } + \__cs_split_function:NN #2 \__prg_set_eq_conditional:nnNNNn + \cs_new_eq:cc #1 } % \end{macrocode} % \end{macro} % % \begin{macro}[aux] -% {\prg_set_eq_conditional_aux:NNNn, \prg_set_eq_conditional_aux:NNNw} +% { +% \__prg_set_eq_conditional:nnNNNn , +% \__prg_set_eq_conditional:nnNnnNNw , +% \__prg_set_eq_conditional_loop:nnnnNw +% } % \begin{macro}[aux, EXP] % { -% \prg_conditional_form_p:nnn , -% \prg_conditional_form_TF:nnn , -% \prg_conditional_form_T:nnn , -% \prg_conditional_form_F:nnn , +% \__prg_conditional_p_form:nnn , +% \__prg_conditional_TF_form:nnn , +% \__prg_conditional_T_form:nnn , +% \__prg_conditional_F_form:nnn , % } -% Manual clist loop over argument |#4|. -% \begin{macrocode} -\cs_set_protected:Npn \prg_set_eq_conditional_aux:NNNn #1#2#3#4 - { \prg_set_eq_conditional_aux:NNNw #1#2#3#4 , ? , \q_recursion_stop } -\cs_set_protected:Npn \prg_set_eq_conditional_aux:NNNw #1#2#3#4 , +% Split the function to be defined, and setup a manual clist loop over +% argument |#6| of the first auxiliary. The second auxiliary receives +% twice three arguments coming from splitting the function to be +% defined and the function to copy. Make sure that both functions +% contained a colon, otherwise we don't know how to build +% conditionals, hence abort. Call the looping macro, with arguments +% \Arg{name_1} \Arg{signature_1} \Arg{name_2} \Arg{signature_2} +% \meta{copying~function} and followed by the comma list. At each +% step in the loop, make sure that the conditional form we copy is +% defined, and copy it, otherwise abort. +% \begin{macrocode} +\cs_set_protected:Npn \__prg_set_eq_conditional:nnNNNn #1#2#3#4#5#6 { - \if:w ? #4 \scan_stop: + \__cs_split_function:NN #5 \__prg_set_eq_conditional:nnNnnNNw + {#1} {#2} #3 #4 + #6 , \scan_stop: , \q_recursion_stop + } +\cs_set_protected:Npn \__prg_set_eq_conditional:nnNnnNNw #1#2#3#4#5#6 + { + \if_meaning:w \c_false_bool #3 + \__msg_kernel_error:nnx { kernel } { missing-colon } + { \token_to_str:c {#1} } + \exp_after:wN \use_none_delimit_by_q_recursion_stop:w + \fi: + \if_meaning:w \c_false_bool #6 + \__msg_kernel_error:nnx { kernel } { missing-colon } + { \token_to_str:c {#4} } \exp_after:wN \use_none_delimit_by_q_recursion_stop:w \fi: - #1 - { \exp_args:NNc \cs_split_function:NN #2 { prg_conditional_form_#4:nnn } } - { \exp_args:NNc \cs_split_function:NN #3 { prg_conditional_form_#4:nnn } } - \prg_set_eq_conditional_aux:NNNw #1 {#2} {#3} + \__prg_set_eq_conditional_loop:nnnnNw {#1} {#2} {#4} {#5} + } +\cs_set_protected:Npn \__prg_set_eq_conditional_loop:nnnnNw #1#2#3#4#5#6 , + { + \if_meaning:w \scan_stop: #6 \scan_stop: + \exp_after:wN \use_none_delimit_by_q_recursion_stop:w + \fi: + \cs_if_exist:cTF + { \use:c { __prg_conditional_ #6 _form:nn } {#3} {#4} } + { + #5 + { \use:c { __prg_conditional_ #6 _form:nn } {#1} {#2} } + { \use:c { __prg_conditional_ #6 _form:nn } {#3} {#4} } + } + { + \__msg_kernel_error:nnx { kernel } { command-not-defined } + { + \token_to_str:c + { \use:c { __prg_conditional_ #6 _form:nn } {#3} {#4} } + } + } + \__prg_set_eq_conditional_loop:nnnnNw {#1} {#2} {#3} {#4} #5 } -\cs_set:Npn \prg_conditional_form_p:nnn #1#2#3 { #1 _p : #2 } -\cs_set:Npn \prg_conditional_form_TF:nnn #1#2#3 { #1 : #2 TF } -\cs_set:Npn \prg_conditional_form_T:nnn #1#2#3 { #1 : #2 T } -\cs_set:Npn \prg_conditional_form_F:nnn #1#2#3 { #1 : #2 F } +\cs_set:Npn \__prg_conditional_p_form:nn #1#2 { #1 _p : #2 } +\cs_set:Npn \__prg_conditional_TF_form:nn #1#2 { #1 : #2 TF } +\cs_set:Npn \__prg_conditional_T_form:nn #1#2 { #1 : #2 T } +\cs_set:Npn \__prg_conditional_F_form:nn #1#2 { #1 : #2 F } % \end{macrocode} % \end{macro} % \end{macro} @@ -1941,7 +2044,7 @@ % All that is left is to define the canonical boolean true and false. % I think Michael originated the idea of expandable boolean tests. At % first these were supposed to expand into either \texttt{TT} or -% \texttt{TF} to be tested using |\if:w| but this was later changed to +% \texttt{TF} to be tested using \cs{if:w} but this was later changed to % |00| and |01|, so they could be used in logical % operations. Later again they were changed to being numerical % constants with values of $1$ for true and $0$ for false. We need @@ -1950,22 +2053,22 @@ % \begin{variable}{\c_true_bool, \c_false_bool} % Here are the canonical boolean values. % \begin{macrocode} -\tex_chardef:D \c_true_bool = 1~ -\tex_chardef:D \c_false_bool = 0~ +\tex_chardef:D \c_true_bool = 1 ~ +\tex_chardef:D \c_false_bool = 0 ~ % \end{macrocode} % \end{variable} % % \subsection{Dissecting a control sequence} % % \begin{macro}[EXP]{\cs_to_str:N} -% \begin{macro}[aux, EXP]{\cs_to_str_aux:N, \cs_to_str_aux:w} +% \begin{macro}[aux, EXP]{\__cs_to_str:N, \__cs_to_str:w} % This converts a control sequence into the character string of its % name, removing the leading escape character. This turns out to be % a non-trivial matter as there a different cases: % \begin{itemize} % \item The usual case of a printable escape character; % \item the case of a non-printable escape characters, e.g., when -% the value of |\tex_escapechar:D| is negative; +% the value of the \tn{escapechar} is negative; % \item when the escape character is a space. % \end{itemize} % One approach to solve this is to test how many tokens result from @@ -1979,109 +2082,97 @@ % a little more intricate still. When the escape character is printable, % \verb*|\token_to_str:N \ | yields the escape character itself and a space. % The character codes are different, thus the \cs{if:w} test is false, -% and \TeX{} reads \cs{cs_to_str_aux:N} after turning the following +% and \TeX{} reads \cs{__cs_to_str:N} after turning the following % control sequence into a string; this auxiliary removes the escape -% character, and stops the expansion of the initial \cs{int_to_roman:w}. +% character, and stops the expansion of the initial \cs{__int_to_roman:w}. % The second case is that the escape character is not printable. Then % the \cs{if:w} test is unfinished after reading a the space from -% \verb*|\token_to_str:N \ |, and the auxiliary \cs{cs_to_str_aux:w} +% \verb*|\token_to_str:N \ |, and the auxiliary \cs{__cs_to_str:w} % is expanded, feeding |-| as a second character for the test; % the test is false, and \TeX{} skips to \cs{fi:}, then performs -% \cs{token_to_str:N}, and stops the \cs{int_to_roman:w} with \cs{c_zero}. +% \cs{token_to_str:N}, and stops the \cs{__int_to_roman:w} with \cs{c_zero}. % The last case is that the escape character is itself a space. In this -% case, the \cs{if:w} test is true, and the auxiliary \cs{cs_to_str_aux:w} -% comes into play, inserting |-\int_value:w|, which expands \cs{c_zero} -% to the character |0|. The initial \cs{int_to_roman:w} then sees +% case, the \cs{if:w} test is true, and the auxiliary \cs{__cs_to_str:w} +% comes into play, inserting |-\__int_value:w|, which expands \cs{c_zero} +% to the character |0|. The initial \cs{__int_to_roman:w} then sees % |0|, which is not a terminated number, followed by the escape character, % a space, which is removed, terminating the argument of -% \cs{int_to_roman:w}. +% \cs{__int_to_roman:w}. % In all three cases, \cs{cs_to_str:N} takes two expansion steps % to be fully expanded. % \begin{macrocode} \cs_set_nopar:Npn \cs_to_str:N { - \int_to_roman:w - \if:w \token_to_str:N \ \cs_to_str_aux:w \fi: - \exp_after:wN \cs_to_str_aux:N \token_to_str:N + \__int_to_roman:w + \if:w \token_to_str:N \ \__cs_to_str:w \fi: + \exp_after:wN \__cs_to_str:N \token_to_str:N } -\cs_set:Npn \cs_to_str_aux:N #1 { \c_zero } -\cs_set:Npn \cs_to_str_aux:w #1 \cs_to_str_aux:N - { - \int_value:w \fi: \exp_after:wN \c_zero } +\cs_set:Npn \__cs_to_str:N #1 { \c_zero } +\cs_set:Npn \__cs_to_str:w #1 \__cs_to_str:N + { - \__int_value:w \fi: \exp_after:wN \c_zero } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}[EXP]{\cs_split_function:NN} +% \begin{macro}[EXP, int]{\__cs_split_function:NN} % \begin{macro}[aux, EXP] -% {\cs_split_function_aux:w, \cs_split_function_auxii:w} +% {\__cs_split_function_i:w, \__cs_split_function_ii:w} % This function takes a function name and splits it into name with % the escape char removed and argument specification. In addition to % this, a third argument, a boolean \meta{true} or \meta{false} is % returned with \meta{true} for when there is a colon in the function % and \meta{false} if there is not. Lastly, the second argument of -% \cs{cs_split_function:NN} is supposed to be a function +% \cs{__cs_split_function:NN} is supposed to be a function % taking three variables, one for name, one for signature, and one % for the boolean. For example, -% |\cs_split_function:NN\foo_bar:cnx\use_i:nnn| as input -% becomes |\use_i:nnn {foo_bar}{cnx}\c_true_bool|. -% -% Can't use a literal |:| because it has the wrong catcode here, so -% it's transformed from |@| with |\tex_lowercase:D|. +% |\__cs_split_function:NN \foo_bar:cnx \use_i:nnn| as input +% becomes |\use_i:nnn {foo_bar} {cnx} \c_true_bool|. +% +% We can't use a literal |:| because it has the wrong catcode here, so +% it's transformed from |@| with \cs{tex_lowercase:D}. +% +% First ensure that we actually get a properly evaluated string by +% expanding \cs{cs_to_str:N} twice. If the function contained a +% colon, the auxiliary takes as |#1| the function name, delimited by +% the first colon, then the signature |#2|, delimited by \cs{q_mark}, +% then \cs{c_true_bool} as |#3|, and |#4| cleans up until \cs{q_stop}. +% Otherwise, the |#1| contains the function name and \cs{q_mark} +% \cs{c_true_bool}, |#2| is empty, |#3| is \cs{c_false_bool}, and |#4| +% cleans up. In both cases, |#5| is the \meta{processor}. The second +% auxiliary trims the trailing \cs{q_mark} from the function name if +% present (that is, if the original function had no colon). % \begin{macrocode} \group_begin: - \tex_lccode:D `\@ = `\: \scan_stop: - \tex_catcode:D `\@ = 12~ +\tex_lccode:D `\@ = `\: \scan_stop: +\tex_catcode:D `\@ = 12 ~ \tex_lowercase:D { \group_end: -% \end{macrocode} -% First ensure that we actually get a properly evaluated str -% by expanding \cs{cs_to_str:N} twice. Insert -% extra colon to catch the error cases. -% \begin{macrocode} - \cs_set:Npn \cs_split_function:NN #1#2 + \cs_set:Npn \__cs_split_function:NN #1 { \exp_after:wN \exp_after:wN - \exp_after:wN \cs_split_function_aux:w - \cs_to_str:N #1 @ a \q_stop #2 - } -% \end{macrocode} -% If no colon in the name, |#2| is |a| with catcode 11 and |#3| is -% empty. If colon in the name, then either |#2| is a colon or the -% first letter of the signature. The letters here have catcode 12. -% If a colon was given we need to a) split off the colon and quark at -% the end and b) ensure we return the name, signature and boolean true -% We can't use \cs{quark_if_no_value:NTF} yet but this is very safe -% anyway as all tokens have catcode~12. -% \begin{macrocode} - \cs_set:Npn \cs_split_function_aux:w #1 @ #2#3 \q_stop #4 - { - \if_meaning:w a #2 - \exp_after:wN \use_i:nn - \else: - \exp_after:wN\use_ii:nn - \fi: - { #4 {#1} { } \c_false_bool } - { \cs_split_function_auxii:w #2#3 \q_stop #4 {#1} } + \exp_after:wN \__cs_split_function_i:w + \cs_to_str:N #1 \q_mark \c_true_bool + @ \q_mark \c_false_bool + \q_stop } - \cs_set:Npn \cs_split_function_auxii:w #1 @a \q_stop #2#3 - { #2{#3}{#1}\c_true_bool } -% \end{macrocode} -% End of lowercase -% \begin{macrocode} + \cs_set:Npn \__cs_split_function_i:w #1 @ #2 \q_mark #3#4 \q_stop #5 + { \__cs_split_function_ii:w #5 #1 \q_mark \q_stop {#2} #3 } + \cs_set:Npn \__cs_split_function_ii:w #1#2 \q_mark #3 \q_stop + { #1 {#2} } } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}[EXP]{\cs_get_function_name:N, \cs_get_function_signature:N} -% Now returning the name is trivial: just discard the last two -% arguments. Similar for signature. +% \begin{macro}[EXP, int] +% {\__cs_get_function_name:N, \__cs_get_function_signature:N} +% Simple wrappers. % \begin{macrocode} -\cs_set:Npn \cs_get_function_name:N #1 - { \cs_split_function:NN #1 \use_i:nnn } -\cs_set:Npn \cs_get_function_signature:N #1 - { \cs_split_function:NN #1 \use_ii:nnn } +\cs_set:Npn \__cs_get_function_name:N #1 + { \__cs_split_function:NN #1 \use_i:nnn } +\cs_set:Npn \__cs_get_function_signature:N #1 + { \__cs_split_function:NN #1 \use_ii:nnn } % \end{macrocode} % \end{macro} % @@ -2089,15 +2180,15 @@ % % A control sequence is said to \emph{exist} (to be used) if has an entry in % the hash table and its meaning is different from the primitive -% |\tex_relax:D| token. A control sequence is said to be \emph{free} +% \tn{relax} token. A control sequence is said to be \emph{free} % (to be defined) if it does not already exist. % % \begin{macro}[pTF, EXP]{\cs_if_exist:N,\cs_if_exist:c} % Two versions for checking existence. For the |N| form we firstly -% check for |\scan_stop:| and then if it is in the hash -% table. There is no problem when inputting something like |\else:| -% or |\fi:| as \TeX{} will only ever skip input in case the token -% tested against is |\scan_stop:|. +% check for \cs{scan_stop:} and then if it is in the hash +% table. There is no problem when inputting something like \cs{else:} +% or \cs{fi:} as \TeX{} will only ever skip input in case the token +% tested against is \cs{scan_stop:}. % \begin{macrocode} \prg_set_conditional:Npnn \cs_if_exist:N #1 { p , T , F , TF } { @@ -2113,7 +2204,7 @@ } % \end{macrocode} % For the |c| form we firstly check if it is in the hash table and -% then for |\scan_stop:| so that we do not add it to the hash table +% then for \cs{scan_stop:} so that we do not add it to the hash table % unless it was already there. Here we have to be careful as the text % to be skipped if the first test is false may contain tokens that % disturb the scanner. Therefore, we ensure that the second test is @@ -2226,14 +2317,14 @@ % \end{macrocode} % \end{macro} % -% \begin{macro} -% {\msg_kernel_error:nnxx, \msg_kernel_error:nnx, \msg_kernel_error:nn} +% \begin{macro}[int] +% {\__msg_kernel_error:nnxx, \__msg_kernel_error:nnx, \__msg_kernel_error:nn} % If an internal error occurs before \LaTeX3 has loaded \pkg{l3msg} then % the code should issue a usable if terse error message and halt. This % can only happen if a coding error is made by the team, so this is % a reasonable response. % \begin{macrocode} -\cs_set_protected:Npn \msg_kernel_error:nnxx #1#2#3#4 +\cs_set_protected:Npn \__msg_kernel_error:nnxx #1#2#3#4 { \tex_errmessage:D { @@ -2245,10 +2336,10 @@ } \tex_end:D } -\cs_set_protected:Npn \msg_kernel_error:nnx #1#2#3 - { \msg_kernel_error:nnxx {#1} {#2} {#3} { } } -\cs_set_protected:Npn \msg_kernel_error:nn #1#2 - { \msg_kernel_error:nnxx {#1} {#2} { } { } } +\cs_set_protected:Npn \__msg_kernel_error:nnx #1#2#3 + { \__msg_kernel_error:nnxx {#1} {#2} {#3} { } } +\cs_set_protected:Npn \__msg_kernel_error:nn #1#2 + { \__msg_kernel_error:nnxx {#1} {#2} { } { } } % \end{macrocode} % \end{macro} % @@ -2256,11 +2347,11 @@ % Another one from \pkg{l3msg} which will be altered later. % \begin{macrocode} \cs_set_nopar:Npn \msg_line_context: - { on~line~\tex_the:D \tex_inputlineno:D } + { on~line~ \tex_the:D \tex_inputlineno:D } % \end{macrocode} % \end{macro} % -% \begin{macro}[int]{\chk_if_free_cs:N, \chk_if_free_cs:c} +% \begin{macro}[int]{\__chk_if_free_cs:N, \__chk_if_free_cs:c} % This command is called by \cs{cs_new_nopar:Npn} and \cs{cs_new_eq:NN} % \emph{etc.}\ % to make sure that the argument sequence is not already in use. If @@ -2269,46 +2360,46 @@ % issued. We have to make sure we don't put the argument into the % conditional processing since it may be an |\if...| type function! % \begin{macrocode} -\cs_set_protected:Npn \chk_if_free_cs:N #1 +\cs_set_protected:Npn \__chk_if_free_cs:N #1 { \cs_if_free:NF #1 { - \msg_kernel_error:nnxx { kernel } { command-already-defined } + \__msg_kernel_error:nnxx { kernel } { command-already-defined } { \token_to_str:N #1 } { \token_to_meaning:N #1 } } } %<*package> \tex_ifodd:D \l@expl@log@functions@bool - \cs_set_protected:Npn \chk_if_free_cs:N #1 + \cs_set_protected:Npn \__chk_if_free_cs:N #1 { \cs_if_free:NF #1 { - \msg_kernel_error:nnxx { kernel } { command-already-defined } + \__msg_kernel_error:nnxx { kernel } { command-already-defined } { \token_to_str:N #1 } { \token_to_meaning:N #1 } } \iow_log:x { Defining~\token_to_str:N #1~ \msg_line_context: } } \fi: %</package> -\cs_set_protected_nopar:Npn \chk_if_free_cs:c - { \exp_args:Nc \chk_if_free_cs:N } +\cs_set_protected_nopar:Npn \__chk_if_free_cs:c + { \exp_args:Nc \__chk_if_free_cs:N } % \end{macrocode} % \end{macro} % -% \begin{macro}[int]{\chk_if_exist_cs:N, \chk_if_exist_cs:c} -% This function issues a warning message when the control sequence +% \begin{macro}[int]{\__chk_if_exist_cs:N, \__chk_if_exist_cs:c} +% This function issues an error message when the control sequence % in its argument does not exist. % \begin{macrocode} -\cs_set_protected:Npn \chk_if_exist_cs:N #1 +\cs_set_protected:Npn \__chk_if_exist_cs:N #1 { \cs_if_exist:NF #1 { - \msg_kernel_error:nnxx { kernel } { command-not-defined } - { \token_to_str:N #1 } { \token_to_meaning:N #1 } + \__msg_kernel_error:nnx { kernel } { command-not-defined } + { \token_to_str:N #1 } } } -\cs_set_protected_nopar:Npn \chk_if_exist_cs:c - { \exp_args:Nc \chk_if_exist_cs:N } +\cs_set_protected_nopar:Npn \__chk_if_exist_cs:c + { \exp_args:Nc \__chk_if_exist_cs:N } % \end{macrocode} % \end{macro} % @@ -2324,22 +2415,22 @@ % Function which check that the control sequence is free before % defining it. % \begin{macrocode} -\cs_set:Npn \cs_tmp:w #1#2 +\cs_set:Npn \__cs_tmp:w #1#2 { \cs_set_protected:Npn #1 ##1 { - \chk_if_free_cs:N ##1 + \__chk_if_free_cs:N ##1 #2 ##1 } } -\cs_tmp:w \cs_new_nopar:Npn \cs_gset_nopar:Npn -\cs_tmp:w \cs_new_nopar:Npx \cs_gset_nopar:Npx -\cs_tmp:w \cs_new:Npn \cs_gset:Npn -\cs_tmp:w \cs_new:Npx \cs_gset:Npx -\cs_tmp:w \cs_new_protected_nopar:Npn \cs_gset_protected_nopar:Npn -\cs_tmp:w \cs_new_protected_nopar:Npx \cs_gset_protected_nopar:Npx -\cs_tmp:w \cs_new_protected:Npn \cs_gset_protected:Npn -\cs_tmp:w \cs_new_protected:Npx \cs_gset_protected:Npx +\__cs_tmp:w \cs_new_nopar:Npn \cs_gset_nopar:Npn +\__cs_tmp:w \cs_new_nopar:Npx \cs_gset_nopar:Npx +\__cs_tmp:w \cs_new:Npn \cs_gset:Npn +\__cs_tmp:w \cs_new:Npx \cs_gset:Npx +\__cs_tmp:w \cs_new_protected_nopar:Npn \cs_gset_protected_nopar:Npn +\__cs_tmp:w \cs_new_protected_nopar:Npx \cs_gset_protected_nopar:Npx +\__cs_tmp:w \cs_new_protected:Npn \cs_gset_protected:Npn +\__cs_tmp:w \cs_new_protected:Npx \cs_gset_protected:Npx % \end{macrocode} % \end{macro} % @@ -2360,14 +2451,14 @@ % \cs{cs_set_nopar:Npn}. This means that there might be a parameter % string between the two arguments. % \begin{macrocode} -\cs_set:Npn \cs_tmp:w #1#2 +\cs_set:Npn \__cs_tmp:w #1#2 { \cs_new_protected_nopar:Npn #1 { \exp_args:Nc #2 } } -\cs_tmp:w \cs_set_nopar:cpn \cs_set_nopar:Npn -\cs_tmp:w \cs_set_nopar:cpx \cs_set_nopar:Npx -\cs_tmp:w \cs_gset_nopar:cpn \cs_gset_nopar:Npn -\cs_tmp:w \cs_gset_nopar:cpx \cs_gset_nopar:Npx -\cs_tmp:w \cs_new_nopar:cpn \cs_new_nopar:Npn -\cs_tmp:w \cs_new_nopar:cpx \cs_new_nopar:Npx +\__cs_tmp:w \cs_set_nopar:cpn \cs_set_nopar:Npn +\__cs_tmp:w \cs_set_nopar:cpx \cs_set_nopar:Npx +\__cs_tmp:w \cs_gset_nopar:cpn \cs_gset_nopar:Npn +\__cs_tmp:w \cs_gset_nopar:cpx \cs_gset_nopar:Npx +\__cs_tmp:w \cs_new_nopar:cpn \cs_new_nopar:Npn +\__cs_tmp:w \cs_new_nopar:cpx \cs_new_nopar:Npx % \end{macrocode} % \end{macro} % @@ -2380,12 +2471,12 @@ % Variants of the \cs{cs_set:Npn} versions which make a csname out % of the first arguments. We may also do this globally. % \begin{macrocode} -\cs_tmp:w \cs_set:cpn \cs_set:Npn -\cs_tmp:w \cs_set:cpx \cs_set:Npx -\cs_tmp:w \cs_gset:cpn \cs_gset:Npn -\cs_tmp:w \cs_gset:cpx \cs_gset:Npx -\cs_tmp:w \cs_new:cpn \cs_new:Npn -\cs_tmp:w \cs_new:cpx \cs_new:Npx +\__cs_tmp:w \cs_set:cpn \cs_set:Npn +\__cs_tmp:w \cs_set:cpx \cs_set:Npx +\__cs_tmp:w \cs_gset:cpn \cs_gset:Npn +\__cs_tmp:w \cs_gset:cpx \cs_gset:Npx +\__cs_tmp:w \cs_new:cpn \cs_new:Npn +\__cs_tmp:w \cs_new:cpx \cs_new:Npx % \end{macrocode} % \end{macro} % @@ -2398,12 +2489,12 @@ % Variants of the \cs{cs_set_protected_nopar:Npn} versions which make % a csname out of the first arguments. We may also do this globally. % \begin{macrocode} -\cs_tmp:w \cs_set_protected_nopar:cpn \cs_set_protected_nopar:Npn -\cs_tmp:w \cs_set_protected_nopar:cpx \cs_set_protected_nopar:Npx -\cs_tmp:w \cs_gset_protected_nopar:cpn \cs_gset_protected_nopar:Npn -\cs_tmp:w \cs_gset_protected_nopar:cpx \cs_gset_protected_nopar:Npx -\cs_tmp:w \cs_new_protected_nopar:cpn \cs_new_protected_nopar:Npn -\cs_tmp:w \cs_new_protected_nopar:cpx \cs_new_protected_nopar:Npx +\__cs_tmp:w \cs_set_protected_nopar:cpn \cs_set_protected_nopar:Npn +\__cs_tmp:w \cs_set_protected_nopar:cpx \cs_set_protected_nopar:Npx +\__cs_tmp:w \cs_gset_protected_nopar:cpn \cs_gset_protected_nopar:Npn +\__cs_tmp:w \cs_gset_protected_nopar:cpx \cs_gset_protected_nopar:Npx +\__cs_tmp:w \cs_new_protected_nopar:cpn \cs_new_protected_nopar:Npn +\__cs_tmp:w \cs_new_protected_nopar:cpx \cs_new_protected_nopar:Npx % \end{macrocode} % \end{macro} % @@ -2416,12 +2507,12 @@ % Variants of the \cs{cs_set_protected:Npn} versions which make a csname % out of the first arguments. We may also do this globally. % \begin{macrocode} -\cs_tmp:w \cs_set_protected:cpn \cs_set_protected:Npn -\cs_tmp:w \cs_set_protected:cpx \cs_set_protected:Npx -\cs_tmp:w \cs_gset_protected:cpn \cs_gset_protected:Npn -\cs_tmp:w \cs_gset_protected:cpx \cs_gset_protected:Npx -\cs_tmp:w \cs_new_protected:cpn \cs_new_protected:Npn -\cs_tmp:w \cs_new_protected:cpx \cs_new_protected:Npx +\__cs_tmp:w \cs_set_protected:cpn \cs_set_protected:Npn +\__cs_tmp:w \cs_set_protected:cpx \cs_set_protected:Npx +\__cs_tmp:w \cs_gset_protected:cpn \cs_gset_protected:Npn +\__cs_tmp:w \cs_gset_protected:cpx \cs_gset_protected:Npx +\__cs_tmp:w \cs_new_protected:cpn \cs_new_protected:Npn +\__cs_tmp:w \cs_new_protected:cpx \cs_new_protected:Npx % \end{macrocode} % \end{macro} % @@ -2456,7 +2547,7 @@ \cs_new_protected_nopar:Npn \cs_gset_eq:cc { \exp_args:Ncc \cs_gset_eq:NN } \cs_new_protected:Npn \cs_new_eq:NN #1 { - \chk_if_free_cs:N #1 + \__chk_if_free_cs:N #1 \tex_global:D \cs_set_eq:NN #1 } \cs_new_protected_nopar:Npn \cs_new_eq:cN { \exp_args:Nc \cs_new_eq:NN } @@ -2488,57 +2579,88 @@ % \end{macrocode} % \end{macro} % +% \subsection{Generating parameter text from argument count} +% +% \begin{macro}[int]{\__cs_parm_from_arg_count:nnF} +% \begin{macro}[aux]{\__cs_parm_from_arg_count_test:nnF} +% \LaTeX3 provides shorthands to define control sequences and +% conditionals with a simple parameter text, derived directly from the +% signature, or more generally from knowing the number of arguments, +% between~$0$ and~$9$. This function expands to its first argument, +% untouched, followed by a brace group containing the parameter text +% |{#|$1$\ldots{}|#|$n$|}|, where $n$ is the result of evaluating the +% second argument (as described in \cs{int_eval:n}). If the second +% argument gives a result outside the range $[0,9]$, the third +% argument is returned instead, normally an error message. Some of +% the functions use here are not defined yet, but will be defined +% before this function is called. +% \begin{macrocode} +\cs_set_protected:Npn \__cs_parm_from_arg_count:nnF #1#2 + { + \exp_args:Nx \__cs_parm_from_arg_count_test:nnF + { + \exp_after:wN \exp_not:n + \if_case:w \__int_eval:w #2 \__int_eval_end: + { } + \or: { ##1 } + \or: { ##1##2 } + \or: { ##1##2##3 } + \or: { ##1##2##3##4 } + \or: { ##1##2##3##4##5 } + \or: { ##1##2##3##4##5##6 } + \or: { ##1##2##3##4##5##6##7 } + \or: { ##1##2##3##4##5##6##7##8 } + \or: { ##1##2##3##4##5##6##7##8##9 } + \else: { \c_false_bool } + \fi: + } + {#1} + } +\cs_set_protected:Npn \__cs_parm_from_arg_count_test:nnF #1#2 + { + \if_meaning:w \c_false_bool #1 + \exp_after:wN \use_ii:nn + \else: + \exp_after:wN \use_i:nn + \fi: + { #2 {#1} } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% % \subsection{Defining functions from a given number of arguments} % -% \begin{macro}[EXP]{\cs_get_arg_count_from_signature:N} -% \begin{macro}[aux, EXP] -% { -% \cs_get_arg_count_from_signature_aux:nnN, -% \cs_get_arg_count_from_signature_auxii:w -% } -% Counting the number of tokens in the signature, i.e., the number -% of arguments the function should take. If there is no signature, -% we return that there is $-1$ arguments to signal an error. -% Otherwise we insert the string |9876543210| after the signature. -% If the signature is empty, the number we want is $0$ so we remove -% the first nine tokens and return the tenth. Similarly, if the -% signature is |nnn| we want to remove the nine tokens |nnn987654| -% and return $3$. Therefore, we simply remove the first nine tokens -% and then return the tenth. -% \begin{macrocode} -\cs_new:Npn \cs_get_arg_count_from_signature:N #1 - { \cs_split_function:NN #1 \cs_get_arg_count_from_signature_aux:nnN } -\cs_new:Npn \cs_get_arg_count_from_signature_aux:nnN #1#2#3 +% \begin{macro}[EXP, int]{\__cs_count_signature:N, \__cs_count_signature:c} +% \begin{macro}[aux, EXP]{\__cs_count_signature:nnN} +% Counting the number of tokens in the signature, \emph{i.e.}, the +% number of arguments the function should take. Since this is not +% used in any time-critical function, we simply use \cs{tl_count:n} if +% there is a signature, otherwise $-1$ arguments to signal an error. +% We need a variant form right away. +% \begin{macrocode} +\cs_new:Npn \__cs_count_signature:N #1 + { \int_eval:n { \__cs_split_function:NN #1 \__cs_count_signature:nnN } } +\cs_new:Npn \__cs_count_signature:nnN #1#2#3 { \if_meaning:w \c_true_bool #3 - \exp_after:wN \use_i:nn + \tl_count:n {#2} \else: - \exp_after:wN\use_ii:nn + \c_minus_one \fi: - { - \exp_after:wN \cs_get_arg_count_from_signature_auxii:w - \use_none:nnnnnnnnn #2 9876543210 \q_stop - } - { -1 } -} -\cs_new:Npn \cs_get_arg_count_from_signature_auxii:w #1#2 \q_stop {#1} -% \end{macrocode} -% A variant form we need right away. -% \begin{macrocode} -\cs_new_nopar:Npn \cs_get_arg_count_from_signature:c - { \exp_args:Nc \cs_get_arg_count_from_signature:N } + } +\cs_new_nopar:Npn \__cs_count_signature:c + { \exp_args:Nc \__cs_count_signature:N } % \end{macrocode} % \end{macro} % \end{macro} % -% \begin{macro}[aux] +% \begin{macro} % { % \cs_generate_from_arg_count:NNnn, % \cs_generate_from_arg_count:cNnn, % \cs_generate_from_arg_count:Ncnn % } -% \begin{macro}[aux]{\cs_generate_from_arg_count_error_msg:Nn} -% \begin{macro}[aux]{\cs_generate_from_arg_count_aux:nwn} % We provide a constructor function for defining functions with a % given number of arguments. For this we need to choose the correct % parameter text and then use that when defining. Since \TeX{} @@ -2552,27 +2674,13 @@ % \begin{macrocode} \cs_new_protected:Npn \cs_generate_from_arg_count:NNnn #1#2#3#4 { - \if_case:w \int_eval:w #3 \int_eval_end: - \cs_generate_from_arg_count_aux:nwn {} - \or: \cs_generate_from_arg_count_aux:nwn {##1} - \or: \cs_generate_from_arg_count_aux:nwn {##1##2} - \or: \cs_generate_from_arg_count_aux:nwn {##1##2##3} - \or: \cs_generate_from_arg_count_aux:nwn {##1##2##3##4} - \or: \cs_generate_from_arg_count_aux:nwn {##1##2##3##4##5} - \or: \cs_generate_from_arg_count_aux:nwn {##1##2##3##4##5##6} - \or: \cs_generate_from_arg_count_aux:nwn {##1##2##3##4##5##6##7} - \or: \cs_generate_from_arg_count_aux:nwn {##1##2##3##4##5##6##7##8} - \or: \cs_generate_from_arg_count_aux:nwn {##1##2##3##4##5##6##7##8##9} - \else: - \cs_generate_from_arg_count_error_msg:Nn #1 {#3} - \use_i:nnn - \fi: - {#2#1} - {#4} + \__cs_parm_from_arg_count:nnF { \use:nnn #2 #1 } {#3} + { + \__msg_kernel_error:nnxx { kernel } { bad-number-of-arguments } + { \token_to_str:N #1 } { \int_eval:n {#3} } + } + {#4} } -\cs_new_protected:Npn - \cs_generate_from_arg_count_aux:nwn #1 #2 \fi: #3 - { \fi: #3 #1 } % \end{macrocode} % A variant form we need right away, plus one which is used elsewhere but % which is most logically created here. @@ -2582,17 +2690,6 @@ \cs_new_protected_nopar:Npn \cs_generate_from_arg_count:Ncnn { \exp_args:NNc \cs_generate_from_arg_count:NNnn } % \end{macrocode} -% The error message. Elsewhere we use the value of $-1$ to signal a -% missing colon in a function, so provide a hint for help on this. -% \begin{macrocode} -\cs_new_protected:Npn \cs_generate_from_arg_count_error_msg:Nn #1#2 - { - \msg_kernel_error:nnxx { kernel } { bad-number-of-arguments } - { \token_to_str:N #1 } { \int_eval:n {#2} } - } -% \end{macrocode} -% \end{macro} -% \end{macro} % \end{macro} % % \subsection{Using the signature to define functions} @@ -2622,7 +2719,7 @@ % \cs_set_protected:Npn \cs_set:Nn #1#2 % { % \cs_generate_from_arg_count:NNnn #1 \cs_set:Npn -% { \cs_get_arg_count_from_signature:N #1 } {#2} +% { \__cs_count_signature:N #1 } {#2} % } % \end{verbatim} % In short, to define \cs{cs_set:Nn} we need just use \cs{cs_set:Npn}, @@ -2630,42 +2727,58 @@ % make it simpler by temporarily defining a function to do this for % us. % \begin{macrocode} -\cs_set:Npn \cs_tmp:w #1#2#3 +\cs_set:Npn \__cs_tmp:w #1#2#3 { - \cs_new_protected:cpx { cs_ #1 : #2 } ##1##2 + \cs_new_protected_nopar:cpx { cs_ #1 : #2 } { - \exp_not:N \cs_generate_from_arg_count:NNnn ##1 - \exp_after:wN \exp_not:N \cs:w cs_#1 : #3 \cs_end: - { \exp_not:N \cs_get_arg_count_from_signature:N ##1 }{##2} + \exp_not:N \__cs_generate_from_signature:NNn + \exp_after:wN \exp_not:N \cs:w cs_ #1 : #3 \cs_end: + } + } +\cs_new_protected:Npn \__cs_generate_from_signature:NNn #1#2 + { + \__cs_split_function:NN #2 \__cs_generate_from_signature:nnNNNn + #1 #2 + } +\cs_new_protected:Npn \__cs_generate_from_signature:nnNNNn #1#2#3#4#5#6 + { + \bool_if:NTF #3 + { + \cs_generate_from_arg_count:NNnn + #5 #4 { \tl_count:n {#2} } {#6} + } + { + \__msg_kernel_error:nnx { kernel } { missing-colon } + { \token_to_str:N #5 } } } % \end{macrocode} % Then we define the 24 variants beginning with |N|. % \begin{macrocode} -\cs_tmp:w { set } { Nn } { Npn } -\cs_tmp:w { set } { Nx } { Npx } -\cs_tmp:w { set_nopar } { Nn } { Npn } -\cs_tmp:w { set_nopar } { Nx } { Npx } -\cs_tmp:w { set_protected } { Nn } { Npn } -\cs_tmp:w { set_protected } { Nx } { Npx } -\cs_tmp:w { set_protected_nopar } { Nn } { Npn } -\cs_tmp:w { set_protected_nopar } { Nx } { Npx } -\cs_tmp:w { gset } { Nn } { Npn } -\cs_tmp:w { gset } { Nx } { Npx } -\cs_tmp:w { gset_nopar } { Nn } { Npn } -\cs_tmp:w { gset_nopar } { Nx } { Npx } -\cs_tmp:w { gset_protected } { Nn } { Npn } -\cs_tmp:w { gset_protected } { Nx } { Npx } -\cs_tmp:w { gset_protected_nopar } { Nn } { Npn } -\cs_tmp:w { gset_protected_nopar } { Nx } { Npx } -\cs_tmp:w { new } { Nn } { Npn } -\cs_tmp:w { new } { Nx } { Npx } -\cs_tmp:w { new_nopar } { Nn } { Npn } -\cs_tmp:w { new_nopar } { Nx } { Npx } -\cs_tmp:w { new_protected } { Nn } { Npn } -\cs_tmp:w { new_protected } { Nx } { Npx } -\cs_tmp:w { new_protected_nopar } { Nn } { Npn } -\cs_tmp:w { new_protected_nopar } { Nx } { Npx } +\__cs_tmp:w { set } { Nn } { Npn } +\__cs_tmp:w { set } { Nx } { Npx } +\__cs_tmp:w { set_nopar } { Nn } { Npn } +\__cs_tmp:w { set_nopar } { Nx } { Npx } +\__cs_tmp:w { set_protected } { Nn } { Npn } +\__cs_tmp:w { set_protected } { Nx } { Npx } +\__cs_tmp:w { set_protected_nopar } { Nn } { Npn } +\__cs_tmp:w { set_protected_nopar } { Nx } { Npx } +\__cs_tmp:w { gset } { Nn } { Npn } +\__cs_tmp:w { gset } { Nx } { Npx } +\__cs_tmp:w { gset_nopar } { Nn } { Npn } +\__cs_tmp:w { gset_nopar } { Nx } { Npx } +\__cs_tmp:w { gset_protected } { Nn } { Npn } +\__cs_tmp:w { gset_protected } { Nx } { Npx } +\__cs_tmp:w { gset_protected_nopar } { Nn } { Npn } +\__cs_tmp:w { gset_protected_nopar } { Nx } { Npx } +\__cs_tmp:w { new } { Nn } { Npn } +\__cs_tmp:w { new } { Nx } { Npx } +\__cs_tmp:w { new_nopar } { Nn } { Npn } +\__cs_tmp:w { new_nopar } { Nx } { Npx } +\__cs_tmp:w { new_protected } { Nn } { Npn } +\__cs_tmp:w { new_protected } { Nx } { Npx } +\__cs_tmp:w { new_protected_nopar } { Nn } { Npn } +\__cs_tmp:w { new_protected_nopar } { Nx } { Npx } % \end{macrocode} % \end{macro} % @@ -2684,49 +2797,40 @@ % \cs_new_protected:cn , \cs_new_protected:cx , % \cs_new_protected_nopar:cn , \cs_new_protected_nopar:cx , % } -% Then something similar for the |c| variants. -% \begin{verbatim} -% \cs_set_protected:Npn \cs_set:cn #1#2 -% { -% \cs_generate_from_arg_count:cNnn {#1} \cs_set:Npn -% { \cs_get_arg_count_from_signature:c {#1} } {#2} -% } -% \end{verbatim} -% The 24 |c| variants. +% The 24 |c| variants simply use \cs{exp_args:Nc}. % \begin{macrocode} -\cs_set:Npn \cs_tmp:w #1#2#3 +\cs_set:Npn \__cs_tmp:w #1#2 { - \cs_new_protected:cpx {cs_#1:#2} ##1##2 + \cs_new_protected_nopar:cpx { cs_ #1 : c #2 } { - \exp_not:N \cs_generate_from_arg_count:cNnn {##1} - \exp_after:wN \exp_not:N \cs:w cs_#1:#3 \cs_end: - { \exp_not:N \cs_get_arg_count_from_signature:c {##1} } {##2} + \exp_not:N \exp_args:Nc + \exp_after:wN \exp_not:N \cs:w cs_ #1 : N #2 \cs_end: } } -\cs_tmp:w { set } { cn } { Npn } -\cs_tmp:w { set } { cx } { Npx } -\cs_tmp:w { set_nopar } { cn } { Npn } -\cs_tmp:w { set_nopar } { cx } { Npx } -\cs_tmp:w { set_protected } { cn } { Npn } -\cs_tmp:w { set_protected } { cx } { Npx } -\cs_tmp:w { set_protected_nopar } { cn } { Npn } -\cs_tmp:w { set_protected_nopar } { cx } { Npx } -\cs_tmp:w { gset } { cn } { Npn } -\cs_tmp:w { gset } { cx } { Npx } -\cs_tmp:w { gset_nopar } { cn } { Npn } -\cs_tmp:w { gset_nopar } { cx } { Npx } -\cs_tmp:w { gset_protected } { cn } { Npn } -\cs_tmp:w { gset_protected } { cx } { Npx } -\cs_tmp:w { gset_protected_nopar } { cn } { Npn } -\cs_tmp:w { gset_protected_nopar } { cx } { Npx } -\cs_tmp:w { new } { cn } { Npn } -\cs_tmp:w { new } { cx } { Npx } -\cs_tmp:w { new_nopar } { cn } { Npn } -\cs_tmp:w { new_nopar } { cx } { Npx } -\cs_tmp:w { new_protected } { cn } { Npn } -\cs_tmp:w { new_protected } { cx } { Npx } -\cs_tmp:w { new_protected_nopar } { cn } { Npn } -\cs_tmp:w { new_protected_nopar } { cx } { Npx } +\__cs_tmp:w { set } { n } +\__cs_tmp:w { set } { x } +\__cs_tmp:w { set_nopar } { n } +\__cs_tmp:w { set_nopar } { x } +\__cs_tmp:w { set_protected } { n } +\__cs_tmp:w { set_protected } { x } +\__cs_tmp:w { set_protected_nopar } { n } +\__cs_tmp:w { set_protected_nopar } { x } +\__cs_tmp:w { gset } { n } +\__cs_tmp:w { gset } { x } +\__cs_tmp:w { gset_nopar } { n } +\__cs_tmp:w { gset_nopar } { x } +\__cs_tmp:w { gset_protected } { n } +\__cs_tmp:w { gset_protected } { x } +\__cs_tmp:w { gset_protected_nopar } { n } +\__cs_tmp:w { gset_protected_nopar } { x } +\__cs_tmp:w { new } { n } +\__cs_tmp:w { new } { x } +\__cs_tmp:w { new_nopar } { n } +\__cs_tmp:w { new_nopar } { x } +\__cs_tmp:w { new_protected } { n } +\__cs_tmp:w { new_protected } { x } +\__cs_tmp:w { new_protected_nopar } { n } +\__cs_tmp:w { new_protected_nopar } { x } % \end{macrocode} % \end{macro} % @@ -2758,25 +2862,25 @@ % % \subsection{Diagnostic wrapper functions} % -% \begin{macro}{\kernel_register_show:N, \kernel_register_show:c} -% Check that the variable, then apply the \tn{showthe} primitive to +% \begin{macro}[int]{\__kernel_register_show:N, \__kernel_register_show:c} +% Check that the variable exists, then apply the \tn{showthe} primitive to % the variable. The odd-looking \cs{use:n} gives a nicer output. % \begin{macrocode} -\cs_new:Npn \kernel_register_show:N #1 +\cs_new_protected:Npn \__kernel_register_show:N #1 { \cs_if_exist:NTF #1 { \tex_showthe:D \use:n {#1} } { - \msg_kernel_error:nnx { kernel } { variable-not-defined } + \__msg_kernel_error:nnx { kernel } { variable-not-defined } { \token_to_str:N #1 } } } -\cs_new_nopar:Npn \kernel_register_show:c - { \exp_args:Nc \kernel_register_show:N } +\cs_new_protected_nopar:Npn \__kernel_register_show:c + { \exp_args:Nc \__kernel_register_show:N } % \end{macrocode} % \end{macro} % -% \subsection{Engine specific definitions} +% \subsection{Engine specific definitions} % % \begin{macro}[pTF, EXP] % {\xetex_if_engine:, \luatex_if_engine:, \pdftex_if_engine:} @@ -2831,7 +2935,7 @@ % % \subsection{String comparisons} % -% \begin{macro}[pTF, EXP]{\str_if_eq:nn, \str_if_eq:xx} +% \begin{macro}[pTF, EXP]{\str_if_eq:nn, \str_if_eq_x:nn} % Modern engines provide a direct way of comparing two token lists, % but returning a number. This set of conditionals therefore make life % a bit clearer. The \texttt{nn} and \texttt{xx} versions are created @@ -2844,7 +2948,7 @@ = \c_zero \prg_return_true: \else: \prg_return_false: \fi: } -\prg_new_conditional:Npnn \str_if_eq:xx #1#2 { p , T , F , TF } +\prg_new_conditional:Npnn \str_if_eq_x:nn #1#2 { p , T , F , TF } { \if_int_compare:w \pdftex_strcmp:D {#1} {#2} = \c_zero \prg_return_true: \else: \prg_return_false: \fi: @@ -2852,20 +2956,83 @@ % \end{macrocode} % \end{macro} % +% \begin{macro}[int, EXP]{\__str_if_eq_x_return:nn} +% It turns out that we often need to compare a token list +% with the result of applying some function to it, and +% return with \cs{prg_return_true/false:}. This test is +% similar to \cs{str_if_eq:nnTF}, but hard-coded for speed. +% \begin{macrocode} +\cs_new:Npn \__str_if_eq_x_return:nn #1 #2 + { + \if_int_compare:w \pdftex_strcmp:D {#1} {#2} = \c_zero + \prg_return_true: + \else: + \prg_return_false: + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\str_case:nnn, \str_case_x:nnn} +% \begin{macro}[int, EXP]{\__prg_case_end:nw} +% \begin{macro}[aux, EXP] +% {\__str_case:nw, \__str_case_x:nw, \__str_case_end:nw} +% No calculations for strings, otherwise no surprises. +% \begin{macrocode} +\cs_new:Npn \str_case:nnn #1#2#3 + { + \tex_romannumeral:D + \__str_case:nw {#1} #2 {#1} {#3} \q_recursion_stop + } +\cs_new:Npn \__str_case:nw #1#2#3 + { + \str_if_eq:nnTF {#1} {#2} + { \__str_case_end:nw {#3} } + { \__str_case:nw {#1} } + } +\cs_new:Npn \str_case_x:nnn #1#2#3 + { + \tex_romannumeral:D + \__str_case_x:nw {#1} #2 {#1} {#3} \q_recursion_stop + } +\cs_new:Npn \__str_case_x:nw #1#2#3 + { + \str_if_eq_x:nnTF {#1} {#2} + { \__str_case_end:nw {#3} } + { \__str_case_x:nw {#1} } + } +% \end{macrocode} +% Here, |#1| will be the code needed, |#2| will be any remaining case +% or cases, and the \cs{c_zero} stops the \tn{romannumeral}. +% \begin{macrocode} +\cs_new:Npn \__prg_case_end:nw #1#2 \q_recursion_stop { \c_zero #1 } +\cs_new_eq:NN \__str_case_end:nw \__prg_case_end:nw +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% % \subsection{Breaking out of mapping functions} % -% \begin{macro}[EXP]{\prg_break_point:n, \prg_map_break:, \prg_map_break:n} +% \begin{macro}[EXP]{\__prg_break_point:Nn, \__prg_map_break:Nn} % In inline mappings, the nesting level must be reset % at the end of the mapping, even when the user decides % to break out. This is done by putting the code that -% must be performed as an argument of \cs{prg_break_point:n}. +% must be performed as an argument of \cs{__prg_break_point:Nn}. % The breaking functions are then defined to jump to -% that point and perform the argument of \cs{prg_break_point:n}, -% before the user's code (if any). +% that point and perform the argument of \cs{__prg_break_point:Nn}, +% before the user's code (if any). There is a check that we close the +% correct loop, otherwise we continue breaking. % \begin{macrocode} -\cs_new_eq:NN \prg_break_point:n \use:n -\cs_new:Npn \prg_map_break: #1 \prg_break_point:n #2 { #2 } -\cs_new:Npn \prg_map_break:n #1 #2 \prg_break_point:n #3 { #3 #1 } +\cs_new_eq:NN \__prg_break_point:Nn \use_ii:nn +\cs_new:Npn \__prg_map_break:Nn #1#2#3 \__prg_break_point:Nn #4#5 + { + #5 + \if_meaning:w #1 #4 + \exp_after:wN \use_iii:nnn + \fi: + \__prg_map_break:Nn #1 {#2} + } % \end{macrocode} % \end{macro} % @@ -2963,6 +3130,24 @@ % \end{macrocode} % \end{macro} % +% Deprecated 2012-06-05 for removal after 2012-12-31. +% +% \begin{macro}[pTF, EXP]{\str_if_eq:xx} +% Not really true \texttt{x}-type expansion +% \begin{macrocode} +\cs_new_eq:NN \str_if_eq_p:xx \str_if_eq_x_p:nn +\cs_new_eq:NN \str_if_eq:xxT \str_if_eq_x:nnT +\cs_new_eq:NN \str_if_eq:xxF \str_if_eq_x:nnF +\cs_new_eq:NN \str_if_eq:xxTF \str_if_eq_x:nnTF +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\chk_if_free_cs:N} +% \begin{macrocode} +\cs_new_eq:NN \chk_if_free_cs:N \__chk_if_free_cs:N +% \end{macrocode} +% \end{macro} +% % \begin{macrocode} %</initex|package> % \end{macrocode} |