зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1185106 - Part 3: Add parser support for Async functions. (r=efaust)
This commit is contained in:
Родитель
9963b230dc
Коммит
367665b0be
|
@ -6347,7 +6347,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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -3080,7 +3110,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:
|
||||
|
@ -3092,6 +3122,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));
|
||||
|
||||
|
@ -3561,7 +3592,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();
|
||||
|
@ -3584,7 +3615,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
|
||||
|
|
|
@ -326,7 +326,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;
|
||||
|
||||
|
@ -746,7 +746,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;
|
||||
|
@ -906,7 +906,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;
|
||||
|
||||
|
|
|
@ -1996,6 +1996,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;
|
||||
|
@ -8010,6 +8011,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");
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
@ -1848,6 +1849,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) &&
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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) ||
|
||||
|
@ -699,7 +700,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;
|
||||
|
|
|
@ -182,6 +182,7 @@ class PackedScopeCoordinate
|
|||
F(VOID) \
|
||||
F(NOT) \
|
||||
F(BITNOT) \
|
||||
F(AWAIT) \
|
||||
\
|
||||
/* \
|
||||
* Binary operators. \
|
||||
|
|
|
@ -701,7 +701,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(),
|
||||
|
@ -720,7 +721,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
|
||||
|
@ -734,6 +736,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());
|
||||
|
@ -749,7 +752,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;
|
||||
|
@ -893,7 +896,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;
|
||||
|
@ -923,7 +928,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();
|
||||
|
||||
|
@ -998,6 +1006,7 @@ ParseNode*
|
|||
Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
|
||||
Handle<PropertyNameVector> formals,
|
||||
GeneratorKind generatorKind,
|
||||
FunctionAsyncKind asyncKind,
|
||||
Directives inheritedDirectives,
|
||||
Directives* newDirectives,
|
||||
HandleObject enclosingStaticScope)
|
||||
|
@ -1014,7 +1023,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();
|
||||
|
@ -1463,7 +1472,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);
|
||||
|
||||
|
@ -1509,6 +1519,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)
|
||||
|
@ -1890,7 +1904,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();
|
||||
|
||||
|
@ -2078,11 +2092,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))
|
||||
|
@ -2266,7 +2289,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;
|
||||
|
||||
|
@ -2472,9 +2495,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();
|
||||
|
@ -2501,7 +2526,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();
|
||||
|
||||
|
@ -2516,8 +2541,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;
|
||||
}
|
||||
|
@ -2587,6 +2612,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())
|
||||
|
@ -2604,13 +2630,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;
|
||||
|
||||
|
@ -2709,13 +2736,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;
|
||||
|
||||
|
@ -2731,7 +2759,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.
|
||||
|
@ -2760,7 +2787,8 @@ Parser<ParseHandler>::appendToCallSiteObj(Node callSiteObj)
|
|||
template <>
|
||||
ParseNode*
|
||||
Parser<FullParseHandler>::standaloneLazyFunction(HandleFunction fun, bool strict,
|
||||
GeneratorKind generatorKind)
|
||||
GeneratorKind generatorKind,
|
||||
FunctionAsyncKind asyncKind)
|
||||
{
|
||||
MOZ_ASSERT(checkOptionsCalled);
|
||||
|
||||
|
@ -2775,7 +2803,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();
|
||||
|
@ -2833,12 +2861,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();
|
||||
|
@ -2882,9 +2910,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))
|
||||
|
@ -2930,7 +2961,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));
|
||||
|
||||
|
@ -2941,6 +2973,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();
|
||||
|
@ -2966,12 +3002,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));
|
||||
|
||||
|
@ -2981,6 +3019,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();
|
||||
|
@ -2997,8 +3039,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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -4970,7 +5014,7 @@ Parser<FullParseHandler>::exportDeclaration()
|
|||
}
|
||||
|
||||
case TOK_FUNCTION:
|
||||
kid = functionStmt(YieldIsKeyword, NameRequired);
|
||||
kid = functionStmt(YieldIsKeyword, NameRequired, SyncFunction);
|
||||
if (!kid)
|
||||
return null();
|
||||
|
||||
|
@ -5020,7 +5064,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;
|
||||
|
@ -6008,7 +6052,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)
|
||||
|
@ -6017,7 +6061,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>
|
||||
|
@ -6470,6 +6516,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;
|
||||
|
@ -6491,8 +6538,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;
|
||||
|
@ -6506,7 +6553,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 <>
|
||||
|
@ -6620,6 +6675,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);
|
||||
|
@ -6788,6 +6844,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)
|
||||
|
@ -6862,7 +6931,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:
|
||||
|
@ -7176,6 +7245,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)
|
||||
|
@ -7196,8 +7279,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();
|
||||
|
||||
|
@ -7257,7 +7346,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();
|
||||
|
||||
|
@ -7519,6 +7608,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)
|
||||
|
@ -8096,13 +8204,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();
|
||||
|
||||
|
@ -8435,8 +8543,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) {
|
||||
|
@ -8968,12 +9084,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(<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) {
|
||||
|
@ -8995,7 +9131,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))
|
||||
{
|
||||
|
@ -9112,7 +9248,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;
|
||||
}
|
||||
|
||||
|
@ -9259,7 +9396,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>
|
||||
|
@ -9368,7 +9506,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);
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
@ -378,6 +380,7 @@ enum class PropertyType {
|
|||
SetterNoExpressionClosure,
|
||||
Method,
|
||||
GeneratorMethod,
|
||||
AsyncMethod,
|
||||
Constructor,
|
||||
DerivedConstructor
|
||||
};
|
||||
|
@ -519,22 +522,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);
|
||||
|
@ -544,7 +551,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) {
|
||||
|
@ -583,7 +590,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();
|
||||
|
||||
|
@ -606,13 +613,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
|
||||
|
@ -664,8 +672,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);
|
||||
|
@ -698,7 +708,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);
|
||||
|
@ -722,13 +732,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);
|
||||
|
@ -839,6 +849,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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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'") \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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_;
|
||||
}
|
||||
|
|
|
@ -2776,6 +2776,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.
|
||||
|
@ -2866,6 +2867,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_);
|
||||
|
|
|
@ -876,6 +876,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);
|
||||
|
@ -1170,6 +1172,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:
|
||||
|
@ -1436,6 +1440,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;
|
||||
}
|
||||
|
@ -2106,11 +2116,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().
|
||||
|
@ -2229,6 +2239,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; }
|
||||
|
|
|
@ -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);
|
|
@ -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") \
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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 "
|
||||
|
|
Загрузка…
Ссылка в новой задаче