<<>> <<;;; Records.scheme>> <<;;; Copyright Ó 1989, 1991 by Xerox Corporation. All rights reserved.>> <<;;; Last changed by Pavel on March 20, 1989 6:20:56 pm PST>> (export (make-record-type record-constructor record-predicate record-accessor record-updater) (define (make-record-type name field-names . rest) (define (compute-field-map parent-size field-names) (let loop ((index (+ parent-size 1)) (field-names field-names) (field-map '())) (if (null? field-names) (reverse field-map) (loop (+ index 1) (cdr field-names) (cons `(,(car field-names) . ,index) field-map))))) (let* ((nargs (length rest)) (parent (if (= nargs 0) #f (car rest))) (print-proc (if (<= nargs 1) #f (cadr rest)))) (unless (<= nargs 2) (error 'make-record-type (cddr rest) "Too many arguments")) (let* ((parent-map (if parent (descriptor-all-field-map parent) '())) (parent-size (if parent (descriptor-size parent) 0)) (field-map (compute-field-map parent-size field-names)) (all-field-map (append parent-map field-map)) (real-print-proc (or print-proc (and parent (descriptor-print-proc parent)) (default-printer name all-field-map))) (size (+ parent-size 1 (length field-names))) (new-cookie (cons real-print-proc size)) (cookie-map (cons `(,new-cookie . ,parent-size) (if parent (descriptor-cookie-map parent) '())))) (make-descriptor name ; name size ; size field-map ; field-map all-field-map ; all-field-map (map cdr all-field-map) ; indices cookie-map ; cookie-map print-proc ; print-proc )))) (define (record-constructor descriptor) (unless (descriptor? descriptor) (error 'record-constructor descriptor "not a record-type descriptor")) (let ((size (descriptor-size descriptor)) (count (length (descriptor-all-field-map descriptor))) (indices (descriptor-indices descriptor)) (cookie-map (descriptor-cookie-map descriptor)) (name (descriptor-name descriptor))) (lambda args "Record value constructor" (unless (= count (length args)) (error (format #f "~S constructor" name) args "Wrong number of arguments")) (let ((record (%make-record size))) (let loop ((map cookie-map)) (unless (null? map) (%record-set! record (cdar map) (caar map)) (loop (cdr map)))) (let loop ((args args) (indices indices)) (cond ((null? args) record) (else (%record-set! record (car indices) (car args)) (loop (cdr args) (cdr indices))))))))) (define (record-predicate descriptor) (unless (descriptor? descriptor) (error 'record-predicate descriptor "not a record-type descriptor")) (let ((cookie-map (descriptor-cookie-map descriptor))) (let ((size (descriptor-size descriptor)) (cookie (caar cookie-map)) (index (cdar cookie-map))) (lambda (value) "Record type predicate" (and (%record? value) (>= (%record-length value) size) (eq? (%record-ref value index) cookie)))))) (define (record-accessor descriptor field-name) (unless (descriptor? descriptor) (error 'record-accessor descriptor "not a record-type descriptor")) (let ((pair (assq field-name (descriptor-field-map descriptor))) (cookie-map (descriptor-cookie-map descriptor)) (name (descriptor-name descriptor))) (if (not pair) (error 'record-accessor field-name "unrecognized field name") (let ((index (cdr pair)) (size (descriptor-size descriptor)) (cookie (caar cookie-map)) (cookie-index (cdar cookie-map))) (lambda (record) "Record field accessor" (if (and (%record? record) (>= (%record-length record) size) (eq? (%record-ref record cookie-index) cookie)) (%record-ref record index) (error (format #f "~S accessor for type ~S" field-name name) record (format #f "not a ~S record" name)))))))) (define (record-updater descriptor field-name) (unless (descriptor? descriptor) (error 'record-updater descriptor "not a record-type descriptor")) (let ((pair (assq field-name (descriptor-field-map descriptor))) (cookie-map (descriptor-cookie-map descriptor)) (name (descriptor-name descriptor))) (if (not pair) (error 'record-updater field-name "unrecognized field name") (let ((index (cdr pair)) (size (descriptor-size descriptor)) (cookie (caar cookie-map)) (cookie-index (cdar cookie-map))) (lambda (record value) "Record field updater" (if (and (%record? record) (>= (%record-length record) size) (eq? (%record-ref record cookie-index) cookie)) (%record-set! record index value) (error (format #f "~S updater for type ~S" field-name name) record (format #f "not a ~S record" name)))))))) (define ((default-printer name all-field-map) port record display?) (format port "#<~S" name) (for-each (lambda (pair) (format port " ~S: ~S" (car pair) (%record-ref record (cdr pair)))) all-field-map) (display ">" port)) <<;;; Bootstrapping descriptors>> <<(make-record-type 'descriptor '(>> <> <> <> <> <> <> << ; in decreasing order of index (i.e., child first)>> <> <<))>> (define descriptor-cookie #f) (define (make-descriptor name size field-map all-field-map indices cookie-map print-proc) (let ((record (%make-record 8))) (%record-set! record 0 descriptor-cookie) (%record-set! record 1 name) (%record-set! record 2 size) (%record-set! record 3 field-map) (%record-set! record 4 all-field-map) (%record-set! record 5 indices) (%record-set! record 6 cookie-map) (%record-set! record 7 print-proc) record)) (define (descriptor? value) (and (%record? value) (= 8 (%record-length value)) (eq? (%record-ref value 0) descriptor-cookie))) (define ((make-descriptor-accessor name index) record) (if (descriptor? record) (%record-ref record index) (error (format #f "~S accessor for record-type descriptors" name) record "not a record-type descriptor"))) (define descriptor-name #f) (define descriptor-size #f) (define descriptor-field-map #f) (define descriptor-all-field-map #f) (define descriptor-indices #f) (define descriptor-cookie-map #f) (define descriptor-print-proc #f) (define (print-descriptor port descriptor display?) (format port "#" (descriptor-name descriptor))) (set! descriptor-cookie (cons print-descriptor 8)) (set! descriptor-name (make-descriptor-accessor 'name 1)) (set! descriptor-size (make-descriptor-accessor 'size 2)) (set! descriptor-field-map (make-descriptor-accessor 'field-map 3)) (set! descriptor-all-field-map (make-descriptor-accessor 'all-field-map 4)) (set! descriptor-indices (make-descriptor-accessor 'indices 5)) (set! descriptor-cookie-map (make-descriptor-accessor 'cookie-map 6)) (set! descriptor-print-proc (make-descriptor-accessor 'print-proc 7)) ) ; end export