Bug 1185106 - Part 3: Add parser support for Async functions. (r=efaust)

This commit is contained in:
Mariusz Kierski 2015-10-05 13:24:03 -07:00
parent 293d33c5a6
commit 9a71bb7002
26 changed files with 427 additions and 75 deletions

View File

@ -6348,7 +6348,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut)
AsmJSParseContext* outerpc = m.parser().pc;
Directives directives(outerpc);
FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, outerpc, directives, NotGenerator);
FunctionBox* funbox = m.parser().newFunctionBox(fn, fun, outerpc, directives, NotGenerator, SyncFunction);
if (!funbox)
return false;

View File

@ -91,6 +91,7 @@ enum UnaryOperator {
UNOP_BITNOT,
UNOP_TYPEOF,
UNOP_VOID,
UNOP_AWAIT,
UNOP_LIMIT
};
@ -160,7 +161,8 @@ static const char* const unopNames[] = {
"!", /* UNOP_NOT */
"~", /* UNOP_BITNOT */
"typeof", /* UNOP_TYPEOF */
"void" /* UNOP_VOID */
"void", /* UNOP_VOID */
"await" /* UNOP_AWAIT */
};
static const char* const nodeTypeNames[] = {
@ -560,6 +562,29 @@ class NodeBuilder
setResult(node, dst);
}
bool newNode(ASTType type, TokenPos* pos,
const char* childName1, HandleValue child1,
const char* childName2, HandleValue child2,
const char* childName3, HandleValue child3,
const char* childName4, HandleValue child4,
const char* childName5, HandleValue child5,
const char* childName6, HandleValue child6,
const char* childName7, HandleValue child7,
const char* childName8, HandleValue child8,
MutableHandleValue dst) {
RootedObject node(cx);
return newNode(type, pos, &node) &&
setProperty(node, childName1, child1) &&
setProperty(node, childName2, child2) &&
setProperty(node, childName3, child3) &&
setProperty(node, childName4, child4) &&
setProperty(node, childName5, child5) &&
setProperty(node, childName6, child6) &&
setProperty(node, childName7, child7) &&
setProperty(node, childName8, child8) &&
setResult(node, dst);
}
bool listNode(ASTType type, const char* propName, NodeVector& elts, TokenPos* pos,
MutableHandleValue dst) {
RootedValue array(cx);
@ -620,8 +645,8 @@ class NodeBuilder
bool function(ASTType type, TokenPos* pos,
HandleValue id, NodeVector& args, NodeVector& defaults,
HandleValue body, HandleValue rest, bool isGenerator, bool isExpression,
MutableHandleValue dst);
HandleValue body, HandleValue rest, bool isGenerator, bool isAsync,
bool isExpression, MutableHandleValue dst);
bool variableDeclarator(HandleValue id, HandleValue init, TokenPos* pos,
MutableHandleValue dst);
@ -1757,7 +1782,7 @@ bool
NodeBuilder::function(ASTType type, TokenPos* pos,
HandleValue id, NodeVector& args, NodeVector& defaults,
HandleValue body, HandleValue rest,
bool isGenerator, bool isExpression,
bool isGenerator, bool isAsync, bool isExpression,
MutableHandleValue dst)
{
RootedValue array(cx), defarray(cx);
@ -1767,6 +1792,7 @@ NodeBuilder::function(ASTType type, TokenPos* pos,
return false;
RootedValue isGeneratorVal(cx, BooleanValue(isGenerator));
RootedValue isAsyncVal(cx, BooleanValue(isAsync));
RootedValue isExpressionVal(cx, BooleanValue(isExpression));
RootedValue cb(cx, callbacks[type]);
@ -1781,6 +1807,7 @@ NodeBuilder::function(ASTType type, TokenPos* pos,
"body", body,
"rest", rest,
"generator", isGeneratorVal,
"async", isAsyncVal,
"expression", isExpressionVal,
dst);
}
@ -2026,6 +2053,9 @@ ASTSerializer::unop(ParseNodeKind kind, JSOp op)
if (kind == PNK_TYPEOFNAME || kind == PNK_TYPEOFEXPR)
return UNOP_TYPEOF;
if (kind == PNK_AWAIT)
return UNOP_AWAIT;
switch (op) {
case JSOP_NEG:
return UNOP_NEG;
@ -3084,7 +3114,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
return leftAssociate(pn, dst);
case PNK_POW:
return rightAssociate(pn, dst);
return rightAssociate(pn, dst);
case PNK_DELETENAME:
case PNK_DELETEPROP:
@ -3096,6 +3126,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
case PNK_NOT:
case PNK_BITNOT:
case PNK_POS:
case PNK_AWAIT:
case PNK_NEG: {
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_kid->pn_pos));
@ -3565,7 +3596,7 @@ ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst)
// FIXME: Provide more information (legacy generator vs star generator).
bool isGenerator = pn->pn_funbox->isGenerator();
bool isAsync = pn->pn_funbox->isAsync();
bool isExpression =
#if JS_HAS_EXPR_CLOSURES
func->isExprBody();
@ -3588,7 +3619,7 @@ ASTSerializer::function(ParseNode* pn, ASTType type, MutableHandleValue dst)
rest.setNull();
return functionArgsAndBody(pn->pn_body, args, defaults, &body, &rest) &&
builder.function(type, &pn->pn_pos, id, args, defaults, body,
rest, isGenerator, isExpression, dst);
rest, isGenerator, isAsync, isExpression, dst);
}
bool

View File

@ -314,7 +314,7 @@ BytecodeCompiler::saveCallerFun(HandleScript evalCaller,
MOZ_ASSERT_IF(fun->strict(), options.strictOption);
Directives directives(/* strict = */ options.strictOption);
ObjectBox* funbox = parser->newFunctionBox(/* fn = */ nullptr, fun, &parseContext,
directives, fun->generatorKind());
directives, fun->generatorKind(), fun->asyncKind());
if (!funbox)
return false;
@ -705,7 +705,7 @@ BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun,
ParseNode* fn;
do {
Directives newDirectives = directives;
fn = parser->standaloneFunctionBody(fun, formals, generatorKind, directives,
fn = parser->standaloneFunctionBody(fun, formals, generatorKind, SyncFunction, directives,
&newDirectives, enclosingStaticScope);
if (!fn && !handleParseFailure(newDirectives))
return false;
@ -865,7 +865,7 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
Rooted<JSFunction*> fun(cx, lazy->functionNonDelazifying());
MOZ_ASSERT(!lazy->isLegacyGenerator());
ParseNode* pn = parser.standaloneLazyFunction(fun, lazy->strict(), lazy->generatorKind());
ParseNode* pn = parser.standaloneLazyFunction(fun, lazy->strict(), lazy->generatorKind(), lazy->asyncKind());
if (!pn)
return false;

View File

@ -1991,6 +1991,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
case PNK_PREDECREMENT:
case PNK_POSTDECREMENT:
case PNK_THROW:
case PNK_AWAIT:
MOZ_ASSERT(pn->isArity(PN_UNARY));
*answer = true;
return true;
@ -8021,6 +8022,13 @@ BytecodeEmitter::emitTree(ParseNode* pn)
return false;
break;
// PNK_AWAIT handling is not yet implemented (in this part),
// so currently we just return "true" as a placeholder.
case PNK_AWAIT:
if (!emit1(JSOP_TRUE))
return false;
break;
case PNK_POSHOLDER:
MOZ_ASSERT_UNREACHABLE("Should never try to emit PNK_POSHOLDER");

View File

@ -329,6 +329,7 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
case PNK_CONDITIONAL:
case PNK_TYPEOFNAME:
case PNK_TYPEOFEXPR:
case PNK_AWAIT:
case PNK_VOID:
case PNK_NOT:
case PNK_BITNOT:
@ -1853,6 +1854,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
return Fold(cx, &pn->pn_left, parser, inGenexpLambda);
case PNK_YIELD:
case PNK_AWAIT:
MOZ_ASSERT(pn->isArity(PN_BINARY));
MOZ_ASSERT((pn->pn_right->isKind(PNK_NAME) && !pn->pn_right->isAssigned()) ||
(pn->pn_right->isKind(PNK_ASSIGN) &&

View File

@ -436,6 +436,11 @@ class FullParseHandler
return new_<BinaryNode>(PNK_YIELD, op, pos, value, gen);
}
ParseNode* newAwaitExpression(uint32_t begin, ParseNode* value, ParseNode* gen) {
TokenPos pos(begin, value ? value->pn_pos.end : begin + 1);
return new_<BinaryNode>(PNK_AWAIT, JSOP_YIELD, pos, value, gen);
}
ParseNode* newYieldStarExpression(uint32_t begin, ParseNode* value, ParseNode* gen) {
TokenPos pos(begin, value->pn_pos.end);
return new_<BinaryNode>(PNK_YIELD_STAR, JSOP_NOP, pos, value, gen);

View File

@ -488,6 +488,7 @@ class NameResolver
break;
case PNK_YIELD:
case PNK_AWAIT:
MOZ_ASSERT(cur->isArity(PN_BINARY));
if (cur->pn_left) {
if (!resolve(cur->pn_left, prefix))

View File

@ -324,7 +324,8 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
// variable, or an assignment of a PNK_GENERATOR node to the '.generator'
// local, for a synthesized, prepended initial yield. Yum!
case PNK_YIELD_STAR:
case PNK_YIELD: {
case PNK_YIELD:
case PNK_AWAIT: {
MOZ_ASSERT(pn->isArity(PN_BINARY));
MOZ_ASSERT(pn->pn_right);
MOZ_ASSERT(pn->pn_right->isKind(PNK_NAME) ||
@ -701,7 +702,8 @@ Parser<FullParseHandler>::cloneParseTree(ParseNode* opn)
RootedFunction fun(context, opn->pn_funbox->function());
NULLCHECK(pn->pn_funbox = newFunctionBox(pn, fun, pc,
Directives(/* strict = */ opn->pn_funbox->strict()),
opn->pn_funbox->generatorKind()));
opn->pn_funbox->generatorKind(),
opn->pn_funbox->asyncKind()));
NULLCHECK(pn->pn_body = cloneParseTree(opn->pn_body));
pn->pn_scopecoord = opn->pn_scopecoord;
pn->pn_dflags = opn->pn_dflags;

View File

@ -183,6 +183,7 @@ class PackedScopeCoordinate
F(VOID) \
F(NOT) \
F(BITNOT) \
F(AWAIT) \
\
/* \
* Binary operators. \

View File

@ -645,7 +645,8 @@ Parser<ParseHandler>::newObjectBox(JSObject* obj)
template <typename ParseHandler>
FunctionBox::FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunction* fun,
JSObject* enclosingStaticScope, ParseContext<ParseHandler>* outerpc,
Directives directives, bool extraWarnings, GeneratorKind generatorKind)
Directives directives, bool extraWarnings, GeneratorKind generatorKind,
FunctionAsyncKind asyncKind)
: ObjectBox(fun, traceListHead),
SharedContext(cx, directives, extraWarnings),
bindings(),
@ -664,7 +665,8 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunct
usesArguments(false),
usesApply(false),
usesThis(false),
funCxFlags()
funCxFlags(),
_asyncKind(asyncKind)
{
// Functions created at parse time may be set singleton after parsing and
// baked into JIT code, so they must be allocated tenured. They are held by
@ -678,6 +680,7 @@ Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun,
ParseContext<ParseHandler>* outerpc,
Directives inheritedDirectives,
GeneratorKind generatorKind,
FunctionAsyncKind asyncKind,
JSObject* enclosingStaticScope)
{
MOZ_ASSERT_IF(outerpc, enclosingStaticScope == outerpc->innermostStaticScope());
@ -693,7 +696,7 @@ Parser<ParseHandler>::newFunctionBox(Node fn, JSFunction* fun,
FunctionBox* funbox =
alloc.new_<FunctionBox>(context, traceListHead, fun, enclosingStaticScope, outerpc,
inheritedDirectives, options().extraWarningsOption,
generatorKind);
generatorKind, asyncKind);
if (!funbox) {
ReportOutOfMemory(context);
return nullptr;
@ -836,7 +839,9 @@ Parser<ParseHandler>::checkStrictBinding(PropertyName* name, Node pn)
if (!pc->sc->needStrictChecks())
return true;
if (name == context->names().eval || name == context->names().arguments || IsKeyword(name)) {
if (name == context->names().eval || name == context->names().arguments ||
(IsKeyword(name) && name != context->names().await))
{
JSAutoByteString bytes;
if (!AtomToPrintableString(context, name, &bytes))
return false;
@ -866,7 +871,10 @@ Parser<ParseHandler>::standaloneModule(HandleModuleObject module)
if (!modulepc.init(*this))
return null();
bool awaitIsKeyword = tokenStream.getAwaitIsKeyword();
tokenStream.setAwaitIsKeyword(true);
ParseNode* pn = statements(YieldIsKeyword);
tokenStream.setAwaitIsKeyword(awaitIsKeyword);
if (!pn)
return null();
@ -941,6 +949,7 @@ ParseNode*
Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
Handle<PropertyNameVector> formals,
GeneratorKind generatorKind,
FunctionAsyncKind asyncKind,
Directives inheritedDirectives,
Directives* newDirectives,
HandleObject enclosingStaticScope)
@ -957,7 +966,7 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
fn->pn_body = argsbody;
FunctionBox* funbox = newFunctionBox(fn, fun, inheritedDirectives, generatorKind,
enclosingStaticScope);
asyncKind, enclosingStaticScope);
if (!funbox)
return null();
funbox->length = fun->nargs() - fun->hasRest();
@ -1406,7 +1415,8 @@ struct BindData
template <typename ParseHandler>
JSFunction*
Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
GeneratorKind generatorKind, HandleObject proto)
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
HandleObject proto)
{
MOZ_ASSERT_IF(kind == Statement, atom != nullptr);
@ -1452,6 +1462,10 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
: JSFunction::INTERPRETED_GENERATOR);
}
// We store the async wrapper in a slot for later access.
if (asyncKind == AsyncFunction)
allocKind = gc::AllocKind::FUNCTION_EXTENDED;
fun = NewFunctionWithProto(context, nullptr, 0, flags, nullptr, atom, proto,
allocKind, TenuredObject);
if (!fun)
@ -1833,7 +1847,7 @@ Parser<ParseHandler>::bindDestructuringArg(BindData<ParseHandler>* data,
template <typename ParseHandler>
bool
Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind,
Node funcpn, bool* hasRest)
FunctionAsyncKind asyncKind, Node funcpn, bool* hasRest)
{
FunctionBox* funbox = pc->sc->asFunctionBox();
@ -2021,11 +2035,20 @@ Parser<ParseHandler>::functionArguments(YieldHandling yieldHandling, FunctionSyn
// before the first default argument.
funbox->length = pc->numArgs() - 1;
}
Node def_expr = assignExprWithoutYield(yieldHandling, JSMSG_YIELD_IN_DEFAULT);
bool awaitIsKeyword;
if (asyncKind == AsyncFunction) {
awaitIsKeyword = tokenStream.getAwaitIsKeyword();
tokenStream.setAwaitIsKeyword(true);
}
Node def_expr = assignExprWithoutYieldAndAwait(yieldHandling, JSMSG_YIELD_IN_DEFAULT);
if (!def_expr)
return false;
if (!handler.setLastFunctionArgumentDefault(funcpn, def_expr))
return false;
if (asyncKind == AsyncFunction) {
tokenStream.setAwaitIsKeyword(awaitIsKeyword);
}
}
if (parenFreeArrow || IsSetterKind(kind))
@ -2210,7 +2233,7 @@ Parser<FullParseHandler>::checkFunctionDefinition(HandlePropertyName funName,
RootedFunction fun(context, handler.nextLazyInnerFunction());
MOZ_ASSERT(!fun->isLegacyGenerator());
FunctionBox* funbox = newFunctionBox(pn, fun, pc, Directives(/* strict = */ false),
fun->generatorKind());
fun->generatorKind(), fun->asyncKind());
if (!funbox)
return false;
@ -2419,9 +2442,11 @@ template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::functionDef(InHandling inHandling, YieldHandling yieldHandling,
HandlePropertyName funName, FunctionSyntaxKind kind,
GeneratorKind generatorKind, InvokedPrediction invoked)
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
InvokedPrediction invoked)
{
MOZ_ASSERT_IF(kind == Statement, funName);
MOZ_ASSERT_IF(asyncKind == AsyncFunction, generatorKind == StarGenerator);
/* Make a TOK_FUNCTION node. */
Node pn = handler.newFunctionDefinition();
@ -2448,7 +2473,7 @@ Parser<ParseHandler>::functionDef(InHandling inHandling, YieldHandling yieldHand
if (!proto)
return null();
}
RootedFunction fun(context, newFunction(funName, kind, generatorKind, proto));
RootedFunction fun(context, newFunction(funName, kind, generatorKind, asyncKind, proto));
if (!fun)
return null();
@ -2463,8 +2488,8 @@ Parser<ParseHandler>::functionDef(InHandling inHandling, YieldHandling yieldHand
tokenStream.tell(&start);
while (true) {
if (functionArgsAndBody(inHandling, pn, fun, kind, generatorKind, directives,
&newDirectives))
if (functionArgsAndBody(inHandling, pn, fun, kind, generatorKind, asyncKind,
directives, &newDirectives))
{
break;
}
@ -2534,6 +2559,7 @@ Parser<SyntaxParseHandler>::finishFunctionDefinition(Node pn, FunctionBox* funbo
if (pc->sc->strict())
lazy->setStrict();
lazy->setGeneratorKind(funbox->generatorKind());
lazy->setAsyncKind(funbox->asyncKind());
if (funbox->usesArguments && funbox->usesApply && funbox->usesThis)
lazy->setUsesArgumentsApplyAndThis();
if (funbox->isDerivedClassConstructor())
@ -2551,13 +2577,14 @@ bool
Parser<FullParseHandler>::functionArgsAndBody(InHandling inHandling, ParseNode* pn,
HandleFunction fun, FunctionSyntaxKind kind,
GeneratorKind generatorKind,
FunctionAsyncKind asyncKind,
Directives inheritedDirectives,
Directives* newDirectives)
{
ParseContext<FullParseHandler>* outerpc = pc;
// Create box for fun->object early to protect against last-ditch GC.
FunctionBox* funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind);
FunctionBox* funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind, asyncKind);
if (!funbox)
return false;
@ -2656,13 +2683,14 @@ bool
Parser<SyntaxParseHandler>::functionArgsAndBody(InHandling inHandling, Node pn, HandleFunction fun,
FunctionSyntaxKind kind,
GeneratorKind generatorKind,
FunctionAsyncKind asyncKind,
Directives inheritedDirectives,
Directives* newDirectives)
{
ParseContext<SyntaxParseHandler>* outerpc = pc;
// Create box for fun->object early to protect against last-ditch GC.
FunctionBox* funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind);
FunctionBox* funbox = newFunctionBox(pn, fun, pc, inheritedDirectives, generatorKind, asyncKind);
if (!funbox)
return false;
@ -2678,7 +2706,6 @@ Parser<SyntaxParseHandler>::functionArgsAndBody(InHandling inHandling, Node pn,
if (!leaveFunction(pn, outerpc, kind))
return false;
// This is a lazy function inner to another lazy function. Remember the
// inner function so that if the outer function is eventually parsed we do
// not need any further parsing or processing of the inner function.
@ -2707,7 +2734,8 @@ Parser<ParseHandler>::appendToCallSiteObj(Node callSiteObj)
template <>
ParseNode*
Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, bool strict,
GeneratorKind generatorKind)
GeneratorKind generatorKind,
FunctionAsyncKind asyncKind)
{
MOZ_ASSERT(checkOptionsCalled);
@ -2722,7 +2750,7 @@ Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, bool strict
RootedObject enclosing(context, fun->lazyScript()->enclosingScope());
Directives directives(/* strict = */ strict);
FunctionBox* funbox = newFunctionBox(pn, fun, directives, generatorKind, enclosing);
FunctionBox* funbox = newFunctionBox(pn, fun, directives, generatorKind, asyncKind, enclosing);
if (!funbox)
return null();
funbox->length = fun->nargs() - fun->hasRest();
@ -2780,12 +2808,12 @@ Parser<ParseHandler>::functionArgsAndBodyGeneric(InHandling inHandling,
// function without concern for conversion to strict mode, use of lazy
// parsing and such.
bool hasRest;
if (!functionArguments(yieldHandling, kind, pn, &hasRest))
return false;
FunctionBox* funbox = pc->sc->asFunctionBox();
bool hasRest;
if (!functionArguments(yieldHandling, kind, funbox->asyncKind(), pn, &hasRest))
return false;
fun->setArgCount(pc->numArgs());
if (hasRest)
fun->setHasRest();
@ -2829,9 +2857,12 @@ Parser<ParseHandler>::functionArgsAndBodyGeneric(InHandling inHandling,
#endif
}
bool beforeAwaitIsKeyword = tokenStream.getAwaitIsKeyword();
tokenStream.setAwaitIsKeyword(funbox->isAsync());
Node body = functionBody(inHandling, yieldHandling, kind, bodyType);
if (!body)
return false;
tokenStream.setAwaitIsKeyword(beforeAwaitIsKeyword);
if ((kind != Method && !IsConstructorKind(kind)) && fun->name() &&
!checkStrictBinding(fun->name(), pn))
@ -2877,7 +2908,8 @@ Parser<ParseHandler>::checkYieldNameValidity()
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));
@ -2888,6 +2920,10 @@ Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling
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();
@ -2913,12 +2949,14 @@ Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling
!report(ParseStrictError, pc->sc->strict(), null(), JSMSG_STRICT_FUNCTION_STATEMENT))
return null();
return functionDef(InAllowed, yieldHandling, name, Statement, generatorKind);
if (asyncKind == AsyncFunction)
generatorKind = StarGenerator;
return functionDef(InAllowed, yieldHandling, name, Statement, generatorKind, asyncKind);
}
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::functionExpr(InvokedPrediction invoked)
Parser<ParseHandler>::functionExpr(InvokedPrediction invoked, FunctionAsyncKind asyncKind)
{
MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_FUNCTION));
@ -2928,6 +2966,10 @@ Parser<ParseHandler>::functionExpr(InvokedPrediction invoked)
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();
@ -2944,8 +2986,10 @@ Parser<ParseHandler>::functionExpr(InvokedPrediction invoked)
tokenStream.ungetToken();
}
if (asyncKind == AsyncFunction)
generatorKind = StarGenerator;
YieldHandling yieldHandling = generatorKind != NotGenerator ? YieldIsKeyword : YieldIsName;
return functionDef(InAllowed, yieldHandling, name, Expression, generatorKind, invoked);
return functionDef(InAllowed, yieldHandling, name, Expression, generatorKind, asyncKind, invoked);
}
/*
@ -4933,7 +4977,7 @@ Parser<FullParseHandler>::exportDeclaration()
}
case TOK_FUNCTION:
kid = functionStmt(YieldIsKeyword, NameRequired);
kid = functionStmt(YieldIsKeyword, NameRequired, SyncFunction);
if (!kid)
return null();
@ -4983,7 +5027,7 @@ Parser<FullParseHandler>::exportDeclaration()
ParseNode* binding = nullptr;
switch (tt) {
case TOK_FUNCTION:
kid = functionStmt(YieldIsKeyword, AllowDefaultName);
kid = functionStmt(YieldIsKeyword, AllowDefaultName, SyncFunction);
if (!kid)
return null();
break;
@ -5968,7 +6012,7 @@ Parser<ParseHandler>::returnStatement(YieldHandling yieldHandling)
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::newYieldExpression(uint32_t begin, typename ParseHandler::Node expr,
bool isYieldStar)
bool isYieldStar, bool isAwait)
{
Node generator = newName(context->names().dotGenerator);
if (!generator)
@ -5977,7 +6021,9 @@ Parser<ParseHandler>::newYieldExpression(uint32_t begin, typename ParseHandler::
return null();
if (isYieldStar)
return handler.newYieldStarExpression(begin, expr, generator);
return handler.newYieldExpression(begin, expr, generator);
if (isAwait)
return handler.newAwaitExpression(begin, expr, generator);
return handler.newYieldExpression(begin, expr, generator, JSOP_YIELD);
}
template <typename ParseHandler>
@ -6430,6 +6476,7 @@ JSOpFromPropertyType(PropertyType propType)
case PropertyType::Normal:
case PropertyType::Method:
case PropertyType::GeneratorMethod:
case PropertyType::AsyncMethod:
case PropertyType::Constructor:
case PropertyType::DerivedConstructor:
return JSOP_INITPROP;
@ -6451,8 +6498,8 @@ FunctionSyntaxKindFromPropertyType(PropertyType propType)
case PropertyType::SetterNoExpressionClosure:
return SetterNoExpressionClosure;
case PropertyType::Method:
return Method;
case PropertyType::GeneratorMethod:
case PropertyType::AsyncMethod:
return Method;
case PropertyType::Constructor:
return ClassConstructor;
@ -6466,7 +6513,15 @@ FunctionSyntaxKindFromPropertyType(PropertyType propType)
static GeneratorKind
GeneratorKindFromPropertyType(PropertyType propType)
{
return propType == PropertyType::GeneratorMethod ? StarGenerator : NotGenerator;
return (propType == PropertyType::GeneratorMethod ||
propType == PropertyType::AsyncMethod)
? StarGenerator : NotGenerator;
}
static FunctionAsyncKind
AsyncKindFromPropertyType(PropertyType propType)
{
return propType == PropertyType::AsyncMethod ? AsyncFunction : SyncFunction;
}
template <>
@ -6580,6 +6635,7 @@ Parser<FullParseHandler>::classDefinition(YieldHandling yieldHandling,
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);
@ -6748,6 +6804,19 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling, bool canHaveDirecti
case TOK_NAME: {
TokenKind next;
TokenKind nextSameLine = TOK_EOF;
#ifdef NIGHTLY_BUILD
if (tokenStream.currentName() == context->names().async) {
if (!tokenStream.peekTokenSameLine(&nextSameLine))
return null();
if (nextSameLine == TOK_FUNCTION) {
tokenStream.consumeKnownToken(TOK_FUNCTION);
return functionStmt(yieldHandling, NameRequired, AsyncFunction);
}
}
#endif
if (!tokenStream.peekToken(&next))
return null();
if (next == TOK_COLON)
@ -6822,7 +6891,7 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling, bool canHaveDirecti
// HoistableDeclaration[?Yield]
case TOK_FUNCTION:
return functionStmt(yieldHandling, NameRequired);
return functionStmt(yieldHandling, NameRequired, SyncFunction);
// ClassDeclaration[?Yield]
case TOK_CLASS:
@ -7136,6 +7205,20 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
bool endsExpr;
if (tt == TOK_NAME) {
TokenKind nextSameLine = TOK_EOF;
#ifdef NIGHTLY_BUILD
if (tokenStream.currentName() == context->names().async) {
if (!tokenStream.peekTokenSameLine(&nextSameLine))
return null();
if (nextSameLine == TOK_FUNCTION) {
tokenStream.consumeKnownToken(TOK_FUNCTION);
return functionExpr(PredictUninvoked, AsyncFunction);
}
}
#endif
if (!tokenStream.nextTokenEndsExpr(&endsExpr))
return null();
if (endsExpr)
@ -7156,8 +7239,14 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
return stringLiteral();
}
if (tt == TOK_YIELD && yieldExpressionsSupported())
if (tt == TOK_YIELD && yieldExpressionsSupported()) {
if (pc->isAsync()) {
report(ParseError, false, null(), JSMSG_YIELD_IN_ASYNC);
return null();
}
return yieldExpression(inHandling);
}
tokenStream.ungetToken();
@ -7217,7 +7306,7 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
return null();
}
Node arrowFunc = functionDef(inHandling, yieldHandling, nullptr, Arrow, NotGenerator);
Node arrowFunc = functionDef(inHandling, yieldHandling, nullptr, Arrow, NotGenerator, SyncFunction);
if (!arrowFunc)
return null();
@ -7479,6 +7568,25 @@ Parser<ParseHandler>::unaryExpr(YieldHandling yieldHandling, InvokedPrediction i
return handler.newDelete(begin, expr);
}
case TOK_AWAIT:
{
TokenKind nextSameLine = TOK_EOF;
#ifdef NIGHTLY_BUILD
if (!tokenStream.peekTokenSameLine(&nextSameLine, TokenStream::Operand))
return null();
if (nextSameLine != TOK_EOL) {
Node kid = unaryExpr(yieldHandling);
if (!kid)
return null();
return newYieldExpression(begin, kid, /* isYieldStar = */ false, /* isAwait = */ true);
} else {
report(ParseError, false, null(), JSMSG_LINE_BREAK_AFTER_AWAIT);
return null();
}
#endif
}
default: {
Node pn = memberExpr(yieldHandling, tt, /* allowCallSyntax = */ true, invoked);
if (!pn)
@ -8056,13 +8164,13 @@ Parser<ParseHandler>::generatorComprehensionLambda(GeneratorKind comprehensionKi
}
RootedFunction fun(context, newFunction(/* atom = */ nullptr, Expression,
comprehensionKind, proto));
comprehensionKind, SyncFunction, proto));
if (!fun)
return null();
// Create box for fun->object early to root it.
Directives directives(/* strict = */ outerpc->sc->strict());
FunctionBox* genFunbox = newFunctionBox(genfn, fun, outerpc, directives, comprehensionKind);
FunctionBox* genFunbox = newFunctionBox(genfn, fun, outerpc, directives, comprehensionKind, SyncFunction);
if (!genFunbox)
return null();
@ -8390,8 +8498,16 @@ Parser<ParseHandler>::generatorComprehension(uint32_t begin)
template <typename ParseHandler>
typename ParseHandler::Node
Parser<ParseHandler>::assignExprWithoutYield(YieldHandling yieldHandling, unsigned msg)
Parser<ParseHandler>::assignExprWithoutYieldAndAwait(YieldHandling yieldHandling, unsigned msg)
{
TokenKind tt;
if (!tokenStream.peekToken(&tt, TokenStream::Operand))
return null();
if (tt == TOK_AWAIT) {
report(ParseError, false, null(), JSMSG_AWAIT_IN_DEFAULT);
return null();
}
uint32_t startYieldOffset = pc->lastYieldOffset;
Node res = assignExpr(InAllowed, yieldHandling);
if (res && pc->lastYieldOffset != startYieldOffset) {
@ -8923,12 +9039,32 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
MOZ_ASSERT(ltok != TOK_RC);
bool isGenerator = false;
bool isAsync = false;
if (ltok == TOK_MUL) {
isGenerator = true;
if (!tokenStream.getToken(&ltok, 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) {
@ -8950,7 +9086,7 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
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))
{
@ -9067,7 +9203,8 @@ Parser<ParseHandler>::propertyName(YieldHandling yieldHandling, Node propList,
if (tt == TOK_LP) {
tokenStream.ungetToken();
*propType = isGenerator ? PropertyType::GeneratorMethod : PropertyType::Method;
*propType = isGenerator ? PropertyType::GeneratorMethod :
(isAsync ? PropertyType::AsyncMethod : PropertyType::Method);
return propName;
}
@ -9214,7 +9351,8 @@ Parser<ParseHandler>::methodDefinition(YieldHandling yieldHandling, PropertyType
{
FunctionSyntaxKind kind = FunctionSyntaxKindFromPropertyType(propType);
GeneratorKind generatorKind = GeneratorKindFromPropertyType(propType);
return functionDef(InAllowed, yieldHandling, funName, kind, generatorKind);
FunctionAsyncKind asyncKind = AsyncKindFromPropertyType(propType);
return functionDef(InAllowed, yieldHandling, funName, kind, generatorKind, asyncKind);
}
template <typename ParseHandler>
@ -9323,7 +9461,8 @@ Parser<ParseHandler>::primaryExpr(YieldHandling yieldHandling, TokenKind tt,
case TOK_YIELD:
if (!checkYieldNameValidity())
return null();
// Fall through.
// Fall through.
case TOK_NAME:
return identifierName(yieldHandling);

View File

@ -127,6 +127,8 @@ struct MOZ_STACK_CLASS ParseContext : public GenericParseContext
bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; }
bool isStarGenerator() const { return generatorKind() == StarGenerator; }
bool isAsync() const { return sc->isFunctionBox() && sc->asFunctionBox()->isAsync(); }
bool isArrowFunction() const {
return sc->isFunctionBox() && sc->asFunctionBox()->function()->isArrow();
}
@ -363,6 +365,7 @@ enum class PropertyType {
SetterNoExpressionClosure,
Method,
GeneratorMethod,
AsyncMethod,
Constructor,
DerivedConstructor
};
@ -504,22 +507,26 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
ObjectBox* newObjectBox(JSObject* obj);
FunctionBox* newFunctionBox(Node fn, JSFunction* fun, ParseContext<ParseHandler>* outerpc,
Directives directives, GeneratorKind generatorKind,
FunctionAsyncKind asyncKind,
JSObject* enclosingStaticScope);
// Use when the funbox is the outermost.
FunctionBox* newFunctionBox(Node fn, HandleFunction fun, Directives directives,
GeneratorKind generatorKind, HandleObject enclosingStaticScope)
GeneratorKind generatorKind,
FunctionAsyncKind asyncKind,
HandleObject enclosingStaticScope)
{
return newFunctionBox(fn, fun, nullptr, directives, generatorKind,
enclosingStaticScope);
asyncKind, enclosingStaticScope);
}
// Use when the funbox should be linked to the outerpc's innermost scope.
FunctionBox* newFunctionBox(Node fn, HandleFunction fun, ParseContext<ParseHandler>* outerpc,
Directives directives, GeneratorKind generatorKind)
Directives directives, GeneratorKind generatorKind,
FunctionAsyncKind asyncKind)
{
RootedObject enclosing(context, outerpc->innermostStaticScope());
return newFunctionBox(fn, fun, outerpc, directives, generatorKind, enclosing);
return newFunctionBox(fn, fun, outerpc, directives, generatorKind, asyncKind, enclosing);
}
ModuleBox* newModuleBox(Node pn, HandleModuleObject module);
@ -529,7 +536,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
* a function expression).
*/
JSFunction* newFunction(HandleAtom atom, FunctionSyntaxKind kind, GeneratorKind generatorKind,
HandleObject proto);
FunctionAsyncKind asyncKind, HandleObject proto);
bool generateBlockId(JSObject* staticScope, uint32_t* blockIdOut) {
if (blockScopes.length() == StmtInfoPC::BlockIdLimit) {
@ -568,7 +575,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
TokenKind* ttp);
inline Node newName(PropertyName* name);
inline Node newYieldExpression(uint32_t begin, Node expr, bool isYieldStar = false);
inline Node newYieldExpression(uint32_t begin, Node expr, bool isYieldStar = false, bool isAsync = false);
inline bool abortIfSyntaxParser();
@ -589,13 +596,14 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
// Parse a function, given only its body. Used for the Function and
// Generator constructors.
Node standaloneFunctionBody(HandleFunction fun, Handle<PropertyNameVector> formals,
GeneratorKind generatorKind,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
Directives inheritedDirectives, Directives* newDirectives,
HandleObject enclosingStaticScope);
// Parse a function, given only its arguments and body. Used for lazily
// parsed functions.
Node standaloneLazyFunction(HandleFunction fun, bool strict, GeneratorKind generatorKind);
Node standaloneLazyFunction(HandleFunction fun, bool strict, GeneratorKind generatorKind,
FunctionAsyncKind asyncKind);
/*
* Parse a function body. Pass StatementListBody if the body is a list of
@ -647,8 +655,10 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
* 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 functionExpr(InvokedPrediction invoked = PredictUninvoked);
Node functionStmt(YieldHandling yieldHandling,
DefaultHandling defaultHandling, FunctionAsyncKind asyncKind);
Node functionExpr(InvokedPrediction invoked = PredictUninvoked,
FunctionAsyncKind asyncKind = SyncFunction);
Node statements(YieldHandling yieldHandling);
Node blockStatement(YieldHandling yieldHandling);
@ -681,7 +691,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
InvokedPrediction invoked = PredictUninvoked);
Node assignExpr(InHandling inHandling, YieldHandling yieldHandling,
InvokedPrediction invoked = PredictUninvoked);
Node assignExprWithoutYield(YieldHandling yieldHandling, unsigned err);
Node assignExprWithoutYieldAndAwait(YieldHandling yieldHandling, unsigned err);
Node yieldExpression(InHandling inHandling);
Node condExpr1(InHandling inHandling, YieldHandling yieldHandling,
InvokedPrediction invoked = PredictUninvoked);
@ -705,13 +715,13 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
* Additional JS parsers.
*/
bool functionArguments(YieldHandling yieldHandling, FunctionSyntaxKind kind,
Node funcpn, bool* hasRest);
FunctionAsyncKind asyncKind, Node funcpn, bool* hasRest);
Node functionDef(InHandling inHandling, YieldHandling uieldHandling, HandlePropertyName name,
FunctionSyntaxKind kind, GeneratorKind generatorKind,
FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
InvokedPrediction invoked = PredictUninvoked);
bool functionArgsAndBody(InHandling inHandling, Node pn, HandleFunction fun,
FunctionSyntaxKind kind, GeneratorKind generatorKind,
FunctionSyntaxKind kind, GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
Directives inheritedDirectives, Directives* newDirectives);
Node unaryOpExpr(YieldHandling yieldHandling, ParseNodeKind kind, JSOp op, uint32_t begin);
@ -822,6 +832,7 @@ class Parser : private JS::AutoGCRooter, public StrictModeGetter
// Top-level entrypoint into destructuring pattern checking/name-analyzing.
bool checkDestructuringPattern(BindData<ParseHandler>* data, Node pattern);
// Recursive methods for checking/name-analyzing subcomponents of a
// destructuring pattern. The array/object methods *must* be passed arrays
// or objects. The name method may be passed anything but will report an

View File

@ -301,10 +301,13 @@ class FunctionBox : public ObjectBox, public SharedContext
FunctionContextFlags funCxFlags;
FunctionAsyncKind _asyncKind;
template <typename ParseHandler>
FunctionBox(ExclusiveContext* cx, ObjectBox* traceListHead, JSFunction* fun,
JSObject* enclosingStaticScope, ParseContext<ParseHandler>* pc,
Directives directives, bool extraWarnings, GeneratorKind generatorKind);
Directives directives, bool extraWarnings, GeneratorKind generatorKind,
FunctionAsyncKind asyncKind);
ObjectBox* toObjectBox() override { return this; }
JSFunction* function() const { return &object->as<JSFunction>(); }
@ -316,6 +319,8 @@ class FunctionBox : public ObjectBox, public SharedContext
bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; }
bool isStarGenerator() const { return generatorKind() == StarGenerator; }
bool isArrow() const { return function()->isArrow(); }
bool isAsync() const { return _asyncKind == AsyncFunction; }
FunctionAsyncKind asyncKind() const { return _asyncKind; }
void setGeneratorKind(GeneratorKind kind) {
// A generator kind can be set at initialization, or when "yield" is

View File

@ -283,8 +283,9 @@ class SyntaxParseHandler
bool addShorthand(Node literal, Node name, Node expr) { return true; }
bool addObjectMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; }
bool addClassMethodDefinition(Node literal, Node name, Node fn, JSOp op, bool isStatic) { return true; }
Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeUnparenthesizedYieldExpr; }
Node newYieldExpression(uint32_t begin, Node value, Node gen, JSOp op) { return NodeUnparenthesizedYieldExpr; }
Node newYieldStarExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
Node newAwaitExpression(uint32_t begin, Node value, Node gen) { return NodeUnparenthesizedYieldExpr; }
// Statements

View File

@ -107,6 +107,8 @@
macro(THROW, "keyword 'throw'") \
macro(DEBUGGER, "keyword 'debugger'") \
macro(YIELD, "keyword 'yield'") \
macro(ASYNC, "keyword 'async'") \
macro(AWAIT, "keyword 'await'") \
macro(LET, "keyword 'let'") \
macro(EXPORT, "keyword 'export'") \
macro(IMPORT, "keyword 'import'") \

View File

@ -986,6 +986,11 @@ TokenStream::putIdentInTokenbuf(const char16_t* identStart)
bool
TokenStream::checkForKeyword(const KeywordInfo* kw, TokenKind* ttp)
{
if (!awaitIsKeyword && kw->tokentype == TOK_AWAIT) {
*ttp = TOK_NAME;
return true;
}
if (kw->tokentype == TOK_RESERVED
#ifndef JS_HAS_CLASSES
|| kw->tokentype == TOK_CLASS

View File

@ -445,6 +445,8 @@ class MOZ_STACK_CLASS TokenStream
{}
};
bool awaitIsKeyword = false;
public:
typedef Token::Modifier Modifier;
static MOZ_CONSTEXPR_VAR Modifier None = Token::None;
@ -685,6 +687,14 @@ class MOZ_STACK_CLASS TokenStream
return true;
}
bool getAwaitIsKeyword() {
return awaitIsKeyword;
}
void setAwaitIsKeyword(bool _awaitIsKeyword) {
awaitIsKeyword = _awaitIsKeyword;
}
class MOZ_STACK_CLASS Position {
public:
// The Token fields may contain pointers to atoms, so for correct

View File

@ -107,6 +107,7 @@ MSG_DEF(JSMSG_PROTO_NOT_OBJORNULL, 1, JSEXN_TYPEERR, "{0}.prototype is not a
MSG_DEF(JSMSG_CANT_CALL_CLASS_CONSTRUCTOR, 0, JSEXN_TYPEERR, "class constructors must be invoked with |new|")
MSG_DEF(JSMSG_DISABLED_DERIVED_CLASS, 1, JSEXN_INTERNALERR, "{0} temporarily disallowed in derived class constructors")
MSG_DEF(JSMSG_NOT_CALLABLE, 1, JSEXN_TYPEERR, "{0} is not callable")
MSG_DEF(JSMSG_NOT_IMPLEMENTED, 1, JSEXN_INTERNALERR, "{0} is not implemented")
// JSON
MSG_DEF(JSMSG_JSON_BAD_PARSE, 3, JSEXN_SYNTAXERR, "JSON.parse: {0} at line {1} column {2} of the JSON data")
@ -187,6 +188,9 @@ MSG_DEF(JSMSG_ARRAY_COMP_LEFTSIDE, 0, JSEXN_SYNTAXERR, "invalid array compre
MSG_DEF(JSMSG_ARRAY_INIT_TOO_BIG, 0, JSEXN_INTERNALERR, "array initialiser 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_ACCESSOR, 0, JSEXN_SYNTAXERR, "async getters and setters are not allowed")
MSG_DEF(JSMSG_ASYNC_CONSTRUCTOR, 0, JSEXN_SYNTAXERR, "constructor may not be async")
MSG_DEF(JSMSG_ASYNC_GENERATOR, 0, JSEXN_SYNTAXERR, "generator function or method may not 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")
@ -268,6 +272,7 @@ MSG_DEF(JSMSG_LABEL_NOT_FOUND, 0, JSEXN_SYNTAXERR, "label not found")
MSG_DEF(JSMSG_LET_CLASS_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a class")
MSG_DEF(JSMSG_LET_COMP_BINDING, 0, JSEXN_SYNTAXERR, "'let' is not a valid name for a comprehension variable")
MSG_DEF(JSMSG_LEXICAL_DECL_NOT_IN_BLOCK, 1, JSEXN_SYNTAXERR, "{0} declaration not directly within block")
MSG_DEF(JSMSG_LINE_BREAK_AFTER_AWAIT, 0, JSEXN_SYNTAXERR, "no line break is allowed after 'await'")
MSG_DEF(JSMSG_LINE_BREAK_AFTER_THROW, 0, JSEXN_SYNTAXERR, "no line break is allowed between 'throw' and its expression")
MSG_DEF(JSMSG_MALFORMED_ESCAPE, 1, JSEXN_SYNTAXERR, "malformed {0} character escape sequence")
MSG_DEF(JSMSG_MISSING_BINARY_DIGITS, 0, JSEXN_SYNTAXERR, "missing binary digits after '0b'")
@ -340,7 +345,9 @@ MSG_DEF(JSMSG_USE_ASM_DIRECTIVE_FAIL, 0, JSEXN_SYNTAXERR, "\"use asm\" is only
MSG_DEF(JSMSG_VAR_HIDES_ARG, 1, JSEXN_TYPEERR, "variable {0} redeclares argument")
MSG_DEF(JSMSG_WHILE_AFTER_DO, 0, JSEXN_SYNTAXERR, "missing while after do-loop body")
MSG_DEF(JSMSG_YIELD_IN_ARROW, 0, JSEXN_SYNTAXERR, "arrow function may not contain yield")
MSG_DEF(JSMSG_YIELD_IN_ASYNC, 0, JSEXN_SYNTAXERR, "async function may not contain yield")
MSG_DEF(JSMSG_YIELD_IN_DEFAULT, 0, JSEXN_SYNTAXERR, "yield in default expression")
MSG_DEF(JSMSG_AWAIT_IN_DEFAULT, 0, JSEXN_SYNTAXERR, "await in default expression")
MSG_DEF(JSMSG_BAD_COLUMN_NUMBER, 0, JSEXN_RANGEERR, "column number out of range")
MSG_DEF(JSMSG_COMPUTED_NAME_IN_PATTERN,0, JSEXN_SYNTAXERR, "computed property names aren't supported in this destructuring declaration")
MSG_DEF(JSMSG_DEFAULT_IN_PATTERN, 0, JSEXN_SYNTAXERR, "destructuring defaults aren't supported in this destructuring declaration")

View File

@ -944,7 +944,12 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool bodyOnly, bool lamb
return nullptr;
}
if (!fun->isArrow()) {
if (!(fun->isStarGenerator() ? out.append("function* ") : out.append("function ")))
bool ok;
if (fun->isStarGenerator())
ok = out.append("function* ");
else
ok = out.append("function ");
if (!ok)
return nullptr;
}
if (fun->atom()) {

View File

@ -285,6 +285,13 @@ class JSFunction : public js::NativeObject
flags_ |= RESOLVED_NAME;
}
void setAsyncKind(js::FunctionAsyncKind asyncKind) {
if (isInterpretedLazy())
lazyScript()->setAsyncKind(asyncKind);
else
nonLazyScript()->setAsyncKind(asyncKind);
}
JSAtom* atom() const { return hasGuessedAtom() ? nullptr : atom_.get(); }
js::PropertyName* name() const {
@ -459,12 +466,18 @@ class JSFunction : public js::NativeObject
return js::NotGenerator;
}
js::FunctionAsyncKind asyncKind() const {
return isInterpretedLazy() ? lazyScript()->asyncKind() : nonLazyScript()->asyncKind();
}
bool isGenerator() const { return generatorKind() != js::NotGenerator; }
bool isLegacyGenerator() const { return generatorKind() == js::LegacyGenerator; }
bool isStarGenerator() const { return generatorKind() == js::StarGenerator; }
bool isAsync() const { return asyncKind() == js::AsyncFunction; }
void setScript(JSScript* script_) {
mutableScript() = script_;
}

View File

@ -2759,6 +2759,7 @@ JSScript::linkToFunctionFromEmitter(js::ExclusiveContext* cx, JS::Handle<JSScrip
script->isGeneratorExp_ = funbox->inGenexpLambda;
script->setGeneratorKind(funbox->generatorKind());
script->setAsyncKind(funbox->asyncKind());
// Link the function and the script to each other, so that StaticScopeIter
// may walk the scope chain of currently compiling scripts.
@ -2849,6 +2850,7 @@ JSScript::fullyInitFromEmitter(ExclusiveContext* cx, HandleScript script, Byteco
MOZ_ASSERT(script->functionNonDelazifying() == funbox->function());
MOZ_ASSERT(script->isGeneratorExp_ == funbox->inGenexpLambda);
MOZ_ASSERT(script->generatorKind() == funbox->generatorKind());
MOZ_ASSERT(script->asyncKind() == funbox->asyncKind());
} else {
MOZ_ASSERT(!script->funHasExtensibleScope_);
MOZ_ASSERT(!script->funNeedsDeclEnvObject_);

View File

@ -873,6 +873,8 @@ class ScriptSourceObject : public NativeObject
enum GeneratorKind { NotGenerator, LegacyGenerator, StarGenerator };
enum FunctionAsyncKind { SyncFunction, AsyncFunction };
static inline unsigned
GeneratorKindAsBits(GeneratorKind generatorKind) {
return static_cast<unsigned>(generatorKind);
@ -1167,6 +1169,8 @@ class JSScript : public js::gc::TenuredCell
bool isDerivedClassConstructor_:1;
bool isAsync_:1;
// Add padding so JSScript is gc::Cell aligned. Make padding protected
// instead of private to suppress -Wunused-private-field compiler warnings.
protected:
@ -1433,6 +1437,12 @@ class JSScript : public js::gc::TenuredCell
generatorKindBits_ = GeneratorKindAsBits(kind);
}
js::FunctionAsyncKind asyncKind() const { return isAsync_ ? js::AsyncFunction : js::SyncFunction; }
void setAsyncKind(js::FunctionAsyncKind kind) {
isAsync_ = kind == js::AsyncFunction;
}
void setNeedsHomeObject() {
needsHomeObject_ = true;
}
@ -2099,11 +2109,11 @@ class LazyScript : public gc::TenuredCell
// Assorted bits that should really be in ScriptSourceObject.
uint32_t version : 8;
uint32_t numFreeVariables : 24;
uint32_t numFreeVariables : 23;
uint32_t numInnerFunctions : 20;
uint32_t generatorKindBits : 2;
uint32_t isAsync : 1;
// N.B. These are booleans but need to be uint32_t to pack correctly on MSVC.
// If you add another boolean here, make sure to initialze it in
// LazyScript::CreateRaw().
@ -2216,6 +2226,10 @@ class LazyScript : public gc::TenuredCell
GeneratorKind generatorKind() const { return GeneratorKindFromBits(p_.generatorKindBits); }
FunctionAsyncKind asyncKind() const { return p_.isAsync ? AsyncFunction : SyncFunction; }
void setAsyncKind(FunctionAsyncKind kind) { p_.isAsync = kind == AsyncFunction; }
bool isGenerator() const { return generatorKind() != NotGenerator; }
bool isLegacyGenerator() const { return generatorKind() == LegacyGenerator; }

View File

@ -0,0 +1,85 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/**
* Currently only a part of async/await grammar is supported:
* - Async function statements are supported.
* - Await expressions are supported (as regular unary expressions).
* All other parts of proposal are probably not supported.
* Even the supported parts of implementation may not be 100% compliant with
* the grammar. This is to be considered a proof-of-concept implementation.
*/
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);
assertEq(Reflect.parse("() => {}").body[0].async, undefined);
// 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");
// Async arrow functions are allowed, but not supported yet
assertThrows(() => Reflect.parse("async () => true"), SyntaxError);
// Async function expressions
assertEq(Reflect.parse("(async function() {})()").body[0].expression.callee.async, true);
assertEq(Reflect.parse("var k = async function() {}").body[0].declarations[0].init.async, true);
assertEq(Reflect.parse("var nmd = async function named() {}").body[0].declarations[0].init.id.name, "named");
// 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);
// 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);
// Yield is not allowed in an async function / treated as identifier
assertThrows(() => Reflect.parse("async function a() { yield 3; }"), 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);

View File

@ -18,6 +18,8 @@
macro(apply, apply, "apply") \
macro(arguments, arguments, "arguments") \
macro(as, as, "as") \
macro(async, async, "async") \
macro(await, await, "await") \
macro(ArrayIteratorNext, ArrayIteratorNext, "ArrayIteratorNext") \
macro(ArrayType, ArrayType, "ArrayType") \
macro(ArrayValues, ArrayValues, "ArrayValues") \

View File

@ -56,6 +56,7 @@
macro(protected, protected_, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \
macro(public, public_, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \
macro(static, static_, TOK_STRICT_RESERVED, JSVERSION_DEFAULT) \
macro(await, await, TOK_AWAIT, JSVERSION_DEFAULT) \
/* \
* Yield is a token inside function*. Outside of a function*, it is a \
* future reserved keyword in strict mode, but a keyword in JS1.7 even \

View File

@ -33,7 +33,7 @@ static const uint32_t XDR_BYTECODE_VERSION_SUBTRAHEND = 311;
static const uint32_t XDR_BYTECODE_VERSION =
uint32_t(0xb973c0de - XDR_BYTECODE_VERSION_SUBTRAHEND);
static_assert(JSErr_Limit == 418,
static_assert(JSErr_Limit == 425,
"GREETINGS, POTENTIAL SUBTRAHEND INCREMENTER! If you added or "
"removed MSG_DEFs from js.msg, you should increment "
"XDR_BYTECODE_VERSION_SUBTRAHEND and update this assertion's "