From: Mark Wooding Date: Sun, 6 Oct 2019 22:03:42 +0000 (+0100) Subject: Static instance support. X-Git-Url: https://git.distorted.org.uk/~mdw/sod/commitdiff_plain/00d59354c311fb28730b7c9b117b0d91aac092cc Static instance support. --- diff --git a/doc/SYMBOLS b/doc/SYMBOLS index 7e18dcd..dc1e784 100644 --- a/doc/SYMBOLS +++ b/doc/SYMBOLS @@ -354,16 +354,20 @@ class-make-proto.lisp make-sod-slot-initarg generic make-sod-slot-initarg-using-slot generic make-sod-user-initarg generic + make-static-instance generic sod-initarg-argument generic sod-message-method-class generic class-output.lisp *instance-class* variable + *static-instance* variable + declare-static-instance generic emit-class-conversion-macro generic emit-class-object-decl generic emit-class-typedef generic emit-message-macro generic emit-message-macro-defn generic + output-static-instance-initializer generic class-utilities.lisp argument-lists-compatible-p function @@ -441,6 +445,12 @@ classes.lisp sod-slot-name generic sod-slot-type generic sod-user-initarg class + static-instance class + static-instance-class generic + static-instance-const-p generic + static-instance-extern-p generic + static-instance-initializers generic setf-generic + static-instance-name generic codegen-impl.lisp codegen class @@ -829,6 +839,7 @@ cl:t delegating-direct-method sod-slot sod-class-slot + static-instance temporary-name temporary-argument temporary-function @@ -1022,6 +1033,8 @@ compute-vtables sod-class compute-vtmsgs sod-class sod-class sod-class sod-class +declare-static-instance + t t decode-property cl:character cl:cons @@ -1262,6 +1275,7 @@ sod-parser:file-location sod-message sod-method sod-slot + static-instance finalize-module module finalize-sod-class @@ -1292,15 +1306,18 @@ hook-output code-fragment-item t t delegating-direct-method (eql :c) t effective-slot (eql cl:class) t + effective-slot (eql static-instance) t ichain (eql :h) t ichain (eql cl:class) t ichain (eql ilayout) t + ichain (eql static-instance) t ichain t t [:after] ilayout (eql :h) t [:after] ilayout (eql :h) t ilayout t t [:after] islots (eql :h) t islots (eql cl:class) t + islots (eql static-instance) t islots t t [:after] method-entry (eql :c) t method-entry (eql vtmsgs) t @@ -1311,16 +1328,21 @@ hook-output sod-class (eql :c) t sod-class (eql :h) t [:after] sod-class (eql :h) t + sod-class (eql static-instance) t sod-class t t [:after] sod-class-effective-slot (eql cl:class) t sod-method (eql :c) t sod-method (eql :h) t sod-slot (eql islots) t + static-instance (eql :c) t [:after] + static-instance (eql :c) t + static-instance (eql :h) t vtable (eql :c) t vtable (eql :h) t vtable t t [:after] vtable-pointer (eql :h) t vtable-pointer (eql cl:class) t + vtable-pointer (eql static-instance) t vtmsgs (eql :c) t vtmsgs (eql :h) t vtmsgs (eql vtmsgs) t @@ -1465,6 +1487,8 @@ make-sod-slot-initarg-using-slot sod-class t sod-slot t make-sod-user-initarg sod-class t t t +make-static-instance + sod-class t t t t method-entry-chain-head method-entry method-entry-chain-tail @@ -1512,6 +1536,8 @@ module-state module (setf module-state) t module +output-static-instance-initializer + static-instance effective-slot t pprint-c-storage-specifier cl:symbol t alignas-storage-specifier t @@ -1576,6 +1602,7 @@ cl:print-object sod-slot t sod-slot-initarg t sod-user-initarg t + static-instance t temporary-name t update-inst t var-inst t @@ -1613,6 +1640,7 @@ cl:shared-initialize sod-method t [:after] sod-slot t [:after] sod-token-scanner t [:after] + static-instance t [:after] simple-method-body aggregating-effective-method t t sod::lifecycle-effective-method t t @@ -1766,6 +1794,18 @@ sod-slot-prepare-function sod-class-slot sod-slot-type sod-slot +static-instance-class + static-instance +static-instance-const-p + static-instance +static-instance-extern-p + static-instance +static-instance-initializers + static-instance +(setf static-instance-initializers) + t static-instance +static-instance-name + static-instance temp-tag temporary-name temporary-var @@ -2207,6 +2247,7 @@ file-location sod:sod-message sod:sod-method sod:sod-slot + sod:static-instance character-scanner charbuf-scanner-place condition-with-location diff --git a/doc/meta.tex b/doc/meta.tex index dc06abf..f341414 100644 --- a/doc/meta.tex +++ b/doc/meta.tex @@ -294,6 +294,29 @@ {check-method-argument-lists @ @} \end{describe} +\begin{describe}{cls} + {static-instance () + \&key :name :location :externp :constp :class :initializers} +\end{describe} + +\begin{describe*} + {\dhead{gf}{static-instance-name @ @> @} + \dhead{gf}{static-instance-extern-p @ + @> @} + \dhead{gf}{static-instance-const-p @ + @> @} + \dhead{gf}{static-instance-class @ @> @} + \dhead{gf}{static-instance-initializers @ @> @} + \dhead{gf} + {setf (static-instance-initializers @) @}} +\end{describe*} + +\begin{describe}{gf} + {make-static-instance @ @ @ + @ @ \&key + \nlret @} +\end{describe} + %%%-------------------------------------------------------------------------- \section{Class finalization protocol} \label{sec:meta.finalization} diff --git a/doc/output.tex b/doc/output.tex index 22d8552..1615119 100644 --- a/doc/output.tex +++ b/doc/output.tex @@ -414,6 +414,18 @@ The following notes may be helpful. % (:classes :end) \\ \hlx{v/} % + (:static-instances :start) & static-instance, :h + & \begin{nprog} \banner{Public static instances} \\ \end{nprog} + \\*\hlx{v} + :static-instances & static-instance, :h + & \begin{nprog} + extern $[@"const"]$ struct @{}__ilayout + @{}__instance; \\ + \#define @ (\&@{}__instance.@.@) + \end{nprog} \\* + (:static-instances :end) & static-instance, :h + & \\ \hlx{v/} + % (:user :start) \\* :user \\* (:user :end) \\ \hlx{v/} @@ -464,6 +476,39 @@ The following notes may be helpful. :early \\* (:early-user :end) \\ \hlx{v/} % + (:static-instances :start) & static-instance, :c + & \begin{nprog} \banner{Static instance definitions} \\ \end{nprog} + \\*\hlx{v} + (:static-instances :decls) & static-instance, :c + & \begin{nprog} + /* Forward declarations. */ \\+ + static $[@"const"]$ struct @{}__ilayout + @{}__instance; \\ + \#define @ (\&@{}__instance.@.@) + \end{nprog} \\* + (:static-instances :gap) & static-instance, :c + & \\ + (@ :start) & sod-class, 'static-instance + & \begin{nprog} + /* Static instance `@'. */ \\ + $[@"static"]$ $[@"const"]$ struct @{}__ilayout + @{}__instance = \{ + \end{nprog} \\*\hlx{v} + (@ :chain @ :start) & ichain, 'static-instance + & \quad \{ \{ /* @ ichain */ \\* + (@ :vtable @) & vtable-pointer, 'static-instance + & \slotlabel{3}{_vt} \&@{}__vtable_@.@, \\* + (@ :slots @ :start) & islots, 'static-instance + & \quad\quad \{ /* Class @ */ \\* + (@ :slots @) & effective-slot, 'static-instance + & \slotlabel{4}{@} @, \\* + (@ :slots @ :end) & islots, 'static-instance + & \quad\quad \}, \\* + (@ :chain @ :end) & ichain, 'static-instance + & \quad \} \}, \\* + (@ :end) & sod-class, 'static-instance + & \begin{nprog} \}; \\ \end{nprog} \\ \hlx{v/} + % (:classes :start) \\*\hlx{v} % (@ :banner) & sod-class, :c @@ -686,6 +731,17 @@ The following notes may be helpful. \>@ @ @}} \end{describe*} +\begin{describe}{var}{*static-instance*} +\end{describe} + +\begin{describe}{gf}{declare-static-instance @ @} +\end{describe} + +\begin{describe}{gf} + {output-static-instance-initializer @ @ + @} +\end{describe} + %%%----- That's all, folks -------------------------------------------------- %%% Local variables: diff --git a/doc/syntax.tex b/doc/syntax.tex index 72329a4..6c05acc 100644 --- a/doc/syntax.tex +++ b/doc/syntax.tex @@ -710,6 +710,27 @@ preprocessor directives in order to declare types and functions for use elsewhere in the generated output files. +\subsection{Static instance definitions} \label{sec:syntax.module.instance} + +\begin{grammar} + ::= + "instance" + @[":" $[\mbox{@}]$@] ";" + + ::= "." "=" +\end{grammar} + +Properties: +\begin{description} +\item[@"extern"] A boolean flag: if true, then the instance is public, and + will be declared in the output header file; if false (the default), then + the instance is only available to code defined within the module. +\item[@"const"] A boolean flag: if true (the default), then the instance is + read-only, and may end up in write-protected storage at run-time; if false, + then the instance will be writable. +\end{description} + + \subsection{Class definitions} \label{sec:syntax.module.class} \begin{grammar} diff --git a/src/class-make-impl.lisp b/src/class-make-impl.lisp index 02fd5f5..b3347bd 100644 --- a/src/class-make-impl.lisp +++ b/src/class-make-impl.lisp @@ -347,4 +347,65 @@ (check-method-return-type-against-message type msgtype) (check-method-argument-lists type msgtype))) +;;;-------------------------------------------------------------------------- +;;; Static instances. + +(defmethod shared-initialize :after + ((instance static-instance) slot-names &key pset) + "Initialize a static instance." + (default-slot-from-property (instance 'externp slot-names) + (pset :extern :boolean) + nil) + (default-slot-from-property (instance 'constp slot-names) + (pset :const :boolean) + t)) + +(defmethod make-static-instance ((class sod-class) name initializers + pset location &key) + + ;; Check that the initializers are all for distinct slots. + (find-duplicates (lambda (initializer previous) + (let ((slot (sod-initializer-slot initializer))) + (cerror*-with-location initializer + "Duplicate initializer for ~ + instance slot `~A' in ~ + static instance `~A'" + slot name) + (info-with-location previous + "Previous definition was here"))) + initializers + :key #'sod-initializer-slot) + + ;; Ensure that every slot will have an initializer, either defined directly + ;; on the instance or as part of some class definition. + (let ((have (make-hash-table))) + + ;; First, populate the hash table with all of the slots for which we have + ;; initializers. + (flet ((seen-slot-initializer (init) + (setf (gethash (sod-initializer-slot init) have) t))) + (mapc #'seen-slot-initializer + initializers) + (dolist (super (sod-class-precedence-list class)) + (mapc #'seen-slot-initializer + (sod-class-instance-initializers super)))) + + ;; Now go through all of the slots and check that they have initializers. + (dolist (super (sod-class-precedence-list class)) + (dolist (slot (sod-class-slots super)) + (unless (gethash slot have) + (cerror*-with-location location + "No initializer for instance slot `~A', ~ + required by static instance `~A'" + slot name) + (info-with-location slot "Slot `~A' defined here" slot))))) + + ;; Make the instance. + (make-instance 'static-instance + :class class + :name name + :initializers initializers + :location (file-location location) + :pset pset)) + ;;;----- That's all, folks -------------------------------------------------- diff --git a/src/class-make-proto.lisp b/src/class-make-proto.lisp index 09b9f98..a978ca3 100644 --- a/src/class-make-proto.lisp +++ b/src/class-make-proto.lisp @@ -272,4 +272,16 @@ This is separated out of `shared-initialize', where it's called, so that it can be overridden conveniently by subclasses.")) +;;;-------------------------------------------------------------------------- +;;; Static instances. + +(export 'make-static-instance) +(defgeneric make-static-instance (class name initializers pset location &key) + (:documentation + "Construct a new static instance of the given CLASS. + + This is the main constructor functoin for static instances. This is a + generic function so that the CLASS can construct static instances in a + special way.")) + ;;;----- That's all, folks -------------------------------------------------- diff --git a/src/class-output.lisp b/src/class-output.lisp index 45a4909..0dfd30a 100644 --- a/src/class-output.lisp +++ b/src/class-output.lisp @@ -539,6 +539,41 @@ (sod-class-nickname target-head))))))) ;;;-------------------------------------------------------------------------- +;;; Static instance declarations. + +(export 'declare-static-instance) +(defgeneric declare-static-instance (instance stream) + (:documentation + "Write a declaration for the static INSTANCE to STREAM. + + Note that, according to whether the instance is external or private, this + may be written as part of the `:h' or `:c' reasons.")) +(defmethod declare-static-instance (instance stream) + (with-slots ((class %class) name externp constp) instance + (format stream "~:[static~;extern~] ~:[~;const ~]struct ~ + ~A ~A__instance;~%~ + #define ~A (&~A__instance.~A.~A)~%" + externp constp (ilayout-struct-tag class) name + name name (sod-class-nickname (sod-class-chain-head class)) + (sod-class-nickname class)))) + +(defmethod hook-output + ((instance static-instance) (reason (eql :h)) sequencer) + "Write an `extern' declaration for an external static instance." + (with-slots (externp) instance + (when externp + (one-off-output 'static-instances-banner sequencer + '(:static-instances :start) + (lambda (stream) + (banner "Public static instances" stream))) + (one-off-output 'static-instances-end sequencer + '(:static-instances :end) + #'terpri) + (sequence-output (stream sequencer) + (:static-instances + (declare-static-instance instance stream)))))) + +;;;-------------------------------------------------------------------------- ;;; Implementation output. (export '*instance-class*) @@ -869,4 +904,134 @@ const struct ~A ~A__classobj = {~%" ((instance :object super :slots) (output-class-initializer slot instance stream)))))) +;;;-------------------------------------------------------------------------- +;;; Static instances. + +(export '*static-instance*) +(defvar-unbound *static-instance* + "The static instance currently being output. + + This is bound during the `hook-output' traversal of a static instance for + `:c', since the slots traversed need to be able to look up initializers + from the static instance definition.") + +(defmethod hook-output ((instance static-instance) + (reason (eql :c)) sequencer) + "Write a static instance definition." + (with-slots (externp) instance + (one-off-output 'static-instances-banner sequencer + '(:static-instances :start) + (lambda (stream) + (banner "Static instance definitions" stream))) + (unless externp + (one-off-output 'static-instances-forward sequencer + '(:static-instances :start) + (lambda (stream) + (format stream "/* Forward declarations. */~%"))) + (one-off-output 'static-instances-forward-gap sequencer + '(:static-instances :gap) + #'terpri) + (sequence-output (stream sequencer) + ((:static-instances :decls) + (declare-static-instance instance stream)))))) + +(defmethod hook-output ((class sod-class) + (reason (eql 'static-instance)) sequencer) + "Output the framing around a static instance initializer." + (let ((instance *static-instance*)) + (with-slots ((class %class) name externp constp) instance + (sequence-output (stream sequencer) + :constraint ((:static-instances :gap) + (*static-instance* :start) + (*static-instance* :end) + (:static-instances :end)) + ((*static-instance* :start) + (format stream "/* Static instance `~A'. */~%~ + ~:[static ~;~]~:[~;const ~]~ + struct ~A ~A__instance = {~%" + name + externp constp + (ilayout-struct-tag class) name)) + ((*static-instance* :end) + (format stream "};~2%")))))) + +(defmethod hook-output ((ichain ichain) + (reason (eql 'static-instance)) sequencer) + "Output the initializer for an ichain." + (with-slots ((class %class) chain-head chain-tail) ichain + (sequence-output (stream sequencer) + :constraint ((*static-instance* :start) + (*static-instance* :ichain chain-head :start) + (*static-instance* :ichain chain-head :end) + (*static-instance* :end)) + ((*static-instance* :ichain chain-head :start) + (format stream " { { /* ~A ichain */~%" + (sod-class-nickname chain-head))) + ((*static-instance* :ichain chain-head :end) + (format stream " } },~%"))))) + +(defmethod hook-output ((islots islots) + (reason (eql 'static-instance)) sequencer) + "Initialize a static instance's slots." + (with-slots ((class %class)) islots + (let ((chain-head (sod-class-chain-head class))) + (sequence-output (stream sequencer) + :constraint + ((*static-instance* :ichain chain-head :start) + (*static-instance* :slots class :start) + (*static-instance* :slots class) + (*static-instance* :slots class :end) + (*static-instance* :ichain chain-head :end)) + ((*static-instance* :slots class :start) + (format stream " { /* Class ~A */~%" class)) + ((*static-instance* :slots class :end) + (format stream " },~%")))))) + +(defmethod hook-output ((vtptr vtable-pointer) + (reason (eql 'static-instance)) sequencer) + "Initialize a vtable pointer in a static instance.." + (with-slots ((class %class) chain-head chain-tail) vtptr + (sequence-output (stream sequencer) + :constraint ((*static-instance* :ichain chain-head :start) + (*static-instance* :vtable chain-head) + (*static-instance* :ichain chain-head :end)) + ((*static-instance* :vtable chain-head) + (format stream " /* ~17@A = */ &~A.~A,~%" + "_vt" + (vtable-name class chain-head) + (sod-class-nickname chain-tail)))))) + +(export 'output-static-instance-initializer) +(defgeneric output-static-instance-initializer (instance slot stream) + (:documentation + "Output an initializer for an effective SLOT in a static INSTANCE.")) +(defmethod output-static-instance-initializer ((instance static-instance) + (slot effective-slot) + stream) + (let* ((direct-slot (effective-slot-direct-slot slot)) + (init (or (find direct-slot + (static-instance-initializers instance) + :key #'sod-initializer-slot) + (effective-slot-initializer slot)))) + (format stream " /* ~15@A = */ ~A,~%" + (sod-slot-name direct-slot) + (sod-initializer-value init)))) + +(defmethod hook-output ((slot effective-slot) + (reason (eql 'static-instance)) sequencer) + "Initialize a slot in a static instance." + (with-slots ((class %class) initializers) *static-instance* + (with-slots ((dslot slot)) slot + (let ((super (sod-slot-class dslot)) + (instance *static-instance*)) + (sequence-output (stream sequencer) + ((instance :slots super) + (output-static-instance-initializer instance slot stream))))))) + +(defmethod hook-output :after + ((instance static-instance) (reason (eql :c)) sequencer) + (with-slots ((class %class)) instance + (let ((*static-instance* instance)) + (hook-output class 'static-instance sequencer)))) + ;;;----- That's all, folks -------------------------------------------------- diff --git a/src/classes.lisp b/src/classes.lisp index 69df4d1..b21f3c0 100644 --- a/src/classes.lisp +++ b/src/classes.lisp @@ -497,4 +497,57 @@ (sod-method-message method) (sod-method-class method)))) +;;;-------------------------------------------------------------------------- +;;; Instances. + +(export '(static-instance static-instance-name static-instance-extern-p + static-instance-const-p static-instance-class + static-instance-initializers)) +(defclass static-instance () + ((name :initarg :name :type string :reader static-instance-name) + (location :initarg :location :initform (file-location nil) + :type file-location :reader file-location) + (externp :initarg :extern :initform nil :type t + :reader static-instance-extern-p) + (constp :initarg :const :initform t :type t + :reader static-instance-const-p) + (%class :initarg :class :type sod-class :reader static-instance-class) + (initializers :initarg :initializers :initform nil + :type list :accessor static-instance-initializers)) + (:documentation + "A static instance is a class instance built at (C) compile time. + + The slots are as follows. + + * The `name' gives the C identifier naming the instance, as a string. + + * The `externp' flag is non-nil if the instance is to be visible outside + of the translation unit. + + * The `location' states where, in the user's source, the instance was + defined. This gets used in error messages. + + * The `class' specifies the class of the instance to construct. + + * The `initializers' are a list of `sod-instance-initializer' objects + which override any existing slot initializers defined on the class.")) + +(defmethod print-object ((instance static-instance) stream) + (with-slots (name (class %class) externp constp initializers) instance + (maybe-print-unreadable-object (instance stream :type t) + (format stream "~:[~;extern ~@_~]~:[~;const ~@_~]~A ~@_~A" + externp constp class name) + (when initializers + (princ ": " stream) + (pprint-indent :block 2 stream) + (let ((first t)) + (dolist (init initializers) + (if first (setf first nil) (princ ", ")) + (pprint-newline :linear stream) + (with-slots (slot (super %class) value) init + (format stream "~@<~A.~A = ~2I~@_~A~:>" + (sod-class-nickname super) + (sod-slot-name slot) + value)))))))) + ;;;----- That's all, folks -------------------------------------------------- diff --git a/src/module-output.lisp b/src/module-output.lisp index 90ecb75..d09dfd8 100644 --- a/src/module-output.lisp +++ b/src/module-output.lisp @@ -132,6 +132,7 @@ (:includes :start) :includes :early-decls (:includes :end) (:early-user :start) :early-user (:early-user :end) (:classes :start) (:classes :end) + (:static-instances :start) :static-instances (:static-instances :end) (:user :start) :user (:user :end) (:guard :end) :epilogue) @@ -181,6 +182,9 @@ (:prologue (:includes :start) :includes (:includes :end) (:early-user :start) :early-user (:early-user :end) + (:static-instances :start) + (:static-instances :decls) (:static-instances :gap) + (:static-instances :end) (:classes :start) (:classes :end) (:user :start) :user (:user :end) :epilogue) diff --git a/src/module-parse.lisp b/src/module-parse.lisp index 8344281..eff4af7 100644 --- a/src/module-parse.lisp +++ b/src/module-parse.lisp @@ -217,6 +217,60 @@ (eval sexp))))) ;;;-------------------------------------------------------------------------- +;;; Static instances. + +(define-pluggable-parser module instance (scanner pset) + ;; `instance' id id list[slot-initializer] `;' + (with-parser-context (token-scanner-context :scanner scanner) + (let ((duff nil) + (floc nil) + (empty-pset (make-property-set))) + (parse (seq ("instance" + (class (seq ((class-name (must :id))) + (setf floc (file-location scanner)) + (restart-case (find-sod-class class-name) + (continue () + (setf duff t) + nil)))) + (name (must :id)) + (inits (? (seq (#\: + (inits (list (:min 0) + (seq ((nick (must :id)) + #\. + (name (must :id)) + (value + (parse-delimited-fragment + scanner #\= '(#\, #\;) + :keep-end t))) + (make-sod-instance-initializer + class nick name value + empty-pset + :add-to-class nil + :location scanner)) + #\,))) + inits))) + #\;) + (unless duff + (acond ((find-if (lambda (item) + (and (typep item 'static-instance) + (string= (static-instance-name item) + name))) + (module-items *module*)) + (cerror*-with-location floc + "Instance with name `~A' ~ + already defined." + name) + (info-with-location (file-location it) + "Previous definition was ~ + here.")) + (t + (add-to-module *module* + (make-static-instance class name + inits + pset + floc)))))))))) + +;;;-------------------------------------------------------------------------- ;;; Class declarations. (export 'class-item) diff --git a/test/bad.ref b/test/bad.ref index de3b354..3188354 100644 --- a/test/bad.ref +++ b/test/bad.ref @@ -29,9 +29,9 @@ * test/bad.sod:40:11: note: Previous definition was here * test/bad.sod:40:2: error: Duplicate primary direct method for message `void wrong.frob(void)' in classs `Wrong' * test/bad.sod:38:2: note: Previous definition was here -* test/bad.sod:48:29: syntax error: Expected `class', `set', `code', `typename', `import', `load', `lisp', or `demo' but found `{' -* test/bad.sod:48:49: syntax error: Expected `class', `set', `code', `typename', `import', `load', `lisp', or `demo' but found `}' -* test/bad.sod:49:0: syntax error: Expected `class', `set', `code', `typename', `import', `load', `lisp', or `demo' but found `}' +* test/bad.sod:48:29: syntax error: Expected `class', `lisp', `load', `import', `typename', `code', `set', `instance', or `demo' but found `{' +* test/bad.sod:48:49: syntax error: Expected `class', `lisp', `load', `import', `typename', `code', `set', `instance', or `demo' but found `}' +* test/bad.sod:49:0: syntax error: Expected `class', `lisp', `load', `import', `typename', `code', `set', `instance', or `demo' but found `}' * test/bad.sod:54:30: error: Type mismatch for keyword argument `x' in methods for message `void fail.badkw(?int x)' applicable to class `Arrgh' * test/bad.sod:56:2: note: Type `double' declared in primary direct method of `Arrgh' (defined here) * test/bad.sod:51:43: note: Type `int' declared in message definition in `Fail' (here) @@ -62,6 +62,12 @@ * test/bad.sod:90:0: error: Class `dismissed' is incomplete * test/bad.sod:90:0: syntax error: Expected `{' but found `;' * test/bad.sod:90:0: syntax error: Expected `}' but found `;' -* test/bad.sod:90:0: syntax error: Expected `class', `set', `code', `typename', `import', `load', `lisp', or `demo' but found `;' -* sod: Finished with 38 errors +* test/bad.sod:90:0: syntax error: Expected `class', `lisp', `load', `import', `typename', `code', `set', `instance', or `demo' but found `;' +* test/bad.sod:93:16: error: No initializer for instance slot `int st.x', required by static instance `noinit' +* test/bad.sod:92:43: note: Slot `int st.x' defined here +* test/bad.sod:93:16: error: No initializer for instance slot `int st.y', required by static instance `noinit' +* test/bad.sod:92:46: note: Slot `int st.y' defined here +* test/bad.sod:94:43: error: Duplicate initializer for instance slot `int st.x' in static instance `dupinit' +* test/bad.sod:94:33: note: Previous definition was here +* sod: Finished with 41 errors ; rc = 2 diff --git a/test/bad.sod b/test/bad.sod index 2799e0e..6451482 100644 --- a/test/bad.sod +++ b/test/bad.sod @@ -88,3 +88,7 @@ class dismissed; class hopeful: dismissed ; + +[nick = st] class Static: SodObject { int x, y; } +instance Static noinit; +instance Static dupinit: st.x = 1, st.x = 2, st.y = 3; diff --git a/test/test.sod b/test/test.sod index 72febd5..5a029cd 100644 --- a/test/test.sod +++ b/test/test.sod @@ -353,4 +353,26 @@ code c: tests { DONE(3); } +/*----- Static instances --------------------------------------------------*/ + +[link = SodObject, nick = st] +class StaticObject: SodObject { + int x, y = 2, z = 3; + [readonly = t] void step() { STEP(me->st.x); } +} + +[extern = t] instance StaticObject mystatic: st.x = 0, st.z = 69; +[const = nil] instance StaticObject otherstatic: st.x = 3, st.y = 42; + +code c: tests { + prepare("static instance"); + StaticObject_step(mystatic); + if (mystatic->st.y == 2) STEP(1); + if (mystatic->st.z == 69) STEP(2); + StaticObject_step(otherstatic); + if (otherstatic->st.y == 42) STEP(4); + if (otherstatic->st.z == 3) STEP(5); + DONE(6); +} + /*----- That's all, folks -------------------------------------------------*/