From: kzc Date: Sat, 15 Feb 2020 20:22:33 +0000 (-0500) Subject: improve `--reduce-test` (#3722) X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=fbfa6178a6081e03c3edcbec706b2c6e103f9ba7;p=UglifyJS.git improve `--reduce-test` (#3722) - hoist body of functions and IIFEs - simplify var declarations --- diff --git a/test/input/reduce/unsafe_math.reduced.js b/test/input/reduce/unsafe_math.reduced.js index ac2f1890..13460423 100644 --- a/test/input/reduce/unsafe_math.reduced.js +++ b/test/input/reduce/unsafe_math.reduced.js @@ -1,13 +1,10 @@ var b = 0; -function f0() { - var expr2 = (0 - 1 - .1 - .1).toString(); - for (var key2 in expr2) { - --b; - } -} +var expr2 = (0 - 1 - .1 - .1).toString(); -var a_1 = f0(); +for (var key2 in expr2) { + --b; +} console.log(b); // output: -19 diff --git a/test/reduce.js b/test/reduce.js index 20b1dd56..a5b1f512 100644 --- a/test/reduce.js +++ b/test/reduce.js @@ -61,9 +61,6 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options) var parent = tt.parent(); - // ignore call expressions - if (parent instanceof U.AST_Call && parent.expression === node) return; - // ensure that the _permute prop is a number. // can not use `node.start._permute |= 0;` as it will erase fractional part. if (typeof node.start._permute === "undefined") node.start._permute = 0; @@ -128,11 +125,43 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options) var expr = [ node.expression, node.args[0], - ][ node.start._permute++ % 2 ]; + null, // intentional + ][ ((node.start._permute += step) * steps | 0) % 3 ]; if (expr) { CHANGED = true; return expr; } + if (node.expression instanceof U.AST_Function) { + // hoist and return expressions from the IIFE function expression + var body = node.expression.body; + node.expression.body = []; + var seq = []; + body.forEach(function(node) { + var expr = expr instanceof U.AST_Exit ? node.value : node.body; + if (expr instanceof U.AST_Node && !is_statement(expr)) { + // collect expressions from each statements' body + seq.push(expr); + } + }); + CHANGED = true; + return to_sequence(seq); + } + } + else if (node instanceof U.AST_Defun) { + switch (((node.start._permute += step) * steps | 0) % 2) { + case 0: + CHANGED = true; + return List.skip; + case 1: + if (!has_exit(node)) { + // hoist function declaration body + var body = node.body; + node.body = []; + body.push(node); // retain function with empty body to be dropped later + CHANGED = true; + return List.splice(body); + } + } } else if (node instanceof U.AST_DWLoop) { var expr = [ @@ -212,6 +241,18 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options) return expr; } } + else if (node instanceof U.AST_SimpleStatement) { + if (node.body instanceof U.AST_Call && node.body.expression instanceof U.AST_Function) { + // hoist simple statement IIFE function expression body + node.start._permute++; + if (!has_exit(node.body.expression)) { + var body = node.body.expression.body; + node.body.expression.body = []; + CHANGED = true; + return List.splice(body); + } + } + } else if (node instanceof U.AST_Switch) { var expr = [ node.expression, // switch expression @@ -256,6 +297,14 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options) CHANGED = true; return node.expression; } + else if (node instanceof U.AST_Var) { + if (node.definitions.length == 1 && node.definitions[0].value) { + // first declaration value + node.start._permute++; + CHANGED = true; + return to_statement(node.definitions[0].value); + } + } else if (node instanceof U.AST_LabeledStatement) { if (node.body instanceof U.AST_Statement && !has_loopcontrol(node.body, node.body, node)) { @@ -291,7 +340,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options) } // replace this node - var newNode = new U.parse(REPLACEMENTS[node.start._permute % REPLACEMENTS.length | 0], { + var newNode = U.parse(REPLACEMENTS[node.start._permute % REPLACEMENTS.length | 0], { expression: true, }); if (is_statement(node)) { @@ -404,6 +453,21 @@ function to_comment(value) { return ("" + value).replace(/\n/g, "\n// "); } +function has_exit(fn) { + var found = false; + var tw = new U.TreeWalker(function(node) { + if (found) return found; + if (node instanceof U.AST_Exit) { + return found = true; + } + if (node instanceof U.AST_Scope && node !== fn) { + return true; // don't descend into nested functions + } + }); + fn.walk(tw); + return found; +} + function has_loopcontrol(body, loop, label) { var found = false; var tw = new U.TreeWalker(function(node) { @@ -426,6 +490,24 @@ function is_statement(node) { return node instanceof U.AST_Statement && !(node instanceof U.AST_Function); } +function merge_sequence(array, node) { + if (node instanceof U.AST_Sequence) { + array.push.apply(array, node.expressions); + } else { + array.push(node); + } + return array; +} + +function to_sequence(expressions) { + if (expressions.length == 0) return new U.AST_Number({value: 0, start: {}}); + if (expressions.length == 1) return expressions[0]; + return new U.AST_Sequence({ + expressions: expressions.reduce(merge_sequence, []), + start: {}, + }); +} + function to_statement(node) { return is_statement(node) ? node : new U.AST_SimpleStatement({ body: node,