support for [await]...of statements (#4627)
This commit is contained in:
@@ -828,6 +828,21 @@ empty_for_in_prop_init: {
|
||||
]
|
||||
}
|
||||
|
||||
for_of: {
|
||||
input: {
|
||||
var async = [ "PASS", 42 ];
|
||||
async.p = "FAIL";
|
||||
for (async of (null, async))
|
||||
console.log(async);
|
||||
}
|
||||
expect_exact: 'var async=["PASS",42];async.p="FAIL";for(async of(null,async))console.log(async);'
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"42",
|
||||
]
|
||||
node_version: ">=0.12"
|
||||
}
|
||||
|
||||
issue_3631_1: {
|
||||
options = {
|
||||
dead_code: true,
|
||||
|
||||
@@ -96,6 +96,48 @@ pause_resume: {
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
for_of: {
|
||||
input: {
|
||||
function* f() {
|
||||
if (yield "PASS") yield "FAIL 1";
|
||||
yield 42;
|
||||
return "FAIL 2";
|
||||
}
|
||||
for (var a of f())
|
||||
console.log(a);
|
||||
}
|
||||
expect_exact: 'function*f(){if(yield"PASS")yield"FAIL 1";yield 42;return"FAIL 2"}for(var a of f())console.log(a);'
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"42",
|
||||
]
|
||||
node_version: ">=4"
|
||||
}
|
||||
|
||||
for_await_of: {
|
||||
input: {
|
||||
async function* f() {
|
||||
if (yield "PASS") yield "FAIL 1";
|
||||
yield {
|
||||
then: function(r) {
|
||||
r(42);
|
||||
},
|
||||
};
|
||||
return "FAIL 2";
|
||||
}
|
||||
(async function(a) {
|
||||
for await (a of f())
|
||||
console.log(a);
|
||||
})();
|
||||
}
|
||||
expect_exact: 'async function*f(){if(yield"PASS")yield"FAIL 1";yield{then:function(r){r(42)}};return"FAIL 2"}(async function(a){for await(a of f())console.log(a)})();'
|
||||
expect_stdout: [
|
||||
"PASS",
|
||||
"42",
|
||||
]
|
||||
node_version: ">=10"
|
||||
}
|
||||
|
||||
collapse_vars_1: {
|
||||
options = {
|
||||
collapse_vars: true,
|
||||
|
||||
@@ -624,7 +624,7 @@ describe("bin/uglifyjs", function() {
|
||||
"Parse error at test/input/invalid/for-in_1.js:2,5",
|
||||
"for (1, 2, a in b) {",
|
||||
" ^",
|
||||
"ERROR: Invalid left-hand side in for..in loop"
|
||||
"ERROR: Invalid left-hand side in for..in/of loop"
|
||||
].join("\n"));
|
||||
done();
|
||||
});
|
||||
@@ -638,7 +638,7 @@ describe("bin/uglifyjs", function() {
|
||||
"Parse error at test/input/invalid/for-in_2.js:2,5",
|
||||
"for (var a, b in c) {",
|
||||
" ^",
|
||||
"ERROR: Only one variable declaration allowed in for..in loop"
|
||||
"ERROR: Only one variable declaration allowed in for..in/of loop"
|
||||
].join("\n"));
|
||||
done();
|
||||
});
|
||||
|
||||
@@ -134,8 +134,8 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
if (parent instanceof U.AST_VarDef && parent.name === node) return;
|
||||
// preserve for (var xxx; ...)
|
||||
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;
|
||||
// preserve for (xxx in/of ...)
|
||||
if (parent instanceof U.AST_ForEnumeration && parent.init === node) return node;
|
||||
|
||||
// node specific permutations with no parent logic
|
||||
|
||||
@@ -303,7 +303,7 @@ module.exports = function reduce_test(testcase, minify_options, reduce_options)
|
||||
return to_statement(expr);
|
||||
}
|
||||
}
|
||||
else if (node instanceof U.AST_ForIn) {
|
||||
else if (node instanceof U.AST_ForEnumeration) {
|
||||
var expr;
|
||||
switch ((node.start._permute * steps | 0) % 3) {
|
||||
case 0:
|
||||
|
||||
@@ -27,7 +27,7 @@ var STMT_IF_ELSE = STMT_("ifelse");
|
||||
var STMT_DO_WHILE = STMT_("dowhile");
|
||||
var STMT_WHILE = STMT_("while");
|
||||
var STMT_FOR_LOOP = STMT_("forloop");
|
||||
var STMT_FOR_IN = STMT_("forin");
|
||||
var STMT_FOR_ENUM = STMT_("forenum");
|
||||
var STMT_SEMI = STMT_("semi");
|
||||
var STMT_EXPR = STMT_("expr");
|
||||
var STMT_SWITCH = STMT_("switch");
|
||||
@@ -142,6 +142,8 @@ var SUPPORT = function(matrix) {
|
||||
default_value: "[ a = 0 ] = [];",
|
||||
destructuring: "[] = [];",
|
||||
exponentiation: "0 ** 0",
|
||||
for_await_of: "async function f(a) { for await (a of []); }",
|
||||
for_of: "for (var a of []);",
|
||||
generator: "function* f(){}",
|
||||
let: "let a;",
|
||||
rest: "var [...a] = [];",
|
||||
@@ -901,21 +903,58 @@ function createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn
|
||||
canBreak = label.break || enableLoopControl(canBreak, CAN_BREAK);
|
||||
canContinue = label.continue || enableLoopControl(canContinue, CAN_CONTINUE);
|
||||
return label.target + "for (var brake" + loop + " = 5; " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + " && brake" + loop + " > 0; --brake" + loop + ")" + createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth);
|
||||
case STMT_FOR_IN:
|
||||
case STMT_FOR_ENUM:
|
||||
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(NO_CONST);
|
||||
return [
|
||||
"{var expr" + loop + " = " + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; ",
|
||||
label.target + " for (",
|
||||
!/^key/.test(key) ? rng(10) ? "" : "var " : !SUPPORT.let || rng(10) ? "var " : rng(2) ? "let " : "const ",
|
||||
!SUPPORT.destructuring || rng(10) ? key : rng(5) ? "[ " + key + " ]" : "{ length: " + key + " }",
|
||||
" in expr" + loop + ") {",
|
||||
rng(5) > 1 ? "c = 1 + c; var " + createVarName(MANDATORY) + " = expr" + loop + "[" + key + "]; " : "",
|
||||
createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth),
|
||||
"}}",
|
||||
].join("");
|
||||
var of = SUPPORT.for_of && rng(20) == 0;
|
||||
var init = "";
|
||||
if (!/^key/.test(key)) {
|
||||
if (!(of && bug_for_of_var) && rng(10) == 0) init = "var ";
|
||||
} else if (!SUPPORT.let || !(of && bug_for_of_var) && rng(10)) {
|
||||
init = "var ";
|
||||
} else if (rng(2)) {
|
||||
init = "let ";
|
||||
} else {
|
||||
init = "const ";
|
||||
}
|
||||
if (!SUPPORT.destructuring || of && !(canThrow && rng(10) == 0) || rng(10)) {
|
||||
init += key;
|
||||
} else if (rng(5)) {
|
||||
init += "[ " + key + " ]";
|
||||
} else {
|
||||
init += "{ length: " + key + " }";
|
||||
}
|
||||
var s = "var expr" + loop + " = ";
|
||||
if (of) {
|
||||
var await = SUPPORT.for_await_of && async && rng(20) == 0;
|
||||
if (SUPPORT.generator && rng(20) == 0) {
|
||||
var gen = getVarName();
|
||||
if (canThrow && rng(10) == 0) {
|
||||
s += gen + "; ";
|
||||
} else {
|
||||
s += gen + " && typeof " + gen + "[Symbol.";
|
||||
s += await ? "asyncIterator" : "iterator";
|
||||
s += '] == "function" ? ' + gen + " : " + createArrayLiteral(recurmax, stmtDepth, canThrow) + "; ";
|
||||
}
|
||||
} else if (rng(5)) {
|
||||
s += createArrayLiteral(recurmax, stmtDepth, canThrow) + "; ";
|
||||
} else if (canThrow && rng(10) == 0) {
|
||||
s += createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; ";
|
||||
} else {
|
||||
s += '"" + (' + createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "); ";
|
||||
}
|
||||
s += label.target + " for ";
|
||||
if (await) s += "await ";
|
||||
s += "(" + init + " of expr" + loop + ") {";
|
||||
} else {
|
||||
s += createExpression(recurmax, COMMA_OK, stmtDepth, canThrow) + "; ";
|
||||
s += label.target + " for (" + init + " in expr" + loop + ") {";
|
||||
}
|
||||
if (rng(3)) s += "c = 1 + c; var " + createVarName(MANDATORY) + " = expr" + loop + "[" + key + "]; ";
|
||||
s += createStatement(recurmax, canThrow, canBreak, canContinue, cannotReturn, stmtDepth) + "}";
|
||||
return "{" + s + "}";
|
||||
case STMT_SEMI:
|
||||
return use_strict && rng(20) === 0 ? '"use strict";' : ";";
|
||||
case STMT_EXPR:
|
||||
@@ -2048,12 +2087,13 @@ if (typeof sandbox.run_code("A:if (0) B:; else B:;") != "string") {
|
||||
if (o.mangle) o.mangle.v8 = true;
|
||||
});
|
||||
}
|
||||
var is_bug_async_arrow_rest = function() {};
|
||||
var bug_async_arrow_rest = function() {};
|
||||
if (SUPPORT.arrow && SUPPORT.async && SUPPORT.rest && typeof sandbox.run_code("async (a = f(...[], b)) => 0;") != "string") {
|
||||
is_bug_async_arrow_rest = function(ex) {
|
||||
bug_async_arrow_rest = function(ex) {
|
||||
return ex.name == "SyntaxError" && ex.message == "Rest parameter must be last formal parameter";
|
||||
};
|
||||
}
|
||||
var bug_for_of_var = SUPPORT.for_of && SUPPORT.let && typeof sandbox.run_code("try {} catch (e) { for (var e of []); }") != "string";
|
||||
if (SUPPORT.destructuring && typeof sandbox.run_code("console.log([ 1 ], {} = 2);") != "string") {
|
||||
beautify_options.output.v8 = true;
|
||||
minify_options.forEach(function(o) {
|
||||
@@ -2083,7 +2123,7 @@ for (var round = 1; round <= num_iterations; round++) {
|
||||
println(result);
|
||||
println();
|
||||
// ignore v8 parser bug
|
||||
return is_bug_async_arrow_rest(result);
|
||||
return bug_async_arrow_rest(result);
|
||||
})) continue;
|
||||
minify_options.forEach(function(options) {
|
||||
var o = JSON.parse(options);
|
||||
@@ -2097,7 +2137,7 @@ for (var round = 1; round <= num_iterations; round++) {
|
||||
uglify_result = sandbox.run_code(uglify_code, toplevel);
|
||||
ok = sandbox.same_stdout(original_result, uglify_result);
|
||||
// ignore v8 parser bug
|
||||
if (!ok && is_bug_async_arrow_rest(uglify_result)) ok = true;
|
||||
if (!ok && bug_async_arrow_rest(uglify_result)) ok = true;
|
||||
// ignore declaration order of global variables
|
||||
if (!ok && !toplevel) {
|
||||
ok = sandbox.same_stdout(sandbox.run_code(sort_globals(original_code)), sandbox.run_code(sort_globals(uglify_code)));
|
||||
|
||||
Reference in New Issue
Block a user