rendered paste body;;;; Fun with macros and custom accessors in Common Lisp
;;;; These do not use the Meta-Object Protocol.
(declaim
(optimize (speed 3) (safety 1)))
(defun db-defstruct-filter-key (lst)
(let ((res nil))
(do ((e lst (nthcdr 2 e)))
((or (null (first e)) (null (second e))) t)
(let ((key (first e)) (val (second e)))
(if (not (eq key ':%id))
(progn
(push val res)
(push key res)))))
res))
(defmacro db-defstruct-p (structure)
(let ((newp (intern (format nil "DB-~S-P" structure)))
(oldp (intern (format nil "~S-P" structure))))
`(progn
(declaim (inline ,newp))
(defun ,newp (o)
(,oldp o)))))
(defmacro db-defstruct-constructor (structure)
(let ((newconstructor (intern (format nil "DB-MAKE-~S" structure)))
(oldconstructor (intern (format nil "MAKE-~S" structure))))
`(progn
(defun ,newconstructor (&rest parameters)
(let* ((valid (db-defstruct-filter-key parameters))
(instance (apply #',oldconstructor valid)))
(db-constructor ',structure instance valid)
instance)))))
(defmacro db-defstruct-accessor (structure slot)
(let ((newslot (intern (format nil "DB-~S-~S" structure slot)))
(oldslot (intern (format nil "~S-~S" structure slot))))
`(progn
(defun ,newslot (o)
(,oldslot o))
(defun (setf ,newslot) (v o)
(let ((res (db-fset ',structure ',slot o (,oldslot o) v)))
(setf (,oldslot o) res)
res)))))
(defmacro db-defstruct (structure &rest slots)
(let* ((validslots
(remove-if #'(lambda (e) (eq (first e) '%id)) slots))
(accessors
(mapcar #'(lambda (e)
`(db-defstruct-accessor ,structure ,(first e)))
validslots)))
`(progn
(defstruct ,structure
(%id nil)
,@validslots)
(db-defstruct-constructor ,structure)
(db-defstruct-p ,structure)
,@accessors
(db-defstruct-function ',structure ',slots))))
(defun db-defstruct-function (structure &rest slots)
(format t "; Creating structure of type ~S with slots ~S~%"
structure slots)
t)
(defun db-constructor (structure object &rest parameters)
(declare (ignore parameters))
(format t "; Constructing object of type ~S: ~S~%" structure object))
(defun db-fset (structure slot object oldvalue value)
(declare (ignore object))
(format t "; Assigning ~S over ~S for slot ~S of type ~S~%"
value oldvalue slot structure)
value)