package-undef.scm 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey, Jonathan Rees, Mike Sperber, Taylor Campbell
  3. ; The entry point for all this.
  4. (define (link! template package noise?)
  5. (if noise?
  6. (noting-undefined-variables package
  7. (lambda ()
  8. (really-link! template package)))
  9. (really-link! template package)))
  10. (define (really-link! template package)
  11. (do ((i 0 (+ i 1)))
  12. ((= i (template-length template)))
  13. (let ((x (template-ref template i)))
  14. (cond ((thingie? x)
  15. (template-set! template
  16. i
  17. (get-location (thingie-binding x)
  18. package
  19. (thingie-name x)
  20. (thingie-assigned? x))))
  21. ((template? x)
  22. (really-link! x package))))))
  23. ; GET-LOCATION returns a location to be stored away in a template. If
  24. ; ASSGINED? (which is #t if the variable is SET!) matches the type of
  25. ; the binding, then we just return the binding's location after noting
  26. ; that we are doing so.
  27. ;
  28. ; If the type doesn't match then we make a location and remember that we
  29. ; have done so. If correct location becomes available later we will replace
  30. ; the bogus one (see env/pedit.scm).
  31. (define (get-location binding cenv name assigned?)
  32. (cond
  33. ((binding? binding)
  34. (let ((place (binding-place binding))
  35. (type (binding-type binding)))
  36. (cond
  37. ((variable-type? type)
  38. (note-caching! cenv name place)
  39. place)
  40. (assigned?
  41. (get-location-for-unassignable cenv name))
  42. ((value-type? type)
  43. (note-caching! cenv name place)
  44. place)
  45. (else
  46. (warning 'get-location "invalid variable reference" name cenv)
  47. (note-caching! cenv name place)
  48. place))))
  49. (assigned?
  50. (get-location-for-undefined cenv name location-for-assignment))
  51. (else
  52. (get-location-for-undefined cenv name location-for-reference))))
  53. ; Packages have three tables used by env/pedit.scm:
  54. ; undefineds
  55. ; locations introduced for missing values
  56. ; undefined-but-assigneds
  57. ; locations introduced for missing cells
  58. ; cached
  59. ; locations used here that were supposed to have been provided by
  60. ; someone else
  61. ; Get a location from PACKAGE's table at ACCESSOR.
  62. (define (location-on-demand accessor)
  63. (lambda (package name)
  64. (let ((table (accessor package)))
  65. (or (table-ref table name)
  66. (let ((new (make-new-location package name)))
  67. (table-set! table name new)
  68. new)))))
  69. (define get-undefined
  70. (location-on-demand package-undefineds))
  71. (define get-undefined-but-assigned
  72. (location-on-demand package-undefined-but-assigneds))
  73. ; If this package is mutable and it gets NAME from some other structure
  74. ; then add NAME and PLACE to its table of cached locations.
  75. (define (package-note-caching! package name place)
  76. (if (package-unstable? package)
  77. (if (not (table-ref (package-definitions package) name))
  78. (let loop ((opens (package-opens package)))
  79. (if (not (null? opens))
  80. (call-with-values
  81. (lambda ()
  82. (interface-ref (structure-interface (car opens))
  83. name))
  84. (lambda (internal-name type)
  85. (if internal-name
  86. (begin
  87. (table-set! (package-cached package) name place)
  88. (package-note-caching!
  89. (structure-package (car opens))
  90. internal-name place))
  91. (loop (cdr opens))))))))))
  92. ; Find the actual package providing PLACE and remember that it is being used.
  93. (define (note-caching! cenv name place)
  94. (if (generated? name)
  95. (note-caching! (generated-env name)
  96. (generated-name name)
  97. place)
  98. (let ((package (cenv->package cenv)))
  99. (if (package? package)
  100. (package-note-caching! package name place)))))
  101. ; Get a location for NAME which is SET! but isn't supposed to be.
  102. ; In this case, we're creating a new, local location for the
  103. ; assignment to happen - the original location isn't touched.
  104. (define (get-location-for-unassignable cenv name)
  105. (if (generated? name)
  106. (get-location-for-unassignable (generated-env name)
  107. (generated-name name))
  108. (let ((package (cenv->package cenv)))
  109. (warning 'get-location-for-unassignable "invalid assignment" name)
  110. (if (package? package)
  111. (lambda () (get-undefined-but-assigned package name))
  112. (lambda () (make-undefined-location name))))))
  113. ; Get a location for NAME, which is undefined.
  114. (define (get-location-for-undefined cenv name get-location)
  115. (if (generated? name)
  116. (get-location-for-undefined (generated-env name)
  117. (generated-name name)
  118. get-location)
  119. (let ((package (cenv->package cenv)))
  120. ((or (fluid $note-undefined)
  121. (lambda (cenv name) (values)))
  122. cenv
  123. name)
  124. (if (package? package)
  125. (let ((place (get-location package name)))
  126. (package-note-caching! package name place)
  127. place)
  128. (make-undefined-location name)))))
  129. (define $note-undefined (make-fluid (lambda (cenv name) (values))))
  130. ; Because of generated names CENV may not be an actual compile-env
  131. (define (cenv->package cenv)
  132. (cond ((compiler-env? cenv)
  133. ;; This returns #f if package is stable (static linking).
  134. (extract-package-from-comp-env cenv))
  135. ((package? cenv)
  136. cenv)
  137. ((structure? cenv)
  138. (structure-package cenv))))
  139. ; Exported for env/pedit.scm.
  140. (define (location-for-reference package name)
  141. (get-undefined-location package name get-undefined #f))
  142. (define (location-for-assignment package name)
  143. (get-undefined-location package name get-undefined-but-assigned #t))
  144. (define (get-undefined-location package name get-undefined warn-assignment?)
  145. (let location ((package package)
  146. (name name)
  147. (warn? warn-assignment?))
  148. (let loop ((opens (package-opens package)))
  149. (if (null? opens)
  150. (get-undefined package name)
  151. (call-with-values
  152. (lambda ()
  153. (interface-ref (structure-interface (car opens))
  154. name))
  155. (lambda (internal-name type)
  156. (if internal-name
  157. (begin
  158. (if warn?
  159. (warning 'location-for-assignment "invalid assignment" name))
  160. (location (structure-package (car opens))
  161. internal-name
  162. #f))
  163. (loop (cdr opens)))))))))
  164. ;----------------
  165. ; Maintain and display a list of undefined names.
  166. ; We bind $NOTE-UNDEFINED to a procedure that adds names to LOSERS, an a-list of
  167. ; (<package> . <undefined-names>). Once THUNK has finished we print out any
  168. ; names that are still undefined. CURRENT-PACKAGE is used only to avoid printing
  169. ; out the name of the current package unnecessarily. CURRENT-PACKAGE may be #f.
  170. (define (noting-undefined-variables current-package thunk)
  171. (let* ((losers '())
  172. (add-name (lambda (env name)
  173. (let ((probe (assq env losers)))
  174. (if probe
  175. (if (not (member name (cdr probe)))
  176. (set-cdr! probe (cons name (cdr probe))))
  177. (set! losers (cons (list env name) losers)))))))
  178. (let-fluid $note-undefined
  179. (lambda (env name)
  180. (if (generated? name)
  181. (add-name (generated-env name)
  182. (generated-name name))
  183. (add-name env name)))
  184. (lambda ()
  185. (dynamic-wind
  186. (lambda () #f)
  187. thunk
  188. (lambda ()
  189. (for-each (lambda (env+names)
  190. (print-undefined-names (car env+names)
  191. (cdr env+names)
  192. current-package))
  193. losers)))))))
  194. (define (print-undefined-names env names current-package)
  195. (let ((names (filter (lambda (name)
  196. ;; Keep the ones that are still unbound.
  197. (not (generic-lookup env name)))
  198. names)))
  199. (if (not (null? names))
  200. (let ((names (map (lambda (name)
  201. (if (generated? name)
  202. (generated-name name)
  203. name))
  204. (reverse names))))
  205. (apply warning
  206. 'print-undefined-names
  207. "undefined variables"
  208. env
  209. names)))))
  210. ; (let ((out (current-noise-port)))
  211. ; (newline out)
  212. ; (display "Undefined" out)
  213. ; (if (and current-package
  214. ; (not (eq? env current-package)))
  215. ; (begin (display " in " out)
  216. ; (write env out)))
  217. ; (display ": " out)
  218. ; (write (map (lambda (name)
  219. ; (if (generated? name)
  220. ; (generated-name name)
  221. ; name))
  222. ; (reverse names))
  223. ; out)
  224. ; (newline out)))))