123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875 |
- ;;; installed-scm-file
- ;;;; Copyright (C) 2000,2001,2002, 2006, 2009, 2010, 2013, 2015 Free Software Foundation, Inc.
- ;;;;
- ;;;; This library is free software; you can redistribute it and/or
- ;;;; modify it under the terms of the GNU Lesser General Public
- ;;;; License as published by the Free Software Foundation; either
- ;;;; version 3 of the License, or (at your option) any later version.
- ;;;;
- ;;;; This library is distributed in the hope that it will be useful,
- ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- ;;;; Lesser General Public License for more details.
- ;;;;
- ;;;; You should have received a copy of the GNU Lesser General Public
- ;;;; License along with this library; if not, write to the Free Software
- ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- ;;;;
- (define-module (oop goops save)
- :use-module (oop goops internal)
- :export (make-unbound save-objects load-objects restore
- enumerate! enumerate-component!
- write-readably write-component write-component-procedure
- literal? readable make-readable))
- (define (make-unbound)
- *unbound*)
- ;;;
- ;;; save-objects ALIST PORT [EXCLUDED] [USES]
- ;;;
- ;;; ALIST ::= ((NAME . OBJECT) ...)
- ;;;
- ;;; Save OBJECT ... to PORT so that when the data is read and evaluated
- ;;; OBJECT ... are re-created under names NAME ... .
- ;;; Exclude any references to objects in the list EXCLUDED.
- ;;; Add a (use-modules . USES) line to the top of the saved text.
- ;;;
- ;;; In some instances, when `save-object' doesn't know how to produce
- ;;; readable syntax for an object, you can explicitly register read
- ;;; syntax for an object using the special form `readable'.
- ;;;
- ;;; Example:
- ;;;
- ;;; The function `foo' produces an object of obscure structure.
- ;;; Only `foo' can construct such objects. Because of this, an
- ;;; object such as
- ;;;
- ;;; (define x (vector 1 (foo)))
- ;;;
- ;;; cannot be saved by `save-objects'. But if you instead write
- ;;;
- ;;; (define x (vector 1 (readable (foo))))
- ;;;
- ;;; `save-objects' will happily produce the necessary read syntax.
- ;;;
- ;;; To add new read syntax, hang methods on `enumerate!' and
- ;;; `write-readably'.
- ;;;
- ;;; enumerate! OBJECT ENV
- ;;; Should call `enumerate-component!' (which takes same args) on
- ;;; each component object. Should return #t if the composite object
- ;;; can be written as a literal. (`enumerate-component!' returns #t
- ;;; if the component is a literal.
- ;;;
- ;;; write-readably OBJECT PORT ENV
- ;;; Should write a readable representation of OBJECT to PORT.
- ;;; Should use `write-component' to print each component object.
- ;;; Use `literal?' to decide if a component is a literal.
- ;;;
- ;;; Utilities:
- ;;;
- ;;; enumerate-component! OBJECT ENV
- ;;;
- ;;; write-component OBJECT PATCHER PORT ENV
- ;;; PATCHER is an expression which, when evaluated, stores OBJECT
- ;;; into its current location.
- ;;;
- ;;; Example:
- ;;;
- ;;; (write-component (car ls) `(set-car! ,ls ,(car ls)) file env)
- ;;;
- ;;; write-component is a macro.
- ;;;
- ;;; literal? COMPONENT ENV
- ;;;
- (define-method (immediate? (o <top>)) #f)
- (define-method (immediate? (o <null>)) #t)
- (define-method (immediate? (o <number>)) #t)
- (define-method (immediate? (o <boolean>)) #t)
- (define-method (immediate? (o <symbol>)) #t)
- (define-method (immediate? (o <char>)) #t)
- (define-method (immediate? (o <keyword>)) #t)
- ;;; enumerate! OBJECT ENVIRONMENT
- ;;;
- ;;; Return #t if object is a literal.
- ;;;
- (define-method (enumerate! (o <top>) env) #t)
- (define-method (write-readably (o <top>) file env)
- ;;(goops-error "No read-syntax defined for object `~S'" o)
- (write o file) ;doesn't catch bugs, but is much more flexible
- )
- ;;;
- ;;; Readables
- ;;;
- (define readables (make-weak-key-hash-table 61))
- (define-macro (readable exp)
- `(make-readable ,exp ',(copy-tree exp)))
- (define (make-readable obj expr)
- (hashq-set! readables obj expr)
- obj)
- (define (readable-expression obj)
- `(readable ,(hashq-ref readables obj)))
- ;; FIXME: if obj is nil or false, this can return a false value. OTOH
- ;; usually this is only for non-immediates.
- (define (readable? obj)
- (hashq-ref readables obj))
- ;;;
- ;;; Writer helpers
- ;;;
- (define (write-component-procedure o file env)
- "Return #f if circular reference"
- (cond ((immediate? o) (write o file) #t)
- ((readable? o) (write (readable-expression o) file) #t)
- ((excluded? o env) (display #f file) #t)
- (else
- (let ((info (object-info o env)))
- (cond ((not (binding? info)) (write-readably o file env) #t)
- ((not (eq? (visiting info) #:defined)) #f) ;forward reference
- (else (display (binding info) file) #t))))))
- ;;; write-component OBJECT PATCHER FILE ENV
- ;;;
- (define-macro (write-component object patcher file env)
- `(or (write-component-procedure ,object ,file ,env)
- (begin
- (display #f ,file)
- (add-patcher! ,patcher ,env))))
- ;;;
- ;;; Strings
- ;;;
- (define-method (enumerate! (o <string>) env) #f)
- ;;;
- ;;; Vectors
- ;;;
- (define-method (enumerate! (o <vector>) env)
- (or (not (vector? o))
- (let ((literal? #t))
- (array-for-each (lambda (o)
- (if (not (enumerate-component! o env))
- (set! literal? #f)))
- o)
- literal?)))
- (define-method (write-readably (o <vector>) file env)
- (if (not (vector? o))
- (write o file)
- (let ((n (vector-length o)))
- (if (zero? n)
- (display "#()" file)
- (let ((not-literal? (not (literal? o env))))
- (display (if not-literal?
- "(vector "
- "#(")
- file)
- (if (and not-literal?
- (literal? (vector-ref o 0) env))
- (display #\' file))
- (write-component (vector-ref o 0)
- `(vector-set! ,o 0 ,(vector-ref o 0))
- file
- env)
- (do ((i 1 (+ 1 i)))
- ((= i n))
- (display #\space file)
- (if (and not-literal?
- (literal? (vector-ref o i) env))
- (display #\' file))
- (write-component (vector-ref o i)
- `(vector-set! ,o ,i ,(vector-ref o i))
- file
- env))
- (display #\) file))))))
- ;;;
- ;;; Arrays
- ;;;
- (define-method (enumerate! (o <array>) env)
- (enumerate-component! (shared-array-root o) env))
- (define (make-mapper array)
- (let* ((n (array-rank array))
- (indices (reverse (if (<= n 11)
- (list-tail '(t s r q p n m l k j i) (- 11 n))
- (let loop ((n n)
- (ls '()))
- (if (zero? n)
- ls
- (loop (- n 1)
- (cons (gensym "i") ls))))))))
- `(lambda ,indices
- (+ ,(shared-array-offset array)
- ,@(map (lambda (ind dim inc)
- `(* ,inc ,(if (pair? dim) `(- ,ind ,(car dim)) ind)))
- indices
- (array-dimensions array)
- (shared-array-increments array))))))
- (define (write-array prefix o not-literal? file env)
- (letrec ((inner (lambda (n indices)
- (if (not (zero? n))
- (let ((el (apply array-ref o
- (reverse (cons 0 indices)))))
- (if (and not-literal?
- (literal? el env))
- (display #\' file))
- (write-component
- el
- `(array-set! ,o ,el ,@indices)
- file
- env)))
- (do ((i 1 (+ 1 i)))
- ((= i n))
- (display #\space file)
- (let ((el (apply array-ref o
- (reverse (cons i indices)))))
- (if (and not-literal?
- (literal? el env))
- (display #\' file))
- (write-component
- el
- `(array-set! ,o ,el ,@indices)
- file
- env))))))
- (display prefix file)
- (let loop ((dims (array-dimensions o))
- (indices '()))
- (cond ((null? (cdr dims))
- (inner (car dims) indices))
- (else
- (let ((n (car dims)))
- (do ((i 0 (+ 1 i)))
- ((= i n))
- (if (> i 0)
- (display #\space file))
- (display prefix file)
- (loop (cdr dims) (cons i indices))
- (display #\) file))))))
- (display #\) file)))
- (define-method (write-readably (o <array>) file env)
- (let ((root (shared-array-root o)))
- (cond ((literal? o env)
- (if (not (vector? root))
- (write o file)
- (begin
- (display #\# file)
- (display (array-rank o) file)
- (write-array #\( o #f file env))))
- ((binding? root env)
- (display "(make-shared-array " file)
- (if (literal? root env)
- (display #\' file))
- (write-component root
- (goops-error "write-readably(<array>): internal error")
- file
- env)
- (display #\space file)
- (display (make-mapper o) file)
- (for-each (lambda (dim)
- (display #\space file)
- (display dim file))
- (array-dimensions o))
- (display #\) file))
- (else
- (display "(list->uniform-array " file)
- (display (array-rank o) file)
- (display " '() " file)
- (write-array "(list " o #f file env)))))
- ;;;
- ;;; Pairs
- ;;;
- ;;; These methods have more complex structure than is required for
- ;;; most objects, since they take over some of the logic of
- ;;; `write-component'.
- ;;;
- (define-method (enumerate! (o <pair>) env)
- (let ((literal? (enumerate-component! (car o) env)))
- (and (enumerate-component! (cdr o) env)
- literal?)))
- (define-method (write-readably (o <pair>) file env)
- (let ((proper? (let loop ((ls o))
- (or (null? ls)
- (and (pair? ls)
- (not (binding? (cdr ls) env))
- (loop (cdr ls))))))
- (1? (or (not (pair? (cdr o)))
- (binding? (cdr o) env)))
- (not-literal? (not (literal? o env)))
- (infos '())
- (refs (ref-stack env)))
- (display (cond ((not not-literal?) #\()
- (proper? "(list ")
- (1? "(cons ")
- (else "(cons* "))
- file)
- (if (and not-literal?
- (literal? (car o) env))
- (display #\' file))
- (write-component (car o) `(set-car! ,o ,(car o)) file env)
- (do ((ls (cdr o) (cdr ls))
- (prev o ls))
- ((or (not (pair? ls))
- (binding? ls env))
- (if (not (null? ls))
- (begin
- (if (not not-literal?)
- (display " ." file))
- (display #\space file)
- (if (and not-literal?
- (literal? ls env))
- (display #\' file))
- (write-component ls `(set-cdr! ,prev ,ls) file env)))
- (display #\) file))
- (display #\space file)
- (set! infos (cons (object-info ls env) infos))
- (push-ref! ls env) ;*fixme* optimize
- (set! (visiting? (car infos)) #t)
- (if (and not-literal?
- (literal? (car ls) env))
- (display #\' file))
- (write-component (car ls) `(set-car! ,ls ,(car ls)) file env)
- )
- (for-each (lambda (info)
- (set! (visiting? info) #f))
- infos)
- (set! (ref-stack env) refs)
- ))
- ;;;
- ;;; Objects
- ;;;
- ;;; Doesn't yet handle unbound slots
- ;; Don't export this function! This is all very temporary.
- ;;
- (define (get-set-for-each proc class)
- (for-each (lambda (slot)
- (unless (memq (slot-definition-allocation slot)
- '(#:class #:each-subclass))
- (let ((ref (slot-definition-slot-ref slot))
- (set (slot-definition-slot-set! slot))
- (index (slot-definition-index slot)))
- (if ref
- (proc ref set)
- (proc (standard-get index) (standard-set index))))))
- (class-slots class)))
- (define (access-for-each proc class)
- (for-each (lambda (slot)
- (unless (memq (slot-definition-allocation slot)
- '(#:class #:each-subclass))
- (let ((name (slot-definition-name slot))
- (accessor (and=> (slot-definition-accessor slot)
- generic-function-name))
- (ref (slot-definition-slot-ref slot))
- (set (slot-definition-slot-set! slot))
- (index (slot-definition-index slot)))
- (if ref
- (proc name accessor ref set)
- (proc name accessor
- (standard-get index) (standard-set index))))))
- (class-slots class)))
- (define-macro (restore class slots . exps)
- "(restore CLASS (SLOT-NAME1 ...) EXP1 ...)"
- `(let ((o ((@@ (oop goops) %allocate-instance) ,class '())))
- (for-each (lambda (name val)
- (slot-set! o name val))
- ',slots
- (list ,@exps))
- o))
- (define-method (enumerate! (o <object>) env)
- (get-set-for-each (lambda (get set)
- (let ((val (get o)))
- (if (not (unbound? val))
- (enumerate-component! val env))))
- (class-of o))
- #f)
- (define-method (write-readably (o <object>) file env)
- (let ((class (class-of o)))
- (display "(restore " file)
- (display (class-name class) file)
- (display " (" file)
- (let ((slotdefs
- (filter (lambda (slotdef)
- (not (or (memq (slot-definition-allocation slotdef)
- '(#:class #:each-subclass))
- (and (slot-bound? o (slot-definition-name slotdef))
- (excluded?
- (slot-ref o (slot-definition-name slotdef))
- env)))))
- (class-slots class))))
- (if (not (null? slotdefs))
- (begin
- (display (slot-definition-name (car slotdefs)) file)
- (for-each (lambda (slotdef)
- (display #\space file)
- (display (slot-definition-name slotdef) file))
- (cdr slotdefs)))))
- (display #\) file)
- (access-for-each (lambda (name aname get set)
- (display #\space file)
- (let ((val (get o)))
- (cond ((unbound? val)
- (display '(make-unbound) file))
- ((excluded? val env))
- (else
- (if (literal? val env)
- (display #\' file))
- (write-component val
- (if aname
- `(set! (,aname ,o) ,val)
- `(slot-set! ,o ',name ,val))
- file env)))))
- class)
- (display #\) file)))
- ;;;
- ;;; Classes
- ;;;
- ;;; Currently, we don't support reading in class objects
- ;;;
- (define-method (enumerate! (o <class>) env) #f)
- (define-method (write-readably (o <class>) file env)
- (display (class-name o) file))
- ;;;
- ;;; Generics
- ;;;
- ;;; Currently, we don't support reading in generic functions
- ;;;
- (define-method (enumerate! (o <generic>) env) #f)
- (define-method (write-readably (o <generic>) file env)
- (display (generic-function-name o) file))
- ;;;
- ;;; Method
- ;;;
- ;;; Currently, we don't support reading in methods
- ;;;
- (define-method (enumerate! (o <method>) env) #f)
- (define-method (write-readably (o <method>) file env)
- (goops-error "No read-syntax for <method> defined"))
- ;;;
- ;;; Environments
- ;;;
- (define-class <environment> ()
- (object-info #:accessor object-info
- #:init-form (make-hash-table 61))
- (excluded #:accessor excluded
- #:init-form (make-hash-table 61))
- (pass-2? #:accessor pass-2?
- #:init-value #f)
- (ref-stack #:accessor ref-stack
- #:init-value '())
- (objects #:accessor objects
- #:init-value '())
- (pre-defines #:accessor pre-defines
- #:init-value '())
- (locals #:accessor locals
- #:init-value '())
- (stand-ins #:accessor stand-ins
- #:init-value '())
- (post-defines #:accessor post-defines
- #:init-value '())
- (patchers #:accessor patchers
- #:init-value '())
- (multiple-bound #:accessor multiple-bound
- #:init-value '())
- )
- (define-method (initialize (env <environment>) initargs)
- (next-method)
- (cond ((get-keyword #:excluded initargs #f)
- => (lambda (excludees)
- (for-each (lambda (e)
- (hashq-create-handle! (excluded env) e #f))
- excludees)))))
- (define-method (object-info o env)
- (hashq-ref (object-info env) o))
- (define-method ((setter object-info) o env x)
- (hashq-set! (object-info env) o x))
- (define (excluded? o env)
- (hashq-get-handle (excluded env) o))
- (define (add-patcher! patcher env)
- (set! (patchers env) (cons patcher (patchers env))))
- (define (push-ref! o env)
- (set! (ref-stack env) (cons o (ref-stack env))))
- (define (pop-ref! env)
- (set! (ref-stack env) (cdr (ref-stack env))))
- (define (container env)
- (car (ref-stack env)))
- (define-class <object-info> ()
- (visiting #:accessor visiting
- #:init-value #f)
- (binding #:accessor binding
- #:init-value #f)
- (literal? #:accessor literal?
- #:init-value #f)
- )
- (define visiting? visiting)
- (define-method (binding (info <boolean>))
- #f)
- (define-method (binding o env)
- (binding (object-info o env)))
- (define binding? binding)
- (define-method (literal? (info <boolean>))
- #t)
- ;;; Note that this method is intended to be used only during the
- ;;; writing pass
- ;;;
- (define-method (literal? o env)
- (or (immediate? o)
- (excluded? o env)
- (let ((info (object-info o env)))
- ;; write-component sets all bindings first to #:defining,
- ;; then to #:defined
- (and (or (not (binding? info))
- ;; we might be using `literal?' in a write-readably method
- ;; to query about the object being defined
- (and (eq? (visiting info) #:defining)
- (null? (cdr (ref-stack env)))))
- (literal? info)))))
- ;;;
- ;;; Enumeration
- ;;;
- ;;; Enumeration has two passes.
- ;;;
- ;;; Pass 1: Detect common substructure, circular references and order
- ;;;
- ;;; Pass 2: Detect literals
- (define (enumerate-component! o env)
- (cond ((immediate? o) #t)
- ((readable? o) #f)
- ((excluded? o env) #t)
- ((pass-2? env)
- (let ((info (object-info o env)))
- (if (binding? info)
- ;; if circular reference, we print as a literal
- ;; (note that during pass-2, circular references are
- ;; forward references, i.e. *not* yet marked with #:pass-2
- (not (eq? (visiting? info) #:pass-2))
- (and (enumerate! o env)
- (begin
- (set! (literal? info) #t)
- #t)))))
- ((object-info o env)
- => (lambda (info)
- (set! (binding info) #t)
- (if (visiting? info)
- ;; circular reference--mark container
- (set! (binding (object-info (container env) env)) #t))))
- (else
- (let ((info (make <object-info>)))
- (set! (object-info o env) info)
- (push-ref! o env)
- (set! (visiting? info) #t)
- (enumerate! o env)
- (set! (visiting? info) #f)
- (pop-ref! env)
- (set! (objects env) (cons o (objects env)))))))
- ;;;
- ;;; Main engine
- ;;;
- (define binding-name car)
- (define binding-object cdr)
- (define (pass-1! alist env)
- ;; Determine object order and necessary bindings
- (for-each (lambda (binding)
- (enumerate-component! (binding-object binding) env))
- alist))
- (define (make-local i)
- (string->symbol (string-append "%o" (number->string i))))
- (define (name-bindings! alist env)
- ;; Name top-level bindings
- (for-each (lambda (b)
- (let ((o (binding-object b)))
- (if (not (or (immediate? o)
- (readable? o)
- (excluded? o env)))
- (let ((info (object-info o env)))
- (if (symbol? (binding info))
- ;; already bound to a variable
- (set! (multiple-bound env)
- (acons (binding info)
- (binding-name b)
- (multiple-bound env)))
- (set! (binding info)
- (binding-name b)))))))
- alist)
- ;; Name rest of bindings and create stand-in and definition lists
- (let post-loop ((ls (objects env))
- (post-defs '()))
- (cond ((or (null? ls)
- (eq? (binding (car ls) env) #t))
- (set! (post-defines env) post-defs)
- (set! (objects env) ls))
- ((not (binding (car ls) env))
- (post-loop (cdr ls) post-defs))
- (else
- (post-loop (cdr ls) (cons (car ls) post-defs)))))
- (let pre-loop ((ls (reverse (objects env)))
- (i 0)
- (pre-defs '())
- (locs '())
- (sins '()))
- (if (null? ls)
- (begin
- (set! (pre-defines env) (reverse pre-defs))
- (set! (locals env) (reverse locs))
- (set! (stand-ins env) (reverse sins)))
- (let ((info (object-info (car ls) env)))
- (cond ((not (binding? info))
- (pre-loop (cdr ls) i pre-defs locs sins))
- ((boolean? (binding info))
- ;; local
- (set! (binding info) (make-local i))
- (pre-loop (cdr ls)
- (+ 1 i)
- pre-defs
- (cons (car ls) locs)
- sins))
- ((null? locs)
- (pre-loop (cdr ls)
- i
- (cons (car ls) pre-defs)
- locs
- sins))
- (else
- (let ((real-name (binding info)))
- (set! (binding info) (make-local i))
- (pre-loop (cdr ls)
- (+ 1 i)
- pre-defs
- (cons (car ls) locs)
- (acons (binding info) real-name sins)))))))))
- (define (pass-2! env)
- (set! (pass-2? env) #t)
- (for-each (lambda (o)
- (let ((info (object-info o env)))
- (set! (literal? info) (enumerate! o env))
- (set! (visiting info) #:pass-2)))
- (append (pre-defines env)
- (locals env)
- (post-defines env))))
- (define (write-define! name val literal? file)
- (display "(define " file)
- (display name file)
- (display #\space file)
- (if literal? (display #\' file))
- (write val file)
- (display ")\n" file))
- (define (write-empty-defines! file env)
- (for-each (lambda (stand-in)
- (write-define! (cdr stand-in) #f #f file))
- (stand-ins env))
- (for-each (lambda (o)
- (write-define! (binding o env) #f #f file))
- (post-defines env)))
- (define (write-definition! prefix o file env)
- (display prefix file)
- (let ((info (object-info o env)))
- (display (binding info) file)
- (display #\space file)
- (if (literal? info)
- (display #\' file))
- (push-ref! o env)
- (set! (visiting info) #:defining)
- (write-readably o file env)
- (set! (visiting info) #:defined)
- (pop-ref! env)
- (display #\) file)))
- (define (write-let*-head! file env)
- (display "(let* (" file)
- (write-definition! "(" (car (locals env)) file env)
- (for-each (lambda (o)
- (write-definition! "\n (" o file env))
- (cdr (locals env)))
- (display ")\n" file))
- (define (write-rebindings! prefix bindings file env)
- (for-each (lambda (patch)
- (display prefix file)
- (display (cdr patch) file)
- (display #\space file)
- (display (car patch) file)
- (display ")\n" file))
- bindings))
- (define (write-definitions! selector prefix file env)
- (for-each (lambda (o)
- (write-definition! prefix o file env)
- (newline file))
- (selector env)))
- (define (write-patches! prefix file env)
- (for-each (lambda (patch)
- (display prefix file)
- (display (let name-objects ((patcher patch))
- (cond ((binding patcher env)
- => (lambda (name)
- (cond ((assq name (stand-ins env))
- => cdr)
- (else name))))
- ((pair? patcher)
- (cons (name-objects (car patcher))
- (name-objects (cdr patcher))))
- (else patcher)))
- file)
- (newline file))
- (reverse (patchers env))))
- (define (write-immediates! alist file)
- (for-each (lambda (b)
- (if (immediate? (binding-object b))
- (write-define! (binding-name b)
- (binding-object b)
- #t
- file)))
- alist))
- (define (write-readables! alist file env)
- (let ((written '()))
- (for-each (lambda (b)
- (cond ((not (readable? (binding-object b))))
- ((assq (binding-object b) written)
- => (lambda (p)
- (set! (multiple-bound env)
- (acons (cdr p)
- (binding-name b)
- (multiple-bound env)))))
- (else
- (write-define! (binding-name b)
- (readable-expression (binding-object b))
- #f
- file)
- (set! written (acons (binding-object b)
- (binding-name b)
- written)))))
- alist)))
- (define-method (save-objects (alist <pair>) (file <string>) . rest)
- (let ((port (open-output-file file)))
- (apply save-objects alist port rest)
- (close-port port)
- *unspecified*))
- (define-method (save-objects (alist <pair>) (file <output-port>) . rest)
- (let ((excluded (if (>= (length rest) 1) (car rest) '()))
- (uses (if (>= (length rest) 2) (cadr rest) '())))
- (let ((env (make <environment> #:excluded excluded)))
- (pass-1! alist env)
- (name-bindings! alist env)
- (pass-2! env)
- (if (not (null? uses))
- (begin
- (write `(use-modules ,@uses) file)
- (newline file)))
- (write-immediates! alist file)
- (if (null? (locals env))
- (begin
- (write-definitions! post-defines "(define " file env)
- (write-patches! "" file env))
- (begin
- (write-definitions! pre-defines "(define " file env)
- (write-empty-defines! file env)
- (write-let*-head! file env)
- (write-rebindings! " (set! " (stand-ins env) file env)
- (write-definitions! post-defines " (set! " file env)
- (write-patches! " " file env)
- (display " )\n" file)))
- (write-readables! alist file env)
- (write-rebindings! "(define " (reverse (multiple-bound env)) file env))))
- (define-method (load-objects (file <string>))
- (let* ((port (open-input-file file))
- (objects (load-objects port)))
- (close-port port)
- objects))
- (define iface (module-public-interface (current-module)))
- (define-method (load-objects (file <input-port>))
- (let ((m (make-module)))
- (module-use! m the-scm-module)
- (module-use! m iface)
- (save-module-excursion
- (lambda ()
- (set-current-module m)
- (let loop ((sexp (read file)))
- (if (not (eof-object? sexp))
- (begin
- (eval sexp m)
- (loop (read file)))))))
- (module-map (lambda (name var)
- (cons name (variable-ref var)))
- m)))
|