goops.scm 56 KB

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