goops.scm 52 KB

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