~ chicken-r7rs (master) /scheme.write.scm
Trap1(module scheme.write (display2 write3 write-shared4 write-simple)5 (import (rename scheme (display display-simple) (write write-simple))6 (only chicken.base foldl when optional)7 (only chicken.platform feature?)8 (only chicken.type :)9 (only chicken.fixnum fx+ fx= fx<=))1011 (when (feature? 'csi)12 (set! ##sys#repl-print-hook13 (lambda (o p)14 (write o p)15 (newline))))1617 (define (interesting? o)18 (or (pair? o)19 (and (vector? o)20 (fx<= 1 (vector-length o)))))2122 (define (uninteresting? o)23 (not (interesting? o)))2425 (define (display-char c p)26 ((##sys#slot (##sys#slot p 2) 2) p c))2728 (define (display-string s p)29 ((##sys#slot (##sys#slot p 2) 3) p s))3031 ;; Build an alist mapping `interesting?` objects to boolean values32 ;; indicating whether those objects occur shared in `o`.33 (define (find-shared o cycles-only?)3435 (define seen '())36 (define (seen? x) (assq x seen))37 (define (seen! x) (set! seen (cons (cons x 1) seen)))3839 ;; Walk the form, tallying the number of times each object is40 ;; encountered. This has the effect of filling `seen` with41 ;; occurence counts for all objects satisfying `interesting?`.42 (let walk! ((o o))43 (when (interesting? o)44 (cond ((seen? o) =>45 (lambda (p)46 (set-cdr! p (fx+ (cdr p) 1))))47 ((pair? o)48 (seen! o)49 (walk! (car o))50 (walk! (cdr o)))51 ((vector? o)52 (seen! o)53 (let ((len (vector-length o)))54 (do ((i 0 (fx+ i 1)))55 ((fx= i len))56 (walk! (vector-ref o i))))))57 ;; If we're only interested in cycles and this object isn't58 ;; self-referential, discount it (resulting in `write` rather59 ;; than `write-shared` behavior).60 (when cycles-only?61 (let ((p (seen? o)))62 (when (fx<= (cdr p) 1)63 (set-cdr! p 0))))))6465 ;; Mark shared objects #t, unshared objects #f.66 (foldl (lambda (a p)67 (if (fx<= (cdr p) 1)68 (cons (cons (car p) #f) a)69 (cons (cons (car p) #t) a)))70 '()71 seen))7273 (define (write-with-shared-structure writer obj cycles-only? port)7475 (define label 0)76 (define (assign-label! pair)77 (set-cdr! pair label)78 (set! label (fx+ label 1)))7980 (define shared81 (find-shared obj cycles-only?))8283 (define (write-interesting/shared o)84 (cond ((pair? o)85 (display-char #\( port)86 (write/shared (car o))87 (let loop ((o (cdr o)))88 (cond ((null? o)89 (display-char #\) port))90 ((and (pair? o)91 (not (cdr (assq o shared))))92 (display-char #\space port)93 (write/shared (car o))94 (loop (cdr o)))95 (else96 (display-string " . " port)97 (write/shared o)98 (display-char #\) port)))))99 ((vector? o)100 (display-string "#(" port)101 (write/shared (vector-ref o 0))102 (let ((len (vector-length o)))103 (do ((i 1 (fx+ i 1)))104 ((fx= i len)105 (display-char #\) port))106 (display-char #\space port)107 (write/shared (vector-ref o i)))))))108109 (define (write/shared o)110 (if (uninteresting? o)111 (writer o port)112 (let* ((p (assq o shared))113 (d (cdr p)))114 (cond ((not d)115 (write-interesting/shared o))116 ((number? d)117 (display-char #\# port)118 (writer d port)119 (display-char #\# port))120 (else121 (display-char #\# port)122 (writer label port)123 (display-char #\= port)124 (assign-label! p)125 (write-interesting/shared o))))))126127 (write/shared obj))128129 (: display (* #!optional output-port -> undefined))130 (define (display o . p)131 (write-with-shared-structure132 display-simple133 o134 #t135 (optional p (current-output-port))))136137 (: write (* #!optional output-port -> undefined))138 (define (write o . p)139 (write-with-shared-structure140 write-simple141 o142 #t143 (optional p (current-output-port))))144145 (: write-shared (* #!optional output-port -> undefined))146 (define (write-shared o . p)147 (write-with-shared-structure148 write-simple149 o150 #f151 (optional p (current-output-port)))))