diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3basics.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3basics.dtx | 255 |
1 files changed, 158 insertions, 97 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx b/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx index c3517204991..debebd7cc60 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3basics.dtx @@ -41,7 +41,7 @@ % }^^A % } % -% \date{Released 2018-04-30} +% \date{Released 2018-05-12} % % \maketitle % @@ -1203,7 +1203,7 @@ \tex_let:D \or: \tex_or:D \tex_let:D \else: \tex_else:D \tex_let:D \fi: \tex_fi:D -\tex_let:D \reverse_if:N \etex_unless:D +\tex_let:D \reverse_if:N \tex_unless:D \tex_let:D \if:w \tex_if:D \tex_let:D \if_charcode:w \tex_if:D \tex_let:D \if_catcode:w \tex_ifcat:D @@ -1230,8 +1230,8 @@ % \begin{macro}[EXP]{\if_cs_exist:N, \if_cs_exist:w, \cs:w, \cs_end:} % Building csnames and testing if control sequences exist. % \begin{macrocode} -\tex_let:D \if_cs_exist:N \etex_ifdefined:D -\tex_let:D \if_cs_exist:w \etex_ifcsname:D +\tex_let:D \if_cs_exist:N \tex_ifdefined:D +\tex_let:D \if_cs_exist:w \tex_ifcsname:D \tex_let:D \cs:w \tex_csname:D \tex_let:D \cs_end: \tex_endcsname:D % \end{macrocode} @@ -1243,7 +1243,7 @@ % \begin{macrocode} \tex_let:D \exp_after:wN \tex_expandafter:D \tex_let:D \exp_not:N \tex_noexpand:D -\tex_let:D \exp_not:n \etex_unexpanded:D +\tex_let:D \exp_not:n \tex_unexpanded:D \tex_let:D \exp:w \tex_romannumeral:D \tex_chardef:D \exp_end: = 0 ~ % \end{macrocode} @@ -1260,9 +1260,9 @@ % \begin{macro}[EXP]{\tl_to_str:n, \token_to_str:N, \__kernel_tl_to_str:w} % Making strings. % \begin{macrocode} -\tex_let:D \tl_to_str:n \etex_detokenize:D +\tex_let:D \tl_to_str:n \tex_detokenize:D \tex_let:D \token_to_str:N \tex_string:D -\tex_let:D \__kernel_tl_to_str:w \etex_detokenize:D +\tex_let:D \__kernel_tl_to_str:w \tex_detokenize:D % \end{macrocode} % \end{macro} % @@ -1332,8 +1332,8 @@ % % \subsection{Defining some constants} % -% \begin{variable}{\c_zero} -% We need the constant \cs{c_zero} +% \begin{variable}{\c_zero_int} +% We need the constant \cs{c_zero_int} % 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 \cs{tex_chardef:D} or @@ -1341,7 +1341,7 @@ % required but it can't be used until the allocation has been set % up properly! % \begin{macrocode} -\tex_chardef:D \c_zero = 0 ~ +\tex_chardef:D \c_zero_int = 0 ~ % \end{macrocode} % \end{variable} % @@ -1349,7 +1349,7 @@ % This is here as this particular integer is needed both in package % mode and to bootstrap \pkg{l3alloc}, and is documented in \pkg{l3int}. % \begin{macrocode} -\etex_ifdefined:D \luatex_luatexversion:D +\tex_ifdefined:D \tex_luatexversion:D \tex_chardef:D \c_max_register_int = 65 535 ~ \tex_else:D \tex_mathchardef:D \c_max_register_int = 32 767 ~ @@ -1375,18 +1375,18 @@ % \begin{macrocode} \tex_let:D \cs_set_nopar:Npn \tex_def:D \tex_let:D \cs_set_nopar:Npx \tex_edef:D -\etex_protected:D \tex_long:D \tex_def:D \cs_set:Npn +\tex_protected:D \tex_long:D \tex_def:D \cs_set:Npn { \tex_long:D \tex_def:D } -\etex_protected:D \tex_long:D \tex_def:D \cs_set:Npx +\tex_protected:D \tex_long:D \tex_def:D \cs_set:Npx { \tex_long:D \tex_edef:D } -\etex_protected:D \tex_long:D \tex_def:D \cs_set_protected_nopar:Npn - { \etex_protected:D \tex_def:D } -\etex_protected:D \tex_long:D \tex_def:D \cs_set_protected_nopar:Npx - { \etex_protected:D \tex_edef:D } -\etex_protected:D \tex_long:D \tex_def:D \cs_set_protected:Npn - { \etex_protected:D \tex_long:D \tex_def:D } -\etex_protected:D \tex_long:D \tex_def:D \cs_set_protected:Npx - { \etex_protected:D \tex_long:D \tex_edef:D } +\tex_protected:D \tex_long:D \tex_def:D \cs_set_protected_nopar:Npn + { \tex_protected:D \tex_def:D } +\tex_protected:D \tex_long:D \tex_def:D \cs_set_protected_nopar:Npx + { \tex_protected:D \tex_edef:D } +\tex_protected:D \tex_long:D \tex_def:D \cs_set_protected:Npn + { \tex_protected:D \tex_long:D \tex_def:D } +\tex_protected:D \tex_long:D \tex_def:D \cs_set_protected:Npx + { \tex_protected:D \tex_long:D \tex_edef:D } % \end{macrocode} % \end{macro} % @@ -1406,13 +1406,13 @@ \cs_set_protected:Npn \cs_gset:Npx { \tex_long:D \tex_xdef:D } \cs_set_protected:Npn \cs_gset_protected_nopar:Npn - { \etex_protected:D \tex_gdef:D } + { \tex_protected:D \tex_gdef:D } \cs_set_protected:Npn \cs_gset_protected_nopar:Npx - { \etex_protected:D \tex_xdef:D } + { \tex_protected:D \tex_xdef:D } \cs_set_protected:Npn \cs_gset_protected:Npn - { \etex_protected:D \tex_long:D \tex_gdef:D } + { \tex_protected:D \tex_long:D \tex_gdef:D } \cs_set_protected:Npn \cs_gset_protected:Npx - { \etex_protected:D \tex_long:D \tex_xdef:D } + { \tex_protected:D \tex_long:D \tex_xdef:D } % \end{macrocode} % \end{macro} % @@ -1458,7 +1458,7 @@ % A candidate, but needed early as it links to string comparisons. % Currently \LuaTeX-only. % \begin{macrocode} -\cs_set:Npn \use_x:n #1 { \luatex_expanded:D {#1} } +\cs_set:Npn \use_x:n #1 { \tex_expanded:D {#1} } % \end{macrocode} % \end{macro} % @@ -1592,7 +1592,7 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}{\debug_on:n, \debug_off:n} +% \begin{macro}{\debug_on:n, \debug_off:n, \@@_all_on:, \@@_all_off:} % % \begin{macrocode} \__kernel_if_debug:TF @@ -1613,6 +1613,26 @@ { \__kernel_msg_error:nnn { kernel } { debug } {##1} } } } + \cs_set_protected:Npn \@@_all_on: + { + \debug_on:n + { + check-declarations , + check-expressions , + deprecation , + log-functions , + } + } + \cs_set_protected:Npn \@@_all_off: + { + \debug_off:n + { + check-declarations , + check-expressions , + deprecation , + log-functions , + } + } } { \cs_set_protected:Npn \debug_on:n #1 @@ -1815,7 +1835,7 @@ % to convert to integer) before it encounters the final % \cs{tex_relax:D}. Since \cs{tex_romannumeral:D} does not absorb % \cs{tex_relax:D} the output will be nonempty. Note that |#3| is -% empty except for mu expressions for which it is \cs{etex_mutoglue:D} +% empty except for mu expressions for which it is \cs{tex_mutoglue:D} % to avoid an \enquote{incompatible glue units} error. Note also that % if we had omitted the first \cs{tex_relax:D} then for instance % |1+2\relax+3| would incorrectly be accepted as a valid integer @@ -2131,7 +2151,7 @@ % \prg_set_protected_conditional:Npnn , % \prg_new_protected_conditional:Npnn , % } -% \begin{macro}{\@@_generate_conditional_parm:nnNpnn} +% \begin{macro}{\@@_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 @@ -2141,23 +2161,24 @@ % \Arg{set~or~new} \Arg{maybe~protected} \Arg{parameters} |{TF,...}| % \Arg{code} to the auxiliary function responsible for defining all % conditionals. +% Note that |e| stands for expandable and |p| for protected. % \begin{macrocode} \cs_set_protected:Npn \prg_set_conditional:Npnn - { \@@_generate_conditional_parm:nnNpnn { set } { } } + { \@@_generate_conditional_parm:NNNpnn \cs_set:Npn e } \cs_set_protected:Npn \prg_new_conditional:Npnn - { \@@_generate_conditional_parm:nnNpnn { new } { } } + { \@@_generate_conditional_parm:NNNpnn \cs_new:Npn e } \cs_set_protected:Npn \prg_set_protected_conditional:Npnn - { \@@_generate_conditional_parm:nnNpnn { set } { _protected } } + { \@@_generate_conditional_parm:NNNpnn \cs_set_protected:Npn p } \cs_set_protected:Npn \prg_new_protected_conditional:Npnn - { \@@_generate_conditional_parm:nnNpnn { new } { _protected } } -\cs_set_protected:Npn \@@_generate_conditional_parm:nnNpnn #1#2#3#4# + { \@@_generate_conditional_parm:NNNpnn \cs_new_protected:Npn p } +\cs_set_protected:Npn \@@_generate_conditional_parm:NNNpnn #1#2#3#4# { \use:x { - \@@_generate_conditional:nnNnnnnn + \@@_generate_conditional:nnNNNnnn \cs_split_function:N #3 } - {#1} {#2} {#4} + #1 #2 {#4} } % \end{macrocode} % \end{macro} @@ -2172,8 +2193,8 @@ % } % \begin{macro} % { -% \@@_generate_conditional_count:nnNnn , -% \@@_generate_conditional_count:nnNnnnn +% \@@_generate_conditional_count:NNNnn , +% \@@_generate_conditional_count:nnNNNnn % } % The user functions for the types automatically inserting the correct % parameter text based on the signature. The various functions only @@ -2189,26 +2210,26 @@ % later. % \begin{macrocode} \cs_set_protected:Npn \prg_set_conditional:Nnn - { \@@_generate_conditional_count:nnNnn { set } { } } + { \@@_generate_conditional_count:NNNnn \cs_set:Npn e } \cs_set_protected:Npn \prg_new_conditional:Nnn - { \@@_generate_conditional_count:nnNnn { new } { } } + { \@@_generate_conditional_count:NNNnn \cs_new:Npn e } \cs_set_protected:Npn \prg_set_protected_conditional:Nnn - { \@@_generate_conditional_count:nnNnn { set } { _protected } } + { \@@_generate_conditional_count:NNNnn \cs_set_protected:Npn p } \cs_set_protected:Npn \prg_new_protected_conditional:Nnn - { \@@_generate_conditional_count:nnNnn { new } { _protected } } -\cs_set_protected:Npn \@@_generate_conditional_count:nnNnn #1#2#3 + { \@@_generate_conditional_count:NNNnn \cs_new_protected:Npn p } +\cs_set_protected:Npn \@@_generate_conditional_count:NNNnn #1#2#3 { \use:x { - \@@_generate_conditional_count:nnNnnnn + \@@_generate_conditional_count:nnNNNnn \cs_split_function:N #3 } - {#1} {#2} + #1 #2 } -\cs_set_protected:Npn \@@_generate_conditional_count:nnNnnnn #1#2#3#4#5 +\cs_set_protected:Npn \@@_generate_conditional_count:nnNNNnn #1#2#3#4#5 { \__kernel_cs_parm_from_arg_count:nnF - { \@@_generate_conditional:nnNnnnnn {#1} {#2} #3 {#4} {#5} } + { \@@_generate_conditional:nnNNNnnn {#1} {#2} #3 #4 #5 } { \tl_count:n {#2} } { \__kernel_msg_error:nnxx { kernel } { bad-number-of-arguments } @@ -2223,8 +2244,10 @@ % % \begin{macro} % { -% \@@_generate_conditional:nnNnnnnn, -% \@@_generate_conditional:nnnnnnw +% \@@_generate_conditional:nnNNNnnn, +% \@@_generate_conditional:NNnnnnNw, +% \@@_generate_conditional_test:w, +% \@@_generate_conditional_fast:nw, % } % 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 @@ -2236,8 +2259,15 @@ % empty), the seventh is the list of forms to define, the eighth is the % replacement text which we will augment when defining the forms. % The use of \cs{tl_to_str:n} makes the later loop more robust. +% +% A large number of our low-level conditionals look like \meta{code} +% \cs{prg_return_true:} \cs{else:} \cs{prg_return_false:} \cs{fi:} so +% we optimize this special case by calling +% \cs{@@_generate_conditional_fast:nw} \Arg{code}. This passes +% \cs{use_i:nn} instead of \cs{use_i_ii:nnn} to functions such as +% \cs{@@_generate_p_form:wNNnnnnN}. % \begin{macrocode} -\cs_set_protected:Npn \@@_generate_conditional:nnNnnnnn #1#2#3#4#5#6#7#8 +\cs_set_protected:Npn \@@_generate_conditional:nnNNNnnn #1#2#3#4#5#6#7#8 { \if_meaning:w \c_false_bool #3 \__kernel_msg_error:nnx { kernel } { missing-colon } @@ -2246,95 +2276,126 @@ \fi: \use:x { - \exp_not:N \@@_generate_conditional:nnnnnnw - \exp_not:n { {#4} {#5} {#1} {#2} {#6} {#8} } + \exp_not:N \@@_generate_conditional:NNnnnnNw + \exp_not:n { #4 #5 {#1} {#2} {#6} } + \@@_generate_conditional_test:w + #8 \q_mark + \@@_generate_conditional_fast:nw + \prg_return_true: \else: \prg_return_false: \fi: \q_mark + \use_none:n + \exp_not:n { {#8} \use_i_ii:nnn } \tl_to_str:n {#7} \exp_not:n { , \q_recursion_tail , \q_recursion_stop } } } +\cs_set:Npn \@@_generate_conditional_test:w + #1 \prg_return_true: \else: \prg_return_false: \fi: \q_mark #2 + { #2 {#1} } +\cs_set:Npn \@@_generate_conditional_fast:nw #1#2 \exp_not:n #3 + { \exp_not:n { {#1} \use_i:nn } } % \end{macrocode} % 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 (unless the form is empty, to allow for |{T, , F}|), -% then \cs{use_none:nnnnnnn} cleans up. Otherwise, the +% then \cs{use_none:nnnnnnnn} cleans up. Otherwise, the % error message is removed by the variant form. % \begin{macrocode} -\cs_set_protected:Npn \@@_generate_conditional:nnnnnnw #1#2#3#4#5#6#7 , +\cs_set_protected:Npn \@@_generate_conditional:NNnnnnNw #1#2#3#4#5#6#7#8 , { - \if_meaning:w \q_recursion_tail #7 + \if_meaning:w \q_recursion_tail #8 \exp_after:wN \use_none_delimit_by_q_recursion_stop:w \fi: - \use:c { @@_generate_ #7 _form:wnnnnnn } - \tl_if_empty:nF {#7} + \use:c { @@_generate_ #8 _form:wNNnnnnN } + \tl_if_empty:nF {#8} { \__kernel_msg_error:nnxx { kernel } { conditional-form-unknown } - {#7} { \token_to_str:c { #3 : #4 } } + {#8} { \token_to_str:c { #3 : #4 } } } - \use_none:nnnnnnn + \use_none:nnnnnnnn \q_stop - {#1} {#2} {#3} {#4} {#5} {#6} - \@@_generate_conditional:nnnnnnw {#1} {#2} {#3} {#4} {#5} {#6} + #1 #2 {#3} {#4} {#5} {#6} #7 + \@@_generate_conditional:NNnnnnNw #1 #2 {#3} {#4} {#5} {#6} #7 } % \end{macrocode} % \end{macro} % % \begin{macro} % { -% \@@_generate_p_form:wnnnnnn, -% \@@_generate_TF_form:wnnnnnn, -% \@@_generate_T_form:wnnnnnn, -% \@@_generate_F_form:wnnnnnn +% \@@_generate_p_form:wNNnnnnN, +% \@@_generate_TF_form:wNNnnnnN, +% \@@_generate_T_form:wNNnnnnN, +% \@@_generate_F_form:wNNnnnnN % } +% \begin{macro}[EXP]{\@@_p_true:w} % 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{exp_end:}: -% notice the construction of the different variants relies on this, -% and that the |TF| and |F| variants 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 \@@_generate_p_form:wnnnnnn - #1 \q_stop #2#3#4#5#6#7 +% following arguments: 1: junk, 2: \cs{cs_set:Npn} or similar, 3: |p| +% (for protected conditionals) or |e|, 4: function name, 5: signature, +% 6: parameter text, 7: replacement (possibly trimmed by +% \cs{@@_generate_conditional_fast:nw}), 8: \cs{use_i_ii:nnn} or +% \cs{use_i:nn} (for \enquote{fast} conditionals). Remember that the +% logic-returning functions expect two arguments to be present after +% \cs{exp_end:}: notice the construction of the different variants +% relies on this, and that the |TF| and |F| variants 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. For \enquote{fast} conditionals, |#7| has an +% extra \cs[no-index]{if_\ldots{}}. To optimize a bit further we +% could replace \cs{exp_after:wN} \cs{use_ii:nnn} and similar by a +% single macro similar to \cs{@@_p_true:w}. The drawback is that if +% the |T| or |F| arguments are actually missing, the recovery from +% the runaway argument would not insert \cs{fi:} back, messing up +% nesting of conditionals. +% \begin{macrocode} +\cs_set_protected:Npn \@@_generate_p_form:wNNnnnnN + #1 \q_stop #2#3#4#5#6#7#8 { - \if_meaning:w \scan_stop: #3 \scan_stop: + \if_meaning:w e #3 \exp_after:wN \use_i:nn \else: \exp_after:wN \use_ii:nn \fi: { - \exp_args:cc { cs_ #2 #3 :Npn } { #4 _p: #5 } #6 - { #7 \exp_end: \c_true_bool \c_false_bool } + #8 + { \exp_args:Nc #2 { #4 _p: #5 } #6 } + { { #7 \exp_end: \c_true_bool \c_false_bool } } + { #7 \@@_p_true:w \fi: \c_false_bool } } { \__kernel_msg_error:nnx { kernel } { protected-predicate } { \token_to_str:c { #4 _p: #5 } } } } -\cs_set_protected:Npn \@@_generate_T_form:wnnnnnn - #1 \q_stop #2#3#4#5#6#7 +\cs_set_protected:Npn \@@_generate_T_form:wNNnnnnN + #1 \q_stop #2#3#4#5#6#7#8 { - \exp_args:cc { cs_ #2 #3 :Npn } { #4 : #5 T } #6 - { #7 \exp_end: \use:n \use_none:n } + #8 + { \exp_args:Nc #2 { #4 : #5 T } #6 } + { { #7 \exp_end: \use:n \use_none:n } } + { #7 \exp_after:wN \use_ii:nn \fi: \use_none:n } } -\cs_set_protected:Npn \@@_generate_F_form:wnnnnnn - #1 \q_stop #2#3#4#5#6#7 +\cs_set_protected:Npn \@@_generate_F_form:wNNnnnnN + #1 \q_stop #2#3#4#5#6#7#8 { - \exp_args:cc { cs_ #2 #3 :Npn } { #4 : #5 F } #6 - { #7 \exp_end: { } } + #8 + { \exp_args:Nc #2 { #4 : #5 F } #6 } + { { #7 \exp_end: { } } } + { #7 \exp_after:wN \use_none:nn \fi: \use:n } } -\cs_set_protected:Npn \@@_generate_TF_form:wnnnnnn - #1 \q_stop #2#3#4#5#6#7 +\cs_set_protected:Npn \@@_generate_TF_form:wNNnnnnN + #1 \q_stop #2#3#4#5#6#7#8 { - \exp_args:cc { cs_ #2 #3 :Npn } { #4 : #5 TF } #6 - { #7 \exp_end: } + #8 + { \exp_args:Nc #2 { #4 : #5 TF } #6 } + { { #7 \exp_end: } } + { #7 \exp_after:wN \use_ii:nnn \fi: \use_ii:nn } } +\cs_set:Npn \@@_p_true:w \fi: \c_false_bool { \fi: \c_true_bool } % \end{macrocode} % \end{macro} +% \end{macro} % % \begin{macro}{\prg_set_eq_conditional:NNn, \prg_new_eq_conditional:NNn} % \begin{macro}{\@@_set_eq_conditional:NNNn} @@ -2530,10 +2591,10 @@ % \verb*|\token_to_str:N \ |, and the auxiliary \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{tex_romannumeral:D} with \cs{c_zero}. +% \cs{token_to_str:N}, and stops the \cs{tex_romannumeral:D} with \cs{c_zero_int}. % 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{@@_to_str:w} -% comes into play, inserting |-\int_value:w|, which expands \cs{c_zero} +% comes into play, inserting |-\int_value:w|, which expands \cs{c_zero_int} % to the character |0|. The initial \cs{tex_romannumeral:D} then sees % |0|, which is not a terminated number, followed by the escape character, % a space, which is removed, terminating the expansion of @@ -2545,18 +2606,18 @@ { % \end{macrocode} % We implement the expansion scheme using \cs{tex_romannumeral:D} -% terminating it with \cs{c_zero} rather than using \cs{exp:w} and +% terminating it with \cs{c_zero_int} rather than using \cs{exp:w} and % \cs{exp_end:} as we normally do. The reason is that the code -% heavily depends on terminating the expansion with \cs{c_zero} so +% heavily depends on terminating the expansion with \cs{c_zero_int} so % we make this dependency explicit. % \begin{macrocode} \tex_romannumeral:D \if:w \token_to_str:N \ \@@_to_str:w \fi: \exp_after:wN \@@_to_str:N \token_to_str:N } -\cs_set:Npn \@@_to_str:N #1 { \c_zero } +\cs_set:Npn \@@_to_str:N #1 { \c_zero_int } \cs_set:Npn \@@_to_str:w #1 \@@_to_str:N - { - \int_value:w \fi: \exp_after:wN \c_zero } + { - \int_value:w \fi: \exp_after:wN \c_zero_int } % \end{macrocode} % If speed is a concern we could use \tn{csstring} in \LuaTeX{}. For % the empty csname that primitive gives an empty result while the |