user.body.scm 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. ;; prometheus.scm --- A prototype-based object system
  2. ;; Copyright (C) 2005, 2006 Jorgen Schaefer
  3. ;; Author: Jorgen Schaefer <forcer@forcix.cx>
  4. ;; This program is free software; you can redistribute it and/or
  5. ;; modify it under the terms of the GNU General Public License
  6. ;; as published by the Free Software Foundation; either version 2
  7. ;; of the License, or (at your option) any later version.
  8. ;; This program is distributed in the hope that it will be useful,
  9. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. ;; GNU General Public License for more details.
  12. ;; You should have received a copy of the GNU General Public License
  13. ;; along with this program; if not, write to the Free Software
  14. ;; Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  15. ;; 02110-1301 USA
  16. ;;; Commentary:
  17. ;; This implements the Prometheus object system ontop of the Hermes
  18. ;; system.
  19. ;;; Code:
  20. ;;;;;;;;;;;;;;;;;;;;;
  21. ;;; "Object Quality" - allows checking if a procedure is a
  22. ;;; prometheus object
  23. (define-record-type <object-quality>
  24. (object-quality)
  25. object-quality?)
  26. (define (object? o)
  27. (guard (e (#t #f))
  28. (object-quality?
  29. (o object-quality?))))
  30. ;;;;;;;;;;;;;;;;;;;;;
  31. ;;; Prometheus Object
  32. ;;; This creates a new root object for a Prometheus hierarchy.
  33. (define (make-prometheus-root-object)
  34. (let ((o (make-hermes-object)))
  35. (o 'add-message! 'clone root-clone)
  36. (o 'add-message! 'message-not-understood root-message-not-understood)
  37. (o 'add-message! 'ambiguous-message-send root-ambiguous-message-send)
  38. (o 'add-message! 'immediate-slot-list root-immediate-slot-list)
  39. (o 'add-message! 'set-immediate-slot-list! root-set-immediate-slot-list!)
  40. (o 'add-message! 'add-value-slot! root-add-value-slot!)
  41. (o 'add-message! 'add-method-slot! root-add-method-slot!)
  42. (o 'add-message! 'add-parent-slot! root-add-parent-slot!)
  43. (o 'add-message! 'delete-slot! root-delete-slot!)
  44. (o 'add-value-slot! object-quality? (object-quality))
  45. o))
  46. ;;; Return the slot list. Each entry in the slot list is a list of
  47. ;;; three elements: The name of the getter, the name of the setter,
  48. ;;; and a boolean whether this is a parent slot or not.
  49. ;;; For the initial object, this is hardcoded. Bad programmer. No
  50. ;;; cookie.
  51. (define (root-immediate-slot-list self resend)
  52. '((clone #f #f)
  53. (message-not-understood #f #f)
  54. (ambiguous-message-send #f #f)
  55. (immediate-slot-list set-immediate-slot-list! #f)
  56. (add-value-slot! #f #f)
  57. (add-method-slot! #f #f)
  58. (add-parent-slot! #f #f)
  59. (delete-slot! #f #f)))
  60. ;;; Set the slot list to be returned in the future to a new list. This
  61. ;;; just adds a new message so the slot list of a parent is never
  62. ;;; overwritten.
  63. (define (root-set-immediate-slot-list! self resend new)
  64. (self 'add-message! 'immediate-slot-list
  65. (lambda (self resend)
  66. new)))
  67. ;;; Return a new object with the parent pointer set to this one.
  68. (define (root-clone self resend)
  69. (let ((child (make-hermes-object)))
  70. (child 'add-message! 'parent
  71. (lambda (self2 resend)
  72. self)
  73. #t)
  74. (child 'add-message! 'immediate-slot-list
  75. (lambda (self2 resend)
  76. '((parent #f parent))))
  77. child))
  78. ;;; When the root object receives a MESSAGE-NOT-UNDERSTOOD message,
  79. ;;; signal an error. We don't handle that.
  80. (define (root-message-not-understood self resend message args)
  81. (error "Message not understood" self message args))
  82. ;;; When the root object receive an AMBIGUOUS-MESSAGE-SEND message,
  83. ;;; signal an error. We don't handle that either.
  84. (define (root-ambiguous-message-send self resend message args)
  85. (error "Message ambiguous" self message args))
  86. (define-syntax make-getter-setter
  87. (syntax-rules ()
  88. ((make-getter-setter 'MESSAGE VALUE TYPE PURE-GETTER)
  89. (make-getter-setter 'MESSAGE VALUE TYPE PURE-GETTER PURE-GETTER))
  90. ((make-getter-setter 'MESSAGE VALUE TYPE PURE-GETTER SETABLE-GETTER)
  91. (case-lambda
  92. ((self resend getter VALUE)
  93. (self 'delete-slot! getter)
  94. (self 'set-immediate-slot-list!
  95. (alist-cons getter
  96. (list #f TYPE)
  97. (self 'immediate-slot-list)))
  98. (self 'add-message! getter PURE-GETTER (eq? TYPE 'parent)))
  99. ((self resend getter setter VALUE)
  100. (self 'delete-slot! getter)
  101. (self 'delete-slot! setter)
  102. (self 'set-immediate-slot-list!
  103. (alist-cons getter
  104. (list setter TYPE)
  105. (self 'immediate-slot-list)))
  106. (self 'add-message! getter SETABLE-GETTER (eq? TYPE 'parent))
  107. (self 'add-message! setter
  108. (lambda (self2 resend new)
  109. (if (eq? self2 self)
  110. (set! VALUE new)
  111. (self2 'MESSAGE getter setter new)))))))))
  112. ;;; Add a value slot. Nothing fancy when no setter is given, except
  113. ;;; that we make sure a possible earlier setter is removed. But when
  114. ;;; there is a setter given, we make them share a value for fast
  115. ;;; modification.
  116. (define root-add-value-slot!
  117. (make-getter-setter 'add-value-slot! value 'value
  118. (lambda (self resend)
  119. value)))
  120. ;;; A method slot is just a normal message slot, except that we record
  121. ;;; its existence in the slot list.
  122. (define root-add-method-slot!
  123. (make-getter-setter 'add-method-slot! value 'method
  124. value
  125. (lambda (self resend . args)
  126. (apply value self resend args))))
  127. ;;; A parent slot isn't very special, either, except that we note its
  128. ;;; special status for both Hermes and our slot list.
  129. (define root-add-parent-slot!
  130. (make-getter-setter 'add-parent-slot! value 'parent
  131. (lambda (self resend)
  132. value)))
  133. ;;; Delete a slot again. If it does have an associated setter, remove
  134. ;;; that setter as well.
  135. (define (root-delete-slot! self resend getter)
  136. (self 'set-immediate-slot-list!
  137. (let loop ((alis (self 'immediate-slot-list)))
  138. (cond
  139. ((null? alis)
  140. '())
  141. ((eq? getter (caar alis))
  142. (self 'delete-message! (cadar alis))
  143. (loop (cdr alis)))
  144. (else
  145. (cons (car alis)
  146. (loop (cdr alis)))))))
  147. (self 'delete-message! getter))
  148. ;;;;;;;;;;;;;;;;;;;
  149. ;;; Syntactic Sugar
  150. ;;; The syntactic sugar for defining methods and objects.
  151. (define-syntax define-method
  152. (syntax-rules ()
  153. ((_ (obj 'message self resend args ...)
  154. body1 body ...)
  155. (obj 'add-method-slot! 'message
  156. (lambda (self resend args ...)
  157. body1 body ...)))))
  158. (define-syntax define-object
  159. (syntax-rules ()
  160. ((_ name (creation-parent (parent-name parent-object) ...)
  161. slots ...)
  162. (define name (let ((o (creation-parent 'clone)))
  163. (o 'add-parent-slot! 'parent-name parent-object)
  164. ...
  165. (define-object/add-slots! o slots ...)
  166. o)))))
  167. (define-syntax define-object/add-slots!
  168. (syntax-rules ()
  169. ((_ o)
  170. (values))
  171. ((_ o ((method-name . method-args) body ...)
  172. slots ...)
  173. (begin
  174. (o 'add-method-slot! 'method-name (lambda method-args
  175. body ...))
  176. (define-object/add-slots! o slots ...)))
  177. ((_ o (slot-getter slot-setter slot-value)
  178. slots ...)
  179. (begin
  180. (o 'add-value-slot! 'slot-getter 'slot-setter slot-value)
  181. (define-object/add-slots! o slots ...)))
  182. ((_ o (slot-getter slot-value)
  183. slots ...)
  184. (begin
  185. (o 'add-value-slot! 'slot-getter slot-value)
  186. (define-object/add-slots! o slots ...)))))
  187. ;;; Let there be light.
  188. ;; FIXME! Better name?
  189. (define *the-root-object* (make-prometheus-root-object))
  190. ;; Added by Jason (2016):
  191. (define-syntax define-generic
  192. (syntax-rules ()
  193. ((_ name)
  194. (define (name obj . args)
  195. (apply obj (cons (quote name) args))))))
  196. ;;; prometheus.body.scm ends here