1 ;;; ECMAScript for Guile
3 ;; Copyright (C) 2009 Free Software Foundation, Inc.
5 ;; This program is free software; you can redistribute it and/or modify
6 ;; it under the terms of the GNU General Public License as published by
7 ;; the Free Software Foundation; either version 2, or (at your option)
10 ;; This program is distributed in the hope that it will be useful,
11 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ;; GNU General Public License for more details.
15 ;; You should have received a copy of the GNU General Public License
16 ;; along with this program; see the file COPYING. If not, write to
17 ;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 ;; Boston, MA 02111-1307, USA.
22 (define-module (language ecmascript compile-ghil)
23 #:use-module (language ghil)
24 #:use-module (ice-9 receive)
25 #:use-module (system base pmatch)
26 #:export (compile-ghil))
28 (define-macro (-> form)
29 `(,(symbol-append 'make-ghil- (car form)) e l . ,(cdr form)))
31 (define-macro (@implv sym)
32 `(-> (ref (ghil-var-at-module! e '(language ecmascript impl) ',sym #t))))
33 (define-macro (@impl sym args)
34 `(-> (call (@implv ,sym) ,args)))
36 (define (compile-ghil exp env opts)
38 (call-with-ghil-environment (make-ghil-toplevel-env) '()
41 (-> (lambda vars #f '()
42 (-> (begin (list (@impl js-init '())
48 (let ((props (source-properties x)))
49 (and (not (null? props))
52 ;; The purpose, you ask? To avoid non-tail recursion when expanding a
53 ;; long pmatch sequence.
54 (define-macro (ormatch x . clauses)
57 (or ,@(map (lambda (c)
58 (if (eq? (car c) 'else)
60 `(pmatch ,X ,c (else #f))))
64 (let ((l (location x)))
65 (define (let1 what proc)
66 (call-with-ghil-bindings e '(%tmp)
68 (-> (bind vars (list what)
69 (proc (car vars)))))))
70 (define (begin1 what proc)
71 (call-with-ghil-bindings e '(%tmp)
73 (-> (bind vars (list what)
74 (-> (begin (list (proc (car vars))
75 (-> (ref (car vars)))))))))))
78 ;; FIXME, null doesn't have much relation to EOL...
92 (list (@impl ->number (list (comp a e)))
95 (-> (inline 'sub (list (-> (quote 0)) (comp a e)))))
97 (@impl bitwise-not (list (comp a e))))
99 (@impl logical-not (list (comp a e))))
101 (-> (inline 'add (list (comp a e) (comp b e)))))
103 (-> (inline 'sub (list (comp a e) (comp b e)))))
105 (-> (inline 'div (list (comp a e) (comp b e)))))
107 (-> (inline 'mul (list (comp a e) (comp b e)))))
109 (@impl mod (list (comp a e) (comp b e))))
111 (@impl shift (list (comp a e) (comp b e))))
113 (@impl shift (list (comp a e) (comp `(- ,b) e))))
115 (-> (inline 'lt? (list (comp a e) (comp b e)))))
117 (-> (inline 'le? (list (comp a e) (comp b e)))))
119 (-> (inline 'gt? (list (comp a e) (comp b e)))))
121 (-> (inline 'ge? (list (comp a e) (comp b e)))))
123 (@impl has-property? (list (comp a e) (comp b e))))
125 (-> (inline 'equal? (list (comp a e) (comp b e)))))
128 (list (-> (inline 'equal?
129 (list (comp a e) (comp b e))))))))
131 (-> (inline 'eqv? (list (comp a e) (comp b e)))))
134 (list (-> (inline 'eqv?
135 (list (comp a e) (comp b e))))))))
137 (@impl band (list (comp a e) (comp b e))))
139 (@impl bxor (list (comp a e) (comp b e))))
141 (@impl bior (list (comp a e) (comp b e))))
143 (-> (and (list (comp a e) (comp b e)))))
145 (-> (or (list (comp a e) (comp b e)))))
146 ((if ,test ,then ,else)
147 (-> (if (@impl ->boolean (list (comp test e)))
150 ((if ,test ,then ,else)
151 (-> (if (@impl ->boolean (list (comp test e)))
153 (@implv *undefined*))))
154 ((postinc (ref ,foo))
155 (begin1 (comp `(ref ,foo) e)
157 (-> (set (ghil-var-for-set! e foo)
160 (-> (quote 1))))))))))
161 ((postinc (pref ,obj ,prop))
165 (list (-> (ref objvar))
169 (list (-> (ref objvar))
172 (list (-> (ref tmpvar))
173 (-> (quote 1))))))))))))
174 ((postinc (aref ,obj ,prop))
180 (list (-> (ref objvar))
184 (list (-> (ref objvar))
187 (list (-> (ref tmpvar))
188 (-> (quote 1))))))))))))))
189 ((postdec (ref ,foo))
190 (begin1 (comp `(ref ,foo) e)
192 (-> (set (ghil-var-for-set! e foo)
195 (-> (quote 1))))))))))
196 ((postdec (pref ,obj ,prop))
200 (list (-> (ref objvar))
204 (list (-> (ref objvar))
207 (list (-> (ref tmpvar))
208 (-> (quote 1))))))))))))
209 ((postdec (aref ,obj ,prop))
215 (list (-> (ref objvar))
219 (list (-> (ref objvar))
222 'sub (list (-> (ref tmpvar))
223 (-> (quote 1))))))))))))))
225 (let ((v (ghil-var-for-set! e foo)))
233 ((preinc (pref ,obj ,prop))
236 (begin1 (-> (inline 'add
238 (list (-> (ref objvar))
242 (@impl pput (list (-> (ref objvar))
244 (-> (ref tmpvar)))))))))
245 ((preinc (aref ,obj ,prop))
250 (begin1 (-> (inline 'add
252 (list (-> (ref objvar))
257 (list (-> (ref objvar))
259 (-> (ref tmpvar)))))))))))
261 (let ((v (ghil-var-for-set! e foo)))
269 ((predec (pref ,obj ,prop))
272 (begin1 (-> (inline 'sub
274 (list (-> (ref objvar))
279 (list (-> (ref objvar))
281 (-> (ref tmpvar)))))))))
282 ((predec (aref ,obj ,prop))
287 (begin1 (-> (inline 'sub
289 (list (-> (ref objvar))
294 (list (-> (ref objvar))
296 (-> (ref tmpvar)))))))))))
298 (-> (ref (ghil-var-for-ref! e id))))
304 (-> (define (ghil-var-define! (ghil-env-parent e) x)
307 (-> (define (ghil-var-define! (ghil-env-parent e) x)
308 (@implv *undefined*))))
309 (else (error "bad var form" form))))
313 (map (lambda (x) (comp x e)) forms))))
314 ((lambda ,formals ,body)
315 (call-with-ghil-environment e '(%args)
317 (-> (lambda vars #t '()
318 (comp-body env l body formals '%args))))))
319 ((call/this ,obj ,prop ,args)
322 (-> (lambda '() #f '()
323 (-> (call (@impl pget (list obj prop))
325 ((call (pref ,obj ,prop) ,args)
326 (comp `(call/this ,(comp obj e)
328 ,(map (lambda (x) (comp x e)) args))
330 ((call (aref ,obj ,prop) ,args)
331 (comp `(call/this ,(comp obj e)
333 ,(map (lambda (x) (comp x e)) args))
336 (-> (call (comp proc e)
337 (map (lambda (x) (comp x e)) args))))
340 (list (comp expr e)))))
343 (map (lambda (x) (comp x e)) args)))
350 (list (-> (quote prop))
353 (error "bad prop-val pair" x))))
363 ((= (ref ,name) ,val)
364 (let ((v (ghil-var-for-set! e name)))
366 (list (-> (set v (comp val e)))
368 ((= (pref ,obj ,prop) ,val)
373 ((= (aref ,obj ,prop) ,val)
379 (comp `(= ,what (+ ,what ,val)) e))
381 (comp `(= ,what (- ,what ,val)) e))
383 (comp `(= ,what (/ ,what ,val)) e))
385 (comp `(= ,what (* ,what ,val)) e))
387 (comp `(= ,what (% ,what ,val)) e))
389 (comp `(= ,what (>> ,what ,val)) e))
391 (comp `(= ,what (<< ,what ,val)) e))
393 (comp `(= ,what (>>> ,what ,val)) e))
395 (comp `(= ,what (& ,what ,val)) e))
397 (comp `(= ,what (bor ,what ,val)) e))
399 (comp `(= ,what (^ ,what ,val)) e))
402 (map (lambda (x) (comp x e))
404 ((delete (pref ,obj ,prop))
408 ((delete (aref ,obj ,prop))
415 (@implv *undefined*)))))
418 (list (comp expr e))))
419 ((do ,statement ,test)
420 (call-with-ghil-bindings e '(%loop %continue)
423 (list (call-with-ghil-environment e '()
425 (-> (lambda '() #f '()
427 (list (comp statement e)
429 (-> (ref (ghil-var-for-ref! e '%continue)))
431 (call-with-ghil-environment e '()
433 (-> (lambda '() #f '()
434 (-> (if (@impl ->boolean (list (comp test e)))
436 (-> (ref (ghil-var-for-ref! e '%loop)))
438 (@implv *undefined*))))))))
439 (-> (call (-> (ref (car vars))) '())))))))
440 ((while ,test ,statement)
441 (call-with-ghil-bindings e '(%continue)
446 (call-with-ghil-environment e '()
448 (-> (lambda '() #f '()
449 (-> (if (@impl ->boolean (list (comp test e)))
451 (list (comp statement e)
453 (-> (ref (ghil-var-for-ref! e '%continue)))
455 (@implv *undefined*)))))))))
456 (-> (call (-> (ref (car vars))) '()))))))))
457 ((for ,init ,test ,inc ,statement)
458 (call-with-ghil-bindings e '(%continue)
462 (comp (or init '(begin)) e)
464 (call-with-ghil-environment e '()
466 (-> (lambda '() #f '()
468 (@impl ->boolean (list (comp test e)))
471 (list (comp statement e)
472 (comp (or inc '(begin)) e)
474 (-> (ref (ghil-var-for-ref! e '%continue)))
476 (@implv *undefined*)))))))))
477 (-> (call (-> (ref (car vars))) '()))))))))
478 ((for-in ,var ,object ,statement)
479 (call-with-ghil-bindings e '(%continue %enum)
484 (call-with-ghil-environment e '()
486 (-> (lambda '() #f '()
487 (-> (if (@impl ->boolean
489 (list (-> (ref (ghil-var-for-ref! e '%enum)))
490 (-> (quote 'length))))))
493 (comp `(= ,var (call/this ,(-> (ref (ghil-var-for-ref! e '%enum)))
498 (-> (call (-> (ref (ghil-var-for-ref! e '%continue)))
500 (@implv *undefined*)))))))))
502 (@impl make-enumerator (list (comp object e)))))
503 (-> (call (-> (ref (car vars))) '()))))))))
505 (let ((var (ghil-var-for-ref! e '%continue)))
506 (if (and (ghil-env? (ghil-var-env var))
507 (eq? (ghil-var-env var) (ghil-env-parent e)))
508 (-> (inline 'return (@implv *undefined*)))
509 (error "bad break, yo"))))
511 (let ((var (ghil-var-for-ref! e '%continue)))
512 (if (and (ghil-env? (ghil-var-env var))
513 (eq? (ghil-var-env var) (ghil-env-parent e)))
514 (-> (inline 'goto/args (list (-> (ref var)))))
515 (error "bad continue, yo"))))
519 (error "compilation not yet implemented:" x)))))
521 (define (comp-body e l body formals %args)
523 (let lp ((in body) (out '()) (rvars (reverse formals)))
525 (((var (,x) . ,morevars) . ,rest)
526 (lp `((var . ,morevars) . ,rest)
528 (if (memq x rvars) rvars (cons x rvars))))
529 (((var (,x ,y) . ,morevars) . ,rest)
530 (lp `((var . ,morevars) . ,rest)
531 `((= (ref ,x) ,y) . ,out)
532 (if (memq x rvars) rvars (cons x rvars))))
535 ((,x . ,rest) (guard (and (pair? x) (eq? (car x) 'lambda)))
539 ((,x . ,rest) (guard (pair? x))
540 (receive (sub-out rvars)
550 (values (reverse! out)
554 (call-with-ghil-bindings e (reverse rvars)
556 (let ((%argv (assq-ref (ghil-env-table e) %args)))
560 (-> (if (-> (inline 'null?
561 (list (-> (ref %argv)))))
564 (list (-> (set (ghil-var-for-ref! e f)
566 (list (-> (ref %argv)))))))
569 (list (-> (ref %argv)))))))))))))
571 ;; fixme: here check for too many args
572 ,(comp out e)))))))))