diff options
author | Karl Berry <karl@freefriends.org> | 2009-11-26 19:24:51 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2009-11-26 19:24:51 +0000 |
commit | 7749142c6b66c1dc668af8960889578eb9a08e0a (patch) | |
tree | 7c72d5f4899829f6bb46d603ae6f1b7fa05213e4 /Master/texmf-dist/source/latex/xpackages | |
parent | 5273fcd7dff0684b0cce66c6baa4b32589909357 (diff) |
xpackages 1750 (25nov09)
git-svn-id: svn://tug.org/texlive/trunk@16178 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/xpackages')
9 files changed, 3861 insertions, 209 deletions
diff --git a/Master/texmf-dist/source/latex/xpackages/xbase/ldcsetup.dtx b/Master/texmf-dist/source/latex/xpackages/xbase/ldcsetup.dtx index 09e37c55cb3..b47930bc217 100644 --- a/Master/texmf-dist/source/latex/xpackages/xbase/ldcsetup.dtx +++ b/Master/texmf-dist/source/latex/xpackages/xbase/ldcsetup.dtx @@ -18,7 +18,7 @@ %% %% The development version of the bundle can be found at %% -%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% http://www.latex-project.org/svnroot/experimental/trunk/ %% %% for those people who are interested. %% @@ -37,7 +37,7 @@ \RequirePackage{expl3} %</driver|package> %\fi -\GetIdInfo$Id: ldcsetup.dtx 1295 2009-05-06 08:32:25Z will $ +\GetIdInfo$Id: ldcsetup.dtx 1628 2009-10-25 09:54:34Z mittelba $ {coding conventions and stuff} %\iffalse %<*driver> @@ -45,7 +45,7 @@ \ProvidesFile{\filename.\filenameext} [\filedate\space v\fileversion\space\filedescription] %\iffalse -\documentclass{ltxdoc} +\documentclass{l3doc} \begin{document} \DocInput{ldcsetup.dtx} \end{document} diff --git a/Master/texmf-dist/source/latex/xpackages/xbase/template-test.tex b/Master/texmf-dist/source/latex/xpackages/xbase/template-test.tex index f8c47c82d59..5684ce7a90f 100644 --- a/Master/texmf-dist/source/latex/xpackages/xbase/template-test.tex +++ b/Master/texmf-dist/source/latex/xpackages/xbase/template-test.tex @@ -17,7 +17,7 @@ %% %% The development version of the bundle can be found at %% -%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% http://www.latex-project.org/svnroot/experimental/trunk/ %% %% for those people who are interested. %% @@ -32,7 +32,7 @@ %% %% ----------------------------------------------------------------------- %% -%% $Id: template-test.tex 251 2004-11-11 19:01:16Z mittelba $ +%% $Id: template-test.tex 1628 2009-10-25 09:54:34Z mittelba $ %% % \fi % diff --git a/Master/texmf-dist/source/latex/xpackages/xbase/template.dtx b/Master/texmf-dist/source/latex/xpackages/xbase/template.dtx index 8b38f6d216c..376b4929933 100644 --- a/Master/texmf-dist/source/latex/xpackages/xbase/template.dtx +++ b/Master/texmf-dist/source/latex/xpackages/xbase/template.dtx @@ -18,7 +18,7 @@ %% %% The development version of the bundle can be found at %% -%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% http://www.latex-project.org/svnroot/experimental/trunk/ %% %% for those people who are interested. %% @@ -37,7 +37,7 @@ \RequirePackage{expl3} %</driver|package> %\fi -\GetIdInfo$Id: template.dtx 1461 2009-08-15 08:38:12Z joseph $ +\GetIdInfo$Id: template.dtx 1670 2009-11-01 22:34:54Z will $ {template} %\iffalse %<*driver> @@ -45,7 +45,7 @@ \ProvidesFile{\filename.\filenameext} [\filedate\space v\fileversion\space\filedescription] %\iffalse -\documentclass{ltxdoc} +\documentclass{l3doc} \makeatletter \newenvironment{decl}[1][]% {\par\small\addvspace{4.5ex plus 1ex}% @@ -1149,7 +1149,7 @@ % |#2| template type/template name\\ % |#3| key value assignments for parameters of |#2| % \begin{macrocode} -\cs_new_nopar:Nn \TP_declare_instance:Nnn { +\cs_new_nopar:Npn \TP_declare_instance:Nnn #1#2#3 { \group_begin: \TP_instdecl_generate_assignments:nn {#2}{#3} \cs_gset_nopar:Npx #1 { @@ -1262,7 +1262,7 @@ % |{type}| returns prefix for csnames for template type, % based on current collection. % \begin{macrocode} -\cs_new_nopar:Nn \TP_get_csname_prefix:n { +\cs_new_nopar:Npn \TP_get_csname_prefix:n #1 { <\exp_after:wN\exp_after:wN\exp_after:wN \use_i:nn \cs:w TP@<#1>\cs_end:>#1/ @@ -1274,7 +1274,7 @@ % \begin{macro}{\TP_get_arg_count:n} % |{type}| returns arg count for the template type. % \begin{macrocode} -\cs_new_nopar:Nn \TP_get_arg_count:n { +\cs_new_nopar:Npn \TP_get_arg_count:n #1 { \exp_after:wN\exp_after:wN\exp_after:wN \use_ii:nn \cs:w TP@<#1>\cs_end: @@ -1357,7 +1357,7 @@ % to look at the first token of the value, to see what sort of key % it is, so call a helper function to split that off. % \begin{macrocode} -\cs_new_nopar:Nn \TP_templdecl_process_KV:nn {% +\cs_new_nopar:Npn \TP_templdecl_process_KV:nn #1#2 {% \cs_set_eq:NN \TP_templdecl_add_global_or_nothing: \prg_do_nothing: \bool_set_false:N\l_TP_global_assignment_bool \tl_set:Nn\l_TP_currkey_tl{#1} @@ -1370,7 +1370,7 @@ % \begin{macro}{\TP_templdecl_parse_KV:N} % Case switch on the possible key types. % \begin{macrocode} -\cs_new_nopar:Nn \TP_templdecl_parse_KV:N { +\cs_new_nopar:Npn \TP_templdecl_parse_KV:N #1 { % \end{macrocode} % In |#1| we have key, in |#2| the first character after the equal % sign and in |#3| the remainder of the line. We now have to parse diff --git a/Master/texmf-dist/source/latex/xpackages/xbase/tprestrict-test.tex b/Master/texmf-dist/source/latex/xpackages/xbase/tprestrict-test.tex index a787694abff..d981888d450 100644 --- a/Master/texmf-dist/source/latex/xpackages/xbase/tprestrict-test.tex +++ b/Master/texmf-dist/source/latex/xpackages/xbase/tprestrict-test.tex @@ -17,7 +17,7 @@ %% %% The development version of the bundle can be found at %% -%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% http://www.latex-project.org/svnroot/experimental/trunk/ %% %% for those people who are interested. %% @@ -32,7 +32,7 @@ %% %% ----------------------------------------------------------------------- %% -%% $Id: tprestrict-test.tex 251 2004-11-11 19:01:16Z mittelba $ +%% $Id: tprestrict-test.tex 1628 2009-10-25 09:54:34Z mittelba $ %% % \fi % diff --git a/Master/texmf-dist/source/latex/xpackages/xbase/xbase.ins b/Master/texmf-dist/source/latex/xpackages/xbase/xbase.ins index 742a1aa8dc3..aef2755ba99 100644 --- a/Master/texmf-dist/source/latex/xpackages/xbase/xbase.ins +++ b/Master/texmf-dist/source/latex/xpackages/xbase/xbase.ins @@ -4,10 +4,10 @@ %% driver files from the dtx files in this package when run through %% LaTeX or TeX. %% -%% (C) Copyright 2000-2005 LaTeX3 Project +%% (C) Copyright 2000-2009 LaTeX3 Project %% %% It may be distributed and/or modified under the conditions of the -%% LaTeX Project Public License (LPPL), either version 1.3a of this +%% 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 %% @@ -22,7 +22,7 @@ %% %% The development version of the bundle can be found at %% -%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% http://www.latex-project.org/svnroot/experimental/trunk/ %% %% for those people who are interested. %% @@ -37,7 +37,7 @@ %% %% ----------------------------------------------------------------------- %% -%% $Id: xbase.ins 302 2005-03-01 22:49:14Z morten $ +%% $Id: xbase.ins 1650 2009-10-30 22:34:24Z joseph $ %% % \fi % @@ -67,6 +67,7 @@ You may however distribute the bundle without such generated files. \generate{% \file{ldcsetup.sty}{\from{ldcsetup.dtx}{package}} \file{template.sty}{\from{template.dtx}{package,trace}} + \file{xtemplate.sty}{\from{xtemplate.dtx}{package}} \file{xparse.sty}{\from{xparse.dtx}{package}} } diff --git a/Master/texmf-dist/source/latex/xpackages/xbase/xparse-test.tex b/Master/texmf-dist/source/latex/xpackages/xbase/xparse-test.tex index 9e681adf520..8614c4ed06a 100644 --- a/Master/texmf-dist/source/latex/xpackages/xbase/xparse-test.tex +++ b/Master/texmf-dist/source/latex/xpackages/xbase/xparse-test.tex @@ -17,7 +17,7 @@ %% %% The development version of the bundle can be found at %% -%% http://www.latex-project.org/cgi-bin/cvsweb.cgi/ +%% http://www.latex-project.org/svnroot/experimental/trunk/ %% %% for those people who are interested. %% @@ -32,7 +32,7 @@ %% %% ----------------------------------------------------------------------- %% -%% $Id: xparse-test.tex 1487 2009-08-22 15:55:24Z joseph $ +%% $Id: xparse-test.tex 1628 2009-10-25 09:54:34Z mittelba $ %% % \fi % diff --git a/Master/texmf-dist/source/latex/xpackages/xbase/xparse.dtx b/Master/texmf-dist/source/latex/xpackages/xbase/xparse.dtx index c227c4612f3..49f83b1efbf 100644 --- a/Master/texmf-dist/source/latex/xpackages/xbase/xparse.dtx +++ b/Master/texmf-dist/source/latex/xpackages/xbase/xparse.dtx @@ -41,7 +41,7 @@ \RequirePackage{l3names} %</driver|package> %\fi -\GetIdInfo$Id: xparse.dtx 1497 2009-08-31 19:17:53Z joseph $ +\GetIdInfo$Id: xparse.dtx 1727 2009-11-06 22:58:32Z joseph $ {Generic document command parser} %\iffalse %<*driver> @@ -89,7 +89,7 @@ % \item \cs{RenewDocumentEnvironment} % \item \cs{ProvideDocumentEnvironment} % \item \cs{IfNoValue(TF)} (the need for \cs{IfValue(TF)} is currently -% an item of active discussion) +% an item of active discussion)x % \item \cs{IfBoolean(TF)} %\end{itemize} % with the other functions currently regarded as `experimental'. Please @@ -99,14 +99,14 @@ %\subsection{Specifying arguments} % % Before introducing the functions used to create document commands, -% the method for specifiying arguments with \pkg{xparse} will be +% the method for specifying arguments with \pkg{xparse} will be % illustrated. In order to allow each argument to be defined % independently, \pkg{xparse} does not simply need to know the % number of arguments for a function, but also the nature of each % one. This is done by constructing an \emph{argument specification}, % which defines the number of arguments, the type of each argument % and any additional information needed for \pkg{xparse} to read the -% user input and properly pass it thorugh to internal functions. +% user input and properly pass it through to internal functions. % % The basic form of the argument specifier is a list of letters, where % each letter defines a type of argument. As will be described below, @@ -141,7 +141,7 @@ % \item[D] As for \texttt{d}, but returns \meta{default} if no % value is given: \texttt{D}\meta{token1}\meta{token2}\marg{default}. % Internally, the \texttt{o}, \texttt{d} and \texttt{O} types are -% shortcuts to an appropriated-constructed \texttt{D} type argument. +% short-cuts to an appropriated-constructed \texttt{D} type argument. % \item[s] An optional star, which will result in a value % \cs{BooleanTrue} if a star is present and \cs{BooleanFalse} % otherwise (as described later). @@ -149,7 +149,10 @@ % \cs{BooleanTrue} if \meta{token} is present and \cs{BooleanFalse} % otherwise. Given as \texttt{t}\meta{token}. % \item[g] An optional argument given inside a pair of \TeX\ group -% tokens (in standard \LaTeX, |{| \ldots |}|). +% tokens (in standard \LaTeX, |{| \ldots |}|), which returns +% \cs{NoValue} if not present. +% \item[G] As for \texttt{g} but returns \meta{default} if no value +% is given: \texttt{G}\marg{default}. %\end{itemize} % % Using these specifiers, it is possible to create complex input syntax @@ -305,9 +308,9 @@ % will use a different internal function if the optional argument % is given than if it is not present. % -% As the \cs{IfNoValue} tests are expandable, it is possible to test -% these values later, for example at the point of typesetting or in -% an expansion context. +% As the \cs{IfNoValue(TF)} tests are expandable, it is possible to +% test these values later, for example at the point of typesetting or +% in an expansion context. %\end{function} % %\begin{function}{\IfValue / (TF) (EXP)} @@ -316,7 +319,7 @@ % \end{syntax} % The reverse form of the \cs{IfNoValue(TF)} tests are also available % as \cs{IfValue(TF)}. The context will determine which logical -% form makes the most sense for a given code senario. +% form makes the most sense for a given code scenario. %\end{function} % %\begin{variable}{ @@ -368,15 +371,20 @@ % followed by \cs{ProcessorB} to the tokens grabbed by the \texttt{m} % argument. % -%\begin{variable}{\l_xparse_arg_toks} +%\begin{variable}{\ProcessedArgument} % \pkg{xparse} defines a very small set of processor functions. In the % main, it is anticipated that code writers will want to create their % own processors. These need to accept one argument, which is the % tokens as grabbed (or as returned by a previous processor function). -% Processor functions should return the processed argument in the -% variable \cs{l_xparse_arg_toks}. This will always be empty when the -% processor function is called by \pkg{xparse}, even if more than one -% argument processor is applied. +% Processor functions should return the processed argument as the +% variable \cs{ProcessedArgument}. This is initialised as a toks before +% each processor is called, but may also be set equal to any other +% variable type: +% \begin{verbatim} +% \toks_set:Nn \ProcessedArgument { <content> } +% \toks_set:NV \ProcessedArgument \LocalVariable +% \cs_set_eq:NN \ProcessedArgument \LocalVariable +% \end{verbatim} %\end{variable} % %\begin{function}{\xparse_process_to_str:n} @@ -430,7 +438,7 @@ %\subsection{Separating interface and implementation} % % One \emph{experimental} idea implemented in \pkg{xparse} is to -% separate out document command intefaces (the argument specification) +% separate out document command interfaces (the argument specification) % from the implementation (code). This is carried out using a % pair of functions, \cs{DeclareDocumentCommandInterface} and % \cs{DeclareDocumentCommandImplementation} @@ -438,10 +446,10 @@ %\begin{function}{\DeclareDocumentCommandInterface} % \begin{syntax} % "\DeclareDocumentCommandInterface" <function> -% ~~~~\Arg{implementation} \Arg{arg.~spec} +% ~~~~\Arg{implementation} \Arg{arg spec} % \end{syntax} % This declares a <function>, which will take arguments as detailed -% in the <arg.~spec>. When executed, the <function> will look for +% in the <arg spec>. When executed, the <function> will look for % code stored as an <implementation>. %\end{function} % @@ -493,7 +501,7 @@ % \texttt{G} are not available. % \item It is not possible to differentiate between, for example % |\foo[| and |\foo{[}|: in both cases the \texttt{[} will be -% interpretted as the start of an optional argument. As a result +% interpreted as the start of an optional argument. As a result % result, checking for optional arguments is less robust than % in the standard version. % \end{itemize} @@ -510,6 +518,12 @@ % and not be be altered later! %\end{variable} % +%\begin{variable}{\l_xparse_arg_toks} +% Token register used as internal representation of +% \cs{ProcessedArgument}. Unlike the later, this register should not +% be used directly when creating new processors. +%\end{variable} +% %\begin{variable}{\l_xparse_args_toks} % Token register for arguments as they are picked up for passing on to % user functions. @@ -520,6 +534,12 @@ % the beginning. %\end{variable} % +%\begin{variable}{\l_xparse_environment_bool} +% When creating functions, a short cut can be taken if all of the +% arguments are of \texttt{m} type. The code for environments cannot +% do that, and so a flag is needed. +%\end{variable} +% %\begin{variable}{\l_xparse_error_bool} % For flagging up errors when making expandable commands. %\end{variable} @@ -548,7 +568,7 @@ % %\begin{variable}{\l_xparse_m_only_bool} % Flag used to indicate that all arguments are of type \texttt{m}, -% with no no modificiations. +% with no no modifications. %\end{variable} % %\begin{variable}{\l_xparse_mandatory_args_int} @@ -558,6 +578,15 @@ % be zero for any trailing optional arguments. %\end{variable} % +%\begin{variable}{ +% \l_xparse_nested_int | +% \l_xparse_nested_toks +%} +% Nested optional (delimited) arguments have to be handled by hand: +% \TeX\ will not count up the token-matching. So an integer is needed +% to count tokens, and a token register to build up the argument. +%\end{variable} +% %\begin{variable}{\l_xparse_processor_bool} % When converting an argument specification into a signature there is % a need to know if there are any argument processors set up. This is @@ -573,8 +602,8 @@ %\end{variable} % %\begin{variable}{\l_xparse_signature_toks} -% For constucting the signature of the function defined. As -% \pkg{xparse} works thorugh an argument specification, grabber +% For constructing the signature of the function defined. As +% \pkg{xparse} works through an argument specification, grabber % functions are added to this toks for each argument. %\end{variable} % @@ -585,7 +614,7 @@ % %\begin{variable}{\l_xparse_total_args_int} % Used to enumerate the total number of arguments (i.e., the number of -% ingroup letters in the argument specification). +% letters in the argument specification). %\end{variable} % %\begin{variable}{\q_xparse_stop} @@ -594,7 +623,10 @@ % %\subsection{Internal functions} % -%\begin{function}{\xparse_add_arg:n} +%\begin{function}{ +% \xparse_add_arg:n | +% \xparse_add_arg:V +%} % \begin{syntax} % "\xparse_add_arg:n" <grabbed arg> % \end{syntax} @@ -653,7 +685,7 @@ % Used to count how many mandatory arguments an argument specification % contains. The \texttt{n} function carries out the set up, before % handing of to the \texttt{N} function. This reads one token, and -% calls the approriate counter function. +% calls the appropriate counter function. %\end{function} % %\begin{function}{ @@ -676,10 +708,7 @@ % mandatory arguments do any more than call the loop again. %\end{function} % -%\begin{function}{ -% \xparse_declare_cmd:Nnn| -% \xparse_declare_cmd:cnn -%} +%\begin{function}{\xparse_declare_cmd:Nnn} % \begin{syntax} % "\xparse_declare_cmd:Nnn" <function> \Arg{signature} % ~~~~\Arg{code} @@ -722,7 +751,7 @@ % ~~~~\Arg{start code} \Arg{end code} % \end{syntax} % Declares <env> as an environment taking <arg spec> arguments -% at \cs{begin}\{<env>\}. The <start code> is eceutre at the beginning +% at \cs{begin}\{<env>\}. The <start code> is executed at the beginning % of the environment, and the <end code> at the end. Both parts may % use the arguments defined by <arg spec>. % \begin{texnote} @@ -780,7 +809,7 @@ % Argument grabbing functions, which re-arrange other <arg data> % so that the argument is read correctly. The \texttt{trailing} % versions do not skip spaces when searching for optional arguments. -% For each argument type, the various versions feed the approriate +% For each argument type, the various versions feed the appropriate % information to a common auxiliary function which then sets up % \cs{xparse_grab_arg:w} to actually carry out the argument absorption. %\end{function} @@ -922,6 +951,16 @@ % \end{macrocode} %\end{macro} % +%\begin{macro}{\l_xparse_environment_bool} +% Generating environments uses the same mechanism as generating +% functions. However, full processing of arguments is always needed +% for environments, and so the function-generating code needs to +% know this. +% \begin{macrocode} +\bool_new:N \l_xparse_environment_bool +% \end{macrocode} +%\end{macro} +% %\begin{macro}{\l_xparse_error_bool} % Used to signal an error when creating expandable functions. % \begin{macrocode} @@ -976,6 +1015,18 @@ % \end{macrocode} %\end{macro} % +%\begin{macro}{\l_xparse_nested_int} +%\begin{macro}{\l_xparse_nested_toks} +% To deal with nested delimited arguments, the code needs to do some +% token counting `by hand'. That requires an integer, and also a token +% register to store the growing argument collected. +% \begin{macrocode} +\int_new:N \l_xparse_nested_int +\toks_new:N \l_xparse_nested_toks +% \end{macrocode} +%\end{macro} +%\end{macro} +% %\begin{macro}{\l_xparse_processor_bool} % When reading through the argument specifier, a flag is needed to % show that a processor has been found for the current argument. This @@ -1035,7 +1086,7 @@ % This is used to determine whether to skip spaces or not where % searching for the argument. % \begin{macrocode} -\cs_new_nopar:Nn \xparse_add_grabber_mandatory:N { +\cs_new_nopar:Npn \xparse_add_grabber_mandatory:N #1 { \toks_put_right:Nx \l_xparse_signature_toks { \exp_not:c { xparse_grab_ #1 \bool_if:NT \l_xparse_long_bool { _long } :w @@ -1044,7 +1095,7 @@ \bool_set_false:N \l_xparse_long_bool \int_decr:N \l_xparse_mandatory_args_int } -\cs_new_nopar:Nn \xparse_add_grabber_optional:N { +\cs_new_nopar:Npn \xparse_add_grabber_optional:N #1 { \toks_put_right:Nx \l_xparse_signature_toks { \exp_not:c { xparse_grab_ #1 @@ -1070,7 +1121,7 @@ % %\begin{macro}{\xparse_add_type_+:w} % Making the next argument \cs{long} means setting the flag and -% knocking one back off the totatl argument count. The \texttt{m} +% knocking one back off the total argument count. The \texttt{m} % arguments are recorded here as this has to be done for every case % where there is then a \cs{long} argument. % \begin{macrocode} @@ -1087,7 +1138,7 @@ %\begin{macro}{\xparse_add_type_>:w} % When a processor is found, the function \cs{xparse_process_arg:n} % is added to the signature along with the processor code itself. When -% the signature is used, the code will be added to an excution list by +% the signature is used, the code will be added to an execution list by % \cs{xparse_process_arg:n}. Here, the loop calls % \cs{xparse_prepare_signature_aux:N} rather than % \cs{xparse_prepare_signature:N} so that the flag is not reset. @@ -1109,7 +1160,7 @@ % the same grabber as is used by \texttt{D}, by putting the % \cs{NoValue} default in the correct place. So there is some % simple argument re-arrangement to do. Remember that |#1| and |#2| -% shoudl be single tokens. +% should be single tokens. % \begin{macrocode} \cs_new:Npn \xparse_add_type_d:w #1#2 { \xparse_add_type_D:w #1 #2 { \NoValue } @@ -1218,9 +1269,9 @@ % This function checks if the argument type actually exists and gives % an error if it doesn't. % \begin{macrocode} -\cs_new_nopar:Nn \xparse_check_and_add:N { +\cs_new_nopar:Npn \xparse_check_and_add:N #1 { \cs_if_free:cTF { xparse_add_type_ #1 :w } { - \msg_error:nnx { xparse } { unknown-argument-type } {#1} + \msg_kernel_error:nnx { xparse } { unknown-argument-type } {#1} \xparse_add_type_m:w }{ \use:c { xparse_add_type_ #1 :w } @@ -1234,16 +1285,16 @@ %\begin{macro}[aux]{\xparse_count_mandatory_aux:N} % To count up mandatory arguments before the main parsing run, the % same approach is used. First, check if the current token is a -% shrot-cut for another argument type. If it is, expand it and loop +% short-cut for another argument type. If it is, expand it and loop % again. If not, then look for a `counting' function to check the % argument type. No error is raised here if one is not found as one % will be raised by later code. % \begin{macrocode} -\cs_new:Nn \xparse_count_mandatory:n { +\cs_new:Npn \xparse_count_mandatory:n #1 { \int_zero:N \l_xparse_mandatory_args_int \xparse_count_mandatory:N #1 \q_nil } -\cs_new:Nn \xparse_count_mandatory:N { +\cs_new:Npn \xparse_count_mandatory:N #1 { \quark_if_nil:NF #1 { \prop_if_in:NnTF \c_xparse_shorthands_prop {#1} { \prop_get:NnN \c_xparse_shorthands_prop {#1} \l_xparse_tmp_tl @@ -1253,7 +1304,7 @@ } } } -\cs_new:Nn \xparse_count_mandatory_aux:N { +\cs_new:Npn \xparse_count_mandatory_aux:N #1 { \cs_if_free:cTF { xparse_count_type_ #1 :w } { \xparse_count_type_m:w }{ @@ -1327,7 +1378,8 @@ %\end{macro} % %\begin{macro}{\xparse_declare_cmd:Nnn} -%\begin{macro}{\xparse_declare_cmd:cnn} +%\begin{macro}[aux]{\xparse_declare_cmd_aux:Nnn} +%\begin{macro}[aux]{\xparse_declare_cmd_aux:cnn} %\begin{macro}[aux]{\xparse_declare_cmd_all_m:Nn} %\begin{macro}[aux]{\xparse_declare_cmd_mixed:Nn} % First, the signature is set up from the argument specification. There @@ -1337,7 +1389,19 @@ % internal function actually contains the code with the user function % as a simple wrapper. % \begin{macrocode} -\cs_new:Nn \xparse_declare_cmd:Nnn { +\cs_new:Npn \xparse_declare_cmd:Nnn #1#2 { + \cs_if_exist:NTF #1 + { + \msg_kernel_warning:nnxx { xparse } { redefine-command } + { \exp_not:N #1 } { \exp_not:n {#2} } + } + { + \msg_kernel_info:nnxx { xparse } { define-command } + { \exp_not:N #1 } { \exp_not:n {#2} } + } + \xparse_declare_cmd_aux:Nnn #1 {#2} +} +\cs_new:Npn \xparse_declare_cmd_aux:Nnn #1#2#3 { \xparse_count_mandatory:n {#2} \xparse_prepare_signature:n {#2} \bool_if:NTF \l_xparse_m_only_bool { @@ -1346,12 +1410,12 @@ \xparse_declare_cmd_mixed:Nn #1 {#3} } } -\cs_generate_variant:Nn \xparse_declare_cmd:Nnn { cnn } -\cs_new:Nn \xparse_declare_cmd_all_m:Nn { +\cs_generate_variant:Nn \xparse_declare_cmd_aux:Nnn { cnn } +\cs_new:Npn \xparse_declare_cmd_all_m:Nn #1#2 { \cs_generate_from_arg_count:NNnn #1 \cs_set_protected_nopar:Npn \l_xparse_total_args_int {#2} } -\cs_new:Nn \xparse_declare_cmd_mixed:Nn { +\cs_new:Npn \xparse_declare_cmd_mixed:Nn #1#2 { \cs_set_protected_nopar:Npx #1 { \exp_not:n { \int_zero:N \l_xparse_processor_int @@ -1368,13 +1432,14 @@ %\end{macro} %\end{macro} %\end{macro} +%\end{macro} % %\begin{macro}{\xparse_declare_cmd_implementation:nNn} -% Creating a stand-alone implementation uisn the `two-part' mechanism +% Creating a stand-alone implementation using the `two-part' mechanism % is quite easy as this is just a wrapper for % \cs{cs_generate_from_arg_count:cNnn}. % \begin{macrocode} -\cs_new:Nn \xparse_declare_cmd_implementation:nNn { +\cs_new:Npn \xparse_declare_cmd_implementation:nNn #1#2#3 { \cs_generate_from_arg_count:cNnn { implementation_ #1 :w } \cs_set:Npn {#2} {#3} } @@ -1391,7 +1456,7 @@ % is created. As before, there is a short-cut for functions which only % have \texttt{m} type arguments. % \begin{macrocode} -\cs_new:Nn \xparse_declare_cmd_interface:Nnn { +\cs_new:Npn \xparse_declare_cmd_interface:Nnn #1#2#3 { \xparse_prepare_signature:n {#3} \bool_if:NTF \l_xparse_m_only_bool { \xparse_declare_cmd_interface_all_m:Nn #1 {#2} @@ -1401,12 +1466,12 @@ \cs_generate_from_arg_count:cNnn { implementation_ #2 :w } \cs_set:Npn \l_xparse_total_args_int { ``#2'' } } -\cs_new:Nn \xparse_declare_cmd_interface_all_m:Nn { +\cs_new:Npn \xparse_declare_cmd_interface_all_m:Nn #1#2 { \cs_generate_from_arg_count:NNnn #1 \cs_set_protected_nopar:Npn \l_xparse_total_args_int { \use:c { implementation_ #2 :w } } } -\cs_new:Nn \xparse_declare_cmd_interface_mixed:Nn { +\cs_new:Npn \xparse_declare_cmd_interface_mixed:Nn #1#2 { \cs_set_protected_nopar:Npx #1 { \exp_not:n { \int_zero:N \l_xparse_processor_int @@ -1428,20 +1493,38 @@ % The idea here is to make sure that the end of the environment has the % same arguments available as the beginning. % \begin{macrocode} -\cs_new:Nn \xparse_declare_env:nnnn { - \xparse_declare_cmd:cnn { environment_begin_ #1 :w } {#2} { +\cs_new:Npn \xparse_declare_env:nnnn #1#2#3#4 { + \bool_set_true:N \l_xparse_environment_bool +%</initex|package> +%<*initex> + \cs_if_exist:cTF { environment_begin_ #1 :w } +%</initex> +%<*package> + \cs_if_exist:cTF {#1} +%</package> +%<*initex|package> + { + \msg_kernel_warning:nnxx { xparse } { redefine-environment } + {#1} { \exp_not:n {#2} } + } + { + \msg_kernel_info:nnxx { xparse } { define-environment } + {#1} { \exp_not:n {#2} } + } + \xparse_declare_cmd_aux:cnn { environment_begin_ #1 :w } {#2} { \group_begin: \toks_set_eq:NN \l_xparse_environment_args_toks \l_xparse_args_toks #3 } + \bool_set_false:N \l_xparse_environment_bool \cs_set_nopar:cpx { environment_end_ #1 :w } { \exp_not:N \exp_last_unbraced:NV \exp_not:c { environment_end_ #1 _aux:N } \exp_not:N \l_xparse_environment_args_toks \exp_not:N \group_end: } - \cs_set_nopar:cx { environment_end_ #1 _aux:N } { + \cs_set_nopar:cpx { environment_end_ #1 _aux:N } ##1 { \exp_not:c { environment_end_ #1 _aux :w } } \cs_generate_from_arg_count:cNnn @@ -1464,7 +1547,7 @@ % be switched here. The total number of mandatory arguments added to % the signature is also decreased by the appropriate amount. % \begin{macrocode} -\cs_new_nopar:Nn \xparse_flush_m_args: { +\cs_new_nopar:Npn \xparse_flush_m_args: { \cs_if_exist:cT { xparse_grab_m_ \int_use:N \l_xparse_m_args_int :w } { @@ -1501,10 +1584,14 @@ % also kept of the total number of arguments. This function sets % everything up then hands off to the parser. % \begin{macrocode} -\cs_new:Nn \xparse_prepare_signature:n { +\cs_new:Npn \xparse_prepare_signature:n #1 { \bool_set_false:N \l_xparse_long_bool \int_zero:N \l_xparse_m_args_int - \bool_set_true:N \l_xparse_m_only_bool + \bool_if:NTF \l_xparse_environment_bool { + \bool_set_false:N \l_xparse_m_only_bool + }{ + \bool_set_true:N \l_xparse_m_only_bool + } \bool_set_false:N \l_xparse_processor_bool \toks_clear:N \l_xparse_signature_toks \int_zero:N \l_xparse_total_args_int @@ -1520,11 +1607,11 @@ % point to watch what is next on the stack so that the loop continues % correctly. % \begin{macrocode} -\cs_new:Nn \xparse_prepare_signature:N { +\cs_new:Npn \xparse_prepare_signature:N #1 { \bool_set_false:N \l_xparse_processor_bool \xparse_prepare_signature_aux:N #1 } -\cs_new:Nn \xparse_prepare_signature_aux:N { +\cs_new:Npn \xparse_prepare_signature_aux:N #1 { \quark_if_nil:NTF #1 { \bool_if:NF \l_xparse_m_only_bool { \xparse_flush_m_args: @@ -1534,7 +1621,7 @@ \prop_get:NnN \c_xparse_shorthands_prop {#1} \l_xparse_tmp_tl \exp_last_unbraced:NV \xparse_prepare_signature:N \l_xparse_tmp_tl }{ - \int_incr:N \l_xparse_total_args_int + \int_incr:N \l_xparse_total_args_int \xparse_check_and_add:N #1 } } @@ -1544,13 +1631,13 @@ %\end{macro} % %\begin{macro}{\xparse_process_arg:n} -% Processors are saved for use later during the grabbbing process. +% Processors are saved for use later during the grabbing process. % \begin{macrocode} -\cs_new:Nn \xparse_process_arg:n { +\cs_new:Npn \xparse_process_arg:n #1 { \int_incr:N \l_xparse_processor_int - \cs_set:cn { + \cs_set:cpn { xparse_processor_ \int_use:N \l_xparse_processor_int :n - } + } ##1 { #1 {##1} } } % \end{macrocode} @@ -1559,17 +1646,18 @@ %\subsection{Grabbing arguments} % %\begin{macro}{\xparse_add_arg:n} +%\begin{macro}{\xparse_add_arg:V} %\begin{macro}[aux]{\xparse_add_arg_aux:n} %\begin{macro}[aux]{\xparse_add_arg_aux:V} % The argument-storing system provides a single point for interfacing -% with processors. They are done in a loop, couning downward. In this +% with processors. They are done in a loop, counting downward. In this % way, the processor which was found last is executed first. The result % is that processors apply from right to left, as intended. Notice that % a set of braces are added back around the result of processing so that % the internal function will correctly pick up one argument for each % input argument. % \begin{macrocode} -\cs_new:Nn \xparse_add_arg:n { +\cs_new:Npn \xparse_add_arg:n #1 { \intexpr_compare:nTF { \l_xparse_processor_int = \c_zero } { \toks_put_right:Nn \l_xparse_args_toks { {#1} } }{ @@ -1581,16 +1669,18 @@ } } } -\cs_new:Nn \xparse_add_arg_aux:n { +\cs_generate_variant:Nn \xparse_add_arg:n { V } +\cs_new:Npn \xparse_add_arg_aux:n #1 { + \cs_set_eq:NN \ProcessedArgument \l_xparse_arg_toks \use:c { xparse_processor_ \int_use:N \l_xparse_processor_int :n } {#1} \int_decr:N \l_xparse_processor_int \intexpr_compare:nTF { \l_xparse_processor_int = \c_zero } { - \toks_put_right:No \l_xparse_args_toks { - \exp_after:wN { \toks_use:N \l_xparse_arg_toks } + \toks_put_right:Nx \l_xparse_args_toks { + { \exp_not:V \ProcessedArgument } } }{ - \xparse_add_arg_aux:V \l_xparse_arg_toks + \xparse_add_arg_aux:V \ProcessedArgument } } \cs_generate_variant:Nn \xparse_add_arg_aux:n { V } @@ -1598,30 +1688,37 @@ %\end{macro} %\end{macro} %\end{macro} +%\end{macro} % -% All of the grabbers follow the same basic pattern. The intial function -% sets u the appropriate information to define \cs{parse_grab_arg:w} to -% grab the argument. This means determining whether to use -% \cs{cs_set:Npn} or \cs{cs_set_nopar:Npn}, and for optional arguments -% whether to skip spaces. In all cases, \cs{xparse_grab_arg:w} is then -% called to actually do the grabbing. +% All of the grabbers follow the same basic pattern. The initial +% function sets up the appropriate information to define +% \cs{parse_grab_arg:w} to grab the argument. This means determining +% whether to use \cs{cs_set:Npn} or \cs{cs_set_nopar:Npn}, and for +% optional arguments whether to skip spaces. In all cases, +% \cs{xparse_grab_arg:w} is then called to actually do the grabbing. % %\begin{macro}{\xparse_grab_arg:w} +%\begin{macro}[aux]{\xparse_grab_arg_aux_i:w} +%\begin{macro}[aux]{\xparse_grab_arg_aux_ii:w} % Each time an argument is actually grabbed, \pkg{xparse} defines a % function to do it. In that way, long arguments from previous functions % can be included in the definition of the grabber function, so that % it does not raise an error if not long. The generic function used -% for this is reserved here. +% for this is reserved here. A couple of auxiliary functions are also +% needed in various places. % \begin{macrocode} -\cs_new:Npn \xparse_grab_aux:w { } +\cs_new:Npn \xparse_grab_arg:w { } +\cs_new:Npn \xparse_grab_arg_aux_i:w { } +\cs_new:Npn \xparse_grab_arg_aux_ii:w { } % \end{macrocode} %\end{macro} +%\end{macro} +%\end{macro} % %\begin{macro}{\xparse_grab_D:w} %\begin{macro}{\xparse_grab_D_long:w} %\begin{macro}{\xparse_grab_D_trailing:w} %\begin{macro}{\xparse_grab_D_long_trailing:w} -%\begin{macro}[aux]{\xparse_grab_D_aux:NNnnNn} % The generic delimited argument grabber. The auxiliary function does % a peek test before calling \cs{xparse_grab_arg:w}, so that the % optional nature of the argument works as expected. @@ -1641,10 +1738,42 @@ \l_xparse_args_toks { \xparse_grab_D_aux:NNnnNn #1 #2 {#3} {#4} \cs_set:Npn { } } -\cs_set:Nn \xparse_grab_D_aux:NNnnNn { - #5 \xparse_grab_arg:w #1 ##1 #2 { - \xparse_add_arg:n {##1} - #4 \l_xparse_args_toks +% \end{macrocode} +%\begin{macro}[aux]{\xparse_grab_D_aux:NNnnNn} +% This is a bit complicated. The idea is that, in order to check for +% nested optional argument tokens (\texttt{[[...]]} and so on) the +% argument needs to be grabbed without removing any braces at all. If +% this is not done, then cases like |[{[}]| fail. So after testing for +% an optional argument, it is collected piece-wise. First, the opening +% token is removed, then a check is made for a group. If it looks like +% the entire argument is a group, then an extra set of braces are +% added back in. The closing token is then used to collect everything +% else. There is then a test to see if there is nesting, by looking +% for a `spare' open-argument token. If that is found, things hand off +% to a loop to deal with that. +% \begin{macrocode} +\cs_new:Npn \xparse_grab_D_aux:NNnnNn #1#2#3#4#5#6 { + #5 \xparse_grab_arg:w #1 { + \peek_meaning:NTF \c_group_begin_token { + \xparse_grab_arg_aux_i:w + }{ + \xparse_grab_arg_aux_ii:w + } + } + #5 \xparse_grab_arg_aux_i:w ##1 { + \peek_charcode:NTF #2 { + \xparse_grab_arg_aux_ii:w { {##1} } + }{ + \xparse_grab_arg_aux_ii:w {##1} + } + } + #5 \xparse_grab_arg_aux_ii:w ##1 #2 { + \tl_if_in:nnTF {##1} {#1} { + \xparse_grab_D_nested:NNnNn #1 #2 {#4} #5 {##1} + }{ + \xparse_add_arg:n {##1} + #4 \l_xparse_args_toks + } } \use:c { peek_charcode #6 :NTF } #1 { \xparse_grab_arg:w @@ -1659,13 +1788,47 @@ %\end{macro} %\end{macro} %\end{macro} +%\begin{macro}[aux]{\xparse_grab_D_nested:NNnNn} +%\begin{macro}[aux]{\xparse_grab_D_nested_aux:n} +% Catching nested optional arguments means more work. As \TeX\ does not +% help here, the brackets have to be counted by hand. The code then +% keeps looking for closing tokens until all of the opening ones +% are matched. +% \begin{macrocode} +\cs_new:Npn \xparse_grab_D_nested:NNnNn #1#2#3#4#5 { + \int_zero:N \l_xparse_nested_int + \toks_set:Nn \l_xparse_nested_toks { #5 #2 } + \cs_set:Npn \xparse_grab_D_nested_aux:n ##1 { + \tl_if_eq:nnT {#1} {##1} { + \int_incr:N \l_xparse_nested_int + } + } + \tl_map_function:nN {#5} \xparse_grab_D_nested_aux:n + #4 \xparse_grab_arg:w ##1 #2 { + \int_decr:N \l_xparse_nested_int + \tl_map_function:nN {##1} \xparse_grab_D_nested_aux:n + \intexpr_compare:nTF { \l_xparse_nested_int = \c_zero } { + \toks_put_right:Nn \l_xparse_nested_toks {##1} + \xparse_add_arg:V \l_xparse_nested_toks + #3 \l_xparse_args_toks + }{ + \toks_put_right:Nn \l_xparse_nested_toks { ##1 #2 } + \xparse_grab_arg:w + } + } + \xparse_grab_arg:w +} +\cs_new:Npn \xparse_grab_D_nested_aux:n #1 { } +% \end{macrocode} +%\end{macro} +%\end{macro} % %\begin{macro}{\xparse_grab_G:w} %\begin{macro}{\xparse_grab_G_long:w} %\begin{macro}{\xparse_grab_G_trailing:w} %\begin{macro}{\xparse_grab_G_long_trailing:w} %\begin{macro}[aux]{\xparse_grab_G_aux:nnNn} -% Optional groups are checed by meaning, so that the same code will +% Optional groups are checked by meaning, so that the same code will % work with, for example, Con\TeX{}t-like input. % \begin{macrocode} \cs_new:Npn \xparse_grab_G:w #1#2 \l_xparse_args_toks { @@ -1680,7 +1843,7 @@ \cs_new:Npn \xparse_grab_G_long_trailing:w #1#2 \l_xparse_args_toks { \xparse_grab_G_aux:nnNn {#1} {#2} \cs_set:Npn { } } -\cs_set:Nn \xparse_grab_G_aux:nnNn { +\cs_set:Npn \xparse_grab_G_aux:nnNn #1#2#3#4 { #3 \xparse_grab_arg:w ##1 { \xparse_add_arg:n {##1} #2 \l_xparse_args_toks @@ -1710,9 +1873,9 @@ \cs_new:Npn \xparse_grab_l_long:w #1 \l_xparse_args_toks { \xparse_grab_l_aux:nN {#1} \cs_set:Npn } -\cs_new:Nn \xparse_grab_l_aux:nN { +\cs_new:Npn \xparse_grab_l_aux:nN #1#2 { #2 \xparse_grab_arg:w ##1## { - \xparse_add_arg:n \l_xparse_args_toks {##1} + \xparse_add_arg:n {##1} #1 \l_xparse_args_toks } \xparse_grab_arg:w @@ -1851,7 +2014,7 @@ \cs_new:Npn \xparse_grab_t_long_trailing:w #1#2 \l_xparse_args_toks { \xparse_grab_t_aux:NnNn #1 {#2} \cs_set:Npn { } } -\cs_new:Nn \xparse_grab_t_aux:NnNn { +\cs_new:Npn \xparse_grab_t_aux:NnNn #1#2#3#4 { #3 \xparse_grab_arg:w { \use:c { peek_charcode_remove #4 :NTF } #1 { \xparse_add_arg:n { \BooleanTrue } @@ -1882,7 +2045,7 @@ \cs_new:Npn \xparse_grab_u_long:w #1#2 \l_xparse_args_toks { \xparse_grab_u_aux:NnN {#1} {#2} \cs_set:Npn } -\cs_new:Nn \xparse_grab_u_aux:NnN { +\cs_new:Npn \xparse_grab_u_aux:NnN #1#2#3 { #3 \xparse_grab_arg:w ##1 #1 { \xparse_add_arg:n {##1} #2 \l_xparse_args_toks @@ -1899,8 +2062,8 @@ %\begin{macro}{\xparse_process_to_str:n} % A basic argument processor: as much an example as anything else. % \begin{macrocode} -\cs_new:Nn \xparse_process_to_str:n { - \toks_set:Nx \l_xparse_arg_toks { +\cs_new:Npn \xparse_process_to_str:n #1 { + \toks_set:Nx \ProcessedArgument { \tl_to_str:n {#1} } } @@ -1911,15 +2074,15 @@ %\begin{macro}[aux]{\xparse_process_comma_split_aux:w} % Turns a co-ordinate pair into two separate values. % \begin{macrocode} -\cs_new:Nn \xparse_process_comma_split:n { +\cs_new:Npn \xparse_process_comma_split:n #1 { \tl_if_in:nnTF {#1} { , } { \xparse_process_comma_split_aux:w #1 \q_stop }{ - \toks_set:Nn \l_xparse_arg_toks { {#1} { \NoValue } } + \toks_set:Nn \ProcessedArgument { {#1} { \NoValue } } } } \cs_new:Npn \xparse_process_comma_split_aux:w #1 , #2 \q_stop { - \toks_set:Nn \l_xparse_arg_toks { {#1} {#2} } + \toks_set:Nn \ProcessedArgument { {#1} {#2} } } % \end{macrocode} %\end{macro} @@ -1946,7 +2109,7 @@ % %\begin{macro}{\xparse_exp_add_type_D:w} % The most complex argument to grab in an expandable manner is the -% general delimited one. First, a shortcut is set up in +% general delimited one. First, a short-cut is set up in % \cs{l_xparse_tmpa_tl} for the name of the current grabber function. % This is then created to grab one argument and test if it is equal % to the opening delimiter. If the test fails, the code adds the default @@ -2075,9 +2238,9 @@ % Virtually identical to the normal version, except calling the % expandable \texttt{add} functions rather than the standard versions. % \begin{macrocode} -\cs_new_nopar:Nn \xparse_exp_check_and_add:N { +\cs_new_nopar:Npn \xparse_exp_check_and_add:N #1 { \cs_if_free:cTF { xparse_exp_add_type_ #1 :w } { - \msg_error:nnx { xparse } { unknown-argument-type } {#1} + \msg_kernel_error:nnx { xparse } { unknown-argument-type } {#1} \tl_set:Nn \l_xparse_last_arg_tl { m } \xparse_exp_add_type_m:w }{ @@ -2093,8 +2256,8 @@ %\begin{macro}[aux]{\xparse_exp_declare_cmd_mixed:Nn} %\begin{macro}[aux]{\xparse_exp_declare_cmd_mixed_aux:Nn} % The overall scheme here is very different from the standard method. -% For each argument, an internal fucntion is created to grab an argument -% and pass along prevous ones. Each `daisy chains' to call the next +% For each argument, an internal function is created to grab an argument +% and pass along previous ones. Each `daisy chains' to call the next % one in the sequence. Thus at the end of the chain, an extra `argument' % function is included to unwind the chain and pass data to the the % internal function containing the actual code. If all of the arguments @@ -2102,7 +2265,16 @@ % version. The \texttt{x} in the lead-off and mop-up functions makes % sure that the braces around the first argument are not lost. % \begin{macrocode} -\cs_new:Nn \xparse_exp_declare_cmd:Nnn { +\cs_new:Npn \xparse_exp_declare_cmd:Nnn #1#2#3 { + \cs_if_exist:NTF #1 + { + \msg_kernel_warning:nnxx { xparse } { redefine-command } + { \exp_not:N #1 } { \exp_not:n {#2} } + } + { + \msg_kernel_info:nnxx { xparse } { define-command } + { \exp_not:N #1 } { \exp_not:n {#2} } + } \tl_set:Nn \l_xparse_function_tl {#1} \xparse_exp_prepare_function:n {#2} \intexpr_compare:nTF { @@ -2113,7 +2285,7 @@ \xparse_exp_declare_cmd_mixed:Nn #1 {#3} } } -\cs_new:Nn \xparse_exp_declare_cmd_all_m:Nn { +\cs_new:Npn \xparse_exp_declare_cmd_all_m:Nn #1#2 { \bool_if:NTF \l_xparse_long_bool { \cs_generate_from_arg_count:NNnn #1 \cs_set:Npn \l_xparse_total_args_int {#2} @@ -2122,14 +2294,14 @@ #1 \cs_set_nopar:Npn \l_xparse_total_args_int {#2} } } -\cs_new:Nn \xparse_exp_declare_cmd_mixed:Nn { +\cs_new:Npn \xparse_exp_declare_cmd_mixed:Nn #1#2 { \exp_args:NnV \tl_if_in:nnTF { l m u } \l_xparse_last_arg_tl { \xparse_exp_declare_cmd_mixed_aux:Nn #1 {#2} }{ - \msg_error:nn { xparse } { expandable-ending-optional } + \msg_kernel_error:nn { xparse } { expandable-ending-optional } } } -\cs_new:Nn \xparse_exp_declare_cmd_mixed_aux:Nn { +\cs_new:Npn \xparse_exp_declare_cmd_mixed_aux:Nn #1#2 { \cs_set_nopar:Npx #1 { \exp_not:c { \token_to_str:N #1 1 } x \exp_not:N \q_xparse_stop } @@ -2153,25 +2325,27 @@ % \texttt{g}, \texttt{l} and \texttt{u} arguments (the later more for % ease than any technical reason). % \begin{macrocode} -\cs_new:Nn \xparse_exp_prepare_function:n { +\cs_new:Npn \xparse_exp_prepare_function:n #1 { \bool_set_false:N \l_xparse_error_bool \tl_if_in:nnT {#1} { > } { - \msg_error:nnx { xparse } { processor-in-expandable } {#1} + \msg_kernel_error:nnx { xparse } { processor-in-expandable } {#1} \bool_set_true:N \l_xparse_error_bool } \tl_if_in:nnT {#1} { g } { - \msg_error:nnx { xparse } { grouped-in-expandable } {#1} + \msg_kernel_error:nnx { xparse } { grouped-in-expandable } + { g } {#1} \bool_set_true:N \l_xparse_error_bool } \tl_if_in:nnT {#1} { G } { - \msg_error:nnx { xparse } { grouped-in-expandable } {#1} + \msg_kernel_error:nnx { xparse } { grouped-in-expandable } + { G } {#1} \bool_set_true:N \l_xparse_error_bool } \bool_if:NF \l_xparse_error_bool { \xparse_exp_prepare_function_aux:n {#1} } } -\cs_new:Nn \xparse_exp_prepare_function_aux:n { +\cs_new:Npn \xparse_exp_prepare_function_aux:n #1 { \cs_set_eq:NN \xparse_prepare_next:w \xparse_exp_prepare_function:N \cs_set_eq:NN \xparse_exp_set:cpx \cs_set_nopar:cpx \bool_set_false:N \l_xparse_long_bool @@ -2190,27 +2364,30 @@ %\begin{macro}{\xparse_exp_prepare_function:N} %\begin{macro}[aux]{\xparse_exp_prepare_function_long:N} %\begin{macro}[aux]{\xparse_exp_prepare_function_short:N} -% Preparing functions is a case of +% Preparing functions is a case of reading the signature, as in the +% normal case. However, everything has to be either short or long, and +% so there is an extra step to make sure that once one \texttt{+} has +% been seen everything has one. That detour then takes us back to +% a standard looping concept. % \begin{macrocode} -\cs_new:Nn \xparse_exp_prepare_function:N { +\cs_new:Npn \xparse_exp_prepare_function:N #1 { \bool_if:NTF \l_xparse_long_bool { \xparse_exp_prepare_function_long:N #1 }{ \xparse_exp_prepare_function_short:N #1 } } -\cs_new:Nn \xparse_exp_prepare_function_long:N { +\cs_new:Npn \xparse_exp_prepare_function_long:N #1 { \quark_if_nil:NF #1 { \tl_if_eq:nnTF {#1} { + } { \xparse_exp_prepare_function_short:N }{ - \msg_error:nn { xparse } { inconsistent-long } + \msg_kernel_error:nn { xparse } { expandable-inconsistent-long } \xparse_exp_prepare_function_short:N #1 } - } } -\cs_new:Nn \xparse_exp_prepare_function_short:N { +\cs_new:Npn \xparse_exp_prepare_function_short:N #1 { \quark_if_nil:NF #1 { \prop_if_in:NnTF \c_xparse_shorthands_prop {#1} { \prop_get:NnN \c_xparse_shorthands_prop {#1} \l_xparse_tmp_tl @@ -2231,7 +2408,7 @@ %\end{macro} % %\begin{macro}{\xparse_exp_set:cpx} -% A shortcut to save constantly re-testing \cs{l_xparse_long_bool}. +% A short-cut to save constantly re-testing \cs{l_xparse_long_bool}. % \begin{macrocode} \cs_new_eq:NN \xparse_exp_set:cpx \cs_set_nopar:cpx % \end{macrocode} @@ -2239,53 +2416,104 @@ % %\subsection{Messages} % -% Some error messages. -% \begin{macrocode} -\msg_new:nnnn { xparse } { command-already-defined } {% - Command name `\token_to_str:N #1' already defined!% -}{% - You have used \token_to_str:N \NewDocumentCommand\\% - with a command that already has a definition.\\% - Perhaps you meant \token_to_str:N \RenewDocumentCommand.% -} -\msg_new:nnnn { xparse } { command-not-yet-defined } {% - Command `\token_to_str:N #1' not yet defined!% -}{% - You have used \token_to_str:N \RenewDocumentCommand\\% - with a command that was never defined.\\% - Perhaps you meant \token_to_str:N \NewDocumentCommand.% -} -\msg_new:nnn { xparse } { environment-already-defined } {% - Environment `#1' already defined!% -} -\msg_new:nnn { xparse } { environment-not-yet-defined } {% - Environment `#1' not yet defined!% -} -\msg_new:nnnn { xparse } { expandable-ending-optional } {% - Expandable command signature ends in optional argument.% -}{% - Expandable functions must have a final mandatory argument.% -} -\msg_new:nnnn { xparse } { grouped-in-expandable } {% - Optional grouped arguments cannot be used with expandable functions.% -}{% - Argument specification `#1' contains an optional grouped argument:\\% - this is only supported for standard robust functions.% -} -\msg_new:nnnn { xparse } { inconsistent-long } {% - Inconsistent long arguments.% -}{% - Expandable commands must have all arguments long if any at all.% -} -\msg_new:nnnn { xparse } { processor-in-expandable } {% - Argument processors cannot be used with expandable functions.% -}{% - Argument specification `#1' contains a processor function:\\% - this is only supported for standard robust functions.% -} -\msg_new:nnn { xparse } { unknown-argument-type } {% - Unknown argument type `#1' replaced by `m'. Fingers crossed ...% -} +% Some messages intended as errors. +% \begin{macrocode} +\msg_kernel_new:nnnn { xparse } { command-already-defined } + {Command `#1' already defined!} + {% + You have used \token_to_str:N \NewDocumentCommand\\% + with a command that already has a definition.\\% + Perhaps you meant \token_to_str:N \RenewDocumentCommand.% + } +\msg_kernel_new:nnnn { xparse } { command-not-yet-defined } + {Command `#1' not yet defined!} + {% + You have used \token_to_str:N \RenewDocumentCommand\\% + with a command that was never defined.\\% + Perhaps you meant \token_to_str:N \NewDocumentCommand.% + } +\msg_kernel_new:nnnn { xparse } { environment-already-defined } + {Environment `#1' already defined!} + {% + You have used \token_to_str:N \NewDocumentEnvironment\\% + with a command that already has a definition.\\% + Perhaps you meant \token_to_str:N \RenewDocumentEnvironment.% + } +\msg_kernel_new:nnnn { xparse } { environment-not-yet-defined } + {Environment `#1' not yet defined!} + {% + You have used \token_to_str:N \RenewDocumentEnvironment\\% + with a command that was never defined.\\% + Perhaps you meant \token_to_str:N \NewDocumentEnvironment.% + } +\msg_kernel_new:nnnn { xparse } { expandable-ending-optional } + {% + Signature for expandable command ends with \\% + optional argument \msg_line_context:.% + } + {% + Expandable commands must have a final mandatory argument\\% + (or no arguments at all). You cannot have a terminal optional\\% + argument with expandable commands.% + } +\msg_kernel_new:nnnn { xparse } { expandable-inconsistent-long } + {% + Inconsistent handling of long arguments for\\% + expandable command \msg_line_context:.% + } + {% + The arguments for an expandable command must either all be\\% + short or all be long. You have tried to mix the two types.% + } +\msg_kernel_new:nnnn { xparse } { grouped-in-expandable } + {% + Argument specifier `#1' forbidden in expandable commands + \msg_line_context:.% + } + {% + Argument specification `#2' contains the optional grouped + argument `#1':\\% + this is only supported for standard robust functions.% + } +\msg_kernel_new:nnnn { xparse } { processor-in-expandable } + {% + Argument processors cannot be used\\% + with expandable functions \msg_line_context:.% + } + {% + Argument specification `#1' contains a processor function:\\% + this is only supported for standard robust functions.% + } +\msg_kernel_new:nnnn { xparse } { unknown-argument-type } + {Unknown argument type `#1' replaced by `m'. Fingers crossed ...} + {% + The letter `#1' does not specify a known argument type.\\% + I'm assuming you want a standard mandatory argument (type `m').% + } +% \end{macrocode} +% +% Intended more for information. +% \begin{macrocode} +\msg_kernel_new:nnn { xparse } { define-command } + {% + Defining document command #1\\% + with arg. spec. `#2' \msg_line_context:.% + } +\msg_kernel_new:nnn { xparse } { define-environment } + {% + Defining document environment `#1'\\% + with arg. spec. `#2' \msg_line_context:.% + } +\msg_kernel_new:nnn { xparse } { redefine-command } + {% + Redefining document command #1\\% + with arg. spec. `#2' \msg_line_context:.% + } +\msg_kernel_new:nnn { xparse } { redefine-environment } + {% + Redefining document environment `#1'\\% + with arg. spec. `#2' \msg_line_context:.% + } % \end{macrocode} % %\subsection{User functions} @@ -2309,24 +2537,26 @@ %\begin{macro}{\ProvideDocumentCommand} % The user macros are pretty simple wrappers around the internal ones. % \begin{macrocode} -\xparse_declare_cmd:Nnn \DeclareDocumentCommand { +m +m +m } { +\cs_new_protected:Npn \DeclareDocumentCommand #1#2#3 { \xparse_declare_cmd:Nnn #1 {#2} {#3} } -\DeclareDocumentCommand \NewDocumentCommand { +m +m +m } { +\cs_new_protected:Npn \NewDocumentCommand #1#2#3 { \cs_if_exist:NTF #1 { - \msg_error:nnx { xparse } { command-already-defined } {#1} + \msg_kernel_error:nnx { xparse } { command-already-defined } + { \exp_not:N #1 } }{ \xparse_declare_cmd:Nnn #1 {#2} {#3} } } -\NewDocumentCommand \RenewDocumentCommand { +m +m +m } { +\cs_new_protected:Npn \RenewDocumentCommand #1#2#3 { \cs_if_exist:NTF #1 { \xparse_declare_cmd:Nnn #1 {#2} {#3} }{ - \msg_error:nnx { xparse } { command-not-yet-defined } {#1} + \msg_kernel_error:nnx { xparse } { command-not-yet-defined } + { \exp_not:N #1 } } } -\NewDocumentCommand \ProvideDocumentCommand { +m +m +m } { +\cs_new_protected:Npn \ProvideDocumentCommand #1#2#3 { \cs_if_exist:NF #1 { \xparse_declare_cmd:Nnn #1 {#2} {#3} } @@ -2342,10 +2572,10 @@ % The separate implementation/interface system is again pretty simple % to create at the outer layer. % \begin{macrocode} -\NewDocumentCommand \DeclareDocumentCommandImplementation { m m +m } { +\cs_new_protected:Npn \DeclareDocumentCommandImplementation #1#2#3 { \xparse_declare_cmd_implementation:nNn {#1} #2 {#3} } -\NewDocumentCommand \DeclareDocumentCommandInterface { m m +m } { +\cs_new_protected:Npn \DeclareDocumentCommandInterface #1#2#3 { \xparse_declare_cmd_interface:Nnn #1 {#2} {#3} } % \end{macrocode} @@ -2358,25 +2588,48 @@ %\begin{macro}{\ProvideDocumentEnvironment} % Very similar for environments. % \begin{macrocode} -\NewDocumentCommand \DeclareDocumentEnvironment { m +m +m +m } { +\cs_new_protected:Npn \DeclareDocumentEnvironment #1#2#3#4 { \xparse_declare_env:nnnn {#1} {#2} {#3} {#4} } -\NewDocumentCommand \NewDocumentEnvironment { m +m +m +m } { +\cs_new_protected:Npn \NewDocumentEnvironment #1#2#3#4 { +%</initex|package> +%<*initex> \cs_if_exist:cTF { environment_begin_ #1 :w } { - \msg_error:nnx { xparse } { environment-already-defined } {#1} +%</initex> +%<*package> + \cs_if_exist:cTF {#1} { +%</package> +%<*initex|package> + \msg_kernel_error:nnx { xparse } + { environment-already-defined } {#1} }{ \xparse_declare_env:nnnn {#1} {#2} {#3} {#4} } } -\NewDocumentCommand \RenewDocumentEnvironment { m +m +m +m } { - \cs_if_exist:cTF { environment_begin_ #1 :w } { +\cs_new_protected:Npn \RenewDocumentEnvironment #1#2#3#4 { +%</initex|package> +%<*initex> + \cs_if_exist:cTF { environment_begin_ #1 :w } { +%</initex> +%<*package> + \cs_if_exist:cTF {#1} { +%</package> +%<*initex|package> \xparse_declare_env:nnnn {#1} {#2} {#3} {#4} }{ - \msg_error:nnx { xparse } { environment-not-yet-defined } {#1} + \msg_kernel_error:nnx { xparse } + { environment-not-yet-defined } {#1} } } -\NewDocumentCommand \ProvideDocumentEnvironment { m +m +m +m } { +\cs_new_protected:Npn \ProvideDocumentEnvironment #1#2#3#4 { +%</initex|package> +%<*initex> \cs_if_exist:cF { environment_begin_ #1 :w } { +%</initex> +%<*package> + \cs_if_exist:cF { #1 } { +%</package> +%<*initex|package> \xparse_declare_env:nnnn {#1} {#2} {#3} {#4} } } @@ -2387,9 +2640,9 @@ %\end{macro} % %\begin{macro}{\DeclareExpandableDocumentCommand} -% The expanable version of the basic function is essentially the same. +% The expandable version of the basic function is essentially the same. % \begin{macrocode} -\NewDocumentCommand \DeclareExpandableDocumentCommand { +m +m +m } { +\cs_new_protected:Npn \DeclareExpandableDocumentCommand #1#2#3 { \xparse_exp_declare_cmd:Nnn #1 {#2} {#3} } % \end{macrocode} @@ -2430,7 +2683,15 @@ % This is coded by hand as making it \cs{protected} ensures that it % will not turn into anything else by accident. % \begin{macrocode} -\NewDocumentCommand \NoValue { } { -NoValue- } +\cs_new_protected:Npn \NoValue { -NoValue- } +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\ProcessedArgument} +% Processed arguments are returned using this name, which is reserved +% here although the definition will change. +% \begin{macrocode} +\cs_new:Npn \ProcessedArgument { } % \end{macrocode} %\end{macro} % diff --git a/Master/texmf-dist/source/latex/xpackages/xbase/xtemplate.dtx b/Master/texmf-dist/source/latex/xpackages/xbase/xtemplate.dtx new file mode 100644 index 00000000000..445474da3ef --- /dev/null +++ b/Master/texmf-dist/source/latex/xpackages/xbase/xtemplate.dtx @@ -0,0 +1,3390 @@ +% \iffalse +%% File: xtemplate.dtx (C) Copyright 1999-2001 David Carlisle, Frank Mittelbach +%% (C) Copyright 2004-2009 Frank Mittelbach, 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 +%%1 +%% This file is part of the ``xbase 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} +%</driver|package> +%\fi +\GetIdInfo$Id: xtemplate.dtx 1746 2009-11-16 01:34:59Z will $ + {Prototype document functions} +%\iffalse +%<*driver> +%\fi +\ProvidesFile{\filename.\filenameext} + [\filedate\space v\fileversion\space\filedescription] +%\iffalse +\documentclass[full]{l3doc} +\ExplSyntaxOn +% SYNTAX environments getting ugly. This helps: +\cs_if_exist:NT \g_doc_syntax_dim { + \dim_set:Nn \g_doc_syntax_dim {\textwidth} +} +\ExplSyntaxOff +\usepackage{booktabs} +\begin{document} + \DocInput{xtemplate.dtx} +\end{document} +%</driver> +% \fi +% +% \title{The \textsf{xtemplate} package\thanks{This file +% has version number \fileversion, last +% revised \filedate.}} +% \author{\Team} +% \date{\filedate} +% \maketitle +% +% \begin{documentation} +% +% \section{Introduction} +% +% There are three broad `layers' between putting down ideas into a source file +% and ending up with a typeset document. These layers of document writing are: +% \begin{enumerate} +% \item Authoring of the text, with mark-up +% \item Document layout design +% \item Implementation (with \TeX\ programming) of the design +% \end{enumerate} +% We write the text as an author, and we see the visual output of the design +% after the document is generated; the \TeX\ implementation in the middle is +% the glue between the two. +% +% \LaTeX's greatest success has been to standardise a system of mark-up that +% balances the trade-off between ease of reading and ease of writing to suit +% almost all forms of technical writing. It's +% other original strength was a good background in typographical design; while +% the standard \LaTeXe\ classes look somewhat dated now in terms of their +% visual design, their typography is generally sound. (Barring the occasional +% minor faults.) +% +% However, \LaTeXe\ has always lacked a standard approach to customising +% the visual design of a document. Changing the looks of the standard classes +% involved either: +% \begin{itemize} +% \item Creating a new version of the implementation code of the class and +% editing it. +% \item Loading one of the many packages to customise certain elements of +% the standard classes. +% \item Loading a completely different document class, such as +% \textsf{KOMA-Script} or \textsf{memoir}, that allows easy +% customisation. +% \end{itemize} +% All three of these approaches have their drawbacks and learning curves. +% +% The idea behind \pkg{xtemplate} is to cleanly separate the three layers +% introduced at the beginning of this section, so that document authors who +% are not programmers can easily change the design of their documents. +% \pkg{xtemplate} also makes it easier for \LaTeX\ programmers to provide +% their own customisations on top of a pre-existing class. +% +% \section{What is a document?} +% +% Besides the textual content of the words themselves, the source file of a +% document contains mark-up elements that add structure to the document. +% These elements include sectional divisions, figure/table captions, +% lists of various sorts, theorems/proofs, and so on. +% The list will be different for every document that can be written. +% +% Each element can be represented logically without worrying about the +% formatting, with mark-up such as \cmd\section, \cmd\caption, +% "\begin{enumerate}" and so on. +% The output of each one of these document +% elements will be a typeset representation of the information marked up, and +% the visual arrangement and design of these elements can vary widely in +% producing a variety of desired outcomes. +% +% For each type of document element, there may be design variations that +% contain the same sort of information but present it in slightly different +% ways. +% For example, the difference between a numbered and an unnumbered +% section, \cmd\section\ and \cmd\section"*", or the difference between an +% itemised list or an enumerated list. +% +% There are three distinct layers in the definition of `a document' at this +% level: +% \begin{enumerate} +% \item Semantic elements such as the ideas of sections and lists. +% \item A set of design solutions for representing these elements visually. +% \item Specific variations for these designs that represent the elements in the document. +% \end{enumerate} +% In the parlance of the \pkg{xtemplate} package, we call these object types, +% templates, and instances, and they are discussed below in +% sections \ref{sec:objects}, \ref{sec:templates}, and~\ref{sec:instances}, +% respectively. +% +% \section {Objects, templates, and instances} +% +% By formally declaring our document to be composed of mark-up elements +% grouped into objects, which are interpreted and typeset with a set of +% templates, each of which has one or more instances with which to compose each +% and every semantic unit of the text, we can cleanly separate +% the components of document construction. +% The \pkg{xtemplate} package provides the tools to do this. +% +% \subsection{Object types}\label{sec:objects} +% +% An `object type' (or sometimes just `object') is an abstract idea of a +% document element that takes a +% fixed number of arguments corresponding to the information from the +% document author that it is representing. +% A sectioning object, for example, might take three inputs: `title', +% `short title', and `label'. +% +% Any given document class will define which object types are to be used in +% the +% document, and any template of a given object type can be used to generate an +% instance for the object. +% (Of course, different templates will produce different typeset +% representations, but the underlying content will be the same.) +% +% \begin{function}{\DeclareObjectType} +% \begin{syntax} +% "\DeclareObjectType" \Arg{name} \Arg{Nargs} +% \end{syntax} +% This function defines an \emph{object type}, +% where \meta{name} is the name of the object type and \meta{Nargs} is the number of +% arguments an instance of this type should take. For example, +% \begin{quote} +% \begin{verbatim} +% \DeclareObjectType{sectioning}{3} +% \end{verbatim} +% \end{quote} +% Note that object types are global entities: \cs{DeclareObjectType} +% will apply outside of any \TeX\ grouping in force when it is +% called. +% \end{function} +% +% \subsection{Templates}\label{sec:templates} +% +% A \emph{template} is a generalised design solution for representing the +% information of a specified \emph{object type}. +% Templates that do the same thing~--- e.g., two completely different ways of +% printing a chapter heading~--- are grouped together by their object type and +% given +% separate names. +% There are two important parts to a template: +% \begin{itemize} +% \item The parameters it takes to vary the design it is producing. +% \item The implementation of the design. +% \end{itemize} +% As a document author or designer does not care about the implementation +% but rather only the interface to the template, these two aspects of the template +% definition are split into two independent declarations, \cmd\DeclareTemplateInterface\ +% and \cmd\DeclareTemplateCode. +% +% \begin{function}{\DeclareTemplateInterface} +% \par +% \begin{syntax} +% "\DeclareTemplateInterface" \Arg{object type} \Arg{template} \Arg{Nargs} +% "{" +% " "<name of key 1> ":" <key type 1> "," +% " "<name of key 2> ":" <key type 2> "=" <optional default> "," +% " ..." +% "}" +% \end{syntax} +% The \meta{name of keys} can be any string of \textsc{ascii} characters (with +% the exception of ":", "=" and "," as they are part of the syntax); +% we recommend only using lower case letters and dashes, however. +% Note that spaces in key names are ignored, so that key names can be +% spaced out for ease of reading without affecting the recognition of +% keys inside and outside of code blocks. +% +% The <key types> define what sort of input the key accepts, such as `boolean', +% `integer', and so on. The complete list of possible <key types> is shown in +% \autoref{tab:keytypes}. +% +% Like objects, templates are global entities: both +% \cs{DeclareTemplateInterface} \cs{DeclareTemplateCode} will apply +% outside of any \TeX\ grouping in force when it is called. +% \end{function} +% +% \begin{table}[p] +% \begin{tabular}{@{}ll@{}} +% \toprule +% Key Type & Description of input \\ +% \midrule +% "boolean" & "true" or "false" \\ +% "choice "\Arg{choices} & A list of pre-defined choices \\ +% "code" & Generalised key type; use "#1" as the input to the key \\ +% "commalist" & A comma-separated list of arbitrary items \\ +% "function "$N$ & A function definition with $N$ arguments +% ($N$ from $0$ to $9$) \\ +% "instance "\Arg{name} & An instance of type \meta{name} \\ +% "integer" & An integer expression (e.g., {\small "(1 + 5)/2"}) \\ +% "length" & A dimension expression (e.g., {\small "3pt + 2cm"}) \\ +% "skip" & A dimension expression with glue +% (e.g., {\small "3pt plus 2pt minus 1pt"}) \\ +% "tokenlist" & A `token list' input; any text or commands \\ +% \bottomrule +% \end{tabular} +% \caption{`Key types' for defining template interfaces with \cs{DeclareTemplateInterface}.} +% \label{tab:keytypes} +% \end{table} +% +% \begin{table}[p] +% \begin{tabular}{@{}lcl@{}} +% \toprule +% Key Type && Description of binding \\ +% \midrule +% "boolean" &$\star$& Boolean variable; e.g., "\l_tmpa_bool" \\ +% "choice" && "{" \meta{choice\,$_1$} "=" \meta{code\,$_1$} "," \meta{choice\,$_2$} "=" \meta{code\,$_2$} "," \dots "}" \\ +% "code" && \meta{code} ; use "#1" as the input to the key \\ +% "commalist" &$\star$& Comma-list variable; e.g., "\l_tmpa_clist" \\ +% "function" &$\star$& Function w/ $N$ arguments; e.g., "\use_i:nn" \\ +% "instance" &$\star$& An instance variable; e.g., "\g_foo_instance" \\ +% "integer" &$\star$& Integer variable; e.g., "\l_tmpa_int" \\ +% "length" &$\star$& Dimension variable; e.g., "\l_tmpa_dim" \\ +% "skip" &$\star$& Skip variable; e.g., "\l_tmpa_skip" \\ +% "tokenlist" &$\star$& Token list variable; e.g., "\l_tmpa_tl" \\ +% \bottomrule +% \end{tabular} +% \caption{Bindings required for different key types when defining template implementations with \cs{DeclareTemplateCode}. Starred entries may be prefixed with the keyword \texttt{global} to make a global assignment.} +% \label{tab:keyvariables} +% \end{table} +% +% \begin{function}{\DeclareTemplateCode} +% \par +% \begin{syntax} +% "\DeclareTemplateCode" \Arg{object type} \Arg{template} \Arg{Nargs} +% "{" +% " "<name of key 1> "=" <internal variable or code 1> "," +% " "<name of key 2> "=" <internal variable or code 2> "," +% " ..." +% "}{" +% " "\meta{implementation code} +% " \AssignTemplateKeys" +% " "\meta{more implementation code} +% "}" +% \end{syntax} +% After the keys have been declared with "\DeclareTemplateInterface", the +% implementation binds each <name of key> with an <internal variable> +% (for key types such as `integer', `length', `tokenlist', etc.) +% \unskip\footnote{^^A +% It is possible, if you wish, to use the same variable for multiple keys; +% this allows `key synonyms' to be defined such as |color| and |colour| which +% can perform the same function in the template implementation.} +% or with a certain <code> fragment to execute, which will be described below. +% +% Assignments to variables which should be made globally are indicated by adding the +% word \texttt{global} before the variable name: +% +% \begin{syntax} +% " "<name of key 1> "=" <internal variable 1> "," +% " "<name of key 2> "=" global <internal variable 2> "," +% \end{syntax} +% +% The key types "choices" and "code" do not take variable bindings; instead, +% fragments of code are defined which are executed instead. The complete list +% of bindings taken by different key types is shown in \autoref{tab:keyvariables}. +% The "choices" key type is explained fully in \autoref{sec:choices-key} below. +% +% \begin{function}{\AssignTemplateKeys} +% \par +% The final argument of \cs{DeclareTemplateCode} contains the <implementation code> +% for the template design, taking arguments |#1|, |#2|, etc.\ according to the number of +% arguments allowed, <Nargs>. \cs{AssignTemplateKeys} must be +% executed in order to assign variables and perform code executions according +% to the keys set. +% \end{function} +% \end{function} +% +% \subsection{Multiple choices} +% \label{sec:choices-key} +% +% The \texttt{choice} keytype implements multiple choice input. At the +% interface level, only the list of valid choices is needed: +% \begin{verbatim} +% \DeclareTemplateInterface { foo } { bar } 0 { +% key-name : choice { A,B,C } +% } +% \end{verbatim} +% where the choices are given as a comma-list (which must therefore +% be wrapped in braces). A default value can also be given: +% \begin{verbatim} +% \DeclareTemplateInterface { foo } { bar } 0 { +% key-name : choice { A,B,C } = A +% } +% \end{verbatim} +% +% At the implementation level, each choice is associated with code, +% using a nested key--value list. +% \begin{verbatim} +% \DeclareTemplateCode { foo } { bar } 0 { +% key-name = { +% A = Code-A , +% B = Code-B , +% C = Code-C , +% } +% } { ... } +% \end{verbatim} +% The two choice lists should match, but in the implementation a +% special \texttt{unknown} choice is also available. This can be used +% to ignore values and implement an `else' branch: +% \begin{verbatim} +% \DeclareTemplateCode { foo } { bar } 0 { +% key-name = { +% A = Code-A , +% B = Code-B , +% C = Code-C , +% unknown = Else-code +% } +% } { ... } +% \end{verbatim} +% The \texttt{unknown} entry must be the last one given, and should +% \emph{not} be listed in the interface part of of the template. +% +% \subsection{Instances}\label{sec:instances} +% +% After a template is defined it still needs to be put to use. +% The parameters that it expects need to be defined before it can be used in +% a document. +% Every time a template has parameters given to it, an \emph{instance} is +% created, and this is the code that ends up in the document to perform the +% typesetting of whatever pieces of information are input into it. +% +% For example, a template might say `here is a section with or without a +% number that might be centred or left aligned and print its contents in a +% certain font of a certain size, with a bit of a gap before and after it' +% whereas an instance declares `this is a section with a number, which is centred and set +% in 12pt italic with a 10pt skip before and a 12pt skip after it'. +% +% Therefore, an instance is just a frozen version of a template with specific +% settings as chosen by the designer. +% +% \begin{function}{\DeclareInstance} +% \par +% \begin{syntax} +% "\DeclareInstance" \Arg{object type} \Arg{instance} \Arg{template} \Arg{parameters} +% \end{syntax} +% The name of the instance being declared is <instance>, with <parameters> +% the keyval input to set some or all of the <template> keys to specific values. +% +% Here is a hypothetical example, where |sectioning| might be an object to be used +% for document subdivisions, |section-num| an instance referring to a `numbered section', +% and |basic| a template for |sectioning| that performs just the basic layout, say: +% \begin{quote} +% \begin{verbatim} +% \DeclareInstance{sectioning}{section-num}{basic} { +% numbered = true , +% justification = center , +% font = \normalsize\itshape , +% before-skip = 10pt , +% after-skip = 12pt , +% } +% \end{verbatim} +% \end{quote} +% \end{function} +% +% +% \subsection{Document interface} +% +% After the instances have been chosen, document commands must be declared to +% use those instances in the document. \cmd\UseInstance\ calls instances directly, +% and this command should be used internally in document-level mark-up. +% +% \begin{function}{\UseInstance} +% \par +% \begin{syntax} +% "\UseInstance" \Arg{object type} \Arg{instance} <arguments> +% \end{syntax} +% \end{function} +% +% It will take as many arguments as were defined for the object type. +% +% Use \textsf{xparse} to declare the document commands in terms of instances. +% Another hypothetical example: +% \begin{quote} +% \begin{verbatim} +% \DeclareDocumentCommand\section{ som }{ +% \IfBooleanTF #1 +% { +% \UseInstance{sectioning}{section-nonum}{#2}{#3} +% } +% { +% \UseInstance{sectioning}{section-num}{#2}{#3} +% } +% } +% \end{verbatim} +% \end{quote} +% +% \begin{function}{\UseTemplate} +% \par +% \begin{syntax} +% "\UseTemplate" \Arg{object type} \Arg{template} \Arg{settings} <arguments> +% \end{syntax} +% There are occasions where creating an instance of a template does not +% make sense, as it will only be used once. In this case, templates can +% be used directly, with the key settings given as an argument to the +% \cs{UseTemplate} function. This will also work when giving an argument +% to a key which needs an instance. For example, if we have an key +% \texttt{instance-key} which expects an instance of \texttt{object2}, +% then we can either declare an instance: +% \begin{quote} +% \begin{verbatim} +% \DeclareInstance {object2} {template2} {temp-instance} { +% <settings> +% } +% \DeclareInstance {object} {template} {instance} { +% instance-key = temp-instance +% } +% \end{verbatim} +% \end{quote} +% or use the template directly: +% \begin{quote} +% \begin{verbatim} +% \DeclareInstance {object} {template} {instance} { +% instance-key = \UseTemplate {object2} {template2} {<settings>} +% } +% \end{verbatim} +% \end{quote} +% Which is the best approach will depend on the exact nature of the +% situation. +% \end{function} +% +% \subsection{Summaries} +% +% For the document designer: +% \begin{itemize} +% \item The class will define which object types are used in a document. +% \item The class will define user commands that contain the required +% instances that the document must use. +% \item Having knowledge of a variety of suitable templates, for each +% required instance a template can be selected and instantiated based on the +% parameters defined by \cmd\DeclareTemplateInterface. +% \end{itemize} +% +% For the class programmer: +% \begin{itemize} +% \item Define the different object types of document elements: what the semantics +% are and what information is required. +% \item Create document commands to call instances that fulfil the needs of +% the object types. +% \item Implement the required templates to produce typeset implementations +% of the document elements and instantiate them with the appropriate names. +% \end{itemize} +% +% \section{Instances in different contexts} +% +% We may wish the behaviour of an instance to change as it is used in varying contexts. +% For example, in the frontmatter of a document, section numbering is +% different. Semantics are the same, but the typesetting changes. But we want +% to use the same user commands, and hence the same instance names. +% +% \emph{Collections} allow us to define multiple instances that we can switch +% between. Collections are activated with \cmd\UseCollection. +% +% At present, it is not clear whether collections fully address the +% issues they target. They should therefore be regarded as highly +% experimental, and may be changed or withdrawn in the future if +% it appears that they do not work well enough! +% +% \begin{function}{\DeclareCollectionInstance} +% +% \begin{syntax} +% "\DeclareCollectionInstance" \Arg{collection} \Arg{object type} \Arg{instance} \Arg{template}\\\hfill \Arg{parameters} +% \end{syntax} +% \end{function} +% +% \begin{function}{\UseCollection} +% \begin{syntax} +% "\UseCollection" \Arg{object type} \Arg{collection} +% \end{syntax} +% \end{function} +% +% The instance declared will override another instance of the same name when +% the collection is active. Note that a collection instance can only be declared if +% the \emph{original} instance already exists. +% +% An example might be: +% \begin{verbatim} +% \UseCollection{sectioning}{frontmatter} +% \section{Nomenclature} +% ... +% \UseCollection{sectioning}{default} +% \section{Introduction} +% \end{verbatim} +% In both cases, the same instance (perhaps `"section-num"') is being used inside +% the \cs{section}. But \cs{DeclareCollectionInstance} will have been used for +% the `"frontmatter"' and override the instance that is used in the default case. +% +% \section{Bits 'n' pieces} +% +% \subsection{Does an instance exist?} +% +% \begin{function}{\IfInstanceExist / (TF)} +% +% \begin{syntax} +% "\IfInstanceExistTF" \Arg{object type} \Arg{instance} \Arg{true code} \Arg{false code} +% "\IfInstanceExistT" \Arg{object type} \Arg{instance} \Arg{true code} +% "\IfInstanceExistF" \Arg{object type} \Arg{instance} \Arg{false code} +% \end{syntax} +% Test if <instance> has been declared. This is useful when the use of an instance +% depends on some global variable, such as the current font selection. Designers +% or users can then implement specific designs for exact situations rather than +% relying on blanket parameter redefinitions. See \pkg{xfrac} for a good example of this. +% \end{function} +% +% \subsection{Changing the defaults of a template's keys} +% +% Template parameters may be assigned specific defaults for instances to use +% if the instance declaration doesn't explicit set those parameters. +% In some cases, the document designer will wish to edit these defaults to +% allow them to `cascade' to the instances. +% The alternative would be to set each parameter identically for each +% instance declaration, a tedious and error-prone process. +% \begin{function}{\EditTemplateDefaults} +% +% \begin{syntax} +% "\EditTemplateDefaults" \Arg{object type} \Arg{template} \Arg{new defaults} +% \end{syntax} +% \end{function} +% +% This command only takes effect for instances that have not yet been declared. +% Use "\EditInstance" if you wish to change an instance that already exists. +% +% \subsection{Small changes to an instance} +% +% When a designer creates an instance but the user wishes to slightly tweak +% it, it is convenient to not have to reset all of the (possibly many) +% parameters defining that instance and only override the specific parameter +% that should be changed. +% \begin{function}{\EditInstance|\EditCollectionInstance} +% \par +% \begin{syntax} +% "\EditInstance" \Arg{object type} \Arg{instance} \Arg{new parameters} +% "\EditCollectionInstance" \Arg{object type} \Arg{collection} \Arg{instance}\\\hfill \Arg{template} \Arg{new parameters} +% \end{syntax} +% These functions change the key settings of an instance of an object +% type. If the instance was derived from a template, this information +% is used to find the correct keys to use for the editing process. +% It may be convenient to use "\ShowInstanceValues" to inspect the values +% used to set the keys originally. +% \end{function} +% +% +% \subsection{Parameters evaluated now} +% +% \begin{function}{\EvaluateNow} +% \begin{syntax} +% "\EvaluteNow" \Arg{expression} +% \end{syntax} +% The standard method when creating an instance from a template is to +% evaluate the <expression> when the instance is used. However, it may +% be desirable to calculate the value when declared, which can be +% forced using \cs{EvaluateNow}. Currently, this functionality is +% regarded as experimental: the team have not found an example where it +% is actually needed, and so it may be dropped \emph{if} no good +% examples are suggested! +% \end{function} +% +% +% \subsection{Setting one key to the value of another} +% +% It is often useful to use the value of one key as the default for another. +% \begin{function}{\KeyValue} +% \begin{syntax} +% "\KeyValue" \Arg{key name} +% \end{syntax} +% This command is used as the argument to an instance key; it will set that +% key to the value of <key name> each time the instance is executed at run-time. +% Using \cs{KeyValue} means that the designer does not need to know +% how a particular key has been implemented. +% \end{function} +% +% \subsection{When template parameters should be frozen} +% +% A class designer may be inheriting templates declared by someone else, +% either third-party code or the \LaTeX\ kernel itself. Sometimes these +% templates will be overly general for the purposes of the document. The user +% should be able to customise parts of the template instances, but otherwise +% be restricted to only those parameters allowed by the designer. +% +% "\DeclareRestrictedTemplate" creates a derived version of a template for +% which certain parameters are frozen as specified but the remaining parameters are +% available to be set as usual in an instance declaration. +% +% \begin{function}{\DeclareRestrictedTemplate} +% \par +% \begin{syntax} +% |\DeclareRestrictedTemplate| \Arg{object type} \Arg{parent} \Arg{new template} \Arg{frozen parameters} +% \end{syntax} +% Defines <new template> based on template <parent> (of certain <object type>) +% with certain keys set and frozen as defined in <keyvals>. +% \end{function} +% +% \section{Getting information about templates and instances} +% +% \begin{function}{ +% \ShowTemplateCode | +% \ShowTemplateDefaults | +% \ShowTemplateKeytypes | +% \ShowTemplateVariables } +% +% \begin{syntax} +% "\ShowTemplateCode" \Arg{object type} \Arg{template} +% \end{syntax} +% These functions pause the typesetting and display +% in the console the various pieces of information for a template. +% \end{function} +% +% \begin{function}{ \ShowInstanceValues | \ShowCollectionInstanceValues } +% +% \begin{syntax} +% "\ShowInstanceValues" \Arg{object type} \Arg{instance} +% "\ShowCollectionInstanceValues" \Arg{object type} \Arg{collection} \Arg{instance} +% \end{syntax} +% These functions pause the typesetting and display in the console +% information about an instance or a collection instance. +% \end{function} +% +% Note that \pkg{xtemplate} uses various special key names internally. +% These all contain a space when stored (which normal keys do not: +% spaces are removed). The same applies to choices: these are stored +% internally as \texttt{\meta{key}~\meta{choice}}. These will show up +% when using the \cs{Show\ldots} functions. The design means that +% there is no danger of a clash between user keys and internal keys. +% Also, standard keys are stored with all letters detokenized, whereas +% the special keys use letters with category code $11$ (letter), again +% to avoid any issues. +% +% \section{Examples} +% +% (Nothing here yet.) +% +%\section{Code documentation} +% +%\subsection{Variables and constants} +% +%\begin{variable}{ +% \c_xtemplate_code_root_tl | +% \c_xtemplate_defaults_root_tl | +% \c_xtemplate_instances_root_tl | +% \c_xtemplate_keytypes_root_tl | +% \c_xtemplate_restrict_root_tl | +% \c_xtemplate_values_root_tl | +% \c_xtemplate_vars_root_tl | +%} +% A number of pieces of code and lists of properties have to be stored +% for templates and instances. The various csname roots are set up as +% token lists to avoid use of the literal text in the code. +%\end{variable} +% +%\begin{variable}{\c_xtemplate_key_order_tl} +% The order keys are declared in must be stored (as property lists +% have no `order'). The special property used is named here. +%\end{variable} +% +%\begin{variable}{\c_xtemplate_keytypes_arg_clist} +% Some keytypes (such as \texttt{instance}) need additional +% information, given as an argument. The list of keytypes that need this +% extra data is set up here, for later use when splitting things. +%\end{variable} +% +%\begin{variable}{\g_xtemplate_object_type_prop} +% For tracking which object types have been declared, and the number +% of arguments each requires. +%\end{variable} +% +%\begin{variable}{\l_xtemplate_assignments_toks} +% This token register is used in two places. First, it is where the +% list of assignments for an instance is constructed during +% \cs{DeclareInstance}. Second, it is where these are copied to to +% allow \cs{AssignTemplateKeys} to work correctly. +%\end{variable} +% +%\begin{variable}{\l_xtemplate_collection_tl} +% The name of the current instance collection active. If no collection +% is in use, this will simply be empty. +%\end{variable} +% +%\begin{variable}{\l_xtemplate_collections_prop} +% Records the collection in force for each object type. +%\end{variable} +% +%\begin{variable}{ +% \l_xtemplate_default_tl | +% \l_xtemplate_key_name_tl | +% \l_xtemplate_keytype_tl | +% \l_xtemplate_keytype_arg_tl | +% \l_xtemplate_value_tl | +% \l_xtemplate_var_tl | +%} +% When processing keys, various properties for the current key need to +% be available. These are copied from the property list to appropriately +% named token lists, and back again, as needed. +%\end{variable} +% +%\begin{variable}{\l_xtemplate_error_bool} +% Used to indicate an error when parsing a key list, so that further +% processing can be abandoned. +%\end{variable} +% +%\begin{variable}{\l_xtemplate_global_bool} +% When actually assigning data to variables, a check is made to see +% if this should be global. The flag here is used to indicate this. +%\end{variable} +% +%\begin{variable}{\l_xtemplate_key_seq} +% The order in which keys are defined is stored here for later +% recovery and use. It is transferred into the property list for the +% template when the template is saved. +%\end{variable} +% +%\begin{variable}{\l_xtemplate_restrict_bool} +% Flag used when editing templates, so that simple editing and +% restricting can share the same underlying editing method. +%\end{variable} +% +%\begin{variable}{ +% \l_xtemplate_restricted_clist | +% \l_xtemplate_keytypes_prop | +% \l_xtemplate_values_prop | +% \l_xtemplate_vars_prop | +%} +% To avoid needing to refer to the data about a template or instance +% by csname in a large number of locations, the data is copied to these +% scratch variables and back again for processing. This makes the code +% easier to follow. +%\end{variable} +% +%\begin{variable}{ +% \l_xtemplate_tmp_clist | +% \l_xtemplate_tmp_dim | +% \l_xtemplate_tmp_int | +% \l_xtemplate_tmp_skip | +% \l_xtemplate_tmp_tl | +%} +% Used when carrying out assignments, as the pre-processing can take +% place here before passing data through to the storage area defined +% by the implementation part of a template. The token list is also used +% for general scratch purposes by \pkg{xtemplate}. +%\end{variable} +% +%\begin{variable}{\l_xtemplate_restrict_bool} +% Flag used when editing templates, so that simple editing and +% restricting can share the same underlying editing method. +%\end{variable} +% +%\subsection{Execute or error functions} +% +% These all either execute code (if the tests are true) or issue +% errors (if the test fails). +% +%\begin{function}{\xtemplate_execute_if_arg_agree:nnT} +% \begin{syntax} +% "\xtemplate_execute_if_arg_agree:nnT" \marg{type} \marg{num} +% ~~~~\marg{true code} +% \end{syntax} +% Tests if the number of arguments required by <type> is equal +% to <num>, then executes either <true code> or generates an error as +% appropriate. +%\end{function} +% +%\begin{function}{\xtemplate_execute_if_code_exist:nnT} +% \begin{syntax} +% "\xtemplate_execute_if_code_exist:nnT" \marg{type} \marg{template} +% ~~~~\marg{true code} +% \end{syntax} +% Tests if <template> of <type> has been defined (i.e., the code has +% been created for an implementation), then executes either +% <true code> or generates an error as appropriate. +%\end{function} +% +%\begin{function}{ +% \xtemplate_execute_if_keytype_exist:nT | +% \xtemplate_execute_if_keytype_exist:VT +%} +% \begin{syntax} +% "\xtemplate_execute_if_keytype_exist:nT" \marg{keytype} +% ~~~~\marg{true code} +% \end{syntax} +% Tests if <keytype> is a known keytype, then executes either +% <true code> or generates an error as appropriate. +%\end{function} +% +%\begin{function}{\xtemplate_execute_if_type_exist:nT} +% \begin{syntax} +% "\xtemplate_if_type_exist:nT" \marg{type} \marg{true code} +% \end{syntax} +% Tests if template <type> has been created, then executes either +% <true code> or generates an error as appropriate. +%\end{function} +% +%\begin{function}{\xtemplate_execute_if_keys_exist:nnT} +% \begin{syntax} +% "\xtemplate_if_keys_exist:nnT" \marg{type} \marg{template} +% ~~~~\marg{true code} +% \end{syntax} +% Tests if keys for <template> of <type> have been declared (but +% not necessarily given an implementation), , then executes either +% <true code> or generates an error as appropriate. +%\end{function} +% +%\subsection{Utility functions} +% +%\begin{function}{ +% \xtemplate_if_key_value:nT / (EXP) | +% \xtemplate_if_key_value:VT / (EXP) +%} +% \begin{syntax} +% "\xtemplate_if_key_value:nT" \marg{tokens} \marg{true code} +% \end{syntax} +% Tests if the first token in <tokens> is \cs{KeyValue}. +%\end{function} +% +%\begin{function}{\xtemplate_if_eval_now:nTF / (EXP)} +% \begin{syntax} +% "\xtemplate_if_eval_now:nTF" \marg{tokens} +% ~~~~\marg{true code} \marg{false code} +% \end{syntax} +% Tests if the first token in <tokens> is a marker for evaluating +% now (\cs{EvaluateNow}). +%\end{function} +% +%\begin{function}{\xtemplate_if_instance_exist:nnn / (TF) (EXP)} +% \begin{syntax} +% "\xtemplate_if_instance_exist:nnnTF" \marg{type} +% ~~~~\marg{collection} \marg{instance} \marg{true code} +% \marg{false code} +% \end{syntax} +% Tests if <instance> of <type> exists for the <collection> given. +%\end{function} +% +%\begin{function}{\xtemplate_if_use_template:nTF / (EXP)} +% \begin{syntax} +% "\xtemplate_if_use_template:nTF" \marg{assignment} +% ~~~~\marg{true code} \marg{false code} +% \end{syntax} +% Tests if {assignment} begins with \cs{UseTemplate}. +%\end{function} +% +%\begin{function}{ +% \xtemplate_store_defaults:n | +% \xtemplate_store_keytypes:n | +% \xtemplate_store_restrictions:n | +% \xtemplate_store_values:n | +% \xtemplate_store_vars:n | +%} +% \begin{syntax} +% "\xtemplate_store_defaults:n" \marg{full name} +% \end{syntax} +% These functions copy information about the current template or +% instance from the scratch variables to those for storing the +% information. The <full name> of the instance or template is needed: +% this includes the <type> and <collection> (if applicable). +%\end{function} +% +%\begin{function}{ +% \xtemplate_recover_defaults:n | +% \xtemplate_recover_keytypes:n | +% \xtemplate_recover_restrictions:n | +% \xtemplate_recover_values:n | +% \xtemplate_recover_vars:n | +%} +% \begin{syntax} +% "\xtemplate_recover_defaults:n" \marg{full name} +% \end{syntax} +% The reverse of the \texttt{store} functions, these functions copy +% data from the storage areas to the scratch variables for use in the +% module. Again, the <full name> is needed, including the <type>. +%\end{function} +% +%\subsection{Creating object types} +% +%\begin{function}{\xtemplate_declare_object_type:nn} +% \begin{syntax} +% "\xtemplate_declare_object_type:nn" \marg{type} \marg{num} +% \end{syntax} +% Declares <type> of object, to accept <num> arguments. +%\end{function} +% +%\subsection{Declaring template keys} +% +%\begin{function}{\xtemplate_declare_template_keys:nnnn} +% \begin{syntax} +% "\xtemplate_declare_template_keys:nnnn" \marg{type} +% ~~~~\marg{template} \marg{num} \marg{keyvals} +% \end{syntax} +% Declares <template> of <type>, and accepting <num> arguments, with +% key types and default values defined by <keyvals>. +%\end{function} +% +%\begin{function}{ +% \xtemplate_parse_keys_elt:n | +% \xtemplate_parse_keys_elt:nn +%} +% \begin{syntax} +% "\xtemplate_parse_keys_elt:nn" \marg{key} \marg{value} +% \end{syntax} +% Functions used to process each key--value pair when declaring +% keys from <keyvals>. +%\end{function} +% +%\begin{function}{\xtemplate_split_keytype:n} +% \begin{syntax} +% "\xtemplate_split_keytype:n" \marg{key} +% \end{syntax} +% Splits a <key> into a key name (stored as \cs{l_xtemplate_key_tl}) +% and a keytype (stored as \cs{l_xtemplate_keytype_tl}). +%\end{function} +% +%\begin{function}{ +% \xtemplate_split_keytype_arg:n | +% \xtemplate_split_keytype_arg:V +%} +% \begin{syntax} +% "\xtemplate_split_keytype_arg:n" \marg{keytype} +% \end{syntax} +% Splits a <keytype> into the type itself and any optional qualifying +% text. The results are stored in \cs{l_xtemplate_keytype_tl} and +% \cs{l_xtemplate_keytype_arg_tl}. +%\end{function} +% +%\subsection{Storing defaults and values} +% +%\begin{function}{ +% \xtemplate_store_value_boolean:n | +% \xtemplate_store_value_choice:n | +% \xtemplate_store_value_choice:V | +% \xtemplate_store_value_code:n | +% \xtemplate_store_value_commalist:n | +% \xtemplate_store_value_function:n | +% \xtemplate_store_value_function:n | +% \xtemplate_store_value_instance:n | +% \xtemplate_store_value_tokenlist:n | +% \xtemplate_store_value_integer:n | +% \xtemplate_store_value_length:n | +% \xtemplate_store_value_skip:n | +%} +% \begin{syntax} +% "\xtemplate_store_value_boolean:n" \marg{value} +% \end{syntax} +% Store values of the given keytype for later assignment to variables. +% For the numeric and Boolean data types, the value is evaluated +% at this stage unless \cs{DelayEvaluation} or \cs{KeyValue} are +% used in the <value>. +%\end{function} +% +%\begin{function}{\xtemplate_store_value_choice_name:n} +% \begin{syntax} +% "\xtemplate_store_value_choice_name:n" \marg{value} +% \end{syntax} +% Stores the name of a choice for a multiple choice key, which will +% be turned into an implementation when code is available. +%\end{function} +% +%\subsection{Implementing templates} +% +%\begin{function}{\xtemplate_declare_template_code:nnnnn} +% \begin{syntax} +% "\xtemplate_declare_template_code:nnnnn" \marg{type} +% ~~~~\marg{template} \marg{num} \marg{keyvals} \marg{code} +% \end{syntax} +% Declares implementation of <template> of <type>, and accepting <num> +% arguments, with keys implemented as listed in <keyvals> and with +% <code> to be executed when the <template> is used. +%\end{function} +% +%\begin{function}{\xtemplate_store_key_implementation:nnn} +% \begin{syntax} +% "\xtemplate_store_key_implementation:nnn" \marg{type} +% ~~~~\marg{template} \marg{keyvals} +% \end{syntax} +% Stores the implementation for keys as specified in <keyvals> for +% a <template> of <type>. +%\end{function} +% +%\begin{function}{ +% \xtemplate_parse_vars_elt:n | +% \xtemplate_parse_vars_elt:nn +%} +% \begin{syntax} +% "\xtemplate_parse_vars_elt:nn" \marg{key} \marg{variable} +% \end{syntax} +% Used by the key--value parser to assign a <variable> for each +% <key> listed. +%\end{function} +% +% +%\begin{function}{\xtemplate_store_key_implementation:nnn} +% \begin{syntax} +% "\xtemplate_store_key_implementation:nnn" \marg{type} +% ~~~~\marg{template} \marg{keyvals} +% \end{syntax} +% Stores the implementation for keys as specified in <keyvals> for +% a <template> of <type>. +%\end{function} +% +%\begin{function}{\xtemplate_implement_choices:n} +% \begin{syntax} +% "\xtemplate_implement_choices:n" {key--value list} +% \end{syntax} +% Master function for turning <key-value lsit> into a set of choices. +%\end{function} + +% +%\begin{function}{ +% \xtemplate_implement_choice_elt:n | +% \xtemplate_implement_choice_elt:nn +%} +% \begin{syntax} +% "\xtemplate_implement_choice_elt:nn" \marg{choice} \marg{code} +% \end{syntax} +% Used by the key--value parser to convert a key--value list of +% choices and code into working multiple choice values. +%\end{function} +% +%\subsection{Modifying templates} +% +%\begin{function}{\xtemplate_declare_restricted:nnnn} +% \begin{syntax} +% "\xtemplate_declare_restricted:nnnn" \marg{type} \marg{parent} +% ~~~~\marg{restricted} \marg{keyvals} +% \end{syntax} +% Creates <restricted> template of <type> based on <parent> by fixing +% values as listed in <keyvals>. +%\end{function} +% +%\begin{function}{\xtemplate_edit_defaults:nnn} +% \begin{syntax} +% "\xtemplate_edit_defaults:nnn" \marg{type} \marg{template} +% ~~~~\marg{keyvals} +% \end{syntax} +% Modifies the default values for <template> of <type> as instructed +% in <keyvals>. +%\end{function} +% +%\begin{function}{\xtemplate_parse_values:nn} +% \begin{syntax} +% "\xtemplate_parse_values:nn" \marg{name} \marg{keyvals} +% \end{syntax} +% Parses <keyvals> for full <name>, finding the value for each key +% and storing it for later assignment. +%\end{function} +% +%\begin{function}{ +% \xtemplate_parse_values_elt:n | +% \xtemplate_parse_values_elt:nn +%} +% \begin{syntax} +% "\xtemplate_parse_values_elt:nn" \marg{key} \marg{variable} +% \end{syntax} +% Used by the key--value parser to find <value> to assing to +% implementation of <key>. +%\end{function} +% +%\begin{function}{\xtemplate_set_template_eq:nn} +% \begin{syntax} +% "\xtemplate_set_template_eq:nn" \marg{copy} \marg{parent} +% \end{syntax} +% Copies all of <parent> template to the <copy>, where both are full +% names (i.e., a template plus type). +%\end{function} +% +%\subsection{Creating instances} +% +%\begin{function}{\xtemplate_declare_instance:nnnnn} +% \begin{syntax} +% "\xtemplate_declare_instance:nnnnn" \marg{type} \marg{template} +% ~~~~\marg{collection} \marg{instance} \marg{keyvals} +% \end{syntax} +% Declares an <instance> (within <collection>) of <template> of <type>, +% using <keyvals> to define the instance. +%\end{function} +% +%\begin{function}{\xtemplate_edit_instance:nnnn} +% \begin{syntax} +% "\xtemplate_declare_instance:nnnn" \marg{type} \marg{collection} +% ~~~~\marg{instance} \marg{keyvals} +% \end{syntax} +% Modifies an <instance> (within <collection>) of <type>, using +% <keyvals> to modify the instance. +%\end{function} +% +%\begin{function}{\xtemplate_convert_to_assignments:} +% \begin{syntax} +% "\xtemplate_convert_to_assignments:" +% \end{syntax} +% Converts the contents of the various scratch property lists into +% a list of variable assignments in \cs{l_xtemplate_assignments_toks}. +%\end{function} +% +%\begin{function}{\xtemplate_find_global:} +% \begin{syntax} +% "\xtemplate_find_global:" +% \end{syntax} +% Checks in \cs{l_xtemplate_var_tl} for the special text +% \texttt{global}, which is removed from the variable is found. The +% flag \cs{l_xtemplate_global_bool} is then set as appropriate. +%\end{function} +% +%\subsection{Converting values to assignments} +% +%\begin{function}{ +% \xtemplate_assign_boolean: | +% \xtemplate_assign_choice: | +% \xtemplate_assign_code: | +% \xtemplate_assign_code:n | +% \xtemplate_assign_commalist: | +% \xtemplate_assign_function: | +% \xtemplate_assign_instance: | +% \xtemplate_assign_integer: | +% \xtemplate_assign_length: | +% \xtemplate_assign_skip: | +% \xtemplate_assign_tokenlist: +%} +% \begin{syntax} +% "\xtemplate_assign_boolean:" +% \end{syntax} +% Convert the given <keytype> of <key> into an assignment to a +% <variable>. +%\end{function} +% +%\begin{function}{\xtemplate_assign_variable:N} +% \begin{syntax} +% "\xtemplate_assign_variable:N" <function> +% \end{syntax} +% Convert the current contents of \cs{l_xtemplate_value_tl} into an +% assignment using <function> to the variable named in +% \cs{l_xtemplate_var_tl}. +%\end{function} +% +%\begin{function}{\xtemplate_key_to_value:} +% \begin{syntax} +% "\xtemplate_key_to_value:" +% \end{syntax} +% Converts an attribute named using \cs{KeyValue} into the +% value of the underlying implementation variable. +%\end{function} +% +%\subsection{Using instances} +% +%\begin{function}{\xtemplate_use_instance:nn} +% \begin{syntax} +% "\xtemplate_use_instance:nn" \marg{type} \marg{instance} +% \end{syntax} +% Executes code stored for <instance> of <type>, taking account of +% any active collection. +%\end{function} +% +%\begin{function}{\xtemplate_use_template:nnn} +% \begin{syntax} +% "\xtemplate_use_template:nnn" \marg{type} \marg{template} +% ~~~~\marg{settings} +% \end{syntax} +% Executes code stored for <template> of <type> using <settings>. +%\end{function} +% +%\begin{function}{\xtemplate_use_collection:nn} +% \begin{syntax} +% "\xtemplate_use_collection:nn" \marg{type} \marg{collection} +% \end{syntax} +% Activates <collection> for instances of \marg{type}. +%\end{function} +% +%\begin{function}{\xtemplate_get_collection:n} +% \begin{syntax} +% "\xtemplate_get_collection:n" \marg{type} +% \end{syntax} +% Sets \cs{l_xtemplate_collection_tl} to the name of the collection +% in force for templates of <type>. +%\end{function} +% +%\begin{function}{\xtemplate_assignments_pop:} +% \begin{syntax} +% "\xtemplate_assignments_pop:" +% \end{syntax} +% Pops \cs{l_xtemplate_assignment_toks}, and therefore executes +% the assignements stored there. +%\end{function} +% +%\begin{function}{\xtemplate_assignments_push:n} +% \begin{syntax} +% "\xtemplate_assignments_push:n" \marg{assignments} +% \end{syntax} +% Pushes <assignments> to \cs{l_xtemplate_assignment_toks} for later +% execution. +%\end{function} +% +%\subsection{Showing details} +% +%\begin{function}{\xtemplate_show_code:nn} +% \begin{syntax} +% "\xtemplate_show_code:nn" \marg{type} \marg{template} +% \end{syntax} +% Shows code associated with <template> of <type>. +%\end{function} +% +%\begin{function}{\xtemplate_show_code:nn} +% \begin{syntax} +% "\xtemplate_show_code:nn" \marg{type} \marg{template} +% \end{syntax} +% Shows code associated with <template> of <type>. +%\end{function} +% +%\begin{function}{\xtemplate_show_defaults:nn} +% \begin{syntax} +% "\xtemplate_show_default:nn" \marg{type} \marg{template} +% \end{syntax} +% Shows default values associated with <template> of <type>. +%\end{function} +% +%\begin{function}{\xtemplate_show_keytypes:nn} +% \begin{syntax} +% "\xtemplate_show_keytypes:nn" \marg{type} \marg{template} +% \end{syntax} +% Shows key types associated with <template> of <type>. +%\end{function} +% +%\begin{function}{\xtemplate_show_values:nnn} +% \begin{syntax} +% "\xtemplate_show_code:nnn" \marg{type} \marg{collection} +% ~~~~\marg{instance} +% \end{syntax} +% Shows values associated with <instance> of <type> within +% <collection>. +%\end{function} +% + +%\begin{function}{\xtemplate_show_vars:nn} +% \begin{syntax} +% "\xtemplate_show_vars:nn" \marg{type} \marg{template} +% \end{syntax} +% Shows variables associated with <template> of <type>. +%\end{function} +% +% \end{documentation} +% +% \begin{implementation} +% +%\section{Implementation} +% +% \pkg{xtemplate} only needs \pkg{expl3}; in format mode, this can be +% skipped. +% \begin{macrocode} +%<*package> +\ProvidesExplPackage + {\filename}{\filedate}{\fileversion}{\filedescription} +\RequirePackage{expl3} +%</package> +%<*initex|package> +% \end{macrocode} +% +%\subsubsection{Variables and constants} +% +%\begin{macro}{\c_xtemplate_code_root_tl} +%\begin{macro}{\c_xtemplate_defaults_root_tl} +%\begin{macro}{\c_xtemplate_instances_root_tl} +%\begin{macro}{\c_xtemplate_keytypes_root_tl} +%\begin{macro}{\c_xtemplate_restrict_root_tl} +%\begin{macro}{\c_xtemplate_values_root_tl} +%\begin{macro}{\c_xtemplate_vars_root_tl} +% So that literal values are kept to a minimum. +% \begin{macrocode} +\tl_new:Nn \c_xtemplate_code_root_tl { xtemplate_code > } +\tl_new:Nn \c_xtemplate_defaults_root_tl { xtemplate_defaults > } +\tl_new:Nn \c_xtemplate_instances_root_tl { xtemplate_instances > } +\tl_new:Nn \c_xtemplate_keytypes_root_tl { xtemplate_keytypes > } +\tl_new:Nn \c_xtemplate_restrict_root_tl { xtemplate_restrict > } +\tl_new:Nn \c_xtemplate_values_root_tl { xtemplate_values > } +\tl_new:Nn \c_xtemplate_vars_root_tl { xtemplate_vars > } +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\c_xtemplate_key_order_tl} +% A special property name, used to store the order keys are defined +% in. +% \begin{macrocode} +\tl_new:Nn \c_xtemplate_key_order_tl { key~order } +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\c_xtemplate_keytypes_arg_clist} +% A list of keytypes which also need additional data (an argument), used +% to parse the keytype correctly. +% \begin{macrocode} +\clist_new:N \c_xtemplate_keytypes_arg_clist +\clist_put_right:Nn \c_xtemplate_keytypes_arg_clist { choice } +\clist_put_right:Nn \c_xtemplate_keytypes_arg_clist { function } +\clist_put_right:Nn \c_xtemplate_keytypes_arg_clist { instance } +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\g_xtemplate_object_type_prop} +% For storing types and the associated number of arguments. +% \begin{macrocode} +\prop_new:N \g_xtemplate_object_type_prop +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\l_xtemplate_assignments_toks} +% When creating an instance, the assigned values are collected here. A +% toks is needed as there can be |#| tokens. +% \begin{macrocode} +\toks_new:N \l_xtemplate_assignments_toks +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\l_xtemplate_collection_tl} +% The current instance collection name is stored here. +% \begin{macrocode} +\tl_new:N \l_xtemplate_collection_tl +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\l_xtemplate_collections_prop} +% Lists current collection in force, indexed by object type. +% \begin{macrocode} +\prop_new:N \l_xtemplate_collections_prop +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\l_xtemplate_default_tl} +% The default value for a key is recovered here from the property list +% in which it is stored. The internal implementation of property lists +% means that this is safe even with un-escaped |#| tokens. +% \begin{macrocode} +\tl_new:N \l_xtemplate_default_tl +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\l_xtemplate_error_bool} +% A flag for errors to be carried forward. +% \begin{macrocode} +\bool_new:N \l_xtemplate_error_bool +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\l_xtemplate_global_bool} +% Used to indicate that assignments should be global. +% \begin{macrocode} +\bool_new:N \l_xtemplate_global_bool +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\l_xtemplate_restrict_bool} +% A flag to indicate that a template is being restricted. +% \begin{macrocode} +\bool_new:N \l_xtemplate_restrict_bool +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\l_xtemplate_restricted_clist} +% A scratch list for restricting templates. +% \begin{macrocode} +\clist_new:N \l_xtemplate_restricted_clist +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\l_xtemplate_key_name_tl} +%\begin{macro}{\l_xtemplate_keytype_tl} +%\begin{macro}{\l_xtemplate_keytype_arg_tl} +%\begin{macro}{\l_xtemplate_value_tl} +%\begin{macro}{\l_xtemplate_var_tl} +% When defining each key in a template, the name and type of the key +% need to be separated and stored. Any argument needed by the +% keytype is also stored separately. +% \begin{macrocode} +\tl_new:N \l_xtemplate_key_name_tl +\tl_new:N \l_xtemplate_keytype_tl +\tl_new:N \l_xtemplate_keytype_arg_tl +\tl_new:N \l_xtemplate_value_tl +\tl_new:N \l_xtemplate_var_tl +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\l_xtemplate_key_seq} +% The order that keys are declared needs to be know, so that they can +% be set in the same way. As property lists are not ordered data types, +% a separate list needs to be kept which \emph{is} ordered. This will +% then be stored in the property list. +% \begin{macrocode} +\seq_new:N \l_xtemplate_key_seq +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\l_xtemplate_keytypes_prop} +%\begin{macro}{\l_xtemplate_values_prop} +%\begin{macro}{\l_xtemplate_vars_prop} +% To avoid needing too many difficult-to-follow csname assignments, +% various scratch token registers are used to build up data, which is +% then transferred +% \begin{macrocode} +\prop_new:N \l_xtemplate_keytypes_prop +\prop_new:N \l_xtemplate_values_prop +\prop_new:N \l_xtemplate_vars_prop +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\l_xtemplate_tmp_clist} +%\begin{macro}{\l_xtemplate_tmp_dim} +%\begin{macro}{\l_xtemplate_tmp_int} +%\begin{macro}{\l_xtemplate_tmp_skip} +% For pre-processing the data stored by \pkg{xtemplate}, a number of +% scratch variables are needed. The assignments are made to these in the +% first instance, unless evaluation is delayed. +% \begin{macrocode} +\clist_new:N \l_xtemplate_tmp_clist +\dim_new:N \l_xtemplate_tmp_dim +\int_new:N \l_xtemplate_tmp_int +\skip_new:N \l_xtemplate_tmp_skip +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\l_xtemplate_tmp_tl} +% A scratch variable for comparisons and so on. +% \begin{macrocode} +\tl_new:N \l_xtemplate_tmp_tl +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\xtemplate_space:} +% A space! +% \begin{macrocode} +\cs_new_eq:NN \xtemplate_space: \iow_space: +% \end{macrocode} +%\end{macro} +% +%\subsection{Testing existence and validity} +% +% There are a number of checks needed for either the existence of +% a object type, template or instance. There are also some for the +% validity of a particular call. All of these are collected up here. +% +%\begin{macro}{\xtemplate_execute_if_arg_agree:nnT} +% A test agreement between the number of arguments for the template +% type and that specified when creating a template. This is not done as a +% separate conditional for efficiency and better error message +% \begin{macrocode} +\cs_new:Npn \xtemplate_execute_if_arg_agree:nnT #1#2#3 { + \prop_get:NnN \g_xtemplate_object_type_prop {#1} \l_xtemplate_tmp_tl + \intexpr_compare:nTF { #2 = \l_xtemplate_tmp_tl } + {#3} + { + \msg_kernel_error:nnxxx { xtemplate } + { argument-number-mismatch } {#1} { \l_xtemplate_tmp_tl } {#2} + } +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\xtemplate_execute_if_code_exist:nnT} +% A template is only fully declared if the code has been set up, +% which can be checked by looking for the template function itself. +% \begin{macrocode} +\cs_new:Npn \xtemplate_execute_if_code_exist:nnT #1#2#3 { + \cs_if_exist:cTF { \c_xtemplate_code_root_tl #1 / #2 :w } + {#3} + { + \msg_kernel_error:nnxx { xtemplate } { no-template-code } + {#1} {#2} + } +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\xtemplate_execute_if_keytype_exist:nT} +%\begin{macro}{\xtemplate_execute_if_keytype_exist:VF} +% The test for valid keytypes looks for a function to set up the key, +% which is part of the `code' side of the template definition. This +% avoids having different lists for the two parts of the process. +% \begin{macrocode} +\cs_new:Npn \xtemplate_execute_if_keytype_exist:nT #1#2 { + \cs_if_exist:cTF { xtemplate_store_value_ #1 :n } + {#2} + { \msg_kernel_error:nnx { xtemplate } { unknown-keytype } {#1} } +} +\cs_generate_variant:Nn \xtemplate_execute_if_keytype_exist:nT { V } +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\xtemplate_execute_if_type_exist:nT} +% To check that a particular object type is valid. +% \begin{macrocode} +\cs_new:Npn \xtemplate_execute_if_type_exist:nT #1#2 { + \prop_if_in:NnTF \g_xtemplate_object_type_prop {#1} + {#2} + { \msg_kernel_error:nnx { xtemplate } { unknown-object-type } {#1} } +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\xtemplate_execute_if_keys_exist:nnT} +% To check that the keys for a template have been set up before trying +% to create any code, a simple check for the correctly-named keytype +% property list. +% \begin{macrocode} +\cs_new:Npn \xtemplate_if_keys_exist:nnT #1#2#3 { + \cs_if_exist:cTF + { g_ \c_xtemplate_keytypes_root_tl #1 / #2 _prop } + {#3} + { + \msg_kernel_error:nnxx { xtemplate } { unknown-template } + {#1} {#2} + } +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\xtemplate_if_key_value:nT} +%\begin{macro}{\xtemplate_if_key_value:VT} +% Tests for the first token in a string being \cs{KeyValue}, where +% \cs{DelayEvaluation} is not important. +% \begin{macrocode} +\prg_set_conditional:Nnn \xtemplate_if_key_value:n { T } { + \tl_if_eq:noTF { \KeyValue } { \tl_head:w #1 \q_nil } { + \prg_return_true: + }{ + \prg_return_false: + } +} +\cs_generate_variant:Nn \xtemplate_if_key_value:nT { V } +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\xtemplate_if_eval_now:nTF} +% Tests for the first token in a string being \cs{EvaluateNow}. +% \begin{macrocode} +\prg_new_conditional:Nnn \xtemplate_if_eval_now:n { TF } { + \tl_if_eq:noTF { \EvaluateNow } { \tl_head:w #1 \q_nil } { + \prg_return_true: + }{ + \prg_return_false: + } +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}[TF]{\xtemplate_if_instance_exist:nnn} +% Testing for an instance is collection dependent. +% \begin{macrocode} +\prg_new_conditional:Nnn \xtemplate_if_instance_exist:nnn { T, F, TF } { + \cs_if_exist:cTF { \c_xtemplate_instances_root_tl #1 / #2 / #3 :w } { + \prg_return_true: + }{ + \prg_return_false: + } +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\xtemplate_if_use_template:nTF} +% Tests for the first token in a string being \cs{UseTemplate}. +% \begin{macrocode} +\prg_new_conditional:Nnn \xtemplate_if_use_template:n { TF } { + \tl_if_eq:noTF { \UseTemplate } { \tl_head:w #1 \q_nil } { + \prg_return_true: + }{ + \prg_return_false: + } +} +% \end{macrocode} +%\end{macro} +% +%\subsubsection{Saving and recovering property lists} +% +% The various property lists for templates have to be shuffled in +% and out of storage. +% +%\begin{macro}{\xtemplate_store_defaults:n} +%\begin{macro}{\xtemplate_store_keytypes:n} +%\begin{macro}{\xtemplate_store_restrictions:n} +%\begin{macro}{\xtemplate_store_values:n} +%\begin{macro}{\xtemplate_store_vars:n} +% The defaults and keytypes are transferred from the scratch property +% lists to the `proper' lists for the template being created. +% \begin{macrocode} +\cs_new:Npn \xtemplate_store_defaults:n #1 { + \cs_if_free:cT { g_ \c_xtemplate_defaults_root_tl #1 _prop } { + \prop_new:c { g_ \c_xtemplate_defaults_root_tl #1 _prop } + } + \prop_gset_eq:cN { g_ \c_xtemplate_defaults_root_tl #1 _prop } + \l_xtemplate_values_prop +} +\cs_new:Npn \xtemplate_store_keytypes:n #1 { + \cs_if_free:cTF { g_ \c_xtemplate_keytypes_root_tl #1 _prop } { + \msg_kernel_info:nnx { xtemplate } { define-template-interface } + {#1} + \prop_new:c { g_ \c_xtemplate_keytypes_root_tl #1 _prop } + } + { + \msg_kernel_warning:nnx { xtemplate } + { redefine-template-interface } {#1} + } + \prop_gset_eq:cN { g_ \c_xtemplate_keytypes_root_tl #1 _prop } + \l_xtemplate_keytypes_prop +} +\cs_new:Npn \xtemplate_store_values:n #1 { + \cs_if_free:cT { l_ \c_xtemplate_values_root_tl #1 _prop } { + \prop_new:c { l_ \c_xtemplate_values_root_tl #1 _prop } + } + \prop_set_eq:cN { l_ \c_xtemplate_values_root_tl #1 _prop } + \l_xtemplate_values_prop +} +\cs_new:Npn \xtemplate_store_restrictions:n #1 { + \clist_gset_eq:cN { g_ \c_xtemplate_restrict_root_tl #1 _clist } + \l_xtemplate_restrict_clist +} +\cs_new:Npn \xtemplate_store_vars:n #1 { + \cs_if_free:cTF { g_ \c_xtemplate_vars_root_tl #1 _prop } { + \msg_kernel_info:nnx { xtemplate } { define-template-code } {#1} + \prop_new:c { g_ \c_xtemplate_vars_root_tl #1 _prop } + } + { + \msg_kernel_warning:nnx { xtemplate } { redefine-template-code } + {#1} + } + \prop_gset_eq:cN { g_ \c_xtemplate_vars_root_tl #1 _prop } + \l_xtemplate_vars_prop +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\xtemplate_recover_defaults:n} +%\begin{macro}{\xtemplate_recover_keytypes:n} +%\begin{macro}{\xtemplate_recover_restrictions:n} +%\begin{macro}{\xtemplate_recover_values:n} +%\begin{macro}{\xtemplate_recover_vars:n} +% Recovering the stored data for a template is rather less complex +% than storing it. All that happens is the data is transferred from +% the permanent to the scratch storage. +% \begin{macrocode} +\cs_new:Npn \xtemplate_recover_defaults:n #1 { + \prop_set_eq:Nc \l_xtemplate_values_prop + { g_ \c_xtemplate_defaults_root_tl #1 _prop } +} +\cs_new:Npn \xtemplate_recover_keytypes:n #1 { + \prop_set_eq:Nc \l_xtemplate_keytypes_prop + { g_ \c_xtemplate_keytypes_root_tl #1 _prop } +} +\cs_new:Npn \xtemplate_recover_restrictions:n #1 { + \clist_set_eq:Nc \l_xtemplate_restrict_clist + { g_ \c_xtemplate_restrict_root_tl #1 _clist } +} +\cs_new:Npn \xtemplate_recover_values:n #1 { + \prop_set_eq:Nc \l_xtemplate_values_prop + { l_ \c_xtemplate_values_root_tl #1 _prop } +} +\cs_new:Npn \xtemplate_recover_vars:n #1 { + \prop_set_eq:Nc \l_xtemplate_vars_prop + { g_ \c_xtemplate_vars_root_tl #1 _prop } +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\subsubsection{Creating new object types} +% +%\begin{macro}{\xtemplate_declare_object_type:nn} +% Although the object type is the `top level' of the template system, +% it is actually very easy to implement. All that happens is that the +% number of arguments required is recorded, indexed by the name of the +% object type. +% \begin{macrocode} +\cs_new:Npn \xtemplate_declare_object_type:nn #1#2 { + \int_set:Nn \l_xtemplate_tmp_int {#2} + \bool_if:nTF { + \intexpr_compare_p:n { #2 > \c_nine } || + \intexpr_compare_p:n { #2 < \c_zero } + } { + \msg_kernel_error:nnxx { xtemplate } { bad-number-of-arguments } + {#1} { \exp_not:V \l_xtemplate_tmp_int } + }{ + \prop_if_in:NnTF \g_xtemplate_object_type_prop {#1} + { + \msg_kernel_warning:nnxx { xtemplate } { redefine-object-type } + {#1} {#2} + } + { + \msg_kernel_info:nnxx { xtemplate } { define-object-type } + {#1} {#2} + } + \prop_gput:NnV \g_xtemplate_object_type_prop {#1} + \l_xtemplate_tmp_int + } +} +% \end{macrocode} +%\end{macro} +% +%\subsection{Design part of template declaration} +% +% The `design' part of a template declaration defines the general +% behaviour of each key, and possibly a default value. However, it does +% not include the implementation. This means that what happens here is +% the two properties are saved to appropriate lists, which can then +% be used later to recover the information when implementing the keys. +% +%\begin{macro}{\xtemplate_declare_template_keys:nnnn} +% The main function for the `design' part of creating a template starts +% by checking that the object type exists and that the number of +% arguments required agree. If that is all fine, then the two storage +% areas for defaults and keytypes are initialised. The mechanism is then +% set up for the \pkg{l3keyval} module to actually parse the keys. +% Finally, the code hands of to the storage routine to save the parsed +% information properly. +% \begin{macrocode} +\cs_new:Npn \xtemplate_declare_template_keys:nnnn #1#2#3#4 { + \xtemplate_execute_if_type_exist:nT {#1} + { + \xtemplate_execute_if_arg_agree:nnT {#1} {#3} + { + \prop_clear:N \l_xtemplate_values_prop + \prop_clear:N \l_xtemplate_keytypes_prop + \seq_clear:N \l_xtemplate_key_seq + \cs_set_eq:NN \KV_key_no_value_elt:n \xtemplate_parse_keys_elt:n + \cs_set_eq:NN \KV_key_value_elt:nn \xtemplate_parse_keys_elt:nn + \KV_parse_space_removal_sanitize:n {#4} + \prop_put:NVV \l_xtemplate_keytypes_prop \c_xtemplate_key_order_tl + \l_xtemplate_key_seq + \xtemplate_store_defaults:n { #1 / #2 } + \xtemplate_store_keytypes:n { #1 / #2 } + } + } +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\xtemplate_parse_keys_elt:n} +%\begin{macro}[aux]{\xtemplate_parse_keys_elt_aux:n} +%\begin{macro}[aux]{\xtemplate_parse_keys_elt_aux:} +% Processing the key part of the key--value pair is always carried out +% using this function, even if a value was found. First, the key name +% is separated from the keytype, and if necessary the keytype is +% separated into two parts. This information is then used to check that +% the keytype is valid, before storing the keytype (plus argument if +% necessary) as a property of the key name. The key name is also stored +% (in braces) in the token list to record the order the keys are defined +% in. +% \begin{macrocode} +\cs_new:Npn \xtemplate_parse_keys_elt:n #1 { + \xtemplate_split_keytype:n {#1} + \bool_if:NF \l_xtemplate_error_bool + { + \xtemplate_execute_if_keytype_exist:VT \l_xtemplate_keytype_tl + { + \clist_map_function:nN { choice , function , instance } + \xtemplate_parse_keys_elt_aux:n + \bool_if:NF \l_xtemplate_error_bool + { + \seq_if_in:NVTF \l_xtemplate_key_seq + \l_xtemplate_key_name_tl + { + \msg_kernel_error:nnx { xtemplate } + { duplicate-key-interface } + { \l_xtemplate_key_name_tl } + } + { \xtemplate_parse_keys_elt_aux: } + } + } + } +} +\cs_new_nopar:Npn \xtemplate_parse_keys_elt_aux:n #1 { + \tl_if_eq:VnT \l_xtemplate_keytype_tl {#1} { + \tl_if_empty:NT \l_xtemplate_keytype_arg_tl { + \msg_kernel_error:nnx { xtemplate } + { keytype-requires-argument } {#1} + \bool_set_true:N \l_xtemplate_error_bool + \clist_map_break: + } + } +} +\cs_new_nopar:Npn \xtemplate_parse_keys_elt_aux: { + \tl_set:Nx \l_xtemplate_tmp_tl { + \l_xtemplate_keytype_tl + \l_xtemplate_keytype_arg_tl + } + \prop_put:NVV \l_xtemplate_keytypes_prop \l_xtemplate_key_name_tl + \l_xtemplate_tmp_tl + \seq_put_right:NV \l_xtemplate_key_seq \l_xtemplate_key_name_tl + \tl_if_eq:VnT \l_xtemplate_keytype_tl { choice } { + \clist_if_in:NnT \l_xtemplate_keytype_arg_tl { unknown } { + \msg_kernel_error:nn { xtemplate } { choice-unknown-reserved } + } + } +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\xtemplate_parse_keys_elt:nn} +% For keys which have a default, the keytype and key name are first +% separated out by the \cs{xtemplate_parse_keys_elt:n} +% routine, before storing the default value in the scratch property list. +% Choices have special handling as the code is not yet available to +% actually do the storing! +% \begin{macrocode} +\cs_new:Npn \xtemplate_parse_keys_elt:nn #1#2 { + \xtemplate_parse_keys_elt:n {#1} + \tl_if_eq:VnTF \l_xtemplate_keytype_tl { choice } { + \xtemplate_store_value_choice_name:n {#2} + }{ + \use:c { xtemplate_store_value_ \l_xtemplate_keytype_tl :n } {#2} + } +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\xtemplate_split_keytype:n} +%\begin{macro}[aux]{\xtemplate_split_keytype_aux:w} +% The keytype and key name should be separated by `\texttt{:}'. As the +% definition might be given inside or outside of a code block, spaces +% are removed and the category code of colons is standardised. After +% that, the standard delimited argument method is used to separate the +% two parts. +% \begin{macrocode} +\group_begin: +\char_set_lccode:nn { `\@ } { `\: } +\char_make_other:N \@ +\tl_to_lowercase:n { + \group_end: + \cs_new:Npn \xtemplate_split_keytype:n #1 { + \bool_set_false:N \l_xtemplate_error_bool + \tl_set:Nn \l_xtemplate_tmpa_tl {#1} + \tl_replace_all_in:Nnn \l_xtemplate_tmpa_tl { ~ } { } + \tl_replace_all_in:Nnn \l_xtemplate_tmpa_tl { : } { @ } + \tl_if_in:VnTF \l_xtemplate_tmpa_tl { @ } { + \exp_after:wN \xtemplate_split_keytype_aux:w \l_xtemplate_tmpa_tl + \q_stop + }{ + \bool_set_true:N \l_xtemplate_error_bool + \msg_kernel_error:nnx { xtemplate } { no-keytype } {#1} + } + } + \cs_new:Npn \xtemplate_split_keytype_aux:w #1 @ #2 \q_stop { + \tl_if_empty:nT {#1} { + \msg_kernel_error:nnx { xtemplate } { empty-key-name } { @ #2 } + } + \tl_set:Nx \l_xtemplate_key_name_tl { \tl_to_str:n {#1} } + \xtemplate_split_keytype_arg:n {#2} + } +} +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\xtemplate_split_keytype_arg:n} +%\begin{macro}{\xtemplate_split_keytype_arg:V} +%\begin{macro}[aux]{\xtemplate_split_keytype_arg_aux:n} +%\begin{macro}[aux]{\xtemplate_split_keytype_arg_aux:w} +% The second stage of sorting out the keytype is to check for an +% argument. As there is no convenient delimiting token to look for, +% a check is made instead for each possible text value for the keytype. +% To keep things faster, this only involves the keytypes that need an +% argument. If a match is made, then a check is also needed to see that +% it is at the start of the keytype information. All being well, the +% split can then be applied. Any non-matching keytypes are assumed to +% be `correct' as given, and are left alone (this is checked by other +% code). +% \begin{macrocode} +\cs_new:Npn \xtemplate_split_keytype_arg:n #1 { + \tl_set:Nn \l_xtemplate_keytype_tl {#1} + \tl_clear:N \l_xtemplate_keytype_arg_tl + \cs_set_nopar:Npn \xtemplate_split_keytype_arg_aux:n ##1 { + \tl_if_in:nnT {#1} {##1} { + \cs_set:Npn \xtemplate_split_keytype_arg_aux:w + ####1 ##1 ####2 \q_stop { + \tl_if_empty:nT {####1} { + \tl_set:Nn \l_xtemplate_keytype_tl {##1} + \tl_set:Nn \l_xtemplate_keytype_arg_tl {####2} + \clist_map_break: + } + } + \xtemplate_split_keytype_arg_aux:w #1 \q_stop + } + } + \clist_map_function:NN \c_xtemplate_keytypes_arg_clist + \xtemplate_split_keytype_arg_aux:n +} +\cs_generate_variant:Nn \xtemplate_split_keytype_arg:n { V } +\cs_new_nopar:Npn \xtemplate_split_keytype_arg_aux:n #1 { } +\cs_new_nopar:Npn \xtemplate_split_keytype_arg_aux:w #1 \q_stop { } +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\subsubsection{Storing values} +% +% As \pkg{xtemplate} pre-processes key values for efficiency reasons, +% there is a need to convert the values given as defaults into +% `ready to use' data. The same general idea is true when an instance +% is declared. However, assignments are not made until an instance is +% used, and so there has to be some intermediate storage. Furthermore, +% the ability to delay evaluation of results is needed. To achieve these +% aims, a series of `process and store' functions are defined here. +% +% All of the information about the key (the key name and the keytype) +% is already stored as variables. The same property list is always used +% to store the data, meaning that the only argument required is the +% value to be processed and potentially stored. +% +%\begin{macro}{\xtemplate_store_value_boolean:n} +% Storing Boolean values requires a test for delayed evaluation, but +% is different to the various numerical variable types as there are +% only two possible values to store. So the code here tests the default +% switch and then records the meaning (either \texttt{true} or +% \texttt{false}). +% \begin{macrocode} +\cs_new:Npn \xtemplate_store_value_boolean:n #1 { + \xtemplate_if_eval_now:nTF {#1} { + \bool_if:cTF { c_ #1 _bool } { + \prop_put:NVn \l_xtemplate_values_prop \l_xtemplate_key_name_tl + { true } + }{ + \prop_put:NVn \l_xtemplate_values_prop \l_xtemplate_key_name_tl + { false } + } + }{ + \prop_put:NVn \l_xtemplate_values_prop \l_xtemplate_key_name_tl {#1} + } +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\xtemplate_store_value_choice:n} +%\begin{macro}{\xtemplate_store_value_choice:V} +%\begin{macro}[aux]{\xtemplate_store_value_choice_aux:n} +%\begin{macro}[aux]{\xtemplate_store_value_choice_aux:V} +%\begin{macro}{\xtemplate_store_value_choice_name:n} +% Choices are a bit odd, as they have to be handled in two parts. When +% an interface is being created, the default is stored with a hidden +% name (using spaces and letter category codes). When a choice is +% actually being used, there is a check for the choice itself, then +% code to handle an unknown before issuing an error. +% \begin{macrocode} +\cs_new:Npn \xtemplate_store_value_choice:n #1 { + \tl_set:Nx \l_xtemplate_tmp_tl + { \l_xtemplate_key_name_tl \xtemplate_space: #1 } + \prop_if_in:NVTF \l_xtemplate_vars_prop \l_xtemplate_tmp_tl { + \xtemplate_store_value_choice_aux:V \l_xtemplate_tmp_tl + }{ + \tl_set:Nx \l_xtemplate_tmp_tl + { \l_xtemplate_key_name_tl \xtemplate_space: unknown } + \prop_if_in:NVTF \l_xtemplate_vars_prop \l_xtemplate_tmp_tl { + \xtemplate_store_value_choice_aux:V \l_xtemplate_tmp_tl + }{ + \prop_get:NVN \l_xtemplate_keytypes_prop \l_xtemplate_key_name_tl + \l_xtemplate_tmp_tl + \xtemplate_split_keytype_arg:V \l_xtemplate_tmp_tl + \msg_kernel_error:nnxxx { xtemplate } { unknown-choice } + {#1} + { \l_xtemplate_key_name_tl } + { \l_xtemplate_keytype_arg_tl } + \prop_gdel:NV \l_xtemplate_values_prop \l_xtemplate_key_name_tl + } + } +} +\cs_generate_variant:Nn \xtemplate_store_value_choice:n { V } +\cs_new:Npn \xtemplate_store_value_choice_aux:n #1 { + \prop_get:NnN \l_xtemplate_vars_prop {#1} \l_xtemplate_tmp_tl + \prop_put:NVV \l_xtemplate_values_prop \l_xtemplate_key_name_tl + \l_xtemplate_tmp_tl +} +\cs_generate_variant:Nn \xtemplate_store_value_choice_aux:n { V } +\cs_new:Npn \xtemplate_store_value_choice_name:n #1 { + \tl_set:Nx \l_xtemplate_tmp_tl + { \l_xtemplate_key_name_tl \xtemplate_space: default } + \prop_put:NVn \l_xtemplate_values_prop \l_xtemplate_tmp_tl {#1} +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\xtemplate_store_value_code:n} +%\begin{macro}{\xtemplate_store_value_commalist:n} +%\begin{macro}{\xtemplate_store_value_function:n} +%\begin{macro}{\xtemplate_store_value_instance:n} +%\begin{macro}{\xtemplate_store_value_tokenlist:n} +% With no need to worry about delayed evaluation, these keytypes all +% just store the input directly. +% \begin{macrocode} +\cs_new:Npn \xtemplate_store_value_code:n #1 { + \prop_put:NVn \l_xtemplate_values_prop \l_xtemplate_key_name_tl {#1} +} +\cs_new:Npn \xtemplate_store_value_commalist:n #1 { + \prop_put:NVn \l_xtemplate_values_prop \l_xtemplate_key_name_tl {#1} +} +\cs_new:Npn \xtemplate_store_value_function:n #1 { + \prop_put:NVn \l_xtemplate_values_prop \l_xtemplate_key_name_tl {#1} +} +\cs_new:Npn \xtemplate_store_value_instance:n #1 { + \prop_put:NVn \l_xtemplate_values_prop \l_xtemplate_key_name_tl {#1} +} +\cs_new:Npn \xtemplate_store_value_tokenlist:n #1 { + \prop_put:NVn \l_xtemplate_values_prop \l_xtemplate_key_name_tl {#1} +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\xtemplate_store_value_integer:n} +%\begin{macro}{\xtemplate_store_value_length:n} +%\begin{macro}{\xtemplate_store_value_skip:n} +% Storing the value of a number is in all cases more or less the same. +% If evaluation is taking place now, assignment is made to a scratch +% variable, and this result is then stored. On the other hand, if +% evaluation is delayed the current data is simply stored `as is'. +% \begin{macrocode} +\cs_new:Npn \xtemplate_store_value_integer:n #1 { + \xtemplate_if_eval_now:nTF {#1} { + \int_set:Nn \l_xtemplate_tmp_int {#1} + \prop_put:NVV \l_xtemplate_values_prop \l_xtemplate_key_name_tl + \l_xtemplate_tmp_int + }{ + \prop_put:NVn \l_xtemplate_values_prop \l_xtemplate_key_name_tl {#1} + } +} +\cs_new:Npn \xtemplate_store_value_length:n #1 { + \xtemplate_if_eval_now:nTF {#1} { + \dim_set:Nn \l_xtemplate_tmp_dim {#1} + \prop_put:NVV \l_xtemplate_values_prop \l_xtemplate_key_name_tl + \l_xtemplate_tmp_dim + }{ + \prop_put:NVn \l_xtemplate_values_prop \l_xtemplate_key_name_tl {#1} + } +} +\cs_new:Npn \xtemplate_store_value_skip:n #1 { + \xtemplate_if_eval_now:nTF {#1} { + \skip_set:Nn \l_xtemplate_tmp_skip {#1} + \prop_put:NVV \l_xtemplate_values_prop \l_xtemplate_key_name_tl + \l_xtemplate_tmp_skip + }{ + \prop_put:NVn \l_xtemplate_values_prop \l_xtemplate_key_name_tl {#1} + } +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\subsubsection{Implementation part of template declaration} +% +%\begin{macro}{\xtemplate_declare_template_code:nnnnn} +% The main function for implementing a template starts with a couple of +% simple checks to make sure that there are no obvious mistakes: the +% number of arguments must agree and the template keys must have been +% declared. +% \begin{macrocode} +\cs_new:Npn \xtemplate_declare_template_code:nnnnn #1#2#3#4#5 { + \xtemplate_execute_if_type_exist:nT {#1} + { + \xtemplate_execute_if_arg_agree:nnT {#1}{#3} + { + \xtemplate_if_keys_exist:nnT {#1} {#2} + { + \xtemplate_store_key_implementation:nnn {#1} {#2} {#4} + \cs_generate_from_arg_count:cNnn + { \c_xtemplate_code_root_tl #1 / #2 :w } \cs_gset:Npn + {#3} {#5} + } + } + } +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\xtemplate_store_key_implementation:nnn} +% Actually storing the implementation part of a template is quite easy +% as it only requires the list of keys given to be turned into a +% property list. There is also some error-checking to do, hence the need +% to have the list of defined keytypes available. In certain cases +% (when choices are involved) parsing the key results in changes to the +% default values. That is why they are loaded and then saved again. +% \begin{macrocode} +\cs_set:Npn \xtemplate_store_key_implementation:nnn #1#2#3 { + \xtemplate_recover_defaults:n { #1 / #2 } + \xtemplate_recover_keytypes:n { #1 / #2 } + \prop_clear:N \l_xtemplate_vars_prop + \cs_set_eq:NN \KV_key_no_value_elt:n \xtemplate_parse_vars_elt:n + \cs_set_eq:NN \KV_key_value_elt:nn \xtemplate_parse_vars_elt:nn + \KV_parse_space_removal_sanitize:n {#3} +% \end{macrocode} +% In certain cases (when choices are involved) parsing the key results in +% changes to the default values. Therefore we have to save those back. +% \begin{macrocode} + \xtemplate_store_defaults:n { #1 / #2 } + \xtemplate_store_vars:n { #1 / #2 } + \clist_clear:N \l_xtemplate_restrict_clist + \xtemplate_store_restrictions:n { #1 / #2 } + \prop_del:NV \l_xtemplate_keytypes_prop \c_xtemplate_key_order_tl + \prop_if_empty:NF \l_xtemplate_keytypes_prop { + \prop_map_inline:Nn \l_xtemplate_keytypes_prop { + \msg_kernel_error:nnxxx { xtemplate } { key-not-implemented } + {##1} {#2} {#1} + } + } +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\xtemplate_parse_vars_elt:n} +% At the implementation stage, every key must have a value given. So +% this is an error function. +% \begin{macrocode} +\cs_new:Npn \xtemplate_parse_vars_elt:n #1 { + \msg_kernel_error:nnx { xtemplate } { key-no-variable } {#1} +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\xtemplate_parse_vars_elt:nn} +% The actual storage part here is very simple: the storage bin name +% is placed into the property list. At the same time, a comparison is +% made with the keytypes defined earlier: if there is a mismatch then +% an error is raised. +% \begin{macrocode} +\cs_new:Npn \xtemplate_parse_vars_elt:nn #1#2 { + \tl_set:Nx \l_xtemplate_key_name_tl { \tl_to_str:n {#1} } + \tl_replace_all_in:Nnn \l_xtemplate_key_name_tl { ~ } { } + \prop_if_in:NVTF \l_xtemplate_keytypes_prop \l_xtemplate_key_name_tl { + \prop_get:NVN \l_xtemplate_keytypes_prop \l_xtemplate_key_name_tl + \l_xtemplate_keytype_tl + \xtemplate_split_keytype_arg:V \l_xtemplate_keytype_tl + \xtemplate_parse_vars_elt_aux:n {#2} + \prop_del:NV \l_xtemplate_keytypes_prop \l_xtemplate_key_name_tl + }{ + \msg_kernel_error:nnx { xtemplate } { unknown-key } {#1} + } +} +% \end{macrocode} +%\end{macro} +%\begin{macro}[aux]{\xtemplate_parse_vars_elt_aux:n} +%\begin{macro}[aux]{\xtemplate_parse_vars_elt_aux:w} +% There now needs to be some sanity checking on the variable name +% given. This does not apply for \texttt{choice} or +% \texttt{code} `variables', but in all other cases the variable needs +% to exist. Also, the only prefix acceptable is \texttt{global}. So +% there are a few related checks to make. +% \begin{macrocode} +\cs_new:Npn \xtemplate_parse_vars_elt_aux:n #1 { + \tl_if_eq:VnTF \l_xtemplate_keytype_tl { choice } + { + \xtemplate_implement_choices:n {#1} + } + { + \tl_if_eq:VnTF \l_xtemplate_keytype_tl { code } + { + \prop_put:NVn \l_xtemplate_vars_prop + \l_xtemplate_key_name_tl {#1} + } + { + \tl_if_eq:noTF {#1} { \tl_head:w #1 \q_nil } + { + \cs_if_exist:NTF #1 + { + \prop_put:NVn \l_xtemplate_vars_prop + \l_xtemplate_key_name_tl {#1} + } + { + \msg_kernel_error:nnx { xtemplate } + { undeclared-variable } + { \exp_not:N #1 } + } + } + { + \tl_if_in:nnTF {#1} { global } + { \xtemplate_parse_vars_elt_aux:w #1 \q_nil } + { + \msg_kernel_error:nnx { xtemplate } { bad-variable } + { \exp_not:n {#1} } + } + } + } + } +} +\cs_new:Npn \xtemplate_parse_vars_elt_aux:w #1 global #2 \q_nil { + \tl_if_empty:nTF {#1} + { + \tl_if_eq:noTF {#2} { \tl_head:w #2 \q_nil } + { + \cs_if_exist:NTF #2 + { + \prop_put:NVn \l_xtemplate_vars_prop + \l_xtemplate_key_name_tl { #1 global #2 } + } + { + \msg_kernel_error:nnx { xtemplate } + { undeclared-variable } + { \exp_not:N #2 } + } + } + { + \msg_kernel_error:nnx { xtemplate } { bad-variable } + { \exp_not:n { #1 global #2 } } + } + } + { + \msg_kernel_error:nnx { xtemplate } { bad-variable } + { \exp_not:n { #1 global #2 } } + } +} +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\xtemplate_implement_choices:n} +% Implementing choices requires a second key--value loop. So after a +% little set-up, the standard parser is called. There is then a +% check for a default choice being set: at this stage the name of +% the choice is replaced by the code to implement it. +% \begin{macrocode} +\cs_new:Npn \xtemplate_implement_choices:n #1 { + \clist_set_eq:NN \l_xtemplate_tmp_clist \l_xtemplate_keytype_arg_tl + \cs_set_eq:NN \KV_key_no_value_elt:n \xtemplate_implement_choice_elt:n + \cs_set_eq:NN \KV_key_value_elt:nn \xtemplate_implement_choice_elt:nn + \prop_put:NVn \l_xtemplate_vars_prop \l_xtemplate_key_name_tl { } + \KV_parse_space_removal_sanitize:n {#1} + \cs_set_eq:NN \KV_key_no_value_elt:n \xtemplate_parse_vars_elt:n + \cs_set_eq:NN \KV_key_value_elt:nn \xtemplate_parse_vars_elt:nn + \tl_set:Nx \l_xtemplate_tmp_tl + { \l_xtemplate_key_name_tl \xtemplate_space: default } + \prop_if_in:NVT \l_xtemplate_values_prop \l_xtemplate_tmp_tl { + \prop_get:NVN \l_xtemplate_values_prop \l_xtemplate_tmp_tl + \l_xtemplate_tmp_tl + \xtemplate_store_value_choice:V \l_xtemplate_tmp_tl + } + \clist_if_empty:NF \l_xtemplate_tmp_clist { + \clist_map_inline:Nn \l_xtemplate_tmp_clist + { + \msg_kernel_error:nnx { xtemplate } { choice-not-implemented } + {##1} + } + } +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\xtemplate_implement_choice_elt:n} +%\begin{macro}{\xtemplate_implement_choice_elt:nn} +% The actual storage of the implementation of a choice is mainly about +% error checking. The code here ensures that all choices have to have +% been declared, apart from the special \texttt{unknown} choice, which +% must come last. The code for each choice is stored along with the +% key name in the variables property list. +% \begin{macrocode} +\cs_new:Npn \xtemplate_implement_choice_elt:n #1 { + \clist_if_empty:NTF \l_xtemplate_tmp_clist { + \tl_if_eq:nnF {#1} { unknown } { + \prop_get:NVN \l_xtemplate_keytypes_prop \l_xtemplate_key_name_tl + \l_xtemplate_tmp_tl + \xtemplate_split_keytype_arg:V \l_xtemplate_tmp_tl + \msg_kernel_error:nnxxx { xtemplate } { unknown-choice } + {#1} + { \l_xtemplate_key_name_tl } + { \l_xtemplate_keytype_arg_tl } + } + }{ + \clist_if_in:NnTF \l_xtemplate_tmp_clist {#1} { + \clist_remove_element:Nn \l_xtemplate_tmp_clist {#1} + }{ + \prop_get:NVN \l_xtemplate_keytypes_prop \l_xtemplate_key_name_tl + \l_xtemplate_tmp_tl + \xtemplate_split_keytype_arg:V \l_xtemplate_tmp_tl + \msg_kernel_error:nnxxx { xtemplate } { unknown-choice } + {#1} + { \l_xtemplate_key_name_tl } + { \l_xtemplate_keytype_arg_tl } + } + } +} +\cs_new:Npn \xtemplate_implement_choice_elt:nn #1#2 { + \xtemplate_implement_choice_elt:n {#1} + \tl_set:Nx \l_xtemplate_tmp_tl + { \l_xtemplate_key_name_tl \xtemplate_space: #1 } + \prop_put:NVn \l_xtemplate_vars_prop \l_xtemplate_tmp_tl {#2} +} +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\subsubsection{Editing template defaults} +% +% Template defaults can be edited either with no other changes or +% to prevent further editing, forming a ``restricted template''. +% In the later case, a new template results, whereas simple editing +% does not produce a new template name. +% +%\begin{macro}{\xtemplate_declare_restricted:nnnn} +% Creating a restricted template means copying the old template to the +% new one first. +% \begin{macrocode} +\cs_new:Npn \xtemplate_declare_restricted:nnnn #1#2#3#4 { + \xtemplate_if_keys_exist:nnT {#1} {#2} + { + \xtemplate_set_template_eq:nn { #1 / #3 } { #1 / #2 } + \bool_set_true:N \l_xtemplate_restrict_bool + \xtemplate_edit_defaults_aux:nnn {#1} {#3} {#4} + } +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\xtemplate_edit_defaults:nnn} +%\begin{macro}[aux]{\xtemplate_edit_defaults_aux:nnn} +% Editing the template defaults means getting the values back out +% of the store, then parsing the list of new values before putting +% the updated list back into storage. The auxiliary function is used +% to allow code-sharing with the template-restriction system. +% \begin{macrocode} +\cs_new:Npn \xtemplate_edit_defaults:nnn { + \bool_set_false:N \l_xtemplate_restrict_bool + \xtemplate_edit_defaults_aux:nnn +} +\cs_new:Npn \xtemplate_edit_defaults_aux:nnn #1#2#3 { + \xtemplate_if_keys_exist:nnT {#1} {#2} + { + \xtemplate_recover_defaults:n { #1 / #2 } + \xtemplate_recover_restrictions:n { #1 / #2 } + \xtemplate_parse_values:nn { #1 / #2 } {#3} + \xtemplate_store_defaults:n { #1 / #2 } + \xtemplate_store_restrictions:n { #1 / #2 } + } +} +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\xtemplate_parse_values:nn} +% The routine to parse values is the same for both editing a +% template and setting up an instance. So the code here does only the +% minimum necessary for reading the values. +% \begin{macrocode} +\cs_new:Npn \xtemplate_parse_values:nn #1#2 { + \xtemplate_recover_keytypes:n {#1} + \clist_clear:N \l_xtemplate_restricted_clist + \cs_set_eq:NN \KV_key_no_value_elt:n \xtemplate_parse_values_elt:n + \cs_set_eq:NN \KV_key_value_elt:nn \xtemplate_parse_values_elt:nn + \KV_parse_space_removal_sanitize:n {#2} +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\xtemplate_parse_values_elt:n} +% Every key needs a value, so this is just an error routine. +% \begin{macrocode} +\cs_new:Npn \xtemplate_parse_values_elt:n #1 { + \bool_set_true:N \l_xtemplate_error_bool + \msg_kernel_error:nnx { xtemplate } { key-no-value } {#1} +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\xtemplate_parse_values_elt:nn} +%\begin{macro}[aux]{\xtemplate_parse_values_elt_aux:nn} +%\begin{macro}[aux]{\xtemplate_parse_values_elt_aux:Vn} +% To store the value, find the keytype then call the saving function. +% These need the current key name saved as \cs{l_xtemplate_key_name_tl}. +% When a template is being restricted, the setting code will be +% skipped for restricted keys. +% \begin{macrocode} +\cs_new:Npn \xtemplate_parse_values_elt:nn #1#2 { + \tl_set:Nx \l_xtemplate_key_name_tl { \tl_to_str:n {#1} } + \tl_replace_all_in:Nnn \l_xtemplate_key_name_tl { ~ } { } + \prop_if_in:NVTF \l_xtemplate_keytypes_prop \l_xtemplate_key_name_tl { + \bool_if:NTF \l_xtemplate_restrict_bool { + \clist_if_in:NVF \l_xtemplate_restricted_clist + \l_xtemplate_key_name_tl { + \xtemplate_parse_values_elt_aux:Vn \l_xtemplate_key_name_tl {#2} + } + }{ + \xtemplate_parse_values_elt_aux:Vn \l_xtemplate_key_name_tl {#2} + } + }{ + \msg_kernel_error:nnx { xtemplate } { unknown-key } + { \l_xtemplate_key_name_tl } + } +} +\cs_new:Npn \xtemplate_parse_values_elt_aux:nn #1#2 { + \clist_put_right:Nn \l_xtemplate_restricted_clist {#1} + \prop_get:NnN \l_xtemplate_keytypes_prop {#1} \l_xtemplate_tmp_tl + \xtemplate_split_keytype_arg:V \l_xtemplate_tmp_tl + \use:c { xtemplate_store_value_ \l_xtemplate_keytype_tl :n } {#2} +} +\cs_generate_variant:Nn \xtemplate_parse_values_elt_aux:nn { Vn } +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\xtemplate_set_template_eq:nn} +% To copy a template, each of the lists plus the code has to be copied +% across. To keep this independent of the list storage system, it is +% all done with two-part shuffles. +% \begin{macrocode} +\cs_new:Npn \xtemplate_set_template_eq:nn #1#2 { + \xtemplate_recover_defaults:n {#2} + \xtemplate_store_defaults:n {#1} + \xtemplate_recover_keytypes:n {#2} + \xtemplate_store_keytypes:n {#1} + \xtemplate_recover_vars:n {#2} + \xtemplate_store_vars:n {#1} + \cs_gset_eq:cc { \c_xtemplate_code_root_tl #1 :w } + { \c_xtemplate_code_root_tl #2 :w } +} +% \end{macrocode} +%\end{macro} +% +%\subsubsection{Creating instances of templates} +% +%\begin{macro}{\xtemplate_declare_instance:nnnnn} +%\begin{macro}[aux]{\xtemplate_declare_instance_aux:nnnnn} +% Making an instance has two distinct parts. First, the keys given are +% parsed to transfer the values into the structured data format used +% internally. This allows the default and given values to be combined +% with no repetition. In the second step, the structured data is +% converted to pre-defined variable assignments, and these are stored +% in the function for the instance. A final check is also made so that +% there is always an instance `outside' of any collection. +% \begin{macrocode} +\cs_new:Npn \xtemplate_declare_instance:nnnnn #1#2#3#4#5 { + \xtemplate_execute_if_code_exist:nnT {#1} {#2} + { + \xtemplate_recover_defaults:n { #1 / #2 } + \xtemplate_recover_vars:n { #1 / #2 } + \xtemplate_declare_instance_aux:nnnnn {#1} {#2} {#3} {#4} {#5} + } +} +\cs_new:Npn \xtemplate_declare_instance_aux:nnnnn #1#2#3#4#5 { + \bool_set_false:N \l_xtemplate_error_bool + \xtemplate_parse_values:nn { #1 / #2 } {#5} + \bool_if:NF \l_xtemplate_error_bool { + \prop_put:Nnn \l_xtemplate_values_prop { from~template } {#2} + \xtemplate_store_values:n { #1 / #3 / #4 } + \xtemplate_convert_to_assignments: + \cs_set:cpx { \c_xtemplate_instances_root_tl #1 / #3 / #4 :w } { + \exp_not:N \xtemplate_assignments_push:n { + \exp_not:V \l_xtemplate_assignments_toks + } + \exp_not:c { \c_xtemplate_code_root_tl #1 / #2 :w } + } + \xtemplate_if_instance_exist:nnnF {#1} { } {#4} { + \cs_set_eq:cc + { \c_xtemplate_instances_root_tl #1 / / #4 :w } + { \c_xtemplate_instances_root_tl #1 / #3 / #4 :w } + } + } +} +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\xtemplate_edit_instance:nnnn} +%\begin{macro}[aux]{\xtemplate_edit_instance_aux:nnnnn} +%\begin{macro}[aux]{\xtemplate_edit_instance_aux:nVnnn} +% Editing an instance is almost identical to declaring one. The only +% variation is the source of the values to use. When editing, they are +% recovered from the previous instance run. +% \begin{macrocode} +\cs_new:Npn \xtemplate_edit_instance:nnnn #1#2#3 { + \xtemplate_if_instance_exist:nnnTF {#1} {#2} {#3} + { + \xtemplate_recover_values:n { #1 / #2 / #3 } + \prop_get:NnN \l_xtemplate_values_prop { from~template } + \l_xtemplate_tmp_tl + \xtemplate_edit_instance_aux:nVnnn {#1} \l_xtemplate_tmp_tl + {#2} {#3} + } + { + \msg_kernel_error:nnxx { xtemplate } { unknown-instance } + {#1} {#3} + } +} +\cs_new:Npn \xtemplate_edit_instance_aux:nnnnn #1#2 { + \xtemplate_recover_vars:n { #1 / #2 } + \xtemplate_declare_instance_aux:nnnnn {#1} {#2} +} +\cs_generate_variant:Nn \xtemplate_edit_instance_aux:nnnnn { nV } +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\xtemplate_convert_to_assignments:} +%\begin{macro}[aux]{\xtemplate_convert_to_assignments_aux:n} +%\begin{macro}[aux]{\xtemplate_convert_to_assignments_aux:nn} +%\begin{macro}[aux]{\xtemplate_convert_to_assignments_aux:nV} +% The idea on converting to a set of assignments is to loop over each +% key, so that the loop order follows the declaration order of the keys. +% This is done using a sequence as property lists are not ``ordered''. +% \begin{macrocode} +\cs_new_nopar:Npn \xtemplate_convert_to_assignments: { + \toks_clear:N \l_xtemplate_assignments_toks + \prop_get:NVN \l_xtemplate_keytypes_prop \c_xtemplate_key_order_tl + \l_xtemplate_key_seq + \seq_map_function:NN \l_xtemplate_key_seq + \xtemplate_convert_to_assignments_aux:n +} +\cs_new:Npn \xtemplate_convert_to_assignments_aux:n #1 { + \prop_get:NnN \l_xtemplate_keytypes_prop {#1} \l_xtemplate_tmp_tl + \xtemplate_convert_to_assignments_aux:nV {#1} \l_xtemplate_tmp_tl +} +% \end{macrocode} +% The second auxiliary function actually does the work. The +% arguments here are the key name (|#1|) and the keytype (|#2|). +% From those, the value to assign and the name of the appropriate +% variable are recovered. A bit of work is then needed to sort out +% keytypes with arguments (for example instances), and to look for +% global assignments. Once that is done, a hand-off can be made to the +% handler for the relevant keytype. +% \begin{macrocode} +\cs_new:Npn \xtemplate_convert_to_assignments_aux:nn #1#2 { + \prop_if_in:NnT \l_xtemplate_values_prop {#1} { + \prop_if_in:NnTF \l_xtemplate_vars_prop {#1} { + \prop_get:NnN \l_xtemplate_values_prop {#1} \l_xtemplate_value_tl + \prop_get:NnN \l_xtemplate_vars_prop {#1} \l_xtemplate_var_tl + \xtemplate_split_keytype_arg:n {#2} + \tl_if_eq:VnF \l_xtemplate_keytype_tl { choice } { + \tl_if_eq:VnF \l_xtemplate_keytype_tl { code } { + \xtemplate_find_global: + } + } + \use:c { xtemplate_assign_ \l_xtemplate_keytype_tl : } + }{ + \msg_kernel_error:nnx { xtemplate } { unknown-attribute } {#1} + } + } +} +\cs_generate_variant:Nn \xtemplate_convert_to_assignments_aux:nn { nV } +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\xtemplate_find_global:} +%\begin{macro}[aux]{\xtemplate_find_global_aux:w} +% Global assignments should have the phrase ``global'' at the front. +% This is pretty easy to find: no other error checking, though. +% \begin{macrocode} +\cs_new_nopar:Npn \xtemplate_find_global: { + \bool_set_false:N \l_xtemplate_global_bool + \tl_if_in:VnT \l_xtemplate_var_tl { global } { + \exp_after:wN \xtemplate_find_global_aux:w \l_xtemplate_var_tl \q_stop + } +} +\cs_new:Npn \xtemplate_find_global_aux:w #1 global #2 \q_stop { + \tl_set:Nn \l_xtemplate_var_tl {#2} + \bool_set_true:N \l_xtemplate_global_bool +} +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\subsection{Using templates directly} +% +% \begin{macro}{\xtemplate_use_template:nnn} +% Directly use a template with a particular parameter setting. +% This is also picked up if used in a nested fashion inside a parameter +% list. The idea is essentially the same as creating an instance, +% just with no saving of the result. +% \begin{macrocode} +\cs_new:Npn \xtemplate_use_template:nnn #1#2#3 { + \xtemplate_recover_defaults:n { #1 / #2 } + \xtemplate_recover_vars:n { #1 / #2 } + \xtemplate_parse_values:nn { #1 / #2 } {#3} + \xtemplate_convert_to_assignments: + \use:c { \c_xtemplate_code_root_tl #1 / #2 :w } +} +% \end{macrocode} +% \end{macro} +% +%\subsubsection{Assigning values to variables} +% +%\begin{macro}{\xtemplate_assign_boolean:} +%\begin{macro}[aux]{\xtemplate_assign_boolean_aux:n} +% Setting a Boolean value is slightly different to everything else +% as the value can be used to work out which \texttt{set} function to +% call. As long as there is no need to recover things from another +% variable, everything is pretty easy. +% \begin{macrocode} +\cs_new_nopar:Npn \xtemplate_assign_boolean: { + \bool_if:NTF \l_xtemplate_global_bool { + \xtemplate_assign_boolean_aux:n { bool_gset } + }{ + \xtemplate_assign_boolean_aux:n { bool_set } + } +} +\cs_new_nopar:Npn \xtemplate_assign_boolean_aux:n #1 { + \xtemplate_if_key_value:VT \l_xtemplate_value_tl { + \xtemplate_key_to_value: + } + \toks_put_left:Nx \l_xtemplate_assignments_toks { + \exp_not:c { #1 _ \l_xtemplate_value_tl :N } + \exp_not:V \l_xtemplate_var_tl + } +} +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\xtemplate_assign_choice:} +% Assigning a choice is actually trivial: the code needed will +% be in \cs{l_xtemplate_value_tl}, and is simply copied to the correct +% place. +% \begin{macrocode} +\cs_new_nopar:Npn \xtemplate_assign_choice: { + \toks_put_left:NV \l_xtemplate_assignments_toks \l_xtemplate_value_tl +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\xtemplate_assign_code:} +%\begin{macro}{\xtemplate_assign_code:n} +% Assigning general code to a key needs a scratch function to be created +% and run when \cs{AssignTemplateKeys} is called. So the appropriate +% definition then use is created in the toks. +% \begin{macrocode} +\cs_new_nopar:Npn \xtemplate_assign_code: { + \toks_put_left:Nx \l_xtemplate_assignments_toks { + \exp_not:N \cs_set:Npn \exp_not:N \xtemplate_assign_code:n ##1 { + \exp_not:V \l_xtemplate_var_tl + } + \exp_not:N \xtemplate_assign_code:n + { \exp_not:V \l_xtemplate_value_tl } + } +} +\cs_new:Npn \xtemplate_assign_code:n #1 { } +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\xtemplate_assign_function:} +%\begin{macro}[aux]{\xtemplate_assign_function_aux:N} +% For functions, the toks needs to have a cs-generation step created. +% This looks a bit messy but is only actually one function. +% \begin{macrocode} +\cs_new_nopar:Npn \xtemplate_assign_function: { + \bool_if:NTF \l_xtemplate_global_bool { + \xtemplate_assign_function_aux:N \cs_gset:Npn + }{ + \xtemplate_assign_function_aux:N \cs_set:Npn + } +} +\cs_new_nopar:Npn \xtemplate_assign_function_aux:N #1 { + \toks_put_left:Nx \l_xtemplate_assignments_toks { + \exp_not:N \cs_generate_from_arg_count:NNnn + \exp_not:V \l_xtemplate_var_tl + \exp_not:N #1 + { \exp_not:V \l_xtemplate_keytype_arg_tl } + { \exp_not:V \l_xtemplate_value_tl } + } +} +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\xtemplate_assign_instance:} +%\begin{macro}[aux]{\xtemplate_assign_instance_aux:N} +% Using an instance means adding the appropriate function creation to +% the toks. No checks are made at this stage, so if the instance is +% not valid then errors will arise later. +% \begin{macrocode} +\cs_new_nopar:Npn \xtemplate_assign_instance: { + \bool_if:NTF \l_xtemplate_global_bool { + \xtemplate_assign_instance_aux:N \cs_gset:Npn + }{ + \xtemplate_assign_instance_aux:N \cs_set:Npn + } +} +\cs_new_nopar:Npn \xtemplate_assign_instance_aux:N #1 { + \toks_put_left:Nx \l_xtemplate_assignments_toks { + \exp_not:N #1 \exp_not:V \l_xtemplate_var_tl { + \exp_not:N \xtemplate_use_instance:nn + { \exp_not:V \l_xtemplate_keytype_arg_tl } + { \exp_not:V \l_xtemplate_value_tl } + } + } +} +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\xtemplate_assign_integer:} +%\begin{macro}{\xtemplate_assign_length:} +%\begin{macro}{\xtemplate_assign_skip:} +% All of the calculated assignments use the same underlying code, with +% only the low-level assignment function changing. +% \begin{macrocode} +\cs_new_nopar:Npn \xtemplate_assign_integer: { + \bool_if:NTF \l_xtemplate_global_bool { + \xtemplate_assign_variable:N \int_gset:Nn + }{ + \xtemplate_assign_variable:N \int_set:Nn + } +} +\cs_new_nopar:Npn \xtemplate_assign_length: { + \bool_if:NTF \l_xtemplate_global_bool { + \xtemplate_assign_variable:N \dim_gset:Nn + }{ + \xtemplate_assign_variable:N \dim_set:Nn + } +} +\cs_new_nopar:Npn \xtemplate_assign_skip: { + \bool_if:NTF \l_xtemplate_global_bool { + \xtemplate_assign_variable:N \skip_gset:Nn + }{ + \xtemplate_assign_variable:N \skip_set:Nn + } +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\xtemplate_assign_tokenlist:} +%\begin{macro}{\xtemplate_assign_commalist:} +%\begin{macro}[aux]{\xtemplate_assign_tokenlist_aux:N} +% Storing lists of tokens is easy: no complex calculations and no +% need to worry about numbers of arguments. The comma list version +% takes advantage of the low-level implementation of the variable type +% to keep down code duplication. +% \begin{macrocode} +\cs_new_nopar:Npn \xtemplate_assign_tokenlist: { + \bool_if:NTF \l_xtemplate_global_bool { + \xtemplate_assign_tokenlist_aux:N \tl_gset:Nn + }{ + \xtemplate_assign_tokenlist_aux:N \tl_set:Nn + } +} +\cs_new_eq:NN \xtemplate_assign_commalist: + \xtemplate_assign_tokenlist: +\cs_new_nopar:Npn \xtemplate_assign_tokenlist_aux:N #1 { + \toks_put_left:Nx \l_xtemplate_assignments_toks { + \exp_not:N #1 \exp_not:V \l_xtemplate_var_tl + { \exp_not:V \l_xtemplate_value_tl } + } +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\xtemplate_assign_variable:N} +% A general-purpose function for all of the numerical assignments. +% As long as the value is not coming from another variable, the stored +% value is simply transferred for output. +% \begin{macrocode} +\cs_new_nopar:Npn \xtemplate_assign_variable:N #1 { + \xtemplate_if_key_value:VT \l_xtemplate_value_tl { + \xtemplate_key_to_value: + } + \toks_put_left:Nx \l_xtemplate_assignments_toks { + \exp_not:N #1 \exp_not:V \l_xtemplate_var_tl + { \exp_not:V \l_xtemplate_value_tl } + } +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\xtemplate_key_to_value:} +%\begin{macro}[aux]{\xtemplate_key_to_value_aux:w} +% The idea here is to recover the attribute value of another key. To +% do that, the marker is removed and a look up takes place. If this +% is successful, then the name of the variable of the attribute is +% returned. This assumes that the value will be used in context where +% it will be converted to a value, for example when setting a number. +% \begin{macrocode} +\cs_new_nopar:Npn \xtemplate_key_to_value: { + \exp_after:wN \xtemplate_key_to_value_aux:w \l_xtemplate_value_tl +} +\cs_new:Npn \xtemplate_key_to_value_aux:w \KeyValue #1 { + \tl_set:Nx \l_xtemplate_tmp_tl { \tl_to_str:n {#1} } + \tl_replace_all_in:Nnn \l_xtemplate_key_name_tl { ~ } { } + \prop_if_in:NVTF \l_xtemplate_vars_prop \l_xtemplate_tmp_tl { + \prop_get:NVN \l_xtemplate_vars_prop \l_xtemplate_tmp_tl + \l_xtemplate_value_tl + }{ + \msg_kernel_error:nnx { xtemplate } { unknown-attribute } + { \l_xtemplate_tmp_tl } + } +} +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\subsubsection{Using instances} +% +%\begin{macro}{\xtemplate_use_instance:nn} +%\begin{macro}[aux]{\xtemplate_use_instance_aux:nNnnn} +%\begin{macro}[aux]{\xtemplate_use_instance_aux:nn} +% Using an instance is just a question of finding the appropriate +% function. There is the possibility that a collection instance exists, +% so this is checked before trying the general instance. If nothing is +% found, an error is raised. One additional complication is that +% if the first token of argument |#2| is \cs{UseTemplate} then that +% is also valid. There is an error-test to make sure that the +% types agree, and if so the template is used directly. +% \begin{macrocode} +\cs_new:Npn \xtemplate_use_instance:nn #1#2 { + \xtemplate_if_use_template:nTF {#2} { + \xtemplate_use_instance_aux:nNnnn {#1} #2 + }{ + \xtemplate_use_instance_aux:nn {#1} {#2} + } +} +\cs_new:Npn \xtemplate_use_instance_aux:nNnnn #1#2#3#4#5 { + \tl_if_eq:nnTF {#1} {#3} { + \xtemplate_use_template:nnn {#3} {#4} {#5} + }{ + \msg_kernel_error:nnxx { xtemplate } { type-mismatch } {#1} {#3} + } +} +\cs_new:Npn \xtemplate_use_instance_aux:nn #1#2 { + \xtemplate_get_collection:n {#1} + \xtemplate_if_instance_exist:nnnTF + {#1} { \l_xtemplate_collection_tl } {#2} { + \use:c { + \c_xtemplate_instances_root_tl #1 / \l_xtemplate_collection_tl /#2 + :w + } + }{ + \xtemplate_if_instance_exist:nnnTF {#1} { } {#2} { + \use:c { \c_xtemplate_instances_root_tl #1 / / #2 :w } + }{ + \msg_kernel_error:nnxx { xtemplate } { unknown-instance } + {#1} {#2} + } + } +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\xtemplate_use_collection:nn} +% Switching to an instance collection is just a question of setting the +% appropriate list. +% \begin{macrocode} +\cs_new:Npn \xtemplate_use_collection:nn #1#2 { + \prop_put:Nnn \l_xtemplate_collections_prop {#1} {#2} +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\xtemplate_get_collection:n} +% Recovering the collection for a given type is pretty easy: just a read +% from the list. +% \begin{macrocode} +\cs_new:Npn \xtemplate_get_collection:n #1 { + \prop_if_in:NnTF \l_xtemplate_collections_prop {#1} { + \prop_get:NnN \l_xtemplate_collections_prop {#1} + \l_xtemplate_collection_tl + }{ + \tl_clear:N \l_xtemplate_collection_tl + } +} +% \end{macrocode} +%\end{macro} +% +%\subsubsection{Assignment manipulation} +% +% A few functions to transfer assignments about, as this is needed by +% \cs{AssignTemplateKeys}. +% +%\begin{macro}{\xtemplate_assignments_pop:} +% To actually use the assignments. +% \begin{macrocode} +\cs_new_nopar:Npn \xtemplate_assignments_pop: { + \toks_use:N \l_xtemplate_assignments_toks +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\xtemplate_assignments_push:n} +% Here, the assignments are stored for later use. +% \begin{macrocode} +\cs_new:Npn \xtemplate_assignments_push:n #1 { + \toks_set:Nn \l_xtemplate_assignments_toks {#1} +} +% \end{macrocode} +%\end{macro} +% +%\subsubsection{Showing templates and instances} +% +%\begin{macro}{\xtemplate_show_code:nn} +% Showing the code for a template is just a translation of +% \cs{cs_show:c}. +% \begin{macrocode} +\cs_new:Npn \xtemplate_show_code:nn #1#2 { + \xtemplate_execute_if_code_exist:nnT {#1} {#2} + { \cs_show:c { \c_xtemplate_code_root_tl #1 / #2 :w } } +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\xtemplate_show_defaults:nn} +%\begin{macro}{\xtemplate_show_keytypes:nn} +%\begin{macro}{\xtemplate_show_values:nnn} +%\begin{macro}{\xtemplate_show_vars:nn} +% Showing the internal data is a case of getting the appropriate +% property list back, then displaying the scratch variable. +% \begin{macrocode} +\cs_new:Npn \xtemplate_show_defaults:nn #1#2 { + \xtemplate_if_keys_exist:nnT {#1} {#2} + { + \xtemplate_recover_defaults:n { #1 / #2 } + \prop_display:N \l_xtemplate_values_prop + } +} +\cs_new:Npn \xtemplate_show_keytypes:nn #1#2 { + \xtemplate_if_keys_exist:nnT {#1} {#2} + { + \xtemplate_recover_keytypes:n { #1 / #2 } + \prop_display:N \l_xtemplate_keytypes_prop + } +} +\cs_new:Npn \xtemplate_show_values:nnn #1#2#3 { + \xtemplate_if_instance_exist:nnnTF {#1} {#2} {#3} + { + \xtemplate_recover_values:n { #1 / #2 / #3 } + \prop_display:N \l_xtemplate_values_prop + } + { + \msg_kernel_error:nnxx { xtemplate } { unknown-instance } + {#1} {#2} + } +} +\cs_new:Npn \xtemplate_show_vars:nn #1#2 { + \xtemplate_execute_if_code_exist:nnT {#1} {#2} + { + \xtemplate_recover_vars:n { #1 / #2 } + \prop_display:N \l_xtemplate_vars_prop + } +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\subsubsection{Messages} +% +% The text for error messages: short and long text for all of them. +% \begin{macrocode} +\msg_kernel_new:nnnn { xtemplate } { argument-number-mismatch } + {Object type `#1' takes `#2' not `#3' argument(s).} + {% + Objects of type `#1' require `#2' arguments.\\% + You have tried to make a template for `#1'\\% + with `#3' arguments, which is not possible:\\% + the number of arguments must agree.% + } +\msg_kernel_new:nnnn { xtemplate } { bad-number-of-arguments } + {% + Impossible number of arguments declared for\\% + object type `#1'.% + } + {% + An object may accept between 0 and 9 arguments.\\% + You asked to use #2 arguments: this is not supported.% + } +\msg_kernel_new:nnnn { xtemplate } { bad-variable } + {Incorrect variable description \msg_line_context:.} + {% + The argument `#1'\\% + is not of the form `<variable>' or `global <variable>'.\\% + It must be given in one of these formats to be used in a template.% + } +\msg_kernel_new:nnnn { xtemplate } { choice-not-implemented } + {The choice `#1' has no implementation \msg_line_context:.} + {% + Each choice listed in the interface for a template must\\% + have an implementation.\\% + I did not find an implementation for `#1'.% + } +\msg_kernel_new:nnnn { xtemplate } { choice-unknown-reserved } + {The choice `unknown' cannot be given for a template key.} + {% + The `unknown' choice is automatically checked by template when\\% + a choice key is given with an unknown value. It should not be\\% + included in the list of named choices for a key, and is always\\% + given last in the implementation of choices.% + } +\msg_kernel_new:nnnn { xtemplate } { duplicate-key-interface } + {Key `#1' appears twice in interface definition \msg_line_context:.} + {% + Each key can only have one interface declared in a template.\\% + I found two interfaces for `#1': probably a typing error.% + } +\msg_kernel_new:nnnn { xtemplate } { empty-key-name } + {No key name found in `#1' \msg_line_context:.} + {% + A template key name and type is given in the form:\\% + \msg_space: <name> : <type> \\% + Parsing your input, I found a `:' but nothing before + it!% + } +\msg_kernel_new:nnnn { xtemplate } { key-no-value } + {The key `#1' has no value \msg_line_context:.} + {% + When creating an instance of a template\\% + every key listed must include a value: + \msg_two_spaces: <key> = <value> + } +\msg_kernel_new:nnnn { xtemplate } { key-no-variable } + {The key `#1' requires implementation details \msg_line_context:.} + {% + When creating template code using + \token_to_str:N \DeclareTemplateCode,\\% + each key name must have an associated implementation.\\% + This should be given after an `=' sign: I did not find one.% + } +\msg_kernel_new:nnnn { xtemplate } { key-not-implemented } + {Key `#1' has no implementation \msg_line_context:.} + {% + The definition of key implementations for template `#2'\\% + of object type `#3' does not include any details for key `#1'.\\% + The key was declared in the interface definition,\\% + and so an implementation is required.% + } +\msg_kernel_new:nnnn { xtemplate } { keytype-requires-argument } + {The keytype `#1' requires an argument \msg_line_context:} + {% + You should have put:\\% + \msg_two_spaces: <key-name> : #1 + \token_to_str:N { <argument> \token_to_str:N } \\% + but I did not find an <argument>.% + } +\msg_kernel_new:nnnn { xtemplate } { no-keytype } + {The key `#1' is missing a keytype \msg_line_context:} + {% + You should have put:\\% + \msg_two_spaces: #1 : <keytype>\\% + but I did not find an <keytype>.% + } +\msg_kernel_new:nnnn { xtemplate } { no-template-code } + {% + The template `#2' of type `#1' is unknown\\% + or has no implementation.% + } + {% + You need to declare a template with + \token_to_str:N \DeclareTemplateInterface \\% + and its code with + \token_to_str:N \DeclareTemplateCode \msg_space: + prior to using it.% + } +\msg_kernel_new:nnnn { xtemplate } { type-mismatch } + {Object types `#1' and `#2' do not agree.} + {% + You are trying to use a template directly with + \token_to_str:N \UseInstance \\% + (or a similar function), but the object types do not match.% + } +\msg_kernel_new:nnnn { xtemplate } { undeclared-variable } + {The variable #1has not been declared.} + {% + Before declaring an instance, all of the required variables\\% + used in template keys must be created.% + } +\msg_kernel_new:nnnn { xtemplate } { unknown-attribute } + {The template attribute `#1' is unknown.} + {% + There is a definition in the current template reading\\% + \token_to_str:N \KeyValue + \token_to_str:N { #1 \token_to_str:N }\\% + but there is no key called `#1'.% + } +\msg_kernel_new:nnnn { xtemplate } { unknown-choice } + {The choice `#1' was not declared for key `#2' \msg_line_context:.} + {% + The key `#2' takes a fixed number of choices:\\% + \clist_map_function:NN #3 \xtemplate_unknown_choice_aux:n + and this list does not include `#1'.% + } +\cs_new:Npn \xtemplate_unknown_choice_aux:n #1 { -~ #1 ;\\} +\msg_kernel_new:nnnn { xtemplate } { unknown-keytype } + {The keytype `#1' is unknown \msg_line_context:.} + {% + Valid keytypes are:\\% + - boolean;\\% + - choice;\\% + - code;\\% + - commalist;\\% + - function;\\% + - instance;\\% + - integer;\\% + - length;\\% + - skip;\\% + - tokenlist.% + } +\msg_kernel_new:nnnn { xtemplate } { unknown-object-type } + {The object type `#1' is unknown \msg_line_context:.} + {% + An object type needs to be declared with + \token_to_str:N \DeclareObjectType \msg_space: + prior to using it.% + } +\msg_kernel_new:nnnn { xtemplate } { unknown-instance } + {The instance `#2' of type `#1' is unknown.} + {% + You have asked to use an instance `#2',\\% + but this has not been created.% + } +\msg_kernel_new:nnnn { xtemplate } { unknown-key } + {Unknown template key `#1' \msg_line_context:.} + {% + The key `#1' was not declared in the interface\\% + for the current template.\\% + Probably you have misspelled the key name.% + } +\msg_kernel_new:nnnn { xtemplate } { unknown-template } + {The template `#2' of type `#1' is unknown \msg_line_context:.} + {% + No interface has been declared for a template\\% + `#2' of object type `#1'.% + } +% \end{macrocode} +% +% Information messages only have text: more text should not be needed. +% \begin{macrocode} +\msg_kernel_new:nnn { xtemplate } { define-template-code } + {Defining template code for `#1' \msg_line_context:.} +\msg_kernel_new:nnn { xtemplate } { define-template-interface } + {Defining template interface for `#1' \msg_line_context:.} +\msg_kernel_new:nnn { xtemplate } { define-object-type } + {Defining object type `#1' with #2 argument(s) \msg_line_context:.} +\msg_kernel_new:nnn { xtemplate } { redefine-template-code } + {Redefining template code for `#1' \msg_line_context:.} +\msg_kernel_new:nnn { xtemplate } { redefine-template-interface } + {Redefining template interface for `#1' \msg_line_context:.} +\msg_kernel_new:nnn { xtemplate } { redefine-object-type } + {Redefining object type `#1' with #2 argument(s) \msg_line_context:.} +% \end{macrocode} +% +%\subsubsection{User functions} +% +% The user functions provided by \pkg{xtemplate} are pretty much direct +% copies of internal ones. However, by sticking to the \pkg{xparse} +% approach only the appropriate arguments are long. +% +%\begin{macro}{\DeclareObjectType} +%\begin{macro}{\DeclareTemplateInterface} +%\begin{macro}{\DeclareTemplateCode} +%\begin{macro}{\DeclareRestrictedTemplate} +%\begin{macro}{\EditTemplateDefaults} +%\begin{macro}{\DeclareInstance} +%\begin{macro}{\DeclareCollectionInstance} +%\begin{macro}{\EditInstance} +%\begin{macro}{\EditCollectionInstance} +%\begin{macro}{\UseTemplate} +%\begin{macro}{\UseInstance} +%\begin{macro}{\UseCollection} +% All simple translations, with the appropriate long/short argument +% filtering. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \DeclareObjectType #1#2 { + \xtemplate_declare_object_type:nn {#1} {#2} +} +\cs_new_protected:Npn \DeclareTemplateInterface #1#2#3#4 { + \xtemplate_declare_template_keys:nnnn {#1} {#2} {#3} {#4} +} +\cs_new_protected:Npn \DeclareTemplateCode #1#2#3#4#5 { + \xtemplate_declare_template_code:nnnnn {#1} {#2} {#3} {#4} {#5} +} +\cs_new_protected:Npn \DeclareRestrictedTemplate #1#2#3#4 { + \xtemplate_declare_restricted:nnnn {#1} {#2} {#3} {#4} +} +\cs_new_protected:Npn \DeclareInstance #1#2#3#4 { + \xtemplate_declare_instance:nnnnn {#1} {#3} { } {#2} {#4} +} +\cs_new_protected:Npn \DeclareCollectionInstance #1#2#3#4#5 { + \xtemplate_declare_instance:nnnnn {#2} {#4} {#1} {#3} {#5} +} +\cs_new_protected:Npn \EditTemplateDefaults #1#2#3 { + \xtemplate_edit_defaults:nnn {#1} {#2} {#3} +} +\cs_new_protected:Npn \EditInstance #1#2#3 { + \xtemplate_edit_instance:nnnn {#1} { } {#2} {#3} +} +\cs_new_protected:Npn \EditCollectionInstance #1#2#3#4 { + \xtemplate_edit_instance:nnnn {#2} {#1} {#3} {#4} +} +\cs_new_protected_nopar:Npn \UseTemplate #1#2#3 { + \xtemplate_use_template:nnn {#1} {#2} {#3} +} +\cs_new_protected_nopar:Npn \UseInstance #1#2 { + \xtemplate_use_instance:nn {#1} {#2} +} +\cs_new_protected_nopar:Npn \UseCollection #1#2 { + \xtemplate_use_collection:nn {#1} {#2} +} +% \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} +% +%\begin{macro}{\ShowTemplateCode} +%\begin{macro}{\ShowTemplateDefaults} +%\begin{macro}{\ShowTemplateKeytypes} +%\begin{macro}{\ShowTemplateVariables} +%\begin{macro}{\ShowInstanceValues} +%\begin{macro}{\ShowCollectionInstanceValues} +% The show functions are again just translation. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \ShowTemplateCode #1#2 { + \xtemplate_show_code:nn {#1} {#2} +} +\cs_new_protected_nopar:Npn \ShowTemplateDefaults #1#2 { + \xtemplate_show_defaults:nn {#1} {#2} +} +\cs_new_protected_nopar:Npn \ShowTemplateKeytypes #1#2 { + \xtemplate_show_keytypes:nn {#1} {#2} +} +\cs_new_protected_nopar:Npn \ShowTemplateVariables #1#2 { + \xtemplate_show_vars:nn {#1} {#2} +} +\cs_new_protected_nopar:Npn \ShowInstanceValues #1#2 { + \xtemplate_show_values:nnn {#1} { } {#2} +} +\cs_new_protected_nopar:Npn \ShowCollectionInstanceValues #1#2#3 { + \xtemplate_show_values:nnn {#1} {#2} {#3} +} +% \end{macrocode} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +%\end{macro} +% +%\begin{macro}[TF]{\IfInstanceExist} +% More direct translation: only the base instance is checked for. +% \begin{macrocode} +\cs_new_nopar:Npn \IfInstanceExistTF #1#2 { + \xtemplate_if_instance_exist:nnnTF {#1} { } {#2} +} +\cs_new_nopar:Npn \IfInstanceExistT #1#2 { + \xtemplate_if_instance_exist:nnnT {#1} { } {#2} +} +\cs_new_nopar:Npn \IfInstanceExistF #1#2 { + \xtemplate_if_instance_exist:nnnF {#1} { } {#2} +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\EvaluateNow} +%\begin{macro}{\KeyValue} +% These are both do nothing functions. Both simply dump their arguments +% when executed: this should not happen with \cs{KeyValue}. +% +% They need to be expandable as they might get called in the context of +% setting some register value. +% \begin{macrocode} +\cs_new_protected:Npn \EvaluateNow #1 {#1} +\cs_new_protected:Npn \KeyValue #1 {#1} +% \end{macrocode} +%\end{macro} +%\end{macro} +% +%\begin{macro}{\AssignTemplateKeys} +% A short call to use a token register by proxy. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \AssignTemplateKeys { + \xtemplate_assignments_pop: +} +% \end{macrocode} +%\end{macro} +% +% +% +%\subsubsection{Recent additions to the code} +% +% \begin{macro}{\TP_split_finite_skip_value:nnNN} +% This macro is for use in error checking template values like +% "text-float-sep" that can't contain infinite glue and needs the +% shrink and/or stretch components. First argument is the skip +% register (which is likely to be user input), second is a template +% key name, and the last two are the \meta{dimen} registers that +% stores the stretch and shrink components. Assignments are global. +% \begin{macrocode} +\cs_new_nopar:Npn \TP_split_finite_skip_value:nnNN #1#2{ + \skip_split_finite_else_action:nnNN {#1} { + \PackageError{xtemplate}{Value~ for~ key~ #2~ contains~ `fil(ll)'} + {Only~ finite~ minus~ or~ plus~ parts~ are~ allowed~ for~ this~ key.} + } +} +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</initex|package> +% \end{macrocode} +% +%\PrintIndex +% +%\end{implementation} diff --git a/Master/texmf-dist/source/latex/xpackages/xtras/l3keys2e.dtx b/Master/texmf-dist/source/latex/xpackages/xtras/l3keys2e.dtx index 9595206ee53..91e4dac4c48 100644 --- a/Master/texmf-dist/source/latex/xpackages/xtras/l3keys2e.dtx +++ b/Master/texmf-dist/source/latex/xpackages/xtras/l3keys2e.dtx @@ -196,7 +196,7 @@ % \texttt{unknown} key is set if it does not already exist for the % current module. % \begin{macrocode} -\cs_new:Nn \keys_latexe_options:n { +\cs_new:Npn \keys_latexe_options:n #1 { \clist_clear:N \keys_latexe_options_clist \keys_latexe_options_global:n {#1} \keys_latexe_options_local: @@ -224,7 +224,7 @@ % file type. The initial test is needed as \LaTeXe\ allows variables to % be equal to \cs{scan_stop:}, which is forbidden in \LaTeX3 code. % \begin{macrocode} -\cs_new:Nn \keys_latexe_options_global:n { +\cs_new:Npn \keys_latexe_options_global:n #1 { \cs_if_eq:NNF \@classoptionslist \scan_stop: { \cs_if_eq:NNTF \@currext \@clsextension { \keys_latexe_options_class:n {#1} @@ -242,7 +242,7 @@ % the combined list for processing. On the other hand, unused options % are stored up in \cs{@unusedoptionlist}. % \begin{macrocode} -\cs_new:Nn \keys_latexe_options_class:n { +\cs_new:Npn \keys_latexe_options_class:n #1 { \clist_map_inline:Nn \@classoptionslist { \keys_if_exist:nnTF {#1} { \keys_latexe_remove_equals:n {##1} } { \clist_put_right:Nn \keys_latexe_options_clist {##1} @@ -260,7 +260,7 @@ % there is nothing to do if the option is not applicable. Each valid % option also needs to be removed from \cs{@unusedoptionlist}. % \begin{macrocode} -\cs_new:Nn \keys_latexe_options_package:n { +\cs_new:Npn \keys_latexe_options_package:n #1 { \clist_map_inline:Nn \@classoptionslist { \keys_if_exist:nnT {#1} { \keys_latexe_remove_equals:n {##1} } { \clist_put_right:Nn \keys_latexe_options_clist {##1} @@ -276,7 +276,7 @@ % \LaTeXe\ stores options for each file in a macro which may or may not % exist, hence the need to use \cs{cs_if_exist:c}. % \begin{macrocode} -\cs_new_nopar:Nn \keys_latexe_options_local: { +\cs_new_nopar:Npn \keys_latexe_options_local: { \cs_if_eq:NNF \@currext \@clsextension { \cs_if_exist:cT { opt@ \@currname . \@currext } { \exp_args:NNc \clist_put_right:NV \keys_latexe_options_clist @@ -293,7 +293,7 @@ % sign from the input. This is all wrapped up in an \texttt{n} function % so that there will always be a sign available. % \begin{macrocode} -\cs_new:Nn \keys_latexe_remove_equals:n { +\cs_new:Npn \keys_latexe_remove_equals:n #1 { \keys_latexe_remove_equals:w #1 = \q_stop } \cs_new:Npn \keys_latexe_remove_equals:w #1 = #2 \q_stop {#1} |