2007-10-09 07:56:30 -04:00
|
|
|
;;; Copyright (c) 2006, 2007 Abdulaziz Ghuloum and Kent Dybvig
|
|
|
|
;;;
|
|
|
|
;;; Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
;;; copy of this software and associated documentation files (the "Software"),
|
|
|
|
;;; to deal in the Software without restriction, including without limitation
|
|
|
|
;;; the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
;;; and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
;;; Software is furnished to do so, subject to the following conditions:
|
|
|
|
;;;
|
|
|
|
;;; The above copyright notice and this permission notice shall be included in
|
|
|
|
;;; all copies or substantial portions of the Software.
|
|
|
|
;;;
|
|
|
|
;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
;;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
;;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
;;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
;;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
;;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
;;; DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
(library (psyntax library-manager)
|
|
|
|
(export imported-label->binding library-subst installed-libraries
|
2007-10-26 12:41:55 -04:00
|
|
|
visit-library library-name library-version library-exists?
|
|
|
|
find-library-by-name install-library library-spec invoke-library
|
2008-05-01 06:02:36 -04:00
|
|
|
current-library-expander
|
2008-02-18 21:58:11 -05:00
|
|
|
current-library-collection library-path library-extensions
|
|
|
|
serialize-all current-precompiled-library-loader)
|
2008-10-13 17:33:25 -04:00
|
|
|
(import (rnrs) (psyntax compat) (rnrs r5rs))
|
2007-05-04 02:23:19 -04:00
|
|
|
|
|
|
|
(define (make-collection)
|
2007-10-09 07:56:30 -04:00
|
|
|
(let ((set '()))
|
2007-05-04 02:23:19 -04:00
|
|
|
(define (set-cons x ls)
|
|
|
|
(cond
|
2007-10-09 07:56:30 -04:00
|
|
|
((memq x ls) ls)
|
|
|
|
(else (cons x ls))))
|
2007-05-04 02:23:19 -04:00
|
|
|
(case-lambda
|
2007-10-09 07:56:30 -04:00
|
|
|
(() set)
|
|
|
|
((x) (set! set (set-cons x set))))))
|
2007-05-04 02:23:19 -04:00
|
|
|
|
2007-05-05 22:42:26 -04:00
|
|
|
(define current-library-collection
|
2007-05-07 04:04:54 -04:00
|
|
|
;;; this works now because make-collection is a lambda
|
|
|
|
;;; binding and this turns into a complex binding as far
|
|
|
|
;;; as letrec is concerned. It will be more ok once we do
|
|
|
|
;;; letrec*.
|
|
|
|
(make-parameter (make-collection)
|
2007-05-04 02:23:19 -04:00
|
|
|
(lambda (x)
|
|
|
|
(unless (procedure? x)
|
2007-12-15 08:22:49 -05:00
|
|
|
(assertion-violation 'current-library-collection "not a procedure" x))
|
2007-05-04 02:23:19 -04:00
|
|
|
x)))
|
|
|
|
|
2007-05-02 04:48:41 -04:00
|
|
|
(define-record library
|
2008-02-18 19:15:47 -05:00
|
|
|
(id name version imp* vis* inv* subst env visit-state
|
2008-02-18 20:39:42 -05:00
|
|
|
invoke-state visit-code invoke-code visible?
|
|
|
|
source-file-name)
|
2008-10-15 07:44:06 -04:00
|
|
|
(lambda (x p wr)
|
2007-10-09 07:56:30 -04:00
|
|
|
(unless (library? x)
|
2007-12-15 08:22:49 -05:00
|
|
|
(assertion-violation 'record-type-printer "not a library"))
|
2007-10-09 07:56:30 -04:00
|
|
|
(display
|
2007-10-26 01:22:11 -04:00
|
|
|
(format "#<library ~s>"
|
2007-10-26 12:41:55 -04:00
|
|
|
(if (null? (library-version x))
|
2007-10-26 01:22:11 -04:00
|
|
|
(library-name x)
|
2007-10-26 12:41:55 -04:00
|
|
|
(append (library-name x) (list (library-version x)))))
|
2007-10-09 07:56:30 -04:00
|
|
|
p)))
|
2007-05-02 04:48:41 -04:00
|
|
|
|
|
|
|
(define (find-dependencies ls)
|
|
|
|
(cond
|
2007-10-09 07:56:30 -04:00
|
|
|
((null? ls) '())
|
2007-12-15 08:22:49 -05:00
|
|
|
(else (assertion-violation 'find-dependencies "cannot handle deps yet"))))
|
2007-05-02 04:48:41 -04:00
|
|
|
|
|
|
|
(define (find-library-by pred)
|
2007-10-09 07:56:30 -04:00
|
|
|
(let f ((ls ((current-library-collection))))
|
2007-05-02 04:48:41 -04:00
|
|
|
(cond
|
2007-10-09 07:56:30 -04:00
|
|
|
((null? ls) #f)
|
|
|
|
((pred (car ls)) (car ls))
|
|
|
|
(else (f (cdr ls))))))
|
2007-05-02 04:48:41 -04:00
|
|
|
|
2007-05-11 20:32:48 -04:00
|
|
|
(define library-path
|
|
|
|
(make-parameter
|
|
|
|
'(".")
|
|
|
|
(lambda (x)
|
2007-10-09 07:56:30 -04:00
|
|
|
(if (and (list? x) (for-all string? x))
|
|
|
|
(map (lambda (x) x) x)
|
2007-12-15 08:22:49 -05:00
|
|
|
(assertion-violation 'library-path "not a list of strings" x)))))
|
2007-10-09 07:56:30 -04:00
|
|
|
|
2007-12-27 15:16:08 -05:00
|
|
|
(define library-extensions
|
|
|
|
(make-parameter
|
|
|
|
'(".sls" ".ss" ".scm")
|
|
|
|
(lambda (x)
|
|
|
|
(if (and (list? x) (for-all string? x))
|
|
|
|
(map (lambda (x) x) x)
|
|
|
|
(assertion-violation 'library-extensions
|
|
|
|
"not a list of strings" x)))))
|
|
|
|
|
2007-12-13 05:57:15 -05:00
|
|
|
(define (library-name->file-name x)
|
2007-10-09 07:56:30 -04:00
|
|
|
(let-values (((p extract) (open-string-output-port)))
|
|
|
|
(define (display-hex n)
|
|
|
|
(cond
|
|
|
|
((<= 0 n 9) (display n p))
|
|
|
|
(else (display
|
|
|
|
(integer->char
|
|
|
|
(+ (char->integer #\A)
|
|
|
|
(- n 10)))
|
|
|
|
p))))
|
|
|
|
(let f ((ls x))
|
2007-12-27 15:16:08 -05:00
|
|
|
(unless (null? ls)
|
|
|
|
(display "/" p)
|
|
|
|
(for-each
|
|
|
|
(lambda (c)
|
|
|
|
(cond
|
|
|
|
((or (char<=? #\a c #\z)
|
|
|
|
(char<=? #\A c #\Z)
|
|
|
|
(char<=? #\0 c #\9)
|
|
|
|
(memv c '(#\- #\. #\_ #\~)))
|
|
|
|
(display c p))
|
|
|
|
(else
|
|
|
|
(display "%" p)
|
|
|
|
(let ((n (char->integer c)))
|
|
|
|
(display-hex (quotient n 16))
|
|
|
|
(display-hex (remainder n 16))))))
|
|
|
|
(string->list
|
|
|
|
(symbol->string (car ls))))
|
|
|
|
(f (cdr ls))))
|
2007-10-09 07:56:30 -04:00
|
|
|
(extract)))
|
|
|
|
|
2007-05-11 20:32:48 -04:00
|
|
|
(define file-locator
|
|
|
|
(make-parameter
|
|
|
|
(lambda (x)
|
2007-10-09 07:56:30 -04:00
|
|
|
(let ((str (library-name->file-name x)))
|
2007-12-27 15:16:08 -05:00
|
|
|
(let f ((ls (library-path))
|
|
|
|
(exts (library-extensions))
|
|
|
|
(failed-list '()))
|
2007-11-19 02:46:45 -05:00
|
|
|
(cond
|
2007-12-27 15:16:08 -05:00
|
|
|
((null? ls)
|
2008-10-13 17:33:25 -04:00
|
|
|
(file-locator-resolution-error x (reverse failed-list)))
|
|
|
|
((null? exts)
|
2007-12-27 15:16:08 -05:00
|
|
|
(f (cdr ls) (library-extensions) failed-list))
|
2007-11-19 02:46:45 -05:00
|
|
|
(else
|
2007-12-27 15:16:08 -05:00
|
|
|
(let ((name (string-append (car ls) str (car exts))))
|
2007-11-19 02:46:45 -05:00
|
|
|
(if (file-exists? name)
|
|
|
|
name
|
2007-12-27 15:16:08 -05:00
|
|
|
(f ls (cdr exts) (cons name failed-list)))))))))
|
2007-05-11 20:32:48 -04:00
|
|
|
(lambda (f)
|
|
|
|
(if (procedure? f)
|
|
|
|
f
|
2007-12-15 08:22:49 -05:00
|
|
|
(assertion-violation 'file-locator "not a procedure" f)))))
|
2007-05-11 20:32:48 -04:00
|
|
|
|
2008-02-18 21:58:11 -05:00
|
|
|
(define (serialize-all serialize compile)
|
|
|
|
(define (library-desc x)
|
|
|
|
(list (library-id x) (library-name x)))
|
|
|
|
(for-each
|
|
|
|
(lambda (x)
|
|
|
|
(when (library-source-file-name x)
|
|
|
|
(serialize
|
|
|
|
(library-source-file-name x)
|
|
|
|
(list (library-id x)
|
|
|
|
(library-name x)
|
|
|
|
(library-version x)
|
|
|
|
(map library-desc (library-imp* x))
|
|
|
|
(map library-desc (library-vis* x))
|
|
|
|
(map library-desc (library-inv* x))
|
|
|
|
(library-subst x)
|
|
|
|
(library-env x)
|
|
|
|
(compile (library-visit-code x))
|
|
|
|
(compile (library-invoke-code x))
|
|
|
|
(library-visible? x)))))
|
|
|
|
((current-library-collection))))
|
2008-02-17 04:08:38 -05:00
|
|
|
|
2008-02-18 21:58:11 -05:00
|
|
|
(define current-precompiled-library-loader
|
|
|
|
(make-parameter (lambda (filename sk) #f)))
|
|
|
|
|
2008-02-18 20:28:54 -05:00
|
|
|
(define (try-load-from-file filename)
|
2008-02-18 21:58:11 -05:00
|
|
|
((current-precompiled-library-loader)
|
|
|
|
filename
|
2008-02-18 20:28:54 -05:00
|
|
|
(case-lambda
|
2008-10-13 17:33:25 -04:00
|
|
|
((id name ver imp* vis* inv* exp-subst exp-env
|
2008-02-18 20:28:54 -05:00
|
|
|
visit-proc invoke-proc visible?)
|
|
|
|
;;; make sure all dependencies are met
|
|
|
|
;;; if all is ok, install the library
|
|
|
|
;;; otherwise, return #f so that the
|
|
|
|
;;; library gets recompiled.
|
2008-10-13 17:33:25 -04:00
|
|
|
(let f ((deps (append imp* vis* inv*)))
|
2008-02-18 20:28:54 -05:00
|
|
|
(cond
|
2008-10-13 17:33:25 -04:00
|
|
|
((null? deps)
|
2008-02-18 20:28:54 -05:00
|
|
|
(install-library id name ver imp* vis* inv*
|
|
|
|
exp-subst exp-env visit-proc invoke-proc
|
2008-02-18 21:58:11 -05:00
|
|
|
#f #f visible? #f)
|
2008-10-13 17:33:25 -04:00
|
|
|
#t)
|
|
|
|
(else
|
|
|
|
(let ((d (car deps)))
|
|
|
|
(let ((label (car d)) (dname (cadr d)))
|
|
|
|
(let ((l (find-library-by-name dname)))
|
2008-02-18 20:28:54 -05:00
|
|
|
(cond
|
2008-10-13 17:33:25 -04:00
|
|
|
((and (library? l) (eq? label (library-id l)))
|
|
|
|
(f (cdr deps)))
|
|
|
|
(else
|
|
|
|
(library-version-mismatch-warning name dname filename)
|
|
|
|
#f)))))))))
|
|
|
|
(others #f))))
|
2008-02-17 04:08:38 -05:00
|
|
|
|
|
|
|
(define library-loader
|
2007-05-11 20:32:48 -04:00
|
|
|
(make-parameter
|
|
|
|
(lambda (x)
|
2007-10-09 07:56:30 -04:00
|
|
|
(let ((file-name ((file-locator) x)))
|
2008-02-17 04:08:38 -05:00
|
|
|
(cond
|
2008-10-13 17:33:25 -04:00
|
|
|
((not file-name)
|
|
|
|
(assertion-violation #f "cannot file library" x))
|
|
|
|
((try-load-from-file file-name))
|
|
|
|
(else
|
2008-02-18 20:28:54 -05:00
|
|
|
((current-library-expander)
|
2008-05-06 15:38:05 -04:00
|
|
|
(read-library-source-file file-name)
|
2008-06-05 03:58:04 -04:00
|
|
|
file-name
|
|
|
|
(lambda (name)
|
|
|
|
(unless (equal? name x)
|
|
|
|
(assertion-violation 'import
|
2008-10-13 17:33:25 -04:00
|
|
|
(let-values (((p e) (open-string-output-port)))
|
2008-06-05 03:58:04 -04:00
|
|
|
(display "expected to find library " p)
|
|
|
|
(write x p)
|
|
|
|
(display " in file " p)
|
|
|
|
(display file-name p)
|
|
|
|
(display ", found " p)
|
|
|
|
(write name p)
|
|
|
|
(display " instead" p)
|
2008-10-13 17:33:25 -04:00
|
|
|
(e))))))))))
|
2007-05-11 20:32:48 -04:00
|
|
|
(lambda (f)
|
|
|
|
(if (procedure? f)
|
|
|
|
f
|
2007-12-15 08:22:49 -05:00
|
|
|
(assertion-violation 'library-locator
|
2007-10-25 14:32:26 -04:00
|
|
|
"not a procedure" f)))))
|
2007-05-11 20:32:48 -04:00
|
|
|
|
|
|
|
(define current-library-expander
|
|
|
|
(make-parameter
|
|
|
|
(lambda (x)
|
2007-12-15 08:22:49 -05:00
|
|
|
(assertion-violation 'library-expander "not initialized"))
|
2007-05-11 20:32:48 -04:00
|
|
|
(lambda (f)
|
|
|
|
(if (procedure? f)
|
|
|
|
f
|
2007-12-15 08:22:49 -05:00
|
|
|
(assertion-violation 'library-expander
|
2007-10-25 14:32:26 -04:00
|
|
|
"not a procedure" f)))))
|
2007-05-11 20:32:48 -04:00
|
|
|
|
|
|
|
(define external-pending-libraries
|
|
|
|
(make-parameter '()))
|
|
|
|
|
|
|
|
(define (find-external-library name)
|
|
|
|
(when (member name (external-pending-libraries))
|
2008-02-17 02:29:36 -05:00
|
|
|
(assertion-violation #f
|
|
|
|
"circular attempt to import library was detected" name))
|
2007-10-09 07:56:30 -04:00
|
|
|
(parameterize ((external-pending-libraries
|
|
|
|
(cons name (external-pending-libraries))))
|
2008-02-17 04:08:38 -05:00
|
|
|
((library-loader) name)
|
|
|
|
(or (find-library-by
|
|
|
|
(lambda (x) (equal? (library-name x) name)))
|
|
|
|
(assertion-violation #f
|
|
|
|
"handling external library did not yield the correct library"
|
|
|
|
name))))
|
|
|
|
|
2007-05-05 22:42:26 -04:00
|
|
|
(define (find-library-by-name name)
|
2007-05-11 20:32:48 -04:00
|
|
|
(or (find-library-by
|
|
|
|
(lambda (x) (equal? (library-name x) name)))
|
|
|
|
(find-external-library name)))
|
2007-05-02 04:48:41 -04:00
|
|
|
|
2007-05-07 03:45:13 -04:00
|
|
|
(define (library-exists? name)
|
|
|
|
(and (find-library-by
|
|
|
|
(lambda (x) (equal? (library-name x) name)))
|
|
|
|
#t))
|
|
|
|
|
2007-05-02 20:05:19 -04:00
|
|
|
(define (find-library-by-spec/die spec)
|
2007-10-09 07:56:30 -04:00
|
|
|
(let ((id (car spec)))
|
2007-05-02 20:05:19 -04:00
|
|
|
(or (find-library-by
|
|
|
|
(lambda (x) (eq? id (library-id x))))
|
2008-02-18 20:28:54 -05:00
|
|
|
(assertion-violation #f
|
|
|
|
"cannot find library with required spec" spec))))
|
2007-05-02 20:05:19 -04:00
|
|
|
|
2007-10-10 07:09:18 -04:00
|
|
|
(define label->binding-table (make-eq-hashtable))
|
2007-05-06 23:32:51 -04:00
|
|
|
|
2007-05-11 20:32:48 -04:00
|
|
|
(define (install-library-record lib)
|
2007-10-09 07:56:30 -04:00
|
|
|
(let ((exp-env (library-env lib)))
|
2007-05-11 20:32:48 -04:00
|
|
|
(for-each
|
|
|
|
(lambda (x)
|
2007-10-09 07:56:30 -04:00
|
|
|
(let ((label (car x)) (binding (cdr x)))
|
|
|
|
(let ((binding
|
2007-05-11 20:32:48 -04:00
|
|
|
(case (car binding)
|
2007-10-09 07:56:30 -04:00
|
|
|
((global)
|
|
|
|
(cons 'global (cons lib (cdr binding))))
|
|
|
|
((global-macro)
|
|
|
|
(cons 'global-macro (cons lib (cdr binding))))
|
|
|
|
((global-macro!)
|
|
|
|
(cons 'global-macro! (cons lib (cdr binding))))
|
|
|
|
(else binding))))
|
|
|
|
(hashtable-set! label->binding-table label binding))))
|
2007-05-11 20:32:48 -04:00
|
|
|
exp-env))
|
|
|
|
((current-library-collection) lib))
|
|
|
|
|
2008-02-18 20:39:42 -05:00
|
|
|
(define install-library
|
|
|
|
(case-lambda
|
2008-10-13 17:33:25 -04:00
|
|
|
((id name ver imp* vis* inv* exp-subst exp-env
|
2008-02-18 20:39:42 -05:00
|
|
|
visit-proc invoke-proc visit-code invoke-code
|
|
|
|
visible? source-file-name)
|
|
|
|
(let ((imp-lib* (map find-library-by-spec/die imp*))
|
|
|
|
(vis-lib* (map find-library-by-spec/die vis*))
|
|
|
|
(inv-lib* (map find-library-by-spec/die inv*)))
|
|
|
|
(unless (and (symbol? id) (list? name) (list? ver))
|
|
|
|
(assertion-violation 'install-library
|
|
|
|
"invalid spec with id/name/ver" id name ver))
|
|
|
|
(when (library-exists? name)
|
|
|
|
(assertion-violation 'install-library
|
|
|
|
"library is already installed" name))
|
|
|
|
(let ((lib (make-library id name ver imp-lib* vis-lib* inv-lib*
|
|
|
|
exp-subst exp-env visit-proc invoke-proc
|
|
|
|
visit-code invoke-code visible? source-file-name)))
|
2008-10-13 17:33:25 -04:00
|
|
|
(install-library-record lib))))))
|
2007-05-02 06:24:37 -04:00
|
|
|
|
2007-05-05 22:42:26 -04:00
|
|
|
(define (imported-label->binding lab)
|
2007-10-09 07:56:30 -04:00
|
|
|
(hashtable-ref label->binding-table lab #f))
|
2007-05-02 20:05:19 -04:00
|
|
|
|
2007-05-05 22:42:26 -04:00
|
|
|
(define (invoke-library lib)
|
2007-10-09 07:56:30 -04:00
|
|
|
(let ((invoke (library-invoke-state lib)))
|
2007-05-02 20:05:19 -04:00
|
|
|
(when (procedure? invoke)
|
|
|
|
(set-library-invoke-state! lib
|
2007-12-15 08:22:49 -05:00
|
|
|
(lambda () (assertion-violation 'invoke "circularity detected" lib)))
|
2007-05-05 22:42:26 -04:00
|
|
|
(for-each invoke-library (library-inv* lib))
|
2007-05-02 20:05:19 -04:00
|
|
|
(set-library-invoke-state! lib
|
2008-02-18 20:28:54 -05:00
|
|
|
(lambda ()
|
|
|
|
(assertion-violation 'invoke "first invoke did not return" lib)))
|
2007-05-02 20:05:19 -04:00
|
|
|
(invoke)
|
|
|
|
(set-library-invoke-state! lib #t))))
|
|
|
|
|
2007-05-07 20:58:12 -04:00
|
|
|
|
|
|
|
(define (visit-library lib)
|
2007-10-09 07:56:30 -04:00
|
|
|
(let ((visit (library-visit-state lib)))
|
2007-05-07 20:58:12 -04:00
|
|
|
(when (procedure? visit)
|
|
|
|
(set-library-visit-state! lib
|
2007-12-15 08:22:49 -05:00
|
|
|
(lambda () (assertion-violation 'visit "circularity detected" lib)))
|
2007-05-07 20:58:12 -04:00
|
|
|
(for-each invoke-library (library-vis* lib))
|
|
|
|
(set-library-visit-state! lib
|
2008-02-18 20:28:54 -05:00
|
|
|
(lambda ()
|
|
|
|
(assertion-violation 'invoke "first visit did not return" lib)))
|
2007-05-07 20:58:12 -04:00
|
|
|
(visit)
|
|
|
|
(set-library-visit-state! lib #t))))
|
|
|
|
|
|
|
|
|
2007-05-05 22:42:26 -04:00
|
|
|
(define (invoke-library-by-spec spec)
|
|
|
|
(invoke-library (find-library-by-spec/die spec)))
|
2007-05-02 20:05:19 -04:00
|
|
|
|
2007-05-05 22:42:26 -04:00
|
|
|
(define installed-libraries
|
2007-05-07 04:52:22 -04:00
|
|
|
(case-lambda
|
2007-10-09 07:56:30 -04:00
|
|
|
((all?)
|
|
|
|
(let f ((ls ((current-library-collection))))
|
2007-05-07 04:52:22 -04:00
|
|
|
(cond
|
2007-10-09 07:56:30 -04:00
|
|
|
((null? ls) '())
|
|
|
|
((or all? (library-visible? (car ls)))
|
|
|
|
(cons (car ls) (f (cdr ls))))
|
|
|
|
(else (f (cdr ls))))))
|
|
|
|
(() (installed-libraries #f))))
|
2007-05-07 04:52:22 -04:00
|
|
|
|
2007-05-05 22:42:26 -04:00
|
|
|
(define library-spec
|
2007-05-02 19:22:54 -04:00
|
|
|
(lambda (x)
|
|
|
|
(unless (library? x)
|
2007-12-15 08:22:49 -05:00
|
|
|
(assertion-violation 'library-spec "not a library" x))
|
2007-10-26 12:41:55 -04:00
|
|
|
(list (library-id x) (library-name x) (library-version x))))
|
2007-05-04 09:22:33 -04:00
|
|
|
)
|
2007-05-02 19:19:37 -04:00
|
|
|
|