(module struct-ct mzscheme
(require-for-syntax "../stx.ss")
(provide register-struct-info
static-struct-info
map-static-struct-frames
(struct info:field (field accessor mutator init?))
(struct base-info:struct
(descriptor constructor predicate field-infos
super complete?))
(struct info:struct
(name descriptor super constructor predicate
gen-accessor gen-mutator field-infos props total-field-count)))
(define static-info-table (make-hash-table 'weak))
(define-struct info:struct
(name descriptor super constructor predicate
gen-accessor gen-mutator field-infos props total-field-count))
(define-struct base-info:struct
(descriptor constructor predicate field-infos super complete?))
(define-struct info:field (field accessor mutator init?))
(define-syntax (register-struct-info stx)
(syntax-case stx ()
[(_ name descriptor super constructor predicate gen-accessor gen-mutator
[(field accessor mutator init?) ...])
(with-syntax ([std-info-expr
#`(let ((c (syntax-local-certifier)))
(list-immutable (c #'descriptor)
(c #'constructor)
(c #'predicate)
#,(with-syntax ([(accessor ...)
(reverse
(syntax->list
#'(accessor ...)))])
#'(list-immutable (c #'accessor) ...))
#,(with-syntax ([(mutator ...)
(reverse
(syntax->list
#'(mutator ...)))])
#'(list-immutable (c #'mutator) ...))
(c #'super)))]
[super-info-expr
(cond [(identifier? #'super)
#'(static-struct-info #'super)]
[(stx-false? #'super)
#'#f]
[(stx-true? #'super)
#'#t])])
#`(let ([std-info std-info-expr]
[super-info super-info-expr])
(hash-table-put!
static-info-table std-info
(let ((c (syntax-local-certifier)))
(make-info:struct
(c #'name)
(c #'descriptor)
super-info
(c #'constructor)
(c #'predicate)
(c #'gen-accessor)
(c #'gen-mutator)
(list-immutable
(make-info:field 'field
(c #'accessor)
(c #'mutator) init?)
...)
null
#,(cond [(identifier? #'super)
#`(if (info:struct-total-field-count super-info)
(+ (info:struct-total-field-count super-info)
#,(length (syntax->list #'(field ...))))
#'#f)]
[(stx-true? #'super)
(length (syntax->list #'(field ...)))]
[(stx-false? #'super)
#'#f]))))
std-info))]))
(define static-struct-info
(case-lambda
[(name thunk1 thunk2)
(let ([std-info (syntax-local-value name thunk1)])
(hash-table-get static-info-table std-info thunk2))]
[(name thunk)
(static-struct-info name thunk
(lambda ()
(raise-syntax-error
'define-struct*
"super struct type not defined via define-struct*"
name)))]
[(name)
(static-struct-info name
(lambda () (raise-syntax-error 'define-struct*
"super struct type not defined" name)))]))
(define (map-static-struct-frames f info)
(let loop ((info info))
(cond [(eq? info #t)
null]
[(info:struct? info)
(cons (f info) (loop (info:struct-super info)))]
[else
(error 'map-static-struct-frames
"struct has unknown ancestor: ~s" info)])))
)