summaryrefslogtreecommitdiff
path: root/js/src
diff options
context:
space:
mode:
Diffstat (limited to 'js/src')
-rw-r--r--js/src/builtin/ReflectParse.cpp38
-rw-r--r--js/src/frontend/BytecodeEmitter.cpp41
-rw-r--r--js/src/frontend/FoldConstants.cpp2
-rw-r--r--js/src/frontend/FullParseHandler.h6
-rw-r--r--js/src/frontend/ParseNode.cpp1
-rw-r--r--js/src/frontend/ParseNode.h30
-rw-r--r--js/src/frontend/Parser.cpp167
-rw-r--r--js/src/frontend/Parser.h19
-rw-r--r--js/src/frontend/SharedContext.h4
-rw-r--r--js/src/frontend/SyntaxParseHandler.h1
-rw-r--r--js/src/js.msg1
-rw-r--r--js/src/jsast.tbl1
12 files changed, 277 insertions, 34 deletions
diff --git a/js/src/builtin/ReflectParse.cpp b/js/src/builtin/ReflectParse.cpp
index 6ca0c30e16..b40c5fb408 100644
--- a/js/src/builtin/ReflectParse.cpp
+++ b/js/src/builtin/ReflectParse.cpp
@@ -544,6 +544,7 @@ class NodeBuilder
TokenPos* pos, MutableHandleValue dst);
MOZ_MUST_USE bool classField(HandleValue name, HandleValue initializer,
TokenPos* pos, MutableHandleValue dst);
+ MOZ_MUST_USE bool staticClassBlock(HandleValue body, TokenPos* pos, MutableHandleValue dst);
/*
* expressions
@@ -1737,6 +1738,18 @@ NodeBuilder::classField(HandleValue name, HandleValue initializer,
}
bool
+NodeBuilder::staticClassBlock(HandleValue body, TokenPos* pos, MutableHandleValue dst)
+{
+ RootedValue cb(cx, callbacks[AST_STATIC_CLASS_BLOCK]);
+ if (!cb.isNull())
+ return callback(cb, body, pos, dst);
+
+ return newNode(AST_STATIC_CLASS_BLOCK, pos,
+ "body", body,
+ dst);
+}
+
+bool
NodeBuilder::classMembers(NodeVector& members, MutableHandleValue dst)
{
return newArray(members, dst);
@@ -1870,6 +1883,7 @@ class ASTSerializer
bool classMethod(ClassMethod* classMethod, MutableHandleValue dst);
bool classField(ClassField* classField, MutableHandleValue dst);
+ bool staticClassBlock(StaticClassBlock* staticClassBlock, MutableHandleValue dst);
bool optIdentifier(HandleAtom atom, TokenPos* pos, MutableHandleValue dst) {
if (!atom) {
@@ -2709,7 +2723,14 @@ ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst)
RootedValue prop(cx);
if (!classField(field, &prop))
- return false;
+ return false;
+ members.infallibleAppend(prop);
+ } else if (item->is<StaticClassBlock>()) {
+ StaticClassBlock* scb = &item->as<StaticClassBlock>();
+ MOZ_ASSERT(memberList->pn_pos.encloses(scb->pn_pos));
+ RootedValue prop(cx);
+ if (!staticClassBlock(scb, &prop))
+ return false;
members.infallibleAppend(prop);
} else {
ClassMethod* method = &item->as<ClassMethod>();
@@ -2788,6 +2809,21 @@ ASTSerializer::classField(ClassField* classField, MutableHandleValue dst)
}
bool
+ASTSerializer::staticClassBlock(StaticClassBlock* staticClassBlock, MutableHandleValue dst)
+{
+ FunctionNode* fun = staticClassBlock->function();
+
+ NodeVector args(cx);
+ NodeVector defaults(cx);
+
+ RootedValue body(cx), rest(cx);
+ rest.setNull();
+ return functionArgsAndBody(fun->body(), args, defaults, false, false,
+ &body, &rest) &&
+ builder.staticClassBlock(body, &staticClassBlock->pn_pos, dst);
+}
+
+bool
ASTSerializer::leftAssociate(ListNode* node, MutableHandleValue dst)
{
MOZ_ASSERT(!node->empty());
diff --git a/js/src/frontend/BytecodeEmitter.cpp b/js/src/frontend/BytecodeEmitter.cpp
index 1524493cb0..eb25903911 100644
--- a/js/src/frontend/BytecodeEmitter.cpp
+++ b/js/src/frontend/BytecodeEmitter.cpp
@@ -1529,6 +1529,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
case PNK_CLASSMETHOD: // by PNK_CLASS
case PNK_CLASSFIELD: // by PNK_CLASS
case PNK_CLASSNAMES: // by PNK_CLASS
+ case PNK_STATICCLASSBLOCK:// by PNK_CLASS
case PNK_CLASSMEMBERLIST: // by PNK_CLASS
case PNK_IMPORT_SPEC_LIST: // by PNK_IMPORT
case PNK_IMPORT_SPEC: // by PNK_IMPORT
@@ -7702,6 +7703,12 @@ BytecodeEmitter::emitPropertyList(ListNode* obj, PropertyEmitter& pe, PropListTy
continue;
}
+ if (propdef->is<StaticClassBlock>()) {
+ // Static class blocks are emitted as part of
+ // emitCreateFieldInitializers.
+ continue;
+ }
+
if (propdef->is<LexicalScopeNode>()) {
// Constructors are sometimes wrapped in LexicalScopeNodes. As we already
// handled emitting the constructor, skip it.
@@ -7943,13 +7950,32 @@ BytecodeEmitter::emitPropertyList(ListNode* obj, PropertyEmitter& pe, PropListTy
return true;
}
+static bool
+HasInitializer(ParseNode* node, bool isStaticContext)
+{
+ // For the purposes of bytecode emission, StaticClassBlocks are treated as if
+ // they were static initializers.
+ return (node->is<ClassField>() &&
+ node->as<ClassField>().isStatic() == isStaticContext) ||
+ (isStaticContext && node->is<StaticClassBlock>());
+}
+
+static FunctionNode*
+GetInitializer(ParseNode* node, bool isStaticContext)
+{
+ MOZ_ASSERT(HasInitializer(node, isStaticContext));
+ MOZ_ASSERT_IF(!node->is<ClassField>(), isStaticContext);
+ return node->is<ClassField>() ? node->as<ClassField>().initializer()
+ : node->as<StaticClassBlock>().function();
+}
+
+
FieldInitializers
BytecodeEmitter::setupFieldInitializers(ListNode* classMembers, FieldPlacement placement)
{
bool isStatic = placement == FieldPlacement::Static;
size_t numFields = classMembers->count_if([isStatic](ParseNode* propdef) {
- return propdef->is<ClassField>()&&
- propdef->as<ClassField>().isStatic() == isStatic;
+ return HasInitializer(propdef, isStatic);
});
return FieldInitializers(numFields);
@@ -8040,11 +8066,10 @@ BytecodeEmitter::emitCreateFieldInitializers(ClassEmitter& ce, ListNode* obj,
}
for (ParseNode* propdef : obj->contents()) {
- if (!propdef->is<ClassField>() ||
- propdef->as<ClassField>().isStatic() != isStatic)
+ if (!HasInitializer(propdef, isStatic))
continue;
- FunctionNode* initializer = propdef->as<ClassField>().initializer();
+ FunctionNode* initializer = GetInitializer(propdef, isStatic);
if (!ce.prepareForFieldInitializer())
return false;
if (!emitTree(initializer)) {
@@ -8173,8 +8198,7 @@ bool
BytecodeEmitter::emitInitializeStaticFields(ListNode* classMembers)
{
size_t numFields = classMembers->count_if([](ParseNode* propdef) {
- return propdef->is<ClassField>()&&
- propdef->as<ClassField>().isStatic();
+ return HasInitializer(propdef, true);
});
if (numFields == 0) {
@@ -8816,8 +8840,7 @@ BytecodeEmitter::emitClass(ClassNode* classNode)
// As an optimization omit the |.initializers| binding when no instance
// fields are present.
bool hasInstanceFields = classMembers->any_of([](ParseNode* propdef) {
- return propdef->is<ClassField>() &&
- !propdef->as<ClassField>().isStatic();
+ return HasInitializer(propdef, false);
});
if (hasInstanceFields) {
lse.emplace(this);
diff --git a/js/src/frontend/FoldConstants.cpp b/js/src/frontend/FoldConstants.cpp
index bb8f0d11b6..813900a23f 100644
--- a/js/src/frontend/FoldConstants.cpp
+++ b/js/src/frontend/FoldConstants.cpp
@@ -403,6 +403,7 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
case PNK_FOROF:
case PNK_FORHEAD:
case PNK_CLASSFIELD:
+ case PNK_STATICCLASSBLOCK:
case PNK_CLASSMEMBERLIST:
case PNK_CLASSNAMES:
case PNK_NEWTARGET:
@@ -1749,6 +1750,7 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
case PNK_ARRAYPUSH:
case PNK_MUTATEPROTO:
case PNK_COMPUTED_NAME:
+ case PNK_STATICCLASSBLOCK:
case PNK_SPREAD:
case PNK_EXPORT:
case PNK_VOID:
diff --git a/js/src/frontend/FullParseHandler.h b/js/src/frontend/FullParseHandler.h
index 4f3492af4d..14733d74f2 100644
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -474,12 +474,18 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
return new_<ClassField>(name, initializer, isStatic);
}
+ MOZ_MUST_USE StaticClassBlock* newStaticClassBlock(FunctionNodeType block)
+ {
+ return new_<StaticClassBlock>(block);
+ }
+
MOZ_MUST_USE bool addClassMemberDefinition(ListNodeType memberList, Node member)
{
MOZ_ASSERT(memberList->isKind(PNK_CLASSMEMBERLIST));
// Constructors can be surrounded by LexicalScopes.
MOZ_ASSERT(member->isKind(PNK_CLASSMETHOD) ||
member->isKind(PNK_CLASSFIELD) ||
+ member->isKind(PNK_STATICCLASSBLOCK) ||
(member->isKind(PNK_LEXICALSCOPE) &&
member->as<LexicalScopeNode>().scopeBody()->isKind(PNK_CLASSMETHOD)));
diff --git a/js/src/frontend/ParseNode.cpp b/js/src/frontend/ParseNode.cpp
index de3ea60931..a529c93d14 100644
--- a/js/src/frontend/ParseNode.cpp
+++ b/js/src/frontend/ParseNode.cpp
@@ -236,6 +236,7 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
case PNK_PREDECREMENT:
case PNK_POSTDECREMENT:
case PNK_COMPUTED_NAME:
+ case PNK_STATICCLASSBLOCK:
case PNK_ARRAYPUSH:
case PNK_SPREAD:
case PNK_MUTATEPROTO:
diff --git a/js/src/frontend/ParseNode.h b/js/src/frontend/ParseNode.h
index 4c9f1cc914..471f42f905 100644
--- a/js/src/frontend/ParseNode.h
+++ b/js/src/frontend/ParseNode.h
@@ -117,6 +117,7 @@ class ObjectBox;
F(MUTATEPROTO) \
F(CLASS) \
F(CLASSMETHOD) \
+ F(STATICCLASSBLOCK) \
F(CLASSFIELD) \
F(CLASSMEMBERLIST) \
F(CLASSNAMES) \
@@ -259,7 +260,7 @@ IsTypeofKind(ParseNodeKind kind)
* that doesn't create an outer binding
* right: Name node for inner binding
* PNK_CLASSMEMBERLIST (ListNode)
- * head: list of N PNK_CLASSMETHOD or PNK_CLASSFIELD nodes
+ * head: list of N PNK_CLASSMETHOD, PNK_CLASSFIELD or PNK_STATICCLASSBLOCK nodes
* count: N >= 0
* PNK_CLASSMETHOD (ClassMethod)
* name: propertyName
@@ -267,6 +268,8 @@ IsTypeofKind(ParseNodeKind kind)
* PNK_CLASSFIELD (ClassField)
* name: fieldName
* initializer: field initializer or null
+ * PNK_STATICCLASSBLOCK (StaticClassBlock)
+ * block: block initializer
* PNK_MODULE (ModuleNode)
* body: statement list of the module
*
@@ -574,6 +577,7 @@ enum ParseNodeArity
macro(CaseClause, CaseClauseType, asCaseClause) \
macro(ClassMethod, ClassMethodType, asClassMethod) \
macro(ClassField, ClassFieldType, asClassField) \
+ macro(StaticClassBlock, StaticClassBlockType, asStaticClassBlock) \
macro(ClassNames, ClassNamesType, asClassNames) \
macro(ForNode, ForNodeType, asFor) \
macro(PropertyAccess, PropertyAccessType, asPropertyAccess) \
@@ -627,6 +631,8 @@ enum class FunctionSyntaxKind
Arrow,
Method, // Method of a class or object.
FieldInitializer, // Field initializers desugar to methods.
+ StaticClassBlock, // Mostly static class blocks act similar to field initializers, however,
+ // there is some difference in static semantics.
ClassConstructor,
DerivedClassConstructor,
Getter,
@@ -2161,6 +2167,28 @@ class ClassField : public BinaryNode
}
};
+// Hold onto the function generated for a class static block like
+//
+// class A {
+// static { /* this static block */ }
+// }
+//
+class StaticClassBlock : public UnaryNode
+{
+ public:
+ explicit StaticClassBlock(FunctionNode* function)
+ : UnaryNode(PNK_STATICCLASSBLOCK, JSOP_NOP, function->pn_pos, function) {
+ }
+
+ static bool test(const ParseNode& node) {
+ bool match = node.isKind(PNK_STATICCLASSBLOCK);
+ MOZ_ASSERT_IF(match, node.is<UnaryNode>());
+ return match;
+ }
+ FunctionNode* function() const { return &kid()->as<FunctionNode>(); }
+};
+
+
class SwitchStatement : public BinaryNode
{
public:
diff --git a/js/src/frontend/Parser.cpp b/js/src/frontend/Parser.cpp
index f69e3cf08a..7c8df7d498 100644
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -463,6 +463,7 @@ FunctionBox::FunctionBox(ExclusiveContext* cx, LifoAlloc& alloc, ObjectBox* trac
hasParameterExprs(false),
hasDirectEvalInParameterExpr(false),
hasDuplicateParameters(false),
+ allowReturn_(true),
useAsm(false),
insideUseAsm(false),
isAnnexB(false),
@@ -526,27 +527,34 @@ FunctionBox::initWithEnclosingParseContext(ParseContext* enclosing, FunctionSynt
allowNewTarget_ = true;
allowSuperProperty_ = fun->allowSuperProperty();
- if (kind == FunctionSyntaxKind::FieldInitializer) {
- setFieldInitializer();
- allowArguments_ = false;
- }
+ if (isGenexpLambda)
+ thisBinding_ = sc->thisBinding();
+ else
+ thisBinding_ = ThisBinding::Function;
if (IsConstructorKind(kind)) {
auto stmt = enclosing->findInnermostStatement<ParseContext::ClassStatement>();
MOZ_ASSERT(stmt);
stmt->constructorBox = this;
+ }
- if (kind == FunctionSyntaxKind::DerivedClassConstructor) {
- setDerivedClassConstructor();
- allowSuperCall_ = true;
- needsThisTDZChecks_ = true;
- }
+ if (kind == FunctionSyntaxKind::DerivedClassConstructor) {
+ setDerivedClassConstructor();
+ allowSuperCall_ = true;
+ needsThisTDZChecks_ = true;
}
- if (isGenexpLambda)
- thisBinding_ = sc->thisBinding();
- else
- thisBinding_ = ThisBinding::Function;
+ if (kind == FunctionSyntaxKind::FieldInitializer ||
+ kind == FunctionSyntaxKind::StaticClassBlock) {
+ allowArguments_ = false;
+ if (kind == FunctionSyntaxKind::StaticClassBlock) {
+ allowSuperCall_ = false;
+ allowReturn_ = false;
+ } else {
+ MOZ_ASSERT(kind == FunctionSyntaxKind::FieldInitializer);
+ setFieldInitializer();
+ }
+ }
}
if (sc->inWith()) {
@@ -2809,6 +2817,7 @@ Parser<ParseHandler>::newFunction(HandleAtom atom, FunctionSyntaxKind kind,
break;
case FunctionSyntaxKind::Method:
case FunctionSyntaxKind::FieldInitializer:
+ case FunctionSyntaxKind::StaticClassBlock:
MOZ_ASSERT(generatorKind == NotGenerator || generatorKind == StarGenerator);
flags = (generatorKind == NotGenerator && asyncKind == SyncFunction
? JSFunction::INTERPRETED_METHOD
@@ -3686,10 +3695,12 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
// See below for an explanation why arrow function parameters and arrow
// function bodies are parsed with different yield/await settings.
{
- AwaitHandling awaitHandling = funbox->isAsync() ||
- (kind == FunctionSyntaxKind::Arrow && awaitIsKeyword())
- ? AwaitIsKeyword
- : AwaitIsName;
+ AwaitHandling awaitHandling = kind == FunctionSyntaxKind::StaticClassBlock
+ ? AwaitIsDisallowed
+ : (funbox->isAsync() ||
+ (kind == FunctionSyntaxKind::Arrow && awaitIsKeyword()))
+ ? AwaitIsKeyword
+ : AwaitIsName;
AutoAwaitIsKeyword<ParseHandler> awaitIsKeyword(this, awaitHandling);
if (!functionArguments(yieldHandling, kind, funNode))
return false;
@@ -7438,12 +7449,26 @@ Parser<ParseHandler>::classMember(YieldHandling yieldHandling,
if (tt == TOK_STATIC) {
if (!tokenStream.peekToken(&tt))
return false;
+
if (tt == TOK_RC) {
tokenStream.consumeKnownToken(tt);
error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt));
return false;
}
+ if (tt == TOK_LC) {
+ /* Parsing static class block: static { ... } */
+ FunctionNodeType staticBlockBody = staticClassBlock(classFields);
+ if (!staticBlockBody)
+ return false;
+
+ StaticClassBlockType classBlock = handler.newStaticClassBlock(staticBlockBody);
+ if (!classBlock)
+ return false;
+
+ return handler.addClassMemberDefinition(classMembers, classBlock);
+ }
+
if (tt != TOK_LP) {
isStatic = true;
} else {
@@ -7970,6 +7995,108 @@ Parser<ParseHandler>::synthesizeConstructor(HandleAtom className, uint32_t class
template <class ParseHandler>
typename ParseHandler::FunctionNodeType
+Parser<ParseHandler>::staticClassBlock(ClassFields& classFields)
+{
+ // Both for getting-this-done, and because this will invariably be executed,
+ // syntax parsing should be aborted.
+ if (!abortIfSyntaxParser())
+ return null();
+
+ TokenPos firstTokenPos(pos());
+
+ // Create the anonymous function object.
+ FunctionSyntaxKind syntaxKind = FunctionSyntaxKind::StaticClassBlock;
+ AutoAwaitIsKeyword<ParseHandler> awaitIsKeyword(this, AwaitIsDisallowed);
+
+ RootedFunction fun(context,
+ newFunction(nullptr, syntaxKind,
+ GeneratorKind::NotGenerator,
+ FunctionAsyncKind::SyncFunction));
+ if (!fun)
+ return null();
+
+ // Create the function node for the static class body.
+ FunctionNodeType funNode = handler.newFunction(syntaxKind, firstTokenPos);
+ if (!funNode)
+ return null();
+
+ // Create the FunctionBox and link it to the function object.
+ Directives directives(true);
+ FunctionBox* funbox = newFunctionBox(funNode, fun, firstTokenPos.begin, directives,
+ GeneratorKind::NotGenerator,
+ FunctionAsyncKind::SyncFunction, false);
+ if (!funbox)
+ return null();
+ funbox->initWithEnclosingParseContext(pc, syntaxKind);
+ MOZ_ASSERT(!funbox->allowSuperCall());
+ MOZ_ASSERT(!funbox->allowArguments());
+ MOZ_ASSERT(!funbox->allowReturn());
+
+ // Set start at `static` token.
+ MOZ_ASSERT(tokenStream.isCurrentTokenType(TOK_STATIC));
+ funbox->setStart(tokenStream, firstTokenPos);
+
+ // Push a SourceParseContext on to the stack.
+ ParseContext* outerpc = pc;
+ ParseContext funpc(this, funbox, /* newDirectives = */ nullptr);
+ if (!funpc.init())
+ return null();
+
+ pc->functionScope().useAsVarScope(pc);
+
+ uint32_t start = firstTokenPos.begin;
+
+ tokenStream.consumeKnownToken(TOK_LC);
+
+ // Static class blocks are code-generated as if they were static field
+ // initializers, so we bump the staticFields count here, which ensures
+ // .staticInitializers is noted as used.
+ classFields.staticFields++;
+
+ LexicalScopeNodeType body = functionBody(InAllowed, YieldIsKeyword, syntaxKind,
+ StatementListBody);
+ if (!body)
+ return null();
+
+ if (tokenStream.isEOF()) {
+ error(JSMSG_UNTERMINATED_STATIC_CLASS_BLOCK);
+ return null();
+ }
+
+ tokenStream.consumeKnownToken(TOK_RC, TokenStream::Operand);
+
+ TokenPos wholeBodyPos(start, pos().end);
+
+ handler.setEndPosition(funNode, wholeBodyPos.end);
+ funbox->setEnd(pos().end);
+
+ // Create a ListNode for the parameters + body (there are no parameters).
+ ListNodeType argsbody = handler.newList(PNK_PARAMSBODY, wholeBodyPos);
+ if (!argsbody)
+ return null();
+
+ handler.setFunctionFormalParametersAndBody(funNode, argsbody);
+ funbox->function()->setArgCount(0);
+
+ if (pc->superScopeNeedsHomeObject()) {
+ funbox->setNeedsHomeObject();
+ }
+
+ handler.setEndPosition(body, pos().begin);
+ handler.setEndPosition(funNode, pos().end);
+ handler.setFunctionBody(funNode, body);
+
+ if (!finishFunction())
+ return null();
+
+ if (!leaveInnerFunction(outerpc))
+ return null();
+
+ return funNode;
+}
+
+template <class ParseHandler>
+typename ParseHandler::FunctionNodeType
Parser<ParseHandler>::fieldInitializerOpt(HandleAtom propAtom, ClassFields& classFields, bool isStatic)
{
bool hasInitializer = false;
@@ -8349,7 +8476,7 @@ Parser<ParseHandler>::statement(YieldHandling yieldHandling)
// The Return parameter is only used here, and the effect is easily
// detected this way, so don't bother passing around an extra parameter
// everywhere.
- if (!pc->isFunctionBox()) {
+ if (!pc->allowReturn()) {
error(JSMSG_BAD_RETURN_OR_YIELD, js_return_str);
return null();
}
@@ -8535,7 +8662,7 @@ Parser<ParseHandler>::statementListItem(YieldHandling yieldHandling,
// The Return parameter is only used here, and the effect is easily
// detected this way, so don't bother passing around an extra parameter
// everywhere.
- if (!pc->isFunctionBox()) {
+ if (!pc->allowReturn()) {
error(JSMSG_BAD_RETURN_OR_YIELD, js_return_str);
return null();
}
@@ -10261,7 +10388,7 @@ Parser<ParseHandler>::checkLabelOrIdentifierReference(PropertyName* ident,
return true;
}
if (tt == TOK_AWAIT) {
- if (awaitIsKeyword()) {
+ if (awaitIsKeyword() || awaitIsDisallowed()) {
errorAt(offset, JSMSG_RESERVED_ID, "await");
return false;
}
diff --git a/js/src/frontend/Parser.h b/js/src/frontend/Parser.h
index d0318e405d..6976487c50 100644
--- a/js/src/frontend/Parser.h
+++ b/js/src/frontend/Parser.h
@@ -526,6 +526,10 @@ class ParseContext : public Nestable<ParseContext>
return sc_->isFunctionBox() && sc_->asFunctionBox()->function()->isMethod();
}
+ bool allowReturn() const {
+ return sc_->isFunctionBox() && sc_->asFunctionBox()->allowReturn();
+ }
+
uint32_t scriptId() const {
return scriptId_;
}
@@ -588,11 +592,11 @@ enum class PropertyType {
};
// Specify a value for an ES6 grammar parametrization. We have no enum for
-// [Return] because its behavior is exactly equivalent to checking whether
+// [Return] because its behavior is almost exactly equivalent to checking whether
// we're in a function box -- easier and simpler than passing an extra
// parameter everywhere.
enum YieldHandling { YieldIsName, YieldIsKeyword };
-enum AwaitHandling : uint8_t { AwaitIsName, AwaitIsKeyword, AwaitIsModuleKeyword };
+enum AwaitHandling : uint8_t { AwaitIsName, AwaitIsKeyword, AwaitIsModuleKeyword, AwaitIsDisallowed };
enum InHandling { InAllowed, InProhibited };
enum DefaultHandling { NameRequired, AllowDefaultName };
enum TripledotHandling { TripledotAllowed, TripledotProhibited };
@@ -817,7 +821,10 @@ class ParserBase : public StrictModeGetter
public:
bool awaitIsKeyword() const {
- return awaitHandling_ != AwaitIsName;
+ return awaitHandling_ == AwaitIsKeyword || awaitHandling_ == AwaitIsModuleKeyword;
+ }
+ bool awaitIsDisallowed() const {
+ return awaitHandling_ == AwaitIsDisallowed;
}
ParseGoal parseGoal() const {
@@ -1450,6 +1457,8 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
// Parse a function body. Pass StatementListBody if the body is a list of
// statements; pass ExpressionBody if the body is a single expression.
+ //
+ // Don't include opening LeftCurly token when invoking.
enum FunctionBodyType { StatementListBody, ExpressionBody };
LexicalScopeNodeType functionBody(InHandling inHandling, YieldHandling yieldHandling,
FunctionSyntaxKind kind, FunctionBodyType type);
@@ -1498,6 +1507,9 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
// The number of static class fields.
size_t staticFields = 0;
+ // The number of static blocks
+ size_t staticBlocks = 0;
+
// The number of static class fields with computed property names.
size_t staticFieldKeys = 0;
};
@@ -1514,6 +1526,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
const ClassFields& classFields, ListNodeType& classMembers);
FunctionNodeType fieldInitializerOpt(HandleAtom atom, ClassFields& classFields, bool isStatic);
+ FunctionNodeType staticClassBlock(ClassFields& classFields);
FunctionNodeType synthesizeConstructor(HandleAtom className,
uint32_t classNameOffset,
bool hasHeritage);
diff --git a/js/src/frontend/SharedContext.h b/js/src/frontend/SharedContext.h
index 4ac2da6fcd..29a8cbd18f 100644
--- a/js/src/frontend/SharedContext.h
+++ b/js/src/frontend/SharedContext.h
@@ -432,6 +432,8 @@ class FunctionBox : public ObjectBox, public SharedContext
bool isExprBody_:1; /* arrow function with expression
* body or expression closure:
* function(x) x*x */
+ bool allowReturn_ : 1; /* Used to issue an early error in static class blocks. */
+
FunctionContextFlags funCxFlags;
@@ -523,6 +525,8 @@ class FunctionBox : public ObjectBox, public SharedContext
isExprBody_ = true;
}
+ bool allowReturn() const { return allowReturn_; }
+
void setGeneratorKind(GeneratorKind kind) {
// A generator kind can be set at initialization, or when "yield" is
// first seen. In both cases the transition can only happen from
diff --git a/js/src/frontend/SyntaxParseHandler.h b/js/src/frontend/SyntaxParseHandler.h
index b274ac642b..130a5da61d 100644
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -333,6 +333,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
MOZ_MUST_USE bool addObjectMethodDefinition(ListNodeType literal, Node name, FunctionNodeType funNode, JSOp op) { return true; }
MOZ_MUST_USE Node newClassMethodDefinition(Node key, FunctionNodeType funNode, JSOp op, bool isStatic) { return NodeGeneric; }
MOZ_MUST_USE Node newClassFieldDefinition(Node name, FunctionNodeType initializer, bool isStatic) { return NodeGeneric; }
+ MOZ_MUST_USE Node newStaticClassBlock(FunctionNodeType block) { return NodeGeneric; }
MOZ_MUST_USE bool addClassMemberDefinition(ListNodeType memberList, Node member) { return true; }
UnaryNodeType newYieldExpression(uint32_t begin, Node value) { return NodeGeneric; }
UnaryNodeType newYieldStarExpression(uint32_t begin, Node value) { return NodeGeneric; }
diff --git a/js/src/js.msg b/js/src/js.msg
index 2cae3ff125..91637edc6a 100644
--- a/js/src/js.msg
+++ b/js/src/js.msg
@@ -347,6 +347,7 @@ MSG_DEF(JSMSG_UNNAMED_CLASS_STMT, 0, JSEXN_SYNTAXERR, "class statement requ
MSG_DEF(JSMSG_UNNAMED_FUNCTION_STMT, 0, JSEXN_SYNTAXERR, "function statement requires a name")
MSG_DEF(JSMSG_UNTERMINATED_COMMENT, 0, JSEXN_SYNTAXERR, "unterminated comment")
MSG_DEF(JSMSG_UNTERMINATED_REGEXP, 0, JSEXN_SYNTAXERR, "unterminated regular expression literal")
+MSG_DEF(JSMSG_UNTERMINATED_STATIC_CLASS_BLOCK, 0, JSEXN_SYNTAXERR, "unterminated static class block")
MSG_DEF(JSMSG_UNTERMINATED_STRING, 0, JSEXN_SYNTAXERR, "unterminated string literal")
MSG_DEF(JSMSG_USELESS_EXPR, 0, JSEXN_TYPEERR, "useless expression")
MSG_DEF(JSMSG_USE_ASM_DIRECTIVE_FAIL, 0, JSEXN_SYNTAXERR, "\"use asm\" is only meaningful in the Directive Prologue of a function body")
diff --git a/js/src/jsast.tbl b/js/src/jsast.tbl
index ba6b60b68c..0ef51622b1 100644
--- a/js/src/jsast.tbl
+++ b/js/src/jsast.tbl
@@ -87,4 +87,5 @@ ASTDEF(AST_COMPUTED_NAME, "ComputedName", "computedNam
ASTDEF(AST_CLASS_STMT, "ClassStatement", "classStatement")
ASTDEF(AST_CLASS_METHOD, "ClassMethod", "classMethod")
ASTDEF(AST_CLASS_FIELD, "ClassField", "classField")
+ASTDEF(AST_STATIC_CLASS_BLOCK, "StaticClassBlock", "staticClassBlock")
/* AST_LIMIT = last + 1 */