tree-il.scm 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649
  1. ;;;; Copyright (C) 2009-2014, 2017-2020 Free Software Foundation, Inc.
  2. ;;;;
  3. ;;;; This library is free software; you can redistribute it and/or
  4. ;;;; modify it under the terms of the GNU Lesser General Public
  5. ;;;; License as published by the Free Software Foundation; either
  6. ;;;; version 3 of the License, or (at your option) any later version.
  7. ;;;;
  8. ;;;; This library is distributed in the hope that it will be useful,
  9. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. ;;;; Lesser General Public License for more details.
  12. ;;;;
  13. ;;;; You should have received a copy of the GNU Lesser General Public
  14. ;;;; License along with this library; if not, write to the Free Software
  15. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  16. ;;;;
  17. (define-module (language tree-il)
  18. #:use-module (srfi srfi-1)
  19. #:use-module (srfi srfi-11)
  20. #:use-module (ice-9 match)
  21. #:use-module (system base syntax)
  22. #:export (tree-il-src
  23. <void> void? make-void void-src
  24. <const> const? make-const const-src const-exp
  25. <primitive-ref> primitive-ref? make-primitive-ref primitive-ref-src primitive-ref-name
  26. <lexical-ref> lexical-ref? make-lexical-ref lexical-ref-src lexical-ref-name lexical-ref-gensym
  27. <lexical-set> lexical-set? make-lexical-set lexical-set-src lexical-set-name lexical-set-gensym lexical-set-exp
  28. <module-ref> module-ref? make-module-ref module-ref-src module-ref-mod module-ref-name module-ref-public?
  29. <module-set> module-set? make-module-set module-set-src module-set-mod module-set-name module-set-public? module-set-exp
  30. <toplevel-ref> toplevel-ref? make-toplevel-ref toplevel-ref-src toplevel-ref-mod toplevel-ref-name
  31. <toplevel-set> toplevel-set? make-toplevel-set toplevel-set-src toplevel-set-mod toplevel-set-name toplevel-set-exp
  32. <toplevel-define> toplevel-define? make-toplevel-define toplevel-define-src toplevel-define-mod toplevel-define-name toplevel-define-exp
  33. <conditional> conditional? make-conditional conditional-src conditional-test conditional-consequent conditional-alternate
  34. <call> call? make-call call-src call-proc call-args
  35. <primcall> primcall? make-primcall primcall-src primcall-name primcall-args
  36. <seq> seq? make-seq seq-src seq-head seq-tail
  37. <lambda> lambda? make-lambda lambda-src lambda-meta lambda-body
  38. <lambda-case> lambda-case? make-lambda-case lambda-case-src
  39. ;; idea: arity
  40. lambda-case-req lambda-case-opt lambda-case-rest lambda-case-kw
  41. lambda-case-inits lambda-case-gensyms
  42. lambda-case-body lambda-case-alternate
  43. <let> let? make-let let-src let-names let-gensyms let-vals let-body
  44. <letrec> letrec? make-letrec letrec-src letrec-in-order? letrec-names letrec-gensyms letrec-vals letrec-body
  45. <fix> fix? make-fix fix-src fix-names fix-gensyms fix-vals fix-body
  46. <let-values> let-values? make-let-values let-values-src let-values-exp let-values-body
  47. <prompt> prompt? make-prompt prompt-src prompt-escape-only? prompt-tag prompt-body prompt-handler
  48. <abort> abort? make-abort abort-src abort-tag abort-args abort-tail
  49. list->seq
  50. parse-tree-il
  51. unparse-tree-il
  52. tree-il->scheme
  53. tree-il-fold
  54. make-tree-il-folder
  55. post-order
  56. pre-order
  57. with-lexicals
  58. tree-il=?
  59. tree-il-hash))
  60. (define (print-tree-il exp port)
  61. (format port "#<tree-il ~S>" (unparse-tree-il exp)))
  62. (define-syntax borrow-core-vtables
  63. (lambda (x)
  64. (syntax-case x ()
  65. ((_)
  66. (let lp ((n 0) (out '()))
  67. (if (< n (vector-length %expanded-vtables))
  68. (lp (1+ n)
  69. (let* ((vtable (vector-ref %expanded-vtables n))
  70. (stem (struct-ref vtable (+ vtable-offset-user 0)))
  71. (fields (struct-ref vtable (+ vtable-offset-user 2)))
  72. (sfields (map
  73. (lambda (f) (datum->syntax x f))
  74. fields))
  75. (type (datum->syntax x (symbol-append '< stem '>)))
  76. (ctor (datum->syntax x (symbol-append 'make- stem)))
  77. (pred (datum->syntax x (symbol-append stem '?))))
  78. (let lp ((n 0) (fields fields)
  79. (out (cons*
  80. #`(define (#,ctor #,@sfields)
  81. (make-struct/simple #,type #,@sfields))
  82. #`(define (#,pred x)
  83. (and (struct? x)
  84. (eq? (struct-vtable x) #,type)))
  85. #`(struct-set! #,type vtable-index-printer
  86. print-tree-il)
  87. #`(define #,type
  88. (vector-ref %expanded-vtables #,n))
  89. out)))
  90. (if (null? fields)
  91. out
  92. (lp (1+ n)
  93. (cdr fields)
  94. (let ((acc (datum->syntax
  95. x (symbol-append stem '- (car fields)))))
  96. (cons #`(define #,acc
  97. (make-procedure-with-setter
  98. (lambda (x) (struct-ref x #,n))
  99. (lambda (x v) (struct-set! x #,n v))))
  100. out)))))))
  101. #`(begin #,@(reverse out))))))))
  102. (borrow-core-vtables)
  103. ;; (<void>)
  104. ;; (<const> exp)
  105. ;; (<primitive-ref> name)
  106. ;; (<lexical-ref> name gensym)
  107. ;; (<lexical-set> name gensym exp)
  108. ;; (<module-ref> mod name public?)
  109. ;; (<module-set> mod name public? exp)
  110. ;; (<toplevel-ref> mod name)
  111. ;; (<toplevel-set> mod name exp)
  112. ;; (<toplevel-define> mod name exp)
  113. ;; (<conditional> test consequent alternate)
  114. ;; (<call> proc args)
  115. ;; (<primcall> name args)
  116. ;; (<seq> head tail)
  117. ;; (<lambda> meta body)
  118. ;; (<lambda-case> req opt rest kw inits gensyms body alternate)
  119. ;; (<let> names gensyms vals body)
  120. ;; (<letrec> in-order? names gensyms vals body)
  121. (define-type (<tree-il> #:common-slots (src) #:printer print-tree-il)
  122. (<fix> names gensyms vals body)
  123. (<let-values> exp body)
  124. (<prompt> escape-only? tag body handler)
  125. (<abort> tag args tail))
  126. ;; A helper.
  127. (define (list->seq loc exps)
  128. (match exps
  129. ((exp . exps)
  130. (let lp ((head exp) (tail exps))
  131. (match tail
  132. (() head)
  133. ((exp . tail) (lp (make-seq loc head exp) tail)))))))
  134. (define (location x)
  135. (and (pair? x)
  136. (let ((props (source-properties x)))
  137. (and (pair? props) props))))
  138. (define (parse-tree-il exp)
  139. (let ((loc (location exp))
  140. (retrans (lambda (x) (parse-tree-il x))))
  141. (match exp
  142. (('void)
  143. (make-void loc))
  144. (('call proc . args)
  145. (make-call loc (retrans proc) (map retrans args)))
  146. (('primcall name . args)
  147. (make-primcall loc name (map retrans args)))
  148. (('if test consequent alternate)
  149. (make-conditional loc (retrans test) (retrans consequent) (retrans alternate)))
  150. (('primitive (and name (? symbol?)))
  151. (make-primitive-ref loc name))
  152. (('lexical (and name (? symbol?)))
  153. (make-lexical-ref loc name name))
  154. (('lexical (and name (? symbol?)) (and sym (? symbol?)))
  155. (make-lexical-ref loc name sym))
  156. (('set! ('lexical (and name (? symbol?))) exp)
  157. (make-lexical-set loc name name (retrans exp)))
  158. (('set! ('lexical (and name (? symbol?)) (and sym (? symbol?))) exp)
  159. (make-lexical-set loc name sym (retrans exp)))
  160. (('@ ((and mod (? symbol?)) ...) (and name (? symbol?)))
  161. (make-module-ref loc mod name #t))
  162. (('set! ('@ ((and mod (? symbol?)) ...) (and name (? symbol?))) exp)
  163. (make-module-set loc mod name #t (retrans exp)))
  164. (('@@ ((and mod (? symbol?)) ...) (and name (? symbol?)))
  165. (make-module-ref loc mod name #f))
  166. (('set! ('@@ ((and mod (? symbol?)) ...) (and name (? symbol?))) exp)
  167. (make-module-set loc mod name #f (retrans exp)))
  168. (('toplevel (and name (? symbol?)))
  169. (make-toplevel-ref loc #f name))
  170. (('set! ('toplevel (and name (? symbol?))) exp)
  171. (make-toplevel-set loc #f name (retrans exp)))
  172. (('define (and name (? symbol?)) exp)
  173. (make-toplevel-define loc #f name (retrans exp)))
  174. (('lambda meta body)
  175. (make-lambda loc meta (retrans body)))
  176. (('lambda-case ((req opt rest kw inits gensyms) body) alternate)
  177. (make-lambda-case loc req opt rest kw
  178. (map retrans inits) gensyms
  179. (retrans body)
  180. (and=> alternate retrans)))
  181. (('lambda-case ((req opt rest kw inits gensyms) body))
  182. (make-lambda-case loc req opt rest kw
  183. (map retrans inits) gensyms
  184. (retrans body)
  185. #f))
  186. (('const exp)
  187. (make-const loc exp))
  188. (('seq head tail)
  189. (make-seq loc (retrans head) (retrans tail)))
  190. ;; Convenience.
  191. (('begin . exps)
  192. (list->seq loc (map retrans exps)))
  193. (('let names gensyms vals body)
  194. (make-let loc names gensyms (map retrans vals) (retrans body)))
  195. (('letrec names gensyms vals body)
  196. (make-letrec loc #f names gensyms (map retrans vals) (retrans body)))
  197. (('letrec* names gensyms vals body)
  198. (make-letrec loc #t names gensyms (map retrans vals) (retrans body)))
  199. (('fix names gensyms vals body)
  200. (make-fix loc names gensyms (map retrans vals) (retrans body)))
  201. (('let-values exp body)
  202. (make-let-values loc (retrans exp) (retrans body)))
  203. (('prompt escape-only? tag body handler)
  204. (make-prompt loc escape-only?
  205. (retrans tag) (retrans body) (retrans handler)))
  206. (('abort tag args tail)
  207. (make-abort loc (retrans tag) (map retrans args) (retrans tail)))
  208. (else
  209. (error "unrecognized tree-il" exp)))))
  210. (define (unparse-tree-il tree-il)
  211. (match tree-il
  212. (($ <void> src)
  213. '(void))
  214. (($ <call> src proc args)
  215. `(call ,(unparse-tree-il proc) ,@(map unparse-tree-il args)))
  216. (($ <primcall> src name args)
  217. `(primcall ,name ,@(map unparse-tree-il args)))
  218. (($ <conditional> src test consequent alternate)
  219. `(if ,(unparse-tree-il test)
  220. ,(unparse-tree-il consequent)
  221. ,(unparse-tree-il alternate)))
  222. (($ <primitive-ref> src name)
  223. `(primitive ,name))
  224. (($ <lexical-ref> src name gensym)
  225. `(lexical ,name ,gensym))
  226. (($ <lexical-set> src name gensym exp)
  227. `(set! (lexical ,name ,gensym) ,(unparse-tree-il exp)))
  228. (($ <module-ref> src mod name public?)
  229. `(,(if public? '@ '@@) ,mod ,name))
  230. (($ <module-set> src mod name public? exp)
  231. `(set! (,(if public? '@ '@@) ,mod ,name) ,(unparse-tree-il exp)))
  232. (($ <toplevel-ref> src mod name)
  233. `(toplevel ,name))
  234. (($ <toplevel-set> src mod name exp)
  235. `(set! (toplevel ,name) ,(unparse-tree-il exp)))
  236. (($ <toplevel-define> src mod name exp)
  237. `(define ,name ,(unparse-tree-il exp)))
  238. (($ <lambda> src meta body)
  239. (if body
  240. `(lambda ,meta ,(unparse-tree-il body))
  241. `(lambda ,meta (lambda-case))))
  242. (($ <lambda-case> src req opt rest kw inits gensyms body alternate)
  243. `(lambda-case ((,req ,opt ,rest ,kw ,(map unparse-tree-il inits) ,gensyms)
  244. ,(unparse-tree-il body))
  245. . ,(if alternate (list (unparse-tree-il alternate)) '())))
  246. (($ <const> src exp)
  247. `(const ,exp))
  248. (($ <seq> src head tail)
  249. `(seq ,(unparse-tree-il head) ,(unparse-tree-il tail)))
  250. (($ <let> src names gensyms vals body)
  251. `(let ,names ,gensyms ,(map unparse-tree-il vals) ,(unparse-tree-il body)))
  252. (($ <letrec> src in-order? names gensyms vals body)
  253. `(,(if in-order? 'letrec* 'letrec) ,names ,gensyms
  254. ,(map unparse-tree-il vals) ,(unparse-tree-il body)))
  255. (($ <fix> src names gensyms vals body)
  256. `(fix ,names ,gensyms ,(map unparse-tree-il vals) ,(unparse-tree-il body)))
  257. (($ <let-values> src exp body)
  258. `(let-values ,(unparse-tree-il exp) ,(unparse-tree-il body)))
  259. (($ <prompt> src escape-only? tag body handler)
  260. `(prompt ,escape-only?
  261. ,(unparse-tree-il tag)
  262. ,(unparse-tree-il body)
  263. ,(unparse-tree-il handler)))
  264. (($ <abort> src tag args tail)
  265. `(abort ,(unparse-tree-il tag) ,(map unparse-tree-il args)
  266. ,(unparse-tree-il tail)))))
  267. (define* (tree-il->scheme e #:optional (env #f) (opts '()))
  268. (values ((@ (language scheme decompile-tree-il)
  269. decompile-tree-il)
  270. e env opts)))
  271. (define-syntax-rule (make-tree-il-folder seed ...)
  272. (lambda (tree down up seed ...)
  273. (define (fold-values proc exps seed ...)
  274. (if (null? exps)
  275. (values seed ...)
  276. (let-values (((seed ...) (proc (car exps) seed ...)))
  277. (fold-values proc (cdr exps) seed ...))))
  278. (let foldts ((tree tree) (seed seed) ...)
  279. (let*-values
  280. (((seed ...) (down tree seed ...))
  281. ((seed ...)
  282. (match tree
  283. (($ <lexical-set> src name gensym exp)
  284. (foldts exp seed ...))
  285. (($ <module-set> src mod name public? exp)
  286. (foldts exp seed ...))
  287. (($ <toplevel-set> src mod name exp)
  288. (foldts exp seed ...))
  289. (($ <toplevel-define> src mod name exp)
  290. (foldts exp seed ...))
  291. (($ <conditional> src test consequent alternate)
  292. (let*-values (((seed ...) (foldts test seed ...))
  293. ((seed ...) (foldts consequent seed ...)))
  294. (foldts alternate seed ...)))
  295. (($ <call> src proc args)
  296. (let-values (((seed ...) (foldts proc seed ...)))
  297. (fold-values foldts args seed ...)))
  298. (($ <primcall> src name args)
  299. (fold-values foldts args seed ...))
  300. (($ <seq> src head tail)
  301. (let-values (((seed ...) (foldts head seed ...)))
  302. (foldts tail seed ...)))
  303. (($ <lambda> src meta body)
  304. (if body
  305. (foldts body seed ...)
  306. (values seed ...)))
  307. (($ <lambda-case> src req opt rest kw inits gensyms body
  308. alternate)
  309. (let-values (((seed ...) (fold-values foldts inits seed ...)))
  310. (if alternate
  311. (let-values (((seed ...) (foldts body seed ...)))
  312. (foldts alternate seed ...))
  313. (foldts body seed ...))))
  314. (($ <let> src names gensyms vals body)
  315. (let*-values (((seed ...) (fold-values foldts vals seed ...)))
  316. (foldts body seed ...)))
  317. (($ <letrec> src in-order? names gensyms vals body)
  318. (let*-values (((seed ...) (fold-values foldts vals seed ...)))
  319. (foldts body seed ...)))
  320. (($ <fix> src names gensyms vals body)
  321. (let*-values (((seed ...) (fold-values foldts vals seed ...)))
  322. (foldts body seed ...)))
  323. (($ <let-values> src exp body)
  324. (let*-values (((seed ...) (foldts exp seed ...)))
  325. (foldts body seed ...)))
  326. (($ <prompt> src escape-only? tag body handler)
  327. (let*-values (((seed ...) (foldts tag seed ...))
  328. ((seed ...) (foldts body seed ...)))
  329. (foldts handler seed ...)))
  330. (($ <abort> src tag args tail)
  331. (let*-values (((seed ...) (foldts tag seed ...))
  332. ((seed ...) (fold-values foldts args seed ...)))
  333. (foldts tail seed ...)))
  334. (_
  335. (values seed ...)))))
  336. (up tree seed ...)))))
  337. (define (tree-il-fold down up seed tree)
  338. "Traverse TREE, calling DOWN before visiting a sub-tree, and UP when
  339. after visiting it. Each of these procedures is invoked as `(PROC TREE
  340. SEED)', where TREE is the sub-tree considered and SEED is the current
  341. result, intially seeded with SEED.
  342. This is an implementation of `foldts' as described by Andy Wingo in
  343. ``Applications of fold to XML transformation''."
  344. ;; Multi-valued fold naturally puts the seeds at the end, whereas
  345. ;; normal fold puts the traversable at the end. Adapt to the expected
  346. ;; argument order.
  347. ((make-tree-il-folder tree) tree down up seed))
  348. (define (pre-post-order pre post x)
  349. (define (elts-eq? a b)
  350. (or (null? a)
  351. (and (eq? (car a) (car b))
  352. (elts-eq? (cdr a) (cdr b)))))
  353. (let lp ((x x))
  354. (post
  355. (let ((x (pre x)))
  356. (match x
  357. ((or ($ <void>)
  358. ($ <const>)
  359. ($ <primitive-ref>)
  360. ($ <lexical-ref>)
  361. ($ <module-ref>)
  362. ($ <toplevel-ref>))
  363. x)
  364. (($ <lexical-set> src name gensym exp)
  365. (let ((exp* (lp exp)))
  366. (if (eq? exp exp*)
  367. x
  368. (make-lexical-set src name gensym exp*))))
  369. (($ <module-set> src mod name public? exp)
  370. (let ((exp* (lp exp)))
  371. (if (eq? exp exp*)
  372. x
  373. (make-module-set src mod name public? exp*))))
  374. (($ <toplevel-set> src mod name exp)
  375. (let ((exp* (lp exp)))
  376. (if (eq? exp exp*)
  377. x
  378. (make-toplevel-set src mod name exp*))))
  379. (($ <toplevel-define> src mod name exp)
  380. (let ((exp* (lp exp)))
  381. (if (eq? exp exp*)
  382. x
  383. (make-toplevel-define src mod name exp*))))
  384. (($ <conditional> src test consequent alternate)
  385. (let ((test* (lp test))
  386. (consequent* (lp consequent))
  387. (alternate* (lp alternate)))
  388. (if (and (eq? test test*)
  389. (eq? consequent consequent*)
  390. (eq? alternate alternate*))
  391. x
  392. (make-conditional src test* consequent* alternate*))))
  393. (($ <call> src proc args)
  394. (let ((proc* (lp proc))
  395. (args* (map lp args)))
  396. (if (and (eq? proc proc*)
  397. (elts-eq? args args*))
  398. x
  399. (make-call src proc* args*))))
  400. (($ <primcall> src name args)
  401. (let ((args* (map lp args)))
  402. (if (elts-eq? args args*)
  403. x
  404. (make-primcall src name args*))))
  405. (($ <seq> src head tail)
  406. (let ((head* (lp head))
  407. (tail* (lp tail)))
  408. (if (and (eq? head head*)
  409. (eq? tail tail*))
  410. x
  411. (make-seq src head* tail*))))
  412. (($ <lambda> src meta body)
  413. (let ((body* (and body (lp body))))
  414. (if (eq? body body*)
  415. x
  416. (make-lambda src meta body*))))
  417. (($ <lambda-case> src req opt rest kw inits gensyms body alternate)
  418. (let ((inits* (map lp inits))
  419. (body* (lp body))
  420. (alternate* (and alternate (lp alternate))))
  421. (if (and (elts-eq? inits inits*)
  422. (eq? body body*)
  423. (eq? alternate alternate*))
  424. x
  425. (make-lambda-case src req opt rest kw inits* gensyms body*
  426. alternate*))))
  427. (($ <let> src names gensyms vals body)
  428. (let ((vals* (map lp vals))
  429. (body* (lp body)))
  430. (if (and (elts-eq? vals vals*)
  431. (eq? body body*))
  432. x
  433. (make-let src names gensyms vals* body*))))
  434. (($ <letrec> src in-order? names gensyms vals body)
  435. (let ((vals* (map lp vals))
  436. (body* (lp body)))
  437. (if (and (elts-eq? vals vals*)
  438. (eq? body body*))
  439. x
  440. (make-letrec src in-order? names gensyms vals* body*))))
  441. (($ <fix> src names gensyms vals body)
  442. (let ((vals* (map lp vals))
  443. (body* (lp body)))
  444. (if (and (elts-eq? vals vals*)
  445. (eq? body body*))
  446. x
  447. (make-fix src names gensyms vals* body*))))
  448. (($ <let-values> src exp body)
  449. (let ((exp* (lp exp))
  450. (body* (lp body)))
  451. (if (and (eq? exp exp*)
  452. (eq? body body*))
  453. x
  454. (make-let-values src exp* body*))))
  455. (($ <prompt> src escape-only? tag body handler)
  456. (let ((tag* (lp tag))
  457. (body* (lp body))
  458. (handler* (lp handler)))
  459. (if (and (eq? tag tag*)
  460. (eq? body body*)
  461. (eq? handler handler*))
  462. x
  463. (make-prompt src escape-only? tag* body* handler*))))
  464. (($ <abort> src tag args tail)
  465. (let ((tag* (lp tag))
  466. (args* (map lp args))
  467. (tail* (lp tail)))
  468. (if (and (eq? tag tag*)
  469. (elts-eq? args args*)
  470. (eq? tail tail*))
  471. x
  472. (make-abort src tag* args* tail*)))))))))
  473. (define (post-order f x)
  474. (pre-post-order (lambda (x) x) f x))
  475. (define (pre-order f x)
  476. (pre-post-order f (lambda (x) x) x))
  477. (define-syntax-rule (with-lexical src id . body)
  478. (let ((k (lambda (id) . body)))
  479. (match id
  480. (($ <lexical-ref>) (k id))
  481. (_
  482. (let ((tmp (gensym "v ")))
  483. (make-let src (list 'id) (list tmp) (list id)
  484. (k (make-lexical-ref src 'id tmp))))))))
  485. (define-syntax with-lexicals
  486. (syntax-rules ()
  487. ((with-lexicals src () . body) (let () . body))
  488. ((with-lexicals src (id . ids) . body)
  489. (with-lexical src id (with-lexicals src ids . body)))))
  490. ;; FIXME: We should have a better primitive than this.
  491. (define (struct-nfields x)
  492. (/ (string-length (symbol->string (struct-layout x))) 2))
  493. (define (tree-il=? a b)
  494. (cond
  495. ((struct? a)
  496. (and (struct? b)
  497. (eq? (struct-vtable a) (struct-vtable b))
  498. ;; Assume that all structs are tree-il, so we skip over the
  499. ;; src slot.
  500. (let lp ((n (1- (struct-nfields a))))
  501. (or (zero? n)
  502. (and (tree-il=? (struct-ref a n) (struct-ref b n))
  503. (lp (1- n)))))))
  504. ((pair? a)
  505. (and (pair? b)
  506. (tree-il=? (car a) (car b))
  507. (tree-il=? (cdr a) (cdr b))))
  508. (else
  509. (equal? a b))))
  510. (define-syntax hash-bits
  511. (make-variable-transformer
  512. (lambda (x)
  513. (syntax-case x ()
  514. (var
  515. (identifier? #'var)
  516. (logcount most-positive-fixnum))))))
  517. (define (tree-il-hash exp)
  518. (let ((hash-depth 4)
  519. (hash-width 3))
  520. (define (hash-exp exp depth)
  521. (define (rotate x bits)
  522. (logior (ash x (- bits))
  523. (ash (logand x (1- (ash 1 bits))) (- hash-bits bits))))
  524. (define (mix h1 h2)
  525. (logxor h1 (rotate h2 8)))
  526. (define (hash-struct s)
  527. (let ((len (struct-nfields s))
  528. (h (hashq (struct-vtable s) most-positive-fixnum)))
  529. (if (zero? depth)
  530. h
  531. (let lp ((i (max (- len hash-width) 1)) (h h))
  532. (if (< i len)
  533. (lp (1+ i) (mix (hash-exp (struct-ref s i) (1+ depth)) h))
  534. h)))))
  535. (define (hash-list l)
  536. (let ((h (hashq 'list most-positive-fixnum)))
  537. (if (zero? depth)
  538. h
  539. (let lp ((l l) (width 0) (h h))
  540. (if (< width hash-width)
  541. (lp (cdr l) (1+ width)
  542. (mix (hash-exp (car l) (1+ depth)) h))
  543. h)))))
  544. (cond
  545. ((struct? exp) (hash-struct exp))
  546. ((list? exp) (hash-list exp))
  547. (else (hash exp most-positive-fixnum))))
  548. (hash-exp exp 0)))