aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/parse.js15
-rw-r--r--test/mocha/async.js44
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");
+ });
+ });
});