usage.scm 7.1 KB

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