goops.scm 57 KB

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