Merge branches 'mdw/doc-reorg' and 'mdw/parser-fixes'
authorMark Wooding <mdw@distorted.org.uk>
Fri, 8 Jun 2018 19:09:02 +0000 (20:09 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Fri, 8 Jun 2018 19:09:02 +0000 (20:09 +0100)
* mdw/doc-reorg: (34 commits)
  doc/refintro.tex, src/sod-module.5: Fix slightly garbled text.
  doc/syntax.tex: Delete (wrong) duplicate rule for <argument-declarator>.
  doc/syntax.tex: Consistently use baseline-level ellipses in syntax.
  doc/concepts.tex: Fix a rather distant demonstrative.
  test/: Add a simple rational-number class.
  src/method-impl.lisp: Initialize `suppliedp' flags properly.
  src/class-output.lisp: Fix missing parentheses around `me' in message macros.
  doc/concepts.tex: Fix garbled fragment ordering rules.
  doc/runtime.tex: Fix name of `SOD_XCHAIN' macro.
  doc/structures.tex, lib/sod-structs.3: Fix in-chain ichain exemplar.
  src/optparse.lisp: Indent a line correctly.
  test/test.sod: Abbreviate the T1 class nicknames.
  src/method-impl.lisp: Mark `sod__obj' as ignorable in effective methods.
  src/method-aggregate.lisp: Allow useful behaviour if no primary methods.
  doc/intro.tex: Begin a (rather extensive) comparison with C++.
  doc/Makefile.am, doc/sod.tex: Actually include the stub intro.
  doc/intro.tex: Fix erroneous `\manpage' to correct `\man'.
  doc/concepts.tex: Include diagram of standard method combination.
  doc/Makefile.am: Enable `\nonstopmode' in TeX processing.
  doc/Makefile.am: Abstract out repeated TeX arguments into a variable.
  ...

* mdw/parser-fixes: (97 commits)
  src/class-finalize.lisp: Improve reporting of CPL construction errors.
  src/class-finalize-impl.lisp: Move error reporting to `merge-class-lists'.
  src/class-finalize-impl.lisp (clos-cpl, dylan-cpl): Improve formatting.
  src/class-finalize-impl.lisp (clos-tiebreaker): Refactor.
  src/class-finalize.lisp (merge-class-lists): Zap pointless `:present' arg.
  src/module-impl.lisp (c-fragment): Fix docstring formatting.
  src/module-parse.lisp: Improve error recovery for core class items.
  src/module-parse.lisp: Abstract out `parse-maybe-dotted-name'.
  src/module-parse.lisp: Use `quote', not `list', to make constant lists.
  src/module-parse.lisp: Use `dotted-name', not `dotted-identifier'.
  src/module-parse.lisp: Catch errors during class-item construction.
  src/module-parse.lisp: Factor out slot and maybe-initializer creation.
  src/module-parse.lisp: Improve error recovery for `class' item framing.
  src/class-utilities.lisp: Permit `temporary-name' objects as class names.
  src/class-utilities.lisp: Improve reporting of multiple root classes.
  src/module-parse.lisp: Improve error recovery for `initarg' class-items.
  src/module-parse.lisp: Improve error recovery for `lisp' items.
  src/module-parse.lisp: Improve error recovery for `load' and `import' items.
  src/module-parse.lisp: Improve error recovery for `test' items.
  src/module-parse.lisp: Improve error recovery for `code' items.
  ...

27 files changed:
doc/Makefile.am
doc/SYMBOLS
doc/concepts.tex
doc/intro.tex [new file with mode: 0644]
doc/refintro.tex [new file with mode: 0644]
doc/runtime.tex
doc/sod.sty
doc/sod.tex
doc/standard-method-combination.svg [deleted file]
doc/stdmeth.tex [new file with mode: 0644]
doc/structures.tex
doc/syntax.tex
doc/tutorial.tex
lib/keyword.h
lib/sod-structs.3
src/builtin.lisp
src/class-make-impl.lisp
src/class-output.lisp
src/method-aggregate.lisp
src/method-impl.lisp
src/optparse.lisp
src/sod-module.5
test/Makefile.am
test/chimaera.sod
test/rat.ref [new file with mode: 0644]
test/rat.sod [new file with mode: 0644]
test/test.sod

index c61002d..4a31b70 100644 (file)
@@ -31,6 +31,9 @@ TEX_FILES              =
 CLEANFILES             += *.aux *.out *.log *.toc *.ind *.idx *.ilg
 EXTRA_DIST             += $(TEX_FILES)
 
+TEXFLAGS                = --interaction=nonstopmode \
+                               --output-directory=$(abs_builddir)
+
 ###--------------------------------------------------------------------------
 ### The manual.
 
@@ -40,6 +43,9 @@ TEX_FILES             += sod.tex
 ## Main document styling and definitions.
 TEX_FILES              += sod.sty
 
+## The introduction.
+TEX_FILES              += intro.tex
+
 ## Tutorial.
 TEX_FILES              += tutorial.tex
 
@@ -68,9 +74,9 @@ MAINTAINERCLEANFILES  += sod.pdf
 EXTRA_DIST             += sod.pdf
 doc_DATA               += sod.pdf
 sod.pdf: $(TEX_FILES)
-       cd $(srcdir) && pdflatex --output-directory=$(abs_builddir) sod.tex
-       cd $(srcdir) && pdflatex --output-directory=$(abs_builddir) sod.tex
+       cd $(srcdir) && pdflatex $(TEXFLAGS) sod.tex
+       cd $(srcdir) && pdflatex $(TEXFLAGS) sod.tex
        makeindex sod.idx
-       cd $(srcdir) && pdflatex --output-directory=$(abs_builddir) sod.tex
+       cd $(srcdir) && pdflatex $(TEXFLAGS) sod.tex
 
 ###----- That's all, folks --------------------------------------------------
index dcd96ec..ca7dc8f 100644 (file)
@@ -954,6 +954,7 @@ effective-method-function-name
 effective-method-keywords
   effective-method
 effective-method-live-p
+  aggregating-effective-method
   sod::lifecycle-effective-method
   simple-effective-method
 effective-method-message
index b4e80ca..9cc5be7 100644 (file)
 \chapter{Concepts} \label{ch:concepts}
 
 %%%--------------------------------------------------------------------------
-\section{Operational model} \label{sec:concepts.model}
-
-The Sod translator runs as a preprocessor, similar in nature to the
-traditional Unix \man{lex}{1} and \man{yacc}{1} tools.  The translator reads
-a \emph{module} file containing class definitions and other information, and
-writes C~source and header files.  The source files contain function
-definitions and static tables which are fed directly to a C~compiler; the
-header files contain declarations for functions and data structures, and are
-included by source files -- whether hand-written or generated by Sod -- which
-makes use of the classes defined in the module.
-
-Sod is not like \Cplusplus: it makes no attempt to `enhance' the C language
-itself.  Sod module files describe classes, messages, methods, slots, and
-other kinds of object-system things, and some of these descriptions need to
-contain C code fragments, but this code is entirely uninterpreted by the Sod
-translator.\footnote{%
-  As long as a code fragment broadly follows C's lexical rules, and properly
-  matches parentheses, brackets, and braces, the Sod translator will copy it
-  into its output unchanged.  It might, in fact, be some other kind of C-like
-  language, such as Objective~C or \Cplusplus.  Or maybe even
-  Objective~\Cplusplus, because if having an object system is good, then
-  having three must be really awesome.} %
-
-The Sod translator is not a closed system.  It is written in Common Lisp, and
-can load extension modules which add new input syntax, output formats, or
-altered behaviour.  The interface for writing such extensions is described in
-\xref{p:lisp}.  Extensions can change almost all details of the Sod object
-system, so the material in this manual must be read with this in mind: this
-manual describes the base system as provided in the distribution.
-
-%%%--------------------------------------------------------------------------
 \section{Modules} \label{sec:concepts.modules}
 
 A \emph{module} is the top-level syntactic unit of input to the Sod
@@ -245,13 +214,13 @@ qualified by the defining class's nickname.
 \subsubsection{Slot initializers}
 As well as defining slot names and types, a class can also associate an
 \emph{initial value} with each slot defined by itself or one of its
-subclasses.  A class $C$ provides an \emph{initialization function} (see
+subclasses.  A class $C$ provides an \emph{initialization message} (see
 \xref{sec:concepts.lifecycle.birth}, and \xref{sec:structures.root.sodclass})
-which sets the slots of a \emph{direct} instance of the class to the correct
-initial values.  If several of $C$'s superclasses define initializers for the
-same slot then the initializer from the most specific such class is used.  If
-none of $C$'s superclasses define an initializer for some slot then that slot
-will be left uninitialized.
+whose methods set the slots of a \emph{direct} instance of the class to the
+correct initial values.  If several of $C$'s superclasses define initializers
+for the same slot then the initializer from the most specific such class is
+used.  If none of $C$'s superclasses define an initializer for some slot then
+that slot will be left uninitialized.
 
 The initializer for a slot with scalar type may be any C expression.  The
 initializer for a slot with aggregate type must contain only constant
@@ -301,7 +270,10 @@ slots.  If you want to hide implementation details, the best approach is to
 stash them in a dynamically allocated private structure, and leave a pointer
 to it in a slot.  (This will also help preserve binary compatibility, because
 the private structure can grow more members as needed.  See
-\xref{sec:fixme.compatibility} for more details.
+\xref{sec:fixme.compatibility} for more details.)
+
+\subsubsection{Vtables}
+
 
 \subsubsection{Class objects}
 In Sod's object system, classes are objects too.  Therefore classes are
@@ -319,8 +291,8 @@ doesn't define any messages, so it doesn't have any methods.  In Sod, a class
 slot containing a function pointer is not at all the same thing as a method.)
 
 \subsubsection{Conversions}
-Suppose one has a value of type pointer to class type of some class~$C$, and
-wants to convert it to a pointer to class type of some other class~$B$.
+Suppose one has a value of type pointer-to-class-type for some class~$C$, and
+wants to convert it to a pointer-to-class-type for some other class~$B$.
 There are three main cases to distinguish.
 \begin{itemize}
 \item If $B$ is a superclass of~$C$, in the same chain, then the conversion
@@ -336,13 +308,13 @@ There are three main cases to distinguish.
   pointer.  The conversion can be performed using the appropriate generated
   upcast macro (see below); the general case is handled by the macro
   \descref{SOD_XCHAIN}{mac}.
-\item If $B$ is a subclass of~$C$ then the conversion is an \emph{upcast};
+\item If $B$ is a subclass of~$C$ then the conversion is a \emph{downcast};
   otherwise the conversion is a~\emph{cross-cast}.  In either case, the
   conversion can fail: the object in question might not be an instance of~$B$
-  at all.  The macro \descref{SOD_CONVERT}{mac} and the function
+  after all.  The macro \descref{SOD_CONVERT}{mac} and the function
   \descref{sod_convert}{fun} perform general conversions.  They return a null
   pointer if the conversion fails.  (There are therefore your analogue to the
-  \Cplusplus @|dynamic_cast<>| operator.)
+  \Cplusplus\ @|dynamic_cast<>| operator.)
 \end{itemize}
 The Sod translator generates macros for performing both in-chain and
 cross-chain upcasts.  For each class~$C$, and each proper superclass~$B$
@@ -489,8 +461,96 @@ If there are no applicable primary methods then no effective method is
 constructed: the vtables contain null pointers in place of pointers to method
 entry functions.
 
+\begin{figure}
+  \begin{tikzpicture}
+    [>=stealth, thick,
+     order/.append style={color=green!70!black},
+     code/.append style={font=\sffamily},
+     action/.append style={font=\itshape},
+     method/.append style={rectangle, draw=black, thin, fill=blue!30,
+                           text height=\ht\strutbox, text depth=\dp\strutbox,
+                           minimum width=40mm}]
+
+    \def\delgstack#1#2#3{
+      \node (#10) [method, #2] {#3};
+      \node (#11) [method, above=6mm of #10] {#3};
+      \draw [->] ($(#10.north)!.5!(#10.north west) + (0mm, 1mm)$) --
+                 ++(0mm, 4mm)
+        node [code, left=4pt, midway] {next_method};
+      \draw [<-] ($(#10.north)!.5!(#10.north east) + (0mm, 1mm)$) --
+                 ++(0mm, 4mm)
+        node [action, right=4pt, midway] {return};
+      \draw [->] ($(#11.north)!.5!(#11.north west) + (0mm, 1mm)$) --
+                 ++(0mm, 4mm)
+        node [code, left=4pt, midway] {next_method}
+        node (ld) [above] {$\smash\vdots\mathstrut$};
+      \draw [<-] ($(#11.north)!.5!(#11.north east) + (0mm, 1mm)$) --
+                 ++(0mm, 4mm)
+        node [action, right=4pt, midway] {return}
+        node (rd) [above] {$\smash\vdots\mathstrut$};
+      \draw [->] ($(ld.north) + (0mm, 1mm)$) -- ++(0mm, 4mm)
+        node [code, left=4pt, midway] {next_method};
+      \draw [<-] ($(rd.north) + (0mm, 1mm)$) -- ++(0mm, 4mm)
+        node [action, right=4pt, midway] {return};
+      \node (p) at ($(ld.north)!.5!(rd.north)$) {};
+      \node (#1n) [method, above=5mm of p] {#3};
+      \draw [->, order] ($(#10.south east) + (4mm, 1mm)$) --
+                          ($(#1n.north east) + (4mm, -1mm)$)
+        node [midway, right, align=left]
+        {Most to \\ least \\ specific};}
+
+    \delgstack{a}{}{Around method}
+    \draw [<-] ($(a0.south)!.5!(a0.south west) - (0mm, 1mm)$) --
+               ++(0mm, -4mm);
+    \draw [->] ($(a0.south)!.5!(a0.south east) - (0mm, 1mm)$) --
+               ++(0mm, -4mm)
+      node [action, right=4pt, midway] {return};
+
+    \draw [->] ($(an.north)!.6!(an.north west) + (0mm, 1mm)$) --
+               ++(-8mm, 8mm)
+      node [code, midway, left=3mm] {next_method}
+      node (b0) [method, above left = 1mm + 4mm and -6mm - 4mm] {};
+    \node (b1) [method] at ($(b0) - (2mm, 2mm)$) {};
+    \node (bn) [method] at ($(b1) - (2mm, 2mm)$) {Before method};
+    \draw [->, order] ($(bn.west) - (6mm, 0mm)$) -- ++(12mm, 12mm)
+      node [midway, above left, align=center] {Most to \\ least \\ specific};
+    \draw [->] ($(b0.north east) + (-10mm, 1mm)$) -- ++(8mm, 8mm)
+      node (p) {};
+
+    \delgstack{m}{above right=1mm and 0mm of an.west |- p}{Primary method}
+    \draw [->] ($(mn.north)!.5!(mn.north west) + (0mm, 1mm)$) -- ++(0mm, 4mm)
+      node [code, left=4pt, midway] {next_method}
+      node [above right = 0mm and -8mm]
+      {$\vcenter{\hbox{\Huge\textcolor{red}{!}}}
+        \vcenter{\hbox{\begin{tabular}[c]{l}
+                         \textsf{next_method} \\
+                         pointer is null
+                       \end{tabular}}}$};
+
+    \draw [->, color=blue, dotted]
+        ($(m0.south)!.2!(m0.south east) - (0mm, 1mm)$) --
+        ($(an.north)!.2!(an.north east) + (0mm, 1mm)$)
+      node [midway, sloped, below] {Return value};
+
+    \draw [<-] ($(an.north)!.6!(an.north east) + (0mm, 1mm)$) --
+               ++(8mm, 8mm)
+      node [action, midway, right=3mm] {return}
+      node (f0) [method, above right = 1mm and -6mm] {};
+    \node (f1) [method] at ($(f0) + (-2mm, 2mm)$) {};
+    \node (fn) [method] at ($(f1) + (-2mm, 2mm)$) {After method};
+    \draw [<-, order] ($(f0.east) + (6mm, 0mm)$) -- ++(-12mm, 12mm)
+      node [midway, above right, align=center]
+      {Least to \\ most \\ specific};
+    \draw [<-] ($(fn.north west) + (6mm, 1mm)$) -- ++(-8mm, 8mm);
+
+  \end{tikzpicture}
+
+  \caption{The standard method combination}
+  \label{fig:concepts.methods.stdmeth}
+\end{figure}
+
 The effective method for a message with standard method combination works as
-follows.
+follows (see also~\xref{fig:concepts.methods.stdmeth}).
 \begin{enumerate}
 
 \item If any applicable methods have the @|around| role, then the most
@@ -616,6 +676,36 @@ There is also a @|custom| aggregating method combination, which is described
 in \xref{sec:fixme.custom-aggregating-method-combination}.
 
 
+\subsection{Sending messages in C} \label{sec:concepts.methods.c}
+
+Each instance is associated with its direct class [FIXME]
+
+The effective methods for each class are determined at translation time, by
+the Sod translator.  For each effective method, one or more \emph{method
+entry functions} are constructed.  A method entry function has three
+responsibilities.
+\begin{itemize}
+\item It converts the receiver pointer to the correct type.  Method entry
+  functions can perform these conversions extremely efficiently: there are
+  separate method entries for each chain of each class which can receive a
+  message, so method entry functions are in the privileged situation of
+  knowing the \emph{exact} class of the receiving object.
+\item If the message accepts a variable-length argument tail, then two method
+  entry functions are created for each chain of each class: one receives a
+  variable-length argument tail, as intended, and captures it in a @|va_list|
+  object; the other accepts an argument of type @|va_list| in place of the
+  variable-length tail and arranges for it to be passed along to the direct
+  methods.
+\item It invokes the effective method with the appropriate arguments.  There
+  might or might not be an actual function corresponding to the effective
+  method itself: the translator may instead open-code the effective method's
+  behaviour into each method entry function; and the machinery for handling
+  `delegation chains', such as is used for @|around| methods and primary
+  methods in the standard method combination, is necessarily scattered among
+  a number of small functions.
+\end{itemize}
+
+
 \subsection{Messages with keyword arguments}
 \label{sec:concepts.methods.keywords}
 
@@ -739,7 +829,11 @@ environment in which it operates.
 
 Details of initialization are necessarily class-specific, but typically it
 involves setting the instance's slots to appropriate values, and possibly
-linking it into some larger data structure to keep track of it.
+linking it into some larger data structure to keep track of it.  It is
+possible for initialization methods to attempt to allocate resources, but
+this must be done carefully: there is currently no way to report an error
+from object initialization, so the object must be marked as incompletely
+initialized, and left in a state where it will be safe to tear down later.
 
 Initialization is performed by sending the imprinted instance an @|init|
 message, defined by the @|SodObject| class.  This message uses a nonstandard
@@ -763,7 +857,7 @@ be executed to set up a new instance.  Each superclass's initialization
 fragments are executed with @|me| bound to an instance pointer of the
 appropriate superclass type, immediately after that superclass's slots (if
 any) have been initialized; therefore, fragments defined by a more specific
-superclass are executed after fragments defined by a more specific
+superclass are executed after fragments defined by a less specific
 superclass.  A class may define more than one initialization fragment: the
 fragments are executed in the order in which they appear in the class
 definition.  It is possible for an initialization fragment to use @|return|
@@ -838,9 +932,9 @@ allocated from the standard @|malloc| heap is done using the
 \descref{sod_destroy}[function]{fun}.
 
 \subsubsection{Teardown}
-Details of initialization are necessarily class-specific, but typically it
-involves setting the instance's slots to appropriate values, and possibly
-linking it into some larger data structure to keep track of it.
+Details of teardown are necessarily class-specific, but typically it
+involves releasing resources held by the instance, and disentangling it from
+any data structures it might be linked into.
 
 Teardown is performed by sending the instance the @|teardown| message,
 defined by the @|SodObject| class.  The message returns an integer, used as a
@@ -854,7 +948,7 @@ This simple protocol can be used, for example, to implement a reference
 counting system, as follows.
 \begin{prog}
   [nick = ref]                                                  \\
-  class ReferenceCountedObject \{                               \\ \ind
+  class ReferenceCountedObject: SodObject \{                    \\ \ind
     unsigned nref = 1;                                          \\-
     void inc() \{ me@->ref.nref++; \}                           \\-
     [role = around]                                             \\
@@ -866,18 +960,18 @@ counting system, as follows.
   \}
 \end{prog}
 
-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 execute the superclass's teardown fragments, and
-to return zero.  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 @|teardown| 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 execute the superclass's teardown
+fragments, and to return zero.  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.
 
 A class can define \emph{teardown fragments}: pieces of literal code to be
 executed to shut down an instance.  Each superclass's teardown fragments are
 executed with @|me| bound to an instance pointer of the appropriate
 superclass type; fragments defined by a more specific superclass are executed
-before fragments defined by a more specific superclass.  A class may define
+before fragments defined by a less specific superclass.  A class may define
 more than one teardown fragment: the fragments are executed in the order in
 which they appear in the class definition.  It is possible for an
 initialization fragment to use @|return| or @|goto| for special control-flow
@@ -898,6 +992,22 @@ determined using the \descref{SOD_INSTBASE}[macro]{mac}.
 %%%--------------------------------------------------------------------------
 \section{Metaclasses} \label{sec:concepts.metaclasses}
 
+%%%--------------------------------------------------------------------------
+\section{Compatibility considerations} \label{sec:concepts.compatibility}
+
+Sod doesn't make source-level compatibility especially difficult.  As long as
+classes, slots, and messages don't change names or dissappear, and slots and
+messages retain their approximate types, everything will be fine.
+
+Binary compatibility is much more difficult.  Unfortunately, Sod classes have
+rather fragile binary interfaces.\footnote{%
+  Research suggestion: investigate alternative instance and vtable layouts
+  which improve binary compatibility, probably at the expense of instance
+  compactness, and efficiency of slot access and message sending.  There may
+  be interesting trade-offs to be made.} %
+
+If instances are allocated [FIXME]
+
 %%%----- That's all, folks --------------------------------------------------
 
 %%% Local variables:
diff --git a/doc/intro.tex b/doc/intro.tex
new file mode 100644 (file)
index 0000000..f4b3168
--- /dev/null
@@ -0,0 +1,262 @@
+%%% -*-latex-*-
+%%%
+%%% Introduction to Sod and its object system
+%%%
+%%% (c) 2015 Straylight/Edgeware
+%%%
+
+%%%----- Licensing notice ---------------------------------------------------
+%%%
+%%% This file is part of the Sensible Object Design, an object system for C.
+%%%
+%%% SOD is free software; you can redistribute it and/or modify
+%%% it under the terms of the GNU General Public License as published by
+%%% the Free Software Foundation; either version 2 of the License, or
+%%% (at your option) any later version.
+%%%
+%%% SOD is distributed in the hope that it will be useful,
+%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+%%% GNU General Public License for more details.
+%%%
+%%% You should have received a copy of the GNU General Public License
+%%% along with SOD; if not, write to the Free Software Foundation,
+%%% Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+\chapter{Introduction} \label{ch:intro}
+
+Sod is an object system for the C programming language.
+
+The software distribution for Sod contains two main parts:
+\begin{itemize}
+\item a translator, or preprocessor, similar in spirit to \man{lex}{1} or
+  \man{yacc}{1}, which reads input files containing class definitions, and
+  writes C source code and header files; and
+\item a very small runtime library, containing the built-in base classes and
+  some simple utility macros and functions for working with instances and
+  classes.
+\end{itemize}
+
+%%%--------------------------------------------------------------------------
+\section{About Sod's object system} \label{ch:intro.about}
+
+Sod implements a fairly sophisticated object system, with multiple
+inheritance, but only single dispatch.
+
+\subsection{Ideology}
+
+Object systems tend to come with ideology attached, so Sod is no exception;
+but Sod's ideology is different from that of most object systems.
+\begin{itemize}
+\item Sod provides an object system, not a module system.  Sod provides no
+  facilities for `information hiding'; there is no equivalent to the
+  @|private| or @|protected| annotations in Java or \Cplusplus.  The author
+  takes the view (a) that such facilities are propertly part of a module
+  system, and that trying to abuse classes so that they become modules is a
+  mistake; and (b) that much useful functionality is unnecessarily hidden
+  away behind abstract interfaces, and a gentle-ish nudge towards greater
+  openness is called for.
+\item Sod's objective is to provide an effective tool for the expert
+  programmer, in the classic `make easy things simple and, difficult things
+  possible' mould.  It isn't intended to be useful in an environment
+  containing unassisted novice programmers.  Sod tries to avoid placing
+  technically unnecessary restrictions on programmers, and is likely to
+  evolve in the direction of eliminating existing restrictions rather than
+  growing new `safety' features.
+\end{itemize}
+
+\subsection{Comparison with other object systems}
+
+Sod's object system is significantly different in flavour\footnote{%
+  The pun was unintentional, but I'm happy with it.} %
+from most popular object-ish languages.  Indeed, it bears far more similarity
+to Flavors, CLOS, and Dylan than to \Cplusplus, \Csharp, or Java (and still
+less to Go or Rust).
+
+Of the popular languages, \Cplusplus's object system is probably closest to
+Sod.  Both are statically compiled, statically typed, implement single
+dispatch, and have relatively simple runtime metaprogramming facilities.
+\Cplusplus\ has a rich compile-time template metalanguage; Sod instead allows
+compile-time metaprogramming in Common Lisp, which is probably less
+convenient for simple cases but rather more pleasant for doing difficult
+things.  Significantly, Sod has the @|SodObject| class, of which all other
+classes\footnote{%
+  Unless you construct a new root class of your own, which you can totally
+  do, but it's hard work.} %
+are subclasses; \Cplusplus\ has no such root class.
+
+Both systems provide multiple inheritance, but go about it very differently.
+The most important difference is that \Cplusplus\ provides only \emph{static
+  delegation}: if you have a class @|B| which defines some (virtual) member
+function @|f|, and a derived class of @|D| which wants to \emph{extend} the
+behaviour of @|f| on instances of @|D|, then you must explicitly call @|B::f|
+at the appropriate point:
+\begin{prog}
+  \#include <iostream>                                          \\+
+                                                                %
+  class B \{                                                    \\
+  public:                                                       \\ \ind
+    virtual void f() \{ std::cout <{}< "B@\\n"; \}              \\
+    virtual @~B() \{ \}                                       \-\\
+  \};                                                           \\+
+                                                                %
+  class D: public B \{                                          \\
+  public:                                                       \\ \ind
+    void f() \{ B::f(); std::cout <{}< "D too@\\n"; \}        \-\\
+  \};
+\end{prog}
+
+This works adequately when only single inheritance is involved.  But if we
+now introduce multiple inheritance, we see the problem.
+\begin{prog}
+  \#include <iostream>                                          \\+
+                                                                %
+  class B \{                                                    \\
+  public:                                                       \\ \ind
+    virtual void f() \{ std::cout <{}< "B@\\n"; \}              \\
+    virtual @~B() \{ \}                                       \-\\
+  \};                                                           \\+
+                                                                %
+  class X: virtual public B \{                                  \\
+  public:                                                       \\ \ind
+    void f() \{ B::f(); std::cout <{}< "X after@\\n"; \}      \-\\
+  \};                                                           \\+
+                                                                %
+  class Y: virtual public B \{                                  \\
+  public:                                                       \\ \ind
+    void f() \{ std::cout <{}< "Y before@\\n"; B::f(); \}     \-\\
+  \};                                                           \\+
+                                                                %
+  class D: public X, public Y \{                                \\
+  public:                                                       \\ \ind
+    void f() \{ X::f(); Y::f(); \} // \comment{oh, dear}      \-\\
+  \};
+\end{prog}
+The above prints
+\begin{prog}
+  B                                                             \\
+  X after                                                       \\
+  Y before                                                      \\
+  B
+\end{prog}
+which is unlikely to be what was wanted: `B' prints twice, and the `before'
+and `after' actions are both in the middle.\footnote{%
+  Of course, one could have arranged to call @|Y::f| before @|X::f| -- but
+  the important point is that one would have needed to \emph{know} that this
+  was necessary.} %
+The problem is that correctly composing behaviour from a collection of
+superclasses requires knowledge of all of the superclasses involved and how
+they're supposed to work together.
+
+The obvious workaround is to separate the functionality -- here, printing the
+messages -- from the plumbing, which arranges to do everything in the right
+order.  You'd end up with a @|_f| member function in each class which wanted
+print something, and then every class would have a virtual @|f| which calls
+the various @|_f| functions in the right order, like this:
+\begin{prog}
+  \#include <iostream>                                          \\+
+                                                                %
+  class B \{                                                    \\
+  protected:                                                    \\ \ind
+    void _f() \{ std::cout <{}< "B@\\n"; \}                   \-\\
+  public:                                                       \\ \ind
+    virtual void f() \{ _f(); \}                                \\
+    virtual ~B() \{ \}                                        \-\\
+  \};                                                           \\+
+                                                                %
+  class X: virtual public B \{                                  \\
+  protected:                                                    \\ \ind
+    void _f() \{ std::cout <{}< "X after@\\n"; \}             \-\\
+  public:                                                       \\ \ind
+    void f() \{ B::_f(); _f(); \}                             \-\\
+  \};                                                           \\+
+                                                                %
+  class Y: virtual public B \{                                  \\
+  protected:                                                    \\ \ind
+    void _f() \{ std::cout <{}< "Y before@\\n"; \}            \-\\
+  public:                                                       \\ \ind
+    void f() \{ _f(); B::_f(); \}                             \-\\
+  \};                                                           \\+
+                                                                %
+  class D: public X, public Y \{                                \\
+  public:                                                       \\ \ind
+    void f() \{ Y::_f(); B::_f(); X::_f(); \}                 \-\\
+  \};
+\end{prog}
+This is clearly much more cumbersome.  Most disastrously, it spreads
+knowledge about how the various classes' contributions to the behaviour of
+@|f| fit together throughout the class graph.  Also, even this approach is
+only suitable for especially simple cases.  Suppose @|Y| needed to add
+behaviour before \emph{and} after @|B| -- maybe @|Y| is taking out a lock,
+and then releasing it.  Then this approach won't work any more; indeed, it's
+hard to see any way to make this work without spreading knowledge about
+@|Y|'s lock everywhere.
+
+Compare Sod's approach.
+\begin{prog}
+  code c: includes \{                                           \\
+  \#include <stdio.h>                                           \\-
+  \#include <sod.h>                                             \\
+  \#include "foo.h"                                             \\
+  \}                                                            \\+
+                                                                %
+  class B: SodObject \{                                         \\ \ind
+    void f() \{ puts("B"); \}                                 \-\\
+  \}                                                            \\+
+                                                                %
+  class X: B \{                                                 \\ \ind
+    void b.f() \{ CALL_NEXT_METHOD; puts("X after"); \}       \-\\
+  \}                                                            \\
+                                                                %
+  class Y: B \{                                                 \\ \ind
+    void b.f() \{ puts("Y before"); CALL_NEXT_METHOD; \}      \-\\
+  \}                                                            \\+
+                                                                %
+  class D: X, Y \{ \}
+\end{prog}
+This prints
+\begin{prog}
+  Y before                                                      \\
+  B                                                             \\
+  X after
+\end{prog}
+as (I think) you'd hope.  @|CALL_NEXT_METHOD| here does the job of figuring
+out what to do next, according to some rather complicated rules
+(described in full in \xref{sec:concepts.methods.combination}).
+
+Indeed, there's an even better way to write this particular case with Sod,
+because Sod has dedicated \emph{method rôles}.
+\begin{prog}
+  code c: includes \{                                           \\
+  \#include <stdio.h>                                           \\-
+  \#include <sod.h>                                             \\
+  \#include "foo.h"                                             \\
+  \}                                                            \\+
+                                                                %
+  class B: SodObject \{                                         \\ \ind
+    void f() \{ puts("B"); \}                                 \-\\
+  \}                                                            \\+
+                                                                %
+  class X: B \{                                                 \\ \ind
+    [role = after] void b.f() \{ puts("X after"); \}          \-\\
+  \}                                                            \\
+                                                                %
+  class Y: B \{                                                 \\ \ind
+    [role = before] void b.f() \{ puts("Y before"); \}        \-\\
+  \}                                                            \\+
+                                                                %
+  class D: X, Y \{ \}
+\end{prog}
+
+%%%--------------------------------------------------------------------------
+\section{About this manual}
+
+This manual intends to provide complete documentation about Sod.
+
+%%%----- That's all, folks --------------------------------------------------
+
+%%% Local variables:
+%%% mode: LaTeX
+%%% TeX-master: "sod.tex"
+%%% TeX-PDF-mode: t
+%%% End:
diff --git a/doc/refintro.tex b/doc/refintro.tex
new file mode 100644 (file)
index 0000000..2d4dbed
--- /dev/null
@@ -0,0 +1,137 @@
+%%% -*-latex-*-
+%%%
+%%% Introduction to the reference section
+%%%
+%%% (c) 2016 Straylight/Edgeware
+%%%
+
+%%%----- Licensing notice ---------------------------------------------------
+%%%
+%%% This file is part of the Sensible Object Design, an object system for C.
+%%%
+%%% SOD is free software; you can redistribute it and/or modify
+%%% it under the terms of the GNU General Public License as published by
+%%% the Free Software Foundation; either version 2 of the License, or
+%%% (at your option) any later version.
+%%%
+%%% SOD is distributed in the hope that it will be useful,
+%%% but WITHOUT ANY WARRANTY; without even the implied warranty of
+%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+%%% GNU General Public License for more details.
+%%%
+%%% You should have received a copy of the GNU General Public License
+%%% along with SOD; if not, write to the Free Software Foundation,
+%%% Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+\chapter{Introduction} \label{ch:refintro}
+
+This part describes Sod in detail, from the perspective of a developer using
+the system to write their own programs.  This task is complicated by the fact
+that Sod is intrinsically open-ended and flexible: it allows programmers to
+extend and alter its behaviour arbitrarily.  As a result, pretty much every
+statement made in this part must be hedged around with disclaimers that it
+might not be true if Sod has been extended in a particular way.  Rather than
+mention this repeatedly, this part will describe Sod as it is provided,
+rather than as it might be when modified.
+
+\Xref{p:lisp} describes Sod's internal API and protocols.  A reader
+interested in understanding the design space of object systems covered by Sod
+will have to read that in order to grasp fully what the system is (and isn't)
+capable of.
+
+The following chapters in this part will describe the Sod object model, the
+syntax read by the translator, and how the two
+
+\begin{itemize}
+
+\item The remainder of this chapter describes some notational conventions
+  which will be used throughout the present part, and describes various
+  aspects of the \emph{module files} which the Sod translator reads.
+
+\item \Xref{ch:class} describes \emph{classes}, which are the primary
+  concepts of interest in Sod.
+
+\end{itemize}
+
+%%%--------------------------------------------------------------------------
+\section{Operational model} \label{sec:refintro.model}
+
+The Sod translator runs as a preprocessor, similar in nature to the
+traditional Unix \man{lex}{1} and \man{yacc}{1} tools.  The translator reads
+a \emph{module} file containing class definitions and other information, and
+writes C~source and header files.  The source files contain function
+definitions and static tables which are fed directly to a C~compiler; the
+header files contain declarations for functions and data structures, and are
+included by source files -- whether hand-written or generated by Sod -- which
+makes use of the classes defined in the module.
+
+Sod is not like \Cplusplus: it makes no attempt to `enhance' the C language
+itself.  Sod module files describe classes, messages, methods, slots, and
+other kinds of object-system things, and some of these descriptions need to
+contain C code fragments, but this code is entirely uninterpreted by the Sod
+translator.\footnote{%
+  As long as a code fragment broadly follows C's lexical rules, and properly
+  matches parentheses, brackets, and braces, the Sod translator will copy it
+  into its output unchanged.  It might, in fact, be some other kind of C-like
+  language, such as Objective~C or \Cplusplus.  Or maybe even
+  Objective~\Cplusplus, because if having an object system is good, then
+  having three must be really awesome.} %
+
+The Sod translator is not a closed system.  It is written in Common Lisp, and
+can load extension modules which add new input syntax, output formats, or
+altered behaviour.  The interface for writing such extensions is described in
+\xref{p:lisp}.  Extensions can change almost all details of the Sod object
+system, so the material in this manual must be read with this in mind: this
+manual describes the base system as provided in the distribution.
+
+%%%--------------------------------------------------------------------------
+\section{Syntax notation} \label{sec:refintro.synnote}
+
+Fortunately, Sod is syntactically quite simple.  The notation is slightly
+unusual in order to make the presentation shorter and easier to read.
+
+Anywhere a simple nonterminal name $x$ may appear in the grammar, an
+\emph{indexed} nonterminal $x[a_1, \ldots, a_n]$ may also appear.  On the
+left-hand side of a production rule, the indices $a_1$, \ldots, $a_n$ are
+variables which vary over all nonterminal and terminal symbols, and the
+variables may also appear on the right-hand side in place of a nonterminal.
+Such a rule stands for a family of rules, in which each variable is replaced
+by each possible simple nonterminal or terminal symbol.
+
+The letter $\epsilon$ denotes the empty nonterminal
+\begin{quote}
+  \syntax{$\epsilon$ ::=}
+\end{quote}
+
+The following indexed productions are used throughout the grammar, some often
+enough that they deserve special notation.
+\begin{itemize}
+\item @[$x$@] abbreviates @<optional>$[x]$, denoting an optional occurrence
+  of $x$:
+  \begin{quote}
+    \syntax{@[$x$@] ::= <optional>$[x]$ ::= $\epsilon$ @! $x$}
+  \end{quote}
+\item $x^*$ abbreviates @<zero-or-more>$[x]$, denoting a sequence of zero or
+  more occurrences of $x$:
+  \begin{quote}
+    \syntax{$x^*$ ::= <zero-or-more>$[x]$ ::=
+      $\epsilon$ @! <zero-or-more>$[x]$ $x$}
+  \end{quote}
+\item $x^+$ abbreviates @<one-or-more>$[x]$, denoting a sequence of one or
+  more occurrences of $x$:
+  \begin{quote}
+    \syntax{$x^+$ ::= <one-or-more>$[x]$ ::= <zero-or-more>$[x]$ $x$}
+  \end{quote}
+\item @<list>$[x]$ denotes a sequence of one or more occurrences of $x$
+  separated by commas:
+  \begin{quote}
+    \syntax{<list>$[x]$ ::= $x$ @! <list>$[x]$ "," $x$}
+  \end{quote}
+\end{itemize}
+
+%%%--------------------------------------------------------------------------
+
+
+%% properties
+
+%%%----- That's all, folks --------------------------------------------------
index a4a15ed..2e04639 100644 (file)
@@ -688,7 +688,7 @@ some (static) type into instance pointers of other static types to the same
 instance.
 
 \begin{describe}[SOD_XCHAIN]{mac}
-    {void *SOD_CHAIN(@<chead>, const @<cls> *@<obj>);}
+    {void *SOD_XCHAIN(@<chead>, const @<cls> *@<obj>);}
   Performs a `cross-chain upcast'.
 
   Given a pointer @<obj> to an instance of a class of type @<cls> and the
index d77c038..2cdb499 100644 (file)
 \def\ind{\quad\=\+\kill}
 \def\@progcr{\futurelet\@tempa\@progcr@i}
 {\def\:{\gdef\@progcr@sp}\: {\@progcr}}
+\atdef~{\textasciitilde}
 \def\@progcr@i{%
   \ifx\@tempa\@sptoken\let\next@\@progcr@sp\else
   \if1\ifx\@tempa[1\else
index 51fa401..b3147bc 100644 (file)
@@ -36,6 +36,8 @@
    totoc=true, font=small]
   {idxlayout}
 \usepackage{tikz}
+\usetikzlibrary{calc}
+\usetikzlibrary{positioning}
 \usepackage{syntax}
 \usepackage{sverb}
 \usepackage{mdwtab}
@@ -63,6 +65,8 @@
 
 \mainmatter
 
+\include{intro}
+
 %%%--------------------------------------------------------------------------
 \part{Tutorial} \label{p:tut}
 
@@ -71,6 +75,7 @@
 %%%--------------------------------------------------------------------------
 \part{Reference} \label{p:ref}
 
+\include{refintro}
 \include{concepts}
 \include{cmdline}
 \include{syntax}
diff --git a/doc/standard-method-combination.svg b/doc/standard-method-combination.svg
deleted file mode 100644 (file)
index f2ca2f3..0000000
+++ /dev/null
@@ -1,604 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created with Inkscape (http://www.inkscape.org/) -->
-<svg
-   xmlns:dc="http://purl.org/dc/elements/1.1/"
-   xmlns:cc="http://creativecommons.org/ns#"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:xlink="http://www.w3.org/1999/xlink"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   width="389.75183"
-   height="344.37515"
-   id="svg2"
-   sodipodi:version="0.32"
-   inkscape:version="0.46"
-   sodipodi:docname="standard-method-combination.svg"
-   inkscape:output_extension="org.inkscape.output.svg.inkscape"
-   version="1.0">
-  <defs
-     id="defs4">
-    <marker
-       inkscape:stockid="Arrow1Mend"
-       orient="auto"
-       refY="0.0"
-       refX="0.0"
-       id="Arrow1Mend"
-       style="overflow:visible;">
-      <path
-         id="path3268"
-         d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
-         style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;"
-         transform="scale(0.4) rotate(180) translate(10,0)" />
-    </marker>
-    <inkscape:perspective
-       sodipodi:type="inkscape:persp3d"
-       inkscape:vp_x="0 : 526.18109 : 1"
-       inkscape:vp_y="0 : 1000 : 0"
-       inkscape:vp_z="744.09448 : 526.18109 : 1"
-       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
-       id="perspective108" />
-    <marker
-       inkscape:stockid="Arrow2Mend"
-       orient="auto"
-       refY="0"
-       refX="0"
-       id="Arrow2Mend"
-       style="overflow:visible">
-      <path
-         id="path3204"
-         style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
-         d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z"
-         transform="scale(-0.6,-0.6)" />
-    </marker>
-    <radialGradient
-       xlink:href="#linearGradient3074"
-       r="21.214399"
-       inkscape:collect="always"
-       id="radialGradient3078"
-       fy="158.17307"
-       fx="61.08794"
-       cy="158.17307"
-       cx="61.08794"
-       gradientTransform="scale(1.2180558,0.8209804)"
-       gradientUnits="userSpaceOnUse" />
-    <linearGradient
-       id="linearGradient3074">
-      <stop
-         style="stop-color:#ffffff;stop-opacity:0.53370786;"
-         offset="0.0000000"
-         id="stop3075" />
-      <stop
-         style="stop-color:#000000;stop-opacity:0.69101125;"
-         offset="1.0000000"
-         id="stop3076" />
-    </linearGradient>
-  </defs>
-  <sodipodi:namedview
-     id="base"
-     pagecolor="#ffffff"
-     bordercolor="#666666"
-     borderopacity="1.0"
-     gridtolerance="10000"
-     guidetolerance="10"
-     objecttolerance="10"
-     inkscape:pageopacity="0.0"
-     inkscape:pageshadow="2"
-     inkscape:zoom="2.268243"
-     inkscape:cx="194.87592"
-     inkscape:cy="172.21547"
-     inkscape:document-units="px"
-     inkscape:current-layer="layer1"
-     showgrid="false"
-     inkscape:window-width="1337"
-     inkscape:window-height="998"
-     inkscape:window-x="225"
-     inkscape:window-y="17"
-     showborder="false" />
-  <metadata
-     id="metadata7">
-    <rdf:RDF>
-      <cc:Work
-         rdf:about="">
-        <dc:format>image/svg+xml</dc:format>
-        <dc:type
-           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
-        <cc:license
-           rdf:resource="http://creativecommons.org/licenses/by-sa/3.0/" />
-        <dc:title>SOD standard method combination diagram</dc:title>
-        <dc:date>2009-09-18</dc:date>
-        <dc:creator>
-          <cc:Agent>
-            <dc:title>Mark Wooding</dc:title>
-          </cc:Agent>
-        </dc:creator>
-        <dc:description>A diagram showing how the applicable methods are invoked by standard method combination in the SOD object system.</dc:description>
-        <dc:rights>
-          <cc:Agent>
-            <dc:title>Straylight/Edgeware</dc:title>
-          </cc:Agent>
-        </dc:rights>
-        <dc:publisher>
-          <cc:Agent>
-            <dc:title>Straylight/Edgeware</dc:title>
-          </cc:Agent>
-        </dc:publisher>
-        <dc:language>en-GB</dc:language>
-      </cc:Work>
-      <cc:License
-         rdf:about="http://creativecommons.org/licenses/by-sa/3.0/">
-        <cc:permits
-           rdf:resource="http://creativecommons.org/ns#Reproduction" />
-        <cc:permits
-           rdf:resource="http://creativecommons.org/ns#Distribution" />
-        <cc:requires
-           rdf:resource="http://creativecommons.org/ns#Notice" />
-        <cc:requires
-           rdf:resource="http://creativecommons.org/ns#Attribution" />
-        <cc:permits
-           rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
-        <cc:requires
-           rdf:resource="http://creativecommons.org/ns#ShareAlike" />
-      </cc:License>
-    </rdf:RDF>
-  </metadata>
-  <g
-     inkscape:label="Layer 1"
-     inkscape:groupmode="layer"
-     id="layer1"
-     transform="translate(-76.574432,-549.18106)">
-    <g
-       id="g3106">
-      <g
-         transform="translate(-6.4194226,7.8915857)"
-         id="g2941">
-        <use
-           transform="translate(-87.171262,-145.57702)"
-           x="0"
-           y="0"
-           xlink:href="#rect2383"
-           id="use8070"
-           width="744.09448"
-           height="1052.3622" />
-        <use
-           height="1052.3622"
-           width="744.09448"
-           id="use8068"
-           xlink:href="#rect2383"
-           y="0"
-           x="0"
-           transform="translate(-91.171262,-141.57702)" />
-        <use
-           transform="translate(-95.171262,-137.57702)"
-           x="0"
-           y="0"
-           xlink:href="#rect2383"
-           id="use8057"
-           width="744.09448"
-           height="1052.3622" />
-      </g>
-      <text
-         id="text7219"
-         y="743.74951"
-         x="137.82718"
-         style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:URW Palladio L;-inkscape-font-specification:URW Palladio L"
-         xml:space="preserve"><tspan
-           id="tspan7221"
-           y="743.74951"
-           x="137.82718"
-           sodipodi:role="line">Before method</tspan></text>
-      <path
-         sodipodi:nodetypes="cc"
-         id="path7232"
-         d="M 96.33489,740.26133 L 127.09404,709.94688"
-         style="fill:none;fill-rule:evenodd;stroke:#00c800;stroke-width:0.75000000000000000;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
-      <flowRoot
-         transform="translate(-301.49963,-67.218524)"
-         style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#00c800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:URW Palladio L;-inkscape-font-specification:URW Palladio L"
-         id="flowRoot7234"
-         xml:space="preserve"><flowRegion
-           id="flowRegion7236"><rect
-             style="text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#00c800;fill-opacity:1"
-             y="756.86218"
-             x="377"
-             height="38.5"
-             width="35.5"
-             id="rect7238" /></flowRegion><flowPara
-           id="flowPara7240">Most to least specific</flowPara></flowRoot>      <path
-         sodipodi:nodetypes="cc"
-         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75000000000000000;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-         d="M 233.72077,768.23762 L 215.68955,750.20639"
-         id="path7292" />
-      <text
-         xml:space="preserve"
-         style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:URW Palladio L;-inkscape-font-specification:URW Palladio L"
-         x="149.36943"
-         y="762.65088"
-         id="text7294"><tspan
-           sodipodi:role="line"
-           id="tspan7296"
-           x="149.36943"
-           y="762.65088"
-           style="font-style:italic">call-next-method</tspan></text>
-      <path
-         id="path7370"
-         d="M 215.3571,720.94472 L 233.38832,702.91349"
-         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75000000000000000;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-         sodipodi:nodetypes="cc" />
-      <use
-         height="1052.3622"
-         width="744.09448"
-         transform="matrix(1,0,0,-1,193.60423,1471.9955)"
-         id="use2946"
-         xlink:href="#g2941"
-         y="0"
-         x="0" />
-      <text
-         xml:space="preserve"
-         style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:URW Palladio L;-inkscape-font-specification:URW Palladio L"
-         x="334.1524"
-         y="735.396"
-         id="text7428"><tspan
-           sodipodi:role="line"
-           x="334.1524"
-           y="735.396"
-           id="tspan7430">After method</tspan></text>
-      <path
-         style="fill:none;fill-rule:evenodd;stroke:#00c800;stroke-width:0.75000000000000000;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-         d="M 414.991,709.26598 L 445.75015,739.58043"
-         id="path7432"
-         sodipodi:nodetypes="cc" />
-      <flowRoot
-         xml:space="preserve"
-         id="flowRoot7434"
-         style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#00c800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:URW Palladio L;-inkscape-font-specification:URW Palladio L"
-         transform="translate(54.25206,-67.572077)"><flowRegion
-           id="flowRegion7436"><rect
-             id="rect7438"
-             width="35.5"
-             height="38.5"
-             x="377"
-             y="756.86218"
-             style="text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#00c800;fill-opacity:1" /></flowRegion><flowPara
-           id="flowPara7440">Least to most specific</flowPara></flowRoot>      <path
-         id="path7442"
-         d="M 309.99443,702.58108 L 328.02565,720.61231"
-         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75000000000000000;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-         sodipodi:nodetypes="cc" />
-      <text
-         id="text7444"
-         y="715.43781"
-         x="326.31656"
-         style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:URW Palladio L;-inkscape-font-specification:URW Palladio L"
-         xml:space="preserve"><tspan
-           style="font-style:italic"
-           y="715.43781"
-           x="326.31656"
-           id="tspan7446"
-           sodipodi:role="line">return</tspan></text>
-      <path
-         sodipodi:nodetypes="cc"
-         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75000000000000000;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-         d="M 328.3581,749.87398 L 310.32688,767.90521"
-         id="path7448" />
-      <path
-         id="path7460"
-         d="M 286.62089,703.05143 L 286.62089,767.7517"
-         style="fill:none;fill-rule:evenodd;stroke:#0000c8;stroke-width:0.75000000000000000;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:0.75000000000000000, 0.75000000000000000;stroke-dashoffset:0;stroke-opacity:1" />
-      <text
-         transform="matrix(0,1,-1,0,0,0)"
-         id="text7983"
-         y="-289.09686"
-         x="705.11279"
-         style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#0000c8;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:URW Palladio L;-inkscape-font-specification:URW Palladio L"
-         xml:space="preserve"><tspan
-           y="-289.09686"
-           x="705.11279"
-           id="tspan7985"
-           sodipodi:role="line">Return value</tspan></text>
-    </g>
-    <g
-       id="g3071">
-      <g
-         id="g2966">
-        <rect
-           y="861.61884"
-           x="211.62221"
-           height="16.482248"
-           width="120.76241"
-           id="rect2383"
-           style="font-size:10px;fill:#c8c8ff;fill-opacity:1;stroke:#000000;stroke-width:0.75;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
-        <rect
-           style="font-size:10px;fill:#c8c8ff;fill-opacity:1;stroke:#000000;stroke-width:0.75;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-           id="rect2883"
-           width="120.76241"
-           height="16.482248"
-           x="211.62221"
-           y="828.91174" />
-        <rect
-           style="font-size:10px;fill:#c8c8ff;fill-opacity:1;stroke:#000000;stroke-width:0.75;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-           id="rect2875"
-           width="120.76241"
-           height="16.482248"
-           x="211.62221"
-           y="770.448" />
-        <path
-           id="path4477"
-           d="M 243.59829,860.1812 L 243.59829,847.80683"
-           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75000000000000000;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
-        <path
-           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75000000000000000;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-           d="M 295.09829,847.18855 L 295.09829,859.56292"
-           id="path5000" />
-        <text
-           xml:space="preserve"
-           style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;line-height:125%;writing-mode:lr-tb;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:URW Palladio L;-inkscape-font-specification:URW Palladio L"
-           x="239.44922"
-           y="856.36218"
-           id="text2952"
-           sodipodi:linespacing="125%"><tspan
-             sodipodi:role="line"
-             id="tspan2954"
-             x="239.44922"
-             y="856.36218"
-             style="font-style:italic;text-align:end;line-height:125%;writing-mode:lr-tb;text-anchor:end">call-next-method</tspan></text>
-        <text
-           id="text5030"
-           y="855.92719"
-           x="299.5"
-           style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:URW Palladio L;-inkscape-font-specification:URW Palladio L"
-           xml:space="preserve"><tspan
-             style="font-style:italic"
-             y="855.92719"
-             x="299.5"
-             id="tspan5032"
-             sodipodi:role="line">return</tspan></text>
-        <path
-           id="path5048"
-           d="M 295.09829,814.18855 L 295.09829,826.56292"
-           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75000000000000000;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
-        <use
-           x="0"
-           y="0"
-           xlink:href="#text5030"
-           id="use2960"
-           transform="translate(0,-33)"
-           width="744.09448"
-           height="1052.3622" />
-        <path
-           id="path5060"
-           d="M 243.59829,801.6812 L 243.59829,789.30683"
-           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75000000000000000;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
-        <path
-           id="path5046"
-           d="M 243.59829,827.1812 L 243.59829,814.80683"
-           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75000000000000000;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
-        <path
-           style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75000000000000000;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-           d="M 295.09829,788.68855 L 295.09829,801.06292"
-           id="path5062" />
-        <text
-           id="text5072"
-           y="808.65448"
-           x="263"
-           style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:URW Palladio L;-inkscape-font-specification:URW Palladio L"
-           xml:space="preserve"><tspan
-             y="808.65448"
-             x="263"
-             id="tspan5074"
-             sodipodi:role="line">. . .</tspan></text>
-        <use
-           x="0"
-           y="0"
-           xlink:href="#text2952"
-           id="use2956"
-           transform="translate(0,-33)"
-           width="744.09448"
-           height="1052.3622" />
-        <use
-           x="0"
-           y="0"
-           xlink:href="#text2952"
-           id="use2958"
-           transform="translate(0,-58.5)"
-           width="744.09448"
-           height="1052.3622" />
-        <use
-           x="0"
-           y="0"
-           xlink:href="#text5030"
-           id="use2962"
-           transform="translate(0,-58.5)"
-           width="744.09448"
-           height="1052.3622" />
-        <flowRoot
-           xml:space="preserve"
-           id="flowRoot5638"
-           style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#00c800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:URW Palladio L;-inkscape-font-specification:URW Palladio L"
-           transform="translate(-34.5,48.169125)"><flowRegion
-             id="flowRegion5640"><rect
-               id="rect5642"
-               width="35.5"
-               height="38.5"
-               x="377"
-               y="756.86218"
-               style="text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#00c800;fill-opacity:1" /></flowRegion><flowPara
-             id="flowPara5644">Most to least specific</flowPara></flowRoot>        <path
-           id="path3347"
-           d="M 338,876.33367 L 338,772.83367"
-           style="fill:none;fill-rule:evenodd;stroke:#00c800;stroke-width:0.75000000000000000;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
-      </g>
-      <path
-         id="path3341"
-         d="M 243.59829,892.6812 L 243.59829,880.30683"
-         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75000000000000000;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
-      <path
-         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75000000000000000;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
-         d="M 295.09829,880.18855 L 295.09829,892.56292"
-         id="path3335" />
-      <use
-         height="1052.3622"
-         width="744.09448"
-         transform="translate(0,33)"
-         id="use2964"
-         xlink:href="#text5030"
-         y="0"
-         x="0" />
-      <g
-         transform="translate(35.976561,0)"
-         id="g2994">
-        <text
-           sodipodi:linespacing="125%"
-           id="text3155"
-           y="873.42499"
-           x="236.11349"
-           style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:URW Palladio L;-inkscape-font-specification:URW Palladio L"
-           xml:space="preserve"><tspan
-             id="tspan3159"
-             y="873.42499"
-             x="236.11349"
-             sodipodi:role="line">Around method</tspan></text>
-        <use
-           x="0"
-           y="0"
-           xlink:href="#text3155"
-           id="use2986"
-           transform="translate(-2.5939942e-6,-32.70712)"
-           width="744.09448"
-           height="1052.3622" />
-        <use
-           x="0"
-           y="0"
-           xlink:href="#text3155"
-           id="use2988"
-           transform="translate(-2.5939942e-6,-91.170866)"
-           width="744.09448"
-           height="1052.3622" />
-      </g>
-    </g>
-    <g
-       id="g3041">
-      <use
-         height="1052.3622"
-         width="744.09448"
-         transform="translate(0,-269.42743)"
-         id="use3038"
-         xlink:href="#text2952"
-         y="0"
-         x="0" />
-      <flowRoot
-         transform="translate(-24.870058,-7.68156)"
-         style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:URW Palladio L;-inkscape-font-specification:URW Palladio L"
-         id="flowRoot7999"
-         xml:space="preserve"><flowRegion
-           id="flowRegion8001"><rect
-             y="558.09454"
-             x="287.08536"
-             height="24.395184"
-             width="79.903069"
-             id="rect8003" /></flowRegion><flowPara
-           id="flowPara8005">‘No next method’ error</flowPara></flowRoot>      <use
-         height="1052.3622"
-         width="744.09448"
-         transform="translate(-7.6293945e-6,-178.00001)"
-         id="use2990"
-         xlink:href="#g2966"
-         y="0"
-         x="0" />
-      <path
-         id="path7372"
-         d="M 244.26849,590.75383 L 244.26849,578.37946"
-         style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.75000000000000000;stroke-linecap:butt;stroke-linejoin:miter;marker-end:url(#Arrow1Mend);stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
-      <g
-         id="g3138">
-        <path
-           d="M 252.33396,551.87647 L 253.31263,549.30103 L 253.7247,551.92798 L 255.37298,549.97064 L 255.11544,551.97949 L 258.92709,550.3312 L 256.14561,552.80363 L 259.18463,554.91549 L 255.88807,553.98833 L 258.56653,558.62413 L 255.37298,554.81247 L 255.78505,560.58146 L 254.3428,555.58511 L 251.71585,558.26357 L 253.41564,554.70946 L 250.53115,556.25472 L 252.33396,554.45191 L 248.93438,555.37907 L 250.73718,553.7823 L 248.11023,553.16419 L 251.25227,552.54608 L 250.78869,550.12517 L 252.33396,551.87647 z"
-           id="path3079"
-           sodipodi:nodetypes="ccccccccccccccccccccccc"
-           style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.19195631pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
-        <path
-           d="M 252.53999,552.6491 L 251.35529,551.41289 L 252.07641,553.00966 L 249.55248,553.2157 L 251.92189,553.67928 L 250.68567,554.55493 L 253.10659,553.98833 L 252.64301,554.76097 L 254.08526,554.03984 L 253.51866,555.63662 L 254.49733,554.86398 L 255.16695,556.61528 L 254.85789,554.24588 L 255.99109,554.76097 L 255.01242,553.57626 L 256.6607,553.67928 L 255.37298,553.11268 L 256.24863,552.13401 L 254.54884,552.39156 L 254.65186,551.41289 L 253.57017,552.90665 L 253.1581,550.94931 L 252.53999,552.6491 z"
-           id="path3080"
-           sodipodi:nodetypes="ccccccccccccccccccccccc"
-           style="fill:#ff3f00;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.19195631pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
-        <path
-           style="fill:#a6a667;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.23994538;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1"
-           sodipodi:nodetypes="ccccccccccccccc"
-           id="path1817"
-           d="M 247.30717,549.89628 C 246.00963,549.94176 244.84256,550.91505 244.19739,551.52591 C 243.54502,552.14928 243.51447,553.31251 243.61252,554.07733 C 243.71058,554.84216 243.96644,555.43302 243.96644,555.43302 L 245.06419,554.95313 C 245.06419,554.95313 244.87482,554.509 244.80025,553.92736 C 244.72626,553.35025 244.78543,552.72675 245.16617,552.28974 C 245.60405,551.74993 246.88452,550.98903 248.22897,551.20098 C 249.13851,551.42743 249.67447,552.72927 250.43297,553.23152 C 251.19147,553.73377 252.21663,553.97614 253.54026,553.71141 C 254.12914,553.53696 254.09465,552.46369 253.30631,552.53568 C 252.21323,552.7543 251.61772,552.57935 251.09882,552.23575 C 250.57991,551.89215 250.13911,551.30485 249.60516,550.66411 L 249.59316,550.65811 C 249.11476,550.16521 248.19393,549.88725 247.30717,549.89628 z" />
-        <path
-           style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:0.19195631pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-           sodipodi:nodetypes="cc"
-           id="path2440"
-           d="M 253.49996,552.61443 C 253.49996,552.61443 252.20973,553.87567 251.25293,553.62922" />
-        <path
-           style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:0.19195631pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-           sodipodi:nodetypes="cc"
-           id="path2441"
-           d="M 251.10796,552.23751 C 250.84702,552.54195 249.60028,552.13603 249.0494,551.73012" />
-        <path
-           style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:0.19195631pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-           sodipodi:nodetypes="cc"
-           id="path2442"
-           d="M 247.81716,549.9035 C 247.87515,550.09197 247.1503,551.23722 246.51243,551.39669" />
-        <path
-           style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:0.19195631pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-           sodipodi:nodetypes="cc"
-           id="path2443"
-           d="M 245.2367,550.70084 C 245.2367,550.70084 245.57013,551.62864 245.12073,552.33899" />
-        <path
-           style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#000000;stroke-width:0.19195631pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-           sodipodi:nodetypes="cc"
-           id="path2444"
-           d="M 243.55506,553.2523 C 243.96097,553.2378 244.88878,554.13661 244.93227,554.52803" />
-        <path
-           d="M 242.68783,554.71626 C 242.57768,555.20411 242.65793,556.90337 241.20017,558.32955 C 237.07117,559.4961 234.0618,562.82062 234.0618,566.78418 C 234.0618,571.7145 238.68629,575.71115 244.37945,575.71115 C 250.0726,575.71115 254.6911,571.7145 254.6911,566.78418 C 254.6911,562.61923 251.37869,559.14526 246.92287,558.15833 C 246.14765,557.08259 245.53252,555.5894 245.72314,554.65131 C 245.3779,554.17559 243.72357,553.79879 242.68783,554.71626 z"
-           id="path1193"
-           sodipodi:nodetypes="cccccccc"
-           style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
-        <path
-           d="M 103.57781,124.91055 A 30.456171,20.527729 0 1 1 42.665472,124.91055 A 30.456171,20.527729 0 1 1 103.57781,124.91055 z"
-           id="path2452"
-           sodipodi:cx="73.121643"
-           sodipodi:cy="124.91055"
-           sodipodi:rx="30.456171"
-           sodipodi:ry="20.527729"
-           sodipodi:type="arc"
-           style="fill:url(#radialGradient3078);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
-           transform="matrix(0.2562315,0,0,0.2197998,225.48526,537.77762)" />
-      </g>
-      <g
-         id="g3028"
-         transform="translate(35.941561,-179.31502)">
-        <text
-           xml:space="preserve"
-           style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;line-height:125%;writing-mode:lr-tb;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:URW Palladio L;-inkscape-font-specification:URW Palladio L"
-           x="236.11349"
-           y="873.42499"
-           id="text3030"
-           sodipodi:linespacing="125%"><tspan
-             sodipodi:role="line"
-             x="236.11349"
-             y="873.42499"
-             id="tspan3032">Primary method</tspan></text>
-        <use
-           height="1052.3622"
-           width="744.09448"
-           transform="translate(-2.5939942e-6,-32.70712)"
-           id="use3034"
-           xlink:href="#text3030"
-           y="0"
-           x="0" />
-        <use
-           height="1052.3622"
-           width="744.09448"
-           transform="translate(-2.5939942e-6,-91.170866)"
-           id="use3036"
-           xlink:href="#text3030"
-           y="0"
-           x="0" />
-      </g>
-    </g>
-  </g>
-</svg>
diff --git a/doc/stdmeth.tex b/doc/stdmeth.tex
new file mode 100644 (file)
index 0000000..03c3734
--- /dev/null
@@ -0,0 +1,96 @@
+%%% -*- mode: latex; TeX-PDF-mode: t -*-
+
+\documentclass{article}
+\usepackage[palatino, helvetica, courier, maths=cmr]{mdwfonts}
+
+\usepackage{syntax}
+\usepackage{tikz}
+\usetikzlibrary{calc}
+\usetikzlibrary{positioning}
+
+\errorcontextlines=999
+
+\begin{document}
+
+\begin{tikzpicture}
+  [>=stealth, thick,
+   order/.append style={color=green!70!black},
+   code/.append style={font=\sffamily},
+   action/.append style={font=\itshape},
+   method/.append style={rectangle, draw=black, thin, fill=blue!30,
+                         text height=\ht\strutbox, text depth=\dp\strutbox,
+                         minimum width=40mm}]
+
+  \def\delgstack#1#2#3{
+    \node (#10) [method, #2] {#3};
+    \node (#11) [method, above=6mm of #10] {#3};
+    \draw [->] ($(#10.north)!.5!(#10.north west) + (0mm, 1mm)$) --
+               ++(0mm, 4mm)
+      node [code, left=4pt, midway] {next_method};
+    \draw [<-] ($(#10.north)!.5!(#10.north east) + (0mm, 1mm)$) --
+               ++(0mm, 4mm)
+      node [action, right=4pt, midway] {return};
+    \draw [->] ($(#11.north)!.5!(#11.north west) + (0mm, 1mm)$) --
+               ++(0mm, 4mm)
+      node [code, left=4pt, midway] {next_method}
+      node (ld) [above] {$\smash\vdots\mathstrut$};
+    \draw [<-] ($(#11.north)!.5!(#11.north east) + (0mm, 1mm)$) --
+               ++(0mm, 4mm)
+      node [action, right=4pt, midway] {return}
+      node (rd) [above] {$\smash\vdots\mathstrut$};
+    \draw [->] ($(ld.north) + (0mm, 1mm)$) -- ++(0mm, 4mm)
+      node [code, left=4pt, midway] {next_method};
+    \draw [<-] ($(rd.north) + (0mm, 1mm)$) -- ++(0mm, 4mm)
+      node [action, right=4pt, midway] {return};
+    \node (p) at ($(ld.north)!.5!(rd.north)$) {};
+    \node (#1n) [method, above=5mm of p] {#3};
+    \draw [->, order] ($(#10.south east) + (4mm, 1mm)$) --
+                        ($(#1n.north east) + (4mm, -1mm)$)
+      node [midway, right, align=left] {Most to \\ least \\ specific};}
+
+  \delgstack{a}{}{Around method}
+  \draw [<-] ($(a0.south)!.5!(a0.south west) - (0mm, 1mm)$) --
+             ++(0mm, -4mm);
+  \draw [->] ($(a0.south)!.5!(a0.south east) - (0mm, 1mm)$) --
+             ++(0mm, -4mm)
+    node [action, right=4pt, midway] {return};
+
+  \draw [->] ($(an.north)!.6!(an.north west) + (0mm, 1mm)$) --
+             ++(-8mm, 8mm)
+    node [code, midway, left=3mm] {next_method}
+    node (b0) [method, above left = 1mm + 4mm and -6mm - 4mm] {};
+  \node (b1) [method] at ($(b0) - (2mm, 2mm)$) {};
+  \node (bn) [method] at ($(b1) - (2mm, 2mm)$) {Before method};
+  \draw [->, order] ($(bn.west) - (6mm, 0mm)$) -- ++(12mm, 12mm)
+    node [midway, above left, align=center] {Most to \\ least \\ specific};
+  \draw [->] ($(b0.north east) + (-10mm, 1mm)$) -- ++(8mm, 8mm)
+    node (p) {};
+
+  \delgstack{m}{above right=1mm and 0mm of an.west |- p}{Primary method}
+  \draw [->] ($(mn.north)!.5!(mn.north west) + (0mm, 1mm)$) -- ++(0mm, 4mm)
+    node [code, left=4pt, midway] {next_method}
+    node [above right = 0mm and -8mm]
+    {$\vcenter{\hbox{\Huge\textcolor{red}{!}}}
+      \vcenter{\hbox{\begin{tabular}[c]{l}
+                       \textsf{next_method} \\
+                       pointer is null
+                     \end{tabular}}}$};
+
+  \draw [->, color=blue, dotted]
+      ($(m0.south)!.2!(m0.south east) - (0mm, 1mm)$) --
+      ($(an.north)!.2!(an.north east) + (0mm, 1mm)$)
+    node [midway, sloped, below] {Return value};
+
+  \draw [<-] ($(an.north)!.6!(an.north east) + (0mm, 1mm)$) --
+             ++(8mm, 8mm)
+    node [action, midway, right=3mm] {return}
+    node (f0) [method, above right = 1mm and -6mm] {};
+  \node (f1) [method] at ($(f0) + (-2mm, 2mm)$) {};
+  \node (fn) [method] at ($(f1) + (-2mm, 2mm)$) {After method};
+  \draw [<-, order] ($(f0.east) + (6mm, 0mm)$) -- ++(-12mm, 12mm)
+    node [midway, above right, align=center] {Least to \\ most \\ specific};
+  \draw [<-] ($(fn.north west) + (6mm, 1mm)$) -- ++(-8mm, 8mm);
+
+\end{tikzpicture}
+
+\end{document}
index 7cc825a..2dfe355 100644 (file)
@@ -201,7 +201,7 @@ recommended.
 
 \begin{describe}[SodClass]{cls}
     {[nick = cls, link = SodObject]                             \\
-     class SodClass : SodObject \{                              \\ \ind
+     class SodClass: SodObject \{                               \\ \ind
        const char *name;                                        \\
        const char *nick;                                        \\
        size_t initsz;                                           \\
@@ -363,7 +363,7 @@ type @|struct $C$__ilayout|.
           @<type>_n @<slot>_n;                                \-\\
         \} $c$;                                               \-\\
       \} $c$;                                                   \\
-      struct $H$__ichain_$h$ $h$;                               \\
+      struct $A$__ichain_$h$ $a$;                               \\
       \quad$\vdots$                                           \-\\
     \} $h$;                                                     \\
     union $B$__ichainu_$i$ $i$;                                 \\
@@ -589,7 +589,7 @@ or a standard message which takes keyword arguments, defined as
                     @<type>_n @<arg>_n?                       \+\\
                   @<type>_{n+1} @<kw>_{n+1} @[= @<dflt>_{n+1}@],
                     $\ldots$,
-                    @<type>_m @<kw>_m @[= @<dflt>_m@]);
+                    @<type>_{n'} @<kw>_{n'} @[= @<dflt>_{n'}@]);
 \end{prog}
 two entry points are defined: the usual `main' entry point which accepts a
 variable number of arguments, and a `valist' entry point which accepts an
index 35ab100..6ebdc78 100644 (file)
 \chapter{Module syntax} \label{ch:syntax}
 
 %%%--------------------------------------------------------------------------
-\section{Notation} \label{sec:syntax.notation}
-
-Fortunately, Sod is syntactically quite simple.  The notation is slightly
-unusual in order to make the presentation shorter and easier to read.
-
-Anywhere a simple nonterminal name $x$ may appear in the grammar, an
-\emph{indexed} nonterminal $x[a_1, \ldots, a_n]$ may also appear.  On the
-left-hand side of a production rule, the indices $a_1$, \ldots, $a_n$ are
-variables which vary over all nonterminal and terminal symbols, and the
-variables may also appear on the right-hand side in place of a nonterminal.
-Such a rule stands for a family of rules, in each variable is replaced by
-each possible simple nonterminal or terminal symbol.
-
-The letter $\epsilon$ denotes the empty nonterminal
-\begin{quote}
-  \syntax{$\epsilon$ ::=}
-\end{quote}
-
-The following indexed productions are used throughout the grammar, some often
-enough that they deserve special notation.
-\begin{itemize}
-\item @[$x$@] abbreviates @<optional>$[x]$, denoting an optional occurrence
-  of $x$:
-  \begin{quote}
-    \syntax{@[$x$@] ::= <optional>$[x]$ ::= $\epsilon$ @! $x$}
-  \end{quote}
-\item $x^*$ abbreviates @<zero-or-more>$[x]$, denoting a sequence of zero or
-  more occurrences of $x$:
-  \begin{quote}
-    \syntax{$x^*$ ::= <zero-or-more>$[x]$ ::=
-      $\epsilon$ @! <zero-or-more>$[x]$ $x$}
-  \end{quote}
-\item $x^+$ abbreviates @<one-or-more>$[x]$, denoting a sequence of one or
-  more occurrences of $x$:
-  \begin{quote}
-    \syntax{$x^+$ ::= <one-or-more>$[x]$ ::= <zero-or-more>$[x]$ $x$}
-  \end{quote}
-\item @<list>$[x]$ denotes a sequence of one or more occurrences of $x$
-  separated by commas:
-  \begin{quote}
-    \syntax{<list>$[x]$ ::= $x$ @! <list>$[x]$ "," $x$}
-  \end{quote}
-\end{itemize}
-
-%%%--------------------------------------------------------------------------
 \section{Lexical syntax} \label{sec:syntax.lex}
 
 Whitespace and comments are discarded.  The remaining characters are
@@ -104,7 +59,7 @@ could be a token.
 
 <digit-char> ::= "0" | <nonzero-digit-char>
 
-<nonzero-digit-char> ::= "1" | "2" $| \cdots |$ "9"
+<nonzero-digit-char> ::= "1" | "2" $| \ldots |$ "9"
 \end{grammar}
 
 The precise definition of @<alpha-char> is left to the function
@@ -157,7 +112,7 @@ discouraged.
 
 <octal-integer> ::= "0" @["o"|"O"@] @<octal-digit-char>^+
 
-<octal-digit-char> ::= "0" | "1" $| \cdots |$ "7"
+<octal-digit-char> ::= "0" | "1" $| \ldots |$ "7"
 
 <hex-integer> ::= "0" @("x"|"X"@) @<hex-digit-char>^+
 
@@ -255,6 +210,16 @@ brackets, braces or parenthesis ends the fragment.
 A @<module> is the top-level syntactic item.  A module consists of a sequence
 of definitions.
 
+[FIXME]
+Properties:
+\begin{description}
+\item[@"module_class"] A symbol naming the Lisp class to use to
+  represent the module.
+\item[@"guard"] An identifier to use as the guard symbol used to prevent
+  multiple inclusion in the header file.
+\end{description}
+
+
 \subsection{Simple definitions} \label{sec:syntax.module.simple}
 
 \subsubsection{Importing modules}
@@ -527,8 +492,6 @@ All of these have their usual C meanings.
 
 <abstract-declarator> ::= <declarator>$[\epsilon, \mbox{@<argument-list>}]$
 
-<argument-declarator> ::= <declarator>$[\mbox{@<identifier> @! $\epsilon$}]$
-
 <argument-declarator> ::=
   <declarator>$[\mbox{@<identifier> @! $\epsilon$}, \mbox{@<argument-list>}]$
 
@@ -585,11 +548,11 @@ necessary in order to resolve certain kinds of circularity.  For example,
 \begin{prog}
 class Sub;                                                      \\+
 
-class Super : SodObject \{                                      \\ \ind
+class Super: SodObject \{                                       \\ \ind
   Sub *sub;                                                   \-\\
 \};                                                             \\+
 
-class Sub : Super \{                                            \\ \ind
+class Sub: Super \{                                             \\ \ind
   /* \dots\ */                                                \-\\
 \};
 \end{prog}
@@ -638,7 +601,7 @@ properties are as follows.
   which messages it will respond to, and what its behaviour will be when it
   receives them.  The property value must be an identifier naming a defined
   subclass of @"SodClass".  The default metaclass is @"SodClass".
-  %%% FIXME xref to theory
+  See \xref{sec:concepts.metaclasses} for more details.
 \item[@"nick"] A nickname for the class, to be used to distinguish it from
   other classes in various limited contexts.  The property value must be an
   identifier; the default is constructed by forcing the class name to
@@ -665,19 +628,28 @@ It is not possible to declare a slot with function type: such an item is
 interpreted as being a @<message-item> or @<method-item>.  Pointers to
 functions are fine.
 
+Properties:
+\begin{description}
+\item[@"slot_class"] A symbol naming the Lisp class to use to represent the
+  direct slot.
+\item[@"initarg"] An identifier naming an initialization argument which can
+  be used to provide a value for the slot.  See
+  \xref{sec:concepts.lifecycle.birth} for the details.
+\end{description}
+
 An @<initializer>, if present, is treated as if a separate
 @<initializer-item> containing the slot name and initializer were present.
 For example,
 \begin{prog}
 [nick = eg]                                                     \\
-class Example : Super \{                                        \\ \ind
+class Example: Super \{                                         \\ \ind
   int foo = 17;                                               \-\\
 \};
 \end{prog}
 means the same as
 \begin{prog}
 [nick = eg]                                                     \\
-class Example : Super \{                                        \\ \ind
+class Example: Super \{                                         \\ \ind
   int foo;                                                      \\
   eg.foo = 17;                                                \-\\
 \};
@@ -700,10 +672,18 @@ The first component of the @<dotted-name> must be the nickname of one of the
 class's superclasses (including itself); the second must be the name of a
 slot defined in that superclass.
 
-An @|initarg| property may be set on an instance slot initializer (or a
-direct slot definition).  See \xref{sec:concepts.lifecycle.birth} for the
-details.  An initializer item must have either an @|initarg| property, or an
-initializer expression, or both.
+Properties:
+\begin{description}
+\item[@"initializer_class"] A symbol naming the Lisp class to use to
+  represent the initializer.
+\item[@"initarg"] An identifier naming an initialization argument which can
+  be used to provide a value for the slot.  See
+  \xref{sec:concepts.lifecycle.birth} for the details.  An initializer item
+  must have either an @|initarg| property, or an initializer expression, or
+  both.
+\item[@"initarg_class"] A symbol naming the Lisp class to use to represent
+  the initarg.  Only permitted if @"initarg" is also set.
+\end{description}
 
 Each class may define at most one initializer item with an explicit
 initializer expression for a given slot.
@@ -715,6 +695,11 @@ initializer expression for a given slot.
   @<declaration-specifier>^+
   <list>$[\mbox{@<init-declarator>}]$ ";"
 \end{grammar}
+Properties:
+\begin{description}
+\item[@"initarg_class"] A symbol naming the Lisp class to use to represent
+  the initarg.
+\end{description}
 
 \subsubsection{Fragment items}
 \begin{grammar}
@@ -730,6 +715,49 @@ initializer expression for a given slot.
   <keyword-declarator>$[\mbox{@<identifier>}]$
   @[<method-body>@]
 \end{grammar}
+Properties:
+\begin{description}
+\item[@"message_class"] A symbol naming the Lisp class to use to represent
+  the message.
+\item[@"combination"] A keyword naming the aggregating method combination to
+  use.
+\item[@"most_specific"] A keyword, either @`first' or @`last', according to
+  whether the most specific applicable method should be invoked first or
+  last.
+\end{description}
+
+Properties for the @|custom| aggregating method combination:
+\begin{description}
+\item[@"retvar"] An identifier for the return value from the effective
+  method.  The default is @|sod__ret|.  Only permitted if the message return
+  type is not @|void|.
+\item[@"valvar"] An identifier holding each return value from a direct method
+  in the effective method.  The default is @|sod__val|.  Only permitted if
+  the method return type (see @"methty" below) is not @|void|.
+\item[@"methty"] A C type, which is the return type for direct methods of
+  this message.
+\item[@"decls"] A code fragment containing declarations to be inserted at the
+  head of the effective method body.  The default is to insert nothing.
+\item[@"before"] A code fragment containing initialization to be performed at
+  the beginning of the effective method body.  The default is to insert
+  nothing.
+\item[@"empty"] A code fragment executed if there are no primary methods;
+  it should usually store a suitable (identity) value in @<retvar>.  The
+  default is not to emit an effective method at all if there are no primary
+  methods.
+\item[@"first"] A code fragment to set the return value after calling the
+  first applicable direct method.  The default is to use the @"each"
+  fragment.
+\item[@"each"] A code fragment to set the return value after calling a direct
+  method.  If @"first" is also set, then it is used after the first direct
+  method instead of this.  The default is to insert nothing, which is
+  probably not what you want.
+\item[@"after"] A code fragment inserted at the end of the effective method
+  body.  The default is to insert nothing.
+\item[@"count"] An identifier naming a variable to be declared in the
+  effective method body, of type @|size_t|, holding the number of applicable
+  methods.  The default is not to provide such a variable.
+\end{description}
 
 \subsubsection{Method items}
 \begin{grammar}
@@ -740,6 +768,14 @@ initializer expression for a given slot.
 
 <method-body> ::= "{" <c-fragment> "}" | "extern" ";"
 \end{grammar}
+Properties:
+\begin{description}
+\item[@"method_class"] A symbol naming the Lisp class to use to represent
+  the direct method.
+\item[@"role"] A keyword naming the direct method's rôle.  For the built-in
+  `simple' message classes, the acceptable rôle names are @|before|,
+  @|after|, and @|around|.  By default, a primary method is constructed.
+\end{description}
 
 %%%----- That's all, folks --------------------------------------------------
 
index ac38e06..3d90293 100644 (file)
@@ -111,16 +111,16 @@ The following is a simple Sod input file.
 \begin{prog}
   /* -*-sod-*- */                                               \\+
 
-  code c : includes \{                                          \\
+  code c: includes \{                                           \\
   \#include "greeter.h"                                         \\
   \}                                                            \\+
 
-  code h : includes \{                                          \\
+  code h: includes \{                                           \\
   \#include <stdio.h>                                           \\
   \#include <sod/sod.h>                                         \\
   \}                                                            \\+
 
-  class Greeter : SodObject \{                                  \\ \ind
+  class Greeter: SodObject \{                                   \\ \ind
     void greet(FILE *fp) \{                                     \\ \ind
       fputs("Hello, world!\textbackslash n", fp);             \-\\
     \}                                                        \-\\
@@ -175,7 +175,7 @@ approach to all of this: it expects you, the programmer, to deal with it.
 
 The basic syntax for @"code" stanzas is
 \begin{prog}
-  code @<file-label> : @<section> \{                            \\ \ind
+  code @<file-label>: @<section> \{                             \\ \ind
     @<code>                                                   \-\\
   \}
 \end{prog}
index 783f0b7..432fbd1 100644 (file)
@@ -235,7 +235,7 @@ extern kw_unkhookfn *kw_unkhook;
     set##_KWSET(KWSET__SUPPLIEDP)                                      \
     set##_KWSET(KWSET__STRUCTMEM)                                      \
   }
-#define KWSET__SUPPLIEDP(type, name, dflt) unsigned name##_suppliedp : 1;
+#define KWSET__SUPPLIEDP(type, name, dflt) unsigned name##_suppliedp: 1;
 #define KWSET__STRUCTMEM(type, name, dflt) type name;
 
 /* --- @KWSET_PARSEFN@ --- *
index 7ac5ccc..672fe59 100644 (file)
@@ -542,7 +542,7 @@ struct \fIC\fB__ilayout {
 \h'6n'} \fIc\fB;
 \h'4n'} \fIc\fB;
 \h'4n'\fR...\fB
-\h'4n'struct \fIH\fB__ichain_\fIh\fB \fIh\fB;
+\h'4n'struct \fIA\fB__ichain_\fIh\fB \fIa\fB;
 \h'2n'} \fIh\fB;
 \h'2n'union \fIB\fB__ichainu_\fIi\fB \fIi\fB;
 \h'2n'\fR...\fB
index be9a8e5..7357752 100644 (file)
@@ -279,7 +279,7 @@ static const SodClass *const ~A__cpl[] = {
 
 (definst suppliedp-struct (stream) (flags var)
   (format stream
-         "~@<struct { ~2I~_~{unsigned ~A : 1;~^ ~_~} ~I~_} ~A;~:>"
+         "~@<struct { ~2I~_~{unsigned ~A: 1;~^ ~_~} ~I~_} ~A;~:>"
          flags var))
 
 ;; Initialization.
index 78f8fed..7495c01 100644 (file)
 
 (defmethod make-sod-user-initarg
     ((class sod-class) name type pset &optional default location)
-  (declare (ignore pset))
   (with-slots (initargs) class
-    (push (make-instance 'sod-user-initarg :location (file-location location)
+    (push (make-instance (get-property pset :initarg-class :symbol
+                                      'sod-user-initarg)
+                        :location (file-location location)
                         :class class :name name :type type :default default)
          initargs)))
 
 
 (defmethod make-sod-slot-initarg-using-slot
     ((class sod-class) name (slot sod-slot) pset &optional location)
-  (declare (ignore pset))
   (with-slots (initargs) class
     (with-slots ((type %type)) slot
-      (push (make-instance 'sod-slot-initarg
+      (push (make-instance (get-property pset :initarg-class :symbol
+                                        'sod-slot-initarg)
                           :location (file-location location)
                           :class class :name name :type type :slot slot)
            initargs))))
index 2d1c222..ee77a2c 100644 (file)
             (when varargsp
               (format stream "#ifdef SOD__HAVE_VARARGS_MACROS~%"))
             (format stream "#define ~A(~{~A~^, ~}) ~
-                                  ~A->_vt->~A.~A(~{~A~^, ~})~%"
+                                  (~A)->_vt->~A.~A(~{~A~^, ~})~%"
                     (message-macro-name class entry)
                     (nreverse in-names)
                     me
                         (c-function-keywords type))))
         (when keys
           (format stream "struct ~A {~%~
-                          ~{  unsigned ~A : 1;~%~}~
+                          ~{  unsigned ~A: 1;~%~}~
                           };~2%"
                   (direct-method-suppliedp-struct-tag method)
                   (mapcar #'argument-name keys))))))))
@@ -511,7 +511,7 @@ const struct ~A ~A__classobj = {~%"
                                  class)
           (format stream "~&struct ~A {~%"
                   (effective-method-keyword-struct-tag method))
-          (format stream "~{  unsigned ~A__suppliedp : 1;~%~}"
+          (format stream "~{  unsigned ~A__suppliedp: 1;~%~}"
                   (mapcar #'argument-name keys))
           (dolist (key keys)
             (write-string "  " stream)
index eeea9df..82ff2ca 100644 (file)
 (defclass aggregating-effective-method (simple-effective-method) ()
   (:documentation "Effective method counterpart to `aggregating-message'."))
 
+(defgeneric aggregating-message-always-live-p (message combination)
+  (:documentation
+   "Return whether the method combination can work without primary methods.
+
+   Return non-nil if the corresponding effective method should be considered
+   live even if it doesn't have any methods.")
+  (:method ((message aggregating-message) (combination t)) nil))
+
+(defmethod effective-method-live-p ((method aggregating-effective-method))
+  (or (let* ((message (effective-method-message method))
+            (comb (sod-message-combination message)))
+       (aggregating-message-always-live-p message comb))
+      (call-next-method)))
+
 ;;;--------------------------------------------------------------------------
 ;;; Implementation.
 
           (methods (gensym "METHODS-")))
      &key properties return-type
          ((:around around-func) '#'funcall)
+         ((:empty empty-func) nil emptyp)
          ((:first-method first-method-func) nil firstp)
          ((:methods methods-func) '#'funcall))
   "Utility macro for definining aggregating method combinations.
    on `check-aggregating-message-type' to check the that the message's return
    type matches RETURN-TYPE.
 
+   If an EMPTY function is given, then (a) it's OK if there are no primary
+   methods, because (b) the EMPTY function is called to set the return
+   value variable in this case.  Note that EMPTY is only called when there
+   are no primary methods.
+
    The AROUND, FIRST-METHOD, and METHODS are function designators (probably
    `lambda' forms) providing pieces of the aggregating behaviour.
 
 
   (with-gensyms (type msg combvar target arg-names args want-type
                 meth targ func call-methfunc
-                aroundfunc fmethfunc methfunc)
+                aroundfunc fmethfunc methfunc bodyfunc)
     `(progn
 
        ;; If properties are listed, arrange for them to be collected.
                             ,combvar ,want-type)))
                  (call-next-method))))
 
+       ;; If there is an EMPTY function then the effective method is always
+       ;; live.
+       ,@(and emptyp
+             `((defmethod aggregating-message-always-live-p
+                   ((,msg aggregating-message)
+                    (,combvar (eql ',comb)))
+                 t)))
+
        ;; Define the main kernel-compuation method.
        (defmethod compute-aggregating-message-kernel
           ((,msg aggregating-message) (,combvar (eql ',comb))
         ;; Declare the necessary variables and give names to the functions
         ;; supplied by the caller.
         (let* (,@(and vars
-                      `((,type (c-type-subtype (sod-message-type ,msg)))))
+                      `((,type (c-type-subtype (sod-message-type ,msg)))
+                        (,(car vars) (temporary-var ,codegen ,type))))
                ,@(mapcar (lambda (var)
-                           (list var `(temporary-var ,codegen ,type)))
-                         vars)
+                           (list var `(and ,methods
+                                           (temporary-var ,codegen ,type))))
+                         (cdr vars))
                (,aroundfunc ,around-func)
                (,methfunc ,methods-func)
                (,fmethfunc ,(if firstp first-method-func methfunc)))
 
-          ;; Arrange to release the temporaries when we're finished with
-          ;; them.
-          (unwind-protect
-               (progn
-
-                 ;; Wrap the AROUND function around most of the work.
-                 (funcall ,aroundfunc
-                          (lambda (&rest ,args)
-                            (flet ((,call-methfunc (,func ,meth)
-                                     ;; Call FUNC, passing it an INVOKE
-                                     ;; function which will generate a call
-                                     ;; to METH.
-                                     (apply ,func
-                                            (lambda
-                                                (&optional (,targ :void))
-                                              (invoke-method ,codegen
-                                                             ,targ
-                                                             ,arg-names
-                                                             ,meth))
-                                            ,args)))
-
-                              ;; The first method might need special
-                              ;; handling.
-                              (,call-methfunc ,fmethfunc (car ,methods))
-
-                              ;; Call the remaining methods in the right
-                              ;; order.
-                              (dolist (,meth (cdr ,methods))
-                                (,call-methfunc ,methfunc ,meth)))))
+          (flet ((,bodyfunc ()
+                   (funcall ,aroundfunc
+                            (lambda (&rest ,args)
+                              (flet ((,call-methfunc (,func ,meth)
+                                       ;; Call FUNC, passing it an INVOKE
+                                       ;; function which will generate a
+                                       ;; call to METH.
+                                       (apply ,func
+                                              (lambda
+                                                  (&optional (,targ :void))
+                                                (invoke-method ,codegen
+                                                               ,targ
+                                                               ,arg-names
+                                                               ,meth))
+                                              ,args)))
+
+                                ;; The first method might need special
+                                ;; handling.
+                                (,call-methfunc ,fmethfunc (car ,methods))
+
+                                ;; Call the remaining methods in the right
+                                ;; order.
+                                (dolist (,meth (cdr ,methods))
+                                  (,call-methfunc ,methfunc ,meth)))))))
+
+            ;; Arrange to release the temporaries when we're finished with
+            ;; them.
+            (unwind-protect
+                 (progn
+
+                   ;; If there are no direct methods, then just do the
+                   ;; empty-effective-method thing to set the return
+                   ;; variable.  Otherwise, wrap AROUND round the main body.
+                   ,(if emptyp
+                        `(if (null ,methods)
+                             (funcall ,empty-func)
+                             (,bodyfunc))
+                        `(,bodyfunc))
 
                  ;; Outside the AROUND function now, deliver the final
                  ;; result to the right place.
                  (deliver-expr ,codegen ,target ,(car vars)))
 
-            ;; Finally, release the temporary variables.
-            ,@(mapcar (lambda (var) `(setf (var-in-use-p ,var) nil))
-                      vars))))
+              ;; Finally, release the temporary variables.
+              ,@(mapcar (lambda (var)
+                          `(when ,var (setf (var-in-use-p ,var) nil)))
+                        vars)))))
 
        ',comb)))
 
 ;;; Fixed aggregating method combinations.
 
 (define-aggregating-method-combination :progn (nil)
-  :return-type void)
+  :return-type void
+  :empty (lambda () nil))
 
 (define-aggregating-method-combination :sum ((acc val) :codegen codegen)
+  :empty (lambda () (emit-inst codegen (make-set-inst acc 0)))
   :first-method (lambda (invoke)
                  (funcall invoke val)
                  (emit-inst codegen (make-set-inst acc val)))
             (emit-inst codegen (make-update-inst acc #\+ val))))
 
 (define-aggregating-method-combination :product ((acc val) :codegen codegen)
+  :empty (lambda () (emit-inst codegen (make-set-inst acc 1)))
   :first-method (lambda (invoke)
                  (funcall invoke val)
                  (emit-inst codegen (make-set-inst acc val)))
                                              (make-set-inst acc val)))))
 
 (define-aggregating-method-combination :and ((ret) :codegen codegen)
+  :empty (lambda () (emit-inst codegen (make-set-inst ret 1)))
   :around (lambda (body)
            (codegen-push codegen)
            (funcall body)
                                              (make-break-inst)))))
 
 (define-aggregating-method-combination :or ((ret) :codegen codegen)
+  :empty (lambda () (emit-inst codegen (make-set-inst ret 0)))
   :around (lambda (body)
            (codegen-push codegen)
            (funcall body)
   '(:retvar :id
     :valvar :id
     :methty :type
+    :empty :fragment
     :decls :fragment
     :before :fragment
     :first :fragment
   (getf (sod-message-plist message) :methty
        (c-type-subtype (sod-message-type message))))
 
+(defmethod aggregating-message-always-live-p
+    ((message aggregating-message) (combination (eql :custom)))
+  (getf (sod-message-plist message) :empty))
+
 (defmethod compute-aggregating-message-kernel
     ((message aggregating-message) (combination (eql :custom))
      codegen target methods arg-names
      &key (retvar "sod_ret") (valvar "sod_val") (methty nil methtyp)
-         decls before each (first each) after count)
+         empty decls before each (first each) after count)
   (let* ((type (c-type-subtype (sod-message-type message)))
         (methty (if methtyp methty type)))
     (unless (eq type c-type-void)
       (ensure-var codegen retvar type))
-    (unless (eq methty c-type-void)
+    (unless (or (null methods)
+               (eq methty c-type-void))
       (ensure-var codegen valvar methty))
-    (when count
+    (when (and methods count)
       (ensure-var codegen count c-type-size-t (length methods)))
-    (when decls
+    (when (and methods decls)
       (emit-decl codegen decls))
     (labels ((maybe-emit (fragment)
               (when fragment (emit-inst codegen fragment)))
                              (if (eq methty c-type-void) :void valvar)
                              arg-names method)
               (maybe-emit fragment)))
-      (maybe-emit before)
-      (invoke (car methods) first)
-      (dolist (method (cdr methods)) (invoke method each))
-      (maybe-emit after)
+      (cond ((and empty (null methods))
+            (emit-inst codegen empty))
+           (t
+            (maybe-emit before)
+            (invoke (car methods) first)
+            (dolist (method (cdr methods)) (invoke method each))
+            (maybe-emit after)))
       (deliver-expr codegen target retvar))))
 
 ;;;----- That's all, folks --------------------------------------------------
index 5ea09e3..e93fb3a 100644 (file)
               (codegen-push codegen)
               (ensure-var codegen "sod__obj" ilayout-type
                           (make-convert-to-ilayout-inst class
-                                                        head "me"))))
+                                                        head "me"))
+              (deliver-call codegen :void "SOD__IGNORE" "sod__obj")))
           (finish-entry (tail)
             (let* ((head (sod-class-chain-head tail))
                    (role (if parm-n :valist nil))
                    (*keyword-struct-disposition* :local))
               (ensure-var codegen *sod-keywords* (c-type (struct tag)))
               (make-keyword-parser-function codegen method tag set keywords)
+              (emit-insts codegen
+                          (mapcar (lambda (keyword)
+                                    (make-set-inst
+                                     (format nil "~A.~A__suppliedp"
+                                             *sod-keywords*
+                                             (argument-name keyword))
+                                     0))
+                                  keywords))
               (parse-keywords (lambda ()
                                 (call :void name kw-addr ap-addr
                                       *null-pointer* 0)))
index 6460c54..367fc50 100644 (file)
@@ -85,7 +85,7 @@
                                                  collect (ext:argv i))))
                               (error "Unsupported Lisp"))))))
 
-         *program-name* (pathname-name (car *command-line*))))
+       *program-name* (pathname-name (car *command-line*))))
 
 ;;;--------------------------------------------------------------------------
 ;;; Fancy conditionals.
                          (opt-long-name o)
                          (opt-arg-optional-p o)
                          (opt-arg-name o)
-                         (opt-documentation o)))))
+                         (opt-%documentation o)))))
             (:constructor %make-option
                 (&key long-name tag negated-tag short-name
                       arg-name arg-optional-p documentation
index 4417673..8e21b5d 100644 (file)
@@ -106,7 +106,7 @@ are variables which vary over all nonterminal and terminal symbols,
 and the variables may also appear on the right-hand side
 in place of a nonterminal.
 Such a rule stands for a family of rules,
-in each variable is replaced by
+in which each variable is replaced by
 each possible simple nonterminal or terminal symbol.
 .PP
 The letter \*e denotes the empty nonterminal
index 5c4d59d..de5b634 100644 (file)
@@ -58,4 +58,13 @@ check-local:: kwtest kwtest.ref
        ./kwtest >kwtest.out
        diff -u $(srcdir)/kwtest.ref kwtest.out
 
+check_PROGRAMS         += rat
+
+EXTRA_DIST             += rat.sod rat.ref
+nodist_rat_SOURCES      = rat.c rat.h
+BUILT_SOURCES          += $(nodist_rat_SOURCES)
+check-local:: rat rat.ref
+       ./rat >rat.out
+       diff -u $(srcdir)/rat.ref rat.out
+
 ###----- That's all, folks --------------------------------------------------
index 976c727..b30248c 100644 (file)
@@ -3,34 +3,34 @@
  * A simple SOD module for testing.
  */
 
-code c : includes {
+code c: includes {
 #include <stdio.h>
 #include "chimaera.h"
 }
 
-code h : includes {
+code h: includes {
 #include "sod.h"
 }
 
 [nick = nml, link = SodObject]
-class Animal : SodObject {
+class Animal: SodObject {
   int tickles = 0;
 
   [combination = progn] void tickle();
   [role = before] void nml.tickle() { me->nml.tickles++; }
 }
 
-class Lion : Animal {
+class Lion: Animal {
   void bite() { puts("Munch!"); }
   void nml.tickle() { Lion_bite(me); }
 }
 
-class Goat : Animal {
+class Goat: Animal {
   void butt() { puts("Bonk!"); }
   void nml.tickle() { Goat_butt(me); }
 }
 
-class Serpent : Animal {
+class Serpent: Animal {
   int limit = 2;
 
   void hiss() { puts("Sssss!"); }
@@ -44,11 +44,11 @@ class Serpent : Animal {
 }
 
 [nick = sir, link = Animal]
-class Chimaera : Lion, Goat, Serpent {
+class Chimaera: Lion, Goat, Serpent {
   serpent.limit = 1;
 }
 
-code c : user {
+code c: user {
 /*----- Main driver code --------------------------------------------------*/
 
 static void tickle_animal(Animal *a)
diff --git a/test/rat.ref b/test/rat.ref
new file mode 100644 (file)
index 0000000..2f3b0f6
--- /dev/null
@@ -0,0 +1,3 @@
+0/1
+6/1
+2/3
diff --git a/test/rat.sod b/test/rat.sod
new file mode 100644 (file)
index 0000000..178e896
--- /dev/null
@@ -0,0 +1,53 @@
+/* -*-sod-*- */
+
+code c: includes {
+#include <assert.h>
+#include <stdio.h>
+
+#include "rat.h"
+}
+
+code h: includes {
+#include "sod.h"
+}
+
+typename FILE;
+
+code c: early_user {
+  static int gcd(int x, int y)
+  {
+    int t;
+    if (x < 0) x = -x;
+    if (y < 0) y = -y;
+    while (y) { t = x%y; x = y; y = t; }
+    return (x);
+  }
+}
+
+[nick = rat, link = SodObject]
+class Rational: SodObject {
+  int num, den;
+  initarg int num = 0, den = 1;
+  init {
+    int g;
+    assert(den);
+    g = gcd(num, den);
+    me->rat.num = num/g;
+    me->rat.den = den/g;
+  }
+
+  void print(FILE *fp) { fprintf(fp, "%d/%d\n", me->rat.num, me->rat.den); }
+}
+
+code c: user {
+  int main(void)
+  {
+    SOD_DECL(Rational, r0, KWARGS(K(den, 9)));
+    SOD_DECL(Rational, r1, KWARGS(K(num, 6)));
+    SOD_DECL(Rational, r2, KWARGS(K(num, 6) K(den, 9)));
+    Rational_print(r0, stdout);
+    Rational_print(r1, stdout);
+    Rational_print(r2, stdout);
+    return (0);
+  }
+}
index 776228b..5779376 100644 (file)
@@ -1,10 +1,10 @@
 /* -*-sod-*- */
 
-code h : includes {
+code h: includes {
 #include "sod.h"
 }
 
-code c : includes {
+code c: includes {
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -12,7 +12,7 @@ code c : includes {
 #include "test.h"
 }
 
-code c : early_user {
+code c: early_user {
 /*----- Preliminary definitions -------------------------------------------*/
 
 /* Confuse the fragment scanner... */
@@ -44,7 +44,7 @@ static void done(int q, const char *where) { step(q, where); }
 
 }
 
-code c : (tests head)
+code c: (tests head)
   [user (tests head) tests (tests tail) main (user end)]
 {
 /*----- Test machinery ----------------------------------------------------*/
@@ -52,12 +52,12 @@ code c : (tests head)
 static void tests(void)
 LBRACE
 }
-code c : (tests tail) {
+code c: (tests tail) {
 RBRACE
 
 }
 
-code c : main {
+code c: main {
 /*----- Main program ------------------------------------------------------*/
 
 int main(void)
@@ -70,7 +70,7 @@ int main(void)
 
 /*----- Various kinds of method combinations ------------------------------*/
 
-code h : early_user {
+code h: early_user {
 struct item {
   struct item *next;
   const char *p;
@@ -78,7 +78,7 @@ struct item {
 
 }
 
-code c : early_user {
+code c: early_user {
 static void *xmalloc(size_t n)
 {
   void *p = malloc(n);
@@ -135,49 +135,74 @@ static int check_vec(struct vec *v, ...)
 
 }
 
-[link = SodObject, nick = t1base]
-class T1Base : SodObject {
-  [combination = progn] void aprogn() { STEP(1); }
-  [combination = sum] int asum() { return 1; }
-  [combination = and] int aand() { return 8; }
-  [combination = max] int amax() { return 12; }
+[link = SodObject, nick = base]
+class T1Base: SodObject {
+  [combination = progn] void aprogn();
+  [combination = sum] int asum();
+  [combination = and] int aand();
+  [combination = max] int amax();
 
   [combination = custom,
+   empty = { sod_ret = 0; },
    decls = { struct item **head = &sod_ret; },
    each = { *head = sod_val; head = &sod_val->next; },
    after = { *head = 0; }]
-  struct item *alist() { return make_item("base"); }
+  struct item *alist();
 
   [combination = custom,
    decls = { int *v; size_t i = 0; }, methty = <int>, count = n,
+   empty = { sod_ret.v = 0; sod_ret.n = 0; },
    before = { v = xmalloc(n*sizeof(int)); },
    each = { v[i++] = sod_val; },
    after = { sod_ret.v = v; sod_ret.n = n; }]
   struct vec avec();
-  int t1base.avec() { return 19; }
 }
 
-[link = T1Base, nick = t1sub]
-class T1Sub : T1Base {
-  void t1base.aprogn() { STEP(0); }
-  int t1base.asum() { return 2; }
-  int t1base.aand() { return 6; }
-  int t1base.amax() { return 17; }
-  struct item *t1base.alist() { return make_item("sub"); }
-  int t1base.avec() { return 4; }
+[link = T1Base, nick = mid]
+class T1Mid: T1Base {
+  void base.aprogn() { STEP(1); }
+  int base.asum() { return 1; }
+  int base.aand() { return 8; }
+  int base.amax() { return 12; }
+  struct item *base.alist() { return make_item("mid"); }
+  int base.avec() { return 19; }
+}
+
+[link = T1Mid, nick = sub]
+class T1Sub: T1Mid {
+  void base.aprogn() { STEP(0); }
+  int base.asum() { return 2; }
+  int base.aand() { return 6; }
+  int base.amax() { return 17; }
+  struct item *base.alist() { return make_item("sub"); }
+  int base.avec() { return 4; }
 }
 
-code c : tests {
+code c: tests {
   prepare("aggregate, base");
   { SOD_DECL(T1Base, t1, NO_KWARGS);
     struct item *l;
     struct vec v;
+    STEP(0); T1Base_aprogn(t1); STEP(1);
+    if (T1Base_asum(t1) == 0) STEP(2);
+    if (T1Base_aand(t1) == 1) STEP(3);
+    if (!t1->_vt->base.amax) STEP(4);
+    l = T1Base_alist(t1);
+    if (!l) STEP(5);
+    v = T1Base_avec(t1);
+    if (!v.n) STEP(6);
+    DONE(7);
+  }
+  prepare("aggregate, mid");
+  { SOD_DECL(T1Mid, t1, NO_KWARGS);
+    struct item *l;
+    struct vec v;
     STEP(0); T1Base_aprogn(t1); /* 1 */
     if (T1Base_asum(t1) == 1) STEP(2);
     if (T1Base_aand(t1) == 8) STEP(3);
     if (T1Base_amax(t1) == 12) STEP(4);
     l = T1Base_alist(t1);
-    if (!check_list(l, "base", (const char *)0)) STEP(5);
+    if (!check_list(l, "mid", (const char *)0)) STEP(5);
     free_list(l);
     v = T1Base_avec(t1);
     if (!check_vec(&v, 19, -1)) STEP(6);
@@ -193,7 +218,7 @@ code c : tests {
     if (T1Base_aand(t1) == 8) STEP(3);
     if (T1Base_amax(t1) == 17) STEP(4);
     l = T1Base_alist(t1);
-    if (!check_list(l, "sub", "base", (const char *)0)) STEP(5);
+    if (!check_list(l, "sub", "mid", (const char *)0)) STEP(5);
     free_list(l);
     v = T1Base_avec(t1);
     if (!check_vec(&v, 4, 19, -1)) STEP(6);
@@ -205,14 +230,14 @@ code c : tests {
 /*----- Slot and user initargs --------------------------------------------*/
 
 [link = SodObject, nick = t2]
-class T2 : SodObject {
+class T2: SodObject {
   [initarg = x] int x = 0;
 
   initarg int y = 1;
   init { if (!y) STEP(0); }
 }
 
-code c : tests {
+code c: tests {
   prepare("initargs, defaults");
   { SOD_DECL(T2, t, NO_KWARGS);
     if (t->t2.x == 0) STEP(0);
@@ -228,24 +253,24 @@ code c : tests {
 /*----- Keyword argument propagation --------------------------------------*/
 
 [link = SodObject, nick = base]
-class T3Base : SodObject {
+class T3Base: SodObject {
   void m0(?int x) { STEP(x); }
   void m1(?) { }
 }
 
 [link = T3Base, nick = mid]
-class T3Mid : T3Base {
+class T3Mid: T3Base {
   void base.m0(?int y) { STEP(y); CALL_NEXT_METHOD; }
   void base.m1(?) { STEP(4); CALL_NEXT_METHOD; }
 }
 
 [link = T3Mid, nick = sub]
-class T3Sub : T3Mid {
+class T3Sub: T3Mid {
   void base.m0(?int z) { STEP(z); CALL_NEXT_METHOD; }
   void base.m1(?int z) { STEP(z); CALL_NEXT_METHOD; }
 }
 
-code c : tests {
+code c: tests {
   prepare("kwargs");
   { SOD_DECL(T3Sub, t, NO_KWARGS);
     T3Base_m0(t, KWARGS(K(z, 0) K(y, 1) K(x, 2)));