substitute.scm 9.8 KB

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