Rename clean_getters to pure_getters; add pure_funcs.
authorMihai Bazon <mihai@bazon.net>
Fri, 4 Oct 2013 10:17:25 +0000 (13:17 +0300)
committerMihai Bazon <mihai@bazon.net>
Fri, 4 Oct 2013 10:17:25 +0000 (13:17 +0300)
README.md
lib/compress.js

index 6980878..3a4d27a 100644 (file)
--- a/README.md
+++ b/README.md
@@ -184,38 +184,67 @@ you can pass a comma-separated list of options.  Options are in the form
 to set `true`; it's effectively a shortcut for `foo=true`).
 
 - `sequences` -- join consecutive simple statements using the comma operator
+
 - `properties` -- rewrite property access using the dot notation, for
   example `foo["bar"] → foo.bar`
+
 - `dead_code` -- remove unreachable code
+
 - `drop_debugger` -- remove `debugger;` statements
+
 - `unsafe` (default: false) -- apply "unsafe" transformations (discussion below)
+
 - `conditionals` -- apply optimizations for `if`-s and conditional
   expressions
+
 - `comparisons` -- apply certain optimizations to binary nodes, for example:
   `!(a <= b) → a > b` (only when `unsafe`), attempts to negate binary nodes,
   e.g. `a = !b && !c && !d && !e → a=!(b||c||d||e)` etc.
+
 - `evaluate` -- attempt to evaluate constant expressions
+
 - `booleans` -- various optimizations for boolean context, for example `!!a
   ? b : c → a ? b : c`
+
 - `loops` -- optimizations for `do`, `while` and `for` loops when we can
   statically determine the condition
+
 - `unused` -- drop unreferenced functions and variables
+
 - `hoist_funs` -- hoist function declarations
+
 - `hoist_vars` (default: false) -- hoist `var` declarations (this is `false`
   by default because it seems to increase the size of the output in general)
+
 - `if_return` -- optimizations for if/return and if/continue
+
 - `join_vars` -- join consecutive `var` statements
+
 - `cascade` -- small optimization for sequences, transform `x, x` into `x`
   and `x = something(), x` into `x = something()`
+
 - `warnings` -- display warnings when dropping unreachable code or unused
   declarations etc.
+
 - `negate_iife` -- negate "Immediately-Called Function Expressions"
   where the return value is discarded, to avoid the parens that the
   code generator would insert.
-- `clean_getters` -- the default is `false`.  If you pass `true` for
+
+- `pure_getters` -- the default is `false`.  If you pass `true` for
   this, UglifyJS will assume that object property access
   (e.g. `foo.bar` or `foo["bar"]`) doesn't have any side effects.
 
+- `pure_funcs` -- default `null`.  You can pass an array of names and
+  UglifyJS will assume that those functions do not produce side
+  effects.  DANGER: will not check if the name is redefined in scope.
+  An example case here, for instance `var q = Math.floor(a/b)`.  If
+  variable `q` is not used elsewhere, UglifyJS will drop it, but will
+  still keep the `Math.floor(a/b)`, not knowing what it does.  You can
+  pass `pure_funcs: [ 'Math.floor' ]` to let it know that this
+  function won't produce any side effect, in which case the whole
+  statement would get discarded.  The current implementation adds some
+  overhead (compression will be slower).
+
 ### The `unsafe` option
 
 It enables some transformations that *might* break code logic in certain
index 76cbc74..4dd273b 100644 (file)
@@ -66,7 +66,8 @@ function Compressor(options, false_by_default) {
         join_vars     : !false_by_default,
         cascade       : !false_by_default,
         side_effects  : !false_by_default,
-        clean_getters : false,
+        pure_getters  : false,
+        pure_funcs    : null,
         negate_iife   : !false_by_default,
         screw_ie8     : false,
 
@@ -809,6 +810,12 @@ merge(Compressor.prototype, {
         def(AST_Constant, function(compressor){ return false });
         def(AST_This, function(compressor){ return false });
 
+        def(AST_Call, function(compressor){
+            var pure = compressor.option("pure_funcs");
+            if (!pure) return true;
+            return pure.indexOf(this.expression.print_to_string()) < 0;
+        });
+
         def(AST_Block, function(compressor){
             for (var i = this.body.length; --i >= 0;) {
                 if (this.body[i].has_side_effects(compressor))
@@ -855,16 +862,16 @@ merge(Compressor.prototype, {
             return false;
         });
         def(AST_Dot, function(compressor){
-            if (!compressor.option("clean_getters")) return true;
+            if (!compressor.option("pure_getters")) return true;
             return this.expression.has_side_effects(compressor);
         });
         def(AST_Sub, function(compressor){
-            if (!compressor.option("clean_getters")) return true;
+            if (!compressor.option("pure_getters")) return true;
             return this.expression.has_side_effects(compressor)
                 || this.property.has_side_effects(compressor);
         });
         def(AST_PropAccess, function(compressor){
-            return !compressor.option("clean_getters");
+            return !compressor.option("pure_getters");
         });
         def(AST_Seq, function(compressor){
             return this.car.has_side_effects(compressor)