((builtin? x) 'builtin)
((symbol? x) 'var)
((integer? x) 'int-literal)
- ((boolean? x) 'bool-literal)
((string? x) 'string-literal)))
(define (ast-traverse f x)
(define (ast-find p x)
(define (inner y) (ast-find p y))
- (define (any p x) (fold-left
- (lambda (acc y) (if acc #t (p y)))
- #f
- x))
- (define (either . fs)
- (if (null? fs) #f
- (if (car fs) (car fs)
- (apply either (cdr fs)))))
(case (ast-type x)
- ['let (either (p x)
+ ['let (or (p x)
(any inner (let-bindings x))
(any inner (let-body x)))]
- ['app (either (p x)
+ ['app (or (p x)
(any inner x))]
- ['lambda (either (p x)
+ ['lambda (or (p x)
(inner (lambda-body x)))]
- ['if (either (p x) (any inner (cdr x)))]
- ['case (either (p x)
+ ['if (or (p x) (any inner (cdr x)))]
+ ['case (or (p x)
(any inner (map cadr (case-cases x)))
(inner (case-switch x)))]
- ['stack (either (p x) (inner (caddr x)))]
+ ['stack (or (p x) (inner (caddr x)))]
[else (p x)]))
(define let-bindings cadr)
(define case-switch cadr)
(define case-cases cddr)
-;; (define (verify-cases data-layouts annotated-program)
-
-;; (define allowed-match-ast-types
-;; '((Int . (int-literal var))
-;; (Bool . (bool-literal var))
-;; (String . (string-literal var))))
+(define (constructor? data-layouts x)
+ (and (eqv? (ast-type x) 'var)
+ (assoc x (flat-map cdr data-layouts))))
+
+(define (all-cases data-layouts type)
+ (let ([sums (assoc type data-layouts)])
+ (if sums
+ (flat-map (lambda (sum)
+ (let* ([sum-name (car sum)]
+ [products (cdr sum)]
+ [product-cases (map (lambda (y) (all-cases data-layouts y)) products)])
+ (if (null? product-cases)
+ (list sum-name) ; singletons aren't enclosed in a list [(foo x) 42] vs [foo 42]
+ (apply combinations (cons (list sum-name) product-cases)))))
+ (cdr sums))
+ '(:binding))))
+
+ ; does a cover b
+(define (case-covers? data-layouts a b)
+ (let ([a-binding? (and (eqv? (ast-type a) 'var) (not (constructor? data-layouts a)))])
+ (cond
+ [(eqv? ':binding b) a-binding?]
+ [a-binding? #t]
+ ; a literal/singleton
+ [(eqv? (ast-type b) 'var) (eqv? b a)]
+ ; two different constructors
+ [(not (eqv? (car a) (car b))) #f]
+ ; two same constructors
+ [else
+ (all (map (lambda (p q)
+ (case-covers? data-layouts p q))
+ (cdr a) (cdr b)))])))
+
+(define (verify-cases data-layouts annotated-program)
;; (define (check-pattern switch-type pat)
;; (unless (assoc (ast-type (ann-expr pat)) allowed) (impossible-match)))))))
-;; (let ([expr (ann-expr annotated-program)])
-;; (case (ast-type expr)
-;; ['case
-;; (let* ([switch-type (ann-type (case-switch expr))]
-;; [allowed (cdr (assoc switch-type allowed-match-ast-types))])
-;; (for-each
-;; []))]))))
+ (let ([expr (ann-expr annotated-program)])
+ (case (ast-type expr)
+ ['case
+ (let* ([switch-type (ann-type (case-switch expr))]
+ [cases (map car (case-cases expr))]
+ [case-covered?
+ (lambda (x) (any (lambda (y) (case-covers? data-layouts y x)) cases))])
+ (unless (all (map case-covered? (all-cases data-layouts switch-type)))
+ (error #f "not all cases covered")))]
+ [else (ast-traverse (lambda (x) (verify-cases data-layouts x)) expr)])))
; (let ([(foo a b) (foo 123 345)]) a)