Bug 1185106 - Part 5.5: Add parser test for async function declaration. r=efaust,till
MozReview-Commit-ID: I8gqeShK7ch
--- a/js/src/jit-test/lib/syntax.js
+++ b/js/src/jit-test/lib/syntax.js
@@ -1176,17 +1176,17 @@ function test_syntax(postfixes, check_er
test("for each (var x in y) ");
test("for each (let ");
test("for each (let x ");
test("for each (let x in ");
test("for each (let x in y ");
test("for each (let x in y) ");
- // asm.js
+ // ==== asm.js ====
test("(function() { 'use asm'; ");
test("(function() { 'use asm'; var ");
test("(function() { 'use asm'; var a ");
test("(function() { 'use asm'; var a = ");
test("(function() { 'use asm'; var a = 1 ");
test("(function() { 'use asm'; var a = 1; ");
test("(function() { 'use asm'; var a = 1; function ");
@@ -1203,9 +1203,43 @@ function test_syntax(postfixes, check_er
test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f] ");
test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; ");
test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; return ");
test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; return f ");
test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; return f; ");
test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; return f; } ");
test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; return f; }) ");
test("(function() { 'use asm'; var a = 1; function f() { } var tbl = [f]; return f; }); ");
+
+ // ==== async/await ====
+
+ function asyncFunctionsEnabled() {
+ try {
+ eval("async function f() { }");
+ return true;
+ } catch (e if e instanceof SyntaxError) {
+ return false;
+ }
+ }
+
+ if (asyncFunctionsEnabled()) {
+ // async/await function decralation
+
+ test("async ");
+ test("async function ");
+ test("async function A ");
+ test("async function A( ");
+ test("async function A() ");
+ test("async function A(a ");
+ test("async function A(a) ");
+ test("async function A(a) { ");
+ test("async function A(a) {} ");
+ test("async function A(a) { await ");
+ test("async function A(a) { await X ");
+ test("async function A(a) { await X; ");
+ test("async function A(a) { await X; } ");
+ test("async function A(a) { await await ");
+ test("async function A(a) { await await await ");
+ test("async function A(a) { await await await X ");
+ test("async function A(a) { await await await X; ");
+ test("async function A(a) { await await await X; } ");
+ }
}
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_7/AsyncFunctions/EarlyErrors.js
@@ -0,0 +1,37 @@
+var BUGNUMBER = 1185106;
+var summary = "EarlyErrors for async function";
+
+print(BUGNUMBER + ": " + summary);
+
+function assertThrowsSE(code) {
+ assertThrows(() => Reflect.parse(code), SyntaxError);
+}
+
+if (asyncFunctionsEnabled() && typeof Reflect !== "undefined" && Reflect.parse) {
+ // If FormalParameters Contains AwaitExpression is true.
+ assertThrowsSE("async function a(k = await 3) {}");
+
+ // If BindingIdentifier is `eval` or `arguments`.
+ assertThrowsSE("'use strict'; async function eval() {}");
+
+ assertThrowsSE("'use strict'; async function arguments() {}");
+
+ // If any element of the BoundNames of FormalParameters also occurs in the
+ // LexicallyDeclaredNames of AsyncFunctionBody.
+ assertThrowsSE("async function a(x) { let x; }");
+
+ // If FormalParameters contains SuperProperty is true.
+ assertThrowsSE("async function a(k = super.prop) { }");
+
+ // If AsyncFunctionBody contains SuperProperty is true.
+ assertThrowsSE("async function a() { super.prop(); }");
+
+ // If FormalParameters contains SuperCall is true.
+ assertThrowsSE("async function a(k = super()) {}");
+
+ // If AsyncFunctionBody contains SuperCall is true.
+ assertThrowsSE("async function a() { super(); }");
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_7/AsyncFunctions/shell.js
@@ -0,0 +1,11 @@
+(function(global) {
+ function asyncFunctionsEnabled() {
+ try {
+ eval("async function f() { }");
+ return true;
+ } catch (e if e instanceof SyntaxError) {
+ return false;
+ }
+ }
+ global.asyncFunctionsEnabled = asyncFunctionsEnabled;
+})(this);
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_7/AsyncFunctions/syntax.js
@@ -0,0 +1,77 @@
+var BUGNUMBER = 1185106;
+var summary = "async/await syntax";
+
+print(BUGNUMBER + ": " + summary);
+
+if (asyncFunctionsEnabled() && typeof Reflect !== "undefined" && Reflect.parse) {
+ assertEq(Reflect.parse("function a() {}").body[0].async, false);
+ assertEq(Reflect.parse("function* a() {}").body[0].async, false);
+ assertEq(Reflect.parse("async function a() {}").body[0].async, true);
+
+ // Async generators are not allowed (with regards to spec)
+ assertThrows(() => Reflect.parse("async function* a() {}"), SyntaxError);
+
+ // No line terminator after async
+ assertEq(Reflect.parse("async\nfunction a(){}").body[0].expression.name, "async");
+
+ // `await` handling for function declaration name inherits.
+ assertEq(Reflect.parse("async function await() {}").body[0].id.name, "await");
+ assertThrows(() => Reflect.parse("async function f() { async function await() {} }"), SyntaxError);
+
+ // Awaiting not directly inside an async function is not allowed
+ assertThrows(() => Reflect.parse("await 4;"), SyntaxError);
+ assertThrows(() => Reflect.parse("function a() { await 4; }"), SyntaxError);
+ assertThrows(() => Reflect.parse("function* a() { await 4; }"), SyntaxError);
+ assertThrows(() => Reflect.parse("async function k() { function a() { await 4; } }"), SyntaxError);
+
+ // No line terminator after await is allowed
+ assertThrows(() => Reflect.parse("async function a() { await\n4; }"), SyntaxError);
+
+ // Await is not allowed as a default expr.
+ assertThrows(() => Reflect.parse("async function a(k = await 3) {}"), SyntaxError);
+ assertThrows(() => Reflect.parse("async function a() { async function b(k = await 3) {} }"), SyntaxError);
+ assertThrows(() => Reflect.parse("async function a() { async function b(k = [await 3]) {} }"), SyntaxError);
+
+ assertThrows(() => Reflect.parse("async function a() { async function b([k = await 3]) {} }"), SyntaxError);
+ assertThrows(() => Reflect.parse("async function a() { async function b([k = [await 3]]) {} }"), SyntaxError);
+ assertThrows(() => Reflect.parse("async function a() { async function b({k = await 3}) {} }"), SyntaxError);
+ assertThrows(() => Reflect.parse("async function a() { async function b({k = [await 3]}) {} }"), SyntaxError);
+
+ // Await is not legal as an identifier in an async function.
+ assertThrows(() => Reflect.parse("async function a() { var await = 4; }"), SyntaxError);
+ assertThrows(() => Reflect.parse("async function a() { return await; }"), SyntaxError);
+
+ // Await is still available as an identifier name in strict mode code.
+ Reflect.parse("function a() { 'use strict'; var await = 3; }");
+ Reflect.parse("'use strict'; var await = 3;");
+
+ // Await is treated differently depending on context. Various cases.
+ Reflect.parse("var await = 3; async function a() { await 4; }");
+ Reflect.parse("async function a() { await 4; } var await = 5");
+ Reflect.parse("async function a() { function b() { return await; } }");
+
+ Reflect.parse("async function a() { var k = { async: 4 } }");
+
+ Reflect.parse("function a() { await: 4 }");
+
+ assertEq(Reflect.parse("async function a() { await 4; }")
+ .body[0].body.body[0].expression.operator, "await");
+
+ assertEq(Reflect.parse("async function a() { async function b() { await 4; } }")
+ .body[0].body.body[0].body.body[0].expression.operator, "await");
+
+ // operator priority test
+ assertEq(Reflect.parse("async function a() { await 2 + 3; }")
+ .body[0].body.body[0].expression.left.argument.value, 2);
+ assertEq(Reflect.parse("async function a() { await 2 + 3; }")
+ .body[0].body.body[0].expression.left.operator, "await");
+ assertEq(Reflect.parse("async function a() { await 2 + 3; }")
+ .body[0].body.body[0].expression.right.value, 3);
+
+ // blocks and other constructions
+ assertEq(Reflect.parse("{ async function a() { return 2; } }")
+ .body[0].body[0].async, true);
+}
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
--- a/js/src/tests/js1_8_5/reflect-parse/PatternBuilders.js
+++ b/js/src/tests/js1_8_5/reflect-parse/PatternBuilders.js
@@ -42,16 +42,26 @@ function genFunDecl(style, id, params, b
return Pattern({ type: "FunctionDeclaration",
id: id,
params: params,
defaults: [],
body: body,
generator: true,
style: style });
}
+function asyncFunDecl(id, params, body) {
+ return Pattern({ type: "FunctionDeclaration",
+ id: id,
+ params: params,
+ defaults: [],
+ body: body,
+ generator: true,
+ async: true,
+ style: "es6" });
+}
function varDecl(decls) {
return Pattern({ type: "VariableDeclaration", declarations: decls, kind: "var" });
}
function letDecl(decls) {
return Pattern({ type: "VariableDeclaration", declarations: decls, kind: "let" });
}
function constDecl(decls) {
return Pattern({ type: "VariableDeclaration", declarations: decls, kind: "const" });
@@ -161,21 +171,39 @@ function funExpr(id, args, body, gen) {
function genFunExpr(style, id, args, body) {
return Pattern({ type: "FunctionExpression",
id: id,
params: args,
body: body,
generator: true,
style: style });
}
+function asyncFunExpr(id, args, body) {
+ return Pattern({ type: "FunctionExpression",
+ id: id,
+ params: args,
+ body: body,
+ generator: true,
+ async: true,
+ style: "es6" });
+}
function arrowExpr(args, body) {
return Pattern({ type: "ArrowFunctionExpression",
params: args,
body: body });
}
+function asyncArrowExpr(isExpression, args, body) {
+ return Pattern({ type: "ArrowFunctionExpression",
+ params: args,
+ body: body,
+ generator: true,
+ async: true,
+ expression: isExpression,
+ style: "es6" });
+}
function metaProperty(meta, property) {
return Pattern({ type: "MetaProperty",
meta: meta,
property: property });
}
function newTarget() {
return metaProperty(ident("new"), ident("target"));
new file mode 100644
--- /dev/null
+++ b/js/src/tests/js1_8_5/reflect-parse/async.js
@@ -0,0 +1,21 @@
+// |reftest| skip-if(!xulRuntime.shell)
+
+function asyncFunctionsEnabled() {
+ try {
+ eval("async function f() { }");
+ return true;
+ } catch (e if e instanceof SyntaxError) {
+ return false;
+ }
+}
+
+if (asyncFunctionsEnabled()) {
+ // async function declaration.
+ assertDecl("async function foo() {}", asyncFunDecl(ident("foo"), [], blockStmt([])));
+
+ // await expression.
+ assertDecl("async function foo() { await bar }", asyncFunDecl(ident("foo"), [], blockStmt([exprStmt(unExpr("await", ident("bar")))])));
+}
+
+if (typeof reportCompare === 'function')
+ reportCompare(true, true);