chiark / gitweb /
New feature: messages with keyword arguments!
[sod] / src / class-output.lisp
index b47f6ba2d6b1e34247ebf635da6e922aa8d27041..abe5132a16b3f7e14c60053975f028a41fc02632 100644 (file)
@@ -68,7 +68,8 @@ (defmethod hook-output progn ((class sod-class) (reason (eql :h)) sequencer)
      (class :vtmsgs :start) (class :vtmsgs :end)
      (class :vtables :start) (class :vtables :end)
      (class :vtable-externs) (class :vtable-externs-after)
-     (class :methods :start) (class :methods) (class :methods :end)
+     (class :methods :start) (class :methods :defs)
+     (class :methods) (class :methods :end)
      (class :ichains :start) (class :ichains :end)
      (class :ilayout :start) (class :ilayout :slots) (class :ilayout :end)
      (class :conversions)
@@ -139,6 +140,14 @@ (defmethod hook-output progn ((class sod-class) (reason (eql :h)) sequencer)
   ;; We need each message's method entry type for this, so we need to dig it
   ;; out of the vtmsgs structure.  Indeed, the vtmsgs for this class contains
   ;; entries for precisely the messages we want to make macros for.
+  (when (some (lambda (message)
+               (or (keyword-message-p message)
+                   (varargs-message-p message)))
+             (sod-class-messages class))
+    (one-off-output 'varargs-macros sequencer :early-decls
+                   (lambda (stream)
+                     (format stream
+                             "~%SOD__VARARGS_MACROS_PREAMBLE~%"))))
   (when (sod-class-messages class)
     (sequence-output (stream sequencer)
       ((class :message-macros)
@@ -174,7 +183,7 @@ (defmethod hook-output progn ((class sod-class) (reason (eql :h)) sequencer)
                        (push name in-names)
                        (push name out-names)))))
             (when varargsp
-              (format stream "#if __STDC_VERSION__ >= 199901~%"))
+              (format stream "#ifdef SOD__HAVE_VARARGS_MACROS~%"))
             (format stream "#define ~A(~{~A~^, ~}) ~
                                   ~A->_vt->~A.~A(~{~A~^, ~})~%"
                     (message-macro-name class entry)
@@ -283,7 +292,17 @@ (defmethod hook-output progn
         (princ "extern " stream)
         (pprint-c-type (commentify-function-type type) stream
                        (sod-method-function-name method))
-        (format stream ";~%"))))))
+        (format stream ";~%")))
+      ((class :methods :defs)
+       (let* ((type (sod-method-type method))
+             (keys (and (typep type 'c-keyword-function-type)
+                        (c-function-keywords type))))
+        (when keys
+          (format stream "struct ~A {~%~
+                          ~{  unsigned ~A : 1;~%~}~
+                          };~2%"
+                  (direct-method-suppliedp-struct-tag method)
+                  (mapcar #'argument-name keys))))))))
 
 (defmethod hook-output progn ((vtable vtable) (reason (eql :h)) sequencer)
   (with-slots ((class %class) chain-head chain-tail) vtable
@@ -447,15 +466,25 @@ (defmethod hook-output progn
 
 (defmethod hook-output progn
     ((method sod-method) (reason (eql :c)) sequencer)
-  (with-slots ((class %class) body) method
+  (with-slots ((class %class) role body message) method
     (unless body
       (return-from hook-output))
     (sequence-output (stream sequencer)
       :constraint ((class :direct-methods :start)
+                  (class :direct-method method :banner)
                   (class :direct-method method :start)
                   (class :direct-method method :body)
                   (class :direct-method method :end)
                   (class :direct-methods :end))
+      ((class :direct-method method :banner)
+       (format-banner-comment stream "Direct ~@[~(~A~) ~]method ~:_~
+                                     on `~A.~A' ~:_defined by `~A'."
+                             role
+                             (sod-class-nickname
+                              (sod-message-class message))
+                             (sod-message-name message)
+                             class)
+       (fresh-line stream))
       ((class :direct-method method :body)
        (pprint-c-type (sod-method-function-type method)
                      stream
@@ -471,6 +500,24 @@ (defmethod hook-output progn
   (with-slots ((class %class) functions) method
     (sequence-output (stream sequencer)
       ((class :effective-methods)
+       (let* ((keys (effective-method-keywords method))
+             (message (effective-method-message method))
+             (msg-class (sod-message-class message)))
+        (when keys
+          (format-banner-comment stream "Keyword argument structure ~:_~
+                                         for `~A.~A' ~:_on class `~A'."
+                                 (sod-class-nickname msg-class)
+                                 (sod-message-name message)
+                                 class)
+          (format stream "~&struct ~A {~%"
+                  (effective-method-keyword-struct-tag method))
+          (format stream "~{  unsigned ~A__suppliedp : 1;~%~}"
+                  (mapcar #'argument-name keys))
+          (dolist (key keys)
+            (write-string "  " stream)
+            (pprint-c-type (argument-type key) stream (argument-name key))
+            (format stream ";~%"))
+          (format stream "};~2%")))
        (dolist (func functions)
         (write func :stream stream :escape nil :circle nil))))))