From 5808b0c4a09dfcde40e64a55e45f63183cfc9abf Mon Sep 17 00:00:00 2001 From: chrdimo Date: Mon, 28 Jan 2013 01:09:05 -0500 Subject: [PATCH] adding option contracts in unstable --- collects/unstable/options.rkt | 167 ++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 collects/unstable/options.rkt diff --git a/collects/unstable/options.rkt b/collects/unstable/options.rkt new file mode 100644 index 0000000000..bdd93c725e --- /dev/null +++ b/collects/unstable/options.rkt @@ -0,0 +1,167 @@ +#lang racket + + +(provide option/c transfer-option exercise-option waive-option) + + +(require syntax/location + (for-syntax racket/provide-transform)) + + +(struct info (val proj blame)) + +(define-values (impersonator-prop:proxy proxy? proxy-info) + (make-impersonator-property 'proxy)) + + +(define (build-proxy val proj blame) + (let ([proxy-info (info val proj blame)]) + (cond [(procedure? val) + (chaperone-procedure + val + values + impersonator-prop:proxy + proxy-info)] + [(vector? val) + (chaperone-vector + val + (λ (v i val) val) + (λ (v i val) val) + impersonator-prop:proxy + proxy-info)] + [(hash? val) + (chaperone-hash + val + (λ (h k) (values k (λ (h k v) v))) + (λ (h k v) (values k v)) + (λ (h k) k) + (λ (h k) k) + impersonator-prop:proxy + proxy-info)] + [(struct? val) + (chaperone-hash + val + (λ (h k) (values k (λ (h k v) v))) + (λ (h k v) (values k v)) + (λ (h k) k) + (λ (h k) k) + impersonator-prop:proxy + proxy-info)]))) + + +(define (run-tester tester val orig-ctc blame here) + (let ([indy-blame (blame-replace-negative blame here)] + [proj (contract-projection orig-ctc)] + [option-blame + (λ (blame context) + (blame-add-context blame context))]) + (unless (tester ((proj + (option-blame + blame + (format "in option contract tester ~e" tester))) + val)) + (raise-blame-error + (option-blame indy-blame (format "option contract tester ~e failure" tester)) + val + "")))) + +(struct option (orig-ctc tester here) + #:property prop:contract + (build-contract-property + #:name + (λ (ctc) (contract-name (option-orig-ctc ctc))) + #:first-order + (λ (ctc) + (λ (val) + ((contract-first-order (option-orig-ctc ctc)) val))) + #:projection + (λ (ctc) + (λ (blame) + (λ (val) + (let ([tester (option-tester ctc)] + [orig-ctc (option-orig-ctc ctc)] + [here (option-here ctc)]) + (unless (symbol? tester) + (run-tester tester val orig-ctc blame here)) + (build-proxy val (contract-projection orig-ctc) blame))))))) + +(define (build-option ctc here #:tester [tester 'dont-care]) + (option ctc tester here)) + +(define-syntax (option/c stx) + (syntax-case stx () + [(_ con) + (syntax-property + #`(build-option con (quote-module-name)) + 'racket/contract:contract + (vector (gensym 'option/c) + (list (car (syntax-e stx))) + '()))] + [(_ con key tester) + (syntax-property + #`(build-option con (quote-module-name) key tester) + 'racket/contract:contract + (vector (gensym 'option/c) + (list (car (syntax-e stx))) + '()))])) + +(struct transfer () + #:property prop:contract + (build-contract-property + #:projection + (λ (ctc) + (λ (blame) + (λ (val) + (let ([option-blame + (blame-add-context + blame + (format "option contract transfer failure: ~a does not have an option" val))] + [pos-blame (blame-positive blame)] + [neg-blame (blame-negative blame)]) + (cond [(proxy? val) + (let ((info (proxy-info val))) + (build-proxy + (info-val info) + (info-proj info) + (blame-update (info-blame info) pos-blame neg-blame)))] + [else (raise-blame-error option-blame val "")]))))))) + +(define-syntax transfer/c + (syntax-id-rules () + [_ (transfer)])) + +(define-for-syntax (fresh-names l) + (map (lambda (x) (datum->syntax #f (gensym x))) (syntax->datum l))) + +(define-syntax transfer-option + (make-provide-pre-transformer + (lambda (stx modes) + (unless (or (null? modes) + (and (= 1 (length modes)) + (zero? (car modes)))) + (raise-syntax-error #f + "allowed only in relative phase-level 0" + stx)) + (syntax-case stx () + [(_ id ... ) + (syntax-local-lift-module-end-declaration + (with-syntax ([(new-id ...) (generate-temporaries #'(id ...))]) + #`(begin + (begin (define new-id id) ...) + (provide (contract-out [rename new-id id transfer/c] ...)))))]) + #`(combine-out)))) + +(define (exercise-option val) + (cond [(proxy? val) + (let ((info (proxy-info val))) + (((info-proj info) + (info-blame info)) + (info-val info)))] + [else (error 'exercise-error "~a has no option to exercise" val)])) + +(define (waive-option val) + (cond [(proxy? val) (info-val (proxy-info val))] + [else (error 'exercise-error "~a has no option to exercise" val)])) + + +