reify.scm 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
  2. ; Structure reification.
  3. (define *least* #f)
  4. (define (reify-structures some)
  5. (let* ((count 0)
  6. (least 1000000)
  7. (greatest -1000000)
  8. (locs (make-table))
  9. (loser (reify-structures-1 some
  10. (lambda (loc)
  11. (let ((id (location-id loc)))
  12. (if (not (table-ref locs id))
  13. (begin
  14. (if (< id least)
  15. (set! *least* loc))
  16. (set! least (min least id))
  17. (set! greatest (max greatest id))
  18. (set! count (+ count 1))
  19. (table-set! locs id loc)))
  20. id))))
  21. (size (+ (- greatest least) 1)))
  22. (write `(least ,least size ,size count ,count)) (newline)
  23. (values loser
  24. (let ((v (make-vector size #f)))
  25. (table-walk (lambda (id loc)
  26. (vector-set! v (- id least) loc))
  27. locs)
  28. v)
  29. least)))
  30. ; This is pretty gross. We really want some kind of object dumper
  31. ; instead.
  32. (define *objects* '()) ;List of (object . creation-form)
  33. (define *object-count* 0)
  34. (define *initializations* '())
  35. (define *deal-with-location* (lambda (loc) loc))
  36. (define *package-table* #f) ;Entries are package-info structures
  37. ; REIFY-STRUCTURES returns a form that evaluates to a procedure that
  38. ; returns an alist of (name . structure). deal-with-location is a
  39. ; procedure that maps locations to labels for them (e.g. integers).
  40. ; The procedure takes one argument, a procedure that will be applied
  41. ; to the labels at startup time to re-obtain the corresponding
  42. ; locations.
  43. (define (reify-structures-1 alist deal-with-location)
  44. (flush-state)
  45. (set! *deal-with-location* deal-with-location)
  46. (display "Reifying") (force-output (current-output-port))
  47. (let* ((result-form (reify-object alist))
  48. (init-exprs (map (lambda (init) (init)) (reverse *initializations*)))
  49. (shebang
  50. `(lambda (get-location)
  51. (let ((the-objects (make-vector ,*object-count* #f)))
  52. ;; silly code to avoid oversize template
  53. (begin ,@(map (lambda (exprs) `(let ((foo (lambda (x) ,@exprs))) (foo 'foo)))
  54. (split-into-sublists init-exprs 100)))
  55. (let ((structs ,result-form))
  56. (set! the-objects #f) ;SO IT CAN BE GC'D
  57. (set! get-location #f)
  58. structs)))))
  59. (newline)
  60. (if *reify-debug* (*reify-debug* shebang))
  61. (flush-state)
  62. (set! *deal-with-location* (lambda (loc) loc))
  63. shebang))
  64. (define (list-split l n)
  65. (let loop ((n n)
  66. (l l)
  67. (rev-result '()))
  68. (if (or (zero? n) (null? l))
  69. (values (reverse rev-result) l)
  70. (loop (- n 1)
  71. (cdr l)
  72. (cons (car l) rev-result)))))
  73. (define (split-into-sublists l n)
  74. (let loop ((l l)
  75. (rev-result '()))
  76. (if (null? l)
  77. (reverse rev-result)
  78. (call-with-values
  79. (lambda () (list-split l n))
  80. (lambda (head rest)
  81. (loop rest
  82. (cons head rev-result)))))))
  83. (define (flush-state)
  84. (set! *objects* '())
  85. (set! *object-count* 0)
  86. (set! *initializations* '())
  87. (set! *package-table* (make-table package-uid)))
  88. ; Return an expression that will evaluate to thing.
  89. (define (reify-object thing)
  90. (cond ((structure? thing)
  91. (let ((p-form (reify-package (structure-package thing))))
  92. (process-one-object
  93. thing
  94. (lambda ()
  95. `(make-structure
  96. ,p-form
  97. ,(interface-expression thing)
  98. ',(structure-name thing)))
  99. (lambda ()
  100. (process-exports thing p-form)
  101. (write-char #\. (current-output-port))
  102. (force-output (current-output-port))))))
  103. ((null? thing) ''())
  104. ((pair? thing)
  105. (if (list? thing)
  106. `(list ,@(map reify-object thing))
  107. `(cons ,(reify-object (car thing))
  108. ,(reify-object (cdr thing)))))
  109. ((symbol? thing)
  110. `',thing)
  111. ((transform? thing)
  112. (process-transform thing))
  113. ((operator? thing)
  114. `(operator ',(operator-name thing)
  115. ',(type->sexp (operator-type thing) #t)))
  116. ((primop? thing)
  117. `(primop ',(primop-name thing)))
  118. ;; ((interface? thing) ...)
  119. (else (assertion-violation 'reify-object "don't know how to reify this" thing))))
  120. (define (reify-package thing)
  121. (process-one-object thing
  122. (lambda ()
  123. (let ((bindings (package-info-bindings (package-info thing))))
  124. `(package
  125. ;; Each binding is a pair (name . loc)
  126. ',(list->vector (map car bindings)) ;names
  127. ',(list->vector (map cdr bindings)) ;location ids
  128. get-location
  129. ,(package-uid thing))))
  130. (lambda ()
  131. (table-set! *package-table*
  132. thing
  133. (make-package-info)))))
  134. ; General utility for uniquifying objects.
  135. (define (process-one-object obj make-creation-form when-new)
  136. (let ((probe (assq obj *objects*)))
  137. (if probe
  138. (cdr probe)
  139. (let* ((index *object-count*)
  140. (form `(vector-ref the-objects ,index)))
  141. (set! *object-count* (+ *object-count* 1))
  142. (set! *objects*
  143. (cons (cons obj form) *objects*))
  144. (add-initialization!
  145. (lambda ()
  146. `(vector-set! the-objects ,index ,(make-creation-form))))
  147. (when-new)
  148. form))))
  149. (define (add-initialization! thunk)
  150. (set! *initializations*
  151. (cons thunk *initializations*)))
  152. ; Add initializers that will create a structure's exported bindings.
  153. (define (process-exports struct p-form)
  154. (let* ((package (structure-package struct))
  155. (info (package-info package)))
  156. (for-each-export (lambda (name want-type binding)
  157. (if (not (process-one-binding name package info p-form))
  158. (warning 'process-exports "undefined export" name package)))
  159. struct)))
  160. ; Packages...
  161. (define package-info-type
  162. (make-record-type 'reify-info
  163. '(bindings ;List of (name static-info location)
  164. table))) ;Caches (assq? name bindings)
  165. (define (package-info package)
  166. (table-ref *package-table* package))
  167. (define make-package-info
  168. (let ((make (record-constructor package-info-type
  169. '(bindings table))))
  170. (lambda ()
  171. (make '()
  172. (make-name-table)))))
  173. (define package-info-bindings (record-accessor package-info-type 'bindings))
  174. (define package-info-table (record-accessor package-info-type 'table))
  175. (define set-package-info-bindings!
  176. (record-modifier package-info-type 'bindings))
  177. (define (process-one-binding name package info p-form) ; => #t iff bound
  178. (let ((table (package-info-table info)))
  179. (if (table-ref table name)
  180. #t
  181. (let ((binding (package-lookup package name)))
  182. (table-set! (package-info-table info) name #t)
  183. (if (binding? binding)
  184. (begin (really-process-one-binding name info binding p-form)
  185. #t)
  186. #f)))))
  187. (define (really-process-one-binding name info binding p-form)
  188. (let ((static (binding-static binding))
  189. (loc (*deal-with-location* (binding-place binding))))
  190. (set-package-info-bindings!
  191. info
  192. (cons (cons name loc)
  193. (package-info-bindings info)))
  194. (if static
  195. (add-package-define! p-form name (reify-object static)))))
  196. (define (add-package-define! p-form name s-form)
  197. (add-initialization!
  198. (lambda ()
  199. `(package-define-static! ,p-form
  200. ',name
  201. ,s-form))))
  202. (define (process-transform transform)
  203. (let ((name (transform-id transform))
  204. (env (transform-env transform)))
  205. (let ((env-form
  206. (if (package? env)
  207. (reify-package env)
  208. (reify-object env))))
  209. (process-one-object
  210. transform
  211. (let ((source (transform-source transform))
  212. (kind (transform-kind transform)))
  213. (lambda ()
  214. `(transform ',kind
  215. ,source ;transformer
  216. ,env-form
  217. ',(type->sexp (transform-type transform) #t) ;type
  218. #f ;',source -- omitted to save space...
  219. ',name)))
  220. (if (package? env)
  221. (lambda ()
  222. (let ((info (package-info env)))
  223. (for-each (lambda (name)
  224. (process-one-binding name env info env-form))
  225. (or (transform-aux-names transform) ; () must be true
  226. (begin
  227. (warning 'process-transform
  228. "reified macro's auxiliary bindings are unknown"
  229. name)
  230. '())))))
  231. (lambda () #f))))))
  232. (define (interface-expression struct)
  233. (let ((names '())
  234. (types '()))
  235. (for-each-export (lambda (name type binding)
  236. (set! names (cons name names))
  237. (set! types (cons (if (eq? type undeclared-type)
  238. ':undeclared
  239. (type->sexp type #t))
  240. types)))
  241. struct)
  242. `(simple-interface ',(list->vector names) ',(list->vector types))))
  243. (define *reify-debug* ;#f
  244. (let ((fn "build/reify-debug.tmp"))
  245. (lambda (x) (call-with-output-file fn
  246. (lambda (port)
  247. (display "Writing linker debug file ")
  248. (display fn) (force-output (current-output-port))
  249. (write x port)
  250. (newline))))))