to-cps.scm 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  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
  6. ;;;
  7. ;;; scheme48-1.9.2/ps-compiler/prescheme/to-cps.scm
  8. ;;;
  9. ;;; Convert a byte-code-compiler node into a cps node.
  10. (define-module (ps-compiler prescheme to-cps)
  11. #:use-module (prescheme scheme48)
  12. #:use-module (prescheme bcomp binding)
  13. #:use-module (prescheme bcomp name)
  14. #:use-module (prescheme bcomp node)
  15. #:use-module (prescheme bcomp schemify)
  16. #:use-module (ps-compiler front cps)
  17. #:use-module (ps-compiler node arch)
  18. #:use-module ((ps-compiler node let-nodes) #:select (let-nodes))
  19. #:use-module ((ps-compiler node node) #:select (make-reference-node
  20. make-lambda-node
  21. make-literal-node
  22. make-call-node
  23. attach
  24. detach
  25. attach-body
  26. call-args
  27. call-arg))
  28. #:use-module ((ps-compiler node node) #:select (lambda-node? call-node? set-lambda-name!) #:prefix cps/)
  29. #:use-module ((ps-compiler node node-util) #:select (attach-call-args attach-three-call-args))
  30. #:use-module (ps-compiler node primop)
  31. #:use-module (ps-compiler node variable)
  32. #:use-module (ps-compiler prescheme infer-early)
  33. #:use-module (ps-compiler prescheme primitive)
  34. #:use-module (ps-compiler prescheme primop primop)
  35. #:use-module (ps-compiler prescheme spec)
  36. #:use-module (ps-compiler prescheme type)
  37. #:use-module (ps-compiler util util)
  38. #:export (x->cps))
  39. ;; Entry point.
  40. (define (x->cps node name)
  41. (receive (value first-call last-lambda)
  42. (cps node)
  43. (if first-call
  44. (bug "(X->CPS ~S) got a non-value" node))
  45. (maybe-add-name! value name)
  46. value))
  47. ;;----------------------------------------------------------------
  48. ;; (CPS <node>)
  49. ;; -> <value> <first-call> <last-lambda>
  50. ;; <value> is the CPSed value of <node>. If <node> contains no non-trivial
  51. ;; calls, <first-call> and <last-lambda> are both #f. Otherwise they are
  52. ;; the first of the non-trivial calls and the continuation of the last.
  53. (define (cps node)
  54. (receive (value first-call last-lambda)
  55. (real-cps node)
  56. (let ((value (cond ((not (list? value))
  57. value)
  58. ((or (null? value)
  59. (not (null? (cdr value))))
  60. (bug "value expression did not return one value ~S"
  61. (schemify node)))
  62. (else
  63. (car value)))))
  64. (values value first-call last-lambda))))
  65. ;; Same as above except that <value> is a list of values.
  66. (define (values-cps node)
  67. (receive (value first-call last-lambda)
  68. (real-cps node)
  69. (values (if (list? value)
  70. value
  71. (list value))
  72. first-call
  73. last-lambda)))
  74. (define (real-cps node)
  75. ((operator-table-ref cps-converters
  76. (node-operator-id node))
  77. node))
  78. (define cps-converters
  79. (make-operator-table
  80. (lambda (node id)
  81. (error "no cps-converter for node ~S" node))))
  82. (define (define-cps-converter name proc)
  83. (operator-define! cps-converters name #f proc))
  84. ;;----------------------------------------------------------------
  85. ;; (TAIL-CPS <node> <continuation-variable>)
  86. ;; -> <first-call>
  87. (define (tail-cps node cont-var)
  88. ((operator-table-ref tail-cps-converters (node-operator-id node))
  89. node
  90. cont-var))
  91. (define tail-cps-converters
  92. (make-operator-table
  93. (lambda (node cont-var)
  94. (error "no tail-cps-converter for node ~S" node))))
  95. (define (define-tail-cps-converter name proc)
  96. (operator-define! tail-cps-converters name #f proc))
  97. ;; Use PROC in the CPS table and give it a wrapper that makes a return for use
  98. ;; in the TAIL-CPS table.
  99. (define (define-value-cps-converter name proc)
  100. (operator-define! cps-converters name #f
  101. (lambda (node)
  102. (values (proc node) #f #f)))
  103. (operator-define! tail-cps-converters name #f
  104. (lambda (node cont-var)
  105. (make-return cont-var (proc node)))))
  106. ;; El Hacko Grande: we use the name of the CONT-VAR to determine whether
  107. ;; it is a return or a join point.
  108. (define (join? var)
  109. (case (variable-name var)
  110. ((c) #f)
  111. ((j) #t)
  112. (else
  113. (bug "funny continuation variable name ~S" var))))
  114. (define (make-return cont-var value)
  115. (really-make-return cont-var (list value)))
  116. (define (make-multiple-value-return cont-var values)
  117. (really-make-return cont-var values))
  118. (define (really-make-return cont-var values)
  119. (let ((return (make-call-node
  120. (get-primop (if (join? cont-var)
  121. (enum primop-enum jump)
  122. (enum primop-enum unknown-return)))
  123. (+ 1 (length values))
  124. 0)))
  125. (attach-call-args return (cons (make-reference-node cont-var) values))
  126. return))
  127. ;;----------------------------------------------------------------
  128. ;; Constants are easy.
  129. (define-value-cps-converter 'literal
  130. (lambda (node)
  131. (cps-literal (node-form node) node)))
  132. (define-value-cps-converter 'quote
  133. (lambda (node)
  134. (cps-literal (cadr (node-form node)) node)))
  135. (define (cps-literal value node)
  136. (make-literal-node value (node-type node)))
  137. (define-value-cps-converter 'unspecific
  138. (lambda (node)
  139. (make-unspecific)))
  140. (define (make-unspecific)
  141. (make-call-node (get-prescheme-primop 'unspecific) 0 0))
  142. ;; Used for primitives in non-call position. The CDR of the form is a
  143. ;; variable that will be bound to the primitive's closed-compiled value.
  144. (define-value-cps-converter 'primitive
  145. (lambda (node)
  146. (make-reference-node (cdr (node-form node)))))
  147. ;;----------------------------------------------------------------
  148. (define-value-cps-converter 'lambda
  149. (lambda (node)
  150. (let ((form (node-form node))
  151. (cont-var (make-variable 'c (lambda-node-return-type node)))
  152. (vars (map (lambda (name)
  153. (let ((var (make-variable (name-node->symbol name)
  154. (node-type name))))
  155. (node-set! name 'variable var)
  156. var))
  157. (cadr (node-form node)))))
  158. (let ((lnode (make-lambda-node 'p 'proc (cons cont-var vars))))
  159. (attach-body lnode (tail-cps (caddr form) cont-var))
  160. lnode))))
  161. ;;----------------------------------------------------------------
  162. ;; References and SET!
  163. (define-value-cps-converter 'name
  164. (lambda (node)
  165. (cond ((node-ref node 'variable)
  166. => make-reference-node) ;; eventually have to check for SET!'s
  167. ((node-ref node 'binding)
  168. => (lambda (binding)
  169. (let ((var (binding-place binding)))
  170. (cond ((not (variable? var))
  171. (bug "binding for ~S has funny place ~S" node var))
  172. ((variable-set!? var)
  173. (make-global-ref var))
  174. (else
  175. (make-reference-node var))))))
  176. (else
  177. (bug "name node ~S has neither variable nor binding" node)))))
  178. (define (make-global-ref var)
  179. (let-nodes
  180. ((call (global-ref 0 (* var))))
  181. call))
  182. ;; Stolen from form.scm as an expedient. This needs to be moved to somewhere
  183. ;; that both FORMS and TO-CPS can see it.
  184. (define (variable-set!? var)
  185. (memq 'set! (variable-flags var)))
  186. (define-cps-converter 'set!
  187. (lambda (node)
  188. (receive (first-call last-lambda)
  189. (make-global-set! (node-form node))
  190. (values (make-unspecific) first-call last-lambda))))
  191. (define-tail-cps-converter 'set!
  192. (lambda (node cont-var)
  193. (receive (first-call last-lambda)
  194. (make-global-set! (node-form node))
  195. (attach-body last-lambda (make-return cont-var (make-unspecific)))
  196. first-call)))
  197. (define (make-global-set! form)
  198. (let ((name (cadr form))
  199. (value (caddr form)))
  200. (receive (value first-call last-lambda)
  201. (cps value)
  202. (maybe-add-name! value name)
  203. (let ((cont (make-lambda-node 'c 'cont '()))
  204. (var (name-node->variable name)))
  205. (let-nodes
  206. ((call (global-set! 1 cont (* var) value)))
  207. (values (splice!->first first-call last-lambda call)
  208. cont))))))
  209. (define (name-node->variable name-node)
  210. (let ((binding (node-ref name-node 'binding)))
  211. (if (and binding
  212. (variable? (binding-place binding)))
  213. (binding-place binding)
  214. (bug "name node ~S has no variable" name-node))))
  215. ;;----------------------------------------------------------------
  216. ;; CALL & GOTO
  217. (define-cps-converter 'call
  218. (lambda (node)
  219. (let ((exp (node-form node)))
  220. (convert-call (car exp) (cdr exp) node))))
  221. ;; Treat non-tail-recursive GOTO's as normal calls.
  222. (define-cps-converter 'goto
  223. (lambda (node)
  224. (let ((exp (node-form node)))
  225. (user-warning "Ignoring non-tail-recursive GOTO: ~S" (schemify node))
  226. (convert-call (cadr exp) (cddr exp) node))))
  227. ;; Dispatch on the procedure. Do something special with lambdas, primitives,
  228. ;; primops (in literal nodes). Everything else is turned into an unknown call.
  229. ;; Calls to primitives are expanded and then CPS'ed.
  230. (define (convert-call proc args node)
  231. (cond ((lambda-node? proc)
  232. (convert-let (node-form proc) args node))
  233. ((primitive-node? proc)
  234. (values-cps (expand-primitive-call proc args node)))
  235. ((and (literal-node? proc)
  236. (primop? (node-form proc)))
  237. (convert-primop-call (node-form proc) args (node-type node)))
  238. (else
  239. (convert-primop-call (get-primop (enum primop-enum unknown-call))
  240. (cons proc ;; add protocol argument
  241. (cons (make-literal normal-protocol)
  242. args))
  243. (node-type node)))))
  244. ;; Same again, except that for unknown tail-recursive calls we use different
  245. ;; protocols for CALL and GOTO.
  246. (define-tail-cps-converter 'call
  247. (lambda (node cont-var)
  248. (if (join? cont-var)
  249. (convert-and-add-jump node cont-var)
  250. (let ((exp (node-form node)))
  251. (tail-convert-call (car exp) (cdr exp) node cont-var normal-protocol)))))
  252. (define-tail-cps-converter 'goto
  253. (lambda (node cont-var)
  254. (if (join? cont-var)
  255. (convert-and-add-jump node cont-var)
  256. (let ((exp (node-form node)))
  257. (tail-convert-call (cadr exp) (cddr exp) node cont-var goto-protocol)))))
  258. (define (convert-and-add-jump node join-var)
  259. (receive (values first-call last-lambda)
  260. (values-cps node)
  261. (let ((jump (make-multiple-value-return join-var values)))
  262. (cond (first-call
  263. (attach-body last-lambda jump)
  264. first-call)
  265. (else
  266. jump)))))
  267. (define (tail-convert-call proc args node cont-var protocol)
  268. (cond ((lambda-node? proc)
  269. (convert-tail-let (node-form proc) args node cont-var))
  270. ((primitive-node? proc)
  271. (tail-cps (expand-primitive-call proc args node)
  272. cont-var))
  273. ((and (literal-node? proc)
  274. (primop? (node-form proc)))
  275. (convert-primop-tail-call (node-form proc) args cont-var))
  276. (else
  277. (convert-unknown-tail-call (cons proc args) cont-var protocol))))
  278. ;; Every primitive has its own expander.
  279. (define (expand-primitive-call proc args node)
  280. ((primitive-expander (node-form proc)) args (node-type node)))
  281. (define lambda-node? (node-predicate 'lambda))
  282. (define primitive-node? (node-predicate 'primitive))
  283. (define literal-node? (node-predicate 'literal))
  284. (define literal-op (get-operator 'literal))
  285. (define (make-literal value)
  286. (make-node literal-op value))
  287. ;;----------------------------------------------------------------
  288. ;; LET (= a call whose procedure is a LAMBDA)
  289. ;; REALLY-CONVERT-LET does all the work. These convert the body of the LET
  290. ;; using either CPS or TAIL-CPS and connect everything up.
  291. (define (convert-let proc args node)
  292. (receive (lnode first-call)
  293. (really-convert-let proc args node)
  294. (receive (vals body-first-call body-last-lambda)
  295. (values-cps (caddr proc))
  296. (values vals
  297. first-call
  298. (splice!->last lnode body-first-call body-last-lambda)))))
  299. (define (convert-tail-let proc args node cont-var)
  300. (receive (lnode first-call)
  301. (really-convert-let proc args node)
  302. (attach-body lnode (tail-cps (caddr proc) cont-var))
  303. first-call))
  304. ;; Make the call to the LET primop and build the lambda node for the procedure.
  305. (define (really-convert-let proc args node)
  306. (receive (call first-call last-lambda)
  307. (cps-call (get-primop (enum primop-enum let)) 1 1 args cps)
  308. (let ((vars (map (lambda (name)
  309. (let ((var (make-variable (name-node->symbol name)
  310. (node-type name))))
  311. (node-set! name 'variable var)
  312. var))
  313. (cadr proc))))
  314. (do ((names (cadr proc) (cdr names))
  315. (index 1 (+ index 1)))
  316. ((null? names))
  317. (maybe-add-argument-name! call index (node-form (car names))))
  318. (let ((lnode (make-lambda-node #f 'cont vars)))
  319. (attach call 0 lnode)
  320. (values lnode (splice!->first first-call last-lambda call))))))
  321. ;; Primitive calls
  322. ;; Use CPS-CALL to do the work and then make a continuation if the primop is
  323. ;; not trivial.
  324. (define (convert-primop-call primop args type)
  325. (let ((trivial? (primop-trivial? primop)))
  326. (receive (call first-call last-lambda)
  327. (cps-call primop (if trivial? 0 1) (if trivial? 0 1) args cps)
  328. (if (not trivial?)
  329. (add-continuation call first-call last-lambda type)
  330. (values call first-call last-lambda)))))
  331. (define (add-continuation call first-call last-lambda type)
  332. (let* ((vars (map (lambda (type)
  333. (make-variable 'v type))
  334. (if (tuple-type? type)
  335. (tuple-type-types type)
  336. (list type))))
  337. (cont (make-lambda-node 'c 'cont vars)))
  338. (attach call 0 cont)
  339. (values (if (tuple-type? type)
  340. (map make-reference-node vars)
  341. (make-reference-node (car vars)))
  342. (splice!->first first-call last-lambda call)
  343. cont)))
  344. ;; Call CONVERT-PRIMOP-CALL and then make a return.
  345. (define (convert-primop-tail-call primop args cont-var)
  346. (receive (value first-call last-lambda)
  347. (convert-primop-call primop args (variable-type cont-var))
  348. (splice!->first first-call
  349. last-lambda
  350. (if (list? value)
  351. (make-multiple-value-return cont-var value)
  352. (make-return cont-var value)))))
  353. ;; Another front for CPS-CALL, passing it the UNKNOWN-TAIL-CALL primop and
  354. ;; its arguments, which are the procedure being called, the protocol, and
  355. ;; the actual arguments.
  356. (define (convert-unknown-tail-call args cont-var protocol)
  357. (receive (call first-call last-lambda)
  358. (cps-call (get-primop (enum primop-enum unknown-tail-call)) 0 1
  359. (cons (car args)
  360. (cons (make-literal protocol) (cdr args)))
  361. cps)
  362. (attach call 0 (make-reference-node cont-var))
  363. (splice!->first first-call last-lambda call)))
  364. ;;----------------------------------------------------------------
  365. ;; BEGIN
  366. ;; These are fronts for CPS-SEQUENCE.
  367. (define-cps-converter 'begin
  368. (lambda (node)
  369. (receive (last-node real-first-call last-lambda)
  370. (cps-sequence (cdr (node-form node)) values-cps)
  371. (if (not real-first-call)
  372. (cps last-node)
  373. (receive (vals first-call real-last-lambda)
  374. (values-cps last-node)
  375. (values vals
  376. real-first-call
  377. (splice!->last last-lambda first-call real-last-lambda)))))))
  378. (define-tail-cps-converter 'begin
  379. (lambda (node cont-var)
  380. (receive (last-node first-call last-lambda)
  381. (cps-sequence (cdr (node-form node)) values-cps)
  382. (splice!->first first-call last-lambda (tail-cps last-node cont-var)))))
  383. ;;----------------------------------------------------------------
  384. ;;
  385. ;; (IF <a> <b> <c>)
  386. ;; =>
  387. ;; (LET ((J (LAMBDA (V) [rest-goes-here])))
  388. ;; (TEST (LAMBDA () [tail-cps <b> J])
  389. ;; (LAMBDA () [tail-cps <c> J])
  390. ;; <a>))
  391. (define-cps-converter 'if
  392. (lambda (node)
  393. (let ((exp (node-form node))
  394. (join-var (make-variable 'j type/unknown))
  395. (res-vars (make-variables (node-type node))))
  396. (receive (call first-call last-lambda)
  397. (convert-if exp join-var)
  398. (let ((let-lambda (make-lambda-node 'c 'cont (list join-var)))
  399. (let-call (make-call-node (get-primop (enum primop-enum let)) 2 1))
  400. (join-lambda (make-lambda-node 'j 'jump res-vars)))
  401. (attach let-call 0 let-lambda)
  402. (attach let-call 1 join-lambda)
  403. (attach-body let-lambda call)
  404. (values (map make-reference-node res-vars)
  405. (splice!->first first-call last-lambda let-call )
  406. join-lambda))))))
  407. (define (make-variables type)
  408. (map (lambda (type)
  409. (make-variable 'v type))
  410. (if (tuple-type? type)
  411. (tuple-type-types type)
  412. (list type))))
  413. ;; Tail-recursive IFs do not require a join point.
  414. (define-tail-cps-converter 'if
  415. (lambda (node cont-var)
  416. (let ((exp (node-form node)))
  417. (receive (call first-call last-lambda)
  418. (convert-if exp cont-var)
  419. (splice!->first first-call last-lambda call)))))
  420. ;; Actually build the two-continuation call to the TEST primop.
  421. (define (convert-if exp cont-var)
  422. (receive (call first-call last-lambda)
  423. (cps-call (get-prescheme-primop 'test) 2 2 (list (cadr exp)) cps)
  424. (let ((true-cont (make-lambda-node 'c 'cont '()))
  425. (true-call (tail-cps (caddr exp) cont-var))
  426. (false-cont (make-lambda-node 'c 'cont '()))
  427. (false-call (tail-cps (cadddr exp) cont-var)))
  428. (attach-body true-cont true-call)
  429. (attach-body false-cont false-call)
  430. (attach call 0 true-cont)
  431. (attach call 1 false-cont)
  432. (values call first-call last-lambda))))
  433. ;;----------------------------------------------------------------
  434. (define-cps-converter 'values
  435. (lambda (node)
  436. (let ((args (cdr (node-form node))))
  437. (receive (call first-call last-lambda)
  438. (cps-call (get-prescheme-primop 'unspecific) 0 0 args cps)
  439. (let ((vals (vector->list (call-args call))))
  440. (map detach vals)
  441. (values vals first-call last-lambda))))))
  442. (define-tail-cps-converter 'values
  443. (lambda (node cont-var)
  444. (let ((args (cdr (node-form node))))
  445. (receive (call first-call last-lambda)
  446. (cps-call (get-primop (enum primop-enum unknown-return)) 0 1 args cps)
  447. (attach call 0 (make-reference-node cont-var))
  448. (splice!->first first-call last-lambda call)))))
  449. (define-cps-converter 'call-with-values
  450. (lambda (node)
  451. (convert-call-with-values node #f)))
  452. (define-tail-cps-converter 'call-with-values
  453. (lambda (node cont-var)
  454. (convert-call-with-values node cont-var)))
  455. ;; Consumer is known to be a lambda node.
  456. (define (convert-call-with-values node maybe-cont-var)
  457. (receive (vals first-call last-lambda)
  458. (values-cps (cadr (node-form node)))
  459. (let ((consumer (x->cps (caddr (node-form node)) #f))
  460. (call (make-call-node (get-primop (if maybe-cont-var
  461. (enum primop-enum tail-call)
  462. (enum primop-enum call)))
  463. (+ 2 (length vals))
  464. (if maybe-cont-var 0 1))))
  465. (attach-call-args call `(#f ,consumer . ,vals))
  466. (cond (maybe-cont-var
  467. (attach call 0 (make-reference-node maybe-cont-var))
  468. (splice!->first first-call last-lambda call))
  469. (else
  470. (add-continuation call first-call last-lambda (node-type node)))))))
  471. ;;----------------------------------------------------------------
  472. ;; LETRECs have been analyzed and restructured by FLATTEN, so we know that
  473. ;; the values are all lambdas.
  474. (define-cps-converter 'letrec
  475. (lambda (node)
  476. (let ((form (node-form node)))
  477. (receive (first-call last-lambda)
  478. (convert-letrec form)
  479. (receive (vals body-first-call body-last-lambda)
  480. (values-cps (caddr form))
  481. (values vals
  482. first-call
  483. (splice!->last last-lambda
  484. body-first-call
  485. body-last-lambda)))))))
  486. (define-tail-cps-converter 'letrec
  487. (lambda (node cont-var)
  488. (let ((form (node-form node)))
  489. (receive (first-call last-lambda)
  490. (convert-letrec form)
  491. (attach-body last-lambda (tail-cps (caddr form) cont-var))
  492. first-call))))
  493. (define (convert-letrec form)
  494. (let ((vars (map (lambda (l)
  495. (let ((var (make-variable (name-node->symbol (car l))
  496. (node-type (car l)))))
  497. (node-set! (car l) 'variable var)
  498. var))
  499. (cadr form)))
  500. (vals (map (lambda (l)
  501. (receive (value first-call last-lambda)
  502. (cps (cadr l))
  503. value))
  504. (cadr form)))
  505. (cont (make-lambda-node 'c 'cont '())))
  506. (let-nodes
  507. ((top (letrec1 1 l1))
  508. (l1 ((x #f) . vars) call2)
  509. (call2 (letrec2 1 cont (* x) . vals)))
  510. (do ((names (cadr form) (cdr names))
  511. (index 2 (+ index 1)))
  512. ((null? names))
  513. (maybe-add-argument-name! call2 index (node-form (caar names))))
  514. (values top cont))))
  515. ;;----------------------------------------------------------------
  516. ;; Utilities.
  517. ;; Stuff is a list of alternating call and lambda nodes, with possible #Fs.
  518. ;; This joins the nodes together by making the calls be the bodies of the
  519. ;; lambdas (the call->lambda links are already done). The last node is
  520. ;; returned.
  521. (define (splice! stuff)
  522. (let loop ((stuff stuff) (first #f) (last #f))
  523. (if (null? stuff)
  524. (values first last)
  525. (receive (first last)
  526. (let ((next (car stuff)))
  527. (cond ((not next)
  528. (values first last))
  529. ((not first)
  530. (values next next))
  531. (else
  532. (if (and (cps/lambda-node? last)
  533. (cps/call-node? next))
  534. (attach-body last next))
  535. (values first next))))
  536. (loop (cdr stuff) first last)))))
  537. (define (splice!->first . stuff)
  538. (receive (first last)
  539. (splice! stuff)
  540. first))
  541. (define (splice!->last . stuff)
  542. (receive (first last)
  543. (splice! stuff)
  544. last))
  545. ;; Adding names to lambda nodes for debugging help.
  546. (define (maybe-add-argument-name! call index name)
  547. (maybe-add-name! (call-arg call index) name))
  548. (define (maybe-add-name! value name)
  549. (if (cps/lambda-node? value)
  550. (cps/set-lambda-name! value (schemify name))))
  551. ;; Getting symbols for use as variable names.
  552. (define (name-node->symbol node)
  553. (let loop ((name (node-form node)))
  554. (if (generated? name)
  555. (loop (generated-name name))
  556. name)))