diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3prop.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3prop.dtx | 272 |
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} |