scope-set-env.scm 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. #lang racket
  2. (require "box.scm")
  3. (require "counter.scm")
  4. (require "sets.scm")
  5. (provide ss-env
  6. ss-env-scope-counter
  7. ss-env-current-scope-set
  8. ss-env-binding-table
  9. ss-env-make
  10. extend-env
  11. add-scopeset-binding!
  12. scope-set-lookup)
  13. (struct ss-env ((scope-counter)
  14. (current-scope-set)
  15. (binding-table))
  16. #:transparent)
  17. (define (ss-env-make assoc)
  18. ;; create a ss-env from a basic assoc lookup table
  19. ;; it does this by turning each (<name> . <value>) entry from the input
  20. ;; into <name> * empty-set -> <value>
  21. ;; in our scope-set binding table
  22. ;;
  23. ;; assumes every entry in the assoc list has a unique name
  24. (let ((ht (make-hash)))
  25. (for-each (lambda (entry)
  26. (hash-set! ht (car entry) (list (cons '() (cdr entry)))))
  27. assoc)
  28. (ss-env (make-counter)
  29. '()
  30. ht)))
  31. (define (extend-env env scop)
  32. (ss-env (ss-env-scope-counter env)
  33. (sorted-list-insert + scop (ss-env-current-scope-set env))
  34. (ss-env-binding-table env)))
  35. ;; the binding table is a hash table:
  36. ;;
  37. ;; name -> (set to value)
  38. ;;
  39. ;; where each 'set to value' is an
  40. ;; assoc list mapping set of scopes -> value
  41. ;; and it is sorted by length (largest set first)
  42. (define (add-scopeset-binding! env scop name value)
  43. (let* ((set (sorted-list-insert + scop (ss-env-current-scope-set env)))
  44. (tbl (ss-env-binding-table env))
  45. (sets->values (hash-ref tbl name '())))
  46. (hash-set! tbl name
  47. (sorted-list-insert (lambda (entry) (- (length (car entry))))
  48. (cons set value)
  49. sets->values))))
  50. ;; This is it
  51. (define (scope-set-lookup env id set)
  52. ;; errors if unbound
  53. ;; errors if ambiguous
  54. ;;
  55. ;; TODO: optimization: exit early if entries are smaller than current best score
  56. ;;
  57. (let loop ((best #f)
  58. (best-score #f)
  59. (sets (hash-ref (ss-env-binding-table env) id)))
  60. (if (null? sets)
  61. (if best
  62. (cdr best)
  63. (error "unbound variable" (list id set)))
  64. (let ((entry (car sets)))
  65. (if (subset-of? + (car entry) set)
  66. (let ((score (length (car entry))))
  67. (if (or (not best-score) (> score best-score))
  68. (loop entry score (cdr sets))
  69. (loop best best-score (cdr sets))))
  70. (loop best best-score (cdr sets)))))))