% \iffalse meta-comment
%
%% File: l3prop.dtx Copyright (C) 1990-2011 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
%%
%%    http://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 released version of this bundle is available from CTAN.
%%
%% -----------------------------------------------------------------------
%%
%% The development version of the bundle can be found at
%%
%%    http://www.latex-project.org/svnroot/experimental/trunk/
%%
%% for those people who are interested.
%%
%%%%%%%%%%%
%% NOTE: %%
%%%%%%%%%%%
%%
%%   Snapshots taken from the repository represent work in progress and may
%%   not work or may contain conflicting material!  We therefore ask
%%   people _not_ to put them into distributions, archives, etc. without
%%   prior consultation with the LaTeX3 Project.
%%
%% -----------------------------------------------------------------------
%
%<*driver|package>
\RequirePackage{l3names}
\GetIdInfo$Id: l3prop.dtx 2839 2011-09-17 20:18:23Z bruno $
  {L3 Experimental property lists}
%</driver|package>
%<*driver>
\documentclass[full]{l3doc}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \title{^^A
%   The \pkg{l3prop} package\\ Property lists^^A
%   \thanks{This file describes v\ExplFileVersion,
%      last revised \ExplFileDate.}^^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 \ExplFileDate}
%
% \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 will overwrite 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 lists} will
%   initially contain no entries.
% \end{function}
%
% \begin{function}{\prop_clear:N, \prop_clear:c}
%   \begin{syntax}
%     \cs{prop_clear:N} \meta{property list}
%   \end{syntax}
%   Clears all entries from the \meta{property list} within the scope of
%   the current \TeX{} group.
% \end{function}
%
% \begin{function}{\prop_gclear:N, \prop_gclear:c}
%   \begin{syntax}
%     \cs{prop_gclear:N} \meta{property list}
%   \end{syntax}
%   Clears all entries from the \meta{property list} globally.
% \end{function}
%
% \begin{function}{\prop_clear_new:N, \prop_clear_new:c}
%   \begin{syntax}
%     \cs{prop_clear_new:N} \meta{property list}
%   \end{syntax}
%   If the \meta{property list} already exists, clears it within the scope
%   of the current \TeX{} group. If the \meta{property list} is not defined,
%   it will be created (using \cs{prop_new:N}). Thus the property list is
%   guaranteed to be available and clear within the current \TeX{}
%   group. The \meta{property list} will exist globally, but the content
%   outside of the current \TeX{} group is not specified.
% \end{function}
%
% \begin{function}{\prop_gclear_new:N, \prop_gclear_new:c}
%   \begin{syntax}
%     \cs{prop_gclear_new:N} \meta{property list}
%   \end{syntax}
%   If the \meta{property list} already exists, clears it globally. If the
%   \meta{property list} is not defined, it will be created (using
%   \cs{prop_new:N}). Thus the property list is guaranteed to be available
%   and globally clear.
% \end{function}
%
% \begin{function}
%   {\prop_set_eq:NN, \prop_set_eq:cN, \prop_set_eq:Nc, \prop_set_eq:cc}
%   \begin{syntax}
%     \cs{prop_set_eq:NN} \meta{property list1} \meta{property list2}
%   \end{syntax}
%   Sets the content of \meta{property list1} equal to that of
%   \meta{property list2}. This assignment is restricted to the current
%   \TeX{} group level.
% \end{function}
%
% \begin{function}
%   {\prop_gset_eq:NN, \prop_gset_eq:cN, \prop_gset_eq:Nc, \prop_gset_eq:cc}
%   \begin{syntax}
%     \cs{prop_gset_eq:NN} \meta{property list1} \meta{property list2}
%   \end{syntax}
%   Sets the content of \meta{property list1} equal to that of
%   \meta{property list2}. This assignment is global and so is not
%   limited by the current \TeX{} group level.
% \end{function}
%
% \section{Adding entries to property lists}
%
% \begin{function}
%   {
%     \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{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}. The assignment is restricted to the current
%   \TeX{} group.
% \end{function}
%
% \begin{function}
%   {
%     \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_gput: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}. The assignment is global.
% \end{function}
%
% \begin{function}{\prop_put_if_new:Nnn, \prop_put_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. The assignment is restricted to the current
%   \TeX{} group.
% \end{function}
%
% \begin{function}{\prop_gput_if_new:Nnn, \prop_gput_if_new:cnn}
%   \begin{syntax}
%     \cs{prop_gput_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. The assignment is global.
% \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} will
%   contain 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} will
%   contain the special marker \cs{q_no_value}. The \meta{key} and
%   \meta{value} are then deleted from the property list. Both
%   assignments are local.
% \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} will
%   contain 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.
% \end{function}
%%
% \section{Modifying property lists}
%
% \begin{function}{\prop_del:Nn, \prop_del:NV, \prop_del:cn, \prop_del:cV}
%   \begin{syntax}
%     \cs{prop_del:Nn} \meta{property list} \Arg{key}
%   \end{syntax}
%   Deletes the entry listed under \meta{key} from the
%   \meta{property list} which may be accessed. 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. The deletion is restricted to the current \TeX{} group.
% \end{function}
%
% \begin{function}{\prop_gdel:Nn, \prop_gdel:NV, \prop_gdel:cn, \prop_gdel:cV}
%   \begin{syntax}
%     \cs{prop_gdel:Nn} \meta{property list} \Arg{key}
%   \end{syntax}
%   Deletes the entry listed under \meta{key} from the
%   \meta{property list} which may be accessed. 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. The deletion is not restricted to the current \TeX{}
%   group: it is global.
% \end{function}
%
% \section{Property list conditionals}
%
% \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 = 2011-08-28, 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 and leaves the
%   \meta{token list variable} unchanged. 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}. The \meta{token list variable} is assigned locally.
% \end{function}
%
% \begin{function}[added = 2011-08-18,TF]{\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 and leaves the
%   \meta{token list variable} unchanged. 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}
%
% \section{Mapping to property lists}
%
% \begin{function}[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} will receive two argument 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}{\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 will receive 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}[rEXP]{\prop_map_break:}
%   \begin{syntax}
%     \cs{prop_map_break:}
%   \end{syntax}
%   Used to terminate a \cs{prop_map_\ldots} function before all
%   entries in the \meta{property list} have been processed. This will
%   normally take 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{prop_map_\ldots} scenario will lead low
%   level \TeX{} errors.
% \end{function}
%
% \begin{function}[rEXP]{\prop_map_break:n}
%   \begin{syntax}
%     \cs{prop_map_break:n} \Arg{tokens}
%   \end{syntax}
%   Used to terminate a \cs{prop_map_\ldots} function before all
%   entries in the \meta{property list} have been processed, inserting
%   the \meta{tokens} after the mapping has ended. This will
%   normally take 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 { <tokens> } }
%           {
%             % Do something useful
%           }
%       }
%   \end{verbatim}
%   Use outside of a \cs{prop_map_\ldots} scenario will lead low
%   level \TeX{} errors.
% \end{function}
%
% \section{Viewing property lists}
%
% \begin{function}{\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}
%
% \section{Experimental property list functions}
%
% This section contains functions which may or may not be retained, depending
% on how useful they are found to be.
%
% \begin{function}[added = 2011-08-18,TF]{\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 and leaves the
%   \meta{token list variable} unchanged. 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}
%
% \begin{function}[added = 2011-08-18,rEXP]
%   {\prop_map_tokens:Nn, \prop_map_tokens:cn}
%   \begin{syntax}
%     \cs{prop_map_tokens:Nn} \meta{property list} \Arg{code}
%   \end{syntax}
%   Analogue of \cs{prop_map_function:NN} which maps several tokens instead
%   of a single function. Useful in particular when mapping through a
%   property list while keeping track of a given key.
% \end{function}
%
% \begin{function}[updated = 2011-09-15,EXP]{\prop_get:Nn, \prop_get:cn}
%   \begin{syntax}
%     \cs{prop_get: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}.
%   \end{texnote}
% \end{function}
%
% \section{Internal property list functions}
%
% \begin{function}{\q_prop}
%   The internal token used to separate out property list entries, separating
%   both the \meta{key} from the \meta{value} and also one entry from another.
% \end{function}
%
% \begin{function}{\c_empty_prop}
%   A permanently-empty property list used for internal comparisons.
% \end{function}
%
% \begin{function}{\prop_split:Nnn}
%   \begin{syntax}
%     \cs{prop_split:Nnn} \meta{property list} \Arg{key} \Arg{code}
%   \end{syntax}
%   Splits the \meta{property list} at the \meta{key}, giving three
%   groups: 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}.
%   The first \meta{extract} retains the internal structure of a property
%   list. The second is only missing the leading separator \cs{q_prop}.
%   This ensures that the concatenation of the two \meta{extracts} is a
%   property list.
%   If the \meta{key} is not present in the \meta{property list} then
%   the second group will contain the marker \cs{q_no_value} and the third
%   is empty.
%   Once the split has occurred, the \meta{code} is inserted followed by the
%   three groups: thus the \meta{code} should properly absorb three
%   arguments.
%   The \meta{key} comparison takes place as described for \cs{str_if_eq:nn}.
% \end{function}
%
% \begin{function}{\prop_split:NnTF}
%   \begin{syntax}
%     \cs{prop_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
%   groups: 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}.
%   The first \meta{extract} retains the internal structure of a property
%   list. The second is only missing the leading separator \cs{q_prop}.
%   This ensures that 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, followed by the three
%   groups: thus the \meta{true code} should properly absorb three arguments.
%   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.
%   The \meta{key} comparison takes place as described for \cs{str_if_eq:nn}.
% \end{function}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{l3prop} implementation}
%
% \TestFiles{m3prop001}
%
%    \begin{macrocode}
%<*initex|package>
%    \end{macrocode}
%
%    \begin{macrocode}
%<*package>
\ProvidesExplPackage
  {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
\package_check_loaded_expl:
%</package>
%    \end{macrocode}
%
% A property list is a macro whose top-level expansion is for the form
% \enquote{\cs{q_prop} \meta{key$_0$} \cs{q_prop} \Arg{value$_0$} \cs{q_prop}
% \ldots \cs{q_prop} \meta{key$_{n-1}$} \cs{q_prop} \Arg{value$_{n-1}$}
% \cs{q_prop}}.
% The trailing \cs{q_prop} is always present for performance reasons: this
% means that empty property lists are not actually empty.
%
% \begin{macro}[int]{\q_prop}
%   A private quark is used as a marker between entries.
%    \begin{macrocode}
\quark_new:N \q_prop
%    \end{macrocode}
% \end{macro}
%
% \begin{variable}{\c_empty_prop}
%   An empty prop contains exactly one \cs{q_prop}.
%    \begin{macrocode}
\tl_const:Nn \c_empty_prop { \q_prop }
%    \end{macrocode}
% \end{variable}
%
% \subsection{Allocation and initialisation}
%
% \begin{macro}{\prop_new:N,\prop_new:c}
%   Internally, property lists are token lists, but an empty prop
%   is not an empty tl, so we need to do things by hand.
%    \begin{macrocode}
\cs_new_protected:Npn \prop_new:N #1 { \cs_new_eq:NN  #1  \c_empty_prop }
\cs_new_protected:Npn \prop_new:c #1 { \cs_new_eq:cN {#1} \c_empty_prop }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\prop_clear:N, \prop_clear:c}
% \begin{macro}{\prop_gclear:N, \prop_gclear:c}
%   The same idea for  clearing
%    \begin{macrocode}
\cs_new_protected:Npn \prop_clear:N #1  { \cs_set_eq:NN   #1  \c_empty_prop }
\cs_new_protected:Npn \prop_clear:c #1  { \cs_set_eq:cN  {#1} \c_empty_prop }
\cs_new_protected:Npn \prop_gclear:N #1 { \cs_gset_eq:NN  #1  \c_empty_prop }
\cs_new_protected:Npn \prop_gclear:c #1 { \cs_gset_eq:cN {#1} \c_empty_prop }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\prop_clear_new:N, \prop_clear_new:c}
% \begin{macro}{\prop_gclear_new:N, \prop_gclear_new:c}
%   Once again a simple copy from the token list functions.
%    \begin{macrocode}
\cs_new_protected:Npn \prop_clear_new:N #1
  { \cs_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
  { \cs_if_exist:NTF #1 { \prop_gclear:N #1 } { \prop_new:N #1 } }
\cs_new_eq:NN \prop_gclear_new:c \prop_gclear:c
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {\prop_set_eq:NN, \prop_set_eq:cN, \prop_set_eq:Nc, \prop_set_eq:cc}
% \begin{macro}
%   {\prop_gset_eq:NN, \prop_gset_eq:cN, \prop_gset_eq:Nc, \prop_gset_eq:cc}
%   Once again, 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}
%
% \subsection{Accessing data in property lists}
%
% \begin{macro}[int]{\prop_split:NnTF}
% \begin{macro}[aux]{\prop_split_aux:NnTF}
% \begin{macro}[aux]{\prop_split_aux:nnnn}
% \begin{macro}[aux]{\prop_split_aux:w}
%   This function is used by most of the module, and hence must be fast.
%   The aim here is to split a property list at a given key into the part
%   before the key--value pair, the value associated with the key and the part
%   after the key--value pair. To do this, the key is first detokenized (to
%   avoid repeatedly doing this), then a delimited function is constructed to
%   match the key. It will match \cs{q_prop} \meta{detokenized key} \cs{q_prop}
%   \marg{value} \meta{extra argument}, effectively separating an
%   \meta{extract1} before the key in the property list and an \meta{extract2}
%   after the key.
%
%   If the key is present in the property list, then \meta{extra argument}
%   is simply \cs{q_prop}, and \cs{prop_splot_aux:nnnn} will gobble this
%   and the false branch (|#4|), leaving the correct code on the input
%   stream. More precisely, it leaves the user code (true branch), followed
%   by three groups, \Arg{extract1} \Arg{value} \Arg{extract2}.
%   In order for \meta{extract1}\meta{extract2} to be a well-formed
%   property list, \meta{extract1} has a leading and trailing \cs{q_prop},
%   retaining exactly the structure of a property list, while \meta{extract2}
%   omits the leading \cs{q_prop}.
%
%   If the key is not there, then \meta{extra argument} is
%   |? \use_ii:nn { }|, and |\prop_split_aux:nnnn ? \use_ii:nn { }| removes
%   the three brace groups that just follow. Then \cs{use_ii:nn} removes
%   the true branch, leaving the false branch, with no trailing material.
%    \begin{macrocode}
\cs_set_protected:Npn \prop_split:NnTF #1#2
  { \exp_args:NNo \prop_split_aux:NnTF #1 { \tl_to_str:n {#2} } }
\cs_new_protected:Npn \prop_split_aux:NnTF #1#2
  {
    \cs_set_protected:Npn \prop_split_aux:w
      ##1 \q_prop #2 \q_prop ##2 ##3 ##4 \q_mark ##5 \q_stop
      { \prop_split_aux:nnnn ##3 { {##1 \q_prop } {##2} {##4} } }
    \exp_after:wN \prop_split_aux:w #1 \q_mark
         \q_prop #2 \q_prop { } { ? \use_ii:nn { } } \q_mark \q_stop
  }
\cs_new:Npn \prop_split_aux:nnnn #1#2#3#4 { #3 #2 }
\cs_new_protected:Npn \prop_split_aux:w { }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}[int]{\prop_split:Nnn}
%   The goal here is to provide a common interface for both true and false
%   branches of \cs{prop_split:NnTF}. In both cases, the code given by the
%   user will be placed in front of three brace groups, \Arg{extract1}
%   \Arg{value} \Arg{extract2}.
%   If the key was missing from the property list, then \meta{extract1}
%   is the full property list, \meta{value} is \cs{q_no_value}, and
%   \meta{extract2} is empty.
%   Otherwise, \meta{extract1} is the part of the property list before the
%   \meta{key}, and has the structure of a property list, \meta{value} is
%   the value corresponding to the \meta{key}, and \meta{extract2} (the part
%   after the \meta{key}) is missing the leading \cs{q_prop}.
%    \begin{macrocode}
\cs_set_protected:Npn \prop_split:Nnn #1#2#3
  {
    \prop_split:NnTF #1 {#2}
    {#3}
    { \exp_args:Nno \use:n {#3} {#1} { \q_no_value } { } }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\prop_del:Nn, \prop_del:NV, \prop_del:cn, \prop_del:cV}
% \begin{macro}{\prop_gdel:Nn, \prop_gdel:NV, \prop_gdel:cn, \prop_gdel:cV}
% \begin{macro}[aux]{\prop_del_aux:NNnnn}
%   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_del:Nn #1#2
  { \prop_split:NnTF #1 {#2} { \prop_del_aux:NNnnn \tl_set:Nn #1 } { } }
\cs_new_protected:Npn \prop_gdel:Nn #1#2
  { \prop_split:NnTF #1 {#2} { \prop_del_aux:NNnnn \tl_gset:Nn #1 } { } }
\cs_new_protected:Npn \prop_del_aux:NNnnn #1#2#3#4#5
  { #1 #2 { #3 #5 } }
\cs_generate_variant:Nn \prop_del:Nn  {     NV }
\cs_generate_variant:Nn \prop_del:Nn  { c , cV }
\cs_generate_variant:Nn \prop_gdel:Nn {     NV }
\cs_generate_variant:Nn \prop_gdel:Nn { c , cV }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \prop_get:NnN, \prop_get:NVN, \prop_get:NoN,
%     \prop_get:cnN, \prop_get:cVN, \prop_get:NoN
%   }
% \begin{macro}[aux]{\prop_get_aux:Nnnn}
%   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
  {
    \prop_split:NnTF #1 {#2}
      { \prop_get_aux:Nnnn #3 }
      { \tl_set:Nn #3 { \q_no_value } }
  }
\cs_new_protected:Npn \prop_get_aux:Nnnn #1#2#3#4
  { \tl_set:Nn #1 {#3} }
\cs_generate_variant:Nn \prop_get:NnN {     NV , No }
\cs_generate_variant:Nn \prop_get:NnN { c , cV , co }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\prop_pop:NnN, \prop_pop:NoN, \prop_pop:cnN, \prop_pop:coN}
% \begin{macro}{\prop_gpop:NnN, \prop_gpop:NoN, \prop_gpop:cnN, \prop_gpop:coN}
% \begin{macro}[aux]{\prop_pop_aux:NNNnnn}
%   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
  {
    \prop_split:NnTF #1 {#2}
      { \prop_pop_aux:NNNnnn \tl_set:Nn #1 #3 }
      { \tl_set:Nn #3 { \q_no_value } }
  }
\cs_new_protected:Npn \prop_gpop:NnN #1#2#3
  {
    \prop_split:NnTF #1 {#2}
      { \prop_pop_aux:NNNnnn \tl_gset:Nn #1 #3 }
      { \tl_set:Nn #3 { \q_no_value } }
  }
\cs_new_protected:Npn \prop_pop_aux:NNNnnn #1#2#3#4#5#6
  {
    \tl_set:Nn #3 {#5}
    #1 #2 { #4 #6 }
  }
\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}
% \end{macro}
%
% \begin{macro}
%   {
%     \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}
%   {
%     \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}[aux]{\prop_put_aux:NNnnnnn}
%   Putting a key--value pair in a property list starts by splitting
%   to remove any existing value. The property list is then
%   reconstructed with the two remaining parts |#5| and |#7| first,
%   followed by the new or updated entry.
%    \begin{macrocode}
\cs_new_protected:Npn \prop_put:Nnn { \prop_put_aux:NNnn \tl_set:Nx }
\cs_new_protected:Npn \prop_gput:Nnn { \prop_put_aux:NNnn \tl_gset:Nx }
\cs_new_protected:Npn \prop_put_aux:NNnn #1#2#3#4
  {
    \prop_split:Nnn #2 {#3} { \prop_put_aux:NNnnnnn #1 #2 {#3} {#4} }
  }
\cs_new_protected:Npn \prop_put_aux:NNnnnnn #1#2#3#4#5#6#7
  {
    #1 #2
      {
        \exp_not:n { #5 #7 }
        \tl_to_str:n {#3} \exp_not:n { \q_prop {#4} \q_prop }
      }
  }
\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}{\prop_put_if_new:Nnn, \prop_put_if_new:cnn}
% \begin{macro}{\prop_gput_if_new:Nnn, \prop_gput_if_new:cnn}
%   Adding conditionally also splits. If the key is already present,
%   the three brace groups given by \cs{prop_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_nopar:Npn \prop_put_if_new:Nnn
  { \prop_put_if_new_aux:NNnn \tl_put_right:Nx }
\cs_new_protected_nopar:Npn \prop_gput_if_new:Nnn
  { \prop_put_if_new_aux:NNnn \tl_gput_right:Nx }
\cs_new_protected:Npn \prop_put_if_new_aux:NNnn #1#2#3#4
  {
    \prop_split:NnTF #2 {#3}
      { \use_none:nnn }
      {
        #1 #2
          { \tl_to_str:n {#3} \exp_not:n { \q_prop {#4} \q_prop } }
      }
  }
\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}
%
% \subsection{Property list conditionals}
%
% \begin{macro}[pTF]{\prop_if_empty:N, \prop_if_empty:c}
%   The test here uses \cs{c_empty_prop} as it is not really empty!
%    \begin{macrocode}
\prg_new_conditional:Npnn \prop_if_empty:N #1 { p, T , F , TF }
  {
    \if_meaning:w #1 \c_empty_prop
      \prg_return_true:
    \else:
      \prg_return_false:
    \fi:
  }
\cs_generate_variant:Nn \prop_if_empty_p:N {c}
\cs_generate_variant:Nn \prop_if_empty:NTF {c}
\cs_generate_variant:Nn \prop_if_empty:NT  {c}
\cs_generate_variant:Nn \prop_if_empty:NF  {c}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[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{macro}[aux]{\prop_if_in_aux:nwn,\prop_if_in_aux:Nw}
%   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
%       {
%         \prop_split:NnTF #1 {#2}
%           {
%             \prg_return_true:
%             \use_none:nnn
%           }
%         { \prg_return_false: }
%       }
%   \end{verbatim}
%   but \cs{prop_split:NnTF} is non-expandable.
%
%   Instead, the key is compared to each key in turn using \cs{str_if_eq:xx},
%   which is expandable. To terminate the mapping, we add the key that
%   is search for at the end of the property list. This second
%   \cs{tl_to_str:n} is not expanded at the start, but only when included
%   in the \cs{str_if_eq:xx}. It cannot make the breaking mechanism choke,
%   because the arbitrary token list material is enclosed in braces.
%   When ending, we test the next token: it is either \cs{q_prop}
%   or \cs{q_recursion_tail} in the case of a missing key.
%   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 \prop_if_in_aux:nwn
      { \tl_to_str:n {#2} } #1
      \tl_to_str:n {#2} \q_prop { }
    \q_recursion_tail \q_recursion_stop
  }
\cs_new:Npn \prop_if_in_aux:nwn #1 \q_prop #2 \q_prop #3
  {
    \str_if_eq:xxTF {#1} {#2}
      { \prop_if_in_aux:Nw }
      { \prop_if_in_aux:nwn {#1} }
  }
\cs_new:Npn \prop_if_in_aux:Nw #1 #2 \q_recursion_stop
  {
    \if_meaning:w \q_prop #1
      \prg_return_true:
    \else:
      \prg_return_false:
    \fi:
  }
\cs_generate_variant:Nn \prop_if_in_p:Nn {     NV , No }
\cs_generate_variant:Nn \prop_if_in_p:Nn { c , cV , co }
\cs_generate_variant:Nn \prop_if_in:NnT  {     NV , No }
\cs_generate_variant:Nn \prop_if_in:NnT  { c , cV , co }
\cs_generate_variant:Nn \prop_if_in:NnF  {     NV , No }
\cs_generate_variant:Nn \prop_if_in:NnF  { c , cV , co }
\cs_generate_variant:Nn \prop_if_in:NnTF {     NV , No }
\cs_generate_variant:Nn \prop_if_in:NnTF { c , cV , co }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Recovering values from property lists with branching}
%
% \begin{macro}[TF]
%   {
%     \prop_get:NnN, \prop_get:NVN, \prop_get:NoN,
%     \prop_get:cnN, \prop_get:cVN, \prop_get:coN
%   }
% \begin{macro}[aux]{\prop_get_aux_true:Nnnn}
%   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 }
  {
    \prop_split:NnTF #1 {#2}
      { \prop_get_aux_true:Nnnn #3 }
      { \prg_return_false: }
  }
\cs_new_protected:Npn \prop_get_aux_true:Nnnn #1#2#3#4
  {
    \tl_set:Nn #1 {#3}
    \prg_return_true:
  }
\cs_generate_variant:Nn \prop_get:NnNT  {     NV , No }
\cs_generate_variant:Nn \prop_get:NnNF  {     NV , No }
\cs_generate_variant:Nn \prop_get:NnNTF {     NV , No }
\cs_generate_variant:Nn \prop_get:NnNT  { c , cV , co }
\cs_generate_variant:Nn \prop_get:NnNF  { c , cV , co }
\cs_generate_variant:Nn \prop_get:NnNTF { c , cV , co }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Mapping to property lists}
%
% \begin{macro}
%   {
%     \prop_map_function:NN, \prop_map_function:Nc,
%     \prop_map_function:cN, \prop_map_function:cc
%   }
% \begin{macro}[aux]{\prop_map_function_aux:Nwn}
%   The fastest way to do a recursion here is to use an
%   \cs{if_meaning:w} test: the keys are strings, and thus
%   cannot match the marker \cs{q_recursion_tail}.
%    \begin{macrocode}
\cs_new_nopar:Npn \prop_map_function:NN #1#2
  {
    \exp_last_unbraced:NNo \prop_map_function_aux:Nwn #2
      #1 \q_recursion_tail \q_prop { } \q_recursion_stop
  }
\cs_new:Npn \prop_map_function_aux:Nwn #1 \q_prop #2 \q_prop #3
  {
    \if_meaning:w \q_recursion_tail #2
      \exp_after:wN \prop_map_break:
    \fi:
    #1 {#2} {#3}
    \prop_map_function_aux:Nwn #1
  }
\cs_generate_variant:Nn \prop_map_function:NN {     Nc }
\cs_generate_variant:Nn \prop_map_function:NN { c , cc }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{variable}{\g_prop_map_inline_int}
%   A nesting counter for mapping.
%    \begin{macrocode}
\int_new:N \g_prop_map_inline_int
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\prop_map_inline:Nn, \prop_map_inline:cn}
%   Mapping in line requires a nesting level counter.
%    \begin{macrocode}
\cs_new_protected:Npn \prop_map_inline:Nn #1#2
  {
    \int_gincr:N \g_prop_map_inline_int
    \cs_gset:cpn { prop_map_inline_ \int_use:N \g_prop_map_inline_int :nn }
      ##1##2 {#2}
    \prop_map_function:Nc #1
      { prop_map_inline_ \int_use:N \g_prop_map_inline_int :nn }
    \int_gdecr:N \g_prop_map_inline_int
  }
\cs_generate_variant:Nn \prop_map_inline:Nn { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\prop_map_break:}
%   Breaking the map function simply means removing everything up to
%   the \cs{q_stop} marker.
%    \begin{macrocode}
\cs_new_eq:NN \prop_map_break: \use_none_delimit_by_q_recursion_stop:w
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\prop_map_break:n}
%   The same idea for using one set of tokens.
%    \begin{macrocode}
\cs_new_eq:NN \prop_map_break:n \use_i_delimit_by_q_recursion_stop:nw
%    \end{macrocode}
% \end{macro}
%
% \subsection{Viewing property lists}
%
% \begin{variable}{\l_prop_show_tl}
%   Used to store the material for display.
%    \begin{macrocode}
\tl_new:N \l_prop_show_tl
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\prop_show:N, \prop_show:c}
% \begin{macro}[aux]{\prop_show_aux:n}
% \begin{macro}[aux]{\prop_show_aux:w}
%   The aim of the mapping here is to create a token list containing the
%   formatted property list. The very first item needs the new line and
%   \verb*|> | removing, which is achieved using a \texttt{w}-type auxiliary.
%   To avoid a low-level \TeX{} error if there is an empty property list, a
%   simple test is used to keep the output \enquote{clean}.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \prop_show:N #1
  {
    \prop_if_empty:NTF #1
      {
        \iow_term:x { Property~list~\token_to_str:N #1~is~empty }
        \tl_show:n { }
      }
      {
        \iow_term:x
          {
            Property~list~\token_to_str:N #1~
            contains~the~pairs~(without~outer~braces):
          }
        \tl_set:Nx \l_prop_show_tl
          { \prop_map_function:NN #1 \prop_show_aux:nn }
        \tl_show:n \exp_after:wN \exp_after:wN \exp_after:wN
          { \exp_after:wN \prop_show_aux:w \l_prop_show_tl }
      }
  }
\cs_new:Npn \prop_show_aux:nn #1#2
  {
    \iow_newline: > \c_space_tl \c_space_tl
    \iow_char:N \{ #1 \iow_char:N \}
    \c_space_tl \c_space_tl => \c_space_tl \c_space_tl
    \iow_char:N \{ \exp_not:n {#2} \iow_char:N \}
  }
\cs_new:Npn \prop_show_aux:w #1 > ~ { }
\cs_generate_variant:Nn \prop_show:N { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Experimental functions}
%
% \begin{macro}[TF]
%   {\prop_pop:NnN, \prop_pop:cnN, \prop_gpop:cnN, \prop_gpop:cnN}
% \begin{macro}[aux]{\prop_pop_aux_true:NNNnnn}
%   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 }
  {
    \prop_split:NnTF #1 {#2}
      { \prop_pop_aux_true:NNNnnn \tl_set:Nn #1 #3 }
      { \prg_return_false: }
  }
\prg_new_protected_conditional:Npnn \prop_gpop:NnN #1#2#3 { T , F , TF }
  {
    \prop_split:NnTF #1 {#2}
      { \prop_pop_aux_true:NNNnnn \tl_gset:Nn #1 #3 }
      { \prg_return_false: }
  }
\cs_new_protected:Npn \prop_pop_aux_true:NNNnnn #1#2#3#4#5#6
  {
    \tl_set:Nn #3 {#5}
    #1 #2 { #4 #6 }
    \prg_return_true:
  }
\cs_generate_variant:Nn \prop_pop:NnNT   { c }
\cs_generate_variant:Nn \prop_pop:NnNF   { c }
\cs_generate_variant:Nn \prop_pop:NnNTF  { c }
\cs_generate_variant:Nn \prop_gpop:NnNT  { c }
\cs_generate_variant:Nn \prop_gpop:NnNF  { c }
\cs_generate_variant:Nn \prop_gpop:NnNTF { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[rEXP]{\prop_map_tokens:Nn, \prop_map_tokens:cn}
% \begin{macro}[aux]{\prop_map_tokens_aux:nwn}
%   The mapping grabs one key--value pair at a time, and stops when
%   reaching the marker key \cs{q_recursion_tail}, which
%   cannot appear in normal keys since those are strings. The odd
%   construction |\use:n {#1}| allows |#1| to contain any token.
%    \begin{macrocode}
\cs_new:Npn \prop_map_tokens:Nn #1#2
  {
    \exp_last_unbraced:Nno \prop_map_tokens_aux:nwn {#2} #1
    \q_recursion_tail \q_prop { } \q_recursion_stop
  }
\cs_new:Npn \prop_map_tokens_aux:nwn #1 \q_prop #2 \q_prop #3
  {
    \if_meaning:w \q_recursion_tail #2
       \exp_after:wN \prop_map_break:
    \fi:
    \use:n {#1} {#2} {#3}
    \prop_map_tokens_aux:nwn {#1}
  }
\cs_generate_variant:Nn \prop_map_tokens:Nn { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[EXP]{\prop_get:Nn, \prop_get:cn}
% \begin{macro}[aux]{\prop_get_Nn_aux:nwn}
%   Getting the value corresponding to a key in a property list in an
%   expandable fashion is a simple instance of mapping some tokens.
%   Map the function \cs{prop_get_aux:nnn} which takes as its three
%   arguments the \meta{key} that we are looking for, the current
%   \meta{key} and the current \meta{value}. If the \meta{keys} match,
%   the \meta{value} is returned. If none of the keys match, this expands
%   to nothing.
%    \begin{macrocode}
\cs_new:Npn \prop_get:Nn #1#2
  {
    \exp_last_unbraced:Noo \prop_get_Nn_aux:nwn
      { \tl_to_str:n {#2} } #1
      \tl_to_str:n {#2} \q_prop { }
    \q_recursion_stop
  }
\cs_new:Npn \prop_get_Nn_aux:nwn #1 \q_prop #2 \q_prop #3
  {
    \str_if_eq:xxTF {#1} {#2}
      { \use_i_delimit_by_q_recursion_stop:nw {#3} }
      { \prop_get_Nn_aux:nwn {#1} }
  }
\cs_generate_variant:Nn \prop_get:Nn { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Deprecated interfaces}
%
% Deprecated on 2011-05-27, for removal by 2011-08-31.
%
% \begin{macro}{\prop_display:N, \prop_display:c}
%   An older name for \cs{prop_show:N}.
%    \begin{macrocode}
%<*deprecated>
\cs_new_eq:NN \prop_display:N \prop_show:N
\cs_new_eq:NN \prop_display:c \prop_show:c
%</deprecated>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\prop_gget:NnN, \prop_gget:NVN, \prop_gget:cnN, \prop_gget:cVN}
% \begin{macro}[aux]{\prop_gget_aux:Nnnn}
%   Getting globally is no longer supported: this is a conceptual change, so
%   the necessary code for the transition is provided directly.
%    \begin{macrocode}
%<*deprecated>
\cs_new_protected:Npn \prop_gget:NnN #1#2#3
  { \prop_split:Nnn #1 {#2} { \prop_gget_aux:Nnnn #3 } }
\cs_new_protected:Npn \prop_gget_aux:Nnnn #1#2#3#4
  { \tl_gset:Nn #1 {#3} }
\cs_generate_variant:Nn \prop_gget:NnN {     NV }
\cs_generate_variant:Nn \prop_gget:NnN { c , cV }
%</deprecated>
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\prop_get_gdel:NnN}
%   This name seems very odd.
%    \begin{macrocode}
%<*deprecated>
\cs_new_eq:NN \prop_get_gdel:NnN \prop_gpop:NnN
%</deprecated>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[TF]{\prop_if_in:cc}
%   A hang-over from an ancient implementation
%    \begin{macrocode}
%<*deprecated>
\cs_generate_variant:Nn \prop_if_in:NnT  { cc }
\cs_generate_variant:Nn \prop_if_in:NnF  { cc }
\cs_generate_variant:Nn \prop_if_in:NnTF { cc }
%</deprecated>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\prop_gput:ccx}
%   Another one.
%    \begin{macrocode}
%<*deprecated>
\cs_generate_variant:Nn \prop_gput:Nnn { ccx }
%</deprecated>
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[pTF]
%   {\prop_if_eq:NN, \prop_if_eq:Nc, \prop_if_eq:cN, \prop_if_eq:cc}
%   These ones do no even make sense!
%    \begin{macrocode}
%<*deprecated>
\prg_new_eq_conditional:NNn \prop_if_eq:NN \tl_if_eq:NN { p , T , F , TF }
\prg_new_eq_conditional:NNn \prop_if_eq:cN \tl_if_eq:cN { p , T , F , TF }
\prg_new_eq_conditional:NNn \prop_if_eq:Nc \tl_if_eq:Nc { p , T , F , TF }
\prg_new_eq_conditional:NNn \prop_if_eq:cc \tl_if_eq:cc { p , T , F , TF }
%</deprecated>
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</initex|package>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex
