summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/l3kernel/l3keys.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/l3kernel/l3keys.dtx')
-rw-r--r--macros/latex/contrib/l3kernel/l3keys.dtx161
1 files changed, 105 insertions, 56 deletions
diff --git a/macros/latex/contrib/l3kernel/l3keys.dtx b/macros/latex/contrib/l3kernel/l3keys.dtx
index d1f9f19268..860854cc77 100644
--- a/macros/latex/contrib/l3kernel/l3keys.dtx
+++ b/macros/latex/contrib/l3kernel/l3keys.dtx
@@ -2,7 +2,7 @@
%
%% File: l3keys.dtx
%
-% Copyright (C) 2006-2020 The LaTeX3 Project
+% Copyright (C) 2006-2021 The LaTeX3 Project
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2020-12-07}
+% \date{Released 2021-01-09}
%
% \maketitle
%
@@ -891,7 +891,45 @@
% \end{verbatim}
% are treated identically.
%
-% \begin{function}[EXP,updated = 2020-02-20]{\keyval_parse:NNn}
+% \begin{function}[rEXP, added=2020-12-19]{\keyval_parse:nnn}
+% \begin{syntax}
+% \cs{keyval_parse:nnn} \Arg{code_1} \Arg{code_2} \Arg{key--value list}
+% \end{syntax}
+% Parses the \meta{key--value list} into a series of \meta{keys} and
+% associated \meta{values}, or keys alone (if no \meta{value} was
+% given). \meta{code_1} receives each \meta{key} (with no \meta{value}) as a
+% trailing brace group, whereas \meta{code_2} is appended by two brace groups,
+% the \meta{key} and \meta{value}.
+% The order of the \meta{keys} in the \meta{key--value list}
+% is preserved. Thus
+% \begin{verbatim}
+% \keyval_parse:nnn
+% { \use_none:nn { code 1 } }
+% { \use_none:nnn { code 2 } }
+% { key1 = value1 , key2 = value2, key3 = , key4 }
+% \end{verbatim}
+% is converted into an input stream
+% \begin{verbatim}
+% \use_none:nnn { code 2 } { key1 } { value1 }
+% \use_none:nnn { code 2 } { key2 } { value2 }
+% \use_none:nnn { code 2 } { key3 } { }
+% \use_none:nn { code 1 } { key4 }
+% \end{verbatim}
+% Note that there is a difference between an empty value (an equals
+% sign followed by nothing) and a missing value (no equals sign at
+% all). Spaces are trimmed from the ends of the \meta{key} and \meta{value},
+% then one \emph{outer} set of braces is removed from the \meta{key}
+% and \meta{value} as part of the processing. If you need exactly the output
+% shown above, you'll need to either \texttt{x}-type or \texttt{e}-type expand
+% the function.
+% \begin{texnote}
+% The result of each list element is returned within \cs{exp_not:n}, which
+% means that the converted input stream does not expand further when
+% appearing in an \texttt{x}-type or \texttt{e}-type argument expansion.
+% \end{texnote}
+% \end{function}
+%
+% \begin{function}[rEXP,updated = 2020-12-19]{\keyval_parse:NNn}
% \begin{syntax}
% \cs{keyval_parse:NNn} \meta{function_1} \meta{function_2} \Arg{key--value list}
% \end{syntax}
@@ -920,6 +958,9 @@
% all). Spaces are trimmed from the ends of the \meta{key} and \meta{value},
% then one \emph{outer} set of braces is removed from the \meta{key}
% and \meta{value} as part of the processing.
+%
+% This shares the implementation of \cs{keyval_parse:nnn}, the difference is
+% only semantically.
% \begin{texnote}
% The result is returned within \cs{exp_not:n}, which means that the
% converted input stream does not expand further when appearing in an
@@ -969,30 +1010,31 @@
{
% \end{macrocode}
%
-% \begin{macro}[EXP]{\keyval_parse:NNn}
+% \begin{macro}[EXP]{\keyval_parse:nnn, \keyval_parse:NNn}
% The main function starts the first of two loops. The outer loop splits the
% key--value list at active commas, the inner loop will do so at other commas.
% The use of \cs{s_@@_mark} here prevents loss of braces from the key
% argument.
% \begin{macrocode}
- \cs_new:Npn \keyval_parse:NNn ##1 ##2 ##3
- { \@@_loop_active:NNw ##1 ##2 \s_@@_mark ##3 #1 \s_@@_tail #1 }
+ \cs_new:Npn \keyval_parse:nnn ##1 ##2 ##3
+ { \@@_loop_active:nnw {##1} {##2} \s_@@_mark ##3 #1 \s_@@_tail #1 }
+ \cs_new_eq:NN \keyval_parse:NNn \keyval_parse:nnn
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[EXP]{\@@_loop_active:NNw}
+% \begin{macro}[EXP]{\@@_loop_active:nnw}
% First a fast test for the end of the loop is done, it'll gobble everything
% up to a \cs{s_@@_tail}. The loop ending macro will gobble everything to the
-% last \cs{s_@@_mark} in this definition.
+% last comma in this definition.
% If the end isn't reached yet, start the second loop splitting at other
-% commas, and after that one iterate the current loop.
+% commas, the next iteration of this first loop will be inserted by the end of
+% \cs{@@_loop_other:nnw}.
% \begin{macrocode}
- \cs_new:Npn \@@_loop_active:NNw ##1 ##2 ##3 #1
+ \cs_new:Npn \@@_loop_active:nnw ##1 ##2 ##3 #1
{
\@@_if_recursion_tail:w ##3
\@@_end_loop_active:w \s_@@_tail
- \@@_loop_other:NNw ##1 ##2 ##3 , \s_@@_tail ,
- \@@_loop_active:NNw ##1 ##2 \s_@@_mark
+ \@@_loop_other:nnw {##1} {##2} ##3 , \s_@@_tail ,
}
% \end{macrocode}
% \end{macro}
@@ -1003,14 +1045,14 @@
% token following \cs{s_@@_mark} that followed the equals sign. Hence they
% also test for the presence of such an equals sign simultaneously.
% \begin{macrocode}
- \cs_new:Npn \@@_split_other:w ##1 = ##2 \s_@@_mark ##3 ##4 \s_@@_stop
+ \cs_new:Npn \@@_split_other:w ##1 = ##2 \s_@@_mark ##3
{ ##3 ##1 \s_@@_stop \s_@@_mark ##2 }
- \cs_new:Npn \@@_split_active:w ##1 #2 ##2 \s_@@_mark ##3 ##4 \s_@@_stop
+ \cs_new:Npn \@@_split_active:w ##1 #2 ##2 \s_@@_mark ##3
{ ##3 ##1 \s_@@_stop \s_@@_mark ##2 }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[EXP]{\@@_loop_other:NNw}
+% \begin{macro}[EXP]{\@@_loop_other:nnw}
% The second loop uses the same test for its end as the first loop, next it
% splits at the first active equals sign using \cs{@@_split_active:w}. The
% \cs{s_@@_nil} prevents accidental brace stripping and acts as a delimiter in
@@ -1018,16 +1060,15 @@
% number of necessary expansion steps for the expected average use case of
% other equals signs and hence perform better on average.
% \begin{macrocode}
- \cs_new:Npn \@@_loop_other:NNw ##1 ##2 ##3 ,
+ \cs_new:Npn \@@_loop_other:nnw ##1 ##2 ##3 ,
{
\@@_if_recursion_tail:w ##3
\@@_end_loop_other:w \s_@@_tail
\@@_split_active:w ##3 \s_@@_nil
\s_@@_mark \@@_split_active_auxi:w
#2 \s_@@_mark \@@_clean_up_active:w
- \s_@@_stop
- ##1 ##2
- \@@_loop_other:NNw ##1 ##2 \s_@@_mark
+ {##1} {##2}
+ \s_@@_mark
}
% \end{macrocode}
% \end{macro}
@@ -1050,7 +1091,6 @@
\@@_split_other:w ##1 \s_@@_nil
\s_@@_mark \@@_misplaced_equal_after_active_error:w
= \s_@@_mark \@@_split_active_auxii:w
- \s_@@_stop
}
% \end{macrocode}
% \cs{@@_split_active_auxii:w} gets the correct key name with a leading
@@ -1061,7 +1101,8 @@
\cs_new:Npn \@@_split_active_auxii:w
##1 \s_@@_nil \s_@@_mark \@@_misplaced_equal_after_active_error:w
\s_@@_stop \s_@@_mark
- { \@@_trim:nN { ##1 } \@@_split_active_auxiii:w }
+ ##2 \s_@@_nil #2 \s_@@_mark \@@_clean_up_active:w
+ { \@@_trim:nN {##1} \@@_split_active_auxiii:w ##2 \s_@@_nil }
% \end{macrocode}
% Next we test for a misplaced active equals sign in the value, if none is
% found \cs{@@_split_active_auxiv:w} will be called.
@@ -1071,8 +1112,7 @@
\@@_split_active:w ##2 \s_@@_nil
\s_@@_mark \@@_misplaced_equal_in_split_error:w
#2 \s_@@_mark \@@_split_active_auxiv:w
- \s_@@_stop
- { ##1 }
+ {##1}
}
% \end{macrocode}
% This runs the last test after sanitising the remainder of the previous one.
@@ -1086,16 +1126,15 @@
\@@_split_other:w ##1 \s_@@_nil
\s_@@_mark \@@_misplaced_equal_in_split_error:w
= \s_@@_mark \@@_split_active_auxv:w
- \s_@@_stop
}
% \end{macrocode}
% This last macro in this execution branch sanitises the last test, trims the
-% value and passes it to \cs{@@_pair:nnNN}.
+% value and passes it to \cs{@@_pair:nnnn}.
% \begin{macrocode}
\cs_new:Npn \@@_split_active_auxv:w
##1 \s_@@_nil \s_@@_mark \@@_misplaced_equal_in_split_error:w
\s_@@_stop \s_@@_mark
- { \@@_trim:nN { ##1 } \@@_pair:nnNN }
+ { \@@_trim:nN { ##1 } \@@_pair:nnnn }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -1115,7 +1154,6 @@
\@@_split_other:w ##1 \s_@@_nil
\s_@@_mark \@@_split_other_auxi:w
= \s_@@_mark \@@_clean_up_other:w
- \s_@@_stop
}
% \end{macrocode}
% \end{macro}
@@ -1132,24 +1170,25 @@
{ \@@_trim:nN { ##1 } \@@_split_other_auxii:w }
% \end{macrocode}
% We know that the value doesn't contain misplaced active equals signs but we
-% have to test for others.
+% have to test for others. Also we need to sanitise the previous test, which
+% is done here and not earlier to avoid superfluous argument grabbing.
% \begin{macrocode}
- \cs_new:Npn \@@_split_other_auxii:w ##1 ##2 \s_@@_nil
+ \cs_new:Npn \@@_split_other_auxii:w
+ ##1 ##2 \s_@@_nil = \s_@@_mark \@@_clean_up_other:w
{
\@@_split_other:w ##2 \s_@@_nil
\s_@@_mark \@@_misplaced_equal_in_split_error:w
= \s_@@_mark \@@_split_other_auxiii:w
- \s_@@_stop
{ ##1 }
}
% \end{macrocode}
% \cs{@@_split_other_auxiii:w} sanitises the test for other equals signs,
-% trims the value and forwards it to \cs{@@_pair:nnNN}.
+% trims the value and forwards it to \cs{@@_pair:nnnn}.
% \begin{macrocode}
\cs_new:Npn \@@_split_other_auxiii:w
##1 \s_@@_nil \s_@@_mark \@@_misplaced_equal_in_split_error:w
\s_@@_stop \s_@@_mark
- { \@@_trim:nN { ##1 } \@@_pair:nnNN }
+ { \@@_trim:nN { ##1 } \@@_pair:nnnn }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -1159,14 +1198,14 @@
% \cs{@@_clean_up_other:w} is the last branch that might exist. It is called
% if no equals sign was found, hence the only possibilities left are a blank
% list element, which is to be skipped, or a lonely key. If it's no empty list
-% element this will trim the key name and forward it to \cs{@@_key:nNN}.
+% element this will trim the key name and forward it to \cs{@@_key:nn}.
% \begin{macrocode}
\cs_new:Npn \@@_clean_up_other:w
##1 \s_@@_nil \s_@@_mark \@@_split_other_auxi:w \s_@@_stop \s_@@_mark
{
\@@_if_blank:w ##1 \s_@@_nil \s_@@_stop \@@_blank_true:w
- \s_@@_mark \s_@@_stop \use:n
- { \@@_trim:nN { ##1 } \@@_key:nNN }
+ \s_@@_mark \s_@@_stop
+ \@@_trim:nN { ##1 } \@@_key:nn
}
% \end{macrocode}
% \end{macro}
@@ -1174,21 +1213,26 @@
% \begin{macro}[EXP]{\@@_misplaced_equal_after_active_error:w}
% \begin{macro}[EXP]{\@@_misplaced_equal_in_split_error:w}
% All these two macros do is gobble the remainder of the current other loop
-% execution and throw an error.
+% execution and throw an error. Afterwards they have to insert the next loop
+% iteration.
% \begin{macrocode}
\cs_new:Npn \@@_misplaced_equal_after_active_error:w
\s_@@_mark ##1 \s_@@_stop \s_@@_mark ##2 \s_@@_nil
- \s_@@_mark ##3 \s_@@_nil ##4 ##5
+ = \s_@@_mark \@@_split_active_auxii:w
+ \s_@@_mark ##3 \s_@@_nil
+ #2 \s_@@_mark \@@_clean_up_active:w
{
\__kernel_msg_expandable_error:nn
{ kernel } { misplaced-equals-sign }
+ \@@_loop_other:nnw
}
\cs_new:Npn \@@_misplaced_equal_in_split_error:w
\s_@@_mark ##1 \s_@@_stop \s_@@_mark ##2 \s_@@_nil
- ##3 ##4 ##5
+ ##3 \s_@@_mark ##4 ##5
{
\__kernel_msg_expandable_error:nn
{ kernel } { misplaced-equals-sign }
+ \@@_loop_other:nnw
}
% \end{macrocode}
% \end{macro}
@@ -1197,21 +1241,20 @@
% \begin{macro}[EXP]{\@@_end_loop_other:w, \@@_end_loop_active:w}
% All that's left for the parsing loops are the macros which end the
% recursion. Both just gobble the remaining tokens of the respective loop
-% including the next recursion call.
+% including the next recursion call. \cs{@@_end_loop_other:w} also has to
+% insert the next iteration of the active loop.
% \begin{macrocode}
\cs_new:Npn \@@_end_loop_other:w
\s_@@_tail
- \@@_split_active:w ##1 \s_@@_nil
- \s_@@_mark \@@_split_active_auxi:w
+ \@@_split_active:w
+ \s_@@_mark \s_@@_tail
+ \s_@@_nil \s_@@_mark
+ \@@_split_active_auxi:w
#2 \s_@@_mark \@@_clean_up_active:w
- \s_@@_stop
- ##2 ##3
- \@@_loop_other:NNw ##4 \s_@@_mark
- { }
+ { \@@_loop_active:nnw }
\cs_new:Npn \@@_end_loop_active:w
\s_@@_tail
- \@@_loop_other:NNw ##1 , \s_@@_tail ,
- \@@_loop_active:NNw ##2 \s_@@_mark
+ \@@_loop_other:nnw ##1 \s_@@_mark \s_@@_tail , \s_@@_tail ,
{ }
% \end{macrocode}
% \end{macro}
@@ -1226,23 +1269,26 @@
\group_end:
% \end{macrocode}
%
-% \begin{macro}[EXP]{\@@_pair:nnNN, \@@_key:nNN}
+% \begin{macro}[EXP]{\@@_pair:nnnn, \@@_key:nn}
% These macros will be called on the parsed keys and values of the key--value
% list. All arguments are completely trimmed. They test for blank key names
-% and call the functions passed to \cs{keyval_parse:NNn} inside of
-% \cs{exp_not:n} with the correct arguments.
+% and call the functions passed to \cs{keyval_parse:nnn} inside of
+% \cs{exp_not:n} with the correct arguments. Afterwards they insert the next
+% iteration of the other loop.
% \begin{macrocode}
-\cs_new:Npn \@@_pair:nnNN #1 #2 #3 #4
+\cs_new:Npn \@@_pair:nnnn #1 #2 #3 #4
{
\@@_if_blank:w \s_@@_mark #2 \s_@@_nil \s_@@_stop \@@_blank_key_error:w
\s_@@_mark \s_@@_stop
\exp_not:n { #4 { #2 } { #1 } }
+ \@@_loop_other:nnw {#3} {#4}
}
-\cs_new:Npn \@@_key:nNN #1 #2 #3
+\cs_new:Npn \@@_key:nn #1 #2
{
\@@_if_blank:w \s_@@_mark #1 \s_@@_nil \s_@@_stop \@@_blank_key_error:w
\s_@@_mark \s_@@_stop
\exp_not:n { #2 { #1 } }
+ \@@_loop_other:nnw {#2}
}
% \end{macrocode}
% \end{macro}
@@ -1263,7 +1309,8 @@
% These macros will be called if the tests above didn't gobble them, they
% execute the branching.
% \begin{macrocode}
-\cs_new:Npn \@@_blank_true:w \s_@@_mark \s_@@_stop \use:n #1 #2 #3 { }
+\cs_new:Npn \@@_blank_true:w \s_@@_mark \s_@@_stop \@@_trim:nN #1 \@@_key:nn
+ { \@@_loop_other:nnw }
\cs_new:Npn \@@_blank_key_error:w \s_@@_mark \s_@@_stop \exp_not:n #1
{
\__kernel_msg_expandable_error:nn
@@ -1303,7 +1350,6 @@
\@@_trim_auxiii:w
#1 \s_@@_nil
\@@_trim_auxiv:w
- \s_@@_stop
}
\cs_new:Npn \@@_trim_auxi:w ##1 \s_@@_mark #1 ##2 \s_@@_mark ##3
{
@@ -1327,8 +1373,11 @@
% \end{macrocode}
% This is the one macro which differs from the original definition.
% \begin{macrocode}
- \cs_new:Npn \@@_trim_auxiv:w \s_@@_mark ##1 \s_@@_nil ##2 \s_@@_stop ##3
- { ##3 { ##1 } }
+ \cs_new:Npn \@@_trim_auxiv:w
+ \s_@@_mark ##1 \s_@@_nil
+ \@@_trim_auxiii:w \s_@@_nil \@@_trim_auxiii:w
+ ##2
+ { ##2 { ##1 } }
}
\@@_tmp:n { ~ }
\group_end: