Bug 1339964 - Support export async function f() {}. r=till
authorTooru Fujisawa <arai_a@mac.com>
Wed, 22 Feb 2017 16:11:35 +0900
changeset 344210 12302127707b1b30a86969e9db2b99d0820dafb5
parent 344209 7e9cf4a61aec21800f6f59a3e1a32d685bb3871a
child 344211 13a54cc4d8be58afabb3078c6ba5f4241dd396f4
push id31402
push usercbook@mozilla.com
push dateWed, 22 Feb 2017 13:33:50 +0000
treeherdermozilla-central@f5372cb6c3c7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstill
bugs1339964
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1339964 - Support export async function f() {}. r=till
js/src/frontend/Parser.cpp
js/src/frontend/Parser.h
js/src/tests/ecma_2017/AsyncFunctions/syntax-modules.js
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -5228,24 +5228,25 @@ Parser<ParseHandler>::exportVariableStat
     if (!processExport(node))
         return null();
 
     return node;
 }
 
 template <typename ParseHandler>
 typename ParseHandler::Node
-Parser<ParseHandler>::exportFunctionDeclaration(uint32_t begin)
+Parser<ParseHandler>::exportFunctionDeclaration(uint32_t begin,
+                                                FunctionAsyncKind asyncKind /* = SyncFunction */)
 {
     if (!abortIfSyntaxParser())
         return null();
 
     MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
 
-    Node kid = functionStmt(YieldIsKeyword, NameRequired);
+    Node kid = functionStmt(YieldIsKeyword, NameRequired, asyncKind);
     if (!kid)
         return null();
 
     if (!checkExportedNameForFunction(kid))
         return null();
 
     Node node = handler.newExportDeclaration(kid, TokenPos(begin, pos().end));
     if (!node)
@@ -5458,16 +5459,30 @@ Parser<ParseHandler>::exportDeclaration(
         return exportClause(begin);
 
       case TOK_VAR:
         return exportVariableStatement(begin);
 
       case TOK_FUNCTION:
         return exportFunctionDeclaration(begin);
 
+      case TOK_ASYNC: {
+        TokenKind nextSameLine = TOK_EOF;
+        if (!tokenStream.peekTokenSameLine(&nextSameLine))
+            return null();
+
+        if (nextSameLine == TOK_FUNCTION) {
+            tokenStream.consumeKnownToken(TOK_FUNCTION);
+            return exportFunctionDeclaration(begin, AsyncFunction);
+        }
+
+        error(JSMSG_DECLARATION_AFTER_EXPORT);
+        return null();
+      }
+
       case TOK_CLASS:
         return exportClassDeclaration(begin);
 
       case TOK_CONST:
         return exportLexicalDeclaration(begin, DeclarationKind::Const);
 
       case TOK_LET:
         return exportLexicalDeclaration(begin, DeclarationKind::Let);
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -1198,17 +1198,18 @@ class Parser final : public ParserBase, 
 
     bool processExport(Node node);
     bool processExportFrom(Node node);
 
     Node exportFrom(uint32_t begin, Node specList);
     Node exportBatch(uint32_t begin);
     bool checkLocalExportNames(Node node);
     Node exportClause(uint32_t begin);
-    Node exportFunctionDeclaration(uint32_t begin);
+    Node exportFunctionDeclaration(uint32_t begin,
+                                   FunctionAsyncKind asyncKind = SyncFunction);
     Node exportVariableStatement(uint32_t begin);
     Node exportClassDeclaration(uint32_t begin);
     Node exportLexicalDeclaration(uint32_t begin, DeclarationKind kind);
     Node exportDefaultFunctionDeclaration(uint32_t begin,
                                           FunctionAsyncKind asyncKind = SyncFunction);
     Node exportDefaultClassDeclaration(uint32_t begin);
     Node exportDefaultAssignExpr(uint32_t begin);
     Node exportDefault(uint32_t begin);
--- a/js/src/tests/ecma_2017/AsyncFunctions/syntax-modules.js
+++ b/js/src/tests/ecma_2017/AsyncFunctions/syntax-modules.js
@@ -11,15 +11,21 @@ if (typeof parseModule === "function") {
     assertThrows(() => parseModule("await 5;"), SyntaxError);
     assertThrows(() => parseModule("function f() { await 5; }"), SyntaxError);
     assertThrows(() => parseModule("() => { await 5; }"), SyntaxError);
     assertThrows(() => parseModule("export var await;"), SyntaxError);
     assertThrows(() => parseModule("await => 1;"), SyntaxError);
     assertThrows(() => parseModule("async function f() { function g() { await 3; } }"), SyntaxError);
 
     if (typeof Reflect !== "undefined" && Reflect.parse) {
+        Reflect.parse("export async function f() {}", { target: "module" });
+        assertThrows(() => Reflect.parse("export async function() {}", { target: "module" }), SyntaxError);
+
+        Reflect.parse("export default async function() {}", { target: "module" });
+        Reflect.parse("export default async function f() {}", { target: "module" });
+
         assertThrows(() => Reflect.parse("export default async function() { yield; }", { target: "module" }), SyntaxError);
         assertThrows(() => Reflect.parse("export default async function() { yield = 1; }", { target: "module" }), SyntaxError);
     }
 }
 
 if (typeof reportCompare === "function")
     reportCompare(true, true);