~ chicken-r7rs (master) d2663609c4a959abf24062f21bf6d6932a05c846
commit d2663609c4a959abf24062f21bf6d6932a05c846 Author: Evan Hanson <evhan@foldling.org> AuthorDate: Tue May 20 10:31:02 2014 +0000 Commit: Evan Hanson <evhan@foldling.org> CommitDate: Tue May 20 10:31:02 2014 +0000 read/write for shared data diff --git a/r7rs.setup b/r7rs.setup index b6f72f1..cb489c5 100644 --- a/r7rs.setup +++ b/r7rs.setup @@ -4,7 +4,7 @@ (use make srfi-1) (define scheme-modules - '("case-lambda" "char" "complex" "cxr" "eval" "file" "inexact" "lazy" "load" "process-context" "r5rs" "read" "repl" "time" "write")) ;XXX + '("case-lambda" "char" "complex" "cxr" "eval" "file" "inexact" "lazy" "load" "process-context" "r5rs" "read" "repl" "time" "write")) (make (("r7rs-compile-time.so" ("r7rs-compile-time.scm" "r7rs-compile-time-module.scm") (compile -s -O3 -d1 r7rs-compile-time-module.scm -J -o r7rs-compile-time.so) diff --git a/scheme.char.scm b/scheme.char.scm index 5421d61..e9e9e70 100644 --- a/scheme.char.scm +++ b/scheme.char.scm @@ -47,13 +47,13 @@ (define-extended-arity-comparator string-ci<=? %string-ci<=? ##sys#check-string) (define-extended-arity-comparator string-ci>=? %string-ci>=? ##sys#check-string) -(: char-foldcase (char --> char)) +(: char-foldcase (char -> char)) (define (char-foldcase c) (char-downcase c)) -(: string-foldcase (string --> string)) +(: string-foldcase (string -> string)) (define (string-foldcase s) (string-map char-foldcase s)) -(: digit-value (char --> (or fixnum boolean))) +(: digit-value (char -> (or fixnum boolean))) (define (digit-value c) (let ((i (char->integer c))) (and (fx>= i 48) (fx<= i 57) (fx- i 48))))) diff --git a/scheme.read.scm b/scheme.read.scm index 6cea019..1ca8fba 100644 --- a/scheme.read.scm +++ b/scheme.read.scm @@ -1,2 +1,79 @@ (module scheme.read (read) - (import scheme)) + (import (except scheme read) + (only chicken current-read-table fx+ fx= optional unless when)) + + (define (data? o) + (not (procedure? o))) + + (define (unthunk o fail) + (let ((v (o))) + (cond ((data? v) v) + ((eq? v o) + (fail "self-referential datum")) + (else + (unthunk v fail))))) + + ;; Fills holes in `o` destructively. + (define (unthunkify! o fail) + (let loop! ((o o)) + (cond ((pair? o) + (if (data? (car o)) + (loop! (car o)) + (set-car! o (unthunk (car o) fail))) + (if (data? (cdr o)) + (loop! (cdr o)) + (set-cdr! o (unthunk (cdr o) fail)))) + ((vector? o) + (let ((len (vector-length o))) + (do ((i 0 (fx+ i 1))) + ((fx= i len)) + (let ((v (vector-ref o i))) + (if (data? v) + (loop! v) + (vector-set! o i (unthunk v fail)))))))))) + + (define (read-with-shared-structure port) + + (define read-table (current-read-table)) + (unless (##sys#slot read-table 3) + (##sys#setslot read-table 3 (##sys#make-vector 256 #f))) + + (define read-hash/orig (##sys#slot (##sys#slot read-table 3) 35)) + (define read-equal/orig (##sys#slot (##sys#slot read-table 3) 61)) + + (define shared '()) + (define (register-shared! n thunk) + (set! shared (cons (cons n thunk) shared))) + + (define (read-hash/shared _ p n) + (##sys#read-char-0 p) + (cond ((assv n shared) => cdr) + (else (##sys#read-error p "undefined datum" n)))) + + (define (read-equal/shared _ p n) + (##sys#read-char-0 p) + (letrec ((o (begin + (register-shared! n (lambda () o)) + (##sys#read p ##sys#default-read-info-hook)))) + o)) + + (define (read/shared p) + (let ((o (##sys#read port ##sys#default-read-info-hook))) + (when (pair? shared) + (unthunkify! o (lambda a (apply ##sys#read-error p a)))) + o)) + + (dynamic-wind + (lambda () + (##sys#setslot (##sys#slot read-table 3) 35 read-hash/shared) + (##sys#setslot (##sys#slot read-table 3) 61 read-equal/shared)) + (lambda () + (read/shared port)) + (lambda () + (##sys#setslot (##sys#slot read-table 3) 35 read-hash/orig) + (##sys#setslot (##sys#slot read-table 3) 61 read-equal/orig)))) + + (: read (#!optional input-port -> *)) + (define (read . port) + (read-with-shared-structure + (optional port (current-input-port))))) diff --git a/scheme.write.scm b/scheme.write.scm index 63cd99a..279a1d1 100644 --- a/scheme.write.scm +++ b/scheme.write.scm @@ -1,6 +1,142 @@ (module scheme.write (display write - ; write-shared + write-shared write-simple) - (import scheme) - (define write-simple write)) + (import (rename scheme (display display-simple) (write write-simple)) + (only chicken foldl fx+ fx= fx<= optional when)) + + (define (interesting? o) + (or (pair? o) + (and (vector? o) + (fx<= 1 (vector-length o))))) + + (define (uninteresting? o) + (not (interesting? o))) + + (define (display-char c p) + ((##sys#slot (##sys#slot p 2) 2) p c)) + + (define (display-string s p) + ((##sys#slot (##sys#slot p 2) 3) p s)) + + ;; Build an alist mapping `interesting?` objects to boolean values + ;; indicating whether those objects occur shared in `o`. + (define (find-shared o cycles-only?) + + (define seen '()) + (define (seen? x) (assq x seen)) + (define (seen! x) (set! seen (cons (cons x 1) seen))) + + ;; Walk the form, tallying the number of times each object is + ;; encountered. This has the effect of filling `seen` with + ;; occurence counts for all objects satisfying `interesting?`. + (let walk! ((o o)) + (when (interesting? o) + (cond ((seen? o) => + (lambda (p) + (set-cdr! p (fx+ (cdr p) 1)))) + ((pair? o) + (seen! o) + (walk! (car o)) + (walk! (cdr o))) + ((vector? o) + (seen! o) + (let ((len (vector-length o))) + (do ((i 0 (fx+ i 1))) + ((fx= i len)) + (walk! (vector-ref o i)))))) + ;; If we're only interested in cycles and this object isn't + ;; self-referential, discount it (resulting in `write` rather + ;; than `write-shared` behavior). + (when cycles-only? + (let ((p (seen? o))) + (when (fx<= (cdr p) 1) + (set-cdr! p 0)))))) + + ;; Mark shared objects #t, unshared objects #f. + (foldl (lambda (a p) + (if (fx<= (cdr p) 1) + (cons (cons (car p) #f) a) + (cons (cons (car p) #t) a))) + '() + seen)) + + (define (write-with-shared-structure writer obj cycles-only? port) + + (define label 0) + (define (assign-label! pair) + (set-cdr! pair label) + (set! label (fx+ label 1))) + + (define shared + (find-shared obj cycles-only?)) + + (define (write-interesting/shared o) + (cond ((pair? o) + (display-char #\( port) + (write/shared (car o)) + (let loop ((o (cdr o))) + (cond ((null? o) + (display-char #\) port)) + ((and (pair? o) + (not (cdr (assq o shared)))) + (display-char #\space port) + (write/shared (car o)) + (loop (cdr o))) + (else + (display-string " . " port) + (write/shared o) + (display-char #\) port))))) + ((vector? o) + (display-string "#(" port) + (write/shared (vector-ref o 0)) + (let ((len (vector-length o))) + (do ((i 1 (fx+ i 1))) + ((fx= i len) + (display-char #\) port)) + (display-char #\space port) + (write/shared (vector-ref o i))))))) + + (define (write/shared o) + (if (uninteresting? o) + (writer o port) + (let* ((p (assq o shared)) + (d (cdr p))) + (cond ((not d) + (write-interesting/shared o)) + ((number? d) + (display-char #\# port) + (writer d port) + (display-char #\# port)) + (else + (display-char #\# port) + (writer label port) + (display-char #\= port) + (assign-label! p) + (write-interesting/shared o)))))) + + (write/shared obj)) + + (: display (* #!optional output-port -> undefined)) + (define (display o . p) + (write-with-shared-structure + display-simple + o + #t + (optional p (current-output-port)))) + + (: write (* #!optional output-port -> undefined)) + (define (write o . p) + (write-with-shared-structure + write-simple + o + #t + (optional p (current-output-port)))) + + (: write-shared (* #!optional output-port -> undefined)) + (define (write-shared o . p) + (write-with-shared-structure + write-simple + o + #f + (optional p (current-output-port)))))Trap