This is mostly clean in `--word-diff'. Here are the exceptions.
* doc/parsing.tex: `--word-diff' gets confused around the various
`condition-with-location' subclasses. This is clean in `-b', so
there's not actually anything complicated happening here.
* doc/parsing.tex: I've sneakily removed a pointless trailing `%'.
* doc/runtime.tex: I've inserted a couple of linebreaks with `%' so as
to shorten the source-file lines.
* doc/runtime.tex: Some `\-' have harmlessly moved past `@\\' macro-
backslashes to take their proper places on the right margin.
\begin{figure} \centering
\parbox{10pt}{\begin{tabbing}
- @|c-type| \\ \ind
- @|qualifiable-c-type| \\ \ind
- @|simple-c-type| \\ \ind
- @|c-class-type| \- \\
- @|tagged-c-type| \\ \ind
- @|c-struct-type| \\
- @|c-union-type| \\
- @|c-enum-type| \- \\
- @|c-atomic-type| \\
- @|c-pointer-type| \- \\
- @|c-array-type| \\
- @|c-function-type| \\ \ind
- @|c-keyword-function-type| \-
+ @|c-type| \\ \ind
+ @|qualifiable-c-type| \\ \ind
+ @|simple-c-type| \\ \ind
+ @|c-class-type| \-\\
+ @|tagged-c-type| \\ \ind
+ @|c-struct-type| \\
+ @|c-union-type| \\
+ @|c-enum-type| \-\\
+ @|c-atomic-type| \\
+ @|c-pointer-type| \-\\
+ @|c-array-type| \\
+ @|c-function-type| \\ \ind
+ @|c-keyword-function-type| \-
\end{tabbing}}
\caption{Classes representing C types}
\label{fig:codegen.c-types.classes}
\end{describe}
\begin{describe}{mac}
- {defctype \=@{ @<name> @! (@<name>^+) @} @<type-spec> \+ \\
- @[[ @|:export| @<export-flag> @]]^* \-
- \nlret @<names>}
+ {defctype \=@{ @<name> @! (@<name>^+) @} @<type-spec> \+\\
+ @[[ @|:export| @<export-flag> @]]^*
+ \-\nlret @<names>}
Defines a new symbolic type specifier @<name>; if a list of @<name>s is
given, then all are defined in the same way. The type constructed by using
any of the @<name>s is as described by the type specifier @<type-spec>.
\end{describe}
\begin{describe}{mac}
- {define-c-type-syntax @<name> @<lambda-list> \\ \ind
- @[[ @<declaration>^* @! @<doc-string> @]] \\
- @<form>^* \-
- \nlret @<name>}
+ {define-c-type-syntax @<name> @<lambda-list> \\ \ind
+ @[[ @<declaration>^* @! @<doc-string> @]] \\
+ @<form>^*
+ \-\nlret @<name>}
Defines the symbol @<name> as a new type operator. When a list of the form
@|(@<name> @<argument>^*)| is used as a type specifier, the @<argument>s
are bound to fresh variables according to @<lambda-list> (a destructuring
\end{describe}
\begin{describe}{mac}
- {define-simple-c-type \=@{ @<name> @! (@<name>^+) @} @<string> \+ \\
- @[[ @|:export| @<export-flag> @]] \-
- \nlret @<name>}
+ {define-simple-c-type
+ \=@{ @<name> @! (@<name>^+) @} @<string> \+\\
+ @[[ @|:export| @<export-flag> @]]
+ \-\nlret @<name>}
Define type specifiers for a new simple C type. Each symbol @<name> is
defined as a symbolic type specifier for the (unique interned) simple C
type whose name is the value of @<string>. Further, each @<name> is
For example,
\begin{prog}
- (c-type (fun \=(lisp (c-type-subtype other-func)) \+ \\
+ (c-type (fun \=(lisp (c-type-subtype other-func)) \+\\
("first" int) . (c-function-arguments other-func))
\end{prog}
evaluates to a function type like @|other-func|, only with an additional
argument of type @|int| added to the front of its argument list. This
could also have been written
\begin{prog}
- (let (\=(args (c-function-arguments other-func)) \+ \\
- (ret (c-type-subtype other-func))) \- \\ \ind
+ (let (\=(args (c-function-arguments other-func)) \+\\
+ (ret (c-type-subtype other-func))) \-\\ \ind
(c-type (fun \=(lisp ret) ("first" int) . args)
\end{prog}
\end{describe}
follows.
\begin{prog}
(fun \=@<return-type>
- @{ (@<arg-name> @<arg-type>) @}^* \+ \\
+ @{ (@<arg-name> @<arg-type>) @}^* \+\\
@{ \=:keys @{ (@<kw-name> @<kw-type> @[@<kw-default>@]) @}^*
- @[. @<form>@] @! \+ \\
+ @[. @<form>@] @! \+\\
. @<form> @}
\end{prog}
where either the symbol @|:keys| appears literally in the specifier, or the
\end{describe}
\begin{describe}{mac}
- {definst @<code> (@<streamvar> \&key @<export>) (@<arg>^*) \\ \ind
- @[[ @<declaration>^* @! @<doc-string> @]] \\
- @<form>^* \-
- \nlret @<code>}
+ {definst @<code> (@<streamvar> \&key @<export>) (@<arg>^*) \\ \ind
+ @[[ @<declaration>^* @! @<doc-string> @]] \\
+ @<form>^*
+ \-\nlret @<code>}
\end{describe}
\begin{describe}{mac}
{format-compound-statement
- (@<stream> @<child> \&optional @<morep>) \\ \ind
- @<declaration>^* \\
+ (@<stream> @<child> \&optional @<morep>) \\ \ind
+ @<declaration>^* \\
@<form>^*}
\end{describe}
\end{describe}
\begin{describe}{mac}
- {with-temporary-var (@<codegen> @<var> @<type>) \\ \ind
- @<declaration>^* \\
- @<form>^* \-
- \nlret @<value>^*}
+ {with-temporary-var (@<codegen> @<var> @<type>) \\ \ind
+ @<declaration>^* \\
+ @<form>^*
+ \-\nlret @<value>^*}
\end{describe}
\begin{describe}{fun}{deliver-expr @<codegen> @<target> @<expr>}
The following simple function correctly allocates and returns space for an
instance of a class given a pointer to its class object @<cls>.
\begin{prog}
- void *allocate_instance(const SodClass *cls) \\ \ind
+ void *allocate_instance(const SodClass *cls) \\ \ind
\{ return malloc(cls@->cls.initsz); \}
\end{prog}
The following simple function imprints storage at address @<p> as an instance
of a class, given a pointer to its class object @<cls>.
\begin{prog}
- void imprint_instance(const SodClass *cls, void *p) \\ \ind
+ void imprint_instance(const SodClass *cls, void *p) \\ \ind
\{ cls@->cls.imprint(p); \}
\end{prog}
This simple protocol can be used, for example, to implement a reference
counting system, as follows.
\begin{prog}
- [nick = ref] \\
- class ReferenceCountedObject \{ \\ \ind
- unsigned nref = 1; \\-
- void inc() \{ me@->ref.nref++; \} \\-
- [role = around] \\
- int obj.teardown() \\
- \{ \\ \ind
- if (--\,--me@->ref.nref) return (1); \\
- else return (CALL_NEXT_METHOD); \- \\
- \} \- \\
+ [nick = ref] \\
+ class ReferenceCountedObject \{ \\ \ind
+ unsigned nref = 1; \\-
+ void inc() \{ me@->ref.nref++; \} \\-
+ [role = around] \\
+ int obj.teardown() \\
+ \{ \\ \ind
+ if (--\,--me@->ref.nref) return (1); \\
+ else return (CALL_NEXT_METHOD); \-\\
+ \} \-\\
\}
\end{prog}
\begin{describe}{cls}
- {method-codegen (codegen) \\ \ind
+ {method-codegen (codegen) \\ \ind
\&key :vars :insts :temp-index
:message :class :method :target}
\end{describe}
\end{describe}
\begin{describe}{cls}
- {daemon-direct-method (basic-direct-method) \\ \ind
+ {daemon-direct-method (basic-direct-method) \\ \ind
\&key :message :location :class :type :body :role}
\end{describe}
\begin{describe}{cls}
- {delegating-direct-method (basic-direct-method) \\ \ind
+ {delegating-direct-method (basic-direct-method) \\ \ind
\&key :message :location :class :type :body :role}
\end{describe}
\begin{describe}{cls}
- {basic-effective-method (effective-method) \\ \ind
+ {basic-effective-method (effective-method) \\ \ind
\&key :message :class :around-methods :before-methods :after-methods}
\end{describe}
\end{describe*}
\begin{describe}{cls}
- {simple-effective-method (basic-effective-method) \\ \ind
+ {simple-effective-method (basic-effective-method) \\ \ind
\&key :message :class
:around-methods :before-methods :after-methods :primary-methods}
\end{describe}
\end{describe}
\begin{describe}{cls}
- {standard-effective-method (simple-effective-method) \\ \ind
+ {standard-effective-method (simple-effective-method) \\ \ind
\&key :message :class
:around-methods :before-methods :after-methods :primary-methods}
\end{describe}
\begin{describe}{gf}
{compute-aggregating-message-kernel
- \=@<message> @<combination> @<target> \+ \\
+ \=@<message> @<combination> @<target> \+\\
@<methods> @<arg-names> \&key}
\end{describe}
\end{describe}
\begin{describe}{cls}
- {aggregating-effective-method (simple-effective-method) \\ \ind
+ {aggregating-effective-method (simple-effective-method) \\ \ind
\&key :message :class
:around-methods :before-methods :after-methods :primary-methods}
\end{describe}
\begin{describe}{mac}
- {define-aggregating-method-combination @<combination> \\ \ind\ind
+ {define-aggregating-method-combination @<combination> \\ \ind\ind
((@<var-name>^*)
@[[ :codegen @<codegen-var> @!
- :methods @<methods-var> @]]) \- \\
+ :methods @<methods-var> @]]) \-\\
@[[ \=:properties (@{ (@{ @<name> @! (@[@<keyword>@] @<name>) @}
@<c-type>
@[@<default>
- @[@<suppliedp-var>@]@]) @}^*) @! \+ \\
- :return-type @<c-type> @! \\
+ @[@<suppliedp-var>@]@]) @}^*) @! \+\\
+ :return-type @<c-type> @! \\
:around @<around-func> @!
:first-method @<first-method-func> @!
:method @<method-func> @]]}
\begin{describe}{mac}
{example-macro
- (@{ @<symbol> @! (@<symbol> @<form>) @}^*) \\ \ind
- @[[ @<declaration>^* @! @<doc-string> @]] \\
+ (@{ @<symbol> @! (@<symbol> @<form>) @}^*) \\ \ind
+ @[[ @<declaration>^* @! @<doc-string> @]] \\
@<form>^*
\nlret @<value>^*}
The synopsis for a macro describes the acceptable syntax using the
\section{Base metaobject classes} \label{sec:meta.classes}
\begin{describe}{cls}
- {sod-class () \\ \ind
- \&key \=:name :nick :location :pset \+ \\
- :superclasses :link :metaclass \\
+ {sod-class () \\ \ind
+ \&key \=:name :nick :location :pset \+\\
+ :superclasses :link :metaclass \\
:slots :instance-initializers :class-initializers \\
- :initargs :initfrags :tearfrags \\
+ :initargs :initfrags :tearfrags \\
:messages :methods}
\end{describe}
\end{describe}
\begin{describe}{cls}
- {sod-class-slot (sod-slot) \\ \ind
+ {sod-class-slot (sod-slot) \\ \ind
\&key :name :location :pset :class :type
:initializer-function :prepare-function}
\end{describe}
\end{describe*}
\begin{describe}{gf}
- {make-sod-method \=@<class> @<nick> @<name> @<type> @<body> \+ \\
- @<pset> \&optional @<floc> \-
+ {make-sod-method
+ \=@<class> @<nick> @<name> @<type> @<body> \+\\
+ @<pset> \&optional @<floc> \-
\nlret @<method>}
\end{describe}
\begin{describe}{gf}
- {make-sod-method-using-message \=@<message> @<class>
- @<type> @<body> \+ \\
- @<pset> \&optional @<floc> \-
+ {make-sod-method-using-message
+ \=@<message> @<class>
+ @<type> @<body> \+\\
+ @<pset> \&optional @<floc> \-
\nlret @<method>}
\end{describe}
These symbols are defined in the @|sod-utilities| package.
\begin{describe}{mac}
- {with-gensyms (@{ @<var> @! (@<var> @[@<name>@]) @}^*) \\ \ind
- @<declaration>^* \\
+ {with-gensyms (@{ @<var> @! (@<var> @[@<name>@]) @}^*) \\ \ind
+ @<declaration>^* \\
@<form>^*}
\end{describe}
\begin{describe}{mac}
{once-only (@[[ :environment @<env> @]]
- @{ @<var> @! (@<var> @[@<value-form>@]) @}^*) \\ \ind
- @<declaration>^* \\
+ @{ @<var> @! (@<var> @[@<value-form>@]) @}^*) \\ \ind
+ @<declaration>^* \\
@<form>^*}
\end{describe}
\begin{describe}{mac}
{with-locatives
@{ @<var> @! (@{ @<var> @!
- (@<var> @[@<locative>@]) @}^*) @} \\ \ind
- @<declaration>^* \\
+ (@<var> @[@<locative>@]) @}^*) @} \\ \ind
+ @<declaration>^* \\
@<form>^*}
\end{describe}
\begin{describe}{mac}
{categorize (\=@<item-var> @<items>
- @[[ :bind (@{ @<var> @! (@<var> @[@<value>@]) @}^*) @]])
- \\ \ind\ind
- (@{ (@<cat-var> @<cat-predicate>) @}^*) \- \\
- @<declaration>^* \\
- @<body-form>^* \-
- \nlret @<value>^*}
+ @[[ :bind (@{ @<var> @!
+ (@<var> @[@<value>@]) @}^*) @]])
+ \\ \ind\ind
+ (@{ (@<cat-var> @<cat-predicate>) @}^*) \-\\
+ @<declaration>^* \\
+ @<body-form>^*
+ \-\nlret @<value>^*}
\end{describe}
\begin{describe}{fun}
\end{describe}
\begin{describe}{mac}
- {maybe-print-unreadable-object (@<object> @<stream>
- @[[ :type @<type> @!
- :identity @<identity> @]]) \\ \ind
- @<declaration>^* \\
+ {maybe-print-unreadable-object
+ (@<object> @<stream>
+ @[[ :type @<type> @!
+ :identity @<identity> @]]) \\ \ind
+ @<declaration>^* \\
@<form>^*}
\end{describe}
\begin{describe}{mac}
{dosequence (@<var> @<sequence>
@[[ :start @<start> @! :end @<end> @!
- :indexvar @<var> @]]) \\ \ind
- @<declaration>^* \\
+ :indexvar @<var> @]]) \\ \ind
+ @<declaration>^* \\
@{ @<tag> @! @<statement> @}^*}
\end{describe}
\end{describe}
\begin{describe}{mac}
- {default-slot (@<instance> @<slot> @[@<slot-names>@]) \\ \ind
+ {default-slot (@<instance> @<slot> @[@<slot-names>@]) \\ \ind
@<form>^*}
\end{describe}
\begin{describe}{mac}
- {define-on-demand-slot @<class> @<slot> (@<instance>) \\ \ind
- @[[ @<declaration>^* @! @<doc-string> @]] \\
+ {define-on-demand-slot @<class> @<slot> (@<instance>) \\ \ind
+ @[[ @<declaration>^* @! @<doc-string> @]] \\
@<form>^*}
\end{describe}
\end{describe}
\begin{describe}{fun}
- {make-option \=@<long-name> @<short-name> \+ \\
- \&optional @<arg-name> \\
- \&key :tag :negated-tag :arg-optional-p :documentation \-
+ {make-option \=@<long-name> @<short-name> \+\\
+ \&optional @<arg-name> \\
+ \&key :tag :negated-tag
+ :arg-optional-p :documentation \-
\nlret @<option>}
\end{describe}
\end{describe}
\begin{describe}{mac}
- {sequence-output (@<stream-var> @<sequencer>) \\ \ind
- @{ :constraint (@<item-name>^*) @} \\
+ {sequence-output (@<stream-var> @<sequencer>) \\ \ind
+ @{ :constraint (@<item-name>^*) @} \\
@{ (@<item-name> @<form>^*) @}^*}
\end{describe}
\begin{describe*}
{\quad\=\quad\=\kill
\dhead{cls}
- {error-with-location (condition-with-location error) \\ \>
+ {error-with-location (condition-with-location error) \\ \>
\&key :location}
\dhead{cls}
{warning-with-location (condition-with-location warning) \\ \>
\&key :location}
\dhead{cls}
{enclosing-error-with-location
- (enclosing-error-with-location error) \\ \>
+ (enclosing-error-with-location error) \\ \>
\&key :condition :location}
\dhead{cls}
{enclosing-warning-with-location
- (enclosing-condition-with-location warning) \\ \>
+ (enclosing-condition-with-location warning) \\ \>
\&key :condition :location}
\dhead{cls}
{simple-condition-with-location
- (condition-with-location simple-condition) \\ \>
+ (condition-with-location simple-condition) \\ \>
\&key :format-control :format-arguments :location}
\dhead{cls}
{simple-error-with-location
- (error-with-location simple-error) \\ \>
+ (error-with-location simple-error) \\ \>
\&key :format-control :format-arguments :location}
\dhead{cls}
{simple-warning-with-location
- (warning-with-location simple-warning) \\ \>
+ (warning-with-location simple-warning) \\ \>
\&key :format-control :format-arguments :location}}
\end{describe*}
characters from a scanner in bulk. The function @<func> is invoked
repeatedly, as if by
\begin{prog}
- (multiple-value-bind (@<donep> @<used>) \\ \ind\ind
- (funcall @<func> @<buf> @<start> @<end>) \- \\
+ (multiple-value-bind (@<donep> @<used>) \\ \ind\ind
+ (funcall @<func> @<buf> @<start> @<end>) \-\\
\textrm\ldots)
\end{prog}
The argument @<buf> is a simple string; @<start> and @<end> are two
fails: the @<fail> function is called with no arguments, and is expected to
return two values. If omitted, @<fail> defaults to
\begin{prog}
- (lambda () \\ \ind
- (values nil nil))%
+ (lambda () \\ \ind
+ (values nil nil))
\end{prog}
The @|charbuf-scanner-map| function returns three values. The first value
\begin{describe}{mac}
{defparse @<name> (@[[ :context (@<var> @<context-class>) @]]
- @<destructuring-lambda-list-item>^*) \\ \ind
- @[[ @<declaration>^* @! @<doc-string> @]] \\
- @<form>^* \-
- \nlret @<name>}
+ @<destructuring-lambda-list-item>^*) \\ \ind
+ @[[ @<declaration>^* @! @<doc-string> @]] \\
+ @<form>^*
+ \-\nlret @<name>}
\end{describe}
\begin{describe}{mac}
{with-parser-context
- (@<context-class> @{ @<init-keyword> @<value> @}^*) \\ \ind
- @<declaration>^* \\
- @<form>^* \-
- \nlret @<value>^*}
+ (@<context-class> @{ @<init-keyword> @<value> @}^*) \\ \ind
+ @<declaration>^* \\
+ @<form>^*
+ \-\nlret @<value>^*}
\end{describe}
\begin{describe}{lmac}
\begin{describe}{mac}
{if-parse (@[[ \=:result @<result-var> @!
- :expected @<expected-var> @! \+ \\
- :consumedp @<consumed-var> @]]) \- \\ \ind\ind
- @<parser> \- \\
- @<consequent> \\
- @[@<alternatve>@] \-
- \nlret @<value>^*}
+ :expected @<expected-var> @! \+\\
+ :consumedp @<consumed-var> @]]) \-\\ \ind\ind
+ @<parser> \-\\
+ @<consequent> \\
+ @[@<alternatve>@]
+ \-\nlret @<value>^*}
\end{describe}
\begin{describe}{mac}
- {when-parse (@[@<result-var>@]) @<parser> \\ \ind
- @<form>^* \-
- \nlret @<value>^*}
+ {when-parse (@[@<result-var>@]) @<parser> \\ \ind
+ @<form>^*
+ \-\nlret @<value>^*}
\end{describe}
\begin{describe}{mac}
{cond-parse (@[[ \=:result @<result-var> @!
- :expected @<expected-var> @! \+ \\
- :consumedp @<consumed-var> @]]) \- \\ \ind
- @{ (@<parser> @<form>^*) @}^* \-
- \nlret @<value>^*}
+ :expected @<expected-var> @! \+\\
+ :consumedp @<consumed-var> @]]) \-\\ \ind
+ @{ (@<parser> @<form>^*) @}^*
+ \-\nlret @<value>^*}
\end{describe}
\begin{describe}{parse}{:eof}
\end{describe}
\begin{describe}{parseform}
- {seq (@{ @<atomic-parser-spec> @! (@[@<var>@] @<parser>) @}^*) \\ \ind
+ {seq (@{ @<atomic-parser-spec> @!
+ (@[@<var>@] @<parser>) @}^*) \\ \ind
@<body-form>^*}
\end{describe}
\end{describe}
\begin{describe}{parseform}
- {many (\=@<accumulator-var> @<init-form> @<update-form> \+ \\
- @[[ \=:new @<new-var> @! :final @<final-form> @! \+ \\
- :min @<minimum> @! :max @<maximum> @! \\
- :commitp @<commitp> @]]) \-\- \\ \ind
+ {many (\=@<accumulator-var> @<init-form> @<update-form> \+\\
+ @[[ \=:new @<new-var> @! :final @<final-form> @! \+\\
+ :min @<minimum> @! :max @<maximum> @! \\
+ :commitp @<commitp> @]]) \-\-\\ \ind
@<item-parser> @[@<sep-parser>@]}
\end{describe}
\begin{describe}{parseform}
{list (@[[ :min @<minimum> @! :max @<maximum> @!
- :commitp @<commitp> @]])\\ \ind
+ :commitp @<commitp> @]]) \\ \ind
@<item-parser> @[@<sep-parser>@]}
\end{describe}
\begin{describe}{parseform}
{skip-many (@[[ :min @<minimum> @! :max @<maximum> @!
- :commitp @<commitp> @]])\\ \ind
+ :commitp @<commitp> @]]) \\ \ind
@<item-parser> @[@<sep-parser>@]}
\end{describe}
\end{describe}
\begin{describe}{parseform}
- {expr \=(@[[ :nestedp @<nestedp-var> @]]) \+ \\
+ {expr \=(@[[ :nestedp @<nestedp-var> @]]) \+\\
@<operand-parser> @<binop-parser>
@<preop-parser> @<postop-parser>}
\end{describe}
\begin{describe*}
{\quad\=\kill
- \dhead{cls}{simple-binary-operator (simple-operator) \\ \>
- \&key :name :function :lprec :rprec :associativity}
+ \dhead{cls}{simple-binary-operator (simple-operator) \\ \>
+ \&key :name :function
+ :lprec :rprec :associativity}
\dhead{cls}{simple-postfix-operator (simple-unary-operator) \\ \>
\&key :name :function :lprec :rprec}
\dhead{cls}{simple-prefix-operator
- (prefix-operator simple-unary-operator) \\ \>
+ (prefix-operator simple-unary-operator) \\ \>
\&key :name :function :rprec}}
\end{describe*}
will be described later.
\begin{describe}[struct kwval]{type}
- {struct kwval \{ \\ \ind
- const char *kw; \\
- const void *val; \- \\
+ {struct kwval \{ \\ \ind
+ const char *kw; \\
+ const void *val; \-\\
\};}
The @|kwval| structure describes a keyword argument name/value pair. The
\end{describe}
\begin{describe}[struct kwtab]{type}
- {struct kwtab \{ \\ \ind
- const struct kwval *v; \\
- size_t n; \- \\
+ {struct kwtab \{ \\ \ind
+ const struct kwval *v; \\
+ size_t n; \-\\
\};}
The @|kwtab| structure describes a list of keyword arguments, represented
\end{prog}
with no separation between them. For example:
\begin{prog}
- \#define example_KWSET(_) @\\ \\ \ind
- _(int, x, 0) @\\ \\
+ \#define example_KWSET(_) @\\ \\ \ind
+ _(int, x, 0) @\\ \\
_(const char *, y, NULL)
\end{prog}
The macro @|KWSET_PARSEFN| defines a keyword argument \emph{parser
function}
\begin{prog}
- void @<set>{}_kwparse(\=struct @<set>{}_kwargs *@<kw>,
- const char *@<kwfirst>, va_list *@<ap>, \+ \\
- const struct kwval *@<v>, size_t @<n>);
+ void @<set>{}_kwparse%
+ (\=struct @<set>{}_kwargs *@<kw>,
+ const char *@<kwfirst>, va_list *@<ap>, \+\\
+ const struct kwval *@<v>, size_t @<n>);
\end{prog}
The macro call can (and usually will) be preceded by storage class
specifiers such as @|static|, for example to adjust the linkage of the
\end{describe}
\begin{describe}[kw_parseempty]{fun}
- {void kw_parseempty(\=const char *@<set>,
- const char *@<kwfirst>, va_list *@<ap>, \+ \\
- const struct kwval *@<v>, size_t @<n>);}
+ {void kw_parseempty%
+ (\=const char *@<set>,
+ const char *@<kwfirst>, va_list *@<ap>, \+\\
+ const struct kwval *@<v>, size_t @<n>);}
This function checks an keyword argument list to make sure that contains no
keyword arguments (other than the special ones described in
\xref{sec:runtime.keywords.calling}).
\begin{prog}
\#define KWARGS_TEST(k, val) KWARGS(K(k, val) K(kw.unknown, 0))
- \\+
+ \\+
static jmp_buf kw_test_jmp;
- \\+
- static void kw_test_unknown(const char *set, const char *kw) \\
- \{ \\ \ind
- if (strcmp(kw, "kw.unknown")) longjmp(kw_test_jmp, 1); \\
- else longjmp(kw_test_jmp, 2); \- \\
- \}
- \\+
- \#define KW_TEST(flag, set, call) do \{ @\\ \\ \ind
- kw_unkhookfn *oldunk = kw_unkhook; @\\ \\
- kw_unkhook = kw_test_unknown; @\\ \\
- switch (setjmp(kw_test_jmp)) \{ @\\ \\ \ind
- case 0: call; abort(); @\\ \\
- case 1: flag = 1; break; @\\ \\
- case 2: flag = 0; break; @\\ \\
- default: abort(); \- @\\ \\
- \} @\\ \\
- kw_unkhook = oldunk; \- @\\ \\
- \} while (0)
- \\+
- @/* Example of use */ \\
- int f; \\
+ \\+
+ static void kw_test_unknown(const char *set, const char *kw) \\
+ \{ \\ \ind
+ if (strcmp(kw, "kw.unknown")) longjmp(kw_test_jmp, 1); \\
+ else longjmp(kw_test_jmp, 2); \-\\
+ \} \\+
+
+ \#define KW_TEST(flag, set, call) do \{ @\\ \\ \ind
+ kw_unkhookfn *oldunk = kw_unkhook; @\\ \\
+ kw_unkhook = kw_test_unknown; @\\ \\
+ switch (setjmp(kw_test_jmp)) \{ @\\ \\ \ind
+ case 0: call; abort(); @\\ \\
+ case 1: flag = 1; break; @\\ \\
+ case 2: flag = 0; break; @\\ \\
+ default: abort(); @\\ \-\\
+ \} @\\ \\
+ kw_unkhook = oldunk; @\\ \-\\
+ \} while (0) \\+
+
+ @/* Example of use */ \\
+ int f; \\
KW_TEST(f, somefunc(1, "two", 3, KWARGS_TEST("shiny", 68.7))); \\
/\=* \comment{now @|f| is nonzero if @|somefunc| accepts the
- @|shiny| keyword} \+ \\
- {}* \comment{(which we hope wants a @|double| argument)} \\
+ @|shiny| keyword} \+\\
+ {}* \comment{(which we hope wants a @|double| argument)} \\
{}*/
\end{prog}
instances have the basic structure of a @|struct sod_instance|.
\begin{describe}[struct sod_instance]{type}
- {struct sod_instance \{ \\ \ind
- const struct sod_vtable *_vt; \- \\
+ {struct sod_instance \{ \\ \ind
+ const struct sod_vtable *_vt; \-\\
\};}
The basic structure of all instances. Members are as follows.
\end{describe}
\begin{describe}[struct sod_vtable]{type}
- {struct sod_vtable \{ \\ \ind
- const SodClass *_class; \\
- size_t _base; \- \\
+ {struct sod_vtable \{ \\ \ind
+ const SodClass *_class; \\
+ size_t _base; \-\\
\};}
A vtable contains static metadata needed for efficient conversions and
\begin{figure}[tbp]
\begin{tabular}{p{10pt}p{10pt}}
\begin{nprog}
- struct SodObject__ilayout \{ \\ \ind
- union \{ \\ \ind
- struct SodObject__ichain_obj \{ \\ \ind
- const struct SodObject__vt_obj *_vt; \- \\
- \} obj; \- \\
- \} obj; \- \\
+ struct SodObject__ilayout \{ \\ \ind
+ union \{ \\ \ind
+ struct SodObject__ichain_obj \{ \\ \ind
+ const struct SodObject__vt_obj *_vt; \-\\
+ \} obj; \-\\
+ \} obj; \-\\
\};
\end{nprog}
&
\begin{nprog}
- struct SodObject__vt_obj \{ \\ \ind
- const SodClass *_class; \\
- size_t _base; \\
- struct SodObject__vtmsgs_obj \{ \\ \ind
- void (*init)(SodObject *me, ...); \\
- void (*init__v)(SodObject *me, va_list); \\
- int (*teardown)(SodObject *me); \- \\
- \} obj; \- \\
+ struct SodObject__vt_obj \{ \\ \ind
+ const SodClass *_class; \\
+ size_t _base; \\
+ struct SodObject__vtmsgs_obj \{ \\ \ind
+ void (*init)(SodObject *me, ...); \\
+ void (*init__v)(SodObject *me, va_list); \\
+ int (*teardown)(SodObject *me); \-\\
+ \} obj; \-\\
\};
- \end{nprog} \\
+ \end{nprog} \\
\end{tabular}
\caption{Instance and vtable layout of @|SodObject|}
\label{fig:structures.root.sodobject}
\end{figure}
\begin{describe}[SodObject]{cls}
- {[nick = obj, metaclass = SodClass, lisp_metaclass = sod_class] \\
- class SodObject \{ \\ \ind
+ {[nick = obj, metaclass = SodClass,
+ lisp_metaclass = sod_class] \\
+ class SodObject \{ \\ \ind
void init(?);
\}}
\subsection{The SodClass class} \label{sec:structures.root.sodclass}
\begin{describe}[SodClass]{cls}
- {[nick = cls, link = SodObject] \\
- class SodClass : SodObject \{ \\ \ind
- const char *name; \\
- const char *nick; \\
- size_t initsz; \\
- size_t align; \\
- void *(*imprint)(void *@<p>); \\
- size_t n_supers; \\
- const SodClass *const *supers; \\
- size_t n_cpl; \\
- const SodClass *const *cpl; \\
- const SodClass *link; \\
- const SodClass *head; \\
- size_t level; \\
- size_t n_chains; \\
- const struct sod_chain *chains; \\
- size_t off_islots; \\
- size_t islotsz; \- \\
+ {[nick = cls, link = SodObject] \\
+ class SodClass : SodObject \{ \\ \ind
+ const char *name; \\
+ const char *nick; \\
+ size_t initsz; \\
+ size_t align; \\
+ void *(*imprint)(void *@<p>); \\
+ size_t n_supers; \\
+ const SodClass *const *supers; \\
+ size_t n_cpl; \\
+ const SodClass *const *cpl; \\
+ const SodClass *link; \\
+ const SodClass *head; \\
+ size_t level; \\
+ size_t n_chains; \\
+ const struct sod_chain *chains; \\
+ size_t off_islots; \\
+ size_t islotsz; \-\\
\}}
The @|SodClass| class defines no additional messages , but there are a
\end{describe}
\begin{describe}[struct sod_chain]{type}
- {struct sod_chain \{ \\ \ind
- size_t n_classes; \\
- const SodClass *const *classes; \\
- size_t off_ichain; \\
- const struct sod_vtable *vt; \\
- size_t ichainsz; \- \\
+ {struct sod_chain \{ \\ \ind
+ size_t n_classes; \\
+ const SodClass *const *classes; \\
+ size_t off_ichain; \\
+ const struct sod_vtable *vt; \\
+ size_t ichainsz; \-\\
\};}
The @|struct sod_chain| structure describes an individual chain of
type @|struct $C$__ilayout|.
\begin{prog}
- struct $C$__ilayout \{ \\ \ind
- union $C$__ichainu_$h$ \{ \\ \ind
- struct $C$__ichain_$h$ \{ \\ \ind
- const struct $C$__vt_$h$ *_vt; \\
- struct $H$__islots $h$; \\
- \quad$\vdots$ \\
- struct $C$__islots \{ \\ \ind
- @<type>_1 @<slot>_1; \\
- \quad$\vdots$ \\
- @<type>_n @<slot>_n; \- \\
- \} $c$; \- \\
- \} $c$; \\
- struct $H$__ichain_$h$ $h$; \\
- \quad$\vdots$ \- \\
- \} $h$; \\
- union $B$__ichainu_$i$ $i$; \\
- \quad$\vdots$ \- \\
- \};
- \\+
+ struct $C$__ilayout \{ \\ \ind
+ union $C$__ichainu_$h$ \{ \\ \ind
+ struct $C$__ichain_$h$ \{ \\ \ind
+ const struct $C$__vt_$h$ *_vt; \\
+ struct $H$__islots $h$; \\
+ \quad$\vdots$ \\
+ struct $C$__islots \{ \\ \ind
+ @<type>_1 @<slot>_1; \\
+ \quad$\vdots$ \\
+ @<type>_n @<slot>_n; \-\\
+ \} $c$; \-\\
+ \} $c$; \\
+ struct $H$__ichain_$h$ $h$; \\
+ \quad$\vdots$ \-\\
+ \} $h$; \\
+ union $B$__ichainu_$i$ $i$; \\
+ \quad$\vdots$ \-\\
+ \}; \\+
+
typedef struct $C$__ichain_$h$ $C$;
\end{prog}
A vtable for a class $C$ with chain head $H$ has the following general
structure.
\begin{prog}
- union $C$__vtu_$h$ \{ \\ \ind
- struct $C$__vt_$h$ \{ \\ \ind
- const $P$ *_class; \\
- size_t _base; \\
- \quad$\vdots$ \\
- const $Q$ *_cls_$j$; \\
- \quad$\vdots$ \\
- ptrdiff_t _off_$i$; \\
- \quad$\vdots$ \\
- struct $C$__vtmsgs_$a$ \{ \\ \ind
- @<type> (*@<msg>)($C$ *, $\dots$); \\
- \quad$\vdots$ \- \\
- \} $a$; \\
- \quad$\vdots$ \- \\
- \} $c$; \- \\
- \};
- \\+
+ union $C$__vtu_$h$ \{ \\ \ind
+ struct $C$__vt_$h$ \{ \\ \ind
+ const $P$ *_class; \\
+ size_t _base; \\
+ \quad$\vdots$ \\
+ const $Q$ *_cls_$j$; \\
+ \quad$\vdots$ \\
+ ptrdiff_t _off_$i$; \\
+ \quad$\vdots$ \\
+ struct $C$__vtmsgs_$a$ \{ \\ \ind
+ @<type> (*@<msg>)($C$ *, $\dots$); \\
+ \quad$\vdots$ \-\\
+ \} $a$; \\
+ \quad$\vdots$ \-\\
+ \} $c$; \-\\
+ \}; \\+
+
extern const union $C$__vtu_$h$ $C$__vtable_$h$;
\end{prog}
\end{prog}
or a standard message which takes keyword arguments, defined as
\begin{prog}
- @<type>_0 $m$(\=@<type>_1 @<arg>_1, $\ldots$, @<type>_n @<arg>_n? \+ \\
- @<type>_{n+1} @<kw>_{n+1} @[= @<dflt>_{n+1}@], $\ldots$,
- @<type>_m @<kw>_m @[= @<dflt>_m@]);
+ @<type>_0 $m$(\=@<type>_1 @<arg>_1,
+ $\ldots$,
+ @<type>_n @<arg>_n? \+\\
+ @<type>_{n+1} @<kw>_{n+1} @[= @<dflt>_{n+1}@],
+ $\ldots$,
+ @<type>_m @<kw>_m @[= @<dflt>_m@]);
\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
list or keywords.
\begin{prog}
@<type>_0 $m$($C$ *me, @<type>_1 @<arg>_1, $\ldots$,
- @<type>_n @<arg>_n, \dots); \\
+ @<type>_n @<arg>_n, \dots); \\
@<type>_0 $m$__v($C$ *me, @<type>_1 @<arg>_1, $\ldots$,
@<type>_n @<arg>_n, va_list sod__ap);
\end{prog}
Finally, the class object is defined as
\begin{prog}
- extern const struct $R$__ilayout $C$__classobj; \\
+ extern const struct $R$__ilayout $C$__classobj; \\
\#define $C$__class (\&$C$__classobj.$j$.$r$)
\end{prog}
The exported symbol @|$C$__classobj| contains the entire class instance.
to name a class which is currently undefined. Forward declarations are
necessary in order to resolve certain kinds of circularity. For example,
\begin{prog}
-class Sub;
-\\+
-class Super : SodObject \{ \\ \ind
- Sub *sub; \- \\
-\};
-\\+
-class Sub : Super \{ \\ \ind
- /* \dots */ \- \\
+class Sub; \\+
+
+class Super : SodObject \{ \\ \ind
+ Sub *sub; \-\\
+\}; \\+
+
+class Sub : Super \{ \\ \ind
+ /* \dots\ */ \-\\
\};
\end{prog}
@<initializer-item> containing the slot name and initializer were present.
For example,
\begin{prog}
-[nick = eg] \\-
-class Example : Super \{ \\ \ind
- int foo = 17; \- \\
+[nick = eg] \\
+class Example : Super \{ \\ \ind
+ int foo = 17; \-\\
\};
\end{prog}
means the same as
\begin{prog}
-[nick = eg] \\-
-class Example : Super \{ \\ \ind
- int foo; \\
- eg.foo = 17; \- \\
+[nick = eg] \\
+class Example : Super \{ \\ \ind
+ int foo; \\
+ eg.foo = 17; \-\\
\};
\end{prog}
Of course, this means that your build system needs to become more
complicated. If you use \man{make}{1}, then something like
\begin{prog}
- SOD = sod
- \\+
- .SUFFIXES: .sod .c .h \\
- .sod.c:; \$(SOD) -tc \$< \\
+ SOD = sod \\+
+
+ .SUFFIXES: .sod .c .h \\
+ .sod.c:; \$(SOD) -tc \$< \\
.sod.h:; \$(SOD) -th \$<
\end{prog}
ought to do the job.
The following is a simple Sod input file.
\begin{prog}
- /* -*-sod-*- */
- \\+
- code c : includes \{ \\
- \#include "greeter.h" \\
- \}
- \\+
- code h : includes \{ \\
- \#include <stdio.h> \\
- \#include <sod/sod.h> \\
- \}
- \\+
- class Greeter : SodObject \{ \\ \ind
- void greet(FILE *fp) \{ \\ \ind
- fputs("Hello, world!\textbackslash n", fp); \- \\
- \} \- \\
+ /* -*-sod-*- */ \\+
+
+ code c : includes \{ \\
+ \#include "greeter.h" \\
+ \} \\+
+
+ code h : includes \{ \\
+ \#include <stdio.h> \\
+ \#include <sod/sod.h> \\
+ \} \\+
+
+ class Greeter : SodObject \{ \\ \ind
+ void greet(FILE *fp) \{ \\ \ind
+ fputs("Hello, world!\textbackslash n", fp); \-\\
+ \} \-\\
\}
\end{prog}
Save it as @"greeter.sod", and run
This will create files @"greeter.c" and @"greeter.h" in the current
directory. Here's how we might use such a simple thing.
\begin{prog}
- \#include "greeter.h"
- \\+
- int main(void) \\
- \{ \\ \ind
- SOD_DECL(Greeter, g);
- \\+
- Greeter_greet(g, stdout); \\
- return (0); \- \\
+ \#include "greeter.h" \\+
+
+ int main(void) \\
+ \{ \\ \ind
+ SOD_DECL(Greeter, g); \\+
+
+ Greeter_greet(g, stdout); \\
+ return (0); \-\\
\}
\end{prog}
Compare this to the traditional
\begin{prog}
- \#include <stdio.h>
- \\+
- int main(void) \\ \ind
+ \#include <stdio.h> \\+
+
+ int main(void) \\ \ind
\{ fputs("Hello, world@\\n", stdout); return (0); \}
\end{prog}
and I'm sure you'll appreciate the benefits of using Sod already -- mostly to
\end{prog}
needs to appear in the generated @|greeter.c| file; the second says that
\begin{prog}
- \#include <stdio.h> \\
+ \#include <stdio.h> \\
\#include <sod/sod.h>
\end{prog}
needs to appear in the header file @|greeter.h|. The generated C files need
The basic syntax for @"code" stanzas is
\begin{prog}
- code @<file-label> : @<section> \{ \\ \ind
- @<code> \- \\
+ code @<file-label> : @<section> \{ \\ \ind
+ @<code> \-\\
\}
\end{prog}
The @<file-label> is either @"c" or @"h", and says which output file the code