2000-10-25 14:51:33 +00:00
|
|
|
|
;;; installed-scm-file
|
|
|
|
|
|
|
2015-01-22 14:54:17 +01:00
|
|
|
|
;;;; Copyright (C) 1998,1999,2000-2003,2006,2009-2011,2013-2015 Free Software Foundation, Inc.
|
2013-01-26 15:41:05 +01:00
|
|
|
|
;;;; Copyright (C) 1993-1998 Erick Gallesio - I3S-CNRS/ESSI <eg@unice.fr>
|
|
|
|
|
|
;;;;
|
2003-04-05 19:15:35 +00:00
|
|
|
|
;;;; This library is free software; you can redistribute it and/or
|
|
|
|
|
|
;;;; modify it under the terms of the GNU Lesser General Public
|
|
|
|
|
|
;;;; License as published by the Free Software Foundation; either
|
2009-06-17 00:22:09 +01:00
|
|
|
|
;;;; version 3 of the License, or (at your option) any later version.
|
2013-01-26 15:41:05 +01:00
|
|
|
|
;;;;
|
2003-04-05 19:15:35 +00:00
|
|
|
|
;;;; This library is distributed in the hope that it will be useful,
|
2000-10-25 14:51:33 +00:00
|
|
|
|
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
2003-04-05 19:15:35 +00:00
|
|
|
|
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
|
;;;; Lesser General Public License for more details.
|
2013-01-26 15:41:05 +01:00
|
|
|
|
;;;;
|
2003-04-05 19:15:35 +00:00
|
|
|
|
;;;; You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
|
;;;; License along with this library; if not, write to the Free Software
|
2005-05-23 19:57:22 +00:00
|
|
|
|
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
2013-01-26 15:41:05 +01:00
|
|
|
|
;;;;
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;;;
|
2013-01-26 15:41:05 +01:00
|
|
|
|
;;;; This file was based upon stklos.stk from the STk distribution
|
|
|
|
|
|
;;;; version 4.0.1 by Erick Gallesio <eg@unice.fr>.
|
2000-10-25 14:51:33 +00:00
|
|
|
|
;;;;
|
|
|
|
|
|
|
|
|
|
|
|
(define-module (oop goops)
|
defining a smob or port type no longer mucks exports of (oop goops)
* libguile/goops.c (DEFVAR): Remove this helper macro, replacing its
uses with scm_module_define, but without scm_module_export.
(create_basic_classes, scm_init_goops_builtins): Update callers.
(make_class_from_template, make_class_from_symbol): Change to not
define variables for classes. This affects ports, struct classes, and
smob classes.
* module/oop/goops.scm: Explicitly list our exports, so there is no more
trickery happening in C.
(find-subclass): Private helper to grub the class hierarchy, so we can
define bindings for smobs, ports, etc. Use to define the classes that
goops.c used to define -- probably a subset, but it's better to have
them listed.
2011-07-01 11:46:32 +02:00
|
|
|
|
#:use-module (srfi srfi-1)
|
Move GOOPS boot to Scheme
* module/oop/goops.scm (build-<class>-slots): New helper, replacing
build_class_class_slots.
(build-slots-list, %compute-getters-n-setters, %compute-layout): New
private helpers, moved here from C.
(%prep-layout!): Reimplement in Scheme.
(make-standard-class): New private helper, replacing
scm_basic_make_class.
(<class>, <top>, <object>): Define in Scheme.
(<foreign-slot>, <protected-slot>, <hidden-slot>, <opaque-slot>,
<read-only-slot>, <self-slot>, <protected-opaque-slot>,
<protected-hidden-slot>, <protected-read-only-slot>, <scm-slot>,
<int-slot>, <float-slot>, <double-slot>, <procedure-class>,
<applicable-struct-class>, <method>, <accessor-method>, <applicable>,
<applicable-struct>, <generic>, <extended-generic>,
<generic-with-setter>, <accessor>, <extended-generic-with-setter>,
<extended-accessor>): Define in Scheme.
(<boolean>, <char>, <list>, <pair>, <null>, <string>, <symbol>,
<vector>, <foreign>, <hashtable>, <fluid>, <dynamic-state>, <frame>,
<vm-continuation>, <bytevector>, <uvec>, <array>, <bitvector>,
<number>, <complex>, <real>, <integer>, <fraction>, <keyword>,
<unknown>, <procedure>, <primitive-generic>, <port>, <input-port>,
<output-port>, <input-output-port>): Define in Scheme.
(compute-slots): Use build-slots-list helper.
* libguile/goops.h:
* libguile/goops.c (scm_basic_basic_make_class, scm_sys_compute_slots)
(scm_sys_prep_layout_x): Remove. These were available to C, but were
undocumented internals that were dangerous, confusing, and
unnecessary.
* libguile/goops.c: Add note about variable versus value references.
Remove internal C routines that were just used during boot, as they
have been moved to Scheme.
(scm_basic_make_class): Change to call out to make-standard-class in
Scheme.
(scm_sys_make_root_class, scm_sys_bless_applicable_struct_vtable_x)
(scm_sys_bless_pure_generic_vtable_x, scm_sys_init_layout_x): New
private helpers.
(scm_sys_goops_early_init): Change to capture values defined in
Scheme.
2015-01-04 13:41:09 -05:00
|
|
|
|
#:use-module (ice-9 match)
|
2015-01-04 15:52:12 -05:00
|
|
|
|
#:use-module (system base target)
|
2015-01-12 21:43:48 +01:00
|
|
|
|
#:use-module ((language tree-il primitives)
|
|
|
|
|
|
:select (add-interesting-primitive!))
|
defining a smob or port type no longer mucks exports of (oop goops)
* libguile/goops.c (DEFVAR): Remove this helper macro, replacing its
uses with scm_module_define, but without scm_module_export.
(create_basic_classes, scm_init_goops_builtins): Update callers.
(make_class_from_template, make_class_from_symbol): Change to not
define variables for classes. This affects ports, struct classes, and
smob classes.
* module/oop/goops.scm: Explicitly list our exports, so there is no more
trickery happening in C.
(find-subclass): Private helper to grub the class hierarchy, so we can
define bindings for smobs, ports, etc. Use to define the classes that
goops.c used to define -- probably a subset, but it's better to have
them listed.
2011-07-01 11:46:32 +02:00
|
|
|
|
#:export-syntax (define-class class standard-define-class
|
|
|
|
|
|
define-generic define-accessor define-method
|
|
|
|
|
|
define-extended-generic define-extended-generics
|
|
|
|
|
|
method)
|
|
|
|
|
|
#:export ( ;; The root of everything.
|
|
|
|
|
|
<top>
|
|
|
|
|
|
<class> <object>
|
|
|
|
|
|
|
|
|
|
|
|
;; Slot types.
|
|
|
|
|
|
<foreign-slot> <protected-slot> <hidden-slot> <opaque-slot>
|
|
|
|
|
|
<read-only-slot> <self-slot> <protected-opaque-slot>
|
|
|
|
|
|
<protected-hidden-slot> <protected-read-only-slot>
|
|
|
|
|
|
<scm-slot> <int-slot> <float-slot> <double-slot>
|
|
|
|
|
|
|
|
|
|
|
|
;; Methods are implementations of generic functions.
|
2011-07-07 00:57:19 +02:00
|
|
|
|
<method> <accessor-method>
|
|
|
|
|
|
|
defining a smob or port type no longer mucks exports of (oop goops)
* libguile/goops.c (DEFVAR): Remove this helper macro, replacing its
uses with scm_module_define, but without scm_module_export.
(create_basic_classes, scm_init_goops_builtins): Update callers.
(make_class_from_template, make_class_from_symbol): Change to not
define variables for classes. This affects ports, struct classes, and
smob classes.
* module/oop/goops.scm: Explicitly list our exports, so there is no more
trickery happening in C.
(find-subclass): Private helper to grub the class hierarchy, so we can
define bindings for smobs, ports, etc. Use to define the classes that
goops.c used to define -- probably a subset, but it's better to have
them listed.
2011-07-01 11:46:32 +02:00
|
|
|
|
;; Applicable objects, either procedures or applicable structs.
|
|
|
|
|
|
<procedure-class> <applicable>
|
|
|
|
|
|
<procedure> <primitive-generic>
|
2011-07-07 00:57:19 +02:00
|
|
|
|
|
defining a smob or port type no longer mucks exports of (oop goops)
* libguile/goops.c (DEFVAR): Remove this helper macro, replacing its
uses with scm_module_define, but without scm_module_export.
(create_basic_classes, scm_init_goops_builtins): Update callers.
(make_class_from_template, make_class_from_symbol): Change to not
define variables for classes. This affects ports, struct classes, and
smob classes.
* module/oop/goops.scm: Explicitly list our exports, so there is no more
trickery happening in C.
(find-subclass): Private helper to grub the class hierarchy, so we can
define bindings for smobs, ports, etc. Use to define the classes that
goops.c used to define -- probably a subset, but it's better to have
them listed.
2011-07-01 11:46:32 +02:00
|
|
|
|
;; Applicable structs.
|
Generics with setters have <applicable-struct-with-setter> layout
* libguile/goops.c (scm_sys_set_object_setter_x): Remove. Instead, we
use slot-set! of 'setter.
(scm_i_define_class_for_vtable): Move lower in the file, and fold in
scm_make_extended_class_from_symbol and make_class_from_symbol.
Properly handle applicable structs with setters.
(scm_class_applicable_struct_with_setter_class): New private capture.
(scm_sys_bless_applicable_struct_vtables_x): Rename to take two
arguments, and bless the second argument as an applicable struct with
setter vtable.
(scm_sys_goops_early_init): Capture setter classes.
* libguile/deprecated.c (SPEC_OF, CPL_OF): Access slots by name, not by
index.
(applicablep, more_specificp): Adapt to use CPL_OF.
(scm_find_method): Access "methods" slot by name.
* libguile/procs.c (scm_setter): Remove special case for generics; if
it's a setter, it will be a normal applicable struct.
* module/oop/goops.scm (<applicable-struct-with-setter-class>)
(<applicable-struct-with-setter>): New classes.
(<generic-with-setter>): Now an instance of the setter metaclass and a
child of the setter class, so that the "setter" slot ends up in the
right place.
(<accessor>, <extended-generic-with-setter>, <extended-accessor>): Be
instances of the setter metaclass.
(<method>, <accessor-method>): Move definitions farther down.
(make): Use slot-set! when initializing setters here.
(initialize): Likewise for <applicable-struct-with-setter>. Remove
specialization for <generic-with-setter>.
2015-01-06 13:41:56 -05:00
|
|
|
|
<applicable-struct-class> <applicable-struct-with-setter-class>
|
|
|
|
|
|
<applicable-struct> <applicable-struct-with-setter>
|
defining a smob or port type no longer mucks exports of (oop goops)
* libguile/goops.c (DEFVAR): Remove this helper macro, replacing its
uses with scm_module_define, but without scm_module_export.
(create_basic_classes, scm_init_goops_builtins): Update callers.
(make_class_from_template, make_class_from_symbol): Change to not
define variables for classes. This affects ports, struct classes, and
smob classes.
* module/oop/goops.scm: Explicitly list our exports, so there is no more
trickery happening in C.
(find-subclass): Private helper to grub the class hierarchy, so we can
define bindings for smobs, ports, etc. Use to define the classes that
goops.c used to define -- probably a subset, but it's better to have
them listed.
2011-07-01 11:46:32 +02:00
|
|
|
|
<generic> <extended-generic>
|
|
|
|
|
|
<generic-with-setter> <extended-generic-with-setter>
|
|
|
|
|
|
<accessor> <extended-accessor>
|
|
|
|
|
|
|
|
|
|
|
|
;; Types with their own allocated typecodes.
|
|
|
|
|
|
<boolean> <char> <list> <pair> <null> <string> <symbol>
|
|
|
|
|
|
<vector> <bytevector> <uvec> <foreign> <hashtable>
|
2013-11-19 21:32:42 +01:00
|
|
|
|
<fluid> <dynamic-state> <frame> <vm> <vm-continuation>
|
Keywords have a tc7
* libguile/tags.h (scm_tc7_keyword): Allocate a tc7, so that the VM can
have cheap keyword? tests.
* libguile/keywords.c:
* libguile/keywords.h: Adapt.
* libguile/goops.c (scm_class_of, scm_sys_goops_early_init): Capture
<keyword>.
* libguile/print.c (iprin1): Inline keyword printer.
* libguile/evalext.c (scm_self_evaluating_p): Add keywords here.
* libguile/deprecated.h:
* libguile/deprecated.c (scm_tc16_keyword): Deprecate.
* module/language/cps/compile-bytecode.scm (compile-fun): Add keyword?
case, and bitvector? case while we're at it.
* module/language/cps/effects-analysis.scm (define-primitive-effects):
Add bytevector?, keyword?, and bitvector? cases.
* module/language/cps/primitives.scm (*branching-primcall-arities*): Add
keyword?.
* module/language/cps/types.scm (bitvector?, keyword?, bytevector?): Add
branch inferrers.
* module/language/tree-il/primitives.scm (*interesting-primitive-names*):
(*effect-free-primitives*):
(*effect+exception-free-primitives*): Add bytevector?, keyword?, and
bitvector?.
* module/oop/goops.scm (<keyword>): New class.
* module/system/base/types.scm (%tc7-keyword, cell->object): Add cases.
* module/system/vm/assembler.scm (br-if-keyword): New definition.
* module/system/vm/disassembler.scm (code-annotation): Add br-if-tc7
case for keywords.
* test-suite/tests/types.test ("clonable objects"): Update now that
keywords are cloneable.
2015-01-19 16:57:42 +01:00
|
|
|
|
<keyword>
|
defining a smob or port type no longer mucks exports of (oop goops)
* libguile/goops.c (DEFVAR): Remove this helper macro, replacing its
uses with scm_module_define, but without scm_module_export.
(create_basic_classes, scm_init_goops_builtins): Update callers.
(make_class_from_template, make_class_from_symbol): Change to not
define variables for classes. This affects ports, struct classes, and
smob classes.
* module/oop/goops.scm: Explicitly list our exports, so there is no more
trickery happening in C.
(find-subclass): Private helper to grub the class hierarchy, so we can
define bindings for smobs, ports, etc. Use to define the classes that
goops.c used to define -- probably a subset, but it's better to have
them listed.
2011-07-01 11:46:32 +02:00
|
|
|
|
|
|
|
|
|
|
;; Numbers.
|
|
|
|
|
|
<number> <complex> <real> <integer> <fraction>
|
|
|
|
|
|
|
|
|
|
|
|
;; Unknown.
|
|
|
|
|
|
<unknown>
|
|
|
|
|
|
|
|
|
|
|
|
;; Particular SMOB data types. All SMOB types have
|
|
|
|
|
|
;; corresponding classes, which may be obtained via class-of,
|
|
|
|
|
|
;; once you have an instance. Perhaps FIXME to provide a
|
|
|
|
|
|
;; smob-type-name->class procedure.
|
|
|
|
|
|
<arbiter> <promise> <thread> <mutex> <condition-variable>
|
|
|
|
|
|
<regexp> <hook> <bitvector> <random-state> <async>
|
Keywords have a tc7
* libguile/tags.h (scm_tc7_keyword): Allocate a tc7, so that the VM can
have cheap keyword? tests.
* libguile/keywords.c:
* libguile/keywords.h: Adapt.
* libguile/goops.c (scm_class_of, scm_sys_goops_early_init): Capture
<keyword>.
* libguile/print.c (iprin1): Inline keyword printer.
* libguile/evalext.c (scm_self_evaluating_p): Add keywords here.
* libguile/deprecated.h:
* libguile/deprecated.c (scm_tc16_keyword): Deprecate.
* module/language/cps/compile-bytecode.scm (compile-fun): Add keyword?
case, and bitvector? case while we're at it.
* module/language/cps/effects-analysis.scm (define-primitive-effects):
Add bytevector?, keyword?, and bitvector? cases.
* module/language/cps/primitives.scm (*branching-primcall-arities*): Add
keyword?.
* module/language/cps/types.scm (bitvector?, keyword?, bytevector?): Add
branch inferrers.
* module/language/tree-il/primitives.scm (*interesting-primitive-names*):
(*effect-free-primitives*):
(*effect+exception-free-primitives*): Add bytevector?, keyword?, and
bitvector?.
* module/oop/goops.scm (<keyword>): New class.
* module/system/base/types.scm (%tc7-keyword, cell->object): Add cases.
* module/system/vm/assembler.scm (br-if-keyword): New definition.
* module/system/vm/disassembler.scm (code-annotation): Add br-if-tc7
case for keywords.
* test-suite/tests/types.test ("clonable objects"): Update now that
keywords are cloneable.
2015-01-19 16:57:42 +01:00
|
|
|
|
<directory> <array> <character-set>
|
2011-07-26 11:48:37 +02:00
|
|
|
|
<dynamic-object> <guardian> <macro>
|
defining a smob or port type no longer mucks exports of (oop goops)
* libguile/goops.c (DEFVAR): Remove this helper macro, replacing its
uses with scm_module_define, but without scm_module_export.
(create_basic_classes, scm_init_goops_builtins): Update callers.
(make_class_from_template, make_class_from_symbol): Change to not
define variables for classes. This affects ports, struct classes, and
smob classes.
* module/oop/goops.scm: Explicitly list our exports, so there is no more
trickery happening in C.
(find-subclass): Private helper to grub the class hierarchy, so we can
define bindings for smobs, ports, etc. Use to define the classes that
goops.c used to define -- probably a subset, but it's better to have
them listed.
2011-07-01 11:46:32 +02:00
|
|
|
|
|
|
|
|
|
|
;; Modules.
|
|
|
|
|
|
<module>
|
|
|
|
|
|
|
|
|
|
|
|
;; Ports.
|
|
|
|
|
|
<port> <input-port> <output-port> <input-output-port>
|
|
|
|
|
|
|
|
|
|
|
|
;; Like SMOB types, all port types have their own classes,
|
|
|
|
|
|
;; which can be accessed via `class-of' once you have an
|
|
|
|
|
|
;; instance. Here we export bindings just for file ports.
|
|
|
|
|
|
<file-port>
|
|
|
|
|
|
<file-input-port> <file-output-port> <file-input-output-port>
|
|
|
|
|
|
|
|
|
|
|
|
is-a? class-of
|
|
|
|
|
|
ensure-metaclass ensure-metaclass-with-supers
|
|
|
|
|
|
make-class
|
|
|
|
|
|
make-generic ensure-generic
|
|
|
|
|
|
make-extended-generic
|
|
|
|
|
|
make-accessor ensure-accessor
|
|
|
|
|
|
add-method!
|
2015-01-09 20:07:06 +01:00
|
|
|
|
class-slot-ref class-slot-set! slot-unbound slot-missing
|
defining a smob or port type no longer mucks exports of (oop goops)
* libguile/goops.c (DEFVAR): Remove this helper macro, replacing its
uses with scm_module_define, but without scm_module_export.
(create_basic_classes, scm_init_goops_builtins): Update callers.
(make_class_from_template, make_class_from_symbol): Change to not
define variables for classes. This affects ports, struct classes, and
smob classes.
* module/oop/goops.scm: Explicitly list our exports, so there is no more
trickery happening in C.
(find-subclass): Private helper to grub the class hierarchy, so we can
define bindings for smobs, ports, etc. Use to define the classes that
goops.c used to define -- probably a subset, but it's better to have
them listed.
2011-07-01 11:46:32 +02:00
|
|
|
|
slot-definition-name slot-definition-options
|
|
|
|
|
|
slot-definition-allocation
|
|
|
|
|
|
|
|
|
|
|
|
slot-definition-getter slot-definition-setter
|
|
|
|
|
|
slot-definition-accessor
|
|
|
|
|
|
slot-definition-init-value slot-definition-init-form
|
2015-01-09 20:07:06 +01:00
|
|
|
|
slot-definition-init-thunk slot-definition-init-keyword
|
defining a smob or port type no longer mucks exports of (oop goops)
* libguile/goops.c (DEFVAR): Remove this helper macro, replacing its
uses with scm_module_define, but without scm_module_export.
(create_basic_classes, scm_init_goops_builtins): Update callers.
(make_class_from_template, make_class_from_symbol): Change to not
define variables for classes. This affects ports, struct classes, and
smob classes.
* module/oop/goops.scm: Explicitly list our exports, so there is no more
trickery happening in C.
(find-subclass): Private helper to grub the class hierarchy, so we can
define bindings for smobs, ports, etc. Use to define the classes that
goops.c used to define -- probably a subset, but it's better to have
them listed.
2011-07-01 11:46:32 +02:00
|
|
|
|
slot-init-function class-slot-definition
|
|
|
|
|
|
method-source
|
|
|
|
|
|
compute-cpl compute-std-cpl compute-get-n-set compute-slots
|
|
|
|
|
|
compute-getter-method compute-setter-method
|
|
|
|
|
|
allocate-instance initialize make-instance make
|
|
|
|
|
|
no-next-method no-applicable-method no-method
|
|
|
|
|
|
change-class update-instance-for-different-class
|
|
|
|
|
|
shallow-clone deep-clone
|
|
|
|
|
|
class-redefinition
|
|
|
|
|
|
apply-generic apply-method apply-methods
|
|
|
|
|
|
compute-applicable-methods %compute-applicable-methods
|
|
|
|
|
|
method-more-specific? sort-applicable-methods
|
|
|
|
|
|
class-subclasses class-methods
|
|
|
|
|
|
goops-error
|
|
|
|
|
|
min-fixnum max-fixnum
|
2015-01-09 20:07:06 +01:00
|
|
|
|
|
defining a smob or port type no longer mucks exports of (oop goops)
* libguile/goops.c (DEFVAR): Remove this helper macro, replacing its
uses with scm_module_define, but without scm_module_export.
(create_basic_classes, scm_init_goops_builtins): Update callers.
(make_class_from_template, make_class_from_symbol): Change to not
define variables for classes. This affects ports, struct classes, and
smob classes.
* module/oop/goops.scm: Explicitly list our exports, so there is no more
trickery happening in C.
(find-subclass): Private helper to grub the class hierarchy, so we can
define bindings for smobs, ports, etc. Use to define the classes that
goops.c used to define -- probably a subset, but it's better to have
them listed.
2011-07-01 11:46:32 +02:00
|
|
|
|
instance? slot-ref-using-class
|
|
|
|
|
|
slot-set-using-class! slot-bound-using-class?
|
|
|
|
|
|
slot-exists-using-class? slot-ref slot-set! slot-bound?
|
|
|
|
|
|
class-name class-direct-supers class-direct-subclasses
|
|
|
|
|
|
class-direct-methods class-direct-slots class-precedence-list
|
|
|
|
|
|
class-slots
|
|
|
|
|
|
generic-function-name
|
|
|
|
|
|
generic-function-methods method-generic-function
|
|
|
|
|
|
method-specializers method-formals
|
|
|
|
|
|
primitive-generic-generic enable-primitive-generic!
|
|
|
|
|
|
method-procedure accessor-method-slot-definition
|
|
|
|
|
|
slot-exists? make find-method get-keyword)
|
|
|
|
|
|
#:no-backtrace)
|
2001-05-19 00:19:25 +00:00
|
|
|
|
|
2015-01-13 23:04:57 +01:00
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; Booting GOOPS is a tortuous process. We begin by loading a small
|
|
|
|
|
|
;;; set of primitives from C.
|
|
|
|
|
|
;;;
|
2015-01-12 21:43:48 +01:00
|
|
|
|
(eval-when (expand load eval)
|
2014-12-24 11:07:47 -05:00
|
|
|
|
(load-extension (string-append "libguile-" (effective-version))
|
2015-01-12 21:43:48 +01:00
|
|
|
|
"scm_init_goops_builtins")
|
2013-11-30 16:40:17 +01:00
|
|
|
|
(add-interesting-primitive! 'class-of))
|
2009-11-06 12:40:20 +01:00
|
|
|
|
|
2015-01-13 23:04:57 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; We then define the slots that must appear in all classes (<class>
|
|
|
|
|
|
;;; objects). These slots must appear in order. We'll use this list to
|
|
|
|
|
|
;;; statically compute offsets for the various fields, to compute the
|
|
|
|
|
|
;;; struct layout for <class> instances, and to compute the slot
|
|
|
|
|
|
;;; definition lists for <class>. Because the list is needed at
|
|
|
|
|
|
;;; expansion-time, we define it as a macro.
|
|
|
|
|
|
;;;
|
2015-01-09 19:10:51 +01:00
|
|
|
|
(define-syntax macro-fold-left
|
|
|
|
|
|
(syntax-rules ()
|
|
|
|
|
|
((_ folder seed ()) seed)
|
|
|
|
|
|
((_ folder seed (head . tail))
|
|
|
|
|
|
(macro-fold-left folder (folder head seed) tail))))
|
|
|
|
|
|
|
2015-01-07 18:42:27 -05:00
|
|
|
|
(define-syntax macro-fold-right
|
|
|
|
|
|
(syntax-rules ()
|
|
|
|
|
|
((_ folder seed ()) seed)
|
|
|
|
|
|
((_ folder seed (head . tail))
|
|
|
|
|
|
(folder head (macro-fold-right folder seed tail)))))
|
|
|
|
|
|
|
2015-01-13 23:04:57 +01:00
|
|
|
|
(define-syntax fold-class-slots
|
2015-01-09 19:10:51 +01:00
|
|
|
|
(lambda (x)
|
|
|
|
|
|
(define slots
|
|
|
|
|
|
'((layout <protected-read-only-slot>)
|
|
|
|
|
|
(flags <hidden-slot>)
|
|
|
|
|
|
(self <self-slot>)
|
|
|
|
|
|
(instance-finalizer <hidden-slot>)
|
|
|
|
|
|
(print)
|
|
|
|
|
|
(name <protected-hidden-slot>)
|
2015-01-11 16:36:45 +01:00
|
|
|
|
(nfields <hidden-slot>)
|
|
|
|
|
|
(%reserved <hidden-slot>)
|
2015-01-09 19:10:51 +01:00
|
|
|
|
(redefined)
|
|
|
|
|
|
(direct-supers)
|
|
|
|
|
|
(direct-slots)
|
|
|
|
|
|
(direct-subclasses)
|
|
|
|
|
|
(direct-methods)
|
|
|
|
|
|
(cpl)
|
|
|
|
|
|
(slots)
|
2015-01-11 16:36:45 +01:00
|
|
|
|
(getters-n-setters)))
|
2015-01-09 19:10:51 +01:00
|
|
|
|
(syntax-case x ()
|
|
|
|
|
|
((_ fold visit seed)
|
|
|
|
|
|
;; The datum->syntax makes it as if the identifiers in `slots'
|
|
|
|
|
|
;; were present in the initial form, which allows them to be used
|
|
|
|
|
|
;; as (components of) introduced identifiers.
|
|
|
|
|
|
#`(fold visit seed #,(datum->syntax #'visit slots))))))
|
|
|
|
|
|
|
2015-01-13 23:04:57 +01:00
|
|
|
|
;;;
|
|
|
|
|
|
;;; Statically define variables for slot offsets: `class-index-layout'
|
|
|
|
|
|
;;; will be 0, `class-index-flags' will be 1, and so on.
|
|
|
|
|
|
;;;
|
2015-01-09 19:10:51 +01:00
|
|
|
|
(let-syntax ((define-class-index
|
|
|
|
|
|
(lambda (x)
|
|
|
|
|
|
(define (id-append ctx a b)
|
|
|
|
|
|
(datum->syntax ctx (symbol-append (syntax->datum a)
|
|
|
|
|
|
(syntax->datum b))))
|
|
|
|
|
|
(define (tail-length tail)
|
|
|
|
|
|
(syntax-case tail ()
|
|
|
|
|
|
((begin) 0)
|
|
|
|
|
|
((visit head tail) (1+ (tail-length #'tail)))))
|
|
|
|
|
|
(syntax-case x ()
|
|
|
|
|
|
((_ (name . _) tail)
|
|
|
|
|
|
#`(begin
|
2015-01-16 10:20:17 +01:00
|
|
|
|
(define-syntax #,(id-append #'name #'class-index- #'name)
|
|
|
|
|
|
(identifier-syntax #,(tail-length #'tail)))
|
2015-01-09 19:10:51 +01:00
|
|
|
|
tail))))))
|
2015-01-13 23:04:57 +01:00
|
|
|
|
(fold-class-slots macro-fold-left define-class-index (begin)))
|
|
|
|
|
|
|
Manipulate GOOPS vtable flags from Scheme, for speed
* libguile/goops.h: Remove unimplemented declarations of
scm_make_next_method, scm_sys_invalidate_method_cache_x, and
stklos_version.
(scm_sys_invalidate_class_x): Remove helper definition. This was
exported in the past but shouldn't have been.
* libguile/goops.c (scm_sys_make_vtable_vtable): Rename from
scm_sys_make_root_class, and don't do anything about flags.
(scm_sys_bless_applicable_struct_vtables_x, scm_class_p)
(scm_sys_invalidate_class_x): Remove; we do these in Scheme now.
(scm_init_goops_builtins): Define Scheme values for vtable flags.
* module/oop/goops.scm (vtable-flag-goops-metaclass)
(class-add-flags!, class-clear-flags!, class-has-flags?)
(class?, instance?): New definitions.
(<class>): Add GOOPS metaclass flags from Scheme.
(<applicable-struct-class>, <applicable-struct-with-setter-class>):
Add flags from Scheme.
(make, initialize): Add class flags as appropriate.
(class-redefinition): Clear the "valid" flag on the old class.
(check-slot-args): Use instance? instead of a CPL check.
2015-01-16 11:26:25 +01:00
|
|
|
|
;;;
|
|
|
|
|
|
;;; Structs that are vtables have a "flags" slot, which corresponds to
|
|
|
|
|
|
;;; class-index-flags. `vtable-flag-vtable' indicates that instances of
|
|
|
|
|
|
;;; a vtable are themselves vtables, and `vtable-flag-validated'
|
|
|
|
|
|
;;; indicates that the struct's layout has been validated. goops.c
|
|
|
|
|
|
;;; defines a couple of additional flags: one to indicate that a vtable
|
|
|
|
|
|
;;; is actually a class, and one to indicate that the class is "valid",
|
|
|
|
|
|
;;; meaning that it hasn't been redefined.
|
|
|
|
|
|
;;;
|
|
|
|
|
|
(define vtable-flag-goops-metaclass
|
|
|
|
|
|
(logior vtable-flag-vtable vtable-flag-goops-class))
|
|
|
|
|
|
|
|
|
|
|
|
(define-inlinable (class-add-flags! class flags)
|
|
|
|
|
|
(struct-set! class class-index-flags
|
|
|
|
|
|
(logior flags (struct-ref class class-index-flags))))
|
|
|
|
|
|
|
|
|
|
|
|
(define-inlinable (class-clear-flags! class flags)
|
|
|
|
|
|
(struct-set! class class-index-flags
|
|
|
|
|
|
(logand (lognot flags) (struct-ref class class-index-flags))))
|
|
|
|
|
|
|
|
|
|
|
|
(define-inlinable (class-has-flags? class flags)
|
|
|
|
|
|
(eqv? flags
|
|
|
|
|
|
(logand (struct-ref class class-index-flags) flags)))
|
|
|
|
|
|
|
|
|
|
|
|
(define-inlinable (class? obj)
|
|
|
|
|
|
(class-has-flags? (struct-vtable obj) vtable-flag-goops-metaclass))
|
|
|
|
|
|
|
|
|
|
|
|
(define-inlinable (instance? obj)
|
|
|
|
|
|
(class-has-flags? (struct-vtable obj) vtable-flag-goops-class))
|
|
|
|
|
|
|
2015-01-13 23:04:57 +01:00
|
|
|
|
;;;
|
|
|
|
|
|
;;; Now that we know the slots that must be present in classes, and
|
|
|
|
|
|
;;; their offsets, we can create the root of the class hierarchy.
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; Note that the `direct-supers', `direct-slots', `cpl', `slots', and
|
|
|
|
|
|
;;; `getters-n-setters' fields will be updated later, once we have
|
|
|
|
|
|
;;; definitions for the specialized slot types like <read-only-slot> and
|
|
|
|
|
|
;;; once we have definitions for <top> and <object>.
|
|
|
|
|
|
;;;
|
|
|
|
|
|
(define <class>
|
|
|
|
|
|
(let-syntax ((cons-layout
|
|
|
|
|
|
;; A simple way to compute class layout for the concrete
|
|
|
|
|
|
;; types used in <class>.
|
|
|
|
|
|
(syntax-rules (<protected-read-only-slot>
|
|
|
|
|
|
<self-slot>
|
|
|
|
|
|
<hidden-slot>
|
|
|
|
|
|
<protected-hidden-slot>)
|
|
|
|
|
|
((_ (name) tail)
|
|
|
|
|
|
(string-append "pw" tail))
|
|
|
|
|
|
((_ (name <protected-read-only-slot>) tail)
|
|
|
|
|
|
(string-append "pr" tail))
|
|
|
|
|
|
((_ (name <self-slot>) tail)
|
|
|
|
|
|
(string-append "sr" tail))
|
|
|
|
|
|
((_ (name <hidden-slot>) tail)
|
|
|
|
|
|
(string-append "uh" tail))
|
|
|
|
|
|
((_ (name <protected-hidden-slot>) tail)
|
|
|
|
|
|
(string-append "ph" tail))))
|
|
|
|
|
|
(cons-slot
|
|
|
|
|
|
(syntax-rules ()
|
|
|
|
|
|
((_ (name) tail) (cons (list 'name) tail))
|
|
|
|
|
|
((_ (name class) tail) (cons (list 'name) tail)))))
|
|
|
|
|
|
(let* ((layout (fold-class-slots macro-fold-right cons-layout ""))
|
|
|
|
|
|
(slots (fold-class-slots macro-fold-right cons-slot '()))
|
Manipulate GOOPS vtable flags from Scheme, for speed
* libguile/goops.h: Remove unimplemented declarations of
scm_make_next_method, scm_sys_invalidate_method_cache_x, and
stklos_version.
(scm_sys_invalidate_class_x): Remove helper definition. This was
exported in the past but shouldn't have been.
* libguile/goops.c (scm_sys_make_vtable_vtable): Rename from
scm_sys_make_root_class, and don't do anything about flags.
(scm_sys_bless_applicable_struct_vtables_x, scm_class_p)
(scm_sys_invalidate_class_x): Remove; we do these in Scheme now.
(scm_init_goops_builtins): Define Scheme values for vtable flags.
* module/oop/goops.scm (vtable-flag-goops-metaclass)
(class-add-flags!, class-clear-flags!, class-has-flags?)
(class?, instance?): New definitions.
(<class>): Add GOOPS metaclass flags from Scheme.
(<applicable-struct-class>, <applicable-struct-with-setter-class>):
Add flags from Scheme.
(make, initialize): Add class flags as appropriate.
(class-redefinition): Clear the "valid" flag on the old class.
(check-slot-args): Use instance? instead of a CPL check.
2015-01-16 11:26:25 +01:00
|
|
|
|
(<class> (%make-vtable-vtable layout)))
|
|
|
|
|
|
(class-add-flags! <class> (logior vtable-flag-goops-class
|
|
|
|
|
|
vtable-flag-goops-valid))
|
2015-01-13 23:04:57 +01:00
|
|
|
|
(struct-set! <class> class-index-name '<class>)
|
|
|
|
|
|
(struct-set! <class> class-index-nfields (length slots))
|
|
|
|
|
|
(struct-set! <class> class-index-direct-supers '())
|
|
|
|
|
|
(struct-set! <class> class-index-direct-slots slots)
|
|
|
|
|
|
(struct-set! <class> class-index-direct-subclasses '())
|
|
|
|
|
|
(struct-set! <class> class-index-direct-methods '())
|
|
|
|
|
|
(struct-set! <class> class-index-cpl '())
|
|
|
|
|
|
(struct-set! <class> class-index-slots slots)
|
|
|
|
|
|
(struct-set! <class> class-index-getters-n-setters '())
|
|
|
|
|
|
(struct-set! <class> class-index-redefined #f)
|
|
|
|
|
|
<class>)))
|
Move GOOPS boot to Scheme
* module/oop/goops.scm (build-<class>-slots): New helper, replacing
build_class_class_slots.
(build-slots-list, %compute-getters-n-setters, %compute-layout): New
private helpers, moved here from C.
(%prep-layout!): Reimplement in Scheme.
(make-standard-class): New private helper, replacing
scm_basic_make_class.
(<class>, <top>, <object>): Define in Scheme.
(<foreign-slot>, <protected-slot>, <hidden-slot>, <opaque-slot>,
<read-only-slot>, <self-slot>, <protected-opaque-slot>,
<protected-hidden-slot>, <protected-read-only-slot>, <scm-slot>,
<int-slot>, <float-slot>, <double-slot>, <procedure-class>,
<applicable-struct-class>, <method>, <accessor-method>, <applicable>,
<applicable-struct>, <generic>, <extended-generic>,
<generic-with-setter>, <accessor>, <extended-generic-with-setter>,
<extended-accessor>): Define in Scheme.
(<boolean>, <char>, <list>, <pair>, <null>, <string>, <symbol>,
<vector>, <foreign>, <hashtable>, <fluid>, <dynamic-state>, <frame>,
<vm-continuation>, <bytevector>, <uvec>, <array>, <bitvector>,
<number>, <complex>, <real>, <integer>, <fraction>, <keyword>,
<unknown>, <procedure>, <primitive-generic>, <port>, <input-port>,
<output-port>, <input-output-port>): Define in Scheme.
(compute-slots): Use build-slots-list helper.
* libguile/goops.h:
* libguile/goops.c (scm_basic_basic_make_class, scm_sys_compute_slots)
(scm_sys_prep_layout_x): Remove. These were available to C, but were
undocumented internals that were dangerous, confusing, and
unnecessary.
* libguile/goops.c: Add note about variable versus value references.
Remove internal C routines that were just used during boot, as they
have been moved to Scheme.
(scm_basic_make_class): Change to call out to make-standard-class in
Scheme.
(scm_sys_make_root_class, scm_sys_bless_applicable_struct_vtable_x)
(scm_sys_bless_pure_generic_vtable_x, scm_sys_init_layout_x): New
private helpers.
(scm_sys_goops_early_init): Change to capture values defined in
Scheme.
2015-01-04 13:41:09 -05:00
|
|
|
|
|
2015-01-13 23:04:57 +01:00
|
|
|
|
;;;
|
|
|
|
|
|
;;; Accessors to fields of <class>.
|
|
|
|
|
|
;;;
|
<class> accessors implemented in Scheme
* libguile/goops.c (scm_class_p): New internal helper, exported to
goops.scm.
(scm_class_name, scm_class_direct_supers, scm_class_direct_slots):
(scm_class_direct_subclasses, scm_class_direct_methods):
(scm_class_precedence_list, scm_class_slots): Dispatch to Scheme.
(scm_sys_goops_early_init): Capture <class> accessors.
* module/oop/goops.scm (define-class-accessor): New helper.
(class-name, class-direct-supers, class-direct-slots):
(class-direct-subclasses, class-direct-methods)
(class-precedence-list, class-slots): Define in Scheme.
(compute-std-cpl, compute-cpl): Move lower.
2015-01-09 21:01:03 +01:00
|
|
|
|
(define-syntax-rule (define-class-accessor name docstring field)
|
|
|
|
|
|
(define (name obj)
|
|
|
|
|
|
docstring
|
|
|
|
|
|
(let ((val obj))
|
|
|
|
|
|
(unless (class? val)
|
|
|
|
|
|
(scm-error 'wrong-type-arg #f "Not a class: ~S"
|
|
|
|
|
|
(list val) #f))
|
|
|
|
|
|
(struct-ref val field))))
|
|
|
|
|
|
|
|
|
|
|
|
(define-class-accessor class-name
|
|
|
|
|
|
"Return the class name of @var{obj}."
|
|
|
|
|
|
class-index-name)
|
|
|
|
|
|
(define-class-accessor class-direct-supers
|
|
|
|
|
|
"Return the direct superclasses of the class @var{obj}."
|
|
|
|
|
|
class-index-direct-supers)
|
|
|
|
|
|
(define-class-accessor class-direct-slots
|
|
|
|
|
|
"Return the direct slots of the class @var{obj}."
|
|
|
|
|
|
class-index-direct-slots)
|
|
|
|
|
|
(define-class-accessor class-direct-subclasses
|
|
|
|
|
|
"Return the direct subclasses of the class @var{obj}."
|
|
|
|
|
|
class-index-direct-subclasses)
|
|
|
|
|
|
(define-class-accessor class-direct-methods
|
|
|
|
|
|
"Return the direct methods of the class @var{obj}."
|
|
|
|
|
|
class-index-direct-methods)
|
|
|
|
|
|
(define-class-accessor class-precedence-list
|
|
|
|
|
|
"Return the class precedence list of the class @var{obj}."
|
|
|
|
|
|
class-index-cpl)
|
|
|
|
|
|
(define-class-accessor class-slots
|
|
|
|
|
|
"Return the slot list of the class @var{obj}."
|
|
|
|
|
|
class-index-slots)
|
|
|
|
|
|
|
2015-01-12 21:16:25 +01:00
|
|
|
|
(define (class-subclasses c)
|
2015-01-13 23:04:57 +01:00
|
|
|
|
"Compute a list of all subclasses of @var{c}, direct and indirect."
|
2015-01-12 21:16:25 +01:00
|
|
|
|
(define (all-subclasses c)
|
|
|
|
|
|
(cons c (append-map all-subclasses
|
|
|
|
|
|
(class-direct-subclasses c))))
|
|
|
|
|
|
(delete-duplicates (cdr (all-subclasses c)) eq?))
|
|
|
|
|
|
|
|
|
|
|
|
(define (class-methods c)
|
2015-01-13 23:04:57 +01:00
|
|
|
|
"Compute a list of all methods that specialize on @var{c} or
|
|
|
|
|
|
subclasses of @var{c}."
|
2015-01-12 21:16:25 +01:00
|
|
|
|
(delete-duplicates (append-map class-direct-methods
|
|
|
|
|
|
(cons c (class-subclasses c)))
|
|
|
|
|
|
eq?))
|
|
|
|
|
|
|
2015-01-13 23:04:57 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; The "getters-n-setters" define how to access slot values for a
|
|
|
|
|
|
;;; particular class. In general, there are many ways to access slot
|
|
|
|
|
|
;;; values, but for standard classes it's pretty easy: each slot is
|
|
|
|
|
|
;;; associated with a field in the object.
|
|
|
|
|
|
;;;
|
|
|
|
|
|
(define (%compute-getters-n-setters slots)
|
|
|
|
|
|
(define (compute-init-thunk options)
|
|
|
|
|
|
(cond
|
|
|
|
|
|
((kw-arg-ref options #:init-value) => (lambda (val) (lambda () val)))
|
|
|
|
|
|
((kw-arg-ref options #:init-thunk))
|
|
|
|
|
|
(else #f)))
|
|
|
|
|
|
(let lp ((slots slots) (n 0))
|
|
|
|
|
|
(match slots
|
|
|
|
|
|
(() '())
|
|
|
|
|
|
(((name . options) . slots)
|
|
|
|
|
|
(let ((init-thunk (compute-init-thunk options)))
|
|
|
|
|
|
(cons `(,name ,init-thunk . ,n)
|
|
|
|
|
|
(lp slots (1+ n))))))))
|
|
|
|
|
|
|
|
|
|
|
|
(struct-set! <class> class-index-getters-n-setters
|
|
|
|
|
|
(%compute-getters-n-setters (class-slots <class>)))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; At this point, we have <class> but no other objects. We need to
|
|
|
|
|
|
;;; define a standard way to make subclasses: how to compute the
|
|
|
|
|
|
;;; precedence list of subclasses, how to compute the list of slots in a
|
|
|
|
|
|
;;; subclass, and what layout to use for instances of those classes.
|
|
|
|
|
|
;;;
|
2015-01-10 00:50:33 +01:00
|
|
|
|
|
<class> accessors implemented in Scheme
* libguile/goops.c (scm_class_p): New internal helper, exported to
goops.scm.
(scm_class_name, scm_class_direct_supers, scm_class_direct_slots):
(scm_class_direct_subclasses, scm_class_direct_methods):
(scm_class_precedence_list, scm_class_slots): Dispatch to Scheme.
(scm_sys_goops_early_init): Capture <class> accessors.
* module/oop/goops.scm (define-class-accessor): New helper.
(class-name, class-direct-supers, class-direct-slots):
(class-direct-subclasses, class-direct-methods)
(class-precedence-list, class-slots): Define in Scheme.
(compute-std-cpl, compute-cpl): Move lower.
2015-01-09 21:01:03 +01:00
|
|
|
|
(define (compute-std-cpl c get-direct-supers)
|
2015-01-13 21:07:42 +01:00
|
|
|
|
"The standard class precedence list computation algorithm."
|
<class> accessors implemented in Scheme
* libguile/goops.c (scm_class_p): New internal helper, exported to
goops.scm.
(scm_class_name, scm_class_direct_supers, scm_class_direct_slots):
(scm_class_direct_subclasses, scm_class_direct_methods):
(scm_class_precedence_list, scm_class_slots): Dispatch to Scheme.
(scm_sys_goops_early_init): Capture <class> accessors.
* module/oop/goops.scm (define-class-accessor): New helper.
(class-name, class-direct-supers, class-direct-slots):
(class-direct-subclasses, class-direct-methods)
(class-precedence-list, class-slots): Define in Scheme.
(compute-std-cpl, compute-cpl): Move lower.
2015-01-09 21:01:03 +01:00
|
|
|
|
(define (only-non-null lst)
|
|
|
|
|
|
(filter (lambda (l) (not (null? l))) lst))
|
|
|
|
|
|
|
|
|
|
|
|
(define (merge-lists reversed-partial-result inputs)
|
|
|
|
|
|
(cond
|
|
|
|
|
|
((every null? inputs)
|
|
|
|
|
|
(reverse! reversed-partial-result))
|
|
|
|
|
|
(else
|
|
|
|
|
|
(let* ((candidate (lambda (c)
|
|
|
|
|
|
(and (not (any (lambda (l)
|
|
|
|
|
|
(memq c (cdr l)))
|
|
|
|
|
|
inputs))
|
|
|
|
|
|
c)))
|
|
|
|
|
|
(candidate-car (lambda (l)
|
|
|
|
|
|
(and (not (null? l))
|
|
|
|
|
|
(candidate (car l)))))
|
|
|
|
|
|
(next (any candidate-car inputs)))
|
2015-01-14 20:06:35 +01:00
|
|
|
|
(unless next
|
|
|
|
|
|
(goops-error "merge-lists: Inconsistent precedence graph"))
|
<class> accessors implemented in Scheme
* libguile/goops.c (scm_class_p): New internal helper, exported to
goops.scm.
(scm_class_name, scm_class_direct_supers, scm_class_direct_slots):
(scm_class_direct_subclasses, scm_class_direct_methods):
(scm_class_precedence_list, scm_class_slots): Dispatch to Scheme.
(scm_sys_goops_early_init): Capture <class> accessors.
* module/oop/goops.scm (define-class-accessor): New helper.
(class-name, class-direct-supers, class-direct-slots):
(class-direct-subclasses, class-direct-methods)
(class-precedence-list, class-slots): Define in Scheme.
(compute-std-cpl, compute-cpl): Move lower.
2015-01-09 21:01:03 +01:00
|
|
|
|
(let ((remove-next (lambda (l)
|
|
|
|
|
|
(if (eq? (car l) next)
|
|
|
|
|
|
(cdr l)
|
|
|
|
|
|
l))))
|
|
|
|
|
|
(merge-lists (cons next reversed-partial-result)
|
|
|
|
|
|
(only-non-null (map remove-next inputs))))))))
|
|
|
|
|
|
(let ((c-direct-supers (get-direct-supers c)))
|
|
|
|
|
|
(merge-lists (list c)
|
|
|
|
|
|
(only-non-null (append (map class-precedence-list
|
|
|
|
|
|
c-direct-supers)
|
|
|
|
|
|
(list c-direct-supers))))))
|
|
|
|
|
|
|
2015-01-13 21:07:42 +01:00
|
|
|
|
;; This version of compute-cpl is replaced with a generic function once
|
|
|
|
|
|
;; GOOPS has booted.
|
<class> accessors implemented in Scheme
* libguile/goops.c (scm_class_p): New internal helper, exported to
goops.scm.
(scm_class_name, scm_class_direct_supers, scm_class_direct_slots):
(scm_class_direct_subclasses, scm_class_direct_methods):
(scm_class_precedence_list, scm_class_slots): Dispatch to Scheme.
(scm_sys_goops_early_init): Capture <class> accessors.
* module/oop/goops.scm (define-class-accessor): New helper.
(class-name, class-direct-supers, class-direct-slots):
(class-direct-subclasses, class-direct-methods)
(class-precedence-list, class-slots): Define in Scheme.
(compute-std-cpl, compute-cpl): Move lower.
2015-01-09 21:01:03 +01:00
|
|
|
|
(define (compute-cpl class)
|
|
|
|
|
|
(compute-std-cpl class class-direct-supers))
|
|
|
|
|
|
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(define (build-slots-list dslots cpl)
|
|
|
|
|
|
(define (check-cpl slots class-slots)
|
2015-01-14 20:06:35 +01:00
|
|
|
|
(when (or-map (match-lambda ((name . options) (assq name slots)))
|
2015-01-04 15:52:12 -05:00
|
|
|
|
class-slots)
|
|
|
|
|
|
(scm-error 'misc-error #f
|
|
|
|
|
|
"a predefined <class> inherited field cannot be redefined"
|
|
|
|
|
|
'() '())))
|
|
|
|
|
|
(define (remove-duplicate-slots slots)
|
|
|
|
|
|
(let lp ((slots (reverse slots)) (res '()) (seen '()))
|
2015-01-14 20:15:53 +01:00
|
|
|
|
(match slots
|
|
|
|
|
|
(() res)
|
|
|
|
|
|
(((and slot (name . options)) . slots)
|
|
|
|
|
|
(if (memq name seen)
|
|
|
|
|
|
(lp slots res seen)
|
|
|
|
|
|
(lp slots (cons slot res) (cons name seen)))))))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(let* ((class-slots (and (memq <class> cpl)
|
|
|
|
|
|
(struct-ref <class> class-index-slots))))
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(when class-slots
|
|
|
|
|
|
(check-cpl dslots class-slots))
|
|
|
|
|
|
(let lp ((cpl (cdr cpl)) (res dslots) (class-slots '()))
|
2015-01-14 20:15:53 +01:00
|
|
|
|
(match cpl
|
|
|
|
|
|
(() (remove-duplicate-slots (append class-slots res)))
|
|
|
|
|
|
((head . cpl)
|
|
|
|
|
|
(let ((new-slots (struct-ref head class-index-direct-slots)))
|
|
|
|
|
|
(cond
|
|
|
|
|
|
((not class-slots)
|
|
|
|
|
|
(lp cpl (append new-slots res) class-slots))
|
|
|
|
|
|
((eq? head <class>)
|
|
|
|
|
|
;; Move class slots to the head of the list.
|
|
|
|
|
|
(lp cpl res new-slots))
|
|
|
|
|
|
(else
|
|
|
|
|
|
(check-cpl new-slots class-slots)
|
|
|
|
|
|
(lp cpl (append new-slots res) class-slots)))))))))
|
Move GOOPS boot to Scheme
* module/oop/goops.scm (build-<class>-slots): New helper, replacing
build_class_class_slots.
(build-slots-list, %compute-getters-n-setters, %compute-layout): New
private helpers, moved here from C.
(%prep-layout!): Reimplement in Scheme.
(make-standard-class): New private helper, replacing
scm_basic_make_class.
(<class>, <top>, <object>): Define in Scheme.
(<foreign-slot>, <protected-slot>, <hidden-slot>, <opaque-slot>,
<read-only-slot>, <self-slot>, <protected-opaque-slot>,
<protected-hidden-slot>, <protected-read-only-slot>, <scm-slot>,
<int-slot>, <float-slot>, <double-slot>, <procedure-class>,
<applicable-struct-class>, <method>, <accessor-method>, <applicable>,
<applicable-struct>, <generic>, <extended-generic>,
<generic-with-setter>, <accessor>, <extended-generic-with-setter>,
<extended-accessor>): Define in Scheme.
(<boolean>, <char>, <list>, <pair>, <null>, <string>, <symbol>,
<vector>, <foreign>, <hashtable>, <fluid>, <dynamic-state>, <frame>,
<vm-continuation>, <bytevector>, <uvec>, <array>, <bitvector>,
<number>, <complex>, <real>, <integer>, <fraction>, <keyword>,
<unknown>, <procedure>, <primitive-generic>, <port>, <input-port>,
<output-port>, <input-output-port>): Define in Scheme.
(compute-slots): Use build-slots-list helper.
* libguile/goops.h:
* libguile/goops.c (scm_basic_basic_make_class, scm_sys_compute_slots)
(scm_sys_prep_layout_x): Remove. These were available to C, but were
undocumented internals that were dangerous, confusing, and
unnecessary.
* libguile/goops.c: Add note about variable versus value references.
Remove internal C routines that were just used during boot, as they
have been moved to Scheme.
(scm_basic_make_class): Change to call out to make-standard-class in
Scheme.
(scm_sys_make_root_class, scm_sys_bless_applicable_struct_vtable_x)
(scm_sys_bless_pure_generic_vtable_x, scm_sys_init_layout_x): New
private helpers.
(scm_sys_goops_early_init): Change to capture values defined in
Scheme.
2015-01-04 13:41:09 -05:00
|
|
|
|
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(define (%compute-layout slots getters-n-setters nfields is-class?)
|
|
|
|
|
|
(define (instance-allocated? g-n-s)
|
|
|
|
|
|
(match g-n-s
|
|
|
|
|
|
((name init-thunk . (? exact-integer? index)) #t)
|
|
|
|
|
|
((name init-thunk getter setter index size) #t)
|
|
|
|
|
|
(_ #f)))
|
|
|
|
|
|
|
|
|
|
|
|
(define (allocated-index g-n-s)
|
|
|
|
|
|
(match g-n-s
|
|
|
|
|
|
((name init-thunk . (? exact-integer? index)) index)
|
|
|
|
|
|
((name init-thunk getter setter index size) index)))
|
|
|
|
|
|
|
|
|
|
|
|
(define (allocated-size g-n-s)
|
|
|
|
|
|
(match g-n-s
|
|
|
|
|
|
((name init-thunk . (? exact-integer? index)) 1)
|
|
|
|
|
|
((name init-thunk getter setter index size) size)))
|
|
|
|
|
|
|
|
|
|
|
|
(define (slot-protection-and-kind options)
|
|
|
|
|
|
(define (subclass? class parent)
|
|
|
|
|
|
(memq parent (class-precedence-list class)))
|
|
|
|
|
|
(let ((type (kw-arg-ref options #:class)))
|
|
|
|
|
|
(if (and type (subclass? type <foreign-slot>))
|
|
|
|
|
|
(values (cond
|
|
|
|
|
|
((subclass? type <self-slot>) #\s)
|
|
|
|
|
|
((subclass? type <protected-slot>) #\p)
|
|
|
|
|
|
(else #\u))
|
|
|
|
|
|
(cond
|
|
|
|
|
|
((subclass? type <opaque-slot>) #\o)
|
|
|
|
|
|
((subclass? type <read-only-slot>) #\r)
|
|
|
|
|
|
((subclass? type <hidden-slot>) #\h)
|
|
|
|
|
|
(else #\w)))
|
|
|
|
|
|
(values #\p #\w))))
|
|
|
|
|
|
|
|
|
|
|
|
(let ((layout (make-string (* nfields 2))))
|
|
|
|
|
|
(let lp ((n 0) (slots slots) (getters-n-setters getters-n-setters))
|
|
|
|
|
|
(match getters-n-setters
|
|
|
|
|
|
(()
|
|
|
|
|
|
(unless (= n nfields) (error "bad nfields"))
|
|
|
|
|
|
(unless (null? slots) (error "inconsistent g-n-s/slots"))
|
|
|
|
|
|
(when is-class?
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(let ((class-layout (struct-ref <class> class-index-layout)))
|
|
|
|
|
|
(unless (string-prefix? (symbol->string class-layout) layout)
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(error "bad layout for class"))))
|
|
|
|
|
|
layout)
|
|
|
|
|
|
((g-n-s . getters-n-setters)
|
|
|
|
|
|
(match slots
|
|
|
|
|
|
(((name . options) . slots)
|
|
|
|
|
|
(cond
|
|
|
|
|
|
((instance-allocated? g-n-s)
|
|
|
|
|
|
(unless (< n nfields) (error "bad nfields"))
|
|
|
|
|
|
(unless (= n (allocated-index g-n-s)) (error "bad allocation"))
|
|
|
|
|
|
(call-with-values (lambda () (slot-protection-and-kind options))
|
|
|
|
|
|
(lambda (protection kind)
|
|
|
|
|
|
(let init ((n n) (size (allocated-size g-n-s)))
|
Move GOOPS boot to Scheme
* module/oop/goops.scm (build-<class>-slots): New helper, replacing
build_class_class_slots.
(build-slots-list, %compute-getters-n-setters, %compute-layout): New
private helpers, moved here from C.
(%prep-layout!): Reimplement in Scheme.
(make-standard-class): New private helper, replacing
scm_basic_make_class.
(<class>, <top>, <object>): Define in Scheme.
(<foreign-slot>, <protected-slot>, <hidden-slot>, <opaque-slot>,
<read-only-slot>, <self-slot>, <protected-opaque-slot>,
<protected-hidden-slot>, <protected-read-only-slot>, <scm-slot>,
<int-slot>, <float-slot>, <double-slot>, <procedure-class>,
<applicable-struct-class>, <method>, <accessor-method>, <applicable>,
<applicable-struct>, <generic>, <extended-generic>,
<generic-with-setter>, <accessor>, <extended-generic-with-setter>,
<extended-accessor>): Define in Scheme.
(<boolean>, <char>, <list>, <pair>, <null>, <string>, <symbol>,
<vector>, <foreign>, <hashtable>, <fluid>, <dynamic-state>, <frame>,
<vm-continuation>, <bytevector>, <uvec>, <array>, <bitvector>,
<number>, <complex>, <real>, <integer>, <fraction>, <keyword>,
<unknown>, <procedure>, <primitive-generic>, <port>, <input-port>,
<output-port>, <input-output-port>): Define in Scheme.
(compute-slots): Use build-slots-list helper.
* libguile/goops.h:
* libguile/goops.c (scm_basic_basic_make_class, scm_sys_compute_slots)
(scm_sys_prep_layout_x): Remove. These were available to C, but were
undocumented internals that were dangerous, confusing, and
unnecessary.
* libguile/goops.c: Add note about variable versus value references.
Remove internal C routines that were just used during boot, as they
have been moved to Scheme.
(scm_basic_make_class): Change to call out to make-standard-class in
Scheme.
(scm_sys_make_root_class, scm_sys_bless_applicable_struct_vtable_x)
(scm_sys_bless_pure_generic_vtable_x, scm_sys_init_layout_x): New
private helpers.
(scm_sys_goops_early_init): Change to capture values defined in
Scheme.
2015-01-04 13:41:09 -05:00
|
|
|
|
(cond
|
2015-01-04 15:52:12 -05:00
|
|
|
|
((zero? size) (lp n slots getters-n-setters))
|
|
|
|
|
|
(else
|
|
|
|
|
|
(string-set! layout (* n 2) protection)
|
|
|
|
|
|
(string-set! layout (1+ (* n 2)) kind)
|
|
|
|
|
|
(init (1+ n) (1- size))))))))
|
|
|
|
|
|
(else
|
|
|
|
|
|
(lp n slots getters-n-setters))))))))))
|
|
|
|
|
|
|
2015-01-13 23:04:57 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; With all of this, we are now able to define subclasses of <class>.
|
|
|
|
|
|
;;;
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(define (%prep-layout! class)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(let* ((is-class? (and (memq <class> (struct-ref class class-index-cpl)) #t))
|
|
|
|
|
|
(layout (%compute-layout
|
|
|
|
|
|
(struct-ref class class-index-slots)
|
|
|
|
|
|
(struct-ref class class-index-getters-n-setters)
|
|
|
|
|
|
(struct-ref class class-index-nfields)
|
|
|
|
|
|
is-class?)))
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(%init-layout! class layout)))
|
|
|
|
|
|
|
|
|
|
|
|
(define (make-standard-class class name dsupers dslots)
|
|
|
|
|
|
(let ((z (make-struct/no-tail class)))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(struct-set! z class-index-direct-supers dsupers)
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(let* ((cpl (compute-cpl z))
|
|
|
|
|
|
(dslots (map (lambda (slot)
|
|
|
|
|
|
(if (pair? slot) slot (list slot)))
|
|
|
|
|
|
dslots))
|
|
|
|
|
|
(slots (build-slots-list dslots cpl))
|
|
|
|
|
|
(nfields (length slots))
|
|
|
|
|
|
(g-n-s (%compute-getters-n-setters slots)))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(struct-set! z class-index-name name)
|
2015-01-11 16:36:45 +01:00
|
|
|
|
(struct-set! z class-index-nfields nfields)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(struct-set! z class-index-direct-slots dslots)
|
|
|
|
|
|
(struct-set! z class-index-direct-subclasses '())
|
|
|
|
|
|
(struct-set! z class-index-direct-methods '())
|
|
|
|
|
|
(struct-set! z class-index-cpl cpl)
|
|
|
|
|
|
(struct-set! z class-index-slots slots)
|
|
|
|
|
|
(struct-set! z class-index-getters-n-setters g-n-s)
|
|
|
|
|
|
(struct-set! z class-index-redefined #f)
|
2015-01-14 20:15:53 +01:00
|
|
|
|
(for-each
|
|
|
|
|
|
(lambda (super)
|
|
|
|
|
|
(let ((subclasses (struct-ref super class-index-direct-subclasses)))
|
|
|
|
|
|
(struct-set! super class-index-direct-subclasses
|
|
|
|
|
|
(cons z subclasses))))
|
|
|
|
|
|
dsupers)
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(%prep-layout! z)
|
|
|
|
|
|
z)))
|
|
|
|
|
|
|
|
|
|
|
|
(define-syntax define-standard-class
|
|
|
|
|
|
(syntax-rules ()
|
|
|
|
|
|
((define-standard-class name (super ...) #:metaclass meta slot ...)
|
|
|
|
|
|
(define name
|
|
|
|
|
|
(make-standard-class meta 'name (list super ...) '(slot ...))))
|
|
|
|
|
|
((define-standard-class name (super ...) slot ...)
|
|
|
|
|
|
(define-standard-class name (super ...) #:metaclass <class> slot ...))))
|
|
|
|
|
|
|
2015-01-13 23:04:57 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; Sweet! Now we can define <top> and <object>, and finish
|
|
|
|
|
|
;;; initializing the `direct-subclasses', `direct-supers', and `cpl'
|
|
|
|
|
|
;;; slots of <class>.
|
|
|
|
|
|
;;;
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(define-standard-class <top> ())
|
|
|
|
|
|
(define-standard-class <object> (<top>))
|
|
|
|
|
|
|
|
|
|
|
|
;; <top>, <object>, and <class> were partially initialized. Correct
|
|
|
|
|
|
;; them here.
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(struct-set! <object> class-index-direct-subclasses (list <class>))
|
|
|
|
|
|
(struct-set! <class> class-index-direct-supers (list <object>))
|
|
|
|
|
|
(struct-set! <class> class-index-cpl (list <class> <object> <top>))
|
2015-01-04 15:52:12 -05:00
|
|
|
|
|
2015-01-13 23:04:57 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; We can also define the various slot types, and finish initializing
|
|
|
|
|
|
;;; `direct-slots', `slots', and `getters-n-setters' of <class>.
|
|
|
|
|
|
;;;
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(define-standard-class <foreign-slot> (<top>))
|
|
|
|
|
|
(define-standard-class <protected-slot> (<foreign-slot>))
|
|
|
|
|
|
(define-standard-class <hidden-slot> (<foreign-slot>))
|
|
|
|
|
|
(define-standard-class <opaque-slot> (<foreign-slot>))
|
|
|
|
|
|
(define-standard-class <read-only-slot> (<foreign-slot>))
|
|
|
|
|
|
(define-standard-class <self-slot> (<read-only-slot>))
|
|
|
|
|
|
(define-standard-class <protected-opaque-slot> (<protected-slot>
|
|
|
|
|
|
<opaque-slot>))
|
|
|
|
|
|
(define-standard-class <protected-hidden-slot> (<protected-slot>
|
|
|
|
|
|
<hidden-slot>))
|
|
|
|
|
|
(define-standard-class <protected-read-only-slot> (<protected-slot>
|
|
|
|
|
|
<read-only-slot>))
|
|
|
|
|
|
(define-standard-class <scm-slot> (<protected-slot>))
|
|
|
|
|
|
(define-standard-class <int-slot> (<foreign-slot>))
|
|
|
|
|
|
(define-standard-class <float-slot> (<foreign-slot>))
|
|
|
|
|
|
(define-standard-class <double-slot> (<foreign-slot>))
|
|
|
|
|
|
|
2015-01-07 18:42:27 -05:00
|
|
|
|
(let-syntax ((visit
|
|
|
|
|
|
(syntax-rules ()
|
|
|
|
|
|
((_ (name) tail)
|
|
|
|
|
|
(cons (list 'name) tail))
|
|
|
|
|
|
((_ (name class) tail)
|
|
|
|
|
|
(cons (list 'name #:class class) tail)))))
|
2015-01-13 23:04:57 +01:00
|
|
|
|
(let* ((dslots (fold-class-slots macro-fold-right visit '()))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(g-n-s (%compute-getters-n-setters dslots)))
|
|
|
|
|
|
(struct-set! <class> class-index-direct-slots dslots)
|
|
|
|
|
|
(struct-set! <class> class-index-slots dslots)
|
|
|
|
|
|
(struct-set! <class> class-index-getters-n-setters g-n-s)))
|
2015-01-04 15:52:12 -05:00
|
|
|
|
|
2015-01-13 23:04:57 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; Now, to build out the class hierarchy.
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(define-standard-class <procedure-class> (<class>))
|
Manipulate GOOPS vtable flags from Scheme, for speed
* libguile/goops.h: Remove unimplemented declarations of
scm_make_next_method, scm_sys_invalidate_method_cache_x, and
stklos_version.
(scm_sys_invalidate_class_x): Remove helper definition. This was
exported in the past but shouldn't have been.
* libguile/goops.c (scm_sys_make_vtable_vtable): Rename from
scm_sys_make_root_class, and don't do anything about flags.
(scm_sys_bless_applicable_struct_vtables_x, scm_class_p)
(scm_sys_invalidate_class_x): Remove; we do these in Scheme now.
(scm_init_goops_builtins): Define Scheme values for vtable flags.
* module/oop/goops.scm (vtable-flag-goops-metaclass)
(class-add-flags!, class-clear-flags!, class-has-flags?)
(class?, instance?): New definitions.
(<class>): Add GOOPS metaclass flags from Scheme.
(<applicable-struct-class>, <applicable-struct-with-setter-class>):
Add flags from Scheme.
(make, initialize): Add class flags as appropriate.
(class-redefinition): Clear the "valid" flag on the old class.
(check-slot-args): Use instance? instead of a CPL check.
2015-01-16 11:26:25 +01:00
|
|
|
|
|
Generics with setters have <applicable-struct-with-setter> layout
* libguile/goops.c (scm_sys_set_object_setter_x): Remove. Instead, we
use slot-set! of 'setter.
(scm_i_define_class_for_vtable): Move lower in the file, and fold in
scm_make_extended_class_from_symbol and make_class_from_symbol.
Properly handle applicable structs with setters.
(scm_class_applicable_struct_with_setter_class): New private capture.
(scm_sys_bless_applicable_struct_vtables_x): Rename to take two
arguments, and bless the second argument as an applicable struct with
setter vtable.
(scm_sys_goops_early_init): Capture setter classes.
* libguile/deprecated.c (SPEC_OF, CPL_OF): Access slots by name, not by
index.
(applicablep, more_specificp): Adapt to use CPL_OF.
(scm_find_method): Access "methods" slot by name.
* libguile/procs.c (scm_setter): Remove special case for generics; if
it's a setter, it will be a normal applicable struct.
* module/oop/goops.scm (<applicable-struct-with-setter-class>)
(<applicable-struct-with-setter>): New classes.
(<generic-with-setter>): Now an instance of the setter metaclass and a
child of the setter class, so that the "setter" slot ends up in the
right place.
(<accessor>, <extended-generic-with-setter>, <extended-accessor>): Be
instances of the setter metaclass.
(<method>, <accessor-method>): Move definitions farther down.
(make): Use slot-set! when initializing setters here.
(initialize): Likewise for <applicable-struct-with-setter>. Remove
specialization for <generic-with-setter>.
2015-01-06 13:41:56 -05:00
|
|
|
|
(define-standard-class <applicable-struct-class>
|
|
|
|
|
|
(<procedure-class>))
|
Manipulate GOOPS vtable flags from Scheme, for speed
* libguile/goops.h: Remove unimplemented declarations of
scm_make_next_method, scm_sys_invalidate_method_cache_x, and
stklos_version.
(scm_sys_invalidate_class_x): Remove helper definition. This was
exported in the past but shouldn't have been.
* libguile/goops.c (scm_sys_make_vtable_vtable): Rename from
scm_sys_make_root_class, and don't do anything about flags.
(scm_sys_bless_applicable_struct_vtables_x, scm_class_p)
(scm_sys_invalidate_class_x): Remove; we do these in Scheme now.
(scm_init_goops_builtins): Define Scheme values for vtable flags.
* module/oop/goops.scm (vtable-flag-goops-metaclass)
(class-add-flags!, class-clear-flags!, class-has-flags?)
(class?, instance?): New definitions.
(<class>): Add GOOPS metaclass flags from Scheme.
(<applicable-struct-class>, <applicable-struct-with-setter-class>):
Add flags from Scheme.
(make, initialize): Add class flags as appropriate.
(class-redefinition): Clear the "valid" flag on the old class.
(check-slot-args): Use instance? instead of a CPL check.
2015-01-16 11:26:25 +01:00
|
|
|
|
(class-add-flags! <applicable-struct-class>
|
|
|
|
|
|
vtable-flag-applicable-vtable)
|
|
|
|
|
|
|
Generics with setters have <applicable-struct-with-setter> layout
* libguile/goops.c (scm_sys_set_object_setter_x): Remove. Instead, we
use slot-set! of 'setter.
(scm_i_define_class_for_vtable): Move lower in the file, and fold in
scm_make_extended_class_from_symbol and make_class_from_symbol.
Properly handle applicable structs with setters.
(scm_class_applicable_struct_with_setter_class): New private capture.
(scm_sys_bless_applicable_struct_vtables_x): Rename to take two
arguments, and bless the second argument as an applicable struct with
setter vtable.
(scm_sys_goops_early_init): Capture setter classes.
* libguile/deprecated.c (SPEC_OF, CPL_OF): Access slots by name, not by
index.
(applicablep, more_specificp): Adapt to use CPL_OF.
(scm_find_method): Access "methods" slot by name.
* libguile/procs.c (scm_setter): Remove special case for generics; if
it's a setter, it will be a normal applicable struct.
* module/oop/goops.scm (<applicable-struct-with-setter-class>)
(<applicable-struct-with-setter>): New classes.
(<generic-with-setter>): Now an instance of the setter metaclass and a
child of the setter class, so that the "setter" slot ends up in the
right place.
(<accessor>, <extended-generic-with-setter>, <extended-accessor>): Be
instances of the setter metaclass.
(<method>, <accessor-method>): Move definitions farther down.
(make): Use slot-set! when initializing setters here.
(initialize): Likewise for <applicable-struct-with-setter>. Remove
specialization for <generic-with-setter>.
2015-01-06 13:41:56 -05:00
|
|
|
|
(define-standard-class <applicable-struct-with-setter-class>
|
|
|
|
|
|
(<applicable-struct-class>))
|
Manipulate GOOPS vtable flags from Scheme, for speed
* libguile/goops.h: Remove unimplemented declarations of
scm_make_next_method, scm_sys_invalidate_method_cache_x, and
stklos_version.
(scm_sys_invalidate_class_x): Remove helper definition. This was
exported in the past but shouldn't have been.
* libguile/goops.c (scm_sys_make_vtable_vtable): Rename from
scm_sys_make_root_class, and don't do anything about flags.
(scm_sys_bless_applicable_struct_vtables_x, scm_class_p)
(scm_sys_invalidate_class_x): Remove; we do these in Scheme now.
(scm_init_goops_builtins): Define Scheme values for vtable flags.
* module/oop/goops.scm (vtable-flag-goops-metaclass)
(class-add-flags!, class-clear-flags!, class-has-flags?)
(class?, instance?): New definitions.
(<class>): Add GOOPS metaclass flags from Scheme.
(<applicable-struct-class>, <applicable-struct-with-setter-class>):
Add flags from Scheme.
(make, initialize): Add class flags as appropriate.
(class-redefinition): Clear the "valid" flag on the old class.
(check-slot-args): Use instance? instead of a CPL check.
2015-01-16 11:26:25 +01:00
|
|
|
|
(class-add-flags! <applicable-struct-with-setter-class>
|
|
|
|
|
|
vtable-flag-setter-vtable)
|
Generics with setters have <applicable-struct-with-setter> layout
* libguile/goops.c (scm_sys_set_object_setter_x): Remove. Instead, we
use slot-set! of 'setter.
(scm_i_define_class_for_vtable): Move lower in the file, and fold in
scm_make_extended_class_from_symbol and make_class_from_symbol.
Properly handle applicable structs with setters.
(scm_class_applicable_struct_with_setter_class): New private capture.
(scm_sys_bless_applicable_struct_vtables_x): Rename to take two
arguments, and bless the second argument as an applicable struct with
setter vtable.
(scm_sys_goops_early_init): Capture setter classes.
* libguile/deprecated.c (SPEC_OF, CPL_OF): Access slots by name, not by
index.
(applicablep, more_specificp): Adapt to use CPL_OF.
(scm_find_method): Access "methods" slot by name.
* libguile/procs.c (scm_setter): Remove special case for generics; if
it's a setter, it will be a normal applicable struct.
* module/oop/goops.scm (<applicable-struct-with-setter-class>)
(<applicable-struct-with-setter>): New classes.
(<generic-with-setter>): Now an instance of the setter metaclass and a
child of the setter class, so that the "setter" slot ends up in the
right place.
(<accessor>, <extended-generic-with-setter>, <extended-accessor>): Be
instances of the setter metaclass.
(<method>, <accessor-method>): Move definitions farther down.
(make): Use slot-set! when initializing setters here.
(initialize): Likewise for <applicable-struct-with-setter>. Remove
specialization for <generic-with-setter>.
2015-01-06 13:41:56 -05:00
|
|
|
|
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(define-standard-class <applicable> (<top>))
|
|
|
|
|
|
(define-standard-class <applicable-struct> (<object> <applicable>)
|
|
|
|
|
|
#:metaclass <applicable-struct-class>
|
|
|
|
|
|
procedure)
|
Generics with setters have <applicable-struct-with-setter> layout
* libguile/goops.c (scm_sys_set_object_setter_x): Remove. Instead, we
use slot-set! of 'setter.
(scm_i_define_class_for_vtable): Move lower in the file, and fold in
scm_make_extended_class_from_symbol and make_class_from_symbol.
Properly handle applicable structs with setters.
(scm_class_applicable_struct_with_setter_class): New private capture.
(scm_sys_bless_applicable_struct_vtables_x): Rename to take two
arguments, and bless the second argument as an applicable struct with
setter vtable.
(scm_sys_goops_early_init): Capture setter classes.
* libguile/deprecated.c (SPEC_OF, CPL_OF): Access slots by name, not by
index.
(applicablep, more_specificp): Adapt to use CPL_OF.
(scm_find_method): Access "methods" slot by name.
* libguile/procs.c (scm_setter): Remove special case for generics; if
it's a setter, it will be a normal applicable struct.
* module/oop/goops.scm (<applicable-struct-with-setter-class>)
(<applicable-struct-with-setter>): New classes.
(<generic-with-setter>): Now an instance of the setter metaclass and a
child of the setter class, so that the "setter" slot ends up in the
right place.
(<accessor>, <extended-generic-with-setter>, <extended-accessor>): Be
instances of the setter metaclass.
(<method>, <accessor-method>): Move definitions farther down.
(make): Use slot-set! when initializing setters here.
(initialize): Likewise for <applicable-struct-with-setter>. Remove
specialization for <generic-with-setter>.
2015-01-06 13:41:56 -05:00
|
|
|
|
(define-standard-class <applicable-struct-with-setter> (<applicable-struct>)
|
|
|
|
|
|
#:metaclass <applicable-struct-with-setter-class>
|
|
|
|
|
|
setter)
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(define-standard-class <generic> (<applicable-struct>)
|
|
|
|
|
|
#:metaclass <applicable-struct-class>
|
|
|
|
|
|
methods
|
|
|
|
|
|
(n-specialized #:init-value 0)
|
|
|
|
|
|
(extended-by #:init-value ())
|
|
|
|
|
|
effective-methods)
|
|
|
|
|
|
(define-standard-class <extended-generic> (<generic>)
|
|
|
|
|
|
#:metaclass <applicable-struct-class>
|
|
|
|
|
|
(extends #:init-value ()))
|
Generics with setters have <applicable-struct-with-setter> layout
* libguile/goops.c (scm_sys_set_object_setter_x): Remove. Instead, we
use slot-set! of 'setter.
(scm_i_define_class_for_vtable): Move lower in the file, and fold in
scm_make_extended_class_from_symbol and make_class_from_symbol.
Properly handle applicable structs with setters.
(scm_class_applicable_struct_with_setter_class): New private capture.
(scm_sys_bless_applicable_struct_vtables_x): Rename to take two
arguments, and bless the second argument as an applicable struct with
setter vtable.
(scm_sys_goops_early_init): Capture setter classes.
* libguile/deprecated.c (SPEC_OF, CPL_OF): Access slots by name, not by
index.
(applicablep, more_specificp): Adapt to use CPL_OF.
(scm_find_method): Access "methods" slot by name.
* libguile/procs.c (scm_setter): Remove special case for generics; if
it's a setter, it will be a normal applicable struct.
* module/oop/goops.scm (<applicable-struct-with-setter-class>)
(<applicable-struct-with-setter>): New classes.
(<generic-with-setter>): Now an instance of the setter metaclass and a
child of the setter class, so that the "setter" slot ends up in the
right place.
(<accessor>, <extended-generic-with-setter>, <extended-accessor>): Be
instances of the setter metaclass.
(<method>, <accessor-method>): Move definitions farther down.
(make): Use slot-set! when initializing setters here.
(initialize): Likewise for <applicable-struct-with-setter>. Remove
specialization for <generic-with-setter>.
2015-01-06 13:41:56 -05:00
|
|
|
|
(define-standard-class <generic-with-setter> (<generic>
|
|
|
|
|
|
<applicable-struct-with-setter>)
|
|
|
|
|
|
#:metaclass <applicable-struct-with-setter-class>)
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(define-standard-class <accessor> (<generic-with-setter>)
|
Generics with setters have <applicable-struct-with-setter> layout
* libguile/goops.c (scm_sys_set_object_setter_x): Remove. Instead, we
use slot-set! of 'setter.
(scm_i_define_class_for_vtable): Move lower in the file, and fold in
scm_make_extended_class_from_symbol and make_class_from_symbol.
Properly handle applicable structs with setters.
(scm_class_applicable_struct_with_setter_class): New private capture.
(scm_sys_bless_applicable_struct_vtables_x): Rename to take two
arguments, and bless the second argument as an applicable struct with
setter vtable.
(scm_sys_goops_early_init): Capture setter classes.
* libguile/deprecated.c (SPEC_OF, CPL_OF): Access slots by name, not by
index.
(applicablep, more_specificp): Adapt to use CPL_OF.
(scm_find_method): Access "methods" slot by name.
* libguile/procs.c (scm_setter): Remove special case for generics; if
it's a setter, it will be a normal applicable struct.
* module/oop/goops.scm (<applicable-struct-with-setter-class>)
(<applicable-struct-with-setter>): New classes.
(<generic-with-setter>): Now an instance of the setter metaclass and a
child of the setter class, so that the "setter" slot ends up in the
right place.
(<accessor>, <extended-generic-with-setter>, <extended-accessor>): Be
instances of the setter metaclass.
(<method>, <accessor-method>): Move definitions farther down.
(make): Use slot-set! when initializing setters here.
(initialize): Likewise for <applicable-struct-with-setter>. Remove
specialization for <generic-with-setter>.
2015-01-06 13:41:56 -05:00
|
|
|
|
#:metaclass <applicable-struct-with-setter-class>)
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(define-standard-class <extended-generic-with-setter> (<extended-generic>
|
|
|
|
|
|
<generic-with-setter>)
|
Generics with setters have <applicable-struct-with-setter> layout
* libguile/goops.c (scm_sys_set_object_setter_x): Remove. Instead, we
use slot-set! of 'setter.
(scm_i_define_class_for_vtable): Move lower in the file, and fold in
scm_make_extended_class_from_symbol and make_class_from_symbol.
Properly handle applicable structs with setters.
(scm_class_applicable_struct_with_setter_class): New private capture.
(scm_sys_bless_applicable_struct_vtables_x): Rename to take two
arguments, and bless the second argument as an applicable struct with
setter vtable.
(scm_sys_goops_early_init): Capture setter classes.
* libguile/deprecated.c (SPEC_OF, CPL_OF): Access slots by name, not by
index.
(applicablep, more_specificp): Adapt to use CPL_OF.
(scm_find_method): Access "methods" slot by name.
* libguile/procs.c (scm_setter): Remove special case for generics; if
it's a setter, it will be a normal applicable struct.
* module/oop/goops.scm (<applicable-struct-with-setter-class>)
(<applicable-struct-with-setter>): New classes.
(<generic-with-setter>): Now an instance of the setter metaclass and a
child of the setter class, so that the "setter" slot ends up in the
right place.
(<accessor>, <extended-generic-with-setter>, <extended-accessor>): Be
instances of the setter metaclass.
(<method>, <accessor-method>): Move definitions farther down.
(make): Use slot-set! when initializing setters here.
(initialize): Likewise for <applicable-struct-with-setter>. Remove
specialization for <generic-with-setter>.
2015-01-06 13:41:56 -05:00
|
|
|
|
#:metaclass <applicable-struct-with-setter-class>)
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(define-standard-class <extended-accessor> (<accessor>
|
|
|
|
|
|
<extended-generic-with-setter>)
|
Generics with setters have <applicable-struct-with-setter> layout
* libguile/goops.c (scm_sys_set_object_setter_x): Remove. Instead, we
use slot-set! of 'setter.
(scm_i_define_class_for_vtable): Move lower in the file, and fold in
scm_make_extended_class_from_symbol and make_class_from_symbol.
Properly handle applicable structs with setters.
(scm_class_applicable_struct_with_setter_class): New private capture.
(scm_sys_bless_applicable_struct_vtables_x): Rename to take two
arguments, and bless the second argument as an applicable struct with
setter vtable.
(scm_sys_goops_early_init): Capture setter classes.
* libguile/deprecated.c (SPEC_OF, CPL_OF): Access slots by name, not by
index.
(applicablep, more_specificp): Adapt to use CPL_OF.
(scm_find_method): Access "methods" slot by name.
* libguile/procs.c (scm_setter): Remove special case for generics; if
it's a setter, it will be a normal applicable struct.
* module/oop/goops.scm (<applicable-struct-with-setter-class>)
(<applicable-struct-with-setter>): New classes.
(<generic-with-setter>): Now an instance of the setter metaclass and a
child of the setter class, so that the "setter" slot ends up in the
right place.
(<accessor>, <extended-generic-with-setter>, <extended-accessor>): Be
instances of the setter metaclass.
(<method>, <accessor-method>): Move definitions farther down.
(make): Use slot-set! when initializing setters here.
(initialize): Likewise for <applicable-struct-with-setter>. Remove
specialization for <generic-with-setter>.
2015-01-06 13:41:56 -05:00
|
|
|
|
#:metaclass <applicable-struct-with-setter-class>)
|
2015-01-04 15:52:12 -05:00
|
|
|
|
|
Generics with setters have <applicable-struct-with-setter> layout
* libguile/goops.c (scm_sys_set_object_setter_x): Remove. Instead, we
use slot-set! of 'setter.
(scm_i_define_class_for_vtable): Move lower in the file, and fold in
scm_make_extended_class_from_symbol and make_class_from_symbol.
Properly handle applicable structs with setters.
(scm_class_applicable_struct_with_setter_class): New private capture.
(scm_sys_bless_applicable_struct_vtables_x): Rename to take two
arguments, and bless the second argument as an applicable struct with
setter vtable.
(scm_sys_goops_early_init): Capture setter classes.
* libguile/deprecated.c (SPEC_OF, CPL_OF): Access slots by name, not by
index.
(applicablep, more_specificp): Adapt to use CPL_OF.
(scm_find_method): Access "methods" slot by name.
* libguile/procs.c (scm_setter): Remove special case for generics; if
it's a setter, it will be a normal applicable struct.
* module/oop/goops.scm (<applicable-struct-with-setter-class>)
(<applicable-struct-with-setter>): New classes.
(<generic-with-setter>): Now an instance of the setter metaclass and a
child of the setter class, so that the "setter" slot ends up in the
right place.
(<accessor>, <extended-generic-with-setter>, <extended-accessor>): Be
instances of the setter metaclass.
(<method>, <accessor-method>): Move definitions farther down.
(make): Use slot-set! when initializing setters here.
(initialize): Likewise for <applicable-struct-with-setter>. Remove
specialization for <generic-with-setter>.
2015-01-06 13:41:56 -05:00
|
|
|
|
(define-standard-class <method> (<object>)
|
|
|
|
|
|
generic-function
|
|
|
|
|
|
specializers
|
|
|
|
|
|
procedure
|
|
|
|
|
|
formals
|
|
|
|
|
|
body
|
|
|
|
|
|
make-procedure)
|
|
|
|
|
|
(define-standard-class <accessor-method> (<method>)
|
|
|
|
|
|
(slot-definition #:init-keyword #:slot-definition))
|
|
|
|
|
|
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(define-standard-class <boolean> (<top>))
|
|
|
|
|
|
(define-standard-class <char> (<top>))
|
|
|
|
|
|
(define-standard-class <list> (<top>))
|
|
|
|
|
|
(define-standard-class <pair> (<list>))
|
|
|
|
|
|
(define-standard-class <null> (<list>))
|
|
|
|
|
|
(define-standard-class <string> (<top>))
|
|
|
|
|
|
(define-standard-class <symbol> (<top>))
|
|
|
|
|
|
(define-standard-class <vector> (<top>))
|
|
|
|
|
|
(define-standard-class <foreign> (<top>))
|
|
|
|
|
|
(define-standard-class <hashtable> (<top>))
|
|
|
|
|
|
(define-standard-class <fluid> (<top>))
|
|
|
|
|
|
(define-standard-class <dynamic-state> (<top>))
|
|
|
|
|
|
(define-standard-class <frame> (<top>))
|
|
|
|
|
|
(define-standard-class <vm-continuation> (<top>))
|
|
|
|
|
|
(define-standard-class <bytevector> (<top>))
|
|
|
|
|
|
(define-standard-class <uvec> (<bytevector>))
|
|
|
|
|
|
(define-standard-class <array> (<top>))
|
|
|
|
|
|
(define-standard-class <bitvector> (<top>))
|
|
|
|
|
|
(define-standard-class <number> (<top>))
|
|
|
|
|
|
(define-standard-class <complex> (<number>))
|
|
|
|
|
|
(define-standard-class <real> (<complex>))
|
|
|
|
|
|
(define-standard-class <integer> (<real>))
|
|
|
|
|
|
(define-standard-class <fraction> (<real>))
|
|
|
|
|
|
(define-standard-class <keyword> (<top>))
|
|
|
|
|
|
(define-standard-class <unknown> (<top>))
|
|
|
|
|
|
(define-standard-class <procedure> (<applicable>)
|
|
|
|
|
|
#:metaclass <procedure-class>)
|
|
|
|
|
|
(define-standard-class <primitive-generic> (<procedure>)
|
|
|
|
|
|
#:metaclass <procedure-class>)
|
|
|
|
|
|
(define-standard-class <port> (<top>))
|
|
|
|
|
|
(define-standard-class <input-port> (<port>))
|
|
|
|
|
|
(define-standard-class <output-port> (<port>))
|
|
|
|
|
|
(define-standard-class <input-output-port> (<input-port> <output-port>))
|
|
|
|
|
|
|
2015-01-11 20:49:16 +01:00
|
|
|
|
(define (inherit-applicable! class)
|
|
|
|
|
|
"An internal routine to redefine a SMOB class that was added after
|
|
|
|
|
|
GOOPS was loaded, and on which scm_set_smob_apply installed an apply
|
|
|
|
|
|
function."
|
|
|
|
|
|
;; Why not use class-redefinition? We would, except that loading the
|
|
|
|
|
|
;; compiler to compile effective methods can happen while GOOPS has
|
|
|
|
|
|
;; only been partially loaded, and loading the compiler might cause
|
|
|
|
|
|
;; SMOB types to be defined that need this facility. Instead we make
|
|
|
|
|
|
;; a very specific hack, not a general solution. Probably the right
|
|
|
|
|
|
;; solution is to avoid using the compiler, but that is another kettle
|
|
|
|
|
|
;; of fish.
|
|
|
|
|
|
(unless (memq <applicable> (class-precedence-list class))
|
|
|
|
|
|
(unless (null? (class-slots class))
|
|
|
|
|
|
(error "SMOB object has slots?"))
|
|
|
|
|
|
(for-each
|
|
|
|
|
|
(lambda (super)
|
|
|
|
|
|
(let ((subclasses (struct-ref super class-index-direct-subclasses)))
|
|
|
|
|
|
(struct-set! super class-index-direct-subclasses
|
|
|
|
|
|
(delq class subclasses))))
|
|
|
|
|
|
(struct-ref class class-index-direct-supers))
|
|
|
|
|
|
(struct-set! class class-index-direct-supers (list <applicable>))
|
|
|
|
|
|
(struct-set! class class-index-cpl (compute-cpl class))
|
|
|
|
|
|
(let ((subclasses (struct-ref <applicable> class-index-direct-subclasses)))
|
|
|
|
|
|
(struct-set! <applicable> class-index-direct-subclasses
|
|
|
|
|
|
(cons class subclasses)))))
|
|
|
|
|
|
|
2015-01-13 23:16:40 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; At this point we have defined the class hierarchy, and it's time to
|
|
|
|
|
|
;;; move on to instance allocation and generics. Once we have generics,
|
|
|
|
|
|
;;; we'll fill out the metaobject protocol.
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; Here we define a limited version of `make', so that we can allocate
|
|
|
|
|
|
;;; instances of specific classes. This definition will be replaced
|
|
|
|
|
|
;;; later.
|
|
|
|
|
|
;;;
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(define (%invalidate-method-cache! gf)
|
|
|
|
|
|
(slot-set! gf 'procedure (delayed-compile gf))
|
|
|
|
|
|
(slot-set! gf 'effective-methods '()))
|
|
|
|
|
|
|
|
|
|
|
|
;; Boot definition.
|
|
|
|
|
|
(define (invalidate-method-cache! gf)
|
|
|
|
|
|
(%invalidate-method-cache! gf))
|
|
|
|
|
|
|
2015-01-11 00:17:22 +01:00
|
|
|
|
(define* (get-keyword key l #:optional default)
|
|
|
|
|
|
"Determine an associated value for the keyword @var{key} from the list
|
|
|
|
|
|
@var{l}. The list @var{l} has to consist of an even number of elements,
|
|
|
|
|
|
where, starting with the first, every second element is a keyword,
|
|
|
|
|
|
followed by its associated value. If @var{l} does not hold a value for
|
|
|
|
|
|
@var{key}, the value @var{default} is returned."
|
|
|
|
|
|
(unless (keyword? key)
|
|
|
|
|
|
(scm-error 'wrong-type-arg #f "Not a keyword: ~S" (list key) #f))
|
|
|
|
|
|
(let lp ((l l))
|
|
|
|
|
|
(match l
|
|
|
|
|
|
(() default)
|
|
|
|
|
|
((kw arg . l)
|
|
|
|
|
|
(unless (keyword? kw)
|
|
|
|
|
|
(scm-error 'wrong-type-arg #f "Not a keyword: ~S" (list kw) #f))
|
|
|
|
|
|
(if (eq? kw key) arg (lp l))))))
|
|
|
|
|
|
|
2015-01-11 19:11:41 +01:00
|
|
|
|
(define (%allocate-instance class)
|
|
|
|
|
|
(let ((obj (allocate-struct class (struct-ref class class-index-nfields))))
|
|
|
|
|
|
(%clear-fields! obj)
|
|
|
|
|
|
obj))
|
|
|
|
|
|
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(define (make class . args)
|
|
|
|
|
|
(cond
|
|
|
|
|
|
((or (eq? class <generic>) (eq? class <accessor>))
|
|
|
|
|
|
(let ((z (make-struct/no-tail class #f '() 0 '())))
|
|
|
|
|
|
(set-procedure-property! z 'name (get-keyword #:name args #f))
|
|
|
|
|
|
(invalidate-method-cache! z)
|
|
|
|
|
|
(when (eq? class <accessor>)
|
|
|
|
|
|
(let ((setter (get-keyword #:setter args #f)))
|
|
|
|
|
|
(when setter
|
Generics with setters have <applicable-struct-with-setter> layout
* libguile/goops.c (scm_sys_set_object_setter_x): Remove. Instead, we
use slot-set! of 'setter.
(scm_i_define_class_for_vtable): Move lower in the file, and fold in
scm_make_extended_class_from_symbol and make_class_from_symbol.
Properly handle applicable structs with setters.
(scm_class_applicable_struct_with_setter_class): New private capture.
(scm_sys_bless_applicable_struct_vtables_x): Rename to take two
arguments, and bless the second argument as an applicable struct with
setter vtable.
(scm_sys_goops_early_init): Capture setter classes.
* libguile/deprecated.c (SPEC_OF, CPL_OF): Access slots by name, not by
index.
(applicablep, more_specificp): Adapt to use CPL_OF.
(scm_find_method): Access "methods" slot by name.
* libguile/procs.c (scm_setter): Remove special case for generics; if
it's a setter, it will be a normal applicable struct.
* module/oop/goops.scm (<applicable-struct-with-setter-class>)
(<applicable-struct-with-setter>): New classes.
(<generic-with-setter>): Now an instance of the setter metaclass and a
child of the setter class, so that the "setter" slot ends up in the
right place.
(<accessor>, <extended-generic-with-setter>, <extended-accessor>): Be
instances of the setter metaclass.
(<method>, <accessor-method>): Move definitions farther down.
(make): Use slot-set! when initializing setters here.
(initialize): Likewise for <applicable-struct-with-setter>. Remove
specialization for <generic-with-setter>.
2015-01-06 13:41:56 -05:00
|
|
|
|
(slot-set! z 'setter setter))))
|
2015-01-04 15:52:12 -05:00
|
|
|
|
z))
|
|
|
|
|
|
(else
|
2015-01-11 19:11:41 +01:00
|
|
|
|
(let ((z (%allocate-instance class)))
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(cond
|
|
|
|
|
|
((or (eq? class <method>) (eq? class <accessor-method>))
|
|
|
|
|
|
(for-each (match-lambda
|
|
|
|
|
|
((kw slot default)
|
|
|
|
|
|
(slot-set! z slot (get-keyword kw args default))))
|
|
|
|
|
|
'((#:generic-function generic-function #f)
|
|
|
|
|
|
(#:specializers specializers ())
|
|
|
|
|
|
(#:procedure procedure #f)
|
|
|
|
|
|
(#:formals formals ())
|
|
|
|
|
|
(#:body body ())
|
|
|
|
|
|
(#:make-procedure make-procedure #f))))
|
|
|
|
|
|
((memq <class> (class-precedence-list class))
|
Manipulate GOOPS vtable flags from Scheme, for speed
* libguile/goops.h: Remove unimplemented declarations of
scm_make_next_method, scm_sys_invalidate_method_cache_x, and
stklos_version.
(scm_sys_invalidate_class_x): Remove helper definition. This was
exported in the past but shouldn't have been.
* libguile/goops.c (scm_sys_make_vtable_vtable): Rename from
scm_sys_make_root_class, and don't do anything about flags.
(scm_sys_bless_applicable_struct_vtables_x, scm_class_p)
(scm_sys_invalidate_class_x): Remove; we do these in Scheme now.
(scm_init_goops_builtins): Define Scheme values for vtable flags.
* module/oop/goops.scm (vtable-flag-goops-metaclass)
(class-add-flags!, class-clear-flags!, class-has-flags?)
(class?, instance?): New definitions.
(<class>): Add GOOPS metaclass flags from Scheme.
(<applicable-struct-class>, <applicable-struct-with-setter-class>):
Add flags from Scheme.
(make, initialize): Add class flags as appropriate.
(class-redefinition): Clear the "valid" flag on the old class.
(check-slot-args): Use instance? instead of a CPL check.
2015-01-16 11:26:25 +01:00
|
|
|
|
(class-add-flags! z (logior vtable-flag-goops-class
|
|
|
|
|
|
vtable-flag-goops-valid))
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(for-each (match-lambda
|
|
|
|
|
|
((kw slot default)
|
|
|
|
|
|
(slot-set! z slot (get-keyword kw args default))))
|
|
|
|
|
|
'((#:name name ???)
|
|
|
|
|
|
(#:dsupers direct-supers ())
|
2015-01-14 20:15:53 +01:00
|
|
|
|
(#:slots direct-slots ()))))
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(else
|
|
|
|
|
|
(error "boot `make' does not support this class" class)))
|
|
|
|
|
|
z))))
|
|
|
|
|
|
|
2015-01-13 23:04:57 +01:00
|
|
|
|
(define (is-a? obj class)
|
|
|
|
|
|
"Return @code{#t} if @var{obj} is an instance of @var{class}, or
|
|
|
|
|
|
@code{#f} otherwise."
|
|
|
|
|
|
(and (memq class (class-precedence-list (class-of obj))) #t))
|
|
|
|
|
|
|
2015-01-13 23:16:40 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
2015-01-14 00:01:51 +01:00
|
|
|
|
;;; Slot access. This protocol is a bit of a mess: there's the `slots'
|
|
|
|
|
|
;;; slot, which ostensibly holds "slot definitions" but really just has
|
|
|
|
|
|
;;; specially formatted lists. And then there's the `getters-n-setters'
|
|
|
|
|
|
;;; slot, which mirrors `slots' but should in theory indicates how to
|
|
|
|
|
|
;;; get at slots for a particular instance -- never mind that `slots'
|
|
|
|
|
|
;;; was also computed for a particular instance, and that
|
|
|
|
|
|
;;; `getters-n-setters' is a strangely structured chain of pairs.
|
|
|
|
|
|
;;; Perhaps we can fix this in the future, following the CLOS MOP, to
|
|
|
|
|
|
;;; have proper <effective-slot-definition> objects.
|
2015-01-13 23:16:40 +01:00
|
|
|
|
;;;
|
2015-01-10 00:50:33 +01:00
|
|
|
|
(define (get-slot-value-using-name class obj slot-name)
|
|
|
|
|
|
(match (assq slot-name (struct-ref class class-index-getters-n-setters))
|
|
|
|
|
|
(#f (slot-missing class obj slot-name))
|
|
|
|
|
|
((name init-thunk . (? exact-integer? index))
|
|
|
|
|
|
(struct-ref obj index))
|
|
|
|
|
|
((name init-thunk getter setter . _)
|
|
|
|
|
|
(getter obj))))
|
|
|
|
|
|
|
|
|
|
|
|
(define (set-slot-value-using-name! class obj slot-name value)
|
|
|
|
|
|
(match (assq slot-name (struct-ref class class-index-getters-n-setters))
|
|
|
|
|
|
(#f (slot-missing class obj slot-name value))
|
|
|
|
|
|
((name init-thunk . (? exact-integer? index))
|
|
|
|
|
|
(struct-set! obj index value))
|
|
|
|
|
|
((name init-thunk getter setter . _)
|
|
|
|
|
|
(setter obj value))))
|
|
|
|
|
|
|
|
|
|
|
|
(define (test-slot-existence class obj slot-name)
|
|
|
|
|
|
(and (assq slot-name (struct-ref class class-index-getters-n-setters))
|
|
|
|
|
|
#t))
|
|
|
|
|
|
|
|
|
|
|
|
(define (check-slot-args class obj slot-name)
|
|
|
|
|
|
(unless (class? class)
|
|
|
|
|
|
(scm-error 'wrong-type-arg #f "Not a class: ~S"
|
|
|
|
|
|
(list class) #f))
|
Manipulate GOOPS vtable flags from Scheme, for speed
* libguile/goops.h: Remove unimplemented declarations of
scm_make_next_method, scm_sys_invalidate_method_cache_x, and
stklos_version.
(scm_sys_invalidate_class_x): Remove helper definition. This was
exported in the past but shouldn't have been.
* libguile/goops.c (scm_sys_make_vtable_vtable): Rename from
scm_sys_make_root_class, and don't do anything about flags.
(scm_sys_bless_applicable_struct_vtables_x, scm_class_p)
(scm_sys_invalidate_class_x): Remove; we do these in Scheme now.
(scm_init_goops_builtins): Define Scheme values for vtable flags.
* module/oop/goops.scm (vtable-flag-goops-metaclass)
(class-add-flags!, class-clear-flags!, class-has-flags?)
(class?, instance?): New definitions.
(<class>): Add GOOPS metaclass flags from Scheme.
(<applicable-struct-class>, <applicable-struct-with-setter-class>):
Add flags from Scheme.
(make, initialize): Add class flags as appropriate.
(class-redefinition): Clear the "valid" flag on the old class.
(check-slot-args): Use instance? instead of a CPL check.
2015-01-16 11:26:25 +01:00
|
|
|
|
(unless (instance? obj)
|
2015-01-10 00:50:33 +01:00
|
|
|
|
(scm-error 'wrong-type-arg #f "Not an instance: ~S"
|
|
|
|
|
|
(list obj) #f))
|
|
|
|
|
|
(unless (symbol? slot-name)
|
|
|
|
|
|
(scm-error 'wrong-type-arg #f "Not a symbol: ~S"
|
|
|
|
|
|
(list slot-name) #f)))
|
|
|
|
|
|
|
|
|
|
|
|
(define (slot-ref-using-class class obj slot-name)
|
|
|
|
|
|
(check-slot-args class obj slot-name)
|
|
|
|
|
|
(let ((val (get-slot-value-using-name class obj slot-name)))
|
|
|
|
|
|
(if (unbound? val)
|
|
|
|
|
|
(slot-unbound class obj slot-name)
|
|
|
|
|
|
val)))
|
|
|
|
|
|
|
|
|
|
|
|
(define (slot-set-using-class! class obj slot-name value)
|
|
|
|
|
|
(check-slot-args class obj slot-name)
|
|
|
|
|
|
(set-slot-value-using-name! class obj slot-name value))
|
|
|
|
|
|
|
|
|
|
|
|
(define (slot-bound-using-class? class obj slot-name)
|
|
|
|
|
|
(check-slot-args class obj slot-name)
|
|
|
|
|
|
(not (unbound? (get-slot-value-using-name class obj slot-name))))
|
|
|
|
|
|
|
|
|
|
|
|
(define (slot-exists-using-class? class obj slot-name)
|
|
|
|
|
|
(check-slot-args class obj slot-name)
|
|
|
|
|
|
(test-slot-existence class obj slot-name))
|
|
|
|
|
|
|
2015-01-14 00:01:51 +01:00
|
|
|
|
;;;
|
|
|
|
|
|
;;; Before we go on, some notes about class redefinition. In GOOPS,
|
|
|
|
|
|
;;; classes can be redefined. Redefinition of a class marks the class
|
|
|
|
|
|
;;; as invalid, and instances will be lazily migrated over to the new
|
|
|
|
|
|
;;; representation as they are accessed. Migration happens when
|
|
|
|
|
|
;;; `class-of' is called on an instance. For more technical details on
|
|
|
|
|
|
;;; object redefinition, see struct.h.
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; In the following interfaces, class-of handles the redefinition
|
|
|
|
|
|
;;; protocol. I would think though that there is some thread-unsafety
|
|
|
|
|
|
;;; here though as the { class, object data } pair needs to be accessed
|
|
|
|
|
|
;;; atomically, not the { class, object } pair.
|
|
|
|
|
|
;;;
|
2015-01-10 00:50:33 +01:00
|
|
|
|
|
|
|
|
|
|
(define (slot-ref obj slot-name)
|
|
|
|
|
|
"Return the value from @var{obj}'s slot with the nam var{slot_name}."
|
2015-01-16 12:55:48 +01:00
|
|
|
|
(unless (symbol? slot-name)
|
|
|
|
|
|
(scm-error 'wrong-type-arg #f "Not a symbol: ~S"
|
|
|
|
|
|
(list slot-name) #f))
|
|
|
|
|
|
(let* ((class (class-of obj))
|
|
|
|
|
|
(val (get-slot-value-using-name class obj slot-name)))
|
|
|
|
|
|
(if (unbound? val)
|
|
|
|
|
|
(slot-unbound class obj slot-name)
|
|
|
|
|
|
val)))
|
2015-01-10 00:50:33 +01:00
|
|
|
|
|
|
|
|
|
|
(define (slot-set! obj slot-name value)
|
|
|
|
|
|
"Set the slot named @var{slot_name} of @var{obj} to @var{value}."
|
2015-01-16 12:55:48 +01:00
|
|
|
|
(unless (symbol? slot-name)
|
|
|
|
|
|
(scm-error 'wrong-type-arg #f "Not a symbol: ~S"
|
|
|
|
|
|
(list slot-name) #f))
|
|
|
|
|
|
(set-slot-value-using-name! (class-of obj) obj slot-name value))
|
2015-01-10 00:50:33 +01:00
|
|
|
|
|
|
|
|
|
|
(define (slot-bound? obj slot-name)
|
|
|
|
|
|
"Return the value from @var{obj}'s slot with the nam var{slot_name}."
|
2015-01-16 12:55:48 +01:00
|
|
|
|
(unless (symbol? slot-name)
|
|
|
|
|
|
(scm-error 'wrong-type-arg #f "Not a symbol: ~S"
|
|
|
|
|
|
(list slot-name) #f))
|
|
|
|
|
|
(not (unbound? (get-slot-value-using-name (class-of obj) obj slot-name))))
|
2015-01-10 00:50:33 +01:00
|
|
|
|
|
|
|
|
|
|
(define (slot-exists? obj slot-name)
|
|
|
|
|
|
"Return @code{#t} if @var{obj} has a slot named @var{slot_name}."
|
2015-01-16 12:55:48 +01:00
|
|
|
|
(unless (symbol? slot-name)
|
|
|
|
|
|
(scm-error 'wrong-type-arg #f "Not a symbol: ~S"
|
|
|
|
|
|
(list slot-name) #f))
|
|
|
|
|
|
(test-slot-existence (class-of obj) obj slot-name))
|
2015-01-10 00:50:33 +01:00
|
|
|
|
|
2015-01-14 00:01:51 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; Method accessors.
|
|
|
|
|
|
;;;
|
2015-01-09 22:05:01 +01:00
|
|
|
|
(define (method-generic-function obj)
|
|
|
|
|
|
"Return the generic function for the method @var{obj}."
|
|
|
|
|
|
(unless (is-a? obj <method>)
|
|
|
|
|
|
(scm-error 'wrong-type-arg #f "Not a method: ~S"
|
|
|
|
|
|
(list obj) #f))
|
|
|
|
|
|
(slot-ref obj 'generic-function))
|
|
|
|
|
|
|
|
|
|
|
|
(define (method-specializers obj)
|
|
|
|
|
|
"Return specializers of the method @var{obj}."
|
|
|
|
|
|
(unless (is-a? obj <method>)
|
|
|
|
|
|
(scm-error 'wrong-type-arg #f "Not a method: ~S"
|
|
|
|
|
|
(list obj) #f))
|
|
|
|
|
|
(slot-ref obj 'specializers))
|
|
|
|
|
|
|
|
|
|
|
|
(define (method-procedure obj)
|
|
|
|
|
|
"Return the procedure of the method @var{obj}."
|
|
|
|
|
|
(unless (is-a? obj <method>)
|
|
|
|
|
|
(scm-error 'wrong-type-arg #f "Not a method: ~S"
|
|
|
|
|
|
(list obj) #f))
|
|
|
|
|
|
(slot-ref obj 'procedure))
|
|
|
|
|
|
|
2015-01-14 00:01:51 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; Generic functions!
|
|
|
|
|
|
;;;
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(define *dispatch-module* (current-module))
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; Generic functions have an applicable-methods cache associated with
|
|
|
|
|
|
;;; them. Every distinct set of types that is dispatched through a
|
|
|
|
|
|
;;; generic adds an entry to the cache. This cache gets compiled out to
|
|
|
|
|
|
;;; a dispatch procedure. In steady-state, this dispatch procedure is
|
|
|
|
|
|
;;; never recompiled; but during warm-up there is some churn, both to
|
|
|
|
|
|
;;; the cache and to the dispatch procedure.
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; So what is the deal if warm-up happens in a multithreaded context?
|
|
|
|
|
|
;;; There is indeed a window between missing the cache for a certain set
|
|
|
|
|
|
;;; of arguments, and then updating the cache with the newly computed
|
|
|
|
|
|
;;; applicable methods. One of the updaters is liable to lose their new
|
|
|
|
|
|
;;; entry.
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; This is actually OK though, because a subsequent cache miss for the
|
|
|
|
|
|
;;; race loser will just cause memoization to try again. The cache will
|
|
|
|
|
|
;;; eventually be consistent. We're not mutating the old part of the
|
|
|
|
|
|
;;; cache, just consing on the new entry.
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; It doesn't even matter if the dispatch procedure and the cache are
|
|
|
|
|
|
;;; inconsistent -- most likely the type-set that lost the dispatch
|
|
|
|
|
|
;;; procedure race will simply re-trigger a memoization, but since the
|
|
|
|
|
|
;;; winner isn't in the effective-methods cache, it will likely also
|
|
|
|
|
|
;;; re-trigger a memoization, and the cache will finally be consistent.
|
|
|
|
|
|
;;; As you can see there is a possibility for ping-pong effects, but
|
|
|
|
|
|
;;; it's unlikely given the shortness of the window between slot-set!
|
|
|
|
|
|
;;; invocations. We could add a mutex, but it is strictly unnecessary,
|
|
|
|
|
|
;;; and would add runtime cost and complexity.
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
|
|
|
|
|
(define (emit-linear-dispatch gf-sym nargs methods free rest?)
|
|
|
|
|
|
(define (gen-syms n stem)
|
|
|
|
|
|
(let lp ((n (1- n)) (syms '()))
|
|
|
|
|
|
(if (< n 0)
|
|
|
|
|
|
syms
|
|
|
|
|
|
(lp (1- n) (cons (gensym stem) syms)))))
|
|
|
|
|
|
(let* ((args (gen-syms nargs "a"))
|
|
|
|
|
|
(types (gen-syms nargs "t")))
|
|
|
|
|
|
(let lp ((methods methods)
|
|
|
|
|
|
(free free)
|
|
|
|
|
|
(exp `(cache-miss ,gf-sym
|
|
|
|
|
|
,(if rest?
|
|
|
|
|
|
`(cons* ,@args rest)
|
|
|
|
|
|
`(list ,@args)))))
|
2015-01-14 20:43:35 +01:00
|
|
|
|
(match methods
|
|
|
|
|
|
(()
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(values `(,(if rest? `(,@args . rest) args)
|
|
|
|
|
|
(let ,(map (lambda (t a)
|
|
|
|
|
|
`(,t (class-of ,a)))
|
|
|
|
|
|
types args)
|
|
|
|
|
|
,exp))
|
|
|
|
|
|
free))
|
2015-01-14 20:43:35 +01:00
|
|
|
|
((#(_ specs _ cmethod) . methods)
|
|
|
|
|
|
(let build-dispatch ((free free)
|
|
|
|
|
|
(types types)
|
|
|
|
|
|
(specs specs)
|
|
|
|
|
|
(checks '()))
|
|
|
|
|
|
(match types
|
|
|
|
|
|
(()
|
|
|
|
|
|
(let ((m-sym (gensym "p")))
|
|
|
|
|
|
(lp methods
|
|
|
|
|
|
(acons cmethod m-sym free)
|
|
|
|
|
|
`(if (and . ,checks)
|
|
|
|
|
|
,(if rest?
|
|
|
|
|
|
`(apply ,m-sym ,@args rest)
|
|
|
|
|
|
`(,m-sym . ,args))
|
|
|
|
|
|
,exp))))
|
|
|
|
|
|
((type . types)
|
|
|
|
|
|
(match specs
|
|
|
|
|
|
((spec . specs)
|
|
|
|
|
|
(let ((var (assq-ref free spec)))
|
|
|
|
|
|
(if var
|
|
|
|
|
|
(build-dispatch free
|
|
|
|
|
|
types
|
|
|
|
|
|
specs
|
|
|
|
|
|
(cons `(eq? ,type ,var)
|
|
|
|
|
|
checks))
|
|
|
|
|
|
(let ((var (gensym "c")))
|
|
|
|
|
|
(build-dispatch (acons spec var free)
|
|
|
|
|
|
types
|
|
|
|
|
|
specs
|
|
|
|
|
|
(cons `(eq? ,type ,var)
|
|
|
|
|
|
checks)))))))))))))))
|
2015-01-04 15:52:12 -05:00
|
|
|
|
|
|
|
|
|
|
(define (compute-dispatch-procedure gf cache)
|
|
|
|
|
|
(define (scan)
|
|
|
|
|
|
(let lp ((ls cache) (nreq -1) (nrest -1))
|
2015-01-16 10:19:47 +01:00
|
|
|
|
(match ls
|
|
|
|
|
|
(()
|
|
|
|
|
|
(collate (make-vector (1+ nreq) '())
|
|
|
|
|
|
(make-vector (1+ nrest) '())))
|
|
|
|
|
|
((#(len specs rest? cmethod) . ls)
|
|
|
|
|
|
(if rest?
|
|
|
|
|
|
(lp ls nreq (max nrest len))
|
|
|
|
|
|
(lp ls (max nreq len) nrest))))))
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(define (collate req rest)
|
|
|
|
|
|
(let lp ((ls cache))
|
2015-01-16 10:19:47 +01:00
|
|
|
|
(match ls
|
|
|
|
|
|
(() (emit req rest))
|
|
|
|
|
|
(((and entry #(len specs rest? cmethod)) . ls)
|
|
|
|
|
|
(if rest?
|
|
|
|
|
|
(vector-set! rest len (cons entry (vector-ref rest len)))
|
|
|
|
|
|
(vector-set! req len (cons entry (vector-ref req len))))
|
|
|
|
|
|
(lp ls)))))
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(define (emit req rest)
|
|
|
|
|
|
(let ((gf-sym (gensym "g")))
|
|
|
|
|
|
(define (emit-rest n clauses free)
|
|
|
|
|
|
(if (< n (vector-length rest))
|
2015-01-16 10:19:47 +01:00
|
|
|
|
(match (vector-ref rest n)
|
|
|
|
|
|
(() (emit-rest (1+ n) clauses free))
|
|
|
|
|
|
;; FIXME: hash dispatch
|
|
|
|
|
|
(methods
|
|
|
|
|
|
(call-with-values
|
|
|
|
|
|
(lambda ()
|
|
|
|
|
|
(emit-linear-dispatch gf-sym n methods free #t))
|
|
|
|
|
|
(lambda (clause free)
|
|
|
|
|
|
(emit-rest (1+ n) (cons clause clauses) free)))))
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(emit-req (1- (vector-length req)) clauses free)))
|
|
|
|
|
|
(define (emit-req n clauses free)
|
|
|
|
|
|
(if (< n 0)
|
|
|
|
|
|
(comp `(lambda ,(map cdr free)
|
|
|
|
|
|
(case-lambda ,@clauses))
|
|
|
|
|
|
(map car free))
|
2015-01-16 10:19:47 +01:00
|
|
|
|
(match (vector-ref req n)
|
|
|
|
|
|
(() (emit-req (1- n) clauses free))
|
|
|
|
|
|
;; FIXME: hash dispatch
|
|
|
|
|
|
(methods
|
|
|
|
|
|
(call-with-values
|
|
|
|
|
|
(lambda ()
|
|
|
|
|
|
(emit-linear-dispatch gf-sym n methods free #f))
|
|
|
|
|
|
(lambda (clause free)
|
|
|
|
|
|
(emit-req (1- n) (cons clause clauses) free)))))))
|
2015-01-04 15:52:12 -05:00
|
|
|
|
|
|
|
|
|
|
(emit-rest 0
|
|
|
|
|
|
(if (or (zero? (vector-length rest))
|
|
|
|
|
|
(null? (vector-ref rest 0)))
|
|
|
|
|
|
(list `(args (cache-miss ,gf-sym args)))
|
|
|
|
|
|
'())
|
|
|
|
|
|
(acons gf gf-sym '()))))
|
|
|
|
|
|
(define (comp exp vals)
|
|
|
|
|
|
;; When cross-compiling Guile itself, the native Guile must generate
|
|
|
|
|
|
;; code for the host.
|
|
|
|
|
|
(with-target %host-type
|
|
|
|
|
|
(lambda ()
|
|
|
|
|
|
(let ((p ((@ (system base compile) compile) exp
|
|
|
|
|
|
#:env *dispatch-module*
|
|
|
|
|
|
#:from 'scheme
|
|
|
|
|
|
#:opts '(#:partial-eval? #f #:cse? #f))))
|
|
|
|
|
|
(apply p vals)))))
|
|
|
|
|
|
|
|
|
|
|
|
;; kick it.
|
|
|
|
|
|
(scan))
|
|
|
|
|
|
|
|
|
|
|
|
;; o/~ ten, nine, eight
|
|
|
|
|
|
;; sometimes that's just how it goes
|
|
|
|
|
|
;; three, two, one
|
|
|
|
|
|
;;
|
|
|
|
|
|
;; get out before it blows o/~
|
|
|
|
|
|
;;
|
|
|
|
|
|
(define timer-init 30)
|
|
|
|
|
|
(define (delayed-compile gf)
|
|
|
|
|
|
(let ((timer timer-init))
|
|
|
|
|
|
(lambda args
|
|
|
|
|
|
(set! timer (1- timer))
|
|
|
|
|
|
(cond
|
|
|
|
|
|
((zero? timer)
|
|
|
|
|
|
(let ((dispatch (compute-dispatch-procedure
|
|
|
|
|
|
gf (slot-ref gf 'effective-methods))))
|
|
|
|
|
|
(slot-set! gf 'procedure dispatch)
|
|
|
|
|
|
(apply dispatch args)))
|
|
|
|
|
|
(else
|
|
|
|
|
|
;; interestingly, this catches recursive compilation attempts as
|
|
|
|
|
|
;; well; in that case, timer is negative
|
|
|
|
|
|
(cache-dispatch gf args))))))
|
|
|
|
|
|
|
|
|
|
|
|
(define (cache-dispatch gf args)
|
|
|
|
|
|
(define (map-until n f ls)
|
|
|
|
|
|
(if (or (zero? n) (null? ls))
|
|
|
|
|
|
'()
|
|
|
|
|
|
(cons (f (car ls)) (map-until (1- n) f (cdr ls)))))
|
|
|
|
|
|
(define (equal? x y) ; can't use the stock equal? because it's a generic...
|
|
|
|
|
|
(cond ((pair? x) (and (pair? y)
|
|
|
|
|
|
(eq? (car x) (car y))
|
|
|
|
|
|
(equal? (cdr x) (cdr y))))
|
|
|
|
|
|
((null? x) (null? y))
|
|
|
|
|
|
(else #f)))
|
|
|
|
|
|
(if (slot-ref gf 'n-specialized)
|
|
|
|
|
|
(let ((types (map-until (slot-ref gf 'n-specialized) class-of args)))
|
|
|
|
|
|
(let lp ((cache (slot-ref gf 'effective-methods)))
|
|
|
|
|
|
(cond ((null? cache)
|
|
|
|
|
|
(cache-miss gf args))
|
|
|
|
|
|
((equal? (vector-ref (car cache) 1) types)
|
|
|
|
|
|
(apply (vector-ref (car cache) 3) args))
|
|
|
|
|
|
(else (lp (cdr cache))))))
|
|
|
|
|
|
(cache-miss gf args)))
|
|
|
|
|
|
|
|
|
|
|
|
(define (cache-miss gf args)
|
|
|
|
|
|
(apply (memoize-method! gf args) args))
|
|
|
|
|
|
|
|
|
|
|
|
(define (memoize-effective-method! gf args applicable)
|
|
|
|
|
|
(define (first-n ls n)
|
|
|
|
|
|
(if (or (zero? n) (null? ls))
|
|
|
|
|
|
'()
|
|
|
|
|
|
(cons (car ls) (first-n (cdr ls) (- n 1)))))
|
|
|
|
|
|
(define (parse n ls)
|
|
|
|
|
|
(cond ((null? ls)
|
|
|
|
|
|
(memoize n #f (map class-of args)))
|
|
|
|
|
|
((= n (slot-ref gf 'n-specialized))
|
|
|
|
|
|
(memoize n #t (map class-of (first-n args n))))
|
|
|
|
|
|
(else
|
|
|
|
|
|
(parse (1+ n) (cdr ls)))))
|
|
|
|
|
|
(define (memoize len rest? types)
|
|
|
|
|
|
(let* ((cmethod (compute-cmethod applicable types))
|
|
|
|
|
|
(cache (cons (vector len types rest? cmethod)
|
|
|
|
|
|
(slot-ref gf 'effective-methods))))
|
|
|
|
|
|
(slot-set! gf 'effective-methods cache)
|
|
|
|
|
|
(slot-set! gf 'procedure (delayed-compile gf))
|
|
|
|
|
|
cmethod))
|
|
|
|
|
|
(parse 0 args))
|
Move GOOPS boot to Scheme
* module/oop/goops.scm (build-<class>-slots): New helper, replacing
build_class_class_slots.
(build-slots-list, %compute-getters-n-setters, %compute-layout): New
private helpers, moved here from C.
(%prep-layout!): Reimplement in Scheme.
(make-standard-class): New private helper, replacing
scm_basic_make_class.
(<class>, <top>, <object>): Define in Scheme.
(<foreign-slot>, <protected-slot>, <hidden-slot>, <opaque-slot>,
<read-only-slot>, <self-slot>, <protected-opaque-slot>,
<protected-hidden-slot>, <protected-read-only-slot>, <scm-slot>,
<int-slot>, <float-slot>, <double-slot>, <procedure-class>,
<applicable-struct-class>, <method>, <accessor-method>, <applicable>,
<applicable-struct>, <generic>, <extended-generic>,
<generic-with-setter>, <accessor>, <extended-generic-with-setter>,
<extended-accessor>): Define in Scheme.
(<boolean>, <char>, <list>, <pair>, <null>, <string>, <symbol>,
<vector>, <foreign>, <hashtable>, <fluid>, <dynamic-state>, <frame>,
<vm-continuation>, <bytevector>, <uvec>, <array>, <bitvector>,
<number>, <complex>, <real>, <integer>, <fraction>, <keyword>,
<unknown>, <procedure>, <primitive-generic>, <port>, <input-port>,
<output-port>, <input-output-port>): Define in Scheme.
(compute-slots): Use build-slots-list helper.
* libguile/goops.h:
* libguile/goops.c (scm_basic_basic_make_class, scm_sys_compute_slots)
(scm_sys_prep_layout_x): Remove. These were available to C, but were
undocumented internals that were dangerous, confusing, and
unnecessary.
* libguile/goops.c: Add note about variable versus value references.
Remove internal C routines that were just used during boot, as they
have been moved to Scheme.
(scm_basic_make_class): Change to call out to make-standard-class in
Scheme.
(scm_sys_make_root_class, scm_sys_bless_applicable_struct_vtable_x)
(scm_sys_bless_pure_generic_vtable_x, scm_sys_init_layout_x): New
private helpers.
(scm_sys_goops_early_init): Change to capture values defined in
Scheme.
2015-01-04 13:41:09 -05:00
|
|
|
|
|
2015-01-04 15:52:12 -05:00
|
|
|
|
;;;
|
|
|
|
|
|
;;; Compiling next methods into method bodies
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
|
|
|
|
|
;;; So, for the reader: there basic idea is that, given that the
|
|
|
|
|
|
;;; semantics of `next-method' depend on the concrete types being
|
|
|
|
|
|
;;; dispatched, why not compile a specific procedure to handle each type
|
|
|
|
|
|
;;; combination that we see at runtime.
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; In theory we can do much better than a bytecode compilation, because
|
|
|
|
|
|
;;; we know the *exact* types of the arguments. It's ideal for native
|
|
|
|
|
|
;;; compilation. A task for the future.
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; I think this whole generic application mess would benefit from a
|
|
|
|
|
|
;;; strict MOP.
|
|
|
|
|
|
|
|
|
|
|
|
(define (compute-cmethod methods types)
|
|
|
|
|
|
(let ((make-procedure (slot-ref (car methods) 'make-procedure)))
|
|
|
|
|
|
(if make-procedure
|
|
|
|
|
|
(make-procedure
|
|
|
|
|
|
(if (null? (cdr methods))
|
|
|
|
|
|
(lambda args
|
|
|
|
|
|
(no-next-method (method-generic-function (car methods)) args))
|
|
|
|
|
|
(compute-cmethod (cdr methods) types)))
|
|
|
|
|
|
(method-procedure (car methods)))))
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; Memoization
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
|
|
|
|
|
(define (memoize-method! gf args)
|
|
|
|
|
|
(let ((applicable ((if (eq? gf compute-applicable-methods)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
%compute-applicable-methods
|
|
|
|
|
|
compute-applicable-methods)
|
|
|
|
|
|
gf args)))
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(cond (applicable
|
|
|
|
|
|
(memoize-effective-method! gf args applicable))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(else
|
|
|
|
|
|
(no-applicable-method gf args)))))
|
2015-01-04 15:52:12 -05:00
|
|
|
|
|
|
|
|
|
|
(set-procedure-property! memoize-method! 'system-procedure #t)
|
|
|
|
|
|
|
|
|
|
|
|
(define no-applicable-method
|
|
|
|
|
|
(make <generic> #:name 'no-applicable-method))
|
|
|
|
|
|
|
|
|
|
|
|
(%goops-early-init)
|
2014-12-24 11:29:45 -05:00
|
|
|
|
|
2001-05-19 00:19:25 +00:00
|
|
|
|
;; Then load the rest of GOOPS
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
2011-04-29 16:34:35 +02:00
|
|
|
|
;; FIXME: deprecate.
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(define min-fixnum (- (expt 2 29)))
|
|
|
|
|
|
(define max-fixnum (- (expt 2 29) 1))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
;;
|
|
|
|
|
|
;; goops-error
|
|
|
|
|
|
;;
|
|
|
|
|
|
(define (goops-error format-string . args)
|
|
|
|
|
|
(scm-error 'goops-error #f format-string args '()))
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; {Meta classes}
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
|
|
|
|
|
(define ensure-metaclass-with-supers
|
|
|
|
|
|
(let ((table-of-metas '()))
|
|
|
|
|
|
(lambda (meta-supers)
|
|
|
|
|
|
(let ((entry (assoc meta-supers table-of-metas)))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(if entry
|
|
|
|
|
|
;; Found a previously created metaclass
|
|
|
|
|
|
(cdr entry)
|
|
|
|
|
|
;; Create a new meta-class which inherit from "meta-supers"
|
|
|
|
|
|
(let ((new (make <class> #:dsupers meta-supers
|
|
|
|
|
|
#:slots '()
|
|
|
|
|
|
#:name (gensym "metaclass"))))
|
|
|
|
|
|
(set! table-of-metas (cons (cons meta-supers new) table-of-metas))
|
|
|
|
|
|
new))))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2009-11-27 20:50:40 +01:00
|
|
|
|
(define (ensure-metaclass supers)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(if (null? supers)
|
|
|
|
|
|
<class>
|
|
|
|
|
|
(let* ((all-metas (map (lambda (x) (class-of x)) supers))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(all-cpls (append-map (lambda (m)
|
|
|
|
|
|
(cdr (class-precedence-list m)))
|
2009-02-05 00:31:38 +01:00
|
|
|
|
all-metas))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(needed-metas '()))
|
|
|
|
|
|
;; Find the most specific metaclasses. The new metaclass will be
|
|
|
|
|
|
;; a subclass of these.
|
|
|
|
|
|
(for-each
|
|
|
|
|
|
(lambda (meta)
|
2015-01-14 20:06:35 +01:00
|
|
|
|
(when (and (not (member meta all-cpls))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(not (member meta needed-metas)))
|
|
|
|
|
|
(set! needed-metas (append needed-metas (list meta)))))
|
|
|
|
|
|
all-metas)
|
|
|
|
|
|
;; Now return a subclass of the metaclasses we found.
|
|
|
|
|
|
(if (null? (cdr needed-metas))
|
|
|
|
|
|
(car needed-metas) ; If there's only one, just use it.
|
|
|
|
|
|
(ensure-metaclass-with-supers needed-metas)))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; {Classes}
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
|
|
|
|
|
;;; (define-class NAME (SUPER ...) SLOT-DEFINITION ... OPTION ...)
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; SLOT-DEFINITION ::= SLOT-NAME | (SLOT-NAME OPTION ...)
|
|
|
|
|
|
;;; OPTION ::= KEYWORD VALUE
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
2009-04-25 14:10:08 +02:00
|
|
|
|
(define (make-class supers slots . options)
|
2015-01-12 21:40:29 +01:00
|
|
|
|
(define (find-duplicate l)
|
|
|
|
|
|
(match l
|
|
|
|
|
|
(() #f)
|
|
|
|
|
|
((head . tail)
|
|
|
|
|
|
(if (memq head tail)
|
|
|
|
|
|
head
|
|
|
|
|
|
(find-duplicate tail)))))
|
|
|
|
|
|
|
2009-11-27 20:50:40 +01:00
|
|
|
|
(let* ((name (get-keyword #:name options (make-unbound)))
|
|
|
|
|
|
(supers (if (not (or-map (lambda (class)
|
|
|
|
|
|
(memq <object>
|
|
|
|
|
|
(class-precedence-list class)))
|
|
|
|
|
|
supers))
|
|
|
|
|
|
(append supers (list <object>))
|
|
|
|
|
|
supers))
|
|
|
|
|
|
(metaclass (or (get-keyword #:metaclass options #f)
|
|
|
|
|
|
(ensure-metaclass supers))))
|
|
|
|
|
|
|
|
|
|
|
|
;; Verify that all direct slots are different and that we don't inherit
|
|
|
|
|
|
;; several time from the same class
|
|
|
|
|
|
(let ((tmp1 (find-duplicate supers))
|
|
|
|
|
|
(tmp2 (find-duplicate (map slot-definition-name slots))))
|
|
|
|
|
|
(if tmp1
|
|
|
|
|
|
(goops-error "make-class: super class ~S is duplicate in class ~S"
|
|
|
|
|
|
tmp1 name))
|
|
|
|
|
|
(if tmp2
|
|
|
|
|
|
(goops-error "make-class: slot ~S is duplicate in class ~S"
|
|
|
|
|
|
tmp2 name)))
|
|
|
|
|
|
|
|
|
|
|
|
;; Everything seems correct, build the class
|
|
|
|
|
|
(apply make metaclass
|
|
|
|
|
|
#:dsupers supers
|
2015-01-09 20:07:06 +01:00
|
|
|
|
#:slots slots
|
2009-11-27 20:50:40 +01:00
|
|
|
|
#:name name
|
|
|
|
|
|
options)))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
;;; (class (SUPER ...) SLOT-DEFINITION ... OPTION ...)
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; SLOT-DEFINITION ::= SLOT-NAME | (SLOT-NAME OPTION ...)
|
|
|
|
|
|
;;; OPTION ::= KEYWORD VALUE
|
|
|
|
|
|
;;;
|
2015-01-04 15:18:39 -05:00
|
|
|
|
(define-syntax class
|
|
|
|
|
|
(lambda (x)
|
|
|
|
|
|
(define (parse-options options)
|
|
|
|
|
|
(syntax-case options ()
|
|
|
|
|
|
(() #'())
|
|
|
|
|
|
((kw arg . options) (keyword? (syntax->datum #'kw))
|
|
|
|
|
|
(with-syntax ((options (parse-options #'options)))
|
|
|
|
|
|
(syntax-case #'kw ()
|
|
|
|
|
|
(#:init-form
|
|
|
|
|
|
#'(kw 'arg #:init-thunk (lambda () arg) . options))
|
|
|
|
|
|
(_
|
|
|
|
|
|
#'(kw arg . options)))))))
|
|
|
|
|
|
(define (check-valid-kwargs args)
|
|
|
|
|
|
(syntax-case args ()
|
|
|
|
|
|
(() #'())
|
|
|
|
|
|
((kw arg . args) (keyword? (syntax->datum #'kw))
|
|
|
|
|
|
#`(kw arg . #,(check-valid-kwargs #'args)))))
|
|
|
|
|
|
(define (parse-slots-and-kwargs args)
|
|
|
|
|
|
(syntax-case args ()
|
|
|
|
|
|
(()
|
|
|
|
|
|
#'(() ()))
|
|
|
|
|
|
((kw . _) (keyword? (syntax->datum #'kw))
|
|
|
|
|
|
#`(() #,(check-valid-kwargs args)))
|
|
|
|
|
|
(((name option ...) args ...)
|
|
|
|
|
|
(with-syntax (((slots kwargs) (parse-slots-and-kwargs #'(args ...)))
|
|
|
|
|
|
((option ...) (parse-options #'(option ...))))
|
|
|
|
|
|
#'(((list 'name option ...) . slots) kwargs)))
|
|
|
|
|
|
((name args ...) (symbol? (syntax->datum #'name))
|
|
|
|
|
|
(with-syntax (((slots kwargs) (parse-slots-and-kwargs #'(args ...))))
|
|
|
|
|
|
#'(('(name) . slots) kwargs)))))
|
|
|
|
|
|
(syntax-case x ()
|
|
|
|
|
|
((class (super ...) arg ...)
|
|
|
|
|
|
(with-syntax ((((slot-def ...) (option ...))
|
|
|
|
|
|
(parse-slots-and-kwargs #'(arg ...))))
|
|
|
|
|
|
#'(make-class (list super ...)
|
|
|
|
|
|
(list slot-def ...)
|
|
|
|
|
|
option ...))))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2009-04-25 14:10:08 +02:00
|
|
|
|
(define-syntax define-class-pre-definition
|
|
|
|
|
|
(lambda (x)
|
|
|
|
|
|
(syntax-case x ()
|
|
|
|
|
|
((_ (k arg rest ...) out ...)
|
2011-05-21 13:12:44 +02:00
|
|
|
|
(keyword? (syntax->datum #'k))
|
|
|
|
|
|
(case (syntax->datum #'k)
|
2009-04-25 14:10:08 +02:00
|
|
|
|
((#:getter #:setter)
|
2011-05-21 13:12:44 +02:00
|
|
|
|
#'(define-class-pre-definition (rest ...)
|
|
|
|
|
|
out ...
|
2015-01-14 20:06:35 +01:00
|
|
|
|
(when (or (not (defined? 'arg))
|
|
|
|
|
|
(not (is-a? arg <generic>)))
|
|
|
|
|
|
(toplevel-define!
|
|
|
|
|
|
'arg
|
|
|
|
|
|
(ensure-generic (if (defined? 'arg) arg #f) 'arg)))))
|
2009-04-25 14:10:08 +02:00
|
|
|
|
((#:accessor)
|
2011-05-21 13:12:44 +02:00
|
|
|
|
#'(define-class-pre-definition (rest ...)
|
|
|
|
|
|
out ...
|
2015-01-14 20:06:35 +01:00
|
|
|
|
(when (or (not (defined? 'arg))
|
|
|
|
|
|
(not (is-a? arg <accessor>)))
|
|
|
|
|
|
(toplevel-define!
|
|
|
|
|
|
'arg
|
|
|
|
|
|
(ensure-accessor (if (defined? 'arg) arg #f) 'arg)))))
|
2009-04-25 14:10:08 +02:00
|
|
|
|
(else
|
2011-05-21 13:12:44 +02:00
|
|
|
|
#'(define-class-pre-definition (rest ...) out ...))))
|
2009-04-25 14:10:08 +02:00
|
|
|
|
((_ () out ...)
|
2011-05-21 13:12:44 +02:00
|
|
|
|
#'(begin out ...)))))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
|
2009-04-25 14:10:08 +02:00
|
|
|
|
;; Some slot options require extra definitions to be made. In
|
|
|
|
|
|
;; particular, we want to make sure that the generic function objects
|
|
|
|
|
|
;; which represent accessors exist before `make-class' tries to add
|
|
|
|
|
|
;; methods to them.
|
|
|
|
|
|
(define-syntax define-class-pre-definitions
|
|
|
|
|
|
(lambda (x)
|
|
|
|
|
|
(syntax-case x ()
|
|
|
|
|
|
((_ () out ...)
|
2011-05-21 13:12:44 +02:00
|
|
|
|
#'(begin out ...))
|
2009-04-25 14:10:08 +02:00
|
|
|
|
((_ (slot rest ...) out ...)
|
2011-05-21 13:12:44 +02:00
|
|
|
|
(keyword? (syntax->datum #'slot))
|
|
|
|
|
|
#'(begin out ...))
|
2009-04-25 14:10:08 +02:00
|
|
|
|
((_ (slot rest ...) out ...)
|
2011-05-21 13:12:44 +02:00
|
|
|
|
(identifier? #'slot)
|
|
|
|
|
|
#'(define-class-pre-definitions (rest ...)
|
|
|
|
|
|
out ...))
|
2009-04-25 14:10:08 +02:00
|
|
|
|
((_ ((slotname slotopt ...) rest ...) out ...)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
#'(define-class-pre-definitions (rest ...)
|
2011-05-21 13:12:44 +02:00
|
|
|
|
out ... (define-class-pre-definition (slotopt ...)))))))
|
2009-04-25 14:10:08 +02:00
|
|
|
|
|
2011-09-02 11:36:14 +02:00
|
|
|
|
(define-syntax-rule (define-class name supers slot ...)
|
|
|
|
|
|
(begin
|
|
|
|
|
|
(define-class-pre-definitions (slot ...))
|
|
|
|
|
|
(if (and (defined? 'name)
|
|
|
|
|
|
(is-a? name <class>)
|
|
|
|
|
|
(memq <object> (class-precedence-list name)))
|
|
|
|
|
|
(class-redefinition name
|
|
|
|
|
|
(class supers slot ... #:name 'name))
|
|
|
|
|
|
(toplevel-define! 'name (class supers slot ... #:name 'name)))))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
|
2011-09-02 11:36:14 +02:00
|
|
|
|
(define-syntax-rule (standard-define-class arg ...)
|
|
|
|
|
|
(define-class arg ...))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; {Generic functions and accessors}
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
2008-10-23 14:24:57 +02:00
|
|
|
|
;; Apparently the desired semantics are that we extend previous
|
|
|
|
|
|
;; procedural definitions, but that if `name' was already a generic, we
|
|
|
|
|
|
;; overwrite its definition.
|
2015-01-04 15:35:25 -05:00
|
|
|
|
(define-syntax define-generic
|
|
|
|
|
|
(lambda (x)
|
|
|
|
|
|
(syntax-case x ()
|
|
|
|
|
|
((define-generic name) (symbol? (syntax->datum #'name))
|
|
|
|
|
|
#'(define name
|
|
|
|
|
|
(if (and (defined? 'name) (is-a? name <generic>))
|
|
|
|
|
|
(make <generic> #:name 'name)
|
|
|
|
|
|
(ensure-generic (if (defined? 'name) name #f) 'name)))))))
|
|
|
|
|
|
|
|
|
|
|
|
(define-syntax define-extended-generic
|
|
|
|
|
|
(lambda (x)
|
|
|
|
|
|
(syntax-case x ()
|
|
|
|
|
|
((define-extended-generic name val) (symbol? (syntax->datum #'name))
|
|
|
|
|
|
#'(define name (make-extended-generic val 'name))))))
|
|
|
|
|
|
|
|
|
|
|
|
(define-syntax define-extended-generics
|
|
|
|
|
|
(lambda (x)
|
|
|
|
|
|
(define (id-append ctx a b)
|
|
|
|
|
|
(datum->syntax ctx (symbol-append (syntax->datum a) (syntax->datum b))))
|
|
|
|
|
|
(syntax-case x ()
|
|
|
|
|
|
((define-extended-generic (name ...) #:prefix (prefix ...))
|
|
|
|
|
|
(and (and-map symbol? (syntax->datum #'(name ...)))
|
|
|
|
|
|
(and-map symbol? (syntax->datum #'(prefix ...))))
|
|
|
|
|
|
(with-syntax ((((val ...)) (map (lambda (name)
|
|
|
|
|
|
(map (lambda (prefix)
|
|
|
|
|
|
(id-append name prefix name))
|
|
|
|
|
|
#'(prefix ...)))
|
|
|
|
|
|
#'(name ...))))
|
|
|
|
|
|
#'(begin
|
|
|
|
|
|
(define-extended-generic name (list val ...))
|
|
|
|
|
|
...))))))
|
2003-01-08 13:24:41 +00:00
|
|
|
|
|
2011-07-07 12:17:08 +02:00
|
|
|
|
(define* (make-generic #:optional name)
|
|
|
|
|
|
(make <generic> #:name name))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2011-07-07 12:17:08 +02:00
|
|
|
|
(define* (make-extended-generic gfs #:optional name)
|
|
|
|
|
|
(let* ((gfs (if (list? gfs) gfs (list gfs)))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(gws? (any (lambda (gf) (is-a? gf <generic-with-setter>)) gfs)))
|
2003-01-08 13:24:41 +00:00
|
|
|
|
(let ((ans (if gws?
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(let* ((sname (and name (make-setter-name name)))
|
|
|
|
|
|
(setters
|
|
|
|
|
|
(append-map (lambda (gf)
|
|
|
|
|
|
(if (is-a? gf <generic-with-setter>)
|
|
|
|
|
|
(list (ensure-generic (setter gf)
|
|
|
|
|
|
sname))
|
|
|
|
|
|
'()))
|
|
|
|
|
|
gfs))
|
|
|
|
|
|
(es (make <extended-generic-with-setter>
|
|
|
|
|
|
#:name name
|
|
|
|
|
|
#:extends gfs
|
|
|
|
|
|
#:setter (make <extended-generic>
|
|
|
|
|
|
#:name sname
|
|
|
|
|
|
#:extends setters))))
|
|
|
|
|
|
(extended-by! setters (setter es))
|
|
|
|
|
|
es)
|
|
|
|
|
|
(make <extended-generic>
|
|
|
|
|
|
#:name name
|
|
|
|
|
|
#:extends gfs))))
|
2003-01-08 13:24:41 +00:00
|
|
|
|
(extended-by! gfs ans)
|
|
|
|
|
|
ans)))
|
|
|
|
|
|
|
|
|
|
|
|
(define (extended-by! gfs eg)
|
|
|
|
|
|
(for-each (lambda (gf)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(slot-set! gf 'extended-by
|
|
|
|
|
|
(cons eg (slot-ref gf 'extended-by))))
|
|
|
|
|
|
gfs)
|
2011-09-02 13:17:19 +02:00
|
|
|
|
(invalidate-method-cache! eg))
|
2003-01-08 13:24:41 +00:00
|
|
|
|
|
|
|
|
|
|
(define (not-extended-by! gfs eg)
|
|
|
|
|
|
(for-each (lambda (gf)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(slot-set! gf 'extended-by
|
|
|
|
|
|
(delq! eg (slot-ref gf 'extended-by))))
|
|
|
|
|
|
gfs)
|
2011-09-02 13:17:19 +02:00
|
|
|
|
(invalidate-method-cache! eg))
|
2003-01-08 13:24:41 +00:00
|
|
|
|
|
2011-07-07 12:17:08 +02:00
|
|
|
|
(define* (ensure-generic old-definition #:optional name)
|
|
|
|
|
|
(cond ((is-a? old-definition <generic>) old-definition)
|
|
|
|
|
|
((procedure-with-setter? old-definition)
|
|
|
|
|
|
(make <generic-with-setter>
|
|
|
|
|
|
#:name name
|
|
|
|
|
|
#:default (procedure old-definition)
|
|
|
|
|
|
#:setter (setter old-definition)))
|
|
|
|
|
|
((procedure? old-definition)
|
|
|
|
|
|
(if (generic-capability? old-definition) old-definition
|
|
|
|
|
|
(make <generic> #:name name #:default old-definition)))
|
|
|
|
|
|
(else (make <generic> #:name name))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2008-10-23 14:24:57 +02:00
|
|
|
|
;; same semantics as <generic>
|
2011-09-02 11:36:14 +02:00
|
|
|
|
(define-syntax-rule (define-accessor name)
|
|
|
|
|
|
(define name
|
|
|
|
|
|
(cond ((not (defined? 'name)) (ensure-accessor #f 'name))
|
|
|
|
|
|
((is-a? name <accessor>) (make <accessor> #:name 'name))
|
|
|
|
|
|
(else (ensure-accessor name 'name)))))
|
2003-03-17 13:53:58 +00:00
|
|
|
|
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(define (make-setter-name name)
|
|
|
|
|
|
(string->symbol (string-append "setter:" (symbol->string name))))
|
|
|
|
|
|
|
2011-07-07 12:17:08 +02:00
|
|
|
|
(define* (make-accessor #:optional name)
|
|
|
|
|
|
(make <accessor>
|
|
|
|
|
|
#:name name
|
|
|
|
|
|
#:setter (make <generic>
|
|
|
|
|
|
#:name (and name (make-setter-name name)))))
|
|
|
|
|
|
|
|
|
|
|
|
(define* (ensure-accessor proc #:optional name)
|
|
|
|
|
|
(cond ((and (is-a? proc <accessor>)
|
|
|
|
|
|
(is-a? (setter proc) <generic>))
|
|
|
|
|
|
proc)
|
|
|
|
|
|
((is-a? proc <generic-with-setter>)
|
|
|
|
|
|
(upgrade-accessor proc (setter proc)))
|
|
|
|
|
|
((is-a? proc <generic>)
|
|
|
|
|
|
(upgrade-accessor proc (make-generic name)))
|
|
|
|
|
|
((procedure-with-setter? proc)
|
|
|
|
|
|
(make <accessor>
|
|
|
|
|
|
#:name name
|
|
|
|
|
|
#:default (procedure proc)
|
|
|
|
|
|
#:setter (ensure-generic (setter proc) name)))
|
|
|
|
|
|
((procedure? proc)
|
|
|
|
|
|
(ensure-accessor (if (generic-capability? proc)
|
|
|
|
|
|
(make <generic> #:name name #:default proc)
|
|
|
|
|
|
(ensure-generic proc name))
|
|
|
|
|
|
name))
|
|
|
|
|
|
(else
|
|
|
|
|
|
(make-accessor name))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2003-03-11 14:50:08 +00:00
|
|
|
|
(define (upgrade-accessor generic setter)
|
2003-01-08 13:24:41 +00:00
|
|
|
|
(let ((methods (slot-ref generic 'methods))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(gws (make (if (is-a? generic <extended-generic>)
|
|
|
|
|
|
<extended-generic-with-setter>
|
|
|
|
|
|
<accessor>)
|
|
|
|
|
|
#:name (generic-function-name generic)
|
|
|
|
|
|
#:extended-by (slot-ref generic 'extended-by)
|
|
|
|
|
|
#:setter setter)))
|
2015-01-14 20:06:35 +01:00
|
|
|
|
(when (is-a? generic <extended-generic>)
|
|
|
|
|
|
(let ((gfs (slot-ref generic 'extends)))
|
|
|
|
|
|
(not-extended-by! gfs generic)
|
|
|
|
|
|
(slot-set! gws 'extends gfs)
|
|
|
|
|
|
(extended-by! gfs gws)))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
;; Steal old methods
|
|
|
|
|
|
(for-each (lambda (method)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(slot-set! method 'generic-function gws))
|
|
|
|
|
|
methods)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(slot-set! gws 'methods methods)
|
2011-09-02 13:17:19 +02:00
|
|
|
|
(invalidate-method-cache! gws)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
gws))
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; {Methods}
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
2014-12-18 21:57:24 +01:00
|
|
|
|
;; Note: `a' and `b' can have unequal lengths (i.e. one can be one
|
|
|
|
|
|
;; element longer than the other when we have a dotted parameter
|
|
|
|
|
|
;; list). For instance, with the call
|
|
|
|
|
|
;;
|
|
|
|
|
|
;; (M 1)
|
|
|
|
|
|
;;
|
|
|
|
|
|
;; with
|
|
|
|
|
|
;;
|
|
|
|
|
|
;; (define-method M (a . l) ....)
|
|
|
|
|
|
;; (define-method M (a) ....)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
;;
|
2014-12-18 21:57:24 +01:00
|
|
|
|
;; we consider that the second method is more specific.
|
2015-01-09 20:07:06 +01:00
|
|
|
|
;;
|
2014-12-18 21:57:24 +01:00
|
|
|
|
;; Precondition: `a' and `b' are methods and are applicable to `types'.
|
|
|
|
|
|
(define (%method-more-specific? a b types)
|
|
|
|
|
|
(let lp ((a-specializers (method-specializers a))
|
|
|
|
|
|
(b-specializers (method-specializers b))
|
|
|
|
|
|
(types types))
|
|
|
|
|
|
(cond
|
|
|
|
|
|
;; (a) less specific than (a b ...) or (a . b)
|
|
|
|
|
|
((null? a-specializers) #t)
|
|
|
|
|
|
;; (a b ...) or (a . b) less specific than (a)
|
|
|
|
|
|
((null? b-specializers) #f)
|
|
|
|
|
|
;; (a . b) less specific than (a b ...)
|
|
|
|
|
|
((not (pair? a-specializers)) #f)
|
|
|
|
|
|
;; (a b ...) more specific than (a . b)
|
|
|
|
|
|
((not (pair? b-specializers)) #t)
|
|
|
|
|
|
(else
|
|
|
|
|
|
(let ((a-specializer (car a-specializers))
|
|
|
|
|
|
(b-specializer (car b-specializers))
|
|
|
|
|
|
(a-specializers (cdr a-specializers))
|
|
|
|
|
|
(b-specializers (cdr b-specializers))
|
|
|
|
|
|
(type (car types))
|
|
|
|
|
|
(types (cdr types)))
|
|
|
|
|
|
(if (eq? a-specializer b-specializer)
|
|
|
|
|
|
(lp a-specializers b-specializers types)
|
|
|
|
|
|
(let lp ((cpl (class-precedence-list type)))
|
|
|
|
|
|
(let ((elt (car cpl)))
|
|
|
|
|
|
(cond
|
|
|
|
|
|
((eq? a-specializer elt) #t)
|
|
|
|
|
|
((eq? b-specializer elt) #f)
|
|
|
|
|
|
(else (lp (cdr cpl))))))))))))
|
|
|
|
|
|
|
2014-12-18 12:51:11 +01:00
|
|
|
|
(define (%sort-applicable-methods methods types)
|
|
|
|
|
|
(sort methods (lambda (a b) (%method-more-specific? a b types))))
|
|
|
|
|
|
|
2015-01-09 22:05:01 +01:00
|
|
|
|
(define (generic-function-methods obj)
|
|
|
|
|
|
"Return the methods of the generic function @var{obj}."
|
|
|
|
|
|
(define (fold-upward method-lists gf)
|
|
|
|
|
|
(cond
|
|
|
|
|
|
((is-a? gf <extended-generic>)
|
|
|
|
|
|
(let lp ((method-lists method-lists) (gfs (slot-ref gf 'extends)))
|
|
|
|
|
|
(match gfs
|
|
|
|
|
|
(() method-lists)
|
|
|
|
|
|
((gf . gfs)
|
|
|
|
|
|
(lp (fold-upward (cons (slot-ref gf 'methods) method-lists) gf)
|
|
|
|
|
|
gfs)))))
|
|
|
|
|
|
(else method-lists)))
|
|
|
|
|
|
(define (fold-downward method-lists gf)
|
|
|
|
|
|
(let lp ((method-lists (cons (slot-ref gf 'methods) method-lists))
|
|
|
|
|
|
(gfs (slot-ref gf 'extended-by)))
|
|
|
|
|
|
(match gfs
|
|
|
|
|
|
(() method-lists)
|
|
|
|
|
|
((gf . gfs)
|
|
|
|
|
|
(lp (fold-downward method-lists gf) gfs)))))
|
|
|
|
|
|
(unless (is-a? obj <generic>)
|
|
|
|
|
|
(scm-error 'wrong-type-arg #f "Not a generic: ~S"
|
|
|
|
|
|
(list obj) #f))
|
|
|
|
|
|
(concatenate (fold-downward (fold-upward '() obj) obj)))
|
|
|
|
|
|
|
2014-12-18 12:51:11 +01:00
|
|
|
|
(define (%compute-applicable-methods gf args)
|
|
|
|
|
|
(define (method-applicable? m types)
|
|
|
|
|
|
(let lp ((specs (method-specializers m)) (types types))
|
|
|
|
|
|
(cond
|
|
|
|
|
|
((null? specs) (null? types))
|
|
|
|
|
|
((not (pair? specs)) #t)
|
|
|
|
|
|
((null? types) #f)
|
|
|
|
|
|
(else
|
|
|
|
|
|
(and (memq (car specs) (class-precedence-list (car types)))
|
|
|
|
|
|
(lp (cdr specs) (cdr types)))))))
|
|
|
|
|
|
(let ((n (length args))
|
|
|
|
|
|
(types (map class-of args)))
|
|
|
|
|
|
(let lp ((methods (generic-function-methods gf))
|
|
|
|
|
|
(applicable '()))
|
|
|
|
|
|
(if (null? methods)
|
|
|
|
|
|
(and (not (null? applicable))
|
|
|
|
|
|
(%sort-applicable-methods applicable types))
|
|
|
|
|
|
(let ((m (car methods)))
|
|
|
|
|
|
(lp (cdr methods)
|
|
|
|
|
|
(if (method-applicable? m types)
|
|
|
|
|
|
(cons m applicable)
|
|
|
|
|
|
applicable)))))))
|
|
|
|
|
|
|
|
|
|
|
|
(define compute-applicable-methods %compute-applicable-methods)
|
|
|
|
|
|
|
2009-04-25 12:50:53 +02:00
|
|
|
|
(define (toplevel-define! name val)
|
|
|
|
|
|
(module-define! (current-module) name val))
|
|
|
|
|
|
|
|
|
|
|
|
(define-syntax define-method
|
|
|
|
|
|
(syntax-rules (setter)
|
|
|
|
|
|
((_ ((setter name) . args) body ...)
|
|
|
|
|
|
(begin
|
2015-01-14 20:06:35 +01:00
|
|
|
|
(when (or (not (defined? 'name))
|
|
|
|
|
|
(not (is-a? name <accessor>)))
|
|
|
|
|
|
(toplevel-define! 'name
|
|
|
|
|
|
(ensure-accessor
|
|
|
|
|
|
(if (defined? 'name) name #f) 'name)))
|
2009-04-25 12:50:53 +02:00
|
|
|
|
(add-method! (setter name) (method args body ...))))
|
|
|
|
|
|
((_ (name . args) body ...)
|
|
|
|
|
|
(begin
|
|
|
|
|
|
;; FIXME: this code is how it always was, but it's quite cracky:
|
|
|
|
|
|
;; it will only define the generic function if it was undefined
|
|
|
|
|
|
;; before (ok), or *was defined to #f*. The latter is crack. But
|
|
|
|
|
|
;; there are bootstrap issues about fixing this -- change it to
|
|
|
|
|
|
;; (is-a? name <generic>) and see.
|
2015-01-14 20:06:35 +01:00
|
|
|
|
(when (or (not (defined? 'name))
|
|
|
|
|
|
(not name))
|
|
|
|
|
|
(toplevel-define! 'name (make <generic> #:name 'name)))
|
2009-04-25 12:50:53 +02:00
|
|
|
|
(add-method! name (method args body ...))))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2009-05-21 13:49:00 +02:00
|
|
|
|
(define-syntax method
|
|
|
|
|
|
(lambda (x)
|
2009-05-21 15:34:29 +02:00
|
|
|
|
(define (parse-args args)
|
|
|
|
|
|
(let lp ((ls args) (formals '()) (specializers '()))
|
2009-05-21 13:49:00 +02:00
|
|
|
|
(syntax-case ls ()
|
2009-05-21 15:34:29 +02:00
|
|
|
|
(((f s) . rest)
|
2011-05-21 13:12:44 +02:00
|
|
|
|
(and (identifier? #'f) (identifier? #'s))
|
|
|
|
|
|
(lp #'rest
|
|
|
|
|
|
(cons #'f formals)
|
|
|
|
|
|
(cons #'s specializers)))
|
2009-05-21 15:34:29 +02:00
|
|
|
|
((f . rest)
|
2011-05-21 13:12:44 +02:00
|
|
|
|
(identifier? #'f)
|
|
|
|
|
|
(lp #'rest
|
|
|
|
|
|
(cons #'f formals)
|
|
|
|
|
|
(cons #'<top> specializers)))
|
2009-05-21 15:34:29 +02:00
|
|
|
|
(()
|
|
|
|
|
|
(list (reverse formals)
|
2011-05-21 13:12:44 +02:00
|
|
|
|
(reverse (cons #''() specializers))))
|
2009-05-21 15:34:29 +02:00
|
|
|
|
(tail
|
2011-05-21 13:12:44 +02:00
|
|
|
|
(identifier? #'tail)
|
|
|
|
|
|
(list (append (reverse formals) #'tail)
|
|
|
|
|
|
(reverse (cons #'<top> specializers)))))))
|
2009-05-21 13:49:00 +02:00
|
|
|
|
|
|
|
|
|
|
(define (find-free-id exp referent)
|
|
|
|
|
|
(syntax-case exp ()
|
|
|
|
|
|
((x . y)
|
2011-05-21 13:12:44 +02:00
|
|
|
|
(or (find-free-id #'x referent)
|
|
|
|
|
|
(find-free-id #'y referent)))
|
2009-05-21 13:49:00 +02:00
|
|
|
|
(x
|
2011-05-21 13:12:44 +02:00
|
|
|
|
(identifier? #'x)
|
|
|
|
|
|
(let ((id (datum->syntax #'x referent)))
|
|
|
|
|
|
(and (free-identifier=? #'x id) id)))
|
2009-05-21 13:49:00 +02:00
|
|
|
|
(_ #f)))
|
|
|
|
|
|
|
|
|
|
|
|
(define (compute-procedure formals body)
|
|
|
|
|
|
(syntax-case body ()
|
|
|
|
|
|
((body0 ...)
|
|
|
|
|
|
(with-syntax ((formals formals))
|
2011-05-21 13:12:44 +02:00
|
|
|
|
#'(lambda formals body0 ...)))))
|
2009-05-21 13:49:00 +02:00
|
|
|
|
|
|
|
|
|
|
(define (->proper args)
|
|
|
|
|
|
(let lp ((ls args) (out '()))
|
|
|
|
|
|
(syntax-case ls ()
|
2011-05-21 13:12:44 +02:00
|
|
|
|
((x . xs) (lp #'xs (cons #'x out)))
|
2009-05-21 13:49:00 +02:00
|
|
|
|
(() (reverse out))
|
2011-05-21 13:12:44 +02:00
|
|
|
|
(tail (reverse (cons #'tail out))))))
|
2009-05-21 13:49:00 +02:00
|
|
|
|
|
|
|
|
|
|
(define (compute-make-procedure formals body next-method)
|
|
|
|
|
|
(syntax-case body ()
|
|
|
|
|
|
((body ...)
|
|
|
|
|
|
(with-syntax ((next-method next-method))
|
|
|
|
|
|
(syntax-case formals ()
|
|
|
|
|
|
((formal ...)
|
2011-05-21 13:12:44 +02:00
|
|
|
|
#'(lambda (real-next-method)
|
|
|
|
|
|
(lambda (formal ...)
|
|
|
|
|
|
(let ((next-method (lambda args
|
|
|
|
|
|
(if (null? args)
|
|
|
|
|
|
(real-next-method formal ...)
|
|
|
|
|
|
(apply real-next-method args)))))
|
|
|
|
|
|
body ...))))
|
2009-05-21 13:49:00 +02:00
|
|
|
|
(formals
|
2011-05-21 13:12:44 +02:00
|
|
|
|
(with-syntax (((formal ...) (->proper #'formals)))
|
|
|
|
|
|
#'(lambda (real-next-method)
|
|
|
|
|
|
(lambda formals
|
|
|
|
|
|
(let ((next-method (lambda args
|
|
|
|
|
|
(if (null? args)
|
|
|
|
|
|
(apply real-next-method formal ...)
|
|
|
|
|
|
(apply real-next-method args)))))
|
|
|
|
|
|
body ...))))))))))
|
2009-05-21 13:49:00 +02:00
|
|
|
|
|
|
|
|
|
|
(define (compute-procedures formals body)
|
|
|
|
|
|
;; So, our use of this is broken, because it operates on the
|
|
|
|
|
|
;; pre-expansion source code. It's equivalent to just searching
|
|
|
|
|
|
;; for referent in the datums. Ah well.
|
|
|
|
|
|
(let ((id (find-free-id body 'next-method)))
|
|
|
|
|
|
(if id
|
|
|
|
|
|
;; return a make-procedure
|
2011-05-21 13:12:44 +02:00
|
|
|
|
(values #'#f
|
2009-05-21 13:49:00 +02:00
|
|
|
|
(compute-make-procedure formals body id))
|
|
|
|
|
|
(values (compute-procedure formals body)
|
2011-05-21 13:12:44 +02:00
|
|
|
|
#'#f))))
|
2009-05-21 13:49:00 +02:00
|
|
|
|
|
|
|
|
|
|
(syntax-case x ()
|
2011-05-21 13:12:44 +02:00
|
|
|
|
((_ args) #'(method args (if #f #f)))
|
2009-05-21 13:49:00 +02:00
|
|
|
|
((_ args body0 body1 ...)
|
2011-05-21 13:12:44 +02:00
|
|
|
|
(with-syntax (((formals (specializer ...)) (parse-args #'args)))
|
2009-05-21 13:49:00 +02:00
|
|
|
|
(call-with-values
|
|
|
|
|
|
(lambda ()
|
2011-05-21 13:12:44 +02:00
|
|
|
|
(compute-procedures #'formals #'(body0 body1 ...)))
|
2009-05-21 13:49:00 +02:00
|
|
|
|
(lambda (procedure make-procedure)
|
|
|
|
|
|
(with-syntax ((procedure procedure)
|
|
|
|
|
|
(make-procedure make-procedure))
|
2011-05-21 13:12:44 +02:00
|
|
|
|
#'(make <method>
|
|
|
|
|
|
#:specializers (cons* specializer ...)
|
|
|
|
|
|
#:formals 'formals
|
|
|
|
|
|
#:body '(body0 body1 ...)
|
|
|
|
|
|
#:make-procedure make-procedure
|
|
|
|
|
|
#:procedure procedure)))))))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2015-01-12 21:43:48 +01:00
|
|
|
|
;;;
|
|
|
|
|
|
;;; {Utilities}
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; These are useful when dealing with method specializers, which might
|
|
|
|
|
|
;;; have a rest argument.
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
|
|
|
|
|
(define (map* fn . l) ; A map which accepts dotted lists (arg lists
|
|
|
|
|
|
(cond ; must be "isomorph"
|
|
|
|
|
|
((null? (car l)) '())
|
|
|
|
|
|
((pair? (car l)) (cons (apply fn (map car l))
|
|
|
|
|
|
(apply map* fn (map cdr l))))
|
|
|
|
|
|
(else (apply fn l))))
|
|
|
|
|
|
|
|
|
|
|
|
(define (for-each* fn . l) ; A for-each which accepts dotted lists (arg lists
|
|
|
|
|
|
(cond ; must be "isomorph"
|
|
|
|
|
|
((null? (car l)) '())
|
|
|
|
|
|
((pair? (car l)) (apply fn (map car l)) (apply for-each* fn (map cdr l)))
|
|
|
|
|
|
(else (apply fn l))))
|
|
|
|
|
|
|
|
|
|
|
|
(define (length* ls)
|
|
|
|
|
|
(do ((n 0 (+ 1 n))
|
|
|
|
|
|
(ls ls (cdr ls)))
|
|
|
|
|
|
((not (pair? ls)) n)))
|
|
|
|
|
|
|
2000-10-25 14:51:33 +00:00
|
|
|
|
;;;
|
|
|
|
|
|
;;; {add-method!}
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
|
|
|
|
|
(define (add-method-in-classes! m)
|
|
|
|
|
|
;; Add method in all the classes which appears in its specializers list
|
|
|
|
|
|
(for-each* (lambda (x)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(let ((dm (class-direct-methods x)))
|
|
|
|
|
|
(unless (memq m dm)
|
|
|
|
|
|
(struct-set! x class-index-direct-methods (cons m dm)))))
|
|
|
|
|
|
(method-specializers m)))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
(define (remove-method-in-classes! m)
|
|
|
|
|
|
;; Remove method in all the classes which appears in its specializers list
|
|
|
|
|
|
(for-each* (lambda (x)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(struct-set! x
|
|
|
|
|
|
class-index-direct-methods
|
|
|
|
|
|
(delv! m (class-direct-methods x))))
|
|
|
|
|
|
(method-specializers m)))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
(define (compute-new-list-of-methods gf new)
|
|
|
|
|
|
(let ((new-spec (method-specializers new))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(methods (slot-ref gf 'methods)))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(let loop ((l methods))
|
|
|
|
|
|
(if (null? l)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(cons new methods)
|
|
|
|
|
|
(if (equal? (method-specializers (car l)) new-spec)
|
|
|
|
|
|
(begin
|
|
|
|
|
|
;; This spec. list already exists. Remove old method from dependents
|
|
|
|
|
|
(remove-method-in-classes! (car l))
|
|
|
|
|
|
(set-car! l new)
|
|
|
|
|
|
methods)
|
|
|
|
|
|
(loop (cdr l)))))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2011-09-02 13:17:19 +02:00
|
|
|
|
(define (method-n-specializers m)
|
|
|
|
|
|
(length* (slot-ref m 'specializers)))
|
|
|
|
|
|
|
|
|
|
|
|
(define (calculate-n-specialized gf)
|
|
|
|
|
|
(fold (lambda (m n) (max n (method-n-specializers m)))
|
|
|
|
|
|
0
|
|
|
|
|
|
(generic-function-methods gf)))
|
|
|
|
|
|
|
|
|
|
|
|
(define (invalidate-method-cache! gf)
|
|
|
|
|
|
(%invalidate-method-cache! gf)
|
|
|
|
|
|
(slot-set! gf 'n-specialized (calculate-n-specialized gf))
|
|
|
|
|
|
(for-each (lambda (gf) (invalidate-method-cache! gf))
|
|
|
|
|
|
(slot-ref gf 'extended-by)))
|
|
|
|
|
|
|
2008-10-31 00:07:04 +01:00
|
|
|
|
(define internal-add-method!
|
|
|
|
|
|
(method ((gf <generic>) (m <method>))
|
|
|
|
|
|
(slot-set! m 'generic-function gf)
|
|
|
|
|
|
(slot-set! gf 'methods (compute-new-list-of-methods gf m))
|
2011-09-02 13:17:19 +02:00
|
|
|
|
(invalidate-method-cache! gf)
|
2008-10-31 00:07:04 +01:00
|
|
|
|
(add-method-in-classes! m)
|
|
|
|
|
|
*unspecified*))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
(define-generic add-method!)
|
|
|
|
|
|
|
2008-10-31 00:07:04 +01:00
|
|
|
|
((method-procedure internal-add-method!) add-method! internal-add-method!)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (add-method! (proc <procedure>) (m <method>))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(if (generic-capability? proc)
|
|
|
|
|
|
(begin
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(enable-primitive-generic! proc)
|
|
|
|
|
|
(add-method! proc m))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(next-method)))
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (add-method! (pg <primitive-generic>) (m <method>))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(add-method! (primitive-generic-generic pg) m))
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (add-method! obj (m <method>))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(goops-error "~S is not a valid generic function" obj))
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; {Access to meta objects}
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; Methods
|
|
|
|
|
|
;;;
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (method-source (m <method>))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(let* ((spec (map* class-name (slot-ref m 'specializers)))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(src (procedure-source (slot-ref m 'procedure))))
|
2009-03-20 12:06:10 +01:00
|
|
|
|
(and src
|
|
|
|
|
|
(let ((args (cadr src))
|
|
|
|
|
|
(body (cddr src)))
|
|
|
|
|
|
(cons 'method
|
|
|
|
|
|
(cons (map* list args spec)
|
|
|
|
|
|
body))))))
|
|
|
|
|
|
|
|
|
|
|
|
(define-method (method-formals (m <method>))
|
|
|
|
|
|
(slot-ref m 'formals))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; Slots
|
|
|
|
|
|
;;;
|
|
|
|
|
|
(define slot-definition-name car)
|
|
|
|
|
|
|
|
|
|
|
|
(define slot-definition-options cdr)
|
|
|
|
|
|
|
|
|
|
|
|
(define (slot-definition-allocation s)
|
|
|
|
|
|
(get-keyword #:allocation (cdr s) #:instance))
|
|
|
|
|
|
|
|
|
|
|
|
(define (slot-definition-getter s)
|
|
|
|
|
|
(get-keyword #:getter (cdr s) #f))
|
|
|
|
|
|
|
|
|
|
|
|
(define (slot-definition-setter s)
|
|
|
|
|
|
(get-keyword #:setter (cdr s) #f))
|
|
|
|
|
|
|
|
|
|
|
|
(define (slot-definition-accessor s)
|
|
|
|
|
|
(get-keyword #:accessor (cdr s) #f))
|
|
|
|
|
|
|
|
|
|
|
|
(define (slot-definition-init-value s)
|
|
|
|
|
|
;; can be #f, so we can't use #f as non-value
|
|
|
|
|
|
(get-keyword #:init-value (cdr s) (make-unbound)))
|
|
|
|
|
|
|
|
|
|
|
|
(define (slot-definition-init-form s)
|
|
|
|
|
|
(get-keyword #:init-form (cdr s) (make-unbound)))
|
|
|
|
|
|
|
|
|
|
|
|
(define (slot-definition-init-thunk s)
|
|
|
|
|
|
(get-keyword #:init-thunk (cdr s) #f))
|
|
|
|
|
|
|
|
|
|
|
|
(define (slot-definition-init-keyword s)
|
|
|
|
|
|
(get-keyword #:init-keyword (cdr s) #f))
|
|
|
|
|
|
|
|
|
|
|
|
(define (class-slot-definition class slot-name)
|
|
|
|
|
|
(assq slot-name (class-slots class)))
|
|
|
|
|
|
|
|
|
|
|
|
(define (slot-init-function class slot-name)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(cadr (assq slot-name (struct-ref class class-index-getters-n-setters))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
limn goops flags, remove foreign objs, rename entity to applicable-struct
* libguile/goops.c (scm_class_applicable_struct)
(scm_class_applicable_struct_with_setter)
(scm_class_applicable_struct_class): Rename from
scm_class_entity, scm_class_entity_with_setter, and
scm_class_entity_class.
(scm_class_simple_method): Removed; this abstraction is not used.
(scm_class_foreign_class, scm_class_foreign_object): Remove these,
they are undocumented and unused. They might come back later.
(scm_sys_inherit_magic_x): Simply inherit the vtable flags from the
class's class. Flags are about layout, and it is the class that
determines the layout of the instance.
(scm_basic_basic_make_class): Don't bother setting GOOPS_OR_VALID,
inherit-magic will do that.
(scm_basic_make_class): Inherit magic after setting the layout. Allows
the struct magic checker to do its job.
(scm_accessor_method_slot_definition): Move implementation to Scheme.
Removes the need for the accessor flag.
(scm_sys_allocate_instance): Adapt to scm_i_alloc_struct name change,
and that alloc-struct will handle finalization.
(scm_compute_applicable_methods): Remove accessor check, as it's
unnecessary.
(scm_make): Adapt to new generic slot order, and no more
simple-method.
(create_standard_classes): What was the GF slot "dispatch-procedure"
is now the applicable-struct slot "procedure". No more foreign class,
foreign object, or simple method. Rename <entity> and friends to
<applicable-struct> and friends. No more entity-with-setter -- though
perhaps it will come back too. Instead generic-with-setter is its own
thing.
* libguile/goops.h (SCM_CLASSF_METACLASS): "A goops class that is a
vtable" -- no need for a separate flag.
(SCM_CLASSF_FOREIGN, SCM_CLASSF_SIMPLE_METHOD)
(SCM_CLASSF_ACCESSOR_METHOD): Removed these unused flags.
(SCM_ACCESSORP): Removed.
Renumber generic slots, rename entity classes, and remove the foreign
class, foreign object, and simple method classes.
* libguile/struct.c (scm_i_struct_inherit_vtable_magic): New function,
called when making new vtables.applicable structs
(scm_i_alloc_struct): Remove 8-bit alignment check, as libGC
guarantees this for us. Handle finalizer registration here.
(scm_make_struct): Factor some things to scm_i_alloc_struct and
scm_i_struct_inherit_vtable_magic.
(scm_make_vtable_vtable): Adapt to scm_i_alloc_struct name change.
* libguile/struct.h (scm_i_alloc_struct): Change name from
scm_alloc_struct, and make internal.
* module/oop/goops.scm (oop): Don't declare #:replace <class> et al,
because <class> isn't defined in the core any more.
(accessor-method-slot-definition): Defined in Scheme now.
Remove <foreign-object> methods.
(initialize on <class>): Prep layout before inheriting magic, as in
scm_basic_make_class.
* module/oop/goops/dispatch.scm (delayed-compile)
(memoize-effective-method!): Adapt to 'procedure slot name change.
2009-11-08 11:24:23 +01:00
|
|
|
|
(define (accessor-method-slot-definition obj)
|
|
|
|
|
|
"Return the slot definition of the accessor @var{obj}."
|
|
|
|
|
|
(slot-ref obj 'slot-definition))
|
|
|
|
|
|
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; {Standard methods used by the C runtime}
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
|
|
|
|
|
;;; Methods to compare objects
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
2009-11-08 11:49:06 +01:00
|
|
|
|
;; Have to do this in a strange order because equal? is used in the
|
|
|
|
|
|
;; add-method! implementation; we need to make sure that when the
|
|
|
|
|
|
;; primitive is extended, that the generic has a method. =
|
|
|
|
|
|
(define g-equal? (make-generic 'equal?))
|
|
|
|
|
|
;; When this generic gets called, we will have already checked eq? and
|
|
|
|
|
|
;; eqv? -- the purpose of this generic is to extend equality. So by
|
|
|
|
|
|
;; default, there is no extension, thus the #f return.
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(add-method! g-equal? (method (x y) #f))
|
2009-11-08 11:49:06 +01:00
|
|
|
|
(set-primitive-generic! equal? g-equal?)
|
2003-03-06 12:51:57 +00:00
|
|
|
|
|
2000-10-25 14:51:33 +00:00
|
|
|
|
;;;
|
|
|
|
|
|
;;; methods to display/write an object
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
|
|
|
|
|
; Code for writing objects must test that the slots they use are
|
2015-01-09 20:07:06 +01:00
|
|
|
|
; bound. Otherwise a slot-unbound method will be called and will
|
2000-10-25 14:51:33 +00:00
|
|
|
|
; conduct to an infinite loop.
|
|
|
|
|
|
|
|
|
|
|
|
;; Write
|
|
|
|
|
|
(define (display-address o file)
|
|
|
|
|
|
(display (number->string (object-address o) 16) file))
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (write o file)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(display "#<instance " file)
|
|
|
|
|
|
(display-address o file)
|
|
|
|
|
|
(display #\> file))
|
|
|
|
|
|
|
|
|
|
|
|
(define write-object (primitive-generic-generic write))
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (write (o <object>) file)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(let ((class (class-of o)))
|
|
|
|
|
|
(if (slot-bound? class 'name)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(begin
|
|
|
|
|
|
(display "#<" file)
|
|
|
|
|
|
(display (class-name class) file)
|
|
|
|
|
|
(display #\space file)
|
|
|
|
|
|
(display-address o file)
|
|
|
|
|
|
(display #\> file))
|
|
|
|
|
|
(next-method))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (write (class <class>) file)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(let ((meta (class-of class)))
|
|
|
|
|
|
(if (and (slot-bound? class 'name)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(slot-bound? meta 'name))
|
|
|
|
|
|
(begin
|
|
|
|
|
|
(display "#<" file)
|
|
|
|
|
|
(display (class-name meta) file)
|
|
|
|
|
|
(display #\space file)
|
|
|
|
|
|
(display (class-name class) file)
|
|
|
|
|
|
(display #\space file)
|
|
|
|
|
|
(display-address class file)
|
|
|
|
|
|
(display #\> file))
|
|
|
|
|
|
(next-method))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (write (gf <generic>) file)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(let ((meta (class-of gf)))
|
|
|
|
|
|
(if (and (slot-bound? meta 'name)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(slot-bound? gf 'methods))
|
|
|
|
|
|
(begin
|
|
|
|
|
|
(display "#<" file)
|
|
|
|
|
|
(display (class-name meta) file)
|
|
|
|
|
|
(let ((name (generic-function-name gf)))
|
|
|
|
|
|
(if name
|
|
|
|
|
|
(begin
|
|
|
|
|
|
(display #\space file)
|
|
|
|
|
|
(display name file))))
|
|
|
|
|
|
(display " (" file)
|
|
|
|
|
|
(display (length (generic-function-methods gf)) file)
|
|
|
|
|
|
(display ")>" file))
|
|
|
|
|
|
(next-method))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (write (o <method>) file)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(let ((meta (class-of o)))
|
|
|
|
|
|
(if (and (slot-bound? meta 'name)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(slot-bound? o 'specializers))
|
|
|
|
|
|
(begin
|
|
|
|
|
|
(display "#<" file)
|
|
|
|
|
|
(display (class-name meta) file)
|
|
|
|
|
|
(display #\space file)
|
|
|
|
|
|
(display (map* (lambda (spec)
|
|
|
|
|
|
(if (slot-bound? spec 'name)
|
|
|
|
|
|
(slot-ref spec 'name)
|
|
|
|
|
|
spec))
|
|
|
|
|
|
(method-specializers o))
|
|
|
|
|
|
file)
|
|
|
|
|
|
(display #\space file)
|
|
|
|
|
|
(display-address o file)
|
|
|
|
|
|
(display #\> file))
|
|
|
|
|
|
(next-method))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
;; Display (do the same thing as write by default)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(define-method (display o file)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(write-object o file))
|
|
|
|
|
|
|
2003-03-07 13:12:47 +00:00
|
|
|
|
;;;
|
|
|
|
|
|
;;; Handling of duplicate bindings in the module system
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
defining a smob or port type no longer mucks exports of (oop goops)
* libguile/goops.c (DEFVAR): Remove this helper macro, replacing its
uses with scm_module_define, but without scm_module_export.
(create_basic_classes, scm_init_goops_builtins): Update callers.
(make_class_from_template, make_class_from_symbol): Change to not
define variables for classes. This affects ports, struct classes, and
smob classes.
* module/oop/goops.scm: Explicitly list our exports, so there is no more
trickery happening in C.
(find-subclass): Private helper to grub the class hierarchy, so we can
define bindings for smobs, ports, etc. Use to define the classes that
goops.c used to define -- probably a subset, but it's better to have
them listed.
2011-07-01 11:46:32 +02:00
|
|
|
|
(define (find-subclass super name)
|
|
|
|
|
|
(let lp ((classes (class-direct-subclasses super)))
|
|
|
|
|
|
(cond
|
|
|
|
|
|
((null? classes)
|
|
|
|
|
|
(error "class not found" name))
|
|
|
|
|
|
((and (slot-bound? (car classes) 'name)
|
|
|
|
|
|
(eq? (class-name (car classes)) name))
|
|
|
|
|
|
(car classes))
|
|
|
|
|
|
(else
|
|
|
|
|
|
(lp (cdr classes))))))
|
|
|
|
|
|
|
|
|
|
|
|
;; A record type.
|
|
|
|
|
|
(define <module> (find-subclass <top> '<module>))
|
|
|
|
|
|
|
2003-03-07 13:12:47 +00:00
|
|
|
|
(define-method (merge-generics (module <module>)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(name <symbol>)
|
|
|
|
|
|
(int1 <module>)
|
|
|
|
|
|
(val1 <top>)
|
|
|
|
|
|
(int2 <module>)
|
|
|
|
|
|
(val2 <top>)
|
|
|
|
|
|
(var <top>)
|
|
|
|
|
|
(val <top>))
|
2003-03-07 13:12:47 +00:00
|
|
|
|
#f)
|
|
|
|
|
|
|
|
|
|
|
|
(define-method (merge-generics (module <module>)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(name <symbol>)
|
|
|
|
|
|
(int1 <module>)
|
|
|
|
|
|
(val1 <generic>)
|
|
|
|
|
|
(int2 <module>)
|
|
|
|
|
|
(val2 <generic>)
|
|
|
|
|
|
(var <top>)
|
|
|
|
|
|
(val <boolean>))
|
2003-03-12 18:41:44 +00:00
|
|
|
|
(and (not (eq? val1 val2))
|
|
|
|
|
|
(make-variable (make-extended-generic (list val2 val1) name))))
|
2003-03-07 13:12:47 +00:00
|
|
|
|
|
|
|
|
|
|
(define-method (merge-generics (module <module>)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(name <symbol>)
|
|
|
|
|
|
(int1 <module>)
|
|
|
|
|
|
(val1 <generic>)
|
|
|
|
|
|
(int2 <module>)
|
|
|
|
|
|
(val2 <generic>)
|
|
|
|
|
|
(var <top>)
|
|
|
|
|
|
(gf <extended-generic>))
|
2003-03-12 18:41:44 +00:00
|
|
|
|
(and (not (memq val2 (slot-ref gf 'extends)))
|
|
|
|
|
|
(begin
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(slot-set! gf
|
|
|
|
|
|
'extends
|
|
|
|
|
|
(cons val2 (delq! val2 (slot-ref gf 'extends))))
|
|
|
|
|
|
(slot-set! val2
|
|
|
|
|
|
'extended-by
|
|
|
|
|
|
(cons gf (delq! gf (slot-ref val2 'extended-by))))
|
2011-09-02 13:17:19 +02:00
|
|
|
|
(invalidate-method-cache! gf)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
var)))
|
2003-03-07 13:12:47 +00:00
|
|
|
|
|
|
|
|
|
|
(module-define! duplicate-handlers 'merge-generics merge-generics)
|
|
|
|
|
|
|
2003-03-11 14:50:08 +00:00
|
|
|
|
(define-method (merge-accessors (module <module>)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(name <symbol>)
|
|
|
|
|
|
(int1 <module>)
|
|
|
|
|
|
(val1 <top>)
|
|
|
|
|
|
(int2 <module>)
|
|
|
|
|
|
(val2 <top>)
|
|
|
|
|
|
(var <top>)
|
|
|
|
|
|
(val <top>))
|
2003-03-11 14:50:08 +00:00
|
|
|
|
#f)
|
|
|
|
|
|
|
|
|
|
|
|
(define-method (merge-accessors (module <module>)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(name <symbol>)
|
|
|
|
|
|
(int1 <module>)
|
|
|
|
|
|
(val1 <accessor>)
|
|
|
|
|
|
(int2 <module>)
|
|
|
|
|
|
(val2 <accessor>)
|
|
|
|
|
|
(var <top>)
|
|
|
|
|
|
(val <top>))
|
2003-03-11 14:50:08 +00:00
|
|
|
|
(merge-generics module name int1 val1 int2 val2 var val))
|
|
|
|
|
|
|
|
|
|
|
|
(module-define! duplicate-handlers 'merge-accessors merge-accessors)
|
|
|
|
|
|
|
2000-10-25 14:51:33 +00:00
|
|
|
|
;;;
|
|
|
|
|
|
;;; slot access
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
|
|
|
|
|
(define (class-slot-g-n-s class slot-name)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(let* ((this-slot (assq slot-name (struct-ref class class-index-slots)))
|
|
|
|
|
|
(getters-n-setters (struct-ref class class-index-getters-n-setters))
|
|
|
|
|
|
(g-n-s (cddr (or (assq slot-name getters-n-setters)
|
|
|
|
|
|
(slot-missing class slot-name)))))
|
2015-01-14 20:06:35 +01:00
|
|
|
|
(unless (memq (slot-definition-allocation this-slot)
|
|
|
|
|
|
'(#:class #:each-subclass))
|
|
|
|
|
|
(slot-missing class slot-name))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
g-n-s))
|
|
|
|
|
|
|
|
|
|
|
|
(define (class-slot-ref class slot)
|
|
|
|
|
|
(let ((x ((car (class-slot-g-n-s class slot)) #f)))
|
|
|
|
|
|
(if (unbound? x)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(slot-unbound class slot)
|
|
|
|
|
|
x)))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
(define (class-slot-set! class slot value)
|
|
|
|
|
|
((cadr (class-slot-g-n-s class slot)) #f value))
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (slot-unbound (c <class>) (o <object>) s)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(goops-error "Slot `~S' is unbound in object ~S" s o))
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (slot-unbound (c <class>) s)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(goops-error "Slot `~S' is unbound in class ~S" s c))
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (slot-unbound (o <object>))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(goops-error "Unbound slot in object ~S" o))
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (slot-missing (c <class>) (o <object>) s)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(goops-error "No slot with name `~S' in object ~S" s o))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (slot-missing (c <class>) s)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(goops-error "No class slot with name `~S' in class ~S" s c))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (slot-missing (c <class>) (o <object>) s value)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(slot-missing c o s))
|
|
|
|
|
|
|
|
|
|
|
|
;;; Methods for the possible error we can encounter when calling a gf
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (no-next-method (gf <generic>) args)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(goops-error "No next method when calling ~S\nwith arguments ~S" gf args))
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (no-applicable-method (gf <generic>) args)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(goops-error "No applicable method for ~S in call ~S"
|
2015-01-09 20:07:06 +01:00
|
|
|
|
gf (cons (generic-function-name gf) args)))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (no-method (gf <generic>) args)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(goops-error "No method defined for ~S" gf))
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; {Cloning functions (from rdeline@CS.CMU.EDU)}
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (shallow-clone (self <object>))
|
2015-01-11 19:11:41 +01:00
|
|
|
|
(let* ((class (class-of self))
|
|
|
|
|
|
(clone (%allocate-instance class))
|
|
|
|
|
|
(slots (map slot-definition-name (class-slots class))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(for-each (lambda (slot)
|
2015-01-14 20:06:35 +01:00
|
|
|
|
(when (slot-bound? self slot)
|
|
|
|
|
|
(slot-set! clone slot (slot-ref self slot))))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
slots)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
clone))
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (deep-clone (self <object>))
|
2015-01-11 19:11:41 +01:00
|
|
|
|
(let* ((class (class-of self))
|
|
|
|
|
|
(clone (%allocate-instance class))
|
|
|
|
|
|
(slots (map slot-definition-name (class-slots class))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(for-each (lambda (slot)
|
2015-01-14 20:06:35 +01:00
|
|
|
|
(when (slot-bound? self slot)
|
|
|
|
|
|
(slot-set! clone slot
|
|
|
|
|
|
(let ((value (slot-ref self slot)))
|
|
|
|
|
|
(if (instance? value)
|
|
|
|
|
|
(deep-clone value)
|
|
|
|
|
|
value)))))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
slots)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
clone))
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; {Class redefinition utilities}
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
|
|
|
|
|
;;; (class-redefinition OLD NEW)
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
|
|
|
|
|
;;; Has correct the following conditions:
|
|
|
|
|
|
|
|
|
|
|
|
;;; Methods
|
2015-01-09 20:07:06 +01:00
|
|
|
|
;;;
|
2000-10-25 14:51:33 +00:00
|
|
|
|
;;; 1. New accessor specializers refer to new header
|
2015-01-09 20:07:06 +01:00
|
|
|
|
;;;
|
2000-10-25 14:51:33 +00:00
|
|
|
|
;;; Classes
|
2015-01-09 20:07:06 +01:00
|
|
|
|
;;;
|
2000-10-25 14:51:33 +00:00
|
|
|
|
;;; 1. New class cpl refers to the new class header
|
|
|
|
|
|
;;; 2. Old class header exists on old super classes direct-subclass lists
|
|
|
|
|
|
;;; 3. New class header exists on new super classes direct-subclass lists
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (class-redefinition (old <class>) (new <class>))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
;; Work on direct methods:
|
2015-01-09 20:07:06 +01:00
|
|
|
|
;; 1. Remove accessor methods from the old class
|
|
|
|
|
|
;; 2. Patch the occurences of new in the specializers by old
|
|
|
|
|
|
;; 3. Displace the methods from old to new
|
|
|
|
|
|
(remove-class-accessors! old) ;; -1-
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(let ((methods (class-direct-methods new)))
|
|
|
|
|
|
(for-each (lambda (m)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(update-direct-method! m new old)) ;; -2-
|
2000-10-25 14:51:33 +00:00
|
|
|
|
methods)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(struct-set! new
|
|
|
|
|
|
class-index-direct-methods
|
|
|
|
|
|
(append methods (class-direct-methods old))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
;; Substitute old for new in new cpl
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(set-car! (struct-ref new class-index-cpl) old)
|
|
|
|
|
|
|
2000-10-25 14:51:33 +00:00
|
|
|
|
;; Remove the old class from the direct-subclasses list of its super classes
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(for-each (lambda (c) (struct-set! c class-index-direct-subclasses
|
|
|
|
|
|
(delv! old (class-direct-subclasses c))))
|
|
|
|
|
|
(class-direct-supers old))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
;; Replace the new class with the old in the direct-subclasses of the supers
|
|
|
|
|
|
(for-each (lambda (c)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(struct-set! c class-index-direct-subclasses
|
|
|
|
|
|
(cons old (delv! new (class-direct-subclasses c)))))
|
|
|
|
|
|
(class-direct-supers new))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
;; Swap object headers
|
|
|
|
|
|
(%modify-class old new)
|
|
|
|
|
|
|
|
|
|
|
|
;; Now old is NEW!
|
|
|
|
|
|
|
|
|
|
|
|
;; Redefine all the subclasses of old to take into account modification
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(for-each
|
|
|
|
|
|
(lambda (c)
|
|
|
|
|
|
(update-direct-subclass! c new old))
|
|
|
|
|
|
(class-direct-subclasses new))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
;; Invalidate class so that subsequent instances slot accesses invoke
|
|
|
|
|
|
;; change-object-class
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(struct-set! new class-index-redefined old)
|
Manipulate GOOPS vtable flags from Scheme, for speed
* libguile/goops.h: Remove unimplemented declarations of
scm_make_next_method, scm_sys_invalidate_method_cache_x, and
stklos_version.
(scm_sys_invalidate_class_x): Remove helper definition. This was
exported in the past but shouldn't have been.
* libguile/goops.c (scm_sys_make_vtable_vtable): Rename from
scm_sys_make_root_class, and don't do anything about flags.
(scm_sys_bless_applicable_struct_vtables_x, scm_class_p)
(scm_sys_invalidate_class_x): Remove; we do these in Scheme now.
(scm_init_goops_builtins): Define Scheme values for vtable flags.
* module/oop/goops.scm (vtable-flag-goops-metaclass)
(class-add-flags!, class-clear-flags!, class-has-flags?)
(class?, instance?): New definitions.
(<class>): Add GOOPS metaclass flags from Scheme.
(<applicable-struct-class>, <applicable-struct-with-setter-class>):
Add flags from Scheme.
(make, initialize): Add class flags as appropriate.
(class-redefinition): Clear the "valid" flag on the old class.
(check-slot-args): Use instance? instead of a CPL check.
2015-01-16 11:26:25 +01:00
|
|
|
|
(class-clear-flags! new vtable-flag-goops-valid) ;must come after slot-set!
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
old)
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; remove-class-accessors!
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (remove-class-accessors! (c <class>))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(for-each (lambda (m)
|
2015-01-14 20:06:35 +01:00
|
|
|
|
(when (is-a? m <accessor-method>)
|
|
|
|
|
|
(let ((gf (slot-ref m 'generic-function)))
|
|
|
|
|
|
;; remove the method from its GF
|
|
|
|
|
|
(slot-set! gf 'methods
|
|
|
|
|
|
(delq1! m (slot-ref gf 'methods)))
|
|
|
|
|
|
(invalidate-method-cache! gf)
|
|
|
|
|
|
;; remove the method from its specializers
|
|
|
|
|
|
(remove-method-in-classes! m))))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(class-direct-methods c)))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; update-direct-method!
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (update-direct-method! (m <method>)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(old <class>)
|
|
|
|
|
|
(new <class>))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(let loop ((l (method-specializers m)))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
;; Note: the <top> in dotted list is never used.
|
2000-10-25 14:51:33 +00:00
|
|
|
|
;; So we can work as if we had only proper lists.
|
2015-01-14 20:06:35 +01:00
|
|
|
|
(when (pair? l)
|
|
|
|
|
|
(when (eqv? (car l) old)
|
|
|
|
|
|
(set-car! l new))
|
|
|
|
|
|
(loop (cdr l)))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; update-direct-subclass!
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (update-direct-subclass! (c <class>)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(old <class>)
|
|
|
|
|
|
(new <class>))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(class-redefinition c
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(make-class (class-direct-supers c)
|
|
|
|
|
|
(class-direct-slots c)
|
|
|
|
|
|
#:name (class-name c)
|
|
|
|
|
|
#:metaclass (class-of c))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; {Utilities for INITIALIZE methods}
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
|
|
|
|
|
;;; compute-slot-accessors
|
|
|
|
|
|
;;;
|
2009-11-27 20:50:40 +01:00
|
|
|
|
(define (compute-slot-accessors class slots)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(for-each
|
|
|
|
|
|
(lambda (s g-n-s)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(let ((getter-function (slot-definition-getter s))
|
|
|
|
|
|
(setter-function (slot-definition-setter s))
|
|
|
|
|
|
(accessor (slot-definition-accessor s)))
|
|
|
|
|
|
(if getter-function
|
|
|
|
|
|
(add-method! getter-function
|
|
|
|
|
|
(compute-getter-method class g-n-s)))
|
|
|
|
|
|
(if setter-function
|
|
|
|
|
|
(add-method! setter-function
|
|
|
|
|
|
(compute-setter-method class g-n-s)))
|
|
|
|
|
|
(if accessor
|
|
|
|
|
|
(begin
|
|
|
|
|
|
(add-method! accessor
|
|
|
|
|
|
(compute-getter-method class g-n-s))
|
|
|
|
|
|
(add-method! (setter accessor)
|
|
|
|
|
|
(compute-setter-method class g-n-s))))))
|
|
|
|
|
|
slots (struct-ref class class-index-getters-n-setters)))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (compute-getter-method (class <class>) slotdef)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(let ((init-thunk (cadr slotdef))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(g-n-s (cddr slotdef)))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(make <accessor-method>
|
|
|
|
|
|
#:specializers (list class)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
#:procedure (cond ((pair? g-n-s)
|
|
|
|
|
|
(make-generic-bound-check-getter (car g-n-s)))
|
|
|
|
|
|
(init-thunk
|
|
|
|
|
|
(standard-get g-n-s))
|
|
|
|
|
|
(else
|
|
|
|
|
|
(bound-check-get g-n-s)))
|
|
|
|
|
|
#:slot-definition slotdef)))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (compute-setter-method (class <class>) slotdef)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(let ((g-n-s (cddr slotdef)))
|
|
|
|
|
|
(make <accessor-method>
|
|
|
|
|
|
#:specializers (list class <top>)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
#:procedure (if (pair? g-n-s)
|
|
|
|
|
|
(cadr g-n-s)
|
|
|
|
|
|
(standard-set g-n-s))
|
|
|
|
|
|
#:slot-definition slotdef)))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
(define (make-generic-bound-check-getter proc)
|
2015-01-06 14:54:44 -05:00
|
|
|
|
(lambda (o)
|
|
|
|
|
|
(let ((val (proc o)))
|
|
|
|
|
|
(if (unbound? val)
|
|
|
|
|
|
(slot-unbound o)
|
|
|
|
|
|
val))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2013-11-30 16:40:17 +01:00
|
|
|
|
;;; Pre-generate getters and setters for the first 20 slots.
|
|
|
|
|
|
(define-syntax define-standard-accessor-method
|
|
|
|
|
|
(lambda (stx)
|
|
|
|
|
|
(define num-standard-pre-cache 20)
|
|
|
|
|
|
(syntax-case stx ()
|
|
|
|
|
|
((_ ((proc n) arg ...) body)
|
|
|
|
|
|
#`(define proc
|
|
|
|
|
|
(let ((cache (vector #,@(map (lambda (n*)
|
|
|
|
|
|
#`(lambda (arg ...)
|
|
|
|
|
|
(let ((n #,n*))
|
|
|
|
|
|
body)))
|
|
|
|
|
|
(iota num-standard-pre-cache)))))
|
|
|
|
|
|
(lambda (n)
|
|
|
|
|
|
(if (< n #,num-standard-pre-cache)
|
|
|
|
|
|
(vector-ref cache n)
|
|
|
|
|
|
(lambda (arg ...) body)))))))))
|
2009-02-14 00:24:32 +01:00
|
|
|
|
|
|
|
|
|
|
(define-standard-accessor-method ((bound-check-get n) o)
|
2013-11-30 16:40:17 +01:00
|
|
|
|
(let ((x (struct-ref o n)))
|
2009-02-14 00:24:32 +01:00
|
|
|
|
(if (unbound? x)
|
2009-10-22 22:42:45 +02:00
|
|
|
|
(slot-unbound o)
|
2009-02-14 00:24:32 +01:00
|
|
|
|
x)))
|
|
|
|
|
|
|
|
|
|
|
|
(define-standard-accessor-method ((standard-get n) o)
|
2013-11-30 16:40:17 +01:00
|
|
|
|
(struct-ref o n))
|
2009-02-14 00:24:32 +01:00
|
|
|
|
|
|
|
|
|
|
(define-standard-accessor-method ((standard-set n) o v)
|
2013-11-30 16:40:17 +01:00
|
|
|
|
(struct-set! o n v))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
;;; compute-getters-n-setters
|
2003-04-20 17:35:41 +00:00
|
|
|
|
;;;
|
2009-11-27 20:50:40 +01:00
|
|
|
|
(define (compute-getters-n-setters class slots)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2003-04-17 17:37:11 +00:00
|
|
|
|
(define (compute-slot-init-function name s)
|
|
|
|
|
|
(or (let ((thunk (slot-definition-init-thunk s)))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(and thunk
|
|
|
|
|
|
(if (thunk? thunk)
|
eval.c closures are now applicable smobs, not tc3s
* libguile/debug.c (scm_procedure_name): Remove a SCM_CLOSUREP case and
some dead code.
(scm_procedure_module): Remove. This was introduced a few months ago
for the hygienic expander, but now it is no longer needed, as the
expander keeps track of this information itself.
* libguile/debug.h: Remove scm_procedure_module.
* libguile/eval.c: Instead of using tc3 closures, define a "boot
closure" applicable smob type, and represent closures with that. The
advantage is that after eval.scm is compiled, boot closures take up no
address space (besides a smob number) in the runtime, and require no
special cases in procedure dispatch.
* libguile/eval.h: Remove the internal functions scm_i_call_closure_0
and scm_closure_apply, and the public function scm_closure.
* libguile/gc.c (scm_storage_prehistory): No tc3_closure displacement
registration.
(scm_i_tag_name): Remove closure case, and a dead cclo case.
* libguile/vm.c (apply_foreign):
* libguile/print.c (iprin1):
* libguile/procs.c (scm_procedure_p, scm_procedure_documentation);
* libguile/evalext.c (scm_self_evaluating_p):
* libguile/goops.c (scm_class_of): Remove tc3_closure/tcs_closure cases.
* libguile/hash.c (scm_hasher):
* libguile/hooks.c (scm_add_hook_x): Use new scm_i_procedure_arity.
* libguile/macros.c (macro_print): Print all macros using the same code.
(scm_macro_transformer): Return any procedure, not just programs.
* libguile/procprop.h:
* libguile/procprop.c (scm_i_procedure_arity): Instead of returning a
list that the caller has to parse, have the same prototype as
scm_i_program_arity. An incompatible change, but it's an internal
function anyway.
(scm_procedure_properties, scm_set_procedure_properties)
(scm_procedure_property, scm_set_procedure_property): Remove closure
cases, and use scm_i_program_arity for arity.
* libguile/procs.h (SCM_CLOSUREP, SCM_CLOSCAR, SCM_CODE)
(SCM_CLOSURE_NUM_REQUIRED_ARGS, SCM_CLOSURE_HAS_REST_ARGS)
(SCM_CLOSURE_BODY, SCM_PROCPROPS, SCM_SETPROCPROPS, SCM_ENV)
(SCM_TOP_LEVEL): Remove these macros that pertain to boot closures
only. Only eval.c should know abut boot closures.
* libguile/procs.c (scm_closure_p): Remove this function. There is a
simple stub in deprecated.scm now.
(scm_thunk_p): Use scm_i_program_arity.
* libguile/tags.h (scm_tc3_closure): Remove. Yay, another tc3 to play
with!
(scm_tcs_closures): Remove.
* libguile/validate.h (SCM_VALIDATE_CLOSURE): Remove.
* module/ice-9/deprecated.scm (closure?): Add stub.
* module/ice-9/documentation.scm (object-documentation)
* module/ice-9/session.scm (help-doc, arity)
* module/oop/goops.scm (compute-getters-n-setters)
* module/oop/goops/describe.scm (describe)
* module/system/repl/describe.scm (display-object, display-type):
Remove calls to closure?.
2009-12-04 19:20:11 +01:00
|
|
|
|
thunk
|
|
|
|
|
|
(goops-error "Bad init-thunk for slot `~S' in ~S: ~S"
|
|
|
|
|
|
name class thunk))))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(let ((init (slot-definition-init-value s)))
|
|
|
|
|
|
(and (not (unbound? init))
|
|
|
|
|
|
(lambda () init)))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
(define (verify-accessors slot l)
|
2003-04-13 14:48:35 +00:00
|
|
|
|
(cond ((integer? l))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
((not (and (list? l) (= (length l) 2)))
|
|
|
|
|
|
(goops-error "Bad getter and setter for slot `~S' in ~S: ~S"
|
|
|
|
|
|
slot class l))
|
|
|
|
|
|
(else
|
|
|
|
|
|
(let ((get (car l))
|
|
|
|
|
|
(set (cadr l)))
|
2015-01-14 20:06:35 +01:00
|
|
|
|
(unless (procedure? get)
|
|
|
|
|
|
(goops-error "Bad getter closure for slot `~S' in ~S: ~S"
|
|
|
|
|
|
slot class get))
|
|
|
|
|
|
(unless (procedure? set)
|
|
|
|
|
|
(goops-error "Bad setter closure for slot `~S' in ~S: ~S"
|
|
|
|
|
|
slot class set))))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
(map (lambda (s)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
;; The strange treatment of nfields is due to backward compatibility.
|
|
|
|
|
|
(let* ((index (slot-ref class 'nfields))
|
|
|
|
|
|
(g-n-s (compute-get-n-set class s))
|
|
|
|
|
|
(size (- (slot-ref class 'nfields) index))
|
|
|
|
|
|
(name (slot-definition-name s)))
|
|
|
|
|
|
;; NOTE: The following is interdependent with C macros
|
|
|
|
|
|
;; defined above goops.c:scm_sys_prep_layout_x.
|
|
|
|
|
|
;;
|
|
|
|
|
|
;; For simple instance slots, we have the simplest form
|
|
|
|
|
|
;; '(name init-function . index)
|
|
|
|
|
|
;; For other slots we have
|
|
|
|
|
|
;; '(name init-function getter setter . alloc)
|
|
|
|
|
|
;; where alloc is:
|
|
|
|
|
|
;; '(index size) for instance allocated slots
|
|
|
|
|
|
;; '() for other slots
|
|
|
|
|
|
(verify-accessors name g-n-s)
|
2015-01-22 12:40:43 +01:00
|
|
|
|
(case (slot-definition-allocation s)
|
|
|
|
|
|
((#:each-subclass #:class)
|
|
|
|
|
|
(unless (and (zero? size) (pair? g-n-s))
|
|
|
|
|
|
(error "Class-allocated slots should not reserve fields"))
|
|
|
|
|
|
;; Don't initialize the slot; that's handled when the slot
|
|
|
|
|
|
;; is allocated, in compute-get-n-set.
|
|
|
|
|
|
(cons name (cons #f g-n-s)))
|
|
|
|
|
|
(else
|
|
|
|
|
|
(cons name
|
|
|
|
|
|
(cons (compute-slot-init-function name s)
|
|
|
|
|
|
(if (or (integer? g-n-s)
|
|
|
|
|
|
(zero? size))
|
|
|
|
|
|
g-n-s
|
|
|
|
|
|
(append g-n-s (list index size)))))))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
slots))
|
|
|
|
|
|
|
|
|
|
|
|
;;; compute-cpl
|
|
|
|
|
|
;;;
|
compute-cpl implementation only in Scheme
* libguile/goops.c (build_class_class_slots, create_basic_classes):
Instead of creating <class> with uninitialized `direct-slots',
`slots', and `getters-n-setters' fields and initializing them later,
create <class> with a "boot" version of unspecialized slots and later
replace the fields with specialized slot classes. This allows
slot-ref to work during early boot, which is necessary to move
compute-cpl to Scheme.
(create_standard_classes): Finish initializing <class> here.
(map, filter_cpl, compute_cpl): Remove the boot-time compute-cpl in C
and its helpers.
(scm_basic_basic_make_class): Call compute-cpl in Scheme.
(fix_cpl): Remove; since we use the correct compute-cpl from the
beginning, there's no need to correct for the deficiencies of the C
implementation any more.
(build_slots_list): Adapt to build_class_class_slots change.
* module/oop/goops.scm (compute-std-cpl, compute-cpl): Move these up to
the top, so they can be called by the boot process.
(compute-clos-cpl, top-sort, std-tie-breaker, build-transitive-closure)
(build-constraints): Remove unused private code.
2014-12-24 09:37:14 -05:00
|
|
|
|
|
|
|
|
|
|
;; Replace the bootstrap compute-cpl with this definition.
|
|
|
|
|
|
(define compute-cpl
|
|
|
|
|
|
(make <generic> #:name 'compute-cpl))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (compute-cpl (class <class>))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(compute-std-cpl class class-direct-supers))
|
|
|
|
|
|
|
|
|
|
|
|
;;; compute-get-n-set
|
|
|
|
|
|
;;;
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (compute-get-n-set (class <class>) s)
|
2015-01-22 12:40:43 +01:00
|
|
|
|
(define (class-slot-init-value)
|
|
|
|
|
|
(let ((thunk (slot-definition-init-thunk s)))
|
|
|
|
|
|
(if thunk
|
|
|
|
|
|
(thunk)
|
|
|
|
|
|
(slot-definition-init-value s))))
|
|
|
|
|
|
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(case (slot-definition-allocation s)
|
|
|
|
|
|
((#:instance) ;; Instance slot
|
|
|
|
|
|
;; get-n-set is just its offset
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(let ((already-allocated (struct-ref class class-index-nfields)))
|
|
|
|
|
|
(struct-set! class class-index-nfields (+ already-allocated 1))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
already-allocated))
|
|
|
|
|
|
|
|
|
|
|
|
((#:class) ;; Class slot
|
2015-01-09 20:07:06 +01:00
|
|
|
|
;; Class-slots accessors are implemented as 2 closures around
|
2000-10-25 14:51:33 +00:00
|
|
|
|
;; a Scheme variable. As instance slots, class slots must be
|
|
|
|
|
|
;; unbound at init time.
|
|
|
|
|
|
(let ((name (slot-definition-name s)))
|
|
|
|
|
|
(if (memq name (map slot-definition-name (class-direct-slots class)))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
;; This slot is direct; create a new shared variable
|
|
|
|
|
|
(make-closure-variable class (class-slot-init-value))
|
|
|
|
|
|
;; Slot is inherited. Find its definition in superclass
|
|
|
|
|
|
(let loop ((l (cdr (class-precedence-list class))))
|
|
|
|
|
|
(let ((r (assoc name
|
|
|
|
|
|
(struct-ref (car l)
|
|
|
|
|
|
class-index-getters-n-setters))))
|
|
|
|
|
|
(if r
|
|
|
|
|
|
(cddr r)
|
|
|
|
|
|
(loop (cdr l))))))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
((#:each-subclass) ;; slot shared by instances of direct subclass.
|
|
|
|
|
|
;; (Thomas Buerger, April 1998)
|
2015-01-22 12:40:43 +01:00
|
|
|
|
(make-closure-variable class (class-slot-init-value)))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
((#:virtual) ;; No allocation
|
|
|
|
|
|
;; slot-ref and slot-set! function must be given by the user
|
|
|
|
|
|
(let ((get (get-keyword #:slot-ref (slot-definition-options s) #f))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(set (get-keyword #:slot-set! (slot-definition-options s) #f)))
|
2015-01-14 20:06:35 +01:00
|
|
|
|
(unless (and get set)
|
|
|
|
|
|
(goops-error "You must supply a #:slot-ref and a #:slot-set! in ~S" s))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(list get set)))
|
|
|
|
|
|
(else (next-method))))
|
|
|
|
|
|
|
2015-01-22 12:40:43 +01:00
|
|
|
|
(define (make-closure-variable class value)
|
|
|
|
|
|
(list (lambda (o) value)
|
|
|
|
|
|
(lambda (o v) (set! value v))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (compute-get-n-set (o <object>) s)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(goops-error "Allocation \"~S\" is unknown" (slot-definition-allocation s)))
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (compute-slots (class <class>))
|
Move GOOPS boot to Scheme
* module/oop/goops.scm (build-<class>-slots): New helper, replacing
build_class_class_slots.
(build-slots-list, %compute-getters-n-setters, %compute-layout): New
private helpers, moved here from C.
(%prep-layout!): Reimplement in Scheme.
(make-standard-class): New private helper, replacing
scm_basic_make_class.
(<class>, <top>, <object>): Define in Scheme.
(<foreign-slot>, <protected-slot>, <hidden-slot>, <opaque-slot>,
<read-only-slot>, <self-slot>, <protected-opaque-slot>,
<protected-hidden-slot>, <protected-read-only-slot>, <scm-slot>,
<int-slot>, <float-slot>, <double-slot>, <procedure-class>,
<applicable-struct-class>, <method>, <accessor-method>, <applicable>,
<applicable-struct>, <generic>, <extended-generic>,
<generic-with-setter>, <accessor>, <extended-generic-with-setter>,
<extended-accessor>): Define in Scheme.
(<boolean>, <char>, <list>, <pair>, <null>, <string>, <symbol>,
<vector>, <foreign>, <hashtable>, <fluid>, <dynamic-state>, <frame>,
<vm-continuation>, <bytevector>, <uvec>, <array>, <bitvector>,
<number>, <complex>, <real>, <integer>, <fraction>, <keyword>,
<unknown>, <procedure>, <primitive-generic>, <port>, <input-port>,
<output-port>, <input-output-port>): Define in Scheme.
(compute-slots): Use build-slots-list helper.
* libguile/goops.h:
* libguile/goops.c (scm_basic_basic_make_class, scm_sys_compute_slots)
(scm_sys_prep_layout_x): Remove. These were available to C, but were
undocumented internals that were dangerous, confusing, and
unnecessary.
* libguile/goops.c: Add note about variable versus value references.
Remove internal C routines that were just used during boot, as they
have been moved to Scheme.
(scm_basic_make_class): Change to call out to make-standard-class in
Scheme.
(scm_sys_make_root_class, scm_sys_bless_applicable_struct_vtable_x)
(scm_sys_bless_pure_generic_vtable_x, scm_sys_init_layout_x): New
private helpers.
(scm_sys_goops_early_init): Change to capture values defined in
Scheme.
2015-01-04 13:41:09 -05:00
|
|
|
|
(build-slots-list (class-direct-slots class)
|
|
|
|
|
|
(class-precedence-list class)))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; {Initialize}
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
2015-01-11 00:17:22 +01:00
|
|
|
|
(define *unbound* (make-unbound))
|
|
|
|
|
|
|
|
|
|
|
|
;; FIXME: This could be much more efficient.
|
|
|
|
|
|
(define (%initialize-object obj initargs)
|
|
|
|
|
|
"Initialize the object @var{obj} with the given arguments
|
|
|
|
|
|
var{initargs}."
|
|
|
|
|
|
(unless (instance? obj)
|
|
|
|
|
|
(scm-error 'wrong-type-arg #f "Not an object: ~S"
|
|
|
|
|
|
(list obj) #f))
|
|
|
|
|
|
(unless (even? (length initargs))
|
|
|
|
|
|
(scm-error 'wrong-type-arg #f "Initargs has odd length: ~S"
|
|
|
|
|
|
(list initargs) #f))
|
|
|
|
|
|
(let ((class (class-of obj)))
|
|
|
|
|
|
(define (get-initarg kw)
|
|
|
|
|
|
(if kw
|
|
|
|
|
|
(get-keyword kw initargs *unbound*)
|
|
|
|
|
|
*unbound*))
|
|
|
|
|
|
(let lp ((get-n-set (struct-ref class class-index-getters-n-setters))
|
|
|
|
|
|
(slots (struct-ref class class-index-slots)))
|
|
|
|
|
|
(match slots
|
|
|
|
|
|
(() obj)
|
|
|
|
|
|
(((name . options) . slots)
|
|
|
|
|
|
(match get-n-set
|
|
|
|
|
|
(((_ init-thunk . _) . get-n-set)
|
|
|
|
|
|
(let ((initarg (get-initarg (get-keyword #:init-keyword options))))
|
|
|
|
|
|
(cond
|
|
|
|
|
|
((not (unbound? initarg))
|
|
|
|
|
|
(slot-set! obj name initarg))
|
|
|
|
|
|
(init-thunk
|
|
|
|
|
|
(slot-set! obj name (init-thunk)))))
|
|
|
|
|
|
(lp get-n-set slots))))))))
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (initialize (object <object>) initargs)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(%initialize-object object initargs))
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (initialize (class <class>) initargs)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(next-method)
|
|
|
|
|
|
(let ((dslots (get-keyword #:slots initargs '()))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(supers (get-keyword #:dsupers initargs '())))
|
Manipulate GOOPS vtable flags from Scheme, for speed
* libguile/goops.h: Remove unimplemented declarations of
scm_make_next_method, scm_sys_invalidate_method_cache_x, and
stklos_version.
(scm_sys_invalidate_class_x): Remove helper definition. This was
exported in the past but shouldn't have been.
* libguile/goops.c (scm_sys_make_vtable_vtable): Rename from
scm_sys_make_root_class, and don't do anything about flags.
(scm_sys_bless_applicable_struct_vtables_x, scm_class_p)
(scm_sys_invalidate_class_x): Remove; we do these in Scheme now.
(scm_init_goops_builtins): Define Scheme values for vtable flags.
* module/oop/goops.scm (vtable-flag-goops-metaclass)
(class-add-flags!, class-clear-flags!, class-has-flags?)
(class?, instance?): New definitions.
(<class>): Add GOOPS metaclass flags from Scheme.
(<applicable-struct-class>, <applicable-struct-with-setter-class>):
Add flags from Scheme.
(make, initialize): Add class flags as appropriate.
(class-redefinition): Clear the "valid" flag on the old class.
(check-slot-args): Use instance? instead of a CPL check.
2015-01-16 11:26:25 +01:00
|
|
|
|
(class-add-flags! class (logior vtable-flag-goops-class
|
|
|
|
|
|
vtable-flag-goops-valid))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(let ((name (get-keyword #:name initargs '???)))
|
|
|
|
|
|
(struct-set! class class-index-name name))
|
2015-01-11 16:36:45 +01:00
|
|
|
|
(struct-set! class class-index-nfields 0)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(struct-set! class class-index-direct-supers supers)
|
|
|
|
|
|
(struct-set! class class-index-direct-slots dslots)
|
|
|
|
|
|
(struct-set! class class-index-direct-subclasses '())
|
|
|
|
|
|
(struct-set! class class-index-direct-methods '())
|
|
|
|
|
|
(struct-set! class class-index-cpl (compute-cpl class))
|
|
|
|
|
|
(struct-set! class class-index-redefined #f)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(let ((slots (compute-slots class)))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(struct-set! class class-index-slots slots)
|
|
|
|
|
|
(let ((getters-n-setters (compute-getters-n-setters class slots)))
|
|
|
|
|
|
(struct-set! class class-index-getters-n-setters getters-n-setters))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
;; Build getters - setters - accessors
|
2009-11-27 20:50:40 +01:00
|
|
|
|
(compute-slot-accessors class slots))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
;; Update the "direct-subclasses" of each inherited classes
|
|
|
|
|
|
(for-each (lambda (x)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(let ((dsubs (struct-ref x class-index-direct-subclasses)))
|
|
|
|
|
|
(struct-set! x class-index-direct-subclasses
|
|
|
|
|
|
(cons class dsubs))))
|
|
|
|
|
|
supers)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2015-01-11 22:01:47 +01:00
|
|
|
|
;; Compute struct layout of instances, set the `layout' slot, and
|
|
|
|
|
|
;; update class flags.
|
|
|
|
|
|
(%prep-layout! class)))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
(define (initialize-object-procedure object initargs)
|
|
|
|
|
|
(let ((proc (get-keyword #:procedure initargs #f)))
|
|
|
|
|
|
(cond ((not proc))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
((pair? proc)
|
|
|
|
|
|
(apply slot-set! object 'procedure proc))
|
|
|
|
|
|
(else
|
2010-06-29 09:14:33 +01:00
|
|
|
|
(slot-set! object 'procedure proc)))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
limn goops flags, remove foreign objs, rename entity to applicable-struct
* libguile/goops.c (scm_class_applicable_struct)
(scm_class_applicable_struct_with_setter)
(scm_class_applicable_struct_class): Rename from
scm_class_entity, scm_class_entity_with_setter, and
scm_class_entity_class.
(scm_class_simple_method): Removed; this abstraction is not used.
(scm_class_foreign_class, scm_class_foreign_object): Remove these,
they are undocumented and unused. They might come back later.
(scm_sys_inherit_magic_x): Simply inherit the vtable flags from the
class's class. Flags are about layout, and it is the class that
determines the layout of the instance.
(scm_basic_basic_make_class): Don't bother setting GOOPS_OR_VALID,
inherit-magic will do that.
(scm_basic_make_class): Inherit magic after setting the layout. Allows
the struct magic checker to do its job.
(scm_accessor_method_slot_definition): Move implementation to Scheme.
Removes the need for the accessor flag.
(scm_sys_allocate_instance): Adapt to scm_i_alloc_struct name change,
and that alloc-struct will handle finalization.
(scm_compute_applicable_methods): Remove accessor check, as it's
unnecessary.
(scm_make): Adapt to new generic slot order, and no more
simple-method.
(create_standard_classes): What was the GF slot "dispatch-procedure"
is now the applicable-struct slot "procedure". No more foreign class,
foreign object, or simple method. Rename <entity> and friends to
<applicable-struct> and friends. No more entity-with-setter -- though
perhaps it will come back too. Instead generic-with-setter is its own
thing.
* libguile/goops.h (SCM_CLASSF_METACLASS): "A goops class that is a
vtable" -- no need for a separate flag.
(SCM_CLASSF_FOREIGN, SCM_CLASSF_SIMPLE_METHOD)
(SCM_CLASSF_ACCESSOR_METHOD): Removed these unused flags.
(SCM_ACCESSORP): Removed.
Renumber generic slots, rename entity classes, and remove the foreign
class, foreign object, and simple method classes.
* libguile/struct.c (scm_i_struct_inherit_vtable_magic): New function,
called when making new vtables.applicable structs
(scm_i_alloc_struct): Remove 8-bit alignment check, as libGC
guarantees this for us. Handle finalizer registration here.
(scm_make_struct): Factor some things to scm_i_alloc_struct and
scm_i_struct_inherit_vtable_magic.
(scm_make_vtable_vtable): Adapt to scm_i_alloc_struct name change.
* libguile/struct.h (scm_i_alloc_struct): Change name from
scm_alloc_struct, and make internal.
* module/oop/goops.scm (oop): Don't declare #:replace <class> et al,
because <class> isn't defined in the core any more.
(accessor-method-slot-definition): Defined in Scheme now.
Remove <foreign-object> methods.
(initialize on <class>): Prep layout before inheriting magic, as in
scm_basic_make_class.
* module/oop/goops/dispatch.scm (delayed-compile)
(memoize-effective-method!): Adapt to 'procedure slot name change.
2009-11-08 11:24:23 +01:00
|
|
|
|
(define-method (initialize (applicable-struct <applicable-struct>) initargs)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(next-method)
|
limn goops flags, remove foreign objs, rename entity to applicable-struct
* libguile/goops.c (scm_class_applicable_struct)
(scm_class_applicable_struct_with_setter)
(scm_class_applicable_struct_class): Rename from
scm_class_entity, scm_class_entity_with_setter, and
scm_class_entity_class.
(scm_class_simple_method): Removed; this abstraction is not used.
(scm_class_foreign_class, scm_class_foreign_object): Remove these,
they are undocumented and unused. They might come back later.
(scm_sys_inherit_magic_x): Simply inherit the vtable flags from the
class's class. Flags are about layout, and it is the class that
determines the layout of the instance.
(scm_basic_basic_make_class): Don't bother setting GOOPS_OR_VALID,
inherit-magic will do that.
(scm_basic_make_class): Inherit magic after setting the layout. Allows
the struct magic checker to do its job.
(scm_accessor_method_slot_definition): Move implementation to Scheme.
Removes the need for the accessor flag.
(scm_sys_allocate_instance): Adapt to scm_i_alloc_struct name change,
and that alloc-struct will handle finalization.
(scm_compute_applicable_methods): Remove accessor check, as it's
unnecessary.
(scm_make): Adapt to new generic slot order, and no more
simple-method.
(create_standard_classes): What was the GF slot "dispatch-procedure"
is now the applicable-struct slot "procedure". No more foreign class,
foreign object, or simple method. Rename <entity> and friends to
<applicable-struct> and friends. No more entity-with-setter -- though
perhaps it will come back too. Instead generic-with-setter is its own
thing.
* libguile/goops.h (SCM_CLASSF_METACLASS): "A goops class that is a
vtable" -- no need for a separate flag.
(SCM_CLASSF_FOREIGN, SCM_CLASSF_SIMPLE_METHOD)
(SCM_CLASSF_ACCESSOR_METHOD): Removed these unused flags.
(SCM_ACCESSORP): Removed.
Renumber generic slots, rename entity classes, and remove the foreign
class, foreign object, and simple method classes.
* libguile/struct.c (scm_i_struct_inherit_vtable_magic): New function,
called when making new vtables.applicable structs
(scm_i_alloc_struct): Remove 8-bit alignment check, as libGC
guarantees this for us. Handle finalizer registration here.
(scm_make_struct): Factor some things to scm_i_alloc_struct and
scm_i_struct_inherit_vtable_magic.
(scm_make_vtable_vtable): Adapt to scm_i_alloc_struct name change.
* libguile/struct.h (scm_i_alloc_struct): Change name from
scm_alloc_struct, and make internal.
* module/oop/goops.scm (oop): Don't declare #:replace <class> et al,
because <class> isn't defined in the core any more.
(accessor-method-slot-definition): Defined in Scheme now.
Remove <foreign-object> methods.
(initialize on <class>): Prep layout before inheriting magic, as in
scm_basic_make_class.
* module/oop/goops/dispatch.scm (delayed-compile)
(memoize-effective-method!): Adapt to 'procedure slot name change.
2009-11-08 11:24:23 +01:00
|
|
|
|
(initialize-object-procedure applicable-struct initargs))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
Generics with setters have <applicable-struct-with-setter> layout
* libguile/goops.c (scm_sys_set_object_setter_x): Remove. Instead, we
use slot-set! of 'setter.
(scm_i_define_class_for_vtable): Move lower in the file, and fold in
scm_make_extended_class_from_symbol and make_class_from_symbol.
Properly handle applicable structs with setters.
(scm_class_applicable_struct_with_setter_class): New private capture.
(scm_sys_bless_applicable_struct_vtables_x): Rename to take two
arguments, and bless the second argument as an applicable struct with
setter vtable.
(scm_sys_goops_early_init): Capture setter classes.
* libguile/deprecated.c (SPEC_OF, CPL_OF): Access slots by name, not by
index.
(applicablep, more_specificp): Adapt to use CPL_OF.
(scm_find_method): Access "methods" slot by name.
* libguile/procs.c (scm_setter): Remove special case for generics; if
it's a setter, it will be a normal applicable struct.
* module/oop/goops.scm (<applicable-struct-with-setter-class>)
(<applicable-struct-with-setter>): New classes.
(<generic-with-setter>): Now an instance of the setter metaclass and a
child of the setter class, so that the "setter" slot ends up in the
right place.
(<accessor>, <extended-generic-with-setter>, <extended-accessor>): Be
instances of the setter metaclass.
(<method>, <accessor-method>): Move definitions farther down.
(make): Use slot-set! when initializing setters here.
(initialize): Likewise for <applicable-struct-with-setter>. Remove
specialization for <generic-with-setter>.
2015-01-06 13:41:56 -05:00
|
|
|
|
(define-method (initialize (applicable-struct <applicable-struct-with-setter>)
|
|
|
|
|
|
initargs)
|
|
|
|
|
|
(next-method)
|
|
|
|
|
|
(slot-set! applicable-struct 'setter (get-keyword #:setter initargs #f)))
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (initialize (generic <generic>) initargs)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(let ((previous-definition (get-keyword #:default initargs #f))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(name (get-keyword #:name initargs #f)))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(next-method)
|
|
|
|
|
|
(slot-set! generic 'methods (if (is-a? previous-definition <procedure>)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(list (method args
|
2008-10-31 00:07:04 +01:00
|
|
|
|
(apply previous-definition args)))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
'()))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(if name
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(set-procedure-property! generic 'name name))
|
2015-01-04 15:52:12 -05:00
|
|
|
|
(invalidate-method-cache! generic)))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2003-01-08 13:24:41 +00:00
|
|
|
|
(define-method (initialize (eg <extended-generic>) initargs)
|
|
|
|
|
|
(next-method)
|
|
|
|
|
|
(slot-set! eg 'extends (get-keyword #:extends initargs '())))
|
|
|
|
|
|
|
2001-03-04 20:46:34 +00:00
|
|
|
|
(define dummy-procedure (lambda args *unspecified*))
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (initialize (method <method>) initargs)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(next-method)
|
|
|
|
|
|
(slot-set! method 'generic-function (get-keyword #:generic-function initargs #f))
|
|
|
|
|
|
(slot-set! method 'specializers (get-keyword #:specializers initargs '()))
|
2001-03-04 20:46:34 +00:00
|
|
|
|
(slot-set! method 'procedure
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(get-keyword #:procedure initargs #f))
|
2008-10-24 11:56:31 +02:00
|
|
|
|
(slot-set! method 'formals (get-keyword #:formals initargs '()))
|
|
|
|
|
|
(slot-set! method 'body (get-keyword #:body initargs '()))
|
don't re-enter the compiler during method dispatch
* libguile/goops.c (scm_make): In the pre-inst `make', default
`procedure' to #f, and read a `make-procedure' instead of
`compile-env'.
* libguile/goops.h (scm_si_make_procedure): This instead of
scm_si_compile_env.
* module/oop/goops.scm (make-method): Remove this unused function. Users
should use (make <method> ...) directly.
(method): Capture `make-procedure' instead of `procedure' in the case
that the body calls a next-method. Allows for the kind of
"recompilation" that we were using before, but with closures instead of
re-entering the compiler. Type-specific compilation is still
interesting, but probably should be implemented in another way.
(initialize): Default #:procedure to #f, and
s/compile-env/make-procedure/.
* module/oop/goops/compile.scm (code-table-lookup): Just return the
cmethod, not the entry -- since the entry is now just (append types
cmethod).
(compile-make-procedure): New procedure, returns a form that, when
evaluated/compiled, will yield a procedure of one argument, the
next-method. When called with a next-method, the procedure returns an
actual method implementation. compile-make-procedure returns #f if the
body doesn't call next-method.
(compile-method): Unify to always return procedures. Much cleaner and
*much* faster in the compiled case. In the interpreted case, there
might be a slight slowdown, but if there is one it should be slight.
* module/oop/goops/dispatch.scm (method-cache-install!): Adapt to removal
of compute-entry-with-cmethod.
2009-02-13 23:30:20 +01:00
|
|
|
|
(slot-set! method 'make-procedure (get-keyword #:make-procedure initargs #f)))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; {Change-class}
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
|
|
|
|
|
(define (change-object-class old-instance old-class new-class)
|
2001-03-04 05:28:21 +00:00
|
|
|
|
(let ((new-instance (allocate-instance new-class '())))
|
2005-04-24 12:29:14 +00:00
|
|
|
|
;; Initialize the slots of the new instance
|
2015-01-16 13:02:31 +01:00
|
|
|
|
(for-each
|
|
|
|
|
|
(lambda (slot)
|
|
|
|
|
|
(if (and (slot-exists? old-instance slot)
|
|
|
|
|
|
(eq? (slot-definition-allocation
|
|
|
|
|
|
(class-slot-definition old-class slot))
|
|
|
|
|
|
#:instance)
|
|
|
|
|
|
(slot-bound? old-instance slot))
|
|
|
|
|
|
;; Slot was present and allocated in old instance; copy it
|
|
|
|
|
|
(slot-set! new-instance slot (slot-ref old-instance slot))
|
|
|
|
|
|
;; slot was absent; initialize it with its default value
|
|
|
|
|
|
(let ((init (slot-init-function new-class slot)))
|
|
|
|
|
|
(when init
|
|
|
|
|
|
(slot-set! new-instance slot (init))))))
|
|
|
|
|
|
(map slot-definition-name (class-slots new-class)))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
;; Exchange old and new instance in place to keep pointers valid
|
|
|
|
|
|
(%modify-instance old-instance new-instance)
|
|
|
|
|
|
;; Allow class specific updates of instances (which now are swapped)
|
|
|
|
|
|
(update-instance-for-different-class new-instance old-instance)
|
|
|
|
|
|
old-instance))
|
|
|
|
|
|
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (update-instance-for-different-class (old-instance <object>)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(new-instance
|
|
|
|
|
|
<object>))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
;;not really important what we do, we just need a default method
|
|
|
|
|
|
new-instance)
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (change-class (old-instance <object>) (new-class <class>))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(change-object-class old-instance (class-of old-instance) new-class))
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; {make}
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; A new definition which overwrites the previous one which was built-in
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (allocate-instance (class <class>) initargs)
|
2015-01-11 19:11:41 +01:00
|
|
|
|
(%allocate-instance class))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (make-instance (class <class>) . initargs)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(let ((instance (allocate-instance class initargs)))
|
|
|
|
|
|
(initialize instance initargs)
|
|
|
|
|
|
instance))
|
|
|
|
|
|
|
|
|
|
|
|
(define make make-instance)
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; {apply-generic}
|
|
|
|
|
|
;;;
|
2015-01-11 22:23:51 +01:00
|
|
|
|
;;; Protocol for calling generic functions, intended to be used when
|
|
|
|
|
|
;;; applying subclasses of <generic> and <generic-with-setter>. The
|
|
|
|
|
|
;;; code below is similar to the first MOP described in AMOP.
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; Note that standard generic functions dispatch only on the classes of
|
|
|
|
|
|
;;; the arguments, and the result of such dispatch can be memoized. The
|
|
|
|
|
|
;;; `cache-dispatch' routine implements this. `apply-generic' isn't
|
|
|
|
|
|
;;; called currently; the generic function MOP was never fully
|
|
|
|
|
|
;;; implemented in GOOPS. However now that GOOPS is implemented
|
|
|
|
|
|
;;; entirely in Scheme (2015) it's much easier to complete this work.
|
|
|
|
|
|
;;; Contributions gladly accepted! Please read the AMOP first though :)
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; The protocol is:
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; + apply-generic (gf args)
|
|
|
|
|
|
;;; + compute-applicable-methods (gf args ...)
|
|
|
|
|
|
;;; + sort-applicable-methods (gf methods args)
|
|
|
|
|
|
;;; + apply-methods (gf methods args)
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; apply-methods calls make-next-method to build the "continuation" of
|
|
|
|
|
|
;;; a method. Applying a next-method will call apply-next-method which
|
|
|
|
|
|
;;; in turn will call apply again to call effectively the following
|
|
|
|
|
|
;;; method. (This paragraph is out of date but is kept so that maybe it
|
|
|
|
|
|
;;; illuminates some future hack.)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
;;;
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (apply-generic (gf <generic>) args)
|
2015-01-14 20:06:35 +01:00
|
|
|
|
(when (null? (slot-ref gf 'methods))
|
|
|
|
|
|
(no-method gf args))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(let ((methods (compute-applicable-methods gf args)))
|
|
|
|
|
|
(if methods
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(apply-methods gf (sort-applicable-methods gf methods args) args)
|
|
|
|
|
|
(no-applicable-method gf args))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
;; compute-applicable-methods is bound to %compute-applicable-methods.
|
|
|
|
|
|
;; *fixme* use let
|
|
|
|
|
|
(define %%compute-applicable-methods
|
|
|
|
|
|
(make <generic> #:name 'compute-applicable-methods))
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (%%compute-applicable-methods (gf <generic>) args)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(%compute-applicable-methods gf args))
|
|
|
|
|
|
|
|
|
|
|
|
(set! compute-applicable-methods %%compute-applicable-methods)
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (sort-applicable-methods (gf <generic>) methods args)
|
2014-12-18 12:51:11 +01:00
|
|
|
|
(%sort-applicable-methods methods (map class-of args)))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (method-more-specific? (m1 <method>) (m2 <method>) targs)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(%method-more-specific? m1 m2 targs))
|
|
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (apply-method (gf <generic>) methods build-next args)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(apply (method-procedure (car methods))
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(build-next (cdr methods) args)
|
|
|
|
|
|
args))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
2001-03-10 03:09:50 +00:00
|
|
|
|
(define-method (apply-methods (gf <generic>) (l <list>) args)
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(letrec ((next (lambda (procs args)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(lambda new-args
|
|
|
|
|
|
(let ((a (if (null? new-args) args new-args)))
|
|
|
|
|
|
(if (null? procs)
|
|
|
|
|
|
(no-next-method gf a)
|
|
|
|
|
|
(apply-method gf procs next a)))))))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
(apply-method gf l next args)))
|
|
|
|
|
|
|
|
|
|
|
|
;; We don't want the following procedure to turn up in backtraces:
|
|
|
|
|
|
(for-each (lambda (proc)
|
2015-01-09 20:07:06 +01:00
|
|
|
|
(set-procedure-property! proc 'system-procedure #t))
|
|
|
|
|
|
(list slot-unbound
|
|
|
|
|
|
slot-missing
|
|
|
|
|
|
no-next-method
|
|
|
|
|
|
no-applicable-method
|
|
|
|
|
|
no-method
|
|
|
|
|
|
))
|
2000-10-25 14:51:33 +00:00
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; {Final initialization}
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
|
|
|
|
|
;; Tell C code that the main bulk of Goops has been loaded
|
|
|
|
|
|
(%goops-loaded)
|
defining a smob or port type no longer mucks exports of (oop goops)
* libguile/goops.c (DEFVAR): Remove this helper macro, replacing its
uses with scm_module_define, but without scm_module_export.
(create_basic_classes, scm_init_goops_builtins): Update callers.
(make_class_from_template, make_class_from_symbol): Change to not
define variables for classes. This affects ports, struct classes, and
smob classes.
* module/oop/goops.scm: Explicitly list our exports, so there is no more
trickery happening in C.
(find-subclass): Private helper to grub the class hierarchy, so we can
define bindings for smobs, ports, etc. Use to define the classes that
goops.c used to define -- probably a subset, but it's better to have
them listed.
2011-07-01 11:46:32 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;;
|
|
|
|
|
|
;;; {SMOB and port classes}
|
|
|
|
|
|
;;;
|
|
|
|
|
|
|
|
|
|
|
|
(define <arbiter> (find-subclass <top> '<arbiter>))
|
|
|
|
|
|
(define <promise> (find-subclass <top> '<promise>))
|
|
|
|
|
|
(define <thread> (find-subclass <top> '<thread>))
|
|
|
|
|
|
(define <mutex> (find-subclass <top> '<mutex>))
|
|
|
|
|
|
(define <condition-variable> (find-subclass <top> '<condition-variable>))
|
|
|
|
|
|
(define <regexp> (find-subclass <top> '<regexp>))
|
|
|
|
|
|
(define <hook> (find-subclass <top> '<hook>))
|
|
|
|
|
|
(define <bitvector> (find-subclass <top> '<bitvector>))
|
|
|
|
|
|
(define <random-state> (find-subclass <top> '<random-state>))
|
|
|
|
|
|
(define <async> (find-subclass <top> '<async>))
|
|
|
|
|
|
(define <directory> (find-subclass <top> '<directory>))
|
|
|
|
|
|
(define <array> (find-subclass <top> '<array>))
|
|
|
|
|
|
(define <character-set> (find-subclass <top> '<character-set>))
|
|
|
|
|
|
(define <dynamic-object> (find-subclass <top> '<dynamic-object>))
|
|
|
|
|
|
(define <guardian> (find-subclass <applicable> '<guardian>))
|
2011-07-26 11:48:37 +02:00
|
|
|
|
(define <macro> (find-subclass <top> '<macro>))
|
defining a smob or port type no longer mucks exports of (oop goops)
* libguile/goops.c (DEFVAR): Remove this helper macro, replacing its
uses with scm_module_define, but without scm_module_export.
(create_basic_classes, scm_init_goops_builtins): Update callers.
(make_class_from_template, make_class_from_symbol): Change to not
define variables for classes. This affects ports, struct classes, and
smob classes.
* module/oop/goops.scm: Explicitly list our exports, so there is no more
trickery happening in C.
(find-subclass): Private helper to grub the class hierarchy, so we can
define bindings for smobs, ports, etc. Use to define the classes that
goops.c used to define -- probably a subset, but it's better to have
them listed.
2011-07-01 11:46:32 +02:00
|
|
|
|
|
|
|
|
|
|
(define (define-class-subtree class)
|
|
|
|
|
|
(define! (class-name class) class)
|
|
|
|
|
|
(for-each define-class-subtree (class-direct-subclasses class)))
|
|
|
|
|
|
|
|
|
|
|
|
(define-class-subtree (find-subclass <port> '<file-port>))
|