compile-tree-il.scm 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562
  1. ;;; ECMAScript for Guile
  2. ;; Copyright (C) 2009, 2011 Free Software Foundation, Inc.
  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. ;;; Code:
  17. (define-module (language ecmascript compile-tree-il)
  18. #:use-module (language tree-il)
  19. #:use-module (ice-9 receive)
  20. #:use-module (system base pmatch)
  21. #:use-module (srfi srfi-1)
  22. #:export (compile-tree-il))
  23. (define-syntax ->
  24. (syntax-rules ()
  25. ((_ (type arg ...))
  26. `(type ,arg ...))))
  27. (define-syntax @implv
  28. (syntax-rules ()
  29. ((_ sym)
  30. (-> (@ '(language ecmascript impl) 'sym)))))
  31. (define-syntax @impl
  32. (syntax-rules ()
  33. ((_ sym arg ...)
  34. (-> (apply (@implv sym) arg ...)))))
  35. (define (empty-lexical-environment)
  36. '())
  37. (define (econs name gensym env)
  38. (acons name (-> (lexical name gensym)) env))
  39. (define (lookup name env)
  40. (or (assq-ref env name)
  41. (-> (toplevel name))))
  42. (define (compile-tree-il exp env opts)
  43. (values
  44. (parse-tree-il
  45. (-> (begin (@impl js-init)
  46. (comp exp (empty-lexical-environment)))))
  47. env
  48. env))
  49. (define (location x)
  50. (and (pair? x)
  51. (let ((props (source-properties x)))
  52. (and (not (null? props))
  53. props))))
  54. ;; for emacs:
  55. ;; (put 'pmatch/source 'scheme-indent-function 1)
  56. (define-syntax pmatch/source
  57. (syntax-rules ()
  58. ((_ x clause ...)
  59. (let ((x x))
  60. (let ((res (pmatch x
  61. clause ...)))
  62. (let ((loc (location x)))
  63. (if loc
  64. (set-source-properties! res (location x))))
  65. res)))))
  66. (define (comp x e)
  67. (let ((l (location x)))
  68. (define (let1 what proc)
  69. (let ((sym (gensym)))
  70. (-> (let (list sym) (list sym) (list what)
  71. (proc sym)))))
  72. (define (begin1 what proc)
  73. (let1 what (lambda (v)
  74. (-> (begin (proc v)
  75. (-> (lexical v v)))))))
  76. (pmatch/source x
  77. (null
  78. ;; FIXME, null doesn't have much relation to EOL...
  79. (-> (const '())))
  80. (true
  81. (-> (const #t)))
  82. (false
  83. (-> (const #f)))
  84. ((number ,num)
  85. (-> (const num)))
  86. ((string ,str)
  87. (-> (const str)))
  88. (this
  89. (@impl get-this))
  90. ((+ ,a)
  91. (-> (apply (-> (primitive '+))
  92. (@impl ->number (comp a e))
  93. (-> (const 0)))))
  94. ((- ,a)
  95. (-> (apply (-> (primitive '-)) (-> (const 0)) (comp a e))))
  96. ((~ ,a)
  97. (@impl bitwise-not (comp a e)))
  98. ((! ,a)
  99. (@impl logical-not (comp a e)))
  100. ((+ ,a ,b)
  101. (-> (apply (-> (primitive '+)) (comp a e) (comp b e))))
  102. ((- ,a ,b)
  103. (-> (apply (-> (primitive '-)) (comp a e) (comp b e))))
  104. ((/ ,a ,b)
  105. (-> (apply (-> (primitive '/)) (comp a e) (comp b e))))
  106. ((* ,a ,b)
  107. (-> (apply (-> (primitive '*)) (comp a e) (comp b e))))
  108. ((% ,a ,b)
  109. (@impl mod (comp a e) (comp b e)))
  110. ((<< ,a ,b)
  111. (@impl shift (comp a e) (comp b e)))
  112. ((>> ,a ,b)
  113. (@impl shift (comp a e) (comp `(- ,b) e)))
  114. ((< ,a ,b)
  115. (-> (apply (-> (primitive '<)) (comp a e) (comp b e))))
  116. ((<= ,a ,b)
  117. (-> (apply (-> (primitive '<=)) (comp a e) (comp b e))))
  118. ((> ,a ,b)
  119. (-> (apply (-> (primitive '>)) (comp a e) (comp b e))))
  120. ((>= ,a ,b)
  121. (-> (apply (-> (primitive '>=)) (comp a e) (comp b e))))
  122. ((in ,a ,b)
  123. (@impl has-property? (comp a e) (comp b e)))
  124. ((== ,a ,b)
  125. (-> (apply (-> (primitive 'equal?)) (comp a e) (comp b e))))
  126. ((!= ,a ,b)
  127. (-> (apply (-> (primitive 'not))
  128. (-> (apply (-> (primitive 'equal?))
  129. (comp a e) (comp b e))))))
  130. ((=== ,a ,b)
  131. (-> (apply (-> (primitive 'eqv?)) (comp a e) (comp b e))))
  132. ((!== ,a ,b)
  133. (-> (apply (-> (primitive 'not))
  134. (-> (apply (-> (primitive 'eqv?))
  135. (comp a e) (comp b e))))))
  136. ((& ,a ,b)
  137. (@impl band (comp a e) (comp b e)))
  138. ((^ ,a ,b)
  139. (@impl bxor (comp a e) (comp b e)))
  140. ((bor ,a ,b)
  141. (@impl bior (comp a e) (comp b e)))
  142. ((and ,a ,b)
  143. (-> (if (@impl ->boolean (comp a e))
  144. (comp b e)
  145. (-> (const #f)))))
  146. ((or ,a ,b)
  147. (let1 (comp a e)
  148. (lambda (v)
  149. (-> (if (@impl ->boolean (-> (lexical v v)))
  150. (-> (lexical v v))
  151. (comp b e))))))
  152. ((if ,test ,then ,else)
  153. (-> (if (@impl ->boolean (comp test e))
  154. (comp then e)
  155. (comp else e))))
  156. ((if ,test ,then)
  157. (-> (if (@impl ->boolean (comp test e))
  158. (comp then e)
  159. (@implv *undefined*))))
  160. ((postinc (ref ,foo))
  161. (begin1 (comp `(ref ,foo) e)
  162. (lambda (var)
  163. (-> (set! (lookup foo e)
  164. (-> (apply (-> (primitive '+))
  165. (-> (lexical var var))
  166. (-> (const 1)))))))))
  167. ((postinc (pref ,obj ,prop))
  168. (let1 (comp obj e)
  169. (lambda (objvar)
  170. (begin1 (@impl pget
  171. (-> (lexical objvar objvar))
  172. (-> (const prop)))
  173. (lambda (tmpvar)
  174. (@impl pput
  175. (-> (lexical objvar objvar))
  176. (-> (const prop))
  177. (-> (apply (-> (primitive '+))
  178. (-> (lexical tmpvar tmpvar))
  179. (-> (const 1))))))))))
  180. ((postinc (aref ,obj ,prop))
  181. (let1 (comp obj e)
  182. (lambda (objvar)
  183. (let1 (comp prop e)
  184. (lambda (propvar)
  185. (begin1 (@impl pget
  186. (-> (lexical objvar objvar))
  187. (-> (lexical propvar propvar)))
  188. (lambda (tmpvar)
  189. (@impl pput
  190. (-> (lexical objvar objvar))
  191. (-> (lexical propvar propvar))
  192. (-> (apply (-> (primitive '+))
  193. (-> (lexical tmpvar tmpvar))
  194. (-> (const 1))))))))))))
  195. ((postdec (ref ,foo))
  196. (begin1 (comp `(ref ,foo) e)
  197. (lambda (var)
  198. (-> (set (lookup foo e)
  199. (-> (apply (-> (primitive '-))
  200. (-> (lexical var var))
  201. (-> (const 1)))))))))
  202. ((postdec (pref ,obj ,prop))
  203. (let1 (comp obj e)
  204. (lambda (objvar)
  205. (begin1 (@impl pget
  206. (-> (lexical objvar objvar))
  207. (-> (const prop)))
  208. (lambda (tmpvar)
  209. (@impl pput
  210. (-> (lexical objvar objvar))
  211. (-> (const prop))
  212. (-> (apply (-> (primitive '-))
  213. (-> (lexical tmpvar tmpvar))
  214. (-> (const 1))))))))))
  215. ((postdec (aref ,obj ,prop))
  216. (let1 (comp obj e)
  217. (lambda (objvar)
  218. (let1 (comp prop e)
  219. (lambda (propvar)
  220. (begin1 (@impl pget
  221. (-> (lexical objvar objvar))
  222. (-> (lexical propvar propvar)))
  223. (lambda (tmpvar)
  224. (@impl pput
  225. (-> (lexical objvar objvar))
  226. (-> (lexical propvar propvar))
  227. (-> (inline
  228. '- (-> (lexical tmpvar tmpvar))
  229. (-> (const 1))))))))))))
  230. ((preinc (ref ,foo))
  231. (let ((v (lookup foo e)))
  232. (-> (begin
  233. (-> (set! v
  234. (-> (apply (-> (primitive '+))
  235. v
  236. (-> (const 1))))))
  237. v))))
  238. ((preinc (pref ,obj ,prop))
  239. (let1 (comp obj e)
  240. (lambda (objvar)
  241. (begin1 (-> (apply (-> (primitive '+))
  242. (@impl pget
  243. (-> (lexical objvar objvar))
  244. (-> (const prop)))
  245. (-> (const 1))))
  246. (lambda (tmpvar)
  247. (@impl pput (-> (lexical objvar objvar))
  248. (-> (const prop))
  249. (-> (lexical tmpvar tmpvar))))))))
  250. ((preinc (aref ,obj ,prop))
  251. (let1 (comp obj e)
  252. (lambda (objvar)
  253. (let1 (comp prop e)
  254. (lambda (propvar)
  255. (begin1 (-> (apply (-> (primitive '+))
  256. (@impl pget
  257. (-> (lexical objvar objvar))
  258. (-> (lexical propvar propvar)))
  259. (-> (const 1))))
  260. (lambda (tmpvar)
  261. (@impl pput
  262. (-> (lexical objvar objvar))
  263. (-> (lexical propvar propvar))
  264. (-> (lexical tmpvar tmpvar))))))))))
  265. ((predec (ref ,foo))
  266. (let ((v (lookup foo e)))
  267. (-> (begin
  268. (-> (set! v
  269. (-> (apply (-> (primitive '-))
  270. v
  271. (-> (const 1))))))
  272. v))))
  273. ((predec (pref ,obj ,prop))
  274. (let1 (comp obj e)
  275. (lambda (objvar)
  276. (begin1 (-> (apply (-> (primitive '-))
  277. (@impl pget
  278. (-> (lexical objvar objvar))
  279. (-> (const prop)))
  280. (-> (const 1))))
  281. (lambda (tmpvar)
  282. (@impl pput
  283. (-> (lexical objvar objvar))
  284. (-> (const prop))
  285. (-> (lexical tmpvar tmpvar))))))))
  286. ((predec (aref ,obj ,prop))
  287. (let1 (comp obj e)
  288. (lambda (objvar)
  289. (let1 (comp prop e)
  290. (lambda (propvar)
  291. (begin1 (-> (apply (-> (primitive '-))
  292. (@impl pget
  293. (-> (lexical objvar objvar))
  294. (-> (lexical propvar propvar)))
  295. (-> (const 1))))
  296. (lambda (tmpvar)
  297. (@impl pput
  298. (-> (lexical objvar objvar))
  299. (-> (lexical propvar propvar))
  300. (-> (lexical tmpvar tmpvar))))))))))
  301. ((ref ,id)
  302. (lookup id e))
  303. ((var . ,forms)
  304. `(begin
  305. ,@(map (lambda (form)
  306. (pmatch form
  307. ((,x ,y)
  308. (-> (define x (comp y e))))
  309. ((,x)
  310. (-> (define x (@implv *undefined*))))
  311. (else (error "bad var form" form))))
  312. forms)))
  313. ((begin)
  314. (-> (void)))
  315. ((begin ,form)
  316. (comp form e))
  317. ((begin . ,forms)
  318. `(begin ,@(map (lambda (x) (comp x e)) forms)))
  319. ((lambda ,formals ,body)
  320. (let ((syms (map (lambda (x)
  321. (gensym (string-append (symbol->string x) " ")))
  322. formals)))
  323. `(lambda ()
  324. (lambda-case
  325. ((() ,formals #f #f ,(map (lambda (x) (@implv *undefined*)) formals) ,syms)
  326. ,(comp-body e body formals syms))))))
  327. ((call/this ,obj ,prop . ,args)
  328. (@impl call/this*
  329. obj
  330. (-> (lambda '()
  331. `(lambda-case
  332. ((() #f #f #f () ())
  333. (apply ,(@impl pget obj prop) ,@args)))))))
  334. ((call (pref ,obj ,prop) ,args)
  335. (comp `(call/this ,(comp obj e)
  336. ,(-> (const prop))
  337. ,@(map (lambda (x) (comp x e)) args))
  338. e))
  339. ((call (aref ,obj ,prop) ,args)
  340. (comp `(call/this ,(comp obj e)
  341. ,(comp prop e)
  342. ,@(map (lambda (x) (comp x e)) args))
  343. e))
  344. ((call ,proc ,args)
  345. `(apply ,(comp proc e)
  346. ,@(map (lambda (x) (comp x e)) args)))
  347. ((return ,expr)
  348. (-> (apply (-> (primitive 'return))
  349. (comp expr e))))
  350. ((array . ,args)
  351. `(apply ,(@implv new-array)
  352. ,@(map (lambda (x) (comp x e)) args)))
  353. ((object . ,args)
  354. `(apply ,(@implv new-object)
  355. ,@(map (lambda (x)
  356. (pmatch x
  357. ((,prop ,val)
  358. (-> (apply (-> (primitive 'cons))
  359. (-> (const prop))
  360. (comp val e))))
  361. (else
  362. (error "bad prop-val pair" x))))
  363. args)))
  364. ((pref ,obj ,prop)
  365. (@impl pget
  366. (comp obj e)
  367. (-> (const prop))))
  368. ((aref ,obj ,index)
  369. (@impl pget
  370. (comp obj e)
  371. (comp index e)))
  372. ((= (ref ,name) ,val)
  373. (let ((v (lookup name e)))
  374. (-> (begin
  375. (-> (set! v (comp val e)))
  376. v))))
  377. ((= (pref ,obj ,prop) ,val)
  378. (@impl pput
  379. (comp obj e)
  380. (-> (const prop))
  381. (comp val e)))
  382. ((= (aref ,obj ,prop) ,val)
  383. (@impl pput
  384. (comp obj e)
  385. (comp prop e)
  386. (comp val e)))
  387. ((+= ,what ,val)
  388. (comp `(= ,what (+ ,what ,val)) e))
  389. ((-= ,what ,val)
  390. (comp `(= ,what (- ,what ,val)) e))
  391. ((/= ,what ,val)
  392. (comp `(= ,what (/ ,what ,val)) e))
  393. ((*= ,what ,val)
  394. (comp `(= ,what (* ,what ,val)) e))
  395. ((%= ,what ,val)
  396. (comp `(= ,what (% ,what ,val)) e))
  397. ((>>= ,what ,val)
  398. (comp `(= ,what (>> ,what ,val)) e))
  399. ((<<= ,what ,val)
  400. (comp `(= ,what (<< ,what ,val)) e))
  401. ((>>>= ,what ,val)
  402. (comp `(= ,what (>>> ,what ,val)) e))
  403. ((&= ,what ,val)
  404. (comp `(= ,what (& ,what ,val)) e))
  405. ((bor= ,what ,val)
  406. (comp `(= ,what (bor ,what ,val)) e))
  407. ((^= ,what ,val)
  408. (comp `(= ,what (^ ,what ,val)) e))
  409. ((new ,what ,args)
  410. (@impl new
  411. (map (lambda (x) (comp x e))
  412. (cons what args))))
  413. ((delete (pref ,obj ,prop))
  414. (@impl pdel
  415. (comp obj e)
  416. (-> (const prop))))
  417. ((delete (aref ,obj ,prop))
  418. (@impl pdel
  419. (comp obj e)
  420. (comp prop e)))
  421. ((void ,expr)
  422. (-> (begin
  423. (comp expr e)
  424. (@implv *undefined*))))
  425. ((typeof ,expr)
  426. (@impl typeof
  427. (comp expr e)))
  428. ((do ,statement ,test)
  429. (let ((%loop (gensym "%loop "))
  430. (%continue (gensym "%continue ")))
  431. (let ((e (econs '%loop %loop (econs '%continue %continue e))))
  432. (-> (letrec '(%loop %continue) (list %loop %continue)
  433. (list (-> (lambda '()
  434. (-> (lambda-case
  435. `((() #f #f #f () ())
  436. ,(-> (begin
  437. (comp statement e)
  438. (-> (apply (-> (lexical '%continue %continue)))))))))))
  439. (-> (lambda '()
  440. (-> (lambda-case
  441. `((() #f #f #f () ())
  442. ,(-> (if (@impl ->boolean (comp test e))
  443. (-> (apply (-> (lexical '%loop %loop))))
  444. (@implv *undefined*)))))))))
  445. (-> (apply (-> (lexical '%loop %loop)))))))))
  446. ((while ,test ,statement)
  447. (let ((%continue (gensym "%continue ")))
  448. (let ((e (econs '%continue %continue e)))
  449. (-> (letrec '(%continue) (list %continue)
  450. (list (-> (lambda '()
  451. (-> (lambda-case
  452. `((() #f #f #f () ())
  453. ,(-> (if (@impl ->boolean (comp test e))
  454. (-> (begin (comp statement e)
  455. (-> (apply (-> (lexical '%continue %continue))))))
  456. (@implv *undefined*)))))))))
  457. (-> (apply (-> (lexical '%continue %continue)))))))))
  458. ((for ,init ,test ,inc ,statement)
  459. (let ((%continue (gensym "%continue ")))
  460. (let ((e (econs '%continue %continue e)))
  461. (-> (letrec '(%continue) (list %continue)
  462. (list (-> (lambda '()
  463. (-> (lambda-case
  464. `((() #f #f #f () ())
  465. ,(-> (if (if test
  466. (@impl ->boolean (comp test e))
  467. (comp 'true e))
  468. (-> (begin (comp statement e)
  469. (comp (or inc '(begin)) e)
  470. (-> (apply (-> (lexical '%continue %continue))))))
  471. (@implv *undefined*)))))))))
  472. (-> (begin (comp (or init '(begin)) e)
  473. (-> (apply (-> (lexical '%continue %continue)))))))))))
  474. ((for-in ,var ,object ,statement)
  475. (let ((%enum (gensym "%enum "))
  476. (%continue (gensym "%continue ")))
  477. (let ((e (econs '%enum %enum (econs '%continue %continue e))))
  478. (-> (letrec '(%enum %continue) (list %enum %continue)
  479. (list (@impl make-enumerator (comp object e))
  480. (-> (lambda '()
  481. (-> (lambda-case
  482. `((() #f #f #f () ())
  483. (-> (if (@impl ->boolean
  484. (@impl pget
  485. (-> (lexical '%enum %enum))
  486. (-> (const 'length))))
  487. (-> (begin
  488. (comp `(= ,var (call/this ,(-> (lexical '%enum %enum))
  489. ,(-> (const 'pop))))
  490. e)
  491. (comp statement e)
  492. (-> (apply (-> (lexical '%continue %continue))))))
  493. (@implv *undefined*)))))))))
  494. (-> (apply (-> (lexical '%continue %continue)))))))))
  495. ((block ,x)
  496. (comp x e))
  497. (else
  498. (error "compilation not yet implemented:" x)))))
  499. (define (comp-body e body formals formal-syms)
  500. (define (process)
  501. (let lp ((in body) (out '()) (rvars '()))
  502. (pmatch in
  503. (((var (,x) . ,morevars) . ,rest)
  504. (lp `((var . ,morevars) . ,rest)
  505. out
  506. (if (or (memq x rvars) (memq x formals))
  507. rvars
  508. (cons x rvars))))
  509. (((var (,x ,y) . ,morevars) . ,rest)
  510. (lp `((var . ,morevars) . ,rest)
  511. `((= (ref ,x) ,y) . ,out)
  512. (if (or (memq x rvars) (memq x formals))
  513. rvars
  514. (cons x rvars))))
  515. (((var) . ,rest)
  516. (lp rest out rvars))
  517. ((,x . ,rest) (guard (and (pair? x) (eq? (car x) 'lambda)))
  518. (lp rest
  519. (cons x out)
  520. rvars))
  521. ((,x . ,rest) (guard (pair? x))
  522. (receive (sub-out rvars)
  523. (lp x '() rvars)
  524. (lp rest
  525. (cons sub-out out)
  526. rvars)))
  527. ((,x . ,rest)
  528. (lp rest
  529. (cons x out)
  530. rvars))
  531. (()
  532. (values (reverse! out)
  533. rvars)))))
  534. (receive (out rvars)
  535. (process)
  536. (let* ((names (reverse rvars))
  537. (syms (map (lambda (x)
  538. (gensym (string-append (symbol->string x) " ")))
  539. names))
  540. (e (fold econs (fold econs e formals formal-syms) names syms)))
  541. (-> (let names syms (map (lambda (x) (@implv *undefined*)) names)
  542. (comp out e))))))