Bug 1418235 - Simplify tracking of parenthesized names in SyntaxParseHandler. r=arai

--HG--
extra : rebase_source : 7154d041e14f24fb5894d2b255e7cb77432505d4
extra : histedit_source : 23250bc47ae3dce24339c5f05b4c1a69f2d3d08b
This commit is contained in:
André Bargull 2017-11-17 06:19:59 -08:00
parent 045ffa33ce
commit f4de88858a
4 changed files with 62 additions and 92 deletions

View File

@ -797,29 +797,18 @@ class FullParseHandler
return pn->isConstant();
}
bool isNameAnyParentheses(ParseNode* node) {
bool isName(ParseNode* node) {
return node->isKind(PNK_NAME);
}
bool isArgumentsAnyParentheses(ParseNode* node, JSContext* cx) {
bool isArgumentsName(ParseNode* node, JSContext* cx) {
return node->isKind(PNK_NAME) && node->pn_atom == cx->names().arguments;
}
bool isEvalAnyParentheses(ParseNode* node, JSContext* cx) {
bool isEvalName(ParseNode* node, JSContext* cx) {
return node->isKind(PNK_NAME) && node->pn_atom == cx->names().eval;
}
const char* nameIsArgumentsEvalAnyParentheses(ParseNode* node, JSContext* cx) {
MOZ_ASSERT(isNameAnyParentheses(node),
"must only call this function on known names");
if (isEvalAnyParentheses(node, cx))
return js_eval_str;
if (isArgumentsAnyParentheses(node, cx))
return js_arguments_str;
return nullptr;
}
bool isAsyncKeyword(ParseNode* node, JSContext* cx) {
return node->isKind(PNK_NAME) &&
node->pn_pos.begin + strlen("async") == node->pn_pos.end &&

View File

@ -6141,9 +6141,8 @@ Parser<ParseHandler, CharT>::forHeadStart(YieldHandling yieldHandling,
if (handler.isUnparenthesizedDestructuringPattern(*forInitialPart)) {
if (!possibleError.checkForDestructuringErrorOrWarning())
return false;
} else if (handler.isNameAnyParentheses(*forInitialPart)) {
const char* chars = handler.nameIsArgumentsEvalAnyParentheses(*forInitialPart, context);
if (chars) {
} else if (handler.isName(*forInitialPart)) {
if (const char* chars = nameIsArgumentsOrEval(*forInitialPart)) {
// |chars| is "arguments" or "eval" here.
if (!strictModeErrorAt(exprOffset, JSMSG_BAD_STRICT_ASSIGN, chars))
return false;
@ -8135,8 +8134,8 @@ Parser<ParseHandler, CharT>::assignExpr(InHandling inHandling, YieldHandling yie
if (!possibleErrorInner.checkForDestructuringErrorOrWarning())
return null();
} else if (handler.isNameAnyParentheses(lhs)) {
if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(lhs, context)) {
} else if (handler.isName(lhs)) {
if (const char* chars = nameIsArgumentsOrEval(lhs)) {
// |chars| is "arguments" or "eval" here.
if (!strictModeErrorAt(exprPos.begin, JSMSG_BAD_STRICT_ASSIGN, chars))
return null();
@ -8178,11 +8177,11 @@ Parser<ParseHandler, CharT>::isValidSimpleAssignmentTarget(Node node,
// error for the various syntaxes that fail this, and warning for the
// various syntaxes that "pass" this but should not, occurs elsewhere.
if (handler.isNameAnyParentheses(node)) {
if (handler.isName(node)) {
if (!pc->sc()->strict())
return true;
return !handler.nameIsArgumentsEvalAnyParentheses(node, context);
return !nameIsArgumentsOrEval(node);
}
if (handler.isPropertyAccess(node))
@ -8196,12 +8195,25 @@ Parser<ParseHandler, CharT>::isValidSimpleAssignmentTarget(Node node,
return false;
}
template <class ParseHandler, typename CharT>
const char*
Parser<ParseHandler, CharT>::nameIsArgumentsOrEval(Node node)
{
MOZ_ASSERT(handler.isName(node), "must only call this function on known names");
if (handler.isEvalName(node, context))
return js_eval_str;
if (handler.isArgumentsName(node, context))
return js_arguments_str;
return nullptr;
}
template <class ParseHandler, typename CharT>
bool
Parser<ParseHandler, CharT>::checkIncDecOperand(Node operand, uint32_t operandOffset)
{
if (handler.isNameAnyParentheses(operand)) {
if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(operand, context)) {
if (handler.isName(operand)) {
if (const char* chars = nameIsArgumentsOrEval(operand)) {
if (!strictModeErrorAt(operandOffset, JSMSG_BAD_STRICT_ASSIGN, chars))
return false;
}
@ -8307,7 +8319,7 @@ Parser<ParseHandler, CharT>::unaryExpr(YieldHandling yieldHandling,
// Per spec, deleting any unary expression is valid -- it simply
// returns true -- except for one case that is illegal in strict mode.
if (handler.isNameAnyParentheses(expr)) {
if (handler.isName(expr)) {
if (!strictModeErrorAt(exprOffset, JSMSG_DEPRECATED_DELETE_OPERAND))
return null();
@ -8607,7 +8619,7 @@ Parser<ParseHandler, CharT>::memberExpr(YieldHandling yieldHandling,
// part of the CoverCallExpressionAndAsyncArrowHead
// syntax when the initial name is "async".
maybeAsyncArrow = true;
} else if (handler.isEvalAnyParentheses(lhs, context)) {
} else if (handler.isEvalName(lhs, context)) {
// Select the right EVAL op and flag pc as having a
// direct eval.
op = pc->sc()->strict() ? JSOP_STRICTEVAL : JSOP_EVAL;
@ -8916,7 +8928,7 @@ Parser<ParseHandler, CharT>::checkDestructuringAssignmentTarget(Node expr, Token
if (possibleError->hasPendingDestructuringError())
return true;
if (handler.isNameAnyParentheses(expr)) {
if (handler.isName(expr)) {
checkDestructuringAssignmentName(expr, exprPos, possibleError);
return true;
}
@ -8946,14 +8958,14 @@ void
Parser<ParseHandler, CharT>::checkDestructuringAssignmentName(Node name, TokenPos namePos,
PossibleError* possibleError)
{
MOZ_ASSERT(handler.isNameAnyParentheses(name));
MOZ_ASSERT(handler.isName(name));
// Return early if a pending destructuring error is already present.
if (possibleError->hasPendingDestructuringError())
return;
if (pc->sc()->needStrictChecks()) {
if (handler.isArgumentsAnyParentheses(name, context)) {
if (handler.isArgumentsName(name, context)) {
if (pc->sc()->strict()) {
possibleError->setPendingDestructuringErrorAt(namePos,
JSMSG_BAD_STRICT_ASSIGN_ARGUMENTS);
@ -8964,7 +8976,7 @@ Parser<ParseHandler, CharT>::checkDestructuringAssignmentName(Node name, TokenPo
return;
}
if (handler.isEvalAnyParentheses(name, context)) {
if (handler.isEvalName(name, context)) {
if (pc->sc()->strict()) {
possibleError->setPendingDestructuringErrorAt(namePos,
JSMSG_BAD_STRICT_ASSIGN_EVAL);
@ -9499,7 +9511,7 @@ Parser<ParseHandler, CharT>::objectLiteral(YieldHandling yieldHandling,
possibleError->setPendingExpressionErrorAt(pos(), JSMSG_COLON_AFTER_ID);
}
if (const char* chars = handler.nameIsArgumentsEvalAnyParentheses(lhs, context)) {
if (const char* chars = nameIsArgumentsOrEval(lhs)) {
// |chars| is "arguments" or "eval" here.
if (!strictModeErrorAt(namePos.begin, JSMSG_BAD_STRICT_ASSIGN, chars))
return null();

View File

@ -861,6 +861,7 @@ class Parser final : public ParserBase, private JS::AutoGCRooter
FunctionCallBehavior behavior = ForbidAssignmentToFunctionCalls);
private:
const char* nameIsArgumentsOrEval(Node node);
bool checkIncDecOperand(Node operand, uint32_t operandOffset);
bool checkStrictAssignment(Node lhs);

View File

@ -59,23 +59,17 @@ class SyntaxParseHandler
// noticed).
NodeFunctionCall,
// Nodes representing *parenthesized* IsValidSimpleAssignmentTarget
// nodes. We can't simply treat all such parenthesized nodes
// identically, because in assignment and increment/decrement contexts
// ES6 says that parentheses constitute a syntax error.
//
// var obj = {};
// var val;
// (val) = 3; (obj.prop) = 4; // okay per ES5's little mind
// [(a)] = [3]; [(obj.prop)] = [4]; // invalid ES6 syntax
// // ...and so on for the other IsValidSimpleAssignmentTarget nodes
//
// We don't know in advance in the current parser when we're parsing
// in a place where name parenthesization changes meaning, so we must
// have multiple node values for these cases.
NodeParenthesizedArgumentsName,
NodeParenthesizedEvalName,
NodeParenthesizedName,
// Node representing normal names which don't require any special
// casing.
NodeName,
// Nodes representing the names "arguments" and "eval".
NodeArgumentsName,
NodeEvalName,
// Node representing the "async" name, which may actually be a
// contextual keyword.
NodePotentialAsyncKeyword,
NodeDottedProperty,
NodeElement,
@ -93,15 +87,6 @@ class SyntaxParseHandler
// is{Unp,P}arenthesized*(Node), parenthesize(Node), and the various
// functions that deal in NodeUnparenthesized* below.
// Nodes representing unparenthesized names.
NodeUnparenthesizedArgumentsName,
NodeUnparenthesizedEvalName,
NodeUnparenthesizedName,
// Node representing the "async" name, which may actually be a
// contextual keyword.
NodePotentialAsyncKeyword,
// Valuable for recognizing potential destructuring patterns.
NodeUnparenthesizedArray,
NodeUnparenthesizedObject,
@ -168,12 +153,12 @@ class SyntaxParseHandler
Node newName(PropertyName* name, const TokenPos& pos, JSContext* cx) {
lastAtom = name;
if (name == cx->names().arguments)
return NodeUnparenthesizedArgumentsName;
return NodeArgumentsName;
if (pos.begin + strlen("async") == pos.end && name == cx->names().async)
return NodePotentialAsyncKeyword;
if (name == cx->names().eval)
return NodeUnparenthesizedEvalName;
return NodeUnparenthesizedName;
return NodeEvalName;
return NodeName;
}
Node newComputedName(Node expr, uint32_t start, uint32_t end) {
@ -181,7 +166,7 @@ class SyntaxParseHandler
}
Node newObjectLiteralPropertyName(JSAtom* atom, const TokenPos& pos) {
return NodeUnparenthesizedName;
return NodeName;
}
Node newNumber(double value, DecimalPoint decimalPoint, const TokenPos& pos) { return NodeGeneric; }
@ -409,9 +394,9 @@ class SyntaxParseHandler
// parsing would *already* have aborted when it saw a destructuring
// pattern. So we can just say any old thing here, because the only
// time we'll be wrong is a case that syntax parsing has already
// rejected. Use NodeUnparenthesizedName so the SyntaxParseHandler
// rejected. Use NodeName so the SyntaxParseHandler
// Parser::cloneLeftHandSide can assert it sees only this.
return NodeUnparenthesizedName;
return NodeName;
}
Node newCatchList(const TokenPos& pos) {
@ -468,13 +453,6 @@ class SyntaxParseHandler
// A number of nodes have different behavior upon parenthesization, but
// only in some circumstances. Convert these nodes to special
// parenthesized forms.
if (node == NodeUnparenthesizedArgumentsName)
return NodeParenthesizedArgumentsName;
if (node == NodeUnparenthesizedEvalName)
return NodeParenthesizedEvalName;
if (node == NodeUnparenthesizedName || node == NodePotentialAsyncKeyword)
return NodeParenthesizedName;
if (node == NodeUnparenthesizedArray)
return NodeParenthesizedArray;
if (node == NodeUnparenthesizedObject)
@ -489,6 +467,10 @@ class SyntaxParseHandler
return NodeGeneric;
}
// Convert parenthesized |async| to a normal name node.
if (node == NodePotentialAsyncKeyword)
return NodeName;
// In all other cases, the parenthesized form of |node| is equivalent
// to the unparenthesized form: return |node| unchanged.
return node;
@ -500,33 +482,19 @@ class SyntaxParseHandler
bool isConstant(Node pn) { return false; }
bool isNameAnyParentheses(Node node) {
return node == NodeUnparenthesizedArgumentsName ||
node == NodeUnparenthesizedEvalName ||
node == NodeUnparenthesizedName ||
node == NodePotentialAsyncKeyword ||
node == NodeParenthesizedArgumentsName ||
node == NodeParenthesizedEvalName ||
node == NodeParenthesizedName;
bool isName(Node node) {
return node == NodeName ||
node == NodeArgumentsName ||
node == NodeEvalName ||
node == NodePotentialAsyncKeyword;
}
bool isArgumentsAnyParentheses(Node node, JSContext* cx) {
return node == NodeUnparenthesizedArgumentsName || node == NodeParenthesizedArgumentsName;
bool isArgumentsName(Node node, JSContext* cx) {
return node == NodeArgumentsName;
}
bool isEvalAnyParentheses(Node node, JSContext* cx) {
return node == NodeUnparenthesizedEvalName || node == NodeParenthesizedEvalName;
}
const char* nameIsArgumentsEvalAnyParentheses(Node node, JSContext* cx) {
MOZ_ASSERT(isNameAnyParentheses(node),
"must only call this method on known names");
if (isEvalAnyParentheses(node, cx))
return js_eval_str;
if (isArgumentsAnyParentheses(node, cx))
return js_arguments_str;
return nullptr;
bool isEvalName(Node node, JSContext* cx) {
return node == NodeEvalName;
}
bool isAsyncKeyword(Node node, JSContext* cx) {