Initial commit of RLA-style output library, src/lib/writer.rls.

This commit is contained in:
Jesse D. McDonald 2011-12-08 17:19:59 -06:00
parent 33ef2ce582
commit dcacdecfff
2 changed files with 211 additions and 0 deletions

178
src/lib/writer.rls Normal file
View File

@ -0,0 +1,178 @@
;(load "lib/primitives.rls")
;(load "lib/primitive/foldl.rls")
;(load "lib/primitive/foldr.rls")
;(load "lib/primitive/reverse.rls")
;(load "lib/primitive/map.rls")
;(load "lib/primitive/append.rls")
;(load "lib/util.rls")
;(load "lib/hash-table.rls")
;(load "lib/symbols.rls")
;(load "lib/keywords.rls")
;(load "lib/parameters.rls")
;(load "lib/abort.rls")
;(load "lib/errors.rls")
;(load "lib/port.rls")
;(load "lib/display.rls")
(define (default-unwritable-value-handler value port)
(write-string "#<unwritable>" port))
(define current-unwritable-value-handler (make-parameter default-unwritable-value-handler))
(define next-reference-number (make-parameter #f))
(define current-reference-table (make-parameter #f))
(define (write-rla value [port (current-output-port)])
(call-with-parameters
(lambda ()
(identify-backrefs value)
(write-rla-value value))
(list current-output-port port)
(list current-reference-table (make-hash-table hash-value eq?))
(list next-reference-number 0)))
(define (identify-backrefs value)
(cond
[(or (boolean? value) (fixnum? value) (float? value) (builtin->string value)) void]
[else
(let ([new? #t])
(hash-table-insert (current-reference-table) value #f
(lambda (oldv) (set! new? #f) #t))
(when new?
(cond
[(box? value)
(identify-backrefs (unbox value))]
[(weak-box? value)
(identify-backrefs (weak-unbox value))]
[(pair? value)
(identify-backrefs (car value))
(identify-backrefs (cdr value))]
[(struct? value)
(identify-backrefs (struct-type value))
(let ([nslots (struct-nslots value)])
(let iter ([n 0])
(when (fix< n nslots)
(identify-backrefs (struct-ref value n))
(iter (fix+ n 1)))))]
[(vector? value)
(let ([size (vector-size value)])
(let iter ([n 0])
(when (fix< n size)
(identify-backrefs (vector-ref value n))
(iter (fix+ n 1)))))])))]))
(define (take-next-number)
(let ([n (next-reference-number)])
(next-reference-number (fix+ n 1))
n))
(define (write-rla-value value)
(cond
[(eq? value #f) (write-string "#f")]
[(eq? value #t) (write-string "#t")]
[(eq? value '()) (write-string "()")]
[(fixnum? value) (write-string (number->string value))]
[(float? value) (write-string "#<float>")]
[else (let ([builtin-name (builtin->string value)])
(if builtin-name
(write-builtin builtin-name)
(write-rla-object/backref value)))]))
(define (write-builtin name)
(write-string "#=")
(write-rla-byte-string name))
(define (write-rla-object/backref obj)
(let* ([ht (current-reference-table)]
[backref (hash-table-lookup ht obj)])
(cond
[(fixnum? backref)
(write-backref backref)]
[backref
(let ([n (take-next-number)])
(hash-table-insert ht obj n)
(write-backref-definition n)
(write-rla-object obj))]
[else
(write-rla-object obj)])))
(define (write-backref number)
(write-char #\#)
(write-char #\=)
(display number))
(define (write-backref-definition number)
(write-char #\#)
(display number)
(write-char #\=))
(define (write-rla-object obj)
(when (immutable? obj) (write-string "#@"))
(cond
[(box? obj) (write-string "#&")
(write-rla-value (unbox obj))]
[(weak-box? obj) (write-string "#W&")
(write-rla-value (weak-unbox obj))]
[(pair? obj) (write-rla-list obj)]
[(struct? obj) (write-rla-struct obj)]
[(vector? obj) (write-rla-vector obj)]
[(byte-string? obj) (write-rla-byte-string obj)]
[else ((current-unwritable-value-handler) obj (current-output-port))]))
(define (write-rla-byte-string str)
(define (number->hexadecimal digit) (byte-string-ref "0123456789abcdef" digit))
(write-char #\")
(let iter ([i 0])
(when (fix< i (byte-string-size str))
(let ([ch (byte-string-ref str i)])
(if (or (and (fix>= ch 32) (fix<= ch 33))
(and (fix>= ch 35) (fix<= ch 91))
(and (fix>= ch 93) (fix<= ch 126)))
(write-char ch)
(begin
(write-string "\\x")
(write-char (number->hexadecimal (fix/ ch 16)))
(write-char (number->hexadecimal (fix% ch 16))))))
(iter (fix+ i 1))))
(write-char #\"))
(define (write-rla-list lst)
(write-char #\()
(write-rla-value (car lst))
(let iter ([rst (cdr lst)])
(cond
[(null? rst)
(write-char #\))]
[(or (not (pair? rst))
(hash-table-lookup (current-reference-table) rst))
(write-string " . ")
(write-rla-value rst)
(write-char #\))]
[else
(write-char #\Space)
(write-rla-value (car rst))
(iter (cdr rst))])))
(define (write-rla-struct obj)
(write-string "#S(")
(write-rla-value (struct-type obj))
(let ([nslots (struct-nslots obj)])
(let iter ([n 0])
(when (fix< n nslots)
(write-char #\Space)
(write-rla-value (struct-ref obj n))
(iter (fix+ n 1)))))
(write-char #\)))
(define (write-rla-vector obj)
(write-string "#(")
(let ([size (vector-size obj)])
(let iter ([n 0])
(when (fix< n size)
(when (fix> n 0)
(write-char #\Space))
(write-rla-value (vector-ref obj n))
(iter (fix+ n 1)))))
(write-char #\)))
; vim:set syntax=scheme sw=2 expandtab:

33
src/test-writer.rls Normal file
View File

@ -0,0 +1,33 @@
(load "lib/primitives.rls")
(load "lib/primitive/foldl.rls")
(load "lib/primitive/foldr.rls")
(load "lib/primitive/reverse.rls")
(load "lib/primitive/map.rls")
(load "lib/primitive/append.rls")
(load "lib/util.rls")
(load "lib/hash-table.rls")
(load "lib/symbols.rls")
(load "lib/keywords.rls")
(load "lib/parameters.rls")
(load "lib/abort.rls")
(load "lib/errors.rls")
(load "lib/port.rls")
(load "lib/display.rls")
(load "lib/writer.rls")
(write-rla 4)
(write-char #\Newline)
(write-rla '(1 2 3))
(write-char #\Newline)
(write-rla (let ([x (cons 1 '())]) (set-cdr! x x) x))
(write-char #\Newline)
(write-rla "abc")
(write-char #\Newline)
(write-rla "\n")
(write-char #\Newline)
(write-rla '#(1 2 3))
(write-char #\Newline)
(write-rla 'a)
(write-char #\Newline)
(write-rla (lambda () 'a))
(write-char #\Newline)