2007-10-25 16:27:34 -04:00
|
|
|
;;; Ikarus Scheme -- A compiler for R6RS Scheme.
|
2008-01-29 00:34:34 -05:00
|
|
|
;;; Copyright (C) 2006,2007,2008 Abdulaziz Ghuloum
|
2007-10-25 16:27:34 -04:00
|
|
|
;;;
|
|
|
|
;;; 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-10-12 02:59:27 -04:00
|
|
|
|
|
|
|
|
|
|
|
(library (ikarus structs)
|
|
|
|
(export
|
|
|
|
make-struct-type struct-type-name struct-type-symbol
|
|
|
|
struct-type-field-names struct-constructor struct-predicate
|
|
|
|
struct-field-accessor struct-field-mutator struct? struct-rtd
|
|
|
|
set-rtd-printer!
|
|
|
|
(rename (struct-rtd struct-type-descriptor))
|
|
|
|
struct-name struct-printer struct-length struct-ref struct-set!)
|
|
|
|
|
|
|
|
(import
|
|
|
|
(ikarus system $structs)
|
|
|
|
(ikarus system $pairs)
|
|
|
|
(ikarus system $fx)
|
|
|
|
(except (ikarus)
|
|
|
|
make-struct-type struct-type-name struct-type-symbol
|
|
|
|
struct-type-field-names struct-constructor struct-predicate
|
|
|
|
struct-field-accessor struct-field-mutator struct? struct-rtd
|
|
|
|
struct-type-descriptor struct-name struct-printer struct-length
|
|
|
|
struct-ref struct-set! set-rtd-printer!))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(define rtd?
|
|
|
|
(lambda (x)
|
|
|
|
(and ($struct? x)
|
|
|
|
(eq? ($struct-rtd x) (base-rtd)))))
|
|
|
|
|
|
|
|
(define rtd-name
|
|
|
|
(lambda (rtd)
|
|
|
|
($struct-ref rtd 0)))
|
|
|
|
|
|
|
|
(define rtd-length
|
|
|
|
(lambda (rtd)
|
|
|
|
($struct-ref rtd 1)))
|
|
|
|
|
|
|
|
(define rtd-fields
|
|
|
|
(lambda (rtd)
|
|
|
|
($struct-ref rtd 2)))
|
|
|
|
|
|
|
|
(define rtd-printer
|
|
|
|
(lambda (rtd)
|
|
|
|
($struct-ref rtd 3)))
|
|
|
|
|
|
|
|
(define rtd-symbol
|
|
|
|
(lambda (rtd)
|
|
|
|
($struct-ref rtd 4)))
|
|
|
|
|
|
|
|
(define set-rtd-name!
|
|
|
|
(lambda (rtd name)
|
|
|
|
($struct-set! rtd 0 name)))
|
|
|
|
|
|
|
|
(define set-rtd-length!
|
|
|
|
(lambda (rtd n)
|
|
|
|
($struct-set! rtd 1 n)))
|
|
|
|
|
|
|
|
(define set-rtd-fields!
|
|
|
|
(lambda (rtd fields)
|
|
|
|
($struct-set! rtd 2 fields)))
|
|
|
|
|
|
|
|
(define $set-rtd-printer!
|
|
|
|
(lambda (rtd printer)
|
|
|
|
($struct-set! rtd 3 printer)))
|
|
|
|
|
|
|
|
(define set-rtd-symbol!
|
|
|
|
(lambda (rtd symbol)
|
|
|
|
($struct-set! rtd 4 symbol)))
|
|
|
|
|
|
|
|
(define make-rtd
|
|
|
|
(lambda (name fields printer symbol)
|
|
|
|
($struct (base-rtd) name (length fields) fields printer symbol)))
|
|
|
|
|
|
|
|
(define verify-field
|
|
|
|
(lambda (x)
|
|
|
|
(unless (symbol? x)
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'make-struct-type "not a valid field name" x))))
|
2007-10-12 02:59:27 -04:00
|
|
|
|
|
|
|
(define set-fields
|
|
|
|
(lambda (r f* i n)
|
|
|
|
(cond
|
|
|
|
[(null? f*)
|
|
|
|
(if ($fx= i n)
|
|
|
|
r
|
|
|
|
#f)]
|
|
|
|
[($fx< i n)
|
|
|
|
(if (null? f*)
|
|
|
|
#f
|
|
|
|
(begin
|
|
|
|
($struct-set! r i ($car f*))
|
|
|
|
(set-fields r ($cdr f*) ($fxadd1 i) n)))]
|
|
|
|
[else #f])))
|
|
|
|
|
|
|
|
(define make-struct-type
|
|
|
|
(case-lambda
|
|
|
|
[(name fields)
|
|
|
|
(unless (string? name)
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'make-struct-type "name must be a string" name))
|
2007-10-12 02:59:27 -04:00
|
|
|
(unless (list? fields)
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'make-struct-type "fields must be a list" fields))
|
2007-10-12 02:59:27 -04:00
|
|
|
(for-each verify-field fields)
|
|
|
|
(let ([g (gensym name)])
|
|
|
|
(let ([rtd (make-rtd name fields #f g)])
|
|
|
|
(set-symbol-value! g rtd)
|
|
|
|
rtd))]
|
|
|
|
[(name fields g)
|
|
|
|
(unless (string? name)
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'make-struct-type "name must be a string" name))
|
2007-10-12 02:59:27 -04:00
|
|
|
(unless (list? fields)
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'make-struct-type "fields must be a list" fields))
|
2007-10-12 02:59:27 -04:00
|
|
|
(for-each verify-field fields)
|
|
|
|
(cond
|
|
|
|
[(symbol-bound? g)
|
|
|
|
(let ([rtd (symbol-value g)])
|
|
|
|
(unless (and (string=? name (struct-type-name rtd))
|
|
|
|
(equal? fields (struct-type-field-names rtd)))
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'make-struct-type "definition mismatch"))
|
2007-10-12 02:59:27 -04:00
|
|
|
rtd)]
|
|
|
|
[else
|
|
|
|
(let ([rtd (make-rtd name fields #f g)])
|
|
|
|
(set-symbol-value! g rtd)
|
|
|
|
rtd)])]))
|
|
|
|
|
|
|
|
(define struct-type-name
|
|
|
|
(lambda (rtd)
|
|
|
|
(unless (rtd? rtd)
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'struct-type-name "not an rtd" rtd))
|
2007-10-12 02:59:27 -04:00
|
|
|
(rtd-name rtd)))
|
|
|
|
|
|
|
|
(define struct-type-symbol
|
|
|
|
(lambda (rtd)
|
|
|
|
(unless (rtd? rtd)
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'struct-type-symbol "not an rtd" rtd))
|
2007-10-12 02:59:27 -04:00
|
|
|
(rtd-symbol rtd)))
|
|
|
|
|
|
|
|
(define struct-type-field-names
|
|
|
|
(lambda (rtd)
|
|
|
|
(unless (rtd? rtd)
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'struct-type-field-names "not an rtd" rtd))
|
2007-10-12 02:59:27 -04:00
|
|
|
(rtd-fields rtd)))
|
|
|
|
|
|
|
|
|
|
|
|
(define struct-constructor
|
|
|
|
(lambda (rtd)
|
|
|
|
(unless (rtd? rtd)
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'struct-constructor "not an rtd"))
|
2007-10-12 02:59:27 -04:00
|
|
|
(lambda args
|
|
|
|
(let ([n (rtd-length rtd)])
|
|
|
|
(let ([r ($make-struct rtd n)])
|
|
|
|
(or (set-fields r args 0 n)
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'struct-constructor
|
2007-10-25 14:32:26 -04:00
|
|
|
"incorrect number of arguments to the constructor"
|
2007-10-12 02:59:27 -04:00
|
|
|
rtd)))))))
|
|
|
|
|
|
|
|
(define struct-predicate
|
|
|
|
(lambda (rtd)
|
|
|
|
(unless (rtd? rtd)
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'struct-predicate "not an rtd"))
|
2007-10-12 02:59:27 -04:00
|
|
|
(lambda (x)
|
|
|
|
(and ($struct? x)
|
|
|
|
(eq? ($struct-rtd x) rtd)))))
|
|
|
|
|
|
|
|
(define field-index
|
|
|
|
(lambda (i rtd who)
|
|
|
|
(cond
|
|
|
|
[(fixnum? i)
|
|
|
|
(unless (and ($fx>= i 0) ($fx< i (rtd-length rtd)))
|
2007-12-15 08:22:49 -05:00
|
|
|
(die who "out of range for rtd" i rtd))
|
2007-10-12 02:59:27 -04:00
|
|
|
i]
|
|
|
|
[(symbol? i)
|
|
|
|
(letrec ([lookup
|
|
|
|
(lambda (n ls)
|
|
|
|
(cond
|
|
|
|
[(null? ls)
|
2007-12-15 08:22:49 -05:00
|
|
|
(die who "not a field" rtd)]
|
2007-10-12 02:59:27 -04:00
|
|
|
[(eq? i ($car ls)) n]
|
|
|
|
[else (lookup ($fx+ n 1) ($cdr ls))]))])
|
|
|
|
(lookup 0 (rtd-fields rtd)))]
|
2007-12-15 08:22:49 -05:00
|
|
|
[else (die who "not a valid index" i)])))
|
2007-10-12 02:59:27 -04:00
|
|
|
|
|
|
|
(define struct-field-accessor
|
|
|
|
(lambda (rtd i)
|
|
|
|
(unless (rtd? rtd)
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'struct-field-accessor "not an rtd" rtd))
|
2007-10-12 02:59:27 -04:00
|
|
|
(let ([i (field-index i rtd 'struct-field-accessor)])
|
|
|
|
(lambda (x)
|
|
|
|
(unless (and ($struct? x)
|
|
|
|
(eq? ($struct-rtd x) rtd))
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'struct-field-accessor "not of correct type" x rtd))
|
2007-10-12 02:59:27 -04:00
|
|
|
($struct-ref x i)))))
|
|
|
|
|
|
|
|
(define struct-field-mutator
|
|
|
|
(lambda (rtd i)
|
|
|
|
(unless (rtd? rtd)
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'struct-field-mutator "not an rtd" rtd))
|
2007-10-12 02:59:27 -04:00
|
|
|
(let ([i (field-index i rtd 'struct-field-mutator)])
|
|
|
|
(lambda (x v)
|
|
|
|
(unless (and ($struct? x)
|
|
|
|
(eq? ($struct-rtd x) rtd))
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'struct-field-mutator "not of correct type" x rtd))
|
2007-10-12 02:59:27 -04:00
|
|
|
($struct-set! x i v)))))
|
|
|
|
|
|
|
|
(define struct?
|
|
|
|
(lambda (x . rest)
|
|
|
|
(if (null? rest)
|
|
|
|
($struct? x)
|
|
|
|
(let ([rtd ($car rest)])
|
|
|
|
(unless (null? ($cdr rest))
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'struct? "too many arguments"))
|
2007-10-12 02:59:27 -04:00
|
|
|
(unless (rtd? rtd)
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'struct? "not an rtd"))
|
2007-10-12 02:59:27 -04:00
|
|
|
(and ($struct? x)
|
|
|
|
(eq? ($struct-rtd x) rtd))))))
|
|
|
|
|
|
|
|
(define struct-rtd
|
|
|
|
(lambda (x)
|
|
|
|
(if ($struct? x)
|
|
|
|
($struct-rtd x)
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'struct-rtd "not a struct" x))))
|
2007-10-12 02:59:27 -04:00
|
|
|
|
|
|
|
(define struct-length
|
|
|
|
(lambda (x)
|
|
|
|
(if ($struct? x)
|
|
|
|
(rtd-length ($struct-rtd x))
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'struct-length "not a struct" x))))
|
2007-10-12 02:59:27 -04:00
|
|
|
|
|
|
|
(define struct-name
|
|
|
|
(lambda (x)
|
|
|
|
(if ($struct? x)
|
|
|
|
(rtd-name ($struct-rtd x))
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'struct-name "not a struct" x))))
|
2007-10-12 02:59:27 -04:00
|
|
|
|
|
|
|
(define struct-printer
|
|
|
|
(lambda (x)
|
|
|
|
(if ($struct? x)
|
|
|
|
(rtd-printer ($struct-rtd x))
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'struct-printer "not a struct" x))))
|
2007-10-12 02:59:27 -04:00
|
|
|
|
|
|
|
(define struct-ref
|
|
|
|
(lambda (x i)
|
2007-12-15 08:22:49 -05:00
|
|
|
(unless ($struct? x) (die 'struct-ref "not a struct" x))
|
|
|
|
(unless (fixnum? i) (die 'struct-ref "not a valid index" i))
|
2007-10-12 02:59:27 -04:00
|
|
|
(let ([n (rtd-length ($struct-rtd x))])
|
|
|
|
(unless (and ($fx>= i 0) ($fx< i n))
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'struct-ref "index is out of range" i x))
|
2007-10-12 02:59:27 -04:00
|
|
|
($struct-ref x i))))
|
|
|
|
|
|
|
|
(define struct-set!
|
|
|
|
(lambda (x i v)
|
2007-12-15 08:22:49 -05:00
|
|
|
(unless ($struct? x) (die 'struct-set! "not a struct" x))
|
|
|
|
(unless (fixnum? i) (die 'struct-set! "not a valid index" i))
|
2007-10-12 02:59:27 -04:00
|
|
|
(let ([n (rtd-length ($struct-rtd x))])
|
|
|
|
(unless (and ($fx>= i 0) ($fx< i n))
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'struct-set! "index is out of range" i x))
|
2007-10-12 02:59:27 -04:00
|
|
|
($struct-set! x i v))))
|
|
|
|
|
|
|
|
(define (set-rtd-printer! x p)
|
|
|
|
(unless (rtd? x)
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'set-rtd-printer! "not an rtd" x))
|
2007-10-12 02:59:27 -04:00
|
|
|
(unless (procedure? p)
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'set-rtd-printer! "not a procedure" p))
|
2007-10-12 02:59:27 -04:00
|
|
|
($set-rtd-printer! x p))
|
|
|
|
|
|
|
|
(set-rtd-fields! (base-rtd) '(name fields length printer symbol))
|
|
|
|
(set-rtd-name! (base-rtd) "base-rtd")
|
|
|
|
($set-rtd-printer! (base-rtd)
|
|
|
|
(lambda (x p)
|
|
|
|
(unless (rtd? x)
|
2007-12-15 08:22:49 -05:00
|
|
|
(die 'struct-type-printer "not an rtd"))
|
2007-10-12 02:59:27 -04:00
|
|
|
(display "#<" p)
|
|
|
|
(display (rtd-name x) p)
|
|
|
|
(display " rtd>" p)))
|
|
|
|
)
|