Very ragged work-in-progress.
[sod] / cutting-room-floor.lisp
index 1781f98..2f82c65 100644 (file)
@@ -8,7 +8,7 @@
        #+ecl #:clos)
   (:export #:c-type
           #:c-declarator-priority #:maybe-parenthesize
-          #:c-declaration
+          #:pprint-c-type
           #:c-type-subtype #:compount-type-declaration
           #:qualifiable-c-type #:c-type-qualifiers #:format-qualifiers
           #:simple-c-type #:c-type-name
          (ldb t-byte flags) type)
     flags))
 
+
+(defun expand-c-type (spec)
+  "Parse SPEC as a C type and return the result.
+
+   The SPEC can be one of the following.
+
+     * A C-TYPE object, which is returned immediately.
+
+     * A list, (OPERATOR . ARGUMENTS), where OPERATOR is a symbol: a parser
+       function associated with the OPERATOR symbol by DEFINE-C-TYPE-SYNTAX
+       or some other means is invoked on the ARGUMENTS, and the result is
+       returned.
+
+     * A symbol, which is treated the same way as a singleton list would be."
+
+  (flet ((interp (sym)
+          (or (get sym 'c-type)
+              (error "Unknown C type operator ~S." sym))))
+    (etypecase spec
+      (c-type spec)
+      (symbol (funcall (interp spec)))
+      (list (apply (interp (car spec)) (cdr spec))))))
+
+(defmacro c-type (spec)
+  "Evaluates to the type that EXPAND-C-TYPE would return.
+
+   Currently this just quotes SPEC and calls EXPAND-C-TYPE at runtime.  Maybe
+   later it will do something more clever."
+  `(expand-c-type ',spec))
+
+;; S-expression machinery.  Qualifiers have hairy syntax and need to be
+;; implemented by hand.
+
+(defun qualifier (qual &rest args)
+  "Parse a qualified C type.
+
+   The ARGS consist of a number of qualifiers and exactly one C-type
+   S-expression.  The result is a qualified version of this type, with the
+   given qualifiers attached."
+  (if (null args)
+      qual
+      (let* ((things (mapcar #'expand-c-type args))
+            (quals (delete-duplicates
+                    (sort (cons qual (remove-if-not #'keywordp things))
+                          #'string<)))
+            (types (remove-if-not (lambda (thing) (typep thing 'c-type))
+                                  things)))
+       (when (or (null types)
+                 (not (null (cdr types))))
+         (error "Only one proper type expected in ~S." args))
+       (qualify-type (car types) quals))))
+(setf (get 'qualifier 'c-type) #'qualifier)
+
+(defun declare-qualifier (qual)
+  "Defines QUAL as being a type qualifier.
+
+   When used as a C-type operator, it applies that qualifier to the type that
+   is its argument."
+  (let ((kw (intern (string qual) :keyword)))
+    (setf (get qual 'c-type)
+         (lambda (&rest args)
+           (apply #'qualifier kw args)))))
+
+;; Define some initial qualifiers.
+(dolist (qual '(const volatile restrict))
+  (declare-qualifier qual))
+
+
+(define-c-type-syntax simple-c-type (name)
+  "Constructs a simple C type called NAME (a string or symbol)."
+  (make-simple-type (c-name-case name)))
+
+(defmethod print-c-type :around
+    (stream (type qualifiable-c-type) &optional colon atsign)
+  (if (c-type-qualifiers type)
+      (pprint-logical-block (stream nil :prefix "(" :suffix ")")
+       (format stream "QUALIFIER~{ ~:_~:I~A~} ~:_"
+               (c-type-qualifiers type))
+       (call-next-method stream type colon atsign))
+      (call-next-method)))
+;; S-expression syntax.
+
+
+(define-c-type-syntax enum (tag)
+  "Construct an enumeration type named TAG."
+  (make-instance 'c-enum-type :tag (c-name-case tag)))
+(define-c-type-syntax struct (tag)
+  "Construct a structure type named TAG."
+  (make-instance 'c-struct-type :tag (c-name-case tag)))
+(define-c-type-syntax union (tag)
+  "Construct a union type named TAG."
+  (make-instance 'c-union-type :tag (c-name-case tag)))
+
+(defgeneric make-me-argument (message class)
+  (:documentation
+   "Return an ARGUMENT object for the `me' argument to MESSAGE, as
+   specialized to CLASS."))
+
+(defmethod make-me-argument
+    ((message basic-message) (class sod-class))
+  (make-argument "me" (make-instance 'c-pointer-type
+                                    :subtype (sod-class-type class))))