#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=?)