123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 |
- #lang racket
- (require "box.scm")
- (require "counter.scm")
- (require "sets.scm")
- (provide ss-env
- ss-env-scope-counter
- ss-env-current-scope-set
- ss-env-binding-table
- ss-env-make
- extend-env
- add-scopeset-binding!
- scope-set-lookup)
- (struct ss-env ((scope-counter)
- (current-scope-set)
- (binding-table))
- #:transparent)
- (define (ss-env-make assoc)
- ;; create a ss-env from a basic assoc lookup table
- ;; it does this by turning each (<name> . <value>) entry from the input
- ;; into <name> * empty-set -> <value>
- ;; in our scope-set binding table
- ;;
- ;; assumes every entry in the assoc list has a unique name
- (let ((ht (make-hash)))
- (for-each (lambda (entry)
- (hash-set! ht (car entry) (list (cons '() (cdr entry)))))
- assoc)
- (ss-env (make-counter)
- '()
- ht)))
- (define (extend-env env scop)
- (ss-env (ss-env-scope-counter env)
- (sorted-list-insert + scop (ss-env-current-scope-set env))
- (ss-env-binding-table env)))
- ;; the binding table is a hash table:
- ;;
- ;; name -> (set to value)
- ;;
- ;; where each 'set to value' is an
- ;; assoc list mapping set of scopes -> value
- ;; and it is sorted by length (largest set first)
- (define (add-scopeset-binding! env scop name value)
- (let* ((set (sorted-list-insert + scop (ss-env-current-scope-set env)))
- (tbl (ss-env-binding-table env))
- (sets->values (hash-ref tbl name '())))
- (hash-set! tbl name
- (sorted-list-insert (lambda (entry) (- (length (car entry))))
- (cons set value)
- sets->values))))
- ;; This is it
- (define (scope-set-lookup env id set)
- ;; errors if unbound
- ;; errors if ambiguous
- ;;
- ;; TODO: optimization: exit early if entries are smaller than current best score
- ;;
- (let loop ((best #f)
- (best-score #f)
- (sets (hash-ref (ss-env-binding-table env) id)))
- (if (null? sets)
- (if best
- (cdr best)
- (error "unbound variable" (list id set)))
- (let ((entry (car sets)))
- (if (subset-of? + (car entry) set)
- (let ((score (length (car entry))))
- (if (or (not best-score) (> score best-score))
- (loop entry score (cdr sets))
- (loop best best-score (cdr sets))))
- (loop best best-score (cdr sets)))))))
|