effective-method-keywords
effective-method
effective-method-live-p
+ sod::lifecycle-effective-method
simple-effective-method
effective-method-message
effective-method
sod-token-scanner t
simple-method-body
aggregating-effective-method t t
+ sod::lifecycle-effective-method t t
standard-effective-method t t
cl:slot-unbound
t basic-direct-method (eql sod::function-type)
aggregating-message
sod-message-effective-method-class
aggregating-message
+ sod::initialization-message
standard-message
sod-message-kernel-function
aggregating-message
Keyword arguments are provided as a general feature for C functions.
However, Sod has special support for messages which accept keyword arguments
-(\xref{sec:concepts.methods.keywords}).
+(\xref{sec:concepts.methods.keywords}); and they play an essential role in
+the instance construction protocol (\xref{sec:concepts.lifecycle.birth}).
%%%--------------------------------------------------------------------------
\section{Messages and methods} \label{sec:concepts.methods}
necessary.
\end{enumerate}
The \descref{SOD_DECL}[macro]{mac} handles constructing instances with
-automatic storage duration (`on the stack'). Currently, there is no built-in
-support for constructing dynamically-allocated instances.
+automatic storage duration (`on the stack'). Programmers can add support for
+other allocation strategies by using the \descref{SOD_INIT}[macro]{mac} and
+the \descref{sod_init}{fun} and \descref{sod_initv}{fun} functions, which
+package up imprinting and initialization.
\subsubsection{Allocation}
Instances of most classes (specifically including those classes defined by
involves setting the instance's slots to appropriate values, and possibly
linking it into some larger data structure to keep track of it.
-Classes can declare initial values for their slots. A class object's @|init|
-slot points to a function which will establish the appropriate initial values
-for a new instance's slots. Slots are not initialized in any particularly
-useful order.
-
-The provided initialization protocol is extremely simplistic; most notably,
-it's not possible to pass parameters into the initialization process.
-Classes which have more complex requirements will need to define and
-implement their own additional (or alternative) protocols.
+Initialization is performed by sending the imprinted instance an @|init|
+message, defined by the @|SodObject| class. This message uses a nonstandard
+method combination which works like the standard combination, except that the
+\emph{default behaviour}, if there is no overriding method, is to initialize
+the instance's slots using the initializers defined in the class and its
+superclasses. This default behaviour may be invoked multiple times if some
+method calls on its @|next_method| more than once, unless some other method
+takes steps to prevent this.
+
+The recommended way to add new initialization behaviour is to define @|after|
+methods on the @|init| message. These will be run after the slot
+initializers have been applied, in reverse precedence order.
+
+Initialization is \emph{parametrized}, so the caller may select from a space
+of possible initial states for the new instance, or to inform the new
+instance about some other objects known to the caller. Specifically, the
+@|init| message accepts keyword arguments (\xref{sec:concepts.keywords})
+which can be defined and used by methods defined on it.
\subsubsection{Example}
The following is a simple function, with syntactic-sugar macro, which
allocate storage for an instance of a class, imprints and initializes it, and
returns a pointer to the new instance.
\begin{prog}
- void *make_instance(const SodClass *c) \\
+ void *make_instance(const SodClass *c, @|\dots|) \\
\{ \\ \ind
+ va_list ap;
void *p = malloc(c@->cls.initsz); \\
if (!p) return (0); \\
- c@->cls.imprint(p); \\
- c@->cls.init(p); \\
+ va_start(ap, c); \\
+ sod_initv(c, p, ap); \\
+ va_end(ap); \\
return (p); \- \\
\}
\\+
- \#define MAKE(cls) (cls *)make_instance(cls\#\#__class)
+ \#define MAKE(cls, keys) (cls *)make_instance(cls\#\#__class, keys)
\end{prog}
The following macros and functions manage the standard steps along an
instance's lifecycle.
+\subsubsection{Low-level operations}
+The following macros and functions are agnostic with respect to storage
+allocation strategies. They don't concern themselves with allocation or
+deallocation, and applications are free to use any suitable mechanism.
+
+\begin{describe*}
+ {\dhead[SOD_INIT]{mac}
+ {@<cls> *SOD_INIT(@<cls>, void *@<p>, @<keywords>);}
+ \dhead[sod_init]{fun}
+ {void *sod_init(const SodClass *@<cls>, void *@<p>, \dots);}
+ \dhead[sod_initv]{fun}
+ {void *sod_initv(const SodClass *@<cls>, void *@<p>, va_list @<ap>);}}
+ Imprints and initializes an instance of a class @<cls> in the storage
+ starting at address~@<p>.
+
+ The direct class for the new instance is specified as a class name to
+ @|SOD_INIT|, or a pointer to a class object to the functions.
+
+ Keyword arguments for the initialization message may be provided. The
+ @|SOD_INIT| macro expects a single preprocessor-time argument which is
+ a use of one of \descref{KWARGS}{mac} or \descref{NO_KWARGS}{mac}; the
+ @|sod_init| function expects the keywords as a variable-length argument
+ tail; and @|sod_initv| expects the keywords to be passed indirectly,
+ through the captured argument-tail cursor @<ap>.
+
+ The return value is an instance pointer for the class @<cls>; the
+ @|SOD_INIT| macro will have converted it to the correct type, so it should
+ probably be used where possible. In fact, this is guaranteed to be equal
+ to @<p> by the layout rules described in
+ \xref{sec:structures.layout.instance}.
+\end{describe*}
+
\subsubsection{Automatic storage duration}
The following macro constructs an instance with automatic storage duration.
-\begin{describe}[SOD_DECL]{mac}{SOD_DECL(@<cls>, @<var>);}
+\begin{describe}[SOD_DECL]{mac}{SOD_DECL(@<cls>, @<var>, @<keywords>);}
Declares and initializes an instance with automatic storage duration.
Given a class name @<cls> and an identifier @<var>, @|SOD_DECL| declares
up, and slots for which initializers are defined are set to the appropriate
initial values.
+ Keyword arguments for the initialization message may be provided. The
+ macro expects a single preprocessor-time argument which is a use of one of
+ \descref{KWARGS}{mac} or \descref{NO_KWARGS}{mac}.
+
The instance has automatic storage duration: pointers to it will become
invalid when control exits the scope of the declaration.
\end{describe}
\begin{nprog}
struct SodObject__vt_obj \{ \\ \ind
const SodClass *_class; \\
- size_t _base; \- \\
+ size_t _base; \\
+ struct SodObject__vtmsgs_obj \{ \\ \ind
+ void (*init)(SodObject *me, ...); \\
+ void (*init__v)(SodObject *me, va_list); \- \\
+ \} obj; \- \\
\};
\end{nprog} \\
\end{tabular}
\begin{describe}[SodObject]{cls}
{[nick = obj, metaclass = SodClass, lisp_metaclass = sod_class] \\
- class SodObject \{ \}}
+ class SodObject \{ \\ \ind
+ void init(?);
+ \}}
- The @|SodObject| class defines no slots or messages. Because @|SodObject|
- has no direct superclasses, there is only one chain, and no inherited
- slots or messages, so the single chain contains only a vtable pointer.
+ The @|SodObject| class defines no slots. Because @|SodObject| has no
+ direct superclasses, there is only one chain, and no inherited slots or
+ messages, so the single chain contains only a vtable pointer.
- Since there are no messages, and @|SodClass| also has only one chain, the
- vtable contains only the standard class pointer and offset-to-base members.
- In a direct instance of @|SodObject| (why would you want one?) the class
- pointer contains the address of @|SodObject__class| and the offset is zero.
+ Since @|SodClass| also has only one chain, the vtable contains only the
+ standard class pointer and offset-to-base members. In a direct instance of
+ @|SodObject| (why would you want one?) the class pointer contains the
+ address of @|SodObject__class| and the offset is zero.
The instance and vtable layout of @|SodObject| is shown in
\xref{fig:structures.root.sodobject}.
+
+ The following message is defined.
+
+ \begin{describe}[obj.init]{msg}{void init(?);}
+ Initialize a newly allocated instance.
+
+ This message uses a custom method combination which works like the
+ standard method combination except that default behaviour specific to the
+ receiver's direct class is invoked if no primary or around method
+ overrides. This default behaviour may be invoked multiple times if some
+ method calls on its @|next_method| function more than once.
+
+ This default behaviour is to initialize the instance's slots using the
+ defined slot initializers: each slot is initialized using the most
+ specific applicable initializer, if any. Slots without an initializer
+ are left uninitialized.
+
+ There are no standard keyword arguments; methods on subclasses are free
+ to introduce their own in the usual way.
+
+ It is usual to provide complex initialization behaviour as @|after|
+ methods. This ensures that slots have been initialized as necessary
+ before the method executes.
+
+ For more details on instance construction, see
+ \xref{sec:concepts.lifecycle.birth}.
+ \end{describe}
\end{describe}
const char *nick; \\
size_t initsz; \\
void *(*imprint)(void *@<p>); \\
- void *(*init)(void *@<p>); \\
size_t n_supers; \\
const SodClass *const *supers; \\
size_t n_cpl; \\
size_t islotsz; \- \\
\}}
- The @|SodClass| class defines no messages, but there are a number of slots.
- Its only direct superclass is @|SodObject| and so (like its superclass) its
- vtable is trivial.
+ The @|SodClass| class defines no additional messages , but there are a
+ number of slots. Its only direct superclass is @|SodObject| and so (like
+ its superclass) its vtable is simple.
The slots defined are as follows.
\begin{description} \let\makelabel\code
the vtable and class pointers are properly initialized, but the slots are
left untouched. The function returns its argument @<p>.
- \item[init] A pointer to a function: given a pointer @<p> to an imprinted
- instance, initialize all of its slots for which initializers are defined.
- Other slots are left untouched. The function returns its argument @<p>.
-
\item[n_supers] The number of direct superclasses. (This is zero exactly
in the case of @|SodObject|.)
struct SodObject__vt_obj {
\h'2n'const SodClass *_class;
\h'2n'size_t _base;
+\h'2n'struct SodObject__vtmsgs_obj {
+\h'4n'void (*init)(SodObject *\fIme\fB, ...);
+\h'4n'void (*init__v)(SodObject *\fIme\fB, va_list);
+\h'2n'} obj;
};
struct SodObject__ilayout {
struct SodClass__vt_obj {
\h'2n'const SodClass *_class;
\h'2n'size_t _base;
+\h'2n'struct SodClass__vtmsgs_obj {
+\h'4n'void (*init)(SodClass *\fIme\fB, ...);
+\h'4n'void (*init__v)(SodClass *\fIme\fB, va_list);
+\h'2n'} obj;
};
struct SodObject__ilayout {
\h'8n'const char *nick;
\h'8n'size_t initsz;
\h'8n'void *(*imprint)(void *\fIp\fB);
-\h'8n'void *(*init)(void *\fIp\fB);
\h'8n'size_t n_supers;
\h'8n'const SodClass *const *supers;
\h'8n'size_t n_cpl;
.SS The SodObject class
The
.B SodObject
-class defines no slots or messages.
+class defines no slots.
Because
.B SodObject
has no direct superclasses,
and no inherited slots or messages,
so the single chain contains only a vtable pointer.
.PP
-Since there are no messages,
-and
+Since
.B SodClass
also has only one chain,
the vtable contains only the standard class pointer and offset-to-base
the class pointer contains the address of
.B SodObject__class
and the offset is zero.
+.PP
+The
+.B init
+message is used to initialize a newly allocated instance.
+.PP
+This message uses a custom method combination
+which works like the standard method combination
+except that default behaviour
+specific to the receiver's direct class
+is invoked if no primary or around method overrides.
+This default behaviour may be invoked multiple times
+if some method calls on its
+.B next_method
+function more than once.
+.PP
+This default behaviour is to initialize the instance's slots
+using the defined slot initializers:
+each slot is initialized
+using the most specific applicable initializer,
+if any.
+Slots without an initializer
+are left uninitialized.
+.PP
+Slots are initialized in reverse-precedence order
+of their defining classes;
+i.e., slots defined by a less specific superclass are initialized
+earlier than slots defined by a more specific superclass.
+Slots defined by the same class are initialized in the order in which
+they appear in the class definition.
+.PP
+There are no standard keyword arguments;
+methods on subclasses are free to
+introduce their own in the usual way.
+.PP
+It is usual to provide complex initialization behaviour as
+.B after
+methods.
+This ensures that slots have been initialized as necessary
+before the method executes.
.
.SS The SodClass class
The
The function returns its argument
.IR p .
.TP
-.BI "void *(*init)(void *" p );
-A pointer to a function:
-given a pointer
-.I p
-to an imprinted instance,
-initialize all of its slots for which initializers are defined.
-Other slots are left untouched.
-The function returns its argument
-.IR p .
-.TP
.B size_t n_supers;
The number of direct superclasses.
(This is zero exactly in the case of
.BI "const SodClass *" cls ,
.BI "const void *" obj );
.PP
+.IB cls " *" \c
+.B SOD_INIT(\c
+.IB cls ,
+.BI "void *" p ,
+.IB keywords );
+.br
+.B void *\c
+.B sod_init(\c
+.BI "const SodClass *" cls ,
+.BI "void *" p ,
+.B ...);
+.br
+.B void *\c
+.B sod_initv(\c
+.BI "const SodClass *" cls ,
+.BI "void *" p ,
+.BI "va_list " ap );
+.br
.B SOD_DECL(\c
.IB cls ,
.IB var );
an instance's lifecycle.
.PP
The
+.B SOD_INIT
+macro,
+and the
+.B sod_init
+and
+.B sod_initv
+functions,
+imprint and initialize an instance of a class
+.I cls
+in the storage starting at address
+.IR p .
+.PP
+The direct class for the new instance is specified as
+a class name to
+.BR SOD_INIT ,
+or a pointer to a class object to the functions.
+.PP
+Keyword arguments for the initialization message may be provided.
+The
+.B SOD_INIT
+macro expects a single preprocessor-time argument
+which is a use of one of
+.B KWARGS
+or
+.B NO_KWARGS
+(see
+.BR keyword (3));
+the
+.B sod_init
+function expects the keywords as
+a variable-length argument tail;
+and
+.B sod_initv
+expects the keywords to be passed indirectly,
+through the captured argument-tail cursor
+.IR ap .
+.PP
+The return value is an instance pointer for the class
+.IR cls ;
+the
+.B SOD_INIT
+macro will have converted it to the correct type,
+so it should probably be used where possible.
+In fact, this is guaranteed to be equal to
+.I p
+by the layout rules described in
+.BR sod-structs (3).
+.PP
+The
.B SOD_DECL
macro declares and initializes an instance
with automatic storage duration.
.
.\"--------------------------------------------------------------------------
.SH SEE ALSO
+.BR keyword (3),
.BR sod (1),
.BR sod-structs (3).
.
return ((char *)obj - vt->_base + chain->off_ichain);
}
+/* --- @sod_init@, @sod_initv@ --- *
+ *
+ * Arguments: @const SodClass *cls@ = class object for new instance
+ * @void *p@ = pointer to storage for new instance
+ * @va_list ap, ...@ = initialization keyword arguments
+ *
+ * Returns: Pointer to the initialized instance.
+ *
+ * Use: Initializes an instance in pre-allocated storage, and returns
+ * a pointer to it.
+ *
+ * This function will imprint the storage, and then send an
+ * `initialize' message to the fresh instance containing the
+ * provided keyword arguments.
+ *
+ * It's usually convenient to use the macro @SOD_INIT@ rather
+ * than calling @sod_init@ directly.
+ */
+
+void *sod_init(const SodClass *cls, void *p, ...)
+{
+ va_list ap;
+
+ va_start(ap, p);
+ sod_initv(cls, p, ap);
+ va_end(ap);
+ return (p);
+}
+
+void *sod_initv(const SodClass *cls, void *p, va_list ap)
+{
+ SodObject *obj;
+
+ cls->cls.imprint(p);
+ obj = SOD_CONVERT(SodObject, p);
+ SodObject_init__v(obj, ap);
+ return (p);
+}
+
/*----- That's all, folks -------------------------------------------------*/
#define SOD_CONVERT(cls, obj) ((cls *)sod_convert(cls##__class, (obj)))
+/* --- @SOD_INIT@ --- *
+ *
+ * Arguments: @cls@ = a class type name
+ * @p@ = pointer to storage to initialize
+ * @keys@ = a @KWARGS(...)@ keyword argument sequence
+ *
+ * Use: Initializes raw storage as an instance of @cls@.
+ */
+
+#define SOD_INIT(cls, p, keys) ((cls *)sod_init(cls##__class, (p), keys))
+
/* --- @SOD_DECL@ --- *
*
- * Arguments: @cls_@ = a class type name
- * @var_@ = a variable name
+ * Arguments: @cls@ = a class type name
+ * @var@ = a variable name
+ * @keys@ = a @KWARGS(...)@ keyword argument sequence
*
- * Use: Declare @var_@ as a pointer to an initialized instance of
- * @cls_@ with automatic lifetime.
+ * Use: Declare @var@ as a pointer to an initialized instance of
+ * @cls@ with automatic lifetime.
*/
-#define SOD_DECL(cls_, var_) \
- struct cls_##__ilayout var_##__layout; \
- cls_ *var_ = \
- cls_##__class->cls.init(cls_##__class->cls.imprint(&var_##__layout))
+#define SOD_DECL(cls, var, keys) \
+ struct cls##__ilayout var##__layout; \
+ cls *var = (cls *)sod_init(cls##__class, &var##__layout, keys)
/*----- Functions provided ------------------------------------------------*/
extern void *sod_convert(const SodClass */*cls*/, const void */*obj*/);
+/* --- @sod_init@, @sod_initv@ --- *
+ *
+ * Arguments: @const SodClass *cls@ = class object for new instance
+ * @void *p@ = pointer to storage for new instance
+ * @va_list ap, ...@ = initialization keyword arguments
+ *
+ * Returns: Pointer to the initialized instance.
+ *
+ * Use: Initializes an instance in pre-allocated storage, and returns
+ * a pointer to it.
+ *
+ * This function will imprint the storage, and then send an
+ * `initialize' message to the fresh instance containing the
+ * provided keyword arguments.
+ *
+ * It's usually convenient to use the macro @SOD_INIT@ rather
+ * than calling @sod_init@ directly.
+ */
+
+extern KWCALL void *sod_init(const SodClass */*cls*/, void */*p*/, ...);
+extern void *sod_initv(const SodClass */*cls*/, void */*p*/, va_list /*ap*/);
+
/*----- That's all, folks -------------------------------------------------*/
#ifdef __cplusplus
(sod-class-nickname tail))))
(ilayout-ichains ilayout)))))
-(define-class-slot "init" (class stream)
- (* (fun (* void) ("/*p*/" (* void))))
- (format nil "~A__init" class)
-
- ;; FIXME this needs a metaobject protocol
- (let ((ilayout (sod-class-ilayout class)))
- (format stream "~&~:
-/* Provide initial values for an instance's slots. */
-static void *~A__init(void *p)~%{~%" class)
- (dolist (ichain (ilayout-ichains ilayout))
- (let ((ich (format nil "sod__obj->~A.~A"
- (sod-class-nickname (ichain-head ichain))
- (sod-class-nickname (ichain-tail ichain)))))
- (dolist (item (ichain-body ichain))
- (etypecase item
- (vtable-pointer
- nil)
- (islots
- (let ((isl (format nil "~A.~A"
- ich
- (sod-class-nickname (islots-class item)))))
- (dolist (slot (islots-slots item))
- (let ((dslot (effective-slot-direct-slot slot))
- (init (effective-slot-initializer slot)))
- (when init
- (format stream " {~% ")
- (pprint-c-type (sod-slot-type dslot) stream
- *sod-tmp-val*)
- (format stream " = ~A;~% ~
- ~A.~A = ~A;~% ~
- }~%"
- (sod-initializer-value init)
- isl (sod-slot-name dslot)
- *sod-tmp-val*))))))))))
- (format stream "~&~:
- return (p);
-}~2%")))
-
;;;--------------------------------------------------------------------------
;;; Superclass structure.
(islots-struct-tag class))
"0"))
+;;;--------------------------------------------------------------------------
+;;; Built-in methods.
+
+;; Common protocol.
+
+(defclass lifecycle-message (standard-message)
+ ())
+
+(defclass lifecycle-effective-method (standard-effective-method)
+ ())
+
+(defmethod effective-method-live-p ((method lifecycle-effective-method))
+ t)
+
+(defgeneric lifecycle-method-kernel (method codegen target)
+ (:documentation
+ "Compute (into CODEGEN) the class-specific part of the METHOD.
+
+ The result, if any, needs to find its way to the TARGET, as usual."))
+
+(defmethod simple-method-body
+ ((method lifecycle-effective-method) codegen target)
+ (invoke-delegation-chain codegen target
+ (effective-method-basic-argument-names method)
+ (effective-method-primary-methods method)
+ (lambda (target)
+ (lifecycle-method-kernel method
+ codegen
+ target))))
+
+;; Initialization.
+
+(defclass initialization-message (lifecycle-message)
+ ())
+
+(defclass initialization-effective-method (lifecycle-effective-method)
+ ())
+
+(defmethod sod-message-effective-method-class
+ ((message initialization-message))
+ 'initialization-effective-method)
+
+(defmethod lifecycle-method-kernel
+ ((method initialization-effective-method) codegen target)
+ (let* ((class (effective-method-class method))
+ (ilayout (sod-class-ilayout class))
+ (obj-tag (ilayout-struct-tag class))
+ (func-type (c-type (fun void ("sod__obj" (* (struct obj-tag))))))
+ (func-name (format nil "~A__init" class)))
+
+ ;; Start building the initialization function.
+ (codegen-push codegen)
+
+ (labels ((set-from-initializer (var type init)
+ ;; Store the value of INIT, which has the given TYPE, in VAR.
+ ;; INIT has the syntax of an initializer: declare and
+ ;; initialize a temporary, and then copy the result.
+ ;; Compilers seem to optimize this properly. Return the
+ ;; resulting code as an instruction.
+ (codegen-push codegen)
+ (emit-decl codegen (make-var-inst *sod-tmp-val* type init))
+ (deliver-expr codegen var *sod-tmp-val*)
+ (codegen-pop-block codegen)))
+
+ ;; Loop over the instance layout emitting initializers as we find them.
+ (dolist (ichain (ilayout-ichains ilayout))
+ (let ((ich (format nil "sod__obj->~A.~A"
+ (sod-class-nickname (ichain-head ichain))
+ (sod-class-nickname (ichain-tail ichain)))))
+ (dolist (item (ichain-body ichain))
+ (etypecase item
+ (vtable-pointer
+ nil)
+ (islots
+ (let ((isl (format nil "~A.~A"
+ ich
+ (sod-class-nickname (islots-class item)))))
+ (dolist (slot (islots-slots item))
+ (let ((dslot (effective-slot-direct-slot slot))
+ (init (effective-slot-initializer slot)))
+ (when init
+ (let* ((slot-type (sod-slot-type dslot))
+ (slot-default (sod-initializer-value init))
+ (target (format nil "~A.~A"
+ isl (sod-slot-name dslot)))
+ (initinst (set-from-initializer target
+ slot-type
+ slot-default)))
+ (emit-inst codegen initinst))))))))))))
+
+ ;; Done making the initialization function.
+ (codegen-pop-function codegen func-name func-type
+ "Instance initialization function ~:_~
+ for class `~A'."
+ class)
+
+ (deliver-call codegen :void func-name "sod__obj")))
+
;;;--------------------------------------------------------------------------
;;; Bootstrapping the class graph.
(make-property-set :nick 'cls)))
(classes (list sod-object sod-class)))
+ ;; Attach the built-in messages.
+ (make-sod-message sod-object "init"
+ (c-type (fun void :keys))
+ (make-property-set
+ :message-class 'initialization-message))
+
;; Sort out the recursion.
(setf (slot-value sod-class 'chain-link) sod-object)
(dolist (class classes)
("module-proto" "pset-proto" "c-types-class-impl" "builtin"))
(:file "builtin" :depends-on
("module-proto" "pset-proto" "c-types-impl" "c-types-class-impl"
- "classes" "class-layout-proto"))
+ "classes" "class-layout-proto" "method-proto"))
(:file "module-parse" :depends-on
("class-make-proto" "class-finalize-proto"
"fragment-parse" "lexer-proto" "module-impl"))
int main(void)
{
{
- SOD_DECL(Lion, l);
+ SOD_DECL(Lion, l, NO_KWARGS);
provoke_lion(l);
tickle_animal(LION__CONV_NML(l));
}
{
- SOD_DECL(Goat, g);
+ SOD_DECL(Goat, g, NO_KWARGS);
provoke_goat(g);
tickle_animal(GOAT__CONV_NML(g));
}
{
- SOD_DECL(Serpent, s);
+ SOD_DECL(Serpent, s, NO_KWARGS);
provoke_serpent(s);
tickle_animal(SERPENT__CONV_NML(s));
}
{
- SOD_DECL(Chimaera, c);
+ SOD_DECL(Chimaera, c, NO_KWARGS);
provoke_lion(CHIMAERA__CONV_LION(c));
provoke_goat(CHIMAERA__CONV_GOAT(c));
provoke_serpent(CHIMAERA__CONV_SERPENT(c));
code c : tests {
prepare("aggregate, base");
- { SOD_DECL(T1Base, t1);
+ { SOD_DECL(T1Base, t1, NO_KWARGS);
struct item *l;
struct vec v;
STEP(0); T1Base_aprogn(t1); /* 1 */
DONE(7);
}
prepare("aggregate, sub");
- { SOD_DECL(T1Sub, t1);
+ { SOD_DECL(T1Sub, t1, NO_KWARGS);
struct item *l;
struct vec v;
T1Base_aprogn(t1); /* 0, 1 */