From 6d58b11af9367b5bb60ada9ed8536a08d29f7dab Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Wed, 5 Jul 2017 06:46:57 -0600 Subject: [PATCH] add racket/private/check The `racket/private/check` module is dead code in this repo, but having it simplifies the "racket7" bootstrap when "racket7" goes so wrong that it can't rebuild itself. --- racket/collects/racket/private/check.rkt | 89 ++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 racket/collects/racket/private/check.rkt diff --git a/racket/collects/racket/private/check.rkt b/racket/collects/racket/private/check.rkt new file mode 100644 index 0000000000..056f10a840 --- /dev/null +++ b/racket/collects/racket/private/check.rkt @@ -0,0 +1,89 @@ +#lang racket/base +(require racket/stxparam + (for-syntax racket/base)) + +;; Support for writing contract checks as assertions at the beginning +;; of a function. The normal usage pattern is +;; +;; (define/who ( ....) +;; (check who ) +;; ... +;; ) +;; +;; where `check/who` binds `who`, but `who` is just an expression +;; for `check`, so it can be a literal symbol (discouraged) or +;; passed to a helper function that performs checks (fine). +;; +;; The `check` macro supports `#:or-false` either before or after +;; , which allows the to be false and constructs +;; a suitable contract string -- putting `#f` in the contract before +;; or after to match `#:or-false`. +;; +;; The `check` macro also supports `#:contract ` after +;; to provide a contract string other than the automatic +;; one. +;; +;; The `procedure-arity-includes/c` export here is a macro that +;; expands to a predicate that checks `procedure?` plus +;; `procedure-arity-incudes?`. + +(provide check + + procedure-arity-includes/c + + define/who + who) + +;; ---------------------------------------- + +(define-syntax (check stx) + (syntax-case stx () + [(_ who pred #:contract ctc v) + #`(unless (pred v) + (raise-argument-error who ctc v))] + [(_ who pred #:or-false v) + #`(check who (lambda (x) (or (not x) (pred x))) #:contract #,(format "(or/c ~a #f)" (syntax->datum #'pred)) v)] + [(_ who #:or-false pred v) + #`(check who (lambda (x) (or (not x) (pred x))) #:contract #,(format "(or/c #f ~a)" (syntax->datum #'pred)) v)] + [(_ who #:test expr #:contract ctc v) + #`(unless expr + (raise-argument-error who ctc v))] + [(_ who pred v) + #`(check who pred #:contract #,(format "~a" (syntax->datum #'pred)) v)])) + +;; ---------------------------------------- + +(define-syntax (procedure-arity-includes/c stx) + (syntax-case stx () + [(_ n) + (exact-nonnegative-integer? (syntax-e #'n)) + #'(lambda (p) + (and (procedure? p) + (procedure-arity-includes? p n)))])) + +;; ---------------------------------------- + +(define-syntax-parameter who + (lambda (stx) + (raise-syntax-error #f "not defined" stx))) + +(define-for-syntax (make-who id) + (lambda (stx) + (syntax-case stx () + [(who . _) + (raise-syntax-error #f "cannot apply" #'who stx)] + [else #`'#,id]))) + +(define-syntax (define/who stx) + (syntax-case stx () + [(_ (id . args) . body) + (syntax/loc stx + (define id + (lambda args + (syntax-parameterize ([who (make-who 'id)]) + . body))))] + [(_ id rhs) + (syntax/loc stx + (define id + (syntax-parameterize ([who (make-who 'id)]) + rhs)))]))