From e0c6872cf40896c7be36b11dcc744620f10adf1d Mon Sep 17 00:00:00 2001
From: Norbert Preining <norbert@preining.info>
Date: Mon, 2 Sep 2019 13:46:59 +0900
Subject: Initial commit

---
 macros/latex/contrib/l3kernel/l3prop.dtx | 1262 ++++++++++++++++++++++++++++++
 1 file changed, 1262 insertions(+)
 create mode 100644 macros/latex/contrib/l3kernel/l3prop.dtx

(limited to 'macros/latex/contrib/l3kernel/l3prop.dtx')

diff --git a/macros/latex/contrib/l3kernel/l3prop.dtx b/macros/latex/contrib/l3kernel/l3prop.dtx
new file mode 100644
index 0000000000..d79073065d
--- /dev/null
+++ b/macros/latex/contrib/l3kernel/l3prop.dtx
@@ -0,0 +1,1262 @@
+% \iffalse meta-comment
+%
+%% File: l3prop.dtx
+%
+% Copyright (C) 1990-2019 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
+% license or (at your option) any later version.  The latest version
+% of this license is in the file
+%
+%    https://www.latex-project.org/lppl.txt
+%
+% This file is part of the "l3kernel bundle" (The Work in LPPL)
+% and all files in that bundle must be distributed together.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the bundle can be found at
+%
+%    https://github.com/latex3/latex3
+%
+% for those people who are interested.
+%
+%<*driver>
+\documentclass[full,kernel]{l3doc}
+\begin{document}
+  \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+%   The \pkg{l3prop} package\\ Property lists^^A
+% }
+%
+% \author{^^A
+%  The \LaTeX3 Project\thanks
+%    {^^A
+%      E-mail:
+%        \href{mailto:latex-team@latex-project.org}
+%          {latex-team@latex-project.org}^^A
+%    }^^A
+% }
+%
+% \date{Released 2019-08-25}
+%
+% \maketitle
+%
+% \begin{documentation}
+%
+% \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.
+%
+% 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
+% entry overwrites the existing one. The \meta{keys} are compared on a
+% string basis, using the same method as \cs{str_if_eq:nn}.
+%
+% 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.
+%
+% \section{Creating and initialising property lists}
+%
+% \begin{function}{\prop_new:N, \prop_new:c}
+%   \begin{syntax}
+%     \cs{prop_new:N} \meta{property list}
+%   \end{syntax}
+%   Creates a new \meta{property list} or raises an error if the name is
+%   already taken. The declaration is global. The \meta{property list}
+%   initially contains no entries.
+% \end{function}
+%
+% \begin{function}
+%   {\prop_clear:N, \prop_clear:c, \prop_gclear:N, \prop_gclear:c}
+%   \begin{syntax}
+%     \cs{prop_clear:N} \meta{property list}
+%   \end{syntax}
+%   Clears all entries from the \meta{property list}.
+% \end{function}
+%
+% \begin{function}
+%   {
+%     \prop_clear_new:N,  \prop_clear_new:c,
+%     \prop_gclear_new:N, \prop_gclear_new:c
+%   }
+%   \begin{syntax}
+%     \cs{prop_clear_new:N} \meta{property list}
+%   \end{syntax}
+%   Ensures that the \meta{property list} exists globally by applying
+%   \cs{prop_new:N} if necessary, then applies
+%   \cs[index=prop_clear:N]{prop_(g)clear:N} to leave
+%   the list empty.
+% \end{function}
+%
+% \begin{function}
+%   {
+%     \prop_set_eq:NN,  \prop_set_eq:cN,  \prop_set_eq:Nc,  \prop_set_eq:cc,
+%     \prop_gset_eq:NN, \prop_gset_eq:cN, \prop_gset_eq:Nc, \prop_gset_eq:cc
+%   }
+%   \begin{syntax}
+%     \cs{prop_set_eq:NN} \meta{property list_1} \meta{property list_2}
+%   \end{syntax}
+%   Sets the content of \meta{property list_1} equal to that of
+%   \meta{property list_2}.
+% \end{function}
+%
+% \section{Adding entries to property lists}
+%
+% \begin{function}[updated = 2012-07-09]
+%   {
+%     \prop_put:Nnn,  \prop_put:NnV,  \prop_put:Nno,  \prop_put:Nnx,
+%     \prop_put:NVn,  \prop_put:NVV,  \prop_put:Non,  \prop_put:Noo,
+%     \prop_put:cnn,  \prop_put:cnV,  \prop_put:cno,  \prop_put:cnx,
+%     \prop_put:cVn,  \prop_put:cVV,  \prop_put:con,  \prop_put:coo,
+%     \prop_gput:Nnn, \prop_gput:NnV, \prop_gput:Nno, \prop_gput:Nnx,
+%     \prop_gput:NVn, \prop_gput:NVV, \prop_gput:Non, \prop_gput:Noo,
+%     \prop_gput:cnn, \prop_gput:cnV, \prop_gput:cno, \prop_gput:cnx,
+%     \prop_gput:cVn, \prop_gput:cVV, \prop_gput:con, \prop_gput:coo
+%   }
+%   \begin{syntax}
+%     \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}.
+% \end{function}
+%
+% \begin{function}
+%   {
+%     \prop_put_if_new:Nnn,  \prop_put_if_new:cnn,
+%     \prop_gput_if_new:Nnn, \prop_gput_if_new:cnn
+%   }
+%   \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.
+% \end{function}
+%
+% \section{Recovering values from property lists}
+%
+% \begin{function}[updated = 2011-08-28]
+%   {
+%     \prop_get:NnN, \prop_get:NVN, \prop_get:NoN,
+%     \prop_get:cnN, \prop_get:cVN, \prop_get:coN,
+%   }
+%   \begin{syntax}
+%     \cs{prop_get:NnN} \meta{property list} \Arg{key} \meta{tl var}
+%   \end{syntax}
+%   Recovers the \meta{value} stored with \meta{key} from the
+%   \meta{property list}, and places this in the \meta{token list
+%   variable}. If the \meta{key} is not found in the
+%   \meta{property list} then the \meta{token list variable} is set
+%   to the special marker \cs{q_no_value}. The \meta{token list
+%     variable} is set within the current \TeX{} group. See also
+%   \cs{prop_get:NnNTF}.
+% \end{function}
+%
+% \begin{function}[updated = 2011-08-18]
+%   {\prop_pop:NnN, \prop_pop:NoN, \prop_pop:cnN, \prop_pop:coN}
+%   \begin{syntax}
+%     \cs{prop_pop:NnN} \meta{property list} \Arg{key} \meta{tl var}
+%   \end{syntax}
+%   Recovers the \meta{value} stored with \meta{key} from the
+%   \meta{property list}, and places this in the \meta{token list
+%   variable}. If the \meta{key} is not found in the
+%   \meta{property list} then the \meta{token list variable} is set
+%   to the special marker \cs{q_no_value}. The \meta{key} and
+%   \meta{value} are then deleted from the property list. Both
+%   assignments are local.  See also \cs{prop_pop:NnNTF}.
+% \end{function}
+%
+% \begin{function}[updated = 2011-08-18]
+%   {\prop_gpop:NnN, \prop_gpop:NoN, \prop_gpop:cnN, \prop_gpop:coN}
+%   \begin{syntax}
+%     \cs{prop_gpop:NnN} \meta{property list} \Arg{key} \meta{tl var}
+%   \end{syntax}
+%   Recovers the \meta{value} stored with \meta{key} from the
+%   \meta{property list}, and places this in the \meta{token list
+%   variable}. If the \meta{key} is not found in the
+%   \meta{property list} then the \meta{token list variable} is set
+%   to the special marker \cs{q_no_value}. The \meta{key} and
+%   \meta{value} are then deleted from the property list.
+%   The \meta{property list} is modified globally, while the assignment of
+%   the \meta{token list variable} is local.  See also \cs{prop_gpop:NnNTF}.
+% \end{function}
+%
+% \begin{function}[added = 2014-07-17, EXP]{\prop_item:Nn, \prop_item:cn}
+%   \begin{syntax}
+%     \cs{prop_item:Nn} \meta{property list} \Arg{key}
+%   \end{syntax}
+%   Expands to the \meta{value} corresponding to the \meta{key} in
+%   the \meta{property list}. If the \meta{key} is missing, this has
+%   an empty expansion.
+%   \begin{texnote}
+%     This function is slower than the non-expandable analogue
+%     \cs{prop_get:NnN}.
+%     The result is returned within the \tn{unexpanded}
+%     primitive (\cs{exp_not:n}), which means that the \meta{value}
+%     does not expand further when appearing in an \texttt{x}-type
+%     argument expansion.
+%   \end{texnote}
+% \end{function}
+%
+% \begin{function}[EXP]{\prop_count:N, \prop_count:c}
+%   \begin{syntax}
+%     \cs{prop_count:N} \meta{property list}
+%   \end{syntax}
+%   Leaves the number of key--value pairs in the \meta{property list} in
+%   the input stream as an \meta{integer denotation}.
+% \end{function}
+%
+% \section{Modifying property lists}
+%
+% \begin{function}[added = 2012-05-12]
+%   {
+%     \prop_remove:Nn,  \prop_remove:NV,  \prop_remove:cn,  \prop_remove:cV,
+%     \prop_gremove:Nn, \prop_gremove:NV, \prop_gremove:cn, \prop_gremove:cV
+%   }
+%   \begin{syntax}
+%     \cs{prop_remove:Nn} \meta{property list} \Arg{key}
+%   \end{syntax}
+%   Removes the entry listed under \meta{key} from the
+%   \meta{property list}.  If the \meta{key} is
+%   not found in the \meta{property list} no change occurs,
+%   \emph{i.e}~there is no need to test for the existence of a key before
+%   deleting it.
+% \end{function}
+%
+% \section{Property list conditionals}
+%
+% \begin{function}[EXP, pTF, added = 2012-03-03]
+%   {\prop_if_exist:N, \prop_if_exist:c}
+%   \begin{syntax}
+%     \cs{prop_if_exist_p:N} \meta{property list}
+%     \cs{prop_if_exist:NTF} \meta{property list} \Arg{true code} \Arg{false code}
+%   \end{syntax}
+%   Tests whether the \meta{property list} is currently defined.  This does not
+%   check that the \meta{property list} really is a property list variable.
+% \end{function}
+%
+% \begin{function}[EXP, pTF]{\prop_if_empty:N, \prop_if_empty:c}
+%   \begin{syntax}
+%     \cs{prop_if_empty_p:N} \meta{property list}
+%     \cs{prop_if_empty:NTF} \meta{property list} \Arg{true code} \Arg{false code}
+%   \end{syntax}
+%   Tests if the \meta{property list} is empty (containing no entries).
+% \end{function}
+%
+% \begin{function}[updated = 2011-09-15, EXP, pTF]
+%   {
+%     \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{syntax}
+%     \cs{prop_if_in:NnTF} \meta{property list} \Arg{key} \Arg{true code} \Arg{false code}
+%   \end{syntax}
+%   Tests if the \meta{key} is present in the \meta{property list},
+%   making the comparison using the method described by \cs{str_if_eq:nnTF}.
+%   \begin{texnote}
+%     This function iterates through every key--value pair in the
+%     \meta{property list} and is therefore slower than using the
+%     non-expandable \cs{prop_get:NnNTF}.
+%   \end{texnote}
+% \end{function}
+%
+% \section{Recovering values from property lists with branching}
+%
+% The functions in this section combine tests for the presence of a key
+% in a property list with  recovery of the associated valued. This makes them
+% useful for cases where different cases follow dependent on the presence
+% or absence of a key in a property list. They offer increased readability
+% and performance over separate testing and recovery phases.
+%
+% \begin{function}[updated = 2012-05-19, TF]
+%   {
+%     \prop_get:NnN, \prop_get:NVN, \prop_get:NoN,
+%     \prop_get:cnN, \prop_get:cVN, \prop_get:coN
+%   }
+%   \begin{syntax}
+%     \cs{prop_get:NnNTF} \meta{property list} \Arg{key} \meta{token list variable} \\
+%     ~~\Arg{true code} \Arg{false code}
+%   \end{syntax}
+%   If the \meta{key} is not present in the \meta{property list}, leaves
+%   the \meta{false code} in the input stream.  The value of the
+%   \meta{token list variable} is not defined in this case and should
+%   not be relied upon.  If the \meta{key} is present in the
+%   \meta{property list}, stores the corresponding \meta{value} in the
+%   \meta{token list variable} without removing it from the
+%   \meta{property list}, then leaves the \meta{true code} in the input
+%   stream.  The \meta{token list variable} is assigned locally.
+% \end{function}
+%
+% \begin{function}[TF, added = 2011-08-18, updated = 2012-05-19]
+%   {\prop_pop:NnN, \prop_pop:cnN}
+%   \begin{syntax}
+%     \cs{prop_pop:NnNTF} \meta{property list} \Arg{key} \meta{token list variable} \Arg{true code} \Arg{false code}
+%   \end{syntax}
+%   If the \meta{key} is not present in the \meta{property list}, leaves
+%   the \meta{false code} in the input stream.  The value of the
+%   \meta{token list variable} is not defined in this case and should
+%   not be relied upon.  If the \meta{key} is present in
+%   the \meta{property list}, pops the corresponding \meta{value}
+%   in the \meta{token list variable}, \emph{i.e.}~removes the item from
+%   the \meta{property list}.
+%   Both the \meta{property list} and the \meta{token list variable}
+%   are assigned locally.
+% \end{function}
+%
+% \begin{function}[TF, added = 2011-08-18, updated = 2012-05-19]
+%   {\prop_gpop:NnN, \prop_gpop:cnN}
+%   \begin{syntax}
+%     \cs{prop_gpop:NnNTF} \meta{property list} \Arg{key} \meta{token list variable} \Arg{true code} \Arg{false code}
+%   \end{syntax}
+%   If the \meta{key} is not present in the \meta{property list}, leaves
+%   the \meta{false code} in the input stream.  The value of the
+%   \meta{token list variable} is not defined in this case and should
+%   not be relied upon.  If the \meta{key} is present in
+%   the \meta{property list}, pops the corresponding \meta{value}
+%   in the \meta{token list variable}, \emph{i.e.}~removes the item from
+%   the \meta{property list}.
+%   The \meta{property list} is modified globally, while the
+%   \meta{token list variable} is assigned locally.
+% \end{function}
+%
+% \section{Mapping to property lists}
+%
+% All mappings are done at the current group level, \emph{i.e.}~any
+% local assignments made by the \meta{function} or \meta{code} discussed
+% below remain in effect after the loop.
+%
+% \begin{function}[updated = 2013-01-08, rEXP]
+%   {\prop_map_function:NN, \prop_map_function:cN}
+%   \begin{syntax}
+%     \cs{prop_map_function:NN} \meta{property list} \meta{function}
+%   \end{syntax}
+%   Applies \meta{function} to every \meta{entry} stored in the
+%   \meta{property list}. The \meta{function} receives two arguments for
+%   each iteration: the \meta{key} and associated \meta{value}.
+%   The order in which \meta{entries} are returned is not defined and
+%   should not be relied upon.
+% \end{function}
+%
+% \begin{function}[updated = 2013-01-08]
+%   {\prop_map_inline:Nn, \prop_map_inline:cn}
+%   \begin{syntax}
+%     \cs{prop_map_inline:Nn} \meta{property list} \Arg{inline function}
+%   \end{syntax}
+%   Applies \meta{inline function} to every \meta{entry} stored
+%   within the \meta{property list}. The \meta{inline function} should
+%   consist of code which receives the \meta{key} as |#1| and the
+%   \meta{value} as |#2|.
+%   The order in which \meta{entries} are returned is not defined and
+%   should not be relied upon.
+% \end{function}
+%
+% \begin{function}[updated = 2012-06-29, rEXP]{\prop_map_break:}
+%   \begin{syntax}
+%     \cs{prop_map_break:}
+%   \end{syntax}
+%   Used to terminate a \cs[no-index]{prop_map_\ldots} function before all
+%   entries in the \meta{property list} have been processed. This
+%   normally takes place within a conditional statement, for example
+%   \begin{verbatim}
+%     \prop_map_inline:Nn \l_my_prop
+%       {
+%         \str_if_eq:nnTF { #1 } { bingo }
+%           { \prop_map_break: }
+%           {
+%             % Do something useful
+%           }
+%       }
+%   \end{verbatim}
+%   Use outside of a \cs[no-index]{prop_map_\ldots} scenario leads to low
+%   level \TeX{} errors.
+%   \begin{texnote}
+%     When the mapping is broken, additional tokens may be inserted
+%     before further items are taken
+%     from the input stream. This depends on the design of the mapping
+%     function.
+%   \end{texnote}
+% \end{function}
+%
+% \begin{function}[updated = 2012-06-29, rEXP]{\prop_map_break:n}
+%   \begin{syntax}
+%     \cs{prop_map_break:n} \Arg{code}
+%   \end{syntax}
+%   Used to terminate a \cs[no-index]{prop_map_\ldots} function before all
+%   entries in the \meta{property list} have been processed, inserting
+%   the \meta{code} after the mapping has ended. This
+%   normally takes place within a conditional statement, for example
+%   \begin{verbatim}
+%     \prop_map_inline:Nn \l_my_prop
+%       {
+%         \str_if_eq:nnTF { #1 } { bingo }
+%           { \prop_map_break:n { <code> } }
+%           {
+%             % Do something useful
+%           }
+%       }
+%   \end{verbatim}
+%   Use outside of a \cs[no-index]{prop_map_\ldots} scenario leads to low
+%   level \TeX{} errors.
+%   \begin{texnote}
+%     When the mapping is broken, additional tokens may be inserted
+%     before the \meta{code} is
+%     inserted into the input stream.
+%     This depends on the design of the mapping function.
+%   \end{texnote}
+% \end{function}
+%
+% \section{Viewing property lists}
+%
+% \begin{function}[updated = 2015-08-01]{\prop_show:N, \prop_show:c}
+%   \begin{syntax}
+%     \cs{prop_show:N} \meta{property list}
+%   \end{syntax}
+%   Displays the entries in the \meta{property list} in the terminal.
+% \end{function}
+%
+% \begin{function}[added = 2014-08-12, updated = 2015-08-01]{\prop_log:N, \prop_log:c}
+%   \begin{syntax}
+%     \cs{prop_log:N} \meta{property list}
+%   \end{syntax}
+%   Writes the entries in the \meta{property list} in the log file.
+% \end{function}
+%
+% \section{Scratch property lists}
+%
+% \begin{variable}[added = 2012-06-23]{\l_tmpa_prop, \l_tmpb_prop}
+%   Scratch property lists for local assignment. These are never used by
+%   the kernel code, and so are safe for use with any \LaTeX3-defined
+%   function. However, they may be overwritten by other non-kernel
+%   code and so should only be used for short-term storage.
+% \end{variable}
+%
+% \begin{variable}[added = 2012-06-23]{\g_tmpa_prop, \g_tmpb_prop}
+%   Scratch property lists for global assignment. These are never used by
+%   the kernel code, and so are safe for use with any \LaTeX3-defined
+%   function. However, they may be overwritten by other non-kernel
+%   code and so should only be used for short-term storage.
+% \end{variable}
+%
+% \section{Constants}
+%
+% \begin{variable}{\c_empty_prop}
+%   A permanently-empty property list used for internal comparisons.
+% \end{variable}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3prop} implementation}
+%
+% \TestFiles{m3prop001, m3prop002, m3prop003, m3prop004, m3show001}
+%
+%    \begin{macrocode}
+%<*initex|package>
+%    \end{macrocode}
+%
+%    \begin{macrocode}
+%<@@=prop>
+%    \end{macrocode}
+%
+% A property list is a macro whose top-level expansion is of the form
+% \begin{quote}
+%   \cs{s_@@}
+%   \cs{@@_pair:wn} \meta{key_1} \cs{s_@@} \Arg{value_1} \\
+%   \ldots{} \\
+%   \cs{@@_pair:wn} \meta{key_n} \cs{s_@@} \Arg{value_n} \\
+% \end{quote}
+% where \cs{s_@@} is a scan mark
+% (equal to \cs{scan_stop:}), and \cs{@@_pair:wn} can be used to map
+% through the property list.
+%
+% \begin{variable}{\s_@@}
+%   The internal token used at the beginning of property lists.  This is
+%   also used after each \meta{key} (see \cs{@@_pair:wn}).
+% \end{variable}
+%
+% \begin{variable}{\@@_pair:wn}
+%   \begin{syntax}
+%     \cs{@@_pair:wn} \meta{key} \cs{s_@@} \Arg{item}
+%   \end{syntax}
+%   The internal token used to begin each key--value pair in the
+%   property list.  If expanded outside of a mapping or manipulation
+%   function, an error is raised.  The definition should always be
+%   set globally.
+% \end{variable}
+%
+% \begin{variable}{\l_@@_internal_tl}
+%   Token list used to store new key--value pairs to be inserted by
+%   functions of the \cs{prop_put:Nnn} family.
+% \end{variable}
+%
+% \begin{function}[updated = 2013-01-08]{\@@_split:NnTF}
+%   \begin{syntax}
+%     \cs{@@_split:NnTF} \meta{property list} \Arg{key} \Arg{true code} \Arg{false code}
+%   \end{syntax}
+%   Splits the \meta{property list} at the \meta{key}, giving three
+%   token lists: the \meta{extract} of \meta{property list} before the
+%   \meta{key}, the \meta{value} associated with the \meta{key} and the
+%   \meta{extract} of the \meta{property list} after the \meta{value}.
+%   Both \meta{extracts} retain the internal structure of a property
+%   list, and the concatenation of the two \meta{extracts} is a
+%   property list.
+%   If the \meta{key} is present in the \meta{property list} then the
+%   \meta{true code} is left in the input stream, with |#1|, |#2|, and
+%   |#3| replaced by the first \meta{extract}, the \meta{value}, and the
+%   second extract.
+%   If the \meta{key} is not present in the \meta{property list} then
+%   the \meta{false code} is left in the input stream, with no trailing
+%   material.
+%   Both \meta{true code} and \meta{false code} are used in the
+%   replacement text of a macro defined internally, hence macro
+%   parameter characters should be doubled, except |#1|, |#2|, and |#3|
+%   which stand in the \meta{true code} for the three extracts from the
+%   property list.
+%   The \meta{key} comparison takes place as described for \cs{str_if_eq:nn}.
+% \end{function}
+%
+% \begin{macro}{\s_@@}
+%   A private scan mark is used as a marker after each key, and at the
+%   very beginning of the property list.
+%    \begin{macrocode}
+\scan_new:N \s_@@
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_pair:wn}
+%   The delimiter is always defined, but when misused simply triggers an
+%   error and removes its argument.
+%    \begin{macrocode}
+\cs_new:Npn \@@_pair:wn #1 \s_@@ #2
+  { \__kernel_msg_expandable_error:nn { kernel } { misused-prop } }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{variable}{\l_@@_internal_tl}
+%   Token list used to store the new key--value pair inserted by
+%   \cs{prop_put:Nnn} and friends.
+%    \begin{macrocode}
+\tl_new:N \l_@@_internal_tl
+%    \end{macrocode}
+% \end{variable}
+%
+% \begin{variable}[tested = m3prop004]{\c_empty_prop}
+%   An empty prop.
+%    \begin{macrocode}
+\tl_const:Nn \c_empty_prop { \s_@@ }
+%    \end{macrocode}
+% \end{variable}
+%
+% \subsection{Allocation and initialisation}
+%
+% \begin{macro}[tested = m3prop001]{\prop_new:N, \prop_new:c}
+%   Property lists are initialized with the value \cs{c_empty_prop}.
+%    \begin{macrocode}
+\cs_new_protected:Npn \prop_new:N #1
+  {
+    \__kernel_chk_if_free_cs:N #1
+    \cs_gset_eq:NN #1 \c_empty_prop
+  }
+\cs_generate_variant:Nn \prop_new:N { c }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[tested = m3prop001]{\prop_clear:N, \prop_clear:c}
+% \begin{macro}[tested = m3prop001]{\prop_gclear:N, \prop_gclear:c}
+%   The same idea for clearing.
+%    \begin{macrocode}
+\cs_new_protected:Npn \prop_clear:N  #1
+  { \prop_set_eq:NN #1 \c_empty_prop }
+\cs_generate_variant:Nn \prop_clear:N  { c }
+\cs_new_protected:Npn \prop_gclear:N #1
+  { \prop_gset_eq:NN #1 \c_empty_prop }
+\cs_generate_variant:Nn \prop_gclear:N { c }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[tested = m3prop001]{\prop_clear_new:N, \prop_clear_new:c}
+% \begin{macro}[tested = m3prop001]{\prop_gclear_new:N, \prop_gclear_new:c}
+%   Once again a simple variation of the token list functions.
+%    \begin{macrocode}
+\cs_new_protected:Npn \prop_clear_new:N  #1
+  { \prop_if_exist:NTF #1 { \prop_clear:N #1 } { \prop_new:N #1 } }
+\cs_generate_variant:Nn \prop_clear_new:N  { c }
+\cs_new_protected:Npn \prop_gclear_new:N #1
+  { \prop_if_exist:NTF #1 { \prop_gclear:N #1 } { \prop_new:N #1 } }
+\cs_generate_variant:Nn \prop_gclear_new:N { c }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[tested = m3prop001]
+%   {\prop_set_eq:NN, \prop_set_eq:cN, \prop_set_eq:Nc, \prop_set_eq:cc}
+% \begin{macro}[tested = m3prop001]
+%   {\prop_gset_eq:NN, \prop_gset_eq:cN, \prop_gset_eq:Nc, \prop_gset_eq:cc}
+%   These are simply copies from the token list functions.
+%    \begin{macrocode}
+\cs_new_eq:NN \prop_set_eq:NN  \tl_set_eq:NN
+\cs_new_eq:NN \prop_set_eq:Nc  \tl_set_eq:Nc
+\cs_new_eq:NN \prop_set_eq:cN  \tl_set_eq:cN
+\cs_new_eq:NN \prop_set_eq:cc  \tl_set_eq:cc
+\cs_new_eq:NN \prop_gset_eq:NN \tl_gset_eq:NN
+\cs_new_eq:NN \prop_gset_eq:Nc \tl_gset_eq:Nc
+\cs_new_eq:NN \prop_gset_eq:cN \tl_gset_eq:cN
+\cs_new_eq:NN \prop_gset_eq:cc \tl_gset_eq:cc
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{variable}[tested = m3prop004]{\l_tmpa_prop, \l_tmpb_prop}
+% \begin{variable}[tested = m3prop004]{\g_tmpa_prop, \g_tmpb_prop}
+%   We can now initialize the scratch variables.
+%    \begin{macrocode}
+\prop_new:N \l_tmpa_prop
+\prop_new:N \l_tmpb_prop
+\prop_new:N \g_tmpa_prop
+\prop_new:N \g_tmpb_prop
+%    \end{macrocode}
+% \end{variable}
+% \end{variable}
+%
+% \begin{variable}{\l_@@_internal_prop}
+%   Property list used by \cs{prop_set_from_keyval:Nn} and others.
+%    \begin{macrocode}
+\prop_new:N \l_@@_internal_prop
+%    \end{macrocode}
+% \end{variable}
+%
+% \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}
+%   {
+%     \@@_from_keyval:n,
+%     \@@_from_keyval_loop:w,
+%     \@@_from_keyval_split:Nw,
+%     \@@_from_keyval_key:n,
+%     \@@_from_keyval_key:w,
+%     \@@_from_keyval_value:n,
+%     \@@_from_keyval_value:w
+%   }
+%   To avoid tracking throughout the loop the variable name and whether
+%   the assignment is local/global, do everything in a scratch variable
+%   and empty it afterwards to avoid wasting memory.  Loop through items
+%   separated by commas, with \cs{prg_do_nothing:} to avoid losing
+%   braces.  After checking for termination, split the item at the first
+%   and then at the second |=| (which ought to be the first of the
+%   trailing~|=| that we added).  For both splits trim spaces and call a
+%   function (first \cs{@@_from_keyval_key:w} then
+%   \cs{@@_from_keyval_value:w}), followed by the trimmed material,
+%   \cs{q_nil}, the subsequent part of the item, and the trailing |=|'s
+%   and \cs{q_stop}.  After finding the \meta{key} just store it after
+%   \cs{q_stop}.  After finding the \meta{value} ignore completely empty
+%   items (both trailing~|=| were used as delimiters and all parts are
+%   empty); if the remaining part~|#2| consists exactly of the second
+%   trailing~|=| (namely there was exactly one |=|~in the item) then
+%   output one key--value pair for the property list; otherwise complain
+%   about a missing or extra~|=|.
+%    \begin{macrocode}
+\cs_new_protected:Npn \prop_set_from_keyval:Nn #1#2
+  {
+    \prop_clear:N \l_@@_internal_prop
+    \@@_from_keyval:n {#2}
+    \prop_set_eq:NN #1 \l_@@_internal_prop
+    \prop_clear:N \l_@@_internal_prop
+  }
+\cs_generate_variant:Nn \prop_set_from_keyval:Nn { c }
+\cs_new_protected:Npn \prop_gset_from_keyval:Nn #1#2
+  {
+    \prop_clear:N \l_@@_internal_prop
+    \@@_from_keyval:n {#2}
+    \prop_gset_eq:NN #1 \l_@@_internal_prop
+    \prop_clear:N \l_@@_internal_prop
+  }
+\cs_generate_variant:Nn \prop_gset_from_keyval:Nn { c }
+\cs_new_protected:Npn \prop_const_from_keyval:Nn #1#2
+  {
+    \prop_clear:N \l_@@_internal_prop
+    \@@_from_keyval:n {#2}
+    \tl_const:Nx #1 { \exp_not:o \l_@@_internal_prop }
+    \prop_clear:N \l_@@_internal_prop
+  }
+\cs_generate_variant:Nn \prop_const_from_keyval:Nn { c }
+\cs_new_protected:Npn \@@_from_keyval:n #1
+  {
+    \@@_from_keyval_loop:w \prg_do_nothing: #1 ,
+      \q_recursion_tail , \q_recursion_stop
+  }
+\cs_new_protected:Npn \@@_from_keyval_loop:w #1 ,
+  {
+    \quark_if_recursion_tail_stop:o {#1}
+    \@@_from_keyval_split:Nw \@@_from_keyval_key:n
+      #1 = = \q_stop {#1}
+    \@@_from_keyval_loop:w \prg_do_nothing:
+  }
+\cs_new_protected:Npn \@@_from_keyval_split:Nw #1#2 =
+  { \tl_trim_spaces_apply:oN {#2} #1 }
+\cs_new_protected:Npn \@@_from_keyval_key:n #1
+  { \@@_from_keyval_key:w #1 \q_nil }
+\cs_new_protected:Npn \@@_from_keyval_key:w #1 \q_nil #2 \q_stop
+  {
+    \@@_from_keyval_split:Nw \@@_from_keyval_value:n
+      \prg_do_nothing: #2 \q_stop {#1}
+  }
+\cs_new_protected:Npn \@@_from_keyval_value:n #1
+  { \@@_from_keyval_value:w #1 \q_nil }
+\cs_new_protected:Npn \@@_from_keyval_value:w #1 \q_nil #2 \q_stop #3#4
+  {
+    \tl_if_empty:nF { #3 #1 #2 }
+      {
+        \str_if_eq:nnTF {#2} { = }
+          { \prop_put:Nnn \l_@@_internal_prop {#3} {#1} }
+          {
+            \__kernel_msg_error:nnx { kernel } { prop-keyval }
+              { \exp_not:o {#4} }
+          }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Accessing data in property lists}
+%
+% \begin{macro}{\@@_split:NnTF}
+% \begin{macro}{\@@_split_aux:NnTF}
+% \begin{macro}[EXP]{\@@_split_aux:w}
+%   This function is used by most of the module, and hence must be fast.
+%   It receives a \meta{property list}, a \meta{key}, a \meta{true code}
+%   and a \meta{false code}.  The aim is to split the \meta{property
+%     list} at the given \meta{key} into the \meta{extract_1} before the
+%   key--value pair, the \meta{value} associated with the \meta{key} and
+%   the \meta{extract_2} after the key--value pair.  This is done using
+%   a delimited function, whose definition is as follows, where the
+%   \meta{key} is turned into a string.
+%   \begin{quote}
+%     \cs{cs_set:Npn} \cs{@@_split_aux:w} |#1| \\
+%     \quad \cs{@@_pair:wn} \meta{key} \cs{s_@@} |#2| \\
+%     \quad |#3| \cs{q_mark} |#4| |#5| \cs{q_stop} \\
+%     \quad |{| |#4| \Arg{true code} \Arg{false code} |}|
+%   \end{quote}
+%
+%   If the \meta{key} is present in the property list,
+%   \cs{@@_split_aux:w}'s |#1| is the part before the \meta{key}, |#2|
+%   is the \meta{value}, |#3| is the part after the \meta{key}, |#4| is
+%   \cs{use_i:nn}, and |#5| is additional tokens that we do not care
+%   about.  The \meta{true code} is left in the input stream, and can
+%   use the parameters |#1|, |#2|, |#3| for the three parts of the
+%   property list as desired.  Namely, the original property list is in
+%   this case |#1| \cs{@@_pair:wn} \meta{key} \cs{s_@@} |{#2}| |#3|.
+%
+%   If the \meta{key} is not there, then the \meta{function} is
+%   \cs{use_ii:nn}, which keeps the \meta{false code}.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_split:NnTF #1#2
+  { \exp_args:NNo \@@_split_aux:NnTF #1 { \tl_to_str:n {#2} } }
+\cs_new_protected:Npn \@@_split_aux:NnTF #1#2#3#4
+  {
+    \cs_set:Npn \@@_split_aux:w ##1
+      \@@_pair:wn #2 \s_@@ ##2 ##3 \q_mark ##4 ##5 \q_stop
+      { ##4 {#3} {#4} }
+    \exp_after:wN \@@_split_aux:w #1 \q_mark \use_i:nn
+      \@@_pair:wn #2 \s_@@ { } \q_mark \use_ii:nn \q_stop
+  }
+\cs_new:Npn \@@_split_aux:w { }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[tested = m3prop002]
+%   {\prop_remove:Nn, \prop_remove:NV, \prop_remove:cn, \prop_remove:cV}
+% \begin{macro}[tested = m3prop002]
+%   {\prop_gremove:Nn, \prop_gremove:NV, \prop_gremove:cn, \prop_gremove:cV}
+%   Deleting from a property starts by splitting the list.
+%   If the key is present in the property list, the returned value is ignored.
+%   If the key is missing, nothing happens.
+%    \begin{macrocode}
+\cs_new_protected:Npn \prop_remove:Nn #1#2
+  {
+    \@@_split:NnTF #1 {#2}
+      { \tl_set:Nn #1 { ##1 ##3 } }
+      { }
+  }
+\cs_new_protected:Npn \prop_gremove:Nn #1#2
+  {
+    \@@_split:NnTF #1 {#2}
+      { \tl_gset:Nn #1 { ##1 ##3 } }
+      { }
+  }
+\cs_generate_variant:Nn \prop_remove:Nn  {     NV }
+\cs_generate_variant:Nn \prop_remove:Nn  { c , cV }
+\cs_generate_variant:Nn \prop_gremove:Nn {     NV }
+\cs_generate_variant:Nn \prop_gremove:Nn { c , cV }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[tested = m3prop002]
+%   {
+%     \prop_get:NnN, \prop_get:NVN, \prop_get:NoN,
+%     \prop_get:cnN, \prop_get:cVN, \prop_get:coN
+%   }
+%   Getting an item from a list is very easy: after splitting,
+%   if the key is in the property list, just set the token list variable
+%   to the return value, otherwise to \cs{q_no_value}.
+%    \begin{macrocode}
+\cs_new_protected:Npn \prop_get:NnN #1#2#3
+  {
+    \@@_split:NnTF #1 {#2}
+      { \tl_set:Nn #3 {##2} }
+      { \tl_set:Nn #3 { \q_no_value } }
+  }
+\cs_generate_variant:Nn \prop_get:NnN {     NV , No }
+\cs_generate_variant:Nn \prop_get:NnN { c , cV , co }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[tested = m3prop002]
+%   {\prop_pop:NnN, \prop_pop:NoN, \prop_pop:cnN, \prop_pop:coN}
+% \begin{macro}[tested = m3prop002]
+%   {\prop_gpop:NnN, \prop_gpop:NoN, \prop_gpop:cnN, \prop_gpop:coN}
+%   Popping a value also starts by doing the split.
+%   If the key is present, save the value in the token list and update the
+%   property list as when deleting.
+%   If the key is missing, save \cs{q_no_value} in the token list.
+%    \begin{macrocode}
+\cs_new_protected:Npn \prop_pop:NnN #1#2#3
+  {
+    \@@_split:NnTF #1 {#2}
+      {
+        \tl_set:Nn #3 {##2}
+        \tl_set:Nn #1 { ##1 ##3 }
+      }
+      { \tl_set:Nn #3 { \q_no_value } }
+  }
+\cs_new_protected:Npn \prop_gpop:NnN #1#2#3
+  {
+    \@@_split:NnTF #1 {#2}
+      {
+        \tl_set:Nn #3 {##2}
+        \tl_gset:Nn #1 { ##1 ##3 }
+      }
+      { \tl_set:Nn #3 { \q_no_value } }
+  }
+\cs_generate_variant:Nn \prop_pop:NnN  {     No }
+\cs_generate_variant:Nn \prop_pop:NnN  { c , co }
+\cs_generate_variant:Nn \prop_gpop:NnN {     No }
+\cs_generate_variant:Nn \prop_gpop:NnN { c , co }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\prop_item:Nn, \prop_item:cn}
+% \begin{macro}[EXP]{\@@_item_Nn:nwwn}
+%   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.
+%    \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:
+  }
+\cs_new:Npn \@@_item_Nn:nwwn #1#2 \@@_pair:wn #3 \s_@@ #4
+  {
+    \str_if_eq:eeTF {#1} {#3}
+      { \prg_break:n { \exp_not:n {#4} } }
+      { \@@_item_Nn:nwwn {#1} }
+  }
+\cs_generate_variant:Nn \prop_item:Nn { c }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\prop_count:N, \prop_count:c}
+% \begin{macro}[EXP]{\@@_count:nn}
+%   Counting the key--value pairs in a property list is done using the
+%   same approach as for other count functions: turn each entry into a
+%   \texttt{+1} then use integer evaluation to actually do the
+%   mathematics.
+%    \begin{macrocode}
+\cs_new:Npn \prop_count:N #1
+  {
+    \int_eval:n
+      {
+        0
+        \prop_map_function:NN #1 \@@_count:nn
+      }
+  }
+\cs_new:Npn \@@_count:nn #1#2 { + 1 }
+\cs_generate_variant:Nn \prop_count:N { c }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[TF, tested = m3prop004]
+%   {\prop_pop:NnN, \prop_pop:cnN, \prop_gpop:NnN, \prop_gpop:cnN}
+%   Popping an item from a property list, keeping track of whether
+%   the key was present or not, is implemented as a conditional.
+%   If the key was missing, neither the property list, nor the token
+%   list are altered. Otherwise, \cs{prg_return_true:} is used after
+%   the assignments.
+%    \begin{macrocode}
+\prg_new_protected_conditional:Npnn \prop_pop:NnN #1#2#3 { T , F , TF }
+  {
+    \@@_split:NnTF #1 {#2}
+      {
+        \tl_set:Nn #3 {##2}
+        \tl_set:Nn #1 { ##1 ##3 }
+        \prg_return_true:
+      }
+      { \prg_return_false: }
+  }
+\prg_new_protected_conditional:Npnn \prop_gpop:NnN #1#2#3 { T , F , TF }
+  {
+    \@@_split:NnTF #1 {#2}
+      {
+        \tl_set:Nn #3 {##2}
+        \tl_gset:Nn #1 { ##1 ##3 }
+        \prg_return_true:
+      }
+      { \prg_return_false: }
+  }
+\prg_generate_conditional_variant:Nnn \prop_pop:NnN { c } { T , F , TF }
+\prg_generate_conditional_variant:Nnn \prop_gpop:NnN { c } { T , F , TF }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[tested = m3prop002]
+%   {
+%     \prop_put:Nnn, \prop_put:NnV, \prop_put:Nno, \prop_put:Nnx,
+%     \prop_put:NVn, \prop_put:NVV, \prop_put:Non, \prop_put:Noo,
+%     \prop_put:cnn, \prop_put:cnV, \prop_put:cno, \prop_put:cnx,
+%     \prop_put:cVn, \prop_put:cVV, \prop_put:con, \prop_put:coo
+%   }
+% \begin{macro}[tested = m3prop002]
+%   {
+%     \prop_gput:Nnn, \prop_gput:NnV, \prop_gput:Nno, \prop_gput:Nnx,
+%     \prop_gput:NVn, \prop_gput:NVV, \prop_gput:Non, \prop_gput:Noo,
+%     \prop_gput:cnn, \prop_gput:cnV, \prop_gput:cno, \prop_gput:cnx,
+%     \prop_gput:cVn, \prop_gput:cVV, \prop_gput:con, \prop_gput:coo
+%   }
+% \begin{macro}{\@@_put:NNnn}
+%   Since the branches of \cs{@@_split:NnTF} are used as the replacement
+%   text of an internal macro, and since the \meta{key} and new
+%   \meta{value} may contain arbitrary tokens, it is not safe to include
+%   them in the argument of \cs{@@_split:NnTF}.  We thus start by
+%   storing in \cs{l_@@_internal_tl} tokens which (after
+%   \texttt{x}-expansion) encode the key--value pair.  This variable can
+%   safely be used in \cs{@@_split:NnTF}.  If the \meta{key} was absent,
+%   append the new key--value to the list.
+%   Otherwise concatenate the extracts |##1|
+%   and |##3| with the new key--value pair \cs{l_@@_internal_tl}.  The
+%   updated entry is placed at the same spot as the original \meta{key}
+%   in the property list, preserving the order of entries.
+%    \begin{macrocode}
+\cs_new_protected:Npn \prop_put:Nnn  { \@@_put:NNnn \tl_set:Nx }
+\cs_new_protected:Npn \prop_gput:Nnn { \@@_put:NNnn \tl_gset:Nx }
+\cs_new_protected:Npn \@@_put:NNnn #1#2#3#4
+  {
+    \tl_set:Nn \l_@@_internal_tl
+      {
+        \exp_not:N \@@_pair:wn \tl_to_str:n {#3}
+        \s_@@ { \exp_not:n {#4} }
+      }
+    \@@_split:NnTF #2 {#3}
+      { #1 #2 { \exp_not:n {##1} \l_@@_internal_tl \exp_not:n {##3} } }
+      { #1 #2 { \exp_not:o {#2} \l_@@_internal_tl } }
+  }
+\cs_generate_variant:Nn \prop_put:Nnn
+  {     NnV , Nno , Nnx , NV , NVV , No , Noo }
+\cs_generate_variant:Nn \prop_put:Nnn
+  { c , cnV , cno , cnx , cV , cVV , co , coo }
+\cs_generate_variant:Nn \prop_gput:Nnn
+  {     NnV , Nno , Nnx , NV , NVV , No , Noo }
+\cs_generate_variant:Nn \prop_gput:Nnn
+  { c , cnV , cno , cnx , cV , cVV , co , coo }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[tested = m3prop002]
+%   {\prop_put_if_new:Nnn, \prop_put_if_new:cnn}
+% \begin{macro}[tested = m3prop002]
+%   {\prop_gput_if_new:Nnn, \prop_gput_if_new:cnn}
+% \begin{macro}{\@@_put_if_new:NNnn}
+%   Adding conditionally also splits. If the key is already present,
+%   the three brace groups given by \cs{@@_split:NnTF} are removed.
+%   If the key is new, then the value is added, being careful to
+%   convert the key to a string using \cs{tl_to_str:n}.
+%    \begin{macrocode}
+\cs_new_protected:Npn \prop_put_if_new:Nnn
+  { \@@_put_if_new:NNnn \tl_set:Nx }
+\cs_new_protected:Npn \prop_gput_if_new:Nnn
+  { \@@_put_if_new:NNnn \tl_gset:Nx }
+\cs_new_protected:Npn \@@_put_if_new:NNnn #1#2#3#4
+  {
+    \tl_set:Nn \l_@@_internal_tl
+      {
+        \exp_not:N \@@_pair:wn \tl_to_str:n {#3}
+        \s_@@ \exp_not:n { {#4} }
+      }
+    \@@_split:NnTF #2 {#3}
+      { }
+      { #1 #2 { \exp_not:o {#2} \l_@@_internal_tl } }
+  }
+\cs_generate_variant:Nn \prop_put_if_new:Nnn  { c }
+\cs_generate_variant:Nn \prop_gput_if_new:Nnn { c }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Property list conditionals}
+%
+% \begin{macro}[pTF, tested = m3prop004]{\prop_if_exist:N, \prop_if_exist:c}
+%   Copies of the \texttt{cs} functions defined in \pkg{l3basics}.
+%    \begin{macrocode}
+\prg_new_eq_conditional:NNn \prop_if_exist:N \cs_if_exist:N
+  { TF , T , F , p }
+\prg_new_eq_conditional:NNn \prop_if_exist:c \cs_if_exist:c
+  { TF , T , F , p }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[pTF, tested = m3prop003]{\prop_if_empty:N, \prop_if_empty:c}
+%   Same test as for token lists.
+%    \begin{macrocode}
+\prg_new_conditional:Npnn \prop_if_empty:N #1 { p , T , F , TF }
+  {
+    \tl_if_eq:NNTF #1 \c_empty_prop
+      \prg_return_true: \prg_return_false:
+  }
+\prg_generate_conditional_variant:Nnn \prop_if_empty:N
+  { c } { p , T , F , TF }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[pTF, tested = m3prop003]
+%   {
+%     \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}
+%   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
+%   \begin{verbatim}
+%     \prg_new_protected_conditional:Npnn \prop_if_in:Nn #1 #2
+%       {
+%         \@@_split:NnTF #1 {#2}
+%           { \prg_return_true: }
+%           { \prg_return_false: }
+%       }
+%   \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.
+%    \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} }
+  }
+\cs_new:Npn \@@_if_in:N #1
+  {
+    \if_meaning:w \q_recursion_tail #1
+      \prg_return_false:
+    \else:
+      \prg_return_true:
+    \fi:
+    \prg_break:
+  }
+\prg_generate_conditional_variant:Nnn \prop_if_in:Nn
+  { NV , No , c , cV , co } { p , T , F , TF }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Recovering values from property lists with branching}
+%
+% \begin{macro}[TF, tested = m3prop004]
+%   {
+%     \prop_get:NnN, \prop_get:NVN, \prop_get:NoN,
+%     \prop_get:cnN, \prop_get:cVN, \prop_get:coN
+%   }
+%   Getting the value corresponding to a key, keeping track of whether
+%   the key was present or not, is implemented as a conditional (with
+%   side effects). If the key was absent, the token list is not altered.
+%    \begin{macrocode}
+\prg_new_protected_conditional:Npnn \prop_get:NnN #1#2#3 { T , F , TF }
+  {
+    \@@_split:NnTF #1 {#2}
+      {
+        \tl_set:Nn #3 {##2}
+        \prg_return_true:
+      }
+      { \prg_return_false: }
+  }
+\prg_generate_conditional_variant:Nnn \prop_get:NnN
+  { NV , No , c , cV , co } { T , F , TF }
+%    \end{macrocode}
+% \end{macro}
+%
+% \subsection{Mapping to property lists}
+%
+% \begin{macro}[tested = m3prop003]
+%   {
+%     \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{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 #2
+    #1
+    \prg_break: \@@_pair:wn \s_@@ { } \prg_break_point:
+    \prg_break_point:Nn \prop_map_break: { }
+  }
+\cs_new:Npn \@@_map_function:Nwwn #1#2 \@@_pair:wn #3 \s_@@ #4
+  {
+    #2
+    #1 {#3} {#4}
+    \@@_map_function:Nwwn #1
+  }
+\cs_generate_variant:Nn \prop_map_function:NN { Nc , c , cc }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[tested = m3prop003]{\prop_map_inline:Nn, \prop_map_inline:cn}
+%   Mapping in line requires a nesting level counter.  Store the current
+%   definition of \cs{@@_pair:wn}, and define it anew.  At the end of
+%   the loop, revert to the earlier definition.  Note that besides pairs
+%   of the form \cs{@@_pair:wn} \meta{key} \cs{s_@@} \Arg{value}, there
+%   are a leading and a trailing tokens, but both are equal to
+%   \cs{scan_stop:}, hence have no effect in such inline mapping.
+%   Such \cs{scan_stop:} could have affected ligatures if they appeared
+%   during the mapping.
+%    \begin{macrocode}
+\cs_new_protected:Npn \prop_map_inline:Nn #1#2
+  {
+    \cs_gset_eq:cN
+      { @@_map_ \int_use:N \g__kernel_prg_map_int :wn } \@@_pair:wn
+    \int_gincr:N \g__kernel_prg_map_int
+    \cs_gset_protected:Npn \@@_pair:wn ##1 \s_@@ ##2 {#2}
+    #1
+    \prg_break_point:Nn \prop_map_break:
+      {
+        \int_gdecr:N \g__kernel_prg_map_int
+        \cs_gset_eq:Nc \@@_pair:wn
+          { @@_map_ \int_use:N \g__kernel_prg_map_int :wn }
+      }
+  }
+\cs_generate_variant:Nn \prop_map_inline:Nn { c }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[tested = m3prop003]{\prop_map_break:}
+% \begin{macro}[tested = m3prop003]{\prop_map_break:n}
+%   The break statements are based on the general \cs{prg_map_break:Nn}.
+%    \begin{macrocode}
+\cs_new:Npn \prop_map_break:
+  { \prg_map_break:Nn \prop_map_break: { } }
+\cs_new:Npn \prop_map_break:n
+  { \prg_map_break:Nn \prop_map_break: }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \subsection{Viewing property lists}
+%
+% \begin{macro}[tested = m3show001]
+%   {\prop_show:N, \prop_show:c, \prop_log:N, \prop_log:c}
+%   Apply the general \cs{__kernel_chk_defined:NT} and
+%   \cs{msg_show:nnnnnn}. Contrarily to sequences and comma lists,
+%   we use \cs{msg_show_item:nn} to format both the key and the value
+%   for each pair.
+%    \begin{macrocode}
+\cs_new_protected:Npn \prop_show:N { \@@_show:NN \msg_show:nnxxxx }
+\cs_generate_variant:Nn \prop_show:N { c }
+\cs_new_protected:Npn \prop_log:N { \@@_show:NN \msg_log:nnxxxx }
+\cs_generate_variant:Nn \prop_log:N { c }
+\cs_new_protected:Npn \@@_show:NN #1#2
+  {
+    \__kernel_chk_defined:NT #2
+      {
+        #1 { LaTeX/kernel } { show-prop }
+          { \token_to_str:N #2 }
+          { \prop_map_function:NN #2 \msg_show_item:nn }
+          { } { }
+      }
+  }
+%    \end{macrocode}
+% \end{macro}
+%
+%    \begin{macrocode}
+%</initex|package>
+%    \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex
-- 
cgit v1.2.3

