(module datatype mzscheme
(require (lib "contract.ss"))
(require-for-syntax (lib "boundmap.ss" "syntax"))
(define-for-syntax datatypes (make-module-identifier-mapping))
(define-syntax (define-datatype stx)
(syntax-case stx ()
[(_ type [variant (field ...)] ...)
(let ([datatype-info
(list #'type (syntax->list #'([variant (field ...)] ...)))])
(module-identifier-mapping-put! datatypes #'type datatype-info)
#'(begin
(define-struct type ())
(define-struct (variant type) (field ...))
...))]))
(define-syntax (provide-datatype stx)
(syntax-case stx ()
[(_ type)
(let ([static-info (module-identifier-mapping-get datatypes #'type)]
[predicate-id (list-ref (syntax-local-value #'type) 2)])
(with-syntax ([([variant (arg ...)] ...) (cadr static-info)])
#`(begin
(provide #,predicate-id)
(provide (struct variant (arg ...)))
...)))]))
(define-syntax (provide-datatype/contract stx)
(syntax-case stx ()
[(_ type [variant (contract ...)] ...)
(let ([static-info (module-identifier-mapping-get datatypes #'type)]
[predicate-id (list-ref (syntax-local-value #'type) 2)])
(with-syntax ([([variant (arg ...)] ...) (cadr static-info)])
#`(begin
(provide #,predicate-id)
(provide/contract (struct (variant type) ([arg contract] ...)))
...)))]))
(provide define-datatype provide-datatype provide-datatype/contract))