r6rs-libraries.scm 9.0 KB

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