Bug 1185106 - Part 5.1: Support async function declaration in Parser. r=efaust,jwalden,till
MozReview-Commit-ID: FhRG1vzpHxb
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -2212,16 +2212,26 @@ Parser<SyntaxParseHandler>::finishFuncti
// Flags that need to copied back into the parser when we do the full
// parse.
PropagateTransitiveParseFlags(funbox, lazy);
fun->initLazyScript(lazy);
return true;
}
+static YieldHandling
+GetYieldHandling(GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
+{
+ if (asyncKind == AsyncFunction)
+ return YieldIsName;
+ if (generatorKind == NotGenerator)
+ return YieldIsName;
+ return YieldIsKeyword;
+}
+
template <>
ParseNode*
Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
HandleScope enclosingScope,
Handle<PropertyNameVector> formals,
GeneratorKind generatorKind,
FunctionAsyncKind asyncKind,
Directives inheritedDirectives,
@@ -2257,17 +2267,17 @@ Parser<FullParseHandler>::standaloneFunc
bool duplicatedParam = false;
for (uint32_t i = 0; i < formals.length(); i++) {
if (!notePositionalFormalParameter(fn, formals[i], false, &duplicatedParam))
return null();
}
funbox->hasDuplicateParameters = duplicatedParam;
- YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
+ YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
ParseNode* pn = functionBody(InAllowed, yieldHandling, Statement, StatementListBody);
if (!pn)
return null();
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand))
return null();
if (tt != TOK_EOF) {
@@ -3033,16 +3043,17 @@ Parser<ParseHandler>::templateLiteral(Yi
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::functionDefinition(InHandling inHandling, YieldHandling yieldHandling,
HandleAtom funName, FunctionSyntaxKind kind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
InvokedPrediction invoked)
{
MOZ_ASSERT_IF(kind == Statement, funName);
+ MOZ_ASSERT_IF(asyncKind == AsyncFunction, generatorKind == StarGenerator);
Node pn = handler.newFunctionDefinition();
if (!pn)
return null();
if (invoked)
pn = handler.setLikelyIIFE(pn);
@@ -3290,25 +3301,25 @@ Parser<FullParseHandler>::standaloneLazy
Directives newDirectives = directives;
ParseContext funpc(this, funbox, &newDirectives);
if (!funpc.init())
return null();
// Our tokenStream has no current token, so pn's position is garbage.
// Substitute the position of the first token in our source. If the function
- // is an arrow, use TokenStream::Operand to keep verifyConsistentModifier
- // from complaining (we will use TokenStream::Operand in functionArguments).
- if (!tokenStream.peekTokenPos(&pn->pn_pos,
- fun->isArrow() ? TokenStream::Operand : TokenStream::None))
- {
- return null();
- }
-
- YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
+ // is a not-async arrow, use TokenStream::Operand to keep
+ // verifyConsistentModifier from complaining (we will use
+ // TokenStream::Operand in functionArguments).
+ TokenStream::Modifier modifier = (fun->isArrow() && asyncKind == SyncFunction)
+ ? TokenStream::Operand : TokenStream::None;
+ if (!tokenStream.peekTokenPos(&pn->pn_pos, modifier))
+ return null();
+
+ YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
FunctionSyntaxKind syntaxKind = Statement;
if (fun->isClassConstructor())
syntaxKind = ClassConstructor;
else if (fun->isMethod())
syntaxKind = Method;
else if (fun->isGetter())
syntaxKind = Getter;
else if (fun->isSetter())
@@ -3393,19 +3404,17 @@ Parser<ParseHandler>::functionFormalPara
#endif
}
// Arrow function parameters inherit yieldHandling from the enclosing
// context, but the arrow body doesn't. E.g. in |(a = yield) => yield|,
// |yield| in the parameters is either a name or keyword, depending on
// whether the arrow function is enclosed in a generator function or not.
// Whereas the |yield| in the function body is always parsed as a name.
- YieldHandling bodyYieldHandling = pc->isGenerator() ? YieldIsKeyword : YieldIsName;
- MOZ_ASSERT_IF(yieldHandling != bodyYieldHandling, kind == Arrow);
-
+ YieldHandling bodyYieldHandling = GetYieldHandling(pc->generatorKind(), pc->asyncKind());
Node body = functionBody(inHandling, bodyYieldHandling, kind, bodyType);
if (!body)
return false;
if ((kind != Method && !IsConstructorKind(kind)) && fun->name()) {
RootedPropertyName propertyName(context, fun->name()->asPropertyName());
if (!checkStrictBinding(propertyName, handler.getPosition(pn)))
return false;
@@ -3441,17 +3450,18 @@ Parser<ParseHandler>::functionFormalPara
handler.setEndPosition(pn, pos().end);
handler.setFunctionBody(pn, body);
return true;
}
template <typename ParseHandler>
typename ParseHandler::Node
-Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling)
+Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling,
+ FunctionAsyncKind asyncKind)
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
// Annex B.3.4 says we can parse function declarations unbraced under if
// or else as if it were braced. That is, |if (x) function f() {}| is
// parsed as |if (x) { function f() {} }|.
Maybe<ParseContext::Statement> synthesizedStmtForAnnexB;
Maybe<ParseContext::Scope> synthesizedScopeForAnnexB;
@@ -3461,22 +3471,26 @@ Parser<ParseHandler>::functionStmt(Yield
synthesizedStmtForAnnexB.emplace(pc, StatementKind::Block);
synthesizedScopeForAnnexB.emplace(this);
if (!synthesizedScopeForAnnexB->init(pc))
return null();
}
}
RootedPropertyName name(context);
- GeneratorKind generatorKind = NotGenerator;
+ GeneratorKind generatorKind = asyncKind == AsyncFunction ? StarGenerator : NotGenerator;
TokenKind tt;
if (!tokenStream.getToken(&tt))
return null();
if (tt == TOK_MUL) {
+ if (asyncKind != SyncFunction) {
+ report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR);
+ return null();
+ }
generatorKind = StarGenerator;
if (!tokenStream.getToken(&tt))
return null();
}
if (tt == TOK_NAME || tt == TOK_YIELD) {
name = bindingIdentifier(yieldHandling);
if (!name)
@@ -3485,19 +3499,19 @@ Parser<ParseHandler>::functionStmt(Yield
name = context->names().starDefaultStar;
tokenStream.ungetToken();
} else {
/* Unnamed function expressions are forbidden in statement context. */
report(ParseError, false, null(), JSMSG_UNNAMED_FUNCTION_STMT);
return null();
}
- YieldHandling newYieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
+ YieldHandling newYieldHandling = GetYieldHandling(generatorKind, asyncKind);
Node fun = functionDefinition(InAllowed, newYieldHandling, name, Statement, generatorKind,
- SyncFunction, PredictUninvoked);
+ asyncKind, PredictUninvoked);
if (!fun)
return null();
if (synthesizedStmtForAnnexB) {
Node synthesizedStmtList = handler.newStatementList(handler.getPosition(fun));
if (!synthesizedStmtList)
return null();
handler.addStatementToList(synthesizedStmtList, fun);
@@ -3519,17 +3533,17 @@ Parser<ParseHandler>::functionExpr(Invok
return null();
if (tt == TOK_MUL) {
generatorKind = StarGenerator;
if (!tokenStream.getToken(&tt))
return null();
}
- YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
+ YieldHandling yieldHandling = GetYieldHandling(generatorKind, SyncFunction);
RootedPropertyName name(context);
if (tt == TOK_NAME || tt == TOK_YIELD) {
name = bindingIdentifier(yieldHandling);
if (!name)
return null();
} else {
tokenStream.ungetToken();
@@ -6945,16 +6959,26 @@ Parser<ParseHandler>::statementListItem(
if (!tokenStream.currentToken().nameContainsEscape() &&
tokenStream.currentName() == context->names().let &&
nextTokenContinuesLetDeclaration(next, yieldHandling))
{
return lexicalDeclaration(yieldHandling, /* isConst = */ false);
}
+ if (tokenStream.currentName() == context->names().async) {
+ TokenKind nextSameLine = TOK_EOF;
+ if (!tokenStream.peekTokenSameLine(&nextSameLine))
+ return null();
+ if (nextSameLine == TOK_FUNCTION) {
+ tokenStream.consumeKnownToken(TOK_FUNCTION);
+ return functionStmt(yieldHandling, NameRequired, AsyncFunction);
+ }
+ }
+
if (next == TOK_COLON)
return labeledStatement(yieldHandling);
return expressionStatement(yieldHandling);
}
case TOK_NEW:
return expressionStatement(yieldHandling, PredictInvoked);
@@ -9049,17 +9073,17 @@ Parser<ParseHandler>::objectLiteral(Yiel
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::methodDefinition(PropertyType propType, HandleAtom funName)
{
FunctionSyntaxKind kind = FunctionSyntaxKindFromPropertyType(propType);
GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType);
- YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
+ YieldHandling yieldHandling = GetYieldHandling(generatorKind, SyncFunction);
return functionDefinition(InAllowed, yieldHandling, funName, kind, generatorKind, SyncFunction);
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::tryNewTarget(Node &newTarget)
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_NEW));
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -497,16 +497,20 @@ class ParseContext : public Nestable<Par
bool isStarGenerator() const {
return generatorKind() == StarGenerator;
}
bool isAsync() const {
return sc_->isFunctionBox() && sc_->asFunctionBox()->isAsync();
}
+ FunctionAsyncKind asyncKind() const {
+ return isAsync() ? AsyncFunction : SyncFunction;
+ }
+
bool isArrowFunction() const {
return sc_->isFunctionBox() && sc_->asFunctionBox()->function()->isArrow();
}
bool isMethod() const {
return sc_->isFunctionBox() && sc_->asFunctionBox()->function()->isMethod();
}
@@ -1030,17 +1034,17 @@ class Parser final : private JS::AutoGCR
// ParseContext is already on the stack.
bool functionFormalParametersAndBody(InHandling inHandling, YieldHandling yieldHandling,
Node pn, FunctionSyntaxKind kind);
// Determine whether |yield| is a valid name in the current context, or
// whether it's prohibited due to strictness, JS version, or occurrence
// inside a star generator.
bool yieldExpressionsSupported() {
- return versionNumber() >= JSVERSION_1_7 || pc->isGenerator();
+ return (versionNumber() >= JSVERSION_1_7 || pc->isGenerator()) && !pc->isAsync();
}
// Match the current token against the BindingIdentifier production with
// the given Yield parameter. If there is no match, report a syntax
// error.
PropertyName* bindingIdentifier(YieldHandling yieldHandling);
virtual bool strictMode() { return pc->sc()->strict(); }
@@ -1069,17 +1073,18 @@ class Parser final : private JS::AutoGCR
* Parsers whose name has a '1' suffix leave the TokenStream state
* pointing to the token one past the end of the parsed fragment. For a
* number of the parsers this is convenient and avoids a lot of
* unnecessary ungetting and regetting of tokens.
*
* Some parsers have two versions: an always-inlined version (with an 'i'
* suffix) and a never-inlined version (with an 'n' suffix).
*/
- Node functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling);
+ Node functionStmt(YieldHandling yieldHandling, DefaultHandling defaultHandling,
+ FunctionAsyncKind asyncKind = SyncFunction);
Node functionExpr(InvokedPrediction invoked = PredictUninvoked);
Node statementList(YieldHandling yieldHandling);
Node blockStatement(YieldHandling yieldHandling,
unsigned errorNumber = JSMSG_CURLY_IN_COMPOUND);
Node doWhileStatement(YieldHandling yieldHandling);
Node whileStatement(YieldHandling yieldHandling);
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -176,16 +176,17 @@ MSG_DEF(JSMSG_UNCAUGHT_EXCEPTION, 1
MSG_DEF(JSMSG_UNKNOWN_FORMAT, 1, JSEXN_INTERNALERR, "unknown bytecode format {0}")
// Frontend
MSG_DEF(JSMSG_ACCESSOR_WRONG_ARGS, 3, JSEXN_SYNTAXERR, "{0} functions must have {1} argument{2}")
MSG_DEF(JSMSG_ARRAY_COMP_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid array comprehension left-hand side")
MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG, 0, JSEXN_INTERNALERR, "array initializer too large")
MSG_DEF(JSMSG_AS_AFTER_IMPORT_STAR, 0, JSEXN_SYNTAXERR, "missing keyword 'as' after import *")
MSG_DEF(JSMSG_AS_AFTER_RESERVED_WORD, 1, JSEXN_SYNTAXERR, "missing keyword 'as' after reserved word '{0}'")
+MSG_DEF(JSMSG_ASYNC_GENERATOR, 0, JSEXN_SYNTAXERR, "generator function or method can't be async")
MSG_DEF(JSMSG_BAD_ANON_GENERATOR_RETURN, 0, JSEXN_TYPEERR, "anonymous generator function returns a value")
MSG_DEF(JSMSG_BAD_ARROW_ARGS, 0, JSEXN_SYNTAXERR, "invalid arrow-function arguments (parentheses around the arrow-function may help)")
MSG_DEF(JSMSG_BAD_BINDING, 1, JSEXN_SYNTAXERR, "redefining {0} is deprecated")
MSG_DEF(JSMSG_BAD_CONST_DECL, 0, JSEXN_SYNTAXERR, "missing = in const declaration")
MSG_DEF(JSMSG_BAD_CONTINUE, 0, JSEXN_SYNTAXERR, "continue must be inside loop")
MSG_DEF(JSMSG_BAD_DESTRUCT_ASS, 0, JSEXN_REFERENCEERR, "invalid destructuring assignment operator")
MSG_DEF(JSMSG_BAD_DESTRUCT_TARGET, 0, JSEXN_SYNTAXERR, "invalid destructuring target")
MSG_DEF(JSMSG_BAD_DESTRUCT_PARENS, 0, JSEXN_SYNTAXERR, "destructuring patterns in assignments can't be parenthesized")
--- a/js/src/vm/CommonPropertyNames.h
+++ b/js/src/vm/CommonPropertyNames.h
@@ -24,16 +24,17 @@
macro(ArraySpecies, ArraySpecies, "ArraySpecies") \
macro(ArraySpeciesCreate, ArraySpeciesCreate, "ArraySpeciesCreate") \
macro(ArrayToLocaleString, ArrayToLocaleString, "ArrayToLocaleString") \
macro(ArrayType, ArrayType, "ArrayType") \
macro(ArrayValues, ArrayValues, "ArrayValues") \
macro(ArrayValuesAt, ArrayValuesAt, "ArrayValuesAt") \
macro(as, as, "as") \
macro(Async, Async, "Async") \
+ macro(async, async, "async") \
macro(await, await, "await") \
macro(Bool8x16, Bool8x16, "Bool8x16") \
macro(Bool16x8, Bool16x8, "Bool16x8") \
macro(Bool32x4, Bool32x4, "Bool32x4") \
macro(Bool64x2, Bool64x2, "Bool64x2") \
macro(boundWithSpace, boundWithSpace, "bound ") \
macro(breakdown, breakdown, "breakdown") \
macro(buffer, buffer, "buffer") \