diff options
-rw-r--r-- | lib/parse.js | 15 | ||||
-rw-r--r-- | test/mocha/async.js | 44 |
2 files changed, 53 insertions, 6 deletions
diff --git a/lib/parse.js b/lib/parse.js index 21e6055a..c65b2f42 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -653,14 +653,15 @@ function parse($TEXT, options) { input : typeof $TEXT == "string" ? tokenizer($TEXT, options.filename, options.html5_comments, options.shebang) : $TEXT, - token : null, - prev : null, - peeked : null, in_async : false, - in_function : 0, in_directives : true, + in_funarg : -1, + in_function : 0, in_loop : 0, - labels : [] + labels : [], + peeked : null, + prev : null, + token : null, }; S.token = next(); @@ -1053,9 +1054,12 @@ function parse($TEXT, options) { if (name && ctor !== AST_Accessor && !(name instanceof AST_SymbolDeclaration)) unexpected(prev()); expect("("); + var was_funarg = S.in_funarg; + S.in_funarg = S.in_function; var argnames = expr_list(")", !options.strict, false, function() { return maybe_destructured(AST_SymbolFunarg); }); + S.in_funarg = was_funarg; var loop = S.in_loop; var labels = S.labels; ++S.in_function; @@ -1638,6 +1642,7 @@ function parse($TEXT, options) { function maybe_await() { var start = S.token; if (!(S.in_async && is("name", "await"))) return maybe_unary(); + if (S.in_funarg === S.in_function) croak("Invalid use of await in function argument"); S.input.context().regex_allowed = true; next(); return new AST_Await({ diff --git a/test/mocha/async.js b/test/mocha/async.js index dc1aa2f4..d4e96609 100644 --- a/test/mocha/async.js +++ b/test/mocha/async.js @@ -12,7 +12,12 @@ describe("async", function() { "function() { function await() {} }", "function() { try {} catch (await) {} }", ].forEach(function(code) { - UglifyJS.parse("(" + code + ")();"); + var ast = UglifyJS.parse("(" + code + ")();"); + assert.strictEqual(ast.TYPE, "Toplevel"); + assert.strictEqual(ast.body.length, 1); + assert.strictEqual(ast.body[0].TYPE, "SimpleStatement"); + assert.strictEqual(ast.body[0].body.TYPE, "Call"); + assert.strictEqual(ast.body[0].body.expression.TYPE, "Function"); assert.throws(function() { UglifyJS.parse("(async " + code + ")();"); }, function(e) { @@ -20,4 +25,41 @@ describe("async", function() { }, code); }); }); + it("Should reject `await` expression outside of async functions", function() { + [ + "await 42;", + "function f() { await 42; }", + "async function f() { function g() { await 42; } }", + ].forEach(function(code) { + assert.throws(function() { + UglifyJS.parse(code); + }, function(e) { + return e instanceof UglifyJS.JS_Parse_Error; + }, code); + }); + }); + it("Should reject `await` expression directly on computed key of function argument", function() { + [ + "function f({ [await 42]: a }) {}", + "async function f({ [await 42]: a }) {}", + ].forEach(function(code) { + assert.throws(function() { + UglifyJS.parse(code); + }, function(e) { + return e instanceof UglifyJS.JS_Parse_Error; + }, code); + }); + }); + it("Should accept `await` expression nested within computed key of function argument", function() { + [ + "function f({ [async function() { await 42; }()]: a }) {}", + "async function f({ [async function() { await 42; }()]: a }) {}", + ].forEach(function(code) { + var ast = UglifyJS.parse(code); + assert.strictEqual(ast.TYPE, "Toplevel"); + assert.strictEqual(ast.body.length, 1); + assert.strictEqual(ast.body[0].argnames.length, 1); + assert.strictEqual(ast.body[0].argnames[0].TYPE, "DestructuredObject"); + }); + }); }); |