summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex-dev/latex-lab/latex-lab-prototype.dtx
diff options
context:
space:
mode:
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.dtx827
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}