summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3prop.dtx')
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3prop.dtx272
1 files changed, 176 insertions, 96 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx b/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx
index 371f894c420..16609f3af80 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3prop.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2021-05-11}
+% \date{Released 2021-05-25}
%
% \maketitle
%
@@ -51,10 +51,11 @@
%
% \LaTeX3 implements a \enquote{property list} data type, which contain
% an unordered list of entries each of which consists of a \meta{key} and
-% an associated \meta{value}. The \meta{key} and \meta{value} may both be
-% any \meta{balanced text}. It is possible to map functions to property lists
-% such that the function is applied to every key--value pair within
-% the list.
+% an associated \meta{value}. The \meta{key} and \meta{value} may both
+% be any \meta{balanced text}, but the \meta{key} is processed using
+% \cs{tl_to_str:n}, meaning that category codes are ignored. It is
+% possible to map functions to property lists such that the function is
+% applied to every key--value pair within the list.
%
% Each entry in a property list must have a unique \meta{key}: if an entry is
% added to a property list which already contains the \meta{key} then the new
@@ -63,7 +64,7 @@
%
% Property lists are intended for storing key-based information for use within
% code. This is in contrast to key--value lists, which are a form of
-% \emph{input} parsed by the \pkg{keys} module.
+% \emph{input} parsed by the \pkg{l3keys} module.
%
% \section{Creating and initialising property lists}
%
@@ -124,6 +125,12 @@
% \end{syntax}
% Sets \meta{prop~var} to contain key--value pairs given in the second
% argument. If duplicate keys appear only one of the values is kept.
+%
+% Spaces are trimmed around every \meta{key} and every \meta{value},
+% and if the result of trimming spaces consists of a single brace
+% group then a set of outer braces is removed. This enables both the
+% \meta{key} and the \meta{value} to contain spaces, commas or equal
+% signs. The \meta{key} is then processed by \cs{tl_to_str:n}.
% \end{function}
%
% \begin{function}[added = 2017-11-28, updated = 2019-08-25]
@@ -137,11 +144,12 @@
% \end{syntax}
% Creates a new constant \meta{prop~var} or raises an error if the
% name is already taken. The \meta{prop~var} is set globally to
-% contain key--value pairs given in the second argument.
-% If duplicate keys appear only one of the values is kept.
+% contain key--value pairs given in the second argument, processed in
+% the way described for \cs{prop_set_from_keyval:Nn}. If duplicate
+% keys appear only one of the values is kept.
% \end{function}
%
-% \section{Adding entries to property lists}
+% \section{Adding and updating property list entries}
%
% \begin{function}[updated = 2012-07-09]
% {
@@ -162,12 +170,12 @@
% \cs{prop_put:Nnn} \meta{property list} \Arg{key} \Arg{value}
% \end{syntax}
% Adds an entry to the \meta{property list} which may be accessed
-% using the \meta{key} and which has \meta{value}. Both the \meta{key}
-% and \meta{value} may contain any \meta{balanced text}. The \meta{key}
-% is stored after processing with \cs{tl_to_str:n}, meaning that
-% category codes are ignored. If the \meta{key} is already present
-% in the \meta{property list}, the existing entry is overwritten
-% by the new \meta{value}.
+% using the \meta{key} and which has \meta{value}. If the \meta{key}
+% is already present in the \meta{property list}, the existing entry
+% is overwritten by the new \meta{value}. Both the \meta{key} and
+% \meta{value} may contain any \meta{balanced text}. The \meta{key} is
+% stored after processing with \cs{tl_to_str:n}, meaning that category
+% codes are ignored.
% \end{function}
%
% \begin{function}
@@ -178,12 +186,51 @@
% \begin{syntax}
% \cs{prop_put_if_new:Nnn} \meta{property list} \Arg{key} \Arg{value}
% \end{syntax}
-% If the \meta{key} is present in the \meta{property list} then
-% no action is taken. If the \meta{key} is not present in the
-% \meta{property list} then a new entry is added. Both the \meta{key}
-% and \meta{value} may contain any \meta{balanced text}. The \meta{key}
-% is stored after processing with \cs{tl_to_str:n}, meaning that
-% category codes are ignored.
+% If the \meta{key} is present in the \meta{property list} then no
+% action is taken. Otherwise, a new entry is added as described for
+% \cs{prop_put:Nnn}.
+% \end{function}
+%
+% \begin{function}[added = 2021-05-16]
+% {
+% \prop_concat:NNN, \prop_concat:ccc,
+% \prop_gconcat:NNN, \prop_gconcat:ccc
+% }
+% \begin{syntax}
+% \cs{prop_concat:NNN} \meta{prop~var_1} \meta{prop~var_2} \meta{prop~var_3}
+% \end{syntax}
+% Combines the key--value pairs of \meta{prop~var_2} and
+% \meta{prop~var_3}, and saves the result in \meta{prop~var_1}. If a
+% key appears in both \meta{prop~var_2} and \meta{prop~var_3} then the
+% last value, namely the value in \meta{prop~var_3} is kept while the
+% other is discarded.
+% \end{function}
+%
+% \begin{function}[added = 2021-05-16]
+% {
+% \prop_put_from_keyval:Nn, \prop_put_from_keyval:cn,
+% \prop_gput_from_keyval:Nn, \prop_gput_from_keyval:cn,
+% }
+% \begin{syntax}
+% \cs{prop_put_from_keyval:Nn} \meta{prop~var}
+% \{
+% \meta{key1} |=| \meta{value1} |,|
+% \meta{key2} |=| \meta{value2} |,| \ldots{}
+% \}
+% \end{syntax}
+% Updates the \meta{prop~var} by adding entries for each key--value
+% pair given in the second argument. The addition is done through
+% \cs{prop_put:Nnn}, hence if the \meta{prop~var} already contains
+% some of the keys, the corresponding values are discarded and
+% replaced by those given in the key--value list. If duplicate keys
+% appear in the key--value list then only one of the values is kept.
+%
+% The function is equivalent to storing the key--value pairs in a
+% temporary property variable using \cs{prop_set_from_keyval:Nn}, then
+% combining \meta{prop~var} with the temporary variable using
+% \cs{prop_concat:NNN}. In particular, the \meta{keys} and
+% \meta{values} are space-trimmed and unbraced as described in
+% \cs{prop_set_from_keyval:Nn}.
% \end{function}
%
% \section{Recovering values from property lists}
@@ -722,15 +769,42 @@
% \end{variable}
%
% \begin{variable}{\l_@@_internal_prop}
-% Property list used by \cs{prop_set_from_keyval:Nn} and others.
+% Property list used by \cs{prop_concat:NNN},
+% \cs{prop_set_from_keyval:Nn} and others.
% \begin{macrocode}
\prop_new:N \l_@@_internal_prop
% \end{macrocode}
% \end{variable}
%
+% \begin{macro}
+% {
+% \prop_concat:NNN, \prop_concat:ccc,
+% \prop_gconcat:NNN, \prop_gconcat:ccc, \@@_concat:NNNN
+% }
+% Combine two property lists. We cannot use a simple
+% \cs{tl_concat:NNN} because there may be some duplicate keys between
+% the two property lists.
+% \begin{macrocode}
+\cs_new_protected:Npn \prop_concat:NNN
+ { \@@_concat:NNNN \prop_set_eq:NN }
+\cs_generate_variant:Nn \prop_concat:NNN { ccc }
+\cs_new_protected:Npn \prop_gconcat:NNN
+ { \@@_concat:NNNN \prop_gset_eq:NN }
+\cs_generate_variant:Nn \prop_gconcat:NNN { ccc }
+\cs_new_protected:Npn \@@_concat:NNNN #1#2#3#4
+ {
+ \prop_set_eq:NN \l_@@_internal_prop #3
+ \prop_map_tokens:Nn #4 { \prop_put:Nnn \l_@@_internal_prop }
+ #1 #2 \l_@@_internal_prop
+ }
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}{\prop_set_from_keyval:Nn, \prop_set_from_keyval:cn}
% \begin{macro}{\prop_gset_from_keyval:Nn, \prop_gset_from_keyval:cn}
% \begin{macro}{\prop_const_from_keyval:Nn, \prop_const_from_keyval:cn}
+% \begin{macro}{\prop_put_from_keyval:Nn, \prop_put_from_keyval:cn}
+% \begin{macro}{\prop_gput_from_keyval:Nn, \prop_gput_from_keyval:cn}
% \begin{macro}
% {
% \@@_from_keyval:n,
@@ -783,6 +857,22 @@
\prop_clear:N \l_@@_internal_prop
}
\cs_generate_variant:Nn \prop_const_from_keyval:Nn { c }
+\cs_new_protected:Npn \prop_put_from_keyval:Nn #1#2
+ {
+ \prop_set_eq:NN \l_@@_internal_prop #1
+ \@@_from_keyval:n {#2}
+ \prop_set_eq:NN #1 \l_@@_internal_prop
+ \prop_clear:N \l_@@_internal_prop
+ }
+\cs_generate_variant:Nn \prop_put_from_keyval:Nn { c }
+\cs_new_protected:Npn \prop_gput_from_keyval:Nn #1#2
+ {
+ \prop_set_eq:NN \l_@@_internal_prop #1
+ \@@_from_keyval:n {#2}
+ \prop_gset_eq:NN #1 \l_@@_internal_prop
+ \prop_clear:N \l_@@_internal_prop
+ }
+\cs_generate_variant:Nn \prop_gput_from_keyval:Nn { c }
\cs_new_protected:Npn \@@_from_keyval:n #1
{
\@@_from_keyval_loop:w \prg_do_nothing: #1 ,
@@ -808,10 +898,10 @@
{ \@@_from_keyval_value:w #1 \s_@@_mark }
\cs_new_protected:Npn \@@_from_keyval_value:w #1 \s_@@_mark #2 \s_@@_stop #3#4
{
- \tl_if_empty:nF { #3 #1 #2 }
+ \tl_if_single:nTF {#2}
+ { \prop_put:Nnn \l_@@_internal_prop {#3} {#1} }
{
- \str_if_eq:nnTF {#2} { = }
- { \prop_put:Nnn \l_@@_internal_prop {#3} {#1} }
+ \tl_if_empty:nF { #3 #1 #2 }
{
\__kernel_msg_error:nnx { prop } { prop-keyval }
{ \exp_not:o {#4} }
@@ -823,6 +913,8 @@
% \end{macro}
% \end{macro}
% \end{macro}
+% \end{macro}
+% \end{macro}
%
% \subsection{Accessing data in property lists}
%
@@ -956,29 +1048,22 @@
% \end{macro}
%
% \begin{macro}[EXP]{\prop_item:Nn, \prop_item:cn}
-% \begin{macro}[EXP]{\@@_item_Nn:nwwn}
+% \begin{macro}[EXP]{\@@_item:nnn}
% Getting the value corresponding to a key in a property list in an
-% expandable fashion is similar to mapping some tokens. Go through
-% the property list one \meta{key}--\meta{value} pair at a time: the
-% arguments of \cs{@@_item_Nn:nwn} are the \meta{key} we are looking
-% for, a \meta{key} of the property list, and its associated value.
-% The \meta{keys} are compared (as strings). If they match, the
-% \meta{value} is returned, within \cs{exp_not:n}. The loop
-% terminates even if the \meta{key} is missing, and yields an empty
-% value, because we have appended the appropriate
-% \meta{key}--\meta{empty value} pair to the property list.
+% expandable fashion simply uses \cs{prop_map_tokens:Nn} to go through
+% the property list. The auxiliary \cs{@@_item:nnn} receives the
+% search string~|#1|, the key~|#2| and the value~|#3| and returns as
+% appropriate.
% \begin{macrocode}
\cs_new:Npn \prop_item:Nn #1#2
{
- \exp_last_unbraced:Noo \@@_item_Nn:nwwn { \tl_to_str:n {#2} } #1
- \@@_pair:wn \tl_to_str:n {#2} \s_@@ { }
- \prg_break_point:
+ \exp_args:NNo \prop_map_tokens:Nn #1
+ { \exp_after:wN \@@_item:nnn \exp_after:wN { \tl_to_str:n {#2} } }
}
-\cs_new:Npn \@@_item_Nn:nwwn #1#2 \@@_pair:wn #3 \s_@@ #4
+\cs_new:Npn \@@_item:nnn #1#2#3
{
- \str_if_eq:eeTF {#1} {#3}
- { \prg_break:n { \exp_not:n {#4} } }
- { \@@_item_Nn:nwwn {#1} }
+ \str_if_eq:eeT {#1} {#2}
+ { \prop_map_break:n { \exp_not:n {#3} } }
}
\cs_generate_variant:Nn \prop_item:Nn { c }
% \end{macrocode}
@@ -1159,7 +1244,7 @@
% \prop_if_in:Nn, \prop_if_in:NV, \prop_if_in:No,
% \prop_if_in:cn, \prop_if_in:cV, \prop_if_in:co
% }
-% \begin{macro}[EXP]{\@@_if_in:nwwn, \@@_if_in:N}
+% \begin{macro}[EXP]{\@@_if_in:nnn}
% Testing expandably if a key is in a property list
% requires to go through the key--value pairs one by one.
% This is rather slow, and a faster test would be
@@ -1172,44 +1257,19 @@
% }
% \end{verbatim}
% but \cs{@@_split:NnTF} is non-expandable.
-%
-% Instead, the key is compared to each key in turn using
-% \cs{str_if_eq:ee}, which is expandable. To terminate the mapping,
-% we append to the property list the key that is searched for. This
-% second \cs{tl_to_str:n} is not expanded at the start, but only when
-% included in the \cs{str_if_eq:ee}. It cannot make the breaking
-% mechanism choke, because the arbitrary token list material is
-% enclosed in braces. The second argument of \cs{@@_if_in:nwwn} is
-% most often empty. When the \meta{key} is found in the list,
-% \cs{@@_if_in:N} receives \cs{@@_pair:wn}, and if it is
-% found as the extra item, the function receives
-% \cs{q_@@_recursion_tail}, easily recognizable.
-%
-% Here, \cs{prop_map_function:NN} is not sufficient for the mapping,
-% since it can only map a single token, and cannot carry the key that
-% is searched for.
+% Instead, we use \cs{prop_map_tokens:Nn} to compare the search key to
+% each key in turn using \cs{str_if_eq:ee}, which is expandable.
% \begin{macrocode}
\prg_new_conditional:Npnn \prop_if_in:Nn #1#2 { p , T , F , TF }
{
- \exp_last_unbraced:Noo \@@_if_in:nwwn { \tl_to_str:n {#2} } #1
- \@@_pair:wn \tl_to_str:n {#2} \s_@@ { }
- \q_@@_recursion_tail
- \prg_break_point:
- }
-\cs_new:Npn \@@_if_in:nwwn #1#2 \@@_pair:wn #3 \s_@@ #4
- {
- \str_if_eq:eeTF {#1} {#3}
- { \@@_if_in:N }
- { \@@_if_in:nwwn {#1} }
+ \exp_args:NNo \prop_map_tokens:Nn #1
+ { \exp_after:wN \@@_if_in:nnn \exp_after:wN { \tl_to_str:n {#2} } }
+ \prg_return_false:
}
-\cs_new:Npn \@@_if_in:N #1
+\cs_new:Npn \@@_if_in:nnn #1#2#3
{
- \if_meaning:w \q_@@_recursion_tail #1
- \prg_return_false:
- \else:
- \prg_return_true:
- \fi:
- \prg_break:
+ \str_if_eq:eeT {#1} {#2}
+ { \prop_map_break:n { \use_i:nn \prg_return_true: } }
}
\prg_generate_conditional_variant:Nnn \prop_if_in:Nn
{ NV , No , c , cV , co } { p , T , F , TF }
@@ -1249,25 +1309,36 @@
% \prop_map_function:NN, \prop_map_function:Nc,
% \prop_map_function:cN, \prop_map_function:cc
% }
-% \begin{macro}{\@@_map_function:Nwwn}
-% The argument delimited by \cs{@@_pair:wn} is empty except at the end
-% of the loop where it is \cs{prg_break:}. No need for any quark
-% test.
+% \begin{macro}{\@@_map_function:Nw}
+% The even-numbered arguments of \cs{@@_map_function:Nw} are keys,
+% hence have string catcodes, except at the end where they are
+% \cs{fi:} \cs{prop_map_break:}. The \cs{fi:} ends the \cs{if_false:}
+% |#|\meta{even} \cs{fi:} construction and we jump out of the loop.
+% No need for any quark test.
% \begin{macrocode}
\cs_new:Npn \prop_map_function:NN #1#2
{
\exp_after:wN \use_i_ii:nnn
- \exp_after:wN \@@_map_function:Nwwn
+ \exp_after:wN \@@_map_function:Nw
\exp_after:wN #2
#1
- \prg_break: \@@_pair:wn \s_@@ { } \prg_break_point:
+ \@@_pair:wn \fi: \prop_map_break: \s_@@ { }
+ \@@_pair:wn \fi: \prop_map_break: \s_@@ { }
+ \@@_pair:wn \fi: \prop_map_break: \s_@@ { }
+ \@@_pair:wn \fi: \prop_map_break: \s_@@ { }
\prg_break_point:Nn \prop_map_break: { }
}
-\cs_new:Npn \@@_map_function:Nwwn #1#2 \@@_pair:wn #3 \s_@@ #4
+\cs_new:Npn \@@_map_function:Nw #1
+ \@@_pair:wn #2 \s_@@ #3
+ \@@_pair:wn #4 \s_@@ #5
+ \@@_pair:wn #6 \s_@@ #7
+ \@@_pair:wn #8 \s_@@ #9
{
- #2
- #1 {#3} {#4}
- \@@_map_function:Nwwn #1
+ \if_false: #2 \fi: #1 {#2} {#3}
+ \if_false: #4 \fi: #1 {#4} {#5}
+ \if_false: #6 \fi: #1 {#6} {#7}
+ \if_false: #8 \fi: #1 {#8} {#9}
+ \@@_map_function:Nw #1
}
\cs_generate_variant:Nn \prop_map_function:NN { Nc , c , cc }
% \end{macrocode}
@@ -1303,26 +1374,35 @@
% \end{macro}
%
% \begin{macro}[rEXP]{\prop_map_tokens:Nn, \prop_map_tokens:cn}
-% \begin{macro}{\@@_map_tokens:nwwn}
+% \begin{macro}{\@@_map_tokens:nw}
% The mapping is very similar to \cs{prop_map_function:NN}. The
% \cs{use_i:nn} removes the leading \cs{s_@@}. The odd construction
% |\use:n {#1}| allows |#1| to contain any token without interfering
-% with \cs{prop_map_break:}. The loop stops when the argument
-% delimited by \cs{@@_pair:wn} is \cs{prg_break:} instead of being
-% empty.
+% with \cs{prop_map_break:}. The loop stops when the \meta{key}
+% between \cs{@@_pair:wn} and \cs{s_@@} is \cs{fi:}
+% \cs{prop_map_break:} instead of being a string.
% \begin{macrocode}
\cs_new:Npn \prop_map_tokens:Nn #1#2
{
\exp_last_unbraced:Nno
- \use_i:nn { \@@_map_tokens:nwwn {#2} } #1
- \prg_break: \@@_pair:wn \s_@@ { } \prg_break_point:
+ \use_i:nn { \@@_map_tokens:nw {#2} } #1
+ \@@_pair:wn \fi: \prop_map_break: \s_@@ { }
+ \@@_pair:wn \fi: \prop_map_break: \s_@@ { }
+ \@@_pair:wn \fi: \prop_map_break: \s_@@ { }
+ \@@_pair:wn \fi: \prop_map_break: \s_@@ { }
\prg_break_point:Nn \prop_map_break: { }
}
-\cs_new:Npn \@@_map_tokens:nwwn #1#2 \@@_pair:wn #3 \s_@@ #4
+\cs_new:Npn \@@_map_tokens:nw #1
+ \@@_pair:wn #2 \s_@@ #3
+ \@@_pair:wn #4 \s_@@ #5
+ \@@_pair:wn #6 \s_@@ #7
+ \@@_pair:wn #8 \s_@@ #9
{
- #2
- \use:n {#1} {#3} {#4}
- \@@_map_tokens:nwwn {#1}
+ \if_false: #2 \fi: \use:n {#1} {#2} {#3}
+ \if_false: #4 \fi: \use:n {#1} {#4} {#5}
+ \if_false: #6 \fi: \use:n {#1} {#6} {#7}
+ \if_false: #8 \fi: \use:n {#1} {#8} {#9}
+ \@@_map_tokens:nw {#1}
}
\cs_generate_variant:Nn \prop_map_tokens:Nn { c }
% \end{macrocode}