racket/collects/syntax/private/id-table.rkt
2010-04-27 16:50:15 -06:00

302 lines
12 KiB
Racket

#lang scheme/base
(require (for-syntax scheme/base
unstable/syntax)
scheme/dict)
(provide id-table-position?)
#|
(require (rename-in scheme/base [car s:car]))
(define-syntax (car stx)
(syntax-case stx ()
[(car x)
#`(begin (unless (pair? x)
(error 'car (format "~s:~s"
'#,(syntax-line stx)
'#,(syntax-column stx))))
(s:car x))]))
|#
(define-struct id-table-position (a b))
(define empty-immutable-hasheq (make-immutable-hasheq null))
(define (check-id x who)
(unless (identifier? x)
(raise-type-error who "identifier" x)))
(define (check-pos x who)
(unless (id-table-position? x)
(raise-type-error who "id-table-position" x)))
(define (wrap f protectors [arity (length protectors)])
(define name (object-name f))
(procedure-reduce-arity
(procedure-rename
(lambda args
(let loop ([args args] [protectors protectors])
(when (pair? args)
(unless (pair? protectors)
(error name "out of guards"))
((car protectors) (car args) name)
(loop (cdr args) (cdr protectors))))
(apply f args))
name)
arity))
(define-syntax (make-code stx)
(syntax-case stx ()
[(_ idtbl
identifier->symbol
identifier=?)
(with-syntax ([mutable-idtbl
(format-id #'idtbl "mutable-~a" (syntax-e #'idtbl))]
[immutable-idtbl
(format-id #'idtbl "immutable-~a" (syntax-e #'idtbl))]
[make-idtbl
(format-id #'idtbl "make-~a" (syntax-e #'idtbl))]
[make-mutable-idtbl
(format-id #'idtbl "make-mutable-~a" (syntax-e #'idtbl))]
[make-immutable-idtbl
(format-id #'idtbl "make-immutable-~a" (syntax-e #'idtbl))]
[mutable-idtbl?
(format-id #'idtbl "mutable-~a?" (syntax-e #'idtbl))]
[immutable-idtbl?
(format-id #'idtbl "immutable-~a?" (syntax-e #'idtbl))])
(define (s x) (format-id #'idtbl "~a~a" (syntax-e #'idtbl) x))
(with-syntax ([idtbl? (s '?)]
[idtbl-hash (s '-hash)]
[idtbl-ref (s '-ref)]
[idtbl-set! (s '-set!)]
[idtbl-set (s '-set)]
[idtbl-remove! (s '-remove!)]
[idtbl-remove (s '-remove)]
[idtbl-count (s '-count)]
[idtbl-iterate-first (s '-iterate-first)]
[idtbl-iterate-next (s '-iterate-next)]
[idtbl-iterate-key (s '-iterate-key)]
[idtbl-iterate-value (s '-iterate-value)]
[idtbl-map (s '-map)]
[idtbl-for-each (s '-for-each)])
#'(begin
;; Struct defs at end, so that dict methods can refer to earlier procs
(define mk
(let ([make-idtbl
(case-lambda
[() (mk null)]
[(init-dict)
(let ([t (make-mutable-idtbl (make-hasheq))])
(for ([(k v) (in-dict init-dict)])
(idtbl-set! t k v))
t)])])
make-idtbl))
(define mkimm
(let ([make-immutable-idtbl
(case-lambda
[() (mkimm null)]
[(init-dict)
(for/fold ([t (make-immutable-idtbl empty-immutable-hasheq)])
([(k v) (in-dict init-dict)])
(idtbl-set t k v))])])
make-immutable-idtbl))
(define (idtbl-ref d id [fail (lambda ()
(error 'idtbl-ref
"no mapping for ~e" id))])
(let ([i (ormap (lambda (i) (and (identifier=? (car i) id) i))
(hash-ref (idtbl-hash d)
(identifier->symbol id)
null))])
(if i
(cdr i)
(if (procedure? fail)
(fail)
fail))))
(define (idtbl-set! d id v)
(let ([l (hash-ref (idtbl-hash d) (identifier->symbol id) null)])
(hash-set! (idtbl-hash d)
(identifier->symbol id)
(let loop ([l l])
(cond [(null? l) (list (cons id v))]
[(identifier=? (caar l) id)
(cons (cons id v) (cdr l))]
[else (cons (car l) (loop (cdr l)))])))))
(define (idtbl-set d id v)
(let ([l (hash-ref (idtbl-hash d) (identifier->symbol id) null)])
(make-immutable-idtbl
(hash-set (idtbl-hash d)
(identifier->symbol id)
(let loop ([l l])
(cond [(null? l) (list (cons id v))]
[(identifier=? (caar l) id)
(cons (cons id v) (cdr l))]
[else (cons (car l) (loop (cdr l)))]))))))
(define (idtbl-remove! d id)
(let* ([l (hash-ref (idtbl-hash d) (identifier->symbol id) null)]
[newl (let loop ([l l])
(cond [(null? l) null]
[(identifier=? (caar l) id)
(cdr l)]
[else (cons (car l) (loop (cdr l)))]))])
(if (pair? newl)
(hash-set! (idtbl-hash d)
(identifier->symbol id)
newl)
(hash-remove! (idtbl-hash d)
(identifier->symbol id)))))
(define (idtbl-remove d id)
(let* ([l (hash-ref (idtbl-hash d) (identifier->symbol id) null)]
[newl (let loop ([l l])
(cond [(null? l) null]
[(identifier=? (caar l) id)
(cdr l)]
[else (cons (car l) (loop (cdr l)))]))])
(make-immutable-idtbl
(if (pair? newl)
(hash-set (idtbl-hash d)
(identifier->symbol id)
newl)
(hash-remove (idtbl-hash d)
(identifier->symbol id))))))
(define (idtbl-count d)
(apply + (hash-map (idtbl-hash d) (lambda (k v) (length v)))))
(define (idtbl-for-each d p)
(define (pp i) (p (car i) (cdr i)))
(hash-for-each (idtbl-hash d)
(lambda (k v) (for-each pp v))))
(define (idtbl-map d f)
(define (fp i) (f (car i) (cdr i)))
(apply append
(hash-map (idtbl-hash d)
(lambda (k v) (map fp v)))))
(define (idtbl-iterate-first d)
(let ([h (idtbl-hash d)])
(let ([a (dict-iterate-first h)])
(and a
(let ([b (dict-iterate-first (dict-iterate-value h a))])
(and b (make-id-table-position a b)))))))
(define (idtbl-iterate-next d pos)
(let ([h (idtbl-hash d)]
[a (id-table-position-a pos)]
[b (id-table-position-b pos)])
(let ([v (dict-iterate-value h a)])
(let ([b2 (dict-iterate-next v b)])
(if b2
(make-id-table-position a b2)
(let ([a2 (dict-iterate-next h a)])
(and a2
(let ([b2 (dict-iterate-first
(dict-iterate-value h a2))])
(and b2 (make-id-table-position a2 b2))))))))))
(define (idtbl-iterate-key d pos)
(let ([h (idtbl-hash d)]
[a (id-table-position-a pos)]
[b (id-table-position-b pos)])
(dict-iterate-key (dict-iterate-value h a) b)))
(define (idtbl-iterate-value d pos)
(let ([h (idtbl-hash d)]
[a (id-table-position-a pos)]
[b (id-table-position-b pos)])
(dict-iterate-value (dict-iterate-value h a) b)))
(define (check-idtbl x who)
(unless (idtbl? x)
(raise-type-error who (symbol->string 'idtbl) x)))
(define (check-mutable-idtbl x who)
(unless (mutable-idtbl? x)
(raise-type-error who (symbol->string 'mutable-idtbl) x)))
(define (check-immutable-idtbl x who)
(unless (immutable-idtbl? x)
(raise-type-error who (symbol->string 'immutable-idtbl) x)))
(define-struct idtbl (hash))
(define-struct (mutable-idtbl idtbl) ()
#:property prop:dict
(vector (wrap idtbl-ref (list check-idtbl check-id void) '(2 3))
(wrap idtbl-set! (list check-mutable-idtbl check-id void))
#f
(wrap idtbl-remove! (list check-mutable-idtbl check-id))
#f
(wrap idtbl-count (list check-idtbl))
(wrap idtbl-iterate-first (list check-idtbl))
(wrap idtbl-iterate-next (list check-idtbl check-pos))
(wrap idtbl-iterate-key (list check-idtbl check-pos))
(wrap idtbl-iterate-value (list check-idtbl check-pos))))
(define-struct (immutable-idtbl idtbl) ()
#:property prop:dict
(vector (wrap idtbl-ref (list check-idtbl check-id void) '(2 3))
#f
(wrap idtbl-set (list check-immutable-idtbl check-id void))
#f
(wrap idtbl-remove (list check-immutable-idtbl check-id))
(wrap idtbl-count (list check-idtbl))
(wrap idtbl-iterate-first (list check-idtbl))
(wrap idtbl-iterate-next (list check-idtbl check-pos))
(wrap idtbl-iterate-key (list check-idtbl check-pos))
(wrap idtbl-iterate-value (list check-idtbl check-pos))))
(#%provide (rename mk make-idtbl)
(rename mkimm make-immutable-idtbl)
idtbl?
mutable-idtbl?
immutable-idtbl?
idtbl-ref
idtbl-set!
idtbl-set
idtbl-remove!
idtbl-remove
idtbl-count
idtbl-iterate-first
idtbl-iterate-next
idtbl-iterate-key
idtbl-iterate-value
idtbl-map
idtbl-for-each))))]))
(define (bound-identifier->symbol id) (syntax-e id))
(make-code bound-id-table
bound-identifier->symbol
bound-identifier=?)
(define (free-identifier->symbol id)
(let ([binding (identifier-binding id)])
(if (pair? binding)
(cadr binding)
(syntax-e id))))
(make-code free-id-table
free-identifier->symbol
free-identifier=?)
(define (resolve id)
(if (syntax-transforming?)
(let-values ([(v next)
(syntax-local-value/immediate id (lambda () (values #f #f)))])
(if next
(resolve next)
id))
id))
(define (free*-identifier->symbol id)
(free-identifier->symbol (resolve id)))
(define (free*-identifier=? a b)
(free-identifier=? (resolve a) (resolve b)))
(make-code free*-id-table
free*-identifier->symbol
free*-identifier=?)