usage.scm 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
  2. ; Getting usage counts and doing a topological sort (so that definitions
  3. ; will be seen before uses, where possible).
  4. ;
  5. ; We change the types of all unassigned top-level variables from
  6. ; (VARIABLE <type>) to <type>.
  7. ;
  8. ; Steps:
  9. ; 1. Make usage records for the variables bound by this package.
  10. ; 2. Analyze each form to update the usage records and to find the referenced
  11. ; variables defined in this package.
  12. ; 3. Update the types of the variables based on their usages.
  13. ; 4. Do a topological sort of the forms using the referenced-variable sets
  14. ; from step 2.
  15. (define (find-usages forms package)
  16. (let ((usages (make-name-table)))
  17. (for-each (lambda (form)
  18. (if (define-node? form)
  19. (let* ((lhs (cadr (node-form form)))
  20. (usage (make-package-usage lhs)))
  21. (table-set! usages (node-form lhs) usage)
  22. (node-set! lhs 'usage usage))))
  23. forms)
  24. (for-each (lambda (form)
  25. (node-set! form
  26. 'free-variables
  27. (analyze form
  28. '()
  29. (lambda (node)
  30. (table-ref usages (node-form node))))))
  31. forms)
  32. (for-each (lambda (form)
  33. (if (define-node? form)
  34. (maybe-update-known-type form package)))
  35. forms)
  36. (sort-forms forms #t)))
  37. (define (maybe-update-known-type node package)
  38. (let* ((lhs (cadr (node-form node)))
  39. (usage (node-ref lhs 'usage)))
  40. (if (= 0 (usage-assignment-count usage))
  41. (let ((new-type (reconstruct-type (caddr (node-form node))
  42. (package->environment package))))
  43. (if (subtype? new-type any-values-type)
  44. (package-refine-type! package
  45. (node-form lhs)
  46. (if (subtype? new-type value-type)
  47. new-type
  48. value-type))
  49. (warn "ill-typed right-hand side"
  50. (schemify node)
  51. (type->sexp new-type #t)))))))
  52. ;----------------
  53. ; Another entry point.
  54. ; Here we want to return all package variables found, not just the ones from
  55. ; this package. We also don't update the actual usage records for package
  56. ; variables, as they refer to the entire package, not just one form.
  57. (define (find-node-usages node)
  58. (let* ((usages (make-name-table))
  59. (referenced (analyze node
  60. '()
  61. (lambda (node)
  62. (let ((usage (node-ref node 'usage)))
  63. (if (and usage
  64. (not (package-usage? usage)))
  65. #f
  66. (let ((name (node-form node)))
  67. (or (table-ref usages name)
  68. (let ((usage (make-package-usage node)))
  69. (table-set! usages name usage)
  70. usage)))))))))
  71. (map (lambda (usage)
  72. (node-form (usage-name-node usage)))
  73. referenced)))
  74. ;----------------
  75. ; The usual node walk. FREE is a list of usage records for package variables
  76. ; that have been seen so far. USAGES is a function that maps names to usages.
  77. (define (analyze node free usages)
  78. ((operator-table-ref usage-analyzers (node-operator-id node))
  79. node
  80. free
  81. usages))
  82. (define (analyze-nodes nodes free usages)
  83. (reduce (lambda (node free)
  84. (analyze node free usages))
  85. free
  86. nodes))
  87. (define usage-analyzers
  88. (make-operator-table (lambda (node free usages)
  89. (analyze-nodes (node-form node) free usages))))
  90. (define (define-usage-analyzer name type proc)
  91. (operator-define! usage-analyzers name type proc))
  92. (define (nothing node free usages) free)
  93. (define-usage-analyzer 'literal #f nothing)
  94. (define-usage-analyzer 'unspecific #f nothing)
  95. (define-usage-analyzer 'unassigned #f nothing)
  96. (define-usage-analyzer 'quote syntax-type nothing)
  97. (define-usage-analyzer 'primitive-procedure syntax-type nothing)
  98. (define-usage-analyzer 'name #f
  99. (lambda (node free usages)
  100. (note-reference! node usages)
  101. (add-if-free node free usages)))
  102. ; If NODE has a usage record, then add it to FREE if it (the usage record) isn't
  103. ; already there.
  104. (define (add-if-free node free usages)
  105. (let ((usage (usages node)))
  106. (if (and usage
  107. (not (memq usage free)))
  108. (cons usage free)
  109. free)))
  110. (define-usage-analyzer 'call #f
  111. (lambda (node free usages)
  112. (let* ((exp (node-form node))
  113. (proc (car exp)))
  114. (if (name-node? proc)
  115. (note-operator! proc usages))
  116. (analyze-nodes exp free usages))))
  117. (define-usage-analyzer 'lambda syntax-type
  118. (lambda (node free usages)
  119. (let* ((exp (node-form node))
  120. (formals (cadr exp)))
  121. (for-each (lambda (node)
  122. (node-set! node 'usage (make-usage)))
  123. (normalize-formals formals))
  124. (analyze (caddr exp) free usages))))
  125. (define-usage-analyzer 'letrec syntax-type
  126. (lambda (node free usages)
  127. (let ((exp (node-form node)))
  128. (analyze-letrec (cadr exp) (caddr exp) free usages))))
  129. (define-usage-analyzer 'pure-letrec syntax-type
  130. (lambda (node free usages)
  131. (let ((exp (node-form node)))
  132. (analyze-letrec (cadr exp) (cadddr exp) free usages))))
  133. (define (analyze-letrec specs body free usages)
  134. (for-each (lambda (spec)
  135. (node-set! (car spec) 'usage (make-usage)))
  136. specs)
  137. (analyze body
  138. (analyze-nodes (map cadr specs)
  139. free
  140. usages)
  141. usages))
  142. (define-usage-analyzer 'begin syntax-type
  143. (lambda (node free usages)
  144. (analyze-nodes (cdr (node-form node)) free usages)))
  145. (define-usage-analyzer 'set! syntax-type
  146. (lambda (node free usages)
  147. (let ((exp (node-form node)))
  148. (let ((lhs (cadr exp))
  149. (rhs (caddr exp)))
  150. (note-assignment! lhs usages)
  151. (analyze rhs (add-if-free lhs free usages) usages)))))
  152. (define-usage-analyzer 'define syntax-type
  153. (lambda (node free usages)
  154. (analyze (caddr (node-form node))
  155. free
  156. usages)))
  157. (define-usage-analyzer 'if syntax-type
  158. (lambda (node free usages)
  159. (analyze-nodes (cdr (node-form node)) free usages)))
  160. (define-usage-analyzer 'lap syntax-type
  161. (lambda (node free usages)
  162. (analyze-nodes (caddr (node-form node))
  163. free
  164. usages)))
  165. (define-usage-analyzer 'loophole syntax-type
  166. (lambda (node free usages)
  167. (analyze (caddr (node-form node))
  168. free
  169. usages)))
  170. ;--------------------
  171. ; Usage records record the number of times that a variable is referenced, set!,
  172. ; and called.
  173. (define-record-type usage :usage
  174. (really-make-usage name-node reference operator assignment)
  175. usage?
  176. (name-node usage-name-node) ; only for package variables
  177. (reference usage-reference-count set-reference!)
  178. (operator usage-operator-count set-operator!)
  179. (assignment usage-assignment-count set-assignment!))
  180. (define (make-usage)
  181. (really-make-usage #f 0 0 0))
  182. (define (make-package-usage name-node)
  183. (really-make-usage name-node 0 0 0))
  184. (define (package-usage? usage)
  185. (usage-name-node usage))
  186. (define (usage-incrementator ref set)
  187. (lambda (node usages)
  188. (let ((v (or (node-ref node 'usage)
  189. (usages node))))
  190. (if v
  191. (set v (+ (ref v) 1))))))
  192. (define note-reference! (usage-incrementator usage-reference-count set-reference!))
  193. (define note-operator! (usage-incrementator usage-operator-count set-operator!))
  194. (define note-assignment! (usage-incrementator usage-assignment-count set-assignment!))