;;; Ikarus Scheme -- A compiler for R6RS Scheme. ;;; Copyright (C) 2006,2007,2008 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 . (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) (die 'make-struct-type "not a valid field name" x)))) (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) (die 'make-struct-type "name must be a string" name)) (unless (list? fields) (die 'make-struct-type "fields must be a list" fields)) (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) (die 'make-struct-type "name must be a string" name)) (unless (list? fields) (die 'make-struct-type "fields must be a list" fields)) (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))) (die 'make-struct-type "definition mismatch")) 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) (die 'struct-type-name "not an rtd" rtd)) (rtd-name rtd))) (define struct-type-symbol (lambda (rtd) (unless (rtd? rtd) (die 'struct-type-symbol "not an rtd" rtd)) (rtd-symbol rtd))) (define struct-type-field-names (lambda (rtd) (unless (rtd? rtd) (die 'struct-type-field-names "not an rtd" rtd)) (rtd-fields rtd))) (define struct-constructor (lambda (rtd) (unless (rtd? rtd) (die 'struct-constructor "not an rtd")) (lambda args (let ([n (rtd-length rtd)]) (let ([r ($make-struct rtd n)]) (or (set-fields r args 0 n) (die 'struct-constructor "incorrect number of arguments to the constructor" rtd))))))) (define struct-predicate (lambda (rtd) (unless (rtd? rtd) (die 'struct-predicate "not an rtd")) (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))) (die who "out of range for rtd" i rtd)) i] [(symbol? i) (letrec ([lookup (lambda (n ls) (cond [(null? ls) (die who "not a field" rtd)] [(eq? i ($car ls)) n] [else (lookup ($fx+ n 1) ($cdr ls))]))]) (lookup 0 (rtd-fields rtd)))] [else (die who "not a valid index" i)]))) (define struct-field-accessor (lambda (rtd i) (unless (rtd? rtd) (die 'struct-field-accessor "not an rtd" rtd)) (let ([i (field-index i rtd 'struct-field-accessor)]) (lambda (x) (unless (and ($struct? x) (eq? ($struct-rtd x) rtd)) (die 'struct-field-accessor "not of correct type" x rtd)) ($struct-ref x i))))) (define struct-field-mutator (lambda (rtd i) (unless (rtd? rtd) (die 'struct-field-mutator "not an rtd" rtd)) (let ([i (field-index i rtd 'struct-field-mutator)]) (lambda (x v) (unless (and ($struct? x) (eq? ($struct-rtd x) rtd)) (die 'struct-field-mutator "not of correct type" x rtd)) ($struct-set! x i v))))) (define struct? (lambda (x . rest) (if (null? rest) ($struct? x) (let ([rtd ($car rest)]) (unless (null? ($cdr rest)) (die 'struct? "too many arguments")) (unless (rtd? rtd) (die 'struct? "not an rtd")) (and ($struct? x) (eq? ($struct-rtd x) rtd)))))) (define struct-rtd (lambda (x) (if ($struct? x) ($struct-rtd x) (die 'struct-rtd "not a struct" x)))) (define struct-length (lambda (x) (if ($struct? x) (rtd-length ($struct-rtd x)) (die 'struct-length "not a struct" x)))) (define struct-name (lambda (x) (if ($struct? x) (rtd-name ($struct-rtd x)) (die 'struct-name "not a struct" x)))) (define struct-printer (lambda (x) (if ($struct? x) (rtd-printer ($struct-rtd x)) (die 'struct-printer "not a struct" x)))) (define struct-ref (lambda (x i) (unless ($struct? x) (die 'struct-ref "not a struct" x)) (unless (fixnum? i) (die 'struct-ref "not a valid index" i)) (let ([n (rtd-length ($struct-rtd x))]) (unless (and ($fx>= i 0) ($fx< i n)) (die 'struct-ref "index is out of range" i x)) ($struct-ref x i)))) (define struct-set! (lambda (x i v) (unless ($struct? x) (die 'struct-set! "not a struct" x)) (unless (fixnum? i) (die 'struct-set! "not a valid index" i)) (let ([n (rtd-length ($struct-rtd x))]) (unless (and ($fx>= i 0) ($fx< i n)) (die 'struct-set! "index is out of range" i x)) ($struct-set! x i v)))) (define (set-rtd-printer! x p) (unless (rtd? x) (die 'set-rtd-printer! "not an rtd" x)) (unless (procedure? p) (die 'set-rtd-printer! "not a procedure" p)) ($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 wr) (unless (rtd? x) (die 'struct-type-printer "not an rtd")) (display "#<" p) (display (rtd-name x) p) (display " rtd>" p))) ) (library (ikarus systems structs) (export $struct-ref $struct/rtd?) (import (ikarus)) (define $struct-ref struct-ref) (define ($struct/rtd? x rtd) (import (ikarus system $structs)) ($struct/rtd? x rtd)))