2007-10-25 16:27:34 -04:00
|
|
|
;;; Ikarus Scheme -- A compiler for R6RS Scheme.
|
|
|
|
;;; Copyright (C) 2006,2007 Abdulaziz Ghuloum
|
|
|
|
;;;
|
|
|
|
;;; This program is free software: you can redistribute it and/or modify
|
|
|
|
;;; it under the terms of the GNU General Public License version 3 as
|
|
|
|
;;; published by the Free Software Foundation.
|
|
|
|
;;;
|
|
|
|
;;; This program 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
|
|
|
|
;;; General Public License for more details.
|
|
|
|
;;;
|
|
|
|
;;; You should have received a copy of the GNU General Public License
|
|
|
|
;;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
2007-05-15 11:37:43 -04:00
|
|
|
|
|
|
|
(library (ikarus fasl write)
|
|
|
|
(export fasl-write)
|
|
|
|
(import
|
2007-10-09 09:22:02 -04:00
|
|
|
(rnrs hashtables)
|
2007-05-15 11:37:43 -04:00
|
|
|
(ikarus system $codes)
|
2007-05-22 19:01:07 -04:00
|
|
|
(ikarus system $pairs)
|
2007-10-12 02:59:27 -04:00
|
|
|
(ikarus system $structs)
|
2007-05-18 18:12:48 -04:00
|
|
|
(ikarus system $io)
|
|
|
|
(ikarus system $bytevectors)
|
|
|
|
(ikarus system $fx)
|
2007-05-21 23:09:45 -04:00
|
|
|
(ikarus system $chars)
|
|
|
|
(ikarus system $strings)
|
2007-06-14 12:38:00 -04:00
|
|
|
(ikarus system $flonums)
|
|
|
|
(ikarus system $bignums)
|
2007-09-04 20:18:11 -04:00
|
|
|
(except (ikarus code-objects) procedure-annotation)
|
2007-05-15 11:37:43 -04:00
|
|
|
(except (ikarus) fasl-write))
|
2007-12-08 14:52:35 -05:00
|
|
|
|
|
|
|
(define (put-tag c p)
|
|
|
|
(write-byte (char->integer c) p))
|
|
|
|
|
2007-05-15 11:37:43 -04:00
|
|
|
(define write-fixnum
|
|
|
|
(lambda (x p)
|
2007-10-25 14:32:26 -04:00
|
|
|
(unless (fixnum? x) (error 'write-fixnum "not a fixnum" x))
|
2007-05-18 15:47:06 -04:00
|
|
|
(write-byte (fxsll (fxlogand x #x3F) 2) p)
|
|
|
|
(write-byte (fxlogand (fxsra x 6) #xFF) p)
|
|
|
|
(write-byte (fxlogand (fxsra x 14) #xFF) p)
|
|
|
|
(write-byte (fxlogand (fxsra x 22) #xFF) p)))
|
2007-05-15 11:37:43 -04:00
|
|
|
(define write-int
|
|
|
|
(lambda (x p)
|
2007-10-25 14:32:26 -04:00
|
|
|
(unless (fixnum? x) (error 'write-int "not a fixnum" x))
|
2007-05-18 15:47:06 -04:00
|
|
|
(write-byte (fxlogand x #xFF) p)
|
|
|
|
(write-byte (fxlogand (fxsra x 8) #xFF) p)
|
|
|
|
(write-byte (fxlogand (fxsra x 16) #xFF) p)
|
|
|
|
(write-byte (fxlogand (fxsra x 24) #xFF) p)))
|
2007-05-15 11:37:43 -04:00
|
|
|
(define fasl-write-immediate
|
|
|
|
(lambda (x p)
|
|
|
|
(cond
|
2007-12-08 14:52:35 -05:00
|
|
|
[(null? x) (put-tag #\N p)]
|
2007-05-15 11:37:43 -04:00
|
|
|
[(fixnum? x)
|
2007-12-08 14:52:35 -05:00
|
|
|
(put-tag #\I p)
|
2007-05-15 11:37:43 -04:00
|
|
|
(write-fixnum x p)]
|
|
|
|
[(char? x)
|
2007-06-17 19:49:40 -04:00
|
|
|
(let ([n ($char->fixnum x)])
|
|
|
|
(if ($fx<= n 255)
|
|
|
|
(begin
|
2007-12-08 14:52:35 -05:00
|
|
|
(put-tag #\c p)
|
2007-06-17 19:49:40 -04:00
|
|
|
(write-byte n p))
|
|
|
|
(begin
|
2007-12-08 14:52:35 -05:00
|
|
|
(put-tag #\C p)
|
2007-06-17 19:49:40 -04:00
|
|
|
(write-int n p))))]
|
2007-05-15 11:37:43 -04:00
|
|
|
[(boolean? x)
|
2007-12-08 14:52:35 -05:00
|
|
|
(put-tag (if x #\T #\F) p)]
|
|
|
|
[(eof-object? x) (put-tag #\E p)]
|
|
|
|
[(eq? x (void)) (put-tag #\U p)]
|
2007-10-25 14:32:26 -04:00
|
|
|
[else (error 'fasl-write "not a fasl-writable immediate" x)])))
|
2007-05-15 11:37:43 -04:00
|
|
|
|
2007-05-21 23:09:45 -04:00
|
|
|
(define (ascii-string? s)
|
|
|
|
(let f ([s s] [i 0] [n (string-length s)])
|
|
|
|
(or ($fx= i n)
|
|
|
|
(and ($char<= ($string-ref s i) ($fixnum->char 127))
|
|
|
|
(f s ($fxadd1 i) n)))))
|
2007-12-08 14:52:35 -05:00
|
|
|
|
2007-05-22 19:01:07 -04:00
|
|
|
(define (count-unshared-cdrs x h n)
|
|
|
|
(cond
|
2007-10-09 09:22:02 -04:00
|
|
|
[(and (pair? x) (eq? (hashtable-ref h x #f) 0))
|
2007-05-22 19:01:07 -04:00
|
|
|
(count-unshared-cdrs ($cdr x) h ($fxadd1 n))]
|
|
|
|
[else n]))
|
2007-12-08 14:52:35 -05:00
|
|
|
|
2007-05-22 19:01:07 -04:00
|
|
|
(define (write-pairs x p h m n)
|
|
|
|
(cond
|
|
|
|
[($fx= n 0) (fasl-write-object x p h m)]
|
|
|
|
[else
|
|
|
|
(write-pairs (cdr x) p h
|
|
|
|
(fasl-write-object (car x) p h m)
|
|
|
|
($fxsub1 n))]))
|
|
|
|
|
2007-05-15 11:37:43 -04:00
|
|
|
(define do-write
|
|
|
|
(lambda (x p h m)
|
|
|
|
(cond
|
2007-05-22 19:01:07 -04:00
|
|
|
[(pair? x)
|
|
|
|
(let ([d ($cdr x)])
|
|
|
|
(let ([n (count-unshared-cdrs d h 0)])
|
|
|
|
(cond
|
|
|
|
[($fx= n 0)
|
2007-12-08 14:52:35 -05:00
|
|
|
(put-tag #\P p)
|
2007-05-22 19:01:07 -04:00
|
|
|
(fasl-write-object d p h
|
|
|
|
(fasl-write-object (car x) p h m))]
|
|
|
|
[else
|
|
|
|
(cond
|
|
|
|
[($fx<= n 255)
|
2007-12-08 14:52:35 -05:00
|
|
|
(put-tag #\l p)
|
2007-05-22 19:01:07 -04:00
|
|
|
(write-byte n p)]
|
|
|
|
[else
|
2007-12-08 14:52:35 -05:00
|
|
|
(put-tag #\L p)
|
2007-05-22 19:01:07 -04:00
|
|
|
(write-int n p)])
|
|
|
|
(write-pairs d p h
|
|
|
|
(fasl-write-object (car x) p h m)
|
|
|
|
n)])))]
|
2007-05-15 11:37:43 -04:00
|
|
|
[(vector? x)
|
2007-12-08 14:52:35 -05:00
|
|
|
(put-tag #\V p)
|
2007-05-15 11:37:43 -04:00
|
|
|
(write-int (vector-length x) p)
|
|
|
|
(let f ([x x] [i 0] [n (vector-length x)] [m m])
|
|
|
|
(cond
|
|
|
|
[(fx= i n) m]
|
|
|
|
[else
|
|
|
|
(f x (fxadd1 i) n
|
|
|
|
(fasl-write-object (vector-ref x i) p h m))]))]
|
|
|
|
[(string? x)
|
2007-05-21 23:09:45 -04:00
|
|
|
(cond
|
|
|
|
[(ascii-string? x)
|
2007-12-08 14:52:35 -05:00
|
|
|
(put-tag #\s p)
|
2007-05-21 23:09:45 -04:00
|
|
|
(write-int (string-length x) p)
|
|
|
|
(let f ([x x] [i 0] [n (string-length x)])
|
|
|
|
(unless (fx= i n)
|
2007-12-08 14:52:35 -05:00
|
|
|
(write-byte (char->integer (string-ref x i)) p)
|
2007-05-21 23:09:45 -04:00
|
|
|
(f x (fxadd1 i) n)))]
|
|
|
|
[else
|
2007-12-08 14:52:35 -05:00
|
|
|
(put-tag #\S p)
|
2007-05-21 23:09:45 -04:00
|
|
|
(write-int (string-length x) p)
|
|
|
|
(let f ([x x] [i 0] [n (string-length x)])
|
|
|
|
(unless (= i n)
|
|
|
|
(write-int (char->integer (string-ref x i)) p)
|
|
|
|
(f x (fxadd1 i) n)))])
|
|
|
|
m]
|
2007-05-15 11:37:43 -04:00
|
|
|
[(gensym? x)
|
2007-12-08 14:52:35 -05:00
|
|
|
(put-tag #\G p)
|
2007-05-15 11:37:43 -04:00
|
|
|
(fasl-write-object (gensym->unique-string x) p h
|
|
|
|
(fasl-write-object (symbol->string x) p h m))]
|
|
|
|
[(symbol? x)
|
2007-12-08 14:52:35 -05:00
|
|
|
(put-tag #\M p)
|
2007-05-15 11:37:43 -04:00
|
|
|
(fasl-write-object (symbol->string x) p h m)]
|
|
|
|
[(code? x)
|
2007-12-08 14:52:35 -05:00
|
|
|
(put-tag #\x p)
|
2007-05-15 11:37:43 -04:00
|
|
|
(write-int (code-size x) p)
|
|
|
|
(write-fixnum (code-freevars x) p)
|
2007-10-10 04:41:11 -04:00
|
|
|
(let ([m (fasl-write-object ($code-annotation x) p h m)])
|
|
|
|
(let f ([i 0] [n (code-size x)])
|
|
|
|
(unless (fx= i n)
|
|
|
|
(write-byte (code-ref x i) p)
|
|
|
|
(f (fxadd1 i) n)))
|
|
|
|
(fasl-write-object (code-reloc-vector x) p h m))]
|
2007-10-12 02:59:27 -04:00
|
|
|
[(struct? x)
|
|
|
|
(let ([rtd (struct-type-descriptor x)])
|
2007-05-15 11:37:43 -04:00
|
|
|
(cond
|
|
|
|
[(eq? rtd (base-rtd))
|
|
|
|
;;; rtd record
|
2007-12-08 14:52:35 -05:00
|
|
|
(put-tag #\R p)
|
2007-10-12 02:59:27 -04:00
|
|
|
(let ([names (struct-type-field-names x)]
|
2007-05-15 11:37:43 -04:00
|
|
|
[m
|
2007-10-12 02:59:27 -04:00
|
|
|
(fasl-write-object (struct-type-symbol x) p h
|
|
|
|
(fasl-write-object (struct-type-name x) p h m))])
|
2007-05-15 11:37:43 -04:00
|
|
|
(write-int (length names) p)
|
|
|
|
(let f ([names names] [m m])
|
|
|
|
(cond
|
|
|
|
[(null? names) m]
|
|
|
|
[else
|
|
|
|
(f (cdr names)
|
|
|
|
(fasl-write-object (car names) p h m))])))]
|
|
|
|
[else
|
|
|
|
;;; non-rtd record
|
2007-12-08 14:52:35 -05:00
|
|
|
(put-tag #\{ p)
|
2007-10-12 02:59:27 -04:00
|
|
|
(write-int (length (struct-type-field-names rtd)) p)
|
|
|
|
(let f ([names (struct-type-field-names rtd)]
|
2007-05-15 11:37:43 -04:00
|
|
|
[m (fasl-write-object rtd p h m)])
|
|
|
|
(cond
|
|
|
|
[(null? names) m]
|
|
|
|
[else
|
|
|
|
(f (cdr names)
|
|
|
|
(fasl-write-object
|
2007-10-12 02:59:27 -04:00
|
|
|
((struct-field-accessor rtd (car names)) x)
|
2007-05-15 11:37:43 -04:00
|
|
|
p h m))]))]))]
|
|
|
|
[(procedure? x)
|
2007-12-08 14:52:35 -05:00
|
|
|
(put-tag #\Q p)
|
2007-05-15 11:37:43 -04:00
|
|
|
(fasl-write-object ($closure-code x) p h m)]
|
2007-05-18 18:12:48 -04:00
|
|
|
[(bytevector? x)
|
2007-12-08 14:52:35 -05:00
|
|
|
(put-tag #\v p)
|
2007-05-18 18:12:48 -04:00
|
|
|
(let ([n ($bytevector-length x)])
|
|
|
|
(write-int n p)
|
|
|
|
(write-bytevector x 0 n p))
|
|
|
|
m]
|
2007-06-14 12:38:00 -04:00
|
|
|
[(flonum? x)
|
2007-12-08 14:52:35 -05:00
|
|
|
(put-tag #\f p)
|
2007-06-14 12:38:00 -04:00
|
|
|
(write-byte ($flonum-u8-ref x 7) p)
|
2007-06-14 12:48:57 -04:00
|
|
|
(write-byte ($flonum-u8-ref x 6) p)
|
|
|
|
(write-byte ($flonum-u8-ref x 5) p)
|
|
|
|
(write-byte ($flonum-u8-ref x 4) p)
|
|
|
|
(write-byte ($flonum-u8-ref x 3) p)
|
|
|
|
(write-byte ($flonum-u8-ref x 2) p)
|
|
|
|
(write-byte ($flonum-u8-ref x 1) p)
|
|
|
|
(write-byte ($flonum-u8-ref x 0) p)
|
2007-06-14 12:38:00 -04:00
|
|
|
m]
|
|
|
|
[(ratnum? x)
|
2007-12-08 14:52:35 -05:00
|
|
|
(put-tag #\r p)
|
2007-06-14 12:38:00 -04:00
|
|
|
(fasl-write-object (numerator x) p h
|
|
|
|
(fasl-write-object (denominator x) p h m))]
|
|
|
|
[(bignum? x)
|
2007-12-08 14:52:35 -05:00
|
|
|
(put-tag #\b p)
|
2007-06-14 12:38:00 -04:00
|
|
|
(let ([sz ($bignum-size x)])
|
|
|
|
(write-int (if ($bignum-positive? x) sz (- sz)) p)
|
|
|
|
(let f ([i 0])
|
|
|
|
(unless (fx= i sz)
|
|
|
|
(write-byte ($bignum-byte-ref x i) p)
|
|
|
|
(f (fxadd1 i)))))
|
|
|
|
m]
|
2007-10-25 14:32:26 -04:00
|
|
|
[else (error 'fasl-write "not fasl-writable" x)])))
|
2007-05-18 18:12:48 -04:00
|
|
|
(define (write-bytevector x i j p)
|
|
|
|
(unless ($fx= i j)
|
|
|
|
($write-byte ($bytevector-u8-ref x i) p)
|
|
|
|
(write-bytevector x ($fxadd1 i) j p)))
|
2007-05-15 11:37:43 -04:00
|
|
|
(define fasl-write-object
|
|
|
|
(lambda (x p h m)
|
|
|
|
(cond
|
|
|
|
[(immediate? x) (fasl-write-immediate x p) m]
|
2007-10-09 09:22:02 -04:00
|
|
|
[(hashtable-ref h x #f) =>
|
2007-05-15 11:37:43 -04:00
|
|
|
(lambda (mark)
|
|
|
|
(unless (fixnum? mark)
|
2007-10-25 14:32:26 -04:00
|
|
|
(error 'fasl-write "BUG: invalid mark" mark))
|
2007-05-15 11:37:43 -04:00
|
|
|
(cond
|
|
|
|
[(fx= mark 0) ; singly referenced
|
|
|
|
(do-write x p h m)]
|
|
|
|
[(fx> mark 0) ; marked but not written
|
2007-10-09 09:22:02 -04:00
|
|
|
(hashtable-set! h x (fx- 0 m))
|
2007-12-08 14:52:35 -05:00
|
|
|
(put-tag #\> p)
|
2007-05-15 11:37:43 -04:00
|
|
|
(write-int m p)
|
|
|
|
(do-write x p h (fxadd1 m))]
|
|
|
|
[else
|
2007-12-08 14:52:35 -05:00
|
|
|
(put-tag #\< p)
|
2007-05-15 11:37:43 -04:00
|
|
|
(write-int (fx- 0 mark) p)
|
|
|
|
m]))]
|
2007-10-25 14:32:26 -04:00
|
|
|
[else (error 'fasl-write "BUG: not in hash table" x)])))
|
2007-05-15 11:37:43 -04:00
|
|
|
(define make-graph
|
|
|
|
(lambda (x h)
|
|
|
|
(unless (immediate? x)
|
|
|
|
(cond
|
2007-10-09 09:22:02 -04:00
|
|
|
[(hashtable-ref h x #f) =>
|
2007-05-15 11:37:43 -04:00
|
|
|
(lambda (i)
|
2007-10-09 09:22:02 -04:00
|
|
|
(hashtable-set! h x (fxadd1 i)))]
|
2007-05-15 11:37:43 -04:00
|
|
|
[else
|
2007-10-09 09:22:02 -04:00
|
|
|
(hashtable-set! h x 0)
|
2007-05-15 11:37:43 -04:00
|
|
|
(cond
|
|
|
|
[(pair? x)
|
|
|
|
(make-graph (car x) h)
|
|
|
|
(make-graph (cdr x) h)]
|
|
|
|
[(vector? x)
|
|
|
|
(let f ([x x] [i 0] [n (vector-length x)])
|
|
|
|
(unless (fx= i n)
|
|
|
|
(make-graph (vector-ref x i) h)
|
|
|
|
(f x (fxadd1 i) n)))]
|
|
|
|
[(symbol? x)
|
|
|
|
(make-graph (symbol->string x) h)
|
|
|
|
(when (gensym? x) (make-graph (gensym->unique-string x) h))]
|
|
|
|
[(string? x) (void)]
|
|
|
|
[(code? x)
|
2007-10-10 04:41:11 -04:00
|
|
|
(make-graph ($code-annotation x) h)
|
2007-05-15 11:37:43 -04:00
|
|
|
(make-graph (code-reloc-vector x) h)]
|
2007-10-12 02:59:27 -04:00
|
|
|
[(struct? x)
|
2007-05-15 11:37:43 -04:00
|
|
|
(when (eq? x (base-rtd))
|
|
|
|
(error 'fasl-write "base-rtd is not writable"))
|
2007-10-12 02:59:27 -04:00
|
|
|
(let ([rtd (struct-type-descriptor x)])
|
2007-05-15 11:37:43 -04:00
|
|
|
(cond
|
|
|
|
[(eq? rtd (base-rtd))
|
|
|
|
;;; this is an rtd
|
2007-10-12 02:59:27 -04:00
|
|
|
(make-graph (struct-type-name x) h)
|
|
|
|
(make-graph (struct-type-symbol x) h)
|
2007-05-15 11:37:43 -04:00
|
|
|
(for-each (lambda (x) (make-graph x h))
|
2007-10-12 02:59:27 -04:00
|
|
|
(struct-type-field-names x))]
|
2007-05-15 11:37:43 -04:00
|
|
|
[else
|
|
|
|
;;; this is a record
|
|
|
|
(make-graph rtd h)
|
|
|
|
(for-each
|
|
|
|
(lambda (name)
|
2007-10-12 02:59:27 -04:00
|
|
|
(make-graph ((struct-field-accessor rtd name) x) h))
|
|
|
|
(struct-type-field-names rtd))]))]
|
2007-05-15 11:37:43 -04:00
|
|
|
[(procedure? x)
|
|
|
|
(let ([code ($closure-code x)])
|
|
|
|
(unless (fxzero? (code-freevars code))
|
|
|
|
(error 'fasl-write
|
2007-12-08 14:52:35 -05:00
|
|
|
"Cannot write a non-thunk procedure; \
|
|
|
|
the one given has free vars"
|
|
|
|
(code-freevars code)))
|
2007-05-15 11:37:43 -04:00
|
|
|
(make-graph code h))]
|
2007-05-18 18:12:48 -04:00
|
|
|
[(bytevector? x) (void)]
|
2007-06-14 12:38:00 -04:00
|
|
|
[(flonum? x) (void)]
|
|
|
|
[(bignum? x) (void)]
|
|
|
|
[(ratnum? x)
|
|
|
|
(make-graph (numerator x) h)
|
|
|
|
(make-graph (denominator x) h)]
|
2007-10-25 14:32:26 -04:00
|
|
|
[else (error 'fasl-write "not fasl-writable" x)])]))))
|
2007-05-15 11:37:43 -04:00
|
|
|
(define fasl-write-to-port
|
|
|
|
(lambda (x port)
|
2007-10-10 07:09:18 -04:00
|
|
|
(let ([h (make-eq-hashtable)])
|
2007-05-15 11:37:43 -04:00
|
|
|
(make-graph x h)
|
2007-12-08 14:52:35 -05:00
|
|
|
(put-tag #\# port)
|
|
|
|
(put-tag #\@ port)
|
|
|
|
(put-tag #\I port)
|
|
|
|
(put-tag #\K port)
|
|
|
|
(put-tag #\0 port)
|
|
|
|
(put-tag #\1 port)
|
2007-05-15 11:37:43 -04:00
|
|
|
(fasl-write-object x port h 1)
|
|
|
|
(void))))
|
|
|
|
(define fasl-write
|
2007-12-08 14:52:35 -05:00
|
|
|
(case-lambda
|
|
|
|
[(x) (fasl-write-to-port x (current-output-port))]
|
|
|
|
[(x port)
|
|
|
|
(unless (output-port? port)
|
|
|
|
(error 'fasl-write "not an output port" port))
|
|
|
|
(fasl-write-to-port x port)])))
|