- `(progn
- (defclass ,class-name (inst)
- ,(mapcar (lambda (public-slot private-slot key)
- `(,private-slot :initarg ,key
- :reader ,(symbolicate 'inst- public-slot)))
- public private keys))
- (defun ,constructor-name (,@bvl)
- (make-instance ',class-name ,@(mappend #'list keys public)))
- (defmethod inst-metric ((,inst-var ,class-name))
- (with-slots (,@private) ,inst-var
- (+ 1 ,@(mapcar (lambda (slot) `(inst-metric ,slot)) private))))
- (defmethod print-object ((,inst-var ,class-name) ,streamvar)
- (with-slots ,(mapcar #'list public private) ,inst-var
- (if *print-escape*
- (print-unreadable-object (,inst-var ,streamvar :type t)
- (format stream "~@<~@{~S ~@_~S~^ ~_~}~:>"
- ,@(mappend #'list keys public)))
- (block ,code ,@body))))
- ,@(and export `((export '(,class-name ,constructor-name
- ,@(mapcar (lambda (slot)
- (symbolicate 'inst- slot))
- public)))))
- ',code))))
+ (multiple-value-bind (docs decls body) (parse-body body)
+
+ ;; We have many jobs to do in the expansion.
+ `(progn
+
+ ;; A class to hold the data.
+ (defclass ,class-name (inst)
+ ,(mapcar (lambda (public-slot private-slot key)
+ `(,private-slot :initarg ,key
+ :reader
+ ,(symbolicate 'inst- public-slot)))
+ public private keys))
+
+ ;; A constructor to make an instance of the class.
+ (defun ,constructor-name (,@bvl)
+ (make-instance ',class-name ,@(mappend #'list keys public)))
+
+ ;; A method on `inst-metric', to feed into inlining heuristics.
+ (defmethod inst-metric ((,inst-var ,class-name))
+ (with-slots (,@private) ,inst-var
+ (+ 1 ,@(mapcar (lambda (slot) `(inst-metric ,slot))
+ private))))
+
+ ;; A method to actually produce the necessary output.
+ (defmethod print-object ((,inst-var ,class-name) ,streamvar)
+ (with-slots ,(mapcar #'list public private) ,inst-var
+ (if *print-escape*
+ (print-unreadable-object (,inst-var ,streamvar :type t)
+ (format ,streamvar "~@<~@{~S ~@_~S~^ ~_~}~:>"
+ ,@(mappend #'list keys public)))
+ (block ,code
+ ,@(if (null decls) body
+ `((locally ,@decls ,@body)))))))
+
+ ;; Maybe export all of this stuff.
+ ,@(and export `((export '(,class-name ,constructor-name
+ ,@(mapcar (lambda (slot)
+ (symbolicate 'inst- slot))
+ public)))))
+
+ ;; Remember the documentation.
+ ,@(and docs `((setf (get ',class-name 'inst-documentation)
+ ,@docs)))
+
+ ;; And try not to spam a REPL.
+ ',code)))))
+
+(defmethod documentation ((symbol symbol) (doc-type (eql 'inst)))
+ (get symbol 'inst-documentation))
+(defmethod (setf documentation) (doc (symbol symbol) (doc-type (eql 'inst)))
+ (setf (get symbol 'inst-documentation) doc))