mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-05-20 11:40:18 +02:00
module-type defined programmatically
* module/ice-9/boot-9.scm (make-record-type): Add an explanatory comment. (%print-module): Remove a hacky comment about redefinitions being difficult, because now the module-printer is called by name from module-type's printer. (module-type): Define the module type, its constructor, predicate, and accessors programmatically, at expansion time. Should reduce any errors in transcription, between adding fields and adding accessors. * libguile/modules.c (scm_lookup_closure_module): Move an explanatory comment here from boot-9.scm.
This commit is contained in:
parent
e31f22ebf0
commit
31ac29b621
2 changed files with 144 additions and 74 deletions
|
@ -242,8 +242,14 @@ scm_lookup_closure_module (SCM proc)
|
||||||
{
|
{
|
||||||
SCM mod;
|
SCM mod;
|
||||||
|
|
||||||
/* FIXME: The `module' property is no longer set. See
|
/* FIXME: The `module' property is no longer set on eval closures, as it
|
||||||
`set-module-eval-closure!' in `boot-9.scm'. */
|
introduced a circular reference that precludes garbage collection of
|
||||||
|
modules with the current weak hash table semantics (see
|
||||||
|
http://lists.gnu.org/archive/html/guile-devel/2009-01/msg00102.html and
|
||||||
|
http://thread.gmane.org/gmane.comp.programming.garbage-collection.boehmgc/2465
|
||||||
|
for details). Since it doesn't appear to be used (only in this
|
||||||
|
function, which has 1 caller), we no longer extend
|
||||||
|
`set-module-eval-closure!' to set the `module' property. */
|
||||||
abort ();
|
abort ();
|
||||||
|
|
||||||
mod = scm_procedure_property (proc, sym_module);
|
mod = scm_procedure_property (proc, sym_module);
|
||||||
|
|
|
@ -651,6 +651,7 @@ If there is no handler at all, Guile prints an error and then exits."
|
||||||
(and (struct? obj) (eq? record-type-vtable (struct-vtable obj))))
|
(and (struct? obj) (eq? record-type-vtable (struct-vtable obj))))
|
||||||
|
|
||||||
(define (make-record-type type-name fields . opt)
|
(define (make-record-type type-name fields . opt)
|
||||||
|
;; Pre-generate constructors for nfields < 20.
|
||||||
(define-syntax make-constructor
|
(define-syntax make-constructor
|
||||||
(lambda (x)
|
(lambda (x)
|
||||||
(define *max-static-argument-count* 20)
|
(define *max-static-argument-count* 20)
|
||||||
|
@ -1423,12 +1424,7 @@ If there is no handler at all, Guile prints an error and then exits."
|
||||||
;;;
|
;;;
|
||||||
|
|
||||||
;; This is how modules are printed. You can re-define it.
|
;; This is how modules are printed. You can re-define it.
|
||||||
;; (Redefining is actually more complicated than simply redefining
|
(define (%print-module mod port)
|
||||||
;; %print-module because that would only change the binding and not
|
|
||||||
;; the value stored in the vtable that determines how record are
|
|
||||||
;; printed. Sigh.)
|
|
||||||
|
|
||||||
(define (%print-module mod port) ; unused args: depth length style table)
|
|
||||||
(display "#<" port)
|
(display "#<" port)
|
||||||
(display (or (module-kind mod) "module") port)
|
(display (or (module-kind mod) "module") port)
|
||||||
(display " " port)
|
(display " " port)
|
||||||
|
@ -1437,23 +1433,140 @@ If there is no handler at all, Guile prints an error and then exits."
|
||||||
(display (number->string (object-address mod) 16) port)
|
(display (number->string (object-address mod) 16) port)
|
||||||
(display ">" port))
|
(display ">" port))
|
||||||
|
|
||||||
;; module-type
|
(letrec-syntax
|
||||||
;;
|
;; Locally extend the syntax to allow record accessors to be defined at
|
||||||
;; A module is characterized by an obarray in which local symbols
|
;; compile-time. Cache the rtd locally to the constructor, the getters and
|
||||||
;; are interned, a list of modules, "uses", from which non-local
|
;; the setters, in order to allow for redefinition of the record type; not
|
||||||
;; bindings can be inherited, and an optional lazy-binder which
|
;; relevant in the case of modules, but perhaps if we make this public, it
|
||||||
;; is a (CLOSURE module symbol) which, as a last resort, can provide
|
;; could matter.
|
||||||
;; bindings that would otherwise not be found locally in the module.
|
|
||||||
;;
|
((define-record-type
|
||||||
;; NOTE: If you change anything here, you also need to change
|
(lambda (x)
|
||||||
;; libguile/modules.h.
|
(define (make-id scope . fragments)
|
||||||
;;
|
(datum->syntax #'scope
|
||||||
(define module-type
|
(apply symbol-append
|
||||||
(make-record-type 'module
|
(map (lambda (x)
|
||||||
'(obarray uses binder eval-closure transformer name kind
|
(if (symbol? x) x (syntax->datum x)))
|
||||||
duplicates-handlers import-obarray
|
fragments))))
|
||||||
observers weak-observers version)
|
|
||||||
%print-module))
|
(define (getter rtd type-name field slot)
|
||||||
|
#`(define #,(make-id rtd type-name '- field)
|
||||||
|
(let ((rtd #,rtd))
|
||||||
|
(lambda (#,type-name)
|
||||||
|
(if (eq? (struct-vtable #,type-name) rtd)
|
||||||
|
(struct-ref #,type-name #,slot)
|
||||||
|
(%record-type-error rtd #,type-name))))))
|
||||||
|
|
||||||
|
(define (setter rtd type-name field slot)
|
||||||
|
#`(define #,(make-id rtd 'set- type-name '- field '!)
|
||||||
|
(let ((rtd #,rtd))
|
||||||
|
(lambda (#,type-name val)
|
||||||
|
(if (eq? (struct-vtable #,type-name) rtd)
|
||||||
|
(struct-set! #,type-name #,slot val)
|
||||||
|
(%record-type-error rtd #,type-name))))))
|
||||||
|
|
||||||
|
(define (accessors rtd type-name fields n exp)
|
||||||
|
(syntax-case fields ()
|
||||||
|
(() exp)
|
||||||
|
(((field #:no-accessors) field* ...) (identifier? #'field)
|
||||||
|
(accessors rtd type-name #'(field* ...) (1+ n)
|
||||||
|
exp))
|
||||||
|
(((field #:no-setter) field* ...) (identifier? #'field)
|
||||||
|
(accessors rtd type-name #'(field* ...) (1+ n)
|
||||||
|
#`(begin #,exp
|
||||||
|
#,(getter rtd type-name #'field n))))
|
||||||
|
(((field #:no-getter) field* ...) (identifier? #'field)
|
||||||
|
(accessors rtd type-name #'(field* ...) (1+ n)
|
||||||
|
#`(begin #,exp
|
||||||
|
#,(setter rtd type-name #'field n))))
|
||||||
|
((field field* ...) (identifier? #'field)
|
||||||
|
(accessors rtd type-name #'(field* ...) (1+ n)
|
||||||
|
#`(begin #,exp
|
||||||
|
#,(getter rtd type-name #'field n)
|
||||||
|
#,(setter rtd type-name #'field n))))))
|
||||||
|
|
||||||
|
(define (predicate rtd type-name fields exp)
|
||||||
|
(accessors
|
||||||
|
rtd type-name fields 0
|
||||||
|
#`(begin
|
||||||
|
#,exp
|
||||||
|
(define (#,(make-id rtd type-name '?) obj)
|
||||||
|
(and (struct? obj) (eq? (struct-vtable obj) #,rtd))))))
|
||||||
|
|
||||||
|
(define (field-list fields)
|
||||||
|
(syntax-case fields ()
|
||||||
|
(() '())
|
||||||
|
(((f . opts) . rest) (identifier? #'f)
|
||||||
|
(cons #'f (field-list #'rest)))
|
||||||
|
((f . rest) (identifier? #'f)
|
||||||
|
(cons #'f (field-list #'rest)))))
|
||||||
|
|
||||||
|
(define (constructor rtd type-name fields exp)
|
||||||
|
(let ((ctor (make-id rtd type-name '-constructor))
|
||||||
|
(args (field-list fields)))
|
||||||
|
(predicate rtd type-name fields
|
||||||
|
#`(begin #,exp
|
||||||
|
(define #,ctor
|
||||||
|
(let ((rtd #,rtd))
|
||||||
|
(lambda #,args
|
||||||
|
(make-struct rtd 0 #,@args))))
|
||||||
|
(struct-set! #,rtd (+ vtable-offset-user 2)
|
||||||
|
#,ctor)))))
|
||||||
|
|
||||||
|
(define (type type-name printer fields)
|
||||||
|
(define (make-layout)
|
||||||
|
(let lp ((fields fields) (slots '()))
|
||||||
|
(syntax-case fields ()
|
||||||
|
(() (datum->syntax #'here
|
||||||
|
(make-struct-layout
|
||||||
|
(apply string-append slots))))
|
||||||
|
((_ . rest) (lp #'rest (cons "pw" slots))))))
|
||||||
|
|
||||||
|
(let ((rtd (make-id type-name type-name '-type)))
|
||||||
|
(constructor rtd type-name fields
|
||||||
|
#`(begin
|
||||||
|
(define #,rtd
|
||||||
|
(make-struct record-type-vtable 0
|
||||||
|
'#,(make-layout)
|
||||||
|
#,printer
|
||||||
|
'#,type-name
|
||||||
|
'#,(field-list fields)))
|
||||||
|
(set-struct-vtable-name! #,rtd '#,type-name)))))
|
||||||
|
|
||||||
|
(syntax-case x ()
|
||||||
|
((_ type-name printer (field ...))
|
||||||
|
(type #'type-name #'printer #'(field ...)))))))
|
||||||
|
|
||||||
|
;; module-type
|
||||||
|
;;
|
||||||
|
;; A module is characterized by an obarray in which local symbols
|
||||||
|
;; are interned, a list of modules, "uses", from which non-local
|
||||||
|
;; bindings can be inherited, and an optional lazy-binder which
|
||||||
|
;; is a (CLOSURE module symbol) which, as a last resort, can provide
|
||||||
|
;; bindings that would otherwise not be found locally in the module.
|
||||||
|
;;
|
||||||
|
;; NOTE: If you change the set of fields or their order, you also need to
|
||||||
|
;; change the constants in libguile/modules.h.
|
||||||
|
;;
|
||||||
|
;; NOTE: The getter `module-eval-closure' is used in libguile/modules.c.
|
||||||
|
;; NOTE: The getter `module-transfomer' is defined libguile/modules.c.
|
||||||
|
;; NOTE: The getter `module-name' is defined later, due to boot reasons.
|
||||||
|
;;
|
||||||
|
(define-record-type module
|
||||||
|
(lambda (obj port) (%print-module obj port))
|
||||||
|
(obarray
|
||||||
|
uses
|
||||||
|
binder
|
||||||
|
eval-closure
|
||||||
|
(transformer #:no-getter)
|
||||||
|
(name #:no-getter)
|
||||||
|
kind
|
||||||
|
duplicates-handlers
|
||||||
|
(import-obarray #:no-setter)
|
||||||
|
observers
|
||||||
|
(weak-observers #:no-setter)
|
||||||
|
version)))
|
||||||
|
|
||||||
|
|
||||||
;; make-module &opt size uses binder
|
;; make-module &opt size uses binder
|
||||||
;;
|
;;
|
||||||
|
@ -1502,55 +1615,6 @@ If there is no handler at all, Guile prints an error and then exits."
|
||||||
|
|
||||||
module))))
|
module))))
|
||||||
|
|
||||||
(define module-constructor (record-constructor module-type))
|
|
||||||
(define module-obarray (record-accessor module-type 'obarray))
|
|
||||||
(define set-module-obarray! (record-modifier module-type 'obarray))
|
|
||||||
(define module-uses (record-accessor module-type 'uses))
|
|
||||||
(define set-module-uses! (record-modifier module-type 'uses))
|
|
||||||
(define module-binder (record-accessor module-type 'binder))
|
|
||||||
(define set-module-binder! (record-modifier module-type 'binder))
|
|
||||||
|
|
||||||
;; NOTE: This binding is used in libguile/modules.c.
|
|
||||||
(define module-eval-closure (record-accessor module-type 'eval-closure))
|
|
||||||
|
|
||||||
;; (define module-transformer (record-accessor module-type 'transformer))
|
|
||||||
(define set-module-transformer! (record-modifier module-type 'transformer))
|
|
||||||
(define module-version (record-accessor module-type 'version))
|
|
||||||
(define set-module-version! (record-modifier module-type 'version))
|
|
||||||
;; (define module-name (record-accessor module-type 'name)) wait until mods are booted
|
|
||||||
(define set-module-name! (record-modifier module-type 'name))
|
|
||||||
(define module-kind (record-accessor module-type 'kind))
|
|
||||||
(define set-module-kind! (record-modifier module-type 'kind))
|
|
||||||
(define module-duplicates-handlers
|
|
||||||
(record-accessor module-type 'duplicates-handlers))
|
|
||||||
(define set-module-duplicates-handlers!
|
|
||||||
(record-modifier module-type 'duplicates-handlers))
|
|
||||||
(define module-observers (record-accessor module-type 'observers))
|
|
||||||
(define set-module-observers! (record-modifier module-type 'observers))
|
|
||||||
(define module-weak-observers (record-accessor module-type 'weak-observers))
|
|
||||||
(define module? (record-predicate module-type))
|
|
||||||
|
|
||||||
(define module-import-obarray (record-accessor module-type 'import-obarray))
|
|
||||||
|
|
||||||
(define set-module-eval-closure!
|
|
||||||
(let ((setter (record-modifier module-type 'eval-closure)))
|
|
||||||
(lambda (module closure)
|
|
||||||
(setter module closure)
|
|
||||||
;; Make it possible to lookup the module from the environment.
|
|
||||||
;; This implementation is correct since an eval closure can belong
|
|
||||||
;; to maximally one module.
|
|
||||||
|
|
||||||
;; XXX: The following line introduces a circular reference that
|
|
||||||
;; precludes garbage collection of modules with the current weak hash
|
|
||||||
;; table semantics (see
|
|
||||||
;; http://lists.gnu.org/archive/html/guile-devel/2009-01/msg00102.html and
|
|
||||||
;; http://thread.gmane.org/gmane.comp.programming.garbage-collection.boehmgc/2465
|
|
||||||
;; for details). Since it doesn't appear to be used (only in
|
|
||||||
;; `scm_lookup_closure_module ()', which has 1 caller), we just comment
|
|
||||||
;; it out.
|
|
||||||
|
|
||||||
;(set-procedure-property! closure 'module module)
|
|
||||||
)))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue