Bug 1185106 - Part 5.5: Add parser test for async function declaration. r=efaust,till draft
authorMariusz Kierski <mkierski@mozilla.com>
Sun, 28 Aug 2016 23:58:21 +0900
changeset 430930 c66eccc055fa97c8eb2d9f127618b5bfa89841af
parent 430929 d0663b559f5061223011d21f091a3566fe2bbfe7
child 430931 bc51f7a59554539c5f2dc42715a129088949d428
push id33945
push userarai_a@mac.com
push dateFri, 28 Oct 2016 11:34:02 +0000
reviewersefaust, till
bugs1185106
milestone52.0a1
Bug 1185106 - Part 5.5: Add parser test for async function declaration. r=efaust,till MozReview-Commit-ID: I8gqeShK7ch
js/src/jit-test/lib/syntax.js
js/src/tests/ecma_7/AsyncFunctions/EarlyErrors.js
js/src/tests/ecma_7/AsyncFunctions/shell.js
js/src/tests/ecma_7/AsyncFunctions/syntax.js
js/src/tests/js1_8_5/reflect-parse/PatternBuilders.js
js/src/tests/js1_8_5/reflect-parse/async.js
--- 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);