substitute.scm 12 KB

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