diff options
Diffstat (limited to 'Master/texmf-dist/source/latex-dev/latex-lab/latex-lab-prototype.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex-dev/latex-lab/latex-lab-prototype.dtx | 827 |
1 files changed, 827 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex-dev/latex-lab/latex-lab-prototype.dtx b/Master/texmf-dist/source/latex-dev/latex-lab/latex-lab-prototype.dtx new file mode 100644 index 00000000000..090e6c91a4f --- /dev/null +++ b/Master/texmf-dist/source/latex-dev/latex-lab/latex-lab-prototype.dtx @@ -0,0 +1,827 @@ +% \iffalse meta-comment +% +%% File: latex-lab-prototype.dtx +% +% Copyright (C) 1999 Frank Mittelbach, Chris Rowley, David Carlisle +% (C) 2004-2010 Frank Mittelbach, The LaTeX Project +% (C) 2011-2022 The LaTeX Project +% +% It may be distributed and/or modified under the conditions of the +% LaTeX Project Public License (LPPL), either version 1.3c of this +% license or (at your option) any later version. The latest version +% of this license is in the file +% +% https://www.latex-project.org/lppl.txt +% +% This file is part of the "latex-lab bundle" (The Work in LPPL) +% and all files in that bundle must be distributed together. +% +% ----------------------------------------------------------------------- +% +% The development version of the bundle can be found at +% +% https://github.com/latex3/latex2e +% +% for those people who are interested. +% +%<*driver> +\documentclass[full]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \textsf{latex-lab-prototype} package\\ Prototype document functions^^A +% } +% +% \author{^^A +% The \LaTeX{} Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released 2022-03-09} +% +% \maketitle +% +% \tableofcontents +% +% \bigskip +% +% \begin{documentation} +% +% There are three broad \enquote{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 this module 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. +% The approach here 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 \cs{section}, \cs{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, \cs{section} and |\section*|, or the difference +% between an itemised list or an enumerated list. +% +% There are three distinct layers in the definition of +% \enquote{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 template system, these are called object types, +% templates, and instances, and they are discussed below in sections +% \ref{sec:objects}, \ref{sec:templates}, and~\ref{sec:instances}, +% respectively. +% +% By formally declaring documents 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. +% +% \section{Object types} +% \label{sec:objects} +% +% An \emph{object type} (sometimes just \enquote{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: \enquote{title}, \enquote{short title}, and +% \enquote{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}{\prototype_declare_object:nn} +% \begin{syntax} +% \cs{prototype_declare_object:nn} \Arg{object type} \Arg{no.~of args} +% \end{syntax} +% This function defines an \meta{object type} taking +% \meta{no.~of arguments}, where the \meta{object type} is an +% abstraction as discussed above. For example, +% \begin{verbatim} +% \prototype_declare_object:nn { sectioning } { 3 } +% \end{verbatim} +% creates an object type \enquote{sectioning}, where each use of that +% object type will need three arguments. +% +% While not formally verified the semantics of all arguments are part +% of the object declaration and need to be carefully documented in +% order to make the use of different templates for the same object +% type meaningful. +% \end{function} +% +% \section{Templates} +% \label{sec:templates} +% +% A \emph{template} is a generalised design solution for representing +% the information of a specified object type. Templates that do the same +% thing, but in different ways, 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} +% +% \begin{function}{\prototype_declare_template:nnnn} +% \begin{syntax} +% \cs{prototype_declare_template:nnnn} +% ~~\Arg{object type} \Arg{template} +% ~~\Arg{key definitions} \Arg{code} +% \end{syntax} +% A \meta{template} interface is declared for a particular +% \meta{object type}. The interface itself is +% defined by the \meta{key definitions}, which is itself a key--value list +% using the same interface as \cs{keys_define:nn}. (The keys created +% here \emph{are} managed \pkg{l3keys} in the tree +% \texttt{prototype/\meta{object}/\meta{template}}). As described below, +% the keys should be defined such that they can be set multiple times: +% first to a default value, then to a specific value for an instance +% and finally to a per-use override. +% +% The \meta{code} argument of \cs{template_declare_template:nnnn} is used +% as the replacement text for the template when it is used, either +% directly or as an instance. This may therefore accept arguments +% |#1|, |#2|, \emph{etc}.~as detailed by the \meta{number of arguments} +% taken by the object type. The template and instance key values (see +% below) are assigned before the \meta{code} is inserted. +% \end{function} +% +% \begin{function}{\prototype_declare_defaults:nnn} +% \begin{syntax} +% \cs{prototype_declare_template:nnnn} +% ~~\Arg{object type} \Arg{template} \Arg{defaults} +% \end{syntax} +% Sets the default values for each \meta{key} in a \meta{template}. When +% a template is used, these values are applied first \emph{before} those +% set by \cs{prototype_use_template:nnn} or +% \cs{prototype_declare_instance:nnnn}. If not default is given, the +% prevailing state when the template is used will apply. +% \end{function} +% +% \section{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 \enquote{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 \enquote{this is a +% section with a number, which is centred and set in $12\,\text{pt}$ +% italic with a $10\,\text{pt}$ skip before and a +% $12\,\text{pt}$ skip after it}. Therefore, an instance is just a +% frozen version of a template with specific settings as chosen by the +% designer. +% +% \begin{function}{\prototype_declare_instance:nnnn} +% \begin{syntax} +% \cs{prototype_declare_instance:nnnn} +% ~~\Arg{object type} \Arg{template} \Arg{instance} \Arg{parameters} +% \end{syntax} +% This function uses a \meta{template} for an \meta{object type} +% to create an \meta{instance}. The \meta{instance} will be set +% up using the \meta{parameters}, which will set some of the +% \meta{keys} in the \meta{template}. +% +% As a practical example, consider an object type for document sections +% (which might include chapters, parts, sections, \emph{etc}.), which +% is called \texttt{sectioning}. One possible template for this +% object type might be called \texttt{basic}, and one instance of this +% template would be a numbered section. The instance declaration might +% read: +% \begin{verbatim} +% \prototype_declare_instance:nnnn { sectioning } { basic } { section-num } +% { +% numbered = true , +% justification = center , +% font = \normalsize\itshape , +% before-skip = 10pt , +% after-skip = 12pt , +% } +% \end{verbatim} +% Of course, the key names here are entirely imaginary, but illustrate +% the general idea of fixing some settings. +% \end{function} +% +% \section{Document interface} +% +% After the instances have been chosen, document commands must be +% declared to use those instances in the document. +% \cs{prototype_use_instance:nn} +% calls instances directly, and this command should be used internally +% in document-level mark-up. +% +% \begin{function}{\prototype_use_instance:nn, \prototype_use_instance:nnn} +% \begin{syntax} +% \cs{prototype_use_instance:nn} +% ~~\Arg{object type} \Arg{instance} \meta{arguments} +% \cs{prototype_use_instance:nn}n +% ~~\Arg{object type} \Arg{instance} \Arg{overrides} \meta{arguments} +% \end{syntax} +% Uses an \meta{instance} of the \meta{object type}, which will require +% \meta{arguments} as determined by the number specified for the +% \meta{object type}. The \meta{instance} must have been declared +% before it can be used, otherwise an error is raised. The \texttt{nnn} +% version allows for local overrides of the instance settings using the +% additional keyval argument. +% \end{function} +% +% \begin{function}{\prototype_use_template:nnnn} +% \begin{syntax} +% \cs{prototype_use_template:nnnn} \Arg{object type} \Arg{template} +% ~~\Arg{settings} \meta{arguments} +% \end{syntax} +% Uses the \meta{template} of the specified \meta{object type}, +% applying the \meta{settings} and absorbing \meta{arguments} as +% detailed by the \meta{object type} declaration. This in effect +% is the same as creating an instance using +% \cs{template_declare_instance:nnnn} and immediately using it with +% \cs{template_use_instance:nnn}, but without the instance having any +% further existence. It is therefore useful where a template needs to +% be used once. +% \end{function} +% +% \section{Showing template information} +% +% \begin{function} +% { +% \prototype_show_template_code:nn , +% \prototype_show_template_defaults:nn , +% \prototype_show_instance_values:nn +% } +% \begin{syntax} +% \cs{prototype_show_template_code:nn} \Arg{object type} \Arg{template} +% \cs{prototype_show_template_defaults:nn} \Arg{object type} \Arg{template} +% \cs{prototype_show_instance_values:nn} \Arg{object type} \Arg{instance} +% \end{syntax} +% Show information about a declare template or instance for +% debugging purposes. +% \end{function} +% +% \section{Open questions and comparison with \pkg{xtemplate}} +% +% The approach here is modelled on that from \pkg{xtemplate}, but since it uses +% \pkg{l3keys} rather than dedicated key handling, there are some differences. +% There is also a simplification in that collections are not supported +% (because we now think that they provided the wrong kind of abstraction). +% +% The various open questions, including those linked to \pkg{xtemplate} +% concepts, are collected here. +% +% \subsection{Module name} +% +% This is currently open for ideas: traditionally \texttt{template} has +% been used. This may link to the need for both templates and instances +% (\emph{vide infra}). +% +% \subsection{Design-level names} +% +% These are currently not provided. That allows both this code and +% \pkg{xtemplate} to be loaded in the same document. We will likely want +% to decide on these names: they could for example include +% \texttt{Prototype} or \texttt{Design}, or could use the existing +% \pkg{xtemplate} if a compatibility approach can be designed. +% +% \subsection{Objects} +% +% Is this name clear? A possible alternative is `element'. +% +% \subsection{Efficiency and repetition of key setting} +% +% In the \pkg{xtemplate} implementation, keys values are stored in property +% lists before being applied. This means that when creating an instance, the +% template defaults can be replaced entirely by any instance values. In +% contrast, the approach here simply precompiles all of the template defaults, +% then appends the precompiled list from the instance. Some variables are +% therefore set twice. More importantly, this means that arbitrary code +% could be executed twice: authors need to be aware of this. +% +% \subsection{Key ordering} +% +% Linked to the previous idea, in \pkg{xtemplate} keys are set in the +% order they are declared in the setup. In contrast, using \pkg{l3keys} +% they are set in the order the keys are given in the input. Is this OK? +% +% \subsection{Setting defaults} +% +% The current approach requires setting the defaults separately from +% the key creation. That means listing keys twice. However, it also +% avoids further overloading of the keyval setup. Is this reasonable? +% +% \subsection{The need for templates and instances} +% +% In \pkg{xtemplate}, storing keys in a \texttt{prop} means that there +% is a real efficiency when creating an instance. In contrast, using +% precompiled keys here, creating a template and creating an instance +% are almost identical. Could we drop the distinction? That would then +% work well if we allowed instances to be derived from others: effectively +% the same as instances from templates, but with a `flatter' approach. +% +% \subsection{Assignment of key values} +% +% The \pkg{xtemplate} approach uses \cs{AssignTemplateKeys} to +% specify when keys are assigned. In contrast, here key assignment is +% automatic. If you look over \TeX{} Live, the only places that +% \cs{AssignTemplateKeys} is not the first thing in the code are in limited +% use cases in \pkg{enotez} and \pkg{xgalley}. In both packages, that's because +% they want to limit the scope of assignment. In \pkg{enotez} the key setting +% is placed inside a group, whereas in \pkg{xgalley} there is a +% save-and-restore approach as a group is not possible. Both of those use-cases +% could be covered in other ways: it's a question of setting up the template +% keys so they assign to an intermediate variable, then assigning those as +% necessary to the live ones for these cases. +% +% The main reason for not using \cs{AssignTemplateKeys} is that the common +% case doesn't need it. We could of course stick to an explicit-assignment +% approach, or have two variants or template-creation, etc., where assignment +% is manual in one of them. +% +% \subsection{Values from other keys} +% +% The \pkg{xtemplate} approach offers \cs{KeyValue} to pass the value of +% one key as the default for another. That relies on the fact that key +% setting is ordered (\emph{vide supra}). It also means that there is +% some code to check for this as part of key setting: it's non-trivial +% to support. The current \pkg{l3keys}-based code doesn't offer this. +% Instead one could use for example meta keys. That is a different +% interface and might occasionally be awkward. We can add some +% \texttt{.store-value:n} property to allow a \cs{keys_value:nn} approach, +% but without key ordering it might still not work in the same way. +% +% \subsection{The nature of debugging data} +% +% Due to the differences in data storage, the \pkg{xtemplate} method offers +% a richer ability to debug template internals than the one here. We can look +% at \emph{e.g.}\ tracking all keys for a template to make this easier. +% It is worth noting that much of this data is really something that +% should be part of the documentation anyway. Also, it would be trivial +% to save the raw defaults and do the `hard' processing only if asked +% to show the values (\emph{i.e.}\ using code similar to that in +% \pkg{xtemplate}). +% +% \subsection{Collections} +% +% These are not implemented at all: we likely want a new approach to +% contexts. +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{latex-lab-prototype} Implementation} +% +% \subsection{File declaration} +% \begin{macrocode} +%<*package> +\ProvidesFile{latex-lab-prototype.sty} + [2022-03-09 v0.1b Experimental prototype document functions] +%</package> +% \end{macrocode} +% +% \begin{macrocode} +%<*2ekernel> +% \end{macrocode} +% +% \begin{macrocode} +\ExplSyntaxOn +% \end{macrocode} +% +% \subsection{\cs{keys_precompile:nnN}} +% +% \begin{macrocode} +%<@@=keys> +% \end{macrocode} +% +% This may not yet be available in \pkg{expl3} so we ensure it is set up +% here: all temporary. We just redefine those internals that need it. +% \begin{macrocode} +\tl_if_exist:NF \l_@@_precompile_tl + { + \bool_new:N \l_@@_precompile_bool + \tl_new:N \l_@@_precompile_tl + } +\cs_gset_protected:Npn \@@_precompile:n #1 + { + \bool_if:NTF \l_@@_precompile_bool + { \tl_put_right:Nn \l_@@_precompile_tl } + { \use:n } + {#1} + } +\cs_gset_protected:Npn \@@_bool_set:Nnnn #1#2#3#4 + { + \bool_if_exist:NF #1 { \bool_new:N #1 } + \@@_choice_make: + \@@_cmd_set:nx { \l_keys_path_str / true } + { \exp_not:c { bool_ #2 set_ #3 :N } \exp_not:N #1 } + \@@_cmd_set:nx { \l_keys_path_str / false } + { \exp_not:c { bool_ #2 set_ #4 :N } \exp_not:N #1 } + \@@_cmd_set_direct:nn { \l_keys_path_str / unknown } + { + \msg_error:nnx { keys } { boolean-values-only } + \l_keys_key_str + } + \@@_default_set:n { true } + } +\cs_gset_protected:Npn \@@_choice_make_aux:N #1 + { + \cs_set_nopar:cpn { \c_@@_type_root_str \l_keys_path_str } + { choice } + \@@_cmd_set_direct:nn \l_keys_path_str { #1 {##1} } + \@@_cmd_set_direct:nn { \l_keys_path_str / unknown } + { + \msg_error:nnxx { keys } { choice-unknown } + \l_keys_path_str {##1} + } + } +\cs_gset_protected:Npn \@@_cmd_set:nn #1#2 + { \@@_cmd_set_direct:nn {#1} { \@@_precompile:n {#2} } } +\cs_gset_protected:Npn \@@_cmd_set_direct:nn #1#2 + { \cs_set_protected:cpn { \c_@@_code_root_str #1 } ##1 {#2} } +\cs_gset_protected:Npn \@@_cs_set:NNpn #1#2#3# + { + \cs_set_protected:cpx { \c_@@_code_root_str \l_keys_path_str } ##1 + { + \@@_precompile:n + { #1 \exp_not:N #2 \exp_not:n {#3} {##1} } + } + \use_none:n + } +\cs_gset_protected:Npn \@@_meta_make:n #1 + { + \exp_args:NVo \@@_cmd_set_direct:nn \l_keys_path_str + { + \exp_after:wN \keys_set:nn \exp_after:wN + { \l_@@_module_str } {#1} + } + } +\cs_gset_protected:Npn \@@_meta_make:nn #1#2 + { + \exp_args:NV \@@_cmd_set_direct:nn + \l_keys_path_str { \keys_set:nn {#1} {#2} } + } +\cs_gset_protected:Npn \keys_precompile:nnN #1#2#3 + { + \bool_set_true:N \l_@@_precompile_bool + \tl_clear:N \l_@@_precompile_tl + \keys_set:nn {#1} {#2} + \bool_set_false:N \l_@@_precompile_bool + \tl_set_eq:NN #3 \l_@@_precompile_tl + } +\cs_gset_protected:Npn \@@_show:Nnn #1#2#3 + { + #1 { keys } { show-key } + { \@@_trim_spaces:n { #2 / #3 } } + { + \keys_if_exist:nnT {#2} {#3} + { + \exp_args:Nnf \msg_show_item_unbraced:nn { code } + { + \exp_args:Ne \@@_show:n + { + \exp_args:Nc \cs_replacement_spec:N + { + \c_@@_code_root_str + \@@_trim_spaces:n { #2 / #3 } + } + } + } + } + } + { } { } + } +\cs_gset:Npx \@@_show:n #1 + { + \exp_not:N \@@_show:w + #1 + \tl_to_str:n { \@@_precompile:n } + #1 + \tl_to_str:n { \@@_precompile:n } + \exp_not:N \s_@@_stop + } +\use:x + { + \cs_gset:Npn \exp_not:N \@@_show:w + ##1 \tl_to_str:n { \@@_precompile:n } + ##2 \tl_to_str:n { \@@_precompile:n } + ##3 \exp_not:N \s_@@_stop + } + { + \tl_if_blank:nTF {#2} + {#1} + { \@@_show:Nw #2 \s_@@_stop } + } +\use:x + { + \cs_gset:Npn \exp_not:N \@@_show:Nw ##1##2 + \c_right_brace_str \exp_not:N \s_@@_stop + } + {#2} +% \end{macrocode} +% +% \subsection{Setup} +% +% \begin{macrocode} +%<@@=prototype> +% \end{macrocode} +% +% \begin{variable}{\l_@@_tmp_tl} +% \begin{macrocode} +\tl_new:N \l_@@_tmp_tl +% \end{macrocode} +% \end{variable} +% +% \subsection{Data structures} +% +% \begin{variable}{\l_@@_object_prop} +% \begin{macrocode} +\prop_new:N \l_@@_object_prop +% \end{macrocode} +% \end{variable} +% +% \subsection{Creating objects} +% +% \begin{macro}{\prototype_declare_object:nn, \@@_declare_object:nn} +% Although the object type is the \enquote{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_protected:Npn \prototype_declare_object:nn #1#2 + { + \exp_args:Nx \@@_declare_object:nn { \int_eval:n {#2} } {#1} + } +\cs_new_protected:Npn \@@_declare_object:nn #1#2 + { + \int_compare:nTF { 0 <= #1 <= 9 } + { + \msg_info:nnnn { prototype } { declare-object-type } {#2} {#1} + \prop_put:Nnn \l_@@_object_prop {#2} {#1} + } + { \msg_error:nnxx { prototype } { bad-number-of-arguments } {#2} {#1} } + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Templates and instances} +% +% \begin{variable}{\l_@@_assignments_tl} +% Used to insert the set keys. +% \begin{macrocode} +\tl_new:N \l_@@_assignments_tl +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\prototype_declare_template:nnnn} +% \begin{macro}{\prototype_declare_defaults:nnn} +% Creating a template means defining the keys, storing the defaults and +% creating the function. The defaults are done separately from the other +% parts as that fits the \pkg{l3keys} pattern but also makes it easy to +% alter that aspect without changing the core implementation. +% \begin{macrocode} +\cs_new_protected:Npn \prototype_declare_template:nnnn #1#2#3#4 + { + \prop_get:NnNTF \l_@@_object_prop {#1} \l_@@_tmp_tl + { + \keys_define:nn { prototype / #1 / #2 } {#3} + \tl_clear_new:c { l_@@_defaults_ #1 _ #2 _tl } + \cs_generate_from_arg_count:cNnn + { @@_template_ #1 _ #2 :w } + \cs_set_protected:Npn + { \l_@@_tmp_tl } + { + \tl_use:N \l_@@_assignments_tl + #4 + } + } + { \msg_error:nnn { prototype } { unknown-object-type } {#1} } + } +\cs_new_protected:Npn \prototype_declare_defaults:nnn #1#2#3 + { + \cs_if_exist:cTF { @@_template_ #1 _ #2 :w } + { \tl_set:cn { l_@@_defaults_ #1 _ #2 _tl } {#3} } + { \msg_error:nnn { prototype } { unknown-template } {#1} {#2} } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +\cs_generate_variant:Nn \keys_precompile:nnN { v , nv } +% \end{macrocode} +% +% \begin{macro}{\prototype_use_template:nnn} +% \begin{macro}{\prototype_declare_instance:nnnn} +% \begin{macro}{\@@_declare_aux:nnnn} +% Using a template and creating an instance are the same thing other +% than the final step: using the template or storing the key settings. +% We do not attempt to maximise efficiency in setting, rather we have +% a clear approach in which the final assignments may have multiple +% entries. +% \begin{macrocode} +\cs_new_protected:Npn \prototype_use_template:nnn #1#2#3 + { + \@@_declare_aux:nnnn {#1} {#2} {#3} + { \use:c { @@_template_ #1 _ #2 :w } } + } +\cs_new_protected:Npn \prototype_declare_instance:nnnn #1#2#3#4 + { + \@@_declare_aux:nnnn {#1} {#2} {#4} + { + \tl_clear_new:c { l_@@_instance_ #1 _ #3 _pars_tl } + \tl_set_eq:cN { l_@@_instance_ #1 _ #3 _pars_tl } + \l_@@_assignments_tl + \tl_clear_new:c { l_@@_instance_ #1 _ #3 _template_tl } + \tl_set:cn { l_@@_instance_ #1 _ #3 _template_tl } {#2} + } + } +\cs_new_protected:Npn \@@_declare_aux:nnnn #1#2#3#4 + { + \cs_if_exist:cTF { @@_template_ #1 _ #2 :w } + { + \keys_precompile:nvN + { prototype / #1 / #2 } + { l_@@_defaults_ #1 _ #2 _tl } + \l_@@_assignments_tl + \keys_precompile:nnN { prototype / #1 / #2 } {#3} \l_@@_tmp_tl + \tl_put_right:NV \l_@@_assignments_tl \l_@@_tmp_tl + #4 + } + { \msg_error:nnn { prototype } { unknown-template } {#1} {#2} } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\prototype_use_instance:nn} +% \begin{macro}{\prototype_use_instance:nnn} +% Recover the values and insert the code. +% \begin{macrocode} +\cs_new_protected:Npn \prototype_use_instance:nn #1#2 + { \prototype_use_instance:nnn {#1} {#2} { } } +\cs_new_protected:Npn \prototype_use_instance:nnn #1#2#3 + { + \tl_if_exist:cTF { l_@@_instance_ #1 _ #2 _template_tl } + { + \tl_set_eq:Nc \l_@@_assignments_tl + { l_@@_instance_ #1 _ #2 _pars_tl } + \tl_if_blank:nF {#3} + { + \keys_precompile:vnN + { + prototype / #1 / + \tl_use:c { l_@@_instance_ #1 _ #2 _template_tl } + } + {#3} + \l_@@_tmp_tl + \tl_put_right:NV \l_@@_assignments_tl + \l_@@_tmp_tl + } + \use:c + { + @@_template_ #1 _ + \tl_use:c { l_@@_instance_ #1 _ #2 _template_tl } + :w + } + } + { \msg_error:nnn { prototype } { unknown-instance } {#1} {#2} } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsection{Showing information} +% +% \begin{macro} +% { +% \prototype_show_template_code:nn , +% \prototype_show_template_defaults:nn , +% \prototype_show_instance_values:nn +% } +% \begin{macrocode} +\cs_new_protected:Npn \prototype_show_template_code:nn #1#2 + { + \prop_if_in:NnTF \l_@@_object_prop {#1} + { \cs_show:c { @@_template_ #1 _ #2 :w } } + { \msg_error:nnn { prototype } { unknown-object-type } {#1} } + } +\cs_new_protected:Npn \prototype_show_template_defaults:nn #1#2 + { + \cs_if_exist:cTF { @@_template_ #1 _ #2 :w } + { \tl_show:c { l_@@_defaults_ #1 _ #2 _tl } } + { \msg_error:nnn { prototype } { unknown-template } {#1} {#2} } + } +\cs_new_protected:Npn \prototype_show_instance_values:nn #1#2 + { + \tl_if_exist:cTF { l_@@_instance_ #1 _ #2 _template_tl } + { \tl_show:c { l_@@_instance_ #1 _ #2 _pars_tl } } + { \msg_error:nnn { prototype } { unknown-instance } {#1} {#2} } + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Messages} +% +% \begin{macrocode} +\msg_new:nnnn { prototype } { bad-number-of-arguments } + { Bad~number~of~arguments~for~object~type~'#1'. } + { + An~object~may~accept~between~0~and~9~arguments.\\ + You~asked~to~use~#2~arguments:~this~is~not~supported. + } +\msg_new:nnnn { prototype } { 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_new:nnnn { prototype } { unknown-object-type } + { The~object~type~'#1'~is~unknown. } + { An~object~type~needs~to~be~declared~prior~to~using~it. } +\msg_new:nnnn { prototype } { unknown-template } + { The~template~'#2'~of~type~'#1'~is~unknown. } + { + No~interface~has~been~declared~for~a~template~ + '#2'~of~object~type~'#1'. + } +% \end{macrocode} +% +% \begin{macrocode} +\msg_new:nnn { prototype } { declare-object-type } + { Declaring~object~type~'#1'~taking~#2~argument(s). } +% \end{macrocode} +% +% \begin{macrocode} +\ExplSyntaxOff +% \end{macrocode} +% +% \begin{macrocode} +%</2ekernel> +% \end{macrocode} +% +% \end{implementation} |