goops.scm 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766
  1. ;;; installed-scm-file
  2. ;;;; Copyright (C) 1998,1999,2000,2001,2002, 2003, 2006, 2009, 2010, 2011 Free Software Foundation, Inc.
  3. ;;;; Copyright (C) 1993-1998 Erick Gallesio - I3S-CNRS/ESSI <eg@unice.fr>
  4. ;;;;
  5. ;;;; This library is free software; you can redistribute it and/or
  6. ;;;; modify it under the terms of the GNU Lesser General Public
  7. ;;;; License as published by the Free Software Foundation; either
  8. ;;;; version 3 of the License, or (at your option) any later version.
  9. ;;;;
  10. ;;;; This library is distributed in the hope that it will be useful,
  11. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. ;;;; Lesser General Public License for more details.
  14. ;;;;
  15. ;;;; You should have received a copy of the GNU Lesser General Public
  16. ;;;; License along with this library; if not, write to the Free Software
  17. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  18. ;;;;
  19. ;;;;
  20. ;;;; This file was based upon stklos.stk from the STk distribution
  21. ;;;; version 4.0.1 by Erick Gallesio <eg@unice.fr>.
  22. ;;;;
  23. (define-module (oop goops)
  24. #:use-module (srfi srfi-1)
  25. #:export-syntax (define-class class standard-define-class
  26. define-generic define-accessor define-method
  27. define-extended-generic define-extended-generics
  28. method)
  29. #:export ( ;; The root of everything.
  30. <top>
  31. <class> <object>
  32. ;; Slot types.
  33. <foreign-slot> <protected-slot> <hidden-slot> <opaque-slot>
  34. <read-only-slot> <self-slot> <protected-opaque-slot>
  35. <protected-hidden-slot> <protected-read-only-slot>
  36. <scm-slot> <int-slot> <float-slot> <double-slot>
  37. ;; Methods are implementations of generic functions.
  38. <method> <accessor-method>
  39. ;; Applicable objects, either procedures or applicable structs.
  40. <procedure-class> <applicable>
  41. <procedure> <primitive-generic>
  42. ;; Applicable structs.
  43. <applicable-struct-class>
  44. <applicable-struct>
  45. <generic> <extended-generic>
  46. <generic-with-setter> <extended-generic-with-setter>
  47. <accessor> <extended-accessor>
  48. ;; Types with their own allocated typecodes.
  49. <boolean> <char> <list> <pair> <null> <string> <symbol>
  50. <vector> <bytevector> <uvec> <foreign> <hashtable>
  51. <fluid> <dynamic-state> <frame> <objcode> <vm> <vm-continuation>
  52. ;; Numbers.
  53. <number> <complex> <real> <integer> <fraction>
  54. ;; Unknown.
  55. <unknown>
  56. ;; Particular SMOB data types. All SMOB types have
  57. ;; corresponding classes, which may be obtained via class-of,
  58. ;; once you have an instance. Perhaps FIXME to provide a
  59. ;; smob-type-name->class procedure.
  60. <arbiter> <promise> <thread> <mutex> <condition-variable>
  61. <regexp> <hook> <bitvector> <random-state> <async>
  62. <directory> <keyword> <array> <character-set>
  63. <dynamic-object> <guardian> <macro>
  64. ;; Modules.
  65. <module>
  66. ;; Ports.
  67. <port> <input-port> <output-port> <input-output-port>
  68. ;; Like SMOB types, all port types have their own classes,
  69. ;; which can be accessed via `class-of' once you have an
  70. ;; instance. Here we export bindings just for file ports.
  71. <file-port>
  72. <file-input-port> <file-output-port> <file-input-output-port>
  73. is-a? class-of
  74. ensure-metaclass ensure-metaclass-with-supers
  75. make-class
  76. make-generic ensure-generic
  77. make-extended-generic
  78. make-accessor ensure-accessor
  79. add-method!
  80. class-slot-ref class-slot-set! slot-unbound slot-missing
  81. slot-definition-name slot-definition-options
  82. slot-definition-allocation
  83. slot-definition-getter slot-definition-setter
  84. slot-definition-accessor
  85. slot-definition-init-value slot-definition-init-form
  86. slot-definition-init-thunk slot-definition-init-keyword
  87. slot-init-function class-slot-definition
  88. method-source
  89. compute-cpl compute-std-cpl compute-get-n-set compute-slots
  90. compute-getter-method compute-setter-method
  91. allocate-instance initialize make-instance make
  92. no-next-method no-applicable-method no-method
  93. change-class update-instance-for-different-class
  94. shallow-clone deep-clone
  95. class-redefinition
  96. apply-generic apply-method apply-methods
  97. compute-applicable-methods %compute-applicable-methods
  98. method-more-specific? sort-applicable-methods
  99. class-subclasses class-methods
  100. goops-error
  101. min-fixnum max-fixnum
  102. ;;; *fixme* Should go into goops.c
  103. instance? slot-ref-using-class
  104. slot-set-using-class! slot-bound-using-class?
  105. slot-exists-using-class? slot-ref slot-set! slot-bound?
  106. class-name class-direct-supers class-direct-subclasses
  107. class-direct-methods class-direct-slots class-precedence-list
  108. class-slots
  109. generic-function-name
  110. generic-function-methods method-generic-function
  111. method-specializers method-formals
  112. primitive-generic-generic enable-primitive-generic!
  113. method-procedure accessor-method-slot-definition
  114. slot-exists? make find-method get-keyword)
  115. #:no-backtrace)
  116. (define *goops-module* (current-module))
  117. ;; First initialize the builtin part of GOOPS
  118. (eval-when (eval load compile)
  119. (%init-goops-builtins))
  120. (eval-when (eval load compile)
  121. (use-modules ((language tree-il primitives) :select (add-interesting-primitive!)))
  122. (add-interesting-primitive! 'class-of)
  123. (define (@slot-ref o n)
  124. (struct-ref o n))
  125. (define (@slot-set! o n v)
  126. (struct-set! o n v))
  127. (add-interesting-primitive! '@slot-ref)
  128. (add-interesting-primitive! '@slot-set!))
  129. ;; Then load the rest of GOOPS
  130. (use-modules (oop goops util)
  131. (oop goops dispatch)
  132. (oop goops compile))
  133. ;; FIXME: deprecate.
  134. (eval-when (eval load compile)
  135. (define min-fixnum (- (expt 2 29)))
  136. (define max-fixnum (- (expt 2 29) 1)))
  137. ;;
  138. ;; goops-error
  139. ;;
  140. (define (goops-error format-string . args)
  141. (scm-error 'goops-error #f format-string args '()))
  142. ;;
  143. ;; is-a?
  144. ;;
  145. (define (is-a? obj class)
  146. (and (memq class (class-precedence-list (class-of obj))) #t))
  147. ;;;
  148. ;;; {Meta classes}
  149. ;;;
  150. (define ensure-metaclass-with-supers
  151. (let ((table-of-metas '()))
  152. (lambda (meta-supers)
  153. (let ((entry (assoc meta-supers table-of-metas)))
  154. (if entry
  155. ;; Found a previously created metaclass
  156. (cdr entry)
  157. ;; Create a new meta-class which inherit from "meta-supers"
  158. (let ((new (make <class> #:dsupers meta-supers
  159. #:slots '()
  160. #:name (gensym "metaclass"))))
  161. (set! table-of-metas (cons (cons meta-supers new) table-of-metas))
  162. new))))))
  163. (define (ensure-metaclass supers)
  164. (if (null? supers)
  165. <class>
  166. (let* ((all-metas (map (lambda (x) (class-of x)) supers))
  167. (all-cpls (append-map (lambda (m)
  168. (cdr (class-precedence-list m)))
  169. all-metas))
  170. (needed-metas '()))
  171. ;; Find the most specific metaclasses. The new metaclass will be
  172. ;; a subclass of these.
  173. (for-each
  174. (lambda (meta)
  175. (if (and (not (member meta all-cpls))
  176. (not (member meta needed-metas)))
  177. (set! needed-metas (append needed-metas (list meta)))))
  178. all-metas)
  179. ;; Now return a subclass of the metaclasses we found.
  180. (if (null? (cdr needed-metas))
  181. (car needed-metas) ; If there's only one, just use it.
  182. (ensure-metaclass-with-supers needed-metas)))))
  183. ;;;
  184. ;;; {Classes}
  185. ;;;
  186. ;;; (define-class NAME (SUPER ...) SLOT-DEFINITION ... OPTION ...)
  187. ;;;
  188. ;;; SLOT-DEFINITION ::= SLOT-NAME | (SLOT-NAME OPTION ...)
  189. ;;; OPTION ::= KEYWORD VALUE
  190. ;;;
  191. (define (kw-do-map mapper f kwargs)
  192. (define (keywords l)
  193. (cond
  194. ((null? l) '())
  195. ((or (null? (cdr l)) (not (keyword? (car l))))
  196. (goops-error "malformed keyword arguments: ~a" kwargs))
  197. (else (cons (car l) (keywords (cddr l))))))
  198. (define (args l)
  199. (if (null? l) '() (cons (cadr l) (args (cddr l)))))
  200. ;; let* to check keywords first
  201. (let* ((k (keywords kwargs))
  202. (a (args kwargs)))
  203. (mapper f k a)))
  204. (define (make-class supers slots . options)
  205. (let* ((name (get-keyword #:name options (make-unbound)))
  206. (supers (if (not (or-map (lambda (class)
  207. (memq <object>
  208. (class-precedence-list class)))
  209. supers))
  210. (append supers (list <object>))
  211. supers))
  212. (metaclass (or (get-keyword #:metaclass options #f)
  213. (ensure-metaclass supers))))
  214. ;; Verify that all direct slots are different and that we don't inherit
  215. ;; several time from the same class
  216. (let ((tmp1 (find-duplicate supers))
  217. (tmp2 (find-duplicate (map slot-definition-name slots))))
  218. (if tmp1
  219. (goops-error "make-class: super class ~S is duplicate in class ~S"
  220. tmp1 name))
  221. (if tmp2
  222. (goops-error "make-class: slot ~S is duplicate in class ~S"
  223. tmp2 name)))
  224. ;; Everything seems correct, build the class
  225. (apply make metaclass
  226. #:dsupers supers
  227. #:slots slots
  228. #:name name
  229. options)))
  230. ;;; (class (SUPER ...) SLOT-DEFINITION ... OPTION ...)
  231. ;;;
  232. ;;; SLOT-DEFINITION ::= SLOT-NAME | (SLOT-NAME OPTION ...)
  233. ;;; OPTION ::= KEYWORD VALUE
  234. ;;;
  235. (define-macro (class supers . slots)
  236. (define (make-slot-definition-forms slots)
  237. (map
  238. (lambda (def)
  239. (cond
  240. ((pair? def)
  241. `(list ',(car def)
  242. ,@(kw-do-map append-map
  243. (lambda (kw arg)
  244. (case kw
  245. ((#:init-form)
  246. `(#:init-form ',arg
  247. #:init-thunk (lambda () ,arg)))
  248. (else (list kw arg))))
  249. (cdr def))))
  250. (else
  251. `(list ',def))))
  252. slots))
  253. (if (not (list? supers))
  254. (goops-error "malformed superclass list: ~S" supers))
  255. (let ((slots (take-while (lambda (x) (not (keyword? x))) slots))
  256. (options (or (find-tail keyword? slots) '())))
  257. `(make-class
  258. ;; evaluate super class variables
  259. (list ,@supers)
  260. ;; evaluate slot definitions, except the slot name!
  261. (list ,@(make-slot-definition-forms slots))
  262. ;; evaluate class options
  263. ,@options)))
  264. (define-syntax define-class-pre-definition
  265. (lambda (x)
  266. (syntax-case x ()
  267. ((_ (k arg rest ...) out ...)
  268. (keyword? (syntax->datum #'k))
  269. (case (syntax->datum #'k)
  270. ((#:getter #:setter)
  271. #'(define-class-pre-definition (rest ...)
  272. out ...
  273. (if (or (not (defined? 'arg))
  274. (not (is-a? arg <generic>)))
  275. (toplevel-define!
  276. 'arg
  277. (ensure-generic (if (defined? 'arg) arg #f) 'arg)))))
  278. ((#:accessor)
  279. #'(define-class-pre-definition (rest ...)
  280. out ...
  281. (if (or (not (defined? 'arg))
  282. (not (is-a? arg <accessor>)))
  283. (toplevel-define!
  284. 'arg
  285. (ensure-accessor (if (defined? 'arg) arg #f) 'arg)))))
  286. (else
  287. #'(define-class-pre-definition (rest ...) out ...))))
  288. ((_ () out ...)
  289. #'(begin out ...)))))
  290. ;; Some slot options require extra definitions to be made. In
  291. ;; particular, we want to make sure that the generic function objects
  292. ;; which represent accessors exist before `make-class' tries to add
  293. ;; methods to them.
  294. (define-syntax define-class-pre-definitions
  295. (lambda (x)
  296. (syntax-case x ()
  297. ((_ () out ...)
  298. #'(begin out ...))
  299. ((_ (slot rest ...) out ...)
  300. (keyword? (syntax->datum #'slot))
  301. #'(begin out ...))
  302. ((_ (slot rest ...) out ...)
  303. (identifier? #'slot)
  304. #'(define-class-pre-definitions (rest ...)
  305. out ...))
  306. ((_ ((slotname slotopt ...) rest ...) out ...)
  307. #'(define-class-pre-definitions (rest ...)
  308. out ... (define-class-pre-definition (slotopt ...)))))))
  309. (define-syntax-rule (define-class name supers slot ...)
  310. (begin
  311. (define-class-pre-definitions (slot ...))
  312. (if (and (defined? 'name)
  313. (is-a? name <class>)
  314. (memq <object> (class-precedence-list name)))
  315. (class-redefinition name
  316. (class supers slot ... #:name 'name))
  317. (toplevel-define! 'name (class supers slot ... #:name 'name)))))
  318. (define-syntax-rule (standard-define-class arg ...)
  319. (define-class arg ...))
  320. ;;;
  321. ;;; {Generic functions and accessors}
  322. ;;;
  323. ;; Apparently the desired semantics are that we extend previous
  324. ;; procedural definitions, but that if `name' was already a generic, we
  325. ;; overwrite its definition.
  326. (define-macro (define-generic name)
  327. (if (not (symbol? name))
  328. (goops-error "bad generic function name: ~S" name))
  329. `(define ,name
  330. (if (and (defined? ',name) (is-a? ,name <generic>))
  331. (make <generic> #:name ',name)
  332. (ensure-generic (if (defined? ',name) ,name #f) ',name))))
  333. (define-macro (define-extended-generic name val)
  334. (if (not (symbol? name))
  335. (goops-error "bad generic function name: ~S" name))
  336. `(define ,name (make-extended-generic ,val ',name)))
  337. (define-macro (define-extended-generics names . args)
  338. (let ((prefixes (get-keyword #:prefix args #f)))
  339. (if prefixes
  340. `(begin
  341. ,@(map (lambda (name)
  342. `(define-extended-generic ,name
  343. (list ,@(map (lambda (prefix)
  344. (symbol-append prefix name))
  345. prefixes))))
  346. names))
  347. (goops-error "no prefixes supplied"))))
  348. (define* (make-generic #:optional name)
  349. (make <generic> #:name name))
  350. (define* (make-extended-generic gfs #:optional name)
  351. (let* ((gfs (if (list? gfs) gfs (list gfs)))
  352. (gws? (any (lambda (gf) (is-a? gf <generic-with-setter>)) gfs)))
  353. (let ((ans (if gws?
  354. (let* ((sname (and name (make-setter-name name)))
  355. (setters
  356. (append-map (lambda (gf)
  357. (if (is-a? gf <generic-with-setter>)
  358. (list (ensure-generic (setter gf)
  359. sname))
  360. '()))
  361. gfs))
  362. (es (make <extended-generic-with-setter>
  363. #:name name
  364. #:extends gfs
  365. #:setter (make <extended-generic>
  366. #:name sname
  367. #:extends setters))))
  368. (extended-by! setters (setter es))
  369. es)
  370. (make <extended-generic>
  371. #:name name
  372. #:extends gfs))))
  373. (extended-by! gfs ans)
  374. ans)))
  375. (define (extended-by! gfs eg)
  376. (for-each (lambda (gf)
  377. (slot-set! gf 'extended-by
  378. (cons eg (slot-ref gf 'extended-by))))
  379. gfs)
  380. (invalidate-method-cache! eg))
  381. (define (not-extended-by! gfs eg)
  382. (for-each (lambda (gf)
  383. (slot-set! gf 'extended-by
  384. (delq! eg (slot-ref gf 'extended-by))))
  385. gfs)
  386. (invalidate-method-cache! eg))
  387. (define* (ensure-generic old-definition #:optional name)
  388. (cond ((is-a? old-definition <generic>) old-definition)
  389. ((procedure-with-setter? old-definition)
  390. (make <generic-with-setter>
  391. #:name name
  392. #:default (procedure old-definition)
  393. #:setter (setter old-definition)))
  394. ((procedure? old-definition)
  395. (if (generic-capability? old-definition) old-definition
  396. (make <generic> #:name name #:default old-definition)))
  397. (else (make <generic> #:name name))))
  398. ;; same semantics as <generic>
  399. (define-syntax-rule (define-accessor name)
  400. (define name
  401. (cond ((not (defined? 'name)) (ensure-accessor #f 'name))
  402. ((is-a? name <accessor>) (make <accessor> #:name 'name))
  403. (else (ensure-accessor name 'name)))))
  404. (define (make-setter-name name)
  405. (string->symbol (string-append "setter:" (symbol->string name))))
  406. (define* (make-accessor #:optional name)
  407. (make <accessor>
  408. #:name name
  409. #:setter (make <generic>
  410. #:name (and name (make-setter-name name)))))
  411. (define* (ensure-accessor proc #:optional name)
  412. (cond ((and (is-a? proc <accessor>)
  413. (is-a? (setter proc) <generic>))
  414. proc)
  415. ((is-a? proc <generic-with-setter>)
  416. (upgrade-accessor proc (setter proc)))
  417. ((is-a? proc <generic>)
  418. (upgrade-accessor proc (make-generic name)))
  419. ((procedure-with-setter? proc)
  420. (make <accessor>
  421. #:name name
  422. #:default (procedure proc)
  423. #:setter (ensure-generic (setter proc) name)))
  424. ((procedure? proc)
  425. (ensure-accessor (if (generic-capability? proc)
  426. (make <generic> #:name name #:default proc)
  427. (ensure-generic proc name))
  428. name))
  429. (else
  430. (make-accessor name))))
  431. (define (upgrade-accessor generic setter)
  432. (let ((methods (slot-ref generic 'methods))
  433. (gws (make (if (is-a? generic <extended-generic>)
  434. <extended-generic-with-setter>
  435. <accessor>)
  436. #:name (generic-function-name generic)
  437. #:extended-by (slot-ref generic 'extended-by)
  438. #:setter setter)))
  439. (if (is-a? generic <extended-generic>)
  440. (let ((gfs (slot-ref generic 'extends)))
  441. (not-extended-by! gfs generic)
  442. (slot-set! gws 'extends gfs)
  443. (extended-by! gfs gws)))
  444. ;; Steal old methods
  445. (for-each (lambda (method)
  446. (slot-set! method 'generic-function gws))
  447. methods)
  448. (slot-set! gws 'methods methods)
  449. (invalidate-method-cache! gws)
  450. gws))
  451. ;;;
  452. ;;; {Methods}
  453. ;;;
  454. (define (toplevel-define! name val)
  455. (module-define! (current-module) name val))
  456. (define-syntax define-method
  457. (syntax-rules (setter)
  458. ((_ ((setter name) . args) body ...)
  459. (begin
  460. (if (or (not (defined? 'name))
  461. (not (is-a? name <accessor>)))
  462. (toplevel-define! 'name
  463. (ensure-accessor
  464. (if (defined? 'name) name #f) 'name)))
  465. (add-method! (setter name) (method args body ...))))
  466. ((_ (name . args) body ...)
  467. (begin
  468. ;; FIXME: this code is how it always was, but it's quite cracky:
  469. ;; it will only define the generic function if it was undefined
  470. ;; before (ok), or *was defined to #f*. The latter is crack. But
  471. ;; there are bootstrap issues about fixing this -- change it to
  472. ;; (is-a? name <generic>) and see.
  473. (if (or (not (defined? 'name))
  474. (not name))
  475. (toplevel-define! 'name (make <generic> #:name 'name)))
  476. (add-method! name (method args body ...))))))
  477. (define-syntax method
  478. (lambda (x)
  479. (define (parse-args args)
  480. (let lp ((ls args) (formals '()) (specializers '()))
  481. (syntax-case ls ()
  482. (((f s) . rest)
  483. (and (identifier? #'f) (identifier? #'s))
  484. (lp #'rest
  485. (cons #'f formals)
  486. (cons #'s specializers)))
  487. ((f . rest)
  488. (identifier? #'f)
  489. (lp #'rest
  490. (cons #'f formals)
  491. (cons #'<top> specializers)))
  492. (()
  493. (list (reverse formals)
  494. (reverse (cons #''() specializers))))
  495. (tail
  496. (identifier? #'tail)
  497. (list (append (reverse formals) #'tail)
  498. (reverse (cons #'<top> specializers)))))))
  499. (define (find-free-id exp referent)
  500. (syntax-case exp ()
  501. ((x . y)
  502. (or (find-free-id #'x referent)
  503. (find-free-id #'y referent)))
  504. (x
  505. (identifier? #'x)
  506. (let ((id (datum->syntax #'x referent)))
  507. (and (free-identifier=? #'x id) id)))
  508. (_ #f)))
  509. (define (compute-procedure formals body)
  510. (syntax-case body ()
  511. ((body0 ...)
  512. (with-syntax ((formals formals))
  513. #'(lambda formals body0 ...)))))
  514. (define (->proper args)
  515. (let lp ((ls args) (out '()))
  516. (syntax-case ls ()
  517. ((x . xs) (lp #'xs (cons #'x out)))
  518. (() (reverse out))
  519. (tail (reverse (cons #'tail out))))))
  520. (define (compute-make-procedure formals body next-method)
  521. (syntax-case body ()
  522. ((body ...)
  523. (with-syntax ((next-method next-method))
  524. (syntax-case formals ()
  525. ((formal ...)
  526. #'(lambda (real-next-method)
  527. (lambda (formal ...)
  528. (let ((next-method (lambda args
  529. (if (null? args)
  530. (real-next-method formal ...)
  531. (apply real-next-method args)))))
  532. body ...))))
  533. (formals
  534. (with-syntax (((formal ...) (->proper #'formals)))
  535. #'(lambda (real-next-method)
  536. (lambda formals
  537. (let ((next-method (lambda args
  538. (if (null? args)
  539. (apply real-next-method formal ...)
  540. (apply real-next-method args)))))
  541. body ...))))))))))
  542. (define (compute-procedures formals body)
  543. ;; So, our use of this is broken, because it operates on the
  544. ;; pre-expansion source code. It's equivalent to just searching
  545. ;; for referent in the datums. Ah well.
  546. (let ((id (find-free-id body 'next-method)))
  547. (if id
  548. ;; return a make-procedure
  549. (values #'#f
  550. (compute-make-procedure formals body id))
  551. (values (compute-procedure formals body)
  552. #'#f))))
  553. (syntax-case x ()
  554. ((_ args) #'(method args (if #f #f)))
  555. ((_ args body0 body1 ...)
  556. (with-syntax (((formals (specializer ...)) (parse-args #'args)))
  557. (call-with-values
  558. (lambda ()
  559. (compute-procedures #'formals #'(body0 body1 ...)))
  560. (lambda (procedure make-procedure)
  561. (with-syntax ((procedure procedure)
  562. (make-procedure make-procedure))
  563. #'(make <method>
  564. #:specializers (cons* specializer ...)
  565. #:formals 'formals
  566. #:body '(body0 body1 ...)
  567. #:make-procedure make-procedure
  568. #:procedure procedure)))))))))
  569. ;;;
  570. ;;; {add-method!}
  571. ;;;
  572. (define (add-method-in-classes! m)
  573. ;; Add method in all the classes which appears in its specializers list
  574. (for-each* (lambda (x)
  575. (let ((dm (class-direct-methods x)))
  576. (if (not (memq m dm))
  577. (slot-set! x 'direct-methods (cons m dm)))))
  578. (method-specializers m)))
  579. (define (remove-method-in-classes! m)
  580. ;; Remove method in all the classes which appears in its specializers list
  581. (for-each* (lambda (x)
  582. (slot-set! x
  583. 'direct-methods
  584. (delv! m (class-direct-methods x))))
  585. (method-specializers m)))
  586. (define (compute-new-list-of-methods gf new)
  587. (let ((new-spec (method-specializers new))
  588. (methods (slot-ref gf 'methods)))
  589. (let loop ((l methods))
  590. (if (null? l)
  591. (cons new methods)
  592. (if (equal? (method-specializers (car l)) new-spec)
  593. (begin
  594. ;; This spec. list already exists. Remove old method from dependents
  595. (remove-method-in-classes! (car l))
  596. (set-car! l new)
  597. methods)
  598. (loop (cdr l)))))))
  599. (define (method-n-specializers m)
  600. (length* (slot-ref m 'specializers)))
  601. (define (calculate-n-specialized gf)
  602. (fold (lambda (m n) (max n (method-n-specializers m)))
  603. 0
  604. (generic-function-methods gf)))
  605. (define (invalidate-method-cache! gf)
  606. (%invalidate-method-cache! gf)
  607. (slot-set! gf 'n-specialized (calculate-n-specialized gf))
  608. (for-each (lambda (gf) (invalidate-method-cache! gf))
  609. (slot-ref gf 'extended-by)))
  610. (define internal-add-method!
  611. (method ((gf <generic>) (m <method>))
  612. (slot-set! m 'generic-function gf)
  613. (slot-set! gf 'methods (compute-new-list-of-methods gf m))
  614. (invalidate-method-cache! gf)
  615. (add-method-in-classes! m)
  616. *unspecified*))
  617. (define-generic add-method!)
  618. ((method-procedure internal-add-method!) add-method! internal-add-method!)
  619. (define-method (add-method! (proc <procedure>) (m <method>))
  620. (if (generic-capability? proc)
  621. (begin
  622. (enable-primitive-generic! proc)
  623. (add-method! proc m))
  624. (next-method)))
  625. (define-method (add-method! (pg <primitive-generic>) (m <method>))
  626. (add-method! (primitive-generic-generic pg) m))
  627. (define-method (add-method! obj (m <method>))
  628. (goops-error "~S is not a valid generic function" obj))
  629. ;;;
  630. ;;; {Access to meta objects}
  631. ;;;
  632. ;;;
  633. ;;; Methods
  634. ;;;
  635. (define-method (method-source (m <method>))
  636. (let* ((spec (map* class-name (slot-ref m 'specializers)))
  637. (src (procedure-source (slot-ref m 'procedure))))
  638. (and src
  639. (let ((args (cadr src))
  640. (body (cddr src)))
  641. (cons 'method
  642. (cons (map* list args spec)
  643. body))))))
  644. (define-method (method-formals (m <method>))
  645. (slot-ref m 'formals))
  646. ;;;
  647. ;;; Slots
  648. ;;;
  649. (define slot-definition-name car)
  650. (define slot-definition-options cdr)
  651. (define (slot-definition-allocation s)
  652. (get-keyword #:allocation (cdr s) #:instance))
  653. (define (slot-definition-getter s)
  654. (get-keyword #:getter (cdr s) #f))
  655. (define (slot-definition-setter s)
  656. (get-keyword #:setter (cdr s) #f))
  657. (define (slot-definition-accessor s)
  658. (get-keyword #:accessor (cdr s) #f))
  659. (define (slot-definition-init-value s)
  660. ;; can be #f, so we can't use #f as non-value
  661. (get-keyword #:init-value (cdr s) (make-unbound)))
  662. (define (slot-definition-init-form s)
  663. (get-keyword #:init-form (cdr s) (make-unbound)))
  664. (define (slot-definition-init-thunk s)
  665. (get-keyword #:init-thunk (cdr s) #f))
  666. (define (slot-definition-init-keyword s)
  667. (get-keyword #:init-keyword (cdr s) #f))
  668. (define (class-slot-definition class slot-name)
  669. (assq slot-name (class-slots class)))
  670. (define (slot-init-function class slot-name)
  671. (cadr (assq slot-name (slot-ref class 'getters-n-setters))))
  672. (define (accessor-method-slot-definition obj)
  673. "Return the slot definition of the accessor @var{obj}."
  674. (slot-ref obj 'slot-definition))
  675. ;;;
  676. ;;; {Standard methods used by the C runtime}
  677. ;;;
  678. ;;; Methods to compare objects
  679. ;;;
  680. ;; Have to do this in a strange order because equal? is used in the
  681. ;; add-method! implementation; we need to make sure that when the
  682. ;; primitive is extended, that the generic has a method. =
  683. (define g-equal? (make-generic 'equal?))
  684. ;; When this generic gets called, we will have already checked eq? and
  685. ;; eqv? -- the purpose of this generic is to extend equality. So by
  686. ;; default, there is no extension, thus the #f return.
  687. (add-method! g-equal? (method (x y) #f))
  688. (set-primitive-generic! equal? g-equal?)
  689. ;;;
  690. ;;; methods to display/write an object
  691. ;;;
  692. ; Code for writing objects must test that the slots they use are
  693. ; bound. Otherwise a slot-unbound method will be called and will
  694. ; conduct to an infinite loop.
  695. ;; Write
  696. (define (display-address o file)
  697. (display (number->string (object-address o) 16) file))
  698. (define-method (write o file)
  699. (display "#<instance " file)
  700. (display-address o file)
  701. (display #\> file))
  702. (define write-object (primitive-generic-generic write))
  703. (define-method (write (o <object>) file)
  704. (let ((class (class-of o)))
  705. (if (slot-bound? class 'name)
  706. (begin
  707. (display "#<" file)
  708. (display (class-name class) file)
  709. (display #\space file)
  710. (display-address o file)
  711. (display #\> file))
  712. (next-method))))
  713. (define-method (write (class <class>) file)
  714. (let ((meta (class-of class)))
  715. (if (and (slot-bound? class 'name)
  716. (slot-bound? meta 'name))
  717. (begin
  718. (display "#<" file)
  719. (display (class-name meta) file)
  720. (display #\space file)
  721. (display (class-name class) file)
  722. (display #\space file)
  723. (display-address class file)
  724. (display #\> file))
  725. (next-method))))
  726. (define-method (write (gf <generic>) file)
  727. (let ((meta (class-of gf)))
  728. (if (and (slot-bound? meta 'name)
  729. (slot-bound? gf 'methods))
  730. (begin
  731. (display "#<" file)
  732. (display (class-name meta) file)
  733. (let ((name (generic-function-name gf)))
  734. (if name
  735. (begin
  736. (display #\space file)
  737. (display name file))))
  738. (display " (" file)
  739. (display (length (generic-function-methods gf)) file)
  740. (display ")>" file))
  741. (next-method))))
  742. (define-method (write (o <method>) file)
  743. (let ((meta (class-of o)))
  744. (if (and (slot-bound? meta 'name)
  745. (slot-bound? o 'specializers))
  746. (begin
  747. (display "#<" file)
  748. (display (class-name meta) file)
  749. (display #\space file)
  750. (display (map* (lambda (spec)
  751. (if (slot-bound? spec 'name)
  752. (slot-ref spec 'name)
  753. spec))
  754. (method-specializers o))
  755. file)
  756. (display #\space file)
  757. (display-address o file)
  758. (display #\> file))
  759. (next-method))))
  760. ;; Display (do the same thing as write by default)
  761. (define-method (display o file)
  762. (write-object o file))
  763. ;;;
  764. ;;; Handling of duplicate bindings in the module system
  765. ;;;
  766. (define (find-subclass super name)
  767. (let lp ((classes (class-direct-subclasses super)))
  768. (cond
  769. ((null? classes)
  770. (error "class not found" name))
  771. ((and (slot-bound? (car classes) 'name)
  772. (eq? (class-name (car classes)) name))
  773. (car classes))
  774. (else
  775. (lp (cdr classes))))))
  776. ;; A record type.
  777. (define <module> (find-subclass <top> '<module>))
  778. (define-method (merge-generics (module <module>)
  779. (name <symbol>)
  780. (int1 <module>)
  781. (val1 <top>)
  782. (int2 <module>)
  783. (val2 <top>)
  784. (var <top>)
  785. (val <top>))
  786. #f)
  787. (define-method (merge-generics (module <module>)
  788. (name <symbol>)
  789. (int1 <module>)
  790. (val1 <generic>)
  791. (int2 <module>)
  792. (val2 <generic>)
  793. (var <top>)
  794. (val <boolean>))
  795. (and (not (eq? val1 val2))
  796. (make-variable (make-extended-generic (list val2 val1) name))))
  797. (define-method (merge-generics (module <module>)
  798. (name <symbol>)
  799. (int1 <module>)
  800. (val1 <generic>)
  801. (int2 <module>)
  802. (val2 <generic>)
  803. (var <top>)
  804. (gf <extended-generic>))
  805. (and (not (memq val2 (slot-ref gf 'extends)))
  806. (begin
  807. (slot-set! gf
  808. 'extends
  809. (cons val2 (delq! val2 (slot-ref gf 'extends))))
  810. (slot-set! val2
  811. 'extended-by
  812. (cons gf (delq! gf (slot-ref val2 'extended-by))))
  813. (invalidate-method-cache! gf)
  814. var)))
  815. (module-define! duplicate-handlers 'merge-generics merge-generics)
  816. (define-method (merge-accessors (module <module>)
  817. (name <symbol>)
  818. (int1 <module>)
  819. (val1 <top>)
  820. (int2 <module>)
  821. (val2 <top>)
  822. (var <top>)
  823. (val <top>))
  824. #f)
  825. (define-method (merge-accessors (module <module>)
  826. (name <symbol>)
  827. (int1 <module>)
  828. (val1 <accessor>)
  829. (int2 <module>)
  830. (val2 <accessor>)
  831. (var <top>)
  832. (val <top>))
  833. (merge-generics module name int1 val1 int2 val2 var val))
  834. (module-define! duplicate-handlers 'merge-accessors merge-accessors)
  835. ;;;
  836. ;;; slot access
  837. ;;;
  838. (define (class-slot-g-n-s class slot-name)
  839. (let* ((this-slot (assq slot-name (slot-ref class 'slots)))
  840. (g-n-s (cddr (or (assq slot-name (slot-ref class 'getters-n-setters))
  841. (slot-missing class slot-name)))))
  842. (if (not (memq (slot-definition-allocation this-slot)
  843. '(#:class #:each-subclass)))
  844. (slot-missing class slot-name))
  845. g-n-s))
  846. (define (class-slot-ref class slot)
  847. (let ((x ((car (class-slot-g-n-s class slot)) #f)))
  848. (if (unbound? x)
  849. (slot-unbound class slot)
  850. x)))
  851. (define (class-slot-set! class slot value)
  852. ((cadr (class-slot-g-n-s class slot)) #f value))
  853. (define-method (slot-unbound (c <class>) (o <object>) s)
  854. (goops-error "Slot `~S' is unbound in object ~S" s o))
  855. (define-method (slot-unbound (c <class>) s)
  856. (goops-error "Slot `~S' is unbound in class ~S" s c))
  857. (define-method (slot-unbound (o <object>))
  858. (goops-error "Unbound slot in object ~S" o))
  859. (define-method (slot-missing (c <class>) (o <object>) s)
  860. (goops-error "No slot with name `~S' in object ~S" s o))
  861. (define-method (slot-missing (c <class>) s)
  862. (goops-error "No class slot with name `~S' in class ~S" s c))
  863. (define-method (slot-missing (c <class>) (o <object>) s value)
  864. (slot-missing c o s))
  865. ;;; Methods for the possible error we can encounter when calling a gf
  866. (define-method (no-next-method (gf <generic>) args)
  867. (goops-error "No next method when calling ~S\nwith arguments ~S" gf args))
  868. (define-method (no-applicable-method (gf <generic>) args)
  869. (goops-error "No applicable method for ~S in call ~S"
  870. gf (cons (generic-function-name gf) args)))
  871. (define-method (no-method (gf <generic>) args)
  872. (goops-error "No method defined for ~S" gf))
  873. ;;;
  874. ;;; {Cloning functions (from rdeline@CS.CMU.EDU)}
  875. ;;;
  876. (define-method (shallow-clone (self <object>))
  877. (let ((clone (%allocate-instance (class-of self) '()))
  878. (slots (map slot-definition-name
  879. (class-slots (class-of self)))))
  880. (for-each (lambda (slot)
  881. (if (slot-bound? self slot)
  882. (slot-set! clone slot (slot-ref self slot))))
  883. slots)
  884. clone))
  885. (define-method (deep-clone (self <object>))
  886. (let ((clone (%allocate-instance (class-of self) '()))
  887. (slots (map slot-definition-name
  888. (class-slots (class-of self)))))
  889. (for-each (lambda (slot)
  890. (if (slot-bound? self slot)
  891. (slot-set! clone slot
  892. (let ((value (slot-ref self slot)))
  893. (if (instance? value)
  894. (deep-clone value)
  895. value)))))
  896. slots)
  897. clone))
  898. ;;;
  899. ;;; {Class redefinition utilities}
  900. ;;;
  901. ;;; (class-redefinition OLD NEW)
  902. ;;;
  903. ;;; Has correct the following conditions:
  904. ;;; Methods
  905. ;;;
  906. ;;; 1. New accessor specializers refer to new header
  907. ;;;
  908. ;;; Classes
  909. ;;;
  910. ;;; 1. New class cpl refers to the new class header
  911. ;;; 2. Old class header exists on old super classes direct-subclass lists
  912. ;;; 3. New class header exists on new super classes direct-subclass lists
  913. (define-method (class-redefinition (old <class>) (new <class>))
  914. ;; Work on direct methods:
  915. ;; 1. Remove accessor methods from the old class
  916. ;; 2. Patch the occurences of new in the specializers by old
  917. ;; 3. Displace the methods from old to new
  918. (remove-class-accessors! old) ;; -1-
  919. (let ((methods (class-direct-methods new)))
  920. (for-each (lambda (m)
  921. (update-direct-method! m new old)) ;; -2-
  922. methods)
  923. (slot-set! new
  924. 'direct-methods
  925. (append methods (class-direct-methods old))))
  926. ;; Substitute old for new in new cpl
  927. (set-car! (slot-ref new 'cpl) old)
  928. ;; Remove the old class from the direct-subclasses list of its super classes
  929. (for-each (lambda (c) (slot-set! c 'direct-subclasses
  930. (delv! old (class-direct-subclasses c))))
  931. (class-direct-supers old))
  932. ;; Replace the new class with the old in the direct-subclasses of the supers
  933. (for-each (lambda (c)
  934. (slot-set! c 'direct-subclasses
  935. (cons old (delv! new (class-direct-subclasses c)))))
  936. (class-direct-supers new))
  937. ;; Swap object headers
  938. (%modify-class old new)
  939. ;; Now old is NEW!
  940. ;; Redefine all the subclasses of old to take into account modification
  941. (for-each
  942. (lambda (c)
  943. (update-direct-subclass! c new old))
  944. (class-direct-subclasses new))
  945. ;; Invalidate class so that subsequent instances slot accesses invoke
  946. ;; change-object-class
  947. (slot-set! new 'redefined old)
  948. (%invalidate-class new) ;must come after slot-set!
  949. old)
  950. ;;;
  951. ;;; remove-class-accessors!
  952. ;;;
  953. (define-method (remove-class-accessors! (c <class>))
  954. (for-each (lambda (m)
  955. (if (is-a? m <accessor-method>)
  956. (let ((gf (slot-ref m 'generic-function)))
  957. ;; remove the method from its GF
  958. (slot-set! gf 'methods
  959. (delq1! m (slot-ref gf 'methods)))
  960. (invalidate-method-cache! gf)
  961. ;; remove the method from its specializers
  962. (remove-method-in-classes! m))))
  963. (class-direct-methods c)))
  964. ;;;
  965. ;;; update-direct-method!
  966. ;;;
  967. (define-method (update-direct-method! (m <method>)
  968. (old <class>)
  969. (new <class>))
  970. (let loop ((l (method-specializers m)))
  971. ;; Note: the <top> in dotted list is never used.
  972. ;; So we can work as if we had only proper lists.
  973. (if (pair? l)
  974. (begin
  975. (if (eqv? (car l) old)
  976. (set-car! l new))
  977. (loop (cdr l))))))
  978. ;;;
  979. ;;; update-direct-subclass!
  980. ;;;
  981. (define-method (update-direct-subclass! (c <class>)
  982. (old <class>)
  983. (new <class>))
  984. (class-redefinition c
  985. (make-class (class-direct-supers c)
  986. (class-direct-slots c)
  987. #:name (class-name c)
  988. #:metaclass (class-of c))))
  989. ;;;
  990. ;;; {Utilities for INITIALIZE methods}
  991. ;;;
  992. ;;; compute-slot-accessors
  993. ;;;
  994. (define (compute-slot-accessors class slots)
  995. (for-each
  996. (lambda (s g-n-s)
  997. (let ((getter-function (slot-definition-getter s))
  998. (setter-function (slot-definition-setter s))
  999. (accessor (slot-definition-accessor s)))
  1000. (if getter-function
  1001. (add-method! getter-function
  1002. (compute-getter-method class g-n-s)))
  1003. (if setter-function
  1004. (add-method! setter-function
  1005. (compute-setter-method class g-n-s)))
  1006. (if accessor
  1007. (begin
  1008. (add-method! accessor
  1009. (compute-getter-method class g-n-s))
  1010. (add-method! (setter accessor)
  1011. (compute-setter-method class g-n-s))))))
  1012. slots (slot-ref class 'getters-n-setters)))
  1013. (define-method (compute-getter-method (class <class>) slotdef)
  1014. (let ((init-thunk (cadr slotdef))
  1015. (g-n-s (cddr slotdef)))
  1016. (make <accessor-method>
  1017. #:specializers (list class)
  1018. #:procedure (cond ((pair? g-n-s)
  1019. (make-generic-bound-check-getter (car g-n-s)))
  1020. (init-thunk
  1021. (standard-get g-n-s))
  1022. (else
  1023. (bound-check-get g-n-s)))
  1024. #:slot-definition slotdef)))
  1025. (define-method (compute-setter-method (class <class>) slotdef)
  1026. (let ((g-n-s (cddr slotdef)))
  1027. (make <accessor-method>
  1028. #:specializers (list class <top>)
  1029. #:procedure (if (pair? g-n-s)
  1030. (cadr g-n-s)
  1031. (standard-set g-n-s))
  1032. #:slot-definition slotdef)))
  1033. (define (make-generic-bound-check-getter proc)
  1034. (lambda (o) (assert-bound (proc o) o)))
  1035. ;; the idea is to compile the index into the procedure, for fastest
  1036. ;; lookup. Also, @slot-ref and @slot-set! have their own bytecodes.
  1037. (eval-when (eval load compile)
  1038. (define num-standard-pre-cache 20))
  1039. (define-macro (define-standard-accessor-method form . body)
  1040. (let ((name (caar form))
  1041. (n-var (cadar form))
  1042. (args (cdr form)))
  1043. (define (make-one x)
  1044. (define (body-trans form)
  1045. (cond ((not (pair? form)) form)
  1046. ((eq? (car form) '@slot-ref)
  1047. `(,(car form) ,(cadr form) ,x))
  1048. ((eq? (car form) '@slot-set!)
  1049. `(,(car form) ,(cadr form) ,x ,(cadddr form)))
  1050. (else
  1051. (map body-trans form))))
  1052. `(lambda ,args ,@(map body-trans body)))
  1053. `(define ,name
  1054. (let ((cache (vector ,@(map make-one (iota num-standard-pre-cache)))))
  1055. (lambda (n)
  1056. (if (< n ,num-standard-pre-cache)
  1057. (vector-ref cache n)
  1058. ((lambda (,n-var) (lambda ,args ,@body)) n)))))))
  1059. (define-standard-accessor-method ((bound-check-get n) o)
  1060. (let ((x (@slot-ref o n)))
  1061. (if (unbound? x)
  1062. (slot-unbound o)
  1063. x)))
  1064. (define-standard-accessor-method ((standard-get n) o)
  1065. (@slot-ref o n))
  1066. (define-standard-accessor-method ((standard-set n) o v)
  1067. (@slot-set! o n v))
  1068. ;;; compute-getters-n-setters
  1069. ;;;
  1070. (define (compute-getters-n-setters class slots)
  1071. (define (compute-slot-init-function name s)
  1072. (or (let ((thunk (slot-definition-init-thunk s)))
  1073. (and thunk
  1074. (if (thunk? thunk)
  1075. thunk
  1076. (goops-error "Bad init-thunk for slot `~S' in ~S: ~S"
  1077. name class thunk))))
  1078. (let ((init (slot-definition-init-value s)))
  1079. (and (not (unbound? init))
  1080. (lambda () init)))))
  1081. (define (verify-accessors slot l)
  1082. (cond ((integer? l))
  1083. ((not (and (list? l) (= (length l) 2)))
  1084. (goops-error "Bad getter and setter for slot `~S' in ~S: ~S"
  1085. slot class l))
  1086. (else
  1087. (let ((get (car l))
  1088. (set (cadr l)))
  1089. (if (not (procedure? get))
  1090. (goops-error "Bad getter closure for slot `~S' in ~S: ~S"
  1091. slot class get))
  1092. (if (not (procedure? set))
  1093. (goops-error "Bad setter closure for slot `~S' in ~S: ~S"
  1094. slot class set))))))
  1095. (map (lambda (s)
  1096. ;; The strange treatment of nfields is due to backward compatibility.
  1097. (let* ((index (slot-ref class 'nfields))
  1098. (g-n-s (compute-get-n-set class s))
  1099. (size (- (slot-ref class 'nfields) index))
  1100. (name (slot-definition-name s)))
  1101. ;; NOTE: The following is interdependent with C macros
  1102. ;; defined above goops.c:scm_sys_prep_layout_x.
  1103. ;;
  1104. ;; For simple instance slots, we have the simplest form
  1105. ;; '(name init-function . index)
  1106. ;; For other slots we have
  1107. ;; '(name init-function getter setter . alloc)
  1108. ;; where alloc is:
  1109. ;; '(index size) for instance allocated slots
  1110. ;; '() for other slots
  1111. (verify-accessors name g-n-s)
  1112. (cons name
  1113. (cons (compute-slot-init-function name s)
  1114. (if (or (integer? g-n-s)
  1115. (zero? size))
  1116. g-n-s
  1117. (append g-n-s (list index size)))))))
  1118. slots))
  1119. ;;; compute-cpl
  1120. ;;;
  1121. ;;; Correct behaviour:
  1122. ;;;
  1123. ;;; (define-class food ())
  1124. ;;; (define-class fruit (food))
  1125. ;;; (define-class spice (food))
  1126. ;;; (define-class apple (fruit))
  1127. ;;; (define-class cinnamon (spice))
  1128. ;;; (define-class pie (apple cinnamon))
  1129. ;;; => cpl (pie) = pie apple fruit cinnamon spice food object top
  1130. ;;;
  1131. ;;; (define-class d ())
  1132. ;;; (define-class e ())
  1133. ;;; (define-class f ())
  1134. ;;; (define-class b (d e))
  1135. ;;; (define-class c (e f))
  1136. ;;; (define-class a (b c))
  1137. ;;; => cpl (a) = a b d c e f object top
  1138. ;;;
  1139. (define-method (compute-cpl (class <class>))
  1140. (compute-std-cpl class class-direct-supers))
  1141. ;; Support
  1142. (define (only-non-null lst)
  1143. (filter (lambda (l) (not (null? l))) lst))
  1144. (define (compute-std-cpl c get-direct-supers)
  1145. (let ((c-direct-supers (get-direct-supers c)))
  1146. (merge-lists (list c)
  1147. (only-non-null (append (map class-precedence-list
  1148. c-direct-supers)
  1149. (list c-direct-supers))))))
  1150. (define (merge-lists reversed-partial-result inputs)
  1151. (cond
  1152. ((every null? inputs)
  1153. (reverse! reversed-partial-result))
  1154. (else
  1155. (let* ((candidate (lambda (c)
  1156. (and (not (any (lambda (l)
  1157. (memq c (cdr l)))
  1158. inputs))
  1159. c)))
  1160. (candidate-car (lambda (l)
  1161. (and (not (null? l))
  1162. (candidate (car l)))))
  1163. (next (any candidate-car inputs)))
  1164. (if (not next)
  1165. (goops-error "merge-lists: Inconsistent precedence graph"))
  1166. (let ((remove-next (lambda (l)
  1167. (if (eq? (car l) next)
  1168. (cdr l)
  1169. l))))
  1170. (merge-lists (cons next reversed-partial-result)
  1171. (only-non-null (map remove-next inputs))))))))
  1172. ;; Modified from TinyClos:
  1173. ;;
  1174. ;; A simple topological sort.
  1175. ;;
  1176. ;; It's in this file so that both TinyClos and Objects can use it.
  1177. ;;
  1178. ;; This is a fairly modified version of code I originally got from Anurag
  1179. ;; Mendhekar <anurag@moose.cs.indiana.edu>.
  1180. ;;
  1181. (define (compute-clos-cpl c get-direct-supers)
  1182. (top-sort ((build-transitive-closure get-direct-supers) c)
  1183. ((build-constraints get-direct-supers) c)
  1184. (std-tie-breaker get-direct-supers)))
  1185. (define (top-sort elements constraints tie-breaker)
  1186. (let loop ((elements elements)
  1187. (constraints constraints)
  1188. (result '()))
  1189. (if (null? elements)
  1190. result
  1191. (let ((can-go-in-now
  1192. (filter
  1193. (lambda (x)
  1194. (every (lambda (constraint)
  1195. (or (not (eq? (cadr constraint) x))
  1196. (memq (car constraint) result)))
  1197. constraints))
  1198. elements)))
  1199. (if (null? can-go-in-now)
  1200. (goops-error "top-sort: Invalid constraints")
  1201. (let ((choice (if (null? (cdr can-go-in-now))
  1202. (car can-go-in-now)
  1203. (tie-breaker result
  1204. can-go-in-now))))
  1205. (loop
  1206. (filter (lambda (x) (not (eq? x choice)))
  1207. elements)
  1208. constraints
  1209. (append result (list choice)))))))))
  1210. (define (std-tie-breaker get-supers)
  1211. (lambda (partial-cpl min-elts)
  1212. (let loop ((pcpl (reverse partial-cpl)))
  1213. (let ((current-elt (car pcpl)))
  1214. (let ((ds-of-ce (get-supers current-elt)))
  1215. (let ((common (filter (lambda (x)
  1216. (memq x ds-of-ce))
  1217. min-elts)))
  1218. (if (null? common)
  1219. (if (null? (cdr pcpl))
  1220. (goops-error "std-tie-breaker: Nothing valid")
  1221. (loop (cdr pcpl)))
  1222. (car common))))))))
  1223. (define (build-transitive-closure get-follow-ons)
  1224. (lambda (x)
  1225. (let track ((result '())
  1226. (pending (list x)))
  1227. (if (null? pending)
  1228. result
  1229. (let ((next (car pending)))
  1230. (if (memq next result)
  1231. (track result (cdr pending))
  1232. (track (cons next result)
  1233. (append (get-follow-ons next)
  1234. (cdr pending)))))))))
  1235. (define (build-constraints get-follow-ons)
  1236. (lambda (x)
  1237. (let loop ((elements ((build-transitive-closure get-follow-ons) x))
  1238. (this-one '())
  1239. (result '()))
  1240. (if (or (null? this-one) (null? (cdr this-one)))
  1241. (if (null? elements)
  1242. result
  1243. (loop (cdr elements)
  1244. (cons (car elements)
  1245. (get-follow-ons (car elements)))
  1246. result))
  1247. (loop elements
  1248. (cdr this-one)
  1249. (cons (list (car this-one) (cadr this-one))
  1250. result))))))
  1251. ;;; compute-get-n-set
  1252. ;;;
  1253. (define-method (compute-get-n-set (class <class>) s)
  1254. (case (slot-definition-allocation s)
  1255. ((#:instance) ;; Instance slot
  1256. ;; get-n-set is just its offset
  1257. (let ((already-allocated (slot-ref class 'nfields)))
  1258. (slot-set! class 'nfields (+ already-allocated 1))
  1259. already-allocated))
  1260. ((#:class) ;; Class slot
  1261. ;; Class-slots accessors are implemented as 2 closures around
  1262. ;; a Scheme variable. As instance slots, class slots must be
  1263. ;; unbound at init time.
  1264. (let ((name (slot-definition-name s)))
  1265. (if (memq name (map slot-definition-name (class-direct-slots class)))
  1266. ;; This slot is direct; create a new shared variable
  1267. (make-closure-variable class)
  1268. ;; Slot is inherited. Find its definition in superclass
  1269. (let loop ((l (cdr (class-precedence-list class))))
  1270. (let ((r (assoc name (slot-ref (car l) 'getters-n-setters))))
  1271. (if r
  1272. (cddr r)
  1273. (loop (cdr l))))))))
  1274. ((#:each-subclass) ;; slot shared by instances of direct subclass.
  1275. ;; (Thomas Buerger, April 1998)
  1276. (make-closure-variable class))
  1277. ((#:virtual) ;; No allocation
  1278. ;; slot-ref and slot-set! function must be given by the user
  1279. (let ((get (get-keyword #:slot-ref (slot-definition-options s) #f))
  1280. (set (get-keyword #:slot-set! (slot-definition-options s) #f)))
  1281. (if (not (and get set))
  1282. (goops-error "You must supply a #:slot-ref and a #:slot-set! in ~S"
  1283. s))
  1284. (list get set)))
  1285. (else (next-method))))
  1286. (define (make-closure-variable class)
  1287. (let ((shared-variable (make-unbound)))
  1288. (list (lambda (o) shared-variable)
  1289. (lambda (o v) (set! shared-variable v)))))
  1290. (define-method (compute-get-n-set (o <object>) s)
  1291. (goops-error "Allocation \"~S\" is unknown" (slot-definition-allocation s)))
  1292. (define-method (compute-slots (class <class>))
  1293. (%compute-slots class))
  1294. ;;;
  1295. ;;; {Initialize}
  1296. ;;;
  1297. (define-method (initialize (object <object>) initargs)
  1298. (%initialize-object object initargs))
  1299. (define-method (initialize (class <class>) initargs)
  1300. (next-method)
  1301. (let ((dslots (get-keyword #:slots initargs '()))
  1302. (supers (get-keyword #:dsupers initargs '())))
  1303. (slot-set! class 'name (get-keyword #:name initargs '???))
  1304. (slot-set! class 'direct-supers supers)
  1305. (slot-set! class 'direct-slots dslots)
  1306. (slot-set! class 'direct-subclasses '())
  1307. (slot-set! class 'direct-methods '())
  1308. (slot-set! class 'cpl (compute-cpl class))
  1309. (slot-set! class 'redefined #f)
  1310. (let ((slots (compute-slots class)))
  1311. (slot-set! class 'slots slots)
  1312. (slot-set! class 'nfields 0)
  1313. (slot-set! class 'getters-n-setters (compute-getters-n-setters class
  1314. slots))
  1315. ;; Build getters - setters - accessors
  1316. (compute-slot-accessors class slots))
  1317. ;; Update the "direct-subclasses" of each inherited classes
  1318. (for-each (lambda (x)
  1319. (slot-set! x
  1320. 'direct-subclasses
  1321. (cons class (slot-ref x 'direct-subclasses))))
  1322. supers)
  1323. ;; Support for the underlying structs:
  1324. ;; Set the layout slot
  1325. (%prep-layout! class)
  1326. ;; Inherit class flags (invisible on scheme level) from supers
  1327. (%inherit-magic! class supers)))
  1328. (define (initialize-object-procedure object initargs)
  1329. (let ((proc (get-keyword #:procedure initargs #f)))
  1330. (cond ((not proc))
  1331. ((pair? proc)
  1332. (apply slot-set! object 'procedure proc))
  1333. (else
  1334. (slot-set! object 'procedure proc)))))
  1335. (define-method (initialize (applicable-struct <applicable-struct>) initargs)
  1336. (next-method)
  1337. (initialize-object-procedure applicable-struct initargs))
  1338. (define-method (initialize (generic <generic>) initargs)
  1339. (let ((previous-definition (get-keyword #:default initargs #f))
  1340. (name (get-keyword #:name initargs #f)))
  1341. (next-method)
  1342. (slot-set! generic 'methods (if (is-a? previous-definition <procedure>)
  1343. (list (method args
  1344. (apply previous-definition args)))
  1345. '()))
  1346. (if name
  1347. (set-procedure-property! generic 'name name))
  1348. ))
  1349. (define-method (initialize (gws <generic-with-setter>) initargs)
  1350. (next-method)
  1351. (%set-object-setter! gws (get-keyword #:setter initargs #f)))
  1352. (define-method (initialize (eg <extended-generic>) initargs)
  1353. (next-method)
  1354. (slot-set! eg 'extends (get-keyword #:extends initargs '())))
  1355. (define dummy-procedure (lambda args *unspecified*))
  1356. (define-method (initialize (method <method>) initargs)
  1357. (next-method)
  1358. (slot-set! method 'generic-function (get-keyword #:generic-function initargs #f))
  1359. (slot-set! method 'specializers (get-keyword #:specializers initargs '()))
  1360. (slot-set! method 'procedure
  1361. (get-keyword #:procedure initargs #f))
  1362. (slot-set! method 'formals (get-keyword #:formals initargs '()))
  1363. (slot-set! method 'body (get-keyword #:body initargs '()))
  1364. (slot-set! method 'make-procedure (get-keyword #:make-procedure initargs #f)))
  1365. ;;;
  1366. ;;; {Change-class}
  1367. ;;;
  1368. (define (change-object-class old-instance old-class new-class)
  1369. (let ((new-instance (allocate-instance new-class '())))
  1370. ;; Initialize the slots of the new instance
  1371. (for-each (lambda (slot)
  1372. (if (and (slot-exists-using-class? old-class old-instance slot)
  1373. (eq? (slot-definition-allocation
  1374. (class-slot-definition old-class slot))
  1375. #:instance)
  1376. (slot-bound-using-class? old-class old-instance slot))
  1377. ;; Slot was present and allocated in old instance; copy it
  1378. (slot-set-using-class!
  1379. new-class
  1380. new-instance
  1381. slot
  1382. (slot-ref-using-class old-class old-instance slot))
  1383. ;; slot was absent; initialize it with its default value
  1384. (let ((init (slot-init-function new-class slot)))
  1385. (if init
  1386. (slot-set-using-class!
  1387. new-class
  1388. new-instance
  1389. slot
  1390. (apply init '()))))))
  1391. (map slot-definition-name (class-slots new-class)))
  1392. ;; Exchange old and new instance in place to keep pointers valid
  1393. (%modify-instance old-instance new-instance)
  1394. ;; Allow class specific updates of instances (which now are swapped)
  1395. (update-instance-for-different-class new-instance old-instance)
  1396. old-instance))
  1397. (define-method (update-instance-for-different-class (old-instance <object>)
  1398. (new-instance
  1399. <object>))
  1400. ;;not really important what we do, we just need a default method
  1401. new-instance)
  1402. (define-method (change-class (old-instance <object>) (new-class <class>))
  1403. (change-object-class old-instance (class-of old-instance) new-class))
  1404. ;;;
  1405. ;;; {make}
  1406. ;;;
  1407. ;;; A new definition which overwrites the previous one which was built-in
  1408. ;;;
  1409. (define-method (allocate-instance (class <class>) initargs)
  1410. (%allocate-instance class initargs))
  1411. (define-method (make-instance (class <class>) . initargs)
  1412. (let ((instance (allocate-instance class initargs)))
  1413. (initialize instance initargs)
  1414. instance))
  1415. (define make make-instance)
  1416. ;;;
  1417. ;;; {apply-generic}
  1418. ;;;
  1419. ;;; Protocol for calling standard generic functions. This protocol is
  1420. ;;; not used for real <generic> functions (in this case we use a
  1421. ;;; completely C hard-coded protocol). Apply-generic is used by
  1422. ;;; goops for calls to subclasses of <generic> and <generic-with-setter>.
  1423. ;;; The code below is similar to the first MOP described in AMOP. In
  1424. ;;; particular, it doesn't used the currified approach to gf
  1425. ;;; call. There are 2 reasons for that:
  1426. ;;; - the protocol below is exposed to mimic completely the one written in C
  1427. ;;; - the currified protocol would be imho inefficient in C.
  1428. ;;;
  1429. (define-method (apply-generic (gf <generic>) args)
  1430. (if (null? (slot-ref gf 'methods))
  1431. (no-method gf args))
  1432. (let ((methods (compute-applicable-methods gf args)))
  1433. (if methods
  1434. (apply-methods gf (sort-applicable-methods gf methods args) args)
  1435. (no-applicable-method gf args))))
  1436. ;; compute-applicable-methods is bound to %compute-applicable-methods.
  1437. ;; *fixme* use let
  1438. (define %%compute-applicable-methods
  1439. (make <generic> #:name 'compute-applicable-methods))
  1440. (define-method (%%compute-applicable-methods (gf <generic>) args)
  1441. (%compute-applicable-methods gf args))
  1442. (set! compute-applicable-methods %%compute-applicable-methods)
  1443. (define-method (sort-applicable-methods (gf <generic>) methods args)
  1444. (let ((targs (map class-of args)))
  1445. (sort methods (lambda (m1 m2) (method-more-specific? m1 m2 targs)))))
  1446. (define-method (method-more-specific? (m1 <method>) (m2 <method>) targs)
  1447. (%method-more-specific? m1 m2 targs))
  1448. (define-method (apply-method (gf <generic>) methods build-next args)
  1449. (apply (method-procedure (car methods))
  1450. (build-next (cdr methods) args)
  1451. args))
  1452. (define-method (apply-methods (gf <generic>) (l <list>) args)
  1453. (letrec ((next (lambda (procs args)
  1454. (lambda new-args
  1455. (let ((a (if (null? new-args) args new-args)))
  1456. (if (null? procs)
  1457. (no-next-method gf a)
  1458. (apply-method gf procs next a)))))))
  1459. (apply-method gf l next args)))
  1460. ;; We don't want the following procedure to turn up in backtraces:
  1461. (for-each (lambda (proc)
  1462. (set-procedure-property! proc 'system-procedure #t))
  1463. (list slot-unbound
  1464. slot-missing
  1465. no-next-method
  1466. no-applicable-method
  1467. no-method
  1468. ))
  1469. ;;;
  1470. ;;; {<composite-metaclass> and <active-metaclass>}
  1471. ;;;
  1472. ;(autoload "active-slot" <active-metaclass>)
  1473. ;(autoload "composite-slot" <composite-metaclass>)
  1474. ;(export <composite-metaclass> <active-metaclass>)
  1475. ;;;
  1476. ;;; {Tools}
  1477. ;;;
  1478. ;; list2set
  1479. ;;
  1480. ;; duplicate the standard list->set function but using eq instead of
  1481. ;; eqv which really sucks a lot, uselessly here
  1482. ;;
  1483. (define (list2set l)
  1484. (let loop ((l l)
  1485. (res '()))
  1486. (cond
  1487. ((null? l) res)
  1488. ((memq (car l) res) (loop (cdr l) res))
  1489. (else (loop (cdr l) (cons (car l) res))))))
  1490. (define (class-subclasses c)
  1491. (letrec ((allsubs (lambda (c)
  1492. (cons c (mapappend allsubs
  1493. (class-direct-subclasses c))))))
  1494. (list2set (cdr (allsubs c)))))
  1495. (define (class-methods c)
  1496. (list2set (mapappend class-direct-methods
  1497. (cons c (class-subclasses c)))))
  1498. ;;;
  1499. ;;; {Final initialization}
  1500. ;;;
  1501. ;; Tell C code that the main bulk of Goops has been loaded
  1502. (%goops-loaded)
  1503. ;;;
  1504. ;;; {SMOB and port classes}
  1505. ;;;
  1506. (define <arbiter> (find-subclass <top> '<arbiter>))
  1507. (define <promise> (find-subclass <top> '<promise>))
  1508. (define <thread> (find-subclass <top> '<thread>))
  1509. (define <mutex> (find-subclass <top> '<mutex>))
  1510. (define <condition-variable> (find-subclass <top> '<condition-variable>))
  1511. (define <regexp> (find-subclass <top> '<regexp>))
  1512. (define <hook> (find-subclass <top> '<hook>))
  1513. (define <bitvector> (find-subclass <top> '<bitvector>))
  1514. (define <random-state> (find-subclass <top> '<random-state>))
  1515. (define <async> (find-subclass <top> '<async>))
  1516. (define <directory> (find-subclass <top> '<directory>))
  1517. (define <keyword> (find-subclass <top> '<keyword>))
  1518. (define <array> (find-subclass <top> '<array>))
  1519. (define <character-set> (find-subclass <top> '<character-set>))
  1520. (define <dynamic-object> (find-subclass <top> '<dynamic-object>))
  1521. (define <guardian> (find-subclass <applicable> '<guardian>))
  1522. (define <macro> (find-subclass <top> '<macro>))
  1523. (define (define-class-subtree class)
  1524. (define! (class-name class) class)
  1525. (for-each define-class-subtree (class-direct-subclasses class)))
  1526. (define-class-subtree (find-subclass <port> '<file-port>))