diff options
author | Alex Lam S.L <alexlamsl@gmail.com> | 2020-10-11 18:18:57 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-12 01:18:57 +0800 |
commit | 55451e7b78c1765c6c3011d880c7980c10b7330f (patch) | |
tree | 8e63243cf2c73dd25867e2cb1ba3c8d7cf0ed1e9 /test | |
parent | ffcce28ce15afe9f0b8d8a4a83b901508eb866de (diff) | |
download | tracifyjs-55451e7b78c1765c6c3011d880c7980c10b7330f.tar.gz tracifyjs-55451e7b78c1765c6c3011d880c7980c10b7330f.zip |
support `const` (#4190)
Diffstat (limited to 'test')
10 files changed, 880 insertions, 101 deletions
diff --git a/test/compress/asm.js b/test/compress/asm.js index 65d20b9c..331eb426 100644 --- a/test/compress/asm.js +++ b/test/compress/asm.js @@ -76,9 +76,8 @@ asm_mixed: { start = start | 0; end = end | 0; var sum = 0.0, p = 0, q = 0; - for (p = start << 3, q = end << 3; (p | 0) < (q | 0); p = p + 8 | 0) { + for (p = start << 3, q = end << 3; (p | 0) < (q | 0); p = p + 8 | 0) sum = sum + +log(values[p >> 3]); - } return +sum; } function geometricMean(start, end) { @@ -91,7 +90,8 @@ asm_mixed: { function no_asm_GeometricMean(stdlib, foreign, buffer) { function logSum(start, end) { start |= 0, end |= 0; - for (var sum = 0, p = 0, q = 0, p = start << 3, q = end << 3; (0 | p) < (0 | q); p = p + 8 | 0) sum += +log(values[p >> 3]); + for (var sum = 0, p = 0, q = 0, p = start << 3, q = end << 3; (0 | p) < (0 | q); p = p + 8 | 0) + sum += +log(values[p >> 3]); return +sum; } function geometricMean(start, end) { diff --git a/test/compress/collapse_vars.js b/test/compress/collapse_vars.js index 24fadceb..4c3a6eda 100644 --- a/test/compress/collapse_vars.js +++ b/test/compress/collapse_vars.js @@ -346,9 +346,8 @@ collapse_vars_if: { return "x" != "Bar" + x / 4 ? g9 : g5; } function f3(x) { - if (x) { + if (x) return 1; - } return 2; } } @@ -4192,9 +4191,8 @@ issue_2436_11: { if (isCollection(arg1)) { var size = arg1, max = arg2, min = 0, res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt); return size && true === size.isMatrix ? matrix(res) : res; - } else { + } else return _randomInt(min = arg1, max = arg2); - } } } } @@ -4310,9 +4308,8 @@ issue_2497: { function sample() { if (true) for (var i = 0; i < 1; ++i) - for (var k = 0; k < 1; ++k) { + for (var k = 0; k < 1; ++k) value = (value = 1) ? value + 1 : 0; - } else for (i = 0; i < 1; ++i) for (k = 0; k < 1; ++k) diff --git a/test/compress/conditionals.js b/test/compress/conditionals.js index 5dfd17bc..8a4e3aad 100644 --- a/test/compress/conditionals.js +++ b/test/compress/conditionals.js @@ -55,14 +55,15 @@ ifs_3_should_warn: { } input: { var x, y; - if (x && !(x + "1") && y) { // 1 + // 1 + if (x && !(x + "1") && y) { var qq; foo(); } else { bar(); } - - if (x || !!(x + "1") || y) { // 2 + // 2 + if (x || !!(x + "1") || y) { foo(); } else { var jj; @@ -71,9 +72,27 @@ ifs_3_should_warn: { } expect: { var x, y; - var qq; bar(); // 1 - var jj; foo(); // 2 - } + // 1 + var qq; bar(); + // 2 + foo(); var jj; + } + expect_warnings: [ + "WARN: + in boolean context always true [test/compress/conditionals.js:3,18]", + "WARN: Boolean && always false [test/compress/conditionals.js:3,12]", + "WARN: Condition left of && always false [test/compress/conditionals.js:3,12]", + "WARN: Condition always false [test/compress/conditionals.js:3,12]", + "WARN: Dropping unreachable code [test/compress/conditionals.js:3,34]", + "WARN: Declarations in unreachable code! [test/compress/conditionals.js:4,12]", + "WARN: + in boolean context always true [test/compress/conditionals.js:10,19]", + "WARN: Boolean || always true [test/compress/conditionals.js:10,12]", + "WARN: Condition left of || always true [test/compress/conditionals.js:10,12]", + "WARN: Condition always true [test/compress/conditionals.js:10,12]", + "WARN: Dropping unreachable code [test/compress/conditionals.js:12,15]", + "WARN: Declarations in unreachable code! [test/compress/conditionals.js:13,12]", + "WARN: Dropping side-effect-free statement [test/compress/conditionals.js:3,12]", + "WARN: Dropping side-effect-free statement [test/compress/conditionals.js:10,12]", + ] } ifs_4: { diff --git a/test/compress/const.js b/test/compress/const.js new file mode 100644 index 00000000..265ca9f6 --- /dev/null +++ b/test/compress/const.js @@ -0,0 +1,667 @@ +mangle_catch_1: { + mangle = {} + input: { + try { + throw "eeeee"; + } catch (c) { + const e = typeof d; + } + console.log(typeof a, typeof b); + } + expect: { + try { + throw "eeeee"; + } catch (e) { + const o = typeof d; + } + console.log(typeof a, typeof b); + } + expect_stdout: "undefined undefined" +} + +mangle_catch_2: { + mangle = {} + input: { + console.log(function f() { + try {} catch (e) { + const f = 0; + } + }()); + } + expect: { + console.log(function o() { + try {} catch (c) { + const o = 0; + } + }()); + } + expect_stdout: "undefined" +} + +retain_block: { + options = {} + input: { + { + const a = "FAIL"; + } + var a = "PASS"; + console.log(a); + } + expect: { + { + const a = "FAIL"; + } + var a = "PASS"; + console.log(a); + } + expect_stdout: true +} + +if_dead_branch: { + options = { + conditionals: true, + dead_code: true, + evaluate: true, + } + input: { + console.log(function() { + if (0) { + const a = 0; + } + return typeof a; + }()); + } + expect: { + console.log(function() { + 0; + { + const a = void 0; + } + return typeof a; + }()); + } + expect_stdout: "undefined" +} + +merge_vars_1: { + options = { + merge_vars: true, + toplevel: true, + } + input: { + const a = console; + console.log(typeof a); + var b = typeof a; + console.log(b); + } + expect: { + const a = console; + console.log(typeof a); + var b = typeof a; + console.log(b); + } + expect_stdout: [ + "object", + "object", + ] +} + +merge_vars_2: { + options = { + inline: true, + merge_vars: true, + toplevel: true, + } + input: { + var a = 0; + (function() { + var b = function f() { + const c = a && f; + c.var += 0; + }(); + console.log(b); + })(1 && --a); + } + expect: { + var a = 0; + 1 && --a, + b = function f() { + const c = a && f; + c.var += 0; + }(), + void console.log(b); + var b; + } + expect_stdout: "undefined" +} + +merge_vars_3: { + options = { + merge_vars: true, + toplevel: true, + } + input: { + { + const a = 0; + var b = console; + console.log(typeof b); + } + var a = 1; + console.log(typeof a); + } + expect: { + { + const a = 0; + var b = console; + console.log(typeof b); + } + var a = 1; + console.log(typeof a); + } + expect_stdout: true +} + +reduce_merge_vars: { + options = { + merge_vars: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + const a = console; + console.log(typeof a); + var b = typeof a; + console.log(b); + } + expect: { + var b = console; + console.log(typeof b); + b = typeof b; + console.log(b); + } + expect_stdout: [ + "object", + "object", + ] +} + +use_before_init_1: { + options = { + reduce_vars: true, + toplevel: true, + } + input: { + a = "foo"; + const a = "bar"; + } + expect: { + a = "foo"; + const a = "bar"; + } + expect_stdout: true +} + +use_before_init_2: { + options = { + toplevel: true, + unused: true, + } + input: { + try { + a = "foo"; + } catch (e) { + console.log("PASS"); + } + const a = "bar"; + } + expect: { + try { + a = "foo"; + } catch (e) { + console.log("PASS"); + } + const a = "bar"; + } + expect_stdout: true +} + +use_before_init_3: { + options = { + side_effects: true, + } + input: { + try { + a; + } catch (e) { + console.log("PASS"); + } + const a = 42; + } + expect: { + try { + a; + } catch (e) { + console.log("PASS"); + } + const a = 42; + } + expect_stdout: true +} + +use_before_init_4: { + options = { + reduce_vars: true, + } + input: { + try { + console.log(a); + } catch (e) { + console.log("PASS"); + } + const a = "FAIL"; + } + expect: { + try { + console.log(a); + } catch (e) { + console.log("PASS"); + } + const a = "FAIL"; + } + expect_stdout: true +} + +collapse_block: { + options = { + collapse_vars: true, + pure_getters: "strict", + unsafe: true, + } + input: { + { + const a = typeof console; + console.log(a); + } + } + expect: { + { + const a = typeof console; + console.log(a); + } + } + expect_stdout: "object" +} + +reduce_block_1: { + options = { + reduce_vars: true, + } + input: { + { + const a = typeof console; + console.log(a); + } + } + expect: { + { + const a = typeof console; + console.log(a); + } + } + expect_stdout: "object" +} + +reduce_block_1_toplevel: { + options = { + reduce_vars: true, + toplevel: true, + } + input: { + { + const a = typeof console; + console.log(a); + } + } + expect: { + var a = typeof console; + console.log(a); + } + expect_stdout: "object" +} + +reduce_block_2: { + options = { + reduce_vars: true, + } + input: { + { + const a = typeof console; + console.log(a); + } + console.log(typeof a); + } + expect: { + { + const a = typeof console; + console.log(a); + } + console.log(typeof a); + } + expect_stdout: true +} + +reduce_block_2_toplevel: { + options = { + reduce_vars: true, + toplevel: true, + } + input: { + { + const a = typeof console; + console.log(a); + } + console.log(typeof a); + } + expect: { + { + const a = typeof console; + console.log(a); + } + console.log(typeof a); + } + expect_stdout: true +} + +hoist_props_1: { + options = { + hoist_props: true, + reduce_vars: true, + } + input: { + { + const o = { + p: "PASS", + }; + console.log(o.p); + } + } + expect: { + { + const o = { + p: "PASS", + }; + console.log(o.p); + } + } + expect_stdout: "PASS" +} + +hoist_props_2: { + options = { + hoist_props: true, + passes: 2, + reduce_vars: true, + toplevel: true, + } + input: { + { + const o = { + p: "PASS", + }; + console.log(o.p); + } + } + expect: { + var o_p = "PASS"; + console.log(o_p); + } + expect_stdout: "PASS" +} + +loop_block_1: { + options = { + loops: true, + } + input: { + do { + const o = console; + console.log(typeof o.log); + } while (!console); + } + expect: { + do { + const o = console; + console.log(typeof o.log); + } while (!console); + } + expect_stdout: "function" +} + +loop_block_2: { + options = { + loops: true, + } + input: { + do { + const o = {}; + (function() { + console.log(typeof this, o.p++); + })(); + } while (!console); + } + expect: { + do { + const o = {}; + (function() { + console.log(typeof this, o.p++); + })(); + } while (!console); + } + expect_stdout: "object NaN" +} + +do_continue: { + options = { + loops: true, + } + input: { + try { + do { + { + const a = 0; + continue; + } + } while ([ A ]); + } catch (e) { + console.log("PASS"); + } + } + expect: { + try { + do { + const a = 0; + continue; + } while ([ A ]); + } catch (e) { + console.log("PASS"); + } + } + expect_stdout: "PASS" +} + +catch_ie8_1: { + options = { + ie8: true, + unused: true, + } + input: { + try {} catch (a) {} + console.log(function a() { + const a = 0; + }()); + } + expect: { + try {} catch (a) {} + console.log(function a() { + }()); + } + expect_stdout: "undefined" +} + +catch_ie8_2: { + options = { + dead_code: true, + ie8: true, + toplevel: true, + unused: true, + } + input: { + try {} catch (a) { + const b = 0; + } + try {} catch (b) {} + console.log(function() { + return this; + }().b); + } + expect: { + console.log(function() { + return this; + }().b); + } + expect_stdout: "undefined" +} + +dead_block_after_return: { + options = { + dead_code: true, + } + input: { + (function(a) { + console.log(a); + return; + { + const a = 0; + } + })(); + } + expect: { + (function(a) { + console.log(a); + return; + { + const a = void 0; + } + })(); + } + expect_stdout: true +} + +const_to_var_scope_adjustment: { + options = { + conditionals: true, + inline: true, + reduce_vars: true, + toplevel: true, + unused: true, + } + input: { + for (var k in [ 42 ]) + console.log(function f() { + if (k) { + const a = 0; + } + }()); + } + expect: { + for (var k in [ 42 ]) + console.log(void (k && 0)); + } + expect_stdout: "undefined" +} + +do_if_continue_1: { + options = { + if_return: true, + } + input: { + do { + if (console) { + console.log("PASS"); + { + const a = 0; + var b; + continue; + } + } + } while (b); + } + expect: { + do { + if (!console); + else { + console.log("PASS"); + { + const a = 0; + var b; + } + } + } while (b); + } + expect_stdout: "PASS" +} + +do_if_continue_2: { + options = { + if_return: true, + } + input: { + do { + if (console) { + console.log("PASS"); + { + const a = 0; + A = 0; + continue; + } + } + } while (A); + } + expect: { + do { + if (!console); + else { + console.log("PASS"); + { + const a = 0; + A = 0; + } + } + } while (A); + } + expect_stdout: "PASS" +} + +drop_unused: { + options = { + evaluate: true, + side_effects: true, + unused: true, + } + input: { + function f(a) { + const b = a, c = b; + 0 && c.p++; + } + console.log(f()); + } + expect: { + function f(a) { + const b = a; + b; + } + console.log(f()); + } + expect_stdout: "undefined" +} diff --git a/test/compress/dead-code.js b/test/compress/dead-code.js index 89829b65..3a5a4527 100644 --- a/test/compress/dead-code.js +++ b/test/compress/dead-code.js @@ -59,6 +59,11 @@ dead_code_2_should_warn: { f(); } expect_stdout: true + expect_warnings: [ + "WARN: Dropping unreachable code [test/compress/dead-code.js:8,12]", + "WARN: Declarations in unreachable code! [test/compress/dead-code.js:10,16]", + "WARN: Dropping unreachable code [test/compress/dead-code.js:10,16]", + ] node_version: "<=4" } @@ -89,11 +94,23 @@ dead_code_constant_boolean_should_warn_more: { function bar() {} // nothing for the while // as for the for, it should keep: - var moo; var x = 10, y; + var moo; bar(); } expect_stdout: true + expect_warnings: [ + "WARN: + in boolean context always true [test/compress/dead-code.js:1,33]", + "WARN: Boolean || always true [test/compress/dead-code.js:1,16]", + "WARN: Dropping unreachable code [test/compress/dead-code.js:1,45]", + "WARN: Declarations in unreachable code! [test/compress/dead-code.js:3,12]", + "WARN: Boolean expression always true [test/compress/dead-code.js:6,47]", + "WARN: Boolean && always false [test/compress/dead-code.js:6,28]", + "WARN: Dropping unreachable code [test/compress/dead-code.js:6,63]", + "WARN: Declarations in unreachable code! [test/compress/dead-code.js:9,12]", + "WARN: Dropping side-effect-free statement [test/compress/dead-code.js:1,15]", + "WARN: Dropping side-effect-free statement [test/compress/dead-code.js:6,28]", + ] node_version: "<=4" } diff --git a/test/compress/issue-1034.js b/test/compress/issue-1034.js index 137aed8c..db488d05 100644 --- a/test/compress/issue-1034.js +++ b/test/compress/issue-1034.js @@ -90,13 +90,13 @@ non_hoisted_function_after_return_2a: { "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:7,16]", "WARN: Dropping unused variable a [test/compress/issue-1034.js:4,20]", "WARN: Dropping unused function nope [test/compress/issue-1034.js:11,21]", - "INFO: pass 0: last_count: Infinity, count: 36", + "INFO: pass 0: last_count: Infinity, count: 35", "WARN: Dropping unreachable code [test/compress/issue-1034.js:9,12]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:9,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:12,12]", "INFO: Dropping unused variable b [test/compress/issue-1034.js:7,20]", "INFO: Dropping unused variable c [test/compress/issue-1034.js:9,16]", - "INFO: pass 1: last_count: 36, count: 18", + "INFO: pass 1: last_count: 35, count: 18", ] } @@ -248,13 +248,13 @@ non_hoisted_function_after_return_2a_strict: { "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:8,16]", "WARN: Dropping unused variable a [test/compress/issue-1034.js:5,20]", "WARN: Dropping unused function nope [test/compress/issue-1034.js:12,21]", - "INFO: pass 0: last_count: Infinity, count: 47", + "INFO: pass 0: last_count: Infinity, count: 46", "WARN: Dropping unreachable code [test/compress/issue-1034.js:10,12]", "WARN: Declarations in unreachable code! [test/compress/issue-1034.js:10,12]", "WARN: Dropping unreachable code [test/compress/issue-1034.js:13,12]", "INFO: Dropping unused variable b [test/compress/issue-1034.js:8,20]", "INFO: Dropping unused variable c [test/compress/issue-1034.js:10,16]", - "INFO: pass 1: last_count: 47, count: 29", + "INFO: pass 1: last_count: 46, count: 29", ] } diff --git a/test/compress/loops.js b/test/compress/loops.js index 1fa3d00c..cfabe6fd 100644 --- a/test/compress/loops.js +++ b/test/compress/loops.js @@ -547,8 +547,8 @@ dead_code_condition: { console.log(a); } expect: { - var c; var a = 0, b = 5; + var c; a += 1, 0, console.log(a); } @@ -1197,3 +1197,28 @@ issue_4182_2: { } expect_stdout: "PASS" } + +do_continue: { + options = { + loops: true, + } + input: { + try { + do { + continue; + } while ([ A ]); + } catch (e) { + console.log("PASS"); + } + } + expect: { + try { + do { + continue; + } while ([ A ]); + } catch (e) { + console.log("PASS"); + } + } + expect_stdout: "PASS" +} diff --git a/test/compress/pure_getters.js b/test/compress/pure_getters.js index 9764f0f4..25efd7fd 100644 --- a/test/compress/pure_getters.js +++ b/test/compress/pure_getters.js @@ -848,9 +848,8 @@ collapse_vars_1_true: { } expect: { function f(a, b) { - for (;;) { + for (;;) if (a.g() || b.p) break; - } } } } diff --git a/test/reduce.js b/test/reduce.js index f1d2b448..ec1fb0bc 100644 --- a/test/reduce.js +++ b/test/reduce.js @@ -121,7 +121,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options) return; } // preserve for (var xxx; ...) - if (parent instanceof U.AST_For && parent.init === node && node instanceof U.AST_Var) return node; + if (parent instanceof U.AST_For && parent.init === node && node instanceof U.AST_Definitions) return node; // preserve for (xxx in ...) if (parent instanceof U.AST_ForIn && parent.init === node) return node; @@ -145,7 +145,9 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options) return permute < 2 ? expr : wrap_with_console_log(expr); } else if (node instanceof U.AST_BlockStatement) { - if (in_list) { + if (in_list && node.body.filter(function(node) { + return node instanceof U.AST_Const; + }).length == 0) { node.start._permute++; CHANGED = true; return List.splice(node.body); @@ -410,7 +412,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options) start: {}, }); } - else if (node instanceof U.AST_Var) { + else if (node instanceof U.AST_Definitions) { // remove empty var statement if (node.definitions.length == 0) return in_list ? List.skip : new U.AST_EmptyStatement({ start: {}, diff --git a/test/ufuzz/index.js b/test/ufuzz/index.js index 60f86667..717252d3 100644 --- a/test/ufuzz/index.js +++ b/test/ufuzz/index.js @@ -275,6 +275,7 @@ var CANNOT_RETURN = true; var NO_DEFUN = false; var DEFUN_OK = true; var DONT_STORE = true; +var NO_CONST = true; var VAR_NAMES = [ "a", @@ -312,6 +313,7 @@ var TYPEOF_OUTCOMES = [ "crap", ]; +var block_vars = []; var unique_vars = []; var loops = 0; var funcs = 0; @@ -374,33 +376,66 @@ function filterDirective(s) { return s; } +function createBlockVariables(recurmax, stmtDepth, canThrow, fn) { + var block_len = block_vars.length; + var var_len = VAR_NAMES.length; + var consts = []; + unique_vars.push("a", "b", "c", "undefined", "NaN", "Infinity"); + while (!rng(block_vars.length > block_len ? 10 : 100)) { + var name = createVarName(MANDATORY, DONT_STORE); + consts.push(name); + block_vars.push(name); + } + unique_vars.length -= 6; + fn(function() { + var s = []; + if (consts.length) { + var save = VAR_NAMES; + VAR_NAMES = VAR_NAMES.filter(function(name) { + return consts.indexOf(name) < 0; + }); + var len = VAR_NAMES.length; + s.push("const " + consts.map(function(name) { + var value = createExpression(recurmax, NO_COMMA, stmtDepth, canThrow); + VAR_NAMES.push(name); + return name + " = " + value; + }).join(", ") + ";"); + VAR_NAMES = save.concat(VAR_NAMES.slice(len)); + } + return s.join("\n"); + }); + block_vars.length = block_len; + if (consts.length) VAR_NAMES.splice(var_len, consts.length); +} + function createFunction(recurmax, allowDefun, canThrow, stmtDepth) { if (--recurmax < 0) { return ";"; } if (!STMT_COUNT_FROM_GLOBAL) stmtDepth = 0; - var namesLenBefore = VAR_NAMES.length; + var s = []; var name; - if (allowDefun || rng(5) > 0) { - name = "f" + funcs++; - } else { - unique_vars.push("a", "b", "c"); - name = createVarName(MANDATORY, !allowDefun); - unique_vars.length -= 3; - } - var s = [ - "function " + name + "(" + createParams() + "){", - strictMode() - ]; - if (rng(5) === 0) { - // functions with functions. lower the recursion to prevent a mess. - s.push(createFunctions(rng(5) + 1, Math.ceil(recurmax * 0.7), DEFUN_OK, canThrow, stmtDepth)); - } else { - // functions with statements - s.push(createStatements(3, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth)); - } - s.push("}", ""); - s = filterDirective(s).join("\n"); + createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) { + var namesLenBefore = VAR_NAMES.length; + if (allowDefun || rng(5) > 0) { + name = "f" + funcs++; + } else { + unique_vars.push("a", "b", "c"); + name = createVarName(MANDATORY, !allowDefun); + unique_vars.length -= 3; + } + s.push("function " + name + "(" + createParams() + "){", strictMode()); + s.push(defns()); + if (rng(5) === 0) { + // functions with functions. lower the recursion to prevent a mess. + s.push(createFunctions(rng(5) + 1, Math.ceil(recurmax * 0.7), DEFUN_OK, canThrow, stmtDepth)); + } else { + // functions with statements + s.push(_createStatements(3, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth)); + } + s.push("}", ""); + s = filterDirective(s).join("\n"); - VAR_NAMES.length = namesLenBefore; + VAR_NAMES.length = namesLenBefore; + }); if (!allowDefun) { // avoid "function statements" (decl inside statements) @@ -414,7 +449,7 @@ function createFunction(recurmax, allowDefun, canThrow, stmtDepth) { return s + ";"; } -function createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) { +function _createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) { if (--recurmax < 0) { return ";"; } var s = ""; while (--n > 0) { @@ -423,6 +458,15 @@ function createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotRe return s; } +function createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) { + var s = ""; + createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) { + s += defns() + "\n"; + s += _createStatements(n, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth); + }); + return s; +} + function enableLoopControl(flag, defaultValue) { return Array.isArray(flag) && flag.indexOf("") < 0 ? flag.concat("") : flag || defaultValue; } @@ -496,7 +540,7 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn var label = createLabel(canBreak, canContinue); canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK); canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE); - var key = rng(10) ? "key" + loop : getVarName(); + var key = rng(10) ? "key" + loop : getVarName(NO_CONST); return [ "{var expr" + loop + " = " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; ", label.target + " for (", @@ -571,13 +615,18 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn // the catch var should only be accessible in the catch clause... // we have to do go through some trouble here to prevent leaking it var nameLenBefore = VAR_NAMES.length; - var catchName = createVarName(MANDATORY); - var freshCatchName = VAR_NAMES.length !== nameLenBefore; - if (!catch_redef) unique_vars.push(catchName); - s += " catch (" + catchName + ") { " + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + " }"; - // remove catch name - if (!catch_redef) unique_vars.pop(); - if (freshCatchName) VAR_NAMES.splice(nameLenBefore, 1); + createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) { + var catchName = createVarName(MANDATORY); + var freshCatchName = VAR_NAMES.length !== nameLenBefore; + if (!catch_redef) unique_vars.push(catchName); + s += " catch (" + catchName + ") { "; + s += defns() + "\n"; + s += _createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth); + s += " }"; + // remove catch name + if (!catch_redef) unique_vars.pop(); + if (freshCatchName) VAR_NAMES.splice(nameLenBefore, 1); + }); } if (n !== 0) s += " finally { " + createStatements(3, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + " }"; return s; @@ -597,7 +646,7 @@ function createSwitchParts(recurmax, n, canThrow, canBreak, canContinue, cannotR if (hadDefault || rng(5) > 0) { s.push( "case " + createExpression(recurmax, NO_COMMA, stmtDepth, canThrow) + ":", - createStatements(rng(3) + 1, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth), + _createStatements(rng(3) + 1, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth), rng(10) > 0 ? " break;" : "/* fall-through */", "" ); @@ -605,7 +654,7 @@ function createSwitchParts(recurmax, n, canThrow, canBreak, canContinue, cannotR hadDefault = true; s.push( "default:", - createStatements(rng(3) + 1, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth), + _createStatements(rng(3) + 1, recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth), "" ); } @@ -653,7 +702,7 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) { case p++: return getVarName(); case p++: - return getVarName() + createAssignment() + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow); + return getVarName(NO_CONST) + createAssignment() + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow); case p++: return createExpression(recurmax, COMMA_OK, stmtDepth, canThrow); case p++: @@ -699,19 +748,22 @@ function _createExpression(recurmax, noComma, stmtDepth, canThrow) { ); break; default: - var instantiate = rng(4) ? "new " : ""; - s.push( - instantiate + "function " + name + "(){", - strictMode() - ); - if (instantiate) for (var i = rng(4); --i >= 0;) { - if (rng(2)) s.push("this." + getDotKey(true) + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ";"); - else s.push("this[" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "]" + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ";"); - } - s.push( - createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth), - rng(2) == 0 ? "}" : "}()" - ); + createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) { + var instantiate = rng(4) ? "new " : ""; + s.push( + instantiate + "function " + name + "(){", + strictMode(), + defns() + ); + if (instantiate) for (var i = rng(4); --i >= 0;) { + if (rng(2)) s.push("this." + getDotKey(true) + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ";"); + else s.push("this[" + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "]" + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ";"); + } + s.push( + _createStatements(rng(5) + 1, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth), + rng(2) == 0 ? "}" : "}()" + ); + }); break; } VAR_NAMES.length = nameLenBefore; @@ -861,13 +913,16 @@ function createAccessor(recurmax, stmtDepth, canThrow) { do { prop2 = getDotKey(); } while (prop1 == prop2); - s = [ - "set " + prop1 + "(" + createVarName(MANDATORY) + "){", - strictMode(), - createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth), - "this." + prop2 + createAssignment() + _createBinaryExpr(recurmax, COMMA_OK, stmtDepth, canThrow) + ";", - "}," - ]; + createBlockVariables(recurmax, stmtDepth, canThrow, function(defns) { + s = [ + "set " + prop1 + "(" + createVarName(MANDATORY) + "){", + strictMode(), + defns(), + _createStatements(2, recurmax, canThrow, CANNOT_BREAK, CANNOT_CONTINUE, CAN_RETURN, stmtDepth), + "this." + prop2 + createAssignment() + _createBinaryExpr(recurmax, COMMA_OK, stmtDepth, canThrow) + ";", + "}," + ]; + }); } VAR_NAMES.length = namesLenBefore; return filterDirective(s).join("\n"); @@ -906,7 +961,7 @@ function _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) { case 1: return "(" + createUnarySafePrefix() + "(" + _createSimpleBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + "))"; case 2: - assignee = getVarName(); + assignee = getVarName(NO_CONST); return "(" + assignee + createAssignment() + _createBinaryExpr(recurmax, noComma, stmtDepth, canThrow) + ")"; case 3: assignee = getVarName(); @@ -968,9 +1023,10 @@ function createUnaryPostfix() { return UNARY_POSTFIX[rng(UNARY_POSTFIX.length)]; } -function getVarName() { +function getVarName(noConst) { // try to get a generated name reachable from current scope. default to just `a` - return VAR_NAMES[INITIAL_NAMES_LEN + rng(VAR_NAMES.length - INITIAL_NAMES_LEN)] || "a"; + var name = VAR_NAMES[INITIAL_NAMES_LEN + rng(VAR_NAMES.length - INITIAL_NAMES_LEN)]; + return !name || noConst && block_vars.indexOf(name) >= 0 ? "a" : name; } function createVarName(maybe, dontStore) { @@ -980,7 +1036,7 @@ function createVarName(maybe, dontStore) { do { name = VAR_NAMES[rng(VAR_NAMES.length)]; if (suffix) name += "_" + suffix; - } while (unique_vars.indexOf(name) >= 0); + } while (unique_vars.indexOf(name) >= 0 || block_vars.indexOf(name) >= 0); if (suffix && !dontStore) VAR_NAMES.push(name); return name; } @@ -1258,10 +1314,6 @@ function patch_try_catch(orig, toplevel) { } } -var fallback_options = [ JSON.stringify({ - compress: false, - mangle: false -}) ]; var minify_options = require("./options.json").map(JSON.stringify); var original_code, original_result, errored; var uglify_code, uglify_result, ok; @@ -1269,10 +1321,19 @@ for (var round = 1; round <= num_iterations; round++) { process.stdout.write(round + " of " + num_iterations + "\r"); original_code = createTopLevelCode(); - var orig_result = [ sandbox.run_code(original_code) ]; + var orig_result = [ sandbox.run_code(original_code), sandbox.run_code(original_code, true) ]; errored = typeof orig_result[0] != "string"; - if (!errored) orig_result.push(sandbox.run_code(original_code, true)); - (errored ? fallback_options : minify_options).forEach(function(options) { + if (errored) { + println("//============================================================="); + println("// original code"); + try_beautify(original_code, false, orig_result[0], println); + println(); + println(); + println("original result:"); + println(orig_result[0]); + println(); + } + minify_options.forEach(function(options) { var o = JSON.parse(options); var toplevel = sandbox.has_toplevel(o); o.validate = true; @@ -1294,6 +1355,8 @@ for (var round = 1; round <= num_iterations; round++) { ok = sandbox.same_stdout(fuzzy_result, uglify_result); } } + // ignore difference in error message caused by Temporal Dead Zone + if (!ok && errored) ok = uglify_result.name == "ReferenceError" && original_result.name == "ReferenceError"; // ignore difference in error message caused by `in` // ignore difference in depth of termination caused by infinite recursion if (!ok) { @@ -1308,16 +1371,6 @@ for (var round = 1; round <= num_iterations; round++) { ok = errored && uglify_code.name == original_result.name; } if (verbose || (verbose_interval && !(round % INTERVAL_COUNT)) || !ok) log(options); - else if (errored) { - println("//============================================================="); - println("// original code"); - try_beautify(original_code, toplevel, original_result, println); - println(); - println(); - println("original result:"); - println(original_result); - println(); - } if (!ok && isFinite(num_iterations)) { println(); process.exit(1); |