Inline helpers into slot-ref, slot-set!, etc
[bpt/guile.git] / module / ice-9 / r6rs-libraries.scm
CommitLineData
b1e4c7cc
JG
1;;; r6rs-libraries.scm --- Support for the R6RS `library' and `import' forms
2
3;; Copyright (C) 2010 Free Software Foundation, Inc.
4;;
5;; This library is free software; you can redistribute it and/or
6;; modify it under the terms of the GNU Lesser General Public
7;; License as published by the Free Software Foundation; either
8;; version 3 of the License, or (at your option) any later version.
9;;
10;; This library is distributed in the hope that it will be useful,
11;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13;; Lesser General Public License for more details.
14;;
15;; You should have received a copy of the GNU Lesser General Public
16;; License along with this library; if not, write to the Free Software
17;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18\f
19
20;; This file is included from boot-9.scm and assumes the existence of (and
21;; expands into) procedures and syntactic forms defined therein.
22
23(define (resolve-r6rs-interface import-spec)
24 (define (make-custom-interface mod)
25 (let ((iface (make-module)))
26 (set-module-kind! iface 'custom-interface)
27 (set-module-name! iface (module-name mod))
28 iface))
29 (define (sym? x) (symbol? (syntax->datum x)))
30
31 (syntax-case import-spec (library only except prefix rename srfi)
acc1d8e3 32 ;; (srfi :n ...) -> (srfi srfi-n ...)
b1e4c7cc
JG
33 ((library (srfi colon-n rest ... (version ...)))
34 (and (and-map sym? #'(srfi rest ...))
35 (symbol? (syntax->datum #'colon-n))
36 (eqv? (string-ref (symbol->string (syntax->datum #'colon-n)) 0) #\:))
37 (let ((srfi-n (string->symbol
38 (string-append
39 "srfi-"
40 (substring (symbol->string (syntax->datum #'colon-n))
41 1)))))
42 (resolve-r6rs-interface
5d7c55bd
IP
43 (syntax-case #'(rest ...) ()
44 (()
45 #`(library (srfi #,srfi-n (version ...))))
46 ((name rest ...)
47 ;; SRFI 97 says that the first identifier after the colon-n
48 ;; is used for the libraries name, so it must be ignored.
49 #`(library (srfi #,srfi-n rest ... (version ...))))))))
b1e4c7cc
JG
50
51 ((library (name name* ... (version ...)))
52 (and-map sym? #'(name name* ...))
53 (resolve-interface (syntax->datum #'(name name* ...))
54 #:version (syntax->datum #'(version ...))))
55
56 ((library (name name* ...))
57 (and-map sym? #'(name name* ...))
58 (resolve-r6rs-interface #'(library (name name* ... ()))))
59
60 ((only import-set identifier ...)
61 (and-map sym? #'(identifier ...))
62 (let* ((mod (resolve-r6rs-interface #'import-set))
63 (iface (make-custom-interface mod)))
64 (for-each (lambda (sym)
65 (module-add! iface sym
66 (or (module-local-variable mod sym)
67 (error "no binding `~A' in module ~A"
68 sym mod))))
69 (syntax->datum #'(identifier ...)))
70 iface))
71
72 ((except import-set identifier ...)
73 (and-map sym? #'(identifier ...))
74 (let* ((mod (resolve-r6rs-interface #'import-set))
75 (iface (make-custom-interface mod)))
76 (module-for-each (lambda (sym var) (module-add! iface sym var)) mod)
77 (for-each (lambda (sym)
78 (if (module-local-variable iface sym)
79 (module-remove! iface sym)
80 (error "no binding `~A' in module ~A" sym mod)))
81 (syntax->datum #'(identifier ...)))
82 iface))
83
84 ((prefix import-set identifier)
85 (sym? #'identifier)
86 (let* ((mod (resolve-r6rs-interface #'import-set))
87 (iface (make-custom-interface mod))
88 (pre (syntax->datum #'identifier)))
89 (module-for-each (lambda (sym var)
90 (module-add! iface (symbol-append pre sym) var))
91 mod)
92 iface))
93
94 ((rename import-set (from to) ...)
95 (and (and-map sym? #'(from ...)) (and-map sym? #'(to ...)))
96 (let* ((mod (resolve-r6rs-interface #'import-set))
97 (iface (make-custom-interface mod)))
98 (module-for-each (lambda (sym var) (module-add! iface sym var)) mod)
99 (let lp ((in (syntax->datum #'((from . to) ...))) (out '()))
100 (cond
101 ((null? in)
102 (for-each
103 (lambda (pair)
104 (if (module-local-variable iface (car pair))
105 (error "duplicate binding for `~A' in module ~A"
106 (car pair) mod)
107 (module-add! iface (car pair) (cdr pair))))
108 out)
109 iface)
110 (else
111 (let ((var (or (module-local-variable mod (caar in))
112 (error "no binding `~A' in module ~A"
113 (caar in) mod))))
114 (module-remove! iface (caar in))
115 (lp (cdr in) (acons (cdar in) var out))))))))
116
117 ((name name* ... (version ...))
118 (and-map sym? #'(name name* ...))
119 (resolve-r6rs-interface #'(library (name name* ... (version ...)))))
120
121 ((name name* ...)
122 (and-map sym? #'(name name* ...))
123 (resolve-r6rs-interface #'(library (name name* ... ()))))))
124
125(define-syntax library
126 (lambda (stx)
127 (define (compute-exports ifaces specs)
128 (define (re-export? sym)
129 (or-map (lambda (iface) (module-local-variable iface sym)) ifaces))
1052739b
AW
130 (define (replace? sym)
131 (module-local-variable the-scm-module sym))
b1e4c7cc 132
1052739b 133 (let lp ((specs specs) (e '()) (r '()) (x '()))
b1e4c7cc 134 (syntax-case specs (rename)
1052739b 135 (() (values e r x))
b1e4c7cc
JG
136 (((rename (from to) ...) . rest)
137 (and (and-map identifier? #'(from ...))
138 (and-map identifier? #'(to ...)))
1052739b 139 (let lp2 ((in #'((from . to) ...)) (e e) (r r) (x x))
b1e4c7cc 140 (syntax-case in ()
1052739b 141 (() (lp #'rest e r x))
b1e4c7cc 142 (((from . to) . in)
1052739b
AW
143 (cond
144 ((re-export? (syntax->datum #'from))
145 (lp2 #'in e (cons #'(from . to) r) x))
146 ((replace? (syntax->datum #'from))
147 (lp2 #'in e r (cons #'(from . to) x)))
148 (else
149 (lp2 #'in (cons #'(from . to) e) r x)))))))
b1e4c7cc
JG
150 ((id . rest)
151 (identifier? #'id)
152 (let ((sym (syntax->datum #'id)))
1052739b
AW
153 (cond
154 ((re-export? sym)
155 (lp #'rest e (cons #'id r) x))
156 ((replace? sym)
157 (lp #'rest e r (cons #'id x)))
158 (else
159 (lp #'rest (cons #'id e) r x))))))))
b1e4c7cc
JG
160
161 (syntax-case stx (export import)
162 ((_ (name name* ...)
163 (export espec ...)
164 (import ispec ...)
165 body ...)
166 (and-map identifier? #'(name name* ...))
167 ;; Add () as the version.
168 #'(library (name name* ... ())
169 (export espec ...)
170 (import ispec ...)
171 body ...))
172
173 ((_ (name name* ... (version ...))
174 (export espec ...)
175 (import ispec ...)
176 body ...)
177 (and-map identifier? #'(name name* ...))
178 (call-with-values
179 (lambda ()
04186f20
JG
180 (compute-exports
181 (map (lambda (im)
182 (syntax-case im (for)
183 ((for import-set import-level ...)
184 (resolve-r6rs-interface #'import-set))
185 (import-set (resolve-r6rs-interface #'import-set))))
186 #'(ispec ...))
187 #'(espec ...)))
1052739b 188 (lambda (exports re-exports replacements)
b1e4c7cc 189 (with-syntax (((e ...) exports)
1052739b
AW
190 ((r ...) re-exports)
191 ((x ...) replacements))
b1e4c7cc
JG
192 ;; It would be nice to push the module that was current before the
193 ;; definition, and pop it after the library definition, but I
194 ;; actually can't see a way to do that. Helper procedures perhaps,
195 ;; around a fluid that is rebound in save-module-excursion? Patches
196 ;; welcome!
197 #'(begin
198 (define-module (name name* ...)
e6c7e9ed 199 #:pure
b1e4c7cc
JG
200 #:version (version ...))
201 (import ispec)
202 ...
b1e4c7cc 203 (export e ...)
1052739b
AW
204 (re-export r ...)
205 (export! x ...)
8210c853 206 (@@ @@ (name name* ...) body)
d9b1c71a 207 ...))))))))
b1e4c7cc
JG
208
209(define-syntax import
210 (lambda (stx)
ffd48603
AW
211 (define (strip-for import-set)
212 (syntax-case import-set (for)
213 ((for import-set import-level ...)
214 #'import-set)
215 (import-set
216 #'import-set)))
217 (syntax-case stx ()
218 ((_ import-set ...)
219 (with-syntax (((library-reference ...) (map strip-for #'(import-set ...))))
f6ddf827 220 #'(eval-when (expand load eval)
ffd48603
AW
221 (let ((iface (resolve-r6rs-interface 'library-reference)))
222 (call-with-deferred-observers
223 (lambda ()
224 (module-use-interfaces! (current-module) (list iface)))))
225 ...
b1e4c7cc 226 (if #f #f)))))))