Issue #2173 - Add a new PNK_PROPERTYNAME to hold location information about property access name

Based-on: m-c 1378808/2
This commit is contained in:
Martok 2023-03-23 18:53:27 +01:00 • committed by roytam1
commit fa1193b8c9
10 changed files with 104 additions and 76 deletions

View file

@ -3066,20 +3066,20 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
case PNK_OPTDOT: case PNK_OPTDOT:
case PNK_DOT: case PNK_DOT:
{ {
MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_expr->pn_pos)); MOZ_ASSERT(pn->pn_pos.encloses(pn->pn_left->pn_pos));
RootedValue expr(cx); RootedValue expr(cx);
RootedValue propname(cx); RootedValue propname(cx);
RootedAtom pnAtom(cx, pn->pn_atom); RootedAtom pnAtom(cx, pn->pn_right->pn_atom);
bool isSuper = pn->is<PropertyAccess>() && bool isSuper = pn->is<PropertyAccess>() &&
pn->as<PropertyAccess>().isSuper(); pn->as<PropertyAccess>().isSuper();
if (isSuper) { if (isSuper) {
if (!builder.super(&pn->pn_expr->pn_pos, &expr)) if (!builder.super(&pn->pn_left->pn_pos, &expr))
return false; return false;
} else { } else {
if (!expression(pn->pn_expr, &expr)) if (!expression(pn->pn_left, &expr))
return false; return false;
} }

View file

@ -1090,7 +1090,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
// Watch out for getters! // Watch out for getters!
case PNK_DOT: case PNK_DOT:
case PNK_OPTDOT: case PNK_OPTDOT:
MOZ_ASSERT(pn->isArity(PN_NAME)); MOZ_ASSERT(pn->isArity(PN_BINARY));
*answer = true; *answer = true;
return true; return true;
@ -1497,6 +1497,7 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
case PNK_CALLSITEOBJ: // by PNK_TAGGED_TEMPLATE case PNK_CALLSITEOBJ: // by PNK_TAGGED_TEMPLATE
case PNK_POSHOLDER: // by PNK_NEWTARGET case PNK_POSHOLDER: // by PNK_NEWTARGET
case PNK_SUPERBASE: // by PNK_ELEM and others case PNK_SUPERBASE: // by PNK_ELEM and others
case PNK_PROPERTYNAME: // by PNK_DOT
MOZ_CRASH("handled by parent nodes"); MOZ_CRASH("handled by parent nodes");
case PNK_LIMIT: // invalid sentinel value case PNK_LIMIT: // invalid sentinel value
@ -1813,11 +1814,11 @@ BytecodeEmitter::emitPropLHS(ParseNode* pn)
MOZ_ASSERT(pn->isKind(PNK_DOT)); MOZ_ASSERT(pn->isKind(PNK_DOT));
MOZ_ASSERT(!pn->as<PropertyAccess>().isSuper()); MOZ_ASSERT(!pn->as<PropertyAccess>().isSuper());
ParseNode* pn2 = pn->pn_expr; ParseNode* pn2 = pn->pn_left;
/* /*
* If the object operand is also a dotted property reference, reverse the * If the object operand is also a dotted property reference, reverse the
* list linked via pn_expr temporarily so we can iterate over it from the * list linked via pn_left temporarily so we can iterate over it from the
* bottom up (reversing again as we go), to avoid excessive recursion. * bottom up (reversing again as we go), to avoid excessive recursion.
*/ */
if (pn2->isKind(PNK_DOT) && !pn2->as<PropertyAccess>().isSuper()) { if (pn2->isKind(PNK_DOT) && !pn2->as<PropertyAccess>().isSuper()) {
@ -1825,9 +1826,9 @@ BytecodeEmitter::emitPropLHS(ParseNode* pn)
ParseNode* pnup = nullptr; ParseNode* pnup = nullptr;
ParseNode* pndown; ParseNode* pndown;
for (;;) { for (;;) {
/* Reverse pndot->pn_expr to point up, not down. */ /* Reverse pndot->pn_left to point up, not down. */
pndown = pndot->pn_expr; pndown = pndot->pn_left;
pndot->pn_expr = pnup; pndot->pn_left = pnup;
if (!pndown->isKind(PNK_DOT) || pndown->as<PropertyAccess>().isSuper()) if (!pndown->isKind(PNK_DOT) || pndown->as<PropertyAccess>().isSuper())
break; break;
pnup = pndot; pnup = pndot;
@ -1840,12 +1841,12 @@ BytecodeEmitter::emitPropLHS(ParseNode* pn)
do { do {
/* Walk back up the list, emitting annotated name ops. */ /* Walk back up the list, emitting annotated name ops. */
if (!emitAtomOp(pndot->pn_atom, JSOP_GETPROP)) if (!emitAtomOp(pndot->pn_right->pn_atom, JSOP_GETPROP))
return false; return false;
/* Reverse the pn_expr link again. */ /* Reverse the pn_left link again. */
pnup = pndot->pn_expr; pnup = pndot->pn_left;
pndot->pn_expr = pndown; pndot->pn_left = pndown;
pndown = pndot; pndown = pndot;
} while ((pndot = pnup) != nullptr); } while ((pndot = pnup) != nullptr);
return true; return true;
@ -2505,7 +2506,7 @@ BytecodeEmitter::emitDestructuringLHSRef(ParseNode* target, size_t* emitted)
// SUPERBASE is pushed onto THIS in poe.prepareForRhs below. // SUPERBASE is pushed onto THIS in poe.prepareForRhs below.
*emitted = 2; *emitted = 2;
} else { } else {
if (!emitTree(target->pn_expr)) // OBJ if (!emitTree(target->pn_left)) // OBJ
return false; return false;
*emitted = 1; *emitted = 1;
} }
@ -9080,8 +9081,9 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
return false; return false;
break; break;
case PNK_PROPERTYNAME:
case PNK_POSHOLDER: case PNK_POSHOLDER:
MOZ_FALLTHROUGH_ASSERT("Should never try to emit PNK_POSHOLDER"); MOZ_FALLTHROUGH_ASSERT("Should never try to emit PNK_POSHOLDER or PNK_PROPERTYNAME");
default: default:
MOZ_ASSERT(0); MOZ_ASSERT(0);

View file

@ -367,6 +367,7 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
case PNK_COMMA: case PNK_COMMA:
case PNK_ARRAY: case PNK_ARRAY:
case PNK_OBJECT: case PNK_OBJECT:
case PNK_PROPERTYNAME:
case PNK_DOT: case PNK_DOT:
case PNK_ELEM: case PNK_ELEM:
case PNK_ARGUMENTS: case PNK_ARGUMENTS:
@ -1367,11 +1368,14 @@ FoldElement(ExclusiveContext* cx, ParseNode** nodePtr, Parser<FullParseHandler>&
// Optimization 3: We have expr["foo"] where foo is not an index. Convert // Optimization 3: We have expr["foo"] where foo is not an index. Convert
// to a property access (like expr.foo) that optimizes better downstream. // to a property access (like expr.foo) that optimizes better downstream.
ParseNode* nameNode = parser.handler.newPropertyName(name, key->pn_pos);
if (!nameNode)
return false;
ParseNode* dottedAccess; ParseNode* dottedAccess;
if (node->isKind(PNK_OPTELEM)) { if (node->isKind(PNK_OPTELEM)) {
dottedAccess = parser.handler.newOptionalPropertyAccess(expr, name, node->pn_pos.end); dottedAccess = parser.handler.newOptionalPropertyAccess(expr, nameNode);
} else { } else {
dottedAccess = parser.handler.newPropertyAccess(expr, name, node->pn_pos.end); dottedAccess = parser.handler.newPropertyAccess(expr, nameNode);
} }
if (!dottedAccess) { if (!dottedAccess) {
return false; return false;
@ -1646,14 +1650,14 @@ FoldDottedProperty(ExclusiveContext* cx, ParseNode* node, Parser<FullParseHandle
bool inGenexpLambda) bool inGenexpLambda)
{ {
MOZ_ASSERT(node->isKind(PNK_DOT) || node->isKind(PNK_OPTDOT)); MOZ_ASSERT(node->isKind(PNK_DOT) || node->isKind(PNK_OPTDOT));
MOZ_ASSERT(node->isArity(PN_NAME)); MOZ_ASSERT(node->isArity(PN_BINARY));
// Iterate through a long chain of dotted property accesses to find the // Iterate through a long chain of dotted property accesses to find the
// most-nested non-dotted property node, then fold that. // most-nested non-dotted property node, then fold that.
ParseNode** nested = &node->pn_expr; ParseNode** nested = &node->pn_left;
while ((*nested)->isKind(PNK_DOT) || (*nested)->isKind(PNK_OPTDOT)) { while ((*nested)->isKind(PNK_DOT) || (*nested)->isKind(PNK_OPTDOT)) {
MOZ_ASSERT((*nested)->isArity(PN_NAME)); MOZ_ASSERT((*nested)->isArity(PN_BINARY));
nested = &(*nested)->pn_expr; nested = &(*nested)->pn_left;
} }
return Fold(cx, nested, parser, inGenexpLambda); return Fold(cx, nested, parser, inGenexpLambda);
@ -1953,6 +1957,9 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
MOZ_ASSERT(pn->isArity(PN_NAME)); MOZ_ASSERT(pn->isArity(PN_NAME));
return Fold(cx, &pn->pn_expr, parser, inGenexpLambda); return Fold(cx, &pn->pn_expr, parser, inGenexpLambda);
case PNK_PROPERTYNAME:
MOZ_CRASH("unreachable, handled by ::Dot");
case PNK_OPTDOT: case PNK_OPTDOT:
case PNK_DOT: case PNK_DOT:
return FoldDottedProperty(cx, pn, parser, inGenexpLambda); return FoldDottedProperty(cx, pn, parser, inGenexpLambda);

View file

@ -707,16 +707,20 @@ class FullParseHandler
return new_<DebuggerStatement>(pos); return new_<DebuggerStatement>(pos);
} }
ParseNode* newPropertyAccess(ParseNode* pn, PropertyName* name, uint32_t end) { ParseNode* newPropertyName(PropertyName* name, const TokenPos& pos) {
return new_<PropertyAccess>(pn, name, pn->pn_pos.begin, end); return new_<NameNode>(PNK_PROPERTYNAME, JSOP_NOP, name, pos);
}
ParseNode* newPropertyAccess(ParseNode* expr, ParseNode* key) {
return new_<PropertyAccess>(expr, key, expr->pn_pos.begin, key->pn_pos.end);
} }
ParseNode* newPropertyByValue(ParseNode* lhs, ParseNode* index, uint32_t end) { ParseNode* newPropertyByValue(ParseNode* lhs, ParseNode* index, uint32_t end) {
return new_<PropertyByValue>(lhs, index, lhs->pn_pos.begin, end); return new_<PropertyByValue>(lhs, index, lhs->pn_pos.begin, end);
} }
ParseNode* newOptionalPropertyAccess(ParseNode* pn, PropertyName* name, uint32_t end) { ParseNode* newOptionalPropertyAccess(ParseNode* expr, ParseNode* key) {
return new_<OptionalPropertyAccess>(pn, name, pn->pn_pos.begin, end); return new_<OptionalPropertyAccess>(expr, key, expr->pn_pos.begin, key->pn_pos.end);
} }
ParseNode* newOptionalPropertyByValue(ParseNode* lhs, ParseNode* index, uint32_t end) { ParseNode* newOptionalPropertyByValue(ParseNode* lhs, ParseNode* index, uint32_t end) {

View file

@ -74,11 +74,11 @@ class NameResolver
bool nameExpression(ParseNode* n, bool* foundName) { bool nameExpression(ParseNode* n, bool* foundName) {
switch (n->getKind()) { switch (n->getKind()) {
case PNK_DOT: case PNK_DOT:
if (!nameExpression(n->expr(), foundName)) if (!nameExpression(n->pn_left, foundName))
return false; return false;
if (!*foundName) if (!*foundName)
return true; return true;
return appendPropertyReference(n->pn_atom); return appendPropertyReference(n->pn_right->pn_atom);
case PNK_NAME: case PNK_NAME:
*foundName = true; *foundName = true;
@ -800,12 +800,12 @@ class NameResolver
} }
case PNK_DOT: case PNK_DOT:
MOZ_ASSERT(cur->isArity(PN_NAME)); MOZ_ASSERT(cur->isArity(PN_BINARY));
// Super prop nodes do not have a meaningful LHS // Super prop nodes do not have a meaningful LHS
if (cur->as<PropertyAccess>().isSuper()) if (cur->as<PropertyAccess>().isSuper())
break; break;
if (!resolve(cur->expr(), prefix)) if (!resolve(cur->pn_left, prefix))
return false; return false;
break; break;
@ -840,6 +840,7 @@ class NameResolver
case PNK_EXPORT_SPEC: // by PNK_EXPORT_SPEC_LIST case PNK_EXPORT_SPEC: // by PNK_EXPORT_SPEC_LIST
case PNK_CALLSITEOBJ: // by PNK_TAGGED_TEMPLATE case PNK_CALLSITEOBJ: // by PNK_TAGGED_TEMPLATE
case PNK_CLASSNAMES: // by PNK_CLASS case PNK_CLASSNAMES: // by PNK_CLASS
case PNK_PROPERTYNAME: // by PNK_DOT
MOZ_CRASH("should have been handled by a parent node"); MOZ_CRASH("should have been handled by a parent node");
case PNK_LIMIT: // invalid sentinel value case PNK_LIMIT: // invalid sentinel value

View file

@ -265,6 +265,8 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
case PNK_WHILE: case PNK_WHILE:
case PNK_SWITCH: case PNK_SWITCH:
case PNK_NEW: case PNK_NEW:
case PNK_OPTDOT:
case PNK_DOT:
case PNK_OPTCALL: case PNK_OPTCALL:
case PNK_CALL: case PNK_CALL:
case PNK_SUPERCALL: case PNK_SUPERCALL:
@ -489,9 +491,8 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
} }
case PNK_LABEL: case PNK_LABEL:
case PNK_OPTDOT:
case PNK_DOT:
case PNK_NAME: case PNK_NAME:
case PNK_PROPERTYNAME:
return PushNameNodeChildren(pn, stack); return PushNameNodeChildren(pn, stack);
case PNK_LEXICALSCOPE: case PNK_LEXICALSCOPE:
@ -731,6 +732,21 @@ UnaryNode::dump(int indent)
void void
BinaryNode::dump(int indent) BinaryNode::dump(int indent)
{ {
if (isKind(PNK_DOT)) {
fprintf(stderr, "(.");
DumpParseTree(pn_right, indent + 2);
fprintf(stderr, " ");
if (as<PropertyAccess>().isSuper())
fprintf(stderr, "super");
else
DumpParseTree(pn_left, indent + 2);
fprintf(stderr, ")");
return;
}
const char* name = parseNodeNames[getKind()]; const char* name = parseNodeNames[getKind()];
fprintf(stderr, "(%s ", name); fprintf(stderr, "(%s ", name);
indent += strlen(name) + 2; indent += strlen(name) + 2;
@ -803,10 +819,7 @@ DumpName(const CharT* s, size_t len)
void void
NameNode::dump(int indent) NameNode::dump(int indent)
{ {
if (isKind(PNK_NAME) || isKind(PNK_DOT)) { if (isKind(PNK_NAME) || isKind(PNK_PROPERTYNAME)) {
if (isKind(PNK_DOT))
fprintf(stderr, "(.");
if (!pn_atom) { if (!pn_atom) {
fprintf(stderr, "#<null name>"); fprintf(stderr, "#<null name>");
} else if (getOp() == JSOP_GETARG && pn_atom->length() == 0) { } else if (getOp() == JSOP_GETARG && pn_atom->length() == 0) {
@ -821,15 +834,6 @@ NameNode::dump(int indent)
else else
DumpName(pn_atom->twoByteChars(nogc), pn_atom->length()); DumpName(pn_atom->twoByteChars(nogc), pn_atom->length());
} }
if (isKind(PNK_DOT)) {
fputc(' ', stderr);
if (as<PropertyAccess>().isSuper())
fprintf(stderr, "super");
else
DumpParseTree(expr(), indent + 2);
fputc(')', stderr);
}
return; return;
} }

View file

@ -32,6 +32,7 @@ class ObjectBox;
F(POSTINCREMENT) \ F(POSTINCREMENT) \
F(PREDECREMENT) \ F(PREDECREMENT) \
F(POSTDECREMENT) \ F(POSTDECREMENT) \
F(PROPERTYNAME) \
F(DOT) \ F(DOT) \
F(ELEM) \ F(ELEM) \
F(OPTDOT) \ F(OPTDOT) \
@ -396,9 +397,9 @@ IsTypeofKind(ParseNodeKind kind)
* contains are nullish. An optional chain can also * contains are nullish. An optional chain can also
* contain nodes such as PNK_DOT, PNK_ELEM, PNK_NAME, * contain nodes such as PNK_DOT, PNK_ELEM, PNK_NAME,
* PNK_CALL, etc. These are evaluated normally. * PNK_CALL, etc. These are evaluated normally.
* PNK_OPTDOT name pn_expr: MEMBER expr to left of . * PNK_OPTDOT binary pn_left: MEMBER expr to left of .
* short circuits back to PNK_OPTCHAIN if nullish. * short circuits back to PNK_OPTCHAIN if nullish.
* pn_atom: name to right of . * pn_right: PropertyName to right of .
* PNK_OPTELEM binary pn_left: MEMBER expr to left of [ * PNK_OPTELEM binary pn_left: MEMBER expr to left of [
* short circuits back to PNK_OPTCHAIN if nullish. * short circuits back to PNK_OPTCHAIN if nullish.
* pn_right: expr between [ and ] * pn_right: expr between [ and ]
@ -406,8 +407,10 @@ IsTypeofKind(ParseNodeKind kind)
* pn_count: 1 + N (where N is number of args) * pn_count: 1 + N (where N is number of args)
* call is a MEMBER expr naming a callable object, * call is a MEMBER expr naming a callable object,
* short circuits back to PNK_OPTCHAIN if nullish. * short circuits back to PNK_OPTCHAIN if nullish.
* PNK_DOT name pn_expr: MEMBER expr to left of . * PNK_PROPERTYNAME pn_atom: property being accessed
* pn_atom: name to right of . * name
* PNK_DOT binary pn_left: MEMBER expr to left of .
* pn_right: PropertyName to right of .
* PNK_ELEM binary pn_left: MEMBER expr to left of [ * PNK_ELEM binary pn_left: MEMBER expr to left of [
* pn_right: expr between [ and ] * pn_right: expr between [ and ]
* PNK_CALL binary pn_left: callee expression on the left of the ( * PNK_CALL binary pn_left: callee expression on the left of the (
@ -600,8 +603,7 @@ class ParseNode
FunctionBox* funbox; /* function object */ FunctionBox* funbox; /* function object */
}; };
ParseNode* expr; /* module or function body, var ParseNode* expr; /* module or function body, var
initializer, argument default, or initializer, or argument default */
base object of PNK_DOT */
} name; } name;
struct { struct {
LexicalScope::Data* bindings; LexicalScope::Data* bindings;
@ -1223,44 +1225,45 @@ class RegExpLiteral : public NullaryNode
} }
}; };
class PropertyAccessBase : public ParseNode class PropertyAccessBase : public BinaryNode
{ {
public: public:
PropertyAccessBase(ParseNodeKind kind, ParseNode* lhs, PropertyName* name, /*
uint32_t begin, uint32_t end) * PropertyAccess nodes can have any expression/'super' as left-hand
: ParseNode(kind, JSOP_NOP, PN_NAME, TokenPos(begin, end)) * side, but the name must be a ParseNodeKind::PropertyName node.
*/
PropertyAccessBase(ParseNodeKind kind, ParseNode* lhs, ParseNode* name, uint32_t begin, uint32_t end)
: BinaryNode(kind, JSOP_NOP, TokenPos(begin, end), lhs, name)
{ {
MOZ_ASSERT(lhs != nullptr); MOZ_ASSERT(lhs != nullptr);
MOZ_ASSERT(name != nullptr); MOZ_ASSERT(name != nullptr);
pn_u.name.expr = lhs;
pn_u.name.atom = name;
} }
static bool test(const ParseNode& node) { static bool test(const ParseNode& node) {
bool match = node.isKind(PNK_DOT) || bool match = node.isKind(PNK_DOT) ||
node.isKind(PNK_OPTDOT); node.isKind(PNK_OPTDOT);
MOZ_ASSERT_IF(match, node.isArity(PN_NAME)); MOZ_ASSERT_IF(match, node.isArity(PN_BINARY));
MOZ_ASSERT_IF(match, node.pn_right->isKind(PNK_PROPERTYNAME));
return match; return match;
} }
ParseNode& expression() const { ParseNode& expression() const {
return *pn_u.name.expr; return *pn_u.binary.left;
} }
PropertyName& name() const { PropertyName& name() const {
return *pn_u.name.atom->asPropertyName(); return *pn_u.binary.right->pn_atom->asPropertyName();
} }
JSAtom* nameAtom() const { JSAtom* nameAtom() const {
return pn_u.name.atom; return pn_u.binary.right->pn_atom;
} }
}; };
class PropertyAccess : public PropertyAccessBase class PropertyAccess : public PropertyAccessBase
{ {
public: public:
PropertyAccess(ParseNode* lhs, PropertyName* name, uint32_t begin, PropertyAccess(ParseNode* lhs, ParseNode* name, uint32_t begin, uint32_t end)
uint32_t end)
: PropertyAccessBase(PNK_DOT, lhs, name, begin, end) : PropertyAccessBase(PNK_DOT, lhs, name, begin, end)
{ {
MOZ_ASSERT(lhs != nullptr); MOZ_ASSERT(lhs != nullptr);
@ -1269,7 +1272,8 @@ class PropertyAccess : public PropertyAccessBase
static bool test(const ParseNode& node) { static bool test(const ParseNode& node) {
bool match = node.isKind(PNK_DOT); bool match = node.isKind(PNK_DOT);
MOZ_ASSERT_IF(match, node.isArity(PN_NAME)); MOZ_ASSERT_IF(match, node.isArity(PN_BINARY));
MOZ_ASSERT_IF(match, node.pn_right->isKind(PNK_PROPERTYNAME));
return match; return match;
} }
@ -1282,8 +1286,7 @@ class PropertyAccess : public PropertyAccessBase
class OptionalPropertyAccess : public PropertyAccessBase class OptionalPropertyAccess : public PropertyAccessBase
{ {
public: public:
OptionalPropertyAccess(ParseNode* lhs, PropertyName* name, uint32_t begin, OptionalPropertyAccess(ParseNode* lhs, ParseNode* name, uint32_t begin, uint32_t end)
uint32_t end)
: PropertyAccessBase(PNK_OPTDOT, lhs, name, begin, end) : PropertyAccessBase(PNK_OPTDOT, lhs, name, begin, end)
{ {
MOZ_ASSERT(lhs != nullptr); MOZ_ASSERT(lhs != nullptr);
@ -1292,7 +1295,8 @@ class OptionalPropertyAccess : public PropertyAccessBase
static bool test(const ParseNode& node) { static bool test(const ParseNode& node) {
bool match = node.isKind(PNK_OPTDOT); bool match = node.isKind(PNK_OPTDOT);
MOZ_ASSERT_IF(match, node.isArity(PN_NAME)); MOZ_ASSERT_IF(match, node.isArity(PN_BINARY));
MOZ_ASSERT_IF(match, node.pn_right->isKind(PNK_PROPERTYNAME));
return match; return match;
} }
}; };

View file

@ -9333,11 +9333,14 @@ Parser<ParseHandler>::memberPropertyAccess(
error(JSMSG_BAD_SUPERPROP, "property"); error(JSMSG_BAD_SUPERPROP, "property");
return null(); return null();
} }
Node name = handler.newPropertyName(field, pos());
if (!name)
return null();
if (optionalKind == OptionalKind::Optional) { if (optionalKind == OptionalKind::Optional) {
MOZ_ASSERT(!handler.isSuperBase(lhs)); MOZ_ASSERT(!handler.isSuperBase(lhs));
return handler.newOptionalPropertyAccess(lhs, field, pos().end); return handler.newOptionalPropertyAccess(lhs, name);
} }
return handler.newPropertyAccess(lhs, field, pos().end); return handler.newPropertyAccess(lhs, name);
} }
template <class ParseHandler> template <class ParseHandler>

View file

@ -360,13 +360,16 @@ class SyntaxParseHandler
} }
Node newDebuggerStatement(const TokenPos& pos) { return NodeGeneric; } Node newDebuggerStatement(const TokenPos& pos) { return NodeGeneric; }
Node newPropertyAccess(Node pn, PropertyName* name, uint32_t end) { Node newPropertyName(PropertyName* name, const TokenPos& pos) {
lastAtom = name; lastAtom = name;
return NodeGeneric;
}
Node newPropertyAccess(Node expr, Node key) {
return NodeDottedProperty; return NodeDottedProperty;
} }
Node newOptionalPropertyAccess(Node pn, PropertyName* name, uint32_t end) { Node newOptionalPropertyAccess(Node expr, Node key) {
lastAtom = name;
return NodeOptionalDottedProperty; return NodeOptionalDottedProperty;
} }

View file

@ -642,16 +642,16 @@ static ParseNode*
DotBase(ParseNode* pn) DotBase(ParseNode* pn)
{ {
MOZ_ASSERT(pn->isKind(PNK_DOT)); MOZ_ASSERT(pn->isKind(PNK_DOT));
MOZ_ASSERT(pn->isArity(PN_NAME)); MOZ_ASSERT(pn->isArity(PN_BINARY));
return pn->expr(); return pn->pn_left;
} }
static PropertyName* static PropertyName*
DotMember(ParseNode* pn) DotMember(ParseNode* pn)
{ {
MOZ_ASSERT(pn->isKind(PNK_DOT)); MOZ_ASSERT(pn->isKind(PNK_DOT));
MOZ_ASSERT(pn->isArity(PN_NAME)); MOZ_ASSERT(pn->isArity(PN_BINARY));
return pn->pn_atom->asPropertyName(); return pn->pn_right->pn_atom->asPropertyName();
} }
static ParseNode* static ParseNode*