substitute.scm 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. ; Copyright (c) 1993-2008 by Richard Kelsey. See file COPYING.
  2. ; Substituting new variables for old in expressions.
  3. (define *free-exp-vars* #f)
  4. (define (substitute-in-expression exp)
  5. (set! *free-exp-vars* '())
  6. (set! *letrec-datas* '())
  7. (let* ((exp (substitute-in-exp exp))
  8. (free *free-exp-vars*))
  9. (set! *free-exp-vars* '())
  10. (for-each (lambda (var)
  11. (set-variable-flag! var #f))
  12. free)
  13. (values exp free)))
  14. (define global-marker (list 'global))
  15. (define (note-binding-use! binding)
  16. (let ((var (binding-place binding)))
  17. (if (variable? var)
  18. (note-variable-use! var))))
  19. (define (note-variable-use! var)
  20. (cond ((not (eq? (variable-flag var) global-marker))
  21. (set! *free-exp-vars* (cons var *free-exp-vars*))
  22. (set-variable-flag! var global-marker))))
  23. ; Main dispatch
  24. (define (substitute-in-exp node)
  25. ((operator-table-ref substitutions (node-operator-id node))
  26. node))
  27. ; Particular operators
  28. (define substitutions
  29. (make-operator-table
  30. (lambda (node)
  31. (error "no substitution for node ~S" node))))
  32. (define (default-substitution node)
  33. (make-similar-node node
  34. (cons (car (node-form node))
  35. (map substitute-in-exp (cdr (node-form node))))))
  36. (define (define-substitution name proc)
  37. (operator-define! substitutions name #f proc))
  38. (define-substitution 'literal identity)
  39. (define-substitution 'quote identity)
  40. (define-substitution 'unspecific identity)
  41. (define-substitution 'real-external
  42. (lambda (node)
  43. (let* ((exp (node-form node))
  44. (type (expand-type-spec (cadr (node-form (caddr exp))))))
  45. (make-literal-node (make-external-value (node-form (cadr exp))
  46. type)))))
  47. (define op/literal (get-operator 'literal))
  48. (define (make-literal-node x)
  49. (make-node op/literal x))
  50. ; We copy the names because the same node may occur in multiple places
  51. ; in the tree.
  52. (define-substitution 'lambda
  53. (lambda (node)
  54. (let* ((new-names (copy-names (cadr (node-form node))))
  55. (body (substitute-in-exp (caddr (node-form node)))))
  56. (make-similar-node node
  57. (list (car (node-form node))
  58. new-names
  59. body)))))
  60. (define (copy-names names)
  61. (map (lambda (name)
  62. (let ((new (make-similar-node name (node-form name))))
  63. (node-set! name 'substitute new)
  64. new))
  65. names))
  66. (define-substitution 'name
  67. (lambda (node)
  68. (substitute-name-node node #f)))
  69. (define (substitute-name-node node call?)
  70. (let ((node (name-node-substitute node)))
  71. (let ((binding (node-ref node 'binding)))
  72. (cond ((not binding)
  73. (note-name-use! node)
  74. node)
  75. ((not (binding? binding))
  76. (bug "unbound variable ~S" (node-form node)))
  77. ((primitive? (binding-static binding))
  78. (make-primitive-node (binding-static binding) call?))
  79. ((location? (binding-place binding))
  80. (let ((value (contents (binding-place binding))))
  81. (if (constant? value)
  82. (make-literal-node value)
  83. (identity
  84. (bug "name ~S has non-constant location ~S" node value)))))
  85. (else
  86. (note-binding-use! binding)
  87. node)))))
  88. (define (name-node-substitute node)
  89. (let loop ((node node) (first? #t))
  90. (cond ((node-ref node 'substitute)
  91. => (lambda (node)
  92. (loop node #f)))
  93. ((and first? (not (node-ref node 'binding)))
  94. (user-error "unbound variable ~S" (node-form node)))
  95. (else
  96. node))))
  97. (define-substitution 'set!
  98. (lambda (node)
  99. (let* ((exp (node-form node))
  100. (name (substitute-name-node (cadr exp) #f))
  101. (binding (node-ref name 'binding)))
  102. (if (not (binding? binding))
  103. (user-error "SET! on local variable ~S" (node-form (cadr exp))))
  104. ((structure-ref forms note-variable-set!!)
  105. (binding-place binding))
  106. (note-binding-use! binding)
  107. (make-similar-node node
  108. (list (car exp)
  109. name
  110. (substitute-in-exp (caddr exp)))))))
  111. (define-substitution 'call
  112. (lambda (node)
  113. (let ((proc (car (node-form node)))
  114. (args (cdr (node-form node))))
  115. (make-similar-node node
  116. (cons (if (name-node? proc)
  117. (substitute-name-node proc #t)
  118. (substitute-in-exp proc))
  119. (map substitute-in-exp args))))))
  120. ; Flush GOTO when it is used with a primitive.
  121. (define-substitution 'goto
  122. (lambda (node)
  123. (let ((proc (cadr (node-form node)))
  124. (args (cddr (node-form node))))
  125. (if (and (name-node? proc)
  126. (bound-to-primitive? proc))
  127. (make-node (get-operator 'call)
  128. (cons (substitute-name-node proc #t)
  129. (map substitute-in-exp args)))
  130. (make-similar-node node
  131. (cons 'goto
  132. (cons (if (name-node? proc)
  133. (substitute-name-node proc #t)
  134. (substitute-in-exp proc))
  135. (map substitute-in-exp args))))))))
  136. (define name-node? (node-predicate 'name))
  137. (define (bound-to-primitive? node)
  138. (let ((node (name-node-substitute node)))
  139. (let ((binding (node-ref node 'binding)))
  140. (and binding
  141. (primitive? (binding-static binding))))))
  142. (define-substitution 'begin default-substitution)
  143. (define-substitution 'if default-substitution)
  144. ; drop the loophole part
  145. (define-substitution 'loophole
  146. (lambda (node)
  147. (substitute-in-exp (caddr (node-form node)))))
  148. ;----------------------------------------------------------------
  149. ; Breaking LETREC's down to improve type inference and make compilation
  150. ; easier.
  151. (define-substitution 'letrec
  152. (lambda (node)
  153. (let* ((exp (node-form node))
  154. (vars (map car (cadr exp)))
  155. (vals (map cadr (cadr exp))))
  156. (receive (names datas)
  157. (copy-letrec-names vars vals exp)
  158. (for-each (lambda (data value)
  159. (expand-letrec-value data value datas exp))
  160. datas
  161. vals)
  162. (let ((sets (strongly-connected-components datas
  163. letrec-data-uses
  164. letrec-data-seen?
  165. set-letrec-data-seen?!)))
  166. ;; so we don't keep track of which vars are referenced in the body
  167. (for-each (lambda (d)
  168. (set-letrec-data-seen?! d #t))
  169. datas)
  170. (do ((sets sets (cdr sets))
  171. (exp (substitute-in-exp (caddr exp))
  172. (build-letrec (car sets) exp)))
  173. ((null? sets)
  174. (for-each (lambda (n)
  175. (node-set! n 'letrec-data #f))
  176. names)
  177. exp)))))))
  178. (define-record-type letrec-data
  179. (name ; the name node for which this data exists
  180. marker ; a unique marker for this LETREC
  181. cell? ; variable is SET! or its value is not a (lambda ...). This is
  182. ; always #F until I can think of a reason to allow otherwise.
  183. )
  184. (value ; the expanded value of this variable
  185. uses ; a list of variables that VALUE uses
  186. seen? ; #T if this has been seen before during the current expansion
  187. ))
  188. (define (copy-letrec-names names vals marker)
  189. (let ((names (map (lambda (name value)
  190. (let ((new (make-similar-node name (node-form name)))
  191. (cell? #f)) ; we no longer allow SET! on LETREC vars.
  192. (node-set! new 'letrec-data
  193. (letrec-data-maker new marker cell?))
  194. (node-set! name 'substitute new)
  195. new))
  196. names
  197. vals)))
  198. (values names (map (lambda (name) (node-ref name 'letrec-data)) names))))
  199. (define lambda-node? (node-predicate 'lambda))
  200. ; List of LETREC bound variables currently in scope.
  201. (define *letrec-datas* '())
  202. (define (note-name-use! name)
  203. (let ((data (node-ref name 'letrec-data)))
  204. (cond ((and data (not (letrec-data-seen? data)))
  205. (set-letrec-data-seen?! data #t)
  206. (set! *letrec-datas* (cons data *letrec-datas*))))))
  207. ; Expand VALUE and determine which of DATAS it uses.
  208. (define (expand-letrec-value data value datas mark)
  209. (let ((old-letrec-vars *letrec-datas*))
  210. (set! *letrec-datas* '())
  211. (for-each (lambda (d) (set-letrec-data-seen?! d #f)) datas)
  212. (set-letrec-data-value! data (substitute-in-exp value))
  213. (receive (ours others)
  214. (partition-list (lambda (data)
  215. (eq? (letrec-data-marker data) mark))
  216. *letrec-datas*)
  217. (set! *letrec-datas* (append others old-letrec-vars))
  218. (set-letrec-data-uses! data ours))))
  219. ; If there is only one variable and its value doesn't reference it, then
  220. ; use a LET instead of a LETREC. Variables whose value is either set! or
  221. ; not a lambda have explicit cells introduced.
  222. (define (build-letrec datas body)
  223. (if (and (null? (cdr datas))
  224. (not (memq? (car datas)
  225. (letrec-data-uses (car datas)))))
  226. (make-let-node (map letrec-data-name datas)
  227. (map letrec-data-value datas)
  228. body)
  229. (receive (cells normal)
  230. (partition-list letrec-data-cell? datas)
  231. (make-let-node (map letrec-data-name cells)
  232. (map (lambda (ignore) (unspecific-node))
  233. cells)
  234. (make-letrec-node (map letrec-data-name normal)
  235. (map letrec-data-value normal)
  236. (make-begin-node
  237. (append (map letrec-data->set! cells)
  238. (list body))))))))
  239. (define op/unspecific (get-operator 'unspecific))
  240. (define op/set! (get-operator 'set!))
  241. (define (unspecific-node)
  242. (make-node op/unspecific '()))
  243. (define (letrec-data->set! data)
  244. (make-node op/set!
  245. (list 'set!
  246. (letrec-data-name data)
  247. (letrec-data-value data))))
  248. (define (make-let-node names values body)
  249. (if (null? names)
  250. body
  251. (make-node op/call
  252. (cons (make-node op/lambda
  253. (list 'lambda names body))
  254. values))))
  255. (define (make-letrec-node names values body)
  256. (if (null? names)
  257. body
  258. (make-node op/letrec
  259. (list 'letrec
  260. (map list names values)
  261. body))))
  262. (define (make-begin-node nodes)
  263. (if (null? (cdr nodes))
  264. (car nodes)
  265. (make-node op/begin (cons 'begin nodes))))
  266. (define op/call (get-operator 'call))
  267. (define op/lambda (get-operator 'lambda))
  268. (define op/letrec (get-operator 'letrec))
  269. (define op/begin (get-operator 'begin))
  270. ;----------------------------------------------------------------
  271. ; A version of MAKE-SIMILAR-NODE that actually makes a new node.
  272. ; I wish this could keep the old node's list of properties.
  273. (define (make-similar-node node form)
  274. (make-node (node-operator node) form))