resolve-module #:ensure argument
[bpt/guile.git] / module / ice-9 / boot-9.scm
index ffd1f68..85b44b1 100644 (file)
 ;; Define delimited continuation operators, and implement catch and throw in
 ;; terms of them.
 
-(define (make-prompt-tag . stem)
-  (gensym (if (pair? stem) (car stem) "prompt")))
+(define make-prompt-tag
+  (lambda* (#:optional (stem "prompt"))
+    (gensym stem)))
+
 (define default-prompt-tag
   ;; not sure if we should expose this to the user as a fluid
   (let ((%default-prompt-tag (make-prompt-tag)))
             (apply prev thrown-k args)))))
 
   (define! 'catch
-    ;; Until we get optargs support into Guile's C evaluator, we have to fake it
-    ;; here.
-    (lambda (k thunk handler . pre-unwind-handler)
+    (lambda* (k thunk handler #:optional pre-unwind-handler)
       "Invoke @var{thunk} in the dynamic context of @var{handler} for
 exceptions matching @var{key}.  If thunk throws to the symbol
 @var{key}, then @var{handler} is invoked this way:
@@ -163,10 +163,9 @@ non-locally, that exit determines the continuation."
          (lambda ()
            (with-fluids
                ((%exception-handler
-                 (if (null? pre-unwind-handler)
-                     (default-throw-handler tag k)
-                     (custom-throw-handler tag k
-                                           (car pre-unwind-handler)))))
+                 (if pre-unwind-handler
+                     (custom-throw-handler tag k pre-unwind-handler)
+                     (default-throw-handler tag k))))
              (thunk)))
          (lambda (cont k . args)
            (apply handler k args))))))
@@ -295,11 +294,8 @@ If there is no handler at all, Guile prints an error and then exits."
 
 ;; this is scheme wrapping the C code so the final pred call is a tail call,
 ;; per SRFI-13 spec
-(define (string-any char_pred s . rest)
-  (let ((start (if (null? rest)
-                   0 (car rest)))
-        (end   (if (or (null? rest) (null? (cdr rest)))
-                   (string-length s) (cadr rest))))
+(define string-any
+  (lambda* (char_pred s #:optional (start 0) (end (string-length s)))
     (if (and (procedure? char_pred)
              (> end start)
              (<= end (string-length s))) ;; let c-code handle range error
@@ -309,11 +305,8 @@ If there is no handler at all, Guile prints an error and then exits."
 
 ;; this is scheme wrapping the C code so the final pred call is a tail call,
 ;; per SRFI-13 spec
-(define (string-every char_pred s . rest)
-  (let ((start (if (null? rest)
-                   0 (car rest)))
-        (end   (if (or (null? rest) (null? (cdr rest)))
-                   (string-length s) (cadr rest))))
+(define string-every
+  (lambda* (char_pred s #:optional (start 0) (end (string-length s)))
     (if (and (procedure? char_pred)
              (> end start)
              (<= end (string-length s))) ;; let c-code handle range error
@@ -353,11 +346,11 @@ If there is no handler at all, Guile prints an error and then exits."
 (define syntax-violation #f)
 (define datum->syntax #f)
 (define syntax->datum #f)
+(define syntax-source #f)
 (define identifier? #f)
 (define generate-temporaries #f)
 (define bound-identifier=? #f)
 (define free-identifier=? #f)
-(define macroexpand #f)
 
 ;; $sc-dispatch is an implementation detail of psyntax. It is used by
 ;; expanded macros, to dispatch an input against a set of patterns.
@@ -365,10 +358,8 @@ If there is no handler at all, Guile prints an error and then exits."
 
 ;; Load it up!
 (primitive-load-path "ice-9/psyntax-pp")
-
-;; %pre-modules-transformer is the Scheme expander from now until the
-;; module system has booted up.
-(define %pre-modules-transformer macroexpand)
+;; The binding for `macroexpand' has now been overridden, making psyntax the
+;; expander now.
 
 (define-syntax and
   (syntax-rules ()
@@ -470,36 +461,12 @@ If there is no handler at all, Guile prints an error and then exits."
 
 (include-from-path "ice-9/quasisyntax")
 
-;;; @bind is used by the old elisp code as a dynamic scoping mechanism.
-;;; Please let the Guile developers know if you are using this macro.
-;;;
-(define-syntax @bind
+(define-syntax current-source-location
   (lambda (x)
-    (define (bound-member id ids)
-      (cond ((null? ids) #f)
-            ((bound-identifier=? id (car ids)) #t)
-            ((bound-member (car ids) (cdr ids)))))
-    
     (syntax-case x ()
-      ((_ () b0 b1 ...)
-       #'(let () b0 b1 ...))
-      ((_ ((id val) ...) b0 b1 ...)
-       (and-map identifier? #'(id ...))
-       (if (let lp ((ids #'(id ...)))
-             (cond ((null? ids) #f)
-                   ((bound-member (car ids) (cdr ids)) #t)
-                   (else (lp (cdr ids)))))
-           (syntax-violation '@bind "duplicate bound identifier" x)
-           (with-syntax (((old-v ...) (generate-temporaries #'(id ...)))
-                         ((v ...) (generate-temporaries #'(id ...))))
-             #'(let ((old-v id) ...
-                     (v val) ...)
-                 (dynamic-wind
-                   (lambda ()
-                     (set! id v) ...)
-                   (lambda () b0 b1 ...)
-                   (lambda ()
-                     (set! id old-v) ...)))))))))
+      ((_)
+       (with-syntax ((s (datum->syntax x (syntax-source x))))
+         #''s)))))
 
 
 \f
@@ -666,9 +633,11 @@ If there is no handler at all, Guile prints an error and then exits."
       (port-with-print-state new-port (get-print-state old-port))
       new-port))
 
-;; 0: type-name, 1: fields
+;; 0: type-name, 1: fields, 2: constructor
 (define record-type-vtable
-  (make-vtable-vtable "prpr" 0
+  ;; FIXME: This should just call make-vtable, not make-vtable-vtable; but for
+  ;; that we need to expose the bare vtable-vtable to Scheme.
+  (make-vtable-vtable "prprpw" 0
                       (lambda (s p)
                         (cond ((eq? s record-type-vtable)
                                (display "#<record-type-vtable>" p))
@@ -680,34 +649,72 @@ If there is no handler at all, Guile prints an error and then exits."
 (define (record-type? obj)
   (and (struct? obj) (eq? record-type-vtable (struct-vtable obj))))
 
-(define (make-record-type type-name fields . opt)
-  (let ((printer-fn (and (pair? opt) (car opt))))
-    (let ((struct (make-struct record-type-vtable 0
-                               (make-struct-layout
-                                (apply string-append
-                                       (map (lambda (f) "pw") fields)))
-                               (or printer-fn
-                                   (lambda (s p)
-                                     (display "#<" p)
-                                     (display type-name p)
-                                     (let loop ((fields fields)
-                                                (off 0))
-                                       (cond
-                                        ((not (null? fields))
-                                         (display " " p)
-                                         (display (car fields) p)
-                                         (display ": " p)
-                                         (display (struct-ref s off) p)
-                                         (loop (cdr fields) (+ 1 off)))))
-                                     (display ">" p)))
-                               type-name
-                               (copy-tree fields))))
-      ;; Temporary solution: Associate a name to the record type descriptor
-      ;; so that the object system can create a wrapper class for it.
-      (set-struct-vtable-name! struct (if (symbol? type-name)
-                                          type-name
-                                          (string->symbol type-name)))
-      struct)))
+(define* (make-record-type type-name fields #:optional printer)
+  ;; Pre-generate constructors for nfields < 20.
+  (define-syntax make-constructor
+    (lambda (x)
+      (define *max-static-argument-count* 20)
+      (define (make-formals n)
+        (let lp ((i 0))
+          (if (< i n)
+              (cons (datum->syntax
+                     x 
+                     (string->symbol
+                      (string (integer->char (+ (char->integer #\a) i)))))
+                    (lp (1+ i)))
+              '())))
+      (syntax-case x ()
+        ((_ rtd exp) (not (identifier? #'exp))
+         #'(let ((n exp))
+             (make-constructor rtd n)))
+        ((_ rtd nfields)
+         #`(case nfields
+             #,@(let lp ((n 0))
+                  (if (< n *max-static-argument-count*)
+                      (cons (with-syntax (((formal ...) (make-formals n))
+                                          (n n))
+                              #'((n)
+                                 (lambda (formal ...)
+                                   (make-struct rtd 0 formal ...))))
+                            (lp (1+ n)))
+                      '()))
+             (else
+              (lambda args
+                (if (= (length args) nfields)
+                    (apply make-struct rtd 0 args)
+                    (scm-error 'wrong-number-of-args
+                               (format #f "make-~a" type-name)
+                               "Wrong number of arguments" '() #f)))))))))
+
+  (define (default-record-printer s p)
+    (display "#<" p)
+    (display (record-type-name (record-type-descriptor s)) p)
+    (let loop ((fields (record-type-fields (record-type-descriptor s)))
+               (off 0))
+      (cond
+       ((not (null? fields))
+        (display " " p)
+        (display (car fields) p)
+        (display ": " p)
+        (display (struct-ref s off) p)
+        (loop (cdr fields) (+ 1 off)))))
+    (display ">" p))
+
+  (let ((rtd (make-struct record-type-vtable 0
+                          (make-struct-layout
+                           (apply string-append
+                                  (map (lambda (f) "pw") fields)))
+                          (or printer default-record-printer)
+                          type-name
+                          (copy-tree fields))))
+    (struct-set! rtd (+ vtable-offset-user 2)
+                 (make-constructor rtd (length fields)))
+    ;; Temporary solution: Associate a name to the record type descriptor
+    ;; so that the object system can create a wrapper class for it.
+    (set-struct-vtable-name! rtd (if (symbol? type-name)
+                                     type-name
+                                     (string->symbol type-name)))
+    rtd))
 
 (define (record-type-name obj)
   (if (record-type? obj)
@@ -719,15 +726,16 @@ If there is no handler at all, Guile prints an error and then exits."
       (struct-ref obj (+ 1 vtable-offset-user))
       (error 'not-a-record-type obj)))
 
-(define (record-constructor rtd . opt)
-  (let ((field-names (if (pair? opt) (car opt) (record-type-fields rtd))))
-    (primitive-eval
-     `(lambda ,field-names
-        (make-struct ',rtd 0 ,@(map (lambda (f)
-                                      (if (memq f field-names)
-                                          f
-                                          #f))
-                                    (record-type-fields rtd)))))))
+(define* (record-constructor rtd #:optional field-names)
+  (if (not field-names)
+      (struct-ref rtd (+ 2 vtable-offset-user))
+      (primitive-eval
+       `(lambda ,field-names
+          (make-struct ',rtd 0 ,@(map (lambda (f)
+                                        (if (memq f field-names)
+                                            f
+                                            #f))
+                                      (record-type-fields rtd)))))))
           
 (define (record-predicate rtd)
   (lambda (obj) (and (struct? obj) (eq? rtd (struct-vtable obj)))))
@@ -900,9 +908,8 @@ If there is no handler at all, Guile prints an error and then exits."
 (define (tms:cstime obj) (vector-ref obj 4))
 
 (define file-position ftell)
-(define (file-set-position port offset . whence)
-  (let ((whence (if (eq? whence '()) SEEK_SET (car whence))))
-    (seek port offset whence)))
+(define* (file-set-position port offset #:optional (whence SEEK_SET))
+  (seek port offset whence))
 
 (define (move->fdes fd/port fd)
   (cond ((integer? fd/port)
@@ -919,23 +926,39 @@ If there is no handler at all, Guile prints an error and then exits."
     (if (> revealed 0)
         (set-port-revealed! port (- revealed 1)))))
 
-(define (dup->port port/fd mode . maybe-fd)
-  (let ((port (fdopen (apply dup->fdes port/fd maybe-fd)
-                      mode)))
-    (if (pair? maybe-fd)
-        (set-port-revealed! port 1))
-    port))
-
-(define (dup->inport port/fd . maybe-fd)
-  (apply dup->port port/fd "r" maybe-fd))
-
-(define (dup->outport port/fd . maybe-fd)
-  (apply dup->port port/fd "w" maybe-fd))
-
-(define (dup port/fd . maybe-fd)
-  (if (integer? port/fd)
-      (apply dup->fdes port/fd maybe-fd)
-      (apply dup->port port/fd (port-mode port/fd) maybe-fd)))
+(define dup->port
+  (case-lambda
+    ((port/fd mode)
+     (fdopen (dup->fdes port/fd) mode))
+    ((port/fd mode new-fd)
+     (let ((port (fdopen (dup->fdes port/fd new-fd) mode)))
+       (set-port-revealed! port 1)
+       port))))
+
+(define dup->inport
+  (case-lambda
+    ((port/fd)
+     (dup->port port/fd "r"))
+    ((port/fd new-fd)
+     (dup->port port/fd "r" new-fd))))
+
+(define dup->outport
+  (case-lambda
+    ((port/fd)
+     (dup->port port/fd "w"))
+    ((port/fd new-fd)
+     (dup->port port/fd "w" new-fd))))
+
+(define dup
+  (case-lambda
+    ((port/fd)
+     (if (integer? port/fd)
+         (dup->fdes port/fd)
+         (dup->port port/fd (port-mode port/fd))))
+    ((port/fd new-fd)
+     (if (integer? port/fd)
+         (dup->fdes port/fd new-fd)
+         (dup->port port/fd (port-mode port/fd) new-fd)))))
 
 (define (duplicate-port port modes)
   (dup->port port modes))
@@ -1075,7 +1098,7 @@ If there is no handler at all, Guile prints an error and then exits."
 
 (set! %load-hook %load-announce)
 
-(define (load name . reader)
+(define* (load name #:optional reader)
   ;; Returns the .go file corresponding to `name'. Does not search load
   ;; paths, only the fallback path. If the .go file is missing or out of
   ;; date, and autocompilation is enabled, will try autocompilation, just
@@ -1113,6 +1136,10 @@ If there is no handler at all, Guile prints an error and then exits."
                  (%load-should-autocompile
                   (%warn-autocompilation-enabled)
                   (format (current-error-port) ";;; compiling ~a\n" name)
+                  ;; This use of @ is (ironically?) boot-safe, as modules have
+                  ;; not been booted yet, so the resolve-module call in psyntax
+                  ;; doesn't try to load a module, and compile-file will be
+                  ;; treated as a function, not a macro.
                   (let ((cfn ((@ (system base compile) compile-file) name
                               #:env (current-module))))
                     (format (current-error-port) ";;; compiled ~a\n" cfn)
@@ -1123,7 +1150,7 @@ If there is no handler at all, Guile prints an error and then exits."
                 ";;; WARNING: compilation of ~a failed:\n;;; key ~a, throw_args ~s\n"
                 name k args)
         #f)))
-  (with-fluids ((current-reader (and (pair? reader) (car reader))))
+  (with-fluids ((current-reader reader))
     (let ((cfn (and=> (and=> (false-if-exception (canonicalize-path name))
                              compiled-file-name)
                       fresh-compiled-file-name)))
@@ -1413,12 +1440,7 @@ If there is no handler at all, Guile prints an error and then exits."
 ;;;
 
 ;; This is how modules are printed.  You can re-define it.
-;; (Redefining is actually more complicated than simply redefining
-;; %print-module because that would only change the binding and not
-;; the value stored in the vtable that determines how record are
-;; printed. Sigh.)
-
-(define (%print-module mod port)  ; unused args: depth length style table)
+(define (%print-module mod port)
   (display "#<" port)
   (display (or (module-kind mod) "module") port)
   (display " " port)
@@ -1427,23 +1449,145 @@ If there is no handler at all, Guile prints an error and then exits."
   (display (number->string (object-address mod) 16) port)
   (display ">" port))
 
-;; module-type
-;;
-;; A module is characterized by an obarray in which local symbols
-;; are interned, a list of modules, "uses", from which non-local
-;; bindings can be inherited, and an optional lazy-binder which
-;; is a (CLOSURE module symbol) which, as a last resort, can provide
-;; bindings that would otherwise not be found locally in the module.
-;;
-;; NOTE: If you change anything here, you also need to change
-;; libguile/modules.h.
-;;
-(define module-type
-  (make-record-type 'module
-                    '(obarray uses binder eval-closure transformer name kind
-                      duplicates-handlers import-obarray
-                      observers weak-observers version)
-                    %print-module))
+(letrec-syntax
+     ;; Locally extend the syntax to allow record accessors to be defined at
+     ;; compile-time. Cache the rtd locally to the constructor, the getters and
+     ;; the setters, in order to allow for redefinition of the record type; not
+     ;; relevant in the case of modules, but perhaps if we make this public, it
+     ;; could matter.
+
+    ((define-record-type
+       (lambda (x)
+         (define (make-id scope . fragments)
+           (datum->syntax #'scope
+                          (apply symbol-append
+                                 (map (lambda (x)
+                                        (if (symbol? x) x (syntax->datum x)))
+                                      fragments))))
+         
+         (define (getter rtd type-name field slot)
+           #`(define #,(make-id rtd type-name '- field)
+               (let ((rtd #,rtd))
+                 (lambda (#,type-name)
+                   (if (eq? (struct-vtable #,type-name) rtd)
+                       (struct-ref #,type-name #,slot)
+                       (%record-type-error rtd #,type-name))))))
+
+         (define (setter rtd type-name field slot)
+           #`(define #,(make-id rtd 'set- type-name '- field '!)
+               (let ((rtd #,rtd))
+                 (lambda (#,type-name val)
+                   (if (eq? (struct-vtable #,type-name) rtd)
+                       (struct-set! #,type-name #,slot val)
+                       (%record-type-error rtd #,type-name))))))
+
+         (define (accessors rtd type-name fields n exp)
+           (syntax-case fields ()
+             (() exp)
+             (((field #:no-accessors) field* ...) (identifier? #'field)
+              (accessors rtd type-name #'(field* ...) (1+ n)
+                         exp))
+             (((field #:no-setter) field* ...) (identifier? #'field)
+              (accessors rtd type-name #'(field* ...) (1+ n)
+                         #`(begin #,exp
+                                  #,(getter rtd type-name #'field n))))
+             (((field #:no-getter) field* ...) (identifier? #'field)
+              (accessors rtd type-name #'(field* ...) (1+ n)
+                         #`(begin #,exp
+                                  #,(setter rtd type-name #'field n))))
+             ((field field* ...) (identifier? #'field)
+              (accessors rtd type-name #'(field* ...) (1+ n)
+                         #`(begin #,exp
+                                  #,(getter rtd type-name #'field n)
+                                  #,(setter rtd type-name #'field n))))))
+
+         (define (predicate rtd type-name fields exp)
+           (accessors
+            rtd type-name fields 0
+            #`(begin
+                #,exp
+                (define (#,(make-id rtd type-name '?) obj)
+                  (and (struct? obj) (eq? (struct-vtable obj) #,rtd))))))
+
+         (define (field-list fields)
+           (syntax-case fields ()
+             (() '())
+             (((f . opts) . rest) (identifier? #'f)
+              (cons #'f (field-list #'rest)))
+             ((f . rest) (identifier? #'f)
+              (cons #'f (field-list #'rest)))))
+
+         (define (constructor rtd type-name fields exp)
+           (let ((ctor (make-id rtd type-name '-constructor))
+                 (args (field-list fields)))
+             (predicate rtd type-name fields
+                        #`(begin #,exp
+                                 (define #,ctor
+                                   (let ((rtd #,rtd))
+                                     (lambda #,args
+                                       (make-struct rtd 0 #,@args))))
+                                 (struct-set! #,rtd (+ vtable-offset-user 2)
+                                              #,ctor)))))
+
+         (define (type type-name printer fields)
+           (define (make-layout)
+             (let lp ((fields fields) (slots '()))
+               (syntax-case fields ()
+                 (() (datum->syntax #'here
+                                    (make-struct-layout
+                                     (apply string-append slots))))
+                 ((_ . rest) (lp #'rest (cons "pw" slots))))))
+
+           (let ((rtd (make-id type-name type-name '-type)))
+             (constructor rtd type-name fields
+                          #`(begin
+                              (define #,rtd
+                                (make-struct record-type-vtable 0
+                                             '#,(make-layout)
+                                             #,printer
+                                             '#,type-name
+                                             '#,(field-list fields)))
+                              (set-struct-vtable-name! #,rtd '#,type-name)))))
+
+         (syntax-case x ()
+           ((_ type-name printer (field ...))
+            (type #'type-name #'printer #'(field ...)))))))
+
+  ;; module-type
+  ;;
+  ;; A module is characterized by an obarray in which local symbols
+  ;; are interned, a list of modules, "uses", from which non-local
+  ;; bindings can be inherited, and an optional lazy-binder which
+  ;; is a (CLOSURE module symbol) which, as a last resort, can provide
+  ;; bindings that would otherwise not be found locally in the module.
+  ;;
+  ;; NOTE: If you change the set of fields or their order, you also need to
+  ;; change the constants in libguile/modules.h.
+  ;;
+  ;; NOTE: The getter `module-eval-closure' is used in libguile/modules.c.
+  ;; NOTE: The getter `module-transfomer' is defined libguile/modules.c.
+  ;; NOTE: The getter `module-name' is defined later, due to boot reasons.
+  ;; NOTE: The getter `module-public-interface' is used in libguile/modules.c.
+  ;;
+  (define-record-type module
+    (lambda (obj port) (%print-module obj port))
+    (obarray
+     uses
+     binder
+     eval-closure
+     (transformer #:no-getter)
+     (name #:no-getter)
+     kind
+     duplicates-handlers
+     (import-obarray #:no-setter)
+     observers
+     (weak-observers #:no-setter)
+     version
+     submodules
+     submodule-binder
+     public-interface
+     filename)))
+
 
 ;; make-module &opt size uses binder
 ;;
@@ -1479,11 +1623,12 @@ If there is no handler at all, Guile prints an error and then exits."
              "Lazy-binder expected to be a procedure or #f." binder))
 
         (let ((module (module-constructor (make-hash-table size)
-                                          uses binder #f %pre-modules-transformer
+                                          uses binder #f macroexpand
                                           #f #f #f
                                           (make-hash-table %default-import-size)
                                           '()
-                                          (make-weak-key-hash-table 31) #f)))
+                                          (make-weak-key-hash-table 31) #f
+                                          (make-hash-table 7) #f #f #f)))
 
           ;; We can't pass this as an argument to module-constructor,
           ;; because we need it to close over a pointer to the module
@@ -1492,55 +1637,6 @@ If there is no handler at all, Guile prints an error and then exits."
 
           module))))
 
-(define module-constructor (record-constructor module-type))
-(define module-obarray  (record-accessor module-type 'obarray))
-(define set-module-obarray! (record-modifier module-type 'obarray))
-(define module-uses  (record-accessor module-type 'uses))
-(define set-module-uses! (record-modifier module-type 'uses))
-(define module-binder (record-accessor module-type 'binder))
-(define set-module-binder! (record-modifier module-type 'binder))
-
-;; NOTE: This binding is used in libguile/modules.c.
-(define module-eval-closure (record-accessor module-type 'eval-closure))
-
-;; (define module-transformer (record-accessor module-type 'transformer))
-(define set-module-transformer! (record-modifier module-type 'transformer))
-(define module-version (record-accessor module-type 'version))
-(define set-module-version! (record-modifier module-type 'version))
-;; (define module-name (record-accessor module-type 'name)) wait until mods are booted
-(define set-module-name! (record-modifier module-type 'name))
-(define module-kind (record-accessor module-type 'kind))
-(define set-module-kind! (record-modifier module-type 'kind))
-(define module-duplicates-handlers
-  (record-accessor module-type 'duplicates-handlers))
-(define set-module-duplicates-handlers!
-  (record-modifier module-type 'duplicates-handlers))
-(define module-observers (record-accessor module-type 'observers))
-(define set-module-observers! (record-modifier module-type 'observers))
-(define module-weak-observers (record-accessor module-type 'weak-observers))
-(define module? (record-predicate module-type))
-
-(define module-import-obarray (record-accessor module-type 'import-obarray))
-
-(define set-module-eval-closure!
-  (let ((setter (record-modifier module-type 'eval-closure)))
-    (lambda (module closure)
-      (setter module closure)
-      ;; Make it possible to lookup the module from the environment.
-      ;; This implementation is correct since an eval closure can belong
-      ;; to maximally one module.
-
-      ;; XXX: The following line introduces a circular reference that
-      ;; precludes garbage collection of modules with the current weak hash
-      ;; table semantics (see
-      ;; http://lists.gnu.org/archive/html/guile-devel/2009-01/msg00102.html and
-      ;; http://thread.gmane.org/gmane.comp.programming.garbage-collection.boehmgc/2465
-      ;; for details).  Since it doesn't appear to be used (only in
-      ;; `scm_lookup_closure_module ()', which has 1 caller), we just comment
-      ;; it out.
-
-      ;(set-procedure-property! closure 'module module)
-      )))
 
 \f
 
@@ -1551,7 +1647,7 @@ If there is no handler at all, Guile prints an error and then exits."
   (set-module-observers! module (cons proc (module-observers module)))
   (cons module proc))
 
-(define (module-observe-weak module observer-id . proc)
+(define* (module-observe-weak module observer-id #:optional (proc observer-id))
   ;; Register PROC as an observer of MODULE under name OBSERVER-ID (which can
   ;; be any Scheme object).  PROC is invoked and passed MODULE any time
   ;; MODULE is modified.  PROC gets unregistered when OBSERVER-ID gets GC'd
@@ -1561,9 +1657,7 @@ If there is no handler at all, Guile prints an error and then exits."
   ;; The two-argument version is kept for backward compatibility: when called
   ;; with two arguments, the observer gets unregistered when closure PROC
   ;; gets GC'd (making it impossible to use an anonymous lambda for PROC).
-
-  (let ((proc (if (null? proc) observer-id (car proc))))
-    (hashq-set! (module-weak-observers module) observer-id proc)))
+  (hashq-set! (module-weak-observers module) observer-id proc))
 
 (define (module-unobserve token)
   (let ((module (car token))
@@ -1842,6 +1936,20 @@ If there is no handler at all, Guile prints an error and then exits."
 (define (module-map proc module)
   (hash-map->list proc (module-obarray module)))
 
+;; Submodules
+;;
+;; Modules exist in a separate namespace from values, because you generally do
+;; not want the name of a submodule, which you might not even use, to collide
+;; with local variables that happen to be named the same as the submodule.
+;;
+(define (module-ref-submodule module name)
+  (or (hashq-ref (module-submodules module) name)
+      (and (module-submodule-binder module)
+           ((module-submodule-binder module) module name))))
+
+(define (module-define-submodule! module name submodule)
+  (hashq-set! (module-submodules module) name submodule))
+
 \f
 
 ;;; {Low Level Bootstrapping}
@@ -1893,19 +2001,18 @@ If there is no handler at all, Guile prints an error and then exits."
 
 (define basic-load load)
 
-(define (load-module filename . reader)
+(define* (load-module filename #:optional reader)
   (save-module-excursion
    (lambda ()
      (let ((oldname (and (current-load-port)
                          (port-filename (current-load-port)))))
-       (apply basic-load
-              (if (and oldname
-                       (> (string-length filename) 0)
-                       (not (char=? (string-ref filename 0) #\/))
-                       (not (string=? (dirname oldname) ".")))
-                  (string-append (dirname oldname) "/" filename)
-                  filename)
-              reader)))))
+       (basic-load (if (and oldname
+                            (> (string-length filename) 0)
+                            (not (char=? (string-ref filename 0) #\/))
+                            (not (string=? (dirname oldname) ".")))
+                       (string-append (dirname oldname) "/" filename)
+                       filename)
+                   reader)))))
 
 
 \f
@@ -1996,15 +2103,15 @@ If there is no handler at all, Guile prints an error and then exits."
 ;;; {Recursive Namespaces}
 ;;;
 ;;; A hierarchical namespace emerges if we consider some module to be
-;;; root, and variables bound to modules as nested namespaces.
+;;; root, and submodules of that module to be nested namespaces.
 ;;;
-;;; The routines in this file manage variable names in hierarchical namespace.
+;;; The routines here manage variable names in hierarchical namespace.
 ;;; Each variable name is a list of elements, looked up in successively nested
 ;;; modules.
 ;;;
 ;;;             (nested-ref some-root-module '(foo bar baz))
-;;;             => <value of a variable named baz in the module bound to bar in
-;;;                 the module bound to foo in some-root-module>
+;;;             => <value of a variable named baz in the submodule bar of
+;;;                 the submodule foo of some-root-module>
 ;;;
 ;;;
 ;;; There are:
@@ -2017,67 +2124,116 @@ If there is no handler at all, Guile prints an error and then exits."
 ;;;     nested-define! a-root name val
 ;;;     nested-remove! a-root name
 ;;;
+;;; These functions manipulate values in namespaces. For referencing the
+;;; namespaces themselves, use the following:
+;;;
+;;;     nested-ref-module a-root name
+;;;     nested-define-module! a-root name mod
 ;;;
-;;; (current-module) is a natural choice for a-root so for convenience there are
+;;; (current-module) is a natural choice for a root so for convenience there are
 ;;; also:
 ;;;
-;;;     local-ref name          ==      nested-ref (current-module) name
-;;;     local-set! name val     ==      nested-set! (current-module) name val
-;;;     local-define! name val  ==      nested-define! (current-module) name val
-;;;     local-remove! name      ==      nested-remove! (current-module) name
+;;;     local-ref name                ==  nested-ref (current-module) name
+;;;     local-set! name val           ==  nested-set! (current-module) name val
+;;;     local-define name val         ==  nested-define! (current-module) name val
+;;;     local-remove name             ==  nested-remove! (current-module) name
+;;;     local-ref-module name         ==  nested-ref-module (current-module) name
+;;;     local-define-module! name m   ==  nested-define-module! (current-module) name m
 ;;;
 
 
 (define (nested-ref root names)
-  (let loop ((cur root)
-             (elts names))
-    (cond
-     ((null? elts)              cur)
-     ((not (module? cur))       #f)
-     (else (loop (module-ref cur (car elts) #f) (cdr elts))))))
+  (if (null? names)
+      root
+      (let loop ((cur root)
+                 (head (car names))
+                 (tail (cdr names)))
+        (if (null? tail)
+            (module-ref cur head #f)
+            (let ((cur (module-ref-submodule cur head)))
+              (and cur
+                   (loop cur (car tail) (cdr tail))))))))
 
 (define (nested-set! root names val)
   (let loop ((cur root)
-             (elts names))
-    (if (null? (cdr elts))
-        (module-set! cur (car elts) val)
-        (loop (module-ref cur (car elts)) (cdr elts)))))
+             (head (car names))
+             (tail (cdr names)))
+    (if (null? tail)
+        (module-set! cur head val)
+        (let ((cur (module-ref-submodule cur head)))
+          (if (not cur)
+              (error "failed to resolve module" names)
+              (loop cur (car tail) (cdr tail)))))))
 
 (define (nested-define! root names val)
   (let loop ((cur root)
-             (elts names))
-    (if (null? (cdr elts))
-        (module-define! cur (car elts) val)
-        (loop (module-ref cur (car elts)) (cdr elts)))))
+             (head (car names))
+             (tail (cdr names)))
+    (if (null? tail)
+        (module-define! cur head val)
+        (let ((cur (module-ref-submodule cur head)))
+          (if (not cur)
+              (error "failed to resolve module" names)
+              (loop cur (car tail) (cdr tail)))))))
 
 (define (nested-remove! root names)
   (let loop ((cur root)
-             (elts names))
-    (if (null? (cdr elts))
-        (module-remove! cur (car elts))
-        (loop (module-ref cur (car elts)) (cdr elts)))))
+             (head (car names))
+             (tail (cdr names)))
+    (if (null? tail)
+        (module-remove! cur head)
+        (let ((cur (module-ref-submodule cur head)))
+          (if (not cur)
+              (error "failed to resolve module" names)
+              (loop cur (car tail) (cdr tail)))))))
+
+
+(define (nested-ref-module root names)
+  (let loop ((cur root)
+             (names names))
+    (if (null? names)
+        cur
+        (let ((cur (module-ref-submodule cur (car names))))
+          (and cur
+               (loop cur (cdr names)))))))
+
+(define (nested-define-module! root names module)
+  (if (null? names)
+      (error "can't redefine root module" root module)
+      (let loop ((cur root)
+                 (head (car names))
+                 (tail (cdr names)))
+        (if (null? tail)
+            (module-define-submodule! cur head module)
+            (let ((cur (or (module-ref-submodule cur head)
+                           (let ((m (make-module 31)))
+                             (set-module-kind! m 'directory)
+                             (set-module-name! m (append (module-name cur)
+                                                         (list head)))
+                             (module-define-submodule! cur head m)
+                             m))))
+              (loop cur (car tail) (cdr tail)))))))
+
 
 (define (local-ref names) (nested-ref (current-module) names))
 (define (local-set! names val) (nested-set! (current-module) names val))
 (define (local-define names val) (nested-define! (current-module) names val))
 (define (local-remove names) (nested-remove! (current-module) names))
+(define (local-ref-module names) (nested-ref-module (current-module) names))
+(define (local-define-module names mod) (nested-define-module! (current-module) names mod))
+
 
 
 \f
 
-;;; {The (%app) module}
-;;;
-;;; The root of conventionally named objects not directly in the top level.
-;;;
-;;; (%app modules)
-;;; (%app modules guile)
+;;; {The (guile) module}
 ;;;
-;;; The directory of all modules and the standard root module.
+;;; The standard module, which has the core Guile bindings. Also called the
+;;; "root module", as it is imported by many other modules, but it is not
+;;; necessarily the root of anything; and indeed, the module named '() might be
+;;; better thought of as a root.
 ;;;
 
-;; module-public-interface is defined in C.
-(define (set-module-public-interface! m i)
-  (module-define! m '%module-public-interface i))
 (define (set-system-module! m s)
   (set-procedure-property! (module-eval-closure m) 'system-module s))
 (define the-root-module (make-root-module))
@@ -2089,23 +2245,54 @@ If there is no handler at all, Guile prints an error and then exits."
 (set-system-module! the-root-module #t)
 (set-system-module! the-scm-module #t)
 
-;; NOTE: This binding is used in libguile/modules.c.
+
+\f
+
+;; Now that we have a root module, even though modules aren't fully booted,
+;; expand the definition of resolve-module.
+;;
+(define (resolve-module name . args)
+  (if (equal? name '(guile))
+      the-root-module
+      (error "unexpected module to resolve during module boot" name)))
+
+;; Cheat.  These bindings are needed by modules.c, but we don't want
+;; to move their real definition here because that would be unnatural.
 ;;
+(define process-define-module #f)
+(define process-use-modules #f)
+(define module-export! #f)
+(define default-duplicate-binding-procedures #f)
+
+;; This boots the module system.  All bindings needed by modules.c
+;; must have been defined by now.
+;;
+(set-current-module the-root-module)
+
+
+\f
+
+;; Now that modules are booted, give module-name its final definition.
+;;
+(define module-name
+  (let ((accessor (record-accessor module-type 'name)))
+    (lambda (mod)
+      (or (accessor mod)
+          (let ((name (list (gensym))))
+            ;; Name MOD and bind it in the module root so that it's visible to
+            ;; `resolve-module'. This is important as `psyntax' stores module
+            ;; names and relies on being able to `resolve-module' them.
+            (set-module-name! mod name)
+            (nested-define-module! (resolve-module '() #f) name mod)
+            (accessor mod))))))
+
 (define (make-modules-in module name)
-  (if (null? name)
-      module
-      (make-modules-in
-       (let* ((var (module-local-variable module (car name)))
-              (val (and var (variable-bound? var) (variable-ref var))))
-         (if (module? val)
-             val
-             (let ((m (make-module 31)))
-               (set-module-kind! m 'directory)
-               (set-module-name! m (append (module-name module)
-                                           (list (car name))))
-               (module-define! module (car name) m)
-               m)))
-       (cdr name))))
+  (or (nested-ref-module module name)
+      (let ((m (make-module 31)))
+        (set-module-kind! m 'directory)
+        (set-module-name! m (append (module-name module) name))
+        (nested-define-module! module name m)
+        m)))
 
 (define (beautify-user-module! module)
   (let ((interface (module-public-interface module)))
@@ -2163,7 +2350,7 @@ If there is no handler at all, Guile prints an error and then exits."
                (cond ((> (car lst1) (car lst2)) #t)
                      ((< (car lst1) (car lst2)) #f)
                      (else (numlist-less (cdr lst1) (cdr lst2)))))))
-    (numlist-less (car pair1) (car pair2)))
+    (not (numlist-less (car pair2) (car pair1))))
   (define (match-version-and-file pair)
     (and (version-matches? version-ref (car pair))
          (let ((filenames                            
@@ -2171,7 +2358,7 @@ If there is no handler at all, Guile prints an error and then exits."
                           (let ((s (false-if-exception (stat file))))
                             (and s (eq? (stat:type s) 'regular))))
                         (map (lambda (ext)
-                               (string-append (cdr pair) "/" name ext))
+                               (string-append (cdr pair) name ext))
                              %load-extensions))))
            (and (not (null? filenames))
                 (cons (car pair) (car filenames))))))
@@ -2182,12 +2369,14 @@ If there is no handler at all, Guile prints an error and then exits."
         (let ((entry (readdir dstrm)))
           (if (eof-object? entry)
               subdir-pairs
-              (let* ((subdir (string-append (cdr root-pair) "/" entry))
+              (let* ((subdir (string-append (cdr root-pair) entry))
                      (num (string->number entry))
-                     (num (and num (append (car root-pair) (list num)))))
+                     (num (and num (exact? num) (append (car root-pair) 
+                                                        (list num)))))
                 (if (and num (eq? (stat:type (stat subdir)) 'directory))
-                    (filter-subdir 
-                     root-pair dstrm (cons (cons num subdir) subdir-pairs))
+                    (filter-subdir
+                     root-pair dstrm (cons (cons num (string-append subdir "/"))
+                                           subdir-pairs))
                     (filter-subdir root-pair dstrm subdir-pairs))))))
       
       (or (and (null? root-pairs) ret)
@@ -2226,70 +2415,32 @@ If there is no handler at all, Guile prints an error and then exits."
 ;; NOTE: This binding is used in libguile/modules.c.
 ;;
 (define resolve-module
-  (let ((the-root-module the-root-module))
-    (lambda (name . args)
-      (if (equal? name '(guile))
-          the-root-module
-          (let ((full-name (append '(%app modules) name)))
-            (let* ((already (nested-ref the-root-module full-name))
-                   (numargs (length args))
-                   (autoload (or (= numargs 0) (car args)))
-                   (version (and (> numargs 1) (cadr args))))
-              (cond
-               ((and already (module? already)
-                     (or (not autoload) (module-public-interface already)))
-                ;; A hit, a palpable hit.
-                (if (and version 
-                         (not (version-matches? version (module-version already))))
-                    (error "incompatible module version already loaded" name))
-                already)
-               (autoload
-                ;; Try to autoload the module, and recurse.
-                (try-load-module name version)
-                (resolve-module name #f))
-               (else
-                ;; A module is not bound (but maybe something else is),
-                ;; we're not autoloading -- here's the weird semantics,
-                ;; we create an empty module.
-                (make-modules-in the-root-module full-name)))))))))
+  (let ((root (make-module)))
+    (set-module-name! root '())
+    ;; Define the-root-module as '(guile).
+    (module-define-submodule! root 'guile the-root-module)
 
-;; Cheat.  These bindings are needed by modules.c, but we don't want
-;; to move their real definition here because that would be unnatural.
-;;
-(define try-module-autoload #f)
-(define process-define-module #f)
-(define process-use-modules #f)
-(define module-export! #f)
-(define default-duplicate-binding-procedures #f)
-
-(define %app (make-module 31))
-(set-module-name! %app '(%app))
-(define app %app) ;; for backwards compatability
-
-(let ((m (make-module 31)))
-  (set-module-name! m '())
-  (local-define '(%app modules) m))
-(local-define '(%app modules guile) the-root-module)
-
-;; This boots the module system.  All bindings needed by modules.c
-;; must have been defined by now.
-;;
-(set-current-module the-root-module)
-;; definition deferred for syncase's benefit.
-(define module-name
-  (let ((accessor (record-accessor module-type 'name)))
-    (lambda (mod)
-      (or (accessor mod)
-          (let ((name (list (gensym))))
-            ;; Name MOD and bind it in THE-ROOT-MODULE so that it's visible
-            ;; to `resolve-module'.  This is important as `psyntax' stores
-            ;; module names and relies on being able to `resolve-module'
-            ;; them.
-            (set-module-name! mod name)
-            (nested-define! the-root-module `(%app modules ,@name) mod)
-            (accessor mod))))))
+    (lambda* (name #:optional (autoload #t) (version #f) #:key (ensure #t))
+      (let ((already (nested-ref-module root name)))
+        (cond
+         ((and already
+               (or (not autoload) (module-public-interface already)))
+          ;; A hit, a palpable hit.
+          (if (and version 
+                   (not (version-matches? version (module-version already))))
+              (error "incompatible module version already loaded" name))
+          already)
+         (autoload
+          ;; Try to autoload the module, and recurse.
+          (try-load-module name version)
+          (resolve-module name #f #:ensure ensure))
+         (else
+          ;; No module found (or if one was, it had no public interface), and
+          ;; we're not autoloading. Make an empty module if #:ensure is true.
+          (or already
+              (and ensure
+                   (make-modules-in root name)))))))))
 
-;; (define-special-value '(%app modules new-ws) (lambda () (make-scm-module)))
 
 (define (try-load-module name version)
   (try-module-autoload name version))
@@ -2335,25 +2486,15 @@ If there is no handler at all, Guile prints an error and then exits."
 ;; or its public interface is not available.  Signal "no binding"
 ;; error if selected binding does not exist in the used module.
 ;;
-(define (resolve-interface name . args)
-
-  (define (get-keyword-arg args kw def)
-    (cond ((memq kw args)
-           => (lambda (kw-arg)
-                (if (null? (cdr kw-arg))
-                    (error "keyword without value: " kw))
-                (cadr kw-arg)))
-          (else
-           def)))
-
-  (let* ((select (get-keyword-arg args #:select #f))
-         (hide (get-keyword-arg args #:hide '()))
-         (renamer (or (get-keyword-arg args #:renamer #f)
-                      (let ((prefix (get-keyword-arg args #:prefix #f)))
-                        (and prefix (symbol-prefix-proc prefix)))
-                      identity))
-         (version (get-keyword-arg args #:version #f))
-         (module (resolve-module name #t version))
+(define* (resolve-interface name #:key
+                            (select #f)
+                            (hide '())
+                            (prefix #f)
+                            (renamer (if prefix
+                                         (symbol-prefix-proc prefix)
+                                         identity))
+                            version)
+  (let* ((module (resolve-module name #t version))
          (public-i (and module (module-public-interface module))))
     (and (or (not module) (not public-i))
          (error "no code for module" name))
@@ -2517,6 +2658,16 @@ If there is no handler at all, Guile prints an error and then exits."
                    re-exports
                    (append (cadr kws) replacements)
                    autoloads))
+            ((#:filename)
+             (or (pair? (cdr kws))
+                 (unrecognized kws))
+             (set-module-filename! module (cadr kws))
+             (loop (cddr kws)
+                   reversed-interfaces
+                   exports
+                   re-exports
+                   replacements
+                   autoloads))
             (else
              (unrecognized kws)))))
     (run-hook module-defined-hook module)
@@ -2545,7 +2696,8 @@ If there is no handler at all, Guile prints an error and then exits."
                           (set-car! autoload i)))
                     (module-local-variable i sym))))))
     (module-constructor (make-hash-table 0) '() b #f #f name 'autoload #f
-                        (make-hash-table 0) '() (make-weak-value-hash-table 31) #f)))
+                        (make-hash-table 0) '() (make-weak-value-hash-table 31) #f
+                        (make-hash-table 0) #f #f #f)))
 
 (define (module-autoload! module . args)
   "Have @var{module} automatically load the module named @var{name} when one
@@ -2575,10 +2727,9 @@ module '(ice-9 q) '(make-q q-length))}."
 ;; This function is called from "modules.c".  If you change it, be
 ;; sure to update "modules.c" as well.
 
-(define (try-module-autoload module-name . args)
+(define* (try-module-autoload module-name #:optional version)
   (let* ((reverse-name (reverse module-name))
          (name (symbol->string (car reverse-name)))
-         (version (and (not (null? args)) (car args)))
          (dir-hint-module-name (reverse (cdr reverse-name)))
          (dir-hint (apply string-append
                           (map (lambda (elt)
@@ -2760,87 +2911,6 @@ module '(ice-9 q) '(make-q q-length))}."
 (define (set-batch-mode?! arg) #t)
 (define (batch-mode?) #t)
 
-(define (error-catching-loop thunk)
-  (let ((status #f)
-        (interactive #t))
-    (define (loop first)
-      (let ((next
-             (catch #t
-
-                    (lambda ()
-                      (call-with-unblocked-asyncs
-                       (lambda ()
-                         (with-traps
-                          (lambda ()
-                            (first)
-
-                            ;; This line is needed because mark
-                            ;; doesn't do closures quite right.
-                            ;; Unreferenced locals should be
-                            ;; collected.
-                            (set! first #f)
-                            (let loop ((v (thunk)))
-                              (loop (thunk)))
-                            #f)))))
-
-                    (lambda (key . args)
-                      (case key
-                        ((quit)
-                         (set! status args)
-                         #f)
-
-                        ((switch-repl)
-                         (apply throw 'switch-repl args))
-
-                        ((abort)
-                         ;; This is one of the closures that require
-                         ;; (set! first #f) above
-                         ;;
-                         (lambda ()
-                           (run-hook abort-hook)
-                           (force-output (current-output-port))
-                           (display "ABORT: "  (current-error-port))
-                           (write args (current-error-port))
-                           (newline (current-error-port))
-                           (if interactive
-                               (begin
-                                 (if (and
-                                      (not has-shown-debugger-hint?)
-                                      (not (memq 'backtrace
-                                                 (debug-options-interface)))
-                                      (stack? (fluid-ref the-last-stack)))
-                                     (begin
-                                       (newline (current-error-port))
-                                       (display
-                                        "Type \"(backtrace)\" to get more information or \"(debug)\" to enter the debugger.\n"
-                                        (current-error-port))
-                                       (set! has-shown-debugger-hint? #t)))
-                                 (force-output (current-error-port)))
-                               (begin
-                                 (primitive-exit 1)))
-                           (set! stack-saved? #f)))
-
-                        (else
-                         ;; This is the other cons-leak closure...
-                         (lambda ()
-                           (cond ((= (length args) 4)
-                                  (apply handle-system-error key args))
-                                 (else
-                                  (apply bad-throw key args)))))))
-
-                    default-pre-unwind-handler)))
-
-        (if next (loop next) status)))
-    (set! set-batch-mode?! (lambda (arg)
-                             (cond (arg
-                                    (set! interactive #f)
-                                    (restore-signals))
-                                   (#t
-                                    (error "sorry, not implemented")))))
-    (set! batch-mode? (lambda () (not interactive)))
-    (call-with-blocked-asyncs
-     (lambda () (loop (lambda () #t))))))
-
 ;;(define the-last-stack (make-fluid)) Defined by scm_init_backtrace ()
 (define before-signal-stack (make-fluid))
 ;; FIXME: stack-saved? is broken in the presence of threads.
@@ -2896,30 +2966,6 @@ module '(ice-9 q) '(make-q q-length))}."
 
 (define exit quit)
 
-;;(define has-shown-backtrace-hint? #f) Defined by scm_init_backtrace ()
-
-;; Replaced by C code:
-;;(define (backtrace)
-;;  (if (fluid-ref the-last-stack)
-;;      (begin
-;;      (newline)
-;;      (display-backtrace (fluid-ref the-last-stack) (current-output-port))
-;;      (newline)
-;;      (if (and (not has-shown-backtrace-hint?)
-;;               (not (memq 'backtrace (debug-options-interface))))
-;;          (begin
-;;            (display
-;;"Type \"(debug-enable 'backtrace)\" if you would like a backtrace
-;;automatically if an error occurs in the future.\n")
-;;            (set! has-shown-backtrace-hint? #t))))
-;;      (display "No backtrace available.\n")))
-
-(define (error-catching-repl r e p)
-  (error-catching-loop
-   (lambda ()
-     (call-with-values (lambda () (e (r)))
-       (lambda the-values (for-each p the-values))))))
-
 (define (gc-run-time)
   (cdr (assq 'gc-time-taken (gc-stats))))
 
@@ -2933,122 +2979,12 @@ module '(ice-9 q) '(make-q q-length))}."
 ;;; The default repl-reader function.  We may override this if we've
 ;;; the readline library.
 (define repl-reader
-  (lambda (prompt . reader)
+  (lambda* (prompt #:optional (reader (fluid-ref current-reader)))
     (if (not (char-ready?))
         (display (if (string? prompt) prompt (prompt))))
     (force-output)
     (run-hook before-read-hook)
-    ((or (and (pair? reader) (car reader))
-         (fluid-ref current-reader)
-         read)
-     (current-input-port))))
-
-(define (scm-style-repl)
-
-  (letrec (
-           (start-gc-rt #f)
-           (start-rt #f)
-           (repl-report-start-timing (lambda ()
-                                       (set! start-gc-rt (gc-run-time))
-                                       (set! start-rt (get-internal-run-time))))
-           (repl-report (lambda ()
-                          (display ";;; ")
-                          (display (inexact->exact
-                                    (* 1000 (/ (- (get-internal-run-time) start-rt)
-                                               internal-time-units-per-second))))
-                          (display "  msec  (")
-                          (display  (inexact->exact
-                                     (* 1000 (/ (- (gc-run-time) start-gc-rt)
-                                                internal-time-units-per-second))))
-                          (display " msec in gc)\n")))
-
-           (consume-trailing-whitespace
-            (lambda ()
-              (let ((ch (peek-char)))
-                (cond
-                 ((eof-object? ch))
-                 ((or (char=? ch #\space) (char=? ch #\tab))
-                  (read-char)
-                  (consume-trailing-whitespace))
-                 ((char=? ch #\newline)
-                  (read-char))))))
-           (-read (lambda ()
-                    (let ((val
-                           (let ((prompt (cond ((string? scm-repl-prompt)
-                                                scm-repl-prompt)
-                                               ((thunk? scm-repl-prompt)
-                                                (scm-repl-prompt))
-                                               (scm-repl-prompt "> ")
-                                               (else ""))))
-                             (repl-reader prompt))))
-
-                      ;; As described in R4RS, the READ procedure updates the
-                      ;; port to point to the first character past the end of
-                      ;; the external representation of the object.  This
-                      ;; means that it doesn't consume the newline typically
-                      ;; found after an expression.  This means that, when
-                      ;; debugging Guile with GDB, GDB gets the newline, which
-                      ;; it often interprets as a "continue" command, making
-                      ;; breakpoints kind of useless.  So, consume any
-                      ;; trailing newline here, as well as any whitespace
-                      ;; before it.
-                      ;; But not if EOF, for control-D.
-                      (if (not (eof-object? val))
-                          (consume-trailing-whitespace))
-                      (run-hook after-read-hook)
-                      (if (eof-object? val)
-                          (begin
-                            (repl-report-start-timing)
-                            (if scm-repl-verbose
-                                (begin
-                                  (newline)
-                                  (display ";;; EOF -- quitting")
-                                  (newline)))
-                            (quit 0)))
-                      val)))
-
-           (-eval (lambda (sourc)
-                    (repl-report-start-timing)
-                    (run-hook before-eval-hook sourc)
-                    (let ((val (start-stack 'repl-stack
-                                            ;; If you change this procedure
-                                            ;; (primitive-eval), please also
-                                            ;; modify the repl-stack case in
-                                            ;; save-stack so that stack cutting
-                                            ;; continues to work.
-                                            (primitive-eval sourc))))
-                      (run-hook after-eval-hook sourc)
-                      val)))
-
-
-           (-print (let ((maybe-print (lambda (result)
-                                        (if (or scm-repl-print-unspecified
-                                                (not (unspecified? result)))
-                                            (begin
-                                              (write result)
-                                              (newline))))))
-                     (lambda (result)
-                       (if (not scm-repl-silent)
-                           (begin
-                             (run-hook before-print-hook result)
-                             (maybe-print result)
-                             (run-hook after-print-hook result)
-                             (if scm-repl-verbose
-                                 (repl-report))
-                             (force-output))))))
-
-           (-quit (lambda (args)
-                    (if scm-repl-verbose
-                        (begin
-                          (display ";;; QUIT executed, repl exitting")
-                          (newline)
-                          (repl-report)))
-                    args)))
-
-    (let ((status (error-catching-repl -read
-                                       -eval
-                                       -print)))
-      (-quit status))))
+    ((or reader read) (current-input-port))))
 
 
 \f
@@ -3118,76 +3054,85 @@ module '(ice-9 q) '(make-q q-length))}."
  (if (memq 'prefix (read-options))
      (error "boot-9 must be compiled with #:kw, not :kw")))
 
-(define (compile-interface-spec spec)
-  (define (make-keyarg sym key quote?)
-    (cond ((or (memq sym spec)
-               (memq key spec))
-           => (lambda (rest)
-                (if quote?
-                    (list key (list 'quote (cadr rest)))
-                    (list key (cadr rest)))))
-          (else
-           '())))
-  (define (map-apply func list)
-    (map (lambda (args) (apply func args)) list))
-  (define keys
-    ;; sym     key      quote?
-    '((:select #:select #t)
-      (:hide   #:hide   #t)
-      (:prefix #:prefix #t)
-      (:renamer #:renamer #f)
-      (:version #:version #t)))
-  (if (not (pair? (car spec)))
-      `(',spec)
-      `(',(car spec)
-        ,@(apply append (map-apply make-keyarg keys)))))
-
 (define (keyword-like-symbol->keyword sym)
   (symbol->keyword (string->symbol (substring (symbol->string sym) 1))))
 
-(define (compile-define-module-args args)
-  ;; Just quote everything except #:use-module and #:use-syntax.  We
-  ;; need to know about all arguments regardless since we want to turn
-  ;; symbols that look like keywords into real keywords, and the
-  ;; keyword args in a define-module form are not regular
-  ;; (i.e. no-backtrace doesn't take a value).
-  (let loop ((compiled-args `((quote ,(car args))))
-             (args (cdr args)))
-    (cond ((null? args)
-           (reverse! compiled-args))
-          ;; symbol in keyword position
-          ((symbol? (car args))
-           (loop compiled-args
-                 (cons (keyword-like-symbol->keyword (car args)) (cdr args))))
-          ((memq (car args) '(#:no-backtrace #:pure))
-           (loop (cons (car args) compiled-args)
-                 (cdr args)))
-          ((null? (cdr args))
-           (error "keyword without value:" (car args)))
-          ((memq (car args) '(#:use-module #:use-syntax))
-           (loop (cons* `(list ,@(compile-interface-spec (cadr args)))
-                        (car args)
-                        compiled-args)
-                 (cddr args)))
-          ((eq? (car args) #:autoload)
-           (loop (cons* `(quote ,(caddr args))
-                        `(quote ,(cadr args))
-                        (car args)
-                        compiled-args)
-                 (cdddr args)))
-          (else
-           (loop (cons* `(quote ,(cadr args))
-                        (car args)
-                        compiled-args)
-                 (cddr args))))))
-
-(defmacro define-module args
-  `(eval-when
-    (eval load compile)
-    (let ((m (process-define-module
-              (list ,@(compile-define-module-args args)))))
-      (set-current-module m)
-      m)))
+;; FIXME: we really need to clean up the guts of the module system.
+;; We can compile to something better than process-define-module.
+(define-syntax define-module
+  (lambda (x)
+    (define (keyword-like? stx)
+      (let ((dat (syntax->datum stx)))
+        (and (symbol? dat)
+             (eqv? (string-ref (symbol->string dat) 0) #\:))))
+    (define (->keyword sym)
+      (symbol->keyword (string->symbol (substring (symbol->string sym) 1))))
+    
+    (define (quotify-iface args)
+      (let loop ((in args) (out '()))
+        (syntax-case in ()
+          (() (reverse! out))
+          ;; The user wanted #:foo, but wrote :foo. Fix it.
+          ((sym . in) (keyword-like? #'sym)
+           (loop #`(#,(->keyword (syntax->datum #'sym)) . in) out))
+          ((kw . in) (not (keyword? (syntax->datum #'kw)))
+           (syntax-violation 'define-module "expected keyword arg" x #'kw))
+          ((#:renamer renamer . in)
+           (loop #'in (cons* #'renamer #:renamer out)))
+          ((kw val . in)
+           (loop #'in (cons* #''val #'kw out))))))
+
+    (define (quotify args)
+      ;; Just quote everything except #:use-module and #:use-syntax.  We
+      ;; need to know about all arguments regardless since we want to turn
+      ;; symbols that look like keywords into real keywords, and the
+      ;; keyword args in a define-module form are not regular
+      ;; (i.e. no-backtrace doesn't take a value).
+      (let loop ((in args) (out '()))
+        (syntax-case in ()
+          (() (reverse! out))
+          ;; The user wanted #:foo, but wrote :foo. Fix it.
+          ((sym . in) (keyword-like? #'sym)
+           (loop #`(#,(->keyword (syntax->datum #'sym)) . in) out))
+          ((kw . in) (not (keyword? (syntax->datum #'kw)))
+           (syntax-violation 'define-module "expected keyword arg" x #'kw))
+          ((#:no-backtrace . in)
+           (loop #'in (cons #:no-backtrace out)))
+          ((#:pure . in)
+           (loop #'in (cons #:pure out)))
+          ((kw)
+           (syntax-violation 'define-module "keyword arg without value" x #'kw))
+          ((use-module (name name* ...) . in)
+           (and (memq (syntax->datum #'use-module) '(#:use-module #:use-syntax))
+                (and-map symbol? (syntax->datum #'(name name* ...))))
+           (loop #'in
+                 (cons* #''((name name* ...))
+                        #'use-module
+                        out)))
+          ((use-module ((name name* ...) arg ...) . in)
+           (and (memq (syntax->datum #'use-module) '(#:use-module #:use-syntax))
+                (and-map symbol? (syntax->datum #'(name name* ...))))
+           (loop #'in
+                 (cons* #`(list '(name name* ...) #,@(quotify-iface #'(arg ...)))
+                        #'use-module
+                        out)))
+          ((#:autoload name bindings . in)
+           (loop #'in (cons* #''bindings #''name #:autoload out)))
+          ((kw val . in)
+           (loop #'in (cons* #''val #'kw out))))))
+    
+    (syntax-case x ()
+      ((_ (name name* ...) arg ...)
+       (with-syntax (((quoted-arg ...) (quotify #'(arg ...))))
+         #'(eval-when (eval load compile expand)
+             (let ((m (process-define-module
+                       (list '(name name* ...)
+                             #:filename (assq-ref
+                                         (or (current-source-location) '())
+                                         'filename)
+                             quoted-arg ...))))
+               (set-current-module m)
+               m)))))))
 
 ;; The guts of the use-modules macro.  Add the interfaces of the named
 ;; modules to the use-list of the current module, in order.
@@ -3204,22 +3149,59 @@ module '(ice-9 q) '(make-q q-length))}."
      (lambda ()
        (module-use-interfaces! (current-module) interfaces)))))
 
-(defmacro use-modules modules
-  `(eval-when
-    (eval load compile)
-    (process-use-modules
-     (list ,@(map (lambda (m)
-                    `(list ,@(compile-interface-spec m)))
-                  modules)))
-    *unspecified*))
-
-(defmacro use-syntax (spec)
-  `(eval-when
-    (eval load compile)
-    (issue-deprecation-warning
-     "`use-syntax' is deprecated. Please contact guile-devel for more info.")
-    (process-use-modules (list (list ,@(compile-interface-spec spec))))
-    *unspecified*))
+(define-syntax use-modules
+  (lambda (x)
+    (define (keyword-like? stx)
+      (let ((dat (syntax->datum stx)))
+        (and (symbol? dat)
+             (eqv? (string-ref (symbol->string dat) 0) #\:))))
+    (define (->keyword sym)
+      (symbol->keyword (string->symbol (substring (symbol->string sym) 1))))
+    
+    (define (quotify-iface args)
+      (let loop ((in args) (out '()))
+        (syntax-case in ()
+          (() (reverse! out))
+          ;; The user wanted #:foo, but wrote :foo. Fix it.
+          ((sym . in) (keyword-like? #'sym)
+           (loop #`(#,(->keyword (syntax->datum #'sym)) . in) out))
+          ((kw . in) (not (keyword? (syntax->datum #'kw)))
+           (syntax-violation 'define-module "expected keyword arg" x #'kw))
+          ((#:renamer renamer . in)
+           (loop #'in (cons* #'renamer #:renamer out)))
+          ((kw val . in)
+           (loop #'in (cons* #''val #'kw out))))))
+
+    (define (quotify specs)
+      (let lp ((in specs) (out '()))
+        (syntax-case in ()
+          (() (reverse out))
+          (((name name* ...) . in)
+           (and-map symbol? (syntax->datum #'(name name* ...)))
+           (lp #'in (cons #''((name name* ...)) out)))
+          ((((name name* ...) arg ...) . in)
+           (and-map symbol? (syntax->datum #'(name name* ...)))
+           (with-syntax (((quoted-arg ...) (quotify-iface #'(arg ...))))
+             (lp #'in (cons #`(list '(name name* ...) quoted-arg ...)
+                            out)))))))
+    
+    (syntax-case x ()
+      ((_ spec ...)
+       (with-syntax (((quoted-args ...) (quotify #'(spec ...))))
+         #'(eval-when (eval load compile expand)
+             (process-use-modules (list quoted-args ...))
+             *unspecified*))))))
+
+(define-syntax use-syntax
+  (syntax-rules ()
+    ((_ spec ...)
+     (begin
+       (eval-when (eval load compile expand)
+         (issue-deprecation-warning
+          "`use-syntax' is deprecated. Please contact guile-devel for more info."))
+       (use-modules spec ...)))))
+
+(include-from-path "ice-9/r6rs-libraries")
 
 (define-syntax define-private
   (syntax-rules ()
@@ -3273,6 +3255,20 @@ module '(ice-9 q) '(make-q q-length))}."
                   (module-add! public-i external-name var)))
               names)))
 
+;; Export all local variables from a module
+;;
+(define (module-export-all! mod)
+  (define (fresh-interface!)
+    (let ((iface (make-module)))
+      (set-module-name! iface (module-name mod))
+      ;; for guile 2: (set-module-version! iface (module-version mod))
+      (set-module-kind! iface 'interface)
+      (set-module-public-interface! mod iface)
+      iface))
+  (let ((iface (or (module-public-interface mod)
+                   (fresh-interface!))))
+    (set-module-obarray! iface (module-obarray mod))))
+
 ;; Re-export a imported variable
 ;;
 (define (module-re-export! m names)
@@ -3289,23 +3285,31 @@ module '(ice-9 q) '(make-q q-length))}."
                          (module-add! public-i external-name var)))))
               names)))
 
-(defmacro export names
-  `(eval-when (eval load compile)
-     (call-with-deferred-observers
-      (lambda ()
-        (module-export! (current-module) ',names)))))
+(define-syntax export
+  (syntax-rules ()
+    ((_ name ...)
+     (eval-when (eval load compile expand)
+       (call-with-deferred-observers
+        (lambda ()
+          (module-export! (current-module) '(name ...))))))))
 
-(defmacro re-export names
-  `(eval-when (eval load compile)
-     (call-with-deferred-observers
-       (lambda ()
-         (module-re-export! (current-module) ',names)))))
+(define-syntax re-export
+  (syntax-rules ()
+    ((_ name ...)
+     (eval-when (eval load compile expand)
+       (call-with-deferred-observers
+        (lambda ()
+          (module-re-export! (current-module) '(name ...))))))))
 
-(defmacro export-syntax names
-  `(export ,@names))
+(define-syntax export-syntax
+  (syntax-rules ()
+    ((_ name ...)
+     (export name ...))))
 
-(defmacro re-export-syntax names
-  `(re-export ,@names))
+(define-syntax re-export-syntax
+  (syntax-rules ()
+    ((_ name ...)
+     (re-export name ...))))
 
 (define load load-module)
 
@@ -3320,11 +3324,8 @@ module '(ice-9 q) '(make-q q-length))}."
                   (if (null? args)
                       (fluid-ref fluid)
                       (fluid-set! fluid (converter (car args))))))))
-    (lambda (init . converter)
-      (let ((fluid (make-fluid))
-            (converter (if (null? converter)
-                           identity
-                           (car converter))))
+    (lambda* (init #:optional (converter identity))
+      (let ((fluid (make-fluid)))
         (fluid-set! fluid (converter init))
         (make fluid converter)))))
 
@@ -3654,7 +3655,11 @@ module '(ice-9 q) '(make-q q-length))}."
     ;; scmsigs.c scm_sigaction_for_thread), so the handlers setup here have
     ;; no effect.
     (let ((old-handlers #f)
-          (start-repl (module-ref (resolve-interface '(system repl repl))
+          ;; We can't use @ here, as modules have been booted, but in Guile's
+          ;; build the srfi-1 helper lib hasn't been built yet, which will
+          ;; result in an error when (system repl repl) is loaded at compile
+          ;; time (to see if it is a macro or not).
+          (start-repl (module-ref (resolve-module '(system repl repl))
                                   'start-repl))
           (signals (if (provided? 'posix)
                        `((,SIGINT . "User interrupt")
@@ -3723,12 +3728,6 @@ module '(ice-9 q) '(make-q q-length))}."
 ;;; Place the user in the guile-user module.
 ;;;
 
-;;; FIXME: annotate ?
-;; (define (syncase exp)
-;;   (with-fluids ((expansion-eval-closure
-;;               (module-eval-closure (current-module))))
-;;     (deannotate/source-properties (macroexpand (annotate exp)))))
-
 ;; FIXME:
 (module-use! the-scm-module (resolve-interface '(srfi srfi-4)))