summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/lt3rawobjects/lt3rawobjects.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/lt3rawobjects/lt3rawobjects.dtx')
-rw-r--r--macros/latex/contrib/lt3rawobjects/lt3rawobjects.dtx1913
1 files changed, 1368 insertions, 545 deletions
diff --git a/macros/latex/contrib/lt3rawobjects/lt3rawobjects.dtx b/macros/latex/contrib/lt3rawobjects/lt3rawobjects.dtx
index d0ee88b064..22ac0f389b 100644
--- a/macros/latex/contrib/lt3rawobjects/lt3rawobjects.dtx
+++ b/macros/latex/contrib/lt3rawobjects/lt3rawobjects.dtx
@@ -22,25 +22,34 @@
%
% \iffalse
%<*driver>
-\ProvidesFile{lt3rawobjects.dtx}[2022/12/09 2.2 Objects and proxies in LaTeX3]
+\ProvidesFile{lt3rawobjects.dtx}[2023/03/17 2.3 Objects and proxies in LaTeX3]
%</driver>
%<package>\NeedsTeXFormat{LaTeX2e}
%<package>\RequirePackage{expl3}[2022-04-10]
-%<package>\ProvidesExplPackage{lt3rawobjects}{2022/12/09}{ 2.2 }{Objects and proxies in LaTeX3}
+%<package>\ProvidesExplPackage{lt3rawobjects}{2023/03/17}{ 2.3 }{Objects and proxies in LaTeX3}
%<*driver>
\documentclass[full]{l3doc}
\usepackage{lt3rawobjects}
\usepackage{xparse}
+\usepackage{xcolor}
+\usepackage{fancyvrb}
\begin{document}
+
+
\DocInput{lt3rawobjects.dtx}
\end{document}
%</driver>
% \fi
%
% \NewDocumentCommand{\thpkg}{}{\pkg{lt3rawobjects}}
-% \NewDocumentCommand{\thvsn}{}{2.2}
-% \NewDocumentCommand{\thdta}{}{2022/12/09}
+% \NewDocumentCommand{\thvsn}{}{2.3}
+% \NewDocumentCommand{\thdta}{}{2023/03/17}
% \NewDocumentCommand{\fromV}{ m }{{\ttfamily From: #1}}
+% \NewDocumentCommand{\fromVD}{ m m }{{\ttfamily From: #1}\par {\ttfamily Deprecated in: #2}}
+%
+% \NewDocumentCommand{\simfun}{m m}{\textcolor{blue}{\textbackslash #1}\textcolor{purple}{:#2}}
+% \NewDocumentCommand{\simvar}{m}{\textcolor{violet}{\textbackslash #1}}
+% \DefineVerbatimEnvironment{Coding}{Verbatim}{numbers=left, frame=single, commandchars={![]}}
%
% \title{The \pkg{lt3rawobjects} package}
% \author{Paolo De Donato}
@@ -53,75 +62,86 @@
% \begin{documentation}
%
% \section{Introduction}
-% First to all notice that \thpkg\ means ``raw object(s)'', indeed \thpkg\ introduces a new mechanism to create objects like the well known C structures. The functions exported by this package are quite low level, and many important mechanisms like member protection and name resolution aren't already defined and should be introduced by intermediate packages. Higher level libraries built on top of \thpkg\ could also implement an improved and simplified syntax since the main focus of \thpkg\ is versatility and expandability rather than common usage.
+% Package \thpkg\ introduces a new mechanism to create and manage structured data called ``objects'' like the well known C structures. The functions exported by this package are quite low level, and many important mechanisms like member protection and name resolution aren't already defined and should be introduced by intermediate packages. Higher level libraries built on top of \thpkg\ could also implement an improved and simplified syntax since the main focus of \thpkg\ is versatility and expandability rather than common usage.
%
% This packages follows the \href{https://semver.org/}{SemVer} specification (\texttt{https://semver.org/}). In particular any major version update (for example from \texttt{1.2} to \texttt{2.0}) may introduce imcompatible changes and so it's not advisable to work with different packages that require different major versions of \thpkg. Instead changes introduced in minor and patch version updates are always backward compatible, and any withdrawn function is declared deprecated instead of being removed.
%
-% \section{Objects and proxies}
-% Usually an object in programming languages can be seen as a collection of variables (organized in different ways depending on the chosen language) treated as part of a single entity. In \thpkg\ objects are collections of
-% \begin{itemize}
-% \item \LaTeX3 variables, called \emph{members};
-% \item \LaTeX3 functions, called \emph{methods};
-% \item generic control sequences, calles simply \emph{macros};
-% \item other \emph{embedded objects}.
-% \end{itemize}
-% Both members and methods can be retrieved from a string representing the container object, that is the \emph{address} of the object and act like the address of a structure in C.
+% \section{Addresses}
+% In this package a \emph{pure address} is any string without spaces (so a sequence of tokens with category code 12 ``other'') that uniquely identifies a resource or an entity. An example of pure address if the name of a control sequence \tn{\meta{name}} that can obtained by full expanding \cs{cs_to_str:N} \tn{\meta{name}}. Instead an \emph{expanded address} is a token list that contains only tokens with category code 11 (letters) or 12 (other) that can be directly converted to a pure address with a simple call to \cs{tl_to_str:n} or by assigning it to a string variable.
+%
+% An \emph{address} is instead a fully expandable token list which full expansion is an expanded address, where full expansion means the expansion process performed inside |c|, |x| and |e| parameters. Moreover, any address should be fully expandable according to the rules of |x| and |e| parameter types with same results, and the name of control sequence resulting from a |c|-type expansion of such address must be equal to its full expansion. For these reasons addresses should not contain parameter tokens like |#| (because they're threat differently by |x| and |e|) or control sequences that prevents expansion like \cs{exp_not:n} (because they leave unexpanded control sequences after an |x| or |e| expansion, and expanded addresses can't have control sequences inside them). In particular, |\tl_to_str:n{ ## }| is \emph{not} a valid address (assuming standard category codes).
+%
+% Addresses could be not full expanded inside an |f| argument, thus an address expanded in an |f| argument should be |x|, |e| or |c| expended later to get the actual pure address. If you need to fully expand an address in an |f| argument (because, for example, your macro should be fully expandable and your engine is too old to support |e| expansion efficiently) then you can put your address inside \cs{rwobj_address_f:n} and pass them to your function. For example,
+% \begin{verbatim}
+% \your_function:f{ \rwobj_address_f:n { your \address } }
+% \end{verbatim}
+% Remember that \cs{rwobj_address_f:n} only works with addresses, can't be used to fully expand any token list.
%
-% An address is composed of two parts: the \emph{module} in which variables are created and an \emph{identifier} that identify uniquely the object inside its module. It's up to the caller that two different objects have different identifiers. The address of an object can be obtained with the \cs{object_address} function. Identifiers and module names should not contain numbers, |#|, |:| and |_| characters in order to avoid conflicts with hidden auxiliary commands. However you can use non letter characters like |-| in order to organize your members and methods.
+% Like functions and variables names, pure addresses should follows some basic naming conventions in order to avoid clashes between addresses in different modules. Each pure address starts with the \meta{module} name in which such address is allocated, then an underscore (|_|) and the \meta{identifier} that uniquely identifies the resource inside the module. The \meta{module} should contain only lowercase ASCII letters.
%
-% Moreover normal control sequences have an address too, but it's simply any token list for which a |c| expansion retrieves the original control sequence. We impose also that any |x| or |e| fully expansion will be a string representing the control sequence's name, for this reason inside an address |#| characters and \cs{exp_not} functions aren't allowed.
+% A \emph{pointer} is just a \LaTeX3 string variable that holds a pure address. We don't enforce to use |str| or any special suffix to denote pointers so you're free to use |str| or a custom \meta{type} as suffix for your pointers in order to distinguish between them according to their type.
%
-% In \thpkg\ objects are created from an existing object that have a suitable inner structure. These objects that can be used to create other objects are called \emph{proxy}. Every object is generated from a particular proxy object, called \emph{generator}, and new objects can be created from a specified proxy with the \cs{object_create} functions.
+% In \thpkg\ all the macros ending with |_adr| or |_address| are fully expandable and can be used to compose valid addresses as explained in their documentation.
%
-% Since proxies are themself objects we need a proxy to instantiate user defined proxies, you can use the |proxy| object in the |rawobjects| module to create you own proxy, which address is held by the \cs{c_proxy_address_str} variable. Proxies must be created from the |proxy| object otherwise they won't be recognized as proxies. Instead of using \cs{object_create} to create proxies you can directly use the function \cs{proxy_create}.
+% \section{Objects}
+% An \emph{object} is just a collection of several related entities called \emph{fields}. Objects are themselves entities so they have addresses and could be contained inside other objects. Objects addresses are also used to compose the addresses of each of their inner entity, thus different objects can have fields with the same name without clashing each other. Each object is uniquely identified by its pure address, which is composed by a \meta{module} and an \meta{identifier} as explained before. The use of underscore character in objects identifiers is reserved. You can retrive the address of an object via the \cs{object_address:nn} function.
%
-% Each member or method inside an object belongs to one of these categories:
-% \begin{enumerate}
-% \item \emph{mutables};
-% \item \emph{near constants};
-% \item \emph{remote constants}.
-% \end{enumerate}
-% \textbf{Warning}: Currently only members (variables) can be mutables, not methods. Mutable members can be added in future releases if they'll be needed.
+% Objects are always created from already existing objects. An object that can be used to create other objects is called |proxy|, and the proxy that has created an object is its \emph{generator}. In the |rawobjects| module is already allocated a particular proxy that can be used to create every other proxy. Its identifier is just |proxy| and its pure address is stored in \cs{c_proxy_address_str}. The functions \cs{object_create} can be used to create new objects.
%
-% Members declared as mutables works as normal variables: you can modify their value and retrieve it at any time. Instead members and methods declared as near constant works as constants: when you create them you must specify their initial value (or function body for methods) and you won't be allowed to modify it later. Remote constants for an object are simply near constants defined in its generator: all near constants defined inside a proxy are automatically visible as remote constants to every object generated from that proxy. Usually functions involving near constants have |nc| inside their name, and |rc| if instead they use remote constants.
+% \section{Fields}
+% Remember that objects are just a collection of different fields uniquely identidied by a pure address. Here an field could be one of the following entities:
+% \begin{itemize}
+% \item a \LaTeX3 variable, in which case the field is called \emph{member};
+% \item a \LaTeX3 constant, in which case the field is called just \emph{constant};
+% \item a \LaTeX3 function, in which case the field is called \emph{method};
+% \item generic control sequences, in which case the field is called simply \emph{macro};
+% \item an entire object, in which case the field is called \emph{embedded object}.
+% \end{itemize}
%
-% Instead of creating embedded objects or mutable members in each of your objects you can push their specifications inside the generating proxy via \cs{proxy_push_embedded}, \cs{proxy_push_member}. In this way either object created from such proxy will have the specified members and embedded objects. Specify mutable members in this way allows you to omit that member type in some functions as \cs{object_member_adr} for example, their member type will be deduced automatically from its specification inside generating proxy.
+% Objects could be declared \emph{local} or \emph{global}. The only difference between a local and a global object is the scope of their members (that are \LaTeX3 variables). You should always create global object unless you specifically need local members.
%
-% Objects can be declared public, private and local, global. In a public/private object every nonconstant member and method is declared public/private, but inside local/global object only assignation to mutable members is performed locally/globally since allocation is always performed globally via \cs{\meta{type}_new:Nn} functions (nevertheless members will be accordingly declared |g_| or |l_|). This is intentional in order to follow the \LaTeX3 guidelines about variables managment, for additional motivations you can see \href{https://github.com/latex3/latex3/issues/410}{this thread} in the \LaTeX3 repository.
+% \subsection{Constants}
+% Constants in an object could be \emph{near} and \emph{remote}. A near constant is just a constant declared in such object and could be referred only by it, instead a remote constant is declared inside its generator and can be referred by any object created from that proxy, thus it's shared between all the generated objects. Functions in this library that work with near constants usually contain |ncmember| in their names, whereas those involving remore constants contain |rcmember| instead.
%
-% Address of members/methods can be obtained with functions in the form \cs{object_\meta{item}\meta{category}_adr} where \meta{item} is |member|, |method|, |macro| or |embedded| and \meta{category} is |nc| for near constants, |rc| for remote ones and empty for others. For example \cs{object_rcmethod_adr} retrieves the address of specified remote constant method.
+% Both near and remote constants are created in the same way via the |_newconst| functions, however remote constant should be created in a proxy whereas near contant are created directly in the target object.
%
-% \section{Put objects inside objects}
-% Sometimes it's necessary to include other objects inside an object, and since objects are structured data types you can't put them directly inside a variable. However \thpkg\ provides some workarounds that allows you to include objects inside other objects, each with its own advantages and disadvantages.
+% \subsection{Methods}
+% Methods are \LaTeX3 functions that can't be changed once they're created. Like constant, methods could be near or remote. Moreover, functions in this library dealing with near methods contain |ncmethod| whereas those dealing with remote methods contain |rcmethod| in their names.
%
-% In the following examples we're in module |mymod| and we want to put inside object |A| another object created with proxy |prx|.
+% \subsection{Members}
+% Members are just mutable \LaTeX3 variables. You can manually create new members in already existing objects or you can put the definition of a new member directly in a proxy with the \cs{proxy_push_member} functions. In this way all the objects created with that proxy will have a member according to such definition. If the object is local/global then all its members are automatically local/global.
%
-% \subsection{Put a pointer variable}
-% A simple solution is creating that object outside |A| with \cs{object_create}
-% \begin{verbatim}
-% \object_create:nnnNN
-% { \object_address:nn{ mymod }{ prx } }{ mymod }{ B } ....
-% \end{verbatim}
-% and then creating a pointer variable inside |A| (usually of type |tl| or |str|) holding the newly created address:
-% \begin{verbatim}
-% \object_new_member:nnn
+% A member can be \emph{tracked} or \emph{not tracked}. A tracked member have additional information, like its type, stored in the object or in its generator. In particular, you don't need to specify the type of a tracked member and some functions in \thpkg\ are able to retrieve the required information. All the members declared in the generator are automatically tracked.
+%
+% \section{Object members}
+% Sometimes it's necessary to store an instance of an object inside another object, since objects are structured entities that can't be entirely contained in a single \LaTeX3 variable you can't just put it inside a member or constant. However, there are some very easy workarounds to insert object instances as fields of other objects.
+%
+% For example, we're in module |MOD| and we have an object with id |PAR|. We want to provide |PAR| with a field that holds an instance of an object created by proxy |PRX|. We can achieve this in three ways:
+%
+% \subsection{Create a pointer member}
+% We first create a new object from |PRX|
+% \begin{Coding}
+% !simfun[object_create][nnn]
+% { !simfun[object_address][nn] { MOD }{ PRX } }{ MOD }{ INST }
+% \end{Coding}
+% then we create an |str| member in |PAR| that will hold the address of the newly created object.
+% \begin{Coding}
+% !simfun[object_new_member][nnn]
% {
-% \object_address:nn{ mymod }{ A }
-% }{ pointer }{ tl }
+% !simfun[object_address][nn] { MOD }{ PAR }
+% }{ pointer }{ str }
%
-% \tl_(g)set:cn
+% !simfun[object_member_set][nnnx]
% {
-% \object_new_member:nnn
-% {
-% \object_address:nn{ mymod }{ A }
-% }{ pointer }{ tl }
+% !simfun[object_address][nn] { MOD }{ PAR }
% }
+% { pointer }{ str }
% {
-% \object_address:nn{ mymod }{ B }
+% !simfun[object_address][nn] { MOD }{ INST }
% }
+% \end{Coding}
%
-% \end{verbatim}
-% you can the access the pointed object by calling \cs{object_member_use} on |pointer| member.
+% You can then get the pointed object by just using the |pointer| member. Notice that you're not force to use the |str| type for the pointer member, but you can also use |tl| or any custom \meta{type}. In the latter case be sure to at least define the following functions: \cs{\meta{type}_new:c}, \cs{\meta{type}_(g)set:cn} and \cs{\meta{type}_use:c}.
%
% \subsubsection*{Advantages}
% \begin{itemize}
@@ -133,43 +153,42 @@
% \subsubsection*{Disadvantages}
% \begin{itemize}
% \item You must manually create both the objects and link them;
-% \item creating objects also creates additional hidden variables, taking so (little) additional space.
+% \item if you forgot to properly initialize the pointer member it'll contain the ``null address'' (the empty string). Despite other programming languages the null address is not treated specially by \thpkg, which makes finding null pointer errors more difficult.
% \end{itemize}
%
% \subsection{Clone the inner structure}
-% Instead of referring a complete object you can just clone the inner structure of |prx| and put inside |A|. For example if |prx| declares member |x| of type |str| and member |y| of type |int| then you can do
-% \begin{verbatim}
-% \object_new_member:nnn
+% Anoter solution is to copy the members declared in |PRX| to |PAR|. For example, if in |PRX| are declared a member with name |x| and type |str|, and a member with name |y| and type |int| then
+% \begin{Coding}
+% !simfun[object_new_member][nnn]
% {
-% \object_address:nn{ mymod }{ A }
+% !simfun[object_address][nn] { MOD }{ PAR }
% }{ prx-x }{ str }
-% \object_new_member:nnn
+% !simfun[object_new_member][nnn]
% {
-% \object_address:nn{ mymod }{ A }
+% !simfun[object_address][nn] { MOD }{ PAR }
% }{ prx-y }{ int }
-% \end{verbatim}
-% and then use |prx-x|, |prx-y| as normal members of |A|.
+% \end{Coding}
%
% \subsubsection*{Advantages}
% \begin{itemize}
-% \item Simple and no additional function needed to create and manage included objects;
-% \item you can put these specifications inside a proxy so that every object created with it will have the required members/methods;
-% \item no hidden variable created, lowest overhead among the proposed solutions.
+% \item Very simple;
+% \item no hidden item is created, this procedure has the lowest overhead among all the proposed solutions here.
% \end{itemize}
%
% \subsubsection*{Disadvantages}
% \begin{itemize}
-% \item Cloning the inner structure doesn't create any object, so you don't have any object address nor you can share the included ``object'' unless you share the container object too.
+% \item If you need the original instance of the stored object then you should create a temporary object and manually copy each field to it. Don't use this method if you later need to retrieve the stored object entirely and not only its fields.
% \end{itemize}
%
% \subsection{Embedded objects}
% From \thpkg\ \texttt{2.2} you can put \emph{embedded objects} inside objects. Embedded objects are created with \cs{embedded_create} function
-% \begin{verbatim}
-% \embedded_create:nnn
+% \begin{Coding}
+% !simfun[embedded_create][nnn]
% {
-% \object_address:nn{ mymod }{ A }
-% }{ prx }{ B }
-% \end{verbatim}
+% !simfun[object_address][nn] { MOD }{ PAR }
+% }
+% { PRX }{ emb }
+% \end{Coding}
% and addresses of emmbedded objects can be retrieved with function \cs{object_embedded_adr}. You can also put the definition of embedded objects in a proxy by using \cs{proxy_push_embedded} just like \cs{proxy_push_member}.
%
% \subsubsection*{Advantages}
@@ -187,13 +206,25 @@
%
% \section{Library functions}
% \label{sec:lib}
+%
+% \subsection{Common functions}
+%
+% \begin{function}[EXP]{\rwobj_address_f:n}
+% \begin{syntax}
+% \cs{rwobj_address_f:n} \Arg{address}
+% \end{syntax}
+% Fully expand an address in an |f|-type argument.
+%
+% \fromV{2.3}
+% \end{function}
+%
% \subsection{Base object functions}
%
-% \begin{function}[EXP]{\object_address:nn}
+% \begin{function}[rEXP]{\object_address:nn}
% \begin{syntax}
% \cs{object_address:nn} \Arg{module} \Arg{id}
% \end{syntax}
-% Composes the address of object in module \meta{module} with identifier \meta{id} and places it in the input stream. Notice that \meta{module} and \meta{id} are converted to strings before composing them in the address, so they shouldn't contain any command inside. If you want to execute its content you should use a new variant, for example |V|, |f| or |e| variants.
+% Composes the address of object in module \meta{module} with identifier \meta{id} and places it in the input stream. Notice that both \meta{module} and \meta{id} are converted to strings before composing them in the address, so they shouldn't contain any command inside.
%
% \fromV{1.0}
% \end{function}
@@ -207,7 +238,7 @@
% \fromV{1.1}
% \end{function}
%
-% \begin{function}[EXP]{\object_embedded_adr:nn, \object_embedded_adr:Vn}
+% \begin{function}[rEXP]{\object_embedded_adr:nn, \object_embedded_adr:Vn}
% \begin{syntax}
% \cs{object_embedded_adr:nn} \Arg{address} \Arg{id}
% \end{syntax}
@@ -258,33 +289,41 @@
%
% \subsection{Members}
%
-% \begin{function}[EXP]{\object_member_adr:nnn, \object_member_adr:Vnn, \object_member_adr:nnv, \object_member_adr:nn, \object_member_adr:Vn}
+% \begin{function}[rEXP]{\object_member_adr:nnn, \object_member_adr:Vnn, \object_member_adr:nnv, \object_member_adr:nn, \object_member_adr:Vn}
% \begin{syntax}
% \cs{object_member_adr:nnn} \marg{address} \marg{member name} \marg{member type}
% \cs{object_member_adr:nn} \marg{address} \marg{member name}
% \end{syntax}
-% Fully expands to the address of specified member variable. If type is not specified it'll be retrieved from the generator proxy, but only if member is specified in the generator.
+% Fully expands to the address of specified member variable. If the member is tracked then you can omit the type field.
%
% \fromV{1.0}
% \end{function}
%
-% \begin{function}[pTF]{\object_member_if_exist:nnn, \object_member_if_exist:Vnn, \object_member_if_exist:nn, \object_member_if_exist:Vn}
+% \begin{function}[pTF]{\object_member_if_exist:nnn, \object_member_if_exist:Vnn}
% \begin{syntax}
% \cs{object_member_if_exist_p:nnn} \marg{address} \marg{member name} \marg{member type}
% \cs{object_member_if_exist:nnnTF} \marg{address} \marg{member name} \marg{member type} \Arg{true code} \Arg{false code}
-% \cs{object_member_if_exist_p:nn} \Arg{address} \Arg{member name}
-% \cs{object_member_if_exist:nnTF} \Arg{address} \Arg{member name} \Arg{true code} \Arg{false code}
% \end{syntax}
% Tests if the specified member exist.
%
% \fromV{2.0}
% \end{function}
%
+% \begin{function}[pTF]{\object_member_if_tracked:nn, \object_member_if_tracked:Vn}
+% \begin{syntax}
+% \cs{object_member_if_tracked_p:nn} \Arg{address} \Arg{member name}
+% \cs{object_member_if_tracked:nnTF} \Arg{address} \Arg{member name} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% Tests if the specified member exist and is tracked.
+%
+% \fromV{2.3}
+% \end{function}
+%
% \begin{function}[EXP]{\object_member_type:nn, \object_member_type:Vn}
% \begin{syntax}
% \cs{object_member_type:nn} \marg{address} \marg{member name}
% \end{syntax}
-% Fully expands to the type of member \meta{member name}. Use this function only with member variables specified in the generator proxy, not with other member variables.
+% Fully expands to the type of specified tracked member.
%
% \fromV{1.0}
% \end{function}
@@ -293,11 +332,20 @@
% \begin{syntax}
% \cs{object_new_member:nnn} \marg{address} \marg{member name} \marg{member type}
% \end{syntax}
-% Creates a new member variable with specified name and type. You can't retrieve the type of these variables with \cs{object_member_type} functions.
+% Creates a new member with specified name and type. The created member is not tracked.
%
% \fromV{1.0}
% \end{function}
%
+% \begin{function}{\object_new_member_tracked:nnn, \object_new_member_tracked:Vnn}
+% \begin{syntax}
+% \cs{object_new_member_tracked:nnn} \marg{address} \marg{member name} \marg{member type}
+% \end{syntax}
+% Creates a new tracked member.
+%
+% \fromV{2.3}
+% \end{function}
+%
% \begin{function}[EXP]{\object_member_use:nnn, \object_member_use:Vnn, \object_member_use:nnv, \object_member_use:nn, \object_member_use:Vn}
% \begin{syntax}
% \cs{object_member_use:nnn} \marg{address} \marg{member name} \marg{member type}
@@ -328,7 +376,35 @@
% \fromV{1.0}
% \end{function}
%
-% \begin{function}[EXP]{\object_ncmember_adr:nnn, \object_ncmember_adr:Vnn, \object_ncmember_adr:vnn, \object_rcmember_adr:nnn, \object_rcmember_adr:Vnn}
+% \begin{function}{\object_member_generate:NN, \object_member_generate_protected:NN}
+% \begin{syntax}
+% \cs{object_member_generate:NN} \cs{\meta{name\textsubscript{1}}} \cs{\meta{name\textsubscript{2}}:\meta{arg1}\meta{args}}
+% \end{syntax}
+% Define the new functions \cs{\meta{name\textsubscript{1}}:nnn\meta{Targs} } and \cs{\meta{name\textsubscript{1}}:nn\meta{Targs} } that pass to \cs{\meta{name\textsubscript{2}}:\meta{arg1}\meta{args} } the specified member address as the first argument. \meta{Targs} is a list of argument specifications obtained by transforming each element of \meta{args} to |n|, |N|, |w|, |T| or |F|.
+%
+% The first three parameters of \cs{\meta{name\textsubscript{1}}:nnn\meta{args} } should be in the following order:
+% \begin{enumerate}
+% \item an object address;
+% \item a member name;
+% \item the type of specified member.
+% \end{enumerate}
+%
+% Function \cs{\meta{name\textsubscript{1}}:nn\meta{args} } only accepts the first two parameters and works only with tracked members. Notice that \meta{arg1} must be only one of the following: |n|, |c|, |v|, |x|, |f|, |e|, |o|.
+%
+% \fromV{2.3}
+% \end{function}
+%
+% \begin{function}{\object_member_generate_inline:Nnn, \object_member_generate_protected_inline:Nnn}
+% \begin{syntax}
+% \cs{object_member_generate_inline:Nnn} \cs{\meta{name\textsubscript{1}}} \Arg{name\textsubscript{2}} \{\meta{arg1}\meta{args}\}
+% \end{syntax}
+% Works as \cs{object_member_generate:NN}, however in \meta{name\textsubscript{2}} you can use parameters |#1| and |#2| to compose the needed function. Parameter |#1| expands to the (fully expanded) member type and |#2| is equal to |g| if the object is global and it's empty if it is local.
+%
+% \fromV{2.3}
+% \end{function}
+%
+% \subsection{Constants}
+% \begin{function}[rEXP]{\object_ncmember_adr:nnn, \object_ncmember_adr:Vnn, \object_ncmember_adr:vnn, \object_rcmember_adr:nnn, \object_rcmember_adr:Vnn}
% \begin{syntax}
% \cs{object_ncmember_adr:nnn} \Arg{address} \Arg{member name} \Arg{member type}
% \end{syntax}
@@ -356,10 +432,26 @@
% \fromV{2.0}
% \end{function}
%
-% \subsection{Methods}
-% Currentlu only constant methods (near and remote) are implemented in \thpkg\ as explained before.
+% \begin{function}{\object_ncmember_generate:NN, \object_ncmember_protected_generate:NN, \object_rcmember_generate:NN, \object_rcmember_protected_generate:NN}
+% \begin{syntax}
+% \cs{object_ncmember_generate:NN} \cs{\meta{name\textsubscript{1}}} \cs{name\textsubscript{2}}:\meta{arg1}\meta{args}
+% \end{syntax}
+% Works as \cs{object_member_generate:NN} but with constants instead of members.
+%
+% \fromV{2.3}
+% \end{function}
%
-% \begin{function}[EXP]{\object_ncmethod_adr:nnn, \object_ncmethod_adr:Vnn, \object_ncmethod_adr:vnn, \object_rcmethod_adr:nnn, \object_rcmethod_adr:Vnn}
+% \begin{function}{\object_ncmember_generate_inline:Nnn, \object_ncmember_protected_generate_inline:Nnn, \object_rcmember_generate_inline:Nnn, \object_rcmember_protected_generate_inline:Nnn}
+% \begin{syntax}
+% \cs{object_ncmember_generate_inline:Nnn} \cs{\meta{name\textsubscript{1}}} \Arg{name\textsubscript{2}} \{\meta{arg1}\meta{args}\}
+% \end{syntax}
+% Works as \cs{object_member_generate_inline:Nnn} but with constants instead of members.
+%
+% \fromV{2.3}
+% \end{function}
+%
+% \subsection{Methods}
+% \begin{function}[rEXP]{\object_ncmethod_adr:nnn, \object_ncmethod_adr:Vnn, \object_ncmethod_adr:vnn, \object_rcmethod_adr:nnn, \object_rcmethod_adr:Vnn}
% \begin{syntax}
% \cs{object_ncmethod_adr:nnn} \Arg{address} \Arg{method name} \Arg{method variant}
% \end{syntax}
@@ -400,9 +492,7 @@
% \fromV{2.0}
% \end{function}
%
-% \subsection{Constant member creation}
-% Unlike normal variables, constant variables in \LaTeX3 are created in different ways depending on the specified type. So we dedicate a new section only to collect some of these fuinctions readapted for near constants (remote constants are simply near constants created on the generator proxy).
-%
+% \subsection{Creation of constants}
% \begin{function}{\object_newconst_tl:nnn, \object_newconst_tl:Vnn, \object_newconst_str:nnn, \object_newconst_str:Vnn, \object_newconst_int:nnn, \object_newconst_int:Vnn, \object_newconst_clist:nnn, \object_newconst_clist:Vnn, \object_newconst_dim:nnn, \object_newconst_dim:Vnn, \object_newconst_skip:nnn, \object_newconst_skip:Vnn, \object_newconst_fp:nnn, \object_newconst_fp:Vnn}
% \begin{syntax}
% \cs{object_newconst_\meta{type}:nnn} \Arg{address} \Arg{constant name} \Arg{value}
@@ -437,14 +527,13 @@
% \begin{syntax}
% \cs{object_newconst:nnnn} \Arg{address} \Arg{constant name} \Arg{type} \Arg{value}
% \end{syntax}
-% Expands to \cs{\meta{type}_const:cn} \marg{address} \marg{value}, use it if you need to create simple constants with custom types.
+% Invokes \cs{\meta{type}_const:cn} to create the specified constant.
%
% \fromV{2.1}
% \end{function}
%
% \subsection{Macros}
-%
-% \begin{function}[EXP]{\object_macro_adr:nn, \object_macro_adr:Vn}
+% \begin{function}[rEXP]{\object_macro_adr:nn, \object_macro_adr:Vn}
% \begin{syntax}
% \cs{object_macro_adr:nn} \Arg{address} \Arg{macro name}
% \end{syntax}
@@ -464,7 +553,7 @@
%
% There isn't any standard function to create macros, and macro declarations can't be inserted in a |proxy| object. In fact a macro is just an unspecialized control sequence at the disposal of users that usually already know how to implement them.
%
-% \subsection{Proxy utilities and object creation}
+% \subsection{Proxies and object creation}
%
% \begin{function}[pTF]{\object_if_proxy:n, \object_if_proxy:V}
% \begin{syntax}
@@ -510,14 +599,24 @@
% \begin{syntax}
% \cs{object_create:nnnNN} \marg{proxy address} \marg{module} \marg{id} \meta{scope} \meta{visibility}
% \end{syntax}
-% Creates an object by using the proxy at \meta{proxy address} and the specified parameters.
+% Creates an object by using the proxy at \meta{proxy address} and the specified parameters. Use this function only if you need to create private objects (at present private objects are functionally equivalent to public objects) or if you need to compile your project with an old version of this library (|< 2.3|).
%
% \fromV{1.0}
% \end{function}
%
+% \begin{function}{\object_create:nnnN, \object_create:VnnN, \object_create:nnn, \object_create:Vnn}
+% \begin{syntax}
+% \cs{object_create:nnnN} \Arg{proxy address} \Arg{module} \Arg{id} \meta{scope}\\
+% \cs{object_create:nnn} \Arg{proxy address} \Arg{module} \Arg{id}
+% \end{syntax}
+% Same as \cs{object_create:nnnNN} but both create only public objects, and the |:nnn| version only global ones. Always use these two function instead of \cs{object_create:nnnNN} unless you strictly need private objects.
+%
+% \fromV{2.3}
+% \end{function}
+%
% \begin{function}{\embedded_create:nnn, \embedded_create:Vnn, \embedded_create:nvn}
% \begin{syntax}
-% \cs{embedded_create:nnn} \Arg{parent object} \Arg{proxy address} \Arg{id}
+% \cs{embedded_create:nnn} \Arg{parent object} \Arg{proxy address} \Arg{id}
% \end{syntax}
% Creates an embedded object with name \meta{id} inside \meta{parent object}.
%
@@ -556,12 +655,22 @@
%
% \begin{function}{\proxy_create:nnN, \proxy_create_set:NnnN, \proxy_create_gset:NnnN}
% \begin{syntax}
-% \cs{proxy_create:nnN} \marg{module} \marg{id} \meta{visibility}
-% \cs{proxy_create_set:NnnN} \meta{str var} \marg{module} \marg{id} \meta{visibility}
+% \cs{proxy_create:nnN} \Arg{module} \Arg{id} \meta{visibility}
+% \cs{proxy_create_set:NnnN} \meta{str var} \Arg{module} \Arg{id} \meta{visibility}
% \end{syntax}
-% Creates a global proxy object.
+% These commands are deprecated because proxies should be global and public. Use instead \cs{proxy_create:nn}, \cs{proxy_create_set:Nnn} and \cs{proxy_create_gset:Nnn}.
%
-% \fromV{1.0}
+% \fromVD{1.0}{2.3}
+% \end{function}
+%
+% \begin{function}{\proxy_create:nn, \proxy_create_set:Nnn, \proxy_create_gset:Nnn}
+% \begin{syntax}
+% \cs{proxy_create:nn} \Arg{module} \Arg{id}
+% \cs{proxy_create_set:Nnn} \meta{str var} \Arg{module} \Arg{id}
+% \end{syntax}
+% Creates a global public proxy object.
+%
+% \fromV{2.3}
% \end{function}
%
% \begin{function}{\proxy_push_member:nnn, \proxy_push_member:Vnn}
@@ -582,6 +691,22 @@
% \fromV{2.2}
% \end{function}
%
+% \begin{function}{\proxy_add_initializer:nN, \proxy_add_initializer:VN}
+% \begin{syntax}
+% \cs{proxy_add_initializer:nN} \Arg{proxy address} \meta{initializer}
+% \end{syntax}
+% Pushes a new initializer that will be executed on each created objects. An initializer is a function that should accept five arguments in this order:
+% \begin{itemize}
+% \item the full expanded address of used proxy as an |n| argument;
+% \item the module name as an |n| argument;
+% \item the full expanded address of created object as an |n| argument.
+% \end{itemize}
+%
+% Initializer will be executed in the same order they're added.
+%
+% \fromV{2.3}
+% \end{function}
+%
% \begin{function}{\object_assign:nn, \object_assign:Vn, \object_assign:nV, \object_assign:VV}
% \begin{syntax}
% \cs{object_assign:nn} \marg{to address} \marg{from address}
@@ -593,127 +718,125 @@
%
% \section{Examples}
% \subsection*{Example 1}
-% Create a public proxy with id \verb|myproxy| with the specification of a single member variable with name \verb|myvar| and type \verb|tl|, then set its address inside \cs{l_myproxy_str}.
+% Create a public proxy with id \verb|myproxy| with the specification of a single member variable with name \verb|myvar| and type \verb|tl|, then set its address inside \cs{g_myproxy_str}.
%
-% \begin{verbatim}
-% \str_new:N \l_myproxy_str
-% \proxy_create_set:NnnN \l_myproxy_str { example }{ myproxy }
-% \c_object_public_str
-% \proxy_push_member:Vnn \l_myproxy_str { myvar }{ tl }
-% \end{verbatim}
+% \begin{Coding}
+% !simfun[str_new][N] !simvar[g_myproxy_str]
+% !simfun[proxy_create_gset][Nnn] !simvar[g_myproxy_str] { example }{ myproxy }
+% !simfun[proxy_push_member][Vnn] !simvar[g_myproxy_str] { myvar }{ tl }
+% \end{Coding}
%
% Then create a new object with name \verb|myobj| with that proxy, assign then token list \verb|\c_dollar_str{} ~ dollar ~ \c_dollar_str{}| to \verb|myvar| and then print it.
%
-% \begin{verbatim}
-% \str_new:N \l_myobj_str
-% \object_create_set:NVnnNN \l_myobj_str \l_myproxy_str
-% { example }{ myobj } \c_object_local_str \c_object_public_str
-% \tl_set:cn
+% \begin{Coding}
+% !simfun[str_new][N] !simvar[g_myobj_str]
+% !simfun[object_create_gset][NVnn] !simvar[g_myobj_str] !simvar[g_myproxy_str]
+% { example }{ myobj }
+% !simfun[tl_gset][cn]
% {
-% \object_member_adr:Vn \l_myobj_str { myvar }
+% !simfun[object_member_adr][Vn] !simvar[g_myobj_str] { myvar }
% }
-% { \c_dollar_str{} ~ dollar ~ \c_dollar_str{} }
-% \object_member_use:Vn \l_myobj_str { myvar }
-% \end{verbatim}
+% { !simvar[c_dollar_str]{} ~ dollar ~ !simvar[c_dollar_str]{} }
+% !simfun[object_member_use][Vn] !simvar[g_myobj_str] { myvar }
+% \end{Coding}
%
% Output: \ExplSyntaxOn
-% \str_new:N \l_myproxy_str
-% \proxy_create_set:NnnN \l_myproxy_str { example }{ myproxy }
-% \c_object_public_str
-% \proxy_push_member:Vnn \l_myproxy_str { myvar }{ tl }
-% \str_new:N \l_myobj_str
-% \object_create_set:NVnnNN \l_myobj_str \l_myproxy_str
-% { example }{ myobj } \c_object_local_str \c_object_public_str
-% \tl_set:cn
+% \str_new:N \g_myproxy_str
+% \proxy_create_gset:Nnn \g_myproxy_str { example }{ myproxy }
+% \proxy_push_member:Vnn \g_myproxy_str { myvar }{ tl }
+% \str_new:N \g_myobj_str
+% \object_create_gset:NVnn \g_myobj_str \g_myproxy_str
+% { example }{ myobj }
+% \tl_gset:cn
% {
-% \object_member_adr:Vn \l_myobj_str { myvar }
+% \object_member_adr:Vn \g_myobj_str { myvar }
% }
% { \c_dollar_str{} ~ dollar ~ \c_dollar_str{} }
-% \object_member_use:Vn \l_myobj_str { myvar }
+% \object_member_use:Vn \g_myobj_str { myvar }
% \ExplSyntaxOff
%
-% If you don't want to specify an object identifier you can also do
+% You can also avoid to specify an object identify and use \cs{object_gallocate_gincr} instead:
%
-% \begin{verbatim}
-% \int_new:N \l_intc_int
-% \object_allocate_incr:NNVnNN \l_myobj_str \l_intc_int \l_myproxy_str
-% { example } \c_object_local_str \c_object_public_str
-% \tl_set:cn
+% \begin{Coding}
+% !simfun[int_new][N] !simvar[g_intc_int]
+% !simfun[object_gallocate_gincr][NNVnNN] !simvar[g_myobj_str] !simvar[g_intc_int] !simvar[g_myproxy_str]
+% { example } !simvar[c_object_local_str] !simvar[c_object_public_str]
+% !simfun[tl_gset][cn]
% {
-% \object_member_adr:Vn \l_myobj_str { myvar }
+% !simfun[object_member_adr][Vn] !simvar[g_myobj_str] { myvar }
% }
-% { \c_dollar_str{} ~ dollar ~ \c_dollar_str{} }
-% \object_member_use:Vn \l_myobj_str { myvar }
-% \end{verbatim}
+% { !simvar[c_dollar_str]{} ~ dollar ~ !simvar[c_dollar_str]{} }
+% !simfun[object_member_use][Vn] !simvar[g_myobj_str] { myvar }
+% \end{Coding}
%
% Output: \ExplSyntaxOn
-% \int_new:N \l_intc_int
-% \object_allocate_incr:NNVnNN \l_myobj_str \l_intc_int \l_myproxy_str
+% \int_new:N \g_intc_int
+% \object_gallocate_gincr:NNVnNN \g_myobj_str \g_intc_int \g_myproxy_str
% { example } \c_object_local_str \c_object_public_str
-% \tl_set:cn
+% \tl_gset:cn
% {
-% \object_member_adr:Vn \l_myobj_str { myvar }
+% \object_member_adr:Vn \g_myobj_str { myvar }
% }
% { \c_dollar_str{} ~ dollar ~ \c_dollar_str{} }
-% \object_member_use:Vn \l_myobj_str { myvar }
+% \object_member_use:Vn \g_myobj_str { myvar }
% \ExplSyntaxOff
%
% \subsection*{Example 2}
% In this example we create a proxy object with an embedded object inside.
%
% Internal proxy
-% \begin{verbatim}
-% \proxy_create:nnN{ mymod }{ INT } \c_object_public_str
-% \proxy_push_member:nnn
+% \begin{Coding}
+% !simfun[proxy_create][nn] { mymod }{ INT }
+% !simfun[proxy_push_member][nnn]
% {
-% \object_address:nn{ mymod }{ INT }
+% !simfun[object_address][nn] { mymod }{ INT }
% }{ var }{ tl }
-% \end{verbatim}
+% \end{Coding}
%
% Container proxy
-% \begin{verbatim}
-% \proxy_create:nnN{ mymod }{ EXT } \c_object_public_str
-% \proxy_push_embedded:nnn
+% \begin{Coding}
+% !simfun[proxy_create][nn] { mymod }{ EXT }
+% !simfun[proxy_push_embedded][nnn]
% {
-% \object_address:nn{ mymod }{ EXT }
+% !simfun[object_address][nn] { mymod }{ EXT }
% }
% { emb }
% {
-% \object_address:nn{ mymod }{ INT }
+% !simfun[object_address][nn] { mymod }{ INT }
% }
-% \end{verbatim}
+% \end{Coding}
%
% Now we create a new object from proxy |EXT|. It'll contain an embedded object created with |INT| proxy:
-% \begin{verbatim}
-% \str_new:N \g_EXTobj_str
-% \int_new:N \g_intcount_int
-% \object_gallocate_gincr:NNnnNN
-% \g_EXTobj_str \g_intcount_int
+% \begin{Coding}
+% !simfun[str_new][N] !simvar[g_EXTobj_str]
+% !simfun[int_new][N] !simvar[g_intcount_int]
+% !simfun[object_gallocate_gincr][NNnnNN]
+% !simvar[g_EXTobj_str] !simvar[g_intcount_int]
% {
-% \object_address:nn{ mymod }{ EXT }
+% !simfun[object_address][nn] { mymod }{ EXT }
% }
% { mymod }
-% \c_object_local_str \c_object_public_str
-% \end{verbatim}
+% !simvar[c_object_local_str] !simvar[c_object_public_str]
+% \end{Coding}
% and use the embedded object in the following way:
-% \begin{verbatim}
-% \object_member_set:nnn
+% \begin{Coding}
+% !simfun[object_member_set][nnn]
% {
-% \object_embedded_adr:Vn \g_EXTobj_str { emb }
+% !simfun[object_embedded_adr][Vn] !simvar[g_EXTobj_str] { emb }
% }{ var }{ Hi }
-% \object_member_use:nn
+% !simfun[object_member_use][nn]
% {
-% \object_embedded_adr:Vn \g_EXTobj_str { emb }
+% !simfun[object_embedded_adr][Vn] !simvar[g_EXTobj_str] { emb }
% }{ var }
-% \end{verbatim}
+% \end{Coding}
% Output: \ExplSyntaxOn
-% \proxy_create:nnN{ mymod }{ INT } \c_object_public_str
+% \proxy_create:nn{ mymod }{ INT }
% \proxy_push_member:nnn
% {
% \object_address:nn{ mymod }{ INT }
% }{ var }{ tl }
%
-% \proxy_create:nnN{ mymod }{ EXT } \c_object_public_str
+% \proxy_create:nn{ mymod }{ EXT }
% \proxy_push_embedded:nnn
% {
% \object_address:nn{ mymod }{ EXT }
@@ -743,44 +866,59 @@
% }{ var }
% \ExplSyntaxOff
%
-% \section{Templated proxies}
-% At the current time there isn't a standardized approach to templated proxies. One problem of standardized templated proxies is how to define struct addresses for every kind of argument (token lists, strings, integer expressions, non expandable arguments, ...).
-%
-% Even if there isn't currently a function to define every kind of templated proxy you can anyway define your templated proxy with your custom parameters. You simply need to define at least two functions:
-% \begin{itemize}
-% \item an expandable macro that, given all the needed arguments, fully expands to the address of your templated proxy. This address can be obtained by calling \cs{object_address} \marg{module} \marg{id} where \meta{id} starts with the name of your templated proxy and is followed by a composition of specified arguments;
-% \item a not expandable macro that tests if the templated proxy with specified arguments is instantiated and, if not, instantiate it with different calls to \cs{proxy_create} and \cs{proxy_push_member}.
-% \end{itemize}
+% \subsection*{Example 3}
+% Here we show how to properly use \cs{object_member_generate:NN}. Suppose we don't know \cs{object_member_use} and we want to use \cs{tl_use:N} to get the value stored in member |MEM| of object |U| in module |MD3|.
%
-% In order to apply these concepts we'll provide a simple implementation of a linked list with a template parameter representing the type of variable that holds our data. A linked list is simply a sequence of nodes where each node contains your data and a pointer to the next node. For the moment we 'll show a possiple implementation of a template proxy class for such |node| objects.
+% \ExplSyntaxOn
+% \proxy_create:nn {MD3}{ex3p}
+% \proxy_push_member:nnn { \object_address:nn {MD3}{ex3p} }{MEM}{tl}
+% \object_create:nnn { \object_address:nn {MD3}{ex3p} }{MD3}{U}
+% \ExplSyntaxOff
%
-% First to all we define an expandable macro that fully expands to our node name:
-% \begin{verbatim}
-% \cs_new:Nn \node_address:n
+% We can do it in this way:
+% \begin{Coding}
+% !simfun[tl_use][c]
% {
-% \object_address:nn { linklist }{ node - #1 }
+% !simfun[object_member_adr][nnn]
+% { !simfun[object_address][nn] { MD3 }{ U } }
+% { MEM }{ tl }
% }
-% \end{verbatim}
-% where the |#1| argument is simply a string representing the type of data held by our linked list (for example |tl|, |str|, |int|, ...). Next we need a functions that instantiate our proxy address if it doesn't exist:
-% \begin{verbatim}
-% \cs_new_protected:Nn \node_instantiate:n
-% {
-% \object_if_exist:nF {\node_address:n { #1 } }
-% {
-% \proxy_create:nnN { linklist }{ node - #1 }
-% \c_object_public_str
-% \proxy_push_member:nnn {\node_address:n { #1 } }
-% { next }{ str }
-% \proxy_push_member:nnn {\node_address:n { #1 } }
-% { data }{ #1 }
-% }
-% }
-% \end{verbatim}
-% As you can see when \cs{node_instantiate} is called it first test if the proxy object exists. If not then it creates a new proxy with that name and populates it with the specifications of two members: a |next| member variable of type |str| that points to the next node, and a |data| member of the specified type that holds your data.
-%
-% Clearly you can define new functions to work with such nodes, for example to test if the next node exists or not, to add and remove a node, search inside a linked list, ...
-%
-%
+% \end{Coding}
+% but this solution is not so pratical since we should write a lot of code each time. We can then use \cs{object_member_generate:NN} to define an auxilary macro \cs{myaux_print_tl:nnn} in this way:
+% \begin{Coding}
+% !simfun[object_member_generate][NN] \myaux_print_tl !simfun[tl_use][c]
+% \end{Coding}
+% then we can get the content of our member in this way:
+% \begin{Coding}
+% !simfun[myaux_print_tl][nnn]
+% { !simfun[object_address][nn] { MD3 }{ U } }
+% { MEM }{ tl }
+% \end{Coding}
+%
+% For example if |U| contains |Hi| then the preceding code will output \ExplSyntaxOn
+% \object_member_set:nnnn
+% { \object_address:nn {MD3}{U}}{MEM}{tl}{Hi}
+% \object_member_generate_inline:Nnn \myaux_print_tl { #1_use }{ c }
+% \myaux_print_tl:nn
+% { \object_address:nn {MD3}{U}}{MEM}
+% \ExplSyntaxOff . If member |MEM| is tracked then you can use also the following command, which is generated together with \cs{myaux_print_tl:nnn}
+% \begin{Coding}
+% !simfun[myaux_print_tl][nn]
+% { !simfun[object_address][nn] { MD3 }{ U } }
+% { MEM }
+% \end{Coding}
+%
+% However, this function only works with |tl| members since we use \cs{tl_use:N}, so you should define a new function for every possible type, and even if you do it newer types introduced in other packages will not be supported. In such cases you can use \cs{object_member_generate_inline:Nnn} which allows you to build the called function by specifying its name and its parameters. The preceding code then becomes
+% \begin{Coding}
+% !simfun[object_member_generate_inline][Nnn] \myaux_print_tl { tl_use }{ c }
+% \end{Coding}
+%
+% This function does much more: in the second argument you can put also the parameters |#1| and |#2| that will expand respectively to the type of specified member and its scope. Let \cs{myaux_print:nnn} be our version of \cs{object_member_use:nnn} that retrieves the valued of the specified member, we are now able to define it in this way:
+% \begin{Coding}
+% !simfun[object_member_generate_inline][Nnn] \myaux_print { #1_use }{ c }
+% \end{Coding}
+%
+% When you use \cs{myaux_print:nnn} on a member of type |int| it replaces all the recurrences of |#1| with |int|, thus it will call \cs{int_use:c}.
%\end{documentation}
%
%\begin{implementation}
@@ -794,16 +932,78 @@
%<@@=rawobjects>
% \end{macrocode}
%
+% Deprecation message
+% \begin{macrocode}
+
+\msg_new:nnn { rawobjects }{ deprecate }
+ {
+ Command ~ #1 ~ is ~ deprecated. ~ Use ~ instead ~ #2
+ }
+
+\cs_new_protected:Nn \@@_launch_deprecate:NN
+ {
+ \msg_warning:nnnn{ rawobjects }{ deprecate }{ #1 }{ #2 }
+ }
+
+% \end{macrocode}
%
+% \begin{macro}{\rwobj_address_f:n}
+% It just performs a |c| expansion before passing it to \cs{cs_to_str:N}.
+% \begin{macrocode}
+
+\cs_new:Nn \rwobj_address_f:n
+ {
+ \exp_args:Nc \cs_to_str:N { #1 }
+ }
+
+% \end{macrocode}
+% \end{macro}
%
%\begin{variable}{\c_object_local_str, \c_object_global_str, \c_object_public_str, \c_object_private_str}
% \begin{macrocode}
-\str_const:Nn \c_object_local_str {loc}
-\str_const:Nn \c_object_global_str {glo}
-\str_const:Nn \c_object_public_str {pub}
-\str_const:Nn \c_object_private_str {pri}
+\str_const:Nn \c_object_local_str {l}
+\str_const:Nn \c_object_global_str {g}
+\str_const:Nn \c_object_public_str {_}
+\str_const:Nn \c_object_private_str {__}
+
+
+\cs_new:Nn \@@_scope:N
+ {
+ \str_use:N #1
+ }
+
+\cs_new:Nn \@@_scope_pfx:N
+ {
+ \str_if_eq:NNF #1 \c_object_local_str
+ { g }
+ }
+
+\cs_generate_variant:Nn \@@_scope_pfx:N { c }
+
+\cs_new:Nn \@@_scope_pfx_cl:n
+ {
+ \@@_scope_pfx:c{
+ \object_ncmember_adr:nnn
+ {
+ \object_embedded_adr:nn { #1 }{ /_I_/ }
+ }
+ { S }{ str }
+ }
+ }
+
+\cs_new:Nn \@@_vis_var:N
+ {
+ \str_use:N #1
+ }
+
+\cs_new:Nn \@@_vis_fun:N
+ {
+ \str_if_eq:NNT #1 \c_object_private_str
+ {
+ __
+ }
+ }
-\str_const:Nn \c_@@_const_str {con}
% \end{macrocode}
%\end{variable}
%
@@ -845,29 +1045,6 @@
% \end{macrocode}
%\end{macro}
%
-% \begin{macrocode}
-\cs_new:Nn \@@_object_modvar:n{
- c __ #1 _ MODULE _ str
-}
-
-\cs_new:Nn \@@_object_pxyvar:n{
- c __ #1 _ PROXY _ str
-}
-
-\cs_new:Nn \@@_object_scovar:n{
- c __ #1 _ SCOPE _ str
-}
-
-\cs_new:Nn \@@_object_visvar:n{
- c __ #1 _ VISIB _ str
-}
-
-\cs_generate_variant:Nn \@@_object_modvar:n { V }
-\cs_generate_variant:Nn \@@_object_pxyvar:n { V }
-\cs_generate_variant:Nn \@@_object_scovar:n { V }
-\cs_generate_variant:Nn \@@_object_visvar:n { V }
-% \end{macrocode}
-%
%\begin{macro}[pTF]{\object_if_exist:n}
%Tests if object exists.
% \begin{macrocode}
@@ -876,7 +1053,11 @@
{
\cs_if_exist:cTF
{
- \@@_object_modvar:n { #1 }
+ \object_ncmember_adr:nnn
+ {
+ \object_embedded_adr:nn{ #1 }{ /_I_/ }
+ }
+ { S }{ str }
}
{
\prg_return_true:
@@ -896,10 +1077,18 @@
%Retrieve the name, module and generating proxy of an object
% \begin{macrocode}
\cs_new:Nn \object_get_module:n {
- \str_use:c { \@@_object_modvar:n { #1 } }
+ \object_ncmember_use:nnn
+ {
+ \object_embedded_adr:nn{ #1 }{ /_I_/ }
+ }
+ { M }{ str }
}
\cs_new:Nn \object_get_proxy_adr:n {
- \str_use:c { \@@_object_pxyvar:n { #1 } }
+ \object_ncmember_use:nnn
+ {
+ \object_embedded_adr:nn{ #1 }{ /_I_/ }
+ }
+ { P }{ str }
}
\cs_generate_variant:Nn \object_get_module:n { V }
@@ -912,7 +1101,14 @@
% \begin{macrocode}
\prg_new_conditional:Nnn \object_if_local:n {p, T, F, TF}
{
- \str_if_eq:cNTF { \@@_object_scovar:n {#1} }
+ \str_if_eq:cNTF
+ {
+ \object_ncmember_adr:nnn
+ {
+ \object_embedded_adr:nn{ #1 }{ /_I_/ }
+ }
+ { S }{ str }
+ }
\c_object_local_str
{
\prg_return_true:
@@ -924,7 +1120,14 @@
\prg_new_conditional:Nnn \object_if_global:n {p, T, F, TF}
{
- \str_if_eq:cNTF { \@@_object_scovar:n {#1} }
+ \str_if_eq:cNTF
+ {
+ \object_ncmember_adr:nnn
+ {
+ \object_embedded_adr:nn{ #1 }{ /_I_/ }
+ }
+ { S }{ str }
+ }
\c_object_global_str
{
\prg_return_true:
@@ -936,7 +1139,14 @@
\prg_new_conditional:Nnn \object_if_public:n {p, T, F, TF}
{
- \str_if_eq:cNTF { \@@_object_visvar:n { #1 } }
+ \str_if_eq:cNTF
+ {
+ \object_ncmember_adr:nnn
+ {
+ \object_embedded_adr:nn{ #1 }{ /_I_/ }
+ }
+ { V }{ str }
+ }
\c_object_public_str
{
\prg_return_true:
@@ -948,7 +1158,14 @@
\prg_new_conditional:Nnn \object_if_private:n {p, T, F, TF}
{
- \str_if_eq:cNTF { \@@_object_visvar:n {#1} }
+ \str_if_eq:cNTF
+ {
+ \object_ncmember_adr:nnn
+ {
+ \object_embedded_adr:nn{ #1 }{ /_I_/ }
+ }
+ { V }{ str }
+ }
\c_object_private_str
{
\prg_return_true:
@@ -993,68 +1210,163 @@
% \end{macrocode}
% \end{macro}
%
-%\begin{macro}{\object_member_adr:nnn, \object_member_adr:nn}
+%\begin{macro}{\@@_member_adr:nnnNN}
+% Macro address without object inference
+% \begin{macrocode}
+
+\cs_new:Nn \@@_member_adr:nnnNN
+ {
+ \@@_scope:N #4
+ \@@_vis_var:N #5
+ #1 \tl_to_str:n { _ MEMBER _ #2 _ #3 }
+ }
+
+\cs_generate_variant:Nn \@@_member_adr:nnnNN { VnnNN, nnncc }
+
+% \end{macrocode}
+% \end{macro}
+%
+%\begin{macro}{\object_member_adr:nnn}
%Get the address of a member variable
% \begin{macrocode}
-\cs_new:Nn \@@_scope:n
+\cs_new:Nn \object_member_adr:nnn
{
- \object_if_local:nTF { #1 }
+ \@@_member_adr:nnncc { #1 }{ #2 }{ #3 }
{
- l
- }
- {
- \str_if_eq:cNTF { \@@_object_scovar:n { #1 } }
- \c_@@_const_str
+ \object_ncmember_adr:nnn
{
- c
+ \object_embedded_adr:nn{ #1 }{ /_I_/ }
}
+ { S }{ str }
+ }
+ {
+ \object_ncmember_adr:nnn
{
- g
+ \object_embedded_adr:nn{ #1 }{ /_I_/ }
}
+ { V }{ str }
}
}
-\cs_new:Nn \@@_scope_pfx:n
- {
- \object_if_local:nF { #1 }
- { g }
- }
+\cs_generate_variant:Nn \object_member_adr:nnn { Vnn, vnn, nnv, nnf }
+
+% \end{macrocode}
+%\end{macro}
+%
+% \begin{macro}[pTF]{\object_member_if_exist:nnn}
+% Tests if the specified member exists
+% \begin{macrocode}
-\cs_new:Nn \@@_vis_var:n
+\prg_new_conditional:Nnn \object_member_if_exist:nnn {p, T, F, TF }
{
- \object_if_private:nTF { #1 }
+ \cs_if_exist:cTF
{
- __
+ \object_member_adr:nnn { #1 }{ #2 }{ #3 }
}
{
- _
+ \prg_return_true:
+ }
+ {
+ \prg_return_false:
}
}
-\cs_new:Nn \@@_vis_fun:n
+\prg_generate_conditional_variant:Nnn \object_member_if_exist:nnn
+ { Vnn }{ p, T, F, TF }
+
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[pTF]{\object_member_if_tracked:nn}
+% Tests if the member is tracked.
+% \begin{macrocode}
+
+\prg_new_conditional:Nnn \object_member_if_tracked:nn {p, T, F, TF }
{
- \object_if_private:nT { #1 }
+ \cs_if_exist:cTF
{
- __
+ \object_rcmember_adr:nnn
+ { #1 }{ #2 _ type }{ str }
+ }
+ {
+ \prg_return_true:
+ }
+ {
+ \cs_if_exist:cTF
+ {
+ \object_ncmember_adr:nnn
+ {
+ \object_embedded_adr:nn { #1 }{ /_T_/ }
+ }
+ { #2 _ type }{ str }
+ }
+ {
+ \prg_return_true:
+ }
+ {
+ \prg_return_false:
+ }
}
}
-\cs_new:Nn \object_member_adr:nnn
+\prg_generate_conditional_variant:Nnn \object_member_if_tracked:nn
+ { Vn }{ p, T, F, TF }
+
+\prg_new_eq_conditional:NNn \object_member_if_exist:nn
+ \object_member_if_tracked:nn { p, T, F, TF }
+\prg_new_eq_conditional:NNn \object_member_if_exist:Vn
+ \object_member_if_tracked:Vn { p, T, F, TF }
+
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\object_member_type:nn}
+% Deduce the type of tracked members.
+% \begin{macrocode}
+
+\cs_new:Nn \object_member_type:nn
{
- \@@_scope:n { #1 }
- \@@_vis_var:n { #1 }
- #1 \tl_to_str:n { _ MEMBER _ #2 _ #3 }
+ \cs_if_exist:cTF
+ {
+ \object_rcmember_adr:nnn
+ { #1 }{ #2 _ type }{ str }
+ }
+ {
+ \object_rcmember_use:nnn
+ { #1 }{ #2 _ type }{ str }
+ }
+ {
+ \cs_if_exist:cT
+ {
+ \object_ncmember_adr:nnn
+ {
+ \object_embedded_adr:nn { #1 }{ /_T_/ }
+ }
+ { #2 _ type }{ str }
+ }
+ {
+ \object_ncmember_use:nnn
+ {
+ \object_embedded_adr:nn { #1 }{ /_T_/ }
+ }
+ { #2 _ type }{ str }
+ }
+ }
}
-\cs_generate_variant:Nn \object_member_adr:nnn { Vnn, vnn, nnv }
+% \end{macrocode}
+% \end{macro}
+%
+%\begin{macro}{\object_member_adr:nn}
+%Get the address of a member variable
+% \begin{macrocode}
\cs_new:Nn \object_member_adr:nn
{
- \object_member_adr:nnv { #1 }{ #2 }
+ \object_member_adr:nnf { #1 }{ #2 }
{
- \object_rcmember_adr:nnn { #1 }
- { #2 _ type }{ str }
+ \object_member_type:nn { #1 }{ #2 }
}
}
@@ -1063,203 +1375,560 @@
% \end{macrocode}
%\end{macro}
%
-%\begin{macro}{\object_member_type:nn}
-%Deduce the member type from the generating proxy.
+% Helper functions for \cs{object_*_generate} functions.
% \begin{macrocode}
-\cs_new:Nn \object_member_type:nn
+\cs_new:Nn \@@_par_trans:N
{
- \object_rcmember_use:nnn { #1 }
- { #2 _ type }{ str }
+ \str_case:nnF { #1 }
+ {
+ { N }{ N }
+ { V }{ N }
+ { n }{ n }
+ { v }{ n }
+ { f }{ n }
+ { x }{ n }
+ { e }{ n }
+ { o }{ n }
+ { ~ }{}
+ }
+ { #1 }
}
-% \end{macrocode}
-%\end{macro}
-%
-% \begin{macrocode}
+\cs_new:Nn \@@_par_trans:n
+ {
+ \str_map_function:nN { #1 } \@@_par_trans:N
+ }
+
+\str_new:N \l_@@_tmp_fa_str
-\msg_new:nnnn { rawobjects }{ scoperr }{ Nonstandard ~ scope }
+\cs_new_protected:Nn \@@_save_dat:n
{
- Operation ~ not ~ permitted ~ on ~ object ~ #1 ~
- ~ since ~ it ~ wasn't ~ declared ~ local ~ or ~ global
+ \str_set:Nx \l_@@_tmp_fa_str
+ { \str_tail:n{ #1 } }
}
+\cs_new_protected:Nn \@@_save_dat:nnN
+ {
+ \str_set:Nx \l_@@_tmp_fa_str
+ { \str_tail:n{ #2 } }
+ }
+\cs_new_protected:Nn \@@_save_dat_aux:n
+ {
+ \@@_save_dat:nnN #1
+ }
+\cs_generate_variant:Nn \@@_save_dat_aux:n { f }
-\cs_new_protected:Nn \@@_force_scope:n
+\cs_new_protected:Nn \@@_save_fun:N
{
- \bool_if:nF
- {
- \object_if_local_p:n { #1 } || \object_if_global_p:n { #1 }
- }
- {
- \msg_error:nnx { rawobjects }{ scoperr }{ #1 }
- }
+ \@@_save_dat_aux:f { \cs_split_function:N #1 }
+ }
+
+\cs_new:Nn \@@_use_dat:nn
+ {
+ #1 : #2 \str_use:N \l_@@_tmp_fa_str
}
% \end{macrocode}
%
-% \begin{macro}[pTF]{\object_member_if_exist:nnn, \object_member_if_exist:nn}
-% Tests if the specified member exists
+% \begin{macro}{\object_member_generate:NN, \object_member_generate_inline:Nnn, \object_member_generate_protected:NN, \object_member_generate_protected_inline:Nnn}
+% Generate member versions of specified functions.
% \begin{macrocode}
-\prg_new_conditional:Nnn \object_member_if_exist:nnn {p, T, F, TF }
+\cs_new_protected:Nn \@@_mgen:nN
{
- \cs_if_exist:cTF
+ \@@_save_fun:N #2
+ \cs_new:cpn { #1 : nnn \str_use:N \l_@@_tmp_fa_str } ##1##2##3
{
- \object_member_adr:nnn { #1 }{ #2 }{ #3 }
+ #2
+ {
+ \object_member_adr:nnn{ ##1 }{ ##2 }{ ##3 }
+ }
}
+ \cs_new:cpn { #1 : nn \str_use:N \l_@@_tmp_fa_str } ##1##2
{
- \prg_return_true:
+ #2
+ {
+ \object_member_adr:nn{ ##1 }{ ##2 }
+ }
+ }
+ }
+\cs_new_protected:Nn \@@_mgen_pr:nN
+ {
+ \@@_save_fun:N #2
+ \cs_new_protected:cpn
+ { #1 : nnn \str_use:N \l_@@_tmp_fa_str } ##1##2##3
+ {
+ #2
+ {
+ \object_member_adr:nnn{ ##1 }{ ##2 }{ ##3 }
+ }
}
+ \cs_new_protected:cpn
+ { #1 : nn \str_use:N \l_@@_tmp_fa_str } ##1##2
{
- \prg_return_false:
+ #2
+ {
+ \object_member_adr:nn{ ##1 }{ ##2 }
+ }
}
}
-\prg_new_conditional:Nnn \object_member_if_exist:nn {p, T, F, TF }
+\cs_new_protected:Nn \@@_mgen:nnn
{
- \cs_if_exist:cTF
+ \@@_save_dat:n { #3 }
+
+ \cs_new:cpn { @@_auxfun_#1 :nn } ##1##2
{
- \object_member_adr:nn { #1 }{ #2 }
+ \use:c{ #2 : #3 }
}
+ \cs_generate_variant:cn { @@_auxfun_#1 :nn }{ nf, ff }
+
+ \cs_new:cpn { #1 : nnn \str_use:N \l_@@_tmp_fa_str } ##1##2##3
{
- \prg_return_true:
+ \use:c { @@_auxfun_#1 :nf }
+ { ##3 }
+ {
+ \@@_scope_pfx_cl:n{ ##1 }
+ }
+ {
+ \object_member_adr:nnn{ ##1 }{ ##2 }{ ##3 }
+ }
}
+ \cs_new:cpn { #1 : nn \str_use:N \l_@@_tmp_fa_str } ##1##2
{
- \prg_return_false:
+ \use:c { @@_auxfun_#1 :ff }
+ {
+ \object_member_type:nn { ##1 }{ ##2 }
+ }
+ {
+ \@@_scope_pfx_cl:n{ ##1 }
+ }
+ {
+ \object_member_adr:nn{ ##1 }{ ##2 }
+ }
}
}
+\cs_new_protected:Nn \@@_mgen_pr:nnn
+ {
+ \@@_save_dat:n { #3 }
-\prg_generate_conditional_variant:Nnn \object_member_if_exist:nnn
- { Vnn }{ p, T, F, TF }
-\prg_generate_conditional_variant:Nnn \object_member_if_exist:nn
- { Vn }{ p, T, F, TF }
+ \cs_new:cpn { @@_auxfun_#1 :nn } ##1##2
+ {
+ \use:c{ #2 : #3 }
+ }
+ \cs_generate_variant:cn { @@_auxfun_#1 :nn }{ nf, ff }
-% \end{macrocode}
-% \end{macro}
+ \cs_new_protected:cpn
+ { #1 : nnn \str_use:N \l_@@_tmp_fa_str } ##1##2##3
+ {
+ \use:c { @@_auxfun_#1 :nf }
+ { ##3 }
+ {
+ \@@_scope_pfx_cl:n{ ##1 }
+ }
+ {
+ \object_member_adr:nnn{ ##1 }{ ##2 }{ ##3 }
+ }
+ }
+ \cs_new_protected:cpn
+ { #1 : nn \str_use:N \l_@@_tmp_fa_str } ##1##2
+ {
+ \use:c { @@_auxfun_#1 :ff }
+ {
+ \object_member_type:nn { ##1 }{ ##2 }
+ }
+ {
+ \@@_scope_pfx_cl:n{ ##1 }
+ }
+ {
+ \object_member_adr:nn{ ##1 }{ ##2 }
+ }
+ }
+ }
-%\begin{macro}{\object_new_member:nnn}
-%Creates a new member variable
-% \begin{macrocode}
+\cs_generate_variant:Nn \@@_mgen:nN { fN }
+\cs_generate_variant:Nn \@@_mgen:nnn { fnn }
+\cs_generate_variant:Nn \@@_mgen_pr:nN { fN }
+\cs_generate_variant:Nn \@@_mgen_pr:nnn { fnn }
-\cs_new_protected:Nn \object_new_member:nnn
+\cs_new_protected:Nn \object_member_generate:NN
{
- \@@_force_scope:n { #1 }
- \cs_if_exist_use:cT { #3 _ new:c }
- {
- { \object_member_adr:nnn { #1 }{ #2 }{ #3 } }
- }
+ \@@_mgen:fN { \cs_to_str:N #1 } #2
+ }
+
+\cs_new_protected:Nn \object_member_generate_inline:Nnn
+ {
+ \@@_mgen:fnn { \cs_to_str:N #1 }{ #2 }{ #3 }
+ }
+\cs_new_protected:Nn \object_member_generate_protected:NN
+ {
+ \@@_mgen_pr:fN { \cs_to_str:N #1 } #2
}
-\cs_generate_variant:Nn \object_new_member:nnn { Vnn, nnv }
+\cs_new_protected:Nn \object_member_generate_protected_inline:Nnn
+ {
+ \@@_mgen_pr:fnn { \cs_to_str:N #1 }{ #2 }{ #3 }
+ }
% \end{macrocode}
-%\end{macro}
+% \end{macro}
%
-%\begin{macro}{\object_member_use:nnn, \object_member_use:nn}
-%Uses a member variable
+% \begin{macro}{\object_ncmember_generate:NN, \object_ncmember_generate_inline:Nnn, \object_ncmember_generate_protected:NN, \object_ncmember_generate_protected_inline:Nnn}
+% Generate ncmember versions of specified functions.
% \begin{macrocode}
-\cs_new:Nn \object_member_use:nnn
+\cs_new_protected:Nn \@@_ncgen:nN
+ {
+ \@@_save_fun:N #2
+ \cs_new:cpn { #1 : nnn \str_use:N \l_@@_tmp_fa_str } ##1##2##3
+ {
+ #2
+ {
+ \object_ncmember_adr:nnn{ ##1 }{ ##2 }{ ##3 }
+ }
+ }
+ }
+\cs_new_protected:Nn \@@_ncgen_pr:nN
{
- \cs_if_exist_use:cT { #3 _ use:c }
+ \@@_save_fun:N #2
+ \cs_new_protected:cpn
+ { #1 : nnn \str_use:N \l_@@_tmp_fa_str } ##1##2##3
{
- { \object_member_adr:nnn { #1 }{ #2 }{ #3 } }
+ #2
+ {
+ \object_ncmember_adr:nnn{ ##1 }{ ##2 }{ ##3 }
+ }
}
}
-\cs_new:Nn \object_member_use:nn
+\cs_new_protected:Nn \@@_ncgen:nnn
{
- \object_member_use:nnv { #1 }{ #2 }
+ \@@_save_dat:n { #3 }
+
+ \cs_new:cpn { @@_auxfun_#1 :nn } ##1##2
{
- \object_rcmember_adr:nnn { #1 }
- { #2 _ type }{ str }
+ \use:c{ #2 : #3 }
+ }
+ \cs_generate_variant:cn { @@_auxfun_#1 :nn }{ nf }
+
+ \cs_new:cpn { #1 : nnn \str_use:N \l_@@_tmp_fa_str } ##1##2##3
+ {
+ \use:c { @@_auxfun_#1 :nf }
+ { ##3 }
+ {
+ \@@_scope_pfx_cl:n{ ##1 }
+ }
+ {
+ \object_ncmember_adr:nnn{ ##1 }{ ##2 }{ ##3 }
+ }
+ }
+ }
+\cs_new_protected:Nn \@@_ncgen_pr:nnn
+ {
+ \@@_save_dat:n { #3 }
+
+ \cs_new:cpn { @@_auxfun_#1 :nn } ##1##2
+ {
+ \use:c{ #2 : #3 }
}
+ \cs_generate_variant:cn { @@_auxfun_#1 :nn }{ nf }
+
+ \cs_new_protected:cpn
+ { #1 : nnn \str_use:N \l_@@_tmp_fa_str } ##1##2##3
+ {
+ \use:c { @@_auxfun_#1 :nf }
+ { ##3 }
+ {
+ \@@_scope_pfx_cl:n{ ##1 }
+ }
+ {
+ \object_ncmember_adr:nnn{ ##1 }{ ##2 }{ ##3 }
+ }
+ }
+ }
+
+\cs_generate_variant:Nn \@@_ncgen:nN { fN }
+\cs_generate_variant:Nn \@@_ncgen:nnn { fnn }
+\cs_generate_variant:Nn \@@_ncgen_pr:nN { fN }
+\cs_generate_variant:Nn \@@_ncgen_pr:nnn { fnn }
+
+\cs_new_protected:Nn \object_ncmember_generate:NN
+ {
+ \@@_ncgen:fN { \cs_to_str:N #1 } #2
}
-\cs_generate_variant:Nn \object_member_use:nnn { Vnn, vnn, nnv }
-\cs_generate_variant:Nn \object_member_use:nn { Vn }
+\cs_new_protected:Nn \object_ncmember_generate_inline:Nnn
+ {
+ \@@_ncgen:fnn { \cs_to_str:N #1 }{ #2 }{ #3 }
+ }
+\cs_new_protected:Nn \object_ncmember_generate_protected:NN
+ {
+ \@@_ncgen_pr:fN { \cs_to_str:N #1 } #2
+ }
+
+\cs_new_protected:Nn \object_ncmember_generate_protected_inline:Nnn
+ {
+ \@@_ncgen_pr:fnn { \cs_to_str:N #1 }{ #2 }{ #3 }
+ }
% \end{macrocode}
-%\end{macro}
+% \end{macro}
%
-%\begin{macro}{\object_member_set:nnnn, \object_member_set_eq:nnn}
-% Set the value a member.
+% \begin{macro}{\object_rcmember_generate:NN, \object_rcmember_generate_inline:Nnn, \object_rcmember_generate_protected:NN, \object_rcmember_generate_protected_inline:Nnn}
+% Generate ncmember versions of specified functions.
% \begin{macrocode}
-\cs_new_protected:Nn \object_member_set:nnnn
+\cs_new_protected:Nn \@@_rcgen:nN
{
- \@@_force_scope:n { #1 }
- \cs_if_exist_use:cT
+ \@@_save_fun:N #2
+ \cs_new:cpn { #1 : nnn \str_use:N \l_@@_tmp_fa_str } ##1##2##3
{
- #3 _ \@@_scope_pfx:n { #1 } set:cn
+ #2
+ {
+ \object_rcmember_adr:nnn{ ##1 }{ ##2 }{ ##3 }
+ }
}
+ }
+\cs_new_protected:Nn \@@_rcgen_pr:nN
+ {
+ \@@_save_fun:N #2
+ \cs_new_protected:cpn
+ { #1 : nnn \str_use:N \l_@@_tmp_fa_str } ##1##2##3
{
- { \object_member_adr:nnn { #1 }{ #2 }{ #3 } } { #4 }
+ #2
+ {
+ \object_rcmember_adr:nnn{ ##1 }{ ##2 }{ ##3 }
+ }
}
}
-\cs_generate_variant:Nn \object_member_set:nnnn { Vnnn, nnvn }
+\cs_new_protected:Nn \@@_rcgen:nnn
+ {
+ \@@_save_dat:n { #3 }
-\cs_new_protected:Nn \object_member_set:nnn
+ \cs_new:cpn { @@_auxfun_#1 :nn } ##1##2
+ {
+ \use:c{ #2 : #3 }
+ }
+ \cs_generate_variant:cn { @@_auxfun_#1 :nn }{ nf }
+
+ \cs_new:cpn { #1 : nnn \str_use:N \l_@@_tmp_fa_str } ##1##2##3
+ {
+ \use:c { @@_auxfun_#1 :nf }
+ { ##3 }
+ {
+ \@@_scope_pfx_cl:n{ ##1 }
+ }
+ {
+ \object_rcmember_adr:nnn{ ##1 }{ ##2 }{ ##3 }
+ }
+ }
+ }
+\cs_new_protected:Nn \@@_rcgen_pr:nnn
{
- \object_member_set:nnvn { #1 }{ #2 }
+ \@@_save_dat:n { #3 }
+
+ \cs_new:cpn { @@_auxfun_#1 :nn } ##1##2
{
- \object_rcmember_adr:nnn { #1 }
- { #2 _ type }{ str }
- } { #3 }
+ \use:c{ #2 : #3 }
+ }
+ \cs_generate_variant:cn { @@_auxfun_#1 :nn }{ nf }
+
+ \cs_new_protected:cpn
+ { #1 : nnn \str_use:N \l_@@_tmp_fa_str } ##1##2##3
+ {
+ \use:c { @@_auxfun_#1 :nf }
+ { ##3 }
+ {
+ \@@_scope_pfx_cl:n{ ##1 }
+ }
+ {
+ \object_rcmember_adr:nnn{ ##1 }{ ##2 }{ ##3 }
+ }
+ }
}
-\cs_generate_variant:Nn \object_member_set:nnn { Vnn }
+\cs_generate_variant:Nn \@@_rcgen:nN { fN }
+\cs_generate_variant:Nn \@@_rcgen:nnn { fnn }
+\cs_generate_variant:Nn \@@_rcgen_pr:nN { fN }
+\cs_generate_variant:Nn \@@_rcgen_pr:nnn { fnn }
+
+\cs_new_protected:Nn \object_rcmember_generate:NN
+ {
+ \@@_rcgen:fN { \cs_to_str:N #1 } #2
+ }
+
+\cs_new_protected:Nn \object_rcmember_generate_inline:Nnn
+ {
+ \@@_rcgen:fnn { \cs_to_str:N #1 }{ #2 }{ #3 }
+ }
+\cs_new_protected:Nn \object_rcmember_generate_protected:NN
+ {
+ \@@_rcgen_pr:fN { \cs_to_str:N #1 } #2
+ }
+
+\cs_new_protected:Nn \object_rcmember_generate_protected_inline:Nnn
+ {
+ \@@_rcgen_pr:fnn { \cs_to_str:N #1 }{ #2 }{ #3 }
+ }
% \end{macrocode}
-%\end{macro}
+% \end{macro}
%
-%\begin{macro}{\object_member_set_eq:nnnN, \object_member_set_eq:nnN}
-% Make a member equal to another variable.
+% Auxilary functions
% \begin{macrocode}
-\cs_new_protected:Nn \object_member_set_eq:nnnN
+\cs_generate_variant:Nn \cs_generate_variant:Nn { cx }
+
+\cs_new_protected:Nn \@@_genmem_int:nnn
{
- \@@_force_scope:n { #1 }
- \cs_if_exist_use:cT
- {
- #3 _ \@@_scope_pfx:n { #1 } set _ eq:cN
- }
- {
- { \object_member_adr:nnn { #1 }{ #2 }{ #3 } } #4
- }
+ \@@_mgen:nnn { #1 }{ #2 }{ #3 }
+ \cs_generate_variant:cx
+ { #1 : nnn \str_use:N \l_@@_tmp_fa_str }
+ { Vnn \str_use:N \l_@@_tmp_fa_str, nnv \str_use:N \l_@@_tmp_fa_str }
+ \cs_generate_variant:cx
+ { #1 : nn \str_use:N \l_@@_tmp_fa_str }
+ { Vn \str_use:N \l_@@_tmp_fa_str }
+ }
+\cs_new_protected:Nn \@@_genmem_pr_int:nnn
+ {
+ \@@_mgen_pr:nnn { #1 }{ #2 }{ #3 }
+ \cs_generate_variant:cx
+ { #1 : nnn \str_use:N \l_@@_tmp_fa_str }
+ { Vnn \str_use:N \l_@@_tmp_fa_str, nnv \str_use:N \l_@@_tmp_fa_str }
+ \cs_generate_variant:cx
+ { #1 : nn \str_use:N \l_@@_tmp_fa_str }
+ { Vn \str_use:N \l_@@_tmp_fa_str }
+ }
+
+\cs_new_protected:Nn \@@_genncm_int:nnn
+ {
+ \@@_ncgen:nnn { #1 }{ #2 }{ #3 }
+ \cs_generate_variant:cx
+ { #1 : nnn \str_use:N \l_@@_tmp_fa_str }
+ { Vnn \str_use:N \l_@@_tmp_fa_str }
+ }
+\cs_new_protected:Nn \@@_genncm_pr_int:nnn
+ {
+ \@@_ncgen_pr:nnn { #1 }{ #2 }{ #3 }
+ \cs_generate_variant:cx
+ { #1 : nnn \str_use:N \l_@@_tmp_fa_str }
+ { Vnn \str_use:N \l_@@_tmp_fa_str }
}
-\cs_generate_variant:Nn \object_member_set_eq:nnnN { VnnN, nnnc, Vnnc, nnvN }
+\cs_new_protected:Nn \@@_genrcm_int:nnn
+ {
+ \@@_rcgen:nnn { #1 }{ #2 }{ #3 }
+ \cs_generate_variant:cx
+ { #1 : nnn \str_use:N \l_@@_tmp_fa_str }
+ { Vnn \str_use:N \l_@@_tmp_fa_str }
+ }
+\cs_new_protected:Nn \@@_genrcm_pr_int:nnn
+ {
+ \@@_rcgen_pr:nnn { #1 }{ #2 }{ #3 }
+ \cs_generate_variant:cx
+ { #1 : nnn \str_use:N \l_@@_tmp_fa_str }
+ { Vnn \str_use:N \l_@@_tmp_fa_str }
+ }
-\cs_new_protected:Nn \object_member_set_eq:nnN
+% \end{macrocode}
+%
+% \begin{macrocode}
+
+\msg_new:nnnn { rawobjects }{ noerr }{ Unspecified ~ scope }
{
- \object_member_set_eq:nnvN { #1 }{ #2 }
+ Object ~ #1 ~ hasn't ~ a ~ scope ~ variable
+ }
+
+% \end{macrocode}
+%
+%\begin{macro}{\object_new_member:nnn, \object_new_member_tracked:nnn}
+%Creates a new member variable
+% \begin{macrocode}
+
+\@@_genmem_pr_int:nnn { object_new_member }{ #1 _ new }{ c }
+
+\cs_new_protected:Nn \object_new_member_tracked:nnn
+ {
+ \object_new_member:nnn { #1 }{ #2 }{ #3 }
+
+ \str_const:cn
{
- \object_rcmember_adr:nnn { #1 }
+ \object_ncmember_adr:nnn
+ {
+ \object_embedded_adr:nn { #1 }{ /_T_/ }
+ }
{ #2 _ type }{ str }
- } #3
+ }
+ { #3 }
}
-\cs_generate_variant:Nn \object_member_set_eq:nnN { VnN, nnc, Vnc }
+\cs_generate_variant:Nn \object_new_member_tracked:nnn { Vnn, nnv }
+
+% \end{macrocode}
+%\end{macro}
+%
+%\begin{macro}{\object_member_use:nnn, \object_member_use:nn}
+%Uses a member variable
+% \begin{macrocode}
+
+\@@_genmem_int:nnn {object_member_use}{ #1_use }{c}
+
+\cs_generate_variant:Nn \object_member_use:nnn {vnn}
+
+% \end{macrocode}
+%\end{macro}
+%
+%\begin{macro}{\object_member_set:nnnn, \object_member_set:nnn}
+% Set the value a member.
+% \begin{macrocode}
+
+\@@_genmem_pr_int:nnn {object_member_set}{ #1_#2 set }{ cn }
+
+% \end{macrocode}
+%\end{macro}
+%
+%\begin{macro}{\object_member_set_eq:nnnN, \object_member_set_eq:nnN}
+% Make a member equal to another variable.
+% \begin{macrocode}
+
+\@@_genmem_pr_int:nnn { object_member_set_eq }{ #1 _ #2 set_eq }{ cN }
+
+\cs_generate_variant:Nn \object_member_set_eq:nnnN { nnnc, Vnnc }
+
+\cs_generate_variant:Nn \object_member_set_eq:nnN { nnc, Vnc }
% \end{macrocode}
%\end{macro}
%
-%\begin{macro}{\object_ncmember_adr:nnn, \object_rcmember_adr:nnn}
-% Get the address of a near/remote constant.
+% \begin{macro}{\object_ncmember_adr:nnn}
+% Get address of near constant
% \begin{macrocode}
\cs_new:Nn \object_ncmember_adr:nnn
{
- c _ #1 \tl_to_str:n { _ CONST _ #2 _ #3 }
+ \tl_to_str:n{ c _ } #1 \tl_to_str:n { _ CONST _ #2 _ #3 }
}
\cs_generate_variant:Nn \object_ncmember_adr:nnn { Vnn, vnn }
+% \end{macrocode}
+% \end{macro}
+%
+%\begin{macro}{\object_rcmember_adr:nnn}
+% Get the address of a remote constant.
+% \begin{macrocode}
+
\cs_new:Nn \object_rcmember_adr:nnn
{
- \object_ncmember_adr:vnn { \@@_object_pxyvar:n { #1 } }
+ \object_ncmember_adr:vnn
+ {
+ \object_ncmember_adr:nnn
+ {
+ \object_embedded_adr:nn{ #1 }{ /_I_/ }
+ }
+ { P }{ str }
+ }
{ #2 }{ #3 }
}
@@ -1311,24 +1980,9 @@
% Uses a near/remote constant.
% \begin{macrocode}
-\cs_new:Nn \object_ncmember_use:nnn
- {
- \cs_if_exist_use:cT { #3 _ use:c }
- {
- { \object_ncmember_adr:nnn { #1 }{ #2 }{ #3 } }
- }
- }
+\@@_genncm_int:nnn { object_ncmember_use }{ #1_use}{ c }
-\cs_new:Nn \object_rcmember_use:nnn
- {
- \cs_if_exist_use:cT { #3 _ use:c }
- {
- { \object_rcmember_adr:nnn { #1 }{ #2 }{ #3 } }
- }
- }
-
-\cs_generate_variant:Nn \object_ncmember_use:nnn { Vnn }
-\cs_generate_variant:Nn \object_rcmember_use:nnn { Vnn }
+\@@_genrcm_int:nnn { object_rcmember_use }{ #1_use}{ c }
% \end{macrocode}
%\end{macro}
@@ -1337,14 +1991,7 @@
% Creates a constant variable, use with caution
% \begin{macrocode}
-\cs_new_protected:Nn \object_newconst:nnnn
- {
- \use:c { #3 _ const:cn }
- {
- \object_ncmember_adr:nnn { #1 }{ #2 }{ #3 }
- }
- { #4 }
- }
+\@@_genncm_pr_int:nnn { object_newconst }{ #1 _ const }{ cn }
% \end{macrocode}
% \end{macro}
@@ -1390,6 +2037,10 @@
\cs_generate_variant:Nn \object_newconst_skip:nnn { Vnn }
\cs_generate_variant:Nn \object_newconst_fp:nnn { Vnn }
+
+\cs_generate_variant:Nn \object_newconst_str:nnn { nnx }
+\cs_generate_variant:Nn \object_newconst_str:nnn { nnV }
+
% \end{macrocode}
%\end{macro}
%
@@ -1445,7 +2096,11 @@
{
\object_ncmethod_adr:vnn
{
- \@@_object_pxyvar:n { #1 }
+ \object_ncmember_adr:nnn
+ {
+ \object_embedded_adr:nn{ #1 }{ /_I_/ }
+ }
+ { P }{ str }
}
{ #2 }{ #3 }
}
@@ -1540,56 +2195,57 @@
% \end{macrocode}
% \end{macro}
%
-%
-%
-%\begin{variable}{\c_proxy_address_str}
-%The address of the \verb|proxy| object.
% \begin{macrocode}
-\str_const:Nx \c_proxy_address_str
- { \object_address:nn { rawobjects }{ proxy } }
-% \end{macrocode}
-%\end{variable}
-%
-%
-% Source of \verb|proxy| object
-% \begin{macrocode}
-
-\str_const:cn { \@@_object_modvar:V \c_proxy_address_str }
- { rawobjects }
-\str_const:cV { \@@_object_pxyvar:V \c_proxy_address_str }
- \c_proxy_address_str
-\str_const:cV { \@@_object_scovar:V \c_proxy_address_str }
- \c_@@_const_str
-\str_const:cV { \@@_object_visvar:V \c_proxy_address_str }
- \c_object_public_str
-
-\seq_const_from_clist:cn
- {
- \object_member_adr:Vnn \c_proxy_address_str { varlist }{ seq }
- }
- { varlist, objlist }
-
-\object_newconst_str:Vnn \c_proxy_address_str { varlist_type }{ seq }
-\object_newconst_str:Vnn \c_proxy_address_str { objlist_type }{ seq }
-\seq_const_from_clist:cn
+\cs_new_protected:Nn \@@_initproxy:nnn
{
- \object_member_adr:Vnn \c_proxy_address_str { objlist }{ seq }
+ \object_newconst:nnnn
+ {
+ \object_embedded_adr:nn{ #3 }{ /_I_/ }
+ }
+ { ifprox }{ bool }{ \c_true_bool }
}
- {}
+\cs_generate_variant:Nn \@@_initproxy:nnn { VnV }
% \end{macrocode}
%
+%
%\begin{macro}[pTF]{\object_if_proxy:n}
%Test if an object is a proxy.
% \begin{macrocode}
+\cs_new:Nn \@@_bol_com:N
+ {
+ \cs_if_exist_p:N #1 && \bool_if_p:N #1
+ }
+
+\cs_generate_variant:Nn \@@_bol_com:N { c }
+
\prg_new_conditional:Nnn \object_if_proxy:n {p, T, F, TF}
{
- \object_test_proxy:nNTF { #1 }
- \c_proxy_address_str
+ \cs_if_exist:cTF
{
- \prg_return_true:
+ \object_ncmember_adr:nnn
+ {
+ \object_embedded_adr:nn{ #1 }{ /_I_/ }
+ }
+ { ifprox }{ bool }
+ }
+ {
+ \bool_if:cTF
+ {
+ \object_ncmember_adr:nnn
+ {
+ \object_embedded_adr:nn{ #1 }{ /_I_/ }
+ }
+ { ifprox }{ bool }
+ }
+ {
+ \prg_return_true:
+ }
+ {
+ \prg_return_false:
+ }
}
{
\prg_return_false:
@@ -1607,7 +2263,14 @@
\prg_new_conditional:Nnn \object_test_proxy:nn {p, T, F, TF}
{
- \str_if_eq:veTF { \@@_object_pxyvar:n { #1 } }
+ \str_if_eq:veTF
+ {
+ \object_ncmember_adr:nnn
+ {
+ \object_embedded_adr:nn{ #1 }{ /_I_/ }
+ }
+ { P }{ str }
+ }
{ #2 }
{
\prg_return_true:
@@ -1619,7 +2282,14 @@
\prg_new_conditional:Nnn \object_test_proxy:nN {p, T, F, TF}
{
- \str_if_eq:cNTF { \@@_object_pxyvar:n { #1 } }
+ \str_if_eq:cNTF
+ {
+ \object_ncmember_adr:nnn
+ {
+ \object_embedded_adr:nn{ #1 }{ /_I_/ }
+ }
+ { P }{ str }
+ }
#2
{
\prg_return_true:
@@ -1637,12 +2307,10 @@
% \end{macrocode}
%\end{macro}
%
-% \begin{macro}{\object_create:nnnNN, \object_create_set:NnnnNN, \object_create_gset:NnnnNN, \embedded_create:nnn}
-% Creates an object from a proxy
+% \begin{macro}{\object_create:nnnNN, \object_create_set:NnnnNN, \object_create_gset:NnnnNN, \object_create:nnnN, \object_create_set:NnnnN, \object_create_gset:NnnnN, \object_create:nnn, \object_create_set:Nnnn, \object_create_gset:Nnnn, \embedded_create:nnn}
+% Creates an object from a proxy.
% \begin{macrocode}
-\msg_new:nnn { aa }{ mess }{ #1 }
-
\msg_new:nnnn { rawobjects }{ notproxy }{ Fake ~ proxy }
{
Object ~ #1 ~ is ~ not ~ a ~ proxy.
@@ -1658,20 +2326,39 @@
\cs_new_protected:Nn \@@_create_anon:nnnNN
{
+ \tl_if_empty:nF{ #1 }
+ {
\@@_force_proxy:n { #1 }
-
- \str_const:cn { \@@_object_modvar:n { #2 } }{ #3 }
- \str_const:cx { \@@_object_pxyvar:n { #2 } }{ #1 }
- \str_const:cV { \@@_object_scovar:n { #2 } } #4
- \str_const:cV { \@@_object_visvar:n { #2 } } #5
+
+
+ \object_newconst_str:nnn
+ {
+ \object_embedded_adr:nn{ #3 }{ /_I_/ }
+ }
+ { M }{ #2 }
+ \object_newconst_str:nnn
+ {
+ \object_embedded_adr:nn{ #3 }{ /_I_/ }
+ }
+ { P }{ #1 }
+ \object_newconst_str:nnV
+ {
+ \object_embedded_adr:nn{ #3 }{ /_I_/ }
+ }
+ { S } #4
+ \object_newconst_str:nnV
+ {
+ \object_embedded_adr:nn{ #3 }{ /_I_/ }
+ }
+ { V } #5
\seq_map_inline:cn
{
\object_member_adr:nnn { #1 }{ varlist }{ seq }
}
{
- \object_new_member:nnv { #2 }{ ##1 }
+ \object_new_member:nnv { #3 }{ ##1 }
{
\object_ncmember_adr:nnn { #1 }{ ##1 _ type }{ str }
}
@@ -1683,22 +2370,35 @@
}
{
\embedded_create:nvn
- { #2 }
+ { #3 }
{
\object_ncmember_adr:nnn { #1 }{ ##1 _ proxy }{ str }
}
{ ##1 }
}
+
+ \tl_map_inline:cn
+ {
+ \object_member_adr:nnn { #1 }{ init }{ tl }
+ }
+ {
+ ##1 { #1 }{ #2 }{ #3 }
+ }
+
+ }
}
-\cs_generate_variant:Nn \@@_create_anon:nnnNN { nnvcc }
+\cs_generate_variant:Nn \@@_create_anon:nnnNN { xnxNN, xvxcc }
\cs_new_protected:Nn \object_create:nnnNN
{
- \@@_create_anon:nnnNN { #1 }{ \object_address:nn { #2 }{ #3 } }
- { #2 } #4 #5
+ \@@_create_anon:xnxNN { #1 }{ #2 }
+ { \object_address:nn { #2 }{ #3 } }
+ #4 #5
}
+\cs_generate_variant:Nn \object_create:nnnNN { VnnNN }
+
\cs_new_protected:Nn \object_create_set:NnnnNN
{
\object_create:nnnNN { #2 }{ #3 }{ #4 } #5 #6
@@ -1710,125 +2410,134 @@
\object_create:nnnNN { #2 }{ #3 }{ #4 } #5 #6
\str_gset:Nx #1 { \object_address:nn { #3 }{ #4 } }
}
-
-\cs_new_protected:Nn \embedded_create:nnn
- {
- \@@_create_anon:nnvcc { #2 }
- {
- \object_embedded_adr:nn
- { #1 }{ #3 }
- }
- {
- \@@_object_modvar:n{ #1 }
- }
- {
- \@@_object_scovar:n{ #1 }
- }
- {
- \@@_object_visvar:n{ #1 }
- }
- }
-\cs_generate_variant:Nn \object_create:nnnNN { VnnNN }
\cs_generate_variant:Nn \object_create_set:NnnnNN { NVnnNN, NnnfNN }
\cs_generate_variant:Nn \object_create_gset:NnnnNN { NVnnNN, NnnfNN }
-\cs_generate_variant:Nn \embedded_create:nnn { nvn, Vnn }
-% \end{macrocode}
-%\end{macro}
-%
-% \begin{macro}{\object_allocate_incr:NNnnNN, \object_gallocate_incr:NNnnNN, \object_allocate_gincr:NNnnNN, \object_gallocate_gincr:NNnnNN}
-% Create an address and use it to instantiate an object
-% \begin{macrocode}
-\cs_new:Nn \@@_combine_aux:nnn
+
+\cs_new_protected:Nn \object_create:nnnN
{
- anon . #3 . #2 . #1
+ \object_create:nnnNN { #1 }{ #2 }{ #3 } #4 \c_object_public_str
}
-
-\cs_generate_variant:Nn \@@_combine_aux:nnn { Vnf }
-\cs_new:Nn \@@_combine:Nn
+\cs_generate_variant:Nn \object_create:nnnN { VnnN }
+
+\cs_new_protected:Nn \object_create_set:NnnnN
{
- \@@_combine_aux:Vnf #1 { #2 }
- {
- \cs_to_str:N #1
- }
+ \object_create_set:NnnnNN #1 { #2 }{ #3 }{ #4 } #5 \c_object_public_str
}
-\cs_new_protected:Nn \object_allocate_incr:NNnnNN
+\cs_new_protected:Nn \object_create_gset:NnnnN
{
- \object_create_set:NnnfNN #1 { #3 }{ #4 }
- {
- \@@_combine:Nn #2 { #3 }
- }
- #5 #6
+ \object_create_gset:NnnnNN #1 { #2 }{ #3 }{ #4 } #5 \c_object_public_str
+ }
- \int_incr:N #2
+\cs_generate_variant:Nn \object_create_set:NnnnN { NVnnN }
+\cs_generate_variant:Nn \object_create_gset:NnnnN { NVnnN }
+
+\cs_new_protected:Nn \object_create:nnn
+ {
+ \object_create:nnnNN { #1 }{ #2 }{ #3 }
+ \c_object_global_str \c_object_public_str
}
-\cs_new_protected:Nn \object_gallocate_incr:NNnnNN
+\cs_generate_variant:Nn \object_create:nnn { Vnn }
+
+\cs_new_protected:Nn \object_create_set:Nnnn
{
- \object_create_gset:NnnfNN #1 { #3 }{ #4 }
- {
- \@@_combine:Nn #2 { #3 }
- }
- #5 #6
+ \object_create_set:NnnnNN #1 { #2 }{ #3 }{ #4 }
+ \c_object_global_str \c_object_public_str
+ }
- \int_incr:N #2
+\cs_new_protected:Nn \object_create_gset:Nnnn
+ {
+ \object_create_gset:NnnnNN #1 { #2 }{ #3 }{ #4 }
+ \c_object_global_str \c_object_public_str
}
-\cs_generate_variant:Nn \object_allocate_incr:NNnnNN { NNVnNN }
+\cs_generate_variant:Nn \object_create_set:Nnnn { NVnn }
+\cs_generate_variant:Nn \object_create_gset:Nnnn { NVnn }
-\cs_generate_variant:Nn \object_gallocate_incr:NNnnNN { NNVnNN }
-\cs_new_protected:Nn \object_allocate_gincr:NNnnNN
+
+
+\cs_new_protected:Nn \embedded_create:nnn
{
- \object_create_set:NnnfNN #1 { #3 }{ #4 }
+ \@@_create_anon:xvxcc { #2 }
+ {
+ \object_ncmember_adr:nnn
+ {
+ \object_embedded_adr:nn{ #1 }{ /_I_/ }
+ }
+ { M }{ str }
+ }
{
- \@@_combine:Nn #2 { #3 }
+ \object_embedded_adr:nn
+ { #1 }{ #3 }
}
- #5 #6
-
- \int_gincr:N #2
- }
-
-\cs_new_protected:Nn \object_gallocate_gincr:NNnnNN
- {
- \object_create_gset:NnnfNN #1 { #3 }{ #4 }
{
- \@@_combine:Nn #2 { #3 }
+ \object_ncmember_adr:nnn
+ {
+ \object_embedded_adr:nn{ #1 }{ /_I_/ }
+ }
+ { S }{ str }
+ }
+ {
+ \object_ncmember_adr:nnn
+ {
+ \object_embedded_adr:nn{ #1 }{ /_I_/ }
+ }
+ { V }{ str }
}
- #5 #6
-
- \int_gincr:N #2
}
-\cs_generate_variant:Nn \object_allocate_gincr:NNnnNN { NNVnNN }
-
-\cs_generate_variant:Nn \object_gallocate_gincr:NNnnNN { NNVnNN }
+\cs_generate_variant:Nn \embedded_create:nnn { nvn, Vnn }
% \end{macrocode}
-% \end{macro}
+%\end{macro}
%
-%\begin{macro}{\proxy_create:nnN, \proxy_create_set:NnnN, \proxy_create_gset:NnnN}
+%\begin{macro}{\proxy_create:nn, \proxy_create_set:Nnn, \proxy_create_gset:Nnn}
%Creates a new proxy object
% \begin{macrocode}
+\cs_new_protected:Nn \proxy_create:nn
+ {
+ \object_create:VnnNN \c_proxy_address_str { #1 }{ #2 }
+ \c_object_global_str \c_object_public_str
+ }
+
+\cs_new_protected:Nn \proxy_create_set:Nnn
+ {
+ \object_create_set:NVnnNN #1 \c_proxy_address_str { #2 }{ #3 }
+ \c_object_global_str \c_object_public_str
+ }
+
+\cs_new_protected:Nn \proxy_create_gset:Nnn
+ {
+ \object_create_gset:NVnnNN #1 \c_proxy_address_str { #2 }{ #3 }
+ \c_object_global_str \c_object_public_str
+ }
+
+
+
\cs_new_protected:Nn \proxy_create:nnN
{
+ \@@_launch_deprecate:NN \proxy_create:nnN \proxy_create:nn
\object_create:VnnNN \c_proxy_address_str { #1 }{ #2 }
\c_object_global_str #3
}
\cs_new_protected:Nn \proxy_create_set:NnnN
{
+ \@@_launch_deprecate:NN \proxy_create_set:NnnN \proxy_create_set:Nnn
\object_create_set:NVnnNN #1 \c_proxy_address_str { #2 }{ #3 }
\c_object_global_str #4
}
\cs_new_protected:Nn \proxy_create_gset:NnnN
{
+ \@@_launch_deprecate:NN \proxy_create_gset:NnnN \proxy_create_gset:Nnn
\object_create_gset:NVnnNN #1 \c_proxy_address_str { #2 }{ #3 }
\c_object_global_str #4
}
@@ -1839,9 +2548,9 @@
%\begin{macro}{\proxy_push_member:nnn}
% Push a new member inside a proxy.
% \begin{macrocode}
+
\cs_new_protected:Nn \proxy_push_member:nnn
{
- \@@_force_scope:n { #1 }
\object_newconst_str:nnn { #1 }{ #2 _ type }{ #3 }
\seq_gput_left:cn
{
@@ -1859,11 +2568,8 @@
% Push a new embedded object inside a proxy.
% \begin{macrocode}
-\cs_generate_variant:Nn \object_newconst_str:nnn { nnx }
-
\cs_new_protected:Nn \proxy_push_embedded:nnn
{
- \@@_force_scope:n { #1 }
\object_newconst_str:nnx { #1 }{ #2 _ proxy }{ #3 }
\seq_gput_left:cn
{
@@ -1877,6 +2583,150 @@
% \end{macrocode}
%\end{macro}
%
+%\begin{macro}{\proxy_add_initializer:nN}
+% Push a new embedded object inside a proxy.
+% \begin{macrocode}
+
+\cs_new_protected:Nn \proxy_add_initializer:nN
+ {
+ \tl_gput_right:cn
+ {
+ \object_member_adr:nnn { #1 }{ init }{ tl }
+ }
+ { #2 }
+ }
+
+\cs_generate_variant:Nn \proxy_add_initializer:nN { VN }
+
+% \end{macrocode}
+%\end{macro}
+%
+%\begin{variable}{\c_proxy_address_str}
+% Variable containing the address of the \verb|proxy| object.
+% \begin{macrocode}
+
+\str_const:Nx \c_proxy_address_str
+ { \object_address:nn { rawobjects }{ proxy } }
+
+\object_newconst_str:nnn
+ {
+ \object_embedded_adr:Vn \c_proxy_address_str { /_I_/ }
+ }
+ { M }{ rawobjects }
+
+\object_newconst_str:nnV
+ {
+ \object_embedded_adr:Vn \c_proxy_address_str { /_I_/ }
+ }
+ { P } \c_proxy_address_str
+
+\object_newconst_str:nnV
+ {
+ \object_embedded_adr:Vn \c_proxy_address_str { /_I_/ }
+ }
+ { S } \c_object_global_str
+
+\object_newconst_str:nnV
+ {
+ \object_embedded_adr:Vn \c_proxy_address_str { /_I_/ }
+ }
+ { V } \c_object_public_str
+
+
+\@@_initproxy:VnV \c_proxy_address_str { rawobjects } \c_proxy_address_str
+
+\object_new_member:Vnn \c_proxy_address_str { init }{ tl }
+
+\object_new_member:Vnn \c_proxy_address_str { varlist }{ seq }
+
+\object_new_member:Vnn \c_proxy_address_str { objlist }{ seq }
+
+\proxy_push_member:Vnn \c_proxy_address_str
+ { init }{ tl }
+\proxy_push_member:Vnn \c_proxy_address_str
+ { varlist }{ seq }
+\proxy_push_member:Vnn \c_proxy_address_str
+ { objlist }{ seq }
+
+\proxy_add_initializer:VN \c_proxy_address_str
+ \@@_initproxy:nnn
+
+% \end{macrocode}
+%\end{variable}
+%
+% \begin{macro}{\object_allocate_incr:NNnnNN, \object_gallocate_incr:NNnnNN, \object_allocate_gincr:NNnnNN, \object_gallocate_gincr:NNnnNN}
+% Create an address and use it to instantiate an object
+% \begin{macrocode}
+
+\cs_new:Nn \@@_combine_aux:nnn
+ {
+ anon . #3 . #2 . #1
+ }
+
+\cs_generate_variant:Nn \@@_combine_aux:nnn { Vnf }
+
+\cs_new:Nn \@@_combine:Nn
+ {
+ \@@_combine_aux:Vnf #1 { #2 }
+ {
+ \cs_to_str:N #1
+ }
+ }
+
+\cs_new_protected:Nn \object_allocate_incr:NNnnNN
+ {
+ \object_create_set:NnnfNN #1 { #3 }{ #4 }
+ {
+ \@@_combine:Nn #2 { #3 }
+ }
+ #5 #6
+
+ \int_incr:N #2
+ }
+
+\cs_new_protected:Nn \object_gallocate_incr:NNnnNN
+ {
+ \object_create_gset:NnnfNN #1 { #3 }{ #4 }
+ {
+ \@@_combine:Nn #2 { #3 }
+ }
+ #5 #6
+
+ \int_incr:N #2
+ }
+
+\cs_generate_variant:Nn \object_allocate_incr:NNnnNN { NNVnNN }
+
+\cs_generate_variant:Nn \object_gallocate_incr:NNnnNN { NNVnNN }
+
+\cs_new_protected:Nn \object_allocate_gincr:NNnnNN
+ {
+ \object_create_set:NnnfNN #1 { #3 }{ #4 }
+ {
+ \@@_combine:Nn #2 { #3 }
+ }
+ #5 #6
+
+ \int_gincr:N #2
+ }
+
+\cs_new_protected:Nn \object_gallocate_gincr:NNnnNN
+ {
+ \object_create_gset:NnnfNN #1 { #3 }{ #4 }
+ {
+ \@@_combine:Nn #2 { #3 }
+ }
+ #5 #6
+
+ \int_gincr:N #2
+ }
+
+\cs_generate_variant:Nn \object_allocate_gincr:NNnnNN { NNVnNN }
+
+\cs_generate_variant:Nn \object_gallocate_gincr:NNnnNN { NNVnNN }
+
+% \end{macrocode}
+% \end{macro}
%
%
%\begin{macro}{\object_assign:nn}
@@ -1888,7 +2738,11 @@
{
\object_member_adr:vnn
{
- \@@_object_pxyvar:n { #1 }
+ \object_ncmember_adr:nnn
+ {
+ \object_embedded_adr:nn{ #1 }{ /_I_/ }
+ }
+ { P }{ str }
}
{ varlist }{ seq }
}
@@ -1904,37 +2758,6 @@
% \end{macrocode}
%\end{macro}
%
-% A simple forward list proxy
-% \begin{macrocode}
-
-\cs_new_protected:Nn \rawobjects_fwl_inst:n
- {
- \object_if_exist:nF
- {
- \object_address:nn { rawobjects }{ fwl ! #1 }
- }
- {
- \proxy_create:nnN { rawobjects }{ fwl ! #1 } \c_object_private_str
- \proxy_push_member
- {
- \object_address:nn { rawobjects }{ fwl ! #1 }
- }
- { next }{ str }
- }
- }
-
-\cs_new_protected:Nn \rawobjects_fwl_newnode:nnnNN
- {
- \rawobjects_fwl_inst:n { #1 }
- \object_create:nnnNN
- {
- \object_address:nn { rawobjects }{ fwl ! #1 }
- }
- { #2 }{ #3 } #4 #5
- }
-
-% \end{macrocode}
-%
% \begin{macrocode}
%</package>
% \end{macrocode}