www

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

commit b687cffb0a4c52580d7b81cba6834a7314bbc3f7
parent 9973e1c705fc71cd57044ed978a2bb6917f68e37
Author: Stephen Chang <stchang@ccs.neu.edu>
Date:   Thu, 30 Jul 2015 14:12:34 -0400

extend define-tycon with "get"- extract matched type by pat var name

Diffstat:
Mtapl/stlc+lit.rkt | 5+++--
Mtapl/stlc.rkt | 4+++-
Mtapl/tests/stlc+lit-tests.rkt | 7++++---
Mtapl/typecheck.rkt | 56++++++++++++++++++++++++++++++++++++++++++--------------
4 files changed, 52 insertions(+), 20 deletions(-)

diff --git a/tapl/stlc+lit.rkt b/tapl/stlc+lit.rkt @@ -1,7 +1,8 @@ #lang racket/base (require "typecheck.rkt") -(require "stlc.rkt") -(provide (all-from-out "stlc.rkt")) +(extends "stlc.rkt" #:impl-uses (→)) +;(require "stlc.rkt") +;(provide (all-from-out "stlc.rkt")) (provide (rename-out [datum/tc #%datum])) ;; Simply-Typed Lambda Calculus, plus numeric literals and primitives diff --git a/tapl/stlc.rkt b/tapl/stlc.rkt @@ -48,7 +48,9 @@ (define current-type=? (make-parameter type=?)) (current-typecheck-relation type=?)) -(define-type-constructor (→ τ_in ... τ_out)) +(define-type-constructor (→ τ_in ... τ_out) + #:declare τ_in type + #:declare τ_out type) (define-syntax (λ/tc stx) (syntax-parse stx diff --git a/tapl/tests/stlc+lit-tests.rkt b/tapl/tests/stlc+lit-tests.rkt @@ -30,9 +30,10 @@ #:with-msg "not a valid type: Bool") (typecheck-fail (λ ([x : Bool]) x) #:with-msg "not a valid type: Bool") -(typecheck-fail (λ ([f : Int]) (f 1 2)) - #:with-msg - "Expected type with pattern: \\(→ τ_in ... τ_out\\), got: Int") +(typecheck-fail + (λ ([f : Int]) (f 1 2)) + #:with-msg + "Expected type of expression f to match pattern \\(→ τ_in ... τ_out\\), got: Int") (check-type (λ ([f : (→ Int Int Int)] [x : Int] [y : Int]) (f x y)) : (→ (→ Int Int Int) Int Int Int)) diff --git a/tapl/typecheck.rkt b/tapl/typecheck.rkt @@ -3,7 +3,7 @@ (for-syntax (except-in racket extends) syntax/parse racket/syntax syntax/stx "stx-utils.rkt") - (for-meta 2 racket/base syntax/parse) + (for-meta 2 racket/base syntax/parse racket/syntax) racket/provide) (provide (for-syntax (all-defined-out)) (all-defined-out) @@ -39,7 +39,7 @@ (define-syntax extends (syntax-parser [(_ base-lang - (~optional (~seq #:use (x ...)) #:defaults ([(x 1) null]))) + (~optional (~seq #:impl-uses (x ...)) #:defaults ([(x 1) null]))) #:with pre (generate-temporary) #:with pre: (format-id #'pre "~a:" #'pre) #'(begin @@ -122,18 +122,25 @@ (define-syntax define-type-constructor (syntax-parser - [(_ (τ:id . pat)) + [(_ (τ:id . pat) + (~optional (~seq #:lits (lit ...)) #:defaults ([(lit 1) null])) + decls ... + #;(~optional (~seq (~seq #:decl tvar (~datum as) cls) ...) + #:defaults ([(tvar 1) null][(cls 1) null]))) #:with τ-match (format-id #'τ "~a-match" #'τ) #:with τ? (format-id #'τ "~a?" #'τ) + #:with τ-get (format-id #'τ "~a-get" #'τ) #:with τ-match+erase (format-id #'τ "~a-match+erase" #'τ) #:with pat-class (generate-temporary #'τ) ; syntax-class name #:with tycon (generate-temporary #'τ) ; need a runtime id for expansion - #'(begin + #`(begin + (define lit void) ... (provide τ) (begin-for-syntax - (define-syntax-class pat-class + (define-syntax-class pat-class #:literals (lit ...) ;; dont check is-type? here; should already be types - ;; only need to check is-type? for user-entered types + ;; only check is-type? for user-entered types, eg tycon call + ;; thus, dont include decls here, only want shape (pattern pat)) (define (τ-match ty) (or (match-type ty tycon pat-class) @@ -146,17 +153,38 @@ ;; expression version of τ-match (define (τ-match+erase e) (syntax-parse (infer+erase e) - [(e- τ) - #:with τ_matched (τ-match #'τ) - #'(e- τ_matched)]))) + [(e- ty) + #:with τ_matched/#f (match-type #'ty tycon pat-class) + #:fail-unless (syntax-e #'τ_matched/#f) + (format + "~a (~a:~a): Expected type of expression ~a to match pattern ~a, got: ~a" + (syntax-source e) (syntax-line e) (syntax-column e) + (syntax->datum e) (type->str (quote-syntax (τ . pat))) (type->str #'ty)) + #'(e- τ_matched/#f)])) + ;; get syntax bound to specific pat var (as declared in def-tycon) + (define-syntax (τ-get stx) + (syntax-parse stx #:datum-literals (from) + [(_ attr from ty) + #:with args (generate-temporary) + #:with args.attr (format-id #'args "~a.~a" #'args #'attr) + #'(syntax-parse ((current-type-eval) ty) + [((~literal #%plain-type) ((~literal #%plain-app) t . args)) + #:declare args pat-class ; check shape of arguments + #:fail-unless (typecheck? #'t #'tycon) ; check tycons match + (format "Type error: expected ~a type, got ~a" + (type->str #'τ) (type->str ty)) + (attribute args.attr)])]))) (define tycon (λ _ (raise (exn:fail:type:runtime (format "~a: Cannot use type at run time" 'τ) (current-continuation-marks))))) (define-syntax (τ stx) - (syntax-parse stx - [(_ . pat) ; first check shape - #:with (~! (~var t type) (... ...)) #'pat ; then check for valid types - #'(#%type (tycon . pat))] + (syntax-parse stx #:literals (lit ...) + [(_ . (~and pat !~ args)) ; first check shape + ; this inner syntax-parse gets the ~! to register + ; otherwise, apparently #:declare's get subst into pat (before ~!) + (syntax-parse #'args + [pat #,@#'(decls ...) ; then check declarations (eg, valid type) + #'(#%type (tycon . args))])] [_ (type-error #:src stx #:msg "Improper usage of type constructor ~a: ~a, expected pattern ~a" #'τ stx (quote-syntax (τ . pat)))])))])) @@ -258,7 +286,7 @@ ;; macro for nicer syntax (define-syntax (⊢ stx) (syntax-parse stx #:datum-literals (:) - [(_ e : τ) #'(assign-type #'e #'τ)] + [(_ e : τ) #'(assign-type #'e #`τ)] [(_ e τ) #'(⊢ e : τ)])) ;; assign-type Type -> Syntax