- (defgeneric consify (obj)
- (:documentation "Return a consy representation of something"))
- (defmacro define-transparent-consify (type)
- (with-gensyms (obj)
- `(defmethod consify ((,obj ,type))
- ,obj)))
- (define-transparent-consify number)
- (define-transparent-consify character)
- (define-transparent-consify string)
- (define-transparent-consify symbol)
- (define-transparent-consify pathname)
- (defvar *unconsify-keywords* nil)
- (defmethod consify ((obj list))
- ;; a more flexible implementation might do (keywordp (car obj)), but this makes the output uglier
- (if (member (car obj) *unconsify-keywords*)
- (cons :quote (mapcar #'consify obj))
- (mapcar #'consify obj)))
- (defgeneric consify-initargs (obj)
- (:documentation "Return a list of initargs that would recreate this class."))
- (defmethod consify ((obj standard-object))
- `(:make-instance ,(class-name (class-of obj)) ,@(consify-initargs obj)))
- (defun consify-initargs-from-slots (obj &rest slot-names)
- (let* ((class (class-of obj))
- (slots (remove-if-not
- (lambda (slot)
- (and (c2mop:slot-definition-initargs slot)
- (or (null slot-names)
- (member (c2mop:slot-definition-name slot) slot-names))))
- (c2mop:class-slots class))))
- (loop for slot in slots
- when (and
- (slot-boundp obj (c2mop:slot-definition-name slot))
- (c2mop:slot-definition-initargs slot))
- append (list (car (c2mop:slot-definition-initargs slot))
- (consify (slot-value obj (c2mop:slot-definition-name slot)))))))
- (defmethod consify-initargs ((obj standard-object))
- (consify-initargs-from-slots obj))
- (defgeneric unconsify-list (car cdr)
- (:documentation "A list with a keyword in the car was found during unconsify! The first element
- was car, the rest were cdr."))
- (defun unconsify (obj)
- "Rehydrate the output of consify."
- (etypecase obj
- ((or string number character symbol pathname) obj)
- (list (if (keywordp (car obj))
- (unconsify-list (car obj) (cdr obj))
- (mapcar #'unconsify obj)))))
- (defmethod unconsify-list (car cdr)
- (mapcar #'unconsify (cons car cdr)))
- (defmacro defunconsify (keyword car-var cdr-var &body body)
- (declare (symbol keyword car-var cdr-var))
- `(progn
- (push ,keyword *unconsify-keywords*)
- (defmethod unconsify-list ((,car-var (eql ,keyword)) ,cdr-var)
- ,@body)))
- (defunconsify :quote car cdr
- (mapcar #'unconsify cdr))
- (defunconsify :make-instance car cdr
- ;; Verify the format of the list as we go along, for good measure
- (check-type (car cdr) symbol)
- (apply #'make-instance (car cdr)
- (loop for it in (cdr cdr)
- for argname-p = t then (not argname-p)
- when argname-p
- collect (progn
- (check-type it keyword)
- it)
- else
- collect (unconsify it)
- finally (assert (not argname-p) () "Odd number of initargs while unconsifying!"))))
- (defun consify-copy (orig)
- "Copy any consifiable object by value."
- (unconsify (consify orig)))