;;; -*- Mode:LISP; Package:SYSTEM-INTERNALS; Fonts:(CPTFONTB); Readtable:CL; Base:10 -*- ;;; Example hairy usage of Defstruct-Define-Type. ;;; Copyright LISP Machine, Inc. 1986 ;;; See filename "Copyright.Text" for ;;; licensing and release information. ;;; ********************************************************* ;;; ********************************************************* ;;; *** NOTE: This is an EXAMPLE, not LMI supported code. *** ;;; *** information contained in this example is subject *** ;;; *** to change without notice. The ways of doing *** ;;; *** the things contained in the example may change *** ;;; *** between system releases. Some techniques which *** ;;; *** are mere examples in one release may become built *** ;;; *** in system features in the next release. Use good *** ;;; *** judgement when copying these techniques. Most *** ;;; *** examples have been motivated by specific customer *** ;;; *** requests, and may not be the best engineered *** ;;; *** or most efficient solution for someone else. *** ;;; ********************************************************* ;;; ********************************************************* ;;; Actually the usual "examples" caveat may be too strongly worded ;;; here. defstruct-define-type is a documented feature ;;; and as is the :print-self message. The thing to look for though ;;; is the :instance type becoming a built in feature in future release. ;;; 13-Aug-86 10:34:21 -GJC (defstruct-define-type :instance :named (:defstruct-keywords :ordered :VOID-DEFAULTS :make-instance) (:cons (init desc kwds) :list desc kwds `(%make-instance ',(defstruct-description-name desc) ,@init)) (:ref (slot-number desc obj) (cond ((cdr (assq :ordered (defstruct-description-property-alist desc))) `(%instance-ref ,obj ,(1+ slot-number))) ('else `(symeval-in-instance ,obj ',(caar (mem #'(lambda (n e) (= n (defstruct-slot-description-number (cdr e)))) slot-number (defstruct-description-slot-alist desc))))))) (:PREDICATE (desc name) `(defun ,name (obj) (typep obj ',(defstruct-description-name desc)))) (:defstruct (desc) (DEFSTRUCT-INSTANCE-TYPE-DEFSTRUCT DESC))) (DEFUN DEFSTRUCT-INSTANCE-TYPE-DEFSTRUCT (DESCRIPTION) ;; THIS CODE GETS CALLED FIRST WHEN A DEFSTRUCT DEFINITION IS MADE. ;; THEREFORE WE CAN OVERRIDE CERTAIN FEATURES AND IMPLEMENT THEM ;; OURSELVES. `((defflavor ,(defstruct-description-name) ,(mapcar #'(lambda (slot) (let ((code (defstruct-slot-description-init-code (cdr slot)))) ;; question of init value. add an option later (cond ((NOT (defstruct-emptyp code)) (list (car slot) code)) ((cdr (assq :VOID-DEFAULTS (defstruct-description-property-alist))) (CAR SLOT)) ('ELSE (list (car slot) nil))))) (defstruct-description-slot-alist)) ,(defstruct-description-include) :INITABLE-INSTANCE-VARIABLES ,@(if (cdr (assq :ordered (defstruct-description-property-alist))) '(:ordered-instance-variables))) ,(LET ((P (DEFSTRUCT-DESCRIPTION-PRINT))) (COND ((NOT P) `(DEFMETHOD (,(defstruct-description-name) :PRINT-SELF) (STREAM DEPTH ESCAPE-P) DEPTH ESCAPE-P (PRINT-INSTANCE-AS-#S SELF STREAM))) ('ELSE (SETF (DEFSTRUCT-DESCRIPTION-PRINT) NIL) (COND ((CAR P) ;; :PRINT-FUNCTION `(DEFMETHOD (,(defstruct-description-name) :PRINT-SELF) (STREAM DEPTH ESCAPE-P) ESCAPE-P (IF PRINT-READABLY (PRINT-NOT-READABLE SELF) (FUNCALL ',(CADR P) SELF STREAM DEPTH)))) ('ELSE `(DEFMETHOD (,(defstruct-description-name) :PRINT-SELF) (STREAM DEPTH ESCAPE-P) DEPTH ESCAPE-P (IF PRINT-READABLY (PRINT-NOT-READABLE SELF) (LET ((,(defstruct-description-name) SELF)) (FORMAT STREAM ,@(CDR P)))))))))) ,@(LET ((DEFAULT-CS (AND (DEFSTRUCT-DESCRIPTION-CALLABLE-CONSTRUCTORS) (cdr (assq :make-instance (defstruct-description-property-alist))) (SUBSET #'(LAMBDA (CS) (NULL (CDR CS))) (DEFSTRUCT-DESCRIPTION-CONSTRUCTORS))))) (WHEN DEFAULT-CS (SETF (DEFSTRUCT-DESCRIPTION-CONSTRUCTORS) (SET-DIFFERENCE (DEFSTRUCT-DESCRIPTION-CONSTRUCTORS) DEFAULT-CS)) (CONS ;; PUT'EM BACK AT RUNTIME FOR #S() IN READ. ETC. `(SETF (DEFSTRUCT-DESCRIPTION-CONSTRUCTORS (GET-DEFSTRUCT-DESCRIPTION ',(DEFSTRUCT-DESCRIPTION-NAME))) (APPEND ',DEFAULT-CS (DEFSTRUCT-DESCRIPTION-CONSTRUCTORS (GET-DEFSTRUCT-DESCRIPTION ',(DEFSTRUCT-DESCRIPTION-NAME))))) (MAPCAR #'(LAMBDA (CS) `(DEFUN ,(CAR CS) (&REST L) (DECLARE (ARGLIST &KEY ,@(mapcar #'car (defstruct-description-slot-alist)))) (APPLY #'MAKE-INSTANCE ',(DEFSTRUCT-DESCRIPTION-NAME) L))) DEFAULT-CS)))))) (DEFUN PRINT-INSTANCE-AS-#S (OBJECT STREAM) (FORMAT STREAM "#S(~S" (TYPE-OF OBJECT)) (DO ((IVARS (FLAVOR-ALL-INSTANCE-VARIABLES (INSTANCE-FLAVOR OBJECT)) (CDR IVARS)) (I 1 (1+ I))) ((NULL IVARS)) (COND ((= (%P-LDB-OFFSET %%Q-DATA-TYPE OBJECT I) DTP-NULL)) ('ELSE (FORMAT STREAM " ~S ~S" (CAR IVARS) (%INSTANCE-REF OBJECT I))))) (FORMAT STREAM ")"))