2010-02-06 12:33:20 -05:00
|
|
|
|
;;; r6rs-libraries.scm --- Support for the R6RS `library' and `import' forms
|
|
|
|
|
|
|
|
|
|
|
|
;; Copyright (C) 2010 Free Software Foundation, Inc.
|
|
|
|
|
|
;;
|
|
|
|
|
|
;; 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
|
|
|
|
|
|
;; version 3 of the License, or (at your option) any later version.
|
|
|
|
|
|
;;
|
|
|
|
|
|
;; This library is distributed in the hope that it will be useful,
|
|
|
|
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
|
;; Lesser General Public License for more details.
|
|
|
|
|
|
;;
|
|
|
|
|
|
;; You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
|
;; License along with this library; if not, write to the Free Software
|
|
|
|
|
|
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;; This file is included from boot-9.scm and assumes the existence of (and
|
|
|
|
|
|
;; expands into) procedures and syntactic forms defined therein.
|
|
|
|
|
|
|
|
|
|
|
|
(define (resolve-r6rs-interface import-spec)
|
|
|
|
|
|
(define (make-custom-interface mod)
|
|
|
|
|
|
(let ((iface (make-module)))
|
|
|
|
|
|
(set-module-kind! iface 'custom-interface)
|
|
|
|
|
|
(set-module-name! iface (module-name mod))
|
|
|
|
|
|
iface))
|
|
|
|
|
|
(define (sym? x) (symbol? (syntax->datum x)))
|
|
|
|
|
|
|
|
|
|
|
|
(syntax-case import-spec (library only except prefix rename srfi)
|
2010-06-19 14:52:21 +02:00
|
|
|
|
;; (srfi :n ...) -> (srfi srfi-n)
|
2010-02-06 12:33:20 -05:00
|
|
|
|
((library (srfi colon-n rest ... (version ...)))
|
|
|
|
|
|
(and (and-map sym? #'(srfi rest ...))
|
|
|
|
|
|
(symbol? (syntax->datum #'colon-n))
|
|
|
|
|
|
(eqv? (string-ref (symbol->string (syntax->datum #'colon-n)) 0) #\:))
|
|
|
|
|
|
(let ((srfi-n (string->symbol
|
|
|
|
|
|
(string-append
|
|
|
|
|
|
"srfi-"
|
|
|
|
|
|
(substring (symbol->string (syntax->datum #'colon-n))
|
|
|
|
|
|
1)))))
|
|
|
|
|
|
(resolve-r6rs-interface
|
2010-06-19 14:52:21 +02:00
|
|
|
|
#`(library (srfi #,srfi-n (version ...))))))
|
2010-02-06 12:33:20 -05:00
|
|
|
|
|
|
|
|
|
|
((library (name name* ... (version ...)))
|
|
|
|
|
|
(and-map sym? #'(name name* ...))
|
|
|
|
|
|
(resolve-interface (syntax->datum #'(name name* ...))
|
|
|
|
|
|
#:version (syntax->datum #'(version ...))))
|
|
|
|
|
|
|
|
|
|
|
|
((library (name name* ...))
|
|
|
|
|
|
(and-map sym? #'(name name* ...))
|
|
|
|
|
|
(resolve-r6rs-interface #'(library (name name* ... ()))))
|
|
|
|
|
|
|
|
|
|
|
|
((only import-set identifier ...)
|
|
|
|
|
|
(and-map sym? #'(identifier ...))
|
|
|
|
|
|
(let* ((mod (resolve-r6rs-interface #'import-set))
|
|
|
|
|
|
(iface (make-custom-interface mod)))
|
|
|
|
|
|
(for-each (lambda (sym)
|
|
|
|
|
|
(module-add! iface sym
|
|
|
|
|
|
(or (module-local-variable mod sym)
|
|
|
|
|
|
(error "no binding `~A' in module ~A"
|
|
|
|
|
|
sym mod))))
|
|
|
|
|
|
(syntax->datum #'(identifier ...)))
|
|
|
|
|
|
iface))
|
|
|
|
|
|
|
|
|
|
|
|
((except import-set identifier ...)
|
|
|
|
|
|
(and-map sym? #'(identifier ...))
|
|
|
|
|
|
(let* ((mod (resolve-r6rs-interface #'import-set))
|
|
|
|
|
|
(iface (make-custom-interface mod)))
|
|
|
|
|
|
(module-for-each (lambda (sym var) (module-add! iface sym var)) mod)
|
|
|
|
|
|
(for-each (lambda (sym)
|
|
|
|
|
|
(if (module-local-variable iface sym)
|
|
|
|
|
|
(module-remove! iface sym)
|
|
|
|
|
|
(error "no binding `~A' in module ~A" sym mod)))
|
|
|
|
|
|
(syntax->datum #'(identifier ...)))
|
|
|
|
|
|
iface))
|
|
|
|
|
|
|
|
|
|
|
|
((prefix import-set identifier)
|
|
|
|
|
|
(sym? #'identifier)
|
|
|
|
|
|
(let* ((mod (resolve-r6rs-interface #'import-set))
|
|
|
|
|
|
(iface (make-custom-interface mod))
|
|
|
|
|
|
(pre (syntax->datum #'identifier)))
|
|
|
|
|
|
(module-for-each (lambda (sym var)
|
|
|
|
|
|
(module-add! iface (symbol-append pre sym) var))
|
|
|
|
|
|
mod)
|
|
|
|
|
|
iface))
|
|
|
|
|
|
|
|
|
|
|
|
((rename import-set (from to) ...)
|
|
|
|
|
|
(and (and-map sym? #'(from ...)) (and-map sym? #'(to ...)))
|
|
|
|
|
|
(let* ((mod (resolve-r6rs-interface #'import-set))
|
|
|
|
|
|
(iface (make-custom-interface mod)))
|
|
|
|
|
|
(module-for-each (lambda (sym var) (module-add! iface sym var)) mod)
|
|
|
|
|
|
(let lp ((in (syntax->datum #'((from . to) ...))) (out '()))
|
|
|
|
|
|
(cond
|
|
|
|
|
|
((null? in)
|
|
|
|
|
|
(for-each
|
|
|
|
|
|
(lambda (pair)
|
|
|
|
|
|
(if (module-local-variable iface (car pair))
|
|
|
|
|
|
(error "duplicate binding for `~A' in module ~A"
|
|
|
|
|
|
(car pair) mod)
|
|
|
|
|
|
(module-add! iface (car pair) (cdr pair))))
|
|
|
|
|
|
out)
|
|
|
|
|
|
iface)
|
|
|
|
|
|
(else
|
|
|
|
|
|
(let ((var (or (module-local-variable mod (caar in))
|
|
|
|
|
|
(error "no binding `~A' in module ~A"
|
|
|
|
|
|
(caar in) mod))))
|
|
|
|
|
|
(module-remove! iface (caar in))
|
|
|
|
|
|
(lp (cdr in) (acons (cdar in) var out))))))))
|
|
|
|
|
|
|
|
|
|
|
|
((name name* ... (version ...))
|
|
|
|
|
|
(and-map sym? #'(name name* ...))
|
|
|
|
|
|
(resolve-r6rs-interface #'(library (name name* ... (version ...)))))
|
|
|
|
|
|
|
|
|
|
|
|
((name name* ...)
|
|
|
|
|
|
(and-map sym? #'(name name* ...))
|
|
|
|
|
|
(resolve-r6rs-interface #'(library (name name* ... ()))))))
|
|
|
|
|
|
|
|
|
|
|
|
(define-syntax library
|
|
|
|
|
|
(lambda (stx)
|
|
|
|
|
|
(define (compute-exports ifaces specs)
|
|
|
|
|
|
(define (re-export? sym)
|
|
|
|
|
|
(or-map (lambda (iface) (module-local-variable iface sym)) ifaces))
|
2010-06-20 23:59:57 +02:00
|
|
|
|
(define (replace? sym)
|
|
|
|
|
|
(module-local-variable the-scm-module sym))
|
2010-02-06 12:33:20 -05:00
|
|
|
|
|
2010-06-20 23:59:57 +02:00
|
|
|
|
(let lp ((specs specs) (e '()) (r '()) (x '()))
|
2010-02-06 12:33:20 -05:00
|
|
|
|
(syntax-case specs (rename)
|
2010-06-20 23:59:57 +02:00
|
|
|
|
(() (values e r x))
|
2010-02-06 12:33:20 -05:00
|
|
|
|
(((rename (from to) ...) . rest)
|
|
|
|
|
|
(and (and-map identifier? #'(from ...))
|
|
|
|
|
|
(and-map identifier? #'(to ...)))
|
2010-06-20 23:59:57 +02:00
|
|
|
|
(let lp2 ((in #'((from . to) ...)) (e e) (r r) (x x))
|
2010-02-06 12:33:20 -05:00
|
|
|
|
(syntax-case in ()
|
2010-06-20 23:59:57 +02:00
|
|
|
|
(() (lp #'rest e r x))
|
2010-02-06 12:33:20 -05:00
|
|
|
|
(((from . to) . in)
|
2010-06-20 23:59:57 +02:00
|
|
|
|
(cond
|
|
|
|
|
|
((re-export? (syntax->datum #'from))
|
|
|
|
|
|
(lp2 #'in e (cons #'(from . to) r) x))
|
|
|
|
|
|
((replace? (syntax->datum #'from))
|
|
|
|
|
|
(lp2 #'in e r (cons #'(from . to) x)))
|
|
|
|
|
|
(else
|
|
|
|
|
|
(lp2 #'in (cons #'(from . to) e) r x)))))))
|
2010-02-06 12:33:20 -05:00
|
|
|
|
((id . rest)
|
|
|
|
|
|
(identifier? #'id)
|
|
|
|
|
|
(let ((sym (syntax->datum #'id)))
|
2010-06-20 23:59:57 +02:00
|
|
|
|
(cond
|
|
|
|
|
|
((re-export? sym)
|
|
|
|
|
|
(lp #'rest e (cons #'id r) x))
|
|
|
|
|
|
((replace? sym)
|
|
|
|
|
|
(lp #'rest e r (cons #'id x)))
|
|
|
|
|
|
(else
|
|
|
|
|
|
(lp #'rest (cons #'id e) r x))))))))
|
2010-02-06 12:33:20 -05:00
|
|
|
|
|
|
|
|
|
|
(syntax-case stx (export import)
|
|
|
|
|
|
((_ (name name* ...)
|
|
|
|
|
|
(export espec ...)
|
|
|
|
|
|
(import ispec ...)
|
|
|
|
|
|
body ...)
|
|
|
|
|
|
(and-map identifier? #'(name name* ...))
|
|
|
|
|
|
;; Add () as the version.
|
|
|
|
|
|
#'(library (name name* ... ())
|
|
|
|
|
|
(export espec ...)
|
|
|
|
|
|
(import ispec ...)
|
|
|
|
|
|
body ...))
|
|
|
|
|
|
|
|
|
|
|
|
((_ (name name* ... (version ...))
|
|
|
|
|
|
(export espec ...)
|
|
|
|
|
|
(import ispec ...)
|
|
|
|
|
|
body ...)
|
|
|
|
|
|
(and-map identifier? #'(name name* ...))
|
|
|
|
|
|
(call-with-values
|
|
|
|
|
|
(lambda ()
|
2010-05-27 21:32:20 -04:00
|
|
|
|
(compute-exports
|
|
|
|
|
|
(map (lambda (im)
|
|
|
|
|
|
(syntax-case im (for)
|
|
|
|
|
|
((for import-set import-level ...)
|
|
|
|
|
|
(resolve-r6rs-interface #'import-set))
|
|
|
|
|
|
(import-set (resolve-r6rs-interface #'import-set))))
|
|
|
|
|
|
#'(ispec ...))
|
|
|
|
|
|
#'(espec ...)))
|
2010-06-20 23:59:57 +02:00
|
|
|
|
(lambda (exports re-exports replacements)
|
2010-02-06 12:33:20 -05:00
|
|
|
|
(with-syntax (((e ...) exports)
|
2010-06-20 23:59:57 +02:00
|
|
|
|
((r ...) re-exports)
|
|
|
|
|
|
((x ...) replacements))
|
2010-02-06 12:33:20 -05:00
|
|
|
|
;; It would be nice to push the module that was current before the
|
|
|
|
|
|
;; definition, and pop it after the library definition, but I
|
|
|
|
|
|
;; actually can't see a way to do that. Helper procedures perhaps,
|
|
|
|
|
|
;; around a fluid that is rebound in save-module-excursion? Patches
|
|
|
|
|
|
;; welcome!
|
|
|
|
|
|
#'(begin
|
|
|
|
|
|
(define-module (name name* ...)
|
2010-05-20 13:59:34 +02:00
|
|
|
|
#:pure
|
2010-02-06 12:33:20 -05:00
|
|
|
|
#:version (version ...))
|
|
|
|
|
|
(import ispec)
|
|
|
|
|
|
...
|
|
|
|
|
|
(export e ...)
|
2010-06-20 23:59:57 +02:00
|
|
|
|
(re-export r ...)
|
|
|
|
|
|
(export! x ...)
|
2010-05-06 22:34:36 +02:00
|
|
|
|
(@@ (name name* ...) body)
|
|
|
|
|
|
...))))))))
|
2010-02-06 12:33:20 -05:00
|
|
|
|
|
|
|
|
|
|
(define-syntax import
|
|
|
|
|
|
(lambda (stx)
|
2010-06-09 08:55:02 +02:00
|
|
|
|
(define (strip-for import-set)
|
|
|
|
|
|
(syntax-case import-set (for)
|
|
|
|
|
|
((for import-set import-level ...)
|
|
|
|
|
|
#'import-set)
|
|
|
|
|
|
(import-set
|
|
|
|
|
|
#'import-set)))
|
|
|
|
|
|
(syntax-case stx ()
|
|
|
|
|
|
((_ import-set ...)
|
|
|
|
|
|
(with-syntax (((library-reference ...) (map strip-for #'(import-set ...))))
|
|
|
|
|
|
#'(eval-when (eval load compile expand)
|
|
|
|
|
|
(let ((iface (resolve-r6rs-interface 'library-reference)))
|
|
|
|
|
|
(call-with-deferred-observers
|
|
|
|
|
|
(lambda ()
|
|
|
|
|
|
(module-use-interfaces! (current-module) (list iface)))))
|
|
|
|
|
|
...
|
2010-02-06 12:33:20 -05:00
|
|
|
|
(if #f #f)))))))
|