home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / CLIPPER / MISC / AIE8901.ZIP / POBCODE.CDE < prev    next >
Encoding:
Text File  |  1988-05-04  |  26.9 KB  |  535 lines

  1. ca oboiecode
  2. WORKING (MESSAGE PENDING)
  3. NO SUCH COMMAND
  4. ca obiecode
  5. WORKING (MESSAGE PENDING)
  6. {slOBIECODE {quKRK-AI    {opKRK   ;12/22,13:37 {hj               {bt
  7. ;; POB.LISP
  8.  
  9. ;;; Shawn Amir
  10. ;;; P.O. Box 1249
  11. ;;; Menlo Park, CA  94026
  12.  
  13. ;;; Dec 11, 1988
  14.  
  15. ;;; This file defines the Property-list OBject (POB) language, an object oriented database
  16. ;;; facility, as summarized in the January 1989 issue of AI expert.  This file contains the
  17. ;;; entire language definition and implementation.  Please feel free to use, copy, modify,
  18. ;;; and generally have a good time with POB!  Written comments and suggestions are welcome.
  19.  
  20. ;;; The other files of interest are:     OBIE.LISP           OBject oriented Inference Engine
  21. ;;;                                      MAM-Dialog.LISP     Dialog window for mini application
  22. ;;;                                      MAM-KS.LISP         Rules for mini application
  23.  
  24. ;;; Developed on a Macintosh II, 2MB of RAM, and Allegro Common LISP 1.1 from Coral Software
  25. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  26.  
  27. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  28. ;;; Everything in the database is an object.  Each object has the following form of a 
  29. ;;; symbol and its property list.
  30. ;;;
  31. ;;;     Node
  32. ;;;       :POB-NAME      Symbol
  33. ;;;       :POB-SUP-L     (Node1 Node2 Node3 ...)
  34. ;;;       :POB-SUB-L     (Node1 Node2 Node3 ...)
  35. ;;;       :POB-MSG-L     (Msg1 Fn1 Msg2 Fn2 Msg3 Fn3 ...)
  36. ;;;       :POB-SLOT-L    (Slot-A Slot-B Slot-C ...)
  37. ;;;       :SLot-A       Value
  38. ;;;       :Slot-B       Value
  39. ;;;       :Slot-C       Value
  40. ;;;        . . .        . . .
  41. ;;;
  42. ;;; 
  43. ;;; NODE corresponds to a unique symbol name gensym, :POB-NAME is a property, and
  44. ;;; SYMBOL is the type of value that it will have.  Slot-A, Slot-B, etc. are
  45. ;;; user-defined properties and are listed in the value for the property :POB-SLOT-L.
  46. ;;; 
  47. ;;; Each node has a number of superiors and a number of subordinates, listed in the
  48. ;;; values for POB-SUP-L and POB-SUB-L respectively.  When a new object is
  49. ;;; instantiated, it will get all the user-defined slots and values that are
  50. ;;; associated with its superiors.  In case of overlap and duplications, the values
  51. ;;; come from the closest superior in a depth-first left-to-right traversal of the
  52. ;;; tree formed by the superiors.
  53. ;;; 
  54. ;;; The SEND function is the method used to get functions to act.  A send takes the
  55. ;;; format of a message and the appropriate arguments.  The object then finds a
  56. ;;; function for the message and executes it with the appropriate arguments.
  57. ;;; 
  58. ;;; The POB-MSG-L slot of each object contains a property list of messages and
  59. ;;; functions associated with them.  Whenever a message is sent to an object, this
  60. ;;; list is first searched to find and execute the appropriate function.  However,
  61. ;;; if no matching message was found in POB-MSG-L then the tree of superiors is
  62. ;;; searched in  a left-to-right and depth-first  manner to locate the first
  63. ;;; instance of a matching message.
  64. ;;;
  65. ;;; Read macros have been defined to simplify accessing properties in objects.
  66. ;;; Instead of writing (Get G075 :POB-SLOT-L) we write [G075 :POB-SLOT-L].  In the
  67. ;;; future changing the underlying representation of objects will be much easier
  68. ;;; if the "[...]" access method is used exclusively.
  69. ;;;
  70. ;;; The main functions in the database are POB-DEFOBJ and POB-SEND which are used to
  71. ;;; define new objects and send them messages for execution.  POB-DEFMSG is used for
  72. ;;; defining new messages and associating them with objects.
  73. ;;;
  74. ;;; By convention, each object in the database will inherit from *POB-OBJ*.  *POB-OBJ*
  75. ;;; defines a minimal set of utility messages:
  76. ;;;
  77. ;;; :ADD-MSG          Adds a message definition to the object
  78. ;;; :DEL-MSG          Remove a message definition from the object
  79. ;;; :GET-MSG-L        Returns the list of messages store IN the object (No inheritance)
  80. ;;; :ADD-SLOT         Add new slot and value to the object
  81. ;;; :DEL-SLOT         Remove old slot from the object
  82. ;;; :ADD-SUP          Add new superior to the object
  83. ;;; :DEL-SUP          delete old superior from the object
  84. ;;; :MAKE-Obj         Add new object
  85. ;;; :DEL-OBJ          Delete existing object
  86. ;;; :GET-SLOT         Return value of existing slot in object
  87. ;;; :SET-SLOT         Set the value of slot in object
  88. ;;; :PRINT-SELF       Print the contents of the object (For debugging)
  89. ;;; :PRINT-SLOT       Prints the contents of specified (or all user-defined slots)
  90.  
  91. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  92. ;;; UTILITIES
  93.  
  94. ;;; Revert-ReadTable changes the current readtable to the standard CommonLisp one.
  95.  
  96. (Defun Revert-Readtable ()
  97.   (Setq *ReadTable* (Copy-Readtable Nil)))
  98.  
  99. ;;; [-Reader is used to implement data access syntax.  It currently translates to
  100. ;;; property list accesses, but this can be easily changed in the future.
  101. ;;;
  102. ;;; [a b c 'd]                     means get field 'D of field C of field B 
  103. ;;;                                of data item A and translates into:
  104. ;;; (getF (getF (get a b) c) 'd)
  105.  
  106. (Eval-when (Eval Load Compile)
  107.   (Defun |[-Reader| (Stream Char)
  108.     (Declare (Ignore Char))                                       ; Ignore the char arg
  109.     (Let ((Arg (Read-Delimited-List #\] Stream T)))               ; Read till "]" 
  110.       (Cond ((Atom Arg) Arg)                                      ; Ignore if Atom
  111.             ((Null (Cdr Arg)) (Cons 'Symbol-Plist Arg))           ; Length is 1
  112.             (T (Do ((ArgList (Cddr Arg) (Cdr ArgList))
  113.                     (Res (List 'Get (Car Arg) (Cadr Arg))
  114.                          (List 'GetF Res (Car ArgList))))
  115.                    ((Null ArgList) Res)))))))                      ; Until done
  116.  
  117. ;;; "[" starts the [-reader macro.  "]" is stylistically used as a delimiter.  Note
  118. ;;; that "]" has the same meaning as ")", but they are not used interchangeably for
  119. ;;; stylistic purposes.
  120.  
  121. (Eval-when (Eval Load Compile)
  122.   (Set-Macro-Character #\[ #'|[-Reader|)                        ; "[" macro calls reader
  123.   (Set-Macro-Character #\] (Get-Macro-Character #\) Nil)))      ; "]" is same as ")"
  124.  
  125. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  126. ;;; INHERITENCE
  127. ;;;
  128. ;;; POB-MAKE-TREE will return a non-repeating list of all the nodes visited by a
  129. ;;; depth-first left-to-right traversal of the tree formed by nodes in the SLOT of
  130. ;;; ROOT.  The return list will start with ROOT and end with the farthest node.
  131.  
  132. (Defun POB-Make-Tree (Root SLot)
  133.   (Let ((Seen-L (List Root)))                                   ; Start with Root
  134.     (labels ((Down-Tree (Cur)
  135.                (DoList (Node [Cur Slot])                        ; For every node in slot
  136.                  (Unless (Member Node Seen-L)                   ; Unless already seen
  137.                    (Push Node Seen-L)                           ; Add to seen list
  138.                    (Down-Tree Node)))))                         ; Recurse depth first
  139.       (Down-Tree Root))                                         ; Start at root
  140.     (Reverse Seen-L)))                                          ; From Root to farthest
  141.  
  142. ;;; POB-Inherit-Slots will traverse the :POB-SUP-L tree usig POB-MAKE-TREE to find all
  143. ;;; the objects.  Each slot belonging to a superior is copied into the object.  The
  144. ;;; :POB-SLOT-L is then updated to reflect all the new application slots.  Note that
  145. ;;; inherited values are copies (Top list level only).
  146.       
  147. (Defun POB-Inherit-SLots (Root)
  148.   (Let ((Local-Slot-L [Root :POB-SLOT-L])                       ; Get all local slots first
  149.         (Sup-Val Nil))
  150.     (DoList (Sup (Cdr (POB-Make-Tree Root :POB-SUP-L)))         ; For each superior
  151.       (DoList (Slot [Sup :POB-SLOT-L])                          ; For each of the slots in it
  152.         (Unless (Member Slot Local-SLot-L)                      ; Unless already seen
  153.           (Push Slot Local-SLot-L)                              ; Add to list of slots
  154.           (Setq Sup-Val [Sup Slot])
  155.           (Setf [Root Slot] (If (Atom Sup-Val) Sup-Val          ; Store copy of value
  156.                                 (Copy-List Sup-Val))))))        ;  in SLOT of ROOT
  157.     (Setf [Root :POB-SLOT-L] Local-SLot-L)))                    ; Store list of slots in Root
  158.  
  159.  
  160. ;;; POB-Add-To-Node-L will add NEW-NODE to SLOT-NAME slot of all the nodes in
  161. ;;; NODE-L, iff NEW-NODE is not already there.  This function is useful for
  162. ;;; adding a new subordinate to SUB-L of all of its superior nodes.
  163.  
  164. (Defun POB-Add-To-Node-L (New-Node Node-L Slot-Name)
  165.   (DoList (Node Node-L)
  166.     (Unless (Member New-Node [Node Slot-Name])
  167.       (Push New-Node [Node SLot-Name]))))
  168.  
  169. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  170. ;;; CREATION
  171. ;;;
  172. ;;; POB-DefObj creates a new object that inherits from its superiors.  The object is
  173. ;;; first created, its slots initialized, slots and values are inherited from the
  174. ;;; superiors, the SLOT-VALUE-L information is written in the object, and finally
  175. ;;; the new object is recorded on the SUB-L of its DIRECT superiors.  Note that SLOT-VALUE-L
  176. ;;; overwrites all other information, inherited or just initialized.  Also note that
  177. ;;; elements in the SUP-L are explicitly evaluated so that variables can denote the name
  178. ;;; of objects in the SUP-L.
  179. ;;;
  180. ;;; SLot-Value-L will take the form  (Slot Value Slot Value ...)
  181.  
  182. (Defun POB-DefObj-Eval (Name Sup-L SLot-Value-L)
  183.   (let ((Self (GenTemp "POB-")))
  184.     (Setf [Self :POB-NAME]    Name
  185.           [Self :POB-SUP-L]   (Copy-List Sup-L)                  ; Give initial list of supers
  186.           [Self :POB-SUB-L]   '()                                ; No subordinates yet
  187.           [Self :POB-MSG-L]   '()                                ; No defined messages yet
  188.           [Self :POB-SLOT-L]  '())                               ; Initialize list of slots
  189.     (Do ((S-V-L SLot-Value-L (Cddr S-V-L))                       ; For each Slot-Value pair
  190.          (Slot-L Nil))
  191.         ((Null S-V-L) (Setf [Self :POB-SLOT-L] SLot-L))          ; Add SLOT-L to self
  192.       (Push (Car S-V-L) Slot-L)                                  ; Add slot name to SLOT-L
  193.       (Setf [Self (Car S-V-L)] (Eval (Cadr S-V-L))))             ; Create the slot and give it value
  194.     (POB-Inherit-Slots Self)                                     ; Inherit slot-values from SUPs
  195.     (POB-Add-To-Node-L Self Sup-L :POB-SUB-L)                    ; Add self to SUB-L of direct SUPs
  196.     Self))                                                       ; Return SELF
  197.  
  198. (DefMacro POB-DefObj (Name Sup-L &Rest SLot-Value-L)
  199.   `(POB-DefObj-Eval ',Name
  200.                    (List ,@Sup-L)
  201.                    ',Slot-Value-L))
  202.       
  203. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  204. ;;; MESSAGE SENDING
  205. ;;;
  206. ;;; POB-SEND causes the OBJ to execute the function corresponding to MSG on ARG-L.
  207. ;;; POB-SEND will climb the SUP-L tree of OBJ to find the message function.  Note that
  208. ;;; OBJ is also passed to MSG-FN as an argument, it will be called POB-SELF inside
  209. ;;; the message function.
  210.  
  211.  
  212. (Defun POB-Send (Obj Msg &Rest Arg-L)
  213.   (Let ((Msg-Fn Nil))
  214.     (Labels ((Find-Msg-Obj (Node)
  215.                 (Or (Setq Msg-Fn [Node :POB-MSG-L Msg])
  216.                     (DoList (Sup [Node :POB-SUP-L])
  217.                       (If (Find-Msg-Obj Sup)
  218.                           (Return T))))))
  219.       (Find-Msg-Obj Obj))
  220.     (If Msg-Fn 
  221.       (Apply Msg-Fn (Cons Obj Arg-L))                           ; Obj will act as POB-SELF
  222.       (Error "Message: ~a to ~a went unclaimed." Msg Obj))))
  223.  
  224. (Defun POB-Send-Arg-L (Obj Msg Arg-L)
  225.   (Let ((Msg-Fn Nil))
  226.     (Labels ((Find-Msg-Obj (Node)
  227.                 (Or (Setq Msg-Fn [Node :POB-MSG-L Msg])
  228.                     (DoList (Sup [Node :POB-SUP-L])
  229.                       (If (Find-Msg-Obj Sup)
  230.                           (Return T))))))
  231.       (Find-Msg-Obj Obj))
  232.     (If Msg-Fn 
  233.       (Apply Msg-Fn (Cons Obj Arg-L))                           ; Obj will act as POB-SELF
  234.       (Error "Message: ~a to ~a went unclaimed." Msg Obj))))
  235.  
  236.  
  237. ;;; POB-SEND-IGNORE works just like POB-SEND, but does not signal an error if the message
  238. ;;; is not claimed.
  239.  
  240. (Defun POB-Send-Ignore (Obj Msg &rest Arg-L)
  241.   (Let ((Msg-Fn Nil))
  242.     (Labels ((Find-Msg-Obj (Node)
  243.                 (Or (Setq Msg-Fn [Node :POB-MSG-L Msg])
  244.                     (DoList (Sup [Node :POB-SUP-L])
  245.                       (If (Find-Msg-Obj Sup)
  246.                           (Return T))))))
  247.       (Find-Msg-Obj Obj))
  248.     (If Msg-Fn 
  249.       (Apply Msg-Fn (Cons Obj Arg-L)))))                        ; Obj will act as POB-SELF
  250.  
  251.  
  252. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  253. ;;; DEFINING MESSAGES
  254. ;;;
  255. ;;; POB-DefMsg is used to define messages and functions for objects.  It adds the
  256. ;;; closure for the new function and the matching message name to the POB-MSG-L
  257. ;;; slot of the OBJ.  It will replace any function already associated with MSG.
  258. ;;; Note that POB-SELF is pushed on to the functions arglist--Refer to POB-SEND.
  259.  
  260.  
  261. (DefMacro POB-DefMsg (Obj Msg Arg-L &Rest Form-L)
  262.   `(Setf (Getf [,Obj :POB-MSG-L] ,Msg)
  263.          (Function (Lambda (POB-SELF ,@Arg-L) ,@Form-L))))
  264.  
  265. ;;; POB-DefMsg-Fn is used to define new messages from inside programs.  The macro simply
  266. ;;; returns a function closure--with POB-SELF pushed on to the argument list.  This
  267. ;;; closure should be added to the object using POB-ADD-MSG function (or :ADD-MSG msg
  268. ;;; to the object).
  269.  
  270. (DefMacro POB-DefMsg-Fn (Arg-L Form-L)
  271.   `(Function (Lambda (POB-SELF ,@(Eval Arg-L)) ,@(Eval Form-L))))
  272.  
  273. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  274. ;;; *POB-OBJ*
  275.  
  276. (DefParameter *POB-OBj* (POB-DefObj POB-BASE-OBJECT ()))         ; No superiors
  277.  
  278. ;;; :ADD-MSG will install a new FN in POB-SELF--the old function matching MSG will be
  279. ;;; over-written.
  280.  
  281. (POB-DefMsg *POB-OBJ* :ADD-MSG (Msg Fn)
  282.     (Setf (Getf [POB-SELF :POB-MSG-L] Msg)
  283.           Fn))
  284.  
  285. ;;; :DEL-MSG removes the MSG and its function from POB-SELF's MSG-L.  Note the
  286. ;;; destructive nature of REMF.
  287.  
  288. (POB-DefMsg *POB-OBJ* :DEL-MSG (Msg)
  289.     (Remf [POB-SELF :POB-MSG-L] Msg))
  290.  
  291. ;;; GET-MSG-L returns a list of all the messages stored in POB-SELF
  292.  
  293. (POB-DefMsg *POB-OBJ* :GET-MSG-L ()
  294.     (Do ((Msg-Fn-L [POB-SELF :POB-MSG-L] (Cddr Msg-Fn-L))
  295.          (Res Nil))
  296.         ((Null Msg-Fn-L) Res)
  297.       (Push (Car Msg-Fn-L) Res)))
  298.  
  299. ;;; :ADD-SLOT will add SLOT with value VAL to POB-SELF and all its subordinates.
  300. ;;; Note that the values in the subordinates will get clobbered if they already have
  301. ;;; SLOT.
  302.  
  303. (POB-DefMsg *POB-OBJ* :ADD-SLOT (New-SLot Val)
  304.     (Do ((Sub-L (POB-Make-Tree POB-SELF :POB-SUB-L) (Cdr Sub-L))) ; Tree of subordinates
  305.         ((Null Sub-L) POB-SELF)                                ; Return POB-SELF
  306.       (Setf [(Car Sub-L) New-Slot] Val)                        ; Add new slot to SUB
  307.       (Unless (Member New-SLot [(Car Sub-L) :POB-SLOT-L])      ; Add to SLOT-L of SUB
  308.         (Push New-SLot [(Car Sub-L) :POB-SLOT-L]))))
  309.  
  310. ;;; :DEL-SLOT removes the slot from POB-SELF and all its subordinates.
  311.  
  312. (POB-DefMsg *POB-OBJ* :DEL-SLOT (Old-SLot)
  313.      (Do ((Sub-L (POB-Make-Tree POB-SELF :POB-SUB-L) (Cdr Sub-L))) ; Tree of subordinates
  314.          ((Null Sub-L) POB-SELF)                                ; Return POB-SELF
  315.        (Remf [(Car Sub-L)] Old-SLot)                            ; Remove OLD-SLOT
  316.        (Setq Slot-L [(Car Sub-L) :POB-SLOT-L])                  ; Get SUB's SLOT-L
  317.        (Setf [(Car Sub-L) :POB-SLOT-L]                          ; Then remove OLD-SLOT
  318.              (Delete Old-SLot [(Car Sub-L) :POB-SLOT-L]))))
  319.  
  320. ;;; :ADD-SUP will add new superiors to :POB-SELF.  POB-SELF will inherit all the NEW
  321. ;;; slots from the superiors--in left to right order.  It will also be added to the
  322. ;;; SUB-L of the superiors.  All objects subordinate to POB-SELF will also forcefully
  323. ;;; inherit the NEW slots and values that POB-SELF gets--these new values will OVERWRITE
  324. ;;; existing slots if the subordinate objects already have them.  (This means that POB-SELF
  325. ;;; will not have any of its slots overwritten; while, the subordinates of POB-SELF MAY
  326. ;;; get their slot overwritten!)
  327. ;;;
  328. ;;; POB-ADD-SLOT-VALUE-L is a helper function used to recursively propagate new slot-values
  329. ;;; in the subordinate tree.
  330. ;;;
  331. ;;;; Slot-Value-L is of the form '(Slot Value Slot Value ...)
  332.  
  333. (Defun POB-Add-Slot-Value-L (Obj Slot-Value-L)
  334.   (Do ((New-Slot-L [OBJ :POB-SLOT-L])                            ; Load up with SLOT-L
  335.        (S-V-L Slot-Value-L (Cddr S-V-L)))                        ; For all SLOT-VALUE pairs
  336.       ((Null S-V-L)                                              ; When no more S-V pairs
  337.        (Setf [Obj :POB-SLOT-L] New-SLot-L)                       ; Store new SLOT-L
  338.        (DoList (Sub [Obj :POB-SUB-L])                            ; For all SUBs
  339.          (POB-Add-Slot-Value-L Sub Slot-Value-L)))               ; Recurse
  340.     (Setf [Obj (Car S-V-L)] (Cadr S-V-L))                        ; Store VALUE in SLOT
  341.     (Unless (Member (Car S-V-L) New-Slot-L)                      ; Unless already in SLOT-L
  342.       (Push (Car S-V-L) New-Slot-L))))                           ; Add to new SLOT-L
  343.  
  344.  
  345. (POB-DefMsg *POB-OBJ* :ADD-SUP (&Rest Sup-L)
  346.     (Let ((New-Sup-L [POB-SELF :POB-SUP-L])
  347.           (New-Sub-L [POB-SELF :POB-SUB-L])
  348.           (New-Slot-L [POB-SELF :POB-SLOT-L])
  349.           (Slot-Value-L ())
  350.           (New-Val Nil))
  351.       (DoList (New-Sup Sup-L)                                   ; For each new superior
  352.         (Unless (Member New-Sup New-Sup-L)                      ; If not already on SUP-L
  353.           (Push New-Sup New-Sup-L)                              ; Add to SUP-L
  354.           (Push POB-SELF [New-Sup :POB-SUB-L])                  ; Put on SUPs SUB-L
  355.           (DoList (New-SLot [New-Sup :POB-SLOT-L])              ; For each SLOT in SUP
  356.             (Unless (Member New-Slot New-Slot-L)                ; If not already in POB-SELF
  357.               (Push New-Slot New-Slot-L)                        ; Add to SLOT-L
  358.               (Setq New-Val [New-Sup New-SLot])                 ; Get value of slot
  359.               (Setf [POB-SELF New-SLot] New-Val)                ; Put slot and value in POB-SELF
  360.               (Push New-Val SLot-Value-L)                       ; Record in SLOT-VALUE-L
  361.               (Push New-Slot Slot-Value-L)))))
  362.       (Setf [POB-SELF :POB-SLOT-L] New-Slot-L)                  ; Restore SLOT-L
  363.       (Setf [POB-SELF :POB-SUP-L] New-Sup-L)                    ; Restore SUP-L
  364.       (DoList (Sub New-Sub-L)                                   ; For each subordinate
  365.         (POB-Add-Slot-Value-L Sub Slot-Value-L)))               ; Add all slots and values (Recurse)
  366.     POB-SELF)                                                   ; Return POB-SELF
  367.  
  368.  
  369. ;;; :ADD-SLOT-VALUE-L is used to add all the slots and their values to self and all its
  370. ;;; subordinates.  Note that the addition is not forceful and will not overwrite
  371. ;;; existing slots and values in POB-SELF or any of the subordinates.
  372.  
  373. (POB-DefMsg *POB-OBJ* :ADD-SLOT-VALUE-L (S-V-L)
  374.   (POB-Add-Slot-Value-L POB-SELF S-V-L))
  375.  
  376. ;;; :DEL-SUP will remove members of DEL-SUP-L from the SUP-L of POB-SELF.  POB-SELF
  377. ;;; will also be stricken from the superior's POB-SUB-L.  Note that inherited
  378. ;;; slots are not removed--only access to inherited functions is discontinued.  Nothing
  379. ;;; is done about the subordinates of POB-SELF.
  380.  
  381. (POB-DefMsg *POB-OBJ* :DEL-SUP (&Rest Del-Sup-L)
  382.    (Let ((New-Sup-L '()))
  383.      (DoList (Sup [POB-SELF :POB-SUP-L])                        ; For all superiors
  384.        (If (Member Sup Del-Sup-L)                               ; If member of delete list
  385.          (Setf [Sup :POB-SUB-L]
  386.                (Delete POB-SELF [Sup :POB-SUB-L]))              ; Remove POB-SELF from their SUB-L
  387.          (Push Sup New-Sup-L)))                                 ; Push sup on new SUP-L
  388.      (Setf [POB-SELF :POB-SUP-L] New-Sup-L)                     ; Store new SUP-L
  389.      POB-SELF))                                                 ; Return POB-SELF
  390.  
  391.  
  392. ;;; MAKE-OBJ will instantiate an object by treating POB-SELF as a class definition.
  393. ;;; The new object will get all its slots from POB-SELF--It will not be a subordinate
  394. ;;; to POB-SELF, but rather subordinate to POB-SELF's superiors.
  395. ;;;
  396. ;;; SLOT-VALUE-L is of the form (Slot Value Slot Value ...)
  397.  
  398. (POB-DefMsg *POB-OBJ* :MAKE-OBJ (Name &Rest Slot-Value-L)
  399.     (Let ((New-Obj (GenTemp "POB-"))                             ; Create new object
  400.           (Sup-L (Copy-List [POB-SELF :POB-SUP-L]))              ; Get copy of SUP-L
  401.           (Slot-L (Copy-list [POB-SELF :POB-SLOT-L]))            ; Get copy of SLOT-L
  402.           (Val Nil))
  403.       (Setf [New-Obj :POB-NAME] name
  404.             [New-Obj :POB-SUP-L] Sup-L
  405.             [New-Obj :POB-SUB-L] '()
  406.             [New-Obj :POB-MSG-L] (Copy-List [POB-SELF :POB-MSG-L])) ; Get copy of MSG-L
  407.       (DoList (Sup Sup-L)                                       ; For all superiors
  408.         (Push New-Obj [Sup :POB-SUB-L]))                        ; add NEW-OBJ as their sub
  409.       (DoList (New-Slot Slot-L)                                 ; For all slots
  410.         (Setq Val [POB-SELF New-Slot])
  411.         (If (Atom Val)
  412.             (Setf [New-Obj New-Slot] Val)
  413.             (Setf [New-Obj New-Slot] (Copy-List Val))))         ; Create them in NEW-OBJ
  414.       (Do ((S-V-L Slot-Value-L (Cddr S-V-L)))                   ; For all Slot-Value pairs
  415.           ((Null S-V-L) T)                                      ; Until done
  416.         (Setf [New-Obj (Car S-V-L)] (Cadr S-V-L))               ; Put slot and value in NEW-OBJ
  417.         (Unless (Member (Car S-V-L) SLot-L)                     ; If not already in SLOT-L
  418.           (Push (Car S-V-L) SLot-L)))                           ; Add to slot-L
  419.       (Setf [New-Obj :POB-SLOT-L] Slot-L)                       ; Store new SLOT-L in NEW-OBJ
  420.       New-Obj))                                                 ; Return NEW-OBJ
  421.  
  422. ;;; :DEL-OBJ cleans out POB-SELF for garbage collection.  For all subordinates of POB-SELF,
  423. ;;; if they have no other superiors, they too are recursively cleaned out.
  424. ;;;
  425. ;;; Clean-Sub is a helper function for cleaning out the tree of subordinates.
  426.  
  427. (POB-DefMsg *POB-OBJ* :DEL-OBJ ()
  428.     (Let ((Sub-L [POB-SELF :POB-SUB-L])
  429.           (Del-L (list POB-Self)))                              ; Only self MUST be deleted
  430.  
  431.       ;; Clean subordinates starting at Node
  432.       (Labels ((Clean-Sub (Node)
  433.                  (Do ((S-L [Node :POB-SUP-L] (Cdr S-L))         ; For all superiors
  434.                       (Rem-Sup-L '()))                          ; Remaining superior list
  435.                      ((Null S-L) 
  436.                       (If Rem-Sup-L                             ; Some superior still remains
  437.                         (Setf [Node :POB-SUP-L] Rem-Sup-L)      ; Remove killed superiors
  438.                         ; Else
  439.                         (progn
  440.                           (Push Node Del-L)                     ; Count this node deleted
  441.                           (DoList (S [Node :POB-SUB-L])         ; For all subordinates
  442.                             (Clean-Sub S))                      ; Recursively clean them out
  443.                           (Setf [Node] Nil))))                  ; Clean out self last
  444.                    (Unless (Member (Car S-L) Del-L)             ; If not member of delete list
  445.                      (Push (Car S-L) Rem-Sup-L)))))             ; Then add to remaining list
  446.  
  447.         (DoList (Sup [POB-SELF :POB-SUP-L])                            ; For all immediate SUPs
  448.           (Setf [Sup :POB-SUB-L] (Delete POB-SELF [Sup :POB-SUB-L])))  ; Remove POB-SELF from SUB-L
  449.  
  450.         (DoList (S Sub-L)                                       ; For all direct subs
  451.           (Clean-Sub S))
  452.         (Setf [POB-SELF] nil)))                                 ; Clean out all slots
  453.     POB-SELF)                                                   ; Return POB-SELF
  454.  
  455. ;;; :SEPARATE causes self to inherit all the messages that were normally available through
  456. ;;; the SUP-L hierarchy.  Self is then removed from the SUB-L slot of its superiors, and
  457. ;;; the superiors are in turn removed from the SUP-L slot of self.  :SEPARATE will speed up
  458. ;;; message processing of POB-SELF by eliminating the need for hierarchical look-up.
  459.  
  460. (POB-DefMsg *POB-OBJ* :SEPARATE ()
  461.    (Let ((Par-L [POB-SELF :POB-SUP-L])
  462.          (Sup-L (POB-Make-Tree POB-SELF :POB-SUP-L))
  463.          (Msg-L [POB-SELF :POB-MSG-L]))
  464.      (DoList (Sup (Cdr Sup-L))                                   ; For all ancestors
  465.        (Do ((M-L [Sup :POB-MSG-L] (Cddr M-L)))                   ;  get the messages and functions
  466.            ((Null M-L) T)
  467.          (Unless (Getf Msg-L (Car M-L))
  468.            (Setq Msg-L (List* (Car M-L) (Cadr M-L) msg-L)))))
  469.  
  470.      (DoList (Par Par-L)                                         ; For all parents of self
  471.        (Setf [Par :POB-SUB-L] (Delete POB-SELF [Par :POB-SUB-L])))   ; remove self from SUB-L
  472.  
  473.      (Setf [POB-SELF :POB-SUP-L] nil                                 ; Self has no more parents
  474.            [POB-SELF :POB-MSG-L] Msg-L)                              ; But self has all their msgs
  475.      POB-SELF))
  476.  
  477. ;;; :INIT-SLOTS is used to initialize all the slots in SLOT-L to VAL.  It is very handy
  478. ;;; for setting a large number of slots to :UNKNOWN or other preset values.
  479.  
  480. (POB-DefMsg *POB-OBJ* :INIT-SLOTS (Slot-L Val)
  481.    (DoList (Slot SLot-L)
  482.      (Setf [POB-SELF SLot] Val)))
  483.  
  484. ;;; :PRINT-OBJ prints POB-SELF
  485.  
  486. (POB-DefMsg *POB-OBJ* :PRINT-SELF ()
  487.    (POB-PRINT-OBJ POB-SELF))
  488.  
  489. (POB-DefMsg *POB-OBJ* :PRINT-SLOT (&Rest SLot-L)
  490.   (If Slot-L 
  491.     (POB-Print-Obj-Slots POB-SELF Slot-L)
  492.     (POB-Print-Obj-SLots POB-SELF [POB-SELF :POB-SLOT-L])))
  493.  
  494. (POB-DefMsg *POB-OBJ* :PRINT-MSG-L ()
  495.   (POB-Print-Msg-L POB-SELF))
  496.  
  497. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  498. ;;; POB-Print-0bj pretty-prints the objects.
  499.  
  500. (Defun POB-Print-Obj (Obj)
  501.   (Let ((P-L (Symbol-Plist Obj)))
  502.     (format T "~%~%--~A--~%" Obj)
  503.     (Do ((P P-L (Cddr P)))
  504.         ((Null P) (Format T "~%") T)
  505.       (Format T "~A" (Car P))
  506.       (Do ((I (Length (String (Car P))) (1+ I)))
  507.           ((/ I 17) T)
  508.         (Format T " "))
  509.       (If (Equal (Car P) :POB-MSG-L)
  510.         (Format T " ../ ~A~%" (POB-SEND Obj :GET-MSG-L))
  511.         (Format T " --/ ~A~%" (Cadr P))))))
  512.  
  513. (Defun POB-Print-Obj-Slots (Obj Slot-L)
  514.     (format T "~%~%--~A--~%" Obj)
  515.     (DoList (Slot SLot-L)
  516.       (format T "~A" Slot)
  517.       (Do ((I (Length (String Slot)) (1+ I)))
  518.           ((/ I 17) T)
  519.         (Format T " "))
  520.       (Format T " --/ ~A~%" [Obj Slot]))
  521.     (Format T "~%")
  522.     T)
  523.  
  524. (defun POB-Print-Msg-L (Obj)
  525.    (format T "~%~%--~A--~%MSG --/ " Obj)
  526.    (Do ((Msg-L [Obj :POB-MSG-L] (Cddr msg-L)))
  527.        ((Null Msg-L) (Format T "~%~%"))
  528.      (Format T "~A~%        " (Car Msg-L)))
  529.    T)
  530.         {et
  531. G-L] (Cddr msg-L)))
  532.        ((Null Msg-L) (Format T "~%~%"))
  533.      (Format T "~A~%        " (Car Msg-L)))
  534.    T)
  535.