From: Julian Graham <joolean@gmail.com>
To: guile-devel <guile-devel@gnu.org>
Subject: Re: r6rs libraries, round three
Date: Thu, 1 Oct 2009 00:32:06 -0400 [thread overview]
Message-ID: <2bc5f8210909302132w258d3f09tf1259bdfd6b1ca9e@mail.gmail.com> (raw)
In-Reply-To: <2bc5f8210909261310q7a32ff83x8ebceb44a78d55c5@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 830 bytes --]
Hi Guilers,
Okay, after poking around in the manual and the code, it looks like
`load-module' does what I need.
Find attached two patches that, combined, add full support for
R6RS-style version information to Guile's module system. I've done a
bit of testing and believe that this code does the Right Thing in a
variety of situations -- e.g., it always attempts to select the
"highest" version number but can recover from situations in which
paths corresponding to higher-numbered versions don't contain actual
module implementations.
Questions, comments? If it seems like this code is on the right
track, I'll add documentation to the appropriate locations.
boot-9.scm is getting a little bit crowded, though -- I don't suppose
it makes sense to move some of the module handling code to an
auxiliary file?
Regards,
Julian
[-- Attachment #2: 0001-Initial-support-for-version-information-in-Guile-s.patch --]
[-- Type: text/x-diff, Size: 5821 bytes --]
From a1d49c00cd6cc144bf526481e5ba7da6aefa0822 Mon Sep 17 00:00:00 2001
From: Julian Graham <julian.graham@aya.yale.edu>
Date: Sat, 26 Sep 2009 14:52:56 -0400
Subject: [PATCH] Initial support for version information in Guile's `module' form.
* module/ice-9/boot-9.scm (module-version, set-module-version!, version-matches?):
New functions.
* module/ice-9/boot-9.scm (module-type, make-module, resolve-module, try-load-module, process-define-module, make-autoload-interface, compile-interface-spec):
Add awareness and checking of version information.
---
module/ice-9/boot-9.scm | 42 ++++++++++++++++++++++++++++++------------
1 files changed, 30 insertions(+), 12 deletions(-)
diff --git a/module/ice-9/boot-9.scm b/module/ice-9/boot-9.scm
index a1537d1..b49f799 100644
--- a/module/ice-9/boot-9.scm
+++ b/module/ice-9/boot-9.scm
@@ -1332,8 +1332,8 @@
(define module-type
(make-record-type 'module
'(obarray uses binder eval-closure transformer name kind
- duplicates-handlers import-obarray
- observers weak-observers)
+ duplicates-handlers import-obarray observers
+ weak-observers version)
%print-module))
;; make-module &opt size uses binder
@@ -1374,13 +1374,12 @@
#f #f #f
(make-hash-table %default-import-size)
'()
- (make-weak-key-hash-table 31))))
+ (make-weak-key-hash-table 31) #f)))
;; We can't pass this as an argument to module-constructor,
;; because we need it to close over a pointer to the module
;; itself.
(set-module-eval-closure! module (standard-eval-closure module))
-
module))))
(define module-constructor (record-constructor module-type))
@@ -1396,6 +1395,8 @@
(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))
@@ -2008,24 +2009,32 @@
;; Import the default set of bindings (from the SCM module) in MODULE.
(module-use! module the-scm-module)))
+;; Temporary kludge before implementing full version matching.
+(define version-matches? equal?)
+
;; NOTE: This binding is used in libguile/modules.c.
;;
(define resolve-module
(let ((the-root-module the-root-module))
- (lambda (name . maybe-autoload)
+ (lambda (name . args)
(if (equal? name '(guile))
the-root-module
(let ((full-name (append '(%app modules) name)))
- (let ((already (nested-ref the-root-module full-name))
- (autoload (or (null? maybe-autoload) (car maybe-autoload))))
+ (let* ((already (nested-ref the-root-module full-name))
+ (numargs (length args))
+ (autoload (or (= numargs 0) (car args)))
+ (version (and (> numargs 1) (cadr args))))
(cond
((and already (module? already)
(or (not autoload) (module-public-interface already)))
;; A hit, a palpable hit.
+ (and version
+ (not (version-matches? version (module-version already)))
+ (error "incompatible module version already loaded" name))
already)
(autoload
;; Try to autoload the module, and recurse.
- (try-load-module name)
+ (try-load-module name version)
(resolve-module name #f))
(else
;; A module is not bound (but maybe something else is),
@@ -2071,7 +2080,7 @@
;; (define-special-value '(%app modules new-ws) (lambda () (make-scm-module)))
-(define (try-load-module name)
+(define (try-load-module name version)
(try-module-autoload name))
(define (purify-module! module)
@@ -2132,7 +2141,8 @@
(let ((prefix (get-keyword-arg args #:prefix #f)))
(and prefix (symbol-prefix-proc prefix)))
identity))
- (module (resolve-module name))
+ (version (get-keyword-arg args #:version #f))
+ (module (resolve-module name #t version))
(public-i (and module (module-public-interface module))))
(and (or (not module) (not public-i))
(error "no code for module" name))
@@ -2253,6 +2263,12 @@
(purify-module! module)
(loop (cdr kws) reversed-interfaces exports re-exports
replacements autoloads))
+ ((#:version)
+ (or (pair? (cdr kws))
+ (unrecognized kws))
+ (set-module-version! module (cadr kws))
+ (loop (cddr kws) reversed-interfaces exports re-exports
+ replacements autoloads))
((#:duplicates)
(if (not (pair? (cdr kws)))
(unrecognized kws))
@@ -2316,7 +2332,8 @@
(set-car! autoload i)))
(module-local-variable i sym))))))
(module-constructor (make-hash-table 0) '() b #f #f name 'autoload #f
- (make-hash-table 0) '() (make-weak-value-hash-table 31))))
+ (make-hash-table 0) '() (make-weak-value-hash-table 31)
+ #f)))
(define (module-autoload! module . args)
"Have @var{module} automatically load the module named @var{name} when one
@@ -2921,7 +2938,8 @@ module '(ice-9 q) '(make-q q-length))}."
'((:select #:select #t)
(:hide #:hide #t)
(:prefix #:prefix #t)
- (:renamer #:renamer #f)))
+ (:renamer #:renamer #f)
+ (:version #:version #f)))
(if (not (pair? (car spec)))
`(',spec)
`(',(car spec)
--
1.6.0.4
[-- Attachment #3: 0002-Complete-support-for-version-information-in-Guile-s.patch --]
[-- Type: text/x-diff, Size: 6333 bytes --]
From 0c44462a331f3b3b2ce641fd083e11dacc55970b Mon Sep 17 00:00:00 2001
From: Julian Graham <julian.graham@aya.yale.edu>
Date: Thu, 1 Oct 2009 00:16:55 -0400
Subject: [PATCH] Complete support for version information in Guile's `module' form.
* module/ice-9/boot-9.scm (find-versioned-module): New function.
* module/ice-9/boot-9.scm (version-matches?): Implement full R6RS
version-matching syntax.
* module/ice-9/boot-9.scm (try-load-module, try-module-autoload):
Check for version argument and use `find-versioned-module' if
present.
---
module/ice-9/boot-9.scm | 102 ++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 96 insertions(+), 6 deletions(-)
diff --git a/module/ice-9/boot-9.scm b/module/ice-9/boot-9.scm
index b49f799..fd0dea6 100644
--- a/module/ice-9/boot-9.scm
+++ b/module/ice-9/boot-9.scm
@@ -2009,8 +2009,94 @@
;; Import the default set of bindings (from the SCM module) in MODULE.
(module-use! module the-scm-module)))
-;; Temporary kludge before implementing full version matching.
-(define version-matches? equal?)
+(define (version-matches? version-ref target)
+ (define (any prec lst)
+ (and (not (null? lst)) (or (prec (car lst)) (any prec (cdr lst)))))
+ (define (every prec lst)
+ (or (null? lst) (and (prec (car lst)) (every prec (cdr lst)))))
+ (define (sub-versions-match? v-refs t)
+ (define (sub-version-matches? v-ref t)
+ (define (curried-sub-version-matches? v) (sub-version-matches? v t))
+ (cond ((number? v-ref) (eqv? v-ref t))
+ ((list? v-ref)
+ (let ((cv (car v-ref)))
+ (cond ((eq? cv '>=) (>= t (cadr v-ref)))
+ ((eq? cv '<=) (<= t (cadr v-ref)))
+ ((eq? cv 'and)
+ (every curried-sub-version-matches? (cdr v-ref)))
+ ((eq? cv 'or)
+ (any curried-sub-version-matches? (cdr v-ref)))
+ ((eq? cv 'not) (not (sub-version-matches? (cadr v-ref) t)))
+ (else (error "Incompatible sub-version reference" cv)))))
+ (else (error "Incompatible sub-version reference" v-ref))))
+ (or (null? v-refs)
+ (and (not (null? t))
+ (sub-version-matches? (car v-refs) (car t))
+ (sub-versions-match? (cdr v-refs) (cdr t)))))
+ (define (curried-version-matches? v) (version-matches? v target))
+ (or (null? version-ref)
+ (let ((cv (car version-ref)))
+ (cond ((eq? cv 'and) (every curried-version-matches? (cdr version-ref)))
+ ((eq? cv 'or) (any curried-version-matches? (cdr version-ref)))
+ ((eq? cv 'not) (not version-matches? (cadr version-ref) target))
+ (else (sub-versions-match? version-ref target))))))
+
+(define (find-versioned-module dir-hint name version-ref roots)
+ (define (subdir-pair-less pair1 pair2)
+ (define (numlist-less lst1 lst2)
+ (or (null? lst2)
+ (and (not (null? lst1))
+ (cond ((> (car lst1) (car lst2)) #t)
+ ((< (car lst1) (car lst2)) #f)
+ (else (numlist-less (cdr lst1) (cdr lst2)))))))
+ (numlist-less (car pair1) (car pair2)))
+
+ (define (match-version-recursive root-pairs leaf-pairs)
+ (define (filter-subdirs root-pairs ret)
+ (define (filter-subdir root-pair dstrm subdir-pairs)
+ (let ((entry (readdir dstrm)))
+ (if (eof-object? entry)
+ subdir-pairs
+ (let* ((subdir (string-append (cdr root-pair) "/" entry))
+ (num (string->number entry))
+ (num (and num (append (car root-pair) (list num)))))
+ (if (and num (eq? (stat:type (stat subdir)) 'directory))
+ (filter-subdir
+ root-pair dstrm (cons (cons num subdir) subdir-pairs))
+ (filter-subdir root-pair dstrm subdir-pairs))))))
+
+ (or (and (null? root-pairs) ret)
+ (let* ((rp (car root-pairs))
+ (dstrm (false-if-exception (opendir (cdr rp)))))
+ (if dstrm
+ (let ((subdir-pairs (filter-subdir rp dstrm '())))
+ (closedir dstrm)
+ (filter-subdirs (cdr root-pairs)
+ (or (and (null? subdir-pairs) ret)
+ (append ret subdir-pairs))))
+ (filter-subdirs (cdr root-pairs) ret)))))
+
+ (define (match-version-and-file pair)
+ (and (version-matches? version-ref (car pair))
+ (let ((filenames
+ (filter file-exists?
+ (map (lambda (ext)
+ (string-append (cdr pair) "/" name ext))
+ %load-extensions))))
+ (and (not (null? filenames))
+ (cons (car pair) (car filenames))))))
+
+ (or (and (null? root-pairs) leaf-pairs)
+ (let ((matching-subdir-pairs (filter-subdirs root-pairs '())))
+ (match-version-recursive
+ matching-subdir-pairs
+ (append leaf-pairs (filter pair? (map match-version-and-file
+ matching-subdir-pairs)))))))
+
+ (define (make-root-pair root) (cons '() (string-append root "/" dir-hint)))
+ (let ((matches (match-version-recursive (map make-root-pair roots) '())))
+ (and (null? matches) (error "No matching modules found."))
+ (cdar (sort matches subdir-pair-less))))
;; NOTE: This binding is used in libguile/modules.c.
;;
@@ -2081,7 +2167,7 @@
;; (define-special-value '(%app modules new-ws) (lambda () (make-scm-module)))
(define (try-load-module name version)
- (try-module-autoload name))
+ (try-module-autoload name version))
(define (purify-module! module)
"Removes bindings in MODULE which are inherited from the (guile) module."
@@ -2363,9 +2449,10 @@ module '(ice-9 q) '(make-q q-length))}."
;; This function is called from "modules.c". If you change it, be
;; sure to update "modules.c" as well.
-(define (try-module-autoload module-name)
+(define (try-module-autoload module-name . args)
(let* ((reverse-name (reverse module-name))
(name (symbol->string (car reverse-name)))
+ (version (and (not (null? args)) (car args)))
(dir-hint-module-name (reverse (cdr reverse-name)))
(dir-hint (apply string-append
(map (lambda (elt)
@@ -2381,8 +2468,11 @@ module '(ice-9 q) '(make-q q-length))}."
(lambda ()
(save-module-excursion
(lambda ()
- (primitive-load-path (in-vicinity dir-hint name) #f)
- (set! didit #t))))))
+ (if version
+ (load (find-versioned-module
+ dir-hint name version %load-path))
+ (primitive-load-path (in-vicinity dir-hint name) #f))
+ (set! didit #t))))))
(lambda () (set-autoloaded! dir-hint name didit)))
didit))))
--
1.6.0.4
next prev parent reply other threads:[~2009-10-01 4:32 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-09-26 20:10 r6rs libraries, round three Julian Graham
2009-10-01 4:32 ` Julian Graham [this message]
2009-10-24 19:10 ` Julian Graham
2009-10-25 22:01 ` Andy Wingo
2009-10-26 3:53 ` Julian Graham
2009-11-01 19:26 ` Julian Graham
2009-11-16 20:47 ` Julian Graham
2009-11-17 19:56 ` Andy Wingo
2009-11-17 20:55 ` Julian Graham
2009-11-18 1:33 ` Andreas Rottmann
2009-11-18 6:40 ` Julian Graham
2009-12-13 3:24 ` Julian Graham
2009-12-22 0:10 ` Andy Wingo
2009-12-23 15:35 ` Julian Graham
2009-12-23 16:10 ` Neil Jerram
2009-12-28 22:42 ` Ludovic Courtès
2009-12-24 13:25 ` Andy Wingo
2009-12-27 20:04 ` Julian Graham
2009-11-18 1:18 ` Andreas Rottmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/guile/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2bc5f8210909302132w258d3f09tf1259bdfd6b1ca9e@mail.gmail.com \
--to=joolean@gmail.com \
--cc=guile-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).