Hi all, Find attached a revised and polished version of the `(ice-9 r6rs-libraries)' module I submitted a couple of months ago. This version includes the following changes:
* The library transformer code's been cleaned up and compacted (by more than 30%) and now uses a `defmacro' form similar to the one used by `use-modules' and `define-module' instead of the messy syncase-based transformer it was using originally. * I've re-organized the code to more closely resemble the structure of `use-modules' and 'define-module' -- the macros delegate syntax parsing to a set of "processing" functions. In addition to making the macros simpler, this should make it easier to unify the module and library systems in the future, if desired. * I've added an `import' macro as specified by R6RS 8.1 "Top Level Program Syntax" [0]. * The module also supports the convention, specified by SRFI-97, that SRFIs can be loaded as R6RS libraries by importing them as `(srfi :[n])' -- my implementation transforms library names of that form to the form used by Guile, `(srfi srfi-[n])'. In case anyone missed the earlier emails on this topic, this module contains macros that transform the R6RS `library' and 'import' forms into Guile's native `define-module' and 'use-modules' forms. In concert with the version and binding export patches that were pushed last week, this means that Guile now supports R6RS 7 "Libraries" [1], and can thus share code (unmodified!) with any other conforming Scheme implementation. I consider this version of the code to be tentatively "complete." You can try it out by dropping r6rs-libraries.scm into module/ice-9 and then loading it in the REPL or including it as a dependency of a normal Guile module. I'm very interested in any feedback people might have, particularly when it comes to the name of the module and where it belongs / when it should be loaded (always? Not in the REPL?). If no one objects, I'll add some documentation and push it. As I mentioned to Andy on IRC, I'm working on a first pass at a set of implementations of the R6RS Standard Libraries (minus the work already done by Ludovic et al on bytevectors, etc.), as much as possible as wrappers around Guile's existing functionality. I should have some status on that soon. Regards, Julian [0] - http://www.r6rs.org/final/html/r6rs/r6rs-Z-H-11.html#node_sec_8.1 [1] - http://www.r6rs.org/final/html/r6rs/r6rs-Z-H-10.html#node_chap_7
;;; r6rs-libraries.scm --- Support for R6RS `library' and `import' forms ;; Copyright (C) 2009 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 ^L (define-module (ice-9 r6rs-libraries) #:use-module (ice-9 optargs) #:use-module (ice-9 regex) #:use-module (srfi srfi-1) #:use-module (srfi srfi-2) #:use-module (srfi srfi-11) #:export-syntax (library import)) (define (name-and-version lst) (let-values (((head tail) (split-at lst (- (length lst) 1)))) (if (pair? (car tail)) (values head (car tail)) (values lst '())))) (define srfi-regex (make-regexp "^\\:([0-9]+)$")) (define* (process-import args #:optional import-map) (define (flatten im) (define (load-library library-ref) (define (transform-library-name name) (define (make-srfi m) (cons 'srfi (list (string->symbol (string-append "srfi-" (match:substring m 1)))))) (or (and (>= (length name) 2) (eq? (car name) 'srfi) (and=> (regexp-exec srfi-regex (symbol->string (cadr name))) make-srfi)) name)) (let-values (((name version) (name-and-version library-ref))) (resolve-interface (transform-library-name name) #:version version))) (define (exeq? x y) (if (list? y) (eq? x (cadr y)) (eq? x y))) (if (or (not (list? im))) (error)) (let* ((op (car im)) (l (case op ((only except prefix rename) (flatten (cadr im))) ((library) (load-library (cadr im))) (else (load-library im))))) (case op ((library) (cons l (module-map (lambda (sym var) sym) l))) ((only) (cons (car l) (lset-intersection exeq? (cdr l) (cddr im)))) ((except) (cons (car l) (lset-difference exeq? (cdr l) (cddr im)))) ((prefix) (let ((p (symbol-prefix-proc (caddr im)))) (cons (car l) (map (lambda (x) (if (list? x) (cons (car x) (p (cadr x))) (cons x (p x)))) (cdr l))))) ((rename) (let ((f (lambda (y) (eq? (car y) (if (list? x) (car x) x))))) (cons (car l) (map (lambda (x) (let ((r (find f (cddr im)))) (if r (cons (if (list? x) (car x) x) (cadr x)) x))) (cdr l))))) (else (cons l (module-map (lambda (sym var) sym) l)))))) (let* ((unwrapped-import-spec (if (eq? (car args) 'for) (cadr args) args)) (ilist (flatten unwrapped-import-spec)) (public-interface (car ilist))) (if import-map (for-each (lambda (x) (hashq-set! import-map x #t)) (map (lambda (x) (if (pair? x) (cdr x) x)) (cdr ilist)))) (append (list (module-name public-interface)) (if (module-version public-interface) (list #:version (module-version public-interface)) (list)) (if (null? (cdr ilist)) '() (list #:select (cdr ilist)))))) (define (process-library args) (define (resolve-export-spec export-specs imports) (define (imported? sym) (hashq-ref imports sym)) (define (flatten-renames export-spec) (if (list? export-spec) (map (lambda (x) (cons (car x) (cadr x))) (cdr export-spec)) (list export-spec))) (partition imported? (apply append (map flatten-renames export-specs)))) (let ((import-map (make-hash-table))) (let-values (((library-name version) (name-and-version (car args))) ((imports) (apply append (map (lambda (x) (list #:use-module (process-import x import-map))) (cdaddr args)))) ((re-exports exports) (resolve-export-spec (cdadr args) import-map))) `(define-module ,library-name ,@(if (null? version) '() (cons #:version version)) ,@imports ,@(if (null? exports) '() (list #:export exports)) ,@(if (null? re-exports) '() (list #:re-export re-exports)))))) (defmacro library args (let ((transformed-args (process-library args))) `(begin ,transformed-args ,@(cdddr args)))) (defmacro import args (let ((transformed-args (map process-import args))) `(use-modules ,@transformed-args))) ;;; r6rs-libraries.scm ends here