Merge remote-tracking branch 'origin/stable-2.0'
[bpt/guile.git] / module / ice-9 / boot-9.scm
index 19c22ea..87c38af 100644 (file)
 
 (define make-prompt-tag
   (lambda* (#:optional (stem "prompt"))
-    (gensym stem)))
+    ;; The only property that prompt tags need have is uniqueness in the
+    ;; sense of eq?.  A one-element list will serve nicely.
+    (list stem)))
 
 (define default-prompt-tag
-  ;; not sure if we should expose this to the user as a fluid
+  ;; Redefined later to be a parameter.
   (let ((%default-prompt-tag (make-prompt-tag)))
     (lambda ()
       %default-prompt-tag)))
 
 (define (call-with-prompt tag thunk handler)
-  (@prompt tag (thunk) handler))
+  ((@@ primitive call-with-prompt) tag thunk handler))
 (define (abort-to-prompt tag . args)
-  (@abort tag args))
+  (abort-to-prompt* tag args))
 
+(define (with-fluid* fluid val thunk)
+  "Set @var{fluid} to @var{value} temporarily, and call @var{thunk}.
+@var{thunk} must be a procedure of no arguments."
+  ((@@ primitive push-fluid) fluid val)
+  (call-with-values thunk
+    (lambda vals
+      ((@@ primitive pop-fluid))
+      (apply values vals))))
 
 ;; Define catch and with-throw-handler, using some common helper routines and a
 ;; shared fluid. Hide the helpers in a lexical contour.
       (lambda (thrown-k . args)
         (if (or (eq? thrown-k catch-k) (eqv? catch-k #t))
             (let ((running (fluid-ref %running-exception-handlers)))
-              (with-fluids ((%running-exception-handlers (cons pre running)))
-                (if (not (memq pre running))
-                    (apply pre thrown-k args))
-                ;; fall through
-                (if prompt-tag
-                    (apply abort-to-prompt prompt-tag thrown-k args)
-                    (apply prev thrown-k args))))
+              (with-fluid* %running-exception-handlers (cons pre running)
+                (lambda ()
+                  (if (not (memq pre running))
+                      (apply pre thrown-k args))
+                  ;; fall through
+                  (if prompt-tag
+                      (apply abort-to-prompt prompt-tag thrown-k args)
+                      (apply prev thrown-k args)))))
             (apply prev thrown-k args)))))
 
   (set! catch
@@ -149,12 +160,11 @@ non-locally, that exit determines the continuation."
             (call-with-prompt
              tag
              (lambda ()
-               (with-fluids
-                   ((%exception-handler
-                     (if pre-unwind-handler
-                         (custom-throw-handler tag k pre-unwind-handler)
-                         (default-throw-handler tag k))))
-                 (thunk)))
+               (with-fluid* %exception-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))))))
 
@@ -166,9 +176,9 @@ for key @var{k}, then invoke @var{thunk}."
               (scm-error 'wrong-type-arg "with-throw-handler"
                          "Wrong type argument in position ~a: ~a"
                          (list 1 k) (list k)))
-          (with-fluids ((%exception-handler
-                         (custom-throw-handler #f k pre-unwind-handler)))
-            (thunk))))
+          (with-fluid%exception-handler
+              (custom-throw-handler #f k pre-unwind-handler)
+            thunk)))
 
   (set! throw
         (lambda (key . args)
@@ -186,10 +196,126 @@ If there is no handler at all, Guile prints an error and then exits."
 
 \f
 
-;;; {R4RS compliance}
+;;; {Language primitives}
 ;;;
 
-(primitive-load-path "ice-9/r4rs")
+;; These are are the procedural wrappers around the primitives of
+;; Guile's language: apply, call-with-current-continuation, etc.
+;;
+;; Usually, a call to a primitive is compiled specially.  The compiler
+;; knows about all these kinds of expressions.  But the primitives may
+;; be referenced not only as operators, but as values as well.  These
+;; stub procedures are the "values" of apply, dynamic-wind, and other
+;; such primitives.
+;;
+(define apply
+  (case-lambda
+    ((fun args)
+     ((@@ primitive apply) fun args))
+    ((fun arg1 . args)
+     (letrec ((append* (lambda (tail)
+                         (let ((tail (car tail))
+                               (tail* (cdr tail)))
+                           (if (null? tail*)
+                               tail
+                               (cons tail (append* tail*)))))))
+       (apply fun (cons arg1 (append* args)))))))
+(define (call-with-current-continuation proc)
+  ((@@ primitive call-with-current-continuation) proc))
+(define (call-with-values producer consumer)
+  ((@@ primitive call-with-values) producer consumer))
+(define (dynamic-wind in thunk out)
+  "All three arguments must be 0-argument procedures.
+Guard @var{in} is called, then @var{thunk}, then
+guard @var{out}.
+
+If, any time during the execution of @var{thunk}, the
+continuation of the @code{dynamic_wind} expression is escaped
+non-locally, @var{out} is called.  If the continuation of
+the dynamic-wind is re-entered, @var{in} is called.  Thus
+@var{in} and @var{out} may be called any number of
+times.
+@lisp
+ (define x 'normal-binding)
+@result{} x
+ (define a-cont
+   (call-with-current-continuation
+     (lambda (escape)
+       (let ((old-x x))
+         (dynamic-wind
+           ;; in-guard:
+           ;;
+           (lambda () (set! x 'special-binding))
+
+           ;; thunk
+           ;;
+           (lambda () (display x) (newline)
+                   (call-with-current-continuation escape)
+                   (display x) (newline)
+                   x)
+
+           ;; out-guard:
+           ;;
+           (lambda () (set! x old-x)))))))
+
+;; Prints:
+special-binding
+;; Evaluates to:
+@result{} a-cont
+x
+@result{} normal-binding
+ (a-cont #f)
+;; Prints:
+special-binding
+;; Evaluates to:
+@result{} a-cont  ;; the value of the (define a-cont...)
+x
+@result{} normal-binding
+a-cont
+@result{} special-binding
+@end lisp"
+  (if (thunk? out)
+      (in)
+      (scm-error 'wrong-type-arg "dynamic-wind" "Not a thunk: ~S"
+                 (list out) #f))
+  ((@@ primitive wind) in out)
+  (call-with-values thunk
+    (lambda vals
+      ((@@ primitive unwind))
+      (out)
+      (apply values vals))))
+
+\f
+
+;;; {Low-Level Port Code}
+;;;
+
+;; These are used to request the proper mode to open files in.
+;;
+(define OPEN_READ "r")
+(define OPEN_WRITE "w")
+(define OPEN_BOTH "r+")
+
+(define *null-device* "/dev/null")
+
+;; NOTE: Later in this file, this is redefined to support keywords
+(define (open-input-file str)
+  "Takes a string naming an existing file and returns an input port
+capable of delivering characters from the file.  If the file
+cannot be opened, an error is signalled."
+  (open-file str OPEN_READ))
+
+;; NOTE: Later in this file, this is redefined to support keywords
+(define (open-output-file str)
+  "Takes a string naming an output file to be created and returns an
+output port capable of writing characters to a new file by that
+name.  If the file cannot be opened, an error is signalled.  If a
+file with the given name already exists, the effect is unspecified."
+  (open-file str OPEN_WRITE))
+
+(define (open-io-file str) 
+  "Open file with name STR for both input and output."
+  (open-file str OPEN_BOTH))
 
 \f
 
@@ -218,13 +344,11 @@ If there is no handler at all, Guile prints an error and then exits."
 (define current-warning-port current-error-port)
 
 (define (warn . stuff)
-  (with-output-to-port (current-warning-port)
-    (lambda ()
-      (newline)
-      (display ";;; WARNING ")
-      (display stuff)
-      (newline)
-      (car (last-pair stuff)))))
+  (newline (current-warning-port))
+  (display ";;; WARNING " (current-warning-port))
+  (display stuff (current-warning-port))
+  (newline (current-warning-port))
+  (car (last-pair stuff)))
 
 \f
 
@@ -586,6 +710,25 @@ If there is no handler at all, Guile prints an error and then exits."
 (define-syntax-rule (delay exp)
   (make-promise (lambda () exp)))
 
+(define-syntax with-fluids
+  (lambda (stx)
+    (define (emit-with-fluids bindings body)
+      (syntax-case bindings ()
+        (()
+         body)
+        (((f v) . bindings)
+         #`(with-fluid* f v
+             (lambda ()
+               #,(emit-with-fluids #'bindings body))))))
+    (syntax-case stx ()
+      ((_ ((fluid val) ...) exp exp* ...)
+       (with-syntax (((fluid-tmp ...) (generate-temporaries #'(fluid ...)))
+                     ((val-tmp ...) (generate-temporaries #'(val ...))))
+         #`(let ((fluid-tmp fluid) ...)
+             (let ((val-tmp val) ...)
+               #,(emit-with-fluids #'((fluid-tmp val-tmp) ...)
+                                   #'(begin exp exp* ...)))))))))
+
 (define-syntax current-source-location
   (lambda (x)
     (syntax-case x ()
@@ -752,116 +895,6 @@ information is unavailable."
 
 \f
 
-;;;
-;;; Enhanced file opening procedures
-;;;
-
-(define* (open-input-file
-          file #:key (binary #f) (encoding #f) (guess-encoding #f))
-  "Takes a string naming an existing file and returns an input port
-capable of delivering characters from the file.  If the file
-cannot be opened, an error is signalled."
-  (open-file file (if binary "rb" "r")
-             #:encoding encoding
-             #:guess-encoding guess-encoding))
-
-(define* (open-output-file file #:key (binary #f) (encoding #f))
-  "Takes a string naming an output file to be created and returns an
-output port capable of writing characters to a new file by that
-name.  If the file cannot be opened, an error is signalled.  If a
-file with the given name already exists, the effect is unspecified."
-  (open-file file (if binary "wb" "w")
-             #:encoding encoding))
-
-(define* (call-with-input-file
-          file proc #:key (binary #f) (encoding #f) (guess-encoding #f))
-  "PROC should be a procedure of one argument, and FILE should be a
-string naming a file.  The file must
-already exist. These procedures call PROC
-with one argument: the port obtained by opening the named file for
-input or output.  If the file cannot be opened, an error is
-signalled.  If the procedure returns, then the port is closed
-automatically and the values yielded by the procedure are returned.
-If the procedure does not return, then the port will not be closed
-automatically unless it is possible to prove that the port will
-never again be used for a read or write operation."
-  (let ((p (open-input-file file
-                            #:binary binary
-                            #:encoding encoding
-                            #:guess-encoding guess-encoding)))
-    (call-with-values
-      (lambda () (proc p))
-      (lambda vals
-        (close-input-port p)
-        (apply values vals)))))
-
-(define* (call-with-output-file file proc #:key (binary #f) (encoding #f))
-  "PROC should be a procedure of one argument, and FILE should be a
-string naming a file.  The behaviour is unspecified if the file
-already exists. These procedures call PROC
-with one argument: the port obtained by opening the named file for
-input or output.  If the file cannot be opened, an error is
-signalled.  If the procedure returns, then the port is closed
-automatically and the values yielded by the procedure are returned.
-If the procedure does not return, then the port will not be closed
-automatically unless it is possible to prove that the port will
-never again be used for a read or write operation."
-  (let ((p (open-output-file file #:binary binary #:encoding encoding)))
-    (call-with-values
-      (lambda () (proc p))
-      (lambda vals
-        (close-output-port p)
-        (apply values vals)))))
-
-(define* (with-input-from-file
-          file thunk #:key (binary #f) (encoding #f) (guess-encoding #f))
-  "THUNK must be a procedure of no arguments, and FILE must be a
-string naming a file.  The file must already exist. The file is opened for
-input, an input port connected to it is made
-the default value returned by `current-input-port',
-and the THUNK is called with no arguments.
-When the THUNK returns, the port is closed and the previous
-default is restored.  Returns the values yielded by THUNK.  If an
-escape procedure is used to escape from the continuation of these
-procedures, their behavior is implementation dependent."
-  (call-with-input-file file
-   (lambda (p) (with-input-from-port p thunk))
-   #:binary binary
-   #:encoding encoding
-   #:guess-encoding guess-encoding))
-
-(define* (with-output-to-file file thunk #:key (binary #f) (encoding #f))
-  "THUNK must be a procedure of no arguments, and FILE must be a
-string naming a file.  The effect is unspecified if the file already exists.
-The file is opened for output, an output port connected to it is made
-the default value returned by `current-output-port',
-and the THUNK is called with no arguments.
-When the THUNK returns, the port is closed and the previous
-default is restored.  Returns the values yielded by THUNK.  If an
-escape procedure is used to escape from the continuation of these
-procedures, their behavior is implementation dependent."
-  (call-with-output-file file
-   (lambda (p) (with-output-to-port p thunk))
-   #:binary binary
-   #:encoding encoding))
-
-(define* (with-error-to-file file thunk #:key (binary #f) (encoding #f))
-  "THUNK must be a procedure of no arguments, and FILE must be a
-string naming a file.  The effect is unspecified if the file already exists.
-The file is opened for output, an output port connected to it is made
-the default value returned by `current-error-port',
-and the THUNK is called with no arguments.
-When the THUNK returns, the port is closed and the previous
-default is restored.  Returns the values yielded by THUNK.  If an
-escape procedure is used to escape from the continuation of these
-procedures, their behavior is implementation dependent."
-  (call-with-output-file file
-   (lambda (p) (with-error-to-port p thunk))
-   #:binary binary
-   #:encoding encoding))
-
-\f
-
 ;;;
 ;;; Extensible exception printing.
 ;;;
@@ -1103,15 +1136,11 @@ VALUE."
 ;; properties within the object itself.
 
 (define (make-object-property)
-  (define-syntax-rule (with-mutex lock exp)
-    (dynamic-wind (lambda () (lock-mutex lock))
-                  (lambda () exp)
-                  (lambda () (unlock-mutex lock))))
-  (let ((prop (make-weak-key-hash-table))
-        (lock (make-mutex)))
+  ;; Weak tables are thread-safe.
+  (let ((prop (make-weak-key-hash-table)))
     (make-procedure-with-setter
-     (lambda (obj) (with-mutex lock (hashq-ref prop obj)))
-     (lambda (obj val) (with-mutex lock (hashq-set! prop obj val))))))
+     (lambda (obj) (hashq-ref prop obj))
+     (lambda (obj val) (hashq-set! prop obj val)))))
 
 
 \f
@@ -1160,6 +1189,16 @@ VALUE."
 
 \f
 
+;;; {IOTA functions: generating lists of numbers}
+;;;
+
+(define (iota n)
+  (let loop ((count (1- n)) (result '()))
+    (if (< count 0) result
+        (loop (1- count) (cons count result)))))
+
+\f
+
 ;;; {Structs}
 ;;;
 
@@ -1224,10 +1263,14 @@ VALUE."
              #,@(let lp ((n 0))
                   (if (< n *max-static-argument-count*)
                       (cons (with-syntax (((formal ...) (make-formals n))
+                                          ((idx ...) (iota n))
                                           (n n))
                               #'((n)
                                  (lambda (formal ...)
-                                   (make-struct rtd 0 formal ...))))
+                                   (let ((s (allocate-struct rtd n)))
+                                     (struct-set! s idx formal)
+                                     ...
+                                     s))))
                             (lp (1+ n)))
                       '()))
              (else
@@ -1268,64 +1311,369 @@ VALUE."
                                      (string->symbol type-name)))
     rtd))
 
-(define (record-type-name obj)
-  (if (record-type? obj)
-      (struct-ref obj vtable-offset-user)
-      (error 'not-a-record-type obj)))
+(define (record-type-name obj)
+  (if (record-type? obj)
+      (struct-ref obj vtable-offset-user)
+      (error 'not-a-record-type obj)))
+
+(define (record-type-fields obj)
+  (if (record-type? obj)
+      (struct-ref obj (+ 1 vtable-offset-user))
+      (error 'not-a-record-type obj)))
+
+(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)))))
+
+(define (%record-type-error rtd obj)  ;; private helper
+  (or (eq? rtd (record-type-descriptor obj))
+      (scm-error 'wrong-type-arg "%record-type-check"
+                 "Wrong type record (want `~S'): ~S"
+                 (list (record-type-name rtd) obj)
+                 #f)))
+
+(define (record-accessor rtd field-name)
+  (let ((pos (list-index (record-type-fields rtd) field-name)))
+    (if (not pos)
+        (error 'no-such-field field-name))
+    (lambda (obj)
+      (if (eq? (struct-vtable obj) rtd)
+          (struct-ref obj pos)
+          (%record-type-error rtd obj)))))
+
+(define (record-modifier rtd field-name)
+  (let ((pos (list-index (record-type-fields rtd) field-name)))
+    (if (not pos)
+        (error 'no-such-field field-name))
+    (lambda (obj val)
+      (if (eq? (struct-vtable obj) rtd)
+          (struct-set! obj pos val)
+          (%record-type-error rtd obj)))))
+
+(define (record? obj)
+  (and (struct? obj) (record-type? (struct-vtable obj))))
+
+(define (record-type-descriptor obj)
+  (if (struct? obj)
+      (struct-vtable obj)
+      (error 'not-a-record obj)))
+
+(provide 'record)
+
+
+\f
+;;; {Parameters}
+;;;
+
+(define <parameter>
+  ;; Three fields: the procedure itself, the fluid, and the converter.
+  (make-struct <applicable-struct-vtable> 0 'pwprpr))
+(set-struct-vtable-name! <parameter> '<parameter>)
+
+(define* (make-parameter init #:optional (conv (lambda (x) x)))
+  "Make a new parameter.
+
+A parameter is a dynamically bound value, accessed through a procedure.
+To access the current value, apply the procedure with no arguments:
+
+  (define p (make-parameter 10))
+  (p) => 10
+
+To provide a new value for the parameter in a dynamic extent, use
+`parameterize':
+
+  (parameterize ((p 20))
+    (p)) => 20
+  (p) => 10
+
+The value outside of the dynamic extent of the body is unaffected.  To
+update the current value, apply it to one argument:
+
+  (p 20) => 10
+  (p) => 20
+
+As you can see, the call that updates a parameter returns its previous
+value.
+
+All values for the parameter are first run through the CONV procedure,
+including INIT, the initial value.  The default CONV procedure is the
+identity procedure.  CONV is commonly used to ensure some set of
+invariants on the values that a parameter may have."
+  (let ((fluid (make-fluid (conv init))))
+    (make-struct <parameter> 0
+                 (case-lambda
+                   (() (fluid-ref fluid))
+                   ((x) (let ((prev (fluid-ref fluid)))
+                          (fluid-set! fluid (conv x))
+                          prev)))
+                 fluid conv)))
+
+(define (parameter? x)
+  (and (struct? x) (eq? (struct-vtable x) <parameter>)))
+
+(define (parameter-fluid p)
+  (if (parameter? p)
+      (struct-ref p 1)
+      (scm-error 'wrong-type-arg "parameter-fluid"
+                 "Not a parameter: ~S" (list p) #f)))
+
+(define (parameter-converter p)
+  (if (parameter? p)
+      (struct-ref p 2)
+      (scm-error 'wrong-type-arg "parameter-fluid"
+                 "Not a parameter: ~S" (list p) #f)))
+
+(define-syntax parameterize
+  (lambda (x)
+    (syntax-case x ()
+      ((_ ((param value) ...) body body* ...)
+       (with-syntax (((p ...) (generate-temporaries #'(param ...))))
+         #'(let ((p param) ...)
+             (if (not (parameter? p))
+                        (scm-error 'wrong-type-arg "parameterize"
+                                   "Not a parameter: ~S" (list p) #f))
+             ...
+             (with-fluids (((struct-ref p 1) ((struct-ref p 2) value))
+                           ...)
+               body body* ...)))))))
+
+(define* (fluid->parameter fluid #:optional (conv (lambda (x) x)))
+  "Make a parameter that wraps a fluid.
+
+The value of the parameter will be the same as the value of the fluid.
+If the parameter is rebound in some dynamic extent, perhaps via
+`parameterize', the new value will be run through the optional CONV
+procedure, as with any parameter.  Note that unlike `make-parameter',
+CONV is not applied to the initial value."
+  (make-struct <parameter> 0
+               (case-lambda
+                 (() (fluid-ref fluid))
+                 ((x) (let ((prev (fluid-ref fluid)))
+                        (fluid-set! fluid (conv x))
+                        prev)))
+               fluid conv))
+
+\f
+
+;;; Once parameters have booted, define the default prompt tag as being
+;;; a parameter.
+;;;
+
+(set! default-prompt-tag (make-parameter (default-prompt-tag)))
+
+\f
+
+;;; Current ports as parameters.
+;;;
+
+(let ()
+  (define-syntax-rule (port-parameterize! binding fluid predicate msg)
+    (begin
+      (set! binding (fluid->parameter (module-ref (current-module) 'fluid)
+                                      (lambda (x)
+                                        (if (predicate x) x
+                                            (error msg x)))))
+      (hashq-remove! (%get-pre-modules-obarray) 'fluid)))
+  
+  (port-parameterize! current-input-port %current-input-port-fluid
+                      input-port? "expected an input port")
+  (port-parameterize! current-output-port %current-output-port-fluid
+                      output-port? "expected an output port")
+  (port-parameterize! current-error-port %current-error-port-fluid
+                      output-port? "expected an output port"))
+
+\f
+
+;;; {Warnings}
+;;;
+
+(define current-warning-port
+  (make-parameter (current-error-port)
+                  (lambda (x)
+                    (if (output-port? x)
+                        x
+                        (error "expected an output port" x)))))
+
+
+\f
+
+;;; {Languages}
+;;;
+
+;; The language can be a symbolic name or a <language> object from
+;; (system base language).
+;;
+(define current-language (make-parameter 'scheme))
+
+
+\f
+
+;;; {High-Level Port Routines}
+;;;
+
+(define* (open-input-file
+          file #:key (binary #f) (encoding #f) (guess-encoding #f))
+  "Takes a string naming an existing file and returns an input port
+capable of delivering characters from the file.  If the file
+cannot be opened, an error is signalled."
+  (open-file file (if binary "rb" "r")
+             #:encoding encoding
+             #:guess-encoding guess-encoding))
+
+(define* (open-output-file file #:key (binary #f) (encoding #f))
+  "Takes a string naming an output file to be created and returns an
+output port capable of writing characters to a new file by that
+name.  If the file cannot be opened, an error is signalled.  If a
+file with the given name already exists, the effect is unspecified."
+  (open-file file (if binary "wb" "w")
+             #:encoding encoding))
+
+(define* (call-with-input-file
+          file proc #:key (binary #f) (encoding #f) (guess-encoding #f))
+  "PROC should be a procedure of one argument, and FILE should be a
+string naming a file.  The file must
+already exist. These procedures call PROC
+with one argument: the port obtained by opening the named file for
+input or output.  If the file cannot be opened, an error is
+signalled.  If the procedure returns, then the port is closed
+automatically and the values yielded by the procedure are returned.
+If the procedure does not return, then the port will not be closed
+automatically unless it is possible to prove that the port will
+never again be used for a read or write operation."
+  (let ((p (open-input-file file
+                            #:binary binary
+                            #:encoding encoding
+                            #:guess-encoding guess-encoding)))
+    (call-with-values
+      (lambda () (proc p))
+      (lambda vals
+        (close-input-port p)
+        (apply values vals)))))
+
+(define* (call-with-output-file file proc #:key (binary #f) (encoding #f))
+  "PROC should be a procedure of one argument, and FILE should be a
+string naming a file.  The behaviour is unspecified if the file
+already exists. These procedures call PROC
+with one argument: the port obtained by opening the named file for
+input or output.  If the file cannot be opened, an error is
+signalled.  If the procedure returns, then the port is closed
+automatically and the values yielded by the procedure are returned.
+If the procedure does not return, then the port will not be closed
+automatically unless it is possible to prove that the port will
+never again be used for a read or write operation."
+  (let ((p (open-output-file file #:binary binary #:encoding encoding)))
+    (call-with-values
+      (lambda () (proc p))
+      (lambda vals
+        (close-output-port p)
+        (apply values vals)))))
+
+(define (with-input-from-port port thunk)
+  (parameterize ((current-input-port port))
+    (thunk)))
 
-(define (record-type-fields obj)
-  (if (record-type? obj)
-      (struct-ref obj (+ 1 vtable-offset-user))
-      (error 'not-a-record-type obj)))
+(define (with-output-to-port port thunk)
+  (parameterize ((current-output-port port))
+    (thunk)))
 
-(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)))))
+(define (with-error-to-port port thunk)
+  (parameterize ((current-error-port port))
+    (thunk)))
 
-(define (%record-type-error rtd obj)  ;; private helper
-  (or (eq? rtd (record-type-descriptor obj))
-      (scm-error 'wrong-type-arg "%record-type-check"
-                 "Wrong type record (want `~S'): ~S"
-                 (list (record-type-name rtd) obj)
-                 #f)))
+(define* (with-input-from-file
+          file thunk #:key (binary #f) (encoding #f) (guess-encoding #f))
+  "THUNK must be a procedure of no arguments, and FILE must be a
+string naming a file.  The file must already exist. The file is opened for
+input, an input port connected to it is made
+the default value returned by `current-input-port',
+and the THUNK is called with no arguments.
+When the THUNK returns, the port is closed and the previous
+default is restored.  Returns the values yielded by THUNK.  If an
+escape procedure is used to escape from the continuation of these
+procedures, their behavior is implementation dependent."
+  (call-with-input-file file
+   (lambda (p) (with-input-from-port p thunk))
+   #:binary binary
+   #:encoding encoding
+   #:guess-encoding guess-encoding))
 
-(define (record-accessor rtd field-name)
-  (let ((pos (list-index (record-type-fields rtd) field-name)))
-    (if (not pos)
-        (error 'no-such-field field-name))
-    (lambda (obj)
-      (if (eq? (struct-vtable obj) rtd)
-          (struct-ref obj pos)
-          (%record-type-error rtd obj)))))
+(define* (with-output-to-file file thunk #:key (binary #f) (encoding #f))
+  "THUNK must be a procedure of no arguments, and FILE must be a
+string naming a file.  The effect is unspecified if the file already exists.
+The file is opened for output, an output port connected to it is made
+the default value returned by `current-output-port',
+and the THUNK is called with no arguments.
+When the THUNK returns, the port is closed and the previous
+default is restored.  Returns the values yielded by THUNK.  If an
+escape procedure is used to escape from the continuation of these
+procedures, their behavior is implementation dependent."
+  (call-with-output-file file
+   (lambda (p) (with-output-to-port p thunk))
+   #:binary binary
+   #:encoding encoding))
 
-(define (record-modifier rtd field-name)
-  (let ((pos (list-index (record-type-fields rtd) field-name)))
-    (if (not pos)
-        (error 'no-such-field field-name))
-    (lambda (obj val)
-      (if (eq? (struct-vtable obj) rtd)
-          (struct-set! obj pos val)
-          (%record-type-error rtd obj)))))
+(define* (with-error-to-file file thunk #:key (binary #f) (encoding #f))
+  "THUNK must be a procedure of no arguments, and FILE must be a
+string naming a file.  The effect is unspecified if the file already exists.
+The file is opened for output, an output port connected to it is made
+the default value returned by `current-error-port',
+and the THUNK is called with no arguments.
+When the THUNK returns, the port is closed and the previous
+default is restored.  Returns the values yielded by THUNK.  If an
+escape procedure is used to escape from the continuation of these
+procedures, their behavior is implementation dependent."
+  (call-with-output-file file
+   (lambda (p) (with-error-to-port p thunk))
+   #:binary binary
+   #:encoding encoding))
 
-(define (record? obj)
-  (and (struct? obj) (record-type? (struct-vtable obj))))
+(define (call-with-input-string string proc)
+  "Calls the one-argument procedure @var{proc} with a newly created
+input port from which @var{string}'s contents may be read.  The value
+yielded by the @var{proc} is returned."
+  (proc (open-input-string string)))
 
-(define (record-type-descriptor obj)
-  (if (struct? obj)
-      (struct-vtable obj)
-      (error 'not-a-record obj)))
+(define (with-input-from-string string thunk)
+  "THUNK must be a procedure of no arguments.
+The test of STRING  is opened for
+input, an input port connected to it is made, 
+and the THUNK is called with no arguments.
+When the THUNK returns, the port is closed.
+Returns the values yielded by THUNK.  If an
+escape procedure is used to escape from the continuation of these
+procedures, their behavior is implementation dependent."
+  (call-with-input-string string
+   (lambda (p) (with-input-from-port p thunk))))
 
-(provide 'record)
+(define (call-with-output-string proc)
+  "Calls the one-argument procedure @var{proc} with a newly created output
+port.  When the function returns, the string composed of the characters
+written into the port is returned."
+  (let ((port (open-output-string)))
+    (proc port)
+    (get-output-string port)))
+
+(define (with-output-to-string thunk)
+  "Calls THUNK and returns its output as a string."
+  (call-with-output-string
+   (lambda (p) (with-output-to-port p thunk))))
+
+(define (with-error-to-string thunk)
+  "Calls THUNK and returns its error output as a string."
+  (call-with-output-string
+   (lambda (p) (with-error-to-port p thunk))))
+
+(define the-eof-object (call-with-input-string "" (lambda (p) (read-char p))))
 
 \f
 
@@ -1376,7 +1724,7 @@ VALUE."
       (lambda (str)
         (->bool (stat str #f)))
       (lambda (str)
-        (let ((port (catch 'system-error (lambda () (open-file str OPEN_READ))
+        (let ((port (catch 'system-error (lambda () (open-input-file str))
                            (lambda args #f))))
           (if port (begin (close-port port) #t)
               #f)))))
@@ -1387,8 +1735,8 @@ VALUE."
         (eq? (stat:type (stat str)) 'directory))
       (lambda (str)
         (let ((port (catch 'system-error
-                           (lambda () (open-file (string-append str "/.")
-                                                 OPEN_READ))
+                           (lambda ()
+                             (open-input-file (string-append str "/.")))
                            (lambda args #f))))
           (if port (begin (close-port port) #t)
               #f)))))
@@ -1818,7 +2166,7 @@ VALUE."
     ((define-record-type
        (lambda (x)
          (define (make-id scope . fragments)
-           (datum->syntax #'scope
+           (datum->syntax scope
                           (apply symbol-append
                                  (map (lambda (x)
                                         (if (symbol? x) x (syntax->datum x)))
@@ -1877,14 +2225,21 @@ VALUE."
               (cons #'f (field-list #'rest)))))
 
          (define (constructor rtd type-name fields exp)
-           (let ((ctor (make-id rtd type-name '-constructor))
-                 (args (field-list fields)))
+           (let* ((ctor (make-id rtd type-name '-constructor))
+                  (args (field-list fields))
+                  (n (length fields))
+                  (slots (iota n)))
              (predicate rtd type-name fields
                         #`(begin #,exp
                                  (define #,ctor
                                    (let ((rtd #,rtd))
                                      (lambda #,args
-                                       (make-struct rtd 0 #,@args))))
+                                       (let ((s (allocate-struct rtd #,n)))
+                                         #,@(map
+                                             (lambda (arg slot)
+                                               #`(struct-set! s #,slot #,arg))
+                                             args slots)
+                                         s))))
                                  (struct-set! #,rtd (+ vtable-offset-user 2)
                                               #,ctor)))))
 
@@ -1953,10 +2308,6 @@ VALUE."
 ;; initial uses list, or binding procedure.
 ;;
 (define* (make-module #:optional (size 31) (uses '()) (binder #f))
-  (define %default-import-size
-    ;; Typical number of imported bindings actually used by a module.
-    600)
-
   (if (not (integer? size))
       (error "Illegal size to make-module." size))
   (if (not (and (list? uses)
@@ -1969,7 +2320,7 @@ VALUE."
   (module-constructor (make-hash-table size)
                       uses binder #f macroexpand
                       #f #f #f
-                      (make-hash-table %default-import-size)
+                      (make-hash-table)
                       '()
                       (make-weak-key-hash-table 31) #f
                       (make-hash-table 7) #f #f #f))
@@ -2289,33 +2640,6 @@ VALUE."
 (define (module-define-submodule! module name submodule)
   (hashq-set! (module-submodules module) name submodule))
 
-;; It used to be, however, that module names were also present in the
-;; value namespace. When we enable deprecated code, we preserve this
-;; legacy behavior.
-;;
-;; These shims are defined here instead of in deprecated.scm because we
-;; need their definitions before loading other modules.
-;;
-(begin-deprecated
- (define (module-ref-submodule module name)
-   (or (hashq-ref (module-submodules module) name)
-       (and (module-submodule-binder module)
-            ((module-submodule-binder module) module name))
-       (let ((var (module-local-variable module name)))
-         (and var (variable-bound? var) (module? (variable-ref var))
-              (begin
-                (warn "module" module "not in submodules table")
-                (variable-ref var))))))
-
- (define (module-define-submodule! module name submodule)
-   (let ((var (module-local-variable module name)))
-     (if (and var
-              (or (not (variable-bound? var))
-                  (not (module? (variable-ref var)))))
-         (warn "defining module" module ": not overriding local definition" var)
-         (module-define! module name submodule)))
-   (hashq-set! (module-submodules module) name submodule)))
-
 \f
 
 ;;; {Module-based Loading}
@@ -3119,145 +3443,6 @@ but it fails to load."
 
 \f
 
-;;; {Parameters}
-;;;
-
-(define <parameter>
-  ;; Three fields: the procedure itself, the fluid, and the converter.
-  (make-struct <applicable-struct-vtable> 0 'pwprpr))
-(set-struct-vtable-name! <parameter> '<parameter>)
-
-(define* (make-parameter init #:optional (conv (lambda (x) x)))
-  "Make a new parameter.
-
-A parameter is a dynamically bound value, accessed through a procedure.
-To access the current value, apply the procedure with no arguments:
-
-  (define p (make-parameter 10))
-  (p) => 10
-
-To provide a new value for the parameter in a dynamic extent, use
-`parameterize':
-
-  (parameterize ((p 20))
-    (p)) => 20
-  (p) => 10
-
-The value outside of the dynamic extent of the body is unaffected.  To
-update the current value, apply it to one argument:
-
-  (p 20) => 10
-  (p) => 20
-
-As you can see, the call that updates a parameter returns its previous
-value.
-
-All values for the parameter are first run through the CONV procedure,
-including INIT, the initial value.  The default CONV procedure is the
-identity procedure.  CONV is commonly used to ensure some set of
-invariants on the values that a parameter may have."
-  (let ((fluid (make-fluid (conv init))))
-    (make-struct <parameter> 0
-                 (case-lambda
-                   (() (fluid-ref fluid))
-                   ((x) (let ((prev (fluid-ref fluid)))
-                          (fluid-set! fluid (conv x))
-                          prev)))
-                 fluid conv)))
-
-(define* (fluid->parameter fluid #:optional (conv (lambda (x) x)))
-  "Make a parameter that wraps a fluid.
-
-The value of the parameter will be the same as the value of the fluid.
-If the parameter is rebound in some dynamic extent, perhaps via
-`parameterize', the new value will be run through the optional CONV
-procedure, as with any parameter.  Note that unlike `make-parameter',
-CONV is not applied to the initial value."
-  (make-struct <parameter> 0
-               (case-lambda
-                 (() (fluid-ref fluid))
-                 ((x) (let ((prev (fluid-ref fluid)))
-                        (fluid-set! fluid (conv x))
-                        prev)))
-               fluid conv))
-
-(define (parameter? x)
-  (and (struct? x) (eq? (struct-vtable x) <parameter>)))
-
-(define (parameter-fluid p)
-  (if (parameter? p)
-      (struct-ref p 1)
-      (scm-error 'wrong-type-arg "parameter-fluid"
-                 "Not a parameter: ~S" (list p) #f)))
-
-(define (parameter-converter p)
-  (if (parameter? p)
-      (struct-ref p 2)
-      (scm-error 'wrong-type-arg "parameter-fluid"
-                 "Not a parameter: ~S" (list p) #f)))
-
-(define-syntax parameterize
-  (lambda (x)
-    (syntax-case x ()
-      ((_ ((param value) ...) body body* ...)
-       (with-syntax (((p ...) (generate-temporaries #'(param ...))))
-         #'(let ((p param) ...)
-             (if (not (parameter? p))
-                        (scm-error 'wrong-type-arg "parameterize"
-                                   "Not a parameter: ~S" (list p) #f))
-             ...
-             (with-fluids (((struct-ref p 1) ((struct-ref p 2) value))
-                           ...)
-               body body* ...)))))))
-
-\f
-;;;
-;;; Current ports as parameters.
-;;;
-
-(let ()
-  (define-syntax-rule (port-parameterize! binding fluid predicate msg)
-    (begin
-      (set! binding (fluid->parameter (module-ref (current-module) 'fluid)
-                                      (lambda (x)
-                                        (if (predicate x) x
-                                            (error msg x)))))
-      (module-remove! (current-module) 'fluid)))
-  
-  (port-parameterize! current-input-port %current-input-port-fluid
-                      input-port? "expected an input port")
-  (port-parameterize! current-output-port %current-output-port-fluid
-                      output-port? "expected an output port")
-  (port-parameterize! current-error-port %current-error-port-fluid
-                      output-port? "expected an output port"))
-
-
-\f
-;;;
-;;; Warnings.
-;;;
-
-(define current-warning-port
-  (make-parameter (current-error-port)
-                  (lambda (x)
-                    (if (output-port? x)
-                        x
-                        (error "expected an output port" x)))))
-
-
-\f
-;;;
-;;; Languages.
-;;;
-
-;; The language can be a symbolic name or a <language> object from
-;; (system base language).
-;;
-(define current-language (make-parameter 'scheme))
-
-
-\f
-
 ;;; {Running Repls}
 ;;;
 
@@ -3334,16 +3519,6 @@ CONV is not applied to the initial value."
 
 \f
 
-;;; {IOTA functions: generating lists of numbers}
-;;;
-
-(define (iota n)
-  (let loop ((count (1- n)) (result '()))
-    (if (< count 0) result
-        (loop (1- count) (cons count result)))))
-
-\f
-
 ;;; {While}
 ;;;
 ;;; with `continue' and `break'.
@@ -3568,13 +3743,6 @@ CONV is not applied to the initial value."
              (process-use-modules (list quoted-args ...))
              *unspecified*))))))
 
-(define-syntax-rule (use-syntax 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-rule (define-private foo bar)
@@ -4026,12 +4194,11 @@ when none is available, reading FILE-NAME with READER."
   ;; placing 'cond-expand-provide' in the relevant module.
   '(guile
     guile-2
+    guile-2.2
     r5rs
     srfi-0   ;; cond-expand itself
     srfi-4   ;; homogeneous numeric vectors
-    ;; We omit srfi-6 because the 'open-input-string' etc in Guile
-    ;; core are not conformant with SRFI-6; they expose details
-    ;; of the binary I/O model and may fail to support some characters.
+    srfi-6   ;; string ports
     srfi-13  ;; string library
     srfi-14  ;; character sets
     srfi-23  ;; `error` procedure