Bug 1185106 - Part 7.1: Support async method in Parser. r=efaust,jwalden,till
MozReview-Commit-ID: IqaY6IwRiHr
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -6398,16 +6398,17 @@ JSOpFromPropertyType(PropertyType propTy
case PropertyType::GetterNoExpressionClosure:
return JSOP_INITPROP_GETTER;
case PropertyType::Setter:
case PropertyType::SetterNoExpressionClosure:
return JSOP_INITPROP_SETTER;
case PropertyType::Normal:
case PropertyType::Method:
case PropertyType::GeneratorMethod:
+ case PropertyType::AsyncMethod:
case PropertyType::Constructor:
case PropertyType::DerivedConstructor:
return JSOP_INITPROP;
default:
MOZ_CRASH("unexpected property type");
}
}
@@ -6419,32 +6420,44 @@ FunctionSyntaxKindFromPropertyType(Prope
return Getter;
case PropertyType::GetterNoExpressionClosure:
return GetterNoExpressionClosure;
case PropertyType::Setter:
return Setter;
case PropertyType::SetterNoExpressionClosure:
return SetterNoExpressionClosure;
case PropertyType::Method:
- return Method;
case PropertyType::GeneratorMethod:
+ case PropertyType::AsyncMethod:
return Method;
case PropertyType::Constructor:
return ClassConstructor;
case PropertyType::DerivedConstructor:
return DerivedClassConstructor;
default:
MOZ_CRASH("unexpected property type");
}
}
static GeneratorKind
GeneratorKindFromPropertyType(PropertyType propType)
{
- return propType == PropertyType::GeneratorMethod ? StarGenerator : NotGenerator;
+ if (propType == PropertyType::GeneratorMethod)
+ return StarGenerator;
+ if (propType == PropertyType::AsyncMethod)
+ return StarGenerator;
+ return NotGenerator;
+}
+
+static FunctionAsyncKind
+AsyncKindFromPropertyType(PropertyType propType)
+{
+ if (propType == PropertyType::AsyncMethod)
+ return AsyncFunction;
+ return SyncFunction;
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::classDefinition(YieldHandling yieldHandling,
ClassContext classContext,
DefaultHandling defaultHandling)
{
@@ -6548,16 +6561,17 @@ Parser<ParseHandler>::classDefinition(Yi
PropertyType propType;
Node propName = propertyName(yieldHandling, classMethods, &propType, &propAtom);
if (!propName)
return null();
if (propType != PropertyType::Getter && propType != PropertyType::Setter &&
propType != PropertyType::Method && propType != PropertyType::GeneratorMethod &&
+ propType != PropertyType::AsyncMethod &&
propType != PropertyType::Constructor && propType != PropertyType::DerivedConstructor)
{
report(ParseError, false, null(), JSMSG_BAD_METHOD_DEF);
return null();
}
if (propType == PropertyType::Getter)
propType = PropertyType::GetterNoExpressionClosure;
@@ -8737,22 +8751,41 @@ Parser<ParseHandler>::propertyName(Yield
{
TokenKind ltok;
if (!tokenStream.getToken(<ok, TokenStream::KeywordIsName))
return null();
MOZ_ASSERT(ltok != TOK_RC, "caller should have handled TOK_RC");
bool isGenerator = false;
+ bool isAsync = false;
if (ltok == TOK_MUL) {
isGenerator = true;
if (!tokenStream.getToken(<ok, TokenStream::KeywordIsName))
return null();
}
+ if (ltok == TOK_NAME && tokenStream.currentName() == context->names().async) {
+ TokenKind tt;
+ if (!tokenStream.getToken(&tt, TokenStream::KeywordIsName))
+ return null();
+ if (tt != TOK_LP && tt != TOK_COLON) {
+ isAsync = true;
+ ltok = tt;
+ } else {
+ tokenStream.ungetToken();
+ tokenStream.addModifierException(TokenStream::NoneIsKeywordIsName);
+ }
+ }
+
+ if (isAsync && isGenerator) {
+ report(ParseError, false, null(), JSMSG_ASYNC_GENERATOR);
+ return null();
+ }
+
propAtom.set(nullptr);
Node propName;
switch (ltok) {
case TOK_NUMBER:
propAtom.set(DoubleToAtom(context, tokenStream.currentToken().number()));
if (!propAtom.get())
return null();
propName = newNumber(tokenStream.currentToken());
@@ -8764,17 +8797,17 @@ Parser<ParseHandler>::propertyName(Yield
propName = computedPropertyName(yieldHandling, propList);
if (!propName)
return null();
break;
case TOK_NAME: {
propAtom.set(tokenStream.currentName());
// Do not look for accessor syntax on generators
- if (isGenerator ||
+ if (isGenerator || isAsync ||
!(propAtom.get() == context->names().get ||
propAtom.get() == context->names().set))
{
propName = handler.newObjectLiteralPropertyName(propAtom, pos());
if (!propName)
return null();
break;
}
@@ -8883,17 +8916,22 @@ Parser<ParseHandler>::propertyName(Yield
*propType = tt == TOK_ASSIGN ?
PropertyType::CoverInitializedName :
PropertyType::Shorthand;
return propName;
}
if (tt == TOK_LP) {
tokenStream.ungetToken();
- *propType = isGenerator ? PropertyType::GeneratorMethod : PropertyType::Method;
+ if (isGenerator)
+ *propType = PropertyType::GeneratorMethod;
+ else if (isAsync)
+ *propType = PropertyType::AsyncMethod;
+ else
+ *propType = PropertyType::Method;
return propName;
}
report(ParseError, false, null(), JSMSG_COLON_AFTER_ID);
return null();
}
template <typename ParseHandler>
@@ -9115,18 +9153,19 @@ 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 = GetYieldHandling(generatorKind, SyncFunction);
- return functionDefinition(InAllowed, yieldHandling, funName, kind, generatorKind, SyncFunction);
+ FunctionAsyncKind asyncKind = AsyncKindFromPropertyType(propType);
+ YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
+ return functionDefinition(InAllowed, yieldHandling, funName, kind, generatorKind, asyncKind);
}
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
@@ -562,16 +562,17 @@ enum class PropertyType {
Shorthand,
CoverInitializedName,
Getter,
GetterNoExpressionClosure,
Setter,
SetterNoExpressionClosure,
Method,
GeneratorMethod,
+ AsyncMethod,
Constructor,
DerivedConstructor
};
// Specify a value for an ES6 grammar parametrization. We have no enum for
// [Return] because its behavior is exactly equivalent to checking whether
// we're in a function box -- easier and simpler than passing an extra
// parameter everywhere.