@|c-struct-type| \\
@|c-union-type| \\
@|c-enum-type| \- \\
+ @|c-atomic-type| \\
@|c-pointer-type| \- \\
@|c-array-type| \\
@|c-function-type| \\ \ind
type specifiers among its arguments.
\end{describe}
-\begin{describe}{fun}{expand-c-type-spec @<type-spec> @> @<form>}
+\begin{describe}{gf}{expand-c-type-spec @<type-spec> @> @<form>}
Returns the Lisp form that @|(c-type @<type-spec>)| would expand into.
+
+ If @<type-spec> is a list, then \descref{expand-c-type-form}{fun} is
+ invoked.
+\end{describe}
+
+\begin{describe}{gf}{expand-c-type-form @<head> @<tail> @> @<form>}
+ Returns the Lisp form that @|(c-type (@<head> . @<tail>)| would expand
+ into.
\end{describe}
\begin{describe}{gf}
\subsection{Type qualifiers and qualifiable types}
\label{sec:clang.ctypes.qual}
+Qualifiers -- @|const|, @|volatile|, and so on -- are represented as lists of
+keywords attached to types. Not all C types can carry qualifiers: notably,
+function and array types cannot be qualified.
+
+For the most part, the C qualifier keywords correspond to like-named Lisp
+keywords, only the Lisp keyword names are in uppercase. The correspondence
+is shown in \xref{tab:clang.ctypes.qual}.
+
+\begin{table}
+ \begin{tabular}[C]{*2{>{\codeface}l}l} \hlx*{hv}
+ \thd{\textbf{C name}} & \thd{\textbf{Lisp name}} \\ \hlx{vhv}
+ _Atomic & :atomic \\
+ const & :const \\
+ restrict & :restrict \\
+ volatile & :volatile \\ \hlx*{vh}
+ \end{tabular}
+ \caption{C and Lisp qualifier names} \label{tab:clang.ctypes.qual}
+\end{table}
+
+The default behaviour, on output, is to convert keywords to lowercase and
+hope for the best: special cases can be dealt with by adding appropriate
+methods to \descref{c-qualifier-keyword}{gf}.
+
\begin{describe}{cls}{qualifiable-c-type (c-type) \&key :qualifiers}
The class @|qualifiable-c-type| describes C types which can bear
`qualifiers' (\Cplusplus\ calls them `cv-qualifiers'): @|const|,
non-null then the final character of the returned string will be a space.
\end{describe}
+\begin{describe}{gf}{c-qualifier-keyword @<qualifier> @> @<string>}
+ Return, as a string, the C keyword corresponding to the Lisp @<qualifier>.
+
+ There is a standard method, which deals with many qualifiers. Additional
+ methods exist for qualifier keywords which need special handling, such as
+ @|:atomic|; they are not listed here explicitly.
+
+ \begin{describe}{meth}{c-qualifier-keyword @<keyword> @> @<string>}
+ Returns the @<keyword>'s print-name, in lower case. This is sufficient
+ for the standard qualifiers @|:const|, @|:restrict|, and @|:volatile|.
+ \end{describe}
+\end{describe}
+
+\begin{describe}{fun}{c-type-qualifier-keywords @<c-type> @> @<list>}
+ Return the @<c-type>'s qualifiers, as a list of C keyword names.
+\end{describe}
+
+
+\subsection{Storage specifiers} \label{sec:clang.ctypes.specs}
+
+Some declaration specifiers, mostly to do with how to store the specific
+object in question, are determinedly `top level', and, unlike qualifiers,
+don't stay attached to the base type when acted on by declarator operators.
+Sod calls these `storage specifiers', though no such category exists in the C
+standard. They have their own protocol, which is similar in many ways to
+that of C types.
+
+Every Lisp keyword is potentially a storage specifier, which simply maps to
+its lower-case print name in C; but other storage specifiers may be more
+complicated objects.
+
+\begin{describe}{cls}
+ {c-storage-specifiers-type (c-type) \&key :subtype :specifiers}
+ A type which carries storage specifiers. The @<subtype> is the actual
+ type, and may be any C type; the @<specifiers> are a list of
+ storage-specifier objects.
+
+ The type specifier @|(specs @<subtype> @<specifier>^*)| wraps the
+ @<subtype> in a @|c-storage-specifiers-type|, carrying the @<specifier>s,
+ which are a list of storage specifiers in S-expression notation.
+\end{describe}
+
+\begin{describe}{fun}{c-type-specifiers @<type> @> @<list>}
+ Returns the list of type specifiers attached to the @<type> object, which
+ must be a @|c-storage-specifiers-type|.
+\end{describe}
+
+\begin{describe}{mac}
+ {define-c-storage-specifier-syntax @<name> @<lambda-list> \\ \ind
+ @[[ @<declaration>^* @! @<doc-string> @]] \\
+ @<form>^* \-
+ \nlret @<name>}
+
+ Defines the symbol @<name> as a new storage-specifier operator. When a
+ list of the form @|(@<name> @<argument>^*)| is used as a storage specifier,
+ the @<argument>s are bound to fresh variables according to the
+ @<lambda-list> (a destructuring lambda-list) and the @<form>s evaluated in
+ order in the resulting lexical environment as an implicit @<progn>. The
+ value should be a Lisp form which will evaluate to the storage-specifier
+ object described by the arguments.
+
+ The @<form>s may call @|expand-c-storage-specifier| in order to recursively
+ expand storage specifiers among its arguments.
+\end{describe}
+
+\begin{describe}{gf}{expand-c-storage-specifier @<spec> @> @<form>}
+ Returns the Lisp form that @<spec> expands to within @|(c-type (specs
+ @<subtype> @<spec>))|.
+
+ If @<spec> is a list, then \descref{expand-c-storage-specifier-form} is
+ invoked.
+\end{describe}
+
+\begin{describe}{gf}{expand-c-storage-specifier-form @<spec> @> @<form>}
+ Returns the Lisp form that @|(@<head> . @<tail>)| expands to within
+ @|(c-type (specs @<subtype> (@<head> . @<tail>)))|.
+\end{describe}
+
+\begin{describe}{gf}{pprint-c-storage-specifier @<spec> @<stream>}
+\end{describe}
+
+\begin{describe}{gf}
+ {print-c-storage-specifier @<stream> @<spec>
+ \&optional @<colon> @<atsign>}
+\end{describe}
+
+\begin{describe}{fun}{wrap-c-type @<func> @<base-type> @> @<c-type>}
+ Apply @<func> to the underlying C type of @<base-type> to create a new
+ `wrapped' type, and attach the storage specifiers of @<base-type> to the
+ wrapped type.
+
+ If @<base-type> is \emph{not} a @|c-storage-specifiers-type|, then return
+ @|(funcall @<func> @<base-type>)|. Otherwise, return a new
+ @|c-storage-specifiers-type|, with the same specifiers, but whose subtype
+ is the result of applying @<func> to the subtype of the original
+ @<base-type>.
+\end{describe}
+
+\begin{describe}{cls}{alignas-storage-specifier () \&key :alignment}
+ The class of @|_Alignas| storage specifiers; an instance denotes the
+ specifier @|_Alignas(@<alignment>)|. The @<alignment> parameter may be any
+ printable object, but is usually a string or C fragment.
+
+ The storage specifier form @|(alignas @<alignment>)| returns a storage
+ specifier @|_Alignas(@<alignment>)|, where @<alignment> is evaluated.
+\end{describe}
+
\subsection{Leaf types} \label{sec:clang.c-types.leaf}
\end{describe}
+\subsection{Atomic types} \label{sec:clang.c-types.atomic}
+
+Atomic types are compound types. The subtype of an atomic type is simply the
+underlying type of the object. Note that, as far as Sod is concerned, atomic
+types are not the same as atomic-qualified types: you must be consistent
+about which you use.
+
+\begin{describe}{cls}
+ {c-atomic-type (qualifiable-c-type) \&key :qualifiers :subtype}
+ Represents an atomic type. An instance denotes the C type
+ @|_Atomic(@<subtype>)|.
+
+ The @<subtype> may be any C type.\footnote{%
+ C does not permit atomic function or array types.} %
+ Two atomic types are equal if and only if their subtypes are equal and they
+ have matching qualifiers. It is possible, though probably not useful, to
+ have an atomic-qualified atomic type.
+
+ The type specifier @|(atomic @<type-spec> @<qualifier>^*)| returns a type
+ qualified atomic @<subtype>, where @<subtype> is the type specified by
+ @<type-spec> and the @<qualifier>s are qualifier keywords (which are
+ evaluated).
+\end{describe}
+
+\begin{describe}{fun}
+ {make-atomic-type @<c-type> \&optional @<qualifiers> @> @<c-atomic-type>}
+ Return an object describing the type qualified atomic @<subtype>. If
+ @<subtype> is interned, then the returned atomic type object is interned
+ also.
+\end{describe}
+
+
\subsection{Pointer types} \label{sec:clang.c-types.pointer}
Pointers are compound types. The subtype of a pointer type is the type it