summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDirk Herrmann <dirk@dirk-herrmanns-seiten.de>2000-08-02 21:21:32 +0000
committerDirk Herrmann <dirk@dirk-herrmanns-seiten.de>2000-08-02 21:21:32 +0000
commitcd10c90e95ee5ecbf15bf994ce749a882b752d11 (patch)
tree4d0ae4b1d8679891820db00c86dea2ea08a35035
parentf707173e5ea066b9262c611c9a88797b34b1bbe0 (diff)
downloadguile-dirk-adding-josts-environments.tar.gz
* Adding new files by Jost to the repository.dirk-adding-josts-environments
-rw-r--r--ice-9/ChangeLog-environments37
-rw-r--r--ice-9/arrays.scm106
-rw-r--r--ice-9/check-version.scm22
-rw-r--r--ice-9/config.scm830
-rw-r--r--ice-9/defmacro.scm114
-rw-r--r--ice-9/error.scm37
-rw-r--r--ice-9/files.scm246
-rw-r--r--ice-9/hooks.scm23
-rw-r--r--ice-9/keywords.scm15
-rw-r--r--ice-9/lists.scm23
-rw-r--r--ice-9/macros.scm28
-rw-r--r--ice-9/math.scm102
-rw-r--r--ice-9/misc.scm333
-rw-r--r--ice-9/modules.scm82
-rw-r--r--ice-9/options.scm223
-rw-r--r--ice-9/posix.scm260
-rw-r--r--ice-9/provide.scm13
-rw-r--r--ice-9/repl.scm478
-rw-r--r--ice-9/run-test.scm5
-rw-r--r--ice-9/structs.scm127
-rw-r--r--ice-9/symbols.scm23
-rw-r--r--libguile/ChangeLog-environments288
-rw-r--r--libguile/environments.c3558
-rw-r--r--libguile/environments.h176
24 files changed, 6998 insertions, 151 deletions
diff --git a/ice-9/ChangeLog-environments b/ice-9/ChangeLog-environments
new file mode 100644
index 000000000..963a335f5
--- /dev/null
+++ b/ice-9/ChangeLog-environments
@@ -0,0 +1,37 @@
+1999-08-24 Jost Boekemeier <jostobfe@calvados.zrz.tu-berlin.de>
+
+ * guile.scm (error-catching-loop): Correct non-RnRS usage of internal
+ defines.
+
+1999-08-12 Jost Boekemeier <jostobfe@calvados.zrz.tu-berlin.de>
+
+ * arrays.scm, check-version.scm defmacro.scm, error.scm,
+ files.scm, guile.scm, hooks.scm, keywords.scm lists.scm,
+ macros.scm, math.scm, misc.scm, modules.scm, options.scm
+ posix.scm, provide.scm, run-test.scm, structs.scm, symbols.scm:
+ new file
+ * Makefile.am: added files
+
+ * debug.scm (define-module): the module imports the modules:
+ hooks, options, defmacro
+ (variable-set!): disabled
+
+ * r4rs.scm (defined?): `defined?' is a special form now.
+ (%load-announce): added environment parameter
+ (load): `load' loads and evaluates expressions in
+ `interaction-environment'
+
+ * boot-9.scm: added warning that this module is obsolete
+ (c-module-registry): load all c modules into the root environment
+ (primitive-load-path): load expressions in file "ice-9/r4rs" into
+ interaction-environment
+ (symbol-property): disabled
+ (record-constructor): evaluates expressions in interaction
+ environment
+ (record-accessor): dto.
+ (record-modifier): dto.
+ (modules): disabled
+ (scm-style-repl): evaluates expressions in interaction-environment
+ (environments): disabled
+ (macros): disabled
+ (variables): disabled
diff --git a/ice-9/arrays.scm b/ice-9/arrays.scm
index 51be69210..6e175fde1 100644
--- a/ice-9/arrays.scm
+++ b/ice-9/arrays.scm
@@ -1,83 +1,27 @@
-;;; installed-scm-file
-;;;; Copyright (C) 1999 Free Software Foundation, Inc.
-;;;;
-;;;; This program is free software; you can redistribute it and/or modify
-;;;; it under the terms of the GNU General Public License as published by
-;;;; the Free Software Foundation; either version 2, or (at your option)
-;;;; any later version.
-;;;;
-;;;; This program is distributed in the hope that it will be useful,
-;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;;;; GNU General Public License for more details.
-;;;;
-;;;; You should have received a copy of the GNU General Public License
-;;;; along with this software; see the file COPYING. If not, write to
-;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
-;;;; Boston, MA 02111-1307 USA
-;;;;
+
+;;; {Arrays}
+;;;
+
+(begin
+ (define uniform-vector? array?)
+ (define make-uniform-vector dimensions->uniform-array)
+ ; (define uniform-vector-ref array-ref)
+ (define (uniform-vector-set! u i o)
+ (uniform-array-set1! u o i))
+ (define uniform-vector-fill! array-fill!)
+ (define uniform-vector-read! uniform-array-read!)
+ (define uniform-vector-write uniform-array-write)
+
+ (define (make-array fill . args)
+ (dimensions->uniform-array args () fill))
+ (define (make-uniform-array prot . args)
+ (dimensions->uniform-array args prot))
+ (define (list->array ndim lst)
+ (list->uniform-array ndim '() lst))
+ (define (list->uniform-vector prot lst)
+ (list->uniform-array 1 prot lst))
+ (define (array-shape a)
+ (map (lambda (ind) (if (number? ind) (list 0 (+ -1 ind)) ind))
+ (array-dimensions a))))
-(define uniform-vector? array?)
-(define make-uniform-vector dimensions->uniform-array)
-
-;; (define uniform-vector-ref array-ref)
-
-(define (uniform-vector-set! u i o)
- (uniform-array-set1! u o i))
-(define uniform-vector-fill! array-fill!)
-(define uniform-vector-read! uniform-array-read!)
-(define uniform-vector-write uniform-array-write)
-
-(define (make-array fill . args)
- (dimensions->uniform-array args () fill))
-(define (make-uniform-array prot . args)
- (dimensions->uniform-array args prot))
-(define (list->array ndim lst)
- (list->uniform-array ndim '() lst))
-(define (list->uniform-vector prot lst)
- (list->uniform-array 1 prot lst))
-(define (array-shape a)
- (map (lambda (ind) (if (number? ind) (list 0 (+ -1 ind)) ind))
- (array-dimensions a)))
-
-(let ((make-array-proc (lambda (template)
- (lambda (c port)
- (read:uniform-vector template port)))))
- (for-each (lambda (char template)
- (read-hash-extend char
- (make-array-proc template)))
- '(#\b #\a #\u #\e #\s #\i #\c #\y #\h #\l)
- '(#t #\a 1 -1 1.0 1/3 0+i #\nul s l)))
-
-(let ((array-proc (lambda (c port)
- (read:array c port))))
- (for-each (lambda (char) (read-hash-extend char array-proc))
- '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)))
-
-(define (read:array digit port)
- (define chr0 (char->integer #\0))
- (let ((rank (let readnum ((val (- (char->integer digit) chr0)))
- (if (char-numeric? (peek-char port))
- (readnum (+ (* 10 val)
- (- (char->integer (read-char port)) chr0)))
- val)))
- (prot (if (eq? #\( (peek-char port))
- '()
- (let ((c (read-char port)))
- (case c ((#\b) #t)
- ((#\a) #\a)
- ((#\u) 1)
- ((#\e) -1)
- ((#\s) 1.0)
- ((#\i) 1/3)
- ((#\c) 0+i)
- (else (error "read:array unknown option " c)))))))
- (if (eq? (peek-char port) #\()
- (list->uniform-array rank prot (read port))
- (error "read:array list not found"))))
-
-(define (read:uniform-vector proto port)
- (if (eq? #\( (peek-char port))
- (list->uniform-array 1 proto (read port))
- (error "read:uniform-vector list not found")))
diff --git a/ice-9/check-version.scm b/ice-9/check-version.scm
new file mode 100644
index 000000000..fd3c9e8e6
--- /dev/null
+++ b/ice-9/check-version.scm
@@ -0,0 +1,22 @@
+
+;;; {Check that the interpreter and scheme code match up.}
+
+(let ((show-line
+ (lambda args
+ (with-output-to-port (current-error-port)
+ (lambda ()
+ (display (car (command-line)))
+ (display ": ")
+ (for-each (lambda (string) (display string))
+ args)
+ (newline))))))
+
+ (load-from-path "ice-9/version.scm")
+
+ (if (not (string=?
+ (libguile-config-stamp) ; from the interprpreter
+ (ice-9-config-stamp))) ; from the Scheme code
+ (begin
+ (show-line "warning: different versions of libguile and ice-9:")
+ (show-line "libguile: configured on " (libguile-config-stamp))
+ (show-line "ice-9: configured on " (ice-9-config-stamp)))))
diff --git a/ice-9/config.scm b/ice-9/config.scm
new file mode 100644
index 000000000..f31bddd4d
--- /dev/null
+++ b/ice-9/config.scm
@@ -0,0 +1,830 @@
+;;;; This is the (ice-9 config) module. It exports the module
+;;;; configuration language and creates the (user guile) module.
+
+;; from r4rs
+(define (call-with-current-continuation proc)
+ (@call-with-current-continuation proc))
+
+
+;; the export list
+(define the-module-exports
+ '(the-module
+ module
+ module-go
+ go
+ module-ref
+ module-open
+ module-protect
+ module-export
+ module-export
+ module-access
+ module-close
+ module-create
+ module-use
+ (module-use (alias use-modules))
+ (module-export (alias export))
+ (module-export (alias export-syntax))
+ define-module
+ define-public
+ module-config-export
+ module-config-protect
+ module-config-open
+ (define-public (alias define*))
+ (define (alias define-private))
+ symbol-property
+ set-symbol-property!
+ remove-symbol-property!
+ (remove-symbol-property! (alias symbol-property-remove!))
+ ))
+
+(define the-module-protects
+ '(module-eval-environment
+ module-interface-environment
+ module-package-name
+ module-name))
+
+
+
+
+;;; Symbol properties
+(define symbol-property
+ (procedure->memoizing-macro
+ (lambda (x env)
+ `(,environment-symbol-property (the-environment) ,(cadr x) ,(caddr x) ))))
+
+(define set-symbol-property!
+ (procedure->memoizing-macro
+ (lambda (x env)
+ `(,environment-set-symbol-property! (the-environment) ,(cadr x) ,(caddr x) ,(cadddr x) ))))
+
+(define remove-symbol-property!
+ (procedure->memoizing-macro
+ (lambda (x env)
+ `(,environment-remove-symbol-property! (the-environment) ,(cadr x) ,(caddr x) ))))
+
+
+;;; {Error Handling}
+;;;
+
+;; from ice-9 error
+(define (error . args)
+ (if (null? args)
+ (scm-error 'misc-error #f "?" #f #f)
+ (let loop ((msg "%s")
+ (rest (cdr args)))
+ (if (not (null? rest))
+ (loop (string-append msg " %S")
+ (cdr rest))
+ (scm-error 'misc-error #f msg args #f)))))
+
+
+
+;;; {Low Level Modules}
+
+
+;; the module-signature (also called `module') maps modules to:
+;; (vector eval-env export-env protect-env package-sym module-sym)
+(define (module-eval-environment module) (vector-ref module 0))
+
+
+;;; the accessor procedures
+
+;; export environment
+(define (module-export-environment module)
+ (vector-ref module 1))
+
+;;; protect environment
+(define (module-protect-environment module)
+ (vector-ref module 2))
+
+;;; package and module name
+(define (module-package-name module) (vector-ref module 3))
+(define (module-name module) (vector-ref module 4))
+(define (make-module eval export protect package name) (vector eval export protect package name (list )))
+
+;; Return the interface environment for module. The interface is
+;; either the protect environment if the module is accessed from
+;; another package or the module's export environment
+(define module-interface-environment
+ (lambda (current-module module)
+ (if (eq? (module-package-name current-module)
+ (module-package-name module))
+ (module-protect-environment module)
+ (module-export-environment module))))
+
+;; export-list used by define-public
+(define (module-export-list module) (vector-ref module 5))
+(define (module-set-export-list! module val) (vector-set! module 5 val))
+
+;; return the current module-signature
+(define the-module
+ (procedure->syntax
+ (lambda (x env)
+ (let ((m (hashq-ref (environment-module-hash) (car (reverse env)))))
+ (if (not m)
+ (error "PANIC: Could not find module for " (car (reverse env)))
+ m)))))
+
+
+;;; Convert a list of symbols into a package/module name
+
+;; (ice-9 my boot) -> (ice-9/my/ . boot)
+;; (boot) -> (user/ . boot)
+(define symlist->package+module
+ (lambda (symlist)
+ (if (not (pair? symlist)) (error "not a symbol list:" symlist))
+ (let ((symlist (if (null? (cdr symlist)) (cons 'user symlist) symlist)))
+ (let loop ((dirs "")
+ (syms symlist))
+ (let ((sym (car syms)))
+ (if (not (symbol? sym)) (error "not a valid symbol:" sym))
+ (if (null? (cdr syms))
+ (cons (string->symbol dirs) sym)
+ (loop (string-append dirs sym "/") (cdr syms))))))))
+
+;; (ice-9/my/ . boot) -> ice-9/my/boot
+(define package+module->module-sym
+ (lambda (name-pair)
+ (string->symbol
+ (string-append (symbol->string (car name-pair))
+ (symbol->string (cdr name-pair))))))
+
+;; (ice-9/my/ . boot) -> ice-9/my/
+(define package+module->package-sym
+ (lambda (name-pair)
+ (car name-pair)))
+
+;; (ice-9 my boot) -> ice-9/my/boot
+(define symlist->module-sym
+ (lambda (mod)
+ (package+module->module-sym (symlist->package+module mod))))
+
+
+;;; The implementation (low level proc. interface)
+
+;; load and evaluate package-sym module-sym in its own environment
+(define module-load-internal
+ (lambda (package-sym module-sym)
+ (let* (
+ (skel (make-module-skeleton package-sym module-sym))
+ (skel-env (module-eval-environment skel))
+ (c_name (string-append (symbol->string module-sym) ".scm"))
+ (full_name (%search-load-path c_name)))
+
+ (if (not full_name)
+ ;; try to invoke c-function directly
+ (let (
+ (c_module_init (and
+ (environment-bound? (c-module-registry) module-sym)
+ (environment-ref (c-module-registry) module-sym))))
+ (if (not c_module_init)
+ (begin
+ ;; remove all references to the created module
+ (environment-undefine (module-registry) module-sym)
+ #f)
+ (begin
+ (c_module_init skel-env)
+
+ ;; now modify the export and protect environment so
+ ;; that all cells are visible
+ (let ((export (module-export-environment skel)))
+ (interface-environment-set-interface!
+ export
+ (list (cons skel-env (environment-fold skel-env (lambda (sym val last) (cons sym last)) (list )))))
+ (interface-environment-set-interface! (module-protect-environment skel) (list (cons export #f))))
+
+ skel)))
+
+ (begin
+ (primitive-load full_name skel-env)
+ skel)))))
+
+;; load `(package module)'
+(define module-load-proc
+ (lambda (mod)
+ (let* (
+ (name-pair (symlist->package+module mod))
+ (package-sym (package+module->package-sym name-pair))
+ (module-sym (package+module->module-sym name-pair)))
+ (module-load-internal package-sym module-sym))))
+
+(define last-indent 0)
+
+;; load package-sym/module-sym only if module has not been loaded
+(define module-auto-load
+ (lambda (package-sym module-sym)
+ (let (
+ (module (and
+ (environment-bound? (module-registry) module-sym)
+ (environment-ref (module-registry) module-sym)))
+ (indent (lambda (count)
+ (do ((i 0 (+ i 1))) ((= i count)) (display " ")))))
+
+ (if (not module)
+
+ (begin
+ (display "loading ")
+ (indent last-indent)
+ (display module-sym) (force-output)
+ (newline)
+
+ (set! last-indent (+ last-indent 2))
+ (let ((module (module-load-internal package-sym module-sym)))
+
+ (set! last-indent (- last-indent 2))
+ module))
+
+ module))))
+
+;; Create a continuation to start a new repl in module.
+;; #f means: start a repl in (user config)
+(define module-go
+ (lambda (module)
+
+ (define (y-or-n? question eof-value count)
+ (let ((i-port (current-input-port))
+ (o-port (current-output-port)))
+ (let loop ((count count))
+ (display question o-port)
+ (display " (y/n)? " o-port)
+ (force-output)
+ (let ((line (read i-port)))
+ (cond ((eof-object? line)
+ (newline o-port)
+ (if (= count 0)
+ eof-value
+ (begin (display "I'll only ask another " o-port)
+ (write count o-port)
+ (display " times." o-port)
+ (newline o-port)
+ (loop (- count 1)))))
+ ((< (string-length line) 1) (loop count))
+ ((char=? (string-ref line 0) #\y) #t)
+ ((char=? (string-ref line 0) #\n) #f)
+ (else (loop count)))))))
+
+ (let ((guile (module-access-proc '(ice-9 repl)))
+ (user/config (module-create (user config)))
+ (quit (lambda args
+ (apply throw 'quit args))))
+
+ ;; (user config) opens the current module (ice-9 config) and
+ ;; imports some symbols
+ (let ((interface (eval-environment-imported (module-eval-environment user/config)))
+ (export (module-export-environment (the-module)))
+ (import-list '(module-ref module-access module-close module-create the-module
+ module-use define-module module module-go go
+ (module-config-export (alias config-export))
+ (module-config-protect (alias config-protect))
+ (module-config-open (alias config-open)))))
+
+ (interface-environment-set-interface! interface (list (cons export import-list))))
+
+
+ (let (
+ (top-repl (module-ref-proc (the-module) guile 'top-repl)))
+
+ (let (
+ (in-module (call-with-current-continuation (lambda (k) (set! module-go k) module))))
+
+ (letrec (
+ (confirm
+ (lambda ()
+ (newline)
+ (y-or-n? "Do you really want to quit guile" #t 1)))
+
+ (user-repl
+ (lambda ()
+ (set-interaction-environment! (module-eval-environment in-module))
+ (let ((ret-val (top-repl in-module)))
+ (newline)
+ ret-val)))
+
+ (config-repl
+ (lambda ()
+ (set-interaction-environment! (module-eval-environment user/config))
+ (top-repl user/config))))
+
+ (let (
+ (ret-val
+ (or (and in-module (user-repl)) (config-repl))))
+
+ (if (not (confirm)) (module-go #f))
+
+ ret-val)))))))
+
+;; fix the interface of the guile module.
+(let* (
+ (guile-module (environment-ref (module-registry) 'ice-9/guile))
+ (guile-eval-env (module-eval-environment guile-module))
+ (guile-export-list (environment-fold guile-eval-env (lambda (sym val rest) (cons sym rest)) '()))
+ (guile-interface (list (cons guile-eval-env guile-export-list)))
+ (export (module-export-environment guile-module))
+ (protect (module-protect-environment guile-module)))
+
+ ;; get out your barf bag ... It is probably better to export
+ ;; %load-path from (ice-9 config) and *features* from whereever but
+ ;; not from the guile module
+ ;;
+ ; export mutable
+ (for-each (lambda (s)
+ (set-car! (memq s guile-export-list) (list s 'mutable-location)))
+ (list
+ '%load-path
+ '*features*
+ ; complete weired ... (from r4rs.scm)
+ '%load-hook
+ 'apply
+ ; argh... (popen.scm)
+ 'gc-thunk
+ ))
+
+
+
+ ; now set the interface
+ (interface-environment-set-interface! export guile-interface)
+ (interface-environment-set-interface! protect guile-interface))
+
+;; update the config module `(ice-9 config)'
+(let* (
+ (config-module (environment-ref (module-registry) 'ice-9/config))
+ (eval (module-eval-environment config-module))
+ (export (module-export-environment config-module))
+ (protect (module-protect-environment config-module)))
+
+ (interface-environment-set-interface! export (list (cons eval the-module-exports)))
+ (interface-environment-set-interface! protect (list (cons eval the-module-protects) (cons export #f))))
+
+;; create a simple but full-featured module.
+(define make-module-skeleton
+ (lambda (package-sym module-sym)
+ (let* (
+ (config-export-env (module-export-environment
+ (environment-ref (module-registry) 'ice-9/config)))
+ (local (make-leaf-environment))
+ (import (make-interface-environment (list (cons config-export-env #f))))
+ (eval (make-eval-environment local import))
+ (export (make-interface-environment (list (list eval)))) ;; export nothing
+ (protect (make-interface-environment (list (cons export #f) (list eval))))
+ (module (make-module eval export protect package-sym module-sym)))
+
+ (hashq-set! (environment-module-hash) eval module)
+ (environment-define (module-registry) module-sym module)
+
+ module)))
+
+(define module-create-proc
+ (lambda (mod)
+ (let* (
+ (name-pair (symlist->package+module mod))
+ (package-sym (package+module->package-sym name-pair))
+ (module-sym (package+module->module-sym name-pair))
+ (module (and
+ (environment-bound? (module-registry) module-sym)
+ (environment-ref (module-registry) module-sym))))
+
+ (if (not module)
+ (let* (
+ (c_name (string-append (symbol->string module-sym) ".scm"))
+ (full_name (%search-load-path c_name)))
+ (if (not full_name)
+ (let* (
+ (skel (make-module-skeleton package-sym module-sym))
+ (eval-env (module-eval-environment skel)))
+ skel)
+
+ (error "module exists but has not been loaded" module-sym)))
+ (error "module exists and has been loaded" module-sym)))))
+
+
+(define module-load-error
+ (lambda (module-sym)
+ (error "module could not be loaded" module-sym)))
+
+;; add an export environment to our module skeleton or set a new
+(define (module-export-proc module export-list)
+ (let (
+ (export (module-export-environment module))
+ (eval (module-eval-environment module)))
+
+ (if (pair? (module-export-list module))
+ (error "You can either use `define-public' or `export', but not both."))
+
+ (module-set-export-list! module #f) ;; can't use `define-public' anymore
+
+ (interface-environment-set-interface! export (list (cons eval export-list)))
+ (if #f #f)))
+
+;; package boundary
+(define (module-protect-proc module protect-list)
+ (let ((protect (module-protect-environment module))
+ (export (module-export-environment module))
+ (eval (module-eval-environment module)))
+
+ (interface-environment-set-interface! protect (list (cons eval protect-list) (cons export #f)))
+ (if #f #f)))
+
+
+;; check for circular references
+;; every interface-environment has a list of environment specs
+;; an environment spec is a list of the environment and its exported symbols
+;; every eval-environment has an interface-environment
+(define referenced
+ (lambda (environment l)
+ (letrec (
+ (search
+ (lambda (l)
+ (cond ((null? l) #f)
+ ((eq? (caar l) environment) #t)
+ (else
+ (or (search (get-list-from-env (caar l)))
+ (search (cdr l)))))))
+
+ (get-list-from-env
+ (lambda (env)
+ (cond ((interface-environment? env)
+ (interface-environment-interface env))
+
+ ((eval-environment? env)
+ (get-list-from-env (eval-environment-imported env)))
+
+ (else (error "FIXME: unsupported environment" env))))))
+
+ (search l))))
+
+
+(define module-access-proc
+ (lambda (mod)
+ (let* (
+ (name-pair (symlist->package+module mod))
+ (package-sym (package+module->package-sym name-pair))
+ (module-sym (package+module->module-sym name-pair)))
+
+ (or (module-auto-load package-sym module-sym)
+ (module-load-error module-sym)))))
+
+
+;; remove module from module-registry
+(define module-close-proc
+ (lambda (mod)
+ (let* (
+ (name-pair (symlist->package+module mod))
+ (package-sym (package+module->package-sym name-pair))
+ (module-sym (package+module->module-sym name-pair)))
+
+ (environment-undefine (module-registry) module-sym))))
+
+
+(define module-open-internal
+ (lambda (skel imports)
+
+ (let* (
+ (eval (module-eval-environment skel))
+ (import (eval-environment-imported eval)))
+
+ (if (referenced eval imports)
+ (error "Can't open modules: circular dependency for " eval))
+
+ (interface-environment-set-interface! import imports))))
+
+(define import-symlist->import-list
+ (lambda (skel import-symlist)
+ (letrec
+ ((fix-imports
+ (lambda (l)
+ (cond
+ ((null? l) '())
+ ((not (list? (caar l))) (cons (cons (car l) #f) (fix-imports (cdr l))))
+ (else (cons (car l) (fix-imports (cdr l))))))))
+
+ (let* (
+ (import-symlist (fix-imports import-symlist))
+ (import-modlist (map (lambda (x) (cons (module-access-proc (car x)) (cdr x))) import-symlist))
+ (import-list (map (lambda (x) (cons (module-interface-environment skel (car x)) (cdr x))) import-modlist)))
+
+ import-list))))
+
+(define module-open-proc
+ (lambda (skel import-symlist)
+ (module-open-internal skel (import-symlist->import-list skel import-symlist))))
+
+(define module-use-proc
+ (lambda (skel import-symlist)
+ (let* (
+ (eval (module-eval-environment skel))
+ (interface-env (eval-environment-imported eval))
+ (interface (interface-environment-interface interface-env))
+ (import-list (import-symlist->import-list skel import-symlist)))
+
+ (module-open-internal skel (append import-list interface))
+ (if #f #f)
+ )))
+
+
+(define module-ref-proc
+ (lambda (curr module sym)
+ (let (
+ (name (module-name module))
+ (interface-env (module-interface-environment curr module))
+ )
+
+ (cond
+ ((environment-bound? interface-env sym)
+ (environment-ref interface-env sym))
+
+ (else (scm-error 'misc-error #f "Symbol `%s' is not exported from `%s'." (list sym name) #f))))))
+
+
+(define (module-proc current-module args)
+ (let* (
+ (mod (car args))
+ (arglist (cdr args))
+ (current-module-sym (module-name current-module))
+ (sym (symlist->module-sym mod))
+ (same-module (eq? current-module-sym sym))
+ (has-exports (assq 'export arglist))
+ (skel (if same-module current-module (module-create-proc mod))))
+
+ (let loop ((arglist arglist)
+ (modules '())
+ (exports '())
+ (protects '()))
+
+ (if (null? arglist)
+ (begin
+
+ (if (not same-module)
+ (error "Can't manipulate a foreign module's interface."))
+
+ (module-open-proc skel modules)
+
+ (if has-exports (module-export-proc skel exports))
+
+ (module-protect-proc skel protects)
+ )
+
+
+ (begin
+ (if (not (pair? (car arglist)))
+ (error "unrecognized module argument in" current-module-sym))
+
+ (let ((fkt (caar arglist)))
+ (case fkt
+ ((open)
+ (loop (cdr arglist)
+ (append modules (cdar arglist))
+ exports
+ protects))
+
+ ((export)
+ (loop (cdr arglist)
+ modules
+ (append exports (cdar arglist))
+ protects))
+
+ ((protect)
+ (loop (cdr arglist)
+ modules
+ exports
+ (append protects (cdar arglist))))
+ (else
+ (error "unrecognized module argument in" current-module-sym)))))))))
+
+(define (go-proc module)
+ (module-go (module-access-proc module)))
+
+
+;;; High level interface
+
+;; declare a module
+(define module
+ (procedure->memoizing-macro
+ (lambda (x env)
+ `(,module-proc (,the-module) (,quote ,(cdr x) )))))
+
+;; open module and start a repl in it
+(define go
+ (procedure->memoizing-macro
+ (lambda (x env)
+ (if (not (list? (cadr x))) (error "not a list:" (cadr x)))
+ `(,go-proc (,quote ,(cadr x))))))
+
+
+;;; low level interface
+
+;; access symbol exported from module
+(define module-ref
+ (procedure->memoizing-macro
+ (lambda (x env)
+ `(,module-ref-proc (,the-module) ,(cadr x) ,(caddr x)))))
+
+;; add module to import-list
+(define module-use
+ (procedure->memoizing-macro
+ (lambda (x env)
+ `(,module-use-proc (,the-module) (,quote ,(cdr x))))))
+
+;; start a new import-list
+(define module-open
+ (procedure->memoizing-macro
+ (lambda (x env)
+ `(,module-open-proc (,the-module) (,quote ,(cdr x))))))
+
+;; load a module
+(define module-load
+ (procedure->memoizing-macro
+ (lambda (x env)
+ (if (not (
+ list? (cadr x))) (error "not a list:" (cadr x)))
+ `(,module-load-proc (,quote ,(cadr x))))))
+
+;; publish symbols (visible to all other modules)
+(define module-protect
+ (procedure->memoizing-macro
+ (lambda (x env)
+ `(,module-protect-proc (,the-module) (,quote ,(cdr x) )))))
+
+;; make symbols visible to modules that belong the current package
+(define module-export
+ (procedure->memoizing-macro
+ (lambda (x env)
+ `(,module-export-proc (,the-module) (,quote ,(cdr x))))))
+
+;; open a module and return a handle
+(define module-access
+ (procedure->memoizing-macro
+ (lambda (x env)
+ (if (not (list? (cadr x))) (error "not a list:" (cadr x)))
+ `(,module-access-proc (,quote ,(cadr x))))))
+
+;; close a module (remove it from the module-registry)
+(define module-close
+ (procedure->memoizing-macro
+ (lambda (x env)
+ (if (not (list? (cadr x))) (error "not a list:" (cadr x)))
+ `(,module-close-proc (,quote ,(cadr x))))))
+
+;; create a in-memory module and return a handle
+(define module-create
+ (procedure->memoizing-macro
+ (lambda (x env)
+ (if (not (list? (cadr x))) (error "not a list:" (cadr x)))
+ `(,module-create-proc (,quote ,(cadr x) )))))
+
+;; import symbols from other modules
+(define module-config-open
+ (procedure->memoizing-macro
+ (lambda (x env)
+ `(,module-open-proc (,module-access-proc (,quote ,(cadr x))) (,quote ,(cddr x))))))
+
+;; make symbols visible within the current package
+(define module-config-protect
+ (procedure->memoizing-macro
+ (lambda (x env)
+ `(,module-protect-proc (,module-access-proc (,quote ,(cadr x))) (,quote ,(cddr x))))))
+
+;; make symbols visible to the world
+(define module-config-export
+ (procedure->memoizing-macro
+ (lambda (x env)
+ `(,module-export-proc (,module-access-proc (,quote ,(cadr x))) (,quote ,(cddr x))))))
+
+
+;;; For backward compatibility
+;;;
+
+(define (define-module-proc current-module args)
+ (let* (
+ (kws (cdr args))
+ (current-module-sym (module-name current-module))
+ (mod (car args))
+ (sym (symlist->module-sym mod))
+
+ ;; do not create a new module if the module names are the
+ ;; same and the current module has not been closed
+ (same-module (and (eq? current-module-sym sym)
+ (environment-bound? (module-registry) current-module-sym)))
+
+ (skel (if same-module
+ current-module
+ (module-create-proc mod))))
+
+
+ (let loop ((kws kws)
+ (modules '()))
+ (if (null? kws)
+ (begin
+ ;; append (ice-9 guile) and (ice-9 config) for convenience
+ (module-open-proc skel (cons '(ice-9 config) (cons '(ice-9 guile) modules)))
+ (if (not same-module) (module-go (module-access-proc mod)))
+ )
+
+ (let ((keyword (car kws)))
+ (let ((keyword (if (keyword? keyword) (keyword->symbol keyword) keyword)))
+ (case keyword
+ ((use-module use-syntax autoload :use-module :use-syntax :autoload)
+ (let (
+ (mod (cadr kws)))
+
+ (if (not (pair? mod))
+ (error "unrecognized defmodule argument" kws))
+
+ (loop (cddr kws)
+ (cons mod modules))))
+ ((no-backtrace :no-backtrace)
+ (loop (cdr kws) modules))
+ (else
+ (error "unrecognized defmodule argument" kws)))))))))
+
+(define define-module
+ (procedure->memoizing-macro
+ (lambda (x env)
+ `(,define-module-proc (,the-module) (,quote ,(cdr x) )))))
+
+;; rewrite me
+(define define-public
+ (procedure->memoizing-macro
+ (lambda (x env)
+ (let ((args (cdr x)))
+ (letrec (
+ (syntax (lambda ()
+ (error "bad syntax" (list 'define-public args))))
+ (defined-name
+ (lambda (n)
+ (cond
+ ((symbol? n) n)
+ ((pair? n) (defined-name (car n)))
+ (else (syntax)))))
+ )
+
+ (if (null? args) (syntax))
+
+ (let (
+ (name (defined-name (car args))))
+
+ `(begin
+ (letrec (
+ ;; according to environment proposal either
+ ;; symbol or (sym tags)
+ (get-symbol
+ (lambda (s)
+ (cond
+ ((pair? s) (car s))
+ (else s))))
+
+ ;; test if symbol is already exported
+ (exported?
+ (lambda (sym l)
+ (cond
+ ((null? l) #f)
+ ((eq? (get-symbol (car l)) sym) #t)
+ (else (exported? sym (cdr l)))))))
+
+ (let* (
+ (module-eval-environment ,module-eval-environment)
+ (module-export-environment ,module-export-environment)
+ (interface-environment-interface ,interface-environment-interface)
+ (environment-bound? ,environment-bound?)
+ (environment-ref ,environment-ref)
+ (environment-define ,environment-define)
+ (the-module ,the-module)
+ (the-environment ,the-environment)
+ (interface-environment-set-interface! ,interface-environment-set-interface!)
+ (module-export-list ,module-export-list)
+
+ (module (the-module))
+ (eval-env (module-eval-environment module))
+ (export (module-export-environment module))
+ (export-list (module-export-list module))
+
+ (val (,and (,environment-bound? eval-env ',name)
+ (,environment-ref eval-env ',name))))
+
+ (if (not (list? export-list))
+ (,error "You can either use `define-public' or `export', but not both"))
+
+ (if (not (memq ',name export-list))
+ (begin
+ (environment-define eval-env ',name val)
+ (set! export-list (cons ',name export-list))
+ (,module-set-export-list! module export-list)
+ (interface-environment-set-interface!
+ export
+ (list (cons eval-env export-list)))))
+
+
+
+ ;; Now (re)define the var normally. Bernard URBAN
+ ;; suggests we use eval here to accomodate Hobbit; it lets
+ ;; the interpreter handle the define-private form, which
+ ;; Hobbit can't digest.
+ (eval '(define ,@ args) (the-environment))
+
+ )))))))))
+
+
+;; the entry point (called by (ice-9 repl))
+(define start
+ (lambda ()
+ (module-go #f)))
+
diff --git a/ice-9/defmacro.scm b/ice-9/defmacro.scm
new file mode 100644
index 000000000..c0c96a526
--- /dev/null
+++ b/ice-9/defmacro.scm
@@ -0,0 +1,114 @@
+(module (ice-9 defmacro)
+ (open (ice-9 error)
+ (ice-9 provide)
+ (ice-9 guile))
+ (export defmacro gentemp defmacro:transformer defmacro:syntax-transformer))
+
+
+;;; {Macros}
+;;;
+
+(define (primitive-macro? m)
+ (and (macro? m)
+ (not (macro-transformer m))))
+
+;;; {Defmacros}
+;;;
+(define macro-table (make-weak-key-hash-table 523))
+(define xformer-table (make-weak-key-hash-table 523))
+
+(define (defmacro? m) (hashq-ref macro-table m))
+(define (assert-defmacro?! m) (hashq-set! macro-table m #t))
+(define (defmacro-transformer m) (hashq-ref xformer-table m))
+(define (set-defmacro-transformer! m t) (hashq-set! xformer-table m t))
+
+(define defmacro:transformer
+ (lambda (f)
+ (let* ((xform (lambda (exp env)
+ (copy-tree (apply f (cdr exp)))))
+ (a (procedure->memoizing-macro xform)))
+ (assert-defmacro?! a)
+ (set-defmacro-transformer! a f)
+ a)))
+
+
+(define defmacro
+ (let ((defmacro-transformer
+ (lambda (name parms . body)
+ (let ((transformer `(lambda ,parms ,@body)))
+ `(define ,name
+ (,(lambda (transformer)
+ (defmacro:transformer transformer))
+ ,transformer))))))
+ (defmacro:transformer defmacro-transformer)))
+
+
+; (defmacro defmacro-public args
+; (define (syntax)
+; (error "bad syntax" (list 'defmacro-public args)))
+; (define (defined-name n)
+; (cond
+; ((symbol? n) n)
+; (else (syntax))))
+; (cond
+; ((null? args) (syntax))
+
+; (#t
+; (let ((name (defined-name (car args))))
+; `(begin
+; (let* (
+; (module (the-module))
+; (eval (module-eval-environment module))
+
+; ;; look up the old value first
+; (val (if (environment-bound? eval ',name)
+; (environment-ref eval ',name)
+; (begin
+; (environment-define eval ',name #f)
+; #f)))
+
+; (export (module-export-environment module)))
+; (if (not (environment? export))
+; (let ( ;; create export environment
+; (export (make-export-environment eval (list ',name))))
+; (module-export-environment-set! module export)
+; )
+; (environment-define export ',name val)))
+
+; ;; Now (re)define the var normally.
+; ;;
+; (defmacro ,@ args))))))
+
+(define defmacro:syntax-transformer
+ (lambda (f)
+ (procedure->syntax
+ (lambda (exp env)
+ (copy-tree (apply f (cdr exp)))))))
+
+
+;; XXX - should the definition of the car really be looked up in the
+;; current module?
+
+(define (macroexpand-1 e)
+ (cond
+ ((pair? e) (let* ((a (car e))
+ (val (and (symbol? a) (local-ref (list a)))))
+ (if (defmacro? val)
+ (apply (defmacro-transformer val) (cdr e))
+ e)))
+ (#t e)))
+
+(define (macroexpand e)
+ (cond
+ ((pair? e) (let* ((a (car e))
+ (val (and (symbol? a) (local-ref (list a)))))
+ (if (defmacro? val)
+ (macroexpand (apply (defmacro-transformer val) (cdr e)))
+ e)))
+ (#t e)))
+
+(define (gentemp)
+ (gensym "scm:G"))
+
+(provide 'defmacro)
+
diff --git a/ice-9/error.scm b/ice-9/error.scm
new file mode 100644
index 000000000..8da006d4f
--- /dev/null
+++ b/ice-9/error.scm
@@ -0,0 +1,37 @@
+;;; {Error Handling}
+;;;
+
+(module (ice-9 error)
+ (open (ice-9 guile)
+ ((ice-9 repl) save-stack))
+ (export error warn))
+
+(define (error . args)
+ (save-stack)
+ (if (null? args)
+ (scm-error 'misc-error #f "?" #f #f)
+ (let loop ((msg "%s")
+ (rest (cdr args)))
+ (if (not (null? rest))
+ (loop (string-append msg " %S")
+ (cdr rest))
+ (scm-error 'misc-error #f msg args #f)))))
+
+;; bad-throw is the hook that is called upon a throw to a an unhandled
+;; key (unless the throw has four arguments, in which case
+;; it's usually interpreted as an error throw.)
+;; If the key has a default handler (a throw-handler-default property),
+;; it is applied to the throw.
+;;
+(define (bad-throw key . args)
+ (apply error "unhandled-exception:" key args))
+
+
+(define (warn . stuff)
+ (with-output-to-port (current-error-port)
+ (lambda ()
+ (newline)
+ (display ";;; WARNING ")
+ (display stuff)
+ (newline)
+ (car (last-pair stuff))))) \ No newline at end of file
diff --git a/ice-9/files.scm b/ice-9/files.scm
new file mode 100644
index 000000000..7c150530c
--- /dev/null
+++ b/ice-9/files.scm
@@ -0,0 +1,246 @@
+(module (ice-9 files)
+
+ (open (ice-9 posix)
+ (ice-9 guile)
+ (ice-9 provide)
+ ((ice-9 strorder) string=?))
+
+ (export scm-line-incrementors
+ read-line
+ file-exists?
+ file-is-directory?
+ has-suffix?
+ load-from-path
+ (dev (alias stat:dev))
+ (ino (alias stat:ino))
+ (mode (alias stat:mode))
+ (nlink (alias stat:nlink))
+ (uid (alias stat:uid))
+ (gid (alias stat:gid))
+ (rdev (alias stat:rdev))
+ (size (alias stat:size))
+ (atime (alias stat:atime))
+ (mtime (alias stat:mtime))
+ (ctime (alias stat:ctime))
+ (blksize (alias stat:blksize))
+ (blocks (alias stat:blocks))
+ (type (alias stat:type))
+ (perms (alias stat:perms))
+ read-delimited
+ read-delimited!
+ ))
+
+
+;;; {Line and Delimited I/O}
+
+;;; corresponds to SCM_LINE_INCREMENTORS in libguile.
+(define scm-line-incrementors "\n")
+
+(define (read-line! string . maybe-port)
+ (let* ((port (if (pair? maybe-port)
+ (car maybe-port)
+ (current-input-port))))
+ (let* ((rv (%read-delimited! scm-line-incrementors
+ string
+ #t
+ port))
+ (terminator (car rv))
+ (nchars (cdr rv)))
+ (cond ((and (= nchars 0)
+ (eof-object? terminator))
+ terminator)
+ ((not terminator) #f)
+ (else nchars)))))
+
+(define (read-delimited! delims buf . args)
+ (let* ((num-args (length args))
+ (port (if (> num-args 0)
+ (car args)
+ (current-input-port)))
+ (handle-delim (if (> num-args 1)
+ (cadr args)
+ 'trim))
+ (start (if (> num-args 2)
+ (caddr args)
+ 0))
+ (end (if (> num-args 3)
+ (cadddr args)
+ (string-length buf))))
+ (let* ((rv (%read-delimited! delims
+ buf
+ (not (eq? handle-delim 'peek))
+ port
+ start
+ end))
+ (terminator (car rv))
+ (nchars (cdr rv)))
+ (cond ((or (not terminator) ; buffer filled
+ (eof-object? terminator))
+ (if (zero? nchars)
+ (if (eq? handle-delim 'split)
+ (cons terminator terminator)
+ terminator)
+ (if (eq? handle-delim 'split)
+ (cons nchars terminator)
+ nchars)))
+ (else
+ (case handle-delim
+ ((trim peek) nchars)
+ ((concat) (string-set! buf nchars terminator)
+ (+ nchars 1))
+ ((split) (cons nchars terminator))
+ (else (error "unexpected handle-delim value: "
+ handle-delim))))))))
+
+(define (read-delimited delims . args)
+ (let* ((port (if (pair? args)
+ (let ((pt (car args)))
+ (set! args (cdr args))
+ pt)
+ (current-input-port)))
+ (handle-delim (if (pair? args)
+ (car args)
+ 'trim)))
+ (let loop ((substrings ())
+ (total-chars 0)
+ (buf-size 100)) ; doubled each time through.
+ (let* ((buf (make-string buf-size))
+ (rv (%read-delimited! delims
+ buf
+ (not (eq? handle-delim 'peek))
+ port))
+ (terminator (car rv))
+ (nchars (cdr rv))
+ (join-substrings
+ (lambda ()
+ (apply string-append
+ (reverse
+ (cons (if (and (eq? handle-delim 'concat)
+ (not (eof-object? terminator)))
+ (string terminator)
+ "")
+ (cons (make-shared-substring buf 0 nchars)
+ substrings))))))
+ (new-total (+ total-chars nchars)))
+ (cond ((not terminator)
+ ;; buffer filled.
+ (loop (cons (substring buf 0 nchars) substrings)
+ new-total
+ (* buf-size 2)))
+ ((eof-object? terminator)
+ (if (zero? new-total)
+ (if (eq? handle-delim 'split)
+ (cons terminator terminator)
+ terminator)
+ (if (eq? handle-delim 'split)
+ (cons (join-substrings) terminator)
+ (join-substrings))))
+ (else
+ (case handle-delim
+ ((trim peek concat) (join-substrings))
+ ((split) (cons (join-substrings) terminator))
+
+
+ (else (error "unexpected handle-delim value: "
+ handle-delim)))))))))
+
+;;; read-line [PORT [HANDLE-DELIM]] reads a newline-terminated string
+;;; from PORT. The return value depends on the value of HANDLE-DELIM,
+;;; which may be one of the symbols `trim', `concat', `peek' and
+;;; `split'. If it is `trim' (the default), the trailing newline is
+;;; removed and the string is returned. If `concat', the string is
+;;; returned with the trailing newline intact. If `peek', the newline
+;;; is left in the input port buffer and the string is returned. If
+;;; `split', the newline is split from the string and read-line
+;;; returns a pair consisting of the truncated string and the newline.
+
+(define (read-line . args)
+ (let* ((port (if (null? args)
+ (current-input-port)
+ (car args)))
+ (handle-delim (if (> (length args) 1)
+ (cadr args)
+ 'trim))
+ (line/delim (%read-line port))
+ (line (car line/delim))
+ (delim (cdr line/delim)))
+ (case handle-delim
+ ((trim) line)
+ ((split) line/delim)
+ ((concat) (if (and (string? line) (char? delim))
+ (string-append line (string delim))
+ line))
+ ((peek) (if (char? delim)
+ (unread-char delim port))
+ line)
+ (else
+ (error "unexpected handle-delim value: " handle-delim)))))
+
+
+
+;;; {Files}
+;;;
+;;; If no one can explain this comment to me by 31 Jan 1998, I will
+;;; assume it is meaningless and remove it. -twp
+;;; !!!! these should be implemented using Tcl commands, not fports.
+
+;; Using the vector returned by stat directly is probably not a good
+;; idea (it could just as well be a record). Hence some accessors.
+(define (dev f) (vector-ref f 0))
+(define (ino f) (vector-ref f 1))
+(define (mode f) (vector-ref f 2))
+(define (nlink f) (vector-ref f 3))
+(define (uid f) (vector-ref f 4))
+(define (gid f) (vector-ref f 5))
+(define (rdev f) (vector-ref f 6))
+(define (size f) (vector-ref f 7))
+(define (atime f) (vector-ref f 8))
+(define (mtime f) (vector-ref f 9))
+(define (ctime f) (vector-ref f 10))
+(define (blksize f) (vector-ref f 11))
+(define (blocks f) (vector-ref f 12))
+
+;; derived from stat mode.
+(define (type f) (vector-ref f 13))
+(define (perms f) (vector-ref f 14))
+
+(define file-exists?
+ (if (feature? 'posix)
+ (lambda (str)
+ (access? str F_OK))
+ (lambda (str)
+ (let ((port (catch 'system-error (lambda () (open-file str OPEN_READ))
+ (lambda args #f))))
+ (if port (begin (close-port port) #t)
+ #f)))))
+
+(define file-is-directory?
+ (if (feature? 'i/o-extensions)
+ (lambda (str)
+ (eq? (type (stat str)) 'directory))
+ (lambda (str)
+ (display str)
+ (newline)
+ (let ((port (catch 'system-error
+ (lambda () (open-file (string-append str "/.")
+ OPEN_READ))
+ (lambda args #f))))
+ (if port (begin (close-port port) #t)
+ #f)))))
+
+(define (has-suffix? str suffix)
+ (let ((sufl (string-length suffix))
+ (sl (string-length str)))
+ (and (> sl sufl)
+ (string=? (substring str (- sl sufl) sl) suffix))))
+
+
+;;; {Loading by paths}
+
+;;; Load a Scheme source file named NAME, searching for it in the
+;;; directories listed in %load-path, and applying each of the file
+;;; name extensions listed in %load-extensions.
+(define (load-from-path name)
+ (start-stack 'load-stack
+ (primitive-load-path name (interaction-environment))))
+
diff --git a/ice-9/hooks.scm b/ice-9/hooks.scm
new file mode 100644
index 000000000..a6e4f6c6b
--- /dev/null
+++ b/ice-9/hooks.scm
@@ -0,0 +1,23 @@
+;;; {Hooks}
+;;;
+;;; Warning: Hooks are now first class objects and add-hook! and remove-hook!
+;;; procedures. This interface is only provided for backward compatibility
+;;; and will be removed.
+;;;
+(module-open (ice-9 guile))
+(if (not (defined? new-add-hook!))
+ (begin
+ (define new-add-hook! add-hook!)
+ (define new-remove-hook! remove-hook!)))
+
+(define (run-hooks hook)
+ (if (and (pair? hook) (eq? (car hook) 'hook))
+ (run-hook hook)
+ (for-each (lambda (thunk) (thunk)) hook)))
+
+(define *suppress-old-style-hook-warning* #f)
+
+(define abort-hook (make-hook))
+
+
+
diff --git a/ice-9/keywords.scm b/ice-9/keywords.scm
new file mode 100644
index 000000000..da45f046a
--- /dev/null
+++ b/ice-9/keywords.scm
@@ -0,0 +1,15 @@
+
+;;; {Keywords}
+;;;
+
+(define (symbol->keyword symbol)
+ (make-keyword-from-dash-symbol (symbol-append '- symbol)))
+
+(define (keyword->symbol kw)
+ (let ((sym (keyword-dash-symbol kw)))
+ (string->symbol (substring sym 1 (string-length sym)))))
+
+(define (kw-arg-ref args kw)
+ (let ((rem (member kw args)))
+ (and rem (pair? (cdr rem)) (cadr rem))))
+
diff --git a/ice-9/lists.scm b/ice-9/lists.scm
new file mode 100644
index 000000000..654bab60e
--- /dev/null
+++ b/ice-9/lists.scm
@@ -0,0 +1,23 @@
+;;; {Lists}
+;;;
+(module (ice-9 lists)
+ (open (ice-9 guile))
+ (export list-index make-list))
+
+(define (list-index l k)
+ (let loop ((n 0)
+ (l l))
+ (and (not (null? l))
+ (if (eq? (car l) k)
+ n
+ (loop (+ n 1) (cdr l))))))
+
+(define (make-list n . init)
+ (if (pair? init) (set! init (car init)))
+ (let loop ((answer '())
+ (n n))
+ (if (<= n 0)
+ answer
+ (loop (cons init answer) (- n 1)))))
+
+
diff --git a/ice-9/macros.scm b/ice-9/macros.scm
new file mode 100644
index 000000000..e697861d1
--- /dev/null
+++ b/ice-9/macros.scm
@@ -0,0 +1,28 @@
+;;; {Macros}
+;;;
+
+;; actually....hobbit might be able to hack these with a little
+;; coaxing
+;;
+(module (ice-9 macros)
+ (export define-macro define-syntax-macro defmacro:transformer defmacro:syntax-transformer)
+ (open (ice-9 guile) (ice-9 defmacro)))
+
+
+(defmacro define-macro (first . rest)
+ (let ((name (if (symbol? first) first (car first)))
+ (transformer
+ (if (symbol? first)
+ (car rest)
+ `(lambda ,(cdr first) ,@rest))))
+ `(define ,name (defmacro:transformer ,transformer))))
+
+
+(defmacro define-syntax-macro (first . rest)
+ (let ((name (if (symbol? first) first (car first)))
+ (transformer
+ (if (symbol? first)
+ (car rest)
+ `(lambda ,(cdr first) ,@rest))))
+ `(define ,name (defmacro:syntax-transformer ,transformer))))
+
diff --git a/ice-9/math.scm b/ice-9/math.scm
new file mode 100644
index 000000000..f60d284e1
--- /dev/null
+++ b/ice-9/math.scm
@@ -0,0 +1,102 @@
+
+;;; {Transcendental Functions}
+;;;
+;;; Derived from "Transcen.scm", Complex trancendental functions for SCM.
+;;; Written by Jerry D. Hedden, (C) FSF.
+;;; See the file `COPYING' for terms applying to this program.
+;;;
+
+(define (exp z)
+ (if (real? z) ($exp z)
+ (make-polar ($exp (real-part z)) (imag-part z))))
+
+(define (log z)
+ (if (and (real? z) (>= z 0))
+ ($log z)
+ (make-rectangular ($log (magnitude z)) (angle z))))
+
+(define (sqrt z)
+ (if (real? z)
+ (if (negative? z) (make-rectangular 0 ($sqrt (- z)))
+ ($sqrt z))
+ (make-polar ($sqrt (magnitude z)) (/ (angle z) 2))))
+
+(define expt
+ (let ((integer-expt integer-expt))
+ (lambda (z1 z2)
+ (cond ((exact? z2)
+ (integer-expt z1 z2))
+ ((and (real? z2) (real? z1) (>= z1 0))
+ ($expt z1 z2))
+ (else
+ (exp (* z2 (log z1))))))))
+
+(define (sinh z)
+ (if (real? z) ($sinh z)
+ (let ((x (real-part z)) (y (imag-part z)))
+ (make-rectangular (* ($sinh x) ($cos y))
+ (* ($cosh x) ($sin y))))))
+(define (cosh z)
+ (if (real? z) ($cosh z)
+ (let ((x (real-part z)) (y (imag-part z)))
+ (make-rectangular (* ($cosh x) ($cos y))
+ (* ($sinh x) ($sin y))))))
+(define (tanh z)
+ (if (real? z) ($tanh z)
+ (let* ((x (* 2 (real-part z)))
+ (y (* 2 (imag-part z)))
+ (w (+ ($cosh x) ($cos y))))
+ (make-rectangular (/ ($sinh x) w) (/ ($sin y) w)))))
+
+(define (asinh z)
+ (if (real? z) ($asinh z)
+ (log (+ z (sqrt (+ (* z z) 1))))))
+
+(define (acosh z)
+ (if (and (real? z) (>= z 1))
+ ($acosh z)
+ (log (+ z (sqrt (- (* z z) 1))))))
+
+(define (atanh z)
+ (if (and (real? z) (> z -1) (< z 1))
+ ($atanh z)
+ (/ (log (/ (+ 1 z) (- 1 z))) 2)))
+
+(define (sin z)
+ (if (real? z) ($sin z)
+ (let ((x (real-part z)) (y (imag-part z)))
+ (make-rectangular (* ($sin x) ($cosh y))
+ (* ($cos x) ($sinh y))))))
+(define (cos z)
+ (if (real? z) ($cos z)
+ (let ((x (real-part z)) (y (imag-part z)))
+ (make-rectangular (* ($cos x) ($cosh y))
+ (- (* ($sin x) ($sinh y)))))))
+(define (tan z)
+ (if (real? z) ($tan z)
+ (let* ((x (* 2 (real-part z)))
+ (y (* 2 (imag-part z)))
+ (w (+ ($cos x) ($cosh y))))
+ (make-rectangular (/ ($sin x) w) (/ ($sinh y) w)))))
+
+(define (asin z)
+ (if (and (real? z) (>= z -1) (<= z 1))
+ ($asin z)
+ (* -i (asinh (* +i z)))))
+
+(define (acos z)
+ (if (and (real? z) (>= z -1) (<= z 1))
+ ($acos z)
+ (+ (/ (angle -1) 2) (* +i (asinh (* +i z))))))
+
+(define (atan z . y)
+ (if (null? y)
+ (if (real? z) ($atan z)
+ (/ (log (/ (- +i z) (+ +i z))) +2i))
+ ($atan2 z (car y))))
+
+(set! abs magnitude)
+
+(define (log10 arg)
+ (/ (log arg) (log 10)))
+
diff --git a/ice-9/misc.scm b/ice-9/misc.scm
new file mode 100644
index 000000000..6c892e7d7
--- /dev/null
+++ b/ice-9/misc.scm
@@ -0,0 +1,333 @@
+(module (ice-9 misc)
+ (export in-vicinity with-fluids)
+ (open (ice-9 structs) (ice-9 files) (ice-9 defmacro) (ice-9 provide) (ice-9 guile)))
+
+
+
+;;; {Simple Debugging Tools}
+;;
+
+;; peek takes any number of arguments, writes them to the
+;; current ouput port, and returns the last argument.
+;; It is handy to wrap around an expression to look at
+;; a value each time is evaluated, e.g.:
+;;
+;; (+ 10 (troublesome-fn))
+;; => (+ 10 (pk 'troublesome-fn-returned (troublesome-fn)))
+;;
+
+(define (peek . stuff)
+ (newline)
+ (display ";;; ")
+ (write stuff)
+ (newline)
+ (car (last-pair stuff)))
+
+(define pk peek)
+
+
+
+
+;;; {Trivial Functions}
+;;;
+
+(define (id x) x)
+(define (1+ n) (+ n 1))
+(define (-1+ n) (+ n -1))
+(define 1- -1+)
+(define return-it noop)
+(define (and=> value procedure) (and value (procedure value)))
+(define (make-hash-table k) (make-vector k '()))
+
+;;; apply-to-args is functionally redunant with apply and, worse,
+;;; is less general than apply since it only takes two arguments.
+;;;
+;;; On the other hand, apply-to-args is a syntacticly convenient way to
+;;; perform binding in many circumstances when the "let" family of
+;;; of forms don't cut it. E.g.:
+;;;
+;;; (apply-to-args (return-3d-mouse-coords)
+;;; (lambda (x y z)
+;;; ...))
+;;;
+
+(define (apply-to-args args fn) (apply fn args))
+
+
+;;; {Integer Math}
+;;;
+
+(define (ipow-by-squaring x k acc proc)
+ (cond ((zero? k) acc)
+ ((= 1 k) (proc acc x))
+ (else (ipow-by-squaring (proc x x)
+ (quotient k 2)
+ (if (even? k) acc (proc acc x))
+ proc))))
+
+(define string-character-length string-length)
+
+
+
+;; A convenience function for combining flag bits. Like logior, but
+;; handles the cases of 0 and 1 arguments.
+;;
+(define (flags . args)
+ (cond
+ ((null? args) 0)
+ ((null? (cdr args)) (car args))
+ (else (apply logior args))))
+
+
+;;; {Multiple return values}
+
+(define *values-rtd*
+ (make-record-type "values"
+ '(values)))
+
+(define values
+ (let ((make-values (record-constructor *values-rtd*)))
+ (lambda x
+ (if (and (not (null? x))
+ (null? (cdr x)))
+ (car x)
+ (make-values x)))))
+
+(define call-with-values
+ (let ((access-values (record-accessor *values-rtd* 'values))
+ (values-predicate? (record-predicate *values-rtd*)))
+ (lambda (producer consumer)
+ (let ((result (producer)))
+ (if (values-predicate? result)
+ (apply consumer (access-values result))
+ (consumer result))))))
+
+
+
+;;; {and-map and or-map}
+;;;
+;;; (and-map fn lst) is like (and (fn (car lst)) (fn (cadr lst)) (fn...) ...)
+;;; (or-map fn lst) is like (or (fn (car lst)) (fn (cadr lst)) (fn...) ...)
+;;; (map-in-order fn lst) is like (map fn lst) but definately in order of lst.
+;;;
+
+;; and-map f l
+;;
+;; Apply f to successive elements of l until exhaustion or f returns #f.
+;; If returning early, return #f. Otherwise, return the last value returned
+;; by f. If f has never been called because l is empty, return #t.
+;;
+(define (and-map f lst)
+ (let loop ((result #t)
+ (l lst))
+ (and result
+ (or (and (null? l)
+ result)
+ (loop (f (car l)) (cdr l))))))
+
+;; or-map f l
+;;
+;; Apply f to successive elements of l until exhaustion or while f returns #f.
+;; If returning early, return the return value of f.
+;;
+(define (or-map f lst)
+ (let loop ((result #f)
+ (l lst))
+ (or result
+ (and (not (null? l))
+ (loop (f (car l)) (cdr l))))))
+
+
+;;; {Booleans}
+;;;
+
+(define (->bool x) (not (not x)))
+
+
+;;; {Load Paths}
+;;;
+
+;;; Here for backward compatability
+;;
+(define scheme-file-suffix (lambda () ".scm"))
+
+(define (in-vicinity vicinity file)
+ (let ((tail (let ((len (string-length vicinity)))
+ (if (zero? len)
+ #f
+ (string-ref vicinity (- len 1))))))
+ (string-append vicinity
+ (if (or (not tail)
+ (eq? tail #\/))
+ ""
+ "/")
+ file)))
+
+
+;;; {Help for scm_shell}
+;;; The argument-processing code used by Guile-based shells generates
+;;; Scheme code based on the argument list. This page contains help
+;;; functions for the code it generates.
+
+(define (command-line) (program-arguments))
+
+;; This is mostly for the internal use of the code generated by
+;; scm_compile_shell_switches.
+(define (load-user-init)
+ (define (has-init? dir)
+ (let ((path (in-vicinity dir ".guile")))
+ (catch 'system-error
+ (lambda ()
+ (let ((stats (stat path)))
+ (if (not (eq? (stat:type stats) 'directory))
+ path)))
+ (lambda dummy #f))))
+ (let ((path (or (has-init? (or (getenv "HOME") "/"))
+ (has-init? (passwd:dir (getpw (getuid)))))))
+ (if path (primitive-load path))))
+
+
+
+;;; {Reader Extensions}
+;;;
+
+;;; Reader code for various "#c" forms.
+;;;
+
+;;; Parse the portion of a #/ list that comes after the first slash.
+(define (read-path-list-notation slash port)
+ (letrec
+
+ ;; Is C a delimiter?
+ ((delimiter? (lambda (c) (or (eof-object? c)
+ (char-whitespace? c)
+ (string-index "()\";" c))))
+
+ ;; Read and return one component of a path list.
+ (read-component
+ (lambda ()
+ (let loop ((reversed-chars '()))
+ (let ((c (peek-char port)))
+ (if (or (delimiter? c)
+ (char=? c #\/))
+ (string->symbol (list->string (reverse reversed-chars)))
+ (loop (cons (read-char port) reversed-chars))))))))
+
+ ;; Read and return a path list.
+ (let loop ((reversed-path (list (read-component))))
+ (let ((c (peek-char port)))
+ (if (and (char? c) (char=? c #\/))
+ (begin
+ (read-char port)
+ (loop (cons (read-component) reversed-path)))
+ (reverse reversed-path))))))
+
+(define (read-path-list-notation-warning slash port)
+ (if (not (getenv "GUILE_HUSH"))
+ (begin
+ (display "warning: obsolete `#/' list notation read from "
+ (current-error-port))
+ (display (port-filename port) (current-error-port))
+ (display "; see guile-core/NEWS." (current-error-port))
+ (newline (current-error-port))
+ (display " Set the GUILE_HUSH environment variable to disable this warning."
+ (current-error-port))
+ (newline (current-error-port))))
+ (read-hash-extend #\/ read-path-list-notation)
+ (read-path-list-notation slash port))
+
+
+(read-hash-extend #\' (lambda (c port)
+ (read port)))
+(read-hash-extend #\. (lambda (c port)
+ (eval (read port) (the-environment))))
+
+(if (feature? 'array)
+ (begin
+ (let ((make-array-proc (lambda (template)
+ (lambda (c port)
+ (read:uniform-vector template port)))))
+ (for-each (lambda (char template)
+ (read-hash-extend char
+ (make-array-proc template)))
+ '(#\b #\a #\u #\e #\s #\i #\c #\y #\h)
+ '(#t #\a 1 -1 1.0 1/3 0+i #\nul s)))
+ (let ((array-proc (lambda (c port)
+ (read:array c port))))
+ (for-each (lambda (char) (read-hash-extend char array-proc))
+ '(#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9)))))
+
+;; pushed to the beginning of the alist since it's used more than the
+;; others at present.
+(read-hash-extend #\/ read-path-list-notation-warning)
+
+(define (read:array digit port)
+ (define chr0 (char->integer #\0))
+ (let ((rank (let readnum ((val (- (char->integer digit) chr0)))
+ (if (char-numeric? (peek-char port))
+ (readnum (+ (* 10 val)
+ (- (char->integer (read-char port)) chr0)))
+ val)))
+ (prot (if (eq? #\( (peek-char port))
+ '()
+ (let ((c (read-char port)))
+ (case c ((#\b) #t)
+ ((#\a) #\a)
+ ((#\u) 1)
+ ((#\e) -1)
+ ((#\s) 1.0)
+ ((#\i) 1/3)
+ ((#\c) 0+i)
+ (else (error "read:array unknown option " c)))))))
+ (if (eq? (peek-char port) #\()
+ (list->uniform-array rank prot (read port))
+ (error "read:array list not found"))))
+
+(define (read:uniform-vector proto port)
+ (if (eq? #\( (peek-char port))
+ (list->uniform-array 1 proto (read port))
+ (error "read:uniform-vector list not found")))
+
+
+;;; {IOTA functions: generating lists of numbers}
+
+(define (reverse-iota n) (if (> n 0) (cons (1- n) (reverse-iota (1- n))) '()))
+(define (iota n) (reverse! (reverse-iota n)))
+
+
+;;; {While}
+;;;
+;;; with `continue' and `break'.
+;;;
+
+(defmacro while (cond . body)
+ `(letrec ((continue (lambda () (or (not ,cond) (begin (begin ,@ body) (continue)))))
+ (break (lambda val (apply throw 'break val))))
+ (catch 'break
+ (lambda () (continue))
+ (lambda v (cadr v)))))
+
+;;; {collect}
+;;;
+;;; Similar to `begin' but returns a list of the results of all constituent
+;;; forms instead of the result of the last form.
+;;; (The definition relies on the current left-to-right
+;;; order of evaluation of operands in applications.)
+
+(defmacro collect forms
+ (cons 'list forms))
+
+;;; {with-fluids}
+
+;; with-fluids is a convenience wrapper for the builtin procedure
+;; `with-fluids*'. The syntax is just like `let':
+;;
+;; (with-fluids ((fluid val)
+;; ...)
+;; body)
+
+(defmacro with-fluids (bindings . body)
+ `(with-fluids* (list ,@(map car bindings)) (list ,@(map cadr bindings))
+ (lambda () ,@body)))
+
+
diff --git a/ice-9/modules.scm b/ice-9/modules.scm
new file mode 100644
index 000000000..630a6e697
--- /dev/null
+++ b/ice-9/modules.scm
@@ -0,0 +1,82 @@
+;;; this is an add-on module for those who want to "load" the module
+;;; system.
+
+
+;; load the standard module system and add the module which exports
+;; the module configuration language to the current module's import
+;; list
+(eval
+ `(letrec (
+
+
+ ; return #f if module system
+ ; has already been loaded
+ (load-module-system
+
+ (let (
+ (load-sys-modules
+ (lambda (repl-env)
+ (if (not (environment-bound? (module-registry) 'ice-9/config))
+ (begin
+ (eval '(make-guile-module) repl-env)
+ (eval '(make-repl-module) repl-env)
+ (eval '(make-user-module) repl-env)
+ (let (
+ (ice-9/config (eval '(make-config-module) repl-env)))
+ (primitive-load-path "ice-9/config.scm" (vector-ref ice-9/config 0))
+ #t))
+ #f))))
+
+ (lambda ()
+ ; the code that creates system
+ ; modules comes from the repl
+ ; module.
+
+ (if (not (environment-bound? (module-registry) 'ice-9/repl))
+
+ (let* (
+ (import (make-interface-environment (list (cons (scheme-guile-environment 2) #t))))
+ (eval-env (make-eval-environment (make-leaf-environment) import)))
+ (primitive-load-path "ice-9/repl.scm" eval-env)
+ (load-sys-modules eval-env))
+ (let* (
+ (repl-module (environment-ref (module-registry) 'ice-9/repl))
+ (eval-env (vector-ref repl-module 0)))
+ (load-sys-modules eval-env))))))
+
+ ; fix current interface
+ (set-new-interface
+ (lambda (current-interface-env)
+ (let (
+ (guile-export (vector-ref (environment-ref (module-registry) 'ice-9/guile) 1))
+ (config-export (vector-ref (environment-ref (module-registry) 'ice-9/config) 1)))
+
+ (interface-environment-set-interface!
+ current-interface-env
+ (list (cons config-export #f) (cons guile-export #f))))))
+
+
+ ; append config-export to
+ ; current interface
+ (append-interface
+ (lambda (current-interface-env)
+ (let (
+ (import-interface (interface-environment-interface current-interface-env))
+ (config-export (vector-ref (environment-ref (module-registry) 'ice-9/config) 1)))
+
+ (if (not (assq config-export import-interface))
+ (interface-environment-set-interface!
+ current-interface-env
+ (cons (cons config-export #t) import-interface)))))))
+
+ (let* (
+ (current-eval-env ,(the-environment))
+ (current-interface-env (eval-environment-imported current-eval-env)))
+
+ (if (load-module-system)
+ (set-new-interface current-interface-env)
+ (append-interface current-interface-env))))
+
+ (scheme-guile-environment 2))
+
+
diff --git a/ice-9/options.scm b/ice-9/options.scm
new file mode 100644
index 000000000..8bc3e3fe7
--- /dev/null
+++ b/ice-9/options.scm
@@ -0,0 +1,223 @@
+(define-module (ice-9 options) :use-module (ice-9 defmacro))
+;;; {Command Line Options}
+;;;
+
+(define (get-option argv kw-opts kw-args return)
+ (cond
+ ((null? argv)
+ (return #f #f argv))
+
+ ((or (not (eq? #\- (string-ref (car argv) 0)))
+ (eq? (string-length (car argv)) 1))
+ (return 'normal-arg (car argv) (cdr argv)))
+
+ ((eq? #\- (string-ref (car argv) 1))
+ (let* ((kw-arg-pos (or (string-index (car argv) #\=)
+ (string-length (car argv))))
+ (kw (symbol->keyword (substring (car argv) 2 kw-arg-pos)))
+ (kw-opt? (member kw kw-opts))
+ (kw-arg? (member kw kw-args))
+ (arg (or (and (not (eq? kw-arg-pos (string-length (car argv))))
+ (substring (car argv)
+ (+ kw-arg-pos 1)
+ (string-length (car argv))))
+ (and kw-arg?
+ (begin (set! argv (cdr argv)) (car argv))))))
+ (if (or kw-opt? kw-arg?)
+ (return kw arg (cdr argv))
+ (return 'usage-error kw (cdr argv)))))
+
+ (else
+ (let* ((char (substring (car argv) 1 2))
+ (kw (symbol->keyword char)))
+ (cond
+
+ ((member kw kw-opts)
+ (let* ((rest-car (substring (car argv) 2 (string-length (car argv))))
+ (new-argv (if (= 0 (string-length rest-car))
+ (cdr argv)
+ (cons (string-append "-" rest-car) (cdr argv)))))
+ (return kw #f new-argv)))
+
+ ((member kw kw-args)
+ (let* ((rest-car (substring (car argv) 2 (string-length (car argv))))
+ (arg (if (= 0 (string-length rest-car))
+ (cadr argv)
+ rest-car))
+ (new-argv (if (= 0 (string-length rest-car))
+ (cddr argv)
+ (cdr argv))))
+ (return kw arg new-argv)))
+
+ (else (return 'usage-error kw argv)))))))
+
+(define (for-next-option proc argv kw-opts kw-args)
+ (let loop ((argv argv))
+ (get-option argv kw-opts kw-args
+ (lambda (opt opt-arg argv)
+ (and opt (proc opt opt-arg argv loop))))))
+
+(define (display-usage-report kw-desc)
+ (for-each
+ (lambda (kw)
+ (or (eq? (car kw) #t)
+ (eq? (car kw) 'else)
+ (let* ((opt-desc kw)
+ (help (cadr opt-desc))
+ (opts (car opt-desc))
+ (opts-proper (if (string? (car opts)) (cdr opts) opts))
+ (arg-name (if (string? (car opts))
+ (string-append "<" (car opts) ">")
+ ""))
+ (left-part (string-append
+ (with-output-to-string
+ (lambda ()
+ (map (lambda (x) (display (keyword-symbol x)) (display " "))
+ opts-proper)))
+ arg-name))
+ (middle-part (if (and (< (string-length left-part) 30)
+ (< (string-length help) 40))
+ (make-string (- 30 (string-length left-part)) #\ )
+ "\n\t")))
+ (display left-part)
+ (display middle-part)
+ (display help)
+ (newline))))
+ kw-desc))
+
+
+
+(define (transform-usage-lambda cases)
+ (let* ((raw-usage (delq! 'else (map car cases)))
+ (usage-sans-specials (map (lambda (x)
+ (or (and (not (list? x)) x)
+ (and (symbol? (car x)) #t)
+ (and (boolean? (car x)) #t)
+ x))
+ raw-usage))
+ (usage-desc (delq! #t usage-sans-specials))
+ (kw-desc (map car usage-desc))
+ (kw-opts (apply append (map (lambda (x) (and (not (string? (car x))) x)) kw-desc)))
+ (kw-args (apply append (map (lambda (x) (and (string? (car x)) (cdr x))) kw-desc)))
+ (transmogrified-cases (map (lambda (case)
+ (cons (let ((opts (car case)))
+ (if (or (boolean? opts) (eq? 'else opts))
+ opts
+ (cond
+ ((symbol? (car opts)) opts)
+ ((boolean? (car opts)) opts)
+ ((string? (caar opts)) (cdar opts))
+ (else (car opts)))))
+ (cdr case)))
+ cases)))
+ `(let ((%display-usage (lambda () (display-usage-report ',usage-desc))))
+ (lambda (%argv)
+ (let %next-arg ((%argv %argv))
+ (get-option %argv
+ ',kw-opts
+ ',kw-args
+ (lambda (%opt %arg %new-argv)
+ (case %opt
+ ,@ transmogrified-cases))))))))
+
+
+;;; {Run-time options}
+
+((let* ((names '((eval-options-interface
+ (eval-options eval-enable eval-disable)
+ (eval-set!))
+
+ (debug-options-interface
+ (debug-options debug-enable debug-disable)
+ (debug-set!))
+
+ (evaluator-traps-interface
+ (traps trap-enable trap-disable)
+ (trap-set!))
+
+ (read-options-interface
+ (read-options read-enable read-disable)
+ (read-set!))
+
+ (print-options-interface
+ (print-options print-enable print-disable)
+ (print-set!))
+
+ (readline-options-interface
+ (readline-options readline-enable readline-disable)
+ (readline-set!))
+ ))
+ (option-name car)
+ (option-value cadr)
+ (option-documentation caddr)
+
+ (print-option (lambda (option)
+ (display (option-name option))
+ (if (< (string-length
+ (symbol->string (option-name option)))
+ 8)
+ (display #\tab))
+ (display #\tab)
+ (display (option-value option))
+ (display #\tab)
+ (display (option-documentation option))
+ (newline)))
+
+ ;; Below follows the macros defining the run-time option interfaces.
+
+ (make-options (lambda (interface)
+ `(lambda args
+ (cond ((null? args) (,interface))
+ ((list? (car args))
+ (,interface (car args)) (,interface))
+ (else (for-each ,print-option
+ (,interface #t)))))))
+
+ (make-enable (lambda (interface)
+ `(lambda flags
+ (,interface (append flags (,interface)))
+ (,interface))))
+
+ (make-disable (lambda (interface)
+ `(lambda flags
+ (let ((options (,interface)))
+ (for-each (lambda (flag)
+ (set! options (delq! flag options)))
+ flags)
+ (,interface options)
+ (,interface)))))
+
+ (make-set! (lambda (interface)
+ `((name exp)
+ (,'quasiquote
+ (begin (,interface (append (,interface)
+ (list '(,'unquote name)
+ (,'unquote exp))))
+ (,interface))))))
+ )
+ (procedure->macro
+ (lambda (exp env)
+ (cons 'begin
+ (apply append
+ (map (lambda (group)
+ (let ((interface (car group)))
+ (append (map (lambda (name constructor)
+ `(define ,name
+ ,(constructor interface)))
+ (cadr group)
+ (list make-options
+ make-enable
+ make-disable))
+ (map (lambda (name constructor)
+ `(defmacro ,name
+ ,@(constructor interface)))
+ (caddr group)
+ (list make-set!)))))
+ names)))))))
+
+(export eval-options eval-enable eval-disable eval-set! debug-options
+debug-enable debug-disable traps trap-enable trap-disable trap-set!
+read-enable read-disable read-set! print-enable print-disable
+print-set! readline-options readline-enable readline-disable
+readline-set!)
+
diff --git a/ice-9/posix.scm b/ice-9/posix.scm
index 9698a0b8a..14ce238da 100644
--- a/ice-9/posix.scm
+++ b/ice-9/posix.scm
@@ -1,70 +1,190 @@
-;;; installed-scm-file
-
-;;;; Copyright (C) 1999 Free Software Foundation, Inc.
-;;;;
-;;;; This program is free software; you can redistribute it and/or modify
-;;;; it under the terms of the GNU General Public License as published by
-;;;; the Free Software Foundation; either version 2, or (at your option)
-;;;; any later version.
-;;;;
-;;;; This program is distributed in the hope that it will be useful,
-;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;;;; GNU General Public License for more details.
-;;;;
-;;;; You should have received a copy of the GNU General Public License
-;;;; along with this software; see the file COPYING. If not, write to
-;;;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
-;;;; Boston, MA 02111-1307 USA
-;;;;
-
-(define (stat:dev f) (vector-ref f 0))
-(define (stat:ino f) (vector-ref f 1))
-(define (stat:mode f) (vector-ref f 2))
-(define (stat:nlink f) (vector-ref f 3))
-(define (stat:uid f) (vector-ref f 4))
-(define (stat:gid f) (vector-ref f 5))
-(define (stat:rdev f) (vector-ref f 6))
-(define (stat:size f) (vector-ref f 7))
-(define (stat:atime f) (vector-ref f 8))
-(define (stat:mtime f) (vector-ref f 9))
-(define (stat:ctime f) (vector-ref f 10))
-(define (stat:blksize f) (vector-ref f 11))
-(define (stat:blocks f) (vector-ref f 12))
-
-;; derived from stat mode.
-(define (stat:type f) (vector-ref f 13))
-(define (stat:perms f) (vector-ref f 14))
-
-(define (passwd:name obj) (vector-ref obj 0))
-(define (passwd:passwd obj) (vector-ref obj 1))
-(define (passwd:uid obj) (vector-ref obj 2))
-(define (passwd:gid obj) (vector-ref obj 3))
-(define (passwd:gecos obj) (vector-ref obj 4))
-(define (passwd:dir obj) (vector-ref obj 5))
-(define (passwd:shell obj) (vector-ref obj 6))
-
-(define (group:name obj) (vector-ref obj 0))
-(define (group:passwd obj) (vector-ref obj 1))
-(define (group:gid obj) (vector-ref obj 2))
-(define (group:mem obj) (vector-ref obj 3))
-
-(define (utsname:sysname obj) (vector-ref obj 0))
-(define (utsname:nodename obj) (vector-ref obj 1))
-(define (utsname:release obj) (vector-ref obj 2))
-(define (utsname:version obj) (vector-ref obj 3))
-(define (utsname:machine obj) (vector-ref obj 4))
-
-(define (getpwent) (getpw))
-(define (setpwent) (setpw #t))
-(define (endpwent) (setpw))
-
-(define (getpwnam name) (getpw name))
-(define (getpwuid uid) (getpw uid))
-
-(define (getgrent) (getgr))
-(define (setgrent) (setgr #f))
-(define (endgrent) (setgr))
-
-(define (getgrnam name) (getgr name))
-(define (getgrgid id) (getgr id))
+(module (ice-9 posix)
+ (open (ice-9 guile)
+ ((ice-9 config) define-public)))
+
+
+;;; {Non-polymorphic versions of POSIX functions}
+
+(define-public (getgrnam name) (getgr name))
+(define-public (getgrgid id) (getgr id))
+(define-public (gethostbyaddr addr) (gethost addr))
+(define-public (gethostbyname name) (gethost name))
+(define-public (getnetbyaddr addr) (getnet addr))
+(define-public (getnetbyname name) (getnet name))
+(define-public (getprotobyname name) (getproto name))
+(define-public (getprotobynumber addr) (getproto addr))
+(define-public (getpwnam name) (getpw name))
+(define-public (getpwuid uid) (getpw uid))
+(define-public (getservbyname name proto) (getserv name proto))
+(define-public (getservbyport port proto) (getserv port proto))
+(define-public (endgrent) (setgr))
+(define-public (endhostent) (sethost))
+(define-public (endnetent) (setnet))
+(define-public (endprotoent) (setproto))
+(define-public (endpwent) (setpw))
+(define-public (endservent) (setserv))
+(define-public (getgrent) (getgr))
+(define-public (gethostent) (gethost))
+(define-public (getnetent) (getnet))
+(define-public (getprotoent) (getproto))
+(define-public (getpwent) (getpw))
+(define-public (getservent) (getserv))
+(define-public (reopen-file . args) (apply freopen args))
+(define-public (setgrent) (setgr #f))
+(define-public (sethostent) (sethost #t))
+(define-public (setnetent) (setnet #t))
+(define-public (setprotoent) (setproto #t))
+(define-public (setpwent) (setpw #t))
+(define-public (setservent) (setserv #t))
+
+(define-public (passwd:name obj) (vector-ref obj 0))
+(define-public (passwd:passwd obj) (vector-ref obj 1))
+(define-public (passwd:uid obj) (vector-ref obj 2))
+(define-public (passwd:gid obj) (vector-ref obj 3))
+(define-public (passwd:gecos obj) (vector-ref obj 4))
+(define-public (passwd:dir obj) (vector-ref obj 5))
+(define-public (passwd:shell obj) (vector-ref obj 6))
+
+(define-public (group:name obj) (vector-ref obj 0))
+(define-public (group:passwd obj) (vector-ref obj 1))
+(define-public (group:gid obj) (vector-ref obj 2))
+(define-public (group:mem obj) (vector-ref obj 3))
+
+(define-public (hostent:name obj) (vector-ref obj 0))
+(define-public (hostent:aliases obj) (vector-ref obj 1))
+(define-public (hostent:addrtype obj) (vector-ref obj 2))
+(define-public (hostent:length obj) (vector-ref obj 3))
+(define-public (hostent:addr-list obj) (vector-ref obj 4))
+
+(define-public (netent:name obj) (vector-ref obj 0))
+(define-public (netent:aliases obj) (vector-ref obj 1))
+(define-public (netent:addrtype obj) (vector-ref obj 2))
+(define-public (netent:net obj) (vector-ref obj 3))
+
+(define-public (protoent:name obj) (vector-ref obj 0))
+(define-public (protoent:aliases obj) (vector-ref obj 1))
+(define-public (protoent:proto obj) (vector-ref obj 2))
+
+(define-public (servent:name obj) (vector-ref obj 0))
+(define-public (servent:aliases obj) (vector-ref obj 1))
+(define-public (servent:port obj) (vector-ref obj 2))
+(define-public (servent:proto obj) (vector-ref obj 3))
+
+(define-public (sockaddr:fam obj) (vector-ref obj 0))
+(define-public (sockaddr:path obj) (vector-ref obj 1))
+(define-public (sockaddr:addr obj) (vector-ref obj 1))
+(define-public (sockaddr:port obj) (vector-ref obj 2))
+
+(define-public (utsname:sysname obj) (vector-ref obj 0))
+(define-public (utsname:nodename obj) (vector-ref obj 1))
+(define-public (utsname:release obj) (vector-ref obj 2))
+(define-public (utsname:version obj) (vector-ref obj 3))
+(define-public (utsname:machine obj) (vector-ref obj 4))
+
+(define-public (tm:sec obj) (vector-ref obj 0))
+(define-public (tm:min obj) (vector-ref obj 1))
+(define-public (tm:hour obj) (vector-ref obj 2))
+(define-public (tm:mday obj) (vector-ref obj 3))
+(define-public (tm:mon obj) (vector-ref obj 4))
+(define-public (tm:year obj) (vector-ref obj 5))
+(define-public (tm:wday obj) (vector-ref obj 6))
+(define-public (tm:yday obj) (vector-ref obj 7))
+(define-public (tm:isdst obj) (vector-ref obj 8))
+(define-public (tm:gmtoff obj) (vector-ref obj 9))
+(define-public (tm:zone obj) (vector-ref obj 10))
+
+(define-public (set-tm:sec obj val) (vector-set! obj 0 val))
+(define-public (set-tm:min obj val) (vector-set! obj 1 val))
+(define-public (set-tm:hour obj val) (vector-set! obj 2 val))
+(define-public (set-tm:mday obj val) (vector-set! obj 3 val))
+(define-public (set-tm:mon obj val) (vector-set! obj 4 val))
+(define-public (set-tm:year obj val) (vector-set! obj 5 val))
+(define-public (set-tm:wday obj val) (vector-set! obj 6 val))
+(define-public (set-tm:yday obj val) (vector-set! obj 7 val))
+(define-public (set-tm:isdst obj val) (vector-set! obj 8 val))
+(define-public (set-tm:gmtoff obj val) (vector-set! obj 9 val))
+(define-public (set-tm:zone obj val) (vector-set! obj 10 val))
+
+(define-public (tms:clock obj) (vector-ref obj 0))
+(define-public (tms:utime obj) (vector-ref obj 1))
+(define-public (tms:stime obj) (vector-ref obj 2))
+(define-public (tms:cutime obj) (vector-ref obj 3))
+(define-public (tms:cstime obj) (vector-ref obj 4))
+
+(define-public (file-position . args) (apply ftell args))
+(define-public (file-set-position . args) (apply fseek args))
+
+(define-public (open-input-pipe command) (open-pipe command OPEN_READ))
+(define-public (open-output-pipe command) (open-pipe command OPEN_WRITE))
+
+(define-public (move->fdes fd/port fd)
+ (cond ((integer? fd/port)
+ (dup->fdes fd/port fd)
+ (close fd/port)
+ fd)
+ (else
+ (primitive-move->fdes fd/port fd)
+ (set-port-revealed! fd/port 1)
+ fd/port)))
+
+(define-public (release-port-handle port)
+ (let ((revealed (port-revealed port)))
+ (if (> revealed 0)
+ (set-port-revealed! port (- revealed 1)))))
+
+(define-public (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-public (dup->inport port/fd . maybe-fd)
+ (apply dup->port port/fd "r" maybe-fd))
+
+(define-public (dup->outport port/fd . maybe-fd)
+ (apply dup->port port/fd "w" maybe-fd))
+
+(define-public (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-public (duplicate-port port modes)
+ (dup->port port modes))
+
+(define-public (fdes->inport fdes)
+ (let loop ((rest-ports (fdes->ports fdes)))
+ (cond ((null? rest-ports)
+ (let ((result (fdopen fdes "r")))
+ (set-port-revealed! result 1)
+ result))
+ ((input-port? (car rest-ports))
+ (set-port-revealed! (car rest-ports)
+ (+ (port-revealed (car rest-ports)) 1))
+ (car rest-ports))
+ (else
+ (loop (cdr rest-ports))))))
+
+(define-public (fdes->outport fdes)
+ (let loop ((rest-ports (fdes->ports fdes)))
+ (cond ((null? rest-ports)
+ (let ((result (fdopen fdes "w")))
+ (set-port-revealed! result 1)
+ result))
+ ((output-port? (car rest-ports))
+ (set-port-revealed! (car rest-ports)
+ (+ (port-revealed (car rest-ports)) 1))
+ (car rest-ports))
+ (else
+ (loop (cdr rest-ports))))))
+
+(define-public (port->fdes port)
+ (set-port-revealed! port (+ (port-revealed port) 1))
+ (fileno port))
+
+(define-public (setenv name value)
+ (if value
+ (putenv (string-append name "=" value))
+ (putenv name)))
+
diff --git a/ice-9/provide.scm b/ice-9/provide.scm
new file mode 100644
index 000000000..a5d7a881c
--- /dev/null
+++ b/ice-9/provide.scm
@@ -0,0 +1,13 @@
+;;; {Features}
+;;
+(module (ice-9 provide)
+ (open (ice-9 guile))
+ (export provide feature?))
+
+(define (provide sym)
+ (if (not (memq sym *features*))
+ (set! *features* (cons sym *features*))))
+
+(define (feature? feature)
+ (and (memq feature *features*) #t))
+
diff --git a/ice-9/repl.scm b/ice-9/repl.scm
new file mode 100644
index 000000000..3a09045e2
--- /dev/null
+++ b/ice-9/repl.scm
@@ -0,0 +1,478 @@
+;;; This is the module (ice-9 repl).
+;;;
+
+;; the current module
+(define make-repl-module
+ (lambda ()
+ (let ((ice-9/repl (and (environment-bound? (module-registry) 'ice-9/repl)
+ (environment-ref (module-registry) 'ice-9/repl))))
+ (if (not ice-9/repl)
+ (let* (
+ (eval (the-environment))
+ (export (make-interface-environment (list (list eval 'top-repl))))
+ (protect (make-interface-environment (list (list eval 'top-repl 'save-stack 'abort-hook))))
+ (ice-9/repl (vector eval export protect 'ice-9/ 'ice-9/repl)))
+ (environment-define (module-registry) 'ice-9/repl ice-9/repl)
+ (hashq-set! (environment-module-hash) eval ice-9/repl))
+ ice-9/repl))))
+
+;; the guile module
+(define make-guile-module
+ (lambda ()
+ (let ((ice-9/guile (and (environment-bound? (module-registry) 'ice-9/guile)
+ (environment-ref (module-registry) 'ice-9/guile))))
+
+ (if (not ice-9/guile)
+ (let* (
+ (eval (scheme-guile-environment 2))
+ (export (make-interface-environment (list (cons eval #t))))
+ (protect (make-interface-environment (list (cons eval #t))))
+ (ice-9/guile (vector eval export protect 'ice-9/ 'ice-9/guile)))
+ (environment-define (module-registry) 'ice-9/guile ice-9/guile)
+ (hashq-set! (environment-module-hash) eval ice-9/guile))
+ ice-9/guile))))
+
+(define make-user-module
+ (lambda ()
+ (let ((user/guile (and (environment-bound? (module-registry) 'user/guile)
+ (environment-ref (module-registry) 'user/guile))))
+
+ (if (not user/guile)
+ (let* (
+ (eval-env (guile-user-environment 2))
+ (export (make-interface-environment (list (cons eval-env #t))))
+ (protect (make-interface-environment (list (cons eval-env #t))))
+ (user/guile (vector eval-env export protect 'user/ 'user/guile)))
+
+ (environment-define (module-registry) 'user/guile user/guile)
+ (hashq-set! (environment-module-hash) eval-env user/guile))
+ user/guile))))
+
+(define make-config-module
+ (lambda ()
+ (let ((ice-9/config (and (environment-bound? (module-registry) 'ice-9/config)
+ (environment-ref (module-registry) 'ice-9/config))))
+
+ (if (not ice-9/config)
+ (let* ((import (make-interface-environment (list (cons (scheme-guile-environment 2) #t))))
+ (eval-env (make-eval-environment (make-leaf-environment) import))
+ (export (make-interface-environment (list (cons eval-env #t))))
+ (protect (make-interface-environment (list (cons eval-env #t))))
+ (ice-9/config (vector eval-env export protect 'ice-9/ 'ice-9/config)))
+
+ (environment-define (module-registry) 'ice-9/config ice-9/config)
+ (hashq-set! (environment-module-hash) eval-env ice-9/config))
+ ice-9/config))))
+
+
+
+
+;;; some more redundancy
+
+(define (module-name module) (vector-ref module 4))
+(define (module-eval-environment module) (vector-ref module 0))
+
+(define (run-hooks hook)
+ (if (and (pair? hook) (eq? (car hook) 'hook))
+ (run-hook hook)
+ (for-each (lambda (thunk) (thunk)) hook)))
+
+
+
+;;; {Running Repls}
+;;;
+
+(define (repl read evaler print)
+ (let loop ((source (read (current-input-port))))
+ (print (evaler source))
+ (loop (read (current-input-port)))))
+
+;; A provisional repl that acts like the SCM repl:
+;;
+(define scm-repl-silent #f)
+(define (assert-repl-silence v) (set! scm-repl-silent v))
+
+(define *unspecified* (if #f #f))
+(define (unspecified? v) (eq? v *unspecified*))
+
+(define scm-repl-print-unspecified #f)
+(define (assert-repl-print-unspecified v) (set! scm-repl-print-unspecified v))
+
+(define scm-repl-verbose #f)
+(define (assert-repl-verbosity v) (set! scm-repl-verbose v))
+
+(define scm-repl-prompt "guile> ")
+
+(define (set-repl-prompt! v) (set! scm-repl-prompt v))
+
+(define (default-lazy-handler key . args)
+ (save-stack lazy-handler-dispatch)
+ (apply throw key args))
+
+(define enter-frame-handler default-lazy-handler)
+(define apply-frame-handler default-lazy-handler)
+(define exit-frame-handler default-lazy-handler)
+
+(define (lazy-handler-dispatch key . args)
+ (case key
+ ((apply-frame)
+ (apply apply-frame-handler key args))
+ ((exit-frame)
+ (apply exit-frame-handler key args))
+ ((enter-frame)
+ (apply enter-frame-handler key args))
+ (else
+ (apply default-lazy-handler key args))))
+
+(define abort-hook (make-hook))
+
+;; these definitions are used if running a script.
+;; otherwise redefined in error-catching-loop.
+(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 ()
+ (lazy-catch #t
+ (lambda ()
+ (dynamic-wind
+ (lambda () (unmask-signals))
+ (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 () (mask-signals))))
+
+ lazy-handler-dispatch))
+
+ (lambda (key . args)
+ (case key
+ ((quit)
+ (force-output)
+ (set! status (car 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)
+ (display "ABORT: " (current-error-port))
+ (write args (current-error-port))
+ (newline (current-error-port))
+ (if interactive
+ (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.\n"
+ (current-error-port))
+ (set! has-shown-debugger-hint? #t)))
+ (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))))))))))
+ (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)))
+
+ (loop (lambda () #t))))
+
+;;(define the-last-stack (make-fluid)) Defined by scm_init_backtrace ()
+(define stack-saved? #f)
+
+(define (save-stack . narrowing)
+ (or stack-saved?
+ (cond ((not (memq 'debug (debug-options-interface)))
+ (fluid-set! the-last-stack #f)
+ (set! stack-saved? #t))
+ (else
+ (fluid-set!
+ the-last-stack
+ (case (stack-id #t)
+ ((repl-stack)
+ (apply make-stack #t save-stack eval #t 0 narrowing))
+ ((load-stack)
+ (apply make-stack #t save-stack 0 #t 0 narrowing))
+ ((tk-stack)
+ (apply make-stack #t save-stack tk-stack-mark #t 0 narrowing))
+ ((#t)
+ (apply make-stack #t save-stack 0 1 narrowing))
+ (else
+ (let ((id (stack-id #t)))
+ (and (procedure? id)
+ (apply make-stack #t save-stack id #t 0 narrowing))))))
+ (set! stack-saved? #t)))))
+
+(define before-error-hook (make-hook))
+(define after-error-hook (make-hook))
+(define before-backtrace-hook (make-hook))
+(define after-backtrace-hook (make-hook))
+
+(define has-shown-debugger-hint? #f)
+
+(define (handle-system-error key . args)
+ (let ((cep (current-error-port)))
+ (cond ((not (stack? (fluid-ref the-last-stack))))
+ ((memq 'backtrace (debug-options-interface))
+ (run-hook before-backtrace-hook)
+ (newline cep)
+ (display-backtrace (fluid-ref the-last-stack) cep)
+ (newline cep)
+ (run-hook after-backtrace-hook)))
+ (run-hook before-error-hook)
+ (apply display-error (fluid-ref the-last-stack) cep args)
+ (run-hook after-error-hook)
+ (force-output cep)
+ (throw 'abort key)))
+
+
+;;(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 () (p (e (r))))))5
+
+(define (gc-run-time)
+ (cdr (assq 'gc-time-taken (gc-stats))))
+
+(define before-read-hook (make-hook))
+(define after-read-hook (make-hook))
+
+;;; The default repl-reader function. We may override this if we've
+;;; the readline library.
+(define repl-reader
+ (lambda (prompt)
+ (display prompt)
+ (force-output)
+ (run-hook before-read-hook)
+ (read (current-input-port))))
+
+(define (scm-style-repl module)
+ (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 (string-append (module-name module) "> " )))
+ (repl-reader prompt))))
+
+ (run-hooks after-read-hook)
+ (if (eof-object? val)
+ (begin
+ (repl-report-start-timing)
+ (if scm-repl-verbose
+ (begin
+ (newline)
+ (display ";;; EOF -- quitting")
+ (newline)))
+ (throw 'quit #f)))
+
+ ;; As described in R4RS, the READ procedure updates the
+ ;; port to point to the first characetr 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.
+ (consume-trailing-whitespace)
+
+ val)))
+
+ (-eval (lambda (sourc)
+ (repl-report-start-timing)
+ (start-stack 'repl-stack (eval sourc (module-eval-environment module)))))
+
+ (-print (lambda (result)
+ (if (not scm-repl-silent)
+ (begin
+ (if (or scm-repl-print-unspecified
+ (not (unspecified? result)))
+ (begin
+ (write result)
+ (newline)))
+ (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))
+
+ (-abort (lambda ()
+ (if scm-repl-verbose
+ (begin
+ (display ";;; ABORT executed.")
+ (newline)
+ (repl-report)))
+ (repl -read -eval -print))))
+
+ (let ((status (error-catching-repl -read
+ -eval
+ -print)))
+ (-quit status))))
+
+
+;; this is just (scm-style-repl) with a wrapper to install and remove
+;; signal handlers. Every module may have exactly one repl.
+
+
+(define (top-repl module)
+ (let ((old-handlers #f)
+ (signals `((,SIGINT . "User interrupt")
+ (,SIGFPE . "Arithmetic error")
+ (,SIGBUS . "Bad memory access (bus error)")
+ (,SIGSEGV . "Bad memory access (Segmentation violation)"))))
+
+ (dynamic-wind
+
+ ;; call at entry
+ (lambda ()
+ (let ((make-handler (lambda (msg)
+ (lambda (sig)
+ (save-stack %deliver-signals)
+ (scm-error 'signal
+ #f
+ msg
+ #f
+ (list sig))))))
+ (set! old-handlers
+ (map (lambda (sig-msg)
+ (sigaction (car sig-msg)
+ (make-handler (cdr sig-msg))))
+ signals))))
+
+ ;; the protected thunk.
+ (lambda ()
+ (scm-style-repl module))
+
+
+ ;; call at exit.
+ (lambda ()
+ (map (lambda (sig-msg old-handler)
+ (if (not (car old-handler))
+ ;; restore original C handler.
+ (sigaction (car sig-msg) #f)
+ ;; restore Scheme handler, SIG_IGN or SIG_DFL.
+ (sigaction (car sig-msg)
+ (car old-handler)
+ (cdr old-handler))))
+ signals old-handlers)))))
+
+;;; This hook is run at the very end of an interactive session.
+;;;
+(define exit-hook (make-hook))
+
+
+
+;; now provide a function which starts the repl
+(define start
+ (lambda ()
+ (make-guile-module)
+ (make-repl-module)
+ (let ((user/guile (make-user-module)))
+
+ (set-interaction-environment! (vector-ref user/guile 0))
+
+ (let (
+ (ret-val (top-repl user/guile))
+
+ (start-module-system
+ (lambda ()
+ ;; create (ice-9 config) and re-start the repl in there
+ (let* ((ice-9/config (make-config-module))
+ (eval-env (vector-ref ice-9/config 0)))
+ (primitive-load-path "ice-9/config.scm" eval-env)
+ (eval '(start) eval-env)))))
+
+ (if (and (eqv? #f ret-val) (isatty? (current-input-port)))
+ (begin
+ (newline)
+ (set! ret-val (start-module-system))))
+
+ (or ret-val 0)))))
+
+
diff --git a/ice-9/run-test.scm b/ice-9/run-test.scm
new file mode 100644
index 000000000..44c73d95f
--- /dev/null
+++ b/ice-9/run-test.scm
@@ -0,0 +1,5 @@
+(define %library-dir
+ (lambda () (string-append (%package-data-dir) "/" (version))))
+
+(chdir (string-append (%library-dir) "/ice-9"))
+(define-module (ice-9 run-test) :use-module (ice-9 test)) \ No newline at end of file
diff --git a/ice-9/structs.scm b/ice-9/structs.scm
new file mode 100644
index 000000000..760e61d8e
--- /dev/null
+++ b/ice-9/structs.scm
@@ -0,0 +1,127 @@
+(module (ice-9 structs)
+
+ (export record-type? make-record-type record-type-name record-type-fields record-constructor record-predicate
+ record-accessor record-modifier record? record-type-descriptor)
+
+ (open (ice-9 provide) (ice-9 symbols) (ice-9 lists) (ice-9 guile)))
+
+;;; {Structs}
+
+(define (struct-layout s)
+ (struct-ref (struct-vtable s) vtable-index-layout))
+
+
+;;; {Records}
+;;;
+
+;; Printing records: by default, records are printed as
+;;
+;; #<type-name field1: val1 field2: val2 ...>
+;;
+;; You can change that by giving a custom printing function to
+;; MAKE-RECORD-TYPE (after the list of field symbols). This function
+;; will be called like
+;;
+;; (<printer> object port)
+;;
+;; It should print OBJECT to PORT.
+
+(define (inherit-print-state old-port new-port)
+ (if (pair? old-port)
+ (cons (if (pair? new-port) (car new-port) new-port)
+ (cdr old-port))
+ new-port))
+
+;; 0: type-name, 1: fields
+(define record-type-vtable
+ (make-vtable-vtable "prpr" 0
+ (lambda (s p)
+ (cond ((eq? s record-type-vtable)
+ (display "#<record-type-vtable>" p))
+ (else
+ (display "#<record-type " p)
+ (display (record-type-name s) p)
+ (display ">" p))))))
+
+(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 symbol-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 (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 . opt)
+ (let ((field-names (if (pair? opt) (car opt) (record-type-fields rtd))))
+ (eval `(lambda ,field-names
+ (make-struct ',rtd 0 ,@(map (lambda (f)
+ (if (memq f field-names)
+ f
+ #f))
+ (record-type-fields rtd))))
+ (the-environment))))
+
+(define (record-predicate rtd)
+ (lambda (obj) (and (struct? obj) (eq? rtd (struct-vtable obj)))))
+
+(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))
+ (eval `(lambda (obj)
+ (and (eq? ',rtd (record-type-descriptor obj))
+ (struct-ref obj ,pos))) (the-environment))))
+
+(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))
+ (eval `(lambda (obj val)
+ (and (eq? ',rtd (record-type-descriptor obj))
+ (struct-set! obj ,pos val))) (the-environment) )))
+
+
+(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)
+
diff --git a/ice-9/symbols.scm b/ice-9/symbols.scm
new file mode 100644
index 000000000..cb2cfb504
--- /dev/null
+++ b/ice-9/symbols.scm
@@ -0,0 +1,23 @@
+;;; {Symbols}
+;;;
+(module (ice-9 symbols)
+ (open (ice-9 guile))
+ (export symbol-append list->symbol symbol obarray-symbol-append obarray-gensym))
+
+(define (symbol-append . args)
+ (string->symbol (apply string-append args)))
+
+(define (list->symbol . args)
+ (string->symbol (apply list->string args)))
+
+(define (symbol . args)
+ (string->symbol (apply string args)))
+
+(define (obarray-symbol-append ob . args)
+ (string->obarray-symbol (apply string-append ob args)))
+
+(define (obarray-gensym obarray . opt)
+ (if (null? opt)
+ (gensym "%%gensym" obarray)
+ (gensym (car opt) obarray)))
+
diff --git a/libguile/ChangeLog-environments b/libguile/ChangeLog-environments
new file mode 100644
index 000000000..b0ed545f2
--- /dev/null
+++ b/libguile/ChangeLog-environments
@@ -0,0 +1,288 @@
+1999-08-21 Jost Boekemeier <jostobfe@calvados.zrz.tu-berlin.de>
+
+ * print.c (scm_init_print): renamed scm_intern0() to
+ scm_intern().
+
+ * eval.c (scm_m_atfop): Funktion uses symbol properties which
+ aren't supported anymore. Disabled.
+ (scm_m_atbind): Disabled.
+
+1999-08-19 Jost Boekemeier <jostobfe@calvados.zrz.tu-berlin.de>
+
+ * eval.c (scm_lookupcar, scm_lookupcar1): Renamed `check' to
+ `modify' which corresponds to the environment_cells `modify'
+ parameter. Special value modify == -1 means that the function
+ should return undef_cell instead of throwing an error.
+
+ * readline.c (scm_init_readline): Funktion accepts
+ environment and returns scheme value. Intern
+ "*readline-completion-function*" in readline's environment.
+ * eval.c (scm_init_eval): Create symbols nil and t in eval's
+ environment.
+ * lang.c (scm_init_lang): function accepts environment and
+ returns scheme value. "nil-while" is interned in lang's
+ environment.
+
+ * gsubr.c (scm_init_gsubr): make "name" a permanent symbol.
+
+ * Makefile.am : removed kw.h
+ * Makefile.in : regenerated
+
+1999-08-12 Jost Boekemeier <jostobfe@calvados.zrz.tu-berlin.de>
+
+ Removed symbol slots and ssymbols.
+ * tags.h (scm_tc7_ssymbol, scm_tc_7_msymbol): removed tags
+ 5 and 7,
+ (scm_tc7_msymbol): added tag 29
+ * gc.c (scm_gc_mark): Do not mark symbol_func and
+ symbol_slots.
+ * symbols.h (SCM_SYMBOL_PROPS): removed
+ (SCM_SYMBOL_FUNC): Removed
+ (SCM_SYMBOL_SLOTS): Removed
+ (SCM_HASHCODE): Symbol carries its own hash code
+ (SCM_SYMBOL_SLOTS): Changed to 2.
+
+ Symbols don't carry values anymore. Instead an environment
+ binds symbols to locations which carry values.
+ * symbols.c: rewritten
+ * symbols.h: removed ssymbols, removed slots from msymbols,
+ added `SCM_HASHCODE',
+ * debug.c eval.c feature.c feature.c filesys.c fports.c
+ gh_funcs.c gc.c gsubr.c keywords.c load.c macros.c net_db.c
+ objects.c options.c ports.c posix.c procs.c read.c
+ readline.c regex-posix.c scmsigs.c script.c socket.c
+ srcprop.c stime.c struct.c, cpp_cnvt.awk:
+ Changed scm_sysintern() into scm_environment_intern() or
+ scm_permanent_object(scm_intern(...)) depending on the
+ context.
+
+ Added environments.
+ * environments.c, environments.h: new file.
+ * gc.c (scm_igc): Added finalize method for weak environment
+ observers.
+ * Makefile.am: added environments.c, added environments.h
+ * Makefile.in: regenerated.
+
+ * libguile.h: removed reference to old "kw.h".
+
+ * init.c (scm_load_startup_files): load ice-9/boot-9.scm and
+ ice-9/init.scm into scm_root_environment.
+ (scm_boot_guile_1): Create the root environment by calling
+ scm_init_environment(). All other modules create bindings
+ in this environment. Store some module's init functions in
+ scm_c_module_registry so that these modules can be
+ initialized when needed.
+ (invoke_main_func): removed old module's post initialisation
+ function (scm_post_boot_init_modules()).
+
+ Memory pointers changed to type (void*)
+ * gc.c (scm_must_malloc): returns (void*)
+ (scm_must_realloc): returns and accepts (void*)
+ (scm_must_free): accepts (void*)
+
+ defined? is a special form.
+ * evalext.c (scm_defined_p): turned `scm_defined_p' into a
+ special form (macro) which tries to find a symbol in the
+ current environment frame or above.
+ (scm_m_undefine): use ENVIRONMENT_UNDEFINE() to remove a
+ binding.
+
+ eval conforms to r5rs.
+ * eval.c (scm_eval2): removed
+ (scm_eval): evaluate expressions in a environment context,
+ create the top of the environment stack: (env-smob . EOL).
+ (scm_eval_x): dto.
+
+ * procs.h (SCM_TOP_LEVEL): replaced by SCM_TOP_LEVEL_ENV
+ from environments.h
+ * eval.c (SCM_CEVAL, scm_m_define): SCM_TOP_LEVEL ->
+ SCM_TOP_LEVEL_ENV
+ * evalext.c (scm_m_undefine): dto.
+
+ Symbol lookup via scm_lookupcar():
+ * eval.c (scm_lookupcar1, scm_lookupcar): additional
+ parameter `modify' which corresponds to
+ SCM_ENVIRONMENT_CELL()'s `for_write' parameter.
+ (SCM_CEVAL): request a writeable location via
+ scm_lookupcar() only if we know that the location will be
+ changed (with set!).
+ (EVALCELLCAR): dto. (argument `modify' is always zero).
+
+ Memoization protocol, environment representation:
+ * eval.c (scm_lookupcar1): rewritten: environment smob
+ replaces `top_thunk'. Changed memoize method to
+ `scm_eval_environment_memoize_cell_internal()'.
+ (scm_lookupcar): scm_lookupcar1 doesn't return 0; test
+ removed.
+ (scm_unmemocar): Changed unmemoize method to
+ `eval_environment_update_memoized'.
+ Renamed scm_sym2vcell() to SCM_ENVIRONMENT_DEFINE().
+
+ * struct.c (scm_make_struct_layout): Renamed
+ scm_intern_obarray() to scm_permanent_object(scm_intern(...))
+
+ * stacks.c (get_applybody): replaced lookup for
+ scm_sym_apply by value of scm_i_apply.
+ (narrow_stack): removed reference to system_module_env_p
+
+ * snarf.h : rewritten. Create symbols in the appropriate
+ environment.
+
+ New startup sequence.
+ * script.c (sym_go): new symbol
+ (sym_top_repl ("top-repl")): removed
+ (scm_compile_shell_switches): evaluate "-c" arguments in
+ scm_root_environment
+ (scm_compile_shell_switches): intern "use-emacs-interface"
+ in scm_root_environment
+ (scm_compile_shell_switches): When interactive load
+ modules.scm into the root environment and start a repl in
+ module `ice-9/guile'.
+
+ * root.h (scm_symhash): removed
+ (scm_keyword_environment): replaces scm_keyword_obarray
+ (scm_root_environment): new variable
+ (scm_c_module_registry): new variable
+ (scm_interaction_environment): new variable
+ * gc.c (scm_init_storage): removed scm_symhash
+
+ * gc.c (scm_init_storage): Moved most-positive-fixnum,
+ most-negative-fixnum and bignum-radix to scm_init_root()
+ because they need a top-level environment.
+ * root.c (scm_init_root): added most-positive-fixnum,
+ most-negative-fixnum and bignum-radix
+ (from scm_init_storage()).
+
+ * backtrace.c, coop-threads.c, coop.c, debug.c, dynwind.c,
+ feature.c, filesys.c, fluids.c, fports.c, gh_data.c,
+ gh_eval.c, gh_init.c, gscm.c, hashtab.c, init.c, iselect.c,
+ keywords.c, load.c, ramap.c, read.c, readline.c, root.c,
+ struct.c, throw.c, unif.c: removed length argument from
+ scm_intern, renamed scm_intern0 to scm_intern.
+
+ Changed keyword obarray into a finite environment.
+ * keywords.c (scm_make_keyword_from_dash_symbol):
+ Renamed scm_sym2ovcell_soft() to
+ SCM_ENVIRONMENT_CELL()/SCM_ENVIRONMENT_DEFINE().
+ (scm_init_keywords): Renamed scm_keyword_obarray to
+ scm_keyword_environment.
+ (scm_c_make_keyword): changed scm_sysintern0() to
+ scm_permanent_object(...);
+ (scm_init_keywords): changed scm_keyword_obarray to
+ scm_keyword_environment
+
+ * gdbint.c (gdb_binding): Look up name in root environment.
+
+ All functions that evaluate expressions must do this in an
+ environment context.
+ * _scm.h: added "environments.h" since environments are
+ used by every c file.
+ * debug.c (scm_memcons): third argument `environment' is
+ required
+ (scm_procedure_environment): scm_tc7_cclo, scm_tcs_subrs,
+ scm_tc7_contin don't close over an environment, throw error.
+ * debug.h: removed declaration for scm_eval_string() which is
+ not defined in debug.c
+ * feature.c (scm_make_named_hook): added environment
+ parameter
+ * gdbint.c (gdb_eval): added environment parameter
+ * gh_eval.c: (gh_eval_str, gh_eval_file): evaluate in
+ scm_interaction_environment
+ * gh_funcs.c: (gh_new_procedure, gh_define): evaluate in
+ scm_interaction_environment
+ * gh_data.c (gh_lookup): look up symbols in
+ scm_interaction_environment
+ (gh_module_lookup): look up symbols in the given environment
+ * gsubr.c (scm_make_gsubr): added environment parameter
+ * macros.c (scm_make_synt): added environment parameter
+ * print.c (scm_init_print): make printer in specified
+ environment
+ * procs.c (scm_make_subr_opt, scm_make_subr,
+ scm_init_iprocs): added environment parameter
+ * strports.c (scm_eval_0str, scm_eval_string): added
+ environment parameter
+ * load.c (load_data): new type
+ (load): load and evaluate expressions in a given environment,
+ argument to load must be (struct load_data*)
+ (scm_primitive_load (primitive-load)): added environment
+ parameter, load hook called with additional environment
+ argument,
+ encapsulate environment and port into load_data.
+ (scm_init_load_path): added environment parameter
+ (scm_primitive_load_path (primitive-load-path)): dto.
+ (scm_read_and_eval_x (read-and-eval!)): environment is
+ optional and defaults to interaction-environment
+ (`scm_interaction_environment').
+ (init_build_info): added environment parameter
+ * async.c (scm_init_async): create "%gc-thunk" in module's
+ environment.
+ * evalext.c (scm_init_evalext): create
+ scm_m_generalized_set_x in module's environment.
+ * feature.c (scm_make_named_hook): intern hook in feature's
+ environment.
+ * (scm_init_feature): intern `*features*' in feature's
+ environment.
+ * gsubr.c (scm_init_gsubr): create `scm_gsubr_apply' in
+ module's environment.
+ * guardians.c (scm_init_guardian): create guard in module's
+ environment.
+ * procs.c (scm_make_subr): added environment argument.
+ (scm_init_iprocs): added environment argument.
+ * options.c (scm_init_opts): Do not intern options into one
+ of the environments. Make them permanent symbols instead.
+ * load.c (scm_init_load): intern "%load-path",
+ "%load-extensions" and "%load-hook", "%guile-build-info" in
+ module's environment.
+ (init_build_info): renamed scm_intern0 to scm_intern.
+ * ramap.c (scm_init_ramap): create scm_array_equal_p in
+ module's environment.
+ * strports.c (scm_eval_string): evaluate form in environment
+ * stacks.c (narrow_stack): removed scm_system_module_env_p
+
+ Turned all .c files into guile c-modules. All module's
+ init functions create bindings in a given environment and
+ return a scheme value.
+ * alist.c, arbiters.c, async.c, backtrace.c, boolean.c,
+ chars.c continuations.c, debug.c, dynamic_linking.c,
+ dynwind.c, eq.c, error.c eval.c, evalext.c, feature.c,
+ filesys.c, fluids.c, fports.c, gc.c gdbint.c, gsubr.c,
+ guardian.c, hash.c, hashtab.c, ioext.c, iselect.c
+ keywords.c, list.c, load.c, macros.c, mallocs.c, net_db.c,
+ numbers.c objects.c, objprop.c, options.c, pairs.c,
+ ports.c, posix.c, print.c procprop.c, procs.c, ramap.c,
+ random.c, read.c, readline.c regex-posix.c, root.c,
+ scmsigs.c, script.c, simpos.c, socket.c, sort.c srcprop.c,
+ stackchk.c, stacks.c, stime.c, strings.c, strop.c,
+ strorder.c strports.c, struct.c, symbols.c, tag.c,
+ threads.c, throw.c, unif.c vectors.c, version.c, vports.c,
+ weaks.c: changed init function so that it evaluates in a
+ given environment and returns a scheme value. * dynl.c
+ (scm_dynamic_call): Call the module init function in a
+ environment context and return its return-value.
+
+ Switched to new environment implementation
+ * eval.c (scm_m_define): rewritten.
+ * debug.c (scm_memcons): rewritten.
+ * evalext.c (scm_m_undefine): rewritten
+
+ Removed all references to variables and modules.
+ * Makefile.am: removed modules.h modules.c variables.c
+ variables.h debug.c (scm_make_gloc (make-gloc), scm_gloc_p
+ (gloc?)): removed
+ * debug.c, eval.c, evalext.c, gdbint.c, init.c,
+ libguile.h: removed #include "modules.h"
+ * debug.c, init.c, libguile.h, symbols.c, variable.c:
+ removed #include "variables.h"
+
+ Removed old module registry.
+ * dynl.c (scm_register_module_xxx, struct moddata,
+ scm_registered_modules, scm_clear_registered_modules):
+ removed
+
+ Removed all variables used by the old module system.
+ * debug.c, eval.c, evalext.c, gdbint.c, init.c, root.c,
+ root.h: removed top_level_lookup_closure
+ (*top-level-lookup-closure*),
+ scm_top_level_lookup_closure_var,
+ scm_can_use_top_level_lookup_closure_var.
+ * eval.c, init.c, root.h: removed scm_system_transformer.
diff --git a/libguile/environments.c b/libguile/environments.c
new file mode 100644
index 000000000..acdc031fc
--- /dev/null
+++ b/libguile/environments.c
@@ -0,0 +1,3558 @@
+#include "_scm.h"
+#include "environments.h"
+#include "symbols.h"
+#include "eval.h"
+#include "smob.h"
+#include "numbers.h"
+#include "alist.h"
+#include "weaks.h"
+#include "gh.h"
+
+#include <stdio.h>
+/*
+ * This file implements first class top-level-environments. An
+ * environment is a datatype that maps `symbols' to `values'.
+ *
+ * For example:
+ * SCM A = scm_make_leaf_environment();
+ * SCM B = scm_make_leaf_environment();
+ * scm_environment_define (A, gh_symbol2scm("a"), gh_int2scm(1))
+ * scm_environment_define (A, gh_symbol2scm("b"), gh_int2scm(2))
+ * scm_environment_define (B, gh_symbol2scm("b"), gh_int2scm(3))
+ *
+ * a b
+ *-----+-------------------------------
+ * A | 1 2
+ * B | 3
+ *
+ *
+ * It has an obarray (hash table) and a list of observers.
+ * The obarray's elements are vcells e.g. (a . 1) in environment A.
+ *
+ * An environment is generic and has the type `scm_tc16_environment'.
+ * It responds to the messages:
+ *
+ * ref -> return `value' (cdr of vcell)
+ * fold -> iterate over all bindings (vcells)
+ * define -> create new binding
+ * undefine -> remove binding
+ * set -> set `value'
+ * cell -> return vcell
+ * bound -> #t if binding exists, #f if not
+ *
+ *
+ * This file defines 3 concrete environment types: leaf, eval and
+ * interface environments.
+ * */
+
+/*
+ * Data structures
+ *
+ * cell: (((symbol . value) . (property alist)) . location_tag)
+ * CAR (cell) -> location
+ * CDR (cell) -> a location tag, either "immutable-location" or
+ * SCM_EOL ("mutable-location")
+ *
+ * vcell: (symbol . value) where value is either a scheme object or a
+ * cached cell
+ *
+ *
+ * Cache
+ *
+ * The following environments cache values (vcells) from other
+ * environments:
+ *
+ * interface-environment caches values from an eval-environment or
+ * interface-environment.
+ *
+ * interface-environment caches values from $n$ other environments
+ *
+ * eval-environment caches values from the interface-environment and from
+ * its local environment.
+ *
+ *
+ * Cache implementation
+ *
+ * All caching environments use the following structure: (symbol
+ * . value) where value is the cached cell from another environment.
+ * Given the eval-environment E which imports bindings from A (see
+ * above) and has B as its local environment, E holds the following
+ * vcell: (b . ((((b . 3)) . property-list) . mutable-location)).
+ * Whenever the location of the binding changes, it will take the new
+ * location and store it in the cdr of the vcell.
+ *
+ *
+ * Update protocol
+ *
+ * Every environment implements an update procedure with four
+ * parameters:
+ * 1. the receiver environment `self'
+ * 2. the calling environment `caller'
+ * 3. a symbol
+ * 4. the old cell
+ * 5. the new cell
+ * 6. the name of the current operation
+ *
+ * When some environment has changed a binding, it sends out an
+ * environment-update message (see broadcast and environment-update)
+ * to all observers. The environment which receives this
+ * environment-update message must:
+ *
+ * 1. find the appropriate cell in its environment
+ * 2. check if the cell it found has changed (by comparing with old cell)
+ * 3. update the cell.
+ * If the environment was not able to update the cell it must:
+ * a. re-construct the old state
+ * b. send out an update broadcast to all observers
+ * c. throw an error
+ *
+ *
+ * Whenever some environment has changed all bindings, it sends out an
+ * environment update message with symbol, old cell and new cell set
+ * to #f. Every environment receiving such a message can either:
+ *
+ * a) update all bindings in its environment by looking up
+ * bindings in caller's environment, or
+ * b) simply clear it's cache.
+ *
+ * An environment observing an eval environment (or any other
+ * user-contributed environments in general) however doesn't have this
+ * choice; it must implement algorithm a) if it still wants to receive
+ * update requests for specific bindings afterwards. The
+ * eval-environment (or user-contributed environments) need to know
+ * for which bindings they have to send out update broadcasts; if they
+ * find a vcell in their cache they know that someone cares about this
+ * binding and announce a change.
+ *
+ * Unmemoization protocoll: Guile's evaluator evals
+ * expressions in two steps:
+ *
+ * 1. compile code into memoized tree code
+ * 2. evaluate the compiled code
+ *
+ * An eval-environment receiving an update request
+ * for a specifig binding must:
+ *
+ * 1. update all expressions pointing to the old binding
+ *
+ * An eval environment receiving an update request
+ * for all bindings must:
+ *
+ * 1. unmemoize all expressions in its cache.
+ *
+ *
+ * All standard environments will send an update message iff:
+ * a) a binding has been removed from an environment (undefine ...) or
+ * b) a new binding in eval-environment's local environment shadows a
+ * binding from its import-environment (define ...) or
+ * c) the signature of an interface-environment has changed or
+ * d) the imported environment of a eval-environment has changed.
+ *
+ */
+
+
+#define SWAP(a, b) {SCM tmp = a; a = b; b = tmp;}
+#define UPDATE_EMPTY_OBARRAY (SCM_VELTS(protect_vec)[0])
+
+#define SCM_OBSERVERP(x) ((SCM_CAR (x)) == scm_tc16_observer)
+#define SCM_OBSERVER_STRUCT(observer) ((struct environment_observer*) SCM_CDR(observer))
+
+/* cell structure: (((sym . val) . symbol-property-alist) . (home-environment . tag)) */
+#define SCM_CELL_PROPERTY_ALIST SCM_CDAR
+#define SCM_CELL_TAG SCM_CDR /* either immutable or mutable_location */
+#define SCM_CELL_VAL SCM_CAAR /* return the (sym . val) of a cell */
+#define SCM_IMMUTABLE_LOCATIONP(tag) (scm_sym_immutable_location==(tag))
+#define SCM_MUTABLE_LOCATIONP(tag) (!(scm_sym_immutable_location==(tag))) /* cells don't carry `scm_sym_mutable_location' tags */
+
+SCM_SYMBOL (scm_sym_immutable_location, "immutable-location");
+SCM_SYMBOL (scm_sym_mutable_location, "mutable-location");
+SCM_SYMBOL (scm_sym_alias, "alias");
+SCM_SYMBOL (scm_sym_syntax, "syntax");
+
+long scm_tc16_environment;
+long scm_tc16_observer;
+static SCM protect_vec;
+
+/* the observer list */
+struct environment_observer {
+ SCM next;
+ SCM synapse;
+
+ short weak_p; /* is scheme weak? */
+
+ /* c is either a default_observer or a user supplied c function. */
+ scm_environment_observer c;
+
+ SCM scheme;
+};
+
+/* leaf environments */
+struct leaf_environment {
+ struct environment environment;
+ SCM synapse;
+ void (*update) (SCM env, SCM caller, SCM sym, SCM old_cell, SCM new_cell, char *name);
+};
+
+/* eval environments */
+struct eval_environment {
+ struct leaf_environment leaf;
+
+ SCM imported; /* interface-environment */
+ SCM local; /* leaf-environment */
+ SCM memoized; /* weak key hash table */
+};
+
+/* interface_environments */
+struct interface_environment {
+ struct leaf_environment leaf;
+
+ scm_environment_conflict_proc c_conflict_proc;
+ short aquisition;
+
+ SCM interface; /* list of environments with interface symbols */
+ SCM conflict_proc;
+
+ short empty;
+};
+
+
+
+/* manipulate obarrays */
+
+/*
+ * Copy symbol to obarray. The symbol must not already exist in obarray.
+ */
+static SCM
+scm_symbol_create_handle (obarray, symbol, scm_hash, init)
+ SCM symbol;
+ SCM obarray;
+ scm_sizet scm_hash;
+ SCM init;
+{
+ SCM sym;
+
+ sym = scm_acons (symbol, init,
+ SCM_VELTS (obarray)[scm_hash]);
+ SCM_VELTS (obarray)[scm_hash] = sym;
+
+ return SCM_CAR (sym);
+}
+
+/*
+ * look up symbol in obarray
+ */
+static SCM
+scm_symbol_get_handle (obarray, sym, scm_hash)
+ SCM sym;
+ SCM obarray;
+ scm_sizet scm_hash;
+{
+ SCM lsym;
+ SCM z;
+
+ for (lsym = SCM_VELTS (obarray)[scm_hash]; SCM_NIMP (lsym); lsym = SCM_CDR (lsym))
+ {
+ z = SCM_CAR (lsym);
+ if (SCM_CAR (z) == sym)
+ {
+ return z;
+ }
+ }
+ return SCM_BOOL_F;
+}
+
+
+/*
+ * remove handle from obarray
+ */
+static SCM
+scm_symbol_remove_handle (obarray, sym, scm_hash)
+ SCM sym;
+ SCM obarray;
+ scm_sizet scm_hash;
+{
+ SCM lsym;
+ SCM *lsymp;
+ SCM z;
+
+ for (lsym = *(lsymp = &SCM_VELTS (obarray)[scm_hash]);
+ SCM_NIMP (lsym);
+ lsym = *(lsymp = SCM_CDRLOC (lsym)))
+ {
+ z = SCM_CAR (lsym);
+ if (SCM_CAR (z) == sym)
+ {
+ *lsymp = SCM_CDR (lsym);
+ return z;
+ }
+ }
+ return SCM_BOOL_F;
+}
+
+static void
+scm_symbol_remove_all_handles (obarray, size)
+ SCM obarray;
+ scm_sizet size;
+{
+ scm_sizet i;
+
+ for (i=0; i<size; i++)
+ {
+ SCM_VELTS (obarray)[i] = SCM_EOL;
+ }
+}
+
+
+
+/* error conditions */
+
+/*
+ * Throw an error if symbol is not bound in environment func
+ */
+static void
+scm_error_environment_unbound(func, message, args, env, symbol)
+ char *func;
+ char *message;
+ SCM args;
+ SCM env;
+ SCM symbol;
+{
+ char error[255] = "Symbol not bound in environment `%s' (symbol: `%s').";
+ SCM arguments = scm_cons(env, scm_cons(symbol, args));
+ scm_misc_error (func, strcat(error, message), arguments);
+}
+
+/*
+ * Throw an error if two imported symbols have the same name
+ */
+static void
+scm_error_environment_name_conflict(func, message, args, env, symbol)
+ char *func;
+ char *message;
+ SCM args;
+ SCM env;
+ SCM symbol;
+{
+ char error[255] = "Symbol `%s' imported from `%s' shadows another symbol with the same name.";
+ SCM arguments = scm_cons(symbol, scm_cons(env, args));
+ scm_misc_error (func, strcat(error, message), arguments);
+}
+
+/*
+ * Throw an error if symbol has conflicting location tags
+ */
+static void
+scm_error_environment_conflicting_tags(func, message, args, env, symbol)
+ char *func;
+ char *message;
+ SCM args;
+ SCM env;
+ SCM symbol;
+{
+ char error[255] = "In environment `%s':\nThe cell for symbol `%s' can either be imported immutable or mutable, but not both.";
+ SCM arguments = scm_cons(env, scm_cons(symbol, args));
+ scm_misc_error (func, strcat(error, message), arguments);
+}
+
+/*
+ * Throw an error if func tried to create (define) or remove
+ * (undefine) a new binding for symbol in env
+ */
+static void
+scm_error_environment_immutable_bindings(func, message, args, env, symbol)
+ char *func;
+ char *message;
+ SCM args;
+ SCM env;
+ SCM symbol;
+{
+ char error[255] = "Immutable bindings in environment %s (symbol: `%s').";
+ SCM arguments = scm_cons(env, scm_cons(symbol, args));
+ scm_misc_error (func, strcat(error, message), arguments);
+}
+
+/*
+ * Throw an error if func tried to change (set_cdr) a immutable vcell.
+ */
+static void
+scm_error_environment_immutable_location(func, message, args, env, symbol)
+ char *func;
+ char *message;
+ SCM args;
+ SCM env;
+ SCM symbol;
+{
+ char error[255] = "Immutable location in environment `%s' (symbol: `%s').";
+ SCM arguments = scm_cons(env, scm_cons(symbol, args));
+ scm_misc_error (func, strcat(error, message), arguments);
+}
+
+
+
+/* generic environments */
+
+SCM
+scm_c_environment_ref (env, sym)
+ SCM env;
+ SCM sym;
+{
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env), env, SCM_ARG1, "scm_c_environment_ref");
+ SCM_ASSERT(SCM_NIMP(sym) && SCM_SYMBOLP(sym), sym, SCM_ARG2, "scm_c_environment_ref");
+
+ return SCM_ENVIRONMENT_REF(env, sym);
+}
+
+SCM_PROC(s_environment_ref, "environment-ref", 2, 0, 0, scm_environment_ref);
+SCM
+scm_environment_ref (env, sym)
+ SCM env;
+ SCM sym;
+{
+ SCM val;
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env), env, SCM_ARG1, s_environment_ref);
+ SCM_ASSERT(SCM_NIMP(sym) && SCM_SYMBOLP(sym), sym, SCM_ARG2, s_environment_ref);
+
+
+ val = SCM_ENVIRONMENT_REF (env, sym);
+
+ if(val == SCM_UNDEFINED)
+ scm_error_environment_unbound(s_environment_ref, "", SCM_EOL, env, sym);
+
+ return val;
+}
+
+
+/*
+ * the default env_folder
+ */
+static SCM
+scm_default_environment_folder (data, symbol, value, tail)
+ SCM data;
+ SCM symbol;
+ SCM value;
+ SCM tail;
+{
+ SCM answer;
+ /* don't pass these values to scheme level */
+ if ((value == SCM_UNDEFINED) || (value == SCM_UNSPECIFIED))
+ return tail;
+
+ answer = gh_call3 (data, symbol, value, tail);
+
+ return answer;
+}
+
+SCM
+scm_c_environment_fold (env, proc, data, init)
+ SCM env;
+ scm_environment_folder proc;
+ SCM data;
+ SCM init;
+{
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env), env, SCM_ARG1, "scm_c_environment_fold");
+
+ return SCM_ENVIRONMENT_FOLD(env, proc, data, init);
+}
+
+SCM_PROC(s_environment_fold, "environment-fold", 3, 0, 0, scm_environment_fold);
+SCM
+scm_environment_fold(env, proc, init)
+ SCM env;
+ SCM proc;
+ SCM init;
+{
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env), env, SCM_ARG1, s_environment_fold);
+ SCM_ASSERT(SCM_NIMP(proc) && (SCM_BOOL_T == scm_procedure_p(proc)), proc, SCM_ARG2, s_environment_fold);
+
+ return SCM_ENVIRONMENT_FOLD (env, scm_default_environment_folder, proc, init);
+}
+
+SCM_PROC(s_environment_define, "environment-define", 3, 0, 0, scm_environment_define);
+SCM
+scm_environment_define(env, sym, val)
+ SCM env;
+ SCM sym;
+ SCM val;
+{
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env), env, SCM_ARG1, s_environment_define);
+ SCM_ASSERT(SCM_NIMP(sym) && SCM_SYMBOLP(sym), sym, SCM_ARG2, s_environment_define);
+
+ SCM_ENVIRONMENT_DEFINE(env, sym, val);
+
+ return SCM_UNSPECIFIED;
+}
+
+SCM_PROC(s_environment_undefine, "environment-undefine", 2, 0, 0, scm_environment_undefine);
+SCM
+scm_environment_undefine(env, sym)
+ SCM env;
+ SCM sym;
+{
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env), env, SCM_ARG1, s_environment_undefine);
+ SCM_ASSERT(SCM_NIMP(sym) && SCM_SYMBOLP(sym), sym, SCM_ARG2, s_environment_undefine);
+
+ SCM_ENVIRONMENT_UNDEFINE(env, sym);
+
+ return SCM_UNSPECIFIED;
+}
+
+SCM_PROC(s_environment_set_x, "environment-set!", 3, 0, 0, scm_environment_set_x);
+SCM
+scm_environment_set_x(env,sym,val)
+ SCM env;
+ SCM sym;
+ SCM val;
+{
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env), env, SCM_ARG1, s_environment_set_x);
+ SCM_ASSERT(SCM_NIMP(sym) && SCM_SYMBOLP(sym), sym, SCM_ARG2, s_environment_set_x);
+
+ SCM_ENVIRONMENT_SET(env, sym, val);
+
+ return SCM_UNSPECIFIED;
+}
+
+SCM
+scm_c_environment_cell(env, sym, for_write)
+ SCM env;
+ SCM sym;
+ int for_write;
+{
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env), env, SCM_ARG1, "scm_c_environment_cell");
+ SCM_ASSERT(SCM_NIMP(sym) && SCM_SYMBOLP(sym), sym, SCM_ARG2, "scm_c_environment_cell");
+
+ return SCM_ENVIRONMENT_CELL (env, sym, for_write);
+}
+
+
+SCM_PROC(s_environment_cell, "environment-cell", 3, 0, 0, scm_environment_cell);
+SCM
+scm_environment_cell(env, sym, for_write)
+ SCM env;
+ SCM sym;
+ SCM for_write;
+{
+ SCM vcell;
+
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env), env, SCM_ARG1, s_environment_cell);
+ SCM_ASSERT(SCM_NIMP(sym) && SCM_SYMBOLP(sym), sym, SCM_ARG2, s_environment_cell);
+
+ vcell = SCM_ENVIRONMENT_CELL (env, sym, for_write == SCM_BOOL_T);
+
+ if (SCM_IMP (vcell))
+ scm_error_environment_unbound(s_environment_cell, "", SCM_EOL, env, sym);
+
+ return vcell;
+}
+
+SCM_PROC(s_environment_bound_p, "environment-bound?", 2, 0, 0, scm_environment_bound_p);
+SCM
+scm_environment_bound_p (env, sym)
+ SCM env;
+ SCM sym;
+{
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env), env, SCM_ARG1, s_environment_bound_p);
+ SCM_ASSERT(SCM_NIMP(sym) && SCM_SYMBOLP(sym), sym, SCM_ARG2, s_environment_bound_p);
+
+ return SCM_ENVIRONMENT_BOUND (env, sym);
+}
+
+/*
+ * call scheme level observer
+ * data is observer proc
+ */
+static void
+default_observer (env, data)
+ SCM env;
+ SCM data;
+{
+ gh_call1 (data, env);
+}
+
+/*
+ * the internal update protocoll uses this function as a tag. Instead
+ * of calling this function it will call environment_update()
+ * directly. */
+static void
+environment_update_dummy_observer (env, data)
+ SCM env;
+ SCM data;
+{
+}
+
+static SCM
+scm_environment_observe_internal (env, proc, data, weak_p)
+ SCM env;
+ scm_environment_observer proc;
+ SCM data;
+ int weak_p;
+{
+ static SCM scm_make_leaf_observer ();
+
+ return scm_make_leaf_observer(SCM_LEAF_ENVIRONMENT_STRUCT(env), proc, data, weak_p);
+}
+
+SCM
+scm_c_environment_observe (env, proc, data, weak_p)
+ SCM env;
+ scm_environment_observer proc;
+ SCM data;
+ int weak_p;
+{
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env), env, SCM_ARG1, "scm_c_environment_observe");
+
+ return SCM_ENVIRONMENT_OBSERVE(env, proc, data, weak_p);
+}
+
+SCM_PROC(s_environment_observe, "environment-observe", 2, 0, 0, scm_environment_observe);
+SCM
+scm_environment_observe(env, proc)
+ SCM env;
+ SCM proc;
+{
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env), env, SCM_ARG1, s_environment_observe);
+
+ return SCM_ENVIRONMENT_OBSERVE (env, default_observer, proc, 0);
+}
+
+SCM_PROC(s_environment_observe_weak, "environment-observe-weak", 2, 0, 0, scm_environment_observe_weak);
+SCM
+scm_environment_observe_weak(env, proc)
+ SCM env;
+ SCM proc;
+{
+ static SCM scm_make_leaf_observer ();
+
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env), env, SCM_ARG1, s_environment_observe_weak);
+
+ return scm_make_leaf_observer(SCM_LEAF_ENVIRONMENT_STRUCT(env), default_observer, proc, 1);
+}
+
+
+/*
+ * Remove observer from list
+ */
+static void
+environment_unobserve (observer)
+ struct environment_observer *observer;
+{
+ SCM leaf_environment;
+ SCM smob;
+ struct environment_observer *node, *prev;
+
+ /* does it observe an environment? */
+ if (SCM_IMP(observer->synapse)) return;
+
+ /* is the environment still available? */
+ leaf_environment = SCM_VELTS (observer->synapse)[0];
+ if(SCM_IMP(leaf_environment)) return;
+
+ /* does the environment have an observer-list? */
+ smob = SCM_VELTS(SCM_LEAF_ENVIRONMENT_STRUCT(leaf_environment)->synapse)[1];
+ if(SCM_IMP(smob)) return;
+
+ /* remove first element */
+ node = SCM_OBSERVER_STRUCT(smob);
+ if(node == observer)
+ {
+ SCM_VELTS(SCM_LEAF_ENVIRONMENT_STRUCT (leaf_environment)->synapse)[1] = node->next;
+ node->synapse = SCM_BOOL_F;
+ }
+
+ /* remove element from list */
+ prev = node;
+ smob = node->next;
+
+ while (SCM_NIMP(smob))
+ {
+ node = SCM_OBSERVER_STRUCT(smob);
+ smob = node->next;
+
+ if (node == observer)
+ {
+ prev->next = smob;
+ node->synapse = SCM_BOOL_F;
+ return;
+ }
+ prev = node;
+ }
+}
+
+static void
+scm_environment_unobserve_internal (dummy, observer_smob)
+ SCM dummy;
+ SCM observer_smob;
+{
+ environment_unobserve (SCM_OBSERVER_STRUCT(observer_smob));
+}
+
+SCM_PROC(s_environment_unobserve, "environment-unobserve", 1, 0, 0, scm_environment_unobserve);
+SCM
+scm_environment_unobserve (observer_smob)
+ SCM observer_smob;
+{
+ struct environment_observer *observer;
+ SCM_ASSERT(SCM_NIMP(observer_smob) && SCM_OBSERVERP(observer_smob),
+ observer_smob, SCM_ARG1, s_environment_unobserve);
+
+ observer = SCM_OBSERVER_STRUCT(observer_smob);
+ if(SCM_NIMP (observer->synapse) && SCM_NIMP(SCM_VELTS(observer->synapse)[0]))
+ {
+ SCM_ENVIRONMENT_UNOBSERVE(SCM_VELTS(observer->synapse)[0], observer_smob);
+ }
+
+ return SCM_UNSPECIFIED;
+}
+
+/*
+ * tell all obervers to update their bindings
+ */
+static void
+scm_environment_broadcast (leaf_env, sym, old_cell, new_cell, name)
+ SCM leaf_env;
+ SCM sym; /* #f -> remove all bindings */
+ SCM old_cell;
+ SCM new_cell; /* #f -> remove binding */
+ char *name;
+{
+ struct leaf_environment *leaf_environment = SCM_LEAF_ENVIRONMENT_STRUCT(leaf_env);
+ SCM node;
+
+ /* call all observers */
+ node = SCM_VELTS(leaf_environment->synapse)[1];
+ while (SCM_NIMP (node))
+ {
+ struct environment_observer *observer = SCM_OBSERVER_STRUCT(node);
+ node = observer->next;
+
+ (observer->c) (leaf_env, observer->scheme);
+ }
+
+
+ /* now the enhanced version for all environments that support it
+ (leaf, export, protect, eval and import environment). Environments
+ which do not support the enhanced update protocol (i.e. do not
+ share the common structure `leaf_environment') must not call
+ environment_observe with argument
+ `environment_update_dummy_observer'. */
+
+ node = SCM_VELTS(leaf_environment->synapse)[1];
+ while (SCM_NIMP (node))
+ {
+ struct environment_observer *observer = SCM_OBSERVER_STRUCT(node);
+ node = observer->next;
+
+ if(observer->c == environment_update_dummy_observer)
+ {
+ (*SCM_LEAF_ENVIRONMENT_STRUCT(observer->scheme)->update)
+ (observer->scheme, leaf_env, sym, old_cell, new_cell, name);
+ }
+ }
+}
+
+static SCM
+mark_environment (SCM environment_smob)
+{
+ struct environment *environment = SCM_ENVIRONMENT_STRUCT(environment_smob);
+
+ scm_gc_mark (environment->obarray);
+
+ /* subtype */
+ if(environment->environment_funcs->mark)
+ {
+ return (*environment->environment_funcs->mark) (environment_smob);
+ }
+
+ return SCM_BOOL_F;
+}
+
+static scm_sizet
+free_environment (SCM environment_smob)
+{
+ struct environment *environment = SCM_ENVIRONMENT_STRUCT(environment_smob);
+ scm_sizet size;
+
+ /* free the concrete but not the generic environment */
+ size = (*environment->environment_funcs->free) (environment_smob);
+
+ return size;
+}
+
+
+static int
+print_environment (SCM environment_smob, SCM port, scm_print_state *pstate)
+{
+ struct environment_funcs *environment_funcs =
+ SCM_ENVIRONMENT_FUNCS(environment_smob);
+
+ if(environment_funcs->print)
+ {
+ return (*environment_funcs->print) (environment_smob, port, pstate);
+ }
+ else
+ {
+ abort(); /* instance of a generic environment!?! */
+ }
+
+ return 1;
+}
+
+static scm_smobfuns environment_funs = {
+ mark_environment, free_environment, print_environment, 0
+};
+
+/*
+ * Create a concrete environment for type `handle'
+ * handle is the parameter for the generic type struct environment. Together
+ * they build a concrete (eval-/export- etc) environment.
+ *
+ * `handle' is a pointer to both struct environment and
+ * struct_export/eval/..._environment. struct environment_funcs
+ * is the class signature and has been initialized by the caller.
+ */
+SCM
+scm_make_environment (void *handle, scm_sizet size)
+{
+ struct environment *environment = (struct environment*) handle;
+ SCM environment_smob;
+
+ environment->obarray = SCM_BOOL_F;
+
+ SCM_NEWCELL (environment_smob);
+ SCM_SETCDR (environment_smob, environment);
+ SCM_SETCAR (environment_smob, scm_tc16_environment);
+
+ environment->obarray =
+ scm_make_vector ((SCM) SCM_MAKINUM (size), SCM_EOL);
+
+ return environment_smob;
+}
+
+SCM_PROC(s_environment_p, "environment?", 1, 0, 0, scm_environment_p);
+SCM
+scm_environment_p(env)
+ SCM env;
+{
+ return (SCM_NIMP(env) && SCM_ENVIRONMENTP(env)) ? SCM_BOOL_T : SCM_BOOL_F;
+}
+
+
+
+
+/* observers */
+
+/* after the sweep phase every weak observer will be checked if its
+ weak `scheme' data is still valid. If not, the observer will be
+ removed from the observer-list and from guardians */
+struct guardian {
+ struct environment_observer observer;
+ struct guardian *next;
+};
+
+static struct guardian *guardians = 0;
+
+/*
+ * create and return a new observer smob observing any of the
+ * standard environments (leaf, eval, export, protect and import).
+ * If data is weak, create a guard for it.
+ */
+static SCM
+scm_make_leaf_observer (leaf_environment, proc, data, weak_p)
+ struct leaf_environment *leaf_environment;
+ scm_environment_observer proc;
+ SCM data;
+ int weak_p;
+{
+ SCM observer_smob;
+ struct environment_observer *observer;
+
+ observer = scm_must_malloc (weak_p ?
+ sizeof (struct guardian) :
+ sizeof (struct environment_observer),
+ "scm_make_leaf_observer");
+
+ observer->weak_p = weak_p;
+ observer->c = proc;
+ observer->scheme = data;
+ observer->next = SCM_EOL;
+
+ SCM_NEWCELL (observer_smob);
+ SCM_SETCDR (observer_smob, observer);
+ SCM_SETCAR (observer_smob, scm_tc16_observer);
+
+ observer->next = SCM_VELTS(leaf_environment->synapse)[1];
+ SCM_VELTS(leaf_environment->synapse)[1] = observer_smob;
+ observer->synapse = leaf_environment->synapse;
+
+ if(weak_p) /* needs guard */
+ {
+ SCM_REDEFER_INTS;
+ ((struct guardian*) observer)->next = guardians;
+ guardians = (struct guardian*) observer;
+ SCM_REALLOW_INTS;
+ }
+
+ return observer_smob;
+}
+
+
+/*
+ * remove the observer_env watching env from env's observer-list
+ */
+static void
+scm_drop_internal_observer(env, observer_env)
+ SCM env;
+ SCM observer_env;
+{
+ struct leaf_environment *leaf_environment = SCM_LEAF_ENVIRONMENT_STRUCT(env);
+ SCM node;
+
+ node = SCM_VELTS(leaf_environment->synapse)[1];
+ while (SCM_NIMP(node))
+ {
+ struct environment_observer *observer = SCM_OBSERVER_STRUCT(node);
+
+ if (observer->c == environment_update_dummy_observer &&
+ observer->scheme == observer_env)
+ {
+ environment_unobserve(observer);
+ return;
+ }
+ node = observer->next;
+ }
+}
+
+/*
+ * remove guard from guardians
+ */
+static void
+scm_remove_guard (guard)
+ struct guardian *guard;
+{
+ struct guardian *node, *prev;
+
+ if (guardians == guard)
+ {
+ guardians = guardians->next;
+ return;
+ }
+
+ prev = guardians;
+ node = guardians->next;
+ while (node)
+ {
+ if (node == guard)
+ {
+ prev->next = node->next;
+ return;
+ }
+ prev = node;
+ node = node->next;
+ }
+
+ /* may happen when removed by finalize_weaks and then
+ gc'ed. */
+}
+
+/*
+ * remove all observers that contain gc'ed `scheme' data
+ * called directly after the sweep phase
+ */
+void
+scm_observer_finalize_weaks()
+{
+ struct guardian *node, *prev;
+
+ while (guardians && SCM_FREEP (guardians->observer.scheme))
+ {
+ environment_unobserve ((struct environment_observer*)guardians);
+ guardians = guardians->next;
+ }
+ if (!guardians) return;
+
+
+ prev = guardians;
+ node = guardians->next;
+ while (node)
+ {
+ if (SCM_FREEP (node->observer.scheme))
+ {
+ environment_unobserve ((struct environment_observer*)node);
+ prev->next = node->next;
+ }
+ prev = node;
+ node = node ->next;
+ }
+}
+
+static SCM
+mark_observer (SCM observer_smob)
+{
+ struct environment_observer *observer = SCM_OBSERVER_STRUCT(observer_smob);
+
+ if (!observer->weak_p)
+ {
+ scm_gc_mark(observer->scheme);
+ }
+
+ scm_gc_mark(observer->synapse);
+
+ return SCM_BOOL_F;
+}
+
+static scm_sizet
+free_observer (SCM observer_smob)
+{
+ struct environment_observer *observer = SCM_OBSERVER_STRUCT(observer_smob);
+
+ if (observer->weak_p) /* observer has guard */
+ {
+ /* remove from guarded list */
+ scm_remove_guard ((struct guard*) observer);
+ }
+
+ free(observer);
+
+ return sizeof observer_smob;
+}
+
+
+static int
+print_observer (SCM type, SCM port, scm_print_state *pstate)
+{
+ scm_puts ("#<observer ", port);
+ scm_puts (SCM_CHARS(scm_number_to_string(scm_ulong2num((unsigned long)type), SCM_MAKINUM (16))), port);
+ scm_puts (">", port);
+
+ return 1;
+}
+
+static scm_smobfuns observer_funs = {
+ mark_observer, free_observer, print_observer, 0
+};
+
+
+
+/* leaf environments */
+
+static SCM
+leaf_environment_get_vcell(env, sym)
+ SCM env;
+ scm_sizet sym;
+{
+ scm_sizet scm_hash = SCM_HASHCODE (sym);
+ return scm_symbol_get_handle (SCM_ENVIRONMENT_OBARRAY(env), sym, scm_hash);
+}
+
+static SCM
+scm_leaf_environment_fold (env, proc, data, init)
+ SCM env;
+ scm_environment_folder proc;
+ SCM data;
+ SCM init;
+{
+ scm_sizet i;
+ SCM retcode;
+ SCM obarray;
+
+ retcode = init;
+
+ obarray = SCM_ENVIRONMENT_OBARRAY(env);
+
+ for (i=0; i<scm_symhash_dim; i++)
+ {
+ SCM lsym;
+
+ for (lsym = SCM_VELTS (obarray)[i]; SCM_NIMP (lsym);
+ lsym = SCM_CDR (lsym))
+ {
+ SCM vcell;
+ vcell = SCM_CAR (lsym);
+ vcell = SCM_CELL_VAL (SCM_CDR (vcell));
+ retcode = (*proc)(data, SCM_CAR(vcell), SCM_CDR(vcell), retcode);
+ }
+ }
+ return retcode;
+}
+
+static SCM
+scm_leaf_environment_define(env, sym, val)
+ SCM env;
+ SCM sym;
+ SCM val;
+{
+ SCM vcell;
+ scm_sizet scm_hash;
+
+ scm_hash = SCM_HASHCODE (sym);
+ vcell = scm_symbol_get_handle (SCM_ENVIRONMENT_OBARRAY(env), sym, scm_hash);
+
+ if (SCM_NIMP (vcell))
+ {
+ SCM_SETCDR (SCM_CELL_VAL (SCM_CDR (vcell)), val);
+ }
+ else
+ { /* create a new cell */
+ SCM cell = scm_cons (scm_cons (scm_cons (sym, val), SCM_EOL), SCM_EOL);
+ vcell = scm_symbol_create_handle (SCM_ENVIRONMENT_OBARRAY(env), sym, scm_hash, cell);
+
+ }
+
+ return SCM_CELL_VAL (SCM_CDR (vcell)); /* environment_define returns "real" vcell */
+}
+
+static void
+scm_leaf_environment_undefine(env, sym)
+ SCM env;
+ SCM sym;
+{
+ SCM obarray = SCM_ENVIRONMENT_OBARRAY(env);
+ scm_sizet scm_hash = SCM_HASHCODE (sym);
+ SCM vcell = scm_symbol_get_handle(obarray, sym, scm_hash);
+
+ if (SCM_IMP (vcell)) return;
+
+ scm_environment_broadcast (env, sym, SCM_CDR(vcell), SCM_BOOL_F, s_environment_undefine);
+
+ /* if succeded ... */
+ scm_symbol_remove_handle(obarray, sym, scm_hash);
+}
+
+static void
+scm_leaf_environment_set_x(env, sym, val)
+ SCM env;
+ SCM sym;
+ SCM val;
+{
+ SCM vcell = leaf_environment_get_vcell(env, sym);
+
+ if (SCM_NIMP (vcell))
+ {
+ SCM_SETCDR( SCM_CELL_VAL (SCM_CDR (vcell)), val);
+ }
+ else
+ {
+ scm_error_environment_unbound(s_environment_set_x, "", SCM_EOL, env, sym);
+ }
+}
+
+static SCM
+scm_leaf_environment_ref (env, sym)
+ SCM env;
+ SCM sym;
+{
+ SCM vcell = leaf_environment_get_vcell(env, sym);
+
+ if (SCM_NIMP(vcell))
+ {
+ return SCM_CDR (SCM_CELL_VAL (SCM_CDR (vcell)));
+ }
+ return SCM_UNDEFINED;
+}
+
+static SCM
+scm_leaf_environment_cell(env, sym, for_write)
+ SCM env;
+ SCM sym;
+ int for_write;
+{
+ SCM vcell = leaf_environment_get_vcell(env, sym);
+
+ if (SCM_NIMP(vcell))
+ {
+ return SCM_CDR (vcell);
+ }
+ return SCM_BOOL_F;
+}
+
+static void
+mark_all_observer_smobs(node)
+ SCM node;
+{
+ while (SCM_NIMP (node))
+ {
+ struct environment_observer *observer = SCM_OBSERVER_STRUCT(node);
+
+ scm_gc_mark(node);
+
+ node = observer->next;
+ }
+}
+
+static SCM
+mark_leaf_environment (env)
+ SCM env;
+{
+ struct leaf_environment *leaf_environment = SCM_LEAF_ENVIRONMENT_STRUCT(env);
+
+ if(SCM_NIMP(leaf_environment->synapse))
+ {
+ mark_all_observer_smobs(SCM_VELTS(leaf_environment->synapse)[1]);
+ scm_gc_mark(leaf_environment->synapse);
+ }
+
+ return SCM_BOOL_F;
+}
+
+static scm_sizet
+free_leaf_environment (env)
+ SCM env;
+{
+ struct leaf_environment *leaf_environment = SCM_LEAF_ENVIRONMENT_STRUCT(env);
+
+ scm_sizet size;
+
+ size = sizeof (struct leaf_environment);
+
+ free (leaf_environment);
+
+ return size;
+}
+
+static int
+print_leaf_environment (SCM type, SCM port, scm_print_state *pstate)
+{
+ scm_puts ("#<leaf environment ", port);
+ scm_puts (SCM_CHARS(scm_number_to_string(scm_ulong2num((unsigned long)type), SCM_MAKINUM (16))), port);
+ scm_puts (">", port);
+ return 1;
+}
+
+struct environment_funcs leaf_environment_funcs = {
+ scm_leaf_environment_ref,
+ scm_leaf_environment_fold,
+ scm_leaf_environment_define,
+ scm_leaf_environment_undefine,
+ scm_leaf_environment_set_x,
+ scm_leaf_environment_cell,
+ scm_environment_observe_internal,
+ scm_environment_unobserve_internal,
+ mark_leaf_environment,
+ free_leaf_environment,
+ print_leaf_environment
+};
+
+void *scm_type_leaf_environment = &leaf_environment_funcs;
+
+SCM_PROC(s_make_leaf_environment, "make-leaf-environment", 0, 0, 0, scm_make_leaf_environment);
+SCM
+scm_make_leaf_environment ()
+{
+ SCM leaf_environment_smob;
+ struct leaf_environment *leaf_environment =
+ scm_must_malloc (sizeof *leaf_environment, s_make_leaf_environment);
+
+ leaf_environment->environment.environment_funcs = &leaf_environment_funcs;
+ leaf_environment->synapse = SCM_EOL;
+ leaf_environment->update = 0;
+
+ leaf_environment_smob = scm_make_environment(leaf_environment, scm_symhash_dim);
+
+ leaf_environment->synapse = scm_make_weak_vector (SCM_MAKINUM(2), SCM_EOL);
+ SCM_VELTS(leaf_environment->synapse)[0] = leaf_environment_smob;
+
+
+ return leaf_environment_smob;
+}
+
+SCM_PROC(s_leaf_environment_p, "leaf-environment?", 1, 0, 0, scm_leaf_environment_p);
+static SCM
+scm_leaf_environment_p (env)
+ SCM env;
+{
+ return SCM_NIMP(env) && SCM_ENVIRONMENTP(env) &&
+ SCM_LEAF_ENVIRONMENTP(env) ? SCM_BOOL_T : SCM_BOOL_F;
+}
+
+
+
+/* eval environments */
+
+static SCM
+eval_environment_get_cell(env, sym, for_write, name)
+ SCM env;
+ SCM sym;
+ int for_write;
+ char *name;
+{
+ struct eval_environment *eval_environment =
+ SCM_EVAL_ENVIRONMENT_STRUCT(env);
+
+ SCM cell;
+ SCM vcell;
+ SCM obarray;
+ SCM local_obarray;
+ scm_sizet scm_hash;
+ SCM import;
+
+ obarray = SCM_ENVIRONMENT_OBARRAY (env);
+ local_obarray = SCM_ENVIRONMENT_OBARRAY (eval_environment->local);
+
+ scm_hash = SCM_HASHCODE (sym);
+
+ /* in cache? */
+ vcell = scm_symbol_get_handle (obarray, sym, scm_hash);
+ if (SCM_NIMP (vcell))
+ {
+ if (!for_write ||
+ SCM_MUTABLE_LOCATIONP (SCM_CELL_TAG (SCM_CDR(vcell))))
+ {
+ return SCM_CDR(vcell);
+ }
+ else
+ {
+ scm_error_environment_immutable_location(name, "", SCM_EOL, env, sym);
+ }
+ }
+ /* in local? */
+ vcell = scm_symbol_get_handle (local_obarray, sym, scm_hash);
+ if (SCM_NIMP (vcell))
+ { /* copy to cache */
+ vcell = scm_symbol_create_handle(obarray, sym, scm_hash, SCM_CDR(vcell));
+
+ return SCM_CDR(vcell);
+ }
+
+
+ import = SCM_EVAL_ENVIRONMENT_IMPORTED(env);
+ cell = SCM_ENVIRONMENT_CELL (import, sym, 0);
+
+ if (SCM_NIMP (cell))
+ {
+ if(!for_write ||
+ SCM_MUTABLE_LOCATIONP(SCM_CELL_TAG (cell)))
+ {
+ /* copy to cache */
+ vcell = scm_symbol_create_handle(obarray, sym, scm_hash, cell);
+ return SCM_CDR(vcell);
+ }
+ else
+ {
+ scm_error_environment_immutable_location(name, "", SCM_EOL, env, sym);
+ }
+ }
+ return SCM_BOOL_F;
+}
+
+static SCM
+scm_eval_environment_cell(env, sym, for_write)
+ SCM env;
+ SCM sym;
+ int for_write;
+{
+ return eval_environment_get_cell (env, sym, for_write, s_environment_cell);
+}
+
+static SCM
+scm_eval_environment_ref (env, sym)
+ SCM env;
+ SCM sym;
+{
+ SCM cell = eval_environment_get_cell(env, sym, 0, s_environment_ref);
+
+ if (SCM_NIMP (cell))
+ {
+ return SCM_CDR (SCM_CELL_VAL (cell));
+ }
+
+ return SCM_UNDEFINED;
+}
+
+static SCM
+scm_eval_environment_fold (env, proc, data, init)
+ SCM env;
+ scm_environment_folder proc;
+ SCM data;
+ SCM init;
+{
+ struct eval_environment *environment = SCM_EVAL_ENVIRONMENT_STRUCT(env);
+ return scm_leaf_environment_fold (environment->local, proc, data, init);
+}
+
+/*
+ * update all memoized expressions to new_vcell+1 or unmemoize them
+ * if new_vcell is SCM_UNDEFINED
+ */
+void
+eval_environment_update_memoized (env, old_vcell, new_vcell)
+ SCM env;
+ SCM old_vcell;
+ SCM new_vcell; /* SCM_UNDEFINED -> unmemoize */
+{
+ SCM lsym;
+ SCM *lsymp;
+ SCM vcell;
+ SCM obarray;
+ unsigned int k;
+
+ obarray = SCM_EVAL_ENVIRONMENT_MEMOIZED(env);
+ k = scm_ihashq (old_vcell, SCM_LENGTH (obarray));
+
+ for (lsym = *(lsymp = &SCM_VELTS (obarray)[k]); SCM_NIMP (lsym);)
+ {
+ vcell = SCM_CAR (lsym);
+ if (SCM_CAR (vcell) == old_vcell)
+ { /* (vcell sym . expr) */
+ SCM expr = SCM_CDDR (vcell);
+ if (SCM_IMP (new_vcell)) /* undefined: unmemoize expr */
+ {
+ SCM sym = SCM_CADR(vcell);
+
+ SCM_SETCAR(expr, sym);
+ lsym = (*lsymp = SCM_CDR (lsym)); /* remove unmemoized */
+ }
+ else /* re-memoize */
+ {
+ SCM_SETCAR (expr, new_vcell + 1);
+ lsym = *(lsymp = SCM_CDRLOC (lsym)); /* next cell */
+ }
+ }
+ else
+ {
+ lsym = *(lsymp = SCM_CDRLOC (lsym)); /* next cell */
+ }
+ }
+}
+
+static void
+eval_environment_unmemoize_all(env)
+ SCM env;
+{
+ scm_sizet i;
+ SCM obarray;
+ SCM lsym;
+ SCM *lsymp;
+
+ obarray = SCM_EVAL_ENVIRONMENT_MEMOIZED (env);
+
+ for (i=0; i<scm_symhash_dim; i++)
+ {
+ for (lsym = *(lsymp = &SCM_VELTS (obarray)[i]);
+ SCM_NIMP (lsym);
+ lsym = (*lsymp = SCM_CDR (lsym))) /* remove unmemoized */
+ {
+ /* (vcell sym . expr) */
+ SCM vcell = SCM_CAR(lsym);
+ SCM sym = SCM_CADR(vcell);
+ SCM expr = SCM_CDDR(vcell);
+
+ SCM_SETCAR(expr, sym); /* unmemoize */
+ }
+ }
+}
+
+/*
+ * Update the value of old_cell to the value of new_cell.
+ * - Do not update a value that has not been cached
+ * - old_cell == #f: remove and unmemoize old binding
+ * - new_cell == #f: remove and unmemoize all bindings
+ * - copy location tags
+ */
+static void
+scm_eval_environment_update (env, caller, sym, old_cell, new_cell, name)
+ SCM env;
+ SCM caller;
+ SCM sym;
+ SCM old_cell;
+ SCM new_cell;
+ char *name;
+{
+ SCM obarray;
+ scm_sizet scm_hash;
+ SCM vcell;
+ obarray = SCM_ENVIRONMENT_OBARRAY(env);
+
+ if (SCM_NIMP(old_cell))
+ {
+ scm_hash = SCM_HASHCODE (sym);
+ vcell = scm_symbol_get_handle (obarray, sym, scm_hash);
+ if (!((SCM_IMP(vcell)) || (SCM_CELL_VAL (SCM_CDR (vcell)) != SCM_CELL_VAL (old_cell))))
+ {
+ old_cell = SCM_CDR(vcell);
+
+ if (SCM_NIMP (new_cell))
+ {
+ SCM_SETCDR (vcell, new_cell);
+ }
+ else
+ {
+ vcell = scm_symbol_remove_handle (obarray, sym, scm_hash);
+ }
+
+ scm_environment_broadcast (env, sym, old_cell, new_cell, name);
+ /* if succeded ... */
+ }
+
+ /* unmemoize all expressions which
+ capture old_cell in the current
+ environment */
+ eval_environment_update_memoized(env, SCM_CELL_VAL(old_cell),
+ SCM_NIMP (new_cell)?
+ SCM_CELL_VAL(new_cell) :
+ new_cell);
+ }
+ else
+ {
+ scm_symbol_remove_all_handles(obarray, scm_symhash_dim);
+ scm_environment_broadcast (env, sym, old_cell, new_cell, name);
+ /* if succeded ... */
+
+ eval_environment_unmemoize_all(env);
+ }
+}
+/*
+ * create a new binding in env and send out an update broadcast
+ * if we shadow a binding from the uses list.
+ *
+ * Do not send out an update broadcast if
+ * 1. vcell was not found in local
+ * 2. environment has no observers
+ * 3. vcell was not found in cache, which means that
+ * binding was never requested by env's observers.
+ */
+static SCM
+scm_eval_environment_define(env, sym, val)
+ SCM env;
+ SCM sym;
+ SCM val;
+{
+ struct eval_environment *eval_environment = SCM_EVAL_ENVIRONMENT_STRUCT(env);
+ SCM obarray;
+ SCM vcell;
+ SCM local_environment;
+ SCM local_obarray;
+ SCM local_vcell;
+ scm_sizet scm_hash;
+
+ obarray = eval_environment->leaf.environment.obarray;
+ scm_hash = SCM_HASHCODE (sym);
+ vcell = scm_symbol_get_handle(obarray, sym, scm_hash);
+
+ local_environment = eval_environment->local;
+ local_obarray = SCM_ENVIRONMENT_OBARRAY (local_environment);
+ local_vcell = scm_symbol_get_handle (local_obarray, sym, scm_hash);
+
+
+ if (SCM_IMP(local_vcell))
+ {
+ /* create a cell and copy into local and
+ into cache */
+ SCM local_cell = scm_cons (scm_cons (scm_cons (sym, val), SCM_EOL), SCM_EOL);
+
+ local_vcell = scm_symbol_create_handle (local_obarray, sym, scm_hash, local_cell);
+ scm_symbol_create_handle(obarray, sym, scm_hash, local_cell);
+
+ if (SCM_NIMP (vcell)) /* we've shadowed a binding from
+ useslist */
+ {
+ SCM shadowed_cell = SCM_CDR(vcell);
+
+ scm_environment_broadcast (env, sym, shadowed_cell, local_cell, s_environment_define);
+
+ /* re-memoize */
+ eval_environment_update_memoized(env, SCM_CELL_VAL(shadowed_cell), SCM_CELL_VAL (local_cell));
+ }
+ }
+ else
+ {
+ /* replace value of existing local cell */
+ SCM_SETCDR (SCM_CELL_VAL(SCM_CDR (local_vcell)), val);
+ }
+
+ return SCM_CELL_VAL (SCM_CDR (local_vcell));
+}
+
+static void
+scm_eval_environment_undefine(env, sym)
+ SCM env;
+ SCM sym;
+{
+ struct eval_environment *eval_environment = SCM_EVAL_ENVIRONMENT_STRUCT(env);
+ SCM shadowed_cell;
+ SCM local_environment;
+ SCM local_obarray;
+ SCM local_vcell;
+ SCM local_cell;
+ scm_sizet scm_hash;
+
+ scm_hash = SCM_HASHCODE (sym);
+ local_environment = eval_environment->local;
+ local_obarray = SCM_ENVIRONMENT_OBARRAY (local_environment);
+ local_vcell = scm_symbol_get_handle (local_obarray, sym, scm_hash);
+
+ /* does it exist? */
+ if (SCM_IMP (local_vcell)) return;
+
+ local_cell = SCM_CDR(local_vcell);
+
+ /* did it shadow a binding? */
+ shadowed_cell = SCM_ENVIRONMENT_CELL (eval_environment->imported, sym, 0);
+
+
+ scm_environment_broadcast (env, sym, local_cell, shadowed_cell, s_environment_undefine);
+
+ /* if succeded ... */
+ eval_environment_update_memoized(env, SCM_CELL_VAL(local_cell),
+ SCM_NIMP(shadowed_cell) ?
+ SCM_CELL_VAL (shadowed_cell) :
+ shadowed_cell);
+
+
+ /* remove from cache and from local */
+ scm_symbol_remove_handle (eval_environment->leaf.environment.obarray, sym, scm_hash);
+ scm_symbol_remove_handle (local_obarray, sym, scm_hash);
+}
+
+static void
+scm_eval_environment_set_x(env, sym, val)
+ SCM env;
+ SCM sym;
+ SCM val;
+{
+ SCM cell = eval_environment_get_cell(env, sym, 1, s_environment_set_x);
+
+ if (SCM_NIMP (cell))
+ {
+ SCM_SETCDR(SCM_CELL_VAL (cell), val);
+ }
+ else
+ {
+ scm_error_environment_unbound(s_environment_set_x, "", SCM_EOL, env, sym);
+ }
+}
+
+
+static SCM
+mark_eval_environment (env)
+ SCM env;
+{
+ struct eval_environment *eval_environment = SCM_EVAL_ENVIRONMENT_STRUCT(env);
+
+ if(SCM_NIMP(eval_environment->leaf.synapse))
+ {
+ mark_all_observer_smobs(SCM_VELTS(eval_environment->leaf.synapse)[1]);
+ scm_gc_mark(eval_environment->leaf.synapse);
+ }
+
+ scm_gc_mark (eval_environment->imported);
+ scm_gc_mark (eval_environment->local);
+ scm_gc_mark (eval_environment->memoized);
+
+ return SCM_BOOL_F;
+}
+
+static scm_sizet
+free_eval_environment (env)
+ SCM env;
+{
+ scm_sizet size;
+ struct eval_environment *eval_environment = SCM_EVAL_ENVIRONMENT_STRUCT(env);
+
+ size = sizeof (struct eval_environment);
+
+ free (eval_environment);
+
+ return size;
+}
+
+static int
+print_eval_environment (SCM type, SCM port, scm_print_state *pstate)
+{
+ scm_puts ("#<eval environment ", port);
+ scm_puts (SCM_CHARS(scm_number_to_string(scm_ulong2num((unsigned long)type), SCM_MAKINUM (16))), port);
+ scm_puts (">", port);
+
+ return 1;
+}
+
+
+static struct environment_funcs eval_environment_funcs = {
+ scm_eval_environment_ref,
+ scm_eval_environment_fold,
+ scm_eval_environment_define,
+ scm_eval_environment_undefine,
+ scm_eval_environment_set_x,
+ scm_eval_environment_cell,
+ scm_environment_observe_internal,
+ scm_environment_unobserve_internal,
+ mark_eval_environment,
+ free_eval_environment,
+ print_eval_environment
+ };
+void *scm_type_eval_environment = &eval_environment_funcs;
+
+
+SCM_PROC(s_make_eval_environment, "make-eval-environment", 2, 0, 0, scm_make_eval_environment);
+SCM
+scm_make_eval_environment (local, imported)
+ SCM local;
+ SCM imported;
+{
+ struct eval_environment *eval_environment;
+ SCM eval_environment_smob;
+
+ SCM_ASSERT(SCM_NIMP(local) && SCM_ENVIRONMENTP(local) && SCM_LEAF_ENVIRONMENTP(local), local, SCM_ARG1, s_make_eval_environment);
+
+ SCM_ASSERT(SCM_NIMP(imported) && SCM_ENVIRONMENTP(imported), imported, SCM_ARG2, s_make_eval_environment);
+
+ eval_environment =
+ scm_must_malloc (sizeof *eval_environment, s_make_eval_environment);
+
+ eval_environment->leaf.environment.environment_funcs = &eval_environment_funcs;
+ eval_environment->local = local;
+ eval_environment->imported = imported;
+ eval_environment->memoized = SCM_BOOL_F;
+
+ eval_environment->leaf.synapse = SCM_BOOL_F;
+ eval_environment->leaf.update = scm_eval_environment_update;
+
+ eval_environment_smob = scm_make_environment(eval_environment, scm_symhash_dim);
+
+ eval_environment->leaf.synapse = scm_make_weak_vector(SCM_MAKINUM(2), SCM_EOL);
+ SCM_VELTS(eval_environment->leaf.synapse)[0] = eval_environment_smob;
+
+ eval_environment->memoized =
+ scm_make_weak_key_hash_table ((SCM) SCM_MAKINUM (scm_symhash_dim));
+
+ if (SCM_NIMP (imported))
+ {
+ /* connect to imported. Will be dropped when
+ environment_smob disappears */
+ SCM_ENVIRONMENT_OBSERVE (imported,
+ environment_update_dummy_observer,
+ eval_environment_smob, 1);
+ }
+
+ /* not necessary to observe local because local cells are changed
+ through eval_environment_define/undefine */
+
+ return eval_environment_smob;
+}
+
+SCM_PROC(s_eval_environment_imported, "eval-environment-imported", 1, 0, 0, scm_eval_environment_imported);
+
+SCM
+scm_eval_environment_imported (env)
+ SCM env;
+{
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env) && SCM_EVAL_ENVIRONMENTP(env), env, SCM_ARG1, s_eval_environment_imported);
+
+ return SCM_EVAL_ENVIRONMENT_IMPORTED(env);
+}
+
+SCM_PROC(s_eval_environment_local, "eval-environment-local", 1, 0, 0, scm_eval_environment_local);
+
+SCM
+scm_eval_environment_local (env)
+ SCM env;
+{
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env) && SCM_EVAL_ENVIRONMENTP(env), env, SCM_ARG1, s_eval_environment_local);
+
+ return SCM_EVAL_ENVIRONMENT_LOCAL(env);
+}
+
+/*
+ * append expr to the list of memoized cells
+ */
+void
+scm_eval_environment_memoize_cell_internal(env, expr, vcell, sym)
+ SCM env;
+ SCM expr;
+ SCM vcell;
+ SCM sym;
+{
+ SCM obarray;
+ unsigned int k;
+
+ obarray = SCM_EVAL_ENVIRONMENT_MEMOIZED (env);
+ k = scm_ihashq (vcell, SCM_LENGTH (obarray));
+
+ SCM_VELTS(obarray)[k] = scm_acons(vcell, scm_cons(sym, expr), SCM_VELTS(obarray)[k]);
+ SCM_SETCAR (expr, vcell + 1);
+
+}
+
+SCM_PROC(s_eval_environment_set_imported_x, "eval-environment-set-imported!", 2, 0, 0, scm_eval_environment_set_imported_x);
+SCM
+scm_eval_environment_set_imported_x (env, imported)
+ SCM env;
+ SCM imported;
+{
+ struct eval_environment *eval_environment;
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env) && SCM_EVAL_ENVIRONMENTP(env), env, SCM_ARG1, s_eval_environment_set_imported_x);
+ SCM_ASSERT(SCM_NIMP(imported) && SCM_ENVIRONMENTP(imported), imported, SCM_ARG2, s_eval_environment_set_imported_x);
+
+ eval_environment = SCM_EVAL_ENVIRONMENT_STRUCT(env);
+
+ eval_environment_unmemoize_all(env);
+ scm_symbol_remove_all_handles(eval_environment->leaf.environment.obarray, scm_symhash_dim);
+
+ /* ask old import-env to remove my old
+ observer */
+ if (SCM_NIMP(eval_environment->imported))
+ {
+ scm_drop_internal_observer(eval_environment->imported, env);
+ }
+
+ eval_environment->imported = imported;
+
+ /* a new observer */
+ SCM_ENVIRONMENT_OBSERVE (imported,
+ environment_update_dummy_observer,
+ env, 1);
+
+ /* environments should update their
+ caches */
+ scm_environment_broadcast (env, SCM_BOOL_F, SCM_BOOL_F, SCM_BOOL_F, s_eval_environment_set_imported_x);
+
+ return SCM_UNSPECIFIED;
+}
+
+SCM_PROC(s_eval_environment_p, "eval-environment?", 1, 0, 0, scm_eval_environment_p);
+SCM
+scm_eval_environment_p (env)
+ SCM env;
+{
+ return SCM_NIMP(env) && SCM_ENVIRONMENTP(env) &&
+ SCM_EVAL_ENVIRONMENTP(env) ? SCM_BOOL_T : SCM_BOOL_F;
+}
+
+
+
+/* interface environments */
+
+/*
+ * Throw an error if two imported symbols with the same name are bound
+ * to two different locations
+ */
+static SCM
+scm_interface_environment_conflict_proc (data, sym, env1, env2)
+ SCM data;
+ SCM sym;
+ SCM env1;
+ SCM env2;
+{
+ /* whamm! */
+ scm_error_environment_name_conflict(SCM_CHARS (data), "", SCM_EOL, env1, sym);
+
+ return 0;
+}
+
+static SCM
+interface_environment_get_vcell(env, sym, for_write, name)
+ SCM env;
+ SCM sym;
+ int for_write;
+ char *name;
+{
+ struct interface_environment *interface_environment = SCM_INTERFACE_ENVIRONMENT_STRUCT(env);
+ scm_sizet scm_hash = SCM_HASHCODE (sym);
+ SCM obarray = interface_environment->leaf.environment.obarray;
+ SCM vcell = scm_symbol_get_handle (obarray, sym, scm_hash);
+
+ if (SCM_IMP (vcell))
+ {
+ /* Special case: aquisition. Assume that all symbols are
+ visible */
+
+ if (interface_environment->aquisition)
+ {
+ SCM cell = SCM_ENVIRONMENT_CELL (SCM_CAAR (interface_environment->interface), sym, for_write);
+
+ if (SCM_NIMP (cell))
+ {
+ /* copy to cache */
+ vcell = scm_symbol_create_handle(obarray, sym, scm_hash, cell);
+ }
+ }
+ }
+ else /* found in cache */
+ {
+ if (for_write && SCM_IMMUTABLE_LOCATIONP (SCM_CELL_TAG (SCM_CDR(vcell))))
+ {
+ scm_error_environment_immutable_location(name, "", SCM_EOL, env, sym);
+ }
+ }
+
+ return vcell;
+}
+
+static SCM interface_environment_fix_interface(SCM env, struct interface_environment *interface_environment, SCM imports, char *name);
+
+static SCM
+scm_interface_environment_ref_fixed (env, sym)
+ SCM env;
+ SCM sym;
+{
+ SCM vcell = interface_environment_get_vcell(env, sym, 0, s_environment_ref);
+
+ if (SCM_NIMP (vcell))
+ {
+ return SCM_CDR (SCM_CELL_VAL (SCM_CDR (vcell)));
+ }
+
+ return SCM_UNDEFINED;
+}
+
+static SCM
+scm_interface_environment_ref(env, sym)
+ SCM env;
+ SCM sym;
+{
+ struct interface_environment *interface = SCM_INTERFACE_ENVIRONMENT_STRUCT(env);
+ interface_environment_fix_interface(env, interface, interface->interface, s_environment_ref);
+
+ return scm_interface_environment_ref_fixed(env, sym);
+}
+
+static void
+no_interface_error(env, imported_environment, name)
+ SCM env;
+ SCM imported_environment;
+ char *name;
+{
+ scm_misc_error(name, "The export environment `%s' for `%s' doesn't have a signature.",
+ scm_listify(env, imported_environment,SCM_UNDEFINED));
+}
+
+/*
+ * iterate over all symbols mentioned in our interface
+ */
+static SCM
+scm_interface_environment_fold_fixed (env, proc, data, init)
+ SCM env;
+ scm_environment_folder proc;
+ SCM data;
+ SCM init;
+{
+ SCM ret_val;
+
+ struct interface_environment *interface_environment = SCM_INTERFACE_ENVIRONMENT_STRUCT(env);
+
+ if (interface_environment->aquisition)
+ {
+ no_interface_error(env, interface_environment->interface, s_environment_fold);
+ }
+ else
+ {
+ ret_val = scm_leaf_environment_fold (env, proc, data, init);
+ }
+
+ return ret_val;
+}
+static SCM
+scm_interface_environment_fold(env, proc, data, init)
+ SCM env;
+ scm_environment_folder proc;
+ SCM data;
+ SCM init;
+{
+ struct interface_environment *interface = SCM_INTERFACE_ENVIRONMENT_STRUCT(env);
+ interface_environment_fix_interface(env, interface, interface->interface, s_environment_fold);
+
+ return scm_interface_environment_fold_fixed(env, proc, data, init);
+}
+
+static SCM
+scm_interface_environment_define_fixed(env, sym, val)
+ SCM env;
+ SCM sym;
+ SCM val;
+{
+ scm_error_environment_immutable_bindings(s_environment_define, "", SCM_EOL, env, sym);
+ return 0;
+}
+
+static void
+scm_interface_environment_undefine_fixed(env, sym)
+ SCM env;
+ SCM sym;
+{
+ scm_error_environment_immutable_bindings(s_environment_undefine, "", SCM_EOL, env, sym);
+}
+
+static void
+scm_interface_environment_set_x_fixed (env, sym, val)
+ SCM env;
+ SCM sym;
+ SCM val;
+{
+ SCM vcell;
+
+ vcell = interface_environment_get_vcell(env, sym, 1, s_environment_set_x);
+
+ if (SCM_NIMP (vcell))
+ {
+ vcell = SCM_CELL_VAL (SCM_CDR (vcell));
+ SCM_SETCDR(vcell, val);
+ }
+ else
+ {
+ scm_error_environment_unbound(s_environment_set_x, "", SCM_EOL, env, sym);
+ }
+}
+static void
+scm_interface_environment_set_x(env, sym, val)
+ SCM env;
+ SCM sym;
+ SCM val;
+{
+ struct interface_environment *interface = SCM_INTERFACE_ENVIRONMENT_STRUCT(env);
+ interface_environment_fix_interface(env, interface, interface->interface, s_environment_set_x);
+
+ scm_interface_environment_set_x_fixed(env, sym, val);
+}
+
+static SCM
+scm_interface_environment_cell_fixed(env, sym, for_write)
+ SCM env;
+ SCM sym;
+ int for_write;
+{
+ SCM vcell = interface_environment_get_vcell(env, sym, for_write, s_environment_cell);
+
+ if (SCM_NIMP (vcell))
+ {
+ return SCM_CDR (vcell); /* (vcell . (list-of-tags)) */
+ }
+
+ return SCM_BOOL_F;
+}
+static SCM
+scm_interface_environment_cell(env, sym, for_write)
+ SCM env;
+ SCM sym;
+ int for_write;
+{
+ struct interface_environment *interface = SCM_INTERFACE_ENVIRONMENT_STRUCT(env);
+ interface_environment_fix_interface(env, interface, interface->interface, s_environment_cell);
+
+ return scm_interface_environment_cell_fixed(env, sym, for_write);
+}
+
+/*
+ * Do not respond to update requests until the environment
+ * is fixed.
+ */
+static void
+scm_interface_environment_update (env, caller, sym, old_cell, new_cell, name)
+ SCM env;
+ SCM caller;
+ SCM old_cell;
+ SCM new_cell;
+ char *name;
+{
+ abort();
+}
+
+/*
+ * Update the value of old_cell to the value of new_cell.
+ * - Do not update a value that has not been cached
+ * - old_cell == #f (remove all cells): re-build cache
+ * - new_cell == #f (remove cell): throw immutable-binding error
+ * - do not copy location tags (the location tag always stays the same)
+ * - throw an error on a request to change the location tag from
+ * mutable-location to immutable-location.
+ * - Always extract the interface and the exported name from the sig
+ */
+static void
+update_cell(env, sig, sym, obarray, old_cell, new_cell, name)
+ SCM env;
+ SCM sig;
+ SCM sym;
+ SCM old_cell;
+ SCM new_cell;
+ char *name;
+{
+ SCM vcell;
+ SCM tags = scm_assq(sym, SCM_CDR(sig));
+ short export_writeable;
+ scm_sizet scm_hash;
+ short new_cell_is_writeable;
+
+ if(SCM_IMP(tags)) return; /* nothing to update */
+
+ scm_hash = SCM_HASHCODE(sym);
+ tags = SCM_CDR(tags);
+
+ export_writeable = SCM_NIMP(scm_sloppy_memq (scm_sym_mutable_location, tags));
+ vcell = scm_symbol_get_handle (obarray, sym, scm_hash);
+
+ /* cache inconsistency? */
+ if (SCM_IMP(vcell)) abort();
+
+ /* if we receive $n$ requests through
+ different paths it may happen that
+ the cell is already updated */
+ if (SCM_CELL_VAL (SCM_CDR (vcell)) == SCM_CELL_VAL (new_cell)) return;
+
+ /* cache inconsistency? */
+ if (SCM_CELL_VAL (SCM_CDR (vcell)) != SCM_CELL_VAL (old_cell)) abort();
+
+ old_cell = SCM_CDR(vcell);
+
+ new_cell_is_writeable = SCM_MUTABLE_LOCATIONP (SCM_CELL_TAG (new_cell));
+ if (new_cell_is_writeable != export_writeable)
+ {
+ if (export_writeable)
+ {
+ /* the user decided to export a mutable location but
+ we received an immutable location. Throw an error. */
+
+ scm_error_environment_immutable_bindings(name, "", SCM_EOL, env, sym);
+ }
+ else
+ {
+ /* reset to old tag by constructing a new cell */
+ new_cell = scm_cons (SCM_CAR (new_cell), export_writeable ? scm_sym_mutable_location : scm_sym_immutable_location);
+ }
+ }
+ SCM_SETCDR (vcell, new_cell);
+}
+static void
+update_all_cells(interface, obarray, name)
+ SCM interface;
+ {
+ SCM l;
+ SCM s;
+
+ for(l = interface; SCM_NIMP(l); l = SCM_CDR(l))
+ {
+ SCM spec = SCM_CAR(l);
+ SCM env = SCM_CAR(spec);
+ SCM sig = SCM_CDR(spec);
+
+ for(s = sig; SCM_NIMP(s); s = SCM_CDR(s))
+ {
+ short new_cell_is_writeable;
+ SCM sym = SCM_CAAR(s);
+ SCM tags = SCM_CDAR(s);
+ scm_sizet scm_hash;
+ short export_writeable = SCM_NIMP(scm_sloppy_memq (scm_sym_mutable_location,tags));
+ SCM alias;
+ SCM new_cell;
+
+ alias = scm_sloppy_assq (scm_sym_alias, tags);
+ if(SCM_NIMP(alias))
+ {
+ alias = SCM_CADR(alias);
+ }
+ else
+ {
+ alias = sym;
+ }
+
+ new_cell = SCM_ENVIRONMENT_CELL(env, sym, 0);
+ if (SCM_IMP(new_cell))
+ {
+ scm_error_environment_unbound(name, "", SCM_EOL, env, sym);
+ }
+
+ new_cell_is_writeable = SCM_MUTABLE_LOCATIONP (SCM_CELL_TAG (new_cell));
+ if (new_cell_is_writeable != export_writeable)
+ {
+ if (export_writeable)
+ {
+ /* the user decided to export a mutable location but
+ we received an immutable location. Throw an error. */
+
+ scm_error_environment_immutable_bindings(name, "", SCM_EOL, env, sym);
+ }
+
+ /* reset to old tag by constructing a new cell */
+ new_cell = scm_cons (SCM_CAR (new_cell), export_writeable ? scm_sym_mutable_location : scm_sym_immutable_location);
+ }
+ /* copy to cache */
+ scm_hash = SCM_HASHCODE (alias);
+ scm_symbol_create_handle (obarray, alias, scm_hash, new_cell);
+ }
+ }
+ }
+static void
+scm_interface_environment_update_fixed (env, caller, sym, old_cell, new_cell, name)
+ SCM env;
+ SCM caller;
+ SCM old_cell;
+ SCM new_cell;
+ char *name;
+{
+ struct interface_environment *interface_environment = SCM_INTERFACE_ENVIRONMENT_STRUCT(env);
+ SCM obarray;
+
+ obarray = interface_environment->leaf.environment.obarray;
+
+ if(interface_environment->aquisition)
+ {
+ scm_symbol_remove_all_handles(obarray, scm_symhash_dim);
+ }
+ else
+ {
+ if (SCM_NIMP (old_cell))
+ {
+ SCM sig;
+
+ if (SCM_IMP(new_cell))
+ {
+ scm_error_environment_immutable_bindings(name, "", SCM_EOL, env, sym);
+ }
+
+ sig = scm_assq(caller, interface_environment->interface);
+ if (SCM_IMP (sig))
+ {
+ abort();
+ }
+ update_cell(env, sig, sym, obarray, old_cell, new_cell, name);
+ }
+ else
+ {
+ scm_symbol_remove_all_handles(obarray, scm_symhash_dim);
+ update_all_cells(interface_environment->interface, obarray, name);
+ }
+ }
+ /* environments should update their
+ caches */
+ scm_environment_broadcast (env, sym, old_cell, new_cell, name);
+}
+
+static SCM
+mark_interface_environment (env)
+ SCM env;
+{
+ struct interface_environment *interface_environment = SCM_INTERFACE_ENVIRONMENT_STRUCT(env);
+
+ if(SCM_NIMP(interface_environment->leaf.synapse))
+ {
+ mark_all_observer_smobs(SCM_VELTS(interface_environment->leaf.synapse)[1]);
+ scm_gc_mark(interface_environment->leaf.synapse);
+ }
+
+ scm_gc_mark (interface_environment->interface);
+ scm_gc_mark (interface_environment->conflict_proc);
+
+ return SCM_BOOL_F;
+}
+
+static scm_sizet
+free_interface_environment (env)
+ SCM env;
+{
+ struct interface_environment *interface_environment = SCM_INTERFACE_ENVIRONMENT_STRUCT(env);
+
+ scm_sizet size;
+
+ size = sizeof (struct interface_environment);
+
+ free (interface_environment);
+
+ return size;
+}
+
+static int
+print_interface_environment (SCM type, SCM port, scm_print_state *pstate)
+{
+ scm_puts ("#<incomplete interface environment ", port);
+ scm_puts (SCM_CHARS(scm_number_to_string(scm_ulong2num((unsigned long)type), SCM_MAKINUM (16))), port);
+ scm_puts (">", port);
+
+ return 1;
+}
+static int
+print_interface_environment_fixed (SCM type, SCM port, scm_print_state *pstate)
+{
+ scm_puts ("#<interface environment ", port);
+ scm_puts (SCM_CHARS(scm_number_to_string(scm_ulong2num((unsigned long)type), SCM_MAKINUM (16))), port);
+ scm_puts (">", port);
+
+ return 1;
+}
+
+static struct environment_funcs interface_environment_funcs_fixed = {
+ scm_interface_environment_ref_fixed,
+ scm_interface_environment_fold_fixed,
+ scm_interface_environment_define_fixed, /* throw error */
+ scm_interface_environment_undefine_fixed, /* throw error */
+ scm_interface_environment_set_x_fixed,
+ scm_interface_environment_cell_fixed,
+ scm_environment_observe_internal,
+ scm_environment_unobserve_internal,
+ mark_interface_environment,
+ free_interface_environment,
+ print_interface_environment_fixed
+};
+void *scm_type_interface_environment_fixed = &interface_environment_funcs_fixed;
+static struct environment_funcs interface_environment_funcs = {
+ scm_interface_environment_ref, /* fix it */
+ scm_interface_environment_fold, /* fix it */
+ scm_interface_environment_define_fixed, /* throw error */
+ scm_interface_environment_undefine_fixed, /* throw error */
+ scm_interface_environment_set_x, /* fix it */
+ scm_interface_environment_cell, /* fix it */
+ scm_environment_observe_internal,
+ scm_environment_unobserve_internal,
+ mark_interface_environment,
+ free_interface_environment,
+ print_interface_environment
+};
+void *scm_type_interface_environment = &interface_environment_funcs;
+
+/*
+ * parse something like this: (sym (alias a) mutable-location)
+ */
+static
+SCM syntax_parse_location_tags(tags_list, name, sym_ret, tags_ret)
+ SCM tags_list;
+ char *name;
+ SCM *sym_ret;
+ SCM *tags_ret;
+{
+ SCM alias_sym;
+ SCM tags = tags_list;
+
+ SCM_ASSERT(SCM_NIMP(tags), tags_list, SCM_ARG2, name);
+
+ if (SCM_SYMBOLP(tags))
+ {
+ alias_sym = *sym_ret = tags_list;
+ *tags_ret = SCM_EOL;
+
+ return alias_sym;
+ }
+ else
+ {
+ SCM_ASSERT(SCM_CONSP(tags), tags_list, SCM_ARG2, name);
+
+ alias_sym = *sym_ret = SCM_CAR(tags);
+ SCM_ASSERT(SCM_NIMP(alias_sym) && SCM_SYMBOLP(alias_sym), tags_list, SCM_ARG2, name);
+
+ *tags_ret = tags = SCM_CDR (tags);
+ }
+
+ for(; SCM_NIMP(tags); tags = SCM_CDR(tags))
+ {
+ SCM tag = SCM_CAR(tags);
+ if(SCM_NIMP(tag) && SCM_SYMBOLP(tag))
+ {
+ SCM_ASSERT((scm_sym_immutable_location == tag)
+ || (scm_sym_mutable_location == tag)
+ || (scm_sym_syntax == tag), tags_list, SCM_ARG2, name);
+ }
+ else
+ {
+ SCM sym_alias; /* the name "alias" */
+
+ SCM_ASSERT(SCM_NIMP(tag) &&
+ SCM_CONSP(tag) &&
+ SCM_NNULLP(SCM_CDR(tag)) &&
+ SCM_NULLP(SCM_CDDR(tag)), tags_list, SCM_ARG2, name);
+
+ sym_alias = SCM_CAR(tag);
+ SCM_ASSERT(scm_sym_alias == sym_alias, tags_list, SCM_ARG2, name);
+
+ alias_sym = SCM_CADR(tag);
+ SCM_ASSERT(SCM_NIMP(alias_sym) && SCM_SYMBOLP(alias_sym), tags_list, SCM_ARG2, name);
+ }
+ }
+
+ return alias_sym;
+}
+
+/*
+ * Copy all symbols and their values from parent.
+ */
+static SCM
+copy_from_parent(env, obarray, imported_obarray, imported_environment, conflict_proc, name)
+ SCM env;
+ SCM obarray;
+ SCM imported_environment;
+ scm_environment_conflict_proc conflict_proc;
+ char *name;
+{
+ scm_sizet i;
+ SCM signature_ret = SCM_EOL;
+
+ /* Can't use environment-fold because
+ we need the cell */
+ for (i=0; i<scm_symhash_dim; i++)
+ {
+ SCM lsym;
+
+ for (lsym = SCM_VELTS (imported_obarray)[i]; SCM_NIMP (lsym);
+ lsym = SCM_CDR (lsym))
+ {
+ SCM old_vcell;
+ SCM vcell = SCM_CAR (lsym);
+ SCM cell = SCM_CDR (vcell);
+ SCM sym = SCM_CAR(vcell);
+ SCM scm_hash = SCM_HASHCODE(sym);
+
+ signature_ret = scm_cons(SCM_LIST1(sym), signature_ret);
+
+ /* check for name clashes */
+ old_vcell = scm_symbol_get_handle (obarray, sym, scm_hash);
+ if (SCM_NIMP(old_vcell))
+ {
+ SCM old_cell = SCM_CDR(old_vcell);
+ if (SCM_CELL_VAL (old_cell) != SCM_CELL_VAL (cell))
+ {
+ (*conflict_proc) (scm_makfrom0str (name), sym, imported_environment, imported_environment);
+
+ }
+ if(SCM_CELL_TAG(old_cell) != SCM_CELL_TAG(cell))
+ {
+ scm_error_environment_conflicting_tags(name, "", SCM_EOL, env, sym);
+ }
+ }
+ else
+ {
+ /* copy to cache */
+ scm_symbol_create_handle (obarray, sym, scm_hash, cell);
+ }
+ }
+ }
+
+ return signature_ret;
+}
+
+/*
+ * parse the interface `imports' into obarray and return the
+ * parsed interface.
+ */
+static SCM
+interface_environment_parse_interface_internal (env, imports, obarray, conflict_proc, name)
+ SCM env;
+ SCM imports;
+ SCM obarray;
+ scm_environment_conflict_proc conflict_proc;
+ char *name;
+{
+ SCM signature_ret;
+ SCM interface_ret;
+ SCM sig;
+ SCM cell;
+ SCM imported_cell;
+ SCM import_list;
+ SCM old_vcell;
+
+ interface_ret = SCM_EOL;
+ /* traverse import list */
+ for (import_list = imports; SCM_NIMP (import_list); import_list = SCM_CDR (import_list))
+ {
+ scm_sizet scm_hash;
+ SCM imported_interface_env;
+ SCM spec;
+ SCM signature;
+
+
+ spec = SCM_CAR(import_list); /* (env ...) or (env . #f) */
+
+ imported_interface_env = SCM_CAR(spec);
+ SCM_ASSERT(SCM_NIMP(imported_interface_env) && SCM_ENVIRONMENTP(imported_interface_env),
+ imported_interface_env, SCM_ARG2, name);
+
+ /*
+ * get the signature
+ */
+ signature = SCM_CDR(spec);/* (sym ...) or #f */
+
+ if(SCM_BOOL_F == signature)
+ {
+ SCM signature_ret;
+ if(SCM_INTERFACE_ENVIRONMENTP(imported_interface_env) ||
+ (SCM_ENVIRONMENT_FUNCS(imported_interface_env) == scm_type_export_environment) ||
+ (SCM_ENVIRONMENT_FUNCS(imported_interface_env) == scm_type_import_environment))
+ {
+ /* delegate to parent */
+ struct interface_environment *interface_environment =
+ SCM_INTERFACE_ENVIRONMENT_STRUCT(imported_interface_env);
+
+ /* if it not fixed, fix it now! */
+ if(SCM_ENVIRONMENT_FUNCS(imported_interface_env) == scm_type_interface_environment)
+ {
+ interface_environment_fix_interface(imported_interface_env,
+ interface_environment,
+ interface_environment->interface,
+ name);
+ }
+
+ if(interface_environment->aquisition)
+ {
+ no_interface_error(env, imported_interface_env, name);
+ }
+
+ signature_ret = copy_from_parent(env,
+ obarray,
+ interface_environment->leaf.environment.obarray,
+ imported_interface_env,
+ conflict_proc, name);
+
+ interface_ret = scm_cons(scm_cons(imported_interface_env, signature_ret), interface_ret);
+ continue;
+ }
+ else
+ {
+ /* no signature: throw error */
+ no_interface_error(env, imported_interface_env, name);
+ }
+ }
+ else
+ { /* signature must be a list */
+ SCM_ASSERT((SCM_NIMP(signature) && SCM_CONSP(signature)) || SCM_NULLP(signature), signature, SCM_ARG2, name);
+ }
+
+ /*
+ * parse it
+ */
+ signature_ret = SCM_EOL;
+ for(sig = signature; SCM_NIMP(sig); sig = SCM_CDR(sig))
+ {
+ SCM alias;
+ SCM sym;
+ SCM tags;
+
+ alias = syntax_parse_location_tags(SCM_CAR(sig), name, &sym, &tags);
+ signature_ret = scm_cons(scm_cons(sym, tags), signature_ret);
+
+ /* find cell in environment */
+ cell = imported_cell = SCM_ENVIRONMENT_CELL(imported_interface_env, sym, 0);
+
+ if (SCM_NIMP (cell))
+ {
+ SCM old_tag;
+ int export_writeable;
+
+ /* check the location tag */
+ old_tag = SCM_CELL_TAG (cell);
+ export_writeable = SCM_NIMP(scm_sloppy_memq (scm_sym_mutable_location, tags));
+
+ if (export_writeable)
+ {
+ /* check if only one tag has been specified */
+ if (SCM_NIMP(scm_sloppy_memq (scm_sym_immutable_location, tags)))
+ {
+ scm_error_environment_conflicting_tags(name, "", SCM_EOL, env, sym);
+ }
+
+ /* throw error if old tag was immutable */
+ if (old_tag == scm_sym_immutable_location)
+ {
+ scm_error_environment_immutable_location(name, "", SCM_EOL, env, sym);
+ }
+ }
+ else
+ {
+ /* set immutable tag by constructing a new cell */
+ if (old_tag != scm_sym_immutable_location) /* SCM_EOL means: writable! */
+ {
+ cell = scm_cons (SCM_CAR (cell), scm_sym_immutable_location);
+
+ }
+ }
+ }
+ else
+ {
+ scm_error_environment_unbound(name, "", SCM_EOL, imported_interface_env, sym);
+ }
+
+ /*
+ * copy to cache
+ */
+ scm_hash = SCM_HASHCODE (alias);
+
+ /* check for name clashes */
+ old_vcell = scm_symbol_get_handle (obarray, alias, scm_hash);
+ if (SCM_NIMP(old_vcell))
+ {
+ SCM old_cell = SCM_CDR(old_vcell);
+ if (SCM_CELL_VAL (old_cell) != SCM_CELL_VAL (cell))
+ {
+ (*conflict_proc) (scm_makfrom0str (name), alias, imported_interface_env, imported_interface_env);
+
+ }
+ if(SCM_CELL_TAG(old_cell) != SCM_CELL_TAG(cell))
+ {
+ scm_error_environment_conflicting_tags(name, "", SCM_EOL, env, alias);
+ }
+ }
+ else
+ {
+ /* copy to cache */
+ scm_symbol_create_handle (obarray, alias, scm_hash, cell);
+ }
+ }
+ interface_ret = scm_cons(scm_cons(imported_interface_env, signature_ret), interface_ret);
+ }
+ return interface_ret;
+}
+
+/*
+ * same as parse_interface but also handles aquisition
+ */
+static SCM
+interface_environment_parse_interface (env, interface_environment, imports, obarray, name)
+ SCM env;
+ struct interface_environment *interface_environment;
+ SCM imports;
+ SCM obarray;
+ char *name;
+{
+ SCM parsed_interface;
+
+ if(!interface_environment->aquisition)
+ {
+ if (interface_environment->aquisition == -1) abort(); /* Unknown!?! */
+
+ parsed_interface =
+ interface_environment_parse_interface_internal(env,
+ imports,
+ obarray,
+ interface_environment->c_conflict_proc,
+ name);
+ }
+ else
+ {
+ /* nothing to parse */
+ parsed_interface = imports;
+ }
+
+ return parsed_interface;
+}
+
+/*
+ * fixit_args, fixit, fixit_rewind, fixit_failed,
+ * interface_environment_fix_interface, scm_interface_environment_ref,
+ * scm_interface_environment_fold, scm_interface_environment_set_x,
+ * scm_interface_environment_cell: Initially lookup bindings, resolve
+ * name clashes and make sure that during interface-env's lifetime these
+ * functions will never be called again.
+ *
+ */
+
+
+static short update_running = 0; /* sanity check */
+struct fixit_args
+{
+ SCM env;
+ struct interface_environment *interface_environment;
+ SCM interface;
+ SCM old_interface;
+ struct environment_funcs *old_environment_funcs;
+ char *name;
+};
+
+/*
+ * Observe all environments mentioned in interface
+ */
+static void
+interface_environment_observe_interface(env, interface, name)
+ SCM env;
+ SCM interface;
+ char *name;
+{
+ SCM node;
+ /* connect to all imported_env. Will be
+ dropped when env disappears. */
+ for (node = interface; SCM_NIMP (node); node = SCM_CDR (node))
+ {
+ SCM spec;
+ SCM imported_environment;
+
+ /* (env ...) or (env . #f) */
+ spec = SCM_CAR(node);
+ SCM_ASSERT(SCM_NIMP(spec) && SCM_CONSP(spec), spec, SCM_ARG2, name);
+
+ imported_environment = SCM_CAR(spec);
+ SCM_ASSERT(SCM_NIMP(imported_environment) && SCM_ENVIRONMENTP(imported_environment), imported_environment, SCM_ARG2, name);
+
+
+ SCM_ENVIRONMENT_OBSERVE (imported_environment,
+ environment_update_dummy_observer,
+ env, 1);
+ }
+}
+
+/*
+ * Drop env's old observers from interface_environment's observer list
+ * */
+static void
+interface_environment_drop_old_observers(env, interface_environment)
+ SCM env;
+ struct interface_environment *interface_environment;
+{
+ SCM node;
+
+ /* remove my old observers */
+ for (node = interface_environment->interface; SCM_NIMP(node); node = SCM_CDR(node))
+ {
+ /* tell environment to remove me from
+ its list */
+ scm_drop_internal_observer(SCM_CAAR(node), env);
+ }
+
+}
+
+/*
+ * check for aquisition
+ */
+static short
+aquisition(interface, name)
+ SCM interface;
+ char *name;
+{
+ SCM l;
+ long length = scm_ilength(interface);
+ SCM_ASSERT(length >=0, interface, SCM_ARG1, name);
+
+ for (l = interface; SCM_NIMP(l); l = SCM_CDR(l))
+ {
+ SCM spec;
+ SCM environment;
+
+ spec = SCM_CAR(l);
+ SCM_ASSERT(SCM_NIMP(spec) && SCM_CONSP(spec), interface, SCM_ARG1, name);
+
+ environment = SCM_CAR(spec);
+ SCM_ASSERT(SCM_NIMP(environment) && SCM_ENVIRONMENTP(environment), interface, SCM_ARG1, name);
+
+ if(SCM_BOOL_T == SCM_CDR(spec))
+ {
+ SCM_ASSERT(length = 1, interface, SCM_ARG1, name);
+
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * try
+ */
+static SCM
+fixit(void *p)
+{
+ SCM parsed_interface;
+ struct fixit_args *u = (struct fixit_args*)p;
+
+ if(u->interface_environment->empty != 1) abort();
+
+ update_running++;
+
+ u->interface_environment->aquisition = aquisition(u->interface, u->name);
+ parsed_interface = interface_environment_parse_interface(u->env,
+ u->interface_environment,
+ u->interface,
+ u->interface_environment->leaf.environment.obarray,
+ u->name);
+
+ u->interface_environment->interface = parsed_interface;
+ u->interface_environment->leaf.environment.environment_funcs = &interface_environment_funcs_fixed;
+ u->interface_environment->leaf.update = scm_interface_environment_update_fixed;
+
+ /* Because we've been an incomplete interface environment we don't
+ have listeners yet. So don't call environment-update() at this point! */
+
+ /* now we're ready to receive update
+ requests */
+ interface_environment_observe_interface(u->env, u->interface, u->name);
+
+ update_running--;
+
+ return SCM_UNSPECIFIED;
+}
+
+/*
+ * re-construct old state after either parse_interface or
+ * scm_environment_broadcast failed
+ */
+static SCM
+fixit_rewind(void *p)
+{
+ struct fixit_args *u = (struct fixit_args*)p;
+
+ scm_symbol_remove_all_handles(u->interface_environment->leaf.environment.obarray, scm_symhash_dim);
+
+ u->interface_environment->interface = u->old_interface;
+ u->interface_environment->aquisition = -1; /* Unknown */
+
+ u->interface_environment->leaf.environment.environment_funcs = u->old_environment_funcs;
+ u->interface_environment->leaf.update = scm_interface_environment_update;
+
+ update_running --;
+
+ return SCM_UNSPECIFIED;
+}
+
+/*
+ * back to old state or abort()
+ */
+static SCM
+fixit_failed(void *p, SCM tag, SCM args)
+{
+ scm_internal_catch(SCM_BOOL_T, fixit_rewind, p, (scm_catch_handler_t)abort, 0);
+
+ scm_ithrow(tag, args, 1);
+
+ abort();
+
+ return 0;
+}
+
+/*
+ * interface_environment_fix_interface: fix env's interface, once and
+ * for all
+ */
+static SCM
+interface_environment_fix_interface(env, interface_environment, imports, name)
+ SCM env;
+ struct interface_environment *interface_environment;
+ SCM imports;
+ char *name;
+{
+ struct fixit_args fixit_args;
+
+ /* abort if fixed */
+ if(interface_environment->leaf.environment.environment_funcs != scm_type_interface_environment)
+ {
+ abort();
+ }
+
+ fixit_args.env = env;
+ fixit_args.interface_environment = interface_environment;
+ fixit_args.interface = imports;
+ fixit_args.old_interface = interface_environment->interface;
+ fixit_args.old_environment_funcs = interface_environment->leaf.environment.environment_funcs;
+ fixit_args.name = name;
+
+ scm_internal_catch(SCM_BOOL_T, fixit, &fixit_args, fixit_failed, &fixit_args);
+
+ interface_environment->empty = 0;
+ return interface_environment->interface;
+}
+
+static SCM
+make_interface_environment(interface_environment, interface, name)
+ struct interface_environment *interface_environment;
+ SCM interface;
+ char *name;
+{
+ SCM interface_environment_smob;
+
+ interface_environment->leaf.environment.environment_funcs = scm_type_interface_environment;
+
+ interface_environment->aquisition = -1; /* Unknown */
+ interface_environment->interface = interface;
+
+ interface_environment->leaf.synapse = SCM_BOOL_F;
+ interface_environment->leaf.update = scm_interface_environment_update;
+
+ interface_environment_smob = scm_make_environment(interface_environment, scm_symhash_dim);
+
+ interface_environment->empty = 1;
+
+ interface_environment->leaf.synapse = scm_make_weak_vector(SCM_MAKINUM(2), SCM_EOL);
+ SCM_VELTS(interface_environment->leaf.synapse)[0] = interface_environment_smob;
+
+ return interface_environment_smob;
+}
+
+SCM_PROC(s_make_interface_environment, "make-interface-environment", 1, 0, 0, scm_make_interface_environment);
+SCM
+scm_make_interface_environment (interface)
+ SCM interface;
+{
+ SCM interface_environment_smob;
+ struct interface_environment *interface_environment;
+
+ SCM_ASSERT(SCM_NULLP(interface) || SCM_NIMP(interface), interface, SCM_ARG1, s_make_interface_environment);
+
+ interface_environment =
+ scm_must_malloc (sizeof *interface_environment, s_make_interface_environment);
+
+ interface_environment->c_conflict_proc = scm_interface_environment_conflict_proc;
+ interface_environment->conflict_proc = SCM_EOL;
+
+ interface_environment_smob = make_interface_environment (interface_environment, interface, s_make_interface_environment);
+
+ return interface_environment_smob;
+}
+
+SCM_PROC(s_interface_environment_p, "interface-environment?", 1, 0, 0, scm_interface_environment_p);
+SCM
+scm_interface_environment_p (env)
+ SCM env;
+{
+ return SCM_NIMP(env) && SCM_ENVIRONMENTP(env) &&
+ SCM_INTERFACE_ENVIRONMENTP(env) ? SCM_BOOL_T : SCM_BOOL_F;
+}
+
+SCM_PROC(s_interface_environment_interface, "interface-environment-interface", 1, 0, 0, scm_interface_environment_interface);
+SCM
+scm_interface_environment_interface (env)
+ SCM env;
+{
+ struct interface_environment *interface_environment;
+ SCM computed_interface;
+
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env) && SCM_INTERFACE_ENVIRONMENTP(env), env, SCM_ARG1, s_interface_environment_interface);
+
+ interface_environment = SCM_INTERFACE_ENVIRONMENT_STRUCT(env);
+
+ /* if not fixed, fix it */
+ computed_interface = (interface_environment->leaf.environment.environment_funcs != scm_type_interface_environment) ?
+ interface_environment->interface :
+ interface_environment_fix_interface(env, interface_environment,
+ interface_environment->interface,
+ s_interface_environment_interface);
+
+ return computed_interface;
+}
+
+/*
+ * update_args, update, update_rewind, update_failed,
+ * interface_environment_set_interface,
+ * scm_interface_environment_set_interface: Set a new interface for
+ * environment `env'. We must send an update broadcast to all
+ * observers if `env's interface has been fixed. This code will
+ * call fix_interface through environment_update_internal's
+ * lookup method.
+ */
+SCM_PROC(s_interface_environment_set_interface_x, "interface-environment-set-interface!", 2, 0, 0, scm_interface_environment_set_interface_x);
+
+struct update_args
+{
+ SCM env;
+ SCM old_interface;
+ SCM old_aquisition;
+ SCM interface;
+ SCM aquisition;
+ struct interface_environment *interface_environment;
+};
+
+/*
+ * try
+ */
+static SCM
+update(void *p)
+{
+ SCM parsed_interface;
+ struct update_args *u = (struct update_args*)p;
+
+ u->interface_environment->aquisition = u->aquisition;
+
+ /* abort if incomplete */
+ if(u->interface_environment->leaf.environment.environment_funcs == scm_type_interface_environment) abort();
+
+ if(update_running != 0) abort();
+
+ update_running = 1;
+
+ SWAP(u->interface_environment->leaf.environment.obarray,
+ UPDATE_EMPTY_OBARRAY);
+ /* parse the signature */
+ parsed_interface =
+ interface_environment_parse_interface(u->env,
+ u->interface_environment,
+ u->interface,
+ u->interface_environment->leaf.environment.obarray,
+ s_interface_environment_set_interface_x);
+
+ /* environments should update their
+ caches: "hey, look at my new cool
+ interface" */
+ u->interface_environment->interface = parsed_interface;
+ scm_environment_broadcast (u->env, SCM_BOOL_F, SCM_BOOL_F, SCM_BOOL_F, s_interface_environment_set_interface_x);
+
+ scm_symbol_remove_all_handles(UPDATE_EMPTY_OBARRAY, scm_symhash_dim);
+
+ /* now we're ready to receive update
+ requests for the new interface */
+ interface_environment_drop_old_observers(u->env, u->interface_environment);
+ interface_environment_observe_interface(u->env, u->interface, s_interface_environment_set_interface_x);
+
+ update_running --;
+
+
+ return SCM_UNSPECIFIED;
+}
+
+/*
+ * re-construct old state after either parse_interface or
+ */
+static SCM
+update_rewind(void *p)
+{
+ struct update_args *u = (struct update_args*)p;
+
+ SWAP(u->interface_environment->leaf.environment.obarray,
+ UPDATE_EMPTY_OBARRAY);
+
+ u->interface_environment->interface = u->old_interface;
+ u->interface_environment->aquisition = u->old_aquisition;
+
+ scm_symbol_remove_all_handles(UPDATE_EMPTY_OBARRAY, scm_symhash_dim);
+
+ /* back to the old observer list */
+ interface_environment_drop_old_observers(u->env, u->interface_environment);
+ interface_environment_observe_interface(u->env, u->old_interface, s_interface_environment_set_interface_x);
+
+ /* environments should update their
+ caches */
+ scm_environment_broadcast (u->env, SCM_BOOL_F, SCM_BOOL_F, SCM_BOOL_F, s_interface_environment_set_interface_x);
+
+ update_running --;
+
+ return SCM_UNSPECIFIED;
+}
+
+/*
+ * back to old state or abort()
+ */
+static SCM
+update_failed(void *p, SCM tag, SCM args)
+{
+ scm_internal_catch(SCM_BOOL_T, update_rewind, p, (scm_catch_handler_t)abort, 0);
+
+ if(update_running != 0) abort();
+
+ scm_ithrow(tag, args, 1);
+
+ abort();
+
+ return 0;
+}
+
+/*
+ * Set a new interface for env/interface_environment
+ */
+static void
+interface_environment_set_interface(env, interface_environment, interface)
+ SCM env;
+ struct interface_environment *interface_environment;
+ SCM interface;
+{
+
+ if(interface_environment->leaf.environment.environment_funcs != scm_type_interface_environment)
+ { /* fixed interface, either interface-, export- or import-environment */
+ struct update_args update_args;
+
+ update_args.env = env;
+ update_args.interface = interface;
+ update_args.aquisition = aquisition(interface);
+ update_args.interface_environment = interface_environment;
+
+ update_args.old_interface = interface_environment->interface;
+ update_args.old_aquisition = interface_environment->aquisition;
+
+ scm_internal_catch(SCM_BOOL_T, update, &update_args, update_failed, &update_args);
+ }
+ else
+ {
+ interface_environment->interface = interface;
+ }
+}
+
+SCM
+scm_interface_environment_set_interface_x (env, interface)
+ SCM env;
+ SCM interface;
+{
+ struct interface_environment *interface_environment;
+
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env) && SCM_INTERFACE_ENVIRONMENTP(env), env, SCM_ARG1, s_interface_environment_interface);
+ SCM_ASSERT((SCM_NIMP(interface) && SCM_CONSP(interface)) || SCM_NULLP(interface), interface, SCM_ARG2, s_interface_environment_set_interface_x);
+
+ interface_environment = SCM_INTERFACE_ENVIRONMENT_STRUCT(env);
+
+ interface_environment_set_interface(env, interface_environment, interface);
+
+ return interface_environment->interface;
+}
+
+
+/* export environments */
+
+static int
+print_export_environment (SCM type, SCM port, scm_print_state *pstate)
+{
+ scm_puts ("#<export environment ", port);
+ scm_puts (SCM_CHARS(scm_number_to_string(scm_ulong2num((unsigned long)type), SCM_MAKINUM (16))), port);
+ scm_puts (">", port);
+
+ return 1;
+}
+
+static struct environment_funcs export_environment_funcs = {
+ scm_interface_environment_ref_fixed,
+ scm_interface_environment_fold_fixed,
+ scm_interface_environment_define_fixed,
+ scm_interface_environment_undefine_fixed,
+ scm_interface_environment_set_x_fixed,
+ scm_interface_environment_cell_fixed,
+ scm_environment_observe_internal,
+ scm_environment_unobserve_internal,
+ mark_interface_environment,
+ free_interface_environment,
+ print_export_environment
+};
+void *scm_type_export_environment = &export_environment_funcs;
+
+SCM_PROC(s_make_export_environment, "make-export-environment", 2, 0, 0, scm_make_export_environment);
+SCM
+scm_make_export_environment (private, signature)
+ SCM private;
+ SCM signature;
+{
+ SCM interface_environment_smob;
+ struct interface_environment *interface_environment;
+
+ SCM_ASSERT(SCM_NIMP(private) && SCM_ENVIRONMENTP(private), private, SCM_ARG1, s_make_export_environment);
+ SCM_ASSERT(SCM_NIMP(signature) && (SCM_CONSP(signature) || SCM_NULLP(signature)), signature, SCM_ARG2, s_make_export_environment);
+
+ interface_environment =
+ scm_must_malloc (sizeof *interface_environment, s_make_export_environment);
+
+ interface_environment->c_conflict_proc = scm_interface_environment_conflict_proc;
+ interface_environment->conflict_proc = SCM_EOL;
+
+ interface_environment_smob =
+ make_interface_environment (interface_environment,
+ SCM_LIST1(scm_cons(private, signature)),
+ s_make_export_environment);
+
+ /* now fix it */
+ interface_environment_fix_interface(interface_environment_smob,
+ interface_environment,
+ interface_environment->interface,
+ s_make_export_environment);
+
+ interface_environment->leaf.environment.environment_funcs = scm_type_export_environment;
+
+ return interface_environment_smob;
+}
+
+SCM_PROC(s_export_environment_private, "export-environment-private", 1, 0, 0, scm_export_environment_private);
+
+SCM
+scm_export_environment_private (env)
+ SCM env;
+{
+ struct interface_environment *interface_environment;
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env) && SCM_EXPORT_ENVIRONMENTP(env), env, SCM_ARG1, s_export_environment_private);
+
+ interface_environment = SCM_INTERFACE_ENVIRONMENT_STRUCT(env);
+
+ return SCM_CAAR(interface_environment->interface);
+}
+
+SCM_PROC(s_export_environment_set_private_x, "export-environment-set-private!", 2, 0, 0, scm_export_environment_set_private_x);
+
+SCM
+scm_export_environment_set_private_x (env, private)
+ SCM env;
+ SCM private;
+{
+ struct interface_environment *interface_environment;
+ SCM old_signature_list;
+
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env), env, SCM_ARG1, s_export_environment_set_private_x);
+ SCM_ASSERT(SCM_NIMP(private) && SCM_ENVIRONMENTP(private), private, SCM_ARG2, s_export_environment_set_private_x);
+
+ interface_environment = SCM_INTERFACE_ENVIRONMENT_STRUCT(env);
+ old_signature_list = SCM_CDR(interface_environment->interface);
+
+ interface_environment_set_interface(env, scm_cons(private, old_signature_list), interface_environment);
+
+ return SCM_UNSPECIFIED;
+}
+
+SCM_PROC(s_export_environment_signature, "export-environment-signature", 1, 0, 0, scm_export_environment_signature);
+
+SCM
+scm_export_environment_signature (env)
+ SCM env;
+{
+
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env) && SCM_EXPORT_ENVIRONMENTP(env), env, SCM_ARG1, s_export_environment_signature);
+
+ return SCM_INTERFACE_ENVIRONMENT_INTERFACE(env);
+}
+
+SCM_PROC(s_export_environment_set_signature_x, "export-environment-set-signature!", 2, 0, 0, scm_export_environment_set_signature_x);
+
+SCM
+scm_export_environment_set_signature_x (env, interface)
+ SCM env;
+ SCM interface;
+{
+ struct interface_environment *interface_environment;
+ SCM old_private;
+
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env) && SCM_EXPORT_ENVIRONMENTP(env), env, SCM_ARG1, s_export_environment_set_signature_x);
+ SCM_ASSERT(SCM_NIMP(interface) && (SCM_CONSP(interface) || SCM_NULLP(interface)), interface, SCM_ARG2, s_export_environment_set_signature_x);
+
+ interface_environment = SCM_INTERFACE_ENVIRONMENT_STRUCT(env);
+ old_private = SCM_CAAR(interface_environment->interface);
+
+ interface_environment_set_interface(env, scm_cons(scm_cons(old_private, interface), SCM_EOL), interface_environment);
+
+ return SCM_UNSPECIFIED;
+}
+
+SCM_PROC(s_export_environment_p, "export-environment?", 1, 0, 0, scm_export_environment_p);
+SCM
+scm_export_environment_p (env)
+ SCM env;
+{
+ return SCM_NIMP(env) && SCM_ENVIRONMENTP(env) &&
+ SCM_EXPORT_ENVIRONMENTP(env) ? SCM_BOOL_T : SCM_BOOL_F;
+}
+
+
+
+/* import environments */
+
+static int
+print_import_environment (SCM type, SCM port, scm_print_state *pstate)
+{
+ scm_puts ("#<import environment ", port);
+ scm_puts (SCM_CHARS(scm_number_to_string(scm_ulong2num((unsigned long)type), SCM_MAKINUM (16))), port);
+ scm_puts (">", port);
+
+ return 1;
+}
+
+static struct environment_funcs import_environment_funcs = {
+ scm_interface_environment_ref_fixed,
+ scm_interface_environment_fold_fixed,
+ scm_interface_environment_define_fixed,
+ scm_interface_environment_undefine_fixed,
+ scm_interface_environment_set_x_fixed,
+ scm_interface_environment_cell_fixed,
+ scm_environment_observe_internal,
+ scm_environment_unobserve_internal,
+ mark_interface_environment,
+ free_interface_environment,
+ print_import_environment
+};
+void *scm_type_import_environment = &import_environment_funcs;
+
+SCM_PROC(s_make_import_environment, "make-import-environment", 2, 0, 0, scm_make_import_environment);
+SCM
+scm_make_import_environment (imports, conflict_proc)
+ SCM imports;
+ SCM conflict_proc;
+{
+ SCM list;
+ SCM interface_imports;
+ SCM interface_environment_smob;
+ struct interface_environment *interface_environment;
+
+ SCM_ASSERT(SCM_NIMP(imports) && (SCM_CONSP(imports) || SCM_NULLP(imports)), imports, SCM_ARG2, s_make_import_environment);
+
+ interface_imports = SCM_EOL;
+ for (list = imports; SCM_NIMP(list); list = SCM_CDR(list))
+ {
+ SCM interface_env = SCM_CAR(list);
+ SCM_ASSERT(SCM_NIMP(interface_env) && SCM_ENVIRONMENTP(interface_env), interface_env, SCM_ARG1, s_make_import_environment);
+ interface_imports = scm_cons(scm_cons(interface_env, SCM_BOOL_F), interface_imports);
+ }
+
+ interface_environment =
+ scm_must_malloc (sizeof *interface_environment, s_make_import_environment);
+
+ interface_environment->c_conflict_proc = gh_call3;
+ interface_environment->conflict_proc = conflict_proc;
+
+ interface_environment_smob =
+ make_interface_environment (interface_environment,
+ interface_imports,
+ s_make_import_environment);
+
+ /* now fix it */
+ interface_environment_fix_interface(interface_environment_smob,
+ interface_environment,
+ interface_imports,
+ s_make_import_environment);
+
+ interface_environment->leaf.environment.environment_funcs = scm_type_import_environment;
+
+ return interface_environment_smob;
+}
+
+SCM_PROC(s_import_environment_p, "import-environment?", 1, 0, 0, scm_import_environment_p);
+SCM
+scm_import_environment_p (env)
+ SCM env;
+{
+ return SCM_NIMP(env) && SCM_ENVIRONMENTP(env) &&
+ SCM_IMPORT_ENVIRONMENTP(env) ? SCM_BOOL_T : SCM_BOOL_F;
+}
+
+SCM_PROC(s_import_environment_imports, "import-environment-imports", 1, 0, 0, scm_import_environment_imports);
+SCM
+scm_import_environment_imports (env)
+ SCM env;
+{
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env) && SCM_IMPORT_ENVIRONMENTP(env), env, SCM_ARG1, s_import_environment_imports);
+
+ return SCM_INTERFACE_ENVIRONMENT_INTERFACE(env);
+}
+
+SCM_PROC(s_import_environment_set_imports_x, "import-environment-set-imports!", 2, 0, 0, scm_import_environment_set_imports_x);
+SCM
+scm_import_environment_set_imports_x (env, imports)
+ SCM env;
+ SCM imports;
+{
+ SCM list;
+ SCM interface_imports;
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env) && SCM_EXPORT_ENVIRONMENTP(env), env, SCM_ARG1, s_import_environment_set_imports_x);
+ SCM_ASSERT(SCM_NIMP(imports) && (SCM_CONSP(imports) || SCM_NULLP(imports)), imports, SCM_ARG2, s_import_environment_set_imports_x);
+
+
+ interface_imports = SCM_EOL;
+ for (list = imports; SCM_NIMP(list); list = SCM_CDR(list))
+ {
+ SCM interface_env = SCM_CAR(list);
+ SCM_ASSERT(SCM_NIMP(interface_env) && SCM_ENVIRONMENTP(interface_env), env, SCM_ARG1, s_make_import_environment);
+ interface_imports = scm_cons(scm_cons(interface_env, SCM_BOOL_F), interface_imports);
+ }
+
+ interface_environment_set_interface(env, SCM_INTERFACE_ENVIRONMENT_STRUCT(env), interface_imports);
+
+ return SCM_UNSPECIFIED;
+}
+
+
+
+/*
+ * intern a symbol in environment env
+ */
+SCM
+scm_environment_intern (env, name, val)
+ SCM env;
+ char *name;
+ SCM val;
+{
+ SCM vcell;
+ SCM sym;
+
+
+ vcell = scm_intern (name);
+ sym = SCM_CAR(vcell);
+
+ return SCM_ENVIRONMENT_DEFINE(env, sym, val);
+}
+
+
+/* Miscellaneous */
+
+/* according to r5rs `load' evaluates expressions in the interaction
+ environment */
+SCM_PROC(s_set_interaction_environment_x, "set-interaction-environment!", 1, 0, 0, scm_set_interaction_environment_x);
+SCM
+scm_set_interaction_environment_x (env)
+ SCM env;
+{
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env) && SCM_EVAL_ENVIRONMENTP(env), env, SCM_ARG1, s_set_interaction_environment_x);
+
+ SCM_DEFER_INTS;
+ scm_interaction_environment = env;
+ SCM_ALLOW_INTS;
+
+ return SCM_UNSPECIFIED;
+}
+
+SCM_PROC(s_interaction_environment, "interaction-environment", 0, 0, 0, scm_interaction_environment_proc);
+SCM
+scm_interaction_environment_proc ()
+{
+ return scm_interaction_environment;
+}
+
+SCM_PROC(s_scheme_guile_environment, "scheme-guile-environment", 0, 1, 0, scm_scheme_guile_environment_proc);
+SCM
+scm_scheme_guile_environment_proc (version)
+ SCM version;
+{
+ SCM_ASSERT(SCM_INUMP(version), version, SCM_ARG1, s_scheme_guile_environment);
+
+ return scm_scheme_guile_environment;
+}
+
+SCM_PROC(s_null_environment, "null-environment", 0, 1, 0, scm_null_environment_proc);
+SCM
+scm_null_environment_proc (version)
+ SCM version;
+{
+ SCM_ASSERT(SCM_INUMP(version), version, SCM_ARG1, s_null_environment);
+
+ return scm_scheme_guile_environment;
+}
+
+SCM_PROC(s_guile_user_environment, "guile-user-environment", 0, 1, 0, scm_guile_user_environment_proc);
+SCM
+scm_guile_user_environment_proc (version)
+ SCM version;
+{
+ SCM_ASSERT(SCM_INUMP(version), version, SCM_ARG1, s_guile_user_environment);
+
+ return scm_guile_user_environment;
+}
+
+SCM_PROC(s_module_registry, "module-registry", 0, 0, 0, scm_module_registry_proc);
+SCM
+scm_module_registry_proc ()
+{
+ return scm_module_registry;
+}
+
+SCM_PROC(s_c_module_registry, "c-module-registry", 0, 0, 0, scm_c_module_registry_proc);
+SCM
+scm_c_module_registry_proc ()
+{
+ return scm_c_module_registry;
+}
+
+SCM_PROC(s_environment_module_hash, "environment-module-hash", 0, 0, 0, scm_environment_module_hash_proc);
+SCM
+scm_environment_module_hash_proc ()
+{
+ return scm_environment_module_hash;
+}
+
+
+
+SCM_PROC(s_environment_set_symbol_property_x, "environment-set-symbol-property!", 4, 0, 0, scm_environment_set_symbol_property_x);
+SCM
+scm_environment_set_symbol_property_x(env, sym, prop, val)
+ SCM env;
+ SCM sym;
+ SCM prop;
+ SCM val;
+{
+ SCM list;
+ SCM pair;
+ SCM cell;
+
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env), env, SCM_ARG1, s_environment_set_symbol_property_x);
+ SCM_ASSERT(SCM_NIMP(sym) && SCM_SYMBOLP(sym), sym, SCM_ARG2, s_environment_set_symbol_property_x);
+ SCM_ASSERT(SCM_NIMP(prop) && SCM_SYMBOLP(prop), prop, SCM_ARG3, s_environment_set_symbol_property_x);
+
+
+ cell = SCM_ENVIRONMENT_CELL (env, sym, 0);
+
+ if(SCM_IMP(cell))
+ {
+ scm_error_environment_unbound (s_environment_set_symbol_property_x, "", SCM_EOL, env, sym);
+ }
+
+ list = SCM_CELL_PROPERTY_ALIST (cell);
+ pair = scm_sloppy_assq (prop, list);
+
+ if (SCM_NIMP (pair))
+ {
+ if (SCM_CONSP (pair))
+ {
+ SCM_SETCDR (pair, val);
+ }
+ }
+ else
+ {
+ SCM_SETCDR (SCM_CAR (cell), scm_acons (prop, val, list));
+ }
+
+ return SCM_UNSPECIFIED;
+}
+
+SCM_PROC(s_environment_symbol_property, "environment-symbol-property", 3, 0, 0, scm_environment_symbol_property);
+SCM
+scm_environment_symbol_property(env, sym, prop)
+ SCM env;
+ SCM sym;
+ SCM prop;
+{
+ SCM list;
+ SCM pair;
+ SCM cell;
+
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env), env, SCM_ARG1, s_environment_symbol_property);
+ SCM_ASSERT(SCM_NIMP(sym) && SCM_SYMBOLP(sym), sym, SCM_ARG2, s_environment_symbol_property);
+ SCM_ASSERT(SCM_NIMP(prop) && SCM_SYMBOLP(prop), prop, SCM_ARG3, s_environment_symbol_property);
+
+ cell = SCM_ENVIRONMENT_CELL (env, sym, 0);
+
+ if(SCM_IMP(cell))
+ {
+ scm_error_environment_unbound (s_environment_symbol_property, "", SCM_EOL, env, sym);
+ }
+
+ list = SCM_CELL_PROPERTY_ALIST (cell);
+ pair = scm_sloppy_assq (prop, list);
+
+ return pair;
+}
+
+SCM_PROC(s_environment_remove_symbol_property_x, "environment-remove-symbol-property!", 3, 0, 0, scm_environment_remove_symbol_property_x);
+SCM
+scm_environment_remove_symbol_property_x(env, sym, prop)
+ SCM env;
+ SCM sym;
+ SCM prop;
+{
+ SCM list;
+ SCM cell;
+
+ SCM_ASSERT(SCM_NIMP(env) && SCM_ENVIRONMENTP(env), env, SCM_ARG1, s_environment_remove_symbol_property_x);
+ SCM_ASSERT(SCM_NIMP(sym) && SCM_SYMBOLP(sym), sym, SCM_ARG2, s_environment_remove_symbol_property_x);
+ SCM_ASSERT(SCM_NIMP(prop) && SCM_SYMBOLP(prop), prop, SCM_ARG3, s_environment_remove_symbol_property_x);
+
+ cell = SCM_ENVIRONMENT_CELL (env, sym, 0);
+
+ if(SCM_IMP(cell))
+ {
+ scm_error_environment_unbound (s_environment_remove_symbol_property_x, "", SCM_EOL, env, sym);
+ }
+
+ list = SCM_CELL_PROPERTY_ALIST (cell);
+
+ SCM_SETCDR (SCM_CAR (cell), scm_assq_remove_x (list, prop));
+
+
+ return SCM_UNSPECIFIED;
+}
+
+void
+scm_environments_prehistory()
+{
+ /* create observer smob */
+ scm_tc16_observer = scm_newsmob(&observer_funs);
+
+ /* create default environment */
+ scm_tc16_environment = scm_newsmob (&environment_funs);
+ scm_interaction_environment = scm_scheme_guile_environment =
+ scm_make_eval_environment (scm_make_leaf_environment(), scm_make_interface_environment(SCM_EOL));
+
+ scm_c_module_registry = scm_make_leaf_environment();
+
+ scm_module_registry = scm_make_leaf_environment();
+ scm_environment_module_hash = scm_make_doubly_weak_hash_table(SCM_MAKINUM (32));
+
+ /* create the user environment */
+ scm_guile_user_environment =
+ scm_make_eval_environment (scm_make_leaf_environment(),
+ scm_make_interface_environment(SCM_LIST1 (scm_cons (scm_scheme_guile_environment, SCM_BOOL_T))));
+
+ /* create supporting data structures */
+ protect_vec = scm_make_vector(SCM_MAKINUM(1), SCM_UNDEFINED);
+ scm_permanent_object(protect_vec);
+
+ UPDATE_EMPTY_OBARRAY = scm_make_vector((SCM) SCM_MAKINUM (scm_symhash_dim), SCM_EOL);
+}
+
+SCM
+scm_init_environments (env)
+ SCM env;
+{
+#include "environments.x"
+
+ return SCM_UNSPECIFIED;
+}
diff --git a/libguile/environments.h b/libguile/environments.h
new file mode 100644
index 000000000..125f6852a
--- /dev/null
+++ b/libguile/environments.h
@@ -0,0 +1,176 @@
+#ifndef ENVIRONMENTSH
+#define ENVIRONMENTSH
+
+#include "__scm.h"
+#include "tags.h"
+
+
+
+typedef void (*scm_environment_observer) (SCM env, SCM data);
+typedef SCM (*scm_environment_folder) (SCM data, SCM symbol, SCM value, SCM tail);
+typedef SCM (*scm_environment_conflict_proc) (SCM data, SCM sym, SCM env1, SCM env2);
+
+struct environment_funcs {
+ SCM (*ref) (SCM self, SCM symbol);
+ SCM (*fold) (SCM self, scm_environment_folder proc, SCM data, SCM init);
+ SCM (*define) (SCM self, SCM symbol, SCM value);
+ void (*undefine) (SCM self, SCM symbol);
+ void (*set) (SCM self, SCM symbol, SCM value);
+ SCM (*cell) (SCM self, SCM symbol, int for_write);
+ SCM (*observe) (SCM self, scm_environment_observer proc, SCM data, int weak_p);
+ void (*unobserve) (SCM dummy, SCM token);
+
+ SCM (*mark) (SCM self);
+ scm_sizet (*free) (SCM self);
+ int (*print) (SCM self, SCM port, scm_print_state *pstate);
+};
+
+struct environment {
+ struct environment_funcs *environment_funcs; /* class signature */
+ SCM obarray;
+};
+
+
+
+/* create the root environment */
+extern void scm_environments_prehistory (void);
+
+/* intern environment functions in env */
+extern SCM scm_init_environments (SCM env);
+
+
+/* generic environment functions */
+
+#define SCM_ENVIRONMENT_FUNCS(env) ( *((struct environment_funcs **) SCM_CDR (env)))
+#define SCM_ENVIRONMENT_OBARRAY(env) (((struct environment*)(SCM_CDR(env)))->obarray)
+#define SCM_ENVIRONMENT_STRUCT(env) ((struct environment*) SCM_CDR (env))
+#define SCM_ENVIRONMENTP(x) ((SCM_CAR (x)) == scm_tc16_environment)
+#define SCM_TOP_LEVEL_ENVP(x) ((SCM_CONSP(x) && (SCM_EOL==SCM_CDR(x))))
+#define SCM_ENVIRONMENT_REF(env, symbol) ((*(SCM_ENVIRONMENT_FUNCS(env)->ref)) (env, symbol))
+#define SCM_ENVIRONMENT_FOLD(env, proc, data, init) ((*(SCM_ENVIRONMENT_FUNCS(env)->fold)) (env, proc, data, init))
+#define SCM_ENVIRONMENT_DEFINE(env, symbol, value) ((*(SCM_ENVIRONMENT_FUNCS(env)->define)) (env, symbol, value))
+#define SCM_ENVIRONMENT_UNDEFINE(env, symbol) ((*(SCM_ENVIRONMENT_FUNCS(env)->undefine)) (env, symbol))
+#define SCM_ENVIRONMENT_SET(env, symbol, value) ((*(SCM_ENVIRONMENT_FUNCS(env)->set)) (env, symbol, value))
+#define SCM_ENVIRONMENT_CELL(env, symbol, for_write) ((*(SCM_ENVIRONMENT_FUNCS(env)->cell)) (env, symbol, for_write))
+#define SCM_ENVIRONMENT_OBSERVE(env, proc, data, weak_p) ((*(SCM_ENVIRONMENT_FUNCS(env)->observe)) (env, proc, data, weak_p))
+#define SCM_ENVIRONMENT_UNOBSERVE(env, token) ((*(SCM_ENVIRONMENT_FUNCS(env)->unobserve)) (env, token))
+#define SCM_ENVIRONMENT_BOUND(env, symbol) (SCM_UNDEFINED==SCM_ENVIRONMENT_REF(env, symbol) ? SCM_BOOL_F : SCM_BOOL_T)
+
+extern long scm_tc16_environment;
+
+extern SCM scm_environment_observe_weak(SCM env, SCM proc);
+extern SCM scm_environment_unobserve (SCM token);
+extern SCM scm_c_environment_ref (SCM env, SCM sym);
+extern SCM scm_environment_ref (SCM env, SCM sym);
+extern SCM scm_c_environment_fold (SCM env, scm_environment_folder proc, SCM data, SCM init);
+extern SCM scm_environment_fold(SCM env, SCM proc, SCM init);
+extern SCM scm_environment_undefine(SCM env, SCM sym);
+extern SCM scm_environment_define(SCM env, SCM sym, SCM val);
+extern SCM scm_environment_set_x(SCM env, SCM sym, SCM val);
+extern SCM scm_c_environment_cell(SCM env, SCM sym, int for_write);
+extern SCM scm_environment_cell(SCM env, SCM sym, SCM for_write);
+extern SCM scm_environment_bound_p (SCM env, SCM sym);
+extern SCM scm_c_environment_observe (SCM env, scm_environment_observer proc, SCM data, int weak_p);
+extern SCM scm_environment_observe(SCM env, SCM proc);
+extern SCM scm_environment_p(SCM env);
+extern SCM scm_make_environment (void *handle, scm_sizet size);
+
+
+
+/* leaf environments */
+#define SCM_LEAF_ENVIRONMENTP(env) ((void*)SCM_ENVIRONMENT_FUNCS(env) == scm_type_leaf_environment)
+#define SCM_LEAF_ENVIRONMENT_STRUCT(env) ((struct leaf_environment*) SCM_CDR (env))
+
+extern void *scm_type_leaf_environment;
+extern SCM scm_make_leaf_environment (void);
+
+extern void *scm_type_immutable_environment;
+extern SCM scm_make_immutable_environment (void);
+
+
+
+/* eval environments */
+#define SCM_EVAL_ENVIRONMENTP(env) (SCM_ENVIRONMENT_FUNCS(env) == scm_type_eval_environment)
+#define SCM_EVAL_ENVIRONMENT_STRUCT(env) ((struct eval_environment*) SCM_CDR (env))
+#define SCM_EVAL_ENVIRONMENT_IMPORTED(eval_env) (SCM_EVAL_ENVIRONMENT_STRUCT(eval_env)->imported)
+#define SCM_EVAL_ENVIRONMENT_LOCAL(eval_env) (SCM_EVAL_ENVIRONMENT_STRUCT(eval_env)->local)
+#define SCM_EVAL_ENVIRONMENT_MEMOIZED(eval_env) (SCM_EVAL_ENVIRONMENT_STRUCT(eval_env)->memoized)
+
+extern void *scm_type_eval_environment;
+
+extern void scm_eval_environment_memoize_cell_internal(SCM env, SCM expr, SCM val, SCM sym);
+extern SCM scm_make_eval_environment (SCM local, SCM imported);
+extern SCM scm_eval_environment_imported (SCM env);
+extern SCM scm_eval_environment_local(SCM env);
+extern SCM scm_eval_environment_set_imported_x (SCM env, SCM imported);
+extern SCM scm_eval_environment_p (SCM env);
+
+
+
+/* interface environments */
+#define SCM_INTERFACE_ENVIRONMENTP(env) ((SCM_ENVIRONMENT_FUNCS(env) == scm_type_interface_environment)||(SCM_ENVIRONMENT_FUNCS(env) == scm_type_interface_environment_fixed))
+#define SCM_INTERFACE_ENVIRONMENT_STRUCT(env) ((struct interface_environment*) SCM_CDR (env))
+#define SCM_INTERFACE_ENVIRONMENT_PRIVATE(interface_env) (SCM_INTERFACE_ENVIRONMENT_STRUCT(interface_env)->private)
+#define SCM_INTERFACE_ENVIRONMENT_INTERFACE(interface_env) (SCM_INTERFACE_ENVIRONMENT_STRUCT(interface_env)->interface)
+
+extern void *scm_type_interface_environment;
+
+extern SCM scm_make_interface_environment (SCM interface);
+extern SCM scm_interface_environment_interface(SCM env);
+extern SCM scm_interface_environment_set_interface_x(SCM env, SCM interface);
+extern SCM scm_interface_environment_p (SCM env);
+
+
+
+/* export environments */
+#define SCM_EXPORT_ENVIRONMENTP(env) (SCM_ENVIRONMENT_FUNCS(env) == scm_type_export_environment)
+#define SCM_EXPORT_ENVIRONMENT_STRUCT(env) ((struct interface_environment*) SCM_CDR (env))
+
+extern void *scm_type_export_environment;
+
+extern SCM scm_make_export_environment (SCM private, SCM signature);
+extern SCM scm_export_environment_signature(SCM env);
+extern SCM scm_export_environment_set_signature_x(SCM env, SCM signature);
+extern SCM scm_export_environment_set_private_x (SCM env, SCM private);
+extern SCM scm_export_environment_private (SCM env);
+extern SCM scm_export_environment_p (SCM env);
+
+
+
+/* import environments */
+#define SCM_IMPORT_ENVIRONMENTP(env) (SCM_ENVIRONMENT_FUNCS(env) == scm_type_import_environment)
+#define SCM_IMPORT_ENVIRONMENT_STRUCT(env) ((struct interface_environment*) SCM_CDR (env))
+#define SCM_IMPORT_ENVIRONMENT_CONFLICT_PROC(import_env) (SCM_IMPORT_ENVIRONMENT_STRUCT(import_env)->conflict_proc)
+
+extern void *scm_type_import_environment;
+
+extern SCM scm_make_import_environment (SCM imports, SCM conflict_proc);
+extern SCM scm_import_environment_imports (SCM env);
+extern SCM scm_import_environment_set_imports_x (SCM env, SCM imports);
+extern SCM scm_import_environment_p (SCM env);
+
+
+
+extern SCM scm_set_interaction_environment_x (SCM env);
+extern SCM scm_interaction_environment_proc (void);
+extern SCM scm_c_module_registry_proc (void);
+extern SCM scm_module_registry_proc (void);
+extern SCM scm_environment_module_hash_proc (void);
+extern SCM scm_null_environment_proc(SCM version);
+extern SCM scm_scheme_guile_environment_proc(SCM version);
+extern SCM scm_guile_user_environment_proc(SCM version);
+extern SCM scm_report_environment_proc(SCM version);
+
+
+
+extern SCM scm_environment_intern (SCM env, char* name, SCM val);
+
+
+
+/* environment-symbol-properties */
+SCM scm_environment_symbol_property(SCM env, SCM sym, SCM prop);
+SCM scm_environment_remove_symbol_property_x(SCM env, SCM sym, SCM prop);
+SCM scm_environment_set_symbol_property_x(SCM env, SCM sym, SCM prop, SCM val);
+
+
+#endif