(module prims mzscheme
(provide (all-defined)
define-type cases)
(require-for-syntax
"types.ss"
(lib "match.ss")
"parse-type.ss"
(lib "struct.ss" "syntax")
(lib "stx.ss" "syntax")
"utils.ss"
"type-name-env.ss")
(require "require-contract.ss"
"internal-forms.ss"
"planet-requires.ss"
(lib "etc.ss")
(lib "contract.ss")
"../CSU660/datatype.ss")
(require-for-syntax-libs)
(define-for-syntax (ignore stx) (syntax-property stx 'typechecker:ignore #t))
(define-syntax (require/typed stx)
(define (type->contract ty)
(match ty
[($ univ) #'any/c]
[($ mu var ($ union (= set:elements (($ value '()) ($ pair-ty elem-ty ($ tvar var))))))
#`(listof-unsafe #,(type->contract elem-ty))]
[($ base-type sym) (case sym
[(Number) #'number?]
[(Boolean) #'boolean?]
[(Keyword) #'keyword?]
[(Port) #'port?]
[(Path) #'path?]
[(String) #'string?]
[(Symbol) #'symbol?]
[(Bytes) #'bytes?]
[(Void) #'void?]
[(Syntax) #'syntax?]
[(Output-Port) #'output-port?]
[(Input-Port) #'input-port?]
[else (error "Base type cannot be converted to contract" sym)])]
[($ union elems)
(with-syntax
([cnts (map type->contract (set:elements elems))])
#'(or/c . cnts))]
[($ funty arrs)
(let ()
(define (f a)
(define-values (dom* rng*)
(match a
[($ arr dom ($ values-ty rngs) #f _ _)
(values (map type->contract dom) #`(values #,(map type->contract rngs)))]
[($ arr dom rng #f _ _)
(values (map type->contract dom) (type->contract rng))]))
(with-syntax
([(dom* ...) dom*]
[rng* rng*])
#'(dom* ... . -> . rng*)))
#`(case-> #,@(map f arrs)))]
[($ vec t)
#`(vectorof #,(type->contract t))]
[($ pair-ty t1 t2)
#`(cons/c #,(type->contract t1) #,(type->contract t2))]
[($ opaque-ty p? cert)
#`(flat-contract #,(cert p?))]
[($ value #f) #'false/c]
[($ value '()) #'null?]
[($ value v) #`(flat-named-contract #,(format "~a" v) (lambda (x) (equal? x v)))]
[else (error "Type cannot be converted to contract" ty)]))
(syntax-case stx ()
[(_ nm ty lib)
(identifier? #'nm)
(with-syntax ([cnt (type->contract (parse-type/id #'nm #'ty))])
(quasisyntax/loc stx (begin (#%expression (quote-syntax (require/typed-internal nm ty)))
#,(syntax-property #'(require/contract nm cnt lib)
'typechecker:ignore #t))))]
[(_ lib [nm ty] ...)
#'(begin (require/typed nm ty lib) ...)]))
(define-syntax (require/opaque-type stx)
(syntax-case stx ()
[(_ ty pred lib)
(and (identifier? #'ty) (identifier? #'pred))
(with-syntax ([pred-cnt #'(any/c . -> . boolean?)])
(begin
(register-type-name #'ty (make-opaque-ty #'pred (syntax-local-certifier)))
(quasisyntax/loc stx
(begin (#%expression (quote-syntax (require/typed-internal pred (Any -> Boolean : (Opaque pred)))))
(define-type-alias ty (Opaque pred))
#,(syntax-property #'(require/contract pred pred-cnt lib)
'typechecker:ignore #t)))))]))
(define-for-syntax (types-of-formals stx)
(syntax-case stx (:)
[([var : ty] ...) (quasisyntax/loc stx (ty ...))]
[([var : ty] ... . [rest : rest-ty]) (syntax/loc stx (ty ... rest-ty ..))])
)
(define-syntax (plambda: stx)
(syntax-case stx ()
[(plambda: (tvars ...) formals . body)
(syntax-property #'(lambda: formals . body)
'typechecker:plambda
#'(tvars ...))]))
(define-syntax (pcase-lambda: stx)
(syntax-case stx ()
[(pcase-lambda: (tvars ...) cl ...)
(syntax-property #'(case-lambda: cl ...)
'typechecker:plambda
#'(tvars ...))]))
(define-syntax (pdefine: stx)
(syntax-case stx (:)
[(pdefine: tvars (nm . formals) : ret-ty . body)
(with-syntax* ([(tys ...) (types-of-formals #'formals)]
[type (syntax/loc #'ret-ty (All tvars (tys ... -> ret-ty)))])
(syntax/loc stx
(define: nm : type
(plambda: tvars formals . body))))]))
(define-for-syntax (relocate stx loc)
(with-syntax ([x stx])
(syntax/loc loc x)))
(define-syntax (ann stx)
(syntax-case stx (:)
[(_ arg : ty)
#'(let: ([id : ty arg]) id)
(syntax-property #'arg 'type-ascription #'ty)]))
(define-syntax (-define-values stx)
(syntax-case stx ()
[(_ (vars ...) body)
(eq? (syntax-local-context) 'module)
(with-syntax* ([(fresh-vars ...) (generate-temporaries #'(vars ...))]
[(props ...) (map (lambda (v) (syntax-property v 'type-label))
(syntax->list #'(vars ...)))]
[(fresh ...) (map (lambda (id orig-id)
(let ([prop-stx (syntax-property #'dummy 'defined-type-label
(syntax-property orig-id 'type-label))])
(datum->syntax-object id (syntax-e id) orig-id prop-stx)))
(syntax->list #'(fresh-vars ...))
(syntax->list #'(vars ...)))])
(with-syntax ([def-fresh (syntax/loc stx (define-values (fresh ...) body))])
#'(begin
def-fresh
(define-syntax vars
(make-set!-transformer
(lambda (s)
(define (fresh-id n)
(syntax-property
(relocate #'fresh n)
(datum->syntax-object #'fresh (syntax-e #'fresh) n #f)
'defined-type-label
(datum->syntax-object n (syntax-object->datum #'props) #'props)))
(syntax-case s (set!)
[(set! nm v) (quasisyntax/loc s (set! #,(fresh-id #'nm) v))]
[(nm . args) (quasisyntax/loc s (#,(fresh-id #'nm) . args))]
[n (identifier? #'n) (fresh-id #'n)])))) ...)))]
[(_ . rest)
(syntax/loc stx (define-values . rest))]))
(define-syntax (define: stx)
(syntax-case stx (:)
[(define: (nm . formals) : ret-ty body ...)
(with-syntax* ([(tys ...) (types-of-formals #'formals)]
[arrty (syntax/loc stx (tys ... -> ret-ty))])
(syntax/loc stx
(define: nm : arrty
(lambda: formals body ...))))]
[(define: nm : ty body)
(identifier? #'nm)
(with-syntax ([new-nm (syntax-property #'nm 'type-label #'ty)])
(syntax/loc stx (define new-nm body)))]
[(define: (vars ...) (f args ...) : ret body ...)
#'(pdefine: (vars ...) (f args ...) : ret body ...)]))
(define-syntax (-define stx)
(syntax-case stx ()
[(_ (f . args) . b)
(eq? (syntax-local-context) 'module)
(syntax/loc stx (-define f (lambda args . b)))]
[(_ v b)
(eq? (syntax-local-context) 'module)
(syntax/loc stx (-define-values (v) b))]
[(_ . rest)
(syntax/loc stx (define . rest))]))
(define-for-syntax (annotate-names stx)
(define (label-one var ty)
(syntax-property var 'type-label ty))
(define (label vars tys)
(map label-one
(syntax->list vars)
(syntax->list tys)))
(syntax-case stx (:)
[[var : ty] (label-one #'var #'ty)]
[([var : ty] ...)
(label #'(var ...) #'(ty ...))]
[([var : ty] ... . [rest : rest-ty])
(append (label #'(var ...) #'(ty ...)) (label-one #'rest #'rest-ty))]))
(define-syntax (lambda: stx)
(syntax-case stx (:)
[(lambda: formals . body)
(with-syntax ([labeled-formals (annotate-names #'formals)])
(syntax/loc stx (lambda labeled-formals . body)))]))
(define-syntax (case-lambda: stx)
(syntax-case stx (:)
[(case-lambda: [formals . body] ...)
(with-syntax ([(lab-formals ...) (map annotate-names (syntax->list #'(formals ...)))])
(syntax/loc stx (case-lambda [lab-formals . body] ...)))]))
(define-syntaxes (let-internal: let*: letrec:)
(let ([mk (lambda (form)
(lambda (stx)
(syntax-case stx (:)
[(_ ([nm : ty . exprs] ...) . body)
(with-syntax* ([(vars ...) (annotate-names #'([nm : ty] ...))]
[bindings (map (lambda (v e loc)
(quasisyntax/loc loc [#,v . #,e]))
(syntax->list #'(vars ...))
(syntax->list #'(exprs ...))
(syntax->list (syntax-case stx () [(_ bs . body) #'bs])))])
(quasisyntax/loc stx (#,form bindings . body)))])))])
(values (mk #'let) (mk #'let*) (mk #'letrec))))
(define-syntax (let: stx)
(syntax-case stx (:)
[(let: nm : ret-ty ([arg : ty val] ...) . body)
(identifier? #'nm)
(syntax/loc stx ((letrec: ([nm : (ty ... -> ret-ty) (lambda: ([arg : ty] ...) . body)]) nm) val ...))]
[(let: . rest)
(syntax/loc stx (let-internal: . rest))]))
(define-syntax (define-type-alias stx)
(syntax-case stx ()
[(_ tname . rest)
(identifier? #'tname)
#`(begin
#,(ignore #'(define-syntax tname (lambda (stx) (raise-syntax-error 'type-check "type name used out of context" stx))))
(#%expression (quote-syntax (define-type-alias-internal tname . rest))))]
[(_ (tname . args) . rest)
#`(begin
#,(ignore #'(define-syntax tname (lambda (stx) (raise-syntax-error 'type-check "type name used out of context" stx))))
(#%expression (quote-syntax (define-type-alias-internal (tname . args) . rest))))]))
(define-syntax (define-typed-struct stx)
(syntax-case stx (:)
[(_ nm ([fld : ty] ...) . opts)
(with-syntax ([d-s (syntax-property (syntax/loc stx (define-struct nm (fld ...) . opts))
'typechecker:ignore #t)]
[dtsi (syntax/loc stx (#%expression (quote-syntax (define-typed-struct-internal nm ([fld : ty] ...)))))])
#'(begin d-s dtsi))]
[(_ (vars ...) nm ([fld : ty] ...) . opts)
(with-syntax ([d-s (syntax-property (syntax/loc stx (define-struct nm (fld ...) . opts))
'typechecker:ignore #t)]
[dtsi (syntax/loc stx (#%expression (quote-syntax (define-typed-struct-internal (vars ...) nm ([fld : ty] ...)))))])
#'(begin d-s dtsi))]))
(define-syntax (require-typed-struct stx)
(syntax-case stx (:)
[(_ nm ([fld : ty] ...) lib)
(with-syntax* ([(struct-info maker pred sel ...) (build-struct-names #'nm (syntax->list #'(fld ...)) #f #t)]
[oty #'(Opaque pred)])
#'(begin
(require/opaque-type nm pred lib)
(require/typed maker (ty ... -> oty) lib)
(require/typed sel (oty -> ty) lib) ...))]))
(define-syntax (--define-type stx)
(syntax-case stx (:)
[(define-datatype nm [variant (fld ty) ...] ...)
(with-syntax* ( [(variant* ...) (generate-temporaries #'(variant ...))]
[((struct-info maker pred sel ...) ...) (map (lambda (name flds) (build-struct-names name flds #f #t name))
(syntax->list #'(variant ...))
(map syntax->list (syntax->list #'((fld ...) ...))))]
[((struct-info* maker* pred* sel* ...) ...) (map (lambda (name flds) (build-struct-names name flds #f #t name))
(syntax->list #'(variant* ...))
(map syntax->list (syntax->list #'((fld ...) ...))))]
[d-s (syntax/loc stx
(begin (define-struct nm ())
(define-struct (variant* nm) (fld ...)) ...
(define variant maker*) ...
(define pred pred*) ...
(begin (define sel sel*) ...) ...))]
[ddi (quasisyntax/loc stx (#%expression (quote-syntax (define-type-internal nm [variant variant* (fld ty) ...] ...))))])
#`(begin
#,(ignore #'d-s)
ddi))]))
(define-syntax (-define-type stx)
(define (ignore stx) (syntax-property stx 'typechecker:ignore #t))
(syntax-case stx (:)
[(define-datatype nm [variant (fld ty) ...] ...)
(with-syntax* ( [(_ _m top-pred . other) (build-struct-names #'nm null #f #f #'nm)]
[((struct-info maker pred sel ...) ...) (map (lambda (name flds) (build-struct-names name flds #f #t name))
(syntax->list #'(variant ...))
(map syntax->list (syntax->list #'((fld ...) ...))))]
[(maker* ...) #'(maker ...)]
[d-s (syntax/loc stx
(begin
(define-syntax nm (lambda (stx) (raise-syntax-error 'type-check "type name used out of context" stx)))
(define-struct variant (fld ...)) ...
(define (top-pred arg) (or (pred arg) ...))))]
[ddi (quasisyntax/loc stx (#%expression (quote-syntax (define-type-internal nm top-pred [variant maker* (fld ty) ...] ...))))])
#`(begin
#,(ignore #'d-s)
ddi))]))
(define-syntax (do: stx)
(syntax-case stx (:)
[(_ : ty ((var : tys init . step) ...) (e0 e1 ...) c ...)
(with-syntax ([(step ...)
(map (lambda (v s)
(syntax-case s ()
[() v]
[(e) #'e]
[_ (raise-syntax-error
#f
"bad variable syntax"
stx)]))
(syntax->list #'(var ...))
(syntax->list #'(step ...)))])
(syntax-case #'(e1 ...) ()
[() (syntax/loc
stx
(let: doloop : ty ([var : tys init] ...)
(if (not e0)
(begin c ... (doloop step ...)))))]
[(e1 e2 ...)
(syntax/loc
stx
(let: doloop : ty ([var : tys init] ...)
(if e0
(begin e1 e2 ...)
(begin c ... (doloop step ...)))))]))]))
(define-syntax (cond* stx)
(syntax-case stx (else and or)
[(cond* [(and e0 es ...) . b] cls ...)
(if e0 (cond* [(and es ...) . b] cls ...) #f)]
[(cond* [pred acc var body ...] cl ...)
(identifier? #'var)
#'(let ([var acc])
(if (pred var)
(begin body ...)
(cond* cl ...)))]
[(cond* [else e ...]) #'(begin e ...)]
[(cond* cl cls ...)
#'(cond cl [else (cond* cls ...)])]
[(cond*) #'(cond)]))
)