diff --git a/collects/mzlib/contract.ss b/collects/mzlib/contract.ss index 6d85921..0dbb994 100644 --- a/collects/mzlib/contract.ss +++ b/collects/mzlib/contract.ss @@ -1806,6 +1806,7 @@ (provide any? + flat-rec-contract union and/c not/f @@ -1824,6 +1825,31 @@ box-immutable/c box/p mixin-contract make-mixin-contract) + (define-syntax (flat-rec-contract stx) + (syntax-case stx () + [(_ name ctc ...) + (identifier? (syntax name)) + (with-syntax ([(ctc-id ...) (generate-temporaries (syntax (ctc ...)))] + [(pred-id ...) (generate-temporaries (syntax (ctc ...)))]) + (syntax + (let* ([pred (lambda (x) (error 'flat-rec-contract "applied too soon"))] + [name (flat-contract (let ([name (lambda (x) (pred x))]) name))]) + (let ([ctc-id (coerce-contract flat-rec-contract ctc)] ...) + (begin + (void) ;; ensure begin has at least one arg. + (unless (flat-contract? ctc-id) + (error 'flat-rec-contract "expected flat contracts as arguments, got ~e" ctc-id)) + ...) + (set! pred + (let ([pred-id (flat-contract-predicate ctc-id)] ...) + (lambda (x) + (or (pred-id x) ...)))) + name))))] + [(_ name ctc ...) + (raise-syntax-error 'flat-rec-contract "expected first argument to be an identifier" stx (syntax name))])) + + ;; tidy contracts + (define (union . args) (for-each (lambda (x) diff --git a/collects/tests/mzscheme/contract-test.ss b/collects/tests/mzscheme/contract-test.ss index 90ba25c..32f01a9 100644 --- a/collects/tests/mzscheme/contract-test.ss +++ b/collects/tests/mzscheme/contract-test.ss @@ -1302,6 +1302,8 @@ (test-flat-contract '(box/p boolean?) (box #f) (box 1)) (test-flat-contract '(box/p (flat-contract boolean?)) (box #t) #f) + (test-flat-contract '(flat-rec-contract sexp (cons/p sexp sexp) number?) '(1 2 . 3) '(1 . #f)) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; case-> arity checking tests ;; @@ -1418,6 +1420,7 @@ (test-name "(box/p boolean?)" (box/p boolean?)) (test-name "(box/p boolean?)" (box/p (flat-contract boolean?))) + (test-name "the-name" (flat-rec-contract the-name)) )) (report-errs)