added in checking that dependent variables are all sensible

This commit is contained in:
Robby Findler 2010-07-30 14:13:11 -05:00
parent 8b05829717
commit 9e92a976a7
2 changed files with 61 additions and 32 deletions

View File

@ -97,6 +97,15 @@ and then operates on it to generate the expanded form
(raise-syntax-error #f "dependent variable not bound" (raise-syntax-error #f "dependent variable not bound"
stx var)))) stx var))))
;; not-range-bound : (listof identifier[used-by-an-arg]) -> void
(define (not-range-bound arg-vars)
(when (istx-ress istx)
(for ([arg-var (in-list arg-vars)])
(when (ormap (λ (a-res) (free-identifier=? (res-var a-res) arg-var))
(istx-ress istx))
(raise-syntax-error #f "an argument cannot depend on a result"
stx arg-var)))))
;; no dups in the domains ;; no dups in the domains
(for ([dom (in-list (istx-args istx))]) (for ([dom (in-list (istx-args istx))])
(when (arg-kwd dom) (when (arg-kwd dom)
@ -126,10 +135,12 @@ and then operates on it to generate the expanded form
(no-var-dups (rst-var (istx-rst istx)))) (no-var-dups (rst-var (istx-rst istx))))
;; dependent arg variables are all bound. ;; dependent arg variables are all bound, but not to a range variable
(for ([an-arg (in-list (istx-args istx))]) (for ([an-arg (in-list (istx-args istx))])
(when (arg-vars an-arg) (let ([a-vars (arg-vars an-arg)])
(ensure-bound (arg-vars an-arg)))) (when a-vars
(ensure-bound a-vars)
(not-range-bound a-vars))))
;; dependent range variables are all bound. ;; dependent range variables are all bound.
(when (istx-ress istx) (when (istx-ress istx)
@ -138,39 +149,48 @@ and then operates on it to generate the expanded form
(ensure-bound (res-vars a-res))))))) (ensure-bound (res-vars a-res)))))))
(define (ensure-no-cycles stx istx) (define (ensure-no-cycles stx istx)
(let ([neighbors (make-hash)] (let ([neighbors (make-free-identifier-mapping)]
[sp '()] [safe (make-free-identifier-mapping)]
[safe (make-hash)] [sp '()])
[vars->stx (make-hash)])
(define (link from to) (define (link from to)
(printf "linking ~s => ~s\n" from to) (printf "linking ~s => ~s\n" from to)
(set! sp (cons (syntax-e from) sp)) (set! sp (cons from sp))
(hash-set! vars->stx (syntax-e from) from) (free-identifier-mapping-put!
(hash-set! neighbors (syntax-e from) neighbors from
(cons (syntax-e to) (cons to (free-identifier-mapping-get neighbors from (λ () '())))))
(hash-ref neighbors (syntax-e from) '()))))
(define (no-links from)
(printf "no links ~s\n" from)
(set! sp (cons from sp))
(free-identifier-mapping-put! neighbors from '()))
(for ([an-arg (in-list (istx-args istx))]) (for ([an-arg (in-list (istx-args istx))])
(when (arg-vars an-arg) (cond
[(arg-vars an-arg)
(for ([nvar (in-list (arg-vars an-arg))]) (for ([nvar (in-list (arg-vars an-arg))])
(link (arg-var an-arg) nvar)))) (link (arg-var an-arg) nvar))]
[else
(no-links (arg-var an-arg))]))
(when (istx-ress istx) (when (istx-ress istx)
(for ([a-res (in-list (istx-ress istx))]) (for ([a-res (in-list (istx-ress istx))])
(when (res-vars a-res) (cond
[(res-vars a-res)
(for ([nvar (in-list (res-vars a-res))]) (for ([nvar (in-list (res-vars a-res))])
(link (res-var a-res) nvar))))) (link (res-var a-res) nvar))]
[else
(no-links (res-var a-res))])))
(for ([var (in-list sp)]) (for ([var (in-list sp)])
(let loop ([var var] (let loop ([var var]
[visited '()]) [visited '()])
(printf "var ~s\n" var)
(cond (cond
[(hash-ref safe var #f) [(free-identifier-mapping-get safe var (λ () #f))
(void)] (void)]
[(member var visited) [(memf (λ (x) (free-identifier=? x var)) visited)
(let ([ids (map (λ (x) (hash-ref vars->stx x)) (let ([ids (trim-at var visited)])
(trim-at var visited))])
(raise-syntax-error #f (raise-syntax-error #f
"cyclic dependencies are not allowed" "cyclic dependencies are not allowed"
stx stx
@ -178,18 +198,18 @@ and then operates on it to generate the expanded form
(cdr ids)))] (cdr ids)))]
[else [else
(let ([new-visited (cons var visited)]) (let ([new-visited (cons var visited)])
(for ([neighbor (in-list (hash-ref neighbors var))]) (for ([neighbor (in-list (free-identifier-mapping-get neighbors var))])
(loop neighbor new-visited) (loop neighbor new-visited)
(hash-set! safe var #t)))]))))) (free-identifier-mapping-put! safe var #t)))])))))
;; trim-at : X (listof X) -> (listof X) ;; trim-at : identifier? (listof identifier?) -> (listof identifier?)
;; returns the shortest prefix of vars that ends with var ;; returns the shortest prefix of vars that ends with var
(define (trim-at var vars) (define (trim-at var vars)
(let loop ([vars vars]) (let loop ([vars vars])
(cond (cond
[(null? vars) (error 'trim-at "not found")] [(null? vars) (error 'trim-at "not found")]
[else (let ([fst (car vars)]) [else (let ([fst (car vars)])
(if (eq? fst var) (if (free-identifier=? fst var)
(list fst) (list fst)
(cons fst (loop (cdr vars)))))]))) (cons fst (loop (cdr vars)))))])))

View File

@ -1,9 +1,6 @@
#lang racket/base #lang racket/base
(require racket/contract) (require racket/contract)
(->i ([x (y) number?])
[y number?])
; => domain cannot depend on a range variable
#| #|
test cases: test cases:
@ -84,6 +81,18 @@ test cases:
;; => cyclic depenencies ;; => cyclic depenencies
(->i ([x (y) number?]
[y number?])
any)
; => no syntax error
(->i ()
(values [x (y) number?]
[y number?]))
; => no syntax error
(->i ([x (y) number?])
[y number?])
; => domain cannot depend on a range variable
|# |#