Optimization: remove unused blocks
[jscl.git] / ecmalisp.lisp
index 909d111..16f557d 100644 (file)
@@ -1352,7 +1352,9 @@ function mv(){
      (ls-compile ,form)))
 
 (define-compilation progn (&rest body)
-  (js!selfcall (ls-compile-block body t)))
+  (if (null (cdr body))
+      (ls-compile (car body) *multiple-value-p*)
+      (js!selfcall (ls-compile-block body t))))
 
 (defun special-variable-p (x)
   (and (claimp x 'variable 'special) t))
@@ -1456,31 +1458,36 @@ function mv(){
 (defvar *block-counter* 0)
 
 (define-compilation block (name &rest body)
-  (let ((tr (integer-to-string (incf *block-counter*))))
-    (let ((b (make-binding name 'block tr)))
-      (js!selfcall
-        "try {" *newline*
-        (let ((*environment* (extend-lexenv (list b) *environment* 'block)))
-          (indent "return " (ls-compile `(progn ,@body) *multiple-value-p*) ";" *newline*))
-        "}" *newline*
-        "catch (cf){" *newline*
-        "    if (cf.type == 'block' && cf.id == " tr ")" *newline*
-        "        return cf.value;" *newline*
-        "    else" *newline*
-        "        throw cf;" *newline*
-        "}" *newline*))))
+  (let* ((tr (integer-to-string (incf *block-counter*)))
+         (b (make-binding name 'block tr))
+         (*environment* (extend-lexenv (list b) *environment* 'block))
+         (cbody (ls-compile-block body t)))
+    (if (member 'used (binding-declarations b))
+        (js!selfcall
+          "try {" *newline*
+          (indent cbody)
+          "}" *newline*
+          "catch (cf){" *newline*
+          "    if (cf.type == 'block' && cf.id == " tr ")" *newline*
+          "        return cf.value;" *newline*
+          "    else" *newline*
+          "        throw cf;" *newline*
+          "}" *newline*)
+        (js!selfcall
+          (indent cbody)))))
 
 (define-compilation return-from (name &optional value)
   (let ((b (lookup-in-lexenv name *environment* 'block)))
-    (if b
-        (js!selfcall
-          "throw ({"
-          "type: 'block', "
-          "id: " (binding-value b) ", "
-          "value: " (ls-compile value) ", "
-          "message: 'Return from unknown block " (symbol-name name) ".'"
-          "})")
-        (error (concat "Unknown block `" (symbol-name name) "'.")))))
+    (when (null b)
+      (error (concat "Unknown block `" (symbol-name name) "'.")))
+    (push-binding-declaration 'used b)
+    (js!selfcall
+      "throw ({"
+      "type: 'block', "
+      "id: " (binding-value b) ", "
+      "value: " (ls-compile value) ", "
+      "message: 'Return from unknown block " (symbol-name name) ".'"
+      "})")))
 
 (define-compilation catch (id &rest body)
   (js!selfcall
@@ -1588,9 +1595,11 @@ function mv(){
     "return ret;" *newline*))
 
 (define-compilation multiple-value-call (func-form &rest forms)
-  (let ((func (ls-compile func-form)))
+  (js!selfcall
+    "var func = " (ls-compile func-form) ";" *newline*
+    "var args = [" (if *multiple-value-p* "values" "pv") "];" *newline*
+    "return "
     (js!selfcall
-      "var args = [values];" *newline*
       "var values = mv;" *newline*
       "var vs;" *newline*
       (mapconcat (lambda (form)
@@ -1600,7 +1609,13 @@ function mv(){
                            "else" *newline*
                            (indent "args.push(vs);" *newline*)))
                  forms)
-      "return (" func ").apply(window, args);" *newline*)))
+      "return func.apply(window, args);" *newline*) ";" *newline*))
+
+(define-compilation multiple-value-prog1 (first-form &rest forms)
+  (js!selfcall
+    "var args = " (ls-compile first-form *multiple-value-p*) ";" *newline*
+    (ls-compile-block forms)
+    "return args;" *newline*))
 
 
 
@@ -2018,7 +2033,7 @@ function mv(){
 (defun ls-compile-block (sexps &optional return-last-p)
   (if return-last-p
       (concat (ls-compile-block (butlast sexps))
-              "return "(ls-compile (car (last sexps)) *multiple-value-p*) ";")
+              "return " (ls-compile (car (last sexps)) *multiple-value-p*) ";")
       (join-trailing
        (remove-if #'null-or-empty-p (mapcar #'ls-compile sexps))
        (concat ";" *newline*))))
@@ -2086,28 +2101,25 @@ function mv(){
     (js-eval (ls-compile-toplevel x t)))
 
   (export '(&rest &optional &body * *gensym-counter* *package* + - / 1+ 1- < <= =
-            = > >= and append apply aref arrayp aset assoc atom block
-            boundp boundp butlast caar cadddr caddr cadr car car case
-            catch cdar cdddr cddr cdr cdr char char-code char=
-            code-char cond cons consp copy-list decf declaim
-            defparameter defun defmacro defvar digit-char-p
-            disassemble documentation dolist dotimes ecase eq eql
-            equal error eval every export fdefinition find-package
-            find-symbol first fourth fset funcall function functionp
-            gensym get-universal-time go identity if in-package incf
-            integerp integerp intern keywordp lambda last length let
-            let* list-all-packages list listp make-array make-package
+            = > >= and append apply aref arrayp aset assoc atom block boundp
+            boundp butlast caar cadddr caddr cadr car car case catch cdar cdddr
+            cddr cdr cdr char char-code char= code-char cond cons consp copy-list
+            decf declaim defparameter defun defmacro defvar digit-char-p
+            disassemble documentation dolist dotimes ecase eq eql equal error eval
+            every export fdefinition find-package find-symbol first fourth fset
+            funcall function functionp gensym get-universal-time go identity if
+            in-package incf integerp integerp intern keywordp lambda last length
+            let let* list-all-packages list listp make-array make-package
             make-symbol mapcar member minusp mod multiple-value-bind
-            multiple-value-call multiple-value-list nil not nth nthcdr
-            null numberp or package-name package-use-list packagep
-            plusp prin1-to-string print proclaim prog1 prog2 progn
-            psetq push quote remove remove-if remove-if-not return
-            return-from revappend reverse second set setq some
-            string-upcase string string= stringp subseq
-            symbol-function symbol-name symbol-package symbol-plist
+            multiple-value-call multiple-value-list multiple-value-prog1 nil not
+            nth nthcdr null numberp or package-name package-use-list packagep
+            plusp prin1-to-string print proclaim prog1 prog2 progn psetq push
+            quote remove remove-if remove-if-not return return-from revappend
+            reverse second set setq some string-upcase string string= stringp
+            subseq symbol-function symbol-name symbol-package symbol-plist
             symbol-value symbolp t tagbody third throw truncate unless
-            unwind-protect values values-list variable warn when
-            write-line write-string zerop))
+            unwind-protect values values-list variable warn when write-line
+            write-string zerop))
 
   (setq *package* *user-package*)