Commit b407d274 authored by Toon Verwaest's avatar Toon Verwaest Committed by Commit Bot

[parser] Further restructure ParseAssignmentExpression

This better separates non-arrow/assignment from the alternative, and
destructuring assignment from other types of assignment to avoid unnecessary
and duplicate branches.

Change-Id: I51c59f86c705646c02f182c9719700c558297e4a
Reviewed-on: https://chromium-review.googlesource.com/c/1328921
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#57385}
parent 948b02ce
...@@ -2661,7 +2661,23 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN) { ...@@ -2661,7 +2661,23 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN) {
ExpressionT expression = ParseConditionalExpression(accept_IN); ExpressionT expression = ParseConditionalExpression(accept_IN);
if (V8_UNLIKELY(peek() == Token::ARROW)) { Token::Value op = peek();
if (!Token::IsArrowOrAssignmentOp(op)) {
if (IsValidReferenceExpression(expression)) {
// Parenthesized identifiers and property references are allowed as part
// of a larger assignment pattern, even though parenthesized patterns
// themselves are not allowed, e.g., "[(x)] = []". Only accumulate
// assignment pattern errors if the parsed expression is more complex.
Accumulate(~ExpressionClassifier::AssignmentPatternProduction);
} else {
Accumulate(ExpressionClassifier::AllProductions);
}
return expression;
}
// Arrow functions.
if (V8_UNLIKELY(op == Token::ARROW)) {
Scanner::Location arrow_loc = scanner()->peek_location(); Scanner::Location arrow_loc = scanner()->peek_location();
ValidateArrowFormalParameters(expression, parenthesized_formals, is_async); ValidateArrowFormalParameters(expression, parenthesized_formals, is_async);
// This reads strangely, but is correct: it checks whether any // This reads strangely, but is correct: it checks whether any
...@@ -2702,45 +2718,42 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN) { ...@@ -2702,45 +2718,42 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN) {
return expression; return expression;
} }
Token::Value op = peek(); // Destructuring assignmment.
if (V8_UNLIKELY(IsValidPattern(expression) && op == Token::ASSIGN)) {
bool is_destructuring_assignment =
IsValidPattern(expression) && peek() == Token::ASSIGN;
if (is_destructuring_assignment) {
ValidateAssignmentPattern(); ValidateAssignmentPattern();
// This is definitely not an expression so don't accumulate // This is definitely not an expression so don't accumulate
// expression-related errors. // expression-related errors.
Accumulate(~ExpressionClassifier::ExpressionProduction); Accumulate(~ExpressionClassifier::ExpressionProduction);
if (!Token::IsAssignmentOp(op)) return expression;
impl()->MarkPatternAsAssigned(expression); impl()->MarkPatternAsAssigned(expression);
} else { Consume(op);
if (IsValidReferenceExpression(expression)) { int pos = position();
// Parenthesized identifiers and property references are allowed as part
// of a larger assignment pattern, even though parenthesized patterns ExpressionClassifier rhs_classifier(this);
// themselves are not allowed, e.g., "[(x)] = []". Only accumulate
// assignment pattern errors if the parsed expression is more complex. ExpressionT right = ParseAssignmentExpression(accept_IN);
Accumulate(~ExpressionClassifier::AssignmentPatternProduction); ValidateExpression();
} else { AccumulateFormalParameterContainmentErrors();
Accumulate(ExpressionClassifier::AllProductions);
ExpressionT result = factory()->NewAssignment(op, expression, right, pos);
auto rewritable = factory()->NewRewritableExpression(result, scope());
impl()->QueueDestructuringAssignmentForRewriting(rewritable);
return rewritable;
} }
if (!Token::IsAssignmentOp(op)) return expression; // This is definitely not an assignment pattern, so don't accumulate
// assignment pattern-related errors.
Accumulate(~ExpressionClassifier::AssignmentPatternProduction);
expression = CheckAndRewriteReferenceExpression( expression = CheckAndRewriteReferenceExpression(
expression, lhs_beg_pos, end_position(), expression, lhs_beg_pos, end_position(),
MessageTemplate::kInvalidLhsInAssignment); MessageTemplate::kInvalidLhsInAssignment);
impl()->MarkExpressionAsAssigned(expression); impl()->MarkExpressionAsAssigned(expression);
}
Consume(op); Consume(op);
if (op != Token::ASSIGN) { Scanner::Location op_location = scanner()->location();
classifier()->RecordPatternError(scanner()->location(),
MessageTemplate::kUnexpectedToken,
Token::String(op));
}
int pos = position();
ExpressionClassifier rhs_classifier(this); ExpressionClassifier rhs_classifier(this);
...@@ -2748,40 +2761,32 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN) { ...@@ -2748,40 +2761,32 @@ ParserBase<Impl>::ParseAssignmentExpression(bool accept_IN) {
ValidateExpression(); ValidateExpression();
AccumulateFormalParameterContainmentErrors(); AccumulateFormalParameterContainmentErrors();
if (op == Token::ASSIGN) {
// We try to estimate the set of properties set by constructors. We define a // We try to estimate the set of properties set by constructors. We define a
// new property whenever there is an assignment to a property of 'this'. We // new property whenever there is an assignment to a property of 'this'. We
// should probably only add properties if we haven't seen them // should probably only add properties if we haven't seen them before.
// before. Otherwise we'll probably overestimate the number of properties. // Otherwise we'll probably overestimate the number of properties.
if (op == Token::ASSIGN && impl()->IsThisProperty(expression)) { if (impl()->IsThisProperty(expression)) function_state_->AddProperty();
function_state_->AddProperty();
}
impl()->CheckAssigningFunctionLiteralToProperty(expression, right); impl()->CheckAssigningFunctionLiteralToProperty(expression, right);
// Check if the right hand side is a call to avoid inferring a // Check if the right hand side is a call to avoid inferring a
// name if we're dealing with "a = function(){...}();"-like // name if we're dealing with "a = function(){...}();"-like
// expression. // expression.
if (op == Token::ASSIGN && !right->IsCall() && !right->IsCallNew()) { if (right->IsCall() || right->IsCallNew()) {
fni_.Infer();
} else {
fni_.RemoveLastFunction(); fni_.RemoveLastFunction();
} else {
fni_.Infer();
} }
if (op == Token::ASSIGN) {
impl()->SetFunctionNameFromIdentifierRef(right, expression); impl()->SetFunctionNameFromIdentifierRef(right, expression);
} else {
classifier()->RecordPatternError(
op_location, MessageTemplate::kUnexpectedToken, Token::String(op));
fni_.RemoveLastFunction();
} }
DCHECK_NE(op, Token::INIT); return factory()->NewAssignment(op, expression, right, op_location.beg_pos);
ExpressionT result = factory()->NewAssignment(op, expression, right, pos);
if (is_destructuring_assignment) {
DCHECK_NE(op, Token::ASSIGN_EXP);
auto rewritable = factory()->NewRewritableExpression(result, scope());
impl()->QueueDestructuringAssignmentForRewriting(rewritable);
result = rewritable;
}
return result;
} }
template <typename Impl> template <typename Impl>
......
...@@ -76,7 +76,6 @@ namespace internal { ...@@ -76,7 +76,6 @@ namespace internal {
T(CONDITIONAL, "?", 3) \ T(CONDITIONAL, "?", 3) \
T(INC, "++", 0) \ T(INC, "++", 0) \
T(DEC, "--", 0) \ T(DEC, "--", 0) \
T(ARROW, "=>", 0) \
/* BEGIN AutoSemicolon */ \ /* BEGIN AutoSemicolon */ \
T(SEMICOLON, ";", 0) \ T(SEMICOLON, ";", 0) \
T(RBRACE, "}", 0) \ T(RBRACE, "}", 0) \
...@@ -84,12 +83,16 @@ namespace internal { ...@@ -84,12 +83,16 @@ namespace internal {
T(EOS, "EOS", 0) \ T(EOS, "EOS", 0) \
/* END AutoSemicolon */ \ /* END AutoSemicolon */ \
\ \
/* Assignment operators. */ \ /* BEGIN ArrowOrAssignmentOp */ \
T(ARROW, "=>", 0) \
/* BEGIN AssignmentOp */ \
/* IsAssignmentOp() relies on this block of enum values being */ \ /* IsAssignmentOp() relies on this block of enum values being */ \
/* contiguous and sorted in the same order! */ \ /* contiguous and sorted in the same order! */ \
T(INIT, "=init", 2) /* AST-use only. */ \ T(INIT, "=init", 2) /* AST-use only. */ \
T(ASSIGN, "=", 2) \ T(ASSIGN, "=", 2) \
BINARY_OP_TOKEN_LIST(T, EXPAND_BINOP_ASSIGN_TOKEN) \ BINARY_OP_TOKEN_LIST(T, EXPAND_BINOP_ASSIGN_TOKEN) \
/* END AssignmentOp */ \
/* END ArrowOrAssignmentOp */ \
\ \
/* Binary operators sorted by precedence. */ \ /* Binary operators sorted by precedence. */ \
/* IsBinaryOp() relies on this block of enum values */ \ /* IsBinaryOp() relies on this block of enum values */ \
...@@ -269,9 +272,14 @@ class Token { ...@@ -269,9 +272,14 @@ class Token {
return IsInRange(token, TEMPLATE_SPAN, LPAREN); return IsInRange(token, TEMPLATE_SPAN, LPAREN);
} }
static bool IsArrowOrAssignmentOp(Value token) {
return IsInRange(token, ARROW, ASSIGN_EXP);
}
static bool IsAssignmentOp(Value token) { static bool IsAssignmentOp(Value token) {
return IsInRange(token, INIT, ASSIGN_EXP); return IsInRange(token, INIT, ASSIGN_EXP);
} }
static bool IsGetOrSet(Value op) { return IsInRange(op, GET, SET); } static bool IsGetOrSet(Value op) { return IsInRange(op, GET, SET); }
static bool IsBinaryOp(Value op) { return IsInRange(op, COMMA, EXP); } static bool IsBinaryOp(Value op) { return IsInRange(op, COMMA, EXP); }
......
...@@ -227,6 +227,7 @@ TEST(IsLiteralToken) { ...@@ -227,6 +227,7 @@ TEST(IsLiteralToken) {
CHECK_EQ(TokenIsLiteral(token), Token::IsLiteral(token)); CHECK_EQ(TokenIsLiteral(token), Token::IsLiteral(token));
} }
} }
bool TokenIsAssignmentOp(Token::Value token) { bool TokenIsAssignmentOp(Token::Value token) {
switch (token) { switch (token) {
case Token::INIT: case Token::INIT:
...@@ -247,6 +248,18 @@ TEST(AssignmentOp) { ...@@ -247,6 +248,18 @@ TEST(AssignmentOp) {
} }
} }
bool TokenIsArrowOrAssignmentOp(Token::Value token) {
return token == Token::ARROW || TokenIsAssignmentOp(token);
}
TEST(ArrowOrAssignmentOp) {
for (int i = 0; i < Token::NUM_TOKENS; i++) {
Token::Value token = static_cast<Token::Value>(i);
CHECK_EQ(TokenIsArrowOrAssignmentOp(token),
Token::IsArrowOrAssignmentOp(token));
}
}
bool TokenIsBinaryOp(Token::Value token) { bool TokenIsBinaryOp(Token::Value token) {
switch (token) { switch (token) {
case Token::COMMA: case Token::COMMA:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment