inline.scm 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey, Jonathan Rees, Mike Sperber, Robert Ransom
  3. ; Once we know that we want something to be inlined, the following things
  4. ; actually make use of the fact. For procedures for which all
  5. ; arguments can be substituted unconditionally, we make a transform
  6. ; (a macro, really) that performs the substitution.
  7. (define (make-inline-transform node type package name)
  8. (let* ((free (find-node-usages node))
  9. (env (package->environment package))
  10. (qualified-free (map (lambda (name)
  11. (cons name
  12. (name->qualified name env)))
  13. free)))
  14. (let ((form (clean-node node '()))
  15. (aux-names (map (lambda (pair)
  16. (do ((name (cdr pair) (qualified-parent-name name)))
  17. ((not (qualified? name))
  18. name)))
  19. qualified-free)))
  20. (make-transform/inline (inline-transform form aux-names)
  21. package ;env ?
  22. type
  23. `(inline-transform ',(remove-bindings form
  24. qualified-free)
  25. ',aux-names)
  26. name))))
  27. ; This routine is obligated to return an S-expression.
  28. ; It's better not to rely on the constancy of node id's, so
  29. ; the output language is a sort of quasi-Scheme. Any form that's a list
  30. ; has an operator name in its car.
  31. ;
  32. ; ENV is an a-list mapping names to qualified (for package variables) or
  33. ; non-clashing (for lexical variables) new names.
  34. ;
  35. ; What about SET! ?
  36. (define (clean-node node env)
  37. (cond ((name-node? node)
  38. (clean-lookup env node))
  39. ((quote-node? node)
  40. `(quote ,(cadr (node-form node))))
  41. ((lambda-node? node)
  42. (clean-lambda node env))
  43. ((call-node? node)
  44. (cons 'call
  45. (map (lambda (node) (clean-node node env))
  46. (node-form node))))
  47. ((loophole-node? node)
  48. (let ((args (cdr (node-form node))))
  49. `(loophole ,(type->sexp (car args) #t)
  50. ,(clean-node (cadr args) env))))
  51. ;; LETREC had better not occur, since we are not prepared for it
  52. ((pair? (node-form node))
  53. (cons (operator-name (node-operator node))
  54. (map (lambda (subnode)
  55. (clean-node subnode env))
  56. (cdr (node-form node)))))
  57. (else (node-form node)))) ;literal
  58. (define (clean-lambda node env)
  59. (let* ((exp (node-form node))
  60. (formals (cadr exp))
  61. (env (fold (lambda (name-node env)
  62. `((,name-node . , (unused-name env (node-form name-node)))
  63. . ,env))
  64. (normalize-formals formals)
  65. env)))
  66. `(lambda ,(let recur ((foo formals))
  67. (cond ((node? foo) (clean-lookup env foo))
  68. ((pair? foo)
  69. (cons (recur (car foo))
  70. (recur (cdr foo))))
  71. (else foo))) ; when does this happen?
  72. ,(clean-node (caddr exp) env))))
  73. ; Package names get looked up by name, lexical names get looked up by the
  74. ; node itself.
  75. (define (clean-lookup env node)
  76. (let ((binding (node-ref node 'binding)))
  77. (if (binding? binding)
  78. `(package-name ,(node-form node) ,binding)
  79. (cdr (assq node env)))))
  80. ; I'm aware that this is pedantic.
  81. (define (unused-name env name)
  82. (let ((sym (name->symbol name)))
  83. (do ((i 0 (+ i 1))
  84. (name sym
  85. (string->symbol (string-append (symbol->string sym)
  86. (number->string i)))))
  87. ((every (lambda (pair)
  88. (not (eq? name (cdr pair))))
  89. env)
  90. name))))
  91. ; We need to remove the binding records from the form that will be used for
  92. ; reification. A better alternative might be for packages to provide dumpable
  93. ; names as stand-ins for bound generated names. The problem is that packages
  94. ; use EQ? tables for names and the linker does not preserve EQ-ness for
  95. ; generated names. Instead, we remember the path and do the lookup that way.
  96. ; This doesn't work if the generated name is itself bound.
  97. ; If the environment in the generated name were the package itself, instead
  98. ; of its environment wrapper, the linker could probably do the right thing
  99. ; with all package-level generated names.
  100. (define (remove-bindings form free)
  101. (let label ((form form))
  102. (if (pair? form)
  103. (case (car form)
  104. ((package-name)
  105. (cdr (assq (cadr form) free))) ; just the name
  106. ((quote) form)
  107. ((lambda)
  108. `(lambda ,(cadr form)
  109. ,(label (caddr form))))
  110. (else
  111. (map label form)))
  112. form)))
  113. ;----------------
  114. ; ST stands for substitution template (cf. MAKE-SUBSTITUTION-TEMPLATE)
  115. (define (inline-transform st aux-names)
  116. (cons
  117. (if (and (pair? st)
  118. (eq? (car st) 'lambda))
  119. (let ((formals (cadr st))
  120. (body (caddr st)))
  121. (lambda (exp package rename)
  122. (let ((args (cdr exp)))
  123. (if (= (length formals) (length args))
  124. (reconstitute body
  125. package
  126. (make-substitution rename formals args))
  127. ;; No need to generate warning since the type checker will
  128. ;; produce one. Besides, we don't want to produce a warning
  129. ;; for things like (> x y z).
  130. exp))))
  131. (lambda (exp package rename)
  132. (cons (reconstitute st package rename)
  133. (cdr exp))))
  134. aux-names))
  135. (define (make-substitution rename formals args)
  136. (let ((subs (map cons formals args)))
  137. (lambda (name)
  138. (let ((probe (assq name subs)))
  139. (cond (probe
  140. (cdr probe))
  141. ((generated? name)
  142. (note 'make-substitution "this shouldn't happen" name)
  143. name) ;TEMPORARY KLUDGE.
  144. (else
  145. (rename name)))))))
  146. ; Turn an s-expression back into a node.
  147. ; ST is an S-expression as returned by MAKE-SUBSTITUTION-TEMPLATE.
  148. (define (reconstitute st package rename)
  149. (let label ((st st))
  150. (cond ((symbol? st)
  151. (let ((foo (rename st)))
  152. (if (name? foo)
  153. (reconstitute-name foo package)
  154. foo)))
  155. ((qualified? st)
  156. (reconstitute-name (qualified->name st rename)
  157. package))
  158. ((pair? st)
  159. (case (car st)
  160. ((quote)
  161. (make-node (get-operator 'quote) st))
  162. ((package-name)
  163. (let ((node (make-node operator/name (cadr st))))
  164. (node-set! node 'binding (caddr st))
  165. node))
  166. ((call)
  167. (make-node (get-operator 'call)
  168. (map label (cdr st))))
  169. ((loophole)
  170. (make-node (get-operator 'loophole)
  171. (list 'loophole
  172. (sexp->type (cadr st) #t)
  173. (label (caddr st)))))
  174. ((lambda)
  175. (assertion-violation 'reconstitute-name "lambda substitution NYI" st))
  176. (else
  177. (let ((keyword (car st)))
  178. (make-node (get-operator keyword)
  179. (cons keyword
  180. (map label (cdr st))))))))
  181. (else
  182. (make-node operator/literal st)))))
  183. (define (reconstitute-name name package)
  184. (let ((binding (package-lookup package name))
  185. (node (make-node operator/name name)))
  186. (if (binding? binding)
  187. (node-set! node 'binding binding))
  188. node))
  189. ; --------------------
  190. ; Convert a qualified name #(>> parent-name symbol) to an alias.
  191. (define (qualified->name qualified rename)
  192. (let recur ((name qualified))
  193. (if (qualified? name)
  194. (let ((parent (recur (qualified-parent-name name))))
  195. (generate-name (qualified-symbol name)
  196. (get-qualified-env (generated-env parent)
  197. (generated-name parent))
  198. parent))
  199. (rename name))))
  200. (define (get-qualified-env env parent)
  201. (let ((binding (generic-lookup env parent)))
  202. (if (binding? binding)
  203. (let ((static (binding-static binding)))
  204. (cond ((transform? static)
  205. (transform-env static))
  206. ((structure? static)
  207. static)
  208. (else
  209. (assertion-violation 'get-qualified-env "invalid qualified reference"
  210. env parent static))))
  211. (assertion-violation 'get-qualified-env "invalid qualified reference"
  212. env parent binding))))