goops.scm 117 KB

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