Created
March 10, 2022 06:40
-
-
Save camoy/013aed6ce597b3276ab04558656a8d57 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#lang racket | |
(require (for-syntax racket/base | |
syntax/id-table | |
syntax/parse | |
syntax/parse/lib/function-header)) | |
(module+ test (require rackunit)) | |
(begin-for-syntax | |
(define raw-sc (make-syntax-introducer)) | |
(define ctc-sc (make-syntax-introducer)) | |
(struct carrier-info (ctc-name raw-name arg-ctcs ret-ctc) | |
#:property prop:rename-transformer 0) | |
(define (make-ctc-map params-stx arg-ctcs-stx) | |
(make-immutable-free-id-table | |
(map cons (syntax->list params-stx) (syntax->list arg-ctcs-stx)))) | |
(define (satisfies? ctc-map op-info args) | |
(define op-ctc-args (carrier-info-arg-ctcs op-info)) | |
(and (= (length op-ctc-args) (length args)) | |
(for/and ([op-ctc-arg (in-list op-ctc-args)] | |
[arg (in-list args)]) | |
(define arg-satisfies (free-id-table-ref ctc-map arg (λ () #f))) | |
(and arg-satisfies (free-identifier=? arg-satisfies op-ctc-arg))))) | |
(define (optimize-body stx ctc-map) | |
(let go ([stx stx]) | |
(syntax-parse stx | |
[(?name:id ?arg:id ...) | |
#:do [(define-values (op-info _) | |
(syntax-local-value/immediate #'?name (λ () (values #f #f))))] | |
#:when (carrier-info? op-info) | |
#:when (satisfies? ctc-map op-info (syntax->list #'(?arg ...))) | |
#:with ?raw-name (carrier-info-raw-name op-info) | |
#'(?raw-name ?arg ...)] | |
[(?e ...) (datum->syntax stx (map go (syntax->list #'(?e ...))))] | |
[_ stx])))) | |
(define-syntax (define/contract/opt stx) | |
(syntax-parse stx | |
#:literals (->) | |
[(_ ?header:function-header | |
(-> ?arg-ctc:id ... ?ret-ctc:id) | |
?body:expr ...) | |
#:with ?name #'?header.name | |
#:with ?ctc-name (ctc-sc #'?name) | |
#:with ?raw-name (raw-sc #'?name) | |
#:with (?p ...) #'?header.params | |
#:do [(define ctc-map (make-ctc-map #'(?p ...) #'(?arg-ctc ...)))] | |
#:with ?opt-body (optimize-body #'(λ (?p ...) ?body ...) ctc-map) | |
#'(begin | |
(define-syntax ?name | |
(carrier-info #'?ctc-name #'?raw-name | |
(list #'?arg-ctc ...) | |
#'?ret-ctc)) | |
(define (?raw-name ?p ...) ?body ...) | |
(define/contract ?ctc-name (-> ?arg-ctc ... ?ret-ctc) ?opt-body))])) | |
(module+ test | |
(define (integer! x) | |
(displayln "ok") | |
(integer? x)) | |
(define/contract/opt (my-add1 x) | |
(-> integer! integer?) | |
(+ 1 x)) | |
(define/contract/opt (f x) | |
(-> integer! integer?) | |
(my-add1 x)) | |
;; notice only one "ok" | |
(check-eq? (f 42) 43)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment