aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Lam S.L <alexlamsl@gmail.com>2019-10-29 19:51:55 +0800
committerGitHub <noreply@github.com>2019-10-29 19:51:55 +0800
commit1d5c2becbd4e0266a702db93649dbe025056b885 (patch)
tree7951e8382bb9b18ffbe9629d09993b8f7cfcd05f
parent22a09ea7c599e2618ee933ed56ca165a3d2d663b (diff)
downloadtracifyjs-1d5c2becbd4e0266a702db93649dbe025056b885.tar.gz
tracifyjs-1d5c2becbd4e0266a702db93649dbe025056b885.zip
enhance `evaluate` (#3549)
-rw-r--r--lib/compress.js68
-rw-r--r--test/compress/evaluate.js81
2 files changed, 127 insertions, 22 deletions
diff --git a/lib/compress.js b/lib/compress.js
index d37108d1..ad47621a 100644
--- a/lib/compress.js
+++ b/lib/compress.js
@@ -3019,7 +3019,26 @@ merge(Compressor.prototype, {
});
def(AST_Call, function(compressor, cached, depth) {
var exp = this.expression;
- if (compressor.option("unsafe") && exp instanceof AST_PropAccess) {
+ if (exp instanceof AST_SymbolRef) {
+ var fn = exp.fixed_value();
+ if (!(fn instanceof AST_Lambda)) return this;
+ if (fn.name && fn.name.definition().recursive_refs > 0) return this;
+ if (fn.body.length != 1 || !fn.is_constant_expression()) return this;
+ var stat = fn.body[0];
+ if (!(stat instanceof AST_Return)) return this;
+ var args = eval_args(this.args);
+ if (!args) return this;
+ fn.argnames.forEach(function(sym, i) {
+ var value = args[i];
+ sym.definition().references.forEach(function(node) {
+ node._eval = function() {
+ return value;
+ };
+ cached.push(node);
+ });
+ });
+ return stat.value ? stat.value._eval(compressor, cached, depth) : undefined;
+ } else if (compressor.option("unsafe") && exp instanceof AST_PropAccess) {
var key = exp.property;
if (key instanceof AST_Node) {
key = key._eval(compressor, cached, depth);
@@ -3037,13 +3056,8 @@ merge(Compressor.prototype, {
var native_fn = native_fns[val.constructor.name];
if (!native_fn || !native_fn[key]) return this;
}
- var args = [];
- for (var i = 0; i < this.args.length; i++) {
- var arg = this.args[i];
- var value = arg._eval(compressor, cached, depth);
- if (arg === value) return this;
- args.push(value);
- }
+ var args = eval_args(this.args);
+ if (!args) return this;
if (key == "replace" && typeof args[1] == "function") return this;
try {
return val[key].apply(val, args);
@@ -3057,6 +3071,17 @@ merge(Compressor.prototype, {
}
}
return this;
+
+ function eval_args(args) {
+ var values = [];
+ for (var i = 0; i < args.length; i++) {
+ var arg = args[i];
+ var value = arg._eval(compressor, cached, depth);
+ if (arg === value) return;
+ values.push(value);
+ }
+ return values;
+ }
});
def(AST_New, return_this);
})(function(node, func) {
@@ -3406,19 +3431,19 @@ merge(Compressor.prototype, {
def(AST_Lambda, function(scope) {
var self = this;
var result = true;
- var inner_scopes = [];
+ var scopes = [];
self.walk(new TreeWalker(function(node, descend) {
if (!result) return true;
if (node instanceof AST_Catch) {
- inner_scopes.push(node.argname.scope);
+ scopes.push(node.argname.scope);
descend();
- inner_scopes.pop();
+ scopes.pop();
return true;
}
- if (node instanceof AST_Scope && node !== self) {
- inner_scopes.push(node);
+ if (node instanceof AST_Scope) {
+ scopes.push(node);
descend();
- inner_scopes.pop();
+ scopes.pop();
return true;
}
if (node instanceof AST_SymbolRef) {
@@ -3427,16 +3452,15 @@ merge(Compressor.prototype, {
return true;
}
var def = node.definition();
- if (!self.variables.has(def.name) && !member(def.scope, inner_scopes)) {
- if (scope) {
- var scope_def = scope.find_variable(node);
- if (def.undeclared ? !scope_def : scope_def === def) {
- result = "f";
- return true;
- }
+ if (member(def.scope, scopes)) return true;
+ if (scope) {
+ var scope_def = scope.find_variable(node);
+ if (def.undeclared ? !scope_def : scope_def === def) {
+ result = "f";
+ return true;
}
- result = false;
}
+ result = false;
return true;
}
}));
diff --git a/test/compress/evaluate.js b/test/compress/evaluate.js
index 0ac117fe..771bd4f6 100644
--- a/test/compress/evaluate.js
+++ b/test/compress/evaluate.js
@@ -1757,3 +1757,84 @@ issue_3387_2: {
}
expect_stdout: "NaN"
}
+
+simple_function_1: {
+ options = {
+ evaluate: true,
+ reduce_vars: true,
+ toplevel: true,
+ unused: true,
+ }
+ input: {
+ function sum(a, b) {
+ return a + b;
+ }
+ console.log(sum(1, 2) * sum(3, 4));
+ }
+ expect: {
+ console.log(21);
+ }
+ expect_stdout: "21"
+}
+
+simple_function_2: {
+ options = {
+ evaluate: true,
+ reduce_vars: true,
+ toplevel: true,
+ unused: true,
+ }
+ input: {
+ var sum = function(a, b) {
+ return a + b;
+ }
+ console.log(sum(1, 2) * sum(3, 4));
+ }
+ expect: {
+ console.log(21);
+ }
+ expect_stdout: "21"
+}
+
+recursive_function_1: {
+ options = {
+ evaluate: true,
+ reduce_vars: true,
+ toplevel: true,
+ unused: true,
+ }
+ input: {
+ function factorial(a) {
+ return a > 0 ? a * factorial(a - 1) : 1;
+ }
+ console.log(factorial(5));
+ }
+ expect: {
+ console.log(function factorial(a) {
+ return a > 0 ? a * factorial(a - 1) : 1;
+ }(5));
+ }
+ expect_stdout: "120"
+}
+
+recursive_function_2: {
+ options = {
+ evaluate: true,
+ reduce_vars: true,
+ toplevel: true,
+ unused: true,
+ }
+ input: {
+ var factorial = function(a) {
+ return a > 0 ? a * factorial(a - 1) : 1;
+ }
+ console.log(factorial(5));
+ }
+ expect: {
+ var factorial = function(a) {
+ return a > 0 ? a * factorial(a - 1) : 1;
+ }
+ console.log(factorial(5));
+ }
+ expect_stdout: "120"
+}