home *** CD-ROM | disk | FTP | other *** search
- ; useful stuff for object programming
-
- ; filter certain keyword arguments for passing argument list to superclass
- (DEFUN REMOVE-KEYS (KEYS LIST)
- (COND ((NULL KEYS) LIST)
- ((NULL LIST) 'NIL)
- ((MEMBER (CAR LIST) KEYS)
- (REMOVE-KEYS (REMOVE (CAR LIST) KEYS) (CDDR LIST)))
- (T (CONS (CAR LIST) (REMOVE-KEYS KEYS (CDR LIST))))))
-
-
- ; fix so that classes can be named (requires PNAME ivar in class Class)
- ; The source files have been modified for PNAME instance variable,
- ; and printing of class PNAME if it exists.
-
- (SEND CLASS :ANSWER :SET-PNAME
- '(NAME)
- '((SETF PNAME (STRING NAME))))
-
-
- ; *SETF* property of SEND is set to allow setting instance variables
- (setf (get 'send '*setf*)
- #'(lambda (obj ivar value)
- (send obj :set-ivar (get ivar 'ivarname) value)))
-
- ; (defclass <classname> [(<instvars>) [(<classvars>) [<superclass>]]])
- ; defclass sets up access methods for all instance and class variables!
- ; an instance variable can be of form <ivar> or (<ivar> <init>)
- ; :ISNEW is automatically defined to accept keyword arguments to overide
- ; default initialization.
-
- (DEFMACRO DEFCLASS (NAME &OPTIONAL IVARS CVARS SUPER
- &AUX (SYM (GENSYM)) (SYM2 (GENSYM)))
- ; CIVAR is instance variable list with init values removed
- (LET ((CIVARS (MAPCAR #'(LAMBDA (X) (IF (CONSP X) (CAR X) X))
- IVARS)))
-
- `(PROGN ; create class and assign to global variable
- (SETF ,NAME
- (SEND CLASS :NEW
- ',CIVARS
- ',CVARS
- ,@(IF SUPER (LIST SUPER) NIL)))
-
- ; Set the name ivar of the class
- (SEND ,NAME :SET-PNAME ',NAME)
-
- ; Generate the :<ivar> and :<cvar> methods
- ,@(MAPCAR #'(LAMBDA (ARG)
- `(SEND ,NAME
- :ANSWER
- ,(INTERN (STRCAT ":" (STRING ARG)))
- 'NIL
- '(,ARG)))
- (APPEND CIVARS CVARS))
-
- ; The method needed to set the instance variables
- (SEND ,NAME :ANSWER :SET-IVAR
- '(,SYM ,SYM2)
- '((EVAL (LIST 'SETQ ,SYM (LIST 'QUOTE ,SYM2) ))))
-
- ; Set the ivarname property of the :<ivar> symbols
- ,@(MAPCAR #'(LAMBDA (ARG)
- `(SETF (GET ',(INTERN (STRCAT ":" (STRING ARG)))
- 'IVARNAME)
- ',ARG))
- CIVARS)
-
- ; Generate the :ISNEW method
- (SEND ,NAME
- :ANSWER :ISNEW
- '(&REST ,SYM &KEY ,@IVARS)
-
- ; first :ISNEW setfs
- ; for all its declared instance variables
- '(,@(MAPCAR #'(LAMBDA (ARG)
- `(SETF (SEND SELF
- ,(INTERN (STRCAT ":"
- (STRING ARG))))
- ,ARG))
- CIVARS)
-
- ; then the remaining initialization arguments are
- ; passed to the superclass.
- (APPLY #'SEND-SUPER
- (CONS ':ISNEW
- (REMOVE-KEYS
- ',(MAPCAR #'(LAMBDA (ARG)
- (INTERN (STRCAT ":"
- (STRING ARG))))
- CIVARS)
- ,SYM)))
- self)))))
-
-
- ; (defmethod <class> <message> (<arglist>) <body>)
-
- (DEFMACRO DEFMETHOD (CLASS MESSAGE ARGLIST &REST BODY)
- `(SEND ,CLASS
- :ANSWER
- ,MESSAGE
- ',ARGLIST
- ',BODY))
-
- ; (definst <class> <instname> [<args>...])
-
- (DEFMACRO DEFINST (CLASS NAME &REST ARGS)
- `(SETF ,NAME
- (SEND ,CLASS
- :NEW
- ,@ARGS)))
-
- ; (extensions suggested by Jim Ferrans)
-
- (DEFUN CLASSP (NAME)
- (WHEN (OBJECTP NAME)
- (EQ (SEND NAME :CLASS) CLASS)))
-
- (DEFMETHOD CLASS :SUPERCLASS () SUPERCLASS)
- (DEFMETHOD CLASS :MESSAGES () MESSAGES)
-
- (DEFMETHOD OBJECT :SUPERCLASS () NIL)
-
- (DEFMETHOD OBJECT :ISMEMBEROF (CLASS)
- (EQ (SEND SELF :CLASS) CLASS))
-
- (DEFMETHOD OBJECT :ISKINDOF (CLASS)
- (DO ((THIS (SEND SELF :CLASS) (SEND THIS :SUPERCLASS)))
- ((OR (NULL THIS)(EQ THIS CLASS))
- (EQ THIS CLASS))))
-
- (DEFMETHOD OBJECT :RESPONDSTO (SELECTOR &AUX TEMP)
- (DO ((THIS (SEND SELF :CLASS) (SEND THIS :SUPERCLASS)))
- ((OR (NULL THIS)
- (SETQ TEMP
- (NOT (NULL (ASSOC SELECTOR
- (SEND THIS :MESSAGES))))))
- TEMP)
- (SETF TEMP NIL)))
-
-
- (DEFMETHOD CLASS :IVARS () IVARS)
-
- (DEFMETHOD CLASS :PNAME () PNAME)
-
- ; :Storeon returns a list that can be executed to re-generate the object.
- ; It relies on the object's class being created using DEFCLASS, so the
- ; instance variables can be generated.
-
-
- (DEFMETHOD OBJECT :STOREON (&AUX CLASS IVLIST RES)
- (SETQ CLASS
- (SEND SELF :CLASS)
- IVLIST
- (DO ((IVARS (SEND CLASS :IVARS)
- (APPEND (SEND SUPER :IVARS) IVARS))
- (SUPER (SEND CLASS :SUPERCLASS)
- (SEND SUPER :SUPERCLASS)))
- ((EQ SUPER OBJECT) IVARS))
- RES
- (MAPCAN #'(LAMBDA (X)
- (LET ((TEMP
- (INTERN (CONCATENATE 'STRING
- ":"
- (STRING X)))))
- (LIST TEMP
- (LET ((Y (SEND SELF TEMP)))
- (IF (AND Y
- (OR (SYMBOLP Y)
- (CONSP Y)))
- (LIST 'QUOTE Y)
- Y)))))
- IVLIST))
- (APPEND (LIST 'SEND (MAKE-SYMBOL (SEND CLASS :PNAME)) ':NEW)
- RES))
-
- ; For classes we must use a different tact.
- ; We will return a PROGN that uses SENDs to create the class and any methods.
- ; It also assumes the global environment. None of the DEFxxx functions
- ; are needed to do this.
-
- ; because of the subrs used in messages, :storeon cannot be used to
- ; generate a reconstructable copy of classes Object and Class.
-
- ; Class variables are not set, because there are no class methods in XLISP
- ; to do this (one would have to create an instance, and send messages to
- ; the instance, and I feel that is going too far).
-
-
- (DEFMETHOD CLASS :STOREON (&AUX (CLASSNAME (INTERN PNAME)))
- (NCONC (LIST 'PROGN)
- (LIST (LIST 'SETQ CLASSNAME
- (LIST 'SEND 'CLASS :NEW IVARS CVARS
- (IF SUPERCLASS
- (INTERN (SEND SUPERCLASS :PNAME))
- NIL))))
- (LIST (LIST 'SEND CLASSNAME :SET-PNAME PNAME))
- (MAPCAR #'(LAMBDA (MESS &AUX
- (VAL (IF (EQ 'CLOSURE (TYPE-OF (CDR MESS)))
- (GET-LAMBDA-EXPRESSION (CDR MESS))
- (LIST NIL NIL MESS))))
- (LIST 'SEND CLASSNAME :ANSWER
- (FIRST MESS)
- (LIST 'QUOTE (CDADR VAL))
- (LIST 'QUOTE (CDDR VAL))))
- MESSAGES)))
-