goops.scm 136 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552
  1. ;;;; goops.scm -- The Guile Object-Oriented Programming System
  2. ;;;;
  3. ;;;; Copyright (C) 1998-2003,2006,2009-2011,2013-2015,2017-2018,2021
  4. ;;;; Free Software Foundation, Inc.
  5. ;;;; Copyright (C) 1993-1998 Erick Gallesio - I3S-CNRS/ESSI <eg@unice.fr>
  6. ;;;;
  7. ;;;; This library is free software; you can redistribute it and/or
  8. ;;;; modify it under the terms of the GNU Lesser General Public
  9. ;;;; License as published by the Free Software Foundation; either
  10. ;;;; version 3 of the License, or (at your option) any later version.
  11. ;;;;
  12. ;;;; This library is distributed in the hope that it will be useful,
  13. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. ;;;; Lesser General Public License for more details.
  16. ;;;;
  17. ;;;; You should have received a copy of the GNU Lesser General Public
  18. ;;;; License along with this library; if not, write to the Free Software
  19. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. ;;;;
  21. ;;;;
  22. ;;;; This file was based upon stklos.stk from the STk distribution
  23. ;;;; version 4.0.1 by Erick Gallesio <eg@unice.fr>.
  24. ;;;;
  25. (define-module (oop goops)
  26. #:use-module (srfi srfi-1)
  27. #:use-module (ice-9 match)
  28. #:use-module ((ice-9 control) #:select (let/ec))
  29. #:use-module (ice-9 threads)
  30. #:use-module ((language tree-il primitives)
  31. :select (add-interesting-primitive!))
  32. #:export-syntax (define-class class standard-define-class
  33. define-generic define-accessor
  34. define-method define-method*
  35. define-extended-generic define-extended-generics
  36. method method*)
  37. #:export ( ;; The root of everything.
  38. <top>
  39. <class> <object>
  40. ;; Slot types.
  41. <slot>
  42. <foreign-slot> <protected-slot> <hidden-slot> <opaque-slot>
  43. <read-only-slot> <protected-opaque-slot>
  44. <protected-hidden-slot> <protected-read-only-slot>
  45. <scm-slot>
  46. ;; Redefinable classes.
  47. <redefinable-class>
  48. ;; Methods are implementations of generic functions.
  49. <method> <accessor-method>
  50. ;; Applicable objects, either procedures or applicable structs.
  51. <procedure-class> <applicable>
  52. <procedure> <primitive-generic>
  53. ;; Applicable structs.
  54. <applicable-struct-class> <applicable-struct-with-setter-class>
  55. <applicable-struct> <applicable-struct-with-setter>
  56. <generic> <extended-generic>
  57. <generic-with-setter> <extended-generic-with-setter>
  58. <accessor> <extended-accessor>
  59. ;; Types with their own allocated typecodes.
  60. <boolean> <char> <list> <pair> <null> <string> <symbol>
  61. <vector> <bytevector> <uvec> <foreign> <hashtable>
  62. <fluid> <dynamic-state> <frame> <vm> <vm-continuation>
  63. <keyword> <syntax> <atomic-box>
  64. ;; Numbers.
  65. <number> <complex> <real> <integer> <fraction>
  66. ;; Unknown.
  67. <unknown>
  68. ;; Particular SMOB data types. All SMOB types have
  69. ;; corresponding classes, which may be obtained via class-of,
  70. ;; once you have an instance. Perhaps FIXME to provide a
  71. ;; smob-type-name->class procedure.
  72. <promise> <thread> <mutex> <condition-variable>
  73. <regexp> <hook> <bitvector> <random-state>
  74. <directory> <array> <character-set>
  75. <dynamic-object> <guardian> <macro>
  76. ;; Modules.
  77. <module>
  78. ;; Ports.
  79. <port> <input-port> <output-port> <input-output-port>
  80. ;; Like SMOB types, all port types have their own classes,
  81. ;; which can be accessed via `class-of' once you have an
  82. ;; instance. Here we export bindings just for file ports.
  83. <file-port>
  84. <file-input-port> <file-output-port> <file-input-output-port>
  85. is-a? class-of
  86. ensure-metaclass ensure-metaclass-with-supers
  87. make-class
  88. make-generic ensure-generic
  89. make-extended-generic
  90. make-accessor ensure-accessor
  91. add-method!
  92. class-slot-ref class-slot-set! slot-unbound slot-missing
  93. slot-definition-name slot-definition-options
  94. slot-definition-allocation
  95. slot-definition-getter slot-definition-setter
  96. slot-definition-accessor
  97. slot-definition-init-value slot-definition-init-form
  98. slot-definition-init-thunk slot-definition-init-keyword
  99. slot-init-function class-slot-definition
  100. method-source
  101. compute-cpl compute-std-cpl compute-get-n-set compute-slots
  102. compute-getter-method compute-setter-method
  103. allocate-instance initialize make-instance make
  104. no-next-method no-applicable-method no-method
  105. change-class update-instance-for-different-class
  106. shallow-clone deep-clone
  107. class-redefinition
  108. apply-generic apply-method apply-methods
  109. compute-applicable-methods %compute-applicable-methods
  110. method-more-specific? sort-applicable-methods
  111. class-subclasses class-methods
  112. goops-error
  113. min-fixnum max-fixnum
  114. instance?
  115. slot-ref slot-set! slot-bound? slot-exists?
  116. class-name class-direct-supers class-direct-subclasses
  117. class-direct-methods class-direct-slots class-precedence-list
  118. class-slots
  119. generic-function-name
  120. generic-function-methods method-generic-function
  121. method-specializers method-formals
  122. primitive-generic-generic enable-primitive-generic!
  123. method-procedure accessor-method-slot-definition
  124. make find-method get-keyword))
  125. ;;;
  126. ;;; Booting GOOPS is a tortuous process. We begin by loading a small
  127. ;;; set of primitives from C.
  128. ;;;
  129. (eval-when (expand load eval)
  130. (load-extension (string-append "libguile-" (effective-version))
  131. "scm_init_goops_builtins")
  132. (add-interesting-primitive! 'class-of))
  133. ;;;
  134. ;;; We then define the slots that must appear in all classes (<class>
  135. ;;; objects) and slot definitions (<slot> objects). These slots must
  136. ;;; appear in order. We'll use this list to statically compute offsets
  137. ;;; for the various fields, to compute the struct layout for <class>
  138. ;;; instances, and to compute the slot definition lists for <class>.
  139. ;;; Because the list is needed at expansion-time, we define it as a
  140. ;;; macro.
  141. ;;;
  142. (define-syntax macro-fold-left
  143. (syntax-rules ()
  144. ((_ folder seed ()) seed)
  145. ((_ folder seed (head . tail))
  146. (macro-fold-left folder (folder head seed) tail))))
  147. (define-syntax macro-fold-right
  148. (syntax-rules ()
  149. ((_ folder seed ()) seed)
  150. ((_ folder seed (head . tail))
  151. (folder head (macro-fold-right folder seed tail)))))
  152. (define-syntax-rule (define-macro-folder macro-folder value ...)
  153. (define-syntax macro-folder
  154. (lambda (x)
  155. (syntax-case x ()
  156. ((_ fold visit seed)
  157. ;; The datum->syntax makes it as if each `value' were present
  158. ;; in the initial form, which allows them to be used as
  159. ;; (components of) introduced identifiers.
  160. #`(fold visit seed #,(datum->syntax #'visit '(value ...))))))))
  161. (define-macro-folder fold-class-slots
  162. (layout #:class <protected-read-only-slot>)
  163. (flags #:class <hidden-slot>)
  164. (instance-finalizer #:class <hidden-slot>)
  165. (print)
  166. (name #:class <protected-hidden-slot>)
  167. (nfields #:class <hidden-slot>)
  168. (%reserved-6 #:class <hidden-slot>)
  169. (%reserved-7 #:class <hidden-slot>)
  170. (direct-supers)
  171. (direct-slots)
  172. (direct-subclasses)
  173. (direct-methods)
  174. (cpl)
  175. (slots))
  176. (define-macro-folder fold-slot-slots
  177. (name #:init-keyword #:name)
  178. (allocation #:init-keyword #:allocation #:init-value #:instance)
  179. (init-keyword #:init-keyword #:init-keyword #:init-value #f)
  180. (init-form #:init-keyword #:init-form)
  181. (init-value #:init-keyword #:init-value)
  182. (init-thunk #:init-keyword #:init-thunk #:init-value #f)
  183. (options)
  184. (getter #:init-keyword #:getter #:init-value #f)
  185. (setter #:init-keyword #:setter #:init-value #f)
  186. (accessor #:init-keyword #:accessor #:init-value #f)
  187. ;; These last don't have #:init-keyword because they are meant to be
  188. ;; set by `allocate-slots', not in compute-effective-slot-definition.
  189. (slot-ref/raw #:init-value #f)
  190. (slot-ref #:init-value #f)
  191. (slot-set! #:init-value #f)
  192. (index #:init-value #f)
  193. (size #:init-value #f))
  194. ;;;
  195. ;;; Statically define variables for slot offsets: `class-index-layout'
  196. ;;; will be 0, `class-index-flags' will be 1, and so on, and the same
  197. ;;; for `slot-index-name' and such for <slot>.
  198. ;;;
  199. (let-syntax ((define-slot-indexer
  200. (syntax-rules ()
  201. ((_ define-index prefix)
  202. (define-syntax define-index
  203. (lambda (x)
  204. (define (id-append ctx a b)
  205. (datum->syntax ctx (symbol-append (syntax->datum a)
  206. (syntax->datum b))))
  207. (define (tail-length tail)
  208. (syntax-case tail ()
  209. ((begin) 0)
  210. ((visit head tail) (1+ (tail-length #'tail)))))
  211. (syntax-case x ()
  212. ((_ (name . _) tail)
  213. #`(begin
  214. (define-syntax #,(id-append #'name #'prefix #'name)
  215. (identifier-syntax #,(tail-length #'tail)))
  216. tail)))))))))
  217. (define-slot-indexer define-class-index class-index-)
  218. (define-slot-indexer define-slot-index slot-index-)
  219. (fold-class-slots macro-fold-left define-class-index (begin))
  220. (fold-slot-slots macro-fold-left define-slot-index (begin)))
  221. ;;;
  222. ;;; Structs that are vtables have a "flags" slot, which corresponds to
  223. ;;; class-index-flags. `vtable-flag-vtable' indicates that instances of
  224. ;;; a vtable are themselves vtables, and `vtable-flag-validated'
  225. ;;; indicates that the struct's layout has been validated. goops.c
  226. ;;; defines a few additional flags: one to indicate that a vtable is
  227. ;;; actually a class, one to indicate that instances of a class are slot
  228. ;;; definition objects (<slot> instances), one to indicate that this
  229. ;;; class has "static slot allocation" (meaning that its slots must
  230. ;;; always be allocated to the same indices in all subclasses), and two
  231. ;;; more flags used for redefinable classes (more below).
  232. ;;;
  233. (define vtable-flag-goops-metaclass
  234. (logior vtable-flag-vtable vtable-flag-goops-class))
  235. (define-inlinable (class-add-flags! class flags)
  236. (struct-set!/unboxed
  237. class
  238. class-index-flags
  239. (logior flags (struct-ref/unboxed class class-index-flags))))
  240. (define-inlinable (class-clear-flags! class flags)
  241. (struct-set!/unboxed
  242. class
  243. class-index-flags
  244. (logand (lognot flags) (struct-ref/unboxed class class-index-flags))))
  245. (define-inlinable (class-has-flags? class flags)
  246. (eqv? flags
  247. (logand (struct-ref/unboxed class class-index-flags) flags)))
  248. (define-inlinable (class? obj)
  249. (class-has-flags? (struct-vtable obj) vtable-flag-goops-metaclass))
  250. (define-inlinable (slot? obj)
  251. (and (struct? obj)
  252. (class-has-flags? (struct-vtable obj) vtable-flag-goops-slot)))
  253. (define-inlinable (instance? obj)
  254. (and (struct? obj)
  255. (class-has-flags? (struct-vtable obj) vtable-flag-goops-class)))
  256. (define (class-has-statically-allocated-slots? class)
  257. (class-has-flags? class vtable-flag-goops-static-slot-allocation))
  258. (define (class-has-indirect-instances? class)
  259. (class-has-flags? class vtable-flag-goops-indirect))
  260. (define (indirect-slots-need-migration? slots)
  261. (class-has-flags? (struct-vtable slots) vtable-flag-goops-needs-migration))
  262. ;;;
  263. ;;; Now that we know the slots that must be present in classes, and
  264. ;;; their offsets, we can create the root of the class hierarchy.
  265. ;;;
  266. ;;; Note that the `direct-supers', `direct-slots', `cpl', and `slots'
  267. ;;; fields will be updated later, once we can create slot definition
  268. ;;; objects and once we have definitions for <top> and <object>.
  269. ;;;
  270. (define <class>
  271. (let-syntax ((cons-layout
  272. ;; A simple way to compute class layout for the concrete
  273. ;; types used in <class>.
  274. (syntax-rules (<protected-read-only-slot>
  275. <hidden-slot>
  276. <protected-hidden-slot>)
  277. ((_ (name) tail)
  278. (string-append "pw" tail))
  279. ((_ (name #:class <protected-read-only-slot>) tail)
  280. (string-append "pw" tail))
  281. ((_ (name #:class <hidden-slot>) tail)
  282. (string-append "uh" tail))
  283. ((_ (name #:class <protected-hidden-slot>) tail)
  284. (string-append "ph" tail)))))
  285. (let* ((layout (fold-class-slots macro-fold-right cons-layout ""))
  286. (nfields (/ (string-length layout) 2))
  287. (<class> (%make-vtable-vtable layout)))
  288. (class-add-flags! <class> vtable-flag-goops-class)
  289. (struct-set! <class> class-index-name '<class>)
  290. (struct-set!/unboxed <class> class-index-nfields nfields)
  291. (struct-set! <class> class-index-direct-supers '())
  292. (struct-set! <class> class-index-direct-slots '())
  293. (struct-set! <class> class-index-direct-subclasses '())
  294. (struct-set! <class> class-index-direct-methods '())
  295. (struct-set! <class> class-index-cpl '())
  296. (struct-set! <class> class-index-slots '())
  297. <class>)))
  298. ;;;
  299. ;;; Accessors to fields of <class>.
  300. ;;;
  301. (define-syntax-rule (define-class-accessor name docstring field)
  302. (define (name obj)
  303. docstring
  304. (let ((val obj))
  305. (unless (class? val)
  306. (scm-error 'wrong-type-arg #f "Not a class: ~S"
  307. (list val) #f))
  308. (struct-ref val field))))
  309. (define-class-accessor class-name
  310. "Return the class name of @var{obj}."
  311. class-index-name)
  312. (define-class-accessor class-direct-supers
  313. "Return the direct superclasses of the class @var{obj}."
  314. class-index-direct-supers)
  315. (define-class-accessor class-direct-slots
  316. "Return the direct slots of the class @var{obj}."
  317. class-index-direct-slots)
  318. (define-class-accessor class-direct-subclasses
  319. "Return the direct subclasses of the class @var{obj}."
  320. class-index-direct-subclasses)
  321. (define-class-accessor class-direct-methods
  322. "Return the direct methods of the class @var{obj}."
  323. class-index-direct-methods)
  324. (define-class-accessor class-precedence-list
  325. "Return the class precedence list of the class @var{obj}."
  326. class-index-cpl)
  327. (define-class-accessor class-slots
  328. "Return the slot list of the class @var{obj}."
  329. class-index-slots)
  330. (define (class-subclasses c)
  331. "Compute a list of all subclasses of @var{c}, direct and indirect."
  332. (define (all-subclasses c)
  333. (cons c (append-map all-subclasses
  334. (class-direct-subclasses c))))
  335. (delete-duplicates (cdr (all-subclasses c)) eq?))
  336. (define (class-methods c)
  337. "Compute a list of all methods that specialize on @var{c} or
  338. subclasses of @var{c}."
  339. (delete-duplicates (append-map class-direct-methods
  340. (cons c (class-subclasses c)))
  341. eq?))
  342. (define (is-a? obj class)
  343. "Return @code{#t} if @var{obj} is an instance of @var{class}, or
  344. @code{#f} otherwise."
  345. (and (memq class (class-precedence-list (class-of obj))) #t))
  346. ;;;
  347. ;;; At this point, <class> is missing slot definitions, but we can't
  348. ;;; create slot definitions until we have a slot definition class.
  349. ;;; Continue with manual object creation until we're able to bootstrap
  350. ;;; more of the protocol. Again, the CPL and class hierarchy slots
  351. ;;; remain uninitialized.
  352. ;;;
  353. (define* (get-keyword key l #:optional default)
  354. "Determine an associated value for the keyword @var{key} from the list
  355. @var{l}. The list @var{l} has to consist of an even number of elements,
  356. where, starting with the first, every second element is a keyword,
  357. followed by its associated value. If @var{l} does not hold a value for
  358. @var{key}, the value @var{default} is returned."
  359. (unless (keyword? key)
  360. (scm-error 'wrong-type-arg #f "Not a keyword: ~S" (list key) #f))
  361. (let lp ((l l))
  362. (match l
  363. (() default)
  364. ((kw arg . l)
  365. (unless (keyword? kw)
  366. (scm-error 'wrong-type-arg #f "Not a keyword: ~S" (list kw) #f))
  367. (if (eq? kw key) arg (lp l))))))
  368. (define *unbound* (list 'unbound))
  369. (define-inlinable (unbound? x)
  370. (eq? x *unbound*))
  371. (define (%allocate-instance class)
  372. (let ((obj (allocate-struct class
  373. (struct-ref/unboxed class class-index-nfields))))
  374. (%clear-fields! obj *unbound*)
  375. obj))
  376. (define <slot>
  377. (let-syntax ((cons-layout
  378. ;; All slots are "pw" in <slot>.
  379. (syntax-rules ()
  380. ((_ _ tail) (string-append "pw" tail)))))
  381. (let* ((layout (fold-slot-slots macro-fold-right cons-layout ""))
  382. (nfields (/ (string-length layout) 2))
  383. (<slot> (make-struct/no-tail <class> (make-struct-layout layout))))
  384. (class-add-flags! <slot> (logior vtable-flag-goops-class
  385. vtable-flag-goops-slot))
  386. (struct-set! <slot> class-index-name '<slot>)
  387. (struct-set!/unboxed <slot> class-index-nfields nfields)
  388. (struct-set! <slot> class-index-direct-supers '())
  389. (struct-set! <slot> class-index-direct-slots '())
  390. (struct-set! <slot> class-index-direct-subclasses '())
  391. (struct-set! <slot> class-index-direct-methods '())
  392. (struct-set! <slot> class-index-cpl (list <slot>))
  393. (struct-set! <slot> class-index-slots '())
  394. <slot>)))
  395. ;;; Access to slot objects is performance-sensitive for slot-ref, so in
  396. ;;; addition to the type-checking accessors that we export, we also
  397. ;;; define some internal inlined helpers that just do an unchecked
  398. ;;; struct-ref in cases where we know the object must be a slot, as
  399. ;;; when accessing class-slots.
  400. ;;;
  401. (define-syntax-rule (define-slot-accessor name docstring %name field)
  402. (begin
  403. (define-syntax-rule (%name obj)
  404. (struct-ref obj field))
  405. (define (name obj)
  406. docstring
  407. (unless (slot? obj)
  408. (scm-error 'wrong-type-arg #f "Not a slot: ~S"
  409. (list obj) #f))
  410. (%name obj))))
  411. (define-slot-accessor slot-definition-name
  412. "Return the name of @var{obj}."
  413. %slot-definition-name slot-index-name)
  414. (define-slot-accessor slot-definition-allocation
  415. "Return the allocation of the slot @var{obj}."
  416. %slot-definition-allocation slot-index-allocation)
  417. (define-slot-accessor slot-definition-init-keyword
  418. "Return the init keyword of the slot @var{obj}, or @code{#f}."
  419. %slot-definition-init-keyword slot-index-init-keyword)
  420. (define-slot-accessor slot-definition-init-form
  421. "Return the init form of the slot @var{obj}, or the unbound value"
  422. %slot-definition-init-form slot-index-init-form)
  423. (define-slot-accessor slot-definition-init-value
  424. "Return the init value of the slot @var{obj}, or the unbound value."
  425. %slot-definition-init-value slot-index-init-value)
  426. (define-slot-accessor slot-definition-init-thunk
  427. "Return the init thunk of the slot @var{obj}, or @code{#f}."
  428. %slot-definition-init-thunk slot-index-init-thunk)
  429. (define-slot-accessor slot-definition-options
  430. "Return the initargs given when creating the slot @var{obj}."
  431. %slot-definition-options slot-index-options)
  432. (define-slot-accessor slot-definition-getter
  433. "Return the getter of the slot @var{obj}, or @code{#f}."
  434. %slot-definition-getter slot-index-getter)
  435. (define-slot-accessor slot-definition-setter
  436. "Return the setter of the slot @var{obj}, or @code{#f}."
  437. %slot-definition-setter slot-index-setter)
  438. (define-slot-accessor slot-definition-accessor
  439. "Return the accessor of the slot @var{obj}, or @code{#f}."
  440. %slot-definition-accessor slot-index-accessor)
  441. (define-slot-accessor slot-definition-slot-ref/raw
  442. "Return the raw slot-ref procedure of the slot @var{obj}."
  443. %slot-definition-slot-ref/raw slot-index-slot-ref/raw)
  444. (define-slot-accessor slot-definition-slot-ref
  445. "Return the slot-ref procedure of the slot @var{obj}."
  446. %slot-definition-slot-ref slot-index-slot-ref)
  447. (define-slot-accessor slot-definition-slot-set!
  448. "Return the slot-set! procedure of the slot @var{obj}."
  449. %slot-definition-slot-set! slot-index-slot-set!)
  450. (define-slot-accessor slot-definition-index
  451. "Return the allocated struct offset of the slot @var{obj}, or @code{#f}."
  452. %slot-definition-index slot-index-index)
  453. (define-slot-accessor slot-definition-size
  454. "Return the number fields used by the slot @var{obj}, or @code{#f}."
  455. %slot-definition-size slot-index-size)
  456. ;; Boot definition.
  457. (define (direct-slot-definition-class class initargs)
  458. (get-keyword #:class initargs <slot>))
  459. ;; Boot definition.
  460. (define (make-slot class initargs)
  461. (let ((slot (make-struct/no-tail class)))
  462. (define-syntax-rule (init-slot offset kw default)
  463. (struct-set! slot offset (get-keyword kw initargs default)))
  464. (init-slot slot-index-name #:name #f)
  465. (init-slot slot-index-allocation #:allocation #:instance)
  466. (init-slot slot-index-init-keyword #:init-keyword #f)
  467. (init-slot slot-index-init-form #:init-form *unbound*)
  468. (init-slot slot-index-init-value #:init-value *unbound*)
  469. (struct-set! slot slot-index-init-thunk
  470. (or (get-keyword #:init-thunk initargs #f)
  471. (let ((val (%slot-definition-init-value slot)))
  472. (if (unbound? val)
  473. #f
  474. (lambda () val)))))
  475. (struct-set! slot slot-index-options initargs)
  476. (init-slot slot-index-getter #:getter #f)
  477. (init-slot slot-index-setter #:setter #f)
  478. (init-slot slot-index-accessor #:accessor #f)
  479. (struct-set! slot slot-index-slot-ref/raw #f)
  480. (struct-set! slot slot-index-slot-ref #f)
  481. (struct-set! slot slot-index-slot-set! #f)
  482. (struct-set! slot slot-index-index #f)
  483. (struct-set! slot slot-index-size #f)
  484. slot))
  485. ;; Boot definition.
  486. (define (make class . args)
  487. (unless (memq <slot> (class-precedence-list class))
  488. (error (format #f "Unsupported class: ~S" class)))
  489. (make-slot class args))
  490. ;; Boot definition.
  491. (define (compute-direct-slot-definition class initargs)
  492. (apply make (direct-slot-definition-class class initargs) initargs))
  493. (define (compute-direct-slot-definition-initargs class slot-spec)
  494. (match slot-spec
  495. ((? symbol? name) (list #:name name))
  496. (((? symbol? name) . initargs)
  497. (cons* #:name name
  498. ;; If there is an #:init-form, the `class' macro will have
  499. ;; already added an #:init-thunk. Still, if there isn't an
  500. ;; #:init-thunk already but we do have an #:init-value,
  501. ;; synthesize an #:init-thunk initarg. This will ensure
  502. ;; that the #:init-thunk gets passed on to the effective
  503. ;; slot definition too.
  504. (if (get-keyword #:init-thunk initargs)
  505. initargs
  506. (let ((value (get-keyword #:init-value initargs *unbound*)))
  507. (if (unbound? value)
  508. initargs
  509. (cons* #:init-thunk (lambda () value) initargs))))))))
  510. (let ()
  511. (define-syntax cons-slot
  512. (syntax-rules ()
  513. ((_ (name #:class class) tail)
  514. ;; Special case to avoid referencing specialized <slot> kinds,
  515. ;; which are not defined yet.
  516. (cons (list 'name) tail))
  517. ((_ (name . initargs) tail)
  518. (cons (list 'name . initargs) tail))))
  519. (define-syntax-rule (initialize-direct-slots! class fold-slots)
  520. (let ((specs (fold-slots macro-fold-right cons-slot '())))
  521. (define (make-direct-slot-definition spec)
  522. (let ((initargs (compute-direct-slot-definition-initargs class spec)))
  523. (compute-direct-slot-definition class initargs)))
  524. (struct-set! class class-index-direct-slots
  525. (map make-direct-slot-definition specs))))
  526. (initialize-direct-slots! <class> fold-class-slots)
  527. (initialize-direct-slots! <slot> fold-slot-slots))
  528. ;;;
  529. ;;; OK, at this point we have initialized `direct-slots' on both <class>
  530. ;;; and <slot>. We need to define a standard way to make subclasses:
  531. ;;; how to compute the precedence list of subclasses, how to compute the
  532. ;;; list of slots in a subclass, and what layout to use for instances of
  533. ;;; those classes.
  534. ;;;
  535. (define (compute-std-cpl c get-direct-supers)
  536. "The standard class precedence list computation algorithm."
  537. (define (only-non-null lst)
  538. (filter (lambda (l) (not (null? l))) lst))
  539. (define (merge-lists reversed-partial-result inputs)
  540. (cond
  541. ((every null? inputs)
  542. (reverse! reversed-partial-result))
  543. (else
  544. (let* ((candidate (lambda (c)
  545. (and (not (any (lambda (l)
  546. (memq c (cdr l)))
  547. inputs))
  548. c)))
  549. (candidate-car (lambda (l)
  550. (and (not (null? l))
  551. (candidate (car l)))))
  552. (next (any candidate-car inputs)))
  553. (unless next
  554. (goops-error "merge-lists: Inconsistent precedence graph"))
  555. (let ((remove-next (lambda (l)
  556. (if (eq? (car l) next)
  557. (cdr l)
  558. l))))
  559. (merge-lists (cons next reversed-partial-result)
  560. (only-non-null (map remove-next inputs))))))))
  561. (let ((c-direct-supers (get-direct-supers c)))
  562. (merge-lists (list c)
  563. (only-non-null (append (map class-precedence-list
  564. c-direct-supers)
  565. (list c-direct-supers))))))
  566. ;; This version of compute-cpl is replaced with a generic function once
  567. ;; GOOPS has booted.
  568. (define (compute-cpl class)
  569. (compute-std-cpl class class-direct-supers))
  570. (define (effective-slot-definition-class class slot)
  571. (class-of slot))
  572. (define (compute-effective-slot-definition class slot)
  573. ;; FIXME: Support slot being a list of slots, as in CLOS.
  574. (apply make
  575. (effective-slot-definition-class class slot)
  576. (slot-definition-options slot)))
  577. (define (build-slots-list dslots cpl)
  578. (define (slot-memq slot slots)
  579. (let ((name (%slot-definition-name slot)))
  580. (let lp ((slots slots))
  581. (match slots
  582. (() #f)
  583. ((slot . slots)
  584. (or (eq? (%slot-definition-name slot) name) (lp slots)))))))
  585. (define (check-cpl slots static-slots)
  586. (match static-slots
  587. (() #t)
  588. ((static-slot . static-slots)
  589. (when (slot-memq static-slot slots)
  590. (scm-error 'misc-error #f
  591. "statically allocated inherited field cannot be redefined: ~a"
  592. (list (%slot-definition-name static-slot)) '()))
  593. (check-cpl slots static-slots))))
  594. (define (remove-duplicate-slots slots)
  595. (let lp ((slots (reverse slots)) (res '()) (seen '()))
  596. (match slots
  597. (() res)
  598. ((slot . slots)
  599. (let ((name (%slot-definition-name slot)))
  600. (if (memq name seen)
  601. (lp slots res seen)
  602. (lp slots (cons slot res) (cons name seen))))))))
  603. ;; For subclases of <class> and <slot>, we need to ensure that the
  604. ;; <class> or <slot> slots come first.
  605. (let ((static-slots
  606. (match (filter class-has-statically-allocated-slots? (cdr cpl))
  607. (() #f)
  608. ((class) (struct-ref class class-index-direct-slots))
  609. (classes
  610. (error "can't subtype multiple classes with static slot allocation"
  611. classes)))))
  612. (when static-slots
  613. (check-cpl dslots static-slots))
  614. (let lp ((cpl (cdr cpl)) (res dslots) (static-slots '()))
  615. (match cpl
  616. (() (remove-duplicate-slots (append static-slots res)))
  617. ((head . cpl)
  618. (let ((new-slots (struct-ref head class-index-direct-slots)))
  619. (cond
  620. ((not static-slots)
  621. (lp cpl (append new-slots res) static-slots))
  622. ((class-has-statically-allocated-slots? head)
  623. ;; Move static slots to the head of the list.
  624. (lp cpl res new-slots))
  625. (else
  626. (check-cpl new-slots static-slots)
  627. (lp cpl (append new-slots res) static-slots)))))))))
  628. ;; Boot definition.
  629. (define (compute-get-n-set class slot)
  630. (let ((index (struct-ref/unboxed class class-index-nfields)))
  631. (struct-set!/unboxed class class-index-nfields (1+ index))
  632. index))
  633. ;;; Pre-generate getters and setters for the first 20 slots.
  634. (define-syntax define-standard-accessor-method
  635. (lambda (stx)
  636. (define num-standard-pre-cache 20)
  637. (syntax-case stx ()
  638. ((_ ((proc n) arg ...) body)
  639. #`(define proc
  640. (let ((cache (vector #,@(map (lambda (n*)
  641. #`(lambda (arg ...)
  642. (let ((n #,n*))
  643. body)))
  644. (iota num-standard-pre-cache)))))
  645. (lambda (n)
  646. (if (< n #,num-standard-pre-cache)
  647. (vector-ref cache n)
  648. (lambda (arg ...) body)))))))))
  649. (define-standard-accessor-method ((bound-check-get n) o)
  650. (let ((x (struct-ref o n)))
  651. (if (unbound? x)
  652. (slot-unbound o)
  653. x)))
  654. (define-standard-accessor-method ((standard-get n) o)
  655. (struct-ref o n))
  656. (define-standard-accessor-method ((standard-set n) o v)
  657. (struct-set! o n v))
  658. (define-standard-accessor-method ((unboxed-get n) o)
  659. (struct-ref/unboxed o n))
  660. (define-standard-accessor-method ((unboxed-set n) o v)
  661. (struct-set!/unboxed o n v))
  662. ;; Boot definitions.
  663. (define (opaque-slot? slot) #f)
  664. (define (read-only-slot? slot) #f)
  665. (define (unboxed-slot? slot)
  666. (memq (%slot-definition-name slot)
  667. '(flags instance-finalizer nfields %reserved-6 %reserved-7)))
  668. (define (allocate-slots class slots)
  669. "Transform the computed list of direct slot definitions @var{slots}
  670. into a corresponding list of effective slot definitions, allocating
  671. slots as we go."
  672. (define (make-effective-slot-definition slot)
  673. ;; `compute-get-n-set' is expected to mutate `nfields' if it
  674. ;; allocates a field to the object. Pretty strange, but we preserve
  675. ;; the behavior for backward compatibility.
  676. (let* ((slot (compute-effective-slot-definition class slot))
  677. (name (%slot-definition-name slot))
  678. (index (struct-ref/unboxed class class-index-nfields))
  679. (g-n-s (compute-get-n-set class slot))
  680. (size (- (struct-ref/unboxed class class-index-nfields) index)))
  681. (call-with-values
  682. (lambda ()
  683. (match g-n-s
  684. ((? integer?)
  685. (unless (= size 1)
  686. (error "unexpected return from compute-get-n-set"))
  687. (cond
  688. ((unboxed-slot? slot)
  689. (let ((get (unboxed-get g-n-s)))
  690. (values get get (unboxed-set g-n-s))))
  691. (else
  692. (values (standard-get g-n-s)
  693. (if (slot-definition-init-thunk slot)
  694. (standard-get g-n-s)
  695. (bound-check-get g-n-s))
  696. (standard-set g-n-s)))))
  697. (((? procedure? get) (? procedure? set))
  698. (values get
  699. (lambda (o)
  700. (let ((value (get o)))
  701. (if (unbound? value)
  702. (slot-unbound class o name)
  703. value)))
  704. set))))
  705. (lambda (get/raw get set)
  706. (let ((get (if (opaque-slot? slot)
  707. (lambda (o)
  708. (error "Slot is opaque" name))
  709. get))
  710. (set (cond
  711. ((opaque-slot? slot)
  712. (lambda (o v)
  713. (error "Slot is opaque" name)))
  714. ((read-only-slot? slot)
  715. (if (unboxed-slot? slot)
  716. (lambda (o v)
  717. (let ((v* (get/raw o)))
  718. (if (zero? v*)
  719. ;; Allow initialization.
  720. (set o v)
  721. (error "Slot is read-only" name))))
  722. (lambda (o v)
  723. (let ((v* (get/raw o)))
  724. (if (unbound? v*)
  725. ;; Allow initialization.
  726. (set o v)
  727. (error "Slot is read-only" name))))))
  728. (else set))))
  729. (struct-set! slot slot-index-slot-ref/raw get/raw)
  730. (struct-set! slot slot-index-slot-ref get)
  731. (struct-set! slot slot-index-slot-set! set)
  732. (struct-set! slot slot-index-index index)
  733. (struct-set! slot slot-index-size size))))
  734. slot))
  735. (struct-set!/unboxed class class-index-nfields 0)
  736. (map-in-order make-effective-slot-definition slots))
  737. (define (%compute-layout slots nfields is-class?)
  738. (define (slot-protection-and-kind slot)
  739. (define (subclass? class parent)
  740. (memq parent (class-precedence-list class)))
  741. (let ((type (get-keyword #:class (%slot-definition-options slot))))
  742. (if (and type (subclass? type <foreign-slot>))
  743. (values (cond
  744. ((subclass? type <protected-slot>) #\p)
  745. (else #\u))
  746. (cond
  747. ((subclass? type <hidden-slot>) #\h)
  748. (else #\w)))
  749. (values #\p #\w))))
  750. (let ((layout (make-string (* nfields 2))))
  751. (let lp ((n 0) (slots slots))
  752. (match slots
  753. (()
  754. (unless (= n nfields) (error "bad nfields"))
  755. (when is-class?
  756. (let ((class-layout (struct-ref <class> class-index-layout)))
  757. (unless (string-prefix? (symbol->string class-layout) layout)
  758. (error "bad layout for class"))))
  759. layout)
  760. ((slot . slots)
  761. (unless (= n (%slot-definition-index slot)) (error "bad allocation"))
  762. (call-with-values (lambda () (slot-protection-and-kind slot))
  763. (lambda (protection kind)
  764. (let init ((n n) (size (%slot-definition-size slot)))
  765. (cond
  766. ((zero? size) (lp n slots))
  767. (else
  768. (unless (< n nfields) (error "bad nfields"))
  769. (string-set! layout (* n 2) protection)
  770. (string-set! layout (1+ (* n 2)) kind)
  771. (init (1+ n) (1- size))))))))))))
  772. ;;;
  773. ;;; With all of this, we are now able to define subclasses of <class>.
  774. ;;;
  775. (define (%prep-layout! class)
  776. (let* ((is-class? (and (memq <class> (struct-ref class class-index-cpl)) #t))
  777. (layout (%compute-layout (struct-ref class class-index-slots)
  778. (struct-ref/unboxed class class-index-nfields)
  779. is-class?)))
  780. (%init-layout! class layout)))
  781. (define (make-standard-class class name dsupers dslots)
  782. (let ((z (make-struct/no-tail class)))
  783. (define (make-direct-slot-definition dslot)
  784. (let ((initargs (compute-direct-slot-definition-initargs z dslot)))
  785. (compute-direct-slot-definition z initargs)))
  786. (struct-set! z class-index-name name)
  787. (struct-set!/unboxed z class-index-nfields 0)
  788. (struct-set! z class-index-direct-supers dsupers)
  789. (struct-set! z class-index-direct-subclasses '())
  790. (struct-set! z class-index-direct-methods '())
  791. (let ((cpl (compute-cpl z)))
  792. (struct-set! z class-index-cpl cpl)
  793. (when (memq <slot> cpl)
  794. (class-add-flags! z vtable-flag-goops-slot))
  795. (let* ((dslots (map make-direct-slot-definition dslots))
  796. (slots (allocate-slots z (build-slots-list dslots cpl))))
  797. (struct-set! z class-index-direct-slots dslots)
  798. (struct-set! z class-index-slots slots)))
  799. (for-each
  800. (lambda (super)
  801. (let ((subclasses (struct-ref super class-index-direct-subclasses)))
  802. (struct-set! super class-index-direct-subclasses
  803. (cons z subclasses))))
  804. dsupers)
  805. (%prep-layout! z)
  806. z))
  807. (define-syntax define-standard-class
  808. (syntax-rules ()
  809. ((define-standard-class name (super ...) #:metaclass meta slot ...)
  810. (define name
  811. (make-standard-class meta 'name (list super ...) '(slot ...))))
  812. ((define-standard-class name (super ...) slot ...)
  813. (define-standard-class name (super ...) #:metaclass <class> slot ...))))
  814. ;;;
  815. ;;; Sweet! Now we can define <top> and <object>, and finish
  816. ;;; initializing the `direct-subclasses', `direct-supers', and `cpl'
  817. ;;; slots of <class>.
  818. ;;;
  819. (define-standard-class <top> ())
  820. (define-standard-class <object> (<top>))
  821. ;; The inheritance links for <top>, <object>, <class>, and <slot> were
  822. ;; partially initialized. Correct them here.
  823. (struct-set! <object> class-index-direct-subclasses (list <slot> <class>))
  824. (struct-set! <class> class-index-direct-supers (list <object>))
  825. (struct-set! <slot> class-index-direct-supers (list <object>))
  826. (struct-set! <class> class-index-cpl (list <class> <object> <top>))
  827. (struct-set! <slot> class-index-cpl (list <slot> <object> <top>))
  828. ;;;
  829. ;;; We can also define the various slot types, and finish initializing
  830. ;;; `direct-slots' and `slots' on <class> and <slot>.
  831. ;;;
  832. (define-standard-class <foreign-slot> (<slot>))
  833. (define-standard-class <protected-slot> (<foreign-slot>))
  834. (define-standard-class <hidden-slot> (<foreign-slot>))
  835. (define-standard-class <opaque-slot> (<foreign-slot>))
  836. (define-standard-class <read-only-slot> (<foreign-slot>))
  837. (define-standard-class <protected-opaque-slot> (<protected-slot>
  838. <opaque-slot>))
  839. (define-standard-class <protected-hidden-slot> (<protected-slot>
  840. <hidden-slot>))
  841. (define-standard-class <protected-read-only-slot> (<protected-slot>
  842. <read-only-slot>))
  843. (define-standard-class <scm-slot> (<protected-slot>))
  844. (define (opaque-slot? slot) (is-a? slot <opaque-slot>))
  845. (define (read-only-slot? slot) (is-a? slot <read-only-slot>))
  846. (define (unboxed-slot? slot)
  847. (and (is-a? slot <foreign-slot>)
  848. (not (is-a? slot <protected-slot>))))
  849. ;;;
  850. ;;; Finally! Initialize `direct-slots' and `slots' on <class>, and
  851. ;;; `slots' on <slot>.
  852. ;;;
  853. (let ()
  854. (define-syntax-rule (cons-slot (name . initargs) tail)
  855. (cons (list 'name . initargs) tail))
  856. (define-syntax-rule (initialize-direct-slots! class fold-slots)
  857. (let ((specs (fold-slots macro-fold-right cons-slot '())))
  858. (define (make-direct-slot-definition spec)
  859. (let ((initargs (compute-direct-slot-definition-initargs class spec)))
  860. (compute-direct-slot-definition class initargs)))
  861. (struct-set! class class-index-direct-slots
  862. (map make-direct-slot-definition specs))))
  863. ;; Boot definition that avoids munging nfields.
  864. (define (allocate-slots class slots)
  865. (define (make-effective-slot-definition slot index)
  866. (let* ((slot (compute-effective-slot-definition class slot))
  867. (get/raw (standard-get index))
  868. (set/raw (standard-set index)))
  869. (struct-set! slot slot-index-slot-ref/raw (standard-get index))
  870. (struct-set! slot slot-index-slot-ref
  871. (if (slot-definition-init-thunk slot)
  872. get/raw
  873. (bound-check-get index)))
  874. (struct-set! slot slot-index-slot-set!
  875. (if (read-only-slot? slot)
  876. (lambda (o v)
  877. (let ((v* (get/raw o)))
  878. (if (unbound? v*)
  879. ;; Allow initialization.
  880. (set/raw o v)
  881. (error "Slot is read-only" slot))))
  882. set/raw))
  883. (struct-set! slot slot-index-index index)
  884. (struct-set! slot slot-index-size 1)
  885. slot))
  886. (map make-effective-slot-definition slots (iota (length slots))))
  887. (define (initialize-slots! class)
  888. (let ((slots (build-slots-list (class-direct-slots class)
  889. (class-precedence-list class))))
  890. (struct-set! class class-index-slots (allocate-slots class slots))))
  891. ;; Finish initializing <class> with the specialized slot kinds.
  892. (initialize-direct-slots! <class> fold-class-slots)
  893. (initialize-slots! <class>)
  894. (initialize-slots! <slot>)
  895. ;; Now that we're all done with that, mark <class> and <slot> as
  896. ;; static.
  897. (class-add-flags! <class> vtable-flag-goops-static-slot-allocation)
  898. (class-add-flags! <slot> vtable-flag-goops-static-slot-allocation))
  899. ;;;
  900. ;;; Now, to build out the class hierarchy.
  901. ;;;
  902. (define-standard-class <procedure-class> (<class>))
  903. (define-standard-class <applicable-struct-class>
  904. (<procedure-class>))
  905. (class-add-flags! <applicable-struct-class>
  906. vtable-flag-applicable-vtable)
  907. (define-standard-class <applicable-struct-with-setter-class>
  908. (<applicable-struct-class>))
  909. (class-add-flags! <applicable-struct-with-setter-class>
  910. vtable-flag-setter-vtable)
  911. (define-standard-class <applicable> (<top>))
  912. (define-standard-class <applicable-struct> (<object> <applicable>)
  913. #:metaclass <applicable-struct-class>
  914. procedure)
  915. (define-standard-class <applicable-struct-with-setter> (<applicable-struct>)
  916. #:metaclass <applicable-struct-with-setter-class>
  917. setter)
  918. (define-standard-class <generic> (<applicable-struct>)
  919. #:metaclass <applicable-struct-class>
  920. methods
  921. (n-specialized #:init-value 0)
  922. (extended-by #:init-value ())
  923. effective-methods)
  924. (define-standard-class <extended-generic> (<generic>)
  925. #:metaclass <applicable-struct-class>
  926. (extends #:init-value ()))
  927. (define-standard-class <generic-with-setter> (<generic>
  928. <applicable-struct-with-setter>)
  929. #:metaclass <applicable-struct-with-setter-class>)
  930. (define-standard-class <accessor> (<generic-with-setter>)
  931. #:metaclass <applicable-struct-with-setter-class>)
  932. (define-standard-class <extended-generic-with-setter> (<extended-generic>
  933. <generic-with-setter>)
  934. #:metaclass <applicable-struct-with-setter-class>)
  935. (define-standard-class <extended-accessor> (<accessor>
  936. <extended-generic-with-setter>)
  937. #:metaclass <applicable-struct-with-setter-class>)
  938. (define-standard-class <method> (<object>)
  939. generic-function
  940. specializers
  941. procedure
  942. formals
  943. body
  944. make-procedure)
  945. (define-standard-class <accessor-method> (<method>)
  946. (slot-definition #:init-keyword #:slot-definition))
  947. (define-standard-class <boolean> (<top>))
  948. (define-standard-class <char> (<top>))
  949. (define-standard-class <list> (<top>))
  950. ;; Not all pairs are lists, but there is code out there that relies on
  951. ;; (is-a? '(1 2 3) <list>) to work. Terrible. How to fix?
  952. (define-standard-class <pair> (<list>))
  953. (define-standard-class <null> (<list>))
  954. (define-standard-class <string> (<top>))
  955. (define-standard-class <symbol> (<top>))
  956. (define-standard-class <vector> (<top>))
  957. (define-standard-class <foreign> (<top>))
  958. (define-standard-class <hashtable> (<top>))
  959. (define-standard-class <fluid> (<top>))
  960. (define-standard-class <dynamic-state> (<top>))
  961. (define-standard-class <frame> (<top>))
  962. (define-standard-class <vm-continuation> (<top>))
  963. (define-standard-class <bytevector> (<top>))
  964. (define-standard-class <uvec> (<bytevector>))
  965. (define-standard-class <array> (<top>))
  966. (define-standard-class <bitvector> (<top>))
  967. (define-standard-class <number> (<top>))
  968. (define-standard-class <complex> (<number>))
  969. (define-standard-class <real> (<complex>))
  970. (define-standard-class <integer> (<real>))
  971. (define-standard-class <fraction> (<real>))
  972. (define-standard-class <keyword> (<top>))
  973. (define-standard-class <syntax> (<top>))
  974. (define-standard-class <atomic-box> (<top>))
  975. (define-standard-class <unknown> (<top>))
  976. (define-standard-class <procedure> (<applicable>)
  977. #:metaclass <procedure-class>)
  978. (define-standard-class <primitive-generic> (<procedure>)
  979. #:metaclass <procedure-class>)
  980. (define-standard-class <port> (<top>))
  981. (define-standard-class <input-port> (<port>))
  982. (define-standard-class <output-port> (<port>))
  983. (define-standard-class <input-output-port> (<input-port> <output-port>))
  984. (define (inherit-applicable! class)
  985. "An internal routine to redefine a SMOB class that was added after
  986. GOOPS was loaded, and on which scm_set_smob_apply installed an apply
  987. function."
  988. (unless (memq <applicable> (class-precedence-list class))
  989. (unless (null? (class-slots class))
  990. (error "SMOB object has slots?"))
  991. (for-each
  992. (lambda (super)
  993. (let ((subclasses (struct-ref super class-index-direct-subclasses)))
  994. (struct-set! super class-index-direct-subclasses
  995. (delq class subclasses))))
  996. (struct-ref class class-index-direct-supers))
  997. (struct-set! class class-index-direct-supers (list <applicable>))
  998. (struct-set! class class-index-cpl (compute-cpl class))
  999. (let ((subclasses (struct-ref <applicable> class-index-direct-subclasses)))
  1000. (struct-set! <applicable> class-index-direct-subclasses
  1001. (cons class subclasses)))))
  1002. ;;;
  1003. ;;; At this point we have defined the class hierarchy, and it's time to
  1004. ;;; move on to instance allocation and generics. Once we have generics,
  1005. ;;; we'll fill out the metaobject protocol.
  1006. ;;;
  1007. ;;; Here we define a limited version of `make', so that we can allocate
  1008. ;;; instances of specific classes. This definition will be replaced
  1009. ;;; later.
  1010. ;;;
  1011. (define (%invalidate-method-cache! gf)
  1012. (slot-set! gf 'effective-methods '())
  1013. (recompute-generic-function-dispatch-procedure! gf))
  1014. ;; Boot definition.
  1015. (define (invalidate-method-cache! gf)
  1016. (%invalidate-method-cache! gf))
  1017. (define (make class . args)
  1018. (cond
  1019. ((or (eq? class <generic>) (eq? class <accessor>))
  1020. (let ((z (make-struct/no-tail class #f '() 0 '())))
  1021. (set-procedure-property! z 'name (get-keyword #:name args #f))
  1022. (invalidate-method-cache! z)
  1023. (when (eq? class <accessor>)
  1024. (let ((setter (get-keyword #:setter args #f)))
  1025. (when setter
  1026. (slot-set! z 'setter setter))))
  1027. z))
  1028. (else
  1029. (let ((z (%allocate-instance class)))
  1030. (cond
  1031. ((or (eq? class <method>) (eq? class <accessor-method>))
  1032. (for-each (match-lambda
  1033. ((kw slot default)
  1034. (slot-set! z slot (get-keyword kw args default))))
  1035. '((#:generic-function generic-function #f)
  1036. (#:specializers specializers ())
  1037. (#:procedure procedure #f)
  1038. (#:formals formals ())
  1039. (#:body body ())
  1040. (#:make-procedure make-procedure #f))))
  1041. ((memq <class> (class-precedence-list class))
  1042. (class-add-flags! z vtable-flag-goops-class)
  1043. (for-each (match-lambda
  1044. ((kw slot default)
  1045. (slot-set! z slot (get-keyword kw args default))))
  1046. '((#:name name ???)
  1047. (#:dsupers direct-supers ())
  1048. (#:slots direct-slots ()))))
  1049. (else
  1050. (error "boot `make' does not support this class" class)))
  1051. z))))
  1052. ;;;
  1053. ;;; Slot access.
  1054. ;;;
  1055. (define-inlinable (%class-slot-definition class slot-name kt kf)
  1056. (let lp ((slots (struct-ref class class-index-slots)))
  1057. (match slots
  1058. ((slot . slots)
  1059. (if (eq? (%slot-definition-name slot) slot-name)
  1060. (kt slot)
  1061. (lp slots)))
  1062. (_ (kf)))))
  1063. (define (class-slot-definition class slot-name)
  1064. (unless (class? class)
  1065. (scm-error 'wrong-type-arg #f "Not a class: ~S" (list class) #f))
  1066. (%class-slot-definition class slot-name
  1067. (lambda (slot) slot)
  1068. (lambda () #f)))
  1069. (define (slot-ref obj slot-name)
  1070. "Return the value from @var{obj}'s slot with the nam var{slot_name}."
  1071. (let ((class (class-of obj)))
  1072. (define (have-slot slot)
  1073. ((%slot-definition-slot-ref slot) obj))
  1074. (define (no-slot)
  1075. (unless (symbol? slot-name)
  1076. (scm-error 'wrong-type-arg #f "Not a symbol: ~S"
  1077. (list slot-name) #f))
  1078. (let ((val (slot-missing class obj slot-name)))
  1079. (if (unbound? val)
  1080. (slot-unbound class obj slot-name)
  1081. val)))
  1082. (%class-slot-definition class slot-name have-slot no-slot)))
  1083. (define (slot-set! obj slot-name value)
  1084. "Set the slot named @var{slot_name} of @var{obj} to @var{value}."
  1085. (let ((class (class-of obj)))
  1086. (define (have-slot slot)
  1087. ((%slot-definition-slot-set! slot) obj value))
  1088. (define (no-slot)
  1089. (unless (symbol? slot-name)
  1090. (scm-error 'wrong-type-arg #f "Not a symbol: ~S"
  1091. (list slot-name) #f))
  1092. (slot-missing class obj slot-name value))
  1093. (%class-slot-definition class slot-name have-slot no-slot)))
  1094. (define (slot-bound? obj slot-name)
  1095. "Return the value from @var{obj}'s slot with the nam var{slot_name}."
  1096. (let ((class (class-of obj)))
  1097. (define (have-slot slot)
  1098. (not (unbound? ((%slot-definition-slot-ref/raw slot) obj))))
  1099. (define (no-slot)
  1100. (unless (symbol? slot-name)
  1101. (scm-error 'wrong-type-arg #f "Not a symbol: ~S"
  1102. (list slot-name) #f))
  1103. (not (unbound? (slot-missing class obj slot-name))))
  1104. (%class-slot-definition class slot-name have-slot no-slot)))
  1105. (define (slot-exists? obj slot-name)
  1106. "Return @code{#t} if @var{obj} has a slot named @var{slot_name}."
  1107. (define (have-slot slot) #t)
  1108. (define (no-slot)
  1109. (unless (symbol? slot-name)
  1110. (scm-error 'wrong-type-arg #f "Not a symbol: ~S"
  1111. (list slot-name) #f))
  1112. #f)
  1113. (%class-slot-definition (class-of obj) slot-name have-slot no-slot))
  1114. ;;;
  1115. ;;; Method accessors.
  1116. ;;;
  1117. (define (method-generic-function obj)
  1118. "Return the generic function for the method @var{obj}."
  1119. (unless (is-a? obj <method>)
  1120. (scm-error 'wrong-type-arg #f "Not a method: ~S"
  1121. (list obj) #f))
  1122. (slot-ref obj 'generic-function))
  1123. (define (method-specializers obj)
  1124. "Return specializers of the method @var{obj}."
  1125. (unless (is-a? obj <method>)
  1126. (scm-error 'wrong-type-arg #f "Not a method: ~S"
  1127. (list obj) #f))
  1128. (slot-ref obj 'specializers))
  1129. (define (method-procedure obj)
  1130. "Return the procedure of the method @var{obj}."
  1131. (unless (is-a? obj <method>)
  1132. (scm-error 'wrong-type-arg #f "Not a method: ~S"
  1133. (list obj) #f))
  1134. (slot-ref obj 'procedure))
  1135. ;;;
  1136. ;;; Generic functions!
  1137. ;;;
  1138. ;;; Generic functions have an applicable-methods cache associated with
  1139. ;;; them. Every distinct set of types that is dispatched through a
  1140. ;;; generic adds an entry to the cache. A composite dispatch procedure
  1141. ;;; is recomputed every time an entry gets added to the cache, or when
  1142. ;;; the cache is invalidated.
  1143. ;;;
  1144. ;;; In steady-state, this dispatch procedure is never regenerated; but
  1145. ;;; during warm-up there is some churn.
  1146. ;;;
  1147. ;;; So what is the deal if warm-up happens in a multithreaded context?
  1148. ;;; There is indeed a window between missing the cache for a certain set
  1149. ;;; of arguments, and then updating the cache with the newly computed
  1150. ;;; applicable methods. One of the updaters is liable to lose their new
  1151. ;;; entry.
  1152. ;;;
  1153. ;;; This is actually OK though, because a subsequent cache miss for the
  1154. ;;; race loser will just cause memoization to try again. The cache will
  1155. ;;; eventually be consistent. We're not mutating the old part of the
  1156. ;;; cache, just consing on the new entry.
  1157. ;;;
  1158. ;;; It doesn't even matter if the dispatch procedure and the cache are
  1159. ;;; inconsistent -- most likely the type-set that lost the dispatch
  1160. ;;; procedure race will simply re-trigger a memoization, but since the
  1161. ;;; winner isn't in the effective-methods cache, it will likely also
  1162. ;;; re-trigger a memoization, and the cache will finally be consistent.
  1163. ;;; As you can see there is a possibility for ping-pong effects, but
  1164. ;;; it's unlikely given the shortness of the window between slot-set!
  1165. ;;; invocations.
  1166. ;;;
  1167. ;;; We probably do need to use atomic access primitives to correctly
  1168. ;;; handle concurrency, but that's a more general Guile concern.
  1169. ;;;
  1170. (define-syntax arity-case
  1171. (lambda (x)
  1172. (syntax-case x ()
  1173. ;; (arity-case n 2 foo bar)
  1174. ;; => (case n
  1175. ;; ((0) (foo))
  1176. ;; ((1) (foo a))
  1177. ;; ((2) (foo a b))
  1178. ;; (else bar))
  1179. ((arity-case n max form alternate)
  1180. (let ((max (syntax->datum #'max)))
  1181. #`(case n
  1182. #,@(let lp ((n 0))
  1183. (let ((ids (map (lambda (n)
  1184. (let* ((n (+ (char->integer #\a) n))
  1185. (c (integer->char n)))
  1186. (datum->syntax #'here (symbol c))))
  1187. (iota n))))
  1188. #`(((#,n) (form #,@ids))
  1189. . #,(if (< n max)
  1190. (lp (1+ n))
  1191. #'()))))
  1192. (else alternate)))))))
  1193. ;;;
  1194. ;;; These dispatchers are set as the "procedure" field of <generic>
  1195. ;;; instances. Unlike CLOS, in GOOPS a generic function can have
  1196. ;;; multiple arities.
  1197. ;;;
  1198. ;;; We pre-generate fast dispatchers for applications of up to 20
  1199. ;;; arguments. More arguments than that will go through slower generic
  1200. ;;; routines that cons arguments into a rest list.
  1201. ;;;
  1202. (define (multiple-arity-dispatcher fv miss)
  1203. (define-syntax dispatch
  1204. (lambda (x)
  1205. (define (build-clauses args)
  1206. (let ((len (length (syntax->datum args))))
  1207. #`((#,args ((vector-ref fv #,len) . #,args))
  1208. . #,(syntax-case args ()
  1209. (() #'())
  1210. ((arg ... _) (build-clauses #'(arg ...)))))))
  1211. (syntax-case x ()
  1212. ((dispatch arg ...)
  1213. #`(case-lambda
  1214. #,@(build-clauses #'(arg ...))
  1215. (args (apply miss args)))))))
  1216. (arity-case (1- (vector-length fv)) 20 dispatch
  1217. (lambda args
  1218. (let ((nargs (length args)))
  1219. (if (< nargs (vector-length fv))
  1220. (apply (vector-ref fv nargs) args)
  1221. (apply miss args))))))
  1222. ;;;
  1223. ;;; The above multiple-arity-dispatcher is entirely sufficient, and
  1224. ;;; should be fast enough. Still, for no good reason we also have an
  1225. ;;; arity dispatcher for generics that are only called with one arity.
  1226. ;;;
  1227. (define (single-arity-dispatcher f nargs miss)
  1228. (define-syntax-rule (dispatch arg ...)
  1229. (case-lambda
  1230. ((arg ...) (f arg ...))
  1231. (args (apply miss args))))
  1232. (arity-case nargs 20 dispatch
  1233. (lambda args
  1234. (if (eqv? (length args) nargs)
  1235. (apply f args)
  1236. (apply miss args)))))
  1237. ;;;
  1238. ;;; The guts of generic function dispatch are here. Once we've selected
  1239. ;;; an arity, we need to map from arguments to effective method. Until
  1240. ;;; we have `eqv?' specializers, this map is entirely a function of the
  1241. ;;; types (classes) of the arguments. So, we look in the cache to see
  1242. ;;; if we have seen this set of concrete types, and if so we apply the
  1243. ;;; previously computed effective method. Otherwise we miss the cache,
  1244. ;;; so we'll have to compute the right answer for this set of types, add
  1245. ;;; the mapping to the cache, and apply the newly computed method.
  1246. ;;;
  1247. ;;; The cached mapping is invalidated whenever a new method is defined
  1248. ;;; on this generic, or whenever the class hierarchy of any method
  1249. ;;; specializer changes.
  1250. ;;;
  1251. (define (single-arity-cache-dispatch cache nargs cache-miss)
  1252. (match cache
  1253. (() cache-miss)
  1254. (((typev . cmethod) . cache)
  1255. (cond
  1256. ((eqv? nargs (vector-length typev))
  1257. (let ((cache-miss (single-arity-cache-dispatch cache nargs cache-miss)))
  1258. (define (type-ref n)
  1259. (and (< n nargs) (vector-ref typev n)))
  1260. (define-syntax args-match?
  1261. (syntax-rules ()
  1262. ((args-match?) #t)
  1263. ((args-match? (arg type) (arg* type*) ...)
  1264. ;; Check that the arg has the exact type that we saw. It
  1265. ;; could be that `type' is #f, which indicates the end of
  1266. ;; the specializers list. Once all specializers have been
  1267. ;; examined, we don't need to look at any more arguments
  1268. ;; to know that this is a cache hit.
  1269. (or (not type)
  1270. (and (eq? (class-of arg) type)
  1271. (args-match? (arg* type*) ...))))))
  1272. (define-syntax dispatch
  1273. (lambda (x)
  1274. (define (bind-types types k)
  1275. (let lp ((types types) (n 0))
  1276. (syntax-case types ()
  1277. (() (k))
  1278. ((type . types)
  1279. #`(let ((type (type-ref #,n)))
  1280. #,(lp #'types (1+ n)))))))
  1281. (syntax-case x ()
  1282. ((dispatch arg ...)
  1283. (with-syntax (((type ...) (generate-temporaries #'(arg ...))))
  1284. (bind-types
  1285. #'(type ...)
  1286. (lambda ()
  1287. #'(lambda (arg ...)
  1288. (if (args-match? (arg type) ...)
  1289. (cmethod arg ...)
  1290. (cache-miss arg ...))))))))))
  1291. (arity-case nargs 20 dispatch
  1292. (lambda args
  1293. (define (args-match? args)
  1294. (let lp ((args args) (n 0))
  1295. (match args
  1296. ((arg . args)
  1297. (or (not (vector-ref typev n))
  1298. (and (eq? (vector-ref typev n) (class-of arg))
  1299. (lp args (1+ n)))))
  1300. (_ #t))))
  1301. (if (args-match? args)
  1302. (apply cmethod args)
  1303. (apply cache-miss args))))))
  1304. (else
  1305. (single-arity-cache-dispatch cache nargs cache-miss))))))
  1306. (define (compute-generic-function-dispatch-procedure gf)
  1307. (define (seen-arities cache)
  1308. (let lp ((arities 0) (cache cache))
  1309. (match cache
  1310. (() arities)
  1311. (((typev . cmethod) . cache)
  1312. (lp (logior arities (ash 1 (vector-length typev)))
  1313. cache)))))
  1314. (define (cache-miss . args)
  1315. (memoize-generic-function-application! gf args)
  1316. (apply gf args))
  1317. (let* ((cache (slot-ref gf 'effective-methods))
  1318. (arities (seen-arities cache))
  1319. (max-arity (let lp ((max -1))
  1320. (if (< arities (ash 1 (1+ max)))
  1321. max
  1322. (lp (1+ max))))))
  1323. (cond
  1324. ((= max-arity -1)
  1325. ;; Nothing in the cache.
  1326. cache-miss)
  1327. ((= arities (ash 1 max-arity))
  1328. ;; Only one arity in the cache.
  1329. (let* ((nargs max-arity)
  1330. (f (single-arity-cache-dispatch cache nargs cache-miss)))
  1331. (single-arity-dispatcher f nargs cache-miss)))
  1332. (else
  1333. ;; Multiple arities.
  1334. (let ((fv (make-vector (1+ max-arity) #f)))
  1335. (let lp ((n 0))
  1336. (when (<= n max-arity)
  1337. (let ((f (single-arity-cache-dispatch cache n cache-miss)))
  1338. (vector-set! fv n f)
  1339. (lp (1+ n)))))
  1340. (multiple-arity-dispatcher fv cache-miss))))))
  1341. (define (recompute-generic-function-dispatch-procedure! gf)
  1342. (slot-set! gf 'procedure
  1343. (compute-generic-function-dispatch-procedure gf)))
  1344. (define (memoize-effective-method! gf args applicable)
  1345. (define (record-types args)
  1346. (let ((typev (make-vector (length args) #f)))
  1347. (let lp ((n 0) (args args))
  1348. (when (and (< n (slot-ref gf 'n-specialized))
  1349. (pair? args))
  1350. (match args
  1351. ((arg . args)
  1352. (vector-set! typev n (class-of arg))
  1353. (lp (1+ n) args)))))
  1354. typev))
  1355. (let* ((typev (record-types args))
  1356. (compute-effective-method (if (eq? (class-of gf) <generic>)
  1357. %compute-effective-method
  1358. compute-effective-method))
  1359. (cmethod (compute-effective-method gf applicable typev))
  1360. (cache (acons typev cmethod (slot-ref gf 'effective-methods))))
  1361. (slot-set! gf 'effective-methods cache)
  1362. (recompute-generic-function-dispatch-procedure! gf)
  1363. cmethod))
  1364. ;;;
  1365. ;;; If a method refers to `next-method' in its body, that method will be
  1366. ;;; able to dispatch to the next most specific method. The exact
  1367. ;;; `next-method' implementation is only known at runtime, as it is a
  1368. ;;; function of which precise argument types are being dispatched, which
  1369. ;;; might be subclasses of the method's declared specializers.
  1370. ;;;
  1371. ;;; Guile implements `next-method' by binding it as a closure variable.
  1372. ;;; An effective method is bound to a specific `next-method' by the
  1373. ;;; `make-procedure' slot of a <method>, which returns the new closure.
  1374. ;;;
  1375. (define (%compute-specialized-effective-method gf method types next-method)
  1376. (match (slot-ref method 'make-procedure)
  1377. (#f (method-procedure method))
  1378. (make-procedure (make-procedure next-method))))
  1379. (define (compute-specialized-effective-method gf method types next-method)
  1380. (%compute-specialized-effective-method gf method types next-method))
  1381. (define (%compute-effective-method gf methods types)
  1382. (match methods
  1383. ((method . methods)
  1384. (let ((compute-specialized-effective-method
  1385. (if (and (eq? (class-of gf) <generic>)
  1386. (eq? (class-of method) <method>))
  1387. %compute-specialized-effective-method
  1388. compute-specialized-effective-method)))
  1389. (compute-specialized-effective-method
  1390. gf method types
  1391. (match methods
  1392. (()
  1393. (lambda args
  1394. (no-next-method gf args)))
  1395. (methods
  1396. (let ((compute-effective-method (if (eq? (class-of gf) <generic>)
  1397. %compute-effective-method
  1398. compute-effective-method)))
  1399. (compute-effective-method gf methods types)))))))))
  1400. ;; Boot definition; overrided with a generic later.
  1401. (define (compute-effective-method gf methods types)
  1402. (%compute-effective-method gf methods types))
  1403. ;;;
  1404. ;;; Memoization
  1405. ;;;
  1406. (define (memoize-generic-function-application! gf args)
  1407. (let ((applicable ((if (eq? (class-of gf) <generic>)
  1408. %compute-applicable-methods
  1409. compute-applicable-methods)
  1410. gf args)))
  1411. (cond (applicable
  1412. (memoize-effective-method! gf args applicable))
  1413. (else
  1414. (no-applicable-method gf args)))))
  1415. (define no-applicable-method
  1416. (make <generic> #:name 'no-applicable-method))
  1417. (%goops-early-init)
  1418. ;; Then load the rest of GOOPS
  1419. ;; FIXME: deprecate.
  1420. (define min-fixnum (- (expt 2 29)))
  1421. (define max-fixnum (- (expt 2 29) 1))
  1422. ;;
  1423. ;; goops-error
  1424. ;;
  1425. (define (goops-error format-string . args)
  1426. (scm-error 'goops-error #f format-string args '()))
  1427. ;;;
  1428. ;;; {Meta classes}
  1429. ;;;
  1430. (define ensure-metaclass-with-supers
  1431. (let ((table-of-metas '()))
  1432. (lambda (meta-supers)
  1433. (let ((entry (assoc meta-supers table-of-metas)))
  1434. (if entry
  1435. ;; Found a previously created metaclass
  1436. (cdr entry)
  1437. ;; Create a new meta-class which inherit from "meta-supers"
  1438. (let ((new (make <class> #:dsupers meta-supers
  1439. #:slots '()
  1440. #:name (gensym "metaclass"))))
  1441. (set! table-of-metas (cons (cons meta-supers new) table-of-metas))
  1442. new))))))
  1443. (define (ensure-metaclass supers)
  1444. (if (null? supers)
  1445. <class>
  1446. (let* ((all-metas (map (lambda (x) (class-of x)) supers))
  1447. (all-cpls (append-map (lambda (m)
  1448. (cdr (class-precedence-list m)))
  1449. all-metas))
  1450. (needed-metas '()))
  1451. ;; Find the most specific metaclasses. The new metaclass will be
  1452. ;; a subclass of these.
  1453. (for-each
  1454. (lambda (meta)
  1455. (when (and (not (member meta all-cpls))
  1456. (not (member meta needed-metas)))
  1457. (set! needed-metas (append needed-metas (list meta)))))
  1458. all-metas)
  1459. ;; Now return a subclass of the metaclasses we found.
  1460. (if (null? (cdr needed-metas))
  1461. (car needed-metas) ; If there's only one, just use it.
  1462. (ensure-metaclass-with-supers needed-metas)))))
  1463. ;;;
  1464. ;;; {Classes}
  1465. ;;;
  1466. ;;; (define-class NAME (SUPER ...) SLOT-DEFINITION ... OPTION ...)
  1467. ;;;
  1468. ;;; SLOT-DEFINITION ::= INSTANCE-OF-<SLOT> | (SLOT-NAME OPTION ...)
  1469. ;;; OPTION ::= KEYWORD VALUE
  1470. ;;;
  1471. (define (make-class supers slots . options)
  1472. (define (find-duplicate l)
  1473. (match l
  1474. (() #f)
  1475. ((head . tail)
  1476. (if (memq head tail)
  1477. head
  1478. (find-duplicate tail)))))
  1479. (define (slot-spec->name slot-spec)
  1480. (match slot-spec
  1481. (((? symbol? name) . args) name)
  1482. ;; We can get here when redefining classes.
  1483. ((? slot? slot) (%slot-definition-name slot))))
  1484. (let* ((name (get-keyword #:name options *unbound*))
  1485. (supers (if (not (or-map (lambda (class)
  1486. (memq <object>
  1487. (class-precedence-list class)))
  1488. supers))
  1489. (append supers (list <object>))
  1490. supers))
  1491. (metaclass (or (get-keyword #:metaclass options #f)
  1492. (ensure-metaclass supers))))
  1493. ;; Verify that all direct slots are different and that we don't inherit
  1494. ;; several time from the same class
  1495. (let ((tmp1 (find-duplicate supers))
  1496. (tmp2 (find-duplicate (map slot-spec->name slots))))
  1497. (if tmp1
  1498. (goops-error "make-class: super class ~S is duplicate in class ~S"
  1499. tmp1 name))
  1500. (if tmp2
  1501. (goops-error "make-class: slot ~S is duplicate in class ~S"
  1502. tmp2 name)))
  1503. ;; Everything seems correct, build the class
  1504. (apply make metaclass
  1505. #:dsupers supers
  1506. #:slots slots
  1507. #:name name
  1508. options)))
  1509. ;;; (class (SUPER ...) SLOT-DEFINITION ... OPTION ...)
  1510. ;;;
  1511. ;;; SLOT-DEFINITION ::= SLOT-NAME | (SLOT-NAME OPTION ...)
  1512. ;;; OPTION ::= KEYWORD VALUE
  1513. ;;;
  1514. (define-syntax class
  1515. (lambda (x)
  1516. (define (parse-options options)
  1517. (syntax-case options ()
  1518. (() #'())
  1519. ((kw arg . options) (keyword? (syntax->datum #'kw))
  1520. (with-syntax ((options (parse-options #'options)))
  1521. (syntax-case #'kw ()
  1522. (#:init-form
  1523. #'(kw 'arg #:init-thunk (lambda () arg) . options))
  1524. (_
  1525. #'(kw arg . options)))))))
  1526. (define (check-valid-kwargs args)
  1527. (syntax-case args ()
  1528. (() #'())
  1529. ((kw arg . args) (keyword? (syntax->datum #'kw))
  1530. #`(kw arg . #,(check-valid-kwargs #'args)))))
  1531. (define (parse-slots-and-kwargs args)
  1532. (syntax-case args ()
  1533. (()
  1534. #'(() ()))
  1535. ((kw . _) (keyword? (syntax->datum #'kw))
  1536. #`(() #,(check-valid-kwargs args)))
  1537. (((name option ...) args ...)
  1538. (with-syntax (((slots kwargs) (parse-slots-and-kwargs #'(args ...)))
  1539. ((option ...) (parse-options #'(option ...))))
  1540. #'(((list 'name option ...) . slots) kwargs)))
  1541. ((name args ...) (symbol? (syntax->datum #'name))
  1542. (with-syntax (((slots kwargs) (parse-slots-and-kwargs #'(args ...))))
  1543. #'(('(name) . slots) kwargs)))))
  1544. (syntax-case x ()
  1545. ((class (super ...) arg ...)
  1546. (with-syntax ((((slot-def ...) (option ...))
  1547. (parse-slots-and-kwargs #'(arg ...))))
  1548. #'(make-class (list super ...)
  1549. (list slot-def ...)
  1550. option ...))))))
  1551. (define-syntax define-class-pre-definition
  1552. (lambda (x)
  1553. (syntax-case x ()
  1554. ((_ (k arg rest ...) out ...)
  1555. (keyword? (syntax->datum #'k))
  1556. (case (syntax->datum #'k)
  1557. ((#:getter #:setter)
  1558. #'(define-class-pre-definition (rest ...)
  1559. out ...
  1560. (when (or (not (defined? 'arg))
  1561. (not (is-a? arg <generic>)))
  1562. (toplevel-define!
  1563. 'arg
  1564. (ensure-generic (if (defined? 'arg) arg #f) 'arg)))))
  1565. ((#:accessor)
  1566. #'(define-class-pre-definition (rest ...)
  1567. out ...
  1568. (when (or (not (defined? 'arg))
  1569. (not (is-a? arg <accessor>)))
  1570. (toplevel-define!
  1571. 'arg
  1572. (ensure-accessor (if (defined? 'arg) arg #f) 'arg)))))
  1573. (else
  1574. #'(define-class-pre-definition (rest ...) out ...))))
  1575. ((_ () out ...)
  1576. #'(begin out ...)))))
  1577. ;; Some slot options require extra definitions to be made. In
  1578. ;; particular, we want to make sure that the generic function objects
  1579. ;; which represent accessors exist before `make-class' tries to add
  1580. ;; methods to them.
  1581. (define-syntax define-class-pre-definitions
  1582. (lambda (x)
  1583. (syntax-case x ()
  1584. ((_ () out ...)
  1585. #'(begin out ...))
  1586. ((_ (slot rest ...) out ...)
  1587. (keyword? (syntax->datum #'slot))
  1588. #'(begin out ...))
  1589. ((_ (slot rest ...) out ...)
  1590. (identifier? #'slot)
  1591. #'(define-class-pre-definitions (rest ...)
  1592. out ...))
  1593. ((_ ((slotname slotopt ...) rest ...) out ...)
  1594. #'(define-class-pre-definitions (rest ...)
  1595. out ... (define-class-pre-definition (slotopt ...)))))))
  1596. (define-syntax-rule (define-class name supers slot ...)
  1597. (begin
  1598. (define-class-pre-definitions (slot ...))
  1599. (let ((cls (class supers slot ... #:name 'name)))
  1600. (toplevel-define!
  1601. 'name
  1602. (if (defined? 'name)
  1603. (class-redefinition name cls)
  1604. cls)))))
  1605. (define-syntax-rule (standard-define-class arg ...)
  1606. (define-class arg ...))
  1607. ;;;
  1608. ;;; {Generic functions and accessors}
  1609. ;;;
  1610. ;; Apparently the desired semantics are that we extend previous
  1611. ;; procedural definitions, but that if `name' was already a generic, we
  1612. ;; overwrite its definition.
  1613. (define-syntax define-generic
  1614. (lambda (x)
  1615. (syntax-case x ()
  1616. ((define-generic name) (symbol? (syntax->datum #'name))
  1617. #'(define name
  1618. (if (and (defined? 'name) (is-a? name <generic>))
  1619. (make <generic> #:name 'name)
  1620. (ensure-generic (if (defined? 'name) name #f) 'name)))))))
  1621. (define-syntax define-extended-generic
  1622. (lambda (x)
  1623. (syntax-case x ()
  1624. ((define-extended-generic name val) (symbol? (syntax->datum #'name))
  1625. #'(define name (make-extended-generic val 'name))))))
  1626. (define-syntax define-extended-generics
  1627. (lambda (x)
  1628. (define (id-append ctx a b)
  1629. (datum->syntax ctx (symbol-append (syntax->datum a) (syntax->datum b))))
  1630. (syntax-case x ()
  1631. ((define-extended-generic (name ...) #:prefix (prefix ...))
  1632. (and (and-map symbol? (syntax->datum #'(name ...)))
  1633. (and-map symbol? (syntax->datum #'(prefix ...))))
  1634. (with-syntax ((((val ...)) (map (lambda (name)
  1635. (map (lambda (prefix)
  1636. (id-append name prefix name))
  1637. #'(prefix ...)))
  1638. #'(name ...))))
  1639. #'(begin
  1640. (define-extended-generic name (list val ...))
  1641. ...))))))
  1642. (define* (make-generic #:optional name)
  1643. (make <generic> #:name name))
  1644. (define* (make-extended-generic gfs #:optional name)
  1645. (let* ((gfs (if (list? gfs) gfs (list gfs)))
  1646. (gws? (any (lambda (gf) (is-a? gf <generic-with-setter>)) gfs)))
  1647. (let ((ans (if gws?
  1648. (let* ((sname (and name (make-setter-name name)))
  1649. (setters
  1650. (append-map (lambda (gf)
  1651. (if (is-a? gf <generic-with-setter>)
  1652. (list (ensure-generic (setter gf)
  1653. sname))
  1654. '()))
  1655. gfs))
  1656. (es (make <extended-generic-with-setter>
  1657. #:name name
  1658. #:extends gfs
  1659. #:setter (make <extended-generic>
  1660. #:name sname
  1661. #:extends setters))))
  1662. (extended-by! setters (setter es))
  1663. es)
  1664. (make <extended-generic>
  1665. #:name name
  1666. #:extends gfs))))
  1667. (extended-by! gfs ans)
  1668. ans)))
  1669. (define (extended-by! gfs eg)
  1670. (for-each (lambda (gf)
  1671. (slot-set! gf 'extended-by
  1672. (cons eg (slot-ref gf 'extended-by))))
  1673. gfs)
  1674. (invalidate-method-cache! eg))
  1675. (define (not-extended-by! gfs eg)
  1676. (for-each (lambda (gf)
  1677. (slot-set! gf 'extended-by
  1678. (delq! eg (slot-ref gf 'extended-by))))
  1679. gfs)
  1680. (invalidate-method-cache! eg))
  1681. (define* (ensure-generic old-definition #:optional name)
  1682. (cond ((is-a? old-definition <generic>) old-definition)
  1683. ((procedure-with-setter? old-definition)
  1684. (make <generic-with-setter>
  1685. #:name name
  1686. #:default (procedure old-definition)
  1687. #:setter (setter old-definition)))
  1688. ((procedure? old-definition)
  1689. (if (generic-capability? old-definition) old-definition
  1690. (make <generic> #:name name #:default old-definition)))
  1691. (else (make <generic> #:name name))))
  1692. ;; same semantics as <generic>
  1693. (define-syntax-rule (define-accessor name)
  1694. (define name
  1695. (cond ((not (defined? 'name)) (ensure-accessor #f 'name))
  1696. ((is-a? name <accessor>) (make <accessor> #:name 'name))
  1697. (else (ensure-accessor name 'name)))))
  1698. (define (make-setter-name name)
  1699. (string->symbol (string-append "setter:" (symbol->string name))))
  1700. (define* (make-accessor #:optional name)
  1701. (make <accessor>
  1702. #:name name
  1703. #:setter (make <generic>
  1704. #:name (and name (make-setter-name name)))))
  1705. (define* (ensure-accessor proc #:optional name)
  1706. (cond ((and (is-a? proc <accessor>)
  1707. (is-a? (setter proc) <generic>))
  1708. proc)
  1709. ((is-a? proc <generic-with-setter>)
  1710. (upgrade-accessor proc (setter proc)))
  1711. ((is-a? proc <generic>)
  1712. (upgrade-accessor proc (make-generic name)))
  1713. ((procedure-with-setter? proc)
  1714. (make <accessor>
  1715. #:name name
  1716. #:default (procedure proc)
  1717. #:setter (ensure-generic (setter proc) name)))
  1718. ((procedure? proc)
  1719. (ensure-accessor (if (generic-capability? proc)
  1720. (make <generic> #:name name #:default proc)
  1721. (ensure-generic proc name))
  1722. name))
  1723. (else
  1724. (make-accessor name))))
  1725. (define (upgrade-accessor generic setter)
  1726. (let ((methods (slot-ref generic 'methods))
  1727. (gws (make (if (is-a? generic <extended-generic>)
  1728. <extended-generic-with-setter>
  1729. <accessor>)
  1730. #:name (generic-function-name generic)
  1731. #:extended-by (slot-ref generic 'extended-by)
  1732. #:setter setter)))
  1733. (when (is-a? generic <extended-generic>)
  1734. (let ((gfs (slot-ref generic 'extends)))
  1735. (not-extended-by! gfs generic)
  1736. (slot-set! gws 'extends gfs)
  1737. (extended-by! gfs gws)))
  1738. ;; Steal old methods
  1739. (for-each (lambda (method)
  1740. (slot-set! method 'generic-function gws))
  1741. methods)
  1742. (slot-set! gws 'methods methods)
  1743. (invalidate-method-cache! gws)
  1744. gws))
  1745. ;;;
  1746. ;;; {Methods}
  1747. ;;;
  1748. ;; Note: `a' and `b' can have unequal lengths (i.e. one can be one
  1749. ;; element longer than the other when we have a dotted parameter
  1750. ;; list). For instance, with the call
  1751. ;;
  1752. ;; (M 1)
  1753. ;;
  1754. ;; with
  1755. ;;
  1756. ;; (define-method M (a . l) ....)
  1757. ;; (define-method M (a) ....)
  1758. ;;
  1759. ;; we consider that the second method is more specific.
  1760. ;;
  1761. ;; Precondition: `a' and `b' are methods and are applicable to `types'.
  1762. (define (%method-more-specific? a b types)
  1763. (let lp ((a-specializers (method-specializers a))
  1764. (b-specializers (method-specializers b))
  1765. (types types))
  1766. (cond
  1767. ;; (a) less specific than (a b ...) or (a . b)
  1768. ((null? a-specializers) #t)
  1769. ;; (a b ...) or (a . b) less specific than (a)
  1770. ((null? b-specializers) #f)
  1771. ;; (a . b) less specific than (a b ...)
  1772. ((not (pair? a-specializers)) #f)
  1773. ;; (a b ...) more specific than (a . b)
  1774. ((not (pair? b-specializers)) #t)
  1775. (else
  1776. (let ((a-specializer (car a-specializers))
  1777. (b-specializer (car b-specializers))
  1778. (a-specializers (cdr a-specializers))
  1779. (b-specializers (cdr b-specializers))
  1780. (type (car types))
  1781. (types (cdr types)))
  1782. (if (eq? a-specializer b-specializer)
  1783. (lp a-specializers b-specializers types)
  1784. (let lp ((cpl (class-precedence-list type)))
  1785. (let ((elt (car cpl)))
  1786. (cond
  1787. ((eq? a-specializer elt) #t)
  1788. ((eq? b-specializer elt) #f)
  1789. (else (lp (cdr cpl))))))))))))
  1790. (define (%sort-applicable-methods methods types)
  1791. (sort methods (lambda (a b) (%method-more-specific? a b types))))
  1792. (define (generic-function-methods obj)
  1793. "Return the methods of the generic function @var{obj}."
  1794. (define (fold-upward method-lists gf)
  1795. (cond
  1796. ((is-a? gf <extended-generic>)
  1797. (let lp ((method-lists method-lists) (gfs (slot-ref gf 'extends)))
  1798. (match gfs
  1799. (() method-lists)
  1800. ((gf . gfs)
  1801. (lp (fold-upward (cons (slot-ref gf 'methods) method-lists) gf)
  1802. gfs)))))
  1803. (else method-lists)))
  1804. (define (fold-downward method-lists gf)
  1805. (let lp ((method-lists (cons (slot-ref gf 'methods) method-lists))
  1806. (gfs (slot-ref gf 'extended-by)))
  1807. (match gfs
  1808. (() method-lists)
  1809. ((gf . gfs)
  1810. (lp (fold-downward method-lists gf) gfs)))))
  1811. (unless (is-a? obj <generic>)
  1812. (scm-error 'wrong-type-arg #f "Not a generic: ~S"
  1813. (list obj) #f))
  1814. (concatenate (fold-downward (fold-upward '() obj) obj)))
  1815. (define (%compute-applicable-methods gf args)
  1816. (define (method-applicable? m types)
  1817. (let ((specs (method-specializers m)))
  1818. (cond
  1819. ((and (is-a? m <accessor-method>)
  1820. (or (null? specs) (null? types)
  1821. (not (eq? (car specs) (car types)))))
  1822. ;; Slot accessor methods are added to each subclass with the
  1823. ;; slot. They only apply to that specific concrete class, which
  1824. ;; appears as the first argument.
  1825. #f)
  1826. (else
  1827. (let lp ((specs specs) (types types))
  1828. (cond
  1829. ((null? specs) (null? types))
  1830. ((not (pair? specs)) #t)
  1831. ((null? types) #f)
  1832. (else
  1833. (and (memq (car specs) (class-precedence-list (car types)))
  1834. (lp (cdr specs) (cdr types))))))))))
  1835. (let ((types (map class-of args)))
  1836. (let lp ((methods (generic-function-methods gf))
  1837. (applicable '()))
  1838. (if (null? methods)
  1839. (and (not (null? applicable))
  1840. (%sort-applicable-methods applicable types))
  1841. (let ((m (car methods)))
  1842. (lp (cdr methods)
  1843. (if (method-applicable? m types)
  1844. (cons m applicable)
  1845. applicable)))))))
  1846. (define compute-applicable-methods %compute-applicable-methods)
  1847. (define (toplevel-define! name val)
  1848. (module-define! (current-module) name val))
  1849. ;;;
  1850. ;;; The GOOPS API would have been simpler by introducing keyword formals
  1851. ;;; in define-method itself, but in order to align with lambda* and
  1852. ;;; define*, we introduce method* and define-method* in parallel to
  1853. ;;; method and define-method.
  1854. ;;;
  1855. ;;; There is some code repetition here. The motivation for that is to
  1856. ;;; pay some here in order to speed up loading and compilation of larger
  1857. ;;; chunks of GOOPS code as well as to make sure that method*:s are as
  1858. ;;; efficient as can be.
  1859. ;;;
  1860. ;;; A more elegant solution would have been to use something akin to
  1861. ;;; Mark H. Weavers macro:
  1862. ;;;
  1863. ;;; (define-syntax define-method*
  1864. ;;; (lambda (x)
  1865. ;;; (syntax-case x ()
  1866. ;;; ((_ (generic arg-spec ... . tail) body ...)
  1867. ;;; (let-values (((required-arg-specs other-arg-specs)
  1868. ;;; (break (compose keyword? syntax->datum)
  1869. ;;; #'(arg-spec ...))))
  1870. ;;; #`(define-method (generic #,@required-arg-specs . rest)
  1871. ;;; (apply (lambda* (#,@other-arg-specs . tail)
  1872. ;;; body ...)
  1873. ;;; rest)))))))
  1874. ;;;
  1875. ;;; With the current state of the compiler, this results in slower code
  1876. ;;; than the implementation below since the apply call isn't
  1877. ;;; eliminated. Note also that it doesn't support the (next-method) call
  1878. ;;; as does the following implementation.
  1879. ;;;
  1880. ;;; If you make changes, bear in mind that define-method* is supposed to
  1881. ;;; also be able to handle ordinary methods without keyword formals. See
  1882. ;;; the Guile Reference and the module (oop goops keyword-formals).
  1883. ;;;
  1884. (define-syntax define-method
  1885. (syntax-rules (setter)
  1886. ((_ ((setter name) . args) body ...)
  1887. (begin
  1888. (when (or (not (defined? 'name))
  1889. (not (is-a? name <accessor>)))
  1890. (toplevel-define! 'name
  1891. (ensure-accessor
  1892. (if (defined? 'name) name #f) 'name)))
  1893. (add-method! (setter name) (method args body ...))))
  1894. ((_ (name . args) body ...)
  1895. (begin
  1896. ;; FIXME: this code is how it always was, but it's quite cracky:
  1897. ;; it will only define the generic function if it was undefined
  1898. ;; before (ok), or *was defined to #f*. The latter is crack. But
  1899. ;; there are bootstrap issues about fixing this -- change it to
  1900. ;; (is-a? name <generic>) and see.
  1901. (when (or (not (defined? 'name))
  1902. (not name))
  1903. (toplevel-define! 'name (make <generic> #:name 'name)))
  1904. (add-method! name (method args body ...))))))
  1905. (define-syntax define-method*
  1906. (syntax-rules (setter)
  1907. ((_ ((setter name) . args) body ...)
  1908. (begin
  1909. (when (or (not (defined? 'name))
  1910. (not (is-a? name <accessor>)))
  1911. (toplevel-define! 'name
  1912. (ensure-accessor
  1913. (if (defined? 'name) name #f) 'name)))
  1914. (add-method! (setter name) (method* args body ...))))
  1915. ((_ (name . args) body ...)
  1916. (begin
  1917. (when (or (not (defined? 'name))
  1918. (not name))
  1919. (toplevel-define! 'name (make <generic> #:name 'name)))
  1920. (add-method! name (method* args body ...))))))
  1921. ;;; This section of helpers is used by both the method and method* syntax
  1922. ;;;
  1923. (eval-when (expand load eval)
  1924. ;; parse-formals METHOD-FORMALS
  1925. ;;
  1926. ;; return (FORMALS SPECIALIZERS KEYWORD-FORMALS)
  1927. ;;
  1928. ;; FORMALS is the possibly improper list of specializable formals.
  1929. ;;
  1930. ;; SPECIALIZERS is a proper list of the corresponding specializers.
  1931. ;; Its last element corresponds to the cdr of the last element in
  1932. ;; METHOD-FORMALS such that the possibly improper list corresponding
  1933. ;; to FORMALS can be obtained by applying cons* to SPECIALIZERS.
  1934. ;; The reason for handling it like this is that the specializers are
  1935. ;; each evaluated to their values and therefore *must* be provided
  1936. ;; by a cons* in the (make <method> ...) expression.
  1937. ;;
  1938. ;; KEYWORD_FORMALS is the part of METHOD-FORMALS which starts with a
  1939. ;; keyword and corresponds to the keyword-syntax of lambda*. These
  1940. ;; are not specializable (which also corresponds to CLOS
  1941. ;; functionality).
  1942. ;;
  1943. (define (parse-keyword-formals method-formals)
  1944. (let lp ((ls method-formals) (formals '()) (specializers '()))
  1945. (syntax-case ls ()
  1946. (((f s) . rest)
  1947. (and (identifier? #'f) (identifier? #'s))
  1948. (lp #'rest
  1949. (cons #'f formals)
  1950. (cons #'s specializers)))
  1951. ((f . rest)
  1952. (identifier? #'f)
  1953. (lp #'rest
  1954. (cons #'f formals)
  1955. (cons #'<top> specializers)))
  1956. ((f . rest)
  1957. (keyword? (syntax->datum #'f))
  1958. (list (reverse formals)
  1959. (reverse (cons #'<top> specializers)) ;to be cons*:ed
  1960. (cons #'f #'rest)))
  1961. (()
  1962. (list (reverse formals)
  1963. (reverse (cons #''() specializers))
  1964. '())) ;yes, not #''(); used in tests
  1965. (tail
  1966. (identifier? #'tail)
  1967. (list (append (reverse formals) #'tail)
  1968. (reverse (cons #'<top> specializers))
  1969. '())))))
  1970. (define (parse-formals method-formals)
  1971. (let lp ((ls method-formals) (formals '()) (specializers '()))
  1972. (syntax-case ls ()
  1973. (((f s) . rest)
  1974. (and (identifier? #'f) (identifier? #'s))
  1975. (lp #'rest
  1976. (cons #'f formals)
  1977. (cons #'s specializers)))
  1978. ((f . rest)
  1979. (identifier? #'f)
  1980. (lp #'rest
  1981. (cons #'f formals)
  1982. (cons #'<top> specializers)))
  1983. (()
  1984. (list (reverse formals)
  1985. (reverse (cons #''() specializers))))
  1986. (tail
  1987. (identifier? #'tail)
  1988. (list (append (reverse formals) #'tail)
  1989. (reverse (cons #'<top> specializers)))))))
  1990. (define (find-free-id exp referent)
  1991. (syntax-case exp ()
  1992. ((x . y)
  1993. (or (find-free-id #'x referent)
  1994. (find-free-id #'y referent)))
  1995. (x
  1996. (identifier? #'x)
  1997. (let ((id (datum->syntax #'x referent)))
  1998. (and (free-identifier=? #'x id) id)))
  1999. (_ #f)))
  2000. (define (compute-procedure formals keyword-formals body)
  2001. (syntax-case body ()
  2002. ((body0 ...)
  2003. (if (null? keyword-formals)
  2004. (with-syntax ((formals formals))
  2005. #'(lambda formals body0 ...))
  2006. (let ((formals (append formals keyword-formals)))
  2007. (with-syntax ((formals formals))
  2008. #'(lambda* formals body0 ...)))))))
  2009. ;; ->formal-ids FORMALS
  2010. ;;
  2011. ;; convert FORMALS into formal-ids format, which is a cell where the
  2012. ;; car is the list of car:s in FORMALS and the cdr is the cdr of the
  2013. ;; last cell in FORMALS, i.e. the final tail.
  2014. ;;
  2015. ;; The motivation for this format is to easily determine if FORMALS
  2016. ;; is improper or not in order to generate the corresponding
  2017. ;; next-method call.
  2018. ;;
  2019. (define (->formal-ids formals)
  2020. (let lp ((ls formals) (out '()))
  2021. (syntax-case ls ()
  2022. ((x . xs) (lp #'xs (cons #'x out)))
  2023. (() (cons (reverse out) '()))
  2024. (tail (cons (reverse out) #'tail)))))
  2025. ;; compute-keyword-formal-ids FORMALS KEYWORD-FORMALS
  2026. ;;
  2027. ;; The main purpose of this beast is to compute the argument list
  2028. ;; for the actual next-method call for the case where the user calls
  2029. ;; (next-method). It is invoked in the case where we have keyword
  2030. ;; formals. Here we have to treat keyword arguments in a special way
  2031. ;; since we, similar to CLOS, only want to pass on the keyword
  2032. ;; arguments that were present in the call. We capture those using
  2033. ;; the rest argument. If not present, we introduce a rest formal.
  2034. ;;
  2035. ;; FORMALS is the non-keyword part of the formal arguments.
  2036. ;; KEYWORD-FORMALS is the part of the formal arguments from the
  2037. ;; first keyword.
  2038. ;;
  2039. ;; return three values:
  2040. ;;
  2041. ;; 1. #'lambda
  2042. ;; 2. the complete formals list
  2043. ;; 3. the argument list for next-method in formals-ids format as
  2044. ;; described above (proper list in CAR, tail in CDR)
  2045. ;;
  2046. (define (compute-keyword-formal-ids formals keyword-formals)
  2047. (define (result formals formal-ids)
  2048. (values #'lambda* formals formal-ids))
  2049. (define (lp-key ls formals formal-ids)
  2050. (syntax-case ls ()
  2051. ((#:rest f)
  2052. (identifier? #'f)
  2053. (result (append (reverse formals) #'f)
  2054. (cons (reverse formal-ids) #'f)))
  2055. (()
  2056. ;; No rest formal is present, so we need to introduce one.
  2057. (let ((rest-formal (car (generate-temporaries '(rest)))))
  2058. (result (append (reverse formals) rest-formal)
  2059. (cons (reverse formal-ids) rest-formal))))
  2060. ((f . rest)
  2061. (lp-key #'rest
  2062. (cons #'f formals) ;keep
  2063. formal-ids)) ;filter away
  2064. (tail
  2065. (result (append (reverse formals) #'tail)
  2066. (cons (reverse formal-ids) #'tail)))))
  2067. (let ((reversed-formals (reverse formals)))
  2068. (let lp ((ls keyword-formals)
  2069. (formals reversed-formals)
  2070. (formal-ids reversed-formals))
  2071. (syntax-case ls ()
  2072. (((f val) . rest)
  2073. (lp #'rest (cons #'(f val) formals) (cons #'f formal-ids)))
  2074. ((#:optional . rest)
  2075. (lp #'rest (cons #:optional formals) formal-ids))
  2076. ((#:key . rest)
  2077. (lp-key #'rest (cons #:key formals) formal-ids))
  2078. ((#:rest f)
  2079. (identifier? #'f)
  2080. (result (append (reverse formals) #'f)
  2081. (cons (reverse formal-ids) #'f)))
  2082. ((f . rest)
  2083. (lp #'rest (cons #'f formals) (cons #'f formal-ids)))
  2084. (()
  2085. (result (reverse formals) (cons (reverse formal-ids) '())))
  2086. (tail
  2087. (result (append (reverse formals) #'tail)
  2088. (cons (reverse formal-ids) #'tail)))))))
  2089. (define (compute-make-procedure formals keyword-formals body next-method)
  2090. (syntax-case body ()
  2091. ((body ...)
  2092. (call-with-values
  2093. (lambda ()
  2094. (if (null? keyword-formals)
  2095. (values #'lambda
  2096. formals
  2097. (->formal-ids formals))
  2098. (compute-keyword-formal-ids formals keyword-formals)))
  2099. (lambda (lambda-type formals formal-ids)
  2100. (with-syntax ((next-method next-method))
  2101. (syntax-case formals ()
  2102. (formals
  2103. #`(lambda (real-next-method)
  2104. (#,lambda-type ;lambda or lambda*
  2105. formals
  2106. (let ((next-method
  2107. (lambda args
  2108. (if (null? args)
  2109. ;; We have (next-method) and need to
  2110. ;; pass on the arguments to the method.
  2111. #,(if (null? (cdr formal-ids))
  2112. ;; proper list of identifiers
  2113. #`(real-next-method
  2114. #,@(car formal-ids))
  2115. ;; last identifier is a rest list
  2116. #`(apply real-next-method
  2117. #,@(car formal-ids)
  2118. #,(cdr formal-ids)))
  2119. ;; user passes arguments to next-method
  2120. (apply real-next-method args)))))
  2121. body ...)))))))))))
  2122. (define (compute-procedures formals keyword-formals body)
  2123. ;; So, our use of this is broken, because it operates on the
  2124. ;; pre-expansion source code. It's equivalent to just searching
  2125. ;; for referent in the datums. Ah well.
  2126. (let ((id (find-free-id body 'next-method)))
  2127. (if id
  2128. ;; return a make-procedure
  2129. (values #'#f
  2130. (compute-make-procedure formals keyword-formals body id))
  2131. (values (compute-procedure formals keyword-formals body)
  2132. #'#f))))
  2133. )
  2134. (define-syntax method
  2135. (lambda (x)
  2136. (syntax-case x ()
  2137. ((_ formals) #'(method formals (if #f #f)))
  2138. ((_ formals body0 body1 ...)
  2139. (with-syntax (((formals (specializer ...))
  2140. (parse-formals #'formals)))
  2141. (call-with-values
  2142. (lambda ()
  2143. (compute-procedures #'formals
  2144. '()
  2145. #'(body0 body1 ...)))
  2146. (lambda (procedure make-procedure)
  2147. (with-syntax ((procedure procedure)
  2148. (make-procedure make-procedure))
  2149. #`(make <method>
  2150. #:specializers (cons* specializer ...) ;yes, this
  2151. ;; The cons* is needed to get the value of each
  2152. ;; specializer.
  2153. #:formals 'formals ;might be improper
  2154. #:body '(body0 body1 ...)
  2155. #:make-procedure make-procedure
  2156. #:procedure procedure)))))))))
  2157. (define-syntax method*
  2158. (lambda (x)
  2159. (syntax-case x ()
  2160. ((_ formals) #'(method* formals (if #f #f)))
  2161. ((_ formals body0 body1 ...)
  2162. (with-syntax (((formals (specializer ...) keyword-formals)
  2163. (parse-keyword-formals #'formals)))
  2164. (call-with-values
  2165. (lambda ()
  2166. (compute-procedures #'formals
  2167. #'keyword-formals
  2168. #'(body0 body1 ...)))
  2169. (lambda (procedure make-procedure)
  2170. (with-syntax ((procedure procedure)
  2171. (make-procedure make-procedure))
  2172. #`(make <method>
  2173. #:specializers (cons* specializer ...)
  2174. #:formals (if (null? 'keyword-formals)
  2175. 'formals ;might be improper
  2176. (append 'formals 'keyword-formals))
  2177. #:body '(body0 body1 ...)
  2178. #:make-procedure make-procedure
  2179. #:procedure procedure)))))))))
  2180. ;;;
  2181. ;;; {Utilities}
  2182. ;;;
  2183. ;;; These are useful when dealing with method specializers, which might
  2184. ;;; have a rest argument.
  2185. ;;;
  2186. (define (map* fn . l) ; A map which accepts dotted lists (arg lists
  2187. (cond ; must be "isomorph"
  2188. ((null? (car l)) '())
  2189. ((pair? (car l)) (cons (apply fn (map car l))
  2190. (apply map* fn (map cdr l))))
  2191. (else (apply fn l))))
  2192. (define (for-each* fn . l) ; A for-each which accepts dotted lists (arg lists
  2193. (cond ; must be "isomorph"
  2194. ((null? (car l)) '())
  2195. ((pair? (car l)) (apply fn (map car l)) (apply for-each* fn (map cdr l)))
  2196. (else (apply fn l))))
  2197. (define (length* ls)
  2198. (do ((n 0 (+ 1 n))
  2199. (ls ls (cdr ls)))
  2200. ((not (pair? ls)) n)))
  2201. ;;;
  2202. ;;; {add-method!}
  2203. ;;;
  2204. (define (add-method-in-classes! m)
  2205. ;; Add method in all the classes which appears in its specializers list
  2206. (for-each* (lambda (x)
  2207. (let ((dm (class-direct-methods x)))
  2208. (unless (memq m dm)
  2209. (struct-set! x class-index-direct-methods (cons m dm)))))
  2210. (method-specializers m)))
  2211. (define (remove-method-in-classes! m)
  2212. ;; Remove method in all the classes which appears in its specializers list
  2213. (for-each* (lambda (x)
  2214. (struct-set! x
  2215. class-index-direct-methods
  2216. (delv! m (class-direct-methods x))))
  2217. (method-specializers m)))
  2218. (define (compute-new-list-of-methods gf new)
  2219. (let ((new-spec (method-specializers new))
  2220. (methods (slot-ref gf 'methods)))
  2221. (let loop ((l methods))
  2222. (if (null? l)
  2223. (cons new methods)
  2224. (if (equal? (method-specializers (car l)) new-spec)
  2225. (begin
  2226. ;; This spec. list already exists. Remove old method from dependents
  2227. (remove-method-in-classes! (car l))
  2228. (set-car! l new)
  2229. methods)
  2230. (loop (cdr l)))))))
  2231. (define (method-n-specializers m)
  2232. (length* (slot-ref m 'specializers)))
  2233. (define (calculate-n-specialized gf)
  2234. (fold (lambda (m n) (max n (method-n-specializers m)))
  2235. 0
  2236. (generic-function-methods gf)))
  2237. (define (invalidate-method-cache! gf)
  2238. (slot-set! gf 'n-specialized (calculate-n-specialized gf))
  2239. (%invalidate-method-cache! gf)
  2240. (for-each (lambda (gf) (invalidate-method-cache! gf))
  2241. (slot-ref gf 'extended-by)))
  2242. (define internal-add-method!
  2243. (method ((gf <generic>) (m <method>))
  2244. (slot-set! m 'generic-function gf)
  2245. (slot-set! gf 'methods (compute-new-list-of-methods gf m))
  2246. (invalidate-method-cache! gf)
  2247. (add-method-in-classes! m)
  2248. *unspecified*))
  2249. (define-generic add-method!)
  2250. ((method-procedure internal-add-method!) add-method! internal-add-method!)
  2251. (define-method (add-method! (proc <procedure>) (m <method>))
  2252. (if (generic-capability? proc)
  2253. (begin
  2254. (enable-primitive-generic! proc)
  2255. (add-method! proc m))
  2256. (next-method)))
  2257. (define-method (add-method! (pg <primitive-generic>) (m <method>))
  2258. (add-method! (primitive-generic-generic pg) m))
  2259. (define-method (add-method! obj (m <method>))
  2260. (goops-error "~S is not a valid generic function" obj))
  2261. ;;;
  2262. ;;; {Access to meta objects}
  2263. ;;;
  2264. ;;;
  2265. ;;; Methods
  2266. ;;;
  2267. (define-method (method-source (m <method>))
  2268. (let* ((spec (map* class-name (slot-ref m 'specializers)))
  2269. (src (procedure-source (slot-ref m 'procedure))))
  2270. (and src
  2271. (let ((args (cadr src))
  2272. (body (cddr src)))
  2273. (cons 'method
  2274. (cons (map* list args spec)
  2275. body))))))
  2276. (define-method (method-formals (m <method>))
  2277. (slot-ref m 'formals))
  2278. ;;;
  2279. ;;; Slots
  2280. ;;;
  2281. (define (slot-init-function class slot-name)
  2282. (%slot-definition-init-thunk (or (class-slot-definition class slot-name)
  2283. (error "slot not found" slot-name))))
  2284. (define (accessor-method-slot-definition obj)
  2285. "Return the slot definition of the accessor @var{obj}."
  2286. (slot-ref obj 'slot-definition))
  2287. ;;;
  2288. ;;; {Standard methods used by the C runtime}
  2289. ;;;
  2290. ;;; Methods to compare objects
  2291. ;;;
  2292. ;; Have to do this in a strange order because equal? is used in the
  2293. ;; add-method! implementation; we need to make sure that when the
  2294. ;; primitive is extended, that the generic has a method. =
  2295. (define g-equal? (make-generic 'equal?))
  2296. ;; When this generic gets called, we will have already checked eq? and
  2297. ;; eqv? -- the purpose of this generic is to extend equality. So by
  2298. ;; default, there is no extension, thus the #f return.
  2299. (add-method! g-equal? (method (x y) #f))
  2300. (set-primitive-generic! equal? g-equal?)
  2301. ;;;
  2302. ;;; methods to display/write an object
  2303. ;;;
  2304. ; Code for writing objects must test that the slots they use are
  2305. ; bound. Otherwise a slot-unbound method will be called and will
  2306. ; conduct to an infinite loop.
  2307. ;; Write
  2308. (define (display-address o file)
  2309. (display (number->string (object-address o) 16) file))
  2310. (define-method (write o file)
  2311. (display "#<instance " file)
  2312. (display-address o file)
  2313. (display #\> file))
  2314. (define write-object (primitive-generic-generic write))
  2315. (define-method (write (o <object>) file)
  2316. (let ((class (class-of o)))
  2317. (if (slot-bound? class 'name)
  2318. (begin
  2319. (display "#<" file)
  2320. (display (class-name class) file)
  2321. (display #\space file)
  2322. (display-address o file)
  2323. (display #\> file))
  2324. (next-method))))
  2325. (define-method (write (slot <slot>) file)
  2326. (let ((class (class-of slot)))
  2327. (if (and (slot-bound? class 'name)
  2328. (slot-bound? slot 'name))
  2329. (begin
  2330. (display "#<" file)
  2331. (display (class-name class) file)
  2332. (display #\space file)
  2333. (display (%slot-definition-name slot) file)
  2334. (display #\space file)
  2335. (display-address slot file)
  2336. (display #\> file))
  2337. (next-method))))
  2338. (define-method (write (class <class>) file)
  2339. (let ((meta (class-of class)))
  2340. (if (and (slot-bound? class 'name)
  2341. (slot-bound? meta 'name))
  2342. (begin
  2343. (display "#<" file)
  2344. (display (class-name meta) file)
  2345. (display #\space file)
  2346. (display (class-name class) file)
  2347. (display #\space file)
  2348. (display-address class file)
  2349. (display #\> file))
  2350. (next-method))))
  2351. (define-method (write (gf <generic>) file)
  2352. (let ((meta (class-of gf)))
  2353. (if (and (slot-bound? meta 'name)
  2354. (slot-bound? gf 'methods))
  2355. (begin
  2356. (display "#<" file)
  2357. (display (class-name meta) file)
  2358. (let ((name (generic-function-name gf)))
  2359. (if name
  2360. (begin
  2361. (display #\space file)
  2362. (display name file))))
  2363. (display " (" file)
  2364. (display (length (generic-function-methods gf)) file)
  2365. (display ")>" file))
  2366. (next-method))))
  2367. (define-method (write (o <method>) file)
  2368. (let ((meta (class-of o)))
  2369. (if (and (slot-bound? meta 'name)
  2370. (slot-bound? o 'specializers))
  2371. (begin
  2372. (display "#<" file)
  2373. (display (class-name meta) file)
  2374. (display #\space file)
  2375. (display (map* (lambda (spec)
  2376. (if (slot-bound? spec 'name)
  2377. (slot-ref spec 'name)
  2378. spec))
  2379. (method-specializers o))
  2380. file)
  2381. (display #\space file)
  2382. (display-address o file)
  2383. (display #\> file))
  2384. (next-method))))
  2385. ;; Display (do the same thing as write by default)
  2386. (define-method (display o file)
  2387. (write-object o file))
  2388. ;;;
  2389. ;;; Handling of duplicate bindings in the module system
  2390. ;;;
  2391. (define (find-subclass super name)
  2392. (let lp ((classes (class-direct-subclasses super)))
  2393. (cond
  2394. ((null? classes)
  2395. (error "class not found" name))
  2396. ((and (slot-bound? (car classes) 'name)
  2397. (eq? (class-name (car classes)) name))
  2398. (car classes))
  2399. (else
  2400. (lp (cdr classes))))))
  2401. ;; A record type.
  2402. (define <module> (find-subclass <top> '<module>))
  2403. (define-method (merge-generics (module <module>)
  2404. (name <symbol>)
  2405. (int1 <module>)
  2406. (val1 <top>)
  2407. (int2 <module>)
  2408. (val2 <top>)
  2409. (var <top>)
  2410. (val <top>))
  2411. #f)
  2412. (define-method (merge-generics (module <module>)
  2413. (name <symbol>)
  2414. (int1 <module>)
  2415. (val1 <generic>)
  2416. (int2 <module>)
  2417. (val2 <generic>)
  2418. (var <top>)
  2419. (val <boolean>))
  2420. (and (not (eq? val1 val2))
  2421. (make-variable (make-extended-generic (list val2 val1) name))))
  2422. (define-method (merge-generics (module <module>)
  2423. (name <symbol>)
  2424. (int1 <module>)
  2425. (val1 <generic>)
  2426. (int2 <module>)
  2427. (val2 <generic>)
  2428. (var <top>)
  2429. (gf <extended-generic>))
  2430. (and (not (memq val2 (slot-ref gf 'extends)))
  2431. (begin
  2432. (slot-set! gf
  2433. 'extends
  2434. (cons val2 (delq! val2 (slot-ref gf 'extends))))
  2435. (slot-set! val2
  2436. 'extended-by
  2437. (cons gf (delq! gf (slot-ref val2 'extended-by))))
  2438. (invalidate-method-cache! gf)
  2439. var)))
  2440. (module-define! duplicate-handlers 'merge-generics merge-generics)
  2441. (define-method (merge-accessors (module <module>)
  2442. (name <symbol>)
  2443. (int1 <module>)
  2444. (val1 <top>)
  2445. (int2 <module>)
  2446. (val2 <top>)
  2447. (var <top>)
  2448. (val <top>))
  2449. #f)
  2450. (define-method (merge-accessors (module <module>)
  2451. (name <symbol>)
  2452. (int1 <module>)
  2453. (val1 <accessor>)
  2454. (int2 <module>)
  2455. (val2 <accessor>)
  2456. (var <top>)
  2457. (val <top>))
  2458. (merge-generics module name int1 val1 int2 val2 var val))
  2459. (module-define! duplicate-handlers 'merge-accessors merge-accessors)
  2460. ;;;
  2461. ;;; slot access
  2462. ;;;
  2463. (define (class-slot-ref class slot-name)
  2464. (let ((slot (class-slot-definition class slot-name)))
  2465. (unless (memq (%slot-definition-allocation slot) '(#:class #:each-subclass))
  2466. (slot-missing class slot-name))
  2467. (let ((x ((%slot-definition-slot-ref/raw slot) #f)))
  2468. (if (unbound? x)
  2469. (slot-unbound class slot-name)
  2470. x))))
  2471. (define (class-slot-set! class slot-name value)
  2472. (let ((slot (class-slot-definition class slot-name)))
  2473. (unless (memq (%slot-definition-allocation slot) '(#:class #:each-subclass))
  2474. (slot-missing class slot-name))
  2475. ((%slot-definition-slot-set! slot) #f value)))
  2476. (define-method (slot-unbound (c <class>) (o <object>) s)
  2477. (goops-error "Slot `~S' is unbound in object ~S" s o))
  2478. (define-method (slot-unbound (c <class>) s)
  2479. (goops-error "Slot `~S' is unbound in class ~S" s c))
  2480. (define-method (slot-unbound (o <object>))
  2481. (goops-error "Unbound slot in object ~S" o))
  2482. (define-method (slot-missing (c <class>) (o <object>) s)
  2483. (goops-error "No slot with name `~S' in object ~S" s o))
  2484. (define-method (slot-missing (c <class>) s)
  2485. (goops-error "No class slot with name `~S' in class ~S" s c))
  2486. (define-method (slot-missing (c <class>) (o <object>) s value)
  2487. (slot-missing c o s))
  2488. ;;; Methods for the possible error we can encounter when calling a gf
  2489. (define-method (no-next-method (gf <generic>) args)
  2490. (goops-error "No next method when calling ~S\nwith arguments ~S" gf args))
  2491. (define-method (no-applicable-method (gf <generic>) args)
  2492. (goops-error "No applicable method for ~S in call ~S"
  2493. gf (cons (generic-function-name gf) args)))
  2494. (define-method (no-method (gf <generic>) args)
  2495. (goops-error "No method defined for ~S" gf))
  2496. ;;;
  2497. ;;; {Cloning functions (from rdeline@CS.CMU.EDU)}
  2498. ;;;
  2499. (define-method (shallow-clone (self <object>))
  2500. (let* ((class (class-of self))
  2501. (clone (%allocate-instance class))
  2502. (slots (map slot-definition-name (class-slots class))))
  2503. (for-each (lambda (slot)
  2504. (when (slot-bound? self slot)
  2505. (slot-set! clone slot (slot-ref self slot))))
  2506. slots)
  2507. clone))
  2508. (define-method (deep-clone (self <object>))
  2509. (let* ((class (class-of self))
  2510. (clone (%allocate-instance class))
  2511. (slots (map slot-definition-name (class-slots class))))
  2512. (for-each (lambda (slot)
  2513. (when (slot-bound? self slot)
  2514. (slot-set! clone slot
  2515. (let ((value (slot-ref self slot)))
  2516. (if (instance? value)
  2517. (deep-clone value)
  2518. value)))))
  2519. slots)
  2520. clone))
  2521. ;;;
  2522. ;;; {Utilities for INITIALIZE methods}
  2523. ;;;
  2524. ;;; compute-slot-accessors
  2525. ;;;
  2526. (define (compute-slot-accessors class slots)
  2527. (for-each
  2528. (lambda (slot)
  2529. (let ((getter (%slot-definition-getter slot))
  2530. (setter (%slot-definition-setter slot))
  2531. (accessor-setter setter)
  2532. (accessor (%slot-definition-accessor slot)))
  2533. (when getter
  2534. (add-method! getter (compute-getter-method class slot)))
  2535. (when setter
  2536. (add-method! setter (compute-setter-method class slot)))
  2537. (when accessor
  2538. (add-method! accessor (compute-getter-method class slot))
  2539. (add-method! (accessor-setter accessor)
  2540. (compute-setter-method class slot)))))
  2541. slots))
  2542. (define-method (compute-getter-method (class <class>) slot)
  2543. (make <accessor-method>
  2544. #:specializers (list class)
  2545. #:procedure (slot-definition-slot-ref slot)
  2546. #:slot-definition slot))
  2547. (define-method (compute-setter-method (class <class>) slot)
  2548. (make <accessor-method>
  2549. #:specializers (list class <top>)
  2550. #:procedure (slot-definition-slot-set! slot)
  2551. #:slot-definition slot))
  2552. (define (make-generic-bound-check-getter proc)
  2553. (lambda (o)
  2554. (let ((val (proc o)))
  2555. (if (unbound? val)
  2556. (slot-unbound o)
  2557. val))))
  2558. ;;; compute-cpl
  2559. ;;;
  2560. ;; Replace the bootstrap compute-cpl with this definition.
  2561. (define compute-cpl
  2562. (make <generic> #:name 'compute-cpl))
  2563. (define-method (compute-cpl (class <class>))
  2564. (compute-std-cpl class class-direct-supers))
  2565. ;;; compute-get-n-set
  2566. ;;;
  2567. (define compute-get-n-set
  2568. (make <generic> #:name 'compute-get-n-set))
  2569. (define-method (compute-get-n-set (class <class>) s)
  2570. (define (class-slot-init-value)
  2571. (let ((thunk (slot-definition-init-thunk s)))
  2572. (if thunk
  2573. (thunk)
  2574. (slot-definition-init-value s))))
  2575. (define (make-closure-variable class value)
  2576. (list (lambda (o) value)
  2577. (lambda (o v) (set! value v))))
  2578. (case (slot-definition-allocation s)
  2579. ((#:instance) ;; Instance slot
  2580. ;; get-n-set is just its offset
  2581. (let ((already-allocated (struct-ref/unboxed class class-index-nfields)))
  2582. (struct-set!/unboxed class class-index-nfields (+ already-allocated 1))
  2583. already-allocated))
  2584. ((#:class) ;; Class slot
  2585. ;; Class-slots accessors are implemented as 2 closures around
  2586. ;; a Scheme variable. As instance slots, class slots must be
  2587. ;; unbound at init time.
  2588. (let ((name (slot-definition-name s)))
  2589. (if (memq name (map slot-definition-name (class-direct-slots class)))
  2590. ;; This slot is direct; create a new shared variable
  2591. (make-closure-variable class (class-slot-init-value))
  2592. ;; Slot is inherited. Find its definition in superclass
  2593. (let lp ((cpl (cdr (class-precedence-list class))))
  2594. (match cpl
  2595. ((super . cpl)
  2596. (let ((s (class-slot-definition super name)))
  2597. (if s
  2598. (list (slot-definition-slot-ref s)
  2599. (slot-definition-slot-set! s))
  2600. ;; Multiple inheritance means that we might have
  2601. ;; to look deeper in the CPL.
  2602. (lp cpl)))))))))
  2603. ((#:each-subclass) ;; slot shared by instances of direct subclass.
  2604. ;; (Thomas Buerger, April 1998)
  2605. (make-closure-variable class (class-slot-init-value)))
  2606. ((#:virtual) ;; No allocation
  2607. ;; slot-ref and slot-set! function must be given by the user
  2608. (let ((get (get-keyword #:slot-ref (slot-definition-options s) #f))
  2609. (set (get-keyword #:slot-set! (slot-definition-options s) #f)))
  2610. (unless (and get set)
  2611. (goops-error "You must supply a #:slot-ref and a #:slot-set! in ~S" s))
  2612. (list get set)))
  2613. (else (next-method))))
  2614. (define-method (compute-get-n-set (o <object>) s)
  2615. (goops-error "Allocation \"~S\" is unknown" (slot-definition-allocation s)))
  2616. (define-method (compute-slots (class <class>))
  2617. (build-slots-list (class-direct-slots class)
  2618. (class-precedence-list class)))
  2619. ;;;
  2620. ;;; {Initialize}
  2621. ;;;
  2622. ;; FIXME: This could be much more efficient.
  2623. (define (%initialize-object obj initargs)
  2624. "Initialize the object @var{obj} with the given arguments
  2625. var{initargs}."
  2626. (define (valid-initargs? initargs)
  2627. (match initargs
  2628. (() #t)
  2629. (((? keyword?) _ . initargs) (valid-initargs? initargs))
  2630. (_ #f)))
  2631. (unless (instance? obj)
  2632. (scm-error 'wrong-type-arg #f "Not an object: ~S"
  2633. (list obj) #f))
  2634. (unless (valid-initargs? initargs)
  2635. (scm-error 'wrong-type-arg #f "Invalid initargs: ~S"
  2636. (list initargs) #f))
  2637. (let ((class (class-of obj)))
  2638. (define (get-initarg kw)
  2639. (if kw
  2640. ;; Inlined get-keyword to avoid checking initargs for validity
  2641. ;; each time.
  2642. (let lp ((initargs initargs))
  2643. (match initargs
  2644. ((kw* val . initargs)
  2645. (if (eq? kw* kw)
  2646. val
  2647. (lp initargs)))
  2648. (_ *unbound*)))
  2649. *unbound*))
  2650. (let lp ((slots (struct-ref class class-index-slots)))
  2651. (match slots
  2652. (() obj)
  2653. ((slot . slots)
  2654. (define (initialize-slot! value)
  2655. ((%slot-definition-slot-set! slot) obj value))
  2656. (let ((initarg (get-initarg (%slot-definition-init-keyword slot))))
  2657. (cond
  2658. ((not (unbound? initarg))
  2659. (initialize-slot! initarg))
  2660. ((%slot-definition-init-thunk slot)
  2661. => (lambda (init-thunk)
  2662. (unless (memq (slot-definition-allocation slot)
  2663. '(#:class #:each-subclass))
  2664. (initialize-slot! (init-thunk)))))))
  2665. (lp slots))))))
  2666. (define-method (initialize (object <object>) initargs)
  2667. (%initialize-object object initargs))
  2668. (define-method (initialize (slot <slot>) initargs)
  2669. (next-method)
  2670. (struct-set! slot slot-index-options initargs)
  2671. (let ((init-thunk (%slot-definition-init-thunk slot)))
  2672. (when init-thunk
  2673. (unless (thunk? init-thunk)
  2674. (goops-error "Bad init-thunk for slot `~S': ~S"
  2675. (%slot-definition-name slot) init-thunk)))))
  2676. (define-method (initialize (class <class>) initargs)
  2677. (define (make-direct-slot-definition dslot)
  2678. (let ((initargs (compute-direct-slot-definition-initargs class dslot)))
  2679. (compute-direct-slot-definition class initargs)))
  2680. (next-method)
  2681. (class-add-flags! class vtable-flag-goops-class)
  2682. (struct-set! class class-index-name (get-keyword #:name initargs '???))
  2683. (struct-set!/unboxed class class-index-nfields 0)
  2684. (struct-set! class class-index-direct-supers
  2685. (get-keyword #:dsupers initargs '()))
  2686. (struct-set! class class-index-direct-subclasses '())
  2687. (struct-set! class class-index-direct-methods '())
  2688. (struct-set! class class-index-cpl (compute-cpl class))
  2689. (when (get-keyword #:static-slot-allocation? initargs #f)
  2690. (match (filter class-has-statically-allocated-slots?
  2691. (class-precedence-list class))
  2692. (()
  2693. (class-add-flags! class vtable-flag-goops-static-slot-allocation))
  2694. (classes
  2695. (error "Class has superclasses with static slot allocation" classes))))
  2696. (struct-set! class class-index-direct-slots
  2697. (map (lambda (slot)
  2698. (if (slot? slot)
  2699. slot
  2700. (make-direct-slot-definition slot)))
  2701. (get-keyword #:slots initargs '())))
  2702. (struct-set! class class-index-slots
  2703. (allocate-slots class (compute-slots class)))
  2704. ;; This is a hack.
  2705. (when (memq <slot> (struct-ref class class-index-cpl))
  2706. (class-add-flags! class vtable-flag-goops-slot))
  2707. ;; Build getters - setters - accessors
  2708. (compute-slot-accessors class (struct-ref class class-index-slots))
  2709. ;; Update the "direct-subclasses" of each inherited classes
  2710. (for-each (lambda (x)
  2711. (let ((dsubs (struct-ref x class-index-direct-subclasses)))
  2712. (struct-set! x class-index-direct-subclasses
  2713. (cons class dsubs))))
  2714. (struct-ref class class-index-direct-supers))
  2715. ;; Compute struct layout of instances, set the `layout' slot, and
  2716. ;; update class flags.
  2717. (%prep-layout! class))
  2718. (define (initialize-object-procedure object initargs)
  2719. (let ((proc (get-keyword #:procedure initargs #f)))
  2720. (cond ((not proc))
  2721. ((pair? proc)
  2722. (apply slot-set! object 'procedure proc))
  2723. (else
  2724. (slot-set! object 'procedure proc)))))
  2725. (define-method (initialize (applicable-struct <applicable-struct>) initargs)
  2726. (next-method)
  2727. (initialize-object-procedure applicable-struct initargs))
  2728. (define-method (initialize (applicable-struct <applicable-struct-with-setter>)
  2729. initargs)
  2730. (next-method)
  2731. (slot-set! applicable-struct 'setter (get-keyword #:setter initargs #f)))
  2732. (define-method (initialize (generic <generic>) initargs)
  2733. (let ((previous-definition (get-keyword #:default initargs #f))
  2734. (name (get-keyword #:name initargs #f)))
  2735. (next-method)
  2736. (slot-set! generic 'methods (if (is-a? previous-definition <procedure>)
  2737. (list (method args
  2738. (apply previous-definition args)))
  2739. '()))
  2740. (if name
  2741. (set-procedure-property! generic 'name name))
  2742. (invalidate-method-cache! generic)))
  2743. (define-method (initialize (eg <extended-generic>) initargs)
  2744. (next-method)
  2745. (slot-set! eg 'extends (get-keyword #:extends initargs '())))
  2746. (define dummy-procedure (lambda args *unspecified*))
  2747. (define-method (initialize (method <method>) initargs)
  2748. (next-method)
  2749. (slot-set! method 'generic-function (get-keyword #:generic-function initargs #f))
  2750. (slot-set! method 'specializers (get-keyword #:specializers initargs '()))
  2751. (slot-set! method 'procedure
  2752. (get-keyword #:procedure initargs #f))
  2753. (slot-set! method 'formals (get-keyword #:formals initargs '()))
  2754. (slot-set! method 'body (get-keyword #:body initargs '()))
  2755. (slot-set! method 'make-procedure (get-keyword #:make-procedure initargs #f)))
  2756. ;;;
  2757. ;;; {make}
  2758. ;;;
  2759. ;;; A new definition which overwrites the previous one which was built-in
  2760. ;;;
  2761. (define-method (allocate-instance (class <class>) initargs)
  2762. (%allocate-instance class))
  2763. (define-method (make-instance (class <class>) . initargs)
  2764. (let ((instance (allocate-instance class initargs)))
  2765. (initialize instance initargs)
  2766. instance))
  2767. (define make make-instance)
  2768. ;;;
  2769. ;;; {apply-generic}
  2770. ;;;
  2771. ;;; Protocol for calling generic functions, intended to be used when
  2772. ;;; applying subclasses of <generic> and <generic-with-setter>. The
  2773. ;;; code below is similar to the first MOP described in AMOP.
  2774. ;;;
  2775. ;;; Note that standard generic functions dispatch only on the classes of
  2776. ;;; the arguments, and the result of such dispatch can be memoized. The
  2777. ;;; `dispatch-generic-function-application-from-cache' routine
  2778. ;;; implements this. `apply-generic' isn't called currently; the
  2779. ;;; generic function MOP was never fully implemented in GOOPS. However
  2780. ;;; now that GOOPS is implemented entirely in Scheme (2015) it's much
  2781. ;;; easier to complete this work. Contributions gladly accepted!
  2782. ;;; Please read the AMOP first though :)
  2783. ;;;
  2784. ;;; The protocol is:
  2785. ;;;
  2786. ;;; + apply-generic (gf args)
  2787. ;;; + compute-applicable-methods (gf args ...)
  2788. ;;; + sort-applicable-methods (gf methods args)
  2789. ;;; + apply-methods (gf methods args)
  2790. ;;;
  2791. ;;; apply-methods calls make-next-method to build the "continuation" of
  2792. ;;; a method. Applying a next-method will call apply-next-method which
  2793. ;;; in turn will call apply again to call effectively the following
  2794. ;;; method. (This paragraph is out of date but is kept so that maybe it
  2795. ;;; illuminates some future hack.)
  2796. ;;;
  2797. (define-method (apply-generic (gf <generic>) args)
  2798. (when (null? (slot-ref gf 'methods))
  2799. (no-method gf args))
  2800. (let ((methods (compute-applicable-methods gf args)))
  2801. (if methods
  2802. (apply-methods gf (sort-applicable-methods gf methods args) args)
  2803. (no-applicable-method gf args))))
  2804. ;; compute-applicable-methods is bound to %compute-applicable-methods.
  2805. (define compute-applicable-methods
  2806. (let ((gf (make <generic> #:name 'compute-applicable-methods)))
  2807. (add-method! gf (method ((gf <generic>) args)
  2808. (%compute-applicable-methods gf args)))
  2809. gf))
  2810. (define-method (sort-applicable-methods (gf <generic>) methods args)
  2811. (%sort-applicable-methods methods (map class-of args)))
  2812. (define-method (method-more-specific? (m1 <method>) (m2 <method>) targs)
  2813. (%method-more-specific? m1 m2 targs))
  2814. (define compute-effective-method
  2815. (let ((gf (make <generic> #:name 'compute-effective-method)))
  2816. (add-method! gf (method ((gf <generic>) methods typev)
  2817. (%compute-effective-method gf methods typev)))
  2818. gf))
  2819. (define compute-specialized-effective-method
  2820. (let ((gf (make <generic> #:name 'compute-specialized-effective-method)))
  2821. (add-method!
  2822. gf
  2823. (method ((gf <generic>) (method <method>) typev next)
  2824. (%compute-specialized-effective-method gf method typev next)))
  2825. gf))
  2826. (define-method (compute-specialized-effective-method (gf <generic>)
  2827. (m <accessor-method>)
  2828. typev
  2829. next)
  2830. (let ((name (slot-definition-name (accessor-method-slot-definition m))))
  2831. (match typev
  2832. (#(class)
  2833. (slot-definition-slot-ref (class-slot-definition class name)))
  2834. (#(class _)
  2835. (slot-definition-slot-set! (class-slot-definition class name)))
  2836. (_
  2837. (next-method)))))
  2838. (define-method (apply-method (gf <generic>) methods build-next args)
  2839. (apply (method-procedure (car methods))
  2840. (build-next (cdr methods) args)
  2841. args))
  2842. (define-method (apply-methods (gf <generic>) (l <list>) args)
  2843. (letrec ((next (lambda (procs args)
  2844. (lambda new-args
  2845. (let ((a (if (null? new-args) args new-args)))
  2846. (if (null? procs)
  2847. (no-next-method gf a)
  2848. (apply-method gf procs next a)))))))
  2849. (apply-method gf l next args)))
  2850. ;; We don't want the following procedure to turn up in backtraces:
  2851. (for-each (lambda (proc)
  2852. (set-procedure-property! proc 'system-procedure #t))
  2853. (list slot-unbound
  2854. slot-missing
  2855. no-next-method
  2856. no-applicable-method
  2857. no-method
  2858. ))
  2859. ;;;
  2860. ;;; Class redefinition
  2861. ;;;
  2862. ;;; GOOPS has a facility to allow a user to change the definition of
  2863. ;;; class. This will cause instances of that class to lazily migrate
  2864. ;;; over to the new definition. Implementing this is tricky because
  2865. ;;; identity is a fundamental part of object-oriented programming; you
  2866. ;;; can't just make a new class and start using it, just like that. In
  2867. ;;; GOOPS, classes are objects too and need to be addressable by
  2868. ;;; identity (by `eq?'). Classes need the ability to change their
  2869. ;;; definition "in place". The same goes for instances; redefining a
  2870. ;;; class might change the amount of storage associated with each
  2871. ;;; instance, and yet we need to update the instances in place, and
  2872. ;;; without having classes maintain a list of all of their instances.
  2873. ;;;
  2874. ;;; The way that we implement this is by adding an indirection. An
  2875. ;;; instance of a redefinable class becomes a small object containing
  2876. ;;; only a single field, a reference to an external "slots" objects that
  2877. ;;; holds the actual slots. There is an exception however for objects
  2878. ;;; that have statically allocated slots, most importantly classes -- in
  2879. ;;; that case the indirected slots are allocated "directly" in the
  2880. ;;; object.
  2881. ;;;
  2882. ;;; Instances update by checking the class of their their indirected
  2883. ;;; slots object. In addition to describing the slots of the indirected
  2884. ;;; slots object, that slots class (which is a direct class) has a
  2885. ;;; "redefined" slot. If the indirect slots object is current, this
  2886. ;;; value is #f. Otherwise it points to the old class definition
  2887. ;;; corresponding to its instances.
  2888. ;;;
  2889. ;;; To try to clarify things, here is a diagram of the "normal" state of
  2890. ;;; affairs. The redefinable class has an associated slots class. When
  2891. ;;; it makes instances, the instances have a pointer to the indirect
  2892. ;;; "slots" object. The class of the indirect slots object is the slots
  2893. ;;; class associated with the instance's class. The "V" arrows indicate
  2894. ;;; a vtable (class-of) relationship. Dashed arrows indicate a reference
  2895. ;;; from a struct slot to an object.
  2896. ;;;
  2897. ;;; Initial state.
  2898. ;;; +-------------+ +------------------------------+
  2899. ;;; | class ----> slots class, redefined: #f |
  2900. ;;; +-V-----------+ +-V----------------------------+
  2901. ;;; V V
  2902. ;;; +-V-----------+ +-V----------------------------+
  2903. ;;; | instance ----> slots ... |
  2904. ;;; +-------------+ +------------------------------+
  2905. ;;;
  2906. ;;; When a class is redefined, it is updated in place. However existing
  2907. ;;; instances are only migrated lazily. So after a class has been
  2908. ;;; redefined but before the instance has been updated, the state looks
  2909. ;;; like this:
  2910. ;;;
  2911. ;;; Redefined state.
  2912. ;;; ,-------------------------------------------.
  2913. ;;; | |
  2914. ;;; +-v-----------+ +----------------------------|-+
  2915. ;;; | old class ----> old slots class, redefined:' VVV
  2916. ;;; +-------------+ +------------------------------+ V
  2917. ;;; V
  2918. ;;; +-------------+ +------------------------------+ V
  2919. ;;; | new class ----> new slots class, redefined:#f| V
  2920. ;;; +-V-----------+ +------------------------------+ V
  2921. ;;; V V
  2922. ;;; +-V-----------+ +------------------------------+ V
  2923. ;;; | old inst ----> slots ... VVV
  2924. ;;; +-------------+ +------------------------------+
  2925. ;;;
  2926. ;;; That is to say, because the class was updated in place, the old
  2927. ;;; instance's vtable is the new class, even though the old instance's
  2928. ;;; slots still correspond to the old class. The vtable of the old slots
  2929. ;;; has the "redefined" field, which has been set to point to a fresh
  2930. ;;; object containing the direct slots of the old class, and a pointer to
  2931. ;;; the old slots class -- as if it were the old class, but with a new
  2932. ;;; temporary identity. This allows us to then call
  2933. ;;;
  2934. ;;; (change-object-class obj old-class new-class)
  2935. ;;;
  2936. ;;; which will allocate a fresh slots object for the old instance
  2937. ;;; corresponding to the new class, completing the migration for that
  2938. ;;; instance.
  2939. ;;;
  2940. ;;; Lazy instance migration is triggered by "class-of". Calling
  2941. ;;; "class-of" on an indirect instance will check the indirect slots to
  2942. ;;; see if they need redefinition. If so, we construct a fresh instance
  2943. ;;; of the new class and swap fields with the old instance (including
  2944. ;;; the indirect-slots field). Unfortunately there is some
  2945. ;;; thread-unsafety here, as retrieving the class is unsynchronized with
  2946. ;;; retrieving the indirect slots.
  2947. ;;;
  2948. (define-class <indirect-slots-class> (<class>)
  2949. (%redefined #:init-value #f))
  2950. (define-class <redefinable-class> (<class>)
  2951. (indirect-slots-class))
  2952. (define-method (compute-slots (class <redefinable-class>))
  2953. (let* ((slots (next-method))
  2954. ;; The base method ensured that at most one superclass has
  2955. ;; statically allocated slots.
  2956. (static-slots
  2957. (match (filter class-has-statically-allocated-slots?
  2958. (cdr (class-precedence-list class)))
  2959. (() '())
  2960. ((class) (struct-ref class class-index-direct-slots)))))
  2961. (define (simplify-slot-definition s)
  2962. ;; Here we take a slot definition and strip it to just be a plain
  2963. ;; old name, suitable for use as a slot for the plain-old-data
  2964. ;; indirect-slots class.
  2965. (and (eq? (slot-definition-allocation s) #:instance)
  2966. (make (class-of s) #:name (slot-definition-name s))))
  2967. (define (maybe-make-indirect-slot-definition s)
  2968. ;; Here we copy over all the frippery of a slot definition
  2969. ;; (accessors, init-keywords, and so on), but we change the slot
  2970. ;; to have virtual allocation and we provide explicit
  2971. ;; slot-ref/slot-set! functions that access the slot value through
  2972. ;; the indirect slots object. For slot definitions without
  2973. ;; instance allocation though, we just pass them through.
  2974. (cond
  2975. ((eq? (slot-definition-allocation s) #:instance)
  2976. (let* ((s* (class-slot-definition (slot-ref class 'indirect-slots-class)
  2977. (slot-definition-name s)))
  2978. (ref (slot-definition-slot-ref/raw s*))
  2979. (set! (slot-definition-slot-set! s*)))
  2980. (apply make (class-of s)
  2981. #:allocation #:virtual
  2982. ;; TODO: Make faster.
  2983. #:slot-ref (lambda (o)
  2984. (ref (slot-ref o 'indirect-slots)))
  2985. #:slot-set! (lambda (o v)
  2986. (set! (slot-ref o 'indirect-slots) v))
  2987. (let loop ((options (slot-definition-options s)))
  2988. (match options
  2989. (() '())
  2990. (((or #:allocation #:slot-ref #:slot-set!) _ . rest)
  2991. (loop rest))
  2992. ((kw arg . rest)
  2993. (cons* kw arg (loop rest))))))))
  2994. (else s)))
  2995. (unless (equal? (list-head slots (length static-slots))
  2996. static-slots)
  2997. (error "unexpected slots"))
  2998. (let* ((indirect-slots (list-tail slots (length static-slots)))
  2999. (indirect-slots-class
  3000. (make-class '()
  3001. (filter-map simplify-slot-definition
  3002. indirect-slots)
  3003. #:name 'indirect-slots
  3004. #:metaclass <indirect-slots-class>)))
  3005. (slot-set! class 'indirect-slots-class indirect-slots-class)
  3006. (append static-slots
  3007. (cons (make <slot> #:name 'indirect-slots)
  3008. (map maybe-make-indirect-slot-definition
  3009. indirect-slots))))))
  3010. (define-method (initialize (class <redefinable-class>) initargs)
  3011. (next-method)
  3012. (class-add-flags! class vtable-flag-goops-indirect))
  3013. (define-method (allocate-instance (class <redefinable-class>) initargs)
  3014. (let ((instance (next-method))
  3015. (nfields (struct-ref/unboxed class class-index-nfields))
  3016. (indirect-slots-class (slot-ref class 'indirect-slots-class)))
  3017. ;; Indirect slots will be last struct field.
  3018. (struct-set! instance (1- nfields) (make indirect-slots-class))
  3019. instance))
  3020. ;; Called when redefining an existing binding, and the new binding is a
  3021. ;; class. Two arguments: the old value, and the new.
  3022. (define-generic class-redefinition)
  3023. (define-method (class-redefinition (old <top>) (new <class>))
  3024. ;; Default class-redefinition method is to just replace old binding
  3025. ;; with the class.
  3026. new)
  3027. (define-method (class-redefinition (old <redefinable-class>)
  3028. (new <redefinable-class>))
  3029. ;; When redefining a redefinable class with a redefinable class, we
  3030. ;; migrate the old definition and its instances to become the new
  3031. ;; definition.
  3032. ;;
  3033. ;; Work on direct methods:
  3034. ;; 1. Remove accessor methods from the old class
  3035. ;; 2. Patch the occurences of new in the specializers by old
  3036. ;; 3. Displace the methods from old to new
  3037. (remove-class-accessors! old) ;; -1-
  3038. (let ((methods (class-direct-methods new)))
  3039. (for-each (lambda (m)
  3040. (update-direct-method! m new old)) ;; -2-
  3041. methods)
  3042. (struct-set! new
  3043. class-index-direct-methods
  3044. (append methods (class-direct-methods old))))
  3045. ;; Substitute old for new in new cpl
  3046. (set-car! (struct-ref new class-index-cpl) old)
  3047. ;; Remove the old class from the direct-subclasses list of its super classes
  3048. (for-each (lambda (c) (struct-set! c class-index-direct-subclasses
  3049. (delv! old (class-direct-subclasses c))))
  3050. (class-direct-supers old))
  3051. ;; Replace the new class with the old in the direct-subclasses of the supers
  3052. (for-each (lambda (c)
  3053. (struct-set! c class-index-direct-subclasses
  3054. (cons old (delv! new (class-direct-subclasses c)))))
  3055. (class-direct-supers new))
  3056. ;; Swap object headers
  3057. (%modify-instance old new)
  3058. ;; Now old is NEW!
  3059. ;; Redefine all the subclasses of old to take into account modification
  3060. (for-each
  3061. (lambda (c)
  3062. (update-direct-subclass! c new old))
  3063. (class-direct-subclasses new))
  3064. ;; Invalidate class so that subsequent instance slot accesses invoke
  3065. ;; change-object-class
  3066. (let ((slots-class (slot-ref new 'indirect-slots-class)))
  3067. (slot-set! slots-class '%redefined new)
  3068. (class-add-flags! slots-class vtable-flag-goops-needs-migration))
  3069. old)
  3070. (define-method (remove-class-accessors! (c <class>))
  3071. (for-each (lambda (m)
  3072. (when (is-a? m <accessor-method>)
  3073. (let ((gf (slot-ref m 'generic-function)))
  3074. ;; remove the method from its GF
  3075. (slot-set! gf 'methods
  3076. (delq1! m (slot-ref gf 'methods)))
  3077. (invalidate-method-cache! gf)
  3078. ;; remove the method from its specializers
  3079. (remove-method-in-classes! m))))
  3080. (class-direct-methods c)))
  3081. (define-method (update-direct-method! (m <method>)
  3082. (old <class>)
  3083. (new <class>))
  3084. (let loop ((l (method-specializers m)))
  3085. ;; Note: the <top> in dotted list is never used.
  3086. ;; So we can work as if we had only proper lists.
  3087. (when (pair? l)
  3088. (when (eqv? (car l) old)
  3089. (set-car! l new))
  3090. (loop (cdr l)))))
  3091. (define-method (update-direct-subclass! (c <class>)
  3092. (old <class>)
  3093. (new <class>))
  3094. (class-redefinition c
  3095. (make-class (class-direct-supers c)
  3096. (class-direct-slots c)
  3097. #:name (class-name c)
  3098. #:metaclass (class-of c))))
  3099. (define (change-object-class old-instance old-class new-class)
  3100. (let ((new-instance (allocate-instance new-class '())))
  3101. ;; Initialize the slots of the new instance
  3102. (for-each
  3103. (lambda (slot)
  3104. (unless (eq? slot 'indirect-slots)
  3105. (if (and (slot-exists? old-instance slot)
  3106. (memq (%slot-definition-allocation
  3107. (class-slot-definition old-class slot))
  3108. '(#:instance #:virtual))
  3109. (slot-bound? old-instance slot))
  3110. ;; Slot was present and allocated in old instance; copy it
  3111. (slot-set! new-instance slot (slot-ref old-instance slot))
  3112. ;; slot was absent; initialize it with its default value
  3113. (let ((init (slot-init-function new-class slot)))
  3114. (when init
  3115. (slot-set! new-instance slot (init)))))))
  3116. (map slot-definition-name (class-slots new-class)))
  3117. ;; Exchange old and new instance in place to keep pointers valid
  3118. (%modify-instance old-instance new-instance)
  3119. ;; Allow class specific updates of instances (which now are swapped)
  3120. (update-instance-for-different-class new-instance old-instance)
  3121. old-instance))
  3122. (define-method (update-instance-for-different-class (old-instance <object>)
  3123. (new-instance
  3124. <object>))
  3125. ;;not really important what we do, we just need a default method
  3126. new-instance)
  3127. (define-method (change-class (old-instance <object>)
  3128. (new-class <redefinable-class>))
  3129. (unless (is-a? (class-of old-instance) <redefinable-class>)
  3130. (error (string-append
  3131. "Default change-class implementation only works on"
  3132. " instances of redefinable classes")))
  3133. (change-object-class old-instance (class-of old-instance) new-class))
  3134. (define class-of-obsolete-indirect-instance
  3135. (let ((lock (make-mutex))
  3136. (stack '()))
  3137. (lambda (instance)
  3138. (let* ((new-class (struct-vtable instance))
  3139. (nfields (struct-ref/unboxed new-class class-index-nfields))
  3140. ;; Indirect slots are in last instance slot. For normal
  3141. ;; instances last slot is 0 of course.
  3142. (slots (struct-ref instance (1- nfields)))
  3143. (old-class (slot-ref (class-of slots) '%redefined)))
  3144. (let/ec return
  3145. (dynamic-wind
  3146. (lambda ()
  3147. (with-mutex lock
  3148. (if (memv slots stack)
  3149. (return (or old-class new-class))
  3150. (set! stack (cons slots stack)))))
  3151. (lambda ()
  3152. (when old-class
  3153. (change-class instance new-class))
  3154. new-class)
  3155. (lambda ()
  3156. (with-mutex lock
  3157. (set! stack (delq! slots stack))))))))))
  3158. ;;;
  3159. ;;; {Final initialization}
  3160. ;;;
  3161. ;; Tell C code that the main bulk of Goops has been loaded
  3162. (%goops-loaded)
  3163. ;;;
  3164. ;;; {SMOB and port classes}
  3165. ;;;
  3166. (define <promise> (find-subclass <top> '<promise>))
  3167. (define <thread> (find-subclass <top> '<thread>))
  3168. (define <mutex> (find-subclass <top> '<mutex>))
  3169. (define <condition-variable> (find-subclass <top> '<condition-variable>))
  3170. (define <regexp> (find-subclass <top> '<regexp>))
  3171. (define <hook> (find-subclass <top> '<hook>))
  3172. (define <bitvector> (find-subclass <top> '<bitvector>))
  3173. (define <random-state> (find-subclass <top> '<random-state>))
  3174. (define <directory> (find-subclass <top> '<directory>))
  3175. (define <array> (find-subclass <top> '<array>))
  3176. (define <character-set> (find-subclass <top> '<character-set>))
  3177. (define <guardian> (find-subclass <applicable> '<guardian>))
  3178. (define <macro> (find-subclass <top> '<macro>))
  3179. ;; <dynamic-object> used to be a SMOB type, albeit not exported even to
  3180. ;; C. However now it's a record type, though still private. Cross our
  3181. ;; fingers that nobody is using it in anger!
  3182. (define <dynamic-object>
  3183. (module-ref (resolve-module '(system foreign-library)) '<foreign-library>))
  3184. (define (define-class-subtree class)
  3185. (define! (class-name class) class)
  3186. (for-each define-class-subtree (class-direct-subclasses class)))
  3187. (define-class-subtree (find-subclass <port> '<file-port>))