1339395 - Part 1: Align parse method for object literals to match array literals.

This commit is contained in:
Gaming4JC 2019-07-14 16:18:57 -04:00 • committed by Roy Tam
commit 2734a01c77
2 changed files with 199 additions and 183 deletions

View file

@ -302,10 +302,9 @@ class FullParseHandler
} }
MOZ_MUST_USE bool addSpreadElement(ParseNode* literal, uint32_t begin, ParseNode* inner) { MOZ_MUST_USE bool addSpreadElement(ParseNode* literal, uint32_t begin, ParseNode* inner) {
TokenPos pos(begin, inner->pn_pos.end); ParseNode* spread = newSpread(begin, inner);
ParseNode* spread = new_<UnaryNode>(PNK_SPREAD, JSOP_NOP, pos, inner);
if (!spread) if (!spread)
return null(); return false;
literal->append(spread); literal->append(spread);
literal->pn_xflags |= PNX_ARRAYHOLESPREAD | PNX_NONCONST; literal->pn_xflags |= PNX_ARRAYHOLESPREAD | PNX_NONCONST;
return true; return true;

View file

@ -4361,85 +4361,90 @@ Parser<ParseHandler>::objectBindingPattern(DeclarationKind kind, YieldHandling y
RootedAtom propAtom(context); RootedAtom propAtom(context);
for (;;) { for (;;) {
TokenKind tt; TokenKind tt;
if (!tokenStream.getToken(&tt)) if (!tokenStream.peekToken(&tt))
return null(); return null();
if (tt == TOK_RC) if (tt == TOK_RC)
break; break;
TokenPos namePos = pos(); if (tt == TOK_TRIPLEDOT) {
// TODO: rest-binding property
tokenStream.ungetToken(); error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt));
PropertyType propType;
Node propName = propertyName(yieldHandling, declKind, literal, &propType, &propAtom);
if (!propName)
return null(); return null();
if (propType == PropertyType::Normal) {
// Handle e.g., |var {p: x} = o| and |var {p: x=0} = o|.
if (!tokenStream.getToken(&tt, TokenStream::Operand))
return null();
Node binding = bindingIdentifierOrPattern(kind, yieldHandling, tt);
if (!binding)
return null();
bool hasInitializer;
if (!tokenStream.matchToken(&hasInitializer, TOK_ASSIGN))
return null();
Node bindingExpr = hasInitializer
? bindingInitializer(binding, kind, yieldHandling)
: binding;
if (!bindingExpr)
return null();
if (!handler.addPropertyDefinition(literal, propName, bindingExpr))
return null();
} else if (propType == PropertyType::Shorthand) {
// Handle e.g., |var {x, y} = o| as destructuring shorthand
// for |var {x: x, y: y} = o|.
MOZ_ASSERT(TokenKindIsPossibleIdentifierName(tt));
Node binding = bindingIdentifier(kind, yieldHandling);
if (!binding)
return null();
if (!handler.addShorthand(literal, propName, binding))
return null();
} else if (propType == PropertyType::CoverInitializedName) {
// Handle e.g., |var {x=1, y=2} = o| as destructuring shorthand
// with default values.
MOZ_ASSERT(TokenKindIsPossibleIdentifierName(tt));
Node binding = bindingIdentifier(kind, yieldHandling);
if (!binding)
return null();
tokenStream.consumeKnownToken(TOK_ASSIGN);
Node bindingExpr = bindingInitializer(binding, kind, yieldHandling);
if (!bindingExpr)
return null();
if (!handler.addPropertyDefinition(literal, propName, bindingExpr))
return null();
} else { } else {
errorAt(namePos.begin, JSMSG_NO_VARIABLE_NAME); TokenPos namePos = tokenStream.nextToken().pos;
return null();
PropertyType propType;
Node propName = propertyName(yieldHandling, declKind, literal, &propType, &propAtom);
if (!propName)
return null();
if (propType == PropertyType::Normal) {
// Handle e.g., |var {p: x} = o| and |var {p: x=0} = o|.
if (!tokenStream.getToken(&tt, TokenStream::Operand))
return null();
Node binding = bindingIdentifierOrPattern(kind, yieldHandling, tt);
if (!binding)
return null();
bool hasInitializer;
if (!tokenStream.matchToken(&hasInitializer, TOK_ASSIGN))
return null();
Node bindingExpr = hasInitializer
? bindingInitializer(binding, kind, yieldHandling)
: binding;
if (!bindingExpr)
return null();
if (!handler.addPropertyDefinition(literal, propName, bindingExpr))
return null();
} else if (propType == PropertyType::Shorthand) {
// Handle e.g., |var {x, y} = o| as destructuring shorthand
// for |var {x: x, y: y} = o|.
MOZ_ASSERT(TokenKindIsPossibleIdentifierName(tt));
Node binding = bindingIdentifier(kind, yieldHandling);
if (!binding)
return null();
if (!handler.addShorthand(literal, propName, binding))
return null();
} else if (propType == PropertyType::CoverInitializedName) {
// Handle e.g., |var {x=1, y=2} = o| as destructuring
// shorthand with default values.
MOZ_ASSERT(TokenKindIsPossibleIdentifierName(tt));
Node binding = bindingIdentifier(kind, yieldHandling);
if (!binding)
return null();
tokenStream.consumeKnownToken(TOK_ASSIGN);
Node bindingExpr = bindingInitializer(binding, kind, yieldHandling);
if (!bindingExpr)
return null();
if (!handler.addPropertyDefinition(literal, propName, bindingExpr))
return null();
} else {
errorAt(namePos.begin, JSMSG_NO_VARIABLE_NAME);
return null();
}
} }
if (!tokenStream.getToken(&tt)) bool matched;
if (!tokenStream.matchToken(&matched, TOK_COMMA))
return null(); return null();
if (tt == TOK_RC) if (!matched)
break; break;
if (tt != TOK_COMMA) {
reportMissingClosing(JSMSG_CURLY_AFTER_LIST, JSMSG_CURLY_OPENED, begin);
return null();
}
} }
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::None,
reportMissingClosing(JSMSG_CURLY_AFTER_LIST,
JSMSG_CURLY_OPENED, begin));
handler.setEndPosition(literal, pos().end); handler.setEndPosition(literal, pos().end);
return literal; return literal;
} }
@ -9682,173 +9687,185 @@ Parser<ParseHandler>::objectLiteral(YieldHandling yieldHandling, PossibleError*
RootedAtom propAtom(context); RootedAtom propAtom(context);
for (;;) { for (;;) {
TokenKind tt; TokenKind tt;
if (!tokenStream.getToken(&tt)) if (!tokenStream.peekToken(&tt))
return null(); return null();
if (tt == TOK_RC) if (tt == TOK_RC)
break; break;
TokenPos namePos = pos(); if (tt == TOK_TRIPLEDOT) {
// TODO: object spread
tokenStream.ungetToken(); error(JSMSG_UNEXPECTED_TOKEN, "property name", TokenKindToDesc(tt));
PropertyType propType;
Node propName = propertyName(yieldHandling, declKind, literal, &propType, &propAtom);
if (!propName)
return null(); return null();
} else {
TokenPos namePos = tokenStream.nextToken().pos;
PropertyType propType;
Node propName = propertyName(yieldHandling, declKind, literal, &propType, &propAtom);
if (!propName)
if (propType == PropertyType::Normal) {
TokenPos exprPos;
if (!tokenStream.peekTokenPos(&exprPos, TokenStream::Operand))
return null();
Node propExpr = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
possibleError);
if (!propExpr)
return null(); return null();
handler.checkAndSetIsDirectRHSAnonFunction(propExpr); if (propType == PropertyType::Normal) {
TokenPos exprPos;
if (!tokenStream.peekTokenPos(&exprPos, TokenStream::Operand))
return null();
if (foldConstants && !FoldConstants(context, &propExpr, this)) Node propExpr = assignExpr(InAllowed, yieldHandling, TripledotProhibited,
return null(); possibleError);
if (!propExpr)
return null();
handler.checkAndSetIsDirectRHSAnonFunction(propExpr);
if (possibleError)
checkDestructuringAssignmentElement(propExpr, exprPos, possibleError);
if (foldConstants && !FoldConstants(context, &propExpr, this))
return null();
if (propAtom == context->names().proto) {
if (seenPrototypeMutation) {
// Directly report the error when we're not in a
// destructuring context.
if (!possibleError) {
errorAt(namePos.begin, JSMSG_DUPLICATE_PROTO_PROPERTY);
return null();
}
// Otherwise delay error reporting until we've
// determined whether or not we're destructuring.
possibleError->setPendingExpressionErrorAt(namePos,
JSMSG_DUPLICATE_PROTO_PROPERTY);
}
seenPrototypeMutation = true;
// Note: this occurs *only* if we observe TOK_COLON! Only
// __proto__: v mutates [[Prototype]]. Getters, setters,
// method/generator definitions, computed property name
// versions of all of these, and shorthands do not.
if (!handler.addPrototypeMutation(literal, namePos.begin, propExpr))
return null();
} else {
if (!handler.isConstant(propExpr))
handler.setListFlag(literal, PNX_NONCONST);
if (!handler.addPropertyDefinition(literal, propName, propExpr))
return null();
}
} else if (propType == PropertyType::Shorthand) {
/*
* Support, e.g., |({x, y} = o)| as destructuring shorthand
* for |({x: x, y: y} = o)|, and |var o = {x, y}| as
* initializer shorthand for |var o = {x: x, y: y}|.
*/
Rooted<PropertyName*> name(context, identifierReference(yieldHandling));
if (!name)
return null();
Node nameExpr = identifierReference(name);
if (!nameExpr)
return null();
if (possibleError)
checkDestructuringAssignmentTarget(nameExpr, namePos, possibleError);
if (!handler.addShorthand(literal, propName, nameExpr))
return null();
} else if (propType == PropertyType::CoverInitializedName) {
/*
* Support, e.g., |({x=1, y=2} = o)| as destructuring
* shorthand with default values, as per ES6 12.14.5
*/
Rooted<PropertyName*> name(context, identifierReference(yieldHandling));
if (!name)
return null();
Node lhs = identifierReference(name);
if (!lhs)
return null();
tokenStream.consumeKnownToken(TOK_ASSIGN);
if (!seenCoverInitializedName) {
// "shorthand default" or "CoverInitializedName" syntax is
// only valid in the case of destructuring.
seenCoverInitializedName = true;
if (propAtom == context->names().proto) {
if (seenPrototypeMutation) {
// Directly report the error when we're not in a
// destructuring context.
if (!possibleError) { if (!possibleError) {
errorAt(namePos.begin, JSMSG_DUPLICATE_PROTO_PROPERTY); // Destructuring defaults are definitely not allowed
// in this object literal, because of something the
// caller knows about the preceding code. For example,
// maybe the preceding token is an operator:
// |x + {y=z}|.
error(JSMSG_COLON_AFTER_ID);
return null(); return null();
} }
// Otherwise delay error reporting until we've determined // Here we set a pending error so that later in the parse,
// whether or not we're destructuring. // once we've determined whether or not we're
possibleError->setPendingExpressionErrorAt(namePos, // destructuring, the error can be reported or ignored
JSMSG_DUPLICATE_PROTO_PROPERTY); // appropriately.
possibleError->setPendingExpressionErrorAt(pos(), JSMSG_COLON_AFTER_ID);
} }
seenPrototypeMutation = true;
// Note: this occurs *only* if we observe TOK_COLON! Only if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(lhs, context)) {
// __proto__: v mutates [[Prototype]]. Getters, setters, // |chars| is "arguments" or "eval" here.
// method/generator definitions, computed property name if (!strictModeErrorAt(namePos.begin, JSMSG_BAD_STRICT_ASSIGN, chars))
// versions of all of these, and shorthands do not. return null();
if (!handler.addPrototypeMutation(literal, namePos.begin, propExpr)) }
Node rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited);
if (!rhs)
return null();
handler.checkAndSetIsDirectRHSAnonFunction(rhs);
Node propExpr = handler.newAssignment(PNK_ASSIGN, lhs, rhs, JSOP_NOP);
if (!propExpr)
return null(); return null();
} else {
if (!handler.isConstant(propExpr))
handler.setListFlag(literal, PNX_NONCONST);
if (!handler.addPropertyDefinition(literal, propName, propExpr)) if (!handler.addPropertyDefinition(literal, propName, propExpr))
return null(); return null();
} } else {
RootedAtom funName(context);
if (!tokenStream.isCurrentTokenType(TOK_RB)) {
funName = propAtom;
if (possibleError) if (propType == PropertyType::Getter || propType == PropertyType::Setter) {
checkDestructuringAssignmentElement(propExpr, exprPos, possibleError); funName = prefixAccessorName(propType, propAtom);
} else if (propType == PropertyType::Shorthand) { if (!funName)
/* return null();
* Support, e.g., |({x, y} = o)| as destructuring shorthand }
* for |({x: x, y: y} = o)|, and |var o = {x, y}| as initializer
* shorthand for |var o = {x: x, y: y}|.
*/
Rooted<PropertyName*> name(context, identifierReference(yieldHandling));
if (!name)
return null();
Node nameExpr = identifierReference(name);
if (!nameExpr)
return null();
if (possibleError)
checkDestructuringAssignmentTarget(nameExpr, namePos, possibleError);
if (!handler.addShorthand(literal, propName, nameExpr))
return null();
} else if (propType == PropertyType::CoverInitializedName) {
/*
* Support, e.g., |({x=1, y=2} = o)| as destructuring shorthand
* with default values, as per ES6 12.14.5
*/
Rooted<PropertyName*> name(context, identifierReference(yieldHandling));
if (!name)
return null();
Node lhs = identifierReference(name);
if (!lhs)
return null();
tokenStream.consumeKnownToken(TOK_ASSIGN);
if (!seenCoverInitializedName) {
// "shorthand default" or "CoverInitializedName" syntax is only
// valid in the case of destructuring.
seenCoverInitializedName = true;
if (!possibleError) {
// Destructuring defaults are definitely not allowed in this object literal,
// because of something the caller knows about the preceding code.
// For example, maybe the preceding token is an operator: `x + {y=z}`.
error(JSMSG_COLON_AFTER_ID);
return null();
} }
// Here we set a pending error so that later in the parse, once we've Node fn = methodDefinition(namePos.begin, propType, funName);
// determined whether or not we're destructuring, the error can be if (!fn)
// reported or ignored appropriately.
possibleError->setPendingExpressionErrorAt(pos(), JSMSG_COLON_AFTER_ID);
}
if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(lhs, context)) {
// |chars| is "arguments" or "eval" here.
if (!strictModeErrorAt(namePos.begin, JSMSG_BAD_STRICT_ASSIGN, chars))
return null(); return null();
}
Node rhs = assignExpr(InAllowed, yieldHandling, TripledotProhibited); handler.checkAndSetIsDirectRHSAnonFunction(fn);
if (!rhs)
return null();
handler.checkAndSetIsDirectRHSAnonFunction(rhs); JSOp op = JSOpFromPropertyType(propType);
if (!handler.addObjectMethodDefinition(literal, propName, fn, op))
return null();
Node propExpr = handler.newAssignment(PNK_ASSIGN, lhs, rhs, JSOP_NOP); if (possibleError) {
if (!propExpr) possibleError->setPendingDestructuringErrorAt(namePos,
return null(); JSMSG_BAD_DESTRUCT_TARGET);
if (!handler.addPropertyDefinition(literal, propName, propExpr))
return null();
} else {
RootedAtom funName(context);
if (!tokenStream.isCurrentTokenType(TOK_RB)) {
funName = propAtom;
if (propType == PropertyType::Getter || propType == PropertyType::Setter) {
funName = prefixAccessorName(propType, propAtom);
if (!funName)
return null();
} }
} }
Node fn = methodDefinition(namePos.begin, propType, funName);
if (!fn)
return null();
handler.checkAndSetIsDirectRHSAnonFunction(fn);
JSOp op = JSOpFromPropertyType(propType);
if (!handler.addObjectMethodDefinition(literal, propName, fn, op))
return null();
if (possibleError)
possibleError->setPendingDestructuringErrorAt(namePos, JSMSG_BAD_DESTRUCT_TARGET);
} }
if (!tokenStream.getToken(&tt)) bool matched;
if (!tokenStream.matchToken(&matched, TOK_COMMA))
return null(); return null();
if (tt == TOK_RC) if (!matched)
break; break;
if (tt != TOK_COMMA) {
reportMissingClosing(JSMSG_CURLY_AFTER_LIST, JSMSG_CURLY_OPENED, openedPos);
return null();
}
} }
MUST_MATCH_TOKEN_MOD_WITH_REPORT(TOK_RC, TokenStream::None,
reportMissingClosing(JSMSG_CURLY_AFTER_LIST,
JSMSG_CURLY_OPENED, openedPos));
handler.setEndPosition(literal, pos().end); handler.setEndPosition(literal, pos().end);
return literal; return literal;
} }