% \iffalse %% File: l3prop.dtx Copyright (C) 1990-2009 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 ``expl3 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 LaTeX Project Team. %% %% ----------------------------------------------------------------------- % %<*driver|package> \RequirePackage{l3names} % %\fi \GetIdInfo$Id: l3prop.dtx 2087 2010-11-23 18:21:44Z joseph $ {L3 Experimental Property Lists} %\iffalse %<*driver> %\fi \ProvidesFile{\filename.\filenameext} [\filedate\space v\fileversion\space\filedescription] %\iffalse \documentclass[full]{l3doc} \begin{document} \DocInput{\filename.\filenameext} \end{document} % % \fi % % % \title{The \textsf{l3prop} package\thanks{This file % has version number \fileversion, last % revised \filedate.}\\ % Property Lists} % \author{\Team} % \date{\filedate} % \maketitle % % \def\propkey{key} % \def\propval{info} % \def\proplist{prop} % % \begin{documentation} % % \LaTeX3 implements a data structure called a `property list' which allows % arbitrary information to be stored and accessed using keywords rather than % numerical indexing. % % A property list might contain a set of keys such as "name", "age", and "ID", % which each have individual values that can be saved and retrieved. % % \section{Functions} % % \begin{function}{% % \prop_new:N | % \prop_new:c | % } % \begin{syntax} % "\prop_new:N" <\proplist> % \end{syntax} % Defines <\proplist> to be a variable of type \meta{\proplist}. % \end{function} % % \begin{function}{% % \prop_clear:N | % \prop_clear:c | % \prop_gclear:N | % \prop_gclear:c | % } % \begin{syntax} % "\prop_clear:N" <\proplist> % \end{syntax} % These functions locally or globally clear <\proplist>. % \end{function} % % \begin{function}{% % \prop_put:Nnn | % \prop_put:Nno | % \prop_put:NnV | % \prop_put:NVn | % \prop_put:NVV | % \prop_put:Nnx | % \prop_put:cnn | % \prop_put:cnx | % \prop_gput:Nnn | % \prop_gput:NVn | % \prop_gput:Nno | % \prop_gput:NnV | % \prop_gput:Nnx | % \prop_gput:cnn | % \prop_gput:ccx | % } % \begin{syntax} % "\prop_put:Nnn" <\proplist> \Arg{\propkey} \Arg{token list} % \end{syntax} % Locally or globally associates with <\propkey> in the <\proplist> % <\proplist>. If <\propkey> has already a meaning within <\proplist> this value is % overwritten. % % The <\propkey> must not contain unescaped "#" tokens but the may. % \end{function} % % \begin{function}{% % \prop_gput_if_new:Nnn | % } % \begin{syntax} % "\prop_gput_if_new:Nnn" <\proplist> \Arg{\propkey} \Arg{token list} % \end{syntax} % Globally associates with <\propkey> in the <\proplist> % <\proplist> but only if <\propkey> has so far no meaning within <\proplist>. % Silently ignored if <\propkey> is already set in the <\proplist>. % \end{function} % % \begin{function}{% % \prop_get:NnN | % \prop_get:NVN | % \prop_get:cnN | % \prop_get:cVN | % \prop_gget:NnN | % \prop_gget:NVN | % \prop_gget:cnN | % \prop_gget:cVN | % } % \begin{syntax} % "\prop_get:NnN" <\proplist> \Arg{\propkey} % \end{syntax} % If <\propval> is the information associated with <\propkey> in the <\proplist> % <\proplist> then the token list variable gets <\propval> assigned. % Otherwise its value is the special quark "\q_no_value". %^^A See section \ref{sec:quarks} to test this. % The assignment is done either locally or globally. % \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} % "\prop_set_eq:NN" <\proplist 1> <\proplist 2> % \end{syntax} % A fast assignment of <\proplist>s. % \end{function} % % \begin{function}{% % \prop_get_gdel:NnN | % } % \begin{syntax} % "\prop_get_gdel:NnN" <\proplist> \Arg{\propkey} % \end{syntax} % Like "\prop_get:NnN" but additionally removes <\propkey> (and its <\propval>) % from <\proplist>. % \end{function} % % \begin{function}{% % \prop_del:Nn | % \prop_del:NV | % \prop_gdel:Nn | % \prop_gdel:NV | % } % \begin{syntax} % "\prop_del:Nn" <\proplist> \Arg{\propkey} % \end{syntax} % Locally or globally deletes <\propkey> and its <\propval> from <\proplist> if % found. Otherwise does nothing. % \end{function} % % % \begin{function}{ \prop_map_function:NN / (EXP) | % \prop_map_function:cN / (EXP) | % \prop_map_function:Nc / (EXP) | % \prop_map_function:cc / (EXP) } % \begin{syntax} % "\prop_map_function:NN" <\proplist> % \end{syntax} % Maps which should be a function with two arguments (<\propkey> % and <\propval>) over every <\propkey> <\propval> pair of <\proplist>. % Property lists do not have any intrinsic ``order'' when stored. As a % result, you should not expect any particular order to apply when using % these mapping functions, even with newly-created properly lists. % \end{function} % % \begin{function}{\prop_map_inline:Nn | % \prop_map_inline:cn % } % \begin{syntax} % "\prop_map_inline:Nn" <\proplist> \Arg{inline function} % \end{syntax} % Just like "\prop_map_function:NN" but with the function of two arguments % supplied as inline code. Within refer to the % arguments via "#1" (<\propkey>) and "#2" (<\propval>). Nestable. % Property lists do not have any intrinsic ``order'' when stored. As a % result, you should not expect any particular order to apply when using % these mapping functions, even with newly-created properly lists. % \end{function} % % % \begin{function}{% % \prop_map_break: | % } % \begin{syntax} % "\prop_map_inline:Nn" \meta{\proplist} "{"\\ % " ... \"\meta{break test}":T {\prop_map_break:} }" % \end{syntax} % For breaking out of a loop. To be used inside "TF"-type functions as shown % in the example above. % \end{function} % % \begin{function}{ \prop_show:N | % \prop_show:c } % \begin{syntax} % "\prop_show:N" <\proplist> % \end{syntax} % Pauses the compilation and shows <\proplist> on the terminal output and % in the log file. % \end{function} % % \begin{function}{ \prop_display:N | % \prop_display:c } % \begin{syntax} % "\prop_display:N" % \end{syntax} % As with "\prop_show:N" but pretty prints the output one line per property pair. % \end{function} % % % \section{Predicates and conditionals} % % \begin{function}{ \prop_if_empty_p:N | % \prop_if_empty_p:c } % \begin{syntax} % "\prop_if_empty_p:N" <\proplist> \Arg{true code} \Arg{false code} % \end{syntax} % Predicates to test whether or not a particular <\proplist> is empty. % \end{function} % % \begin{function}{ \prop_if_empty:N / (TF)(EXP) | % \prop_if_empty:c / (TF)(EXP) } % \begin{syntax} % "\prop_if_empty:NTF" <\proplist> \Arg{true code} \Arg{false code} % \end{syntax} % Set of conditionals that test whether or not a particular <\proplist> % is empty. % \end{function} % % \begin{function}{ % \prop_if_eq_p:NN / (EXP) | % \prop_if_eq_p:cN / (EXP) | % \prop_if_eq_p:Nc / (EXP) | % \prop_if_eq_p:cc / (EXP) | % \prop_if_eq:NN / (EXP)(TF) | % \prop_if_eq:cN / (EXP)(TF) | % \prop_if_eq:Nc / (EXP)(TF) | % \prop_if_eq:cc / (EXP)(TF) | % } % \begin{syntax} % "\prop_if_eq:NNF" <\proplist 1> <\proplist 2> \Arg{false code} % \end{syntax} % Execute if <\proplist 1> doesn't hold the same token list as % <\proplist 2>. Only expandable for new versions of pdf\TeX. % \end{function} % % % \begin{function}{% % \prop_if_in:Nn / (TF) | % \prop_if_in:NV / (TF) | % \prop_if_in:No / (TF) | % \prop_if_in:cn / (TF) | % \prop_if_in:cc / (TF) | % } % \begin{syntax} % "\prop_if_in:NnTF" <\proplist> \Arg{\propkey} \Arg{true code} \Arg{false code} % \end{syntax} % Tests if <\propkey> is used in <\proplist> and then either executes % or . % \end{function} % % \section{Internal functions} % % \begin{function}{\q_prop} % Quark used to delimit property lists internally. % \end{function} % % \begin{function}{% % \prop_put_aux:w | % \prop_put_if_new_aux:w | % } % Internal functions implementing the put operations. % \end{function} % % \begin{function}{% % \prop_get_aux:w | % \prop_gget_aux:w | % \prop_get_del_aux:w | % \prop_del_aux:w | % } % Internal functions implementing the get and delete operations. % \end{function} % % \begin{function}{% % \prop_if_in_aux:w | % } % Internal function implementing the key test operation. % \end{function} % % \begin{function}{% % \prop_map_function_aux:w | % } % Internal function implementing the map operations. % \end{function} % % \begin{function}{% % \g_prop_inline_level_int | % } % Integer used in internal name for function used inside % "\prop_map_inline:NN". % \end{function} % % \begin{function}{\prop_split_aux:Nnn} % \begin{syntax} % "\prop_split_aux:Nnn" <\proplist> <\propkey> % \end{syntax} % Internal function that invokes with 3 arguments: 1st is the % beginning of <\proplist> before <\propkey>, 2nd is the value associated with % <\propkey>, 3rd is the rest of <\proplist> after <\propkey>. If there is no key % <\propkey> in <\proplist>, then the 2 arg is "\q_no_value" and the 3rd arg is % empty; otherwise the 3rd argument has the two extra tokens <\propkey> % "\q_no_value" at the end. % % This function is used to implement various get operations. % \end{function} % % \end{documentation} % % \begin{implementation} % % \section{\pkg{l3prop} implementation} % % A property list is a token register whose contents is % of the form\par % {\centering|\q_prop| \meta{\propkey$\sb1$} |\q_prop| \marg{\propval$\sb1$} \ldots{} % |\q_prop| \meta{\propkey$\sb n$} |\q_prop| \marg{\propval$\sb n$}\par} % % The property \m{\propkey}s and \m{\propval}s might be arbitrary token lists; each % \m{\propval} is surrounded by braces. % % We start by ensuring that the required packages are loaded. % \begin{macrocode} %<*package> \ProvidesExplPackage {\filename}{\filedate}{\fileversion}{\filedescription} \package_check_loaded_expl: % %<*initex|package> % \end{macrocode} % % \begin{macro}{\q_prop} % The separator between \m{\propkey}s and \m{\propval}s and \m{\propkey}s. % \begin{macrocode} \quark_new:N\q_prop % \end{macrocode} % \end{macro} % % To get values from property-lists, token lists should be passed to % the appropriate functions. % % \subsection{Functions} % % \begin{macro}{\prop_new:N} % \begin{macro}{\prop_new:c} % Property lists are implemented as token registers. % \begin{macrocode} \cs_new_eq:NN \prop_new:N \toks_new:N \cs_new_eq:NN \prop_new:c \toks_new:c % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\prop_clear:N} % \begin{macro}{\prop_clear:c} % \begin{macro}{\prop_gclear:N} % \begin{macro}{\prop_gclear:c} % The same goes for clearing a property list, either % locally or globally. % \begin{macrocode} \cs_new_eq:NN \prop_clear:N \toks_clear:N \cs_new_eq:NN \prop_clear:c \toks_clear:c \cs_new_eq:NN \prop_gclear:N \toks_gclear:N \cs_new_eq:NN \prop_gclear:c \toks_gclear:c % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\prop_set_eq:NN} % \begin{macro}{\prop_set_eq:Nc} % \begin{macro}{\prop_set_eq:cN} % \begin{macro}{\prop_set_eq:cc} % \begin{macro}{\prop_gset_eq:NN} % \begin{macro}{\prop_gset_eq:Nc} % \begin{macro}{\prop_gset_eq:cN} % \begin{macro}{\prop_gset_eq:cc} % This makes two \m{\proplist}s have the same contents. % \begin{macrocode} \cs_new_eq:NN \prop_set_eq:NN \toks_set_eq:NN \cs_new_eq:NN \prop_set_eq:Nc \toks_set_eq:Nc \cs_new_eq:NN \prop_set_eq:cN \toks_set_eq:cN \cs_new_eq:NN \prop_set_eq:cc \toks_set_eq:cc \cs_new_eq:NN \prop_gset_eq:NN \toks_gset_eq:NN \cs_new_eq:NN \prop_gset_eq:Nc \toks_gset_eq:Nc \cs_new_eq:NN \prop_gset_eq:cN \toks_gset_eq:cN \cs_new_eq:NN \prop_gset_eq:cc \toks_gset_eq:cc % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\prop_show:N} % \begin{macro}{\prop_show:c} % Show on the console the raw contents of a property list's token register. % \begin{macrocode} \cs_new_eq:NN \prop_show:N \toks_show:N \cs_new_eq:NN \prop_show:c \toks_show:c % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\prop_display:N} % \begin{macro}{\prop_display:c} % Pretty print the contents of a property list on the console. % \begin{macrocode} \cs_new_protected_nopar:Npn \prop_display:N #1 { \iow_term:x { Property-list~\token_to_str:N #1~contains~ the~pairs~(without~outer~braces): } \toks_clear:N \l_tmpa_toks \prop_map_inline:Nn #1 { \toks_if_empty:NF \l_tmpa_toks { \toks_put_right:Nx \l_tmpa_toks {^^J>~} } \toks_put_right:Nx \l_tmpa_toks { \c_space_tl \iow_char:N \{ \exp_not: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 \} } } \toks_show:N \l_tmpa_toks } \cs_generate_variant:Nn \prop_display:N {c} % \end{macrocode} % \end{macro} % \end{macro} % % % \begin{macro}{\prop_split_aux:Nnn} % |\prop_split_aux:Nnn|\meta{\proplist}\meta{\propkey}\meta{cmd} invokes \meta{cmd} % with 3 arguments: 1st is the beginning of \meta{\proplist} before % \meta{\propkey}, 2nd is the value associated with \meta{\propkey}, 3rd is the % rest of \meta{\proplist} after \meta{\propkey}. If there is no property % \meta{\propkey} in \meta{\proplist}, then the 2nd argument will be |\q_no_value| % and the 3rd argument is empty; otherwise the 3rd argument has the % extra tokens |\q_prop| \meta{\propkey} |\q_prop| |\q_no_value| at the end. % \begin{macrocode} \cs_new_protected:Npn \prop_split_aux:Nnn #1#2#3{ \cs_set:Npn \prop_tmp:w ##1 \q_prop #2 \q_prop ##2##3 \q_stop { #3 {##1}{##2}{##3} } \exp_after:wN \prop_tmp:w \toks_use:N #1 \q_prop #2 \q_prop \q_no_value \q_stop } % \end{macrocode} % \end{macro} % % \begin{macro}{\prop_get:NnN} % \begin{macro}{\prop_get:NVN} % \begin{macro}{\prop_get:cnN} % \begin{macro}{\prop_get:cVN} % \begin{macro}{\prop_get_aux:w} % |\prop_get:NnN |\meta{\proplist}\meta{\propkey}\meta{tl var.}~defines % \meta{tl var.}~to be the value associated with \meta{\propkey} in \meta{\proplist}, % |\q_no_value| if not found. % \begin{macrocode} \cs_new_protected:Npn \prop_get:NnN #1#2 { \prop_split_aux:Nnn #1{#2}\prop_get_aux:w } \cs_new_protected:Npn \prop_get_aux:w #1#2#3#4 { \tl_set:Nn #4 {#2} } % \end{macrocode} % % \begin{macrocode} \cs_generate_variant:Nn \prop_get:NnN { NVN, cnN, cVN } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\prop_gget:NnN} % \begin{macro}{\prop_gget:NVN} % \begin{macro}{\prop_gget:NnN} % \begin{macro}{\prop_gget:NVN} % \begin{macro}{\prop_gget_aux:w} % The global version of the previous function. % \begin{macrocode} \cs_new_protected:Npn \prop_gget:NnN #1#2{ \prop_split_aux:Nnn #1{#2}\prop_gget_aux:w} \cs_new_protected:Npn \prop_gget_aux:w #1#2#3#4{\tl_gset:Nx#4{\exp_not:n{#2}}} % \end{macrocode} % % \begin{macrocode} \cs_generate_variant:Nn \prop_gget:NnN { NVN, cnN, cVN } % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\prop_get_gdel:NnN} % \begin{macro}{\prop_get_del_aux:w} % |\prop_get_gdel:NnN| is the same as |\prop_get:NnN| but the % \m{\propkey} and its value are afterwards globally removed % from \m{property_list}. One probably also needs the local % variants or only the local one, or\ldots\ We decide this later. % \begin{macrocode} \cs_new_protected:Npn \prop_get_gdel:NnN #1#2#3{ \prop_split_aux:Nnn #1{#2}{\prop_get_del_aux:w #3{\toks_gset:Nn #1}{#2}}} \cs_new_protected:Npn \prop_get_del_aux:w #1#2#3#4#5#6{ \tl_set:Nn #1 {#5} \quark_if_no_value:NF #1 { \cs_set_nopar:Npn \prop_tmp:w ##1\q_prop#3\q_prop\q_no_value {#2{#4##1}} \prop_tmp:w #6} } % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}{\prop_put:Nnn} % \begin{macro}{\prop_put:Nno} % \begin{macro}{\prop_put:NnV} % \begin{macro}{\prop_put:Nnx} % \begin{macro}{\prop_put:NVn} % \begin{macro}{\prop_put:NVV} % \begin{macro}{\prop_put:cnn} % \begin{macro}{\prop_put:cnx} % \begin{macro}{\prop_gput:Nnn} % \begin{macro}{\prop_gput:NVn} % \begin{macro}{\prop_gput:NnV} % \begin{macro}{\prop_gput:Nno} % \begin{macro}{\prop_gput:Nnx} % \begin{macro}{\prop_gput:cnn} % \begin{macro}{\prop_gput:ccx} % \begin{macro}{\prop_put_aux:w} % |\prop_put:Nnn| \marg{\proplist} \marg{\propkey} \marg{\propval} adds/changes the % value associated with \meta{\propkey} in \meta{\proplist} to \meta{\propval}. % \begin{macrocode} \cs_new_protected:Npn \prop_put:Nnn #1#2{ \prop_split_aux:Nnn #1{#2}{ \prop_clear:N #1 \prop_put_aux:w {\toks_put_right:Nn #1}{#2} } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \prop_gput:Nnn #1#2{ \prop_split_aux:Nnn #1{#2}{ \prop_gclear:N #1 \prop_put_aux:w {\toks_gput_right:Nn #1}{#2} } } % \end{macrocode} % % \begin{macrocode} \cs_new_protected:Npn \prop_put_aux:w #1#2#3#4#5#6{ #1{\q_prop#2\q_prop{#6}#3} \tl_if_empty:nF{#5} { \cs_set_nopar:Npn \prop_tmp:w ##1\q_prop#2\q_prop\q_no_value {#1{##1}} \prop_tmp:w #5 } } % \end{macrocode} % % \begin{macrocode} \cs_generate_variant:Nn \prop_put:Nnn { Nno , NnV, Nnx, NVn, NVV, cnn , cnx } % \end{macrocode} % % \begin{macrocode} \cs_generate_variant:Nn \prop_gput:Nnn {NVn,NnV,Nno,Nnx,Nox,cnn,ccx} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\prop_del:Nn} % \begin{macro}{\prop_del:NV} % \begin{macro}{\prop_gdel:NV} % \begin{macro}{\prop_gdel:Nn} % \begin{macro}{\prop_del_aux:w} % |\prop_del:Nn |\meta{\proplist}\meta{\propkey} deletes the entry for % \meta{\propkey} in \meta{\proplist}, if any. % \begin{macrocode} \cs_new_protected:Npn \prop_del:Nn #1#2{ \prop_split_aux:Nnn #1{#2}{\prop_del_aux:w {\toks_set:Nn #1}{#2}}} \cs_new_protected:Npn \prop_gdel:Nn #1#2{ \prop_split_aux:Nnn #1{#2}{\prop_del_aux:w {\toks_gset:Nn #1}{#2}}} \cs_new_protected:Npn \prop_del_aux:w #1#2#3#4#5{ \cs_set_nopar:Npn \prop_tmp:w {#4} \quark_if_no_value:NF \prop_tmp:w { \cs_set_nopar:Npn \prop_tmp:w ##1\q_prop#2\q_prop\q_no_value {#1{#3##1}} \prop_tmp:w #5 } } \cs_generate_variant:Nn \prop_del:Nn { NV } \cs_generate_variant:Nn \prop_gdel:Nn { NV } % % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % % \begin{macro}{\prop_gput_if_new:Nnn} % \begin{macro}{\prop_put_if_new_aux:w} % |\prop_gput_if_new:Nnn| \m{\proplist} \m{\propkey} % \m{\propval} is equivalent to % \begin{tabbing} % xxxxx\=xxxxx\= \kill % |\prop_if_in:NnTF |\m{\proplist}\m{\propkey} \\ % \> |{}%| \\ % \> |{\prop_gput:Nnn| \\ % \>\> \m{property_list} \\ % \>\> \m{\propkey} \\ % \>\> \m{\propval}|}| % \end{tabbing} % Here we go (listening to Porgy \& Bess in a recording with Ella % F. and Louis A. which makes writing macros sometimes difficult; I % find myself humming instead of working): % \begin{macrocode} \cs_new_protected:Npn \prop_gput_if_new:Nnn #1#2{ \prop_split_aux:Nnn #1{#2}{\prop_put_if_new_aux:w #1{#2}}} \cs_new_protected:Npn \prop_put_if_new_aux:w #1#2#3#4#5#6{ \tl_if_empty:nT {#5}{#1{\q_prop#2\q_prop{#6}#3}}} % \end{macrocode} % \end{macro} % \end{macro} % % % \subsection{Predicates and conditionals} % % \begin{macro}{\prop_if_empty_p:N,\prop_if_empty_p:c} % \begin{macro}[TF]{\prop_if_empty:N,\prop_if_empty:c} % This conditional takes a \m{\proplist} as its argument and evaluates % either the true or the false case, depending on whether or not % \m{\proplist} contains any properties. % \begin{macrocode} \prg_new_eq_conditional:NNn \prop_if_empty:N \toks_if_empty:N {p,TF,T,F} \prg_new_eq_conditional:NNn \prop_if_empty:c \toks_if_empty:c {p,TF,T,F} % \end{macrocode} % \end{macro} % \end{macro} % % % \begin{macro}{\prop_if_eq_p:NN,\prop_if_eq_p:cN, % \prop_if_eq_p:Nc,\prop_if_eq_p:cc} % \begin{macro}[TF]{\prop_if_eq:NN,\prop_if_eq:Nc, % \prop_if_eq:cN,\prop_if_eq:cc} % These functions test whether two property lists are equal. % \begin{macrocode} \prg_new_eq_conditional:NNn \prop_if_eq:NN \toks_if_eq:NN {p,TF,T,F} \prg_new_eq_conditional:NNn \prop_if_eq:cN \toks_if_eq:cN {p,TF,T,F} \prg_new_eq_conditional:NNn \prop_if_eq:Nc \toks_if_eq:Nc {p,TF,T,F} \prg_new_eq_conditional:NNn \prop_if_eq:cc \toks_if_eq:cc {p,TF,T,F} % \end{macrocode} % \end{macro} % \end{macro} % % \begin{macro}[TF]{\prop_if_in:Nn} % \begin{macro}[TF]{\prop_if_in:NV} % \begin{macro}[TF]{\prop_if_in:No} % \begin{macro}[TF]{\prop_if_in:cn} % \begin{macro}[TF]{\prop_if_in:cc} % \begin{macro}{\prop_if_in_aux:w} % |\prop_if_in:NnTF| \m{property_list} \m{\propkey} % \m{true_case} \m{false_case} will check whether or not % \m{\propkey} is on the \m{property_list} and then select % either the true or false case. % \begin{macrocode} \prg_new_protected_conditional:Nnn \prop_if_in:Nn {TF,T,F} { \prop_split_aux:Nnn #1 {#2} {\prop_if_in_aux:w} } \cs_new_nopar:Npn \prop_if_in_aux:w #1#2#3 { \quark_if_no_value:nTF {#2} {\prg_return_false:} {\prg_return_true:} } % \end{macrocode} % % \begin{macrocode} \cs_generate_variant:Nn \prop_if_in:NnTF {NV,No,cn,cc} \cs_generate_variant:Nn \prop_if_in:NnT {NV,No,cn,cc} \cs_generate_variant:Nn \prop_if_in:NnF {NV,No,cn,cc} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \subsection{Mapping functions} % % \begin{macro}{\prop_map_function:NN} % \begin{macro}{\prop_map_function:cN} % \begin{macro}{\prop_map_function:Nc} % \begin{macro}{\prop_map_function:cc} % \begin{macro}{\prop_map_function_aux:w} % Maps a function on every entry in the property list. The % function must take 2 arguments: a key and a value. % % First, some failed attempts: % \begin{verbatim} % \cs_new_nopar:Npn \prop_map_function:NN #1#2{ % \exp_after:wN \prop_map_function_aux:w % \exp_after:wN #2 \toks_use:N #1 \q_prop{}\q_prop \q_no_value \q_stop % } % \cs_new_nopar:Npn \prop_map_function_aux:w #1\q_prop#2\q_prop#3{ % \if_predicate:w \tl_if_empty_p:n{#2} % \exp_after:wN \prop_map_break: % \fi: % #1{#2}{#3} % \prop_map_function_aux:w #1 % } % \end{verbatim} % problem with the above implementation is that an empty key stops the mapping but all % other functions in the module allow the use of empty keys (as one value) % \begin{verbatim} % \cs_set_nopar:Npn \prop_map_function:NN #1#2{ % \exp_after:wN \prop_map_function_aux:w % \exp_after:wN #2 \toks_use:N #1 \q_prop \q_no_value \q_prop \q_no_value % } % \cs_set_nopar:Npn \prop_map_function_aux:w #1\q_prop#2\q_prop#3{ % \quark_if_no_value:nF{#2} % { % #1{#2}{#3} % \prop_map_function_aux:w #1 % } % } % \end{verbatim} % problem with the above implementation is that |\quark_if_no_value:nF| is fairly slow and % if |\quark_if_no_value:NF| is used instead we have to do an assignment thus % making the mapping not expandable (is that important?) % % Here's the current version of the code: % \begin{macrocode} \cs_set_nopar:Npn \prop_map_function:NN #1#2 { \exp_after:wN \prop_map_function_aux:w \exp_after:wN #2 \toks_use:N #1 \q_prop \q_nil \q_prop \q_no_value \q_stop } \cs_set:Npn \prop_map_function_aux:w #1 \q_prop #2 \q_prop #3 { \if_meaning:w \q_nil #2 \exp_after:wN \prop_map_break: \fi: #1{#2}{#3} \prop_map_function_aux:w #1 } % \end{macrocode} % (potential) problem with the above implementation is that it will % return true if |#2| contains more than just |\q_nil| thus executing % whatever follows. Claim: this can't happen |:-)| so we should be ok % \begin{macrocode} \cs_generate_variant:Nn \prop_map_function:NN {c,Nc,cc} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\prop_map_inline:Nn} % \begin{macro}{\prop_map_inline:cn} % \begin{macro}{\g_prop_inline_level_int} % The inline functions are straight forward. It takes longer % to test if the list is empty than to run it on an empty list so % we don't waste time doing that. % \begin{macrocode} \int_new:N \g_prop_inline_level_int \cs_new_protected_nopar:Npn \prop_map_inline:Nn #1#2 { \int_gincr:N \g_prop_inline_level_int \cs_gset:cpn {prop_map_inline_ \int_use:N \g_prop_inline_level_int :n} ##1##2{#2} \prop_map_function:Nc #1 {prop_map_inline_ \int_use:N \g_prop_inline_level_int :n} \int_gdecr:N \g_prop_inline_level_int } % \end{macrocode} % % \begin{macrocode} \cs_generate_variant:Nn\prop_map_inline:Nn {cn} % \end{macrocode} % \end{macro} % \end{macro} % \end{macro} % % \begin{macro}{\prop_map_break:} % The break statement. % \begin{macrocode} \cs_new_eq:NN \prop_map_break: \use_none_delimit_by_q_stop:w % \end{macrocode} % \end{macro} % % \begin{macrocode} % % \end{macrocode} % % Show token usage: % \begin{macrocode} %<*showmemory> %\showMemUsage % % \end{macrocode} % % \end{implementation} % \PrintIndex % % \endinput