(module hierarchy mzscheme
(require-for-syntax (lib "boundmap.ss" "syntax"))
(require (lib "contract.ss"))
(define-for-syntax hierarchies (make-module-identifier-mapping))
(define-for-syntax disable-hierarchy-contracts? (make-parameter #f))
(define-syntax (without-hierarchy-contracts stx)
(syntax-case stx ()
[(_ e)
(parameterize ([disable-hierarchy-contracts? #t])
(local-expand #'e
(syntax-local-context)
(list #'define-values
#'define-syntaxes
#'define-struct
#'provide
#'require)))]))
(define-syntax (define-hierarchy/1 stx)
(syntax-case stx ()
[(_ (name parent) (field ...) child-name ...)
(with-syntax ([(parent-field ...) (list-ref (module-identifier-mapping-get hierarchies #'parent) 2)])
(module-identifier-mapping-put! hierarchies #'name
(list #'parent
#'(field ...)
#'(parent-field ... field ...)
#'(child-name ...)))
#'(define-struct (name parent) (field ...)))]
[(_ name (field ...) child-name ...)
(begin
(module-identifier-mapping-put! hierarchies #'name
(list #f
#'(field ...)
#'(field ...)
#'(child-name ...)))
#'(define-struct name (field ...)))]))
(define-syntax (provide-hierarchy/contract/1 stx)
(syntax-case stx ()
[(_ name (contract ...))
(let ([static-info (module-identifier-mapping-get hierarchies #'name)])
(with-syntax ([(local-field ...) (list-ref static-info 1)]
[(every-field ...) (list-ref static-info 2)])
(cond
[(disable-hierarchy-contracts?)
#'(provide (struct name (local-field ...)))]
[(car static-info)
#`(provide/contract (struct (name #,(car static-info)) ([every-field contract] ...)))]
[else
#'(provide/contract (struct name ([every-field contract] ...)))])))]))
(define-syntax define-hierarchy
(syntax-rules ()
[(_ (name (field ...) (child-name etc ...) ...))
(begin
(define-hierarchy/1 name (field ...) child-name ...)
(define-hierarchy/child name child-name etc ...)
...)]))
(define-syntax define-hierarchy/child
(syntax-rules ()
[(_ parent name (field ...) (child-name etc ...) ...)
(begin
(define-hierarchy/1 (name parent) (field ...) child-name ...)
(define-hierarchy/child name child-name etc ...)
...)]))
(define-syntax provide-hierarchy/contract
(syntax-rules ()
[(_ (name (contract ...)
(child (child-contract ...) etc ...)
...))
(begin
(provide-hierarchy/contract/1 name (contract ...))
(provide-hierarchy/contract (child (contract ... child-contract ...) etc ...))
...)]))
(define-syntax (provide-hierarchy stx)
(syntax-case stx ()
[(_ name)
(let ([static-info (module-identifier-mapping-get hierarchies #'name)])
(with-syntax ([(field ...) (list-ref static-info 1)]
[(child ...) (list-ref static-info 3)])
#'(begin
(provide (struct name (field ...)))
(provide-hierarchy child)
...)))]))
(define-syntax define-hierarchy/provide/contract
(syntax-rules ()
[(_ (name ([field contract] ...)
(child ([child-field child-contract] ...) etc ...)
...))
(begin
(both->define (name ([field contract] ...)
(child ([child-field child-contract] ...) etc ...)
...))
(both->provide (name (contract ...)
(child ([child-field child-contract] ...) etc ...)
...)))]))
(define-syntax both->define
(syntax-rules ()
[(_ (name ([field contract] ...)
(child ([child-field child-contract] ...) etc ...)
...))
(begin
(define-hierarchy/1 name (field ...) child ...)
(both->define/child ((child name) ([child-field child-contract] ...) etc ...))
...)]))
(define-syntax both->define/child
(syntax-rules ()
[(_ ((name parent) ([field contract] ...)
(child ([child-field child-contract] ...) etc ...)
...))
(begin
(define-hierarchy/1 (name parent) (field ...) child ...)
(both->define/child ((child name) ([child-field child-contract] ...) etc ...))
...)]))
(define-syntax both->provide
(syntax-rules ()
[(_ (name (contract ...)
(child ([child-field child-contract] ...) etc ...)
...))
(begin
(provide-hierarchy/contract/1 name (contract ...))
(both->provide (child (contract ... child-contract ...) etc ...))
...)]))
(provide define-hierarchy provide-hierarchy
provide-hierarchy/contract define-hierarchy/provide/contract
without-hierarchy-contracts))