mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-13 05:15:45 +00:00
Bug 1499448 - Implement syntax for public and private fields. r=jorendorff
Differential Revision: https://phabricator.services.mozilla.com/D8887 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
7dd4276f45
commit
b0f51cc3b0
@ -549,7 +549,7 @@ class NodeBuilder
|
||||
|
||||
MOZ_MUST_USE bool classDefinition(bool expr, HandleValue name, HandleValue heritage,
|
||||
HandleValue block, TokenPos* pos, MutableHandleValue dst);
|
||||
MOZ_MUST_USE bool classMethods(NodeVector& methods, MutableHandleValue dst);
|
||||
MOZ_MUST_USE bool classMembers(NodeVector& members, MutableHandleValue dst);
|
||||
MOZ_MUST_USE bool classMethod(HandleValue name, HandleValue body, PropKind kind, bool isStatic,
|
||||
TokenPos* pos, MutableHandleValue dst);
|
||||
|
||||
@ -1652,9 +1652,9 @@ NodeBuilder::classMethod(HandleValue name, HandleValue body, PropKind kind, bool
|
||||
}
|
||||
|
||||
bool
|
||||
NodeBuilder::classMethods(NodeVector& methods, MutableHandleValue dst)
|
||||
NodeBuilder::classMembers(NodeVector& members, MutableHandleValue dst)
|
||||
{
|
||||
return newArray(methods, dst);
|
||||
return newArray(members, dst);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -2392,7 +2392,7 @@ ASTSerializer::classDefinition(ClassNode* pn, bool expr, MutableHandleValue dst)
|
||||
}
|
||||
|
||||
return optExpression(pn->heritage(), &heritage) &&
|
||||
statement(pn->methodList(), &classBody) &&
|
||||
statement(pn->memberList(), &classBody) &&
|
||||
builder.classDefinition(expr, className, heritage, classBody, &pn->pn_pos, dst);
|
||||
}
|
||||
|
||||
@ -2620,26 +2620,31 @@ ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst)
|
||||
case ParseNodeKind::Class:
|
||||
return classDefinition(&pn->as<ClassNode>(), false, dst);
|
||||
|
||||
case ParseNodeKind::ClassMethodList:
|
||||
case ParseNodeKind::ClassMemberList:
|
||||
{
|
||||
ListNode* methodList = &pn->as<ListNode>();
|
||||
NodeVector methods(cx);
|
||||
if (!methods.reserve(methodList->count())) {
|
||||
ListNode* memberList = &pn->as<ListNode>();
|
||||
NodeVector members(cx);
|
||||
if (!members.reserve(memberList->count())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (ParseNode* item : methodList->contents()) {
|
||||
for (ParseNode* item : memberList->contents()) {
|
||||
if (item->is<ClassField>()) {
|
||||
// TODO(khyperia): Implement private field access.
|
||||
return false;
|
||||
}
|
||||
|
||||
ClassMethod* method = &item->as<ClassMethod>();
|
||||
MOZ_ASSERT(methodList->pn_pos.encloses(method->pn_pos));
|
||||
MOZ_ASSERT(memberList->pn_pos.encloses(method->pn_pos));
|
||||
|
||||
RootedValue prop(cx);
|
||||
if (!classMethod(method, &prop)) {
|
||||
return false;
|
||||
}
|
||||
methods.infallibleAppend(prop);
|
||||
members.infallibleAppend(prop);
|
||||
}
|
||||
|
||||
return builder.classMethods(methods, dst);
|
||||
return builder.classMembers(members, dst);
|
||||
}
|
||||
|
||||
default:
|
||||
@ -2960,6 +2965,7 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
|
||||
case ParseNodeKind::Dot:
|
||||
{
|
||||
PropertyAccess* prop = &pn->as<PropertyAccess>();
|
||||
// TODO(khyperia): Implement private field access.
|
||||
MOZ_ASSERT(prop->pn_pos.encloses(prop->expression().pn_pos));
|
||||
|
||||
RootedValue expr(cx);
|
||||
|
@ -121,14 +121,22 @@ CreateScriptSourceObject(JSContext* cx, const JS::ReadOnlyCompileOptions& option
|
||||
bool
|
||||
IsIdentifier(JSLinearString* str);
|
||||
|
||||
bool
|
||||
IsIdentifierNameOrPrivateName(JSLinearString* str);
|
||||
|
||||
/*
|
||||
* As above, but taking chars + length.
|
||||
*/
|
||||
bool
|
||||
IsIdentifier(const char* chars, size_t length);
|
||||
IsIdentifier(const Latin1Char* chars, size_t length);
|
||||
bool
|
||||
IsIdentifier(const char16_t* chars, size_t length);
|
||||
|
||||
bool
|
||||
IsIdentifierNameOrPrivateName(const Latin1Char* chars, size_t length);
|
||||
bool
|
||||
IsIdentifierNameOrPrivateName(const char16_t* chars, size_t length);
|
||||
|
||||
/* True if str is a keyword. Defined in TokenStream.cpp. */
|
||||
bool
|
||||
IsKeyword(JSLinearString* str);
|
||||
|
@ -1043,6 +1043,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
|
||||
return true;
|
||||
|
||||
case ParseNodeKind::ObjectPropertyName:
|
||||
case ParseNodeKind::PrivateName: // no side effects, unlike ParseNodeKind::Name
|
||||
case ParseNodeKind::String:
|
||||
case ParseNodeKind::TemplateString:
|
||||
MOZ_ASSERT(pn->is<NameNode>());
|
||||
@ -1486,17 +1487,18 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
|
||||
case ParseNodeKind::ForOf: // by ParseNodeKind::For
|
||||
case ParseNodeKind::ForHead: // by ParseNodeKind::For
|
||||
case ParseNodeKind::ClassMethod: // by ParseNodeKind::Class
|
||||
case ParseNodeKind::ClassField: // by ParseNodeKind::Class
|
||||
case ParseNodeKind::ClassNames: // by ParseNodeKind::Class
|
||||
case ParseNodeKind::ClassMethodList: // by ParseNodeKind::Class
|
||||
case ParseNodeKind::ImportSpecList: // by ParseNodeKind::Import
|
||||
case ParseNodeKind::ClassMemberList: // by ParseNodeKind::Class
|
||||
case ParseNodeKind::ImportSpecList: // by ParseNodeKind::Import
|
||||
case ParseNodeKind::ImportSpec: // by ParseNodeKind::Import
|
||||
case ParseNodeKind::ExportBatchSpec:// by ParseNodeKind::Export
|
||||
case ParseNodeKind::ExportSpecList: // by ParseNodeKind::Export
|
||||
case ParseNodeKind::ExportBatchSpec: // by ParseNodeKind::Export
|
||||
case ParseNodeKind::ExportSpecList: // by ParseNodeKind::Export
|
||||
case ParseNodeKind::ExportSpec: // by ParseNodeKind::Export
|
||||
case ParseNodeKind::CallSiteObj: // by ParseNodeKind::TaggedTemplate
|
||||
case ParseNodeKind::PosHolder: // by ParseNodeKind::NewTarget
|
||||
case ParseNodeKind::SuperBase: // by ParseNodeKind::Elem and others
|
||||
case ParseNodeKind::PropertyName: // by ParseNodeKind::Dot
|
||||
case ParseNodeKind::CallSiteObj: // by ParseNodeKind::TaggedTemplate
|
||||
case ParseNodeKind::PosHolder: // by ParseNodeKind::NewTarget
|
||||
case ParseNodeKind::SuperBase: // by ParseNodeKind::Elem and others
|
||||
case ParseNodeKind::PropertyName: // by ParseNodeKind::Dot
|
||||
MOZ_CRASH("handled by parent nodes");
|
||||
|
||||
case ParseNodeKind::Limit: // invalid sentinel value
|
||||
@ -1789,6 +1791,8 @@ BytecodeEmitter::emitPropLHS(PropertyAccess* prop)
|
||||
}
|
||||
|
||||
while (true) {
|
||||
// TODO(khyperia): Implement private field access.
|
||||
|
||||
// Walk back up the list, emitting annotated name ops.
|
||||
if (!emitAtomOp(pndot->key().atom(), JSOP_GETPROP)) {
|
||||
return false;
|
||||
@ -1810,6 +1814,7 @@ bool
|
||||
BytecodeEmitter::emitPropIncDec(UnaryNode* incDec)
|
||||
{
|
||||
PropertyAccess* prop = &incDec->kid()->as<PropertyAccess>();
|
||||
// TODO(khyperia): Implement private field access.
|
||||
bool isSuper = prop->isSuper();
|
||||
ParseNodeKind kind = incDec->getKind();
|
||||
PropOpEmitter poe(this,
|
||||
@ -2624,6 +2629,7 @@ BytecodeEmitter::emitSetOrInitializeDestructuring(ParseNode* target, Destructuri
|
||||
// // [Other]
|
||||
// // OBJ VAL
|
||||
PropertyAccess* prop = &target->as<PropertyAccess>();
|
||||
// TODO(khyperia): Implement private field access.
|
||||
bool isSuper = prop->isSuper();
|
||||
PropOpEmitter poe(this,
|
||||
PropOpEmitter::Kind::SimpleAssignment,
|
||||
@ -3993,6 +3999,7 @@ BytecodeEmitter::emitAssignment(ParseNode* lhs, JSOp compoundOp, ParseNode* rhs)
|
||||
switch (lhs->getKind()) {
|
||||
case ParseNodeKind::Dot: {
|
||||
PropertyAccess* prop = &lhs->as<PropertyAccess>();
|
||||
// TODO(khyperia): Implement private field access.
|
||||
if (!poe->emitGet(prop->key().atom())) { // [Super]
|
||||
// // THIS SUPERBASE PROP
|
||||
// // [Other]
|
||||
@ -4066,6 +4073,7 @@ BytecodeEmitter::emitAssignment(ParseNode* lhs, JSOp compoundOp, ParseNode* rhs)
|
||||
switch (lhs->getKind()) {
|
||||
case ParseNodeKind::Dot: {
|
||||
PropertyAccess* prop = &lhs->as<PropertyAccess>();
|
||||
// TODO(khyperia): Implement private field access.
|
||||
if (!poe->emitAssignment(prop->key().atom())) { // VAL
|
||||
return false;
|
||||
}
|
||||
@ -6392,6 +6400,7 @@ BytecodeEmitter::emitDeleteProperty(UnaryNode* deleteNode)
|
||||
MOZ_ASSERT(deleteNode->isKind(ParseNodeKind::DeleteProp));
|
||||
|
||||
PropertyAccess* propExpr = &deleteNode->kid()->as<PropertyAccess>();
|
||||
// TODO(khyperia): Implement private field access.
|
||||
PropOpEmitter poe(this,
|
||||
PropOpEmitter::Kind::Delete,
|
||||
propExpr->as<PropertyAccess>().isSuper()
|
||||
@ -6793,6 +6802,7 @@ BytecodeEmitter::emitCalleeAndThis(ParseNode* callee, ParseNode* call, CallOrNew
|
||||
case ParseNodeKind::Dot: {
|
||||
MOZ_ASSERT(emitterMode != BytecodeEmitter::SelfHosting);
|
||||
PropertyAccess* prop = &callee->as<PropertyAccess>();
|
||||
// TODO(khyperia): Implement private field access.
|
||||
bool isSuper = prop->isSuper();
|
||||
|
||||
PropOpEmitter& poe = cone.prepareForPropCallee(isSuper);
|
||||
@ -7018,7 +7028,9 @@ BytecodeEmitter::emitCallOrNew(BinaryNode* callNode,
|
||||
cur->isKind(ParseNodeKind::Dot);
|
||||
cur = &cur->as<PropertyAccess>().expression())
|
||||
{
|
||||
ParseNode* left = &cur->as<PropertyAccess>().expression();
|
||||
PropertyAccess* prop = &cur->as<PropertyAccess>();
|
||||
ParseNode* left = &prop->expression();
|
||||
// TODO(khyperia): Implement private field access.
|
||||
if (left->isKind(ParseNodeKind::Name) || left->isKind(ParseNodeKind::This) ||
|
||||
left->isKind(ParseNodeKind::SuperBase))
|
||||
{
|
||||
@ -7302,6 +7314,10 @@ bool
|
||||
BytecodeEmitter::emitPropertyList(ListNode* obj, MutableHandlePlainObject objp, PropListType type)
|
||||
{
|
||||
for (ParseNode* propdef : obj->contents()) {
|
||||
if (propdef->is<ClassField>()) {
|
||||
// TODO(khyperia): Implement private field access.
|
||||
return false;
|
||||
}
|
||||
if (!updateSourceCoordNotes(propdef->pn_pos.begin)) {
|
||||
return false;
|
||||
}
|
||||
@ -8132,9 +8148,13 @@ BytecodeEmitter::emitClass(ClassNode* classNode)
|
||||
{
|
||||
ClassNames* names = classNode->names();
|
||||
ParseNode* heritageExpression = classNode->heritage();
|
||||
ListNode* classMethods = classNode->methodList();
|
||||
ListNode* classMembers = classNode->memberList();
|
||||
CodeNode* constructor = nullptr;
|
||||
for (ParseNode* mn : classMethods->contents()) {
|
||||
for (ParseNode* mn : classMembers->contents()) {
|
||||
if (mn->is<ClassField>()) {
|
||||
// TODO(khyperia): Implement private field access.
|
||||
return false;
|
||||
}
|
||||
ClassMethod& method = mn->as<ClassMethod>();
|
||||
ParseNode& methodName = method.name();
|
||||
if (!method.isStatic() &&
|
||||
@ -8321,7 +8341,7 @@ BytecodeEmitter::emitClass(ClassNode* classNode)
|
||||
}
|
||||
|
||||
RootedPlainObject obj(cx);
|
||||
if (!emitPropertyList(classMethods, &obj, ClassBody)) { // ... CONSTRUCTOR HOMEOBJ
|
||||
if (!emitPropertyList(classMembers, &obj, ClassBody)) { // ... CONSTRUCTOR HOMEOBJ
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -8693,6 +8713,7 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
|
||||
|
||||
case ParseNodeKind::Dot: {
|
||||
PropertyAccess* prop = &pn->as<PropertyAccess>();
|
||||
// TODO(khyperia): Implement private field access.
|
||||
bool isSuper = prop->isSuper();
|
||||
PropOpEmitter poe(this,
|
||||
PropOpEmitter::Kind::Get,
|
||||
|
@ -365,6 +365,7 @@ ContainsHoistedDeclaration(JSContext* cx, ParseNode* node, bool* result)
|
||||
case ParseNodeKind::Arguments:
|
||||
case ParseNodeKind::Call:
|
||||
case ParseNodeKind::Name:
|
||||
case ParseNodeKind::PrivateName:
|
||||
case ParseNodeKind::TemplateString:
|
||||
case ParseNodeKind::TemplateStringList:
|
||||
case ParseNodeKind::TaggedTemplate:
|
||||
@ -386,7 +387,8 @@ ContainsHoistedDeclaration(JSContext* cx, ParseNode* node, bool* result)
|
||||
case ParseNodeKind::ForOf:
|
||||
case ParseNodeKind::ForHead:
|
||||
case ParseNodeKind::ClassMethod:
|
||||
case ParseNodeKind::ClassMethodList:
|
||||
case ParseNodeKind::ClassField:
|
||||
case ParseNodeKind::ClassMemberList:
|
||||
case ParseNodeKind::ClassNames:
|
||||
case ParseNodeKind::NewTarget:
|
||||
case ParseNodeKind::ImportMeta:
|
||||
@ -1631,6 +1633,7 @@ Fold(JSContext* cx, ParseNode** pnp, PerHandlerParser<FullParseHandler>& parser)
|
||||
return true;
|
||||
|
||||
case ParseNodeKind::ObjectPropertyName:
|
||||
case ParseNodeKind::PrivateName:
|
||||
case ParseNodeKind::String:
|
||||
case ParseNodeKind::TemplateString:
|
||||
MOZ_ASSERT(pn->is<NameNode>());
|
||||
@ -1759,7 +1762,7 @@ Fold(JSContext* cx, ParseNode** pnp, PerHandlerParser<FullParseHandler>& parser)
|
||||
case ParseNodeKind::Array:
|
||||
case ParseNodeKind::Object:
|
||||
case ParseNodeKind::StatementList:
|
||||
case ParseNodeKind::ClassMethodList:
|
||||
case ParseNodeKind::ClassMemberList:
|
||||
case ParseNodeKind::TemplateStringList:
|
||||
case ParseNodeKind::Var:
|
||||
case ParseNodeKind::Const:
|
||||
@ -1849,6 +1852,17 @@ Fold(JSContext* cx, ParseNode** pnp, PerHandlerParser<FullParseHandler>& parser)
|
||||
Fold(cx, node->unsafeRightReference(), parser);
|
||||
}
|
||||
|
||||
case ParseNodeKind::ClassField: {
|
||||
ClassField* node = &pn->as<ClassField>();
|
||||
if (node->hasInitializer()) {
|
||||
if (!Fold(cx, node->unsafeInitializerReference(), parser)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case ParseNodeKind::NewTarget:
|
||||
case ParseNodeKind::ImportMeta: {
|
||||
#ifdef DEBUG
|
||||
|
@ -264,7 +264,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
|
||||
if (!elision) {
|
||||
return false;
|
||||
}
|
||||
addList(/* list = */ literal, /* child = */ elision);
|
||||
addList(/* list = */ literal, /* kid = */ elision);
|
||||
literal->setHasArrayHoleOrSpread();
|
||||
literal->setHasNonConstInitializer();
|
||||
return true;
|
||||
@ -277,7 +277,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
|
||||
if (!spread) {
|
||||
return false;
|
||||
}
|
||||
addList(/* list = */ literal, /* child = */ spread);
|
||||
addList(/* list = */ literal, /* kid = */ spread);
|
||||
literal->setHasArrayHoleOrSpread();
|
||||
literal->setHasNonConstInitializer();
|
||||
return true;
|
||||
@ -287,7 +287,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
|
||||
if (!element->isConstant()) {
|
||||
literal->setHasNonConstInitializer();
|
||||
}
|
||||
addList(/* list = */ literal, /* child = */ element);
|
||||
addList(/* list = */ literal, /* kid = */ element);
|
||||
}
|
||||
|
||||
BinaryNodeType newCall(Node callee, Node args) {
|
||||
@ -310,11 +310,11 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
|
||||
return new_<ListNode>(ParseNodeKind::Object, TokenPos(begin, begin + 1));
|
||||
}
|
||||
|
||||
ClassNodeType newClass(Node name, Node heritage, Node methodBlock, const TokenPos& pos) {
|
||||
return new_<ClassNode>(name, heritage, methodBlock, pos);
|
||||
ClassNodeType newClass(Node name, Node heritage, Node memberBlock, const TokenPos& pos) {
|
||||
return new_<ClassNode>(name, heritage, memberBlock, pos);
|
||||
}
|
||||
ListNodeType newClassMethodList(uint32_t begin) {
|
||||
return new_<ListNode>(ParseNodeKind::ClassMethodList, TokenPos(begin, begin + 1));
|
||||
ListNodeType newClassMemberList(uint32_t begin) {
|
||||
return new_<ListNode>(ParseNodeKind::ClassMemberList, TokenPos(begin, begin + 1));
|
||||
}
|
||||
ClassNamesType newClassNames(Node outer, Node inner, const TokenPos& pos) {
|
||||
return new_<ClassNames>(outer, inner, pos);
|
||||
@ -339,7 +339,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
|
||||
if (!mutation) {
|
||||
return false;
|
||||
}
|
||||
addList(/* list = */ literal, /* child = */ mutation);
|
||||
addList(/* list = */ literal, /* kid = */ mutation);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -357,7 +357,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
|
||||
literal->setHasNonConstInitializer();
|
||||
}
|
||||
|
||||
addList(/* list = */ literal, /* child = */ propdef);
|
||||
addList(/* list = */ literal, /* kid = */ propdef);
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool addPropertyDefinition(ListNodeType literal, Node key, Node val) {
|
||||
@ -380,7 +380,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
|
||||
if (!propdef) {
|
||||
return false;
|
||||
}
|
||||
addList(/* list = */ literal, /* child = */ propdef);
|
||||
addList(/* list = */ literal, /* kid = */ propdef);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -392,7 +392,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
|
||||
if (!spread) {
|
||||
return false;
|
||||
}
|
||||
addList(/* list = */ literal, /* child = */ spread);
|
||||
addList(/* list = */ literal, /* kid = */ spread);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -408,15 +408,15 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
|
||||
return false;
|
||||
}
|
||||
|
||||
addList(/* list = */ literal, /* child = */ propdef);
|
||||
addList(/* list = */ literal, /* kid = */ propdef);
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool addClassMethodDefinition(ListNodeType methodList, Node key,
|
||||
MOZ_MUST_USE bool addClassMethodDefinition(ListNodeType memberList, Node key,
|
||||
CodeNodeType funNode, AccessorType atype,
|
||||
bool isStatic)
|
||||
{
|
||||
MOZ_ASSERT(methodList->isKind(ParseNodeKind::ClassMethodList));
|
||||
MOZ_ASSERT(memberList->isKind(ParseNodeKind::ClassMemberList));
|
||||
MOZ_ASSERT(isUsableAsObjectPropertyName(key));
|
||||
|
||||
checkAndSetIsDirectRHSAnonFunction(funNode);
|
||||
@ -426,7 +426,22 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
|
||||
if (!classMethod) {
|
||||
return false;
|
||||
}
|
||||
addList(/* list = */ methodList, /* child = */ classMethod);
|
||||
addList(/* list = */ memberList, /* kid = */ classMethod);
|
||||
return true;
|
||||
}
|
||||
|
||||
MOZ_MUST_USE bool addClassFieldDefinition(ListNodeType memberList,
|
||||
Node name, Node initializer)
|
||||
{
|
||||
MOZ_ASSERT(memberList->isKind(ParseNodeKind::ClassMemberList));
|
||||
MOZ_ASSERT(isUsableAsObjectPropertyName(name));
|
||||
|
||||
ClassField* classField = new_<ClassField>(name, initializer);
|
||||
|
||||
if (!classField) {
|
||||
return false;
|
||||
}
|
||||
addList(/* list = */ memberList, /* kid = */ classField);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -466,7 +481,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
|
||||
void addStatementToList(ListNodeType list, Node stmt) {
|
||||
MOZ_ASSERT(list->isKind(ParseNodeKind::StatementList));
|
||||
|
||||
addList(/* list = */ list, /* child = */ stmt);
|
||||
addList(/* list = */ list, /* kid = */ stmt);
|
||||
|
||||
if (isFunctionStmt(stmt)) {
|
||||
// Notify the emitter that the block contains body-level function
|
||||
@ -483,7 +498,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
|
||||
void addCaseStatementToList(ListNodeType list, CaseClauseType caseClause) {
|
||||
MOZ_ASSERT(list->isKind(ParseNodeKind::StatementList));
|
||||
|
||||
addList(/* list = */ list, /* child = */ caseClause);
|
||||
addList(/* list = */ list, /* kid = */ caseClause);
|
||||
|
||||
if (caseClause->statementList()->hasTopLevelFunctionDeclarations()) {
|
||||
list->setHasTopLevelFunctionDeclarations();
|
||||
@ -735,11 +750,11 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
|
||||
funbox->functionNode = funNode;
|
||||
}
|
||||
void addFunctionFormalParameter(CodeNodeType funNode, Node argpn) {
|
||||
addList(/* list = */ funNode->body(), /* child = */ argpn);
|
||||
addList(/* list = */ funNode->body(), /* kid = */ argpn);
|
||||
}
|
||||
void setFunctionBody(CodeNodeType funNode, LexicalScopeNodeType body) {
|
||||
MOZ_ASSERT(funNode->body()->isKind(ParseNodeKind::ParamsBody));
|
||||
addList(/* list = */ funNode->body(), /* child = */ body);
|
||||
addList(/* list = */ funNode->body(), /* kid = */ body);
|
||||
}
|
||||
|
||||
CodeNodeType newModule(const TokenPos& pos) {
|
||||
|
@ -90,6 +90,7 @@ class NameResolver
|
||||
}
|
||||
|
||||
case ParseNodeKind::Name:
|
||||
case ParseNodeKind::PrivateName:
|
||||
*foundName = true;
|
||||
return buf->append(n->as<NameNode>().atom());
|
||||
|
||||
@ -148,6 +149,7 @@ class NameResolver
|
||||
}
|
||||
|
||||
switch (cur->getKind()) {
|
||||
case ParseNodeKind::PrivateName:
|
||||
case ParseNodeKind::Name: return cur; /* found the initialized declaration */
|
||||
case ParseNodeKind::This: return cur; /* Setting a property of 'this'. */
|
||||
case ParseNodeKind::Function: return nullptr; /* won't find an assignment or declaration */
|
||||
@ -447,6 +449,7 @@ class NameResolver
|
||||
break;
|
||||
|
||||
case ParseNodeKind::ObjectPropertyName:
|
||||
case ParseNodeKind::PrivateName: // TODO(khyperia): Implement private field access.
|
||||
case ParseNodeKind::String:
|
||||
case ParseNodeKind::TemplateString:
|
||||
MOZ_ASSERT(cur->is<NameNode>());
|
||||
@ -540,6 +543,21 @@ class NameResolver
|
||||
break;
|
||||
}
|
||||
|
||||
case ParseNodeKind::ClassField: {
|
||||
ClassField* node = &cur->as<ClassField>();
|
||||
if (!resolve(&node->name(), prefix)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (node->hasInitializer()) {
|
||||
if (!resolve(&node->initializer(), prefix)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ParseNodeKind::Elem: {
|
||||
PropertyByValue* elem = &cur->as<PropertyByValue>();
|
||||
if (!elem->isSuper() && !resolve(&elem->expression(), prefix)) {
|
||||
@ -701,7 +719,7 @@ class NameResolver
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!resolve(classNode->methodList(), prefix)) {
|
||||
if (!resolve(classNode->memberList(), prefix)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
@ -809,7 +827,7 @@ class NameResolver
|
||||
break;
|
||||
|
||||
case ParseNodeKind::Object:
|
||||
case ParseNodeKind::ClassMethodList:
|
||||
case ParseNodeKind::ClassMemberList:
|
||||
for (ParseNode* element : cur->as<ListNode>().contents()) {
|
||||
if (!resolve(element, prefix)) {
|
||||
return false;
|
||||
|
@ -174,6 +174,9 @@ ParseNode::dump(GenericPrinter& out, int indent)
|
||||
case PN_NAME:
|
||||
as<NameNode>().dump(out, indent);
|
||||
return;
|
||||
case PN_FIELD:
|
||||
as<ClassField>().dump(out, indent);
|
||||
return;
|
||||
case PN_NUMBER:
|
||||
as<NumericLiteral>().dump(out, indent);
|
||||
return;
|
||||
@ -347,6 +350,7 @@ NameNode::dump(GenericPrinter& out, int indent)
|
||||
return;
|
||||
|
||||
case ParseNodeKind::Name:
|
||||
case ParseNodeKind::PrivateName: // atom() already includes the '#', no need to specially include it.
|
||||
case ParseNodeKind::PropertyName:
|
||||
if (!atom()) {
|
||||
out.put("#<null name>");
|
||||
@ -388,6 +392,21 @@ NameNode::dump(GenericPrinter& out, int indent)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ClassField::dump(GenericPrinter& out, int indent)
|
||||
{
|
||||
out.printf("(");
|
||||
if (hasInitializer()) {
|
||||
indent += 2;
|
||||
}
|
||||
DumpParseTree(&name(), out, indent);
|
||||
if (hasInitializer()) {
|
||||
IndentNewLine(out, indent);
|
||||
DumpParseTree(&initializer(), out, indent);
|
||||
}
|
||||
out.printf(")");
|
||||
}
|
||||
|
||||
void
|
||||
LexicalScopeNode::dump(GenericPrinter& out, int indent)
|
||||
{
|
||||
|
@ -68,6 +68,7 @@ class ObjectBox;
|
||||
F(Arguments, PN_LIST) \
|
||||
F(Name, PN_NAME) \
|
||||
F(ObjectPropertyName, PN_NAME) \
|
||||
F(PrivateName, PN_NAME) \
|
||||
F(ComputedName, PN_UNARY) \
|
||||
F(Number, PN_NUMBER) \
|
||||
F(String, PN_NAME) \
|
||||
@ -128,7 +129,8 @@ class ObjectBox;
|
||||
F(MutateProto, PN_UNARY) \
|
||||
F(Class, PN_TERNARY) \
|
||||
F(ClassMethod, PN_BINARY) \
|
||||
F(ClassMethodList, PN_LIST) \
|
||||
F(ClassField, PN_FIELD) \
|
||||
F(ClassMemberList, PN_LIST) \
|
||||
F(ClassNames, PN_BINARY) \
|
||||
F(NewTarget, PN_BINARY) \
|
||||
F(PosHolder, PN_NULLARY) \
|
||||
@ -253,15 +255,15 @@ IsTypeofKind(ParseNodeKind kind)
|
||||
* kid1: ClassNames for class name. can be null for anonymous class.
|
||||
* kid2: expression after `extends`. null if no expression
|
||||
* kid3: either of
|
||||
* * ClassMethodList, if anonymous class
|
||||
* * LexicalScopeNode which contains ClassMethodList as scopeBody,
|
||||
* * ClassMemberList, if anonymous class
|
||||
* * LexicalScopeNode which contains ClassMemberList as scopeBody,
|
||||
* if named class
|
||||
* ClassNames (ClassNames)
|
||||
* left: Name node for outer binding, or null if the class is an expression
|
||||
* that doesn't create an outer binding
|
||||
* right: Name node for inner binding
|
||||
* ClassMethodList (ListNode)
|
||||
* head: list of N ClassMethod nodes
|
||||
* ClassMemberList (ListNode)
|
||||
* head: list of N ClassMethod or ClassField nodes
|
||||
* count: N >= 0
|
||||
* ClassMethod (ClassMethod)
|
||||
* name: propertyName
|
||||
@ -520,6 +522,7 @@ enum ParseNodeArity
|
||||
PN_CODE, /* module or function definition node */
|
||||
PN_LIST, /* generic singly linked list */
|
||||
PN_NAME, /* name, label, string */
|
||||
PN_FIELD, /* field name, optional initializer */
|
||||
PN_NUMBER, /* numeric literal */
|
||||
PN_REGEXP, /* regexp literal */
|
||||
PN_LOOP, /* loop control (break/continue) */
|
||||
@ -532,6 +535,7 @@ enum ParseNodeArity
|
||||
macro(AssignmentNode, AssignmentNodeType, asAssignment) \
|
||||
macro(CaseClause, CaseClauseType, asCaseClause) \
|
||||
macro(ClassMethod, ClassMethodType, asClassMethod) \
|
||||
macro(ClassField, ClassFieldType, asClassField) \
|
||||
macro(ClassNames, ClassNamesType, asClassNames) \
|
||||
macro(ForNode, ForNodeType, asFor) \
|
||||
macro(PropertyAccess, PropertyAccessType, asPropertyAccess) \
|
||||
@ -713,6 +717,12 @@ class ParseNode
|
||||
ParseNode* initOrStmt; /* var initializer, argument default,
|
||||
* or label statement target */
|
||||
} name;
|
||||
struct {
|
||||
private:
|
||||
friend class ClassField;
|
||||
ParseNode* name;
|
||||
ParseNode* initializer; /* field initializer - optional */
|
||||
} field;
|
||||
struct {
|
||||
private:
|
||||
friend class RegExpLiteral;
|
||||
@ -972,7 +982,7 @@ class BinaryNode : public ParseNode
|
||||
}
|
||||
|
||||
// Methods used by FoldConstants.cpp.
|
||||
// caller are responsible for keeping the list consistent.
|
||||
// callers are responsible for keeping the list consistent.
|
||||
ParseNode** unsafeLeftReference() {
|
||||
return &pn_u.binary.left;
|
||||
}
|
||||
@ -1179,7 +1189,7 @@ class ListNode : public ParseNode
|
||||
MOZ_MUST_USE bool hasNonConstInitializer() const {
|
||||
MOZ_ASSERT(isKind(ParseNodeKind::Array) ||
|
||||
isKind(ParseNodeKind::Object) ||
|
||||
isKind(ParseNodeKind::ClassMethodList));
|
||||
isKind(ParseNodeKind::ClassMemberList));
|
||||
return pn_u.list.xflags & hasNonConstInitializerBit;
|
||||
}
|
||||
|
||||
@ -1196,7 +1206,7 @@ class ListNode : public ParseNode
|
||||
void setHasNonConstInitializer() {
|
||||
MOZ_ASSERT(isKind(ParseNodeKind::Array) ||
|
||||
isKind(ParseNodeKind::Object) ||
|
||||
isKind(ParseNodeKind::ClassMethodList));
|
||||
isKind(ParseNodeKind::ClassMemberList));
|
||||
pn_u.list.xflags |= hasNonConstInitializerBit;
|
||||
}
|
||||
|
||||
@ -1960,6 +1970,48 @@ class ClassMethod : public BinaryNode
|
||||
}
|
||||
};
|
||||
|
||||
class ClassField : public ParseNode
|
||||
{
|
||||
public:
|
||||
ClassField(ParseNode* name, ParseNode* initializer)
|
||||
: ParseNode(ParseNodeKind::ClassField, JSOP_NOP, PN_FIELD,
|
||||
initializer == nullptr ? name->pn_pos : TokenPos::box(name->pn_pos, initializer->pn_pos))
|
||||
{
|
||||
pn_u.field.name = name;
|
||||
pn_u.field.initializer = initializer;
|
||||
}
|
||||
|
||||
static bool test(const ParseNode& node) {
|
||||
return node.isKind(ParseNodeKind::ClassField);
|
||||
}
|
||||
|
||||
ParseNode& name() const {
|
||||
return *pn_u.field.name;
|
||||
}
|
||||
|
||||
bool hasInitializer() const {
|
||||
return pn_u.field.initializer != nullptr;
|
||||
}
|
||||
|
||||
ParseNode& initializer() const {
|
||||
return *pn_u.field.initializer;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void dump(GenericPrinter& out, int indent);
|
||||
#endif
|
||||
|
||||
// Methods used by FoldConstants.cpp.
|
||||
// callers are responsible for keeping the list consistent.
|
||||
ParseNode** unsafeNameReference() {
|
||||
return &pn_u.field.name;
|
||||
}
|
||||
|
||||
ParseNode** unsafeInitializerReference() {
|
||||
return &pn_u.field.initializer;
|
||||
}
|
||||
};
|
||||
|
||||
class SwitchStatement : public BinaryNode
|
||||
{
|
||||
public:
|
||||
@ -2046,13 +2098,13 @@ class ClassNames : public BinaryNode
|
||||
class ClassNode : public TernaryNode
|
||||
{
|
||||
public:
|
||||
ClassNode(ParseNode* names, ParseNode* heritage, ParseNode* methodsOrBlock,
|
||||
ClassNode(ParseNode* names, ParseNode* heritage, ParseNode* membersOrBlock,
|
||||
const TokenPos& pos)
|
||||
: TernaryNode(ParseNodeKind::Class, names, heritage, methodsOrBlock, pos)
|
||||
: TernaryNode(ParseNodeKind::Class, names, heritage, membersOrBlock, pos)
|
||||
{
|
||||
MOZ_ASSERT_IF(names, names->is<ClassNames>());
|
||||
MOZ_ASSERT(methodsOrBlock->is<LexicalScopeNode>() ||
|
||||
methodsOrBlock->isKind(ParseNodeKind::ClassMethodList));
|
||||
MOZ_ASSERT(membersOrBlock->is<LexicalScopeNode>() ||
|
||||
membersOrBlock->isKind(ParseNodeKind::ClassMemberList));
|
||||
}
|
||||
|
||||
static bool test(const ParseNode& node) {
|
||||
@ -2067,14 +2119,14 @@ class ClassNode : public TernaryNode
|
||||
ParseNode* heritage() const {
|
||||
return kid2();
|
||||
}
|
||||
ListNode* methodList() const {
|
||||
ParseNode* methodsOrBlock = kid3();
|
||||
if (methodsOrBlock->isKind(ParseNodeKind::ClassMethodList)) {
|
||||
return &methodsOrBlock->as<ListNode>();
|
||||
ListNode* memberList() const {
|
||||
ParseNode* membersOrBlock = kid3();
|
||||
if (membersOrBlock->isKind(ParseNodeKind::ClassMemberList)) {
|
||||
return &membersOrBlock->as<ListNode>();
|
||||
}
|
||||
|
||||
ListNode* list = &methodsOrBlock->as<LexicalScopeNode>().scopeBody()->as<ListNode>();
|
||||
MOZ_ASSERT(list->isKind(ParseNodeKind::ClassMethodList));
|
||||
ListNode* list = &membersOrBlock->as<LexicalScopeNode>().scopeBody()->as<ListNode>();
|
||||
MOZ_ASSERT(list->isKind(ParseNodeKind::ClassMemberList));
|
||||
return list;
|
||||
}
|
||||
Handle<LexicalScope::Data*> scopeBindings() const {
|
||||
|
@ -5017,7 +5017,7 @@ GeneralParser<ParseHandler, Unit>::objectBindingPattern(DeclarationKind kind,
|
||||
TokenPos namePos = anyChars.nextToken().pos;
|
||||
|
||||
PropertyType propType;
|
||||
Node propName = propertyName(yieldHandling, declKind, literal, &propType, &propAtom);
|
||||
Node propName = propertyName(yieldHandling, PropertyNameInPattern, declKind, literal, &propType, &propAtom);
|
||||
if (!propName) {
|
||||
return null();
|
||||
}
|
||||
@ -8027,8 +8027,8 @@ GeneralParser<ParseHandler, Unit>::classDefinition(YieldHandling yieldHandling,
|
||||
|
||||
MUST_MATCH_TOKEN(TokenKind::LeftCurly, JSMSG_CURLY_BEFORE_CLASS);
|
||||
|
||||
ListNodeType classMethods = handler.newClassMethodList(pos().begin);
|
||||
if (!classMethods) {
|
||||
ListNodeType classMembers = handler.newClassMemberList(pos().begin);
|
||||
if (!classMembers) {
|
||||
return null();
|
||||
}
|
||||
|
||||
@ -8072,11 +8072,44 @@ GeneralParser<ParseHandler, Unit>::classDefinition(YieldHandling yieldHandling,
|
||||
}
|
||||
|
||||
PropertyType propType;
|
||||
Node propName = propertyName(yieldHandling, declKind, classMethods, &propType, &propAtom);
|
||||
Node propName = propertyName(yieldHandling, PropertyNameInClass, declKind, classMembers, &propType, &propAtom);
|
||||
if (!propName) {
|
||||
return null();
|
||||
}
|
||||
|
||||
if (propType == PropertyType::Field) {
|
||||
if (isStatic) {
|
||||
errorAt(nameOffset, JSMSG_BAD_METHOD_DEF);
|
||||
return null();
|
||||
}
|
||||
if (!tokenStream.getToken(&tt)) {
|
||||
return null();
|
||||
}
|
||||
Node initializer = null();
|
||||
if (tt == TokenKind::Assign) {
|
||||
initializer = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
|
||||
if (!tokenStream.getToken(&tt)) {
|
||||
return null();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(khyperia): Implement ASI
|
||||
if (tt != TokenKind::Semi) {
|
||||
error(JSMSG_MISSING_SEMI_FIELD);
|
||||
return null();
|
||||
}
|
||||
|
||||
if (!handler.addClassFieldDefinition(classMembers, propName, initializer)) {
|
||||
return null();
|
||||
}
|
||||
|
||||
// TODO(khyperia): Change the below to `continue;` once fields are
|
||||
// fully supported in the backend. We can't fail in BytecodeCompiler
|
||||
// because of lazy parsing.
|
||||
errorAt(nameOffset, JSMSG_FIELDS_NOT_SUPPORTED);
|
||||
return null();
|
||||
}
|
||||
|
||||
if (propType != PropertyType::Getter && propType != PropertyType::Setter &&
|
||||
propType != PropertyType::Method && propType != PropertyType::GeneratorMethod &&
|
||||
propType != PropertyType::AsyncMethod &&
|
||||
@ -8133,7 +8166,7 @@ GeneralParser<ParseHandler, Unit>::classDefinition(YieldHandling yieldHandling,
|
||||
}
|
||||
|
||||
AccessorType atype = ToAccessorType(propType);
|
||||
if (!handler.addClassMethodDefinition(classMethods, propName, funNode, atype, isStatic)) {
|
||||
if (!handler.addClassMethodDefinition(classMembers, propName, funNode, atype, isStatic)) {
|
||||
return null();
|
||||
}
|
||||
}
|
||||
@ -8149,7 +8182,7 @@ GeneralParser<ParseHandler, Unit>::classDefinition(YieldHandling yieldHandling,
|
||||
}
|
||||
|
||||
Node nameNode = null();
|
||||
Node methodsOrBlock = classMethods;
|
||||
Node membersOrBlock = classMembers;
|
||||
if (name) {
|
||||
// The inner name is immutable.
|
||||
if (!noteDeclaredName(name, DeclarationKind::Const, namePos)) {
|
||||
@ -8161,12 +8194,12 @@ GeneralParser<ParseHandler, Unit>::classDefinition(YieldHandling yieldHandling,
|
||||
return null();
|
||||
}
|
||||
|
||||
Node classBlock = finishLexicalScope(*innerScope, classMethods);
|
||||
Node classBlock = finishLexicalScope(*innerScope, classMembers);
|
||||
if (!classBlock) {
|
||||
return null();
|
||||
}
|
||||
|
||||
methodsOrBlock = classBlock;
|
||||
membersOrBlock = classBlock;
|
||||
|
||||
// Pop the inner scope.
|
||||
innerScope.reset();
|
||||
@ -8193,7 +8226,7 @@ GeneralParser<ParseHandler, Unit>::classDefinition(YieldHandling yieldHandling,
|
||||
|
||||
MOZ_ALWAYS_TRUE(setLocalStrictMode(savedStrictness));
|
||||
|
||||
return handler.newClass(nameNode, classHeritage, methodsOrBlock,
|
||||
return handler.newClass(nameNode, classHeritage, membersOrBlock,
|
||||
TokenPos(classStartOffset, classEndOffset));
|
||||
}
|
||||
|
||||
@ -9604,6 +9637,7 @@ GeneralParser<ParseHandler, Unit>::memberExpr(YieldHandling yieldHandling,
|
||||
if (!tokenStream.getToken(&tt)) {
|
||||
return null();
|
||||
}
|
||||
|
||||
if (TokenKindIsPossibleIdentifierName(tt)) {
|
||||
PropertyName* field = anyChars.currentName();
|
||||
if (handler.isSuperBase(lhs) && !checkAndMarkSuperScope()) {
|
||||
@ -9817,7 +9851,7 @@ GeneralParser<ParseHandler, Unit>::checkLabelOrIdentifierReference(PropertyName*
|
||||
tt = hint;
|
||||
}
|
||||
|
||||
if (tt == TokenKind::Name) {
|
||||
if (tt == TokenKind::Name || tt == TokenKind::PrivateName) {
|
||||
return true;
|
||||
}
|
||||
if (TokenKindIsContextualKeyword(tt)) {
|
||||
@ -10275,10 +10309,11 @@ GeneralParser<ParseHandler, Unit>::arrayInitializer(YieldHandling yieldHandling,
|
||||
template <class ParseHandler, typename Unit>
|
||||
typename ParseHandler::Node
|
||||
GeneralParser<ParseHandler, Unit>::propertyName(YieldHandling yieldHandling,
|
||||
const Maybe<DeclarationKind>& maybeDecl,
|
||||
ListNodeType propList,
|
||||
PropertyType* propType,
|
||||
MutableHandleAtom propAtom)
|
||||
PropertyNameContext propertyNameContext,
|
||||
const Maybe<DeclarationKind>& maybeDecl,
|
||||
ListNodeType propList,
|
||||
PropertyType* propType,
|
||||
MutableHandleAtom propAtom)
|
||||
{
|
||||
TokenKind ltok;
|
||||
if (!tokenStream.getToken(<ok)) {
|
||||
@ -10449,6 +10484,16 @@ GeneralParser<ParseHandler, Unit>::propertyName(YieldHandling yieldHandling,
|
||||
return propName;
|
||||
}
|
||||
|
||||
if (propertyNameContext == PropertyNameInClass && (tt == TokenKind::Semi || tt == TokenKind::Assign)) {
|
||||
if (isGenerator || isAsync) {
|
||||
error(JSMSG_BAD_PROP_ID);
|
||||
return null();
|
||||
}
|
||||
anyChars.ungetToken();
|
||||
*propType = PropertyType::Field;
|
||||
return propName;
|
||||
}
|
||||
|
||||
if (TokenKindIsPossibleIdentifierName(ltok) &&
|
||||
(tt == TokenKind::Comma || tt == TokenKind::RightCurly || tt == TokenKind::Assign))
|
||||
{
|
||||
@ -10567,7 +10612,7 @@ GeneralParser<ParseHandler, Unit>::objectLiteral(YieldHandling yieldHandling,
|
||||
TokenPos namePos = anyChars.nextToken().pos;
|
||||
|
||||
PropertyType propType;
|
||||
Node propName = propertyName(yieldHandling, declKind, literal, &propType, &propAtom);
|
||||
Node propName = propertyName(yieldHandling, PropertyNameInLiteral, declKind, literal, &propType, &propAtom);
|
||||
if (!propName) {
|
||||
return null();
|
||||
}
|
||||
|
@ -240,7 +240,8 @@ enum class PropertyType {
|
||||
AsyncMethod,
|
||||
AsyncGeneratorMethod,
|
||||
Constructor,
|
||||
DerivedConstructor
|
||||
DerivedConstructor,
|
||||
Field,
|
||||
};
|
||||
|
||||
enum AwaitHandling : uint8_t { AwaitIsName, AwaitIsKeyword, AwaitIsModuleKeyword };
|
||||
@ -1243,7 +1244,9 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_TYPE)
|
||||
bool checkLexicalDeclarationDirectlyWithinBlock(ParseContext::Statement& stmt,
|
||||
DeclarationKind kind, TokenPos pos);
|
||||
|
||||
enum PropertyNameContext { PropertyNameInLiteral, PropertyNameInPattern, PropertyNameInClass };
|
||||
Node propertyName(YieldHandling yieldHandling,
|
||||
PropertyNameContext propertyNameContext,
|
||||
const mozilla::Maybe<DeclarationKind>& maybeDecl,
|
||||
ListNodeType propList,
|
||||
PropertyType* propType, MutableHandleAtom propAtom);
|
||||
|
@ -279,7 +279,7 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
|
||||
BinaryNodeType newTaggedTemplate(Node tag, Node args) { return NodeGeneric; }
|
||||
|
||||
ListNodeType newObjectLiteral(uint32_t begin) { return NodeUnparenthesizedObject; }
|
||||
ListNodeType newClassMethodList(uint32_t begin) { return NodeGeneric; }
|
||||
ListNodeType newClassMemberList(uint32_t begin) { return NodeGeneric; }
|
||||
ClassNamesType newClassNames(Node outer, Node inner, const TokenPos& pos) {
|
||||
return NodeGeneric;
|
||||
}
|
||||
@ -305,11 +305,15 @@ FOR_EACH_PARSENODE_SUBCLASS(DECLARE_AS)
|
||||
CodeNodeType funNode, AccessorType atype) {
|
||||
return true;
|
||||
}
|
||||
MOZ_MUST_USE bool addClassMethodDefinition(ListNodeType methodList, Node key,
|
||||
MOZ_MUST_USE bool addClassMethodDefinition(ListNodeType memberList, Node key,
|
||||
CodeNodeType funNode, AccessorType atype,
|
||||
bool isStatic) {
|
||||
return true;
|
||||
}
|
||||
MOZ_MUST_USE bool addClassFieldDefinition(ListNodeType memberList,
|
||||
Node name, Node initializer) {
|
||||
return true;
|
||||
}
|
||||
UnaryNodeType newYieldExpression(uint32_t begin, Node value) { return NodeGeneric; }
|
||||
UnaryNodeType newYieldStarExpression(uint32_t begin, Node value) { return NodeGeneric; }
|
||||
UnaryNodeType newAwaitExpression(uint32_t begin, Node value) { return NodeGeneric; }
|
||||
|
@ -73,6 +73,7 @@
|
||||
macro(LeftParen, "'('") \
|
||||
macro(RightParen, "')'") \
|
||||
macro(Name, "identifier") \
|
||||
macro(PrivateName, "private identifier") \
|
||||
macro(Number, "numeric literal") \
|
||||
macro(String, "string literal") \
|
||||
\
|
||||
@ -322,6 +323,7 @@ inline MOZ_MUST_USE bool
|
||||
TokenKindIsPossibleIdentifier(TokenKind tt)
|
||||
{
|
||||
return tt == TokenKind::Name ||
|
||||
tt == TokenKind::PrivateName ||
|
||||
TokenKindIsContextualKeyword(tt) ||
|
||||
TokenKindIsStrictReservedWord(tt);
|
||||
}
|
||||
|
@ -119,36 +119,28 @@ FindReservedWord<Utf8Unit>(const Utf8Unit* units, size_t length)
|
||||
}
|
||||
|
||||
static const ReservedWordInfo*
|
||||
FindReservedWord(JSLinearString* str)
|
||||
FindReservedWord(JSLinearString* str, js::frontend::NameVisibility* visibility)
|
||||
{
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
return str->hasLatin1Chars()
|
||||
? FindReservedWord(str->latin1Chars(nogc), str->length())
|
||||
: FindReservedWord(str->twoByteChars(nogc), str->length());
|
||||
}
|
||||
|
||||
template <typename CharT>
|
||||
static bool
|
||||
IsIdentifierImpl(const CharT* chars, size_t length)
|
||||
{
|
||||
using namespace js;
|
||||
|
||||
if (length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!unicode::IsIdentifierStart(char16_t(*chars))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const CharT* end = chars + length;
|
||||
while (++chars != end) {
|
||||
if (!unicode::IsIdentifierPart(char16_t(*chars))) {
|
||||
return false;
|
||||
if (str->hasLatin1Chars()) {
|
||||
const JS::Latin1Char* chars = str->latin1Chars(nogc);
|
||||
size_t length = str->length();
|
||||
if (length > 0 && chars[0] == '#') {
|
||||
*visibility = js::frontend::NameVisibility::Private;
|
||||
return nullptr;
|
||||
}
|
||||
*visibility = js::frontend::NameVisibility::Public;
|
||||
return FindReservedWord(chars, length);
|
||||
}
|
||||
|
||||
return true;
|
||||
const char16_t* chars = str->twoByteChars(nogc);
|
||||
size_t length = str->length();
|
||||
if (length > 0 && chars[0] == '#') {
|
||||
*visibility = js::frontend::NameVisibility::Private;
|
||||
return nullptr;
|
||||
}
|
||||
*visibility = js::frontend::NameVisibility::Public;
|
||||
return FindReservedWord(chars, length);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
@ -171,15 +163,71 @@ GetSingleCodePoint(const char16_t** p, const char16_t* end)
|
||||
return codePoint;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsIdentifierMaybeNonBMP(const char16_t* chars, size_t length)
|
||||
{
|
||||
using namespace js;
|
||||
namespace js {
|
||||
|
||||
if (IsIdentifierImpl(chars, length)) {
|
||||
return true;
|
||||
namespace frontend {
|
||||
|
||||
bool
|
||||
IsIdentifier(JSLinearString* str)
|
||||
{
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
MOZ_ASSERT(str);
|
||||
if (str->hasLatin1Chars()) {
|
||||
return IsIdentifier(str->latin1Chars(nogc), str->length());
|
||||
}
|
||||
return IsIdentifier(str->twoByteChars(nogc), str->length());
|
||||
}
|
||||
|
||||
bool
|
||||
IsIdentifierNameOrPrivateName(JSLinearString* str)
|
||||
{
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
MOZ_ASSERT(str);
|
||||
if (str->hasLatin1Chars()) {
|
||||
return IsIdentifierNameOrPrivateName(str->latin1Chars(nogc), str->length());
|
||||
}
|
||||
return IsIdentifierNameOrPrivateName(str->twoByteChars(nogc), str->length());
|
||||
}
|
||||
|
||||
bool
|
||||
IsIdentifier(const Latin1Char* chars, size_t length)
|
||||
{
|
||||
if (length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!unicode::IsIdentifierStart(char16_t(*chars))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const Latin1Char* end = chars + length;
|
||||
while (++chars != end) {
|
||||
if (!unicode::IsIdentifierPart(char16_t(*chars))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IsIdentifierNameOrPrivateName(const Latin1Char* chars, size_t length)
|
||||
{
|
||||
if (length == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (char16_t(*chars) == '#') {
|
||||
++chars;
|
||||
--length;
|
||||
}
|
||||
|
||||
return IsIdentifier(chars, length);
|
||||
}
|
||||
|
||||
bool
|
||||
IsIdentifier(const char16_t* chars, size_t length)
|
||||
{
|
||||
if (length == 0) {
|
||||
return false;
|
||||
}
|
||||
@ -203,37 +251,45 @@ IsIdentifierMaybeNonBMP(const char16_t* chars, size_t length)
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
namespace frontend {
|
||||
|
||||
bool
|
||||
IsIdentifier(JSLinearString* str)
|
||||
IsIdentifierNameOrPrivateName(const char16_t* chars, size_t length)
|
||||
{
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
MOZ_ASSERT(str);
|
||||
if (str->hasLatin1Chars()) {
|
||||
return ::IsIdentifierImpl(str->latin1Chars(nogc), str->length());
|
||||
if (length == 0) {
|
||||
return false;
|
||||
}
|
||||
return ::IsIdentifierMaybeNonBMP(str->twoByteChars(nogc), str->length());
|
||||
}
|
||||
|
||||
bool
|
||||
IsIdentifier(const char* chars, size_t length)
|
||||
{
|
||||
return ::IsIdentifierImpl(chars, length);
|
||||
}
|
||||
const char16_t* p = chars;
|
||||
const char16_t* end = chars + length;
|
||||
uint32_t codePoint;
|
||||
|
||||
bool
|
||||
IsIdentifier(const char16_t* chars, size_t length)
|
||||
{
|
||||
return ::IsIdentifierImpl(chars, length);
|
||||
codePoint = GetSingleCodePoint(&p, end);
|
||||
if (codePoint == '#') {
|
||||
if (length == 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
codePoint = GetSingleCodePoint(&p, end);
|
||||
}
|
||||
|
||||
if (!unicode::IsIdentifierStart(codePoint)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (p < end) {
|
||||
codePoint = GetSingleCodePoint(&p, end);
|
||||
if (!unicode::IsIdentifierPart(codePoint)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
IsKeyword(JSLinearString* str)
|
||||
{
|
||||
if (const ReservedWordInfo* rw = FindReservedWord(str)) {
|
||||
NameVisibility visibility;
|
||||
if (const ReservedWordInfo* rw = FindReservedWord(str, &visibility)) {
|
||||
return TokenKindIsKeyword(rw->tokentype);
|
||||
}
|
||||
|
||||
@ -243,17 +299,19 @@ IsKeyword(JSLinearString* str)
|
||||
TokenKind
|
||||
ReservedWordTokenKind(PropertyName* str)
|
||||
{
|
||||
if (const ReservedWordInfo* rw = FindReservedWord(str)) {
|
||||
NameVisibility visibility;
|
||||
if (const ReservedWordInfo* rw = FindReservedWord(str, &visibility)) {
|
||||
return rw->tokentype;
|
||||
}
|
||||
|
||||
return TokenKind::Name;
|
||||
return visibility == NameVisibility::Private ? TokenKind::PrivateName : TokenKind::Name;
|
||||
}
|
||||
|
||||
const char*
|
||||
ReservedWordToCharZ(PropertyName* str)
|
||||
{
|
||||
if (const ReservedWordInfo* rw = FindReservedWord(str)) {
|
||||
NameVisibility visibility;
|
||||
if (const ReservedWordInfo* rw = FindReservedWord(str, &visibility)) {
|
||||
return ReservedWordToCharZ(rw->tokentype);
|
||||
}
|
||||
|
||||
@ -1660,6 +1718,42 @@ GeneralTokenStreamChars<Unit, AnyCharsAccess>::matchUnicodeEscapeIdent(uint32_t*
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename Unit, class AnyCharsAccess>
|
||||
MOZ_MUST_USE bool
|
||||
TokenStreamSpecific<Unit, AnyCharsAccess>::matchIdentifierStart(IdentifierEscapes* sawEscape)
|
||||
{
|
||||
int32_t unit = getCodeUnit();
|
||||
if (unicode::IsIdentifierStart(char16_t(unit))) {
|
||||
*sawEscape = IdentifierEscapes::None;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (unit == '\\') {
|
||||
*sawEscape = IdentifierEscapes::SawUnicodeEscape;
|
||||
|
||||
uint32_t codePoint;
|
||||
uint32_t escapeLength = matchUnicodeEscapeIdStart(&codePoint);
|
||||
if (escapeLength != 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// We could point "into" a mistyped escape, e.g. for "\u{41H}" we
|
||||
// could point at the 'H'. But we don't do that now, so the code
|
||||
// unit after the '\' isn't necessarily bad, so just point at the
|
||||
// start of the actually-invalid escape.
|
||||
ungetCodeUnit('\\');
|
||||
error(JSMSG_BAD_ESCAPE);
|
||||
return false;
|
||||
}
|
||||
|
||||
*sawEscape = IdentifierEscapes::None;
|
||||
|
||||
// NOTE: |unit| may be EOF here.
|
||||
ungetCodeUnit(unit);
|
||||
error(JSMSG_MISSING_PRIVATE_NAME);
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename Unit, class AnyCharsAccess>
|
||||
bool
|
||||
TokenStreamSpecific<Unit, AnyCharsAccess>::getDirectives(bool isMultiline,
|
||||
@ -1931,9 +2025,11 @@ TokenStreamSpecific<Unit, AnyCharsAccess>::putIdentInCharBuffer(const Unit* iden
|
||||
template<typename Unit, class AnyCharsAccess>
|
||||
MOZ_MUST_USE bool
|
||||
TokenStreamSpecific<Unit, AnyCharsAccess>::identifierName(TokenStart start,
|
||||
const Unit* identStart,
|
||||
IdentifierEscapes escaping,
|
||||
Modifier modifier, TokenKind* out)
|
||||
const Unit* identStart,
|
||||
IdentifierEscapes escaping,
|
||||
Modifier modifier,
|
||||
NameVisibility visibility,
|
||||
TokenKind* out)
|
||||
{
|
||||
// Run the bad-token code for every path out of this function except the
|
||||
// two success-cases.
|
||||
@ -1995,11 +2091,14 @@ TokenStreamSpecific<Unit, AnyCharsAccess>::identifierName(TokenStart start,
|
||||
const Unit* chars = identStart;
|
||||
size_t length = this->sourceUnits.addressOfNextCodeUnit() - identStart;
|
||||
|
||||
// Represent reserved words lacking escapes as reserved word tokens.
|
||||
if (const ReservedWordInfo* rw = FindReservedWord(chars, length)) {
|
||||
noteBadToken.release();
|
||||
newSimpleToken(rw->tokentype, start, modifier, out);
|
||||
return true;
|
||||
// Private identifiers start with a '#', and so cannot be reserved words.
|
||||
if (visibility == NameVisibility::Public) {
|
||||
// Represent reserved words lacking escapes as reserved word tokens.
|
||||
if (const ReservedWordInfo* rw = FindReservedWord(chars, length)) {
|
||||
noteBadToken.release();
|
||||
newSimpleToken(rw->tokentype, start, modifier, out);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
atom = atomizeSourceChars(anyCharsAccess().cx, MakeSpan(chars, length));
|
||||
@ -2009,7 +2108,16 @@ TokenStreamSpecific<Unit, AnyCharsAccess>::identifierName(TokenStart start,
|
||||
}
|
||||
|
||||
noteBadToken.release();
|
||||
newNameToken(atom->asPropertyName(), start, modifier, out);
|
||||
if (visibility == NameVisibility::Private) {
|
||||
MOZ_ASSERT(identStart[0] == static_cast<Unit>('#'), "Private identifier starts with #");
|
||||
newPrivateNameToken(atom->asPropertyName(), start, modifier, out);
|
||||
|
||||
// TODO(khypera): Delete the below once private names are supported.
|
||||
errorAt(start.offset(), JSMSG_FIELDS_NOT_SUPPORTED);
|
||||
return false;
|
||||
} else {
|
||||
newNameToken(atom->asPropertyName(), start, modifier, out);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2440,7 +2548,7 @@ TokenStreamSpecific<Unit, AnyCharsAccess>::getTokenInternal(TokenKind* const ttp
|
||||
"or else we'll fail to maintain line-info/flags "
|
||||
"for EOL here");
|
||||
|
||||
return identifierName(start, identStart, IdentifierEscapes::None, modifier, ttp);
|
||||
return identifierName(start, identStart, IdentifierEscapes::None, modifier, NameVisibility::Public, ttp);
|
||||
}
|
||||
|
||||
error(JSMSG_ILLEGAL_CHARACTER);
|
||||
@ -2489,7 +2597,8 @@ TokenStreamSpecific<Unit, AnyCharsAccess>::getTokenInternal(TokenKind* const ttp
|
||||
if (c1kind == Ident) {
|
||||
TokenStart start(this->sourceUnits, -1);
|
||||
return identifierName(start, this->sourceUnits.addressOfNextCodeUnit() - 1,
|
||||
IdentifierEscapes::None, modifier, ttp);
|
||||
IdentifierEscapes::None, modifier,
|
||||
NameVisibility::Public, ttp);
|
||||
}
|
||||
|
||||
// Look for a decimal number.
|
||||
@ -2682,6 +2791,16 @@ TokenStreamSpecific<Unit, AnyCharsAccess>::getTokenInternal(TokenKind* const ttp
|
||||
simpleKind = TokenKind::Dot;
|
||||
break;
|
||||
|
||||
case '#': {
|
||||
TokenStart start(this->sourceUnits, -1);
|
||||
const Unit* identStart = this->sourceUnits.addressOfNextCodeUnit() - 1;
|
||||
IdentifierEscapes sawEscape;
|
||||
if (!matchIdentifierStart(&sawEscape)) {
|
||||
return badToken();
|
||||
}
|
||||
return identifierName(start, identStart, sawEscape, modifier, NameVisibility::Private, ttp);
|
||||
}
|
||||
|
||||
case '=':
|
||||
if (matchCodeUnit('=')) {
|
||||
simpleKind = matchCodeUnit('=') ? TokenKind::StrictEq : TokenKind::Eq;
|
||||
@ -2705,7 +2824,7 @@ TokenStreamSpecific<Unit, AnyCharsAccess>::getTokenInternal(TokenKind* const ttp
|
||||
if (uint32_t escapeLength = matchUnicodeEscapeIdStart(&codePoint)) {
|
||||
return identifierName(start,
|
||||
this->sourceUnits.addressOfNextCodeUnit() - escapeLength - 1,
|
||||
IdentifierEscapes::SawUnicodeEscape, modifier, ttp);
|
||||
IdentifierEscapes::SawUnicodeEscape, modifier, NameVisibility::Public, ttp);
|
||||
}
|
||||
|
||||
// We could point "into" a mistyped escape, e.g. for "\u{41H}" we
|
||||
|
@ -289,6 +289,8 @@ enum class InvalidEscapeType {
|
||||
// The only escapes found in IdentifierName are of the Unicode flavor.
|
||||
enum class IdentifierEscapes { None, SawUnicodeEscape };
|
||||
|
||||
enum class NameVisibility { Public, Private };
|
||||
|
||||
class TokenStreamShared;
|
||||
|
||||
struct Token
|
||||
@ -406,7 +408,7 @@ struct Token
|
||||
// Mutators
|
||||
|
||||
void setName(PropertyName* name) {
|
||||
MOZ_ASSERT(type == TokenKind::Name);
|
||||
MOZ_ASSERT(type == TokenKind::Name || type == TokenKind::PrivateName);
|
||||
u.name = name;
|
||||
}
|
||||
|
||||
@ -432,7 +434,7 @@ struct Token
|
||||
// Type-safe accessors
|
||||
|
||||
PropertyName* name() const {
|
||||
MOZ_ASSERT(type == TokenKind::Name);
|
||||
MOZ_ASSERT(type == TokenKind::Name || type == TokenKind::PrivateName);
|
||||
return u.name->JSAtom::asPropertyName(); // poor-man's type verification
|
||||
}
|
||||
|
||||
@ -627,7 +629,7 @@ class TokenStreamAnyChars
|
||||
|
||||
public:
|
||||
PropertyName* currentName() const {
|
||||
if (isCurrentTokenType(TokenKind::Name)) {
|
||||
if (isCurrentTokenType(TokenKind::Name) || isCurrentTokenType(TokenKind::PrivateName)) {
|
||||
return currentToken().name();
|
||||
}
|
||||
|
||||
@ -636,7 +638,7 @@ class TokenStreamAnyChars
|
||||
}
|
||||
|
||||
bool currentNameHasEscapes() const {
|
||||
if (isCurrentTokenType(TokenKind::Name)) {
|
||||
if (isCurrentTokenType(TokenKind::Name) || isCurrentTokenType(TokenKind::PrivateName)) {
|
||||
TokenPos pos = currentToken().pos;
|
||||
return (pos.end - pos.begin) != currentToken().name()->length();
|
||||
}
|
||||
@ -1927,6 +1929,15 @@ class GeneralTokenStreamChars
|
||||
token->setName(name);
|
||||
}
|
||||
|
||||
void newPrivateNameToken(PropertyName* name,
|
||||
TokenStart start,
|
||||
TokenStreamShared::Modifier modifier,
|
||||
TokenKind* out)
|
||||
{
|
||||
Token* token = newToken(TokenKind::PrivateName, start, modifier, out);
|
||||
token->setName(name);
|
||||
}
|
||||
|
||||
void newRegExpToken(RegExpFlag reflags, TokenStart start, TokenKind* out)
|
||||
{
|
||||
Token* token = newToken(TokenKind::RegExp, start, TokenStreamShared::Operand, out);
|
||||
@ -2000,6 +2011,7 @@ class GeneralTokenStreamChars
|
||||
|
||||
uint32_t matchUnicodeEscapeIdStart(uint32_t* codePoint);
|
||||
bool matchUnicodeEscapeIdent(uint32_t* codePoint);
|
||||
bool matchIdentifierStart();
|
||||
|
||||
/**
|
||||
* If possible, compute a line of context for an otherwise-filled-in |err|
|
||||
@ -2335,6 +2347,7 @@ class MOZ_STACK_CLASS TokenStreamSpecific
|
||||
using GeneralCharsBase::matchUnicodeEscapeIdStart;
|
||||
using GeneralCharsBase::newAtomToken;
|
||||
using GeneralCharsBase::newNameToken;
|
||||
using GeneralCharsBase::newPrivateNameToken;
|
||||
using GeneralCharsBase::newNumberToken;
|
||||
using GeneralCharsBase::newRegExpToken;
|
||||
using GeneralCharsBase::newSimpleToken;
|
||||
@ -2670,7 +2683,9 @@ class MOZ_STACK_CLASS TokenStreamSpecific
|
||||
|
||||
MOZ_MUST_USE bool identifierName(TokenStart start, const Unit* identStart,
|
||||
IdentifierEscapes escaping, Modifier modifier,
|
||||
TokenKind* out);
|
||||
NameVisibility visibility, TokenKind* out);
|
||||
|
||||
MOZ_MUST_USE bool matchIdentifierStart(IdentifierEscapes* sawEscape);
|
||||
|
||||
MOZ_MUST_USE bool getTokenInternal(TokenKind* const ttp, const Modifier modifier);
|
||||
|
||||
|
@ -265,6 +265,7 @@ MSG_DEF(JSMSG_FROM_AFTER_EXPORT_STAR, 0, JSEXN_SYNTAXERR, "missing keyword 'fro
|
||||
MSG_DEF(JSMSG_GARBAGE_AFTER_INPUT, 2, JSEXN_SYNTAXERR, "unexpected garbage after {0}, starting with {1}")
|
||||
MSG_DEF(JSMSG_IDSTART_AFTER_NUMBER, 0, JSEXN_SYNTAXERR, "identifier starts immediately after numeric literal")
|
||||
MSG_DEF(JSMSG_BAD_ESCAPE, 0, JSEXN_SYNTAXERR, "invalid escape sequence")
|
||||
MSG_DEF(JSMSG_MISSING_PRIVATE_NAME, 0, JSEXN_SYNTAXERR, "'#' not followed by identifier")
|
||||
MSG_DEF(JSMSG_ILLEGAL_CHARACTER, 0, JSEXN_SYNTAXERR, "illegal character")
|
||||
MSG_DEF(JSMSG_IMPORT_META_OUTSIDE_MODULE, 0, JSEXN_SYNTAXERR, "import.meta may only appear in a module")
|
||||
MSG_DEF(JSMSG_IMPORT_DECL_AT_TOP_LEVEL, 0, JSEXN_SYNTAXERR, "import declarations may only appear at top level of a module")
|
||||
@ -355,6 +356,8 @@ MSG_DEF(JSMSG_COMPUTED_NAME_IN_PATTERN,0, JSEXN_SYNTAXERR, "computed property na
|
||||
MSG_DEF(JSMSG_DEFAULT_IN_PATTERN, 0, JSEXN_SYNTAXERR, "destructuring defaults aren't supported in this destructuring declaration")
|
||||
MSG_DEF(JSMSG_BAD_NEWTARGET, 0, JSEXN_SYNTAXERR, "new.target only allowed within functions")
|
||||
MSG_DEF(JSMSG_ESCAPED_KEYWORD, 0, JSEXN_SYNTAXERR, "keywords must be written literally, without embedded escapes")
|
||||
MSG_DEF(JSMSG_MISSING_SEMI_FIELD, 0, JSEXN_SYNTAXERR, "missing ; after field definition")
|
||||
MSG_DEF(JSMSG_FIELDS_NOT_SUPPORTED, 0, JSEXN_SYNTAXERR, "fields are not currently supported")
|
||||
|
||||
// UTF-8 source text encoding errors
|
||||
MSG_DEF(JSMSG_BAD_LEADING_UTF8_UNIT, 1, JSEXN_SYNTAXERR, "{0} byte doesn't begin a valid UTF-8 code point")
|
||||
|
@ -78,4 +78,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")
|
||||
/* AST_LIMIT = last + 1 */
|
||||
|
@ -461,6 +461,14 @@ skip script test262/intl402/DateTimeFormat/prototype/resolvedOptions/order.js
|
||||
skip script test262/intl402/PluralRules/prototype/resolvedOptions/order.js
|
||||
skip script test262/intl402/NumberFormat/prototype/resolvedOptions/order.js
|
||||
|
||||
# Fields are not fully implemented yet
|
||||
skip script non262/fields/access.js
|
||||
skip script non262/fields/basic.js
|
||||
skip script non262/fields/error.js
|
||||
skip script non262/fields/field_types.js
|
||||
skip script non262/fields/literal.js
|
||||
skip script non262/fields/mixed_methods.js
|
||||
skip script non262/fields/quirks.js
|
||||
|
||||
###########################################################
|
||||
# Tests disabled due to issues in test262 importer script #
|
||||
|
19
js/src/tests/non262/fields/access.js
Normal file
19
js/src/tests/non262/fields/access.js
Normal file
@ -0,0 +1,19 @@
|
||||
// * * * THIS TEST IS DISABLED - Fields are not fully implemented yet
|
||||
|
||||
class C {
|
||||
x = 5;
|
||||
}
|
||||
|
||||
c = new C();
|
||||
|
||||
reportCompare(c.x, undefined); // TODO
|
||||
//reportCompare(c.x, 5);
|
||||
|
||||
class D {
|
||||
#y = 5;
|
||||
}
|
||||
|
||||
d = new D();
|
||||
|
||||
reportCompare(d.#y, undefined); // TODO
|
||||
//reportCompare(d.#y, 5);
|
14
js/src/tests/non262/fields/basic.js
Normal file
14
js/src/tests/non262/fields/basic.js
Normal file
@ -0,0 +1,14 @@
|
||||
// * * * THIS TEST IS DISABLED - Fields are not fully implemented yet
|
||||
|
||||
class C {
|
||||
x;
|
||||
y = 2;
|
||||
}
|
||||
|
||||
class D {
|
||||
#x;
|
||||
#y = 2;
|
||||
}
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
45
js/src/tests/non262/fields/error.js
Normal file
45
js/src/tests/non262/fields/error.js
Normal file
@ -0,0 +1,45 @@
|
||||
// * * * THIS TEST IS DISABLED - Fields are not fully implemented yet
|
||||
|
||||
let source = `class C {
|
||||
x
|
||||
}`;
|
||||
assertThrowsInstanceOf(() => Function(source), SyntaxError);
|
||||
|
||||
source = `class C {
|
||||
-2;
|
||||
-2 = 2;
|
||||
}`;
|
||||
assertThrowsInstanceOf(() => Function(source), SyntaxError);
|
||||
|
||||
source = `class C {
|
||||
x += 2;
|
||||
}`;
|
||||
assertThrowsInstanceOf(() => Function(source), SyntaxError);
|
||||
|
||||
source = `class C {
|
||||
#2;
|
||||
}`;
|
||||
assertThrowsInstanceOf(() => Function(source), SyntaxError);
|
||||
|
||||
source = `class C {
|
||||
#["h" + "i"];
|
||||
}`;
|
||||
assertThrowsInstanceOf(() => Function(source), SyntaxError);
|
||||
|
||||
source = `class C {
|
||||
#"hi";
|
||||
}`;
|
||||
assertThrowsInstanceOf(() => Function(source), SyntaxError);
|
||||
|
||||
source = `function f() {
|
||||
class C {
|
||||
#"should still throw error during lazy parse";
|
||||
}
|
||||
}`;
|
||||
assertThrowsInstanceOf(() => Function(source), SyntaxError);
|
||||
|
||||
source = `#outside;`;
|
||||
assertThrowsInstanceOf(() => eval(source), SyntaxError);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
25
js/src/tests/non262/fields/field_types.js
Normal file
25
js/src/tests/non262/fields/field_types.js
Normal file
@ -0,0 +1,25 @@
|
||||
// * * * THIS TEST IS DISABLED - Fields are not fully implemented yet
|
||||
|
||||
class C {
|
||||
[Math.sqrt(4)];
|
||||
[Math.sqrt(8)] = 5 + 2;
|
||||
"hi";
|
||||
"bye" = {};
|
||||
2 = 2;
|
||||
0x101 = 2;
|
||||
0o101 = 2;
|
||||
0b101 = 2;
|
||||
NaN = 0; // actually the field called "NaN", not the number
|
||||
Infinity = 50; // actually the field called "Infinity", not the number
|
||||
// all the keywords below are proper fields (?!?)
|
||||
with = 0;
|
||||
//static = 0; // doesn't work yet
|
||||
async = 0;
|
||||
get = 0;
|
||||
set = 0;
|
||||
export = 0;
|
||||
function = 0;
|
||||
}
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
46
js/src/tests/non262/fields/literal.js
Normal file
46
js/src/tests/non262/fields/literal.js
Normal file
@ -0,0 +1,46 @@
|
||||
// * * * THIS TEST IS DISABLED - Fields are not fully implemented yet
|
||||
|
||||
source = `var y = {
|
||||
x;
|
||||
}`;
|
||||
assertThrowsInstanceOf(() => eval(source), SyntaxError);
|
||||
|
||||
// This is legal, and is equivalent to `var y = { x: x };`
|
||||
// source = `var y = {
|
||||
// x
|
||||
// }`;
|
||||
// assertThrowsInstanceOf(() => eval(source), SyntaxError);
|
||||
|
||||
source = `var y = {
|
||||
#x;
|
||||
}`;
|
||||
assertThrowsInstanceOf(() => eval(source), SyntaxError);
|
||||
|
||||
// Temporarily disabled due to the same reason above.
|
||||
// source = `var y = {
|
||||
// #x
|
||||
// }`;
|
||||
// assertThrowsInstanceOf(() => eval(source), SyntaxError);
|
||||
|
||||
source = `var y = {
|
||||
x = 2;
|
||||
}`;
|
||||
assertThrowsInstanceOf(() => eval(source), SyntaxError);
|
||||
|
||||
source = `var y = {
|
||||
x = 2
|
||||
}`;
|
||||
assertThrowsInstanceOf(() => eval(source), SyntaxError);
|
||||
|
||||
source = `var y = {
|
||||
#x = 2;
|
||||
}`;
|
||||
assertThrowsInstanceOf(() => eval(source), SyntaxError);
|
||||
|
||||
source = `var y = {
|
||||
#x = 2
|
||||
}`;
|
||||
assertThrowsInstanceOf(() => eval(source), SyntaxError);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
11
js/src/tests/non262/fields/mixed_methods.js
Normal file
11
js/src/tests/non262/fields/mixed_methods.js
Normal file
@ -0,0 +1,11 @@
|
||||
// * * * THIS TEST IS DISABLED - Fields are not fully implemented yet
|
||||
|
||||
class C {
|
||||
x;
|
||||
y(){}
|
||||
z = 2;
|
||||
w(){};
|
||||
}
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
16
js/src/tests/non262/fields/quirks.js
Normal file
16
js/src/tests/non262/fields/quirks.js
Normal file
@ -0,0 +1,16 @@
|
||||
// * * * THIS TEST IS DISABLED - Fields are not fully implemented yet
|
||||
|
||||
class C {
|
||||
x;;;;
|
||||
y
|
||||
;
|
||||
}
|
||||
|
||||
class D {
|
||||
x = 5;
|
||||
y = (x += 1);
|
||||
// TODO: Assert values of x and y
|
||||
}
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(true, true);
|
@ -325,7 +325,7 @@ JS::CompileFunction(JSContext* cx, AutoObjectVector& envChain,
|
||||
}
|
||||
|
||||
// If name is not valid identifier
|
||||
if (!js::frontend::IsIdentifier(name, nameLen)) {
|
||||
if (!js::frontend::IsIdentifier(reinterpret_cast<const Latin1Char*>(name), nameLen)) {
|
||||
isInvalidName = true;
|
||||
}
|
||||
}
|
||||
|
@ -2210,7 +2210,7 @@ js::IdToPrintableUTF8(JSContext* cx, HandleId id, IdToPrintableBehavior behavior
|
||||
// ToString(<symbol>) throws a TypeError, therefore require that callers
|
||||
// request source representation when |id| is a property key.
|
||||
MOZ_ASSERT_IF(behavior == IdToPrintableBehavior::IdIsIdentifier,
|
||||
JSID_IS_ATOM(id) && frontend::IsIdentifier(JSID_TO_ATOM(id)));
|
||||
JSID_IS_ATOM(id) && frontend::IsIdentifierNameOrPrivateName(JSID_TO_ATOM(id)));
|
||||
|
||||
RootedValue v(cx, IdToValue(id));
|
||||
JSString* str;
|
||||
|
Loading…
Reference in New Issue
Block a user