X-Git-Url: https://git.distorted.org.uk/~mdw/sod/blobdiff_plain/ae0f15ee8427fa91cfd1945bfded847032cb8a25..b7fcf94152e4c1938fbca55d13b1e6a64b694bd6:/src/c-types-proto.lisp?ds=sidebyside diff --git a/src/c-types-proto.lisp b/src/c-types-proto.lisp index 1057321..0c95d02 100644 --- a/src/c-types-proto.lisp +++ b/src/c-types-proto.lisp @@ -246,6 +246,93 @@ (t name))) ;;;-------------------------------------------------------------------------- +;;; Storage specifier protocol. + +(export 'pprint-c-storage-specifier) +(defgeneric pprint-c-storage-specifier (spec stream) + (:documentation "Print the storage specifier SPEC to STREAM, as C syntax.") + (:method ((spec symbol) stream) (princ (string-downcase spec) stream))) + +(export 'print-c-storage-specifier) +(defgeneric print-c-storage-specifier (stream spec &optional colon atsign) + (:documentation + "Print the storage specifier SPEC to STREAM, as an S-expression. + + This function is suitable for use in `format's ~/.../ command.") + (:method (stream (spec t) &optional colon atsign) + (declare (ignore colon atsign)) + (prin1 spec stream)) + (:method (stream (spec symbol) &optional colon atsign) + (declare (ignore colon atsign)) + (princ (string-downcase spec) stream))) + +(export '(expand-c-storage-specifier expand-c-storage-specifier-form)) +(eval-when (:compile-toplevel :load-toplevel :execute) + (defgeneric expand-c-storage-specifier (spec) + (:documentation + "Expand SPEC into Lisp code to construct a storage specifier.") + (:method ((spec list)) + (expand-c-storage-specifier-form (car spec) (cdr spec))) + (:method ((spec symbol)) + (if (keywordp spec) spec + (expand-c-storage-specifier-form spec nil)))) + (defgeneric expand-c-storage-specifier-form (head tail) + (:documentation + "Expand a C storage-specifier form beginning with HEAD.") + (:method ((name (eql 'lisp)) tail) + `(progn ,@tail)))) + +(export 'define-c-storage-specifier-syntax) +(defmacro define-c-storage-specifier-syntax (name bvl &body body) + "Define a C storage-specifier syntax function. + + A function defined by BODY and with lambda-list BVL is associated wth the + NAME. When `expand-c-storage-specifier' sees a list (NAME . STUFF), it + will call this function with the argument list STUFF." + (with-gensyms (head tail) + (multiple-value-bind (doc decls body) (parse-body body) + `(eval-when (:compile-toplevel :load-toplevel :execute) + (defmethod expand-c-storage-specifier-form + ((,head (eql ',name)) ,tail) + ,@doc + (destructuring-bind ,bvl ,tail + ,@decls + (block ,name ,@body))) + ',name)))) + +;;;-------------------------------------------------------------------------- +;;; A type for carrying storage specifiers. + +(export '(c-storage-specifiers-type c-type-specifiers)) +(defclass c-storage-specifiers-type (c-type) + ((specifiers :initarg :specifiers :type list :reader c-type-specifiers) + (subtype :initarg :subtype :type c-type :reader c-type-subtype)) + (:documentation + "A type for carrying storage specifiers. + + Properly, storage specifiers should only appear on an outermost type. + This fake C type is a handy marker for the presence of storage specifiers, + so that they can be hoisted properly when constructing derived types.")) + +(export 'wrap-c-type) +(defun wrap-c-type (wrapper-func base-type) + "Handle storage specifiers correctly when making a derived type. + + WRAPPER-FUNC should be a function which will return some derived type of + BASE-TYPE. This function differs from `funcall' only when BASE-TYPE is + actually a `c-storage-specifiers-type', in which case it invokes + WRAPPER-FUNC on the underlying type, and re-attaches the storage + specifiers to the derived type." + (if (typep base-type 'c-storage-specifiers-type) + (let* ((unwrapped-type (c-type-subtype base-type)) + (wrapped-type (funcall wrapper-func unwrapped-type)) + (specifiers (c-type-specifiers base-type))) + (make-or-intern-c-type 'c-storage-specifiers-type unwrapped-type + :specifiers specifiers + :subtype wrapped-type)) + (funcall wrapper-func base-type))) + +;;;-------------------------------------------------------------------------- ;;; Function arguments. (export '(argument argumentp make-argument argument-name argument-type))