src/: Enhance `definst' to allow general BVL syntax.
[sod] / src / codegen-proto.lisp
index 264fd03..4bfaeca 100644 (file)
      * Instance slots named after the ARGS, with matching keyword initargs,
        and `inst-ARG' readers.
 
-     * A constructor `make-CODE-inst' which accepts the ARGS (in order, not
-       with keywords) as arguments and returns a fresh instance.
+     * A constructor `make-CODE-inst' which accepts the ARGS (as an ordinary
+       BVL) as arguments and returns a fresh instance.
 
      * A print method, which prints a diagnostic dump if `*print-escape*' is
        set, or invokes the BODY (with STREAMVAR bound to the output stream)
    If EXPORT is non-nil, then export the `CODE-inst' and `make-CODE-inst'
    symbols."
 
-  (let ((inst-var (gensym "INST"))
-       (class-name (symbolicate code '-inst))
-       (constructor-name (symbolicate 'make- code '-inst))
-       (keys (mapcar (lambda (arg) (intern (symbol-name arg) :keyword))
-                     args)))
+  (let* ((inst-var (gensym "INST"))
+        (class-name (symbolicate code '-inst))
+        (constructor-name (symbolicate 'make- code '-inst))
+        (slots (mapcan (lambda (arg)
+                         (if (listp arg) (list (car arg))
+                             (let ((name (symbol-name arg)))
+                               (if (and (plusp (length name))
+                                        (char/= (char name 0) #\&))
+                                   (list arg)
+                                   nil))))
+                       args))
+        (keys (mapcar (lambda (arg) (intern (symbol-name arg) :keyword))
+                      slots)))
     `(progn
        (defclass ,class-name (inst)
-        ,(mapcar (lambda (arg key)
-                   `(,arg :initarg ,key :reader ,(symbolicate 'inst- arg)))
-                 args keys))
+        ,(mapcar (lambda (slot key)
+                   `(,slot :initarg ,key
+                           :reader ,(symbolicate 'inst- slot)))
+                 slots keys))
        (defun ,constructor-name (,@args)
-        (make-instance ',class-name ,@(mappend #'list keys args)))
+        (make-instance ',class-name ,@(mappend #'list keys slots)))
        (defmethod inst-metric ((,inst-var ,class-name))
-        (with-slots (,@args) ,inst-var
-          (+ 1 ,@(mapcar (lambda (arg) `(inst-metric ,arg)) args))))
+        (with-slots (,@slots) ,inst-var
+          (+ 1 ,@(mapcar (lambda (slot) `(inst-metric ,slot)) slots))))
        (defmethod print-object ((,inst-var ,class-name) ,streamvar)
-        (with-slots (,@args) ,inst-var
+        (with-slots (,@slots) ,inst-var
           (if *print-escape*
               (print-unreadable-object (,inst-var ,streamvar :type t)
                 (format stream "~@<~@{~S ~@_~S~^ ~_~}~:>"
-                        ,@(mappend #'list keys args)))
+                        ,@(mappend #'list keys slots)))
               (block ,code ,@body))))
        ,@(and export `((export '(,class-name ,constructor-name
-                                ,@(mapcar (lambda (arg)
-                                            (symbolicate 'inst- arg))
-                                          args)))))
+                                ,@(mapcar (lambda (slot)
+                                            (symbolicate 'inst- slot))
+                                          slots)))))
        ',code)))
 
 ;; Formatting utilities.
 ;; package or the `common-lisp' package.  Use gensyms for these slot names to
 ;; prevent them from leaking.
 
-(definst var (stream :export t) (name #1=#:type init)
+(definst var (stream :export t) (name #1=#:type &optional init)
   (pprint-c-type #1# stream name)
   (when init
     (format stream " = ~A" init))
   (format stream "~@<~A ~A= ~@_~2I~A;~:>" var op #1#))
 
 ;; Special kinds of expressions.
-(definst call (stream :export t) (#1=#:func args)
+(definst call (stream :export t) (#1=#:func &rest args)
   (format stream "~A(~@<~{~A~^, ~_~}~:>)" #1# args))
 
 ;; Simple statements.
   (format stream "{~:@_~@<  ~2I~@[~{~A~:@_~}~:@_~]~{~A~^~:@_~}~:>~:@_}"
          decls body))
 
-(definst if (stream :export t) (#1=#:cond conseq alt)
+(definst if (stream :export t) (#1=#:cond conseq &optional alt)
   (format-compound-statement (stream conseq alt)
     (format stream "if (~A)" #1#))
   (when alt
 (export 'deliver-call)
 (defun deliver-call (codegen target func &rest args)
   "Emit a statement to call FUNC with ARGS and deliver the result to TARGET."
-  (deliver-expr codegen target (make-call-inst func args)))
+  (deliver-expr codegen target (apply #'make-call-inst func args)))
 
 ;;;----- That's all, folks --------------------------------------------------