(/debug "loading compiler.lisp!")
-(define-js-macro selfcall (&body body)
- `(call (function () ,@body)))
-
-(define-js-macro bool (expr)
- `(if ,expr ,(convert t) ,(convert nil)))
-
;;; Translate the Lisp code to Javascript. It will compile the special
;;; forms. Some primitive functions are compiled as special forms
;;; too. The respective real functions are defined in the target (see
;;; the beginning of this file) as well as some primitive functions.
-(defun interleave (list element &optional after-last-p)
- (unless (null list)
- (with-collect
- (collect (car list))
- (dolist (x (cdr list))
- (collect element)
- (collect x))
- (when after-last-p
- (collect element)))))
+(define-js-macro selfcall (&body body)
+ `(call (function () ,@body)))
+
+(define-js-macro bool (expr)
+ `(if ,expr ,(convert t) ,(convert nil)))
-;;; Like CODE, but prefix each line with four spaces. Two versions
-;;; of this function are available, because the Ecmalisp version is
-;;; very slow and bootstraping was annoying.
+(define-js-macro method-call (x method &rest args)
+ `(call (get ,x ,method) ,@args))
;;; A Form can return a multiple values object calling VALUES, like
;;; values(arg1, arg2, ...). It will work in any context, as well as
(eq (binding-type b) 'variable)
(not (member 'special (binding-declarations b)))
(not (member 'constant (binding-declarations b))))
- ;; TODO: Unnecesary make-symbol when codegen migration is
- ;; finished.
`(= ,(binding-value b) ,(convert val)))
((and b (eq (binding-type b) 'macro))
(convert `(setf ,var ,val)))
(cond
((integerp sexp) sexp)
((floatp sexp) sexp)
- ((characterp sexp)
- ;; TODO: Remove selfcall after migration
- `(selfcall (return ,(string sexp))))
+ ((characterp sexp) (string sexp))
(t
(or (cdr (assoc sexp *literal-table* :test #'eql))
(let ((dumped (typecase sexp
(define-compilation %while (pred &rest body)
`(selfcall
(while (!== ,(convert pred) ,(convert nil))
- 0 ; TODO: Force
- ; braces. Unnecesary when code
- ; is gone
,(convert-block body))
(return ,(convert nil))))
(if (and (== (get cf "type") "block")
(== (get cf "id") ,idvar))
,(if *multiple-value-p*
- `(return (call (get |values| "apply") this (call |forcemv| (get cf "values"))))
+ `(return (method-call |values| "apply" this (call |forcemv| (get cf "values"))))
`(return (get cf "values")))
(throw cf))))
- ;; TODO: is selfcall necessary here?
`(selfcall ,cbody)))))
(define-compilation return-from (name &optional value)
(define-compilation catch (id &rest body)
`(selfcall
- (var (|id| ,(convert id)))
+ (var (id ,(convert id)))
(try
,(convert-block body t))
(catch (|cf|)
(if (and (== (get |cf| "type") "catch")
- (== (get |cf| "id") |id|))
+ (== (get |cf| "id") id))
,(if *multiple-value-p*
- `(return (call (get |values| "apply")
- this
- (call |forcemv| (get |cf| "values"))))
- `(return (call (get |pv| "apply")
- this
- (call |forcemv| (get |cf| "values")))))
+ `(return (method-call |values| "apply" this (call |forcemv| (get |cf| "values"))))
+ `(return (method-call |pv| "apply" this (call |forcemv| (get |cf| "values")))))
(throw |cf|)))))
(define-compilation throw (id value)
`(selfcall
(var (|values| |mv|))
(throw (object
- |type| "catch"
- |id| ,(convert id)
- |values| ,(convert value t)
- |message| "Throw uncatched."))))
+ "type" "catch"
+ "id" ,(convert id)
+ "values" ,(convert value t)
+ "message" "Throw uncatched."))))
(defun go-tag-p (x)
(or (integerp x) (symbolp x)))
(define-compilation unwind-protect (form &rest clean-up)
`(selfcall
- (var (|ret| ,(convert nil)))
+ (var (ret ,(convert nil)))
(try
- (= |ret| ,(convert form)))
+ (= ret ,(convert form)))
(finally
,(convert-block clean-up))
- (return |ret|)))
+ (return ret)))
(define-compilation multiple-value-call (func-form &rest forms)
`(selfcall
(collect `(= vs ,(convert form t)))
(collect `(if (and (=== (typeof vs) "object")
(in "multiple-value" vs))
- (= args (call (get args "concat") vs))
- (call (get args "push") vs))))))
+ (= args (method-call args "concat" vs))
+ (method-call args "push" vs))))))
(= (property args 1) (- (property args "length") 2))
- (return (call (get func "apply") |window| args))))))
+ (return (method-call func "apply" |window| args))))))
(define-compilation multiple-value-prog1 (first-form &rest forms)
`(selfcall
(var (args ,(convert first-form *multiple-value-p*)))
- ;; TODO: Interleave is temporal
(progn ,@(mapcar #'convert forms))
(return args)))
`(bool (== (typeof ,x) "number")))
(define-builtin floor (x)
- `(call (get |Math| |floor|) ,x))
+ `(method-call |Math| "floor" ,x))
(define-builtin expt (x y)
- `(call (get |Math| |pow|) ,x ,y))
+ `(method-call |Math| "pow" ,x ,y))
(define-builtin float-to-string (x)
- `(call |make_lisp_string| (call (get ,x |toString|))))
+ `(call |make_lisp_string| (method-call ,x |toString|)))
(define-builtin cons (x y)
`(object "car" ,x "cdr" ,y))
(get tmp "cdr")))))
(define-builtin rplaca (x new)
- `(= (get ,x "car") ,new))
+ `(selfcall
+ (var (tmp ,x))
+ (= (get tmp "car") ,new)
+ (return tmp)))
(define-builtin rplacd (x new)
- `(= (get ,x "cdr") ,new))
+ `(selfcall
+ (var (tmp ,x))
+ (= (get tmp "cdr") ,new)
+ (return tmp)))
(define-builtin symbolp (x)
`(bool (instanceof ,x |Symbol|)))
`(or (get ,x "plist") ,(convert nil)))
(define-builtin lambda-code (x)
- `(call |make_lisp_string| (call (get ,x "toString"))))
+ `(call |make_lisp_string| (method-call ,x "toString")))
(define-builtin eq (x y)
`(bool (=== ,x ,y)))
(mapcar #'convert args)))))
(var (tail ,(convert last)))
(while (!= tail ,(convert nil))
- (call (get args "push") (get tail "car"))
+ (method-call args "push" (get tail "car"))
(post++ (property args 1))
(= tail (get tail "cdr")))
- (return (call (get (if (=== (typeof f) "function")
- f
- (get f "fvalue"))
- "apply")
- this
- args))))))
+ (return (method-call (if (=== (typeof f) "function")
+ f
+ (get f "fvalue"))
+ "apply"
+ this
+ args))))))
(define-builtin js-eval (string)
(if *multiple-value-p*
`(selfcall
(var (v (call |globalEval| (call |xstring| ,string))))
- (return (call (get |values| "apply") this (call |forcemv| v))))
+ (return (method-call |values| "apply" this (call |forcemv| v))))
`(call |globalEval| (call |xstring| ,string))))
(define-builtin %throw (string)
`(bool (=== (typeof ,x) "function")))
(define-builtin %write-string (x)
- `(call (get |lisp| "write") ,x))
+ `(method-call |lisp| "write" ,x))
(define-builtin /debug (x)
- `(call (get |console| "log") (call |xstring| ,x)))
+ `(method-call |console| "log" (call |xstring| ,x)))
;;; Storage vectors. They are used to implement arrays and (in the
(define-builtin concatenate-storage-vector (sv1 sv2)
`(selfcall
(var (sv1 ,sv1))
- (var (r (call (get sv1 "concat") ,sv2)))
+ (var (r (method-call sv1 "concat" ,sv2)))
(= (get r "type") (get sv1 "type"))
(= (get r "stringp") (get sv1 "stringp"))
(return r)))
(define-builtin get-internal-real-time ()
- `(call (get (new (call |Date|)) "getTime")))
+ `(method-call (new (call |Date|)) "getTime"))
(define-builtin values-array (array)
(if *multiple-value-p*
- `(call (get |values| "apply") this ,array)
- `(call (get |pv| "apply") this ,array)))
+ `(method-call |values| "apply" this ,array)
+ `(method-call |pv| "apply" this ,array)))
(define-raw-builtin values (&rest args)
(if *multiple-value-p*
((and (symbolp function)
#+jscl (eq (symbol-package function) (find-package "COMMON-LISP"))
#-jscl t)
- `(call (get ,(convert `',function) "fvalue") ,@arglist))
+ `(method-call ,(convert `',function) "fvalue" ,@arglist))
#+jscl((symbolp function)
`(call ,(convert `#',function) ,@arglist))
((and (consp function) (eq (car function) 'lambda))
`(call ,(convert `#',function) ,@arglist))
((and (consp function) (eq (car function) 'oget))
- `(call ,(convert function) ,@arglist))
+ `(call |js_to_lisp|
+ (call ,(reduce (lambda (obj p)
+ `(property ,obj (call |xstring| ,p)))
+ (mapcar #'convert (cdr function)))
+ ,@(mapcar (lambda (s)
+ `(call |lisp_to_js| ,s))
+ args))))
(t
(error "Bad function descriptor")))))
(return ,(convert (car (last sexps)) *multiple-value-p*)))
`(progn ,@(mapcar #'convert sexps)))))
-(defun convert* (sexp &optional multiple-value-p)
+(defun convert (sexp &optional multiple-value-p)
(multiple-value-bind (sexp expandedp) (!macroexpand-1 sexp)
(when expandedp
- (return-from convert* (convert sexp multiple-value-p)))
+ (return-from convert (convert sexp multiple-value-p)))
;; The expression has been macroexpanded. Now compile it!
(let ((*multiple-value-p* multiple-value-p))
(cond
(t
(error "How should I compile `~S'?" sexp))))))
-(defun convert (sexp &optional multiple-value-p)
- (convert* sexp multiple-value-p))
-
(defvar *compile-print-toplevels* nil)