src/c-types-parse.lisp: Hoist up the `ds-FOO' methods for raw types.
[sod] / src / c-types-parse.lisp
index 45336a1..4475c72 100644 (file)
@@ -7,7 +7,7 @@
 
 ;;;----- Licensing notice ---------------------------------------------------
 ;;;
-;;; This file is part of the Sensble Object Design, an object system for C.
+;;; 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
   ;; accessor functions later.
   ((label :type keyword :initarg :label :reader ds-label)
    (name :type string :initarg :name :reader ds-name)
-   (kind :type (member type sign size qualifier)
+   (kind :type (member type complexity sign size qualifier)
         :initarg :kind :reader ds-kind)
    (taggedp :type boolean :initarg :taggedp
            :initform nil :reader ds-taggedp))
   (:documentation
    "Represents the important components of a declaration specifier.
 
-    The only interesting instances of this class are in the table
-    `*declspec-map*'."))
+   The only interesting instances of this class are in the table
+   `*declspec-map*'."))
 
 (defmethod shared-initialize :after ((ds declspec) slot-names &key)
   "If no name is provided then derive one from the label.
 
 (defparameter *declspec-map*
   (let ((map (make-hash-table :test #'equal)))
-    (dolist (item '((type :void :char :int :float :double)
+    (dolist (item '((type :void :char :int :float :double
+                         (:bool :compat "_Bool"))
+                   (complexity (:complex :compat "_Complex")
+                               (:imaginary :compat "_Imaginary"))
                    ((type :taggedp t) :enum :struct :union)
                    (size :short :long (:long-long :name "long long"))
                    (sign :signed :unsigned)
          (destructuring-bind (label
                               &key
                               (name (string-downcase label))
+                              compat
                               (taggedp taggedp))
              (if (consp spec) spec (list spec))
            (let ((ds (make-instance 'declspec
                                     :label label
-                                    :name name
+                                    :name (or compat name)
                                     :kind kind
                                     :taggedp taggedp)))
              (setf (gethash name map) ds
-                   (gethash label map) ds))))))
+                   (gethash label map) ds)
+             (when compat
+               (setf (gethash compat map) ds)))))))
     map)
   "Maps symbolic labels and textual names to `declspec' instances.")
 
+(defmethod ds-label ((ty c-type)) :c-type)
+(defmethod ds-name ((ty c-type)) (princ-to-string ty))
+(defmethod ds-kind ((ty c-type)) 'type)
+
 ;; A collection of declaration specifiers, and how to merge them together.
 
 (defclass declspecs ()
   ;; This could have been done with `defstruct' just as well, but a
   ;; `defclass' can be tweaked interactively, which is a win at the moment.
   ((type :initform nil :initarg :type :reader ds-type)
+   (complexity :initform nil :initarg :complexity :reader ds-complexity)
    (sign :initform nil :initarg :sign :reader ds-sign)
    (size :initform nil :initarg :size :reader ds-size)
    (qualifier :initform nil :initarg :qualifiers :reader ds-qualifiers))
-  (:documentation
-   "Represents a collection of declaration specifiers.
+  (:documentation "Represents a collection of declaration specifiers.
 
-    This is used during type parsing to represent the type under
-    construction.  Instances are immutable: we build new ones rather than
-    modifying existing ones.  This leads to a certain amount of churn, but
-    we'll just have to live with that.
+   This is used during type parsing to represent the type under construction.
+   Instances are immutable: we build new ones rather than modifying existing
+   ones.  This leads to a certain amount of churn, but we'll just have to
+   live with that.
 
-    (Why are instances immutable?  Because it's much easier to merge a new
-    specifier into an existing collection and then check that the resulting
-    thing is valid, rather than having to deal with all of the possible
-    special cases of what the new thing might be.  And if the merged
-    collection isn't good, I must roll back to the previous version.  So I
-    don't get to take advantage of a mutable structure.)"))
-
-(defmethod ds-label ((ty c-type)) :c-type)
-(defmethod ds-name ((ty c-type)) (princ-to-string ty))
-(defmethod ds-kind ((ty c-type)) 'type)
+   (Why are instances immutable?  Because it's much easier to merge a new
+   specifier into an existing collection and then check that the resulting
+   thing is valid, rather than having to deal with all of the possible
+   special cases of what the new thing might be.  And if the merged
+   collection isn't good, I must roll back to the previous version.  So I
+   don't get to take advantage of a mutable structure.)"))
 
 (defparameter *good-declspecs*
-  '(((:int) (:signed :unsigned) (:short :long :long-long))
-    ((:char) (:signed :unsigned) ())
-    ((:double) () (:long))
-    (t () ()))
+  '(((:int) (:signed :unsigned) (:short :long :long-long) ())
+    ((:char) (:signed :unsigned) () ())
+    ((:double) () (:long) (:complex :imaginary))
+    (t () () ()))
   "List of good collections of declaration specifiers.
 
-   Each item is a list of the form (TYPES SIGNS SIZES).  Each of TYPES, SIGNS
-   and SIZES is either a list of acceptable specifiers of the appropriate
-   kind, or T, which matches any specifier.")
+   Each item is a list of the form (TYPES SIGNS SIZES COMPLEXITIES).  Each of
+   TYPES, SIGNS, SIZES, and COMPLEXITIES, is either a list of acceptable
+   specifiers of the appropriate kind, or T, which matches any specifier.")
 
 (defun good-declspecs-p (specs)
   "Are SPECS a good collection of declaration specifiers?"
-  (let ((speclist (list (ds-type specs) (ds-sign specs) (ds-size specs))))
+  (let ((speclist (list (ds-type specs)
+                       (ds-sign specs)
+                       (ds-size specs)
+                       (ds-complexity specs))))
     (some (lambda (it)
            (every (lambda (spec pat)
                     (or (eq pat t) (null spec)
   (let ((type (ds-type specs))
        (size (ds-size specs))
        (sign (ds-sign specs))
+       (cplx (ds-complexity specs))
        (quals (mapcar #'ds-label (ds-qualifiers specs))))
     (cond ((typep type 'c-type)
           (qualify-c-type type quals))
-         ((or type size sign)
+         ((or type size sign cplx)
           (when (and sign (eq (ds-label sign) :signed)
                      (eq (ds-label type) :int))
             (setf sign nil))
           (make-simple-type (format nil "~{~@[~A~^ ~]~}"
                                     (mapcar #'ds-name
                                             (remove nil
-                                                    (list sign size type))))
+                                                    (list sign cplx
+                                                          size type))))
                             quals))
          (t
           nil))))
   ;; Turns out to be easier to do this by hand.
   (let ((ds (and (eq (token-type scanner) :id)
                 (let ((kw (token-value scanner)))
-                  (or (gethash kw *module-type-map*)
+                  (or (and (boundp '*module-type-map*)
+                           (gethash kw *module-type-map*))
                       (gethash kw *declspec-map*))))))
     (cond ((or (not ds) (and predicate (not (funcall predicate ds))))
           (values (list indicator) nil nil))
                          (cons #'identity name))))
 
               (argument-list ()
-                ;; [ argument [ `,' argument ]* [ `,' `...' ] ] | `...'
+                ;; [argument [`,' argument]* [`,' `...']] | `...'
                 ;;
                 ;; The possibility of a trailing `,' `...' means that we
                 ;; can't use the standard `list' parser.  Note that, unlike