Fix #597
authorRichard van Velzen <rvanvelzen1@gmail.com>
Wed, 31 Dec 2014 11:23:00 +0000 (12:23 +0100)
committerRichard van Velzen <rvanvelzen1@gmail.com>
Wed, 31 Dec 2014 11:23:00 +0000 (12:23 +0100)
NaN and Infinity were replaced in the output generation, instead of
during compression. This could lead to results where `1/0` was inserted
without parens leading to invalid output.

The nodes are replaced in the compression step now, and the output
generation returns their regular names. This should not be a problem,
since they're already only constructed from the original name.

lib/compress.js
lib/output.js
test/compress/issue-597.js [new file with mode: 0644]

index e63ce14..f803072 100644 (file)
@@ -2203,14 +2203,30 @@ merge(Compressor.prototype, {
               case "undefined":
                 return make_node(AST_Undefined, self);
               case "NaN":
-                return make_node(AST_NaN, self);
+                return make_node(AST_NaN, self).transform(compressor);
               case "Infinity":
-                return make_node(AST_Infinity, self);
+                return make_node(AST_Infinity, self).transform(compressor);
             }
         }
         return self;
     });
 
+    OPT(AST_Infinity, function (self, compressor) {
+        return make_node(AST_Binary, self, {
+            operator : '/',
+            left     : make_node(AST_Number, null, {value: 1}),
+            right    : make_node(AST_Number, null, {value: 0})
+        });
+    });
+
+    OPT(AST_NaN, function (self, compressor) {
+        return make_node(AST_Binary, self, {
+            operator : '/',
+            left     : make_node(AST_Number, null, {value: 0}),
+            right    : make_node(AST_Number, null, {value: 0})
+        });
+    });
+
     OPT(AST_Undefined, function(self, compressor){
         if (compressor.option("unsafe")) {
             var scope = compressor.find_parent(AST_Scope);
index 7fe61af..5a8f603 100644 (file)
@@ -549,12 +549,6 @@ function OutputStream(options) {
             return true;
     });
 
-    PARENS(AST_NaN, function(output){
-        var p = output.parent();
-        if (p instanceof AST_PropAccess && p.expression === this)
-            return true;
-    });
-
     PARENS([ AST_Assign, AST_Conditional ], function (output){
         var p = output.parent();
         // !(a = false) → true
@@ -1109,10 +1103,10 @@ function OutputStream(options) {
     });
     DEFPRINT(AST_Hole, noop);
     DEFPRINT(AST_Infinity, function(self, output){
-        output.print("1/0");
+        output.print("Infinity");
     });
     DEFPRINT(AST_NaN, function(self, output){
-        output.print("0/0");
+        output.print("NaN");
     });
     DEFPRINT(AST_This, function(self, output){
         output.print("this");
diff --git a/test/compress/issue-597.js b/test/compress/issue-597.js
new file mode 100644 (file)
index 0000000..3c651a4
--- /dev/null
@@ -0,0 +1,25 @@
+NaN_and_Infinity_must_have_parens: {
+    options = {};
+    input: {
+        Infinity.toString();
+        NaN.toString();
+    }
+    expect: {
+        (1/0).toString();
+        (0/0).toString();
+    }
+}
+
+NaN_and_Infinity_should_not_be_replaced_when_they_are_redefined: {
+    options = {};
+    input: {
+        var Infinity, NaN;
+        Infinity.toString();
+        NaN.toString();
+    }
+    expect: {
+        var Infinity, NaN;
+        Infinity.toString();
+        NaN.toString();
+    }
+}