goops.scm 52 KB

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