merged the opt/c changes back into the trunk (finally!)
svn: r5481
This commit is contained in:
parent
e911124dbf
commit
4ad8fdadea
|
@ -9,14 +9,10 @@
|
||||||
"private/contract-basic-opters.ss")
|
"private/contract-basic-opters.ss")
|
||||||
|
|
||||||
(provide
|
(provide
|
||||||
;; opt is not ready yet
|
opt/c ;(all-from "private/contract-opt.ss")
|
||||||
#;(all-from "private/contract-opt.ss")
|
(all-from-except "private/contract-ds.ss"
|
||||||
#;(all-from-except "private/contract-opt-guts.ss"
|
lazy-depth-to-look)
|
||||||
make-opt-contract
|
|
||||||
orig-ctc-prop
|
|
||||||
orig-ctc-pred?
|
|
||||||
orig-ctc-get)
|
|
||||||
(all-from "private/contract-ds.ss")
|
|
||||||
(all-from-except "private/contract-arrow.ss"
|
(all-from-except "private/contract-arrow.ss"
|
||||||
check-procedure)
|
check-procedure)
|
||||||
(all-from-except "private/contract-guts.ss"
|
(all-from-except "private/contract-guts.ss"
|
||||||
|
|
|
@ -1747,21 +1747,27 @@
|
||||||
;;
|
;;
|
||||||
;; arrow opter
|
;; arrow opter
|
||||||
;;
|
;;
|
||||||
(define/opter (-> opt/i pos neg stx)
|
(define/opter (-> opt/i opt/info stx)
|
||||||
(define (opt/arrow-ctc doms rngs)
|
(define (opt/arrow-ctc doms rngs)
|
||||||
(let*-values ([(dom-vars rng-vars) (values (generate-temporaries doms)
|
(let*-values ([(dom-vars rng-vars) (values (generate-temporaries doms)
|
||||||
(generate-temporaries rngs))]
|
(generate-temporaries rngs))]
|
||||||
[(next-doms lifts-doms partials-doms)
|
[(next-doms lifts-doms superlifts-doms partials-doms stronger-ribs-dom)
|
||||||
(let loop ([vars dom-vars]
|
(let loop ([vars dom-vars]
|
||||||
[doms doms]
|
[doms doms]
|
||||||
[next-doms null]
|
[next-doms null]
|
||||||
[lifts-doms null]
|
[lifts-doms null]
|
||||||
[partials-doms null])
|
[superlifts-doms null]
|
||||||
|
[partials-doms null]
|
||||||
|
[stronger-ribs null])
|
||||||
(cond
|
(cond
|
||||||
[(null? doms) (values (reverse next-doms) lifts-doms partials-doms)]
|
[(null? doms) (values (reverse next-doms)
|
||||||
|
lifts-doms
|
||||||
|
superlifts-doms
|
||||||
|
partials-doms
|
||||||
|
stronger-ribs)]
|
||||||
[else
|
[else
|
||||||
(let-values ([(next lift partial _ __)
|
(let-values ([(next lift superlift partial _ __ this-stronger-ribs)
|
||||||
(opt/i neg pos (car doms))])
|
(opt/i (opt/info-swap-blame opt/info) (car doms))])
|
||||||
(loop (cdr vars)
|
(loop (cdr vars)
|
||||||
(cdr doms)
|
(cdr doms)
|
||||||
(cons (with-syntax ((next next)
|
(cons (with-syntax ((next next)
|
||||||
|
@ -1769,18 +1775,26 @@
|
||||||
(syntax (let ((val car-vars)) next)))
|
(syntax (let ((val car-vars)) next)))
|
||||||
next-doms)
|
next-doms)
|
||||||
(append lifts-doms lift)
|
(append lifts-doms lift)
|
||||||
(append partials-doms partial)))]))]
|
(append superlifts-doms superlift)
|
||||||
[(next-rngs lifts-rngs partials-rngs)
|
(append partials-doms partial)
|
||||||
|
(append this-stronger-ribs stronger-ribs)))]))]
|
||||||
|
[(next-rngs lifts-rngs superlifts-rngs partials-rngs stronger-ribs-rng)
|
||||||
(let loop ([vars rng-vars]
|
(let loop ([vars rng-vars]
|
||||||
[rngs rngs]
|
[rngs rngs]
|
||||||
[next-rngs null]
|
[next-rngs null]
|
||||||
[lifts-rngs null]
|
[lifts-rngs null]
|
||||||
[partials-rngs null])
|
[superlifts-rngs null]
|
||||||
|
[partials-rngs null]
|
||||||
|
[stronger-ribs null])
|
||||||
(cond
|
(cond
|
||||||
[(null? rngs) (values (reverse next-rngs) lifts-rngs partials-rngs)]
|
[(null? rngs) (values (reverse next-rngs)
|
||||||
|
lifts-rngs
|
||||||
|
superlifts-rngs
|
||||||
|
partials-rngs
|
||||||
|
stronger-ribs)]
|
||||||
[else
|
[else
|
||||||
(let-values ([(next lift partial _ __)
|
(let-values ([(next lift superlift partial _ __ this-stronger-ribs)
|
||||||
(opt/i pos neg (car rngs))])
|
(opt/i opt/info (car rngs))])
|
||||||
(loop (cdr vars)
|
(loop (cdr vars)
|
||||||
(cdr rngs)
|
(cdr rngs)
|
||||||
(cons (with-syntax ((next next)
|
(cons (with-syntax ((next next)
|
||||||
|
@ -1788,9 +1802,13 @@
|
||||||
(syntax (let ((val car-vars)) next)))
|
(syntax (let ((val car-vars)) next)))
|
||||||
next-rngs)
|
next-rngs)
|
||||||
(append lifts-rngs lift)
|
(append lifts-rngs lift)
|
||||||
(append partials-rngs partial)))]))])
|
(append superlifts-rngs superlift)
|
||||||
|
(append partials-rngs partial)
|
||||||
|
(append this-stronger-ribs stronger-ribs)))]))])
|
||||||
(values
|
(values
|
||||||
(with-syntax ((pos pos)
|
(with-syntax ((pos (opt/info-pos opt/info))
|
||||||
|
(src-info (opt/info-src-info opt/info))
|
||||||
|
(orig-str (opt/info-orig-str opt/info))
|
||||||
((dom-arg ...) dom-vars)
|
((dom-arg ...) dom-vars)
|
||||||
((rng-arg ...) rng-vars)
|
((rng-arg ...) rng-vars)
|
||||||
((next-dom ...) next-doms)
|
((next-dom ...) next-doms)
|
||||||
|
@ -1802,23 +1820,31 @@
|
||||||
(let-values ([(rng-arg ...) (val next-dom ...)])
|
(let-values ([(rng-arg ...) (val next-dom ...)])
|
||||||
(values next-rng ...))))))
|
(values next-rng ...))))))
|
||||||
(append lifts-doms lifts-rngs)
|
(append lifts-doms lifts-rngs)
|
||||||
|
(append superlifts-doms superlifts-rngs)
|
||||||
(append partials-doms partials-rngs)
|
(append partials-doms partials-rngs)
|
||||||
#f
|
#f
|
||||||
#f)))
|
#f
|
||||||
|
(append stronger-ribs-dom stronger-ribs-rng))))
|
||||||
|
|
||||||
(define (opt/arrow-any-ctc doms)
|
(define (opt/arrow-any-ctc doms)
|
||||||
(let*-values ([(dom-vars) (generate-temporaries doms)]
|
(let*-values ([(dom-vars) (generate-temporaries doms)]
|
||||||
[(next-doms lifts-doms partials-doms)
|
[(next-doms lifts-doms superlifts-doms partials-doms stronger-ribs-dom)
|
||||||
(let loop ([vars dom-vars]
|
(let loop ([vars dom-vars]
|
||||||
[doms doms]
|
[doms doms]
|
||||||
[next-doms null]
|
[next-doms null]
|
||||||
[lifts-doms null]
|
[lifts-doms null]
|
||||||
[partials-doms null])
|
[superlifts-doms null]
|
||||||
|
[partials-doms null]
|
||||||
|
[stronger-ribs null])
|
||||||
(cond
|
(cond
|
||||||
[(null? doms) (values (reverse next-doms) lifts-doms partials-doms)]
|
[(null? doms) (values (reverse next-doms)
|
||||||
|
lifts-doms
|
||||||
|
superlifts-doms
|
||||||
|
partials-doms
|
||||||
|
stronger-ribs)]
|
||||||
[else
|
[else
|
||||||
(let-values ([(next lift partial flat _)
|
(let-values ([(next lift superlift partial flat _ this-stronger-ribs)
|
||||||
(opt/i pos neg (car doms))])
|
(opt/i (opt/info-swap-blame opt/info) (car doms))])
|
||||||
(loop (cdr vars)
|
(loop (cdr vars)
|
||||||
(cdr doms)
|
(cdr doms)
|
||||||
(cons (with-syntax ((next next)
|
(cons (with-syntax ((next next)
|
||||||
|
@ -1826,9 +1852,13 @@
|
||||||
(syntax (let ((val car-vars)) next)))
|
(syntax (let ((val car-vars)) next)))
|
||||||
next-doms)
|
next-doms)
|
||||||
(append lifts-doms lift)
|
(append lifts-doms lift)
|
||||||
(append partials-doms partial)))]))])
|
(append superlifts-doms superlift)
|
||||||
|
(append partials-doms partial)
|
||||||
|
(append this-stronger-ribs stronger-ribs)))]))])
|
||||||
(values
|
(values
|
||||||
(with-syntax ((pos pos)
|
(with-syntax ((pos (opt/info-pos opt/info))
|
||||||
|
(src-info (opt/info-src-info opt/info))
|
||||||
|
(orig-str (opt/info-orig-str opt/info))
|
||||||
((dom-arg ...) dom-vars)
|
((dom-arg ...) dom-vars)
|
||||||
((next-dom ...) next-doms)
|
((next-dom ...) next-doms)
|
||||||
(dom-len (length dom-vars)))
|
(dom-len (length dom-vars)))
|
||||||
|
@ -1837,11 +1867,13 @@
|
||||||
(λ (dom-arg ...)
|
(λ (dom-arg ...)
|
||||||
(val next-dom ...)))))
|
(val next-dom ...)))))
|
||||||
lifts-doms
|
lifts-doms
|
||||||
|
superlifts-doms
|
||||||
partials-doms
|
partials-doms
|
||||||
#f
|
#f
|
||||||
#f)))
|
#f
|
||||||
|
stronger-ribs-dom)))
|
||||||
|
|
||||||
(syntax-case stx (-> values any)
|
(syntax-case* stx (-> values any) module-or-top-identifier=?
|
||||||
[(-> dom ... (values rng ...))
|
[(-> dom ... (values rng ...))
|
||||||
(opt/arrow-ctc (syntax->list (syntax (dom ...)))
|
(opt/arrow-ctc (syntax->list (syntax (dom ...)))
|
||||||
(syntax->list (syntax (rng ...))))]
|
(syntax->list (syntax (rng ...))))]
|
||||||
|
|
|
@ -1,81 +1,104 @@
|
||||||
(module contract-basic-opters mzscheme
|
(module contract-basic-opters mzscheme
|
||||||
(require "contract-guts.ss"
|
(require "contract-guts.ss"
|
||||||
"contract-opt.ss")
|
"contract-opt.ss"
|
||||||
|
"contract.ss")
|
||||||
(require-for-syntax "contract-opt-guts.ss")
|
(require-for-syntax "contract-opt-guts.ss")
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;; opt/pred helper
|
;; opt/pred helper
|
||||||
;;
|
;;
|
||||||
(define-for-syntax (opt/pred pos pred)
|
(define-for-syntax (opt/pred opt/info pred)
|
||||||
(let* ((lift-vars (generate-temporaries (syntax (pred))))
|
(printf "~s\n" (list 'opt/pred opt/info pred))
|
||||||
(lift-pred-var (car lift-vars)))
|
(with-syntax ((pred pred))
|
||||||
(with-syntax ((lift-pred lift-pred-var))
|
(values
|
||||||
(values
|
(with-syntax ((val (opt/info-val opt/info))
|
||||||
(with-syntax ((pos pos))
|
(ctc (opt/info-contract opt/info))
|
||||||
(syntax (if (lift-pred val)
|
(pos (opt/info-pos opt/info))
|
||||||
val
|
(src-info (opt/info-src-info opt/info))
|
||||||
(raise-contract-error
|
(orig-str (opt/info-orig-str opt/info)))
|
||||||
val
|
(syntax (if (pred val)
|
||||||
src-info
|
val
|
||||||
pos
|
(raise-contract-error
|
||||||
orig-str
|
val
|
||||||
"expected <~a>, given: ~e"
|
src-info
|
||||||
((name-get ctc) ctc)
|
pos
|
||||||
val))))
|
orig-str
|
||||||
(list (cons lift-pred-var pred))
|
"expected <~a>, given: ~e"
|
||||||
null
|
((name-get ctc) ctc)
|
||||||
(syntax (lift-pred val))
|
val))))
|
||||||
#f))))
|
null
|
||||||
|
null
|
||||||
|
null
|
||||||
|
(syntax (pred val))
|
||||||
|
#f
|
||||||
|
null)))
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;; built-in predicate opters
|
;; built-in predicate opters
|
||||||
;;
|
;;
|
||||||
(define/opter (null? opt/i pos neg stx)
|
(define/opter (null? opt/i opt/info stx)
|
||||||
(syntax-case stx (null?)
|
(syntax-case stx (null?)
|
||||||
[null? (opt/pred pos #'null?)]))
|
[null? (opt/pred opt/info #'null?)]))
|
||||||
(define/opter (boolean? opt/i pos neg stx)
|
(define/opter (boolean? opt/i opt/info stx)
|
||||||
|
(printf "boolean opter\n")
|
||||||
(syntax-case stx (boolean?)
|
(syntax-case stx (boolean?)
|
||||||
[boolean? (opt/pred pos #'boolean?)]))
|
[boolean? (opt/pred opt/info #'boolean?)]))
|
||||||
(define/opter (integer? opt/i pos neg stx)
|
(define/opter (integer? opt/i opt/info stx)
|
||||||
(syntax-case stx (integer?)
|
(syntax-case stx (integer?)
|
||||||
[integer? (opt/pred pos #'integer?)]))
|
[integer? (opt/pred opt/info #'integer?)]))
|
||||||
(define/opter (char? opt/i pos neg stx)
|
(define/opter (char? opt/i opt/info stx)
|
||||||
(syntax-case stx (char?)
|
(syntax-case stx (char?)
|
||||||
[char? (opt/pred pos #'char?)]))
|
[char? (opt/pred opt/info #'char?)]))
|
||||||
(define/opter (number? opt/i pos neg stx)
|
(define/opter (number? opt/i opt/info stx)
|
||||||
(syntax-case stx (number?)
|
(syntax-case stx (number?)
|
||||||
[number? (opt/pred pos #'number?)]))
|
[number? (opt/pred opt/info #'number?)]))
|
||||||
(define/opter (pair? opt/i pos neg stx)
|
(define/opter (pair? opt/i opt/info stx)
|
||||||
(syntax-case stx (pair?)
|
(syntax-case stx (pair?)
|
||||||
[pair? (opt/pred pos #'pair?)]))
|
[pair? (opt/pred opt/info #'pair?)]))
|
||||||
|
(define/opter (not opt/i opt/info stx)
|
||||||
|
(syntax-case stx (not)
|
||||||
|
[not (opt/pred opt/info #'not)]))
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;; any/c
|
;; any/c
|
||||||
;;
|
;;
|
||||||
(define/opter (any/c opt/i pos neg stx)
|
(define/opter (any/c opt/i opt/info stx)
|
||||||
(syntax-case stx (any/c)
|
(syntax-case stx (any/c)
|
||||||
[any/c (values
|
[any/c (values
|
||||||
#'val
|
(opt/info-val opt/info)
|
||||||
|
null
|
||||||
null
|
null
|
||||||
null
|
null
|
||||||
#'#t
|
#'#t
|
||||||
#f)]))
|
#f
|
||||||
|
null)]))
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; false/c
|
||||||
|
;;
|
||||||
|
(define/opter (false/c opt/i opt/info stx)
|
||||||
|
(syntax-case stx (false/c)
|
||||||
|
[false/c (opt/pred opt/info #'not)]))
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;; flat-contract helper
|
;; flat-contract helper
|
||||||
;;
|
;;
|
||||||
(define-for-syntax (opt/flat-ctc pos pred checker)
|
(define-for-syntax (opt/flat-ctc opt/info pred checker)
|
||||||
(syntax-case pred (null? number? integer? boolean? pair?)
|
(syntax-case pred (null? number? integer? boolean? pair? not)
|
||||||
;; Better way of doing this?
|
;; Better way of doing this?
|
||||||
[null? (opt/pred pos pred)]
|
[null? (opt/pred opt/info pred)]
|
||||||
[number? (opt/pred pos pred)]
|
[number? (opt/pred opt/info pred)]
|
||||||
[integer? (opt/pred pos pred)]
|
[integer? (opt/pred opt/info pred)]
|
||||||
[boolean? (opt/pred pos pred)]
|
[boolean? (opt/pred opt/info pred)]
|
||||||
[pair? (opt/pred pos pred)]
|
[pair? (opt/pred opt/info pred)]
|
||||||
[pred
|
[pred
|
||||||
(let* ((lift-vars (generate-temporaries (syntax (pred error-check))))
|
(let* ((lift-vars (generate-temporaries (syntax (pred error-check))))
|
||||||
(lift-pred (car lift-vars)))
|
(lift-pred (car lift-vars)))
|
||||||
(with-syntax ((pos pos)
|
(with-syntax ((val (opt/info-val opt/info))
|
||||||
|
(ctc (opt/info-contract opt/info))
|
||||||
|
(pos (opt/info-pos opt/info))
|
||||||
|
(src-info (opt/info-src-info opt/info))
|
||||||
|
(orig-str (opt/info-orig-str opt/info))
|
||||||
(lift-pred lift-pred))
|
(lift-pred lift-pred))
|
||||||
(values
|
(values
|
||||||
(syntax (if (lift-pred val)
|
(syntax (if (lift-pred val)
|
||||||
|
@ -93,55 +116,17 @@
|
||||||
(list #'pred (cond [(eq? checker 'check-flat-contract) #'(check-flat-contract lift-pred)]
|
(list #'pred (cond [(eq? checker 'check-flat-contract) #'(check-flat-contract lift-pred)]
|
||||||
[(eq? checker 'check-flat-named-contract) #'(check-flat-named-contract lift-pred)])))
|
[(eq? checker 'check-flat-named-contract) #'(check-flat-named-contract lift-pred)])))
|
||||||
null
|
null
|
||||||
|
null
|
||||||
(syntax (lift-pred val))
|
(syntax (lift-pred val))
|
||||||
#f)))]))
|
#f
|
||||||
|
null)))]))
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;; flat-contract and friends
|
;; flat-contract and friends
|
||||||
;;
|
;;
|
||||||
(define/opter (flat-contract opt/i pos neg stx)
|
(define/opter (flat-contract opt/i opt/info stx)
|
||||||
(syntax-case stx (flat-contract)
|
(syntax-case stx (flat-contract)
|
||||||
[(flat-contract pred) (opt/flat-ctc pos #'pred 'check-flat-contract)]))
|
[(flat-contract pred) (opt/flat-ctc opt/info #'pred 'check-flat-contract)]))
|
||||||
(define/opter (flat-named-contract opt/i pos neg stx)
|
(define/opter (flat-named-contract opt/i opt/info stx)
|
||||||
(syntax-case stx (flat-named-contract)
|
(syntax-case stx (flat-named-contract)
|
||||||
[(flat-named-contract name pred) (opt/flat-ctc pos #'pred 'check-flat-named-contract)]))
|
[(flat-named-contract name pred) (opt/flat-ctc opt/info #'pred 'check-flat-named-contract)])))
|
||||||
|
|
||||||
;;
|
|
||||||
;; unknown
|
|
||||||
;;
|
|
||||||
;; BUGS: currently, opt/c reports error on something like
|
|
||||||
;; (opt/c (or/c (begin (print "side effect") number?) boolean?))
|
|
||||||
;; because the begin sequence is unrecognized, and we have no idea of
|
|
||||||
;; knowing that `number?' is a pred that we can opt.
|
|
||||||
;; WORKAROUND: wrap `flat-contract' around the pred, it optimizes to the same
|
|
||||||
;; thing.
|
|
||||||
;;
|
|
||||||
(define/opter (unknown opt/i pos neg stx)
|
|
||||||
(define (opt/unknown-ctc uctc)
|
|
||||||
(let* ((lift-vars (generate-temporaries (syntax (lift error-check))))
|
|
||||||
(lift-var (car lift-vars))
|
|
||||||
(partial-var (car (generate-temporaries (syntax (partial))))))
|
|
||||||
(values
|
|
||||||
(with-syntax ((partial-var partial-var)
|
|
||||||
(lift-var lift-var)
|
|
||||||
(uctc uctc))
|
|
||||||
(syntax (partial-var val)))
|
|
||||||
(interleave-lifts
|
|
||||||
lift-vars
|
|
||||||
(list uctc
|
|
||||||
(with-syntax ((lift-var lift-var))
|
|
||||||
(syntax
|
|
||||||
(unless (contract? lift-var)
|
|
||||||
(error 'contract "expected contract, given ~e" lift-var))))))
|
|
||||||
(list (cons
|
|
||||||
partial-var
|
|
||||||
(with-syntax ((lift-var lift-var)
|
|
||||||
(pos pos)
|
|
||||||
(neg neg))
|
|
||||||
(syntax (((proj-get lift-var) lift-var) pos neg src-info orig-str)))))
|
|
||||||
#f
|
|
||||||
lift-var)))
|
|
||||||
|
|
||||||
(syntax-case stx ()
|
|
||||||
[ctc
|
|
||||||
(opt/unknown-ctc #'ctc)])))
|
|
|
@ -2,9 +2,11 @@
|
||||||
(provide ensure-well-formed
|
(provide ensure-well-formed
|
||||||
build-func-params
|
build-func-params
|
||||||
build-clauses
|
build-clauses
|
||||||
|
build-enforcer-clauses
|
||||||
generate-arglists)
|
generate-arglists)
|
||||||
|
|
||||||
(require (lib "list.ss"))
|
(require (lib "list.ss")
|
||||||
|
"contract-opt-guts.ss")
|
||||||
(require-for-template mzscheme)
|
(require-for-template mzscheme)
|
||||||
|
|
||||||
#|
|
#|
|
||||||
|
@ -32,14 +34,19 @@ which are then called when the contract's fields are explored
|
||||||
|
|
||||||
(define (build-clauses name coerce-contract stx clauses)
|
(define (build-clauses name coerce-contract stx clauses)
|
||||||
(let* ([field-names
|
(let* ([field-names
|
||||||
(map (λ (clause)
|
(let loop ([clauses (syntax->list clauses)])
|
||||||
(syntax-case clause ()
|
(cond
|
||||||
[(id . whatever) (syntax id)]
|
[(null? clauses) null]
|
||||||
|
[else
|
||||||
|
(let ([clause (car clauses)])
|
||||||
|
(syntax-case* clause (where and) raw-comparison?
|
||||||
|
[where null]
|
||||||
|
[and null]
|
||||||
|
[(id . whatever) (cons (syntax id) (loop (cdr clauses)))]
|
||||||
[else (raise-syntax-error name
|
[else (raise-syntax-error name
|
||||||
"expected a field name and a contract together"
|
"expected a field name and a contract together"
|
||||||
stx
|
stx
|
||||||
clause)]))
|
clause)]))]))]
|
||||||
(syntax->list clauses))]
|
|
||||||
[all-ac-ids (generate-temporaries field-names)]
|
[all-ac-ids (generate-temporaries field-names)]
|
||||||
[defeat-inlining
|
[defeat-inlining
|
||||||
;; makes the procedure "big enough" so
|
;; makes the procedure "big enough" so
|
||||||
|
@ -55,23 +62,165 @@ which are then called when the contract's fields are explored
|
||||||
[maker-args '()])
|
[maker-args '()])
|
||||||
(cond
|
(cond
|
||||||
[(null? clauses)
|
[(null? clauses)
|
||||||
(reverse maker-args)]
|
(with-syntax ([(maker-args ...) (reverse maker-args)])
|
||||||
|
(syntax ((maker-args ... #f)
|
||||||
|
())))]
|
||||||
[else
|
[else
|
||||||
|
(let ([clause (car clauses)])
|
||||||
|
(syntax-case* clause (and where) raw-comparison?
|
||||||
|
[where
|
||||||
|
(build-clauses/where name stx (cdr clauses) field-names (reverse maker-args))]
|
||||||
|
[and
|
||||||
|
(build-clauses/and name stx (cdr clauses) '() '() (reverse maker-args))]
|
||||||
|
[else
|
||||||
|
(let ([ac-id (car ac-ids)])
|
||||||
|
(syntax-case clause ()
|
||||||
|
[(id (x ...) ctc-exp)
|
||||||
|
(and (identifier? (syntax id))
|
||||||
|
(andmap identifier? (syntax->list (syntax (x ...)))))
|
||||||
|
(let ([maker-arg #`(λ #,(match-up (reverse prior-ac-ids)
|
||||||
|
(syntax (x ...))
|
||||||
|
field-names)
|
||||||
|
#,(defeat-inlining
|
||||||
|
#`(#,coerce-contract '#,name ctc-exp)))])
|
||||||
|
(loop (cdr clauses)
|
||||||
|
(cdr ac-ids)
|
||||||
|
(cons (car ac-ids) prior-ac-ids)
|
||||||
|
(cons maker-arg maker-args)))]
|
||||||
|
[(id (x ...) ctc-exp)
|
||||||
|
(begin
|
||||||
|
(unless (identifier? (syntax id))
|
||||||
|
(raise-syntax-error name "expected identifier" stx (syntax id)))
|
||||||
|
(for-each (λ (x) (unless (identifier? x)
|
||||||
|
(raise-syntax-error name "expected identifier" stx x)))
|
||||||
|
(syntax->list (syntax (x ...)))))]
|
||||||
|
[(id ctc-exp)
|
||||||
|
(identifier? (syntax id))
|
||||||
|
(loop (cdr clauses)
|
||||||
|
(cdr ac-ids)
|
||||||
|
(cons (car ac-ids) prior-ac-ids)
|
||||||
|
(cons #`(#,coerce-contract '#,name ctc-exp) maker-args))]
|
||||||
|
[(id ctc-exp)
|
||||||
|
(raise-syntax-error name "expected identifier" stx (syntax id))]
|
||||||
|
[_
|
||||||
|
(raise-syntax-error name "expected name/identifier binding" stx clause)]))]))]))))
|
||||||
|
|
||||||
|
(define (build-clauses/where name stx clauses field-names maker-args)
|
||||||
|
(with-syntax ([(field-names ...) field-names])
|
||||||
|
(let loop ([clauses clauses]
|
||||||
|
[vars '()]
|
||||||
|
[procs '()])
|
||||||
|
(cond
|
||||||
|
[(null? clauses)
|
||||||
|
;; if there is no `and' clause, assume that it is always satisfied
|
||||||
|
(build-clauses/and name stx (list (syntax #t)) vars procs maker-args)]
|
||||||
|
[else
|
||||||
|
(let ([clause (car clauses)])
|
||||||
|
(syntax-case* clause (and) raw-comparison?
|
||||||
|
[and (build-clauses/and name stx (cdr clauses) vars procs maker-args)]
|
||||||
|
[(id exp)
|
||||||
|
(identifier? (syntax id))
|
||||||
|
(loop (cdr clauses)
|
||||||
|
(cons (syntax id) vars)
|
||||||
|
(cons (syntax (λ (field-names ...) exp)) procs))]
|
||||||
|
[(id exp)
|
||||||
|
(raise-syntax-error name "expected an identifier" stx (syntax id))]
|
||||||
|
[_
|
||||||
|
(raise-syntax-error name "expected an identifier and an expression" stx clause)]))]))))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(define (build-enforcer-clauses opt/i opt/info name stx clauses f-x/vals f-xs/vals
|
||||||
|
helper-id helper-info helper-freev)
|
||||||
|
(define (opt/enforcer-clause stx)
|
||||||
|
(syntax-case stx ()
|
||||||
|
[(f arg ...)
|
||||||
|
;; we need to override the default optimization of recursive calls to use our helper
|
||||||
|
(and (opt/info-recf opt/info) (module-identifier=? (opt/info-recf opt/info) #'f))
|
||||||
|
(values
|
||||||
|
#`(f #,(opt/info-val opt/info) arg ...)
|
||||||
|
null
|
||||||
|
null
|
||||||
|
null
|
||||||
|
#f
|
||||||
|
#f
|
||||||
|
null)]
|
||||||
|
#;
|
||||||
|
[(f arg ...)
|
||||||
|
;; we need to override the default optimization of recursive calls to use our helper
|
||||||
|
(module-identifier=? (opt/info-recf opt/info) #'f)
|
||||||
|
(with-syntax ((helper helper-id)
|
||||||
|
(val (opt/info-val opt/info))
|
||||||
|
(info helper-info))
|
||||||
|
(values
|
||||||
|
(syntax (helper val info arg ...))
|
||||||
|
null
|
||||||
|
null
|
||||||
|
null
|
||||||
|
#f
|
||||||
|
#f
|
||||||
|
null))]
|
||||||
|
[else (opt/i opt/info stx)]))
|
||||||
|
|
||||||
|
(let* ([field-names
|
||||||
|
(map (λ (clause)
|
||||||
|
(syntax-case clause ()
|
||||||
|
[(id . whatever) (syntax id)]
|
||||||
|
[else (raise-syntax-error name
|
||||||
|
"expected a field name and a contract together"
|
||||||
|
stx
|
||||||
|
clause)]))
|
||||||
|
(syntax->list clauses))]
|
||||||
|
[all-ac-ids (generate-temporaries field-names)])
|
||||||
|
(let loop ([clauses (syntax->list clauses)]
|
||||||
|
[let-vars f-x/vals]
|
||||||
|
[arglists f-xs/vals]
|
||||||
|
[ac-ids all-ac-ids]
|
||||||
|
[prior-ac-ids '()]
|
||||||
|
[maker-args '()]
|
||||||
|
[lifts-ps '()]
|
||||||
|
[superlifts-ps '()]
|
||||||
|
[stronger-ribs-ps '()])
|
||||||
|
(cond
|
||||||
|
[(null? clauses)
|
||||||
|
(values (reverse maker-args)
|
||||||
|
lifts-ps
|
||||||
|
superlifts-ps
|
||||||
|
stronger-ribs-ps)]
|
||||||
|
[else
|
||||||
(let ([clause (car clauses)]
|
(let ([clause (car clauses)]
|
||||||
|
[let-var (car let-vars)]
|
||||||
|
[arglist (car arglists)]
|
||||||
[ac-id (car ac-ids)])
|
[ac-id (car ac-ids)])
|
||||||
(syntax-case clause ()
|
(syntax-case clause ()
|
||||||
[(id (x ...) ctc-exp)
|
[(id (x ...) ctc-exp)
|
||||||
(and (identifier? (syntax id))
|
(and (identifier? (syntax id))
|
||||||
(andmap identifier? (syntax->list (syntax (x ...)))))
|
(andmap identifier? (syntax->list (syntax (x ...)))))
|
||||||
(let ([maker-arg #`(λ #,(match-up (reverse prior-ac-ids)
|
(let*-values ([(next lifts superlifts partials _ _2 _3)
|
||||||
(syntax (x ...))
|
(opt/enforcer-clause (syntax ctc-exp))]
|
||||||
field-names)
|
[(maker-arg)
|
||||||
#,(defeat-inlining
|
(with-syntax ((val (opt/info-val opt/info))
|
||||||
#`(#,coerce-contract '#,name ctc-exp)))])
|
((arg ...) arglist)
|
||||||
|
[(new-let-vars ...) (match-up (reverse prior-ac-ids)
|
||||||
|
(syntax (x ...))
|
||||||
|
field-names)])
|
||||||
|
#`(#,let-var
|
||||||
|
#,(bind-lifts
|
||||||
|
superlifts
|
||||||
|
#`(let ([new-let-vars arg] ...)
|
||||||
|
#,(bind-lifts
|
||||||
|
(append lifts partials)
|
||||||
|
#`(let ((val #,let-var))
|
||||||
|
#,next))))))])
|
||||||
(loop (cdr clauses)
|
(loop (cdr clauses)
|
||||||
|
(cdr let-vars)
|
||||||
|
(cdr arglists)
|
||||||
(cdr ac-ids)
|
(cdr ac-ids)
|
||||||
(cons (car ac-ids) prior-ac-ids)
|
(cons (car ac-ids) prior-ac-ids)
|
||||||
(cons maker-arg maker-args)))]
|
(cons maker-arg maker-args)
|
||||||
|
lifts-ps
|
||||||
|
superlifts-ps
|
||||||
|
stronger-ribs-ps))]
|
||||||
[(id (x ...) ctc-exp)
|
[(id (x ...) ctc-exp)
|
||||||
(begin
|
(begin
|
||||||
(unless (identifier? (syntax id))
|
(unless (identifier? (syntax id))
|
||||||
|
@ -81,13 +230,45 @@ which are then called when the contract's fields are explored
|
||||||
(syntax->list (syntax (x ...)))))]
|
(syntax->list (syntax (x ...)))))]
|
||||||
[(id ctc-exp)
|
[(id ctc-exp)
|
||||||
(identifier? (syntax id))
|
(identifier? (syntax id))
|
||||||
(loop (cdr clauses)
|
(let*-values ([(next lifts superlifts partials _ __ stronger-ribs)
|
||||||
(cdr ac-ids)
|
(opt/enforcer-clause (syntax ctc-exp))]
|
||||||
(cons (car ac-ids) prior-ac-ids)
|
[(maker-arg)
|
||||||
(cons #`(#,coerce-contract '#,name ctc-exp) maker-args))]
|
(with-syntax ((val (opt/info-val opt/info)))
|
||||||
|
#`(#,let-var
|
||||||
|
#,(bind-lifts
|
||||||
|
partials
|
||||||
|
#`(let ((val #,let-var))
|
||||||
|
#,next))))])
|
||||||
|
(loop (cdr clauses)
|
||||||
|
(cdr let-vars)
|
||||||
|
(cdr arglists)
|
||||||
|
(cdr ac-ids)
|
||||||
|
(cons (car ac-ids) prior-ac-ids)
|
||||||
|
(cons maker-arg maker-args)
|
||||||
|
(append lifts-ps lifts)
|
||||||
|
(append superlifts-ps superlifts)
|
||||||
|
(append stronger-ribs-ps stronger-ribs)))]
|
||||||
[(id ctc-exp)
|
[(id ctc-exp)
|
||||||
(raise-syntax-error name "expected identifier" stx (syntax id))]))]))))
|
(raise-syntax-error name "expected identifier" stx (syntax id))]))]))))
|
||||||
|
|
||||||
|
(define (build-clauses/and name stx clauses synth-names synth-procs maker-args)
|
||||||
|
(unless (pair? clauses)
|
||||||
|
(raise-syntax-error name "expected an expression after `and' keyword" stx))
|
||||||
|
(unless (null? (cdr clauses))
|
||||||
|
(raise-syntax-error name "expected only one expression after `and' keyword" stx (cadr clauses)))
|
||||||
|
(with-syntax ([(maker-args ...) maker-args]
|
||||||
|
[(synth-names ...) synth-names]
|
||||||
|
[(synth-procs ...) synth-procs]
|
||||||
|
[exp (car clauses)])
|
||||||
|
(syntax ((maker-args ... (list (λ (ht) (let ([synth-names (hash-table-get ht 'synth-names)] ...) exp))
|
||||||
|
(cons 'synth-names synth-procs) ...))
|
||||||
|
(synth-names ...)))))
|
||||||
|
|
||||||
|
(define (raw-comparison? x y)
|
||||||
|
(and (identifier? x)
|
||||||
|
(identifier? y)
|
||||||
|
(eq? (syntax-e x) (syntax-e y))))
|
||||||
|
|
||||||
;; generate-arglists : (listof X) -> (listof (listof X))
|
;; generate-arglists : (listof X) -> (listof (listof X))
|
||||||
;; produces the list of arguments to the dependent contract
|
;; produces the list of arguments to the dependent contract
|
||||||
;; functions, given the names of some variables.
|
;; functions, given the names of some variables.
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
#|
|
#|
|
||||||
|
|
||||||
|
Need to break the parent pointer links at some point.
|
||||||
|
This leaks, as is.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
why make a separate struct for the contract information
|
why make a separate struct for the contract information
|
||||||
instead of putting it into the wrapper struct in an
|
instead of putting it into the wrapper struct in an
|
||||||
extra field?
|
extra field?
|
||||||
|
@ -12,11 +17,27 @@ it around flattened out.
|
||||||
|
|
||||||
|
|
||||||
(module contract-ds mzscheme
|
(module contract-ds mzscheme
|
||||||
(require "contract-guts.ss")
|
(require "contract-guts.ss"
|
||||||
|
"contract-opt.ss"
|
||||||
|
"contract-ds-helpers.ss")
|
||||||
(require-for-syntax "contract-ds-helpers.ss"
|
(require-for-syntax "contract-ds-helpers.ss"
|
||||||
"contract-helpers.ss")
|
"contract-helpers.ss"
|
||||||
|
"contract-opt-guts.ss"
|
||||||
|
(lib "etc.ss"))
|
||||||
|
|
||||||
(provide define-contract-struct)
|
(provide define-contract-struct
|
||||||
|
|
||||||
|
make-opt-contract/info
|
||||||
|
opt-contract/info-contract
|
||||||
|
opt-contract/info-enforcer
|
||||||
|
opt-contract/info-pos
|
||||||
|
opt-contract/info-neg
|
||||||
|
opt-contract/info-src-info
|
||||||
|
opt-contract/info-orig-str
|
||||||
|
lazy-depth-to-look
|
||||||
|
|
||||||
|
unknown?
|
||||||
|
synthesized-value)
|
||||||
|
|
||||||
(define-syntax (define-contract-struct stx)
|
(define-syntax (define-contract-struct stx)
|
||||||
(syntax-case stx ()
|
(syntax-case stx ()
|
||||||
|
@ -43,9 +64,11 @@ it around flattened out.
|
||||||
[predicate/val (list-ref struct-names 2)]
|
[predicate/val (list-ref struct-names 2)]
|
||||||
[selectors/val (cdddr struct-names)]
|
[selectors/val (cdddr struct-names)]
|
||||||
[struct/c-name/val (add-suffix "/c")]
|
[struct/c-name/val (add-suffix "/c")]
|
||||||
[struct/dc-name/val(add-suffix "/dc")]
|
[struct/dc-name/val (add-suffix "/dc")]
|
||||||
[field-count/val (length selectors/val)]
|
[field-count/val (length selectors/val)]
|
||||||
[f-x/vals (generate-temporaries (syntax (fields ...)))])
|
[f-x/vals (generate-temporaries (syntax (fields ...)))]
|
||||||
|
[f-xs/vals (generate-arglists f-x/vals)])
|
||||||
|
|
||||||
(with-syntax ([struct/c struct/c-name/val]
|
(with-syntax ([struct/c struct/c-name/val]
|
||||||
[struct/dc struct/dc-name/val]
|
[struct/dc struct/dc-name/val]
|
||||||
[field-count field-count/val]
|
[field-count field-count/val]
|
||||||
|
@ -57,8 +80,9 @@ it around flattened out.
|
||||||
[(selector-indicies+1 ...) (map add1 (nums-up-to field-count/val))]
|
[(selector-indicies+1 ...) (map add1 (nums-up-to field-count/val))]
|
||||||
[(ctc-x ...) (generate-temporaries (syntax (fields ...)))]
|
[(ctc-x ...) (generate-temporaries (syntax (fields ...)))]
|
||||||
[(f-x ...) f-x/vals]
|
[(f-x ...) f-x/vals]
|
||||||
[((f-xs ...) ...) (generate-arglists f-x/vals)]
|
[((f-xs ...) ...) f-xs/vals]
|
||||||
[wrap-name (string->symbol (format "~a/lazy-contract" (syntax-e (syntax name))))])
|
[wrap-name (string->symbol (format "~a/lazy-contract" (syntax-e (syntax name))))]
|
||||||
|
[opt-wrap-name (string->symbol (format "~a/lazy-opt-contract" (syntax-e (syntax name))))])
|
||||||
#`
|
#`
|
||||||
(begin
|
(begin
|
||||||
|
|
||||||
|
@ -66,15 +90,52 @@ it around flattened out.
|
||||||
#,@(if (eq? (syntax-local-context) 'top-level)
|
#,@(if (eq? (syntax-local-context) 'top-level)
|
||||||
(list
|
(list
|
||||||
(syntax
|
(syntax
|
||||||
(define-syntaxes (contract-type contract-maker contract-predicate contract-get contract-set)
|
(define-syntaxes (contract-type contract-maker contract-predicate contract-get contract-set
|
||||||
|
already-there? burrow-in rewrite-fields wrap-get)
|
||||||
(values))))
|
(values))))
|
||||||
(list))
|
(list))
|
||||||
|
|
||||||
|
(define (evaluate-attrs stct contract/info)
|
||||||
|
(when (wrap-parent-get stct 0) ;; test to make sure this even has attributes
|
||||||
|
(let* ([any-unknown? #f]
|
||||||
|
[any-became-known? #f]
|
||||||
|
[synth-info (wrap-parent-get stct 0)]
|
||||||
|
[ht (synth-info-vals synth-info)])
|
||||||
|
(hash-table-for-each
|
||||||
|
ht
|
||||||
|
(lambda (k v)
|
||||||
|
(when (unknown? v)
|
||||||
|
(let ([proc (unknown-proc v)])
|
||||||
|
(let ([new (proc (wrap-get stct selector-indicies+1) ...)])
|
||||||
|
(cond
|
||||||
|
[(unknown? new)
|
||||||
|
(set! any-unknown? #t)]
|
||||||
|
[else
|
||||||
|
(set! any-became-known? #t)
|
||||||
|
(hash-table-put! ht k new)]))))))
|
||||||
|
(unless any-unknown?
|
||||||
|
(check-synth-info-test stct synth-info contract/info))
|
||||||
|
(when any-became-known?
|
||||||
|
(for-each
|
||||||
|
(lambda (x) ((evaluate-attr-prop-accessor x) x contract/info))
|
||||||
|
(synth-info-parents synth-info)))
|
||||||
|
(unless any-unknown?
|
||||||
|
(set-synth-info-parents! synth-info '())))))
|
||||||
|
|
||||||
(define-values (wrap-type wrap-maker wrap-predicate wrap-get wrap-set)
|
(define-values (wrap-type wrap-maker wrap-predicate wrap-get wrap-set)
|
||||||
(make-struct-type 'wrap-name
|
(make-struct-type 'wrap-name
|
||||||
|
wrap-parent-type ;; super struct
|
||||||
|
2 ;; field count
|
||||||
|
(max 0 (- field-count 1)) ;; auto-field-k
|
||||||
|
#f ;; auto-field-v
|
||||||
|
(list (cons evaluate-attr-prop evaluate-attrs))
|
||||||
|
inspector))
|
||||||
|
|
||||||
|
(define-values (opt-wrap-type opt-wrap-maker opt-wrap-predicate opt-wrap-get opt-wrap-set)
|
||||||
|
(make-struct-type 'opt-wrap-name
|
||||||
#f ;; super struct
|
#f ;; super struct
|
||||||
2 ;; field count
|
2 ;; field count
|
||||||
(- field-count 1) ;; auto-field-k
|
field-count ;; auto-field-k
|
||||||
#f ;; auto-field-v
|
#f ;; auto-field-v
|
||||||
'() ;; prop-value-list
|
'() ;; prop-value-list
|
||||||
inspector))
|
inspector))
|
||||||
|
@ -88,17 +149,20 @@ it around flattened out.
|
||||||
'() ;; prop-value-list
|
'() ;; prop-value-list
|
||||||
inspector))
|
inspector))
|
||||||
|
|
||||||
(define (predicate x) (or (raw-predicate x) (wrap-predicate x)))
|
(define (predicate x) (or (raw-predicate x) (opt-wrap-predicate x) (wrap-predicate x)))
|
||||||
|
|
||||||
(define-syntax (struct/dc stx)
|
(define-syntax (struct/dc stx)
|
||||||
(syntax-case stx ()
|
(syntax-case stx ()
|
||||||
[(_ clause (... ...))
|
[(_ clause (... ...))
|
||||||
(with-syntax ([(maker-args (... ...))
|
(with-syntax ([((maker-args (... ...))
|
||||||
|
(names (... ...)))
|
||||||
(build-clauses 'struct/dc
|
(build-clauses 'struct/dc
|
||||||
(syntax coerce-contract)
|
(syntax coerce-contract)
|
||||||
stx
|
stx
|
||||||
(syntax (clause (... ...))))])
|
(syntax (clause (... ...))))])
|
||||||
(syntax (contract-maker maker-args (... ...))))]))
|
(syntax
|
||||||
|
(let ([names 'names] (... ...))
|
||||||
|
(contract-maker maker-args (... ...)))))]))
|
||||||
|
|
||||||
(define (do-selection stct i+1)
|
(define (do-selection stct i+1)
|
||||||
(let-values ([(stct fields ...)
|
(let-values ([(stct fields ...)
|
||||||
|
@ -107,32 +171,54 @@ it around flattened out.
|
||||||
[(raw-predicate stct)
|
[(raw-predicate stct)
|
||||||
;; found the original value
|
;; found the original value
|
||||||
(values #f (get stct selector-indicies) ...)]
|
(values #f (get stct selector-indicies) ...)]
|
||||||
[else
|
|
||||||
|
[(opt-wrap-predicate stct)
|
||||||
|
(let ((inner (opt-wrap-get stct 0)))
|
||||||
|
(if inner
|
||||||
|
(let* ((info (opt-wrap-get stct 1))
|
||||||
|
(enforcer (opt-contract/info-enforcer info)))
|
||||||
|
(let-values ([(inner-stct fields ...) (loop inner)])
|
||||||
|
(let-values ([(fields ...) (enforcer stct fields ...)])
|
||||||
|
(opt-wrap-set stct 0 #f)
|
||||||
|
(opt-wrap-set stct selector-indicies+1 fields) ...
|
||||||
|
(values stct fields ...))))
|
||||||
|
|
||||||
|
;; found a cached version
|
||||||
|
(values #f (opt-wrap-get stct selector-indicies+1) ...)))]
|
||||||
|
[(wrap-predicate stct)
|
||||||
(let ([inner (wrap-get stct 0)])
|
(let ([inner (wrap-get stct 0)])
|
||||||
(if inner
|
(if inner
|
||||||
;; we have a contract to update
|
;; we have a contract to update
|
||||||
(let-values ([(_1 fields ...) (loop inner)])
|
(let ([contract/info (wrap-get stct 1)])
|
||||||
(let-values ([(fields ...)
|
(let-values ([(_1 fields ...) (loop inner)])
|
||||||
(rewrite-fields (wrap-get stct 1) fields ...)])
|
(let-values ([(fields ...)
|
||||||
(wrap-set stct 0 #f)
|
(rewrite-fields stct contract/info fields ...)])
|
||||||
(wrap-set stct selector-indicies+1 fields) ...
|
(wrap-set stct 0 #f)
|
||||||
(values stct fields ...)))
|
(wrap-set stct selector-indicies+1 fields) ...
|
||||||
|
(evaluate-attrs stct contract/info)
|
||||||
|
(values stct fields ...))))
|
||||||
|
|
||||||
;; found a cached version of the value
|
;; found a cached version of the value
|
||||||
(values #f (wrap-get stct selector-indicies+1) ...)))]))])
|
(values #f (wrap-get stct selector-indicies+1) ...)))]))])
|
||||||
(wrap-get stct i+1)))
|
(cond
|
||||||
|
[(opt-wrap-predicate stct) (opt-wrap-get stct i+1)]
|
||||||
|
[(wrap-predicate stct) (wrap-get stct i+1)])))
|
||||||
|
|
||||||
(define (rewrite-fields contract/info ctc-x ...)
|
(define (rewrite-fields parent contract/info ctc-x ...)
|
||||||
(let* ([f-x (let ([ctc-field (contract-get (contract/info-contract contract/info)
|
(let* ([f-x (let* ([ctc-field (contract-get (contract/info-contract contract/info)
|
||||||
selector-indicies)])
|
selector-indicies)]
|
||||||
(let ([ctc (if (procedure? ctc-field)
|
[ctc (if (procedure? ctc-field)
|
||||||
(ctc-field f-xs ...)
|
(ctc-field f-xs ...)
|
||||||
ctc-field)])
|
ctc-field)]
|
||||||
((((proj-get ctc) ctc) (contract/info-pos contract/info)
|
|
||||||
(contract/info-neg contract/info)
|
[ctc-field-val
|
||||||
(contract/info-src-info contract/info)
|
((((proj-get ctc) ctc) (contract/info-pos contract/info)
|
||||||
(contract/info-orig-str contract/info))
|
(contract/info-neg contract/info)
|
||||||
ctc-x)))] ...)
|
(contract/info-src-info contract/info)
|
||||||
|
(contract/info-orig-str contract/info))
|
||||||
|
ctc-x)])
|
||||||
|
(update-parent-links parent ctc-field-val)
|
||||||
|
ctc-field-val)] ...)
|
||||||
(values f-x ...)))
|
(values f-x ...)))
|
||||||
|
|
||||||
(define (stronger-lazy-contract? a b)
|
(define (stronger-lazy-contract? a b)
|
||||||
|
@ -145,7 +231,8 @@ it around flattened out.
|
||||||
(λ (pos-blame neg-blame src-info orig-str)
|
(λ (pos-blame neg-blame src-info orig-str)
|
||||||
(let ([contract/info (make-contract/info ctc pos-blame neg-blame src-info orig-str)])
|
(let ([contract/info (make-contract/info ctc pos-blame neg-blame src-info orig-str)])
|
||||||
(λ (val)
|
(λ (val)
|
||||||
(unless (or (wrap-predicate val)
|
(unless (or (wrap-predicate val)
|
||||||
|
(opt-wrap-predicate val)
|
||||||
(raw-predicate val))
|
(raw-predicate val))
|
||||||
(raise-contract-error
|
(raise-contract-error
|
||||||
val
|
val
|
||||||
|
@ -157,22 +244,43 @@ it around flattened out.
|
||||||
[(already-there? contract/info val lazy-depth-to-look)
|
[(already-there? contract/info val lazy-depth-to-look)
|
||||||
val]
|
val]
|
||||||
[else
|
[else
|
||||||
(wrap-maker val contract/info)])))))
|
(let ([wrapper (wrap-maker val contract/info)])
|
||||||
|
(let ([synth-setup-stuff (contract-get ctc field-count)])
|
||||||
|
(when synth-setup-stuff
|
||||||
|
(let ([ht (make-hash-table)])
|
||||||
|
(for-each (λ (pr) (hash-table-put! ht (car pr) (make-unknown (cdr pr))))
|
||||||
|
(cdr synth-setup-stuff))
|
||||||
|
(wrap-parent-set wrapper 0 (make-synth-info '() ht (car synth-setup-stuff))))))
|
||||||
|
wrapper)])))))
|
||||||
|
|
||||||
|
(define (already-there/opt? val new-n new-r)
|
||||||
|
(cond
|
||||||
|
[(and (opt-wrap-predicate val)
|
||||||
|
(opt-wrap-get val 0))
|
||||||
|
(let ([old-n (opt-wrap-get val 2)]
|
||||||
|
[old-r (opt-wrap-get val 3)])
|
||||||
|
(flattened-stronger old-n old-r new-n new-r))]
|
||||||
|
[else #f]))
|
||||||
|
|
||||||
|
(define (flattened-stronger this-val this-rank that-val that-rank)
|
||||||
|
(and (<= this-val that-val)
|
||||||
|
(>= this-rank that-rank)))
|
||||||
|
|
||||||
(define (already-there? new-contract/info val depth)
|
(define (already-there? new-contract/info val depth)
|
||||||
(cond
|
(cond
|
||||||
[(raw-predicate val) #f]
|
[(raw-predicate val) #f]
|
||||||
[(zero? depth) #f]
|
[(zero? depth) #f]
|
||||||
[(wrap-get val 0)
|
[(wrap-predicate val)
|
||||||
(let ([old-contract/info (wrap-get val 1)])
|
(and (wrap-get val 0)
|
||||||
(if (and (eq? (contract/info-pos new-contract/info)
|
(let ([old-contract/info (wrap-get val 1)])
|
||||||
(contract/info-pos old-contract/info))
|
(if (and (eq? (contract/info-pos new-contract/info)
|
||||||
(eq? (contract/info-neg new-contract/info)
|
(contract/info-pos old-contract/info))
|
||||||
(contract/info-neg old-contract/info))
|
(eq? (contract/info-neg new-contract/info)
|
||||||
(contract-stronger? (contract/info-contract old-contract/info)
|
(contract/info-neg old-contract/info))
|
||||||
(contract/info-contract new-contract/info)))
|
(contract-stronger? (contract/info-contract old-contract/info)
|
||||||
#t
|
(contract/info-contract new-contract/info)))
|
||||||
(already-there? new-contract/info (wrap-get val 0) (- depth 1))))]
|
#t
|
||||||
|
(already-there? new-contract/info (wrap-get val 0) (- depth 1)))))]
|
||||||
[else
|
[else
|
||||||
;; when the zeroth field is cleared out, we don't
|
;; when the zeroth field is cleared out, we don't
|
||||||
;; have a contract to compare to anymore.
|
;; have a contract to compare to anymore.
|
||||||
|
@ -180,14 +288,19 @@ it around flattened out.
|
||||||
|
|
||||||
(define (struct/c ctc-x ...)
|
(define (struct/c ctc-x ...)
|
||||||
(let ([ctc-x (coerce-contract 'struct/c ctc-x)] ...)
|
(let ([ctc-x (coerce-contract 'struct/c ctc-x)] ...)
|
||||||
(contract-maker ctc-x ...)))
|
(contract-maker ctc-x ... #f)))
|
||||||
|
|
||||||
(define (selectors x) (burrow-in x 'selectors selector-indicies)) ...
|
(define (selectors x)
|
||||||
|
(burrow-in x 'selectors selector-indicies)) ...
|
||||||
|
|
||||||
(define (burrow-in struct selector-name i)
|
(define (burrow-in struct selector-name i)
|
||||||
(cond
|
(cond
|
||||||
[(raw-predicate struct)
|
[(raw-predicate struct)
|
||||||
(get struct i)]
|
(get struct i)]
|
||||||
|
[(opt-wrap-predicate struct)
|
||||||
|
(if (opt-wrap-get struct 0)
|
||||||
|
(do-selection struct (+ i 1))
|
||||||
|
(opt-wrap-get struct (+ i 1)))]
|
||||||
[(wrap-predicate struct)
|
[(wrap-predicate struct)
|
||||||
(if (wrap-get struct 0)
|
(if (wrap-get struct 0)
|
||||||
(do-selection struct (+ i 1))
|
(do-selection struct (+ i 1))
|
||||||
|
@ -196,32 +309,297 @@ it around flattened out.
|
||||||
(error selector-name "expected <~a>, got ~e" 'name struct)]))
|
(error selector-name "expected <~a>, got ~e" 'name struct)]))
|
||||||
|
|
||||||
(define (lazy-contract-name ctc)
|
(define (lazy-contract-name ctc)
|
||||||
(let ([list-of-subcontracts (list (contract-get ctc selector-indicies) ...)])
|
(do-contract-name 'struct/c
|
||||||
(cond
|
'struct/dc
|
||||||
[(andmap contract? list-of-subcontracts)
|
(list (contract-get ctc selector-indicies) ...)
|
||||||
(apply build-compound-type-name 'struct/c list-of-subcontracts)]
|
'(fields ...)
|
||||||
[else
|
(contract-get ctc field-count)))
|
||||||
(let ([dots (string->symbol "...")])
|
|
||||||
(apply build-compound-type-name 'struct/dc
|
|
||||||
(map (λ (field ctc)
|
|
||||||
(if (contract? ctc)
|
|
||||||
(build-compound-type-name field ctc)
|
|
||||||
(build-compound-type-name field dots)))
|
|
||||||
'(fields ...)
|
|
||||||
list-of-subcontracts)))])))
|
|
||||||
|
|
||||||
(define-values (contract-type contract-maker contract-predicate contract-get contract-set)
|
(define-values (contract-type contract-maker contract-predicate contract-get contract-set)
|
||||||
(make-struct-type 'contract-name
|
(make-struct-type 'contract-name
|
||||||
#f
|
#f
|
||||||
field-count
|
(+ field-count 1) ;; extra field is for synthesized attribute ctcs
|
||||||
|
;; it is a list whose first element is
|
||||||
|
;; a procedure (called once teh attrs are known) that
|
||||||
|
;; indicates if the test passes. the rest of the elements are
|
||||||
|
;; procedures that build the attrs
|
||||||
|
;; this field is #f when there is no synthesized attrs
|
||||||
0 ;; auto-field-k
|
0 ;; auto-field-k
|
||||||
'() ;; auto-field-v
|
'() ;; auto-field-v
|
||||||
(list (cons proj-prop lazy-contract-proj)
|
(list (cons proj-prop lazy-contract-proj)
|
||||||
(cons name-prop lazy-contract-name)
|
(cons name-prop lazy-contract-name)
|
||||||
(cons first-order-prop (λ (ctc) predicate))
|
(cons first-order-prop (λ (ctc) predicate))
|
||||||
(cons stronger-prop stronger-lazy-contract?)))))))]))
|
(cons stronger-prop stronger-lazy-contract?))))
|
||||||
|
|
||||||
|
(define-for-syntax (build-enforcer opt/i opt/info name stx clauses
|
||||||
|
helper-id-var helper-info helper-freev
|
||||||
|
enforcer-id-var)
|
||||||
|
(define (make-free-vars free-vars freev)
|
||||||
|
(let loop ([i 0]
|
||||||
|
[stx null]
|
||||||
|
[free-vars free-vars])
|
||||||
|
(cond
|
||||||
|
[(null? free-vars) (reverse stx)]
|
||||||
|
[else (loop (+ i 1)
|
||||||
|
(cons (with-syntax ((var (car free-vars))
|
||||||
|
(freev freev)
|
||||||
|
(j (+ i 2)))
|
||||||
|
(syntax (var (opt-wrap-get stct j)))) stx)
|
||||||
|
(cdr free-vars))])))
|
||||||
|
|
||||||
|
(let*-values ([(inner-val) #'val]
|
||||||
|
[(clauses lifts superlifts stronger-ribs)
|
||||||
|
(build-enforcer-clauses opt/i
|
||||||
|
(make-opt/info #'ctc
|
||||||
|
inner-val
|
||||||
|
#'pos
|
||||||
|
#'neg
|
||||||
|
#'src-info
|
||||||
|
#'orig-str
|
||||||
|
(opt/info-free-vars opt/info)
|
||||||
|
(opt/info-recf opt/info)
|
||||||
|
(opt/info-base-pred opt/info)
|
||||||
|
(opt/info-this opt/info)
|
||||||
|
(opt/info-that opt/info)
|
||||||
|
(opt/info-sv-index opt/info))
|
||||||
|
name
|
||||||
|
stx
|
||||||
|
clauses
|
||||||
|
(list (syntax f-x) ...)
|
||||||
|
(list (list (syntax f-xs) ...) ...)
|
||||||
|
helper-id-var
|
||||||
|
helper-info
|
||||||
|
helper-freev)])
|
||||||
|
(with-syntax ([(clause (... ...)) clauses]
|
||||||
|
[enforcer-id enforcer-id-var]
|
||||||
|
[helper-id helper-id-var]
|
||||||
|
[free-vars (make-free-vars (append (opt/info-free-vars opt/info)) #'freev)]
|
||||||
|
[(saved-lifts (... ...)) (lifts-to-save lifts)])
|
||||||
|
(values
|
||||||
|
#`(λ (stct f-x ...)
|
||||||
|
(let* ([info (opt-wrap-get stct 1)]
|
||||||
|
[enforcer (opt-contract/info-enforcer info)]
|
||||||
|
[ctc (opt-contract/info-contract info)]
|
||||||
|
[pos (opt-contract/info-pos info)]
|
||||||
|
[neg (opt-contract/info-neg info)]
|
||||||
|
[src-info (opt-contract/info-src-info info)]
|
||||||
|
[orig-str (opt-contract/info-orig-str info)])
|
||||||
|
(let free-vars
|
||||||
|
#,(bind-lifts
|
||||||
|
lifts
|
||||||
|
#`(let-syntax #,(if (opt/info-recf opt/info)
|
||||||
|
(#`[#,(opt/info-recf opt/info)
|
||||||
|
(lambda (stx)
|
||||||
|
(syntax-case stx ()
|
||||||
|
[(f val args ((... ...) (... ...)))
|
||||||
|
#'(helper-id val
|
||||||
|
info
|
||||||
|
args
|
||||||
|
((... ...) (... ...))
|
||||||
|
saved-lifts (... ...))]))])
|
||||||
|
#`())
|
||||||
|
(let* (clause (... ...))
|
||||||
|
(values f-x ...)))))))
|
||||||
|
lifts
|
||||||
|
superlifts
|
||||||
|
stronger-ribs))))
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; struct/dc opter
|
||||||
|
;;
|
||||||
|
(define/opter (struct/dc opt/i opt/info stx)
|
||||||
|
(syntax-case stx ()
|
||||||
|
[(_ clause (... ...))
|
||||||
|
(let ((enforcer-id-var (car (generate-temporaries (syntax (enforcer)))))
|
||||||
|
(helper-id-var (car (generate-temporaries (syntax (helper)))))
|
||||||
|
(contract/info-var (car (generate-temporaries (syntax (contract/info))))))
|
||||||
|
(let-values ([(enforcer lifts superlifts stronger-ribs)
|
||||||
|
(build-enforcer opt/i
|
||||||
|
opt/info
|
||||||
|
'struct/dc
|
||||||
|
stx
|
||||||
|
(syntax (clause (... ...)))
|
||||||
|
helper-id-var
|
||||||
|
#'info
|
||||||
|
#'freev
|
||||||
|
enforcer-id-var)])
|
||||||
|
(let ([to-save (append (opt/info-free-vars opt/info)
|
||||||
|
(lifts-to-save lifts))])
|
||||||
|
(with-syntax ((val (opt/info-val opt/info))
|
||||||
|
(pos (opt/info-pos opt/info))
|
||||||
|
(neg (opt/info-neg opt/info))
|
||||||
|
(src-info (opt/info-src-info opt/info))
|
||||||
|
(orig-str (opt/info-orig-str opt/info))
|
||||||
|
(ctc (opt/info-contract opt/info))
|
||||||
|
(base-pred (or (opt/info-base-pred opt/info) #'(λ (x) #f)))
|
||||||
|
(enforcer-id enforcer-id-var)
|
||||||
|
(helper-id helper-id-var)
|
||||||
|
(contract/info contract/info-var)
|
||||||
|
((j (... ...)) (let loop ([i 2]
|
||||||
|
[lst to-save])
|
||||||
|
(cond
|
||||||
|
[(null? lst) null]
|
||||||
|
[else (cons i (loop (+ i 1) (cdr lst)))])))
|
||||||
|
((free-var (... ...)) to-save))
|
||||||
|
(values
|
||||||
|
(syntax (helper-id val contract/info free-var (... ...)))
|
||||||
|
lifts
|
||||||
|
(append
|
||||||
|
superlifts
|
||||||
|
(list (with-syntax ([(stronger-this-var (... ...)) (map stronger-rib-this-var stronger-ribs)]
|
||||||
|
[(stronger-that-var (... ...)) (map stronger-rib-that-var stronger-ribs)]
|
||||||
|
[(stronger-exps (... ...)) (map stronger-rib-stronger-exp stronger-ribs)]
|
||||||
|
[(stronger-indexes (... ...)) (build-list (length stronger-ribs)
|
||||||
|
(λ (x) (+ x 2)))]
|
||||||
|
[(stronger-var (... ...)) (map stronger-rib-save-id stronger-ribs)])
|
||||||
|
(cons #'is-stronger?
|
||||||
|
#'(λ (val i free-var (... ...))
|
||||||
|
(cond
|
||||||
|
[(= i 0) #f]
|
||||||
|
[(and (opt-wrap-predicate val)
|
||||||
|
(opt-wrap-get val 0))
|
||||||
|
(let ([stronger-this-var stronger-var]
|
||||||
|
(... ...)
|
||||||
|
|
||||||
|
;; this computation is bogus
|
||||||
|
;; it only works if the stronger vars and the things
|
||||||
|
;; saved in the wrapper are the same
|
||||||
|
[stronger-that-var (opt-wrap-get val stronger-indexes)]
|
||||||
|
(... ...))
|
||||||
|
|
||||||
|
(or (and
|
||||||
|
;; make sure this is the same contract -- if not,
|
||||||
|
;; the rest of this test is bogus and may fail at runtime
|
||||||
|
(eq? enforcer-id (opt-contract/info-enforcer
|
||||||
|
(opt-wrap-get val 1)))
|
||||||
|
stronger-exps
|
||||||
|
(... ...))
|
||||||
|
(is-stronger? (opt-wrap-get val 0)
|
||||||
|
(- i 1)
|
||||||
|
free-var (... ...))))]
|
||||||
|
[else #f]))))
|
||||||
|
(cons
|
||||||
|
helper-id-var
|
||||||
|
(syntax
|
||||||
|
(λ (val info free-var (... ...))
|
||||||
|
(let ([ctc (opt-contract/info-contract info)]
|
||||||
|
[pos (opt-contract/info-pos info)]
|
||||||
|
[neg (opt-contract/info-neg info)]
|
||||||
|
[src-info (opt-contract/info-src-info info)]
|
||||||
|
[orig-str (opt-contract/info-orig-str info)])
|
||||||
|
(cond
|
||||||
|
;; FIXME terribly broken
|
||||||
|
[(base-pred val) val]
|
||||||
|
[else
|
||||||
|
(begin
|
||||||
|
(unless (or (wrap-predicate val)
|
||||||
|
(opt-wrap-predicate val)
|
||||||
|
(raw-predicate val))
|
||||||
|
(raise-contract-error
|
||||||
|
val
|
||||||
|
src-info
|
||||||
|
pos
|
||||||
|
orig-str
|
||||||
|
"expected <~a>, got ~e"
|
||||||
|
((name-get ctc) ctc)
|
||||||
|
val))
|
||||||
|
(cond
|
||||||
|
;; this is where the optimized stronger needs to be called.
|
||||||
|
[(is-stronger? val 5 free-var (... ...))
|
||||||
|
val]
|
||||||
|
;; ALLOCATE OPT-WRAP
|
||||||
|
[else
|
||||||
|
(let ([w (opt-wrap-maker val info)])
|
||||||
|
(opt-wrap-set w j free-var) (... ...)
|
||||||
|
w)]))])))))
|
||||||
|
(cons enforcer-id-var enforcer)))
|
||||||
|
(list (cons contract/info-var
|
||||||
|
(syntax
|
||||||
|
(make-opt-contract/info ctc
|
||||||
|
enforcer-id
|
||||||
|
pos
|
||||||
|
neg
|
||||||
|
src-info
|
||||||
|
orig-str))))
|
||||||
|
#f
|
||||||
|
#f
|
||||||
|
stronger-ribs)))))]))
|
||||||
|
|
||||||
|
)))]))
|
||||||
|
|
||||||
|
(define (do-contract-name name/c name/dc list-of-subcontracts fields attrs)
|
||||||
|
(cond
|
||||||
|
[(and (andmap contract? list-of-subcontracts) (not attrs))
|
||||||
|
(apply build-compound-type-name name/c list-of-subcontracts)]
|
||||||
|
[else
|
||||||
|
(let ([fields
|
||||||
|
(map (λ (field ctc)
|
||||||
|
(if (contract? ctc)
|
||||||
|
(build-compound-type-name field ctc)
|
||||||
|
(build-compound-type-name field '...)))
|
||||||
|
fields
|
||||||
|
list-of-subcontracts)])
|
||||||
|
(cond
|
||||||
|
[attrs
|
||||||
|
(apply build-compound-type-name
|
||||||
|
name/dc
|
||||||
|
(append fields
|
||||||
|
(list 'where)
|
||||||
|
(map (λ (x) `(,(car x) ...))
|
||||||
|
(reverse (cdr attrs)))
|
||||||
|
(list 'and '...)))]
|
||||||
|
[else (apply build-compound-type-name name/dc fields)]))]))
|
||||||
|
|
||||||
(define-struct contract/info (contract pos neg src-info orig-str))
|
(define-struct contract/info (contract pos neg src-info orig-str))
|
||||||
|
(define-struct opt-contract/info (contract enforcer pos neg src-info orig-str))
|
||||||
|
|
||||||
|
;; parents : (listof wrap-parent)
|
||||||
|
;; vals : hash-table[symbol -o> (union (make-unknown proc[field-vals -> any]) any)
|
||||||
|
;; test : proc[vals-hash-table -> boolean]
|
||||||
|
(define-struct synth-info (parents vals test))
|
||||||
|
|
||||||
|
(define-struct unknown (proc))
|
||||||
|
|
||||||
|
(define secret (gensym))
|
||||||
|
(define (synthesized-value wrap key)
|
||||||
|
(unless (wrap-parent-predicate wrap)
|
||||||
|
(error 'synthesized-value "expected struct value with contract as first argument, got ~e" wrap))
|
||||||
|
(let ([ans (hash-table-get (synth-info-vals (wrap-parent-get wrap 0))
|
||||||
|
key
|
||||||
|
secret)])
|
||||||
|
(when (eq? ans secret)
|
||||||
|
(error 'synthesized-value "the key ~e is not mapped in ~e" key wrap))
|
||||||
|
ans))
|
||||||
|
|
||||||
|
(define (check-synth-info-test stct synth-info contract/info)
|
||||||
|
(unless ((synth-info-test synth-info) (synth-info-vals synth-info))
|
||||||
|
(raise-contract-error
|
||||||
|
stct
|
||||||
|
(contract/info-src-info contract/info)
|
||||||
|
(contract/info-pos contract/info)
|
||||||
|
(contract/info-orig-str contract/info)
|
||||||
|
"failed `and' clause, got ~e" stct)))
|
||||||
|
|
||||||
|
(define-values (evaluate-attr-prop evaluate-attr-prop-predicate evaluate-attr-prop-accessor)
|
||||||
|
(make-struct-type-property 'evaluate-attr-prop))
|
||||||
|
|
||||||
|
(define-values (wrap-parent-type wrap-parent-maker wrap-parent-predicate wrap-parent-get wrap-parent-set)
|
||||||
|
(make-struct-type 'wrap-parent
|
||||||
|
#f ;; parent
|
||||||
|
0 ;; fields
|
||||||
|
1 ;; auto fields
|
||||||
|
))
|
||||||
|
|
||||||
|
(define (update-parent-links parent ctc-field-val)
|
||||||
|
(when (wrap-parent-predicate ctc-field-val)
|
||||||
|
(let ([old (wrap-parent-get ctc-field-val 0)])
|
||||||
|
(when old
|
||||||
|
;; add in new parent
|
||||||
|
(wrap-parent-set ctc-field-val 0
|
||||||
|
(make-synth-info
|
||||||
|
(cons parent (synth-info-parents old))
|
||||||
|
(synth-info-vals old)
|
||||||
|
(synth-info-test old)))))))
|
||||||
|
|
||||||
(define max-cache-size 5)
|
(define max-cache-size 5)
|
||||||
(define lazy-depth-to-look 5)
|
(define lazy-depth-to-look 5)
|
||||||
|
@ -265,4 +643,4 @@ test-case:
|
||||||
|#
|
|#
|
||||||
|
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -193,16 +193,21 @@
|
||||||
(define (raise-contract-error val src-info blame contract-sexp fmt . args)
|
(define (raise-contract-error val src-info blame contract-sexp fmt . args)
|
||||||
(raise
|
(raise
|
||||||
(make-exn:fail:contract2
|
(make-exn:fail:contract2
|
||||||
((contract-violation->string)
|
(string->immutable-string
|
||||||
val src-info blame contract-sexp (apply format fmt args))
|
((contract-violation->string) val
|
||||||
|
src-info
|
||||||
|
blame
|
||||||
|
contract-sexp
|
||||||
|
(apply format fmt args)))
|
||||||
(current-continuation-marks)
|
(current-continuation-marks)
|
||||||
(if src-info
|
(if src-info
|
||||||
(list (make-srcloc (syntax-source src-info)
|
(list (make-srcloc
|
||||||
(syntax-line src-info)
|
(syntax-source src-info)
|
||||||
(syntax-column src-info)
|
(syntax-line src-info)
|
||||||
(syntax-position src-info)
|
(syntax-column src-info)
|
||||||
(syntax-span src-info)))
|
(syntax-position src-info)
|
||||||
'()))))
|
(syntax-span src-info)))
|
||||||
|
'()))))
|
||||||
|
|
||||||
(define print-contract-liner
|
(define print-contract-liner
|
||||||
(let ([default (pretty-print-print-line)])
|
(let ([default (pretty-print-print-line)])
|
||||||
|
@ -308,7 +313,12 @@
|
||||||
(error 'flat-contract-predicate "expected a flat contract, got ~e" x))
|
(error 'flat-contract-predicate "expected a flat contract, got ~e" x))
|
||||||
((flat-get x) x))
|
((flat-get x) x))
|
||||||
(define (flat-contract? x) (flat-pred? x))
|
(define (flat-contract? x) (flat-pred? x))
|
||||||
(define (contract-name ctc) ((name-get ctc) ctc))
|
(define (contract-name ctc)
|
||||||
|
(if (and (procedure? ctc)
|
||||||
|
(procedure-arity-includes? ctc 1))
|
||||||
|
(or (object-name ctc)
|
||||||
|
'unknown)
|
||||||
|
((name-get ctc) ctc)))
|
||||||
(define (contract? x) (proj-pred? x))
|
(define (contract? x) (proj-pred? x))
|
||||||
(define (contract-proc ctc) ((proj-get ctc) ctc))
|
(define (contract-proc ctc) ((proj-get ctc) ctc))
|
||||||
|
|
||||||
|
@ -444,4 +454,4 @@
|
||||||
(define (flat-contract/predicate? pred)
|
(define (flat-contract/predicate? pred)
|
||||||
(or (flat-contract? pred)
|
(or (flat-contract? pred)
|
||||||
(and (procedure? pred)
|
(and (procedure? pred)
|
||||||
(procedure-arity-includes? pred 1)))))
|
(procedure-arity-includes? pred 1)))))
|
|
@ -1,56 +1,48 @@
|
||||||
(module contract-opt-guts mzscheme
|
(module contract-opt-guts mzscheme
|
||||||
(require "contract-guts.ss")
|
(require (lib "private/boundmap.ss" "syntax")
|
||||||
|
(lib "list.ss")
|
||||||
|
"contract-guts.ss")
|
||||||
|
(require-for-template mzscheme)
|
||||||
|
|
||||||
(provide get-opter reg-opter! opter
|
(provide get-opter reg-opter! opter
|
||||||
|
interleave-lifts
|
||||||
|
|
||||||
make-opt-contract
|
make-opt/info
|
||||||
orig-ctc-prop orig-ctc-pred? orig-ctc-get
|
opt/info-contract
|
||||||
|
opt/info-val
|
||||||
make-lifts interleave-lifts)
|
opt/info-pos
|
||||||
|
opt/info-neg
|
||||||
|
opt/info-src-info
|
||||||
|
opt/info-orig-str
|
||||||
|
opt/info-free-vars
|
||||||
|
opt/info-recf
|
||||||
|
opt/info-base-pred
|
||||||
|
opt/info-this
|
||||||
|
opt/info-that
|
||||||
|
opt/info-sv-index
|
||||||
|
|
||||||
|
sv-index
|
||||||
|
inc-sv-index!
|
||||||
|
|
||||||
|
opt/info-swap-blame)
|
||||||
|
|
||||||
(define-values (orig-ctc-prop orig-ctc-pred? orig-ctc-get)
|
|
||||||
(make-struct-type-property 'original-contract))
|
|
||||||
|
|
||||||
;; optimized contracts
|
|
||||||
;;
|
|
||||||
;; getting the name of an optimized contract is slow, but it is only
|
|
||||||
;; called when blame is raised (thankfully).
|
|
||||||
;;
|
|
||||||
;; note that lifts, partials, flat, and unknown are all built into the
|
|
||||||
;; projection itself and should not be exposed to the outside anyhow.
|
|
||||||
(define-struct/prop opt-contract (proj orig-ctc)
|
|
||||||
((proj-prop (λ (ctc) ((opt-contract-proj ctc) ctc)))
|
|
||||||
(name-prop (λ (ctc) ((name-get ((orig-ctc-get ctc) ctc)) ((orig-ctc-get ctc) ctc))))
|
|
||||||
(orig-ctc-prop (λ (ctc) ((opt-contract-orig-ctc ctc))))
|
|
||||||
(stronger-prop (λ (this that)
|
|
||||||
#f)))) ;; TODO, how to do this?
|
|
||||||
|
|
||||||
;; a hash table of opters
|
;; a hash table of opters
|
||||||
(define opters-table
|
(define opters-table
|
||||||
(make-hash-table 'equal))
|
(make-module-identifier-mapping))
|
||||||
|
|
||||||
;; get-opter : syntax -> opter
|
;; get-opter : syntax -> opter
|
||||||
(define (get-opter ctc)
|
(define (get-opter ctc)
|
||||||
(hash-table-get opters-table ctc #f))
|
(module-identifier-mapping-get opters-table ctc (λ () #f)))
|
||||||
|
|
||||||
;; opter : (union symbol identifier) -> opter
|
;; opter : (union symbol identifier) -> opter
|
||||||
(define (opter ctc)
|
(define (opter ctc)
|
||||||
(if (or (identifier? ctc) (symbol? ctc))
|
(if (identifier? ctc)
|
||||||
(let ((key (if (syntax? ctc) (syntax-e ctc) ctc)))
|
(get-opter ctc)
|
||||||
(get-opter key))
|
(error 'opter "the argument must be a bound identifier, got ~e" ctc)))
|
||||||
(error 'opter "the argument must either be an identifier or a syntax object of an identifier, got ~e" ctc)))
|
|
||||||
|
|
||||||
;; reg-opter! : symbol opter ->
|
;; reg-opter! : symbol opter ->
|
||||||
(define (reg-opter! ctc opter)
|
(define (reg-opter! ctc opter)
|
||||||
(hash-table-put! opters-table ctc opter))
|
(module-identifier-mapping-put! opters-table ctc opter))
|
||||||
|
|
||||||
;; make-lifts : list -> syntax
|
|
||||||
;; converts a list of lifted-var lifted-expr pairs into a syntax object
|
|
||||||
;; suitable for use in a let.
|
|
||||||
(define (make-lifts lst)
|
|
||||||
(map (λ (x) (with-syntax ((var (car x))
|
|
||||||
(e (cdr x)))
|
|
||||||
(syntax (var e)))) lst))
|
|
||||||
|
|
||||||
;; interleave-lifts : list list -> list
|
;; interleave-lifts : list list -> list
|
||||||
;; interleaves a list of variables names and a list of sexps into a list of
|
;; interleaves a list of variables names and a list of sexps into a list of
|
||||||
|
@ -60,4 +52,115 @@
|
||||||
(if (null? vars) null
|
(if (null? vars) null
|
||||||
(cons (cons (car vars) (car sexps))
|
(cons (cons (car vars) (car sexps))
|
||||||
(interleave-lifts (cdr vars) (cdr sexps))))
|
(interleave-lifts (cdr vars) (cdr sexps))))
|
||||||
(error 'interleave-lifts "expected lists of equal length, got ~e and ~e" vars sexps))))
|
(error 'interleave-lifts "expected lists of equal length, got ~e and ~e" vars sexps)))
|
||||||
|
|
||||||
|
|
||||||
|
;; struct for color-keeping across opters
|
||||||
|
(define-struct opt/info (contract val pos neg src-info orig-str free-vars recf base-pred this that sv-index))
|
||||||
|
|
||||||
|
;; sv-index : opt/info -> int
|
||||||
|
(define (sv-index info)
|
||||||
|
(unbox (opt/info-sv-index info)))
|
||||||
|
|
||||||
|
;; inc-sv-index! : opt/info int -> unit
|
||||||
|
(define (inc-sv-index! info n)
|
||||||
|
(let ((old (unbox (opt/info-sv-index info))))
|
||||||
|
(set-box! (opt/info-sv-index info) (+ old n))))
|
||||||
|
|
||||||
|
;; opt/info-swap-blame : opt/info -> opt/info
|
||||||
|
;; swaps pos and neg
|
||||||
|
(define (opt/info-swap-blame info)
|
||||||
|
(let ((ctc (opt/info-contract info))
|
||||||
|
(val (opt/info-val info))
|
||||||
|
(pos (opt/info-neg info))
|
||||||
|
(neg (opt/info-pos info))
|
||||||
|
(src-info (opt/info-src-info info))
|
||||||
|
(orig-str (opt/info-orig-str info))
|
||||||
|
(free-vars (opt/info-free-vars info))
|
||||||
|
(recf (opt/info-recf info))
|
||||||
|
(base-pred (opt/info-base-pred info))
|
||||||
|
(this (opt/info-this info))
|
||||||
|
(that (opt/info-that info))
|
||||||
|
(sv-index (opt/info-sv-index info)))
|
||||||
|
(make-opt/info ctc val pos neg src-info orig-str free-vars recf base-pred this that sv-index)))
|
||||||
|
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;
|
||||||
|
;; stronger helper functions
|
||||||
|
;;
|
||||||
|
|
||||||
|
;; new-stronger-var : identifier (identifier identifier -> exp) -> stronger-rib
|
||||||
|
;; the second identifier should be bound (in a lift) to an expression whose value has to be saved.
|
||||||
|
;; The ids passed to cogen are expected to be bound to two contracts' values of that expression, when
|
||||||
|
;; those contracts are being compared for strongerness
|
||||||
|
(define (new-stronger-var id cogen)
|
||||||
|
(with-syntax ([(var-this var-that) (generate-temporaries (list id id))])
|
||||||
|
(make-stronger-rib (syntax var-this)
|
||||||
|
(syntax var-that)
|
||||||
|
id
|
||||||
|
(cogen (syntax var-this)
|
||||||
|
(syntax var-that)))))
|
||||||
|
|
||||||
|
(define empty-stronger '())
|
||||||
|
|
||||||
|
(define-struct stronger-rib (this-var that-var save-id stronger-exp))
|
||||||
|
|
||||||
|
(provide new-stronger-var
|
||||||
|
(struct stronger-rib (this-var that-var save-id stronger-exp)))
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;
|
||||||
|
;; lifting helper functions
|
||||||
|
;;
|
||||||
|
(provide lift/binding lift/effect empty-lifts bind-lifts bind-superlifts lifts-to-save)
|
||||||
|
|
||||||
|
;; lift/binding : syntax[expression] identifier lifts -> (values syntax lifts)
|
||||||
|
;; adds a new id to `lifts' that is bound to `e'. Returns the
|
||||||
|
;; variable that was bound
|
||||||
|
;; values that are lifted are also saved in the wrapper to make sure that the rhs's are evaluated at the right time.
|
||||||
|
(define (lift/binding e id-hint lifts)
|
||||||
|
(syntax-case e ()
|
||||||
|
[x
|
||||||
|
(or (identifier? e)
|
||||||
|
(number? (syntax-e e))
|
||||||
|
(boolean? (syntax-e e)))
|
||||||
|
(values e lifts)]
|
||||||
|
#;
|
||||||
|
[x
|
||||||
|
(identifier? e)
|
||||||
|
(values e
|
||||||
|
(snoc (cons e e) lifts))]
|
||||||
|
[else
|
||||||
|
(let ([x (car (generate-temporaries (list id-hint)))])
|
||||||
|
(values x
|
||||||
|
(snoc (cons x e) lifts)))]))
|
||||||
|
|
||||||
|
;; lift/effect : syntax[expression] lifts -> lifts
|
||||||
|
;; adds a new lift to `lifts' that is evaluated for effect. no variable returned
|
||||||
|
(define (lift/effect e lifts)
|
||||||
|
(let ([x (car (generate-temporaries '(lift/effect)))])
|
||||||
|
(snoc (cons #f e) lifts)))
|
||||||
|
|
||||||
|
(define (snoc x l) (append l (list x)))
|
||||||
|
|
||||||
|
;; empty-lifts : lifts
|
||||||
|
;; the initial lifts
|
||||||
|
(define empty-lifts '())
|
||||||
|
|
||||||
|
(define (bind-lifts lifts stx) (do-bind-lifts lifts stx #'let*))
|
||||||
|
(define (bind-superlifts lifts stx) (do-bind-lifts lifts stx #'letrec))
|
||||||
|
|
||||||
|
(define (do-bind-lifts lifts stx binding-form)
|
||||||
|
(if (null? lifts)
|
||||||
|
stx
|
||||||
|
(with-syntax ([((lifts-x . lift-e) ...) lifts])
|
||||||
|
(with-syntax ([(lifts-x ...) (map (λ (x) (if (identifier? x) x (car (generate-temporaries '(junk)))))
|
||||||
|
(syntax->list (syntax (lifts-x ...))))]
|
||||||
|
[binding-form binding-form])
|
||||||
|
#`(binding-form ([lifts-x lift-e] ...)
|
||||||
|
#,stx)))))
|
||||||
|
|
||||||
|
(define (lifts-to-save lifts) (filter values (map car lifts)))
|
||||||
|
|
||||||
|
)
|
|
@ -1,25 +1,31 @@
|
||||||
(module contract-opt mzscheme
|
(module contract-opt mzscheme
|
||||||
(require "contract-guts.ss"
|
(require "contract-guts.ss"
|
||||||
"contract-opt-guts.ss")
|
(lib "etc.ss"))
|
||||||
(require-for-syntax "contract-opt-guts.ss"
|
(require-for-syntax "contract-opt-guts.ss"
|
||||||
|
(lib "etc.ss")
|
||||||
(lib "list.ss"))
|
(lib "list.ss"))
|
||||||
|
|
||||||
(provide opt/c define/opter)
|
(provide opt/c define/opter define/osc opt-stronger-vars-ref)
|
||||||
|
|
||||||
;; define/opter : id -> syntax
|
;; define/opter : id -> syntax
|
||||||
;;
|
;;
|
||||||
;; Takes an expression which is to be expected of the following signature:
|
;; Takes an expression which is to be expected of the following signature:
|
||||||
;;
|
;;
|
||||||
;; opter : id id syntax ->
|
;; opter : id id syntax list-of-ids ->
|
||||||
;; syntax syntax-list syntax-list (union syntax #f) (union syntax #f)
|
;; syntax syntax-list syntax-list syntax-list (union syntax #f) (union syntax #f) syntax
|
||||||
|
;;
|
||||||
;;
|
;;
|
||||||
;; It takes in an identifier for pos, neg, and the original syntax. An identifier
|
;; It takes in an identifier for pos, neg, and the original syntax. An identifier
|
||||||
;; that can be used to call the opt/i function is also implicitly passed into
|
;; that can be used to call the opt/i function is also implicitly passed into
|
||||||
;; every opter.
|
;; every opter. A list of free-variables is implicitly passed if the calling context
|
||||||
|
;; was define/osc otherwise it is null.
|
||||||
;;
|
;;
|
||||||
;; Every opter needs to return:
|
;; Every opter needs to return:
|
||||||
;; - the optimized syntax
|
;; - the optimized syntax
|
||||||
;; - lifted variables: a list of (id, sexp) pairs
|
;; - lifted variables: a list of (id, sexp) pairs
|
||||||
|
;; - super-lifted variables: functions or the such defined at the toplevel of the
|
||||||
|
;; calling context of the opt routine.
|
||||||
|
;; Currently this is only used for struct contracts.
|
||||||
;; - partially applied contracts: a list of (id, sexp) pairs
|
;; - partially applied contracts: a list of (id, sexp) pairs
|
||||||
;; - if the contract being optimized is flat,
|
;; - if the contract being optimized is flat,
|
||||||
;; then an sexp that evals to bool,
|
;; then an sexp that evals to bool,
|
||||||
|
@ -30,51 +36,240 @@
|
||||||
;; then #f (that is, it is not unknown)
|
;; then #f (that is, it is not unknown)
|
||||||
;; else the symbol of the lifted variable
|
;; else the symbol of the lifted variable
|
||||||
;; This is used for contracts with subcontracts (like cons) doing checks.
|
;; This is used for contracts with subcontracts (like cons) doing checks.
|
||||||
|
;; - a list of stronger-ribs
|
||||||
(define-syntax (define/opter stx)
|
(define-syntax (define/opter stx)
|
||||||
(syntax-case stx ()
|
(syntax-case stx ()
|
||||||
[(_ (for opt/i pos neg stx) expr ...)
|
[(_ (for opt/i opt/info stx) expr ...)
|
||||||
(if (identifier? #'for)
|
(if (identifier? #'for)
|
||||||
#'(begin
|
#'(begin
|
||||||
(begin-for-syntax
|
(begin-for-syntax
|
||||||
(reg-opter!
|
(reg-opter!
|
||||||
'for
|
#'for
|
||||||
(λ (opt/i pos neg stx)
|
(λ (opt/i opt/info stx)
|
||||||
expr ...)))
|
expr ...)))
|
||||||
#t)
|
#t)
|
||||||
(error 'define/opter "expected opter name to be an identifier, got ~e" (syntax-e #'for)))]))
|
(error 'define/opter "expected opter name to be an identifier, got ~e" (syntax-e #'for)))]))
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; opt/unknown : opt/i id id syntax
|
||||||
|
;;
|
||||||
|
(define-for-syntax (opt/unknown opt/i opt/info uctc)
|
||||||
|
(let* ((lift-var (car (generate-temporaries (syntax (lift)))))
|
||||||
|
(partial-var (car (generate-temporaries (syntax (partial)))))
|
||||||
|
(partial-flat-var (car (generate-temporaries (syntax (partial-flat))))))
|
||||||
|
(values
|
||||||
|
(with-syntax ((partial-var partial-var)
|
||||||
|
(lift-var lift-var)
|
||||||
|
(uctc uctc)
|
||||||
|
(val (opt/info-val opt/info)))
|
||||||
|
(syntax (partial-var val)))
|
||||||
|
(list (cons lift-var
|
||||||
|
;; FIXME needs to get the contract name somehow
|
||||||
|
(with-syntax ((uctc uctc))
|
||||||
|
(syntax (coerce-contract 'opt/c uctc)))))
|
||||||
|
null
|
||||||
|
(list (cons
|
||||||
|
partial-var
|
||||||
|
(with-syntax ((lift-var lift-var)
|
||||||
|
(pos (opt/info-pos opt/info))
|
||||||
|
(neg (opt/info-neg opt/info))
|
||||||
|
(src-info (opt/info-src-info opt/info))
|
||||||
|
(orig-str (opt/info-orig-str opt/info)))
|
||||||
|
(syntax (((proj-get lift-var) lift-var) pos neg src-info orig-str))))
|
||||||
|
(cons
|
||||||
|
partial-flat-var
|
||||||
|
(with-syntax ((lift-var lift-var))
|
||||||
|
(syntax (if (flat-pred? lift-var)
|
||||||
|
((flat-get lift-var) lift-var)
|
||||||
|
(lambda (x) (error 'opt/unknown "flat called on an unknown that had no flat pred ~s ~s"
|
||||||
|
lift-var
|
||||||
|
x)))))))
|
||||||
|
(with-syntax ([val (opt/info-val opt/info)]
|
||||||
|
[partial-flat-var partial-flat-var])
|
||||||
|
#'(partial-flat-var val))
|
||||||
|
lift-var
|
||||||
|
null)))
|
||||||
|
|
||||||
|
;;
|
||||||
|
;; opt/recursive-call
|
||||||
|
;;
|
||||||
|
;; BUG: currently does not try to optimize the arguments, this requires changing
|
||||||
|
;; every opter to keep track of bound variables.
|
||||||
|
;;
|
||||||
|
(define-for-syntax (opt/recursive-call opt/info stx)
|
||||||
|
(values
|
||||||
|
(with-syntax ((stx stx)
|
||||||
|
(val (opt/info-val opt/info))
|
||||||
|
(pos (opt/info-pos opt/info))
|
||||||
|
(neg (opt/info-neg opt/info))
|
||||||
|
(src-info (opt/info-src-info opt/info))
|
||||||
|
(orig-str (opt/info-orig-str opt/info)))
|
||||||
|
(syntax (let ((ctc stx))
|
||||||
|
((((proj-get ctc) ctc) pos neg src-info orig-str) val))))
|
||||||
|
null
|
||||||
|
null
|
||||||
|
null
|
||||||
|
#f
|
||||||
|
#f
|
||||||
|
null
|
||||||
|
null))
|
||||||
|
|
||||||
|
;; make-stronger : list-of-(union syntax #f) -> syntax
|
||||||
|
(define-for-syntax (make-stronger strongers)
|
||||||
|
(let ((filtered (filter (λ (x) (not (eq? x #f))) strongers)))
|
||||||
|
(if (null? filtered)
|
||||||
|
#t
|
||||||
|
(with-syntax (((stronger ...) strongers))
|
||||||
|
(syntax (and stronger ...))))))
|
||||||
|
|
||||||
;; opt/c : syntax -> syntax
|
;; opt/c : syntax -> syntax
|
||||||
;; opt/c is an optimization routine that takes in an sexp containing
|
;; opt/c is an optimization routine that takes in an sexp containing
|
||||||
;; contract combinators and attempts to "unroll" those combinators to save
|
;; contract combinators and attempts to "unroll" those combinators to save
|
||||||
;; on things such as closure allocation time.
|
;; on things such as closure allocation time.
|
||||||
(define-syntax (opt/c stx)
|
(define-syntax (opt/c stx)
|
||||||
|
|
||||||
;; opt/i : id id syntax ->
|
;; opt/i : id opt/info syntax ->
|
||||||
;; syntax syntax-list syntax-list (union syntax #f) (union syntax #f)
|
;; syntax syntax-list syntax-list (union syntax #f) (union syntax #f)
|
||||||
(define (opt/i pos neg stx)
|
(define (opt/i opt/info stx)
|
||||||
(syntax-case stx ()
|
(syntax-case stx (if)
|
||||||
[(ctc arg ...)
|
[(ctc arg ...)
|
||||||
(and (identifier? #'ctc) (opter #'ctc))
|
(and (identifier? #'ctc) (opter #'ctc))
|
||||||
((opter #'ctc) opt/i pos neg stx)]
|
((opter #'ctc) opt/i opt/info stx)]
|
||||||
[argless-ctc
|
[argless-ctc
|
||||||
(and (identifier? #'argless-ctc) (opter #'argless-ctc))
|
(and (identifier? #'argless-ctc) (opter #'argless-ctc))
|
||||||
((opter #'argless-ctc) opt/i pos neg stx)]
|
((opter #'argless-ctc) opt/i opt/info stx)]
|
||||||
[else
|
[else
|
||||||
(if (opter 'unknown)
|
(opt/unknown opt/i opt/info stx)]))
|
||||||
((opter 'unknown) opt/i pos neg stx)
|
|
||||||
(error 'opt/c "opt libraries not loaded properly"))]))
|
|
||||||
|
|
||||||
(syntax-case stx ()
|
(syntax-case stx ()
|
||||||
[(_ e)
|
[(_ e)
|
||||||
(let-values ([(next lifts partials _ __) (opt/i #'pos #'neg #'e)])
|
(let*-values ([(info) (make-opt/info #'ctc
|
||||||
|
#'val
|
||||||
|
#'pos
|
||||||
|
#'neg
|
||||||
|
#'src-info
|
||||||
|
#'orig-str
|
||||||
|
null
|
||||||
|
#f
|
||||||
|
#f
|
||||||
|
#'this
|
||||||
|
#'that
|
||||||
|
(box 0))]
|
||||||
|
[(next lifts superlifts partials _ __ stronger-ribs) (opt/i info #'e)])
|
||||||
|
(with-syntax ((next next))
|
||||||
|
(bind-superlifts
|
||||||
|
superlifts
|
||||||
|
(bind-lifts
|
||||||
|
lifts
|
||||||
|
#`(make-opt-contract
|
||||||
|
(λ (ctc)
|
||||||
|
(λ (pos neg src-info orig-str)
|
||||||
|
#,(bind-lifts
|
||||||
|
partials
|
||||||
|
#`(λ (val)
|
||||||
|
next))))
|
||||||
|
(λ () e)
|
||||||
|
(λ (this that) #f)
|
||||||
|
(vector)
|
||||||
|
(begin-lifted (box #f)))))))]))
|
||||||
|
|
||||||
|
;; define/osc : syntax -> syntax
|
||||||
|
;; define/osc allows you define optimized recursive contracts, and must be used
|
||||||
|
;; to define struct contracts.
|
||||||
|
(define-syntax (define/osc stx)
|
||||||
|
|
||||||
|
;; opt/i : id opt/info syntax ->
|
||||||
|
;; syntax syntax-list syntax-list (union syntax #f) (union syntax #f)
|
||||||
|
;;
|
||||||
|
;; this is different from opt/i only in the aspect that it calls the recursive-call opter
|
||||||
|
;; if it recognizes a recursive call.
|
||||||
|
(define (opt/i opt/info stx)
|
||||||
|
(syntax-case stx ()
|
||||||
|
[(ctc arg ...)
|
||||||
|
(and (identifier? #'ctc) (or (opter #'ctc)
|
||||||
|
(module-identifier=? (opt/info-recf opt/info) #'ctc)))
|
||||||
|
(if (module-identifier=? (opt/info-recf opt/info) #'ctc)
|
||||||
|
;; this is a recursive call
|
||||||
|
(opt/recursive-call opt/info stx)
|
||||||
|
((opter #'ctc) opt/i opt/info stx))]
|
||||||
|
[argless-ctc
|
||||||
|
(and (identifier? #'argless-ctc) (opter #'argless-ctc))
|
||||||
|
((opter #'argless-ctc) opt/i opt/info stx)]
|
||||||
|
[else
|
||||||
|
(opt/unknown opt/i opt/info stx)]))
|
||||||
|
|
||||||
|
(syntax-case stx ()
|
||||||
|
[(_ (f arg ...) base-pred e)
|
||||||
|
(let*-values ([(info) (make-opt/info #'ctc
|
||||||
|
#'val
|
||||||
|
#'pos
|
||||||
|
#'neg
|
||||||
|
#'src-info
|
||||||
|
#'orig-str
|
||||||
|
(syntax->list (syntax (arg ...)))
|
||||||
|
#'f
|
||||||
|
#'base-pred
|
||||||
|
#'this
|
||||||
|
#'that
|
||||||
|
(box 0))]
|
||||||
|
[(next lifts superlifts partials _ __ stronger-ribs) (opt/i info #'e)])
|
||||||
(with-syntax ((next next)
|
(with-syntax ((next next)
|
||||||
(lifts (make-lifts lifts))
|
((superlift ...) (map (λ (x) (with-syntax ((var (car x))
|
||||||
(partials (make-lifts partials))
|
(e (cdr x)))
|
||||||
(stx stx))
|
(syntax (define var e)))) superlifts))
|
||||||
(syntax (make-opt-contract
|
((stronger-this-var ...) (map stronger-rib-this-var stronger-ribs))
|
||||||
(λ (ctc)
|
((stronger-that-var ...) (map stronger-rib-that-var stronger-ribs))
|
||||||
(let* lifts
|
((stronger-exps ...) (map stronger-rib-stronger-exp stronger-ribs))
|
||||||
(λ (pos neg src-info orig-str)
|
((stronger-indexes ...) (build-list (length stronger-ribs) values))
|
||||||
(let partials
|
((stronger-var ...) (map stronger-rib-save-id stronger-ribs)))
|
||||||
(λ (val) next)))))
|
#`(begin
|
||||||
(λ () e)))))])))
|
;; superlifts are defines
|
||||||
|
superlift ...
|
||||||
|
|
||||||
|
(define (f arg ...)
|
||||||
|
|
||||||
|
#,(bind-lifts
|
||||||
|
lifts
|
||||||
|
#`(make-opt-contract
|
||||||
|
(λ (ctc)
|
||||||
|
(λ (pos neg src-info orig-str)
|
||||||
|
#,(bind-lifts
|
||||||
|
partials
|
||||||
|
#`(λ (val) (if (base-pred val)
|
||||||
|
val
|
||||||
|
next)))))
|
||||||
|
(λ () e)
|
||||||
|
(λ (this that)
|
||||||
|
(let ([stronger-that-var (vector-ref (opt-contract-stronger-vars that) stronger-indexes)]
|
||||||
|
...
|
||||||
|
[stronger-this-var (vector-ref (opt-contract-stronger-vars this) stronger-indexes)]
|
||||||
|
...)
|
||||||
|
(and stronger-exps ...)))
|
||||||
|
(vector stronger-var ...)
|
||||||
|
(begin-lifted (box #f))))))))]))
|
||||||
|
|
||||||
|
;; optimized contracts
|
||||||
|
;;
|
||||||
|
;; getting the name of an optimized contract is slow, but it is only
|
||||||
|
;; called when blame is raised (thankfully).
|
||||||
|
;;
|
||||||
|
;; note that lifts, partials, flat, and unknown are all built into the
|
||||||
|
;; projection itself and should not be exposed to the outside anyhow.
|
||||||
|
(define-values (orig-ctc-prop orig-ctc-pred? orig-ctc-get)
|
||||||
|
(make-struct-type-property 'original-contract))
|
||||||
|
|
||||||
|
(define-struct/prop opt-contract (proj orig-ctc stronger stronger-vars stamp)
|
||||||
|
((proj-prop (λ (ctc) ((opt-contract-proj ctc) ctc)))
|
||||||
|
;; I think provide/contract and contract calls this, so we are in effect allocating
|
||||||
|
;; the original once
|
||||||
|
(name-prop (λ (ctc) (contract-name ((orig-ctc-get ctc) ctc))))
|
||||||
|
(orig-ctc-prop (λ (ctc) ((opt-contract-orig-ctc ctc))))
|
||||||
|
(stronger-prop (λ (this that)
|
||||||
|
(and (opt-contract? that)
|
||||||
|
(eq? (opt-contract-stamp this) (opt-contract-stamp that))
|
||||||
|
((opt-contract-stronger this) this that))))))
|
||||||
|
|
||||||
|
;; opt-stronger-vars-ref : int opt-contract -> any
|
||||||
|
(define (opt-stronger-vars-ref i ctc)
|
||||||
|
(let ((v (opt-contract-stronger-vars ctc)))
|
||||||
|
(vector-ref v i))))
|
||||||
|
|
|
@ -279,18 +279,13 @@ add struct contracts for immutable structs?
|
||||||
[predicate-id (list-ref struct-info 2)]
|
[predicate-id (list-ref struct-info 2)]
|
||||||
[selector-ids (reverse (list-ref struct-info 3))]
|
[selector-ids (reverse (list-ref struct-info 3))]
|
||||||
[mutator-ids (reverse (list-ref struct-info 4))]
|
[mutator-ids (reverse (list-ref struct-info 4))]
|
||||||
[parent-struct-count (let ([parent-info (extract-parent-struct-info struct-name-position)])
|
[all-parent-struct-count/names (get-field-counts/struct-names struct-name provide-stx)]
|
||||||
(and parent-info
|
[parent-struct-count (if (null? all-parent-struct-count/names)
|
||||||
(let ([fields (cadddr parent-info)])
|
#f
|
||||||
(cond
|
(let ([pp (cdr all-parent-struct-count/names)])
|
||||||
[(null? fields) 0]
|
(if (null? pp)
|
||||||
[(not (car (last-pair fields)))
|
#f
|
||||||
(raise-syntax-error
|
(car (car pp)))))]
|
||||||
'provide/contract
|
|
||||||
"cannot determine the number of fields in super struct"
|
|
||||||
provide-stx
|
|
||||||
struct-name)]
|
|
||||||
[else (length fields)]))))]
|
|
||||||
[field-contract-ids (map (λ (field-name)
|
[field-contract-ids (map (λ (field-name)
|
||||||
(a:mangle-id provide-stx
|
(a:mangle-id provide-stx
|
||||||
"provide/contract-field-contract"
|
"provide/contract-field-contract"
|
||||||
|
@ -364,6 +359,52 @@ add struct contracts for immutable structs?
|
||||||
provide-stx
|
provide-stx
|
||||||
struct-name))
|
struct-name))
|
||||||
|
|
||||||
|
;; make sure the field names are right.
|
||||||
|
(let* ([relative-counts (let loop ([c (map car all-parent-struct-count/names)])
|
||||||
|
(cond
|
||||||
|
[(null? c) null]
|
||||||
|
[(null? (cdr c)) c]
|
||||||
|
[else (cons (- (car c) (cadr c))
|
||||||
|
(loop (cdr c)))]))]
|
||||||
|
[names (map cdr all-parent-struct-count/names)]
|
||||||
|
[maker-name (format "~a" (syntax-e constructor-id))]
|
||||||
|
[struct-name (substring maker-name 5 (string-length maker-name))])
|
||||||
|
(let loop ([count (car relative-counts)]
|
||||||
|
[name (car names)]
|
||||||
|
[counts (cdr relative-counts)]
|
||||||
|
[names (cdr names)]
|
||||||
|
[selector-strs (reverse (map (λ (x) (format "~a" (syntax-e x))) selector-ids))]
|
||||||
|
[field-names (reverse field-names)])
|
||||||
|
|
||||||
|
(cond
|
||||||
|
[(or (null? counts) (null? names) (null? selector-strs) (null? field-names))
|
||||||
|
(void)]
|
||||||
|
[(zero? count)
|
||||||
|
(loop (car counts) (car names) (cdr counts) (cdr names)
|
||||||
|
selector-strs
|
||||||
|
field-names)]
|
||||||
|
[else
|
||||||
|
(let* ([selector-str (car selector-strs)]
|
||||||
|
[field-name (car field-names)]
|
||||||
|
[field-name-should-be
|
||||||
|
(substring selector-str
|
||||||
|
(+ (string-length name) 1)
|
||||||
|
(string-length selector-str))]
|
||||||
|
[field-name-is (format "~a" (syntax-e field-name))])
|
||||||
|
(unless (equal? field-name-should-be field-name-is)
|
||||||
|
(raise-syntax-error 'provide/contract
|
||||||
|
(format "expected field name to be ~a, but found ~a"
|
||||||
|
field-name-should-be
|
||||||
|
field-name-is)
|
||||||
|
provide-stx
|
||||||
|
field-name))
|
||||||
|
(loop (- count 1)
|
||||||
|
name
|
||||||
|
counts
|
||||||
|
names
|
||||||
|
(cdr selector-strs)
|
||||||
|
(cdr field-names)))])))
|
||||||
|
|
||||||
(with-syntax ([((selector-codes selector-new-names) ...)
|
(with-syntax ([((selector-codes selector-new-names) ...)
|
||||||
(filter
|
(filter
|
||||||
(λ (x) x)
|
(λ (x) x)
|
||||||
|
@ -434,19 +475,18 @@ add struct contracts for immutable structs?
|
||||||
[super-id (if (boolean? super-id)
|
[super-id (if (boolean? super-id)
|
||||||
super-id
|
super-id
|
||||||
(with-syntax ([super-id super-id])
|
(with-syntax ([super-id super-id])
|
||||||
(syntax (cert #'super-id))))])
|
(syntax ((syntax-local-certifier) #'super-id))))])
|
||||||
(syntax (begin
|
(syntax (begin
|
||||||
(provide (rename id-rename struct-name))
|
(provide (rename id-rename struct-name))
|
||||||
(define-syntax id-rename
|
(define-syntax id-rename
|
||||||
(let ([cert (syntax-local-certifier #t)])
|
(list-immutable ((syntax-local-certifier) #'-struct:struct-name)
|
||||||
(list-immutable (cert #'-struct:struct-name)
|
((syntax-local-certifier) #'constructor-new-name)
|
||||||
(cert #'constructor-new-name)
|
((syntax-local-certifier) #'predicate-new-name)
|
||||||
(cert #'predicate-new-name)
|
(list-immutable ((syntax-local-certifier) #'rev-selector-new-names) ...
|
||||||
(list-immutable (cert #'rev-selector-new-names) ...
|
((syntax-local-certifier) #'rev-selector-old-names) ...)
|
||||||
(cert #'rev-selector-old-names) ...)
|
(list-immutable ((syntax-local-certifier) #'rev-mutator-new-names) ...
|
||||||
(list-immutable (cert #'rev-mutator-new-names) ...
|
((syntax-local-certifier) #'rev-mutator-old-names) ...)
|
||||||
(cert #'rev-mutator-old-names) ...)
|
super-id)))))]
|
||||||
super-id))))))]
|
|
||||||
[struct:struct-name struct:struct-name]
|
[struct:struct-name struct:struct-name]
|
||||||
[-struct:struct-name -struct:struct-name]
|
[-struct:struct-name -struct:struct-name]
|
||||||
[struct-name struct-name]
|
[struct-name struct-name]
|
||||||
|
@ -454,7 +494,7 @@ add struct contracts for immutable structs?
|
||||||
(syntax/loc stx
|
(syntax/loc stx
|
||||||
(begin
|
(begin
|
||||||
struct-code
|
struct-code
|
||||||
(define field-contract-ids field-contracts) ...
|
(define field-contract-ids (verify-contract field-contracts)) ...
|
||||||
selector-codes ...
|
selector-codes ...
|
||||||
mutator-codes ...
|
mutator-codes ...
|
||||||
predicate-code
|
predicate-code
|
||||||
|
@ -487,6 +527,37 @@ add struct contracts for immutable structs?
|
||||||
(loop (cdr l1)
|
(loop (cdr l1)
|
||||||
(+ i 1)))])))
|
(+ i 1)))])))
|
||||||
|
|
||||||
|
;; get-field-counts/struct-names : syntax syntax -> (listof (cons symbol number))
|
||||||
|
;; returns a list of numbers corresponding to the numbers of fields for each of the parent structs
|
||||||
|
(define (get-field-counts/struct-names struct-name provide-stx)
|
||||||
|
(let loop ([parent-info-id struct-name])
|
||||||
|
(let ([parent-info
|
||||||
|
(and (identifier? parent-info-id)
|
||||||
|
(syntax-local-value parent-info-id (λ () #f)))])
|
||||||
|
(cond
|
||||||
|
[(boolean? parent-info) null]
|
||||||
|
[else
|
||||||
|
(let ([fields (list-ref parent-info 3)]
|
||||||
|
[constructor (list-ref parent-info 1)])
|
||||||
|
(cond
|
||||||
|
[(and (not (null? fields))
|
||||||
|
(not (car (last-pair fields))))
|
||||||
|
(raise-syntax-error
|
||||||
|
'provide/contract
|
||||||
|
"cannot determine the number of fields in super struct"
|
||||||
|
provide-stx
|
||||||
|
struct-name)]
|
||||||
|
[else
|
||||||
|
(cons (cons (length fields) (constructor->struct-name constructor))
|
||||||
|
(loop (list-ref parent-info 5)))]))]))))
|
||||||
|
|
||||||
|
(define (constructor->struct-name stx)
|
||||||
|
(and stx
|
||||||
|
(let ([m (regexp-match #rx"^make-(.*)$" (format "~a" (syntax-e stx)))])
|
||||||
|
(and m
|
||||||
|
(cadr m)))))
|
||||||
|
|
||||||
|
|
||||||
;; extract-parent-struct-info : syntax -> (union #f (list syntax syntax (listof syntax) ...))
|
;; extract-parent-struct-info : syntax -> (union #f (list syntax syntax (listof syntax) ...))
|
||||||
(define (extract-parent-struct-info stx)
|
(define (extract-parent-struct-info stx)
|
||||||
(syntax-case stx ()
|
(syntax-case stx ()
|
||||||
|
@ -497,7 +568,8 @@ add struct contracts for immutable structs?
|
||||||
(raise-syntax-error 'provide/contract
|
(raise-syntax-error 'provide/contract
|
||||||
"expected a struct name"
|
"expected a struct name"
|
||||||
provide-stx
|
provide-stx
|
||||||
(syntax b))))]
|
(syntax b))))
|
||||||
|
(syntax b)]
|
||||||
[a #f]))
|
[a #f]))
|
||||||
|
|
||||||
;; extract-struct-info : syntax -> (union #f (list syntax syntax (listof syntax) ...))
|
;; extract-struct-info : syntax -> (union #f (list syntax syntax (listof syntax) ...))
|
||||||
|
@ -575,7 +647,7 @@ add struct contracts for immutable structs?
|
||||||
(provide (rename id-rename external-name))
|
(provide (rename id-rename external-name))
|
||||||
|
|
||||||
(define pos-module-source (module-source-as-symbol #'pos-stx))
|
(define pos-module-source (module-source-as-symbol #'pos-stx))
|
||||||
(define contract-id ctrct)
|
(define contract-id (verify-contract ctrct))
|
||||||
|
|
||||||
(define-syntax id-rename
|
(define-syntax id-rename
|
||||||
(make-provide/contract-transformer (quote-syntax contract-id)
|
(make-provide/contract-transformer (quote-syntax contract-id)
|
||||||
|
@ -594,6 +666,13 @@ add struct contracts for immutable structs?
|
||||||
(begin
|
(begin
|
||||||
bodies ...))))]))
|
bodies ...))))]))
|
||||||
|
|
||||||
|
(define (verify-contract x)
|
||||||
|
(unless (or (contract? x)
|
||||||
|
(and (procedure? x)
|
||||||
|
(procedure-arity-includes? x 1)))
|
||||||
|
(error 'provide/contract "expected a contract or a procedure of arity one, got ~e" x))
|
||||||
|
x)
|
||||||
|
|
||||||
|
|
||||||
(define (make-pc-struct-type struct-name struct:struct-name . ctcs)
|
(define (make-pc-struct-type struct-name struct:struct-name . ctcs)
|
||||||
(let-values ([(struct:struct-name _make _pred _get _set)
|
(let-values ([(struct:struct-name _make _pred _get _set)
|
||||||
|
@ -643,7 +722,8 @@ add struct contracts for immutable structs?
|
||||||
(contract/proc a-contract to-check pos-blame-e neg-blame-e (quote-syntax src-loc))))]
|
(contract/proc a-contract to-check pos-blame-e neg-blame-e (quote-syntax src-loc))))]
|
||||||
[(_ a-contract-e to-check pos-blame-e neg-blame-e src-info-e)
|
[(_ a-contract-e to-check pos-blame-e neg-blame-e src-info-e)
|
||||||
(syntax/loc stx
|
(syntax/loc stx
|
||||||
(contract/proc a-contract-e to-check pos-blame-e neg-blame-e src-info-e))]))
|
(begin
|
||||||
|
(contract/proc a-contract-e to-check pos-blame-e neg-blame-e src-info-e)))]))
|
||||||
|
|
||||||
(define (contract/proc a-contract-raw name pos-blame neg-blame src-info)
|
(define (contract/proc a-contract-raw name pos-blame neg-blame src-info)
|
||||||
(unless (or (contract? a-contract-raw)
|
(unless (or (contract? a-contract-raw)
|
||||||
|
@ -988,66 +1068,119 @@ add struct contracts for immutable structs?
|
||||||
;;
|
;;
|
||||||
;; or/c opter
|
;; or/c opter
|
||||||
;;
|
;;
|
||||||
(define/opter (or/c opt/i pos neg stx)
|
(define/opter (or/c opt/i opt/info stx)
|
||||||
|
;; FIXME code duplication
|
||||||
|
(define (opt/or-unknown uctc)
|
||||||
|
(let* ((lift-var (car (generate-temporaries (syntax (lift)))))
|
||||||
|
(partial-var (car (generate-temporaries (syntax (partial))))))
|
||||||
|
(values
|
||||||
|
(with-syntax ((partial-var partial-var)
|
||||||
|
(lift-var lift-var)
|
||||||
|
(uctc uctc)
|
||||||
|
(val (opt/info-val opt/info)))
|
||||||
|
(syntax (partial-var val)))
|
||||||
|
(list (cons lift-var
|
||||||
|
;; FIXME needs to get the contract name somehow
|
||||||
|
(with-syntax ((uctc uctc))
|
||||||
|
(syntax (coerce-contract 'opt/c uctc)))))
|
||||||
|
null
|
||||||
|
(list (cons
|
||||||
|
partial-var
|
||||||
|
(with-syntax ((lift-var lift-var)
|
||||||
|
(pos (opt/info-pos opt/info))
|
||||||
|
(neg (opt/info-neg opt/info))
|
||||||
|
(src-info (opt/info-src-info opt/info))
|
||||||
|
(orig-str (opt/info-orig-str opt/info)))
|
||||||
|
(syntax (((proj-get lift-var) lift-var) pos neg src-info orig-str)))))
|
||||||
|
#f
|
||||||
|
lift-var
|
||||||
|
(list #f)
|
||||||
|
null)))
|
||||||
|
|
||||||
(define (opt/or-ctc ps)
|
(define (opt/or-ctc ps)
|
||||||
(let ((lift-from-hos null)
|
(let ((lift-from-hos null)
|
||||||
|
(superlift-from-hos null)
|
||||||
(partial-from-hos null))
|
(partial-from-hos null))
|
||||||
(let-values ([(opt-ps lift-ps partial-ps hos ho-ctc)
|
(let-values ([(opt-ps lift-ps superlift-ps partial-ps stronger-ribs hos ho-ctc)
|
||||||
(let loop ([ps ps]
|
(let loop ([ps ps]
|
||||||
[next-ps null]
|
[next-ps null]
|
||||||
[lift-ps null]
|
[lift-ps null]
|
||||||
|
[superlift-ps null]
|
||||||
[partial-ps null]
|
[partial-ps null]
|
||||||
|
[stronger-ribs null]
|
||||||
[hos null]
|
[hos null]
|
||||||
[ho-ctc #f])
|
[ho-ctc #f])
|
||||||
(cond
|
(cond
|
||||||
[(null? ps) (values next-ps lift-ps partial-ps (reverse hos) ho-ctc)]
|
[(null? ps) (values next-ps
|
||||||
|
lift-ps
|
||||||
|
superlift-ps
|
||||||
|
partial-ps
|
||||||
|
stronger-ribs
|
||||||
|
(reverse hos)
|
||||||
|
ho-ctc)]
|
||||||
[else
|
[else
|
||||||
(let-values ([(next lift partial flat _)
|
(let-values ([(next lift superlift partial flat _ this-stronger-ribs)
|
||||||
(opt/i pos neg (car ps))])
|
(opt/i opt/info (car ps))])
|
||||||
(if flat
|
(if flat
|
||||||
(loop (cdr ps)
|
(loop (cdr ps)
|
||||||
(cons flat next-ps)
|
(cons flat next-ps)
|
||||||
(append lift-ps lift)
|
(append lift-ps lift)
|
||||||
|
(append superlift-ps superlift)
|
||||||
(append partial-ps partial)
|
(append partial-ps partial)
|
||||||
|
(append this-stronger-ribs stronger-ribs)
|
||||||
hos
|
hos
|
||||||
ho-ctc)
|
ho-ctc)
|
||||||
(if (< (length hos) 1)
|
(if (< (length hos) 1)
|
||||||
(loop (cdr ps)
|
(loop (cdr ps)
|
||||||
next-ps
|
next-ps
|
||||||
(append lift-ps lift)
|
(append lift-ps lift)
|
||||||
|
(append superlift-ps superlift)
|
||||||
(append partial-ps partial)
|
(append partial-ps partial)
|
||||||
|
(append this-stronger-ribs stronger-ribs)
|
||||||
(cons (car ps) hos)
|
(cons (car ps) hos)
|
||||||
next)
|
next)
|
||||||
(loop (cdr ps)
|
(loop (cdr ps)
|
||||||
next-ps
|
next-ps
|
||||||
lift-ps
|
lift-ps
|
||||||
|
superlift-ps
|
||||||
partial-ps
|
partial-ps
|
||||||
|
stronger-ribs
|
||||||
(cons (car ps) hos)
|
(cons (car ps) hos)
|
||||||
ho-ctc))))]))])
|
ho-ctc))))]))])
|
||||||
(with-syntax ((next-ps (with-syntax (((opt-p ...) opt-ps))
|
(with-syntax ((next-ps
|
||||||
(syntax (or #f opt-p ...)))))
|
(with-syntax (((opt-p ...) (reverse opt-ps)))
|
||||||
|
(syntax (or opt-p ...)))))
|
||||||
(values
|
(values
|
||||||
(cond
|
(cond
|
||||||
[(null? hos) (with-syntax ((pos pos))
|
[(null? hos)
|
||||||
(syntax
|
(with-syntax ([val (opt/info-val opt/info)]
|
||||||
(if next-ps val
|
[pos (opt/info-pos opt/info)]
|
||||||
(raise-contract-error val src-info pos orig-str
|
[src-info (opt/info-src-info opt/info)]
|
||||||
"none of the branches of the or/c matched"))))]
|
[orig-str (opt/info-orig-str opt/info)])
|
||||||
|
(syntax
|
||||||
|
(if next-ps
|
||||||
|
val
|
||||||
|
(raise-contract-error val src-info pos orig-str
|
||||||
|
"none of the branches of the or/c matched"))))]
|
||||||
[(= (length hos) 1) (with-syntax ((ho-ctc ho-ctc))
|
[(= (length hos) 1) (with-syntax ((ho-ctc ho-ctc))
|
||||||
(syntax
|
(syntax
|
||||||
(if next-ps val ho-ctc)))]
|
(if next-ps val ho-ctc)))]
|
||||||
[(> (length hos) 1)
|
;; FIXME something's not right with this case.
|
||||||
(let-values ([(next-hos lift-hos partial-hos _ __)
|
[(> (length hos) 1)
|
||||||
((opter 'unknown) opt/i pos neg (cons #'or/c hos))])
|
(let-values ([(next-hos lift-hos superlift-hos partial-hos _ __ stronger-hos stronger-vars-hos)
|
||||||
|
(opt/or-unknown stx)])
|
||||||
(set! lift-from-hos lift-hos)
|
(set! lift-from-hos lift-hos)
|
||||||
|
(set! superlift-from-hos superlift-hos)
|
||||||
(set! partial-from-hos partial-hos)
|
(set! partial-from-hos partial-hos)
|
||||||
(with-syntax ((next-hos next-hos))
|
(with-syntax ((next-hos next-hos))
|
||||||
(syntax
|
(syntax
|
||||||
(if next-ps val next-hos))))])
|
(if next-ps val next-hos))))])
|
||||||
(append lift-ps lift-from-hos)
|
(append lift-ps lift-from-hos)
|
||||||
|
(append superlift-ps superlift-from-hos)
|
||||||
(append partial-ps partial-from-hos)
|
(append partial-ps partial-from-hos)
|
||||||
(if (null? hos) (syntax next-ps) #f)
|
(if (null? hos) (syntax next-ps) #f)
|
||||||
#f)))))
|
#f
|
||||||
|
stronger-ribs)))))
|
||||||
|
|
||||||
(syntax-case stx (or/c)
|
(syntax-case stx (or/c)
|
||||||
[(or/c p ...)
|
[(or/c p ...)
|
||||||
|
@ -1179,58 +1312,136 @@ add struct contracts for immutable structs?
|
||||||
;;
|
;;
|
||||||
;; between/c opter helper
|
;; between/c opter helper
|
||||||
;;
|
;;
|
||||||
(define-for-syntax (opt/between-ctc pos stx low high op checker)
|
|
||||||
(let* ((lift-vars (generate-temporaries (syntax (low high error-check))))
|
|
||||||
(lift-low (car lift-vars))
|
|
||||||
(lift-high (cadr lift-vars)))
|
|
||||||
(with-syntax ((pos pos)
|
|
||||||
(op op)
|
|
||||||
(n lift-low)
|
|
||||||
(m lift-high))
|
|
||||||
(values
|
|
||||||
(syntax (if (and (number? val) (op n val m)) val
|
|
||||||
(raise-contract-error
|
|
||||||
val
|
|
||||||
src-info
|
|
||||||
pos
|
|
||||||
orig-str
|
|
||||||
"expected <~a>, given: ~e"
|
|
||||||
((name-get ctc) ctc)
|
|
||||||
val)))
|
|
||||||
(interleave-lifts
|
|
||||||
lift-vars
|
|
||||||
(list low
|
|
||||||
high
|
|
||||||
(cond
|
|
||||||
[(eq? checker 'between/c) #'(check-between/c n m)]
|
|
||||||
[(eq? checker '>/c) #'(check-unary-between/c '>/c n)]
|
|
||||||
[(eq? checker '>=/c) #'(check-unary-between/c '>=/c n)]
|
|
||||||
[(eq? checker '</c) #'(check-unary-between/c '</c m)]
|
|
||||||
[(eq? checker '<=/c) #'(check-unary-between/c '<=/c m)])))
|
|
||||||
null
|
|
||||||
(syntax (and (number? val) (op n val m)))
|
|
||||||
#f))))
|
|
||||||
|
|
||||||
;;
|
;;
|
||||||
;; between/c and friends' opters
|
;; between/c opters
|
||||||
;;
|
;;
|
||||||
;; note that the checkers are used by both optimized and normal contracts.
|
;; note that the checkers are used by both optimized and normal contracts.
|
||||||
;;
|
;;
|
||||||
(define/opter (between/c opt/i pos neg stx)
|
(define/opter (between/c opt/i opt/info stx)
|
||||||
(syntax-case stx (between/c)
|
(syntax-case stx (between/c)
|
||||||
[(between/c low high) (opt/between-ctc pos stx #'low #'high #'<= 'between/c)]))
|
[(between/c low high)
|
||||||
(define/opter (>/c opt/i pos neg stx)
|
(let*-values ([(lift-low lifts1) (lift/binding #'low 'between-low empty-lifts)]
|
||||||
(syntax-case stx (>/c)
|
[(lift-high lifts2) (lift/binding #'high 'between-high lifts1)])
|
||||||
[(>/c low) (opt/between-ctc pos stx #'low #'+inf.0 #'< '>/c)]))
|
(with-syntax ([n lift-low]
|
||||||
(define/opter (>=/c opt/i pos neg stx)
|
[m lift-high])
|
||||||
|
(let ([lifts3 (lift/effect #'(check-between/c n m) lifts2)])
|
||||||
|
(with-syntax ((val (opt/info-val opt/info))
|
||||||
|
(ctc (opt/info-contract opt/info))
|
||||||
|
(pos (opt/info-pos opt/info))
|
||||||
|
(src-info (opt/info-src-info opt/info))
|
||||||
|
(orig-str (opt/info-orig-str opt/info))
|
||||||
|
(this (opt/info-this opt/info))
|
||||||
|
(that (opt/info-that opt/info)))
|
||||||
|
(values
|
||||||
|
(syntax (if (and (number? val) (<= n val m))
|
||||||
|
val
|
||||||
|
(raise-contract-error
|
||||||
|
val
|
||||||
|
src-info
|
||||||
|
pos
|
||||||
|
orig-str
|
||||||
|
"expected <~a>, given: ~e"
|
||||||
|
((name-get ctc) ctc)
|
||||||
|
val)))
|
||||||
|
lifts3
|
||||||
|
null
|
||||||
|
null
|
||||||
|
(syntax (and (number? val) (<= n val m)))
|
||||||
|
#f
|
||||||
|
(list (new-stronger-var
|
||||||
|
lift-low
|
||||||
|
(λ (this that)
|
||||||
|
(with-syntax ([this this]
|
||||||
|
[that that])
|
||||||
|
(syntax (<= that this)))))
|
||||||
|
(new-stronger-var
|
||||||
|
lift-high
|
||||||
|
(λ (this that)
|
||||||
|
(with-syntax ([this this]
|
||||||
|
[that that])
|
||||||
|
(syntax (<= this that)))))))))))]))
|
||||||
|
|
||||||
|
(define-for-syntax (single-comparison-opter opt/info stx check-arg comparison arg)
|
||||||
|
(with-syntax ([comparison comparison])
|
||||||
|
(let*-values ([(lift-low lifts2) (lift/binding arg 'single-comparison-val empty-lifts)])
|
||||||
|
(with-syntax ([m lift-low])
|
||||||
|
(let ([lifts3 (lift/effect (check-arg #'m) lifts2)])
|
||||||
|
(with-syntax ((val (opt/info-val opt/info))
|
||||||
|
(ctc (opt/info-contract opt/info))
|
||||||
|
(pos (opt/info-pos opt/info))
|
||||||
|
(src-info (opt/info-src-info opt/info))
|
||||||
|
(orig-str (opt/info-orig-str opt/info))
|
||||||
|
(this (opt/info-this opt/info))
|
||||||
|
(that (opt/info-that opt/info)))
|
||||||
|
(values
|
||||||
|
(syntax (if (and (number? val) (comparison val m))
|
||||||
|
val
|
||||||
|
(raise-contract-error
|
||||||
|
val
|
||||||
|
src-info
|
||||||
|
pos
|
||||||
|
orig-str
|
||||||
|
"expected <~a>, given: ~e"
|
||||||
|
((name-get ctc) ctc)
|
||||||
|
val)))
|
||||||
|
lifts3
|
||||||
|
null
|
||||||
|
null
|
||||||
|
(syntax (and (number? val) (comparison val m)))
|
||||||
|
#f
|
||||||
|
(list (new-stronger-var
|
||||||
|
lift-low
|
||||||
|
(λ (this that)
|
||||||
|
(with-syntax ([this this]
|
||||||
|
[that that])
|
||||||
|
(syntax (comparison this that)))))))))))))
|
||||||
|
|
||||||
|
(define/opter (>=/c opt/i opt/info stx)
|
||||||
(syntax-case stx (>=/c)
|
(syntax-case stx (>=/c)
|
||||||
[(>=/c low) (opt/between-ctc pos stx #'low #'+inf.0 #'<= '>=/c)]))
|
[(>=/c low)
|
||||||
(define/opter (</c opt/i pos neg stx)
|
(single-comparison-opter
|
||||||
(syntax-case stx (</c)
|
opt/info
|
||||||
[(</c high) (opt/between-ctc pos stx #'-inf.0 #'high #'< '</c)]))
|
stx
|
||||||
(define/opter (<=/c opt/i pos neg stx)
|
(λ (m) (with-syntax ([m m])
|
||||||
|
#'(check-unary-between/c '>=/c m)))
|
||||||
|
#'>=
|
||||||
|
#'low)]))
|
||||||
|
|
||||||
|
(define/opter (<=/c opt/i opt/info stx)
|
||||||
(syntax-case stx (<=/c)
|
(syntax-case stx (<=/c)
|
||||||
[(<=/c high) (opt/between-ctc pos stx #'-inf.0 #'high #'<= '<=/c)]))
|
[(<=/c high)
|
||||||
|
(single-comparison-opter
|
||||||
|
opt/info
|
||||||
|
stx
|
||||||
|
(λ (m) (with-syntax ([m m])
|
||||||
|
#'(check-unary-between/c '<=/c m)))
|
||||||
|
#'<=
|
||||||
|
#'high)]))
|
||||||
|
|
||||||
|
(define/opter (>/c opt/i opt/info stx)
|
||||||
|
(syntax-case stx (>/c)
|
||||||
|
[(>/c low)
|
||||||
|
(single-comparison-opter
|
||||||
|
opt/info
|
||||||
|
stx
|
||||||
|
(λ (m) (with-syntax ([m m])
|
||||||
|
#'(check-unary-between/c '>/c m)))
|
||||||
|
#'>
|
||||||
|
#'low)]))
|
||||||
|
|
||||||
|
(define/opter (</c opt/i opt/info stx)
|
||||||
|
(syntax-case stx (</c)
|
||||||
|
[(</c high)
|
||||||
|
(single-comparison-opter
|
||||||
|
opt/info
|
||||||
|
stx
|
||||||
|
(λ (m) (with-syntax ([m m])
|
||||||
|
#'(check-unary-between/c '</c m)))
|
||||||
|
#'<
|
||||||
|
#'high)]))
|
||||||
|
|
||||||
(define (</c x)
|
(define (</c x)
|
||||||
(flat-named-contract
|
(flat-named-contract
|
||||||
|
@ -1404,21 +1615,26 @@ add struct contracts for immutable structs?
|
||||||
;;
|
;;
|
||||||
;; cons/c opter
|
;; cons/c opter
|
||||||
;;
|
;;
|
||||||
(define/opter (cons/c opt/i pos neg stx)
|
(define/opter (cons/c opt/i opt/info stx)
|
||||||
(define (opt/cons-ctc hdp tlp)
|
(define (opt/cons-ctc hdp tlp)
|
||||||
(let-values ([(next-hdp lifts-hdp partials-hdp flat-hdp unknown-hdp)
|
(let-values ([(next-hdp lifts-hdp superlifts-hdp partials-hdp flat-hdp unknown-hdp stronger-ribs-hd)
|
||||||
(opt/i pos neg hdp)]
|
(opt/i opt/info hdp)]
|
||||||
[(next-tlp lifts-tlp partials-tlp flat-tlp unknown-tlp)
|
[(next-tlp lifts-tlp superlifts-tlp partials-tlp flat-tlp unknown-tlp stronger-ribs-tl)
|
||||||
(opt/i pos neg tlp)]
|
(opt/i opt/info tlp)]
|
||||||
[(error-check) (car (generate-temporaries (syntax (error-check))))])
|
[(error-check) (car (generate-temporaries (syntax (error-check))))])
|
||||||
(with-syntax ((next (with-syntax ((flat-hdp flat-hdp)
|
(with-syntax ((next (with-syntax ((flat-hdp flat-hdp)
|
||||||
(flat-tlp flat-tlp))
|
(flat-tlp flat-tlp)
|
||||||
|
(val (opt/info-val opt/info)))
|
||||||
(syntax
|
(syntax
|
||||||
(and (pair? val)
|
(and (pair? val)
|
||||||
(let ((val (car val))) flat-hdp)
|
(let ((val (car val))) flat-hdp)
|
||||||
(let ((val (cdr val))) flat-tlp))))))
|
(let ((val (cdr val))) flat-tlp))))))
|
||||||
(values
|
(values
|
||||||
(with-syntax ((pos pos))
|
(with-syntax ((val (opt/info-val opt/info))
|
||||||
|
(ctc (opt/info-contract opt/info))
|
||||||
|
(pos (opt/info-pos opt/info))
|
||||||
|
(src-info (opt/info-src-info opt/info))
|
||||||
|
(orig-str (opt/info-orig-str opt/info)))
|
||||||
(syntax (if next
|
(syntax (if next
|
||||||
val
|
val
|
||||||
(raise-contract-error
|
(raise-contract-error
|
||||||
|
@ -1451,9 +1667,11 @@ add struct contracts for immutable structs?
|
||||||
(unless check
|
(unless check
|
||||||
(error 'cons/c "expected two flat contracts or procedures of arity 1, got: ~e and ~e"
|
(error 'cons/c "expected two flat contracts or procedures of arity 1, got: ~e and ~e"
|
||||||
hdp tlp)))))))
|
hdp tlp)))))))
|
||||||
|
(append superlifts-hdp superlifts-tlp)
|
||||||
(append partials-hdp partials-tlp)
|
(append partials-hdp partials-tlp)
|
||||||
(syntax (if next #t #f))
|
(syntax (if next #t #f))
|
||||||
#f))))
|
#f
|
||||||
|
(append stronger-ribs-hd stronger-ribs-tl)))))
|
||||||
|
|
||||||
(syntax-case stx (cons/c)
|
(syntax-case stx (cons/c)
|
||||||
[(cons/c hdp tlp)
|
[(cons/c hdp tlp)
|
||||||
|
@ -1540,15 +1758,20 @@ add struct contracts for immutable structs?
|
||||||
;;
|
;;
|
||||||
;; cons-immutable/c opter
|
;; cons-immutable/c opter
|
||||||
;;
|
;;
|
||||||
(define/opter (cons-immutable/c opt/i pos neg stx)
|
(define/opter (cons-immutable/c opt/i opt/info stx)
|
||||||
(define (opt/cons-immutable-ctc hdp tlp)
|
(define (opt/cons-immutable-ctc hdp tlp)
|
||||||
(let-values ([(next-hdp lifts-hdp partials-hdp flat-hdp unknown-hdp)
|
(let-values ([(next-hdp lifts-hdp superlifts-hdp partials-hdp flat-hdp unknown-hdp stronger-ribs-hd)
|
||||||
(opt/i pos neg hdp)]
|
(opt/i opt/info hdp)]
|
||||||
[(next-tlp lifts-tlp partials-tlp flat-tlp unknown-tlp)
|
[(next-tlp lifts-tlp superlifts-tlp partials-tlp flat-tlp unknown-tlp stronger-ribs-tl)
|
||||||
(opt/i pos neg tlp)])
|
(opt/i opt/info tlp)])
|
||||||
(with-syntax ((check (syntax (and (immutable? val) (pair? val)))))
|
(with-syntax ((check (with-syntax ((val (opt/info-val opt/info)))
|
||||||
|
(syntax (and (immutable? val) (pair? val))))))
|
||||||
(values
|
(values
|
||||||
(with-syntax ((pos pos)
|
(with-syntax ((val (opt/info-val opt/info))
|
||||||
|
(ctc (opt/info-contract opt/info))
|
||||||
|
(pos (opt/info-pos opt/info))
|
||||||
|
(src-info (opt/info-src-info opt/info))
|
||||||
|
(orig-str (opt/info-orig-str opt/info))
|
||||||
(next-hdp next-hdp)
|
(next-hdp next-hdp)
|
||||||
(next-tlp next-tlp))
|
(next-tlp next-tlp))
|
||||||
(syntax (if check
|
(syntax (if check
|
||||||
|
@ -1563,15 +1786,18 @@ add struct contracts for immutable structs?
|
||||||
((name-get ctc) ctc)
|
((name-get ctc) ctc)
|
||||||
val))))
|
val))))
|
||||||
(append lifts-hdp lifts-tlp)
|
(append lifts-hdp lifts-tlp)
|
||||||
|
(append superlifts-hdp superlifts-tlp)
|
||||||
(append partials-hdp partials-tlp)
|
(append partials-hdp partials-tlp)
|
||||||
(if (and flat-hdp flat-tlp)
|
(if (and flat-hdp flat-tlp)
|
||||||
(with-syntax ((flat-hdp flat-hdp)
|
(with-syntax ((val (opt/info-val opt/info))
|
||||||
|
(flat-hdp flat-hdp)
|
||||||
(flat-tlp flat-tlp))
|
(flat-tlp flat-tlp))
|
||||||
(syntax (if (and check
|
(syntax (if (and check
|
||||||
(let ((val (car val))) flat-hdp)
|
(let ((val (car val))) flat-hdp)
|
||||||
(let ((val (cdr val))) flat-tlp)) #t #f)))
|
(let ((val (cdr val))) flat-tlp)) #t #f)))
|
||||||
#f)
|
#f)
|
||||||
#f))))
|
#f
|
||||||
|
(append stronger-ribs-hd stronger-ribs-tl)))))
|
||||||
|
|
||||||
(syntax-case stx (cons-immutable/c)
|
(syntax-case stx (cons-immutable/c)
|
||||||
[(cons-immutable/c hdp tlp) (opt/cons-immutable-ctc #'hdp #'tlp)]))
|
[(cons-immutable/c hdp tlp) (opt/cons-immutable-ctc #'hdp #'tlp)]))
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user