📄 save.scm
字号:
((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)))))))(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 write-component (procedure->memoizing-macro (lambda (exp env) `(or (write-component-procedure ,(cadr exp) ,@(cdddr exp)) (begin (display #f ,(cadddr exp)) (add-patcher! ,(caddr exp) 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-method (load-objects (file <input-port>)) (let ((m (make-module))) (module-use! m the-scm-module) (module-use! m %module-public-interface) (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)))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -