Index: src/preparser.h |
diff --git a/src/preparser.h b/src/preparser.h |
index cdfceea2608f19a6d6f93bc7804d7288e318fc61..3e4c49d8ca81d6f8c4b9bccf93e5d19f35c2320f 100644 |
--- a/src/preparser.h |
+++ b/src/preparser.h |
@@ -115,6 +115,7 @@ class ParserBase : public Traits { |
allow_harmony_default_parameters_(false), |
allow_harmony_spread_calls_(false), |
allow_harmony_destructuring_(false), |
+ allow_harmony_destructuring_assignment_(false), |
allow_harmony_spread_arrays_(false), |
allow_harmony_new_target_(false), |
allow_strong_mode_(false), |
@@ -134,6 +135,7 @@ class ParserBase : public Traits { |
ALLOW_ACCESSORS(harmony_default_parameters); |
ALLOW_ACCESSORS(harmony_spread_calls); |
ALLOW_ACCESSORS(harmony_destructuring); |
+ ALLOW_ACCESSORS(harmony_destructuring_assignment); |
ALLOW_ACCESSORS(harmony_spread_arrays); |
ALLOW_ACCESSORS(harmony_new_target); |
ALLOW_ACCESSORS(strong_mode); |
@@ -549,8 +551,11 @@ class ParserBase : public Traits { |
} |
void ValidateExpression(const ExpressionClassifier* classifier, bool* ok) { |
- if (!classifier->is_valid_expression()) { |
- ReportClassifierError(classifier->expression_error()); |
+ if (!classifier->is_valid_expression() || |
+ classifier->has_cover_initialized_name()) { |
+ ReportClassifierError(ExpressionClassifier::FirdRecorded( |
+ classifier->expression_error(), |
+ classifier->cover_initialized_name_error())); |
*ok = false; |
} |
} |
@@ -688,6 +693,8 @@ class ParserBase : public Traits { |
ExpressionT ParseExpression(bool accept_IN, bool* ok); |
ExpressionT ParseExpression(bool accept_IN, ExpressionClassifier* classifier, |
bool* ok); |
+ ExpressionT ParseExpression(bool accept_IN, int flags, |
+ ExpressionClassifier* classifier, bool* ok); |
ExpressionT ParseArrayLiteral(ExpressionClassifier* classifier, bool* ok); |
ExpressionT ParsePropertyName(IdentifierT* name, bool* is_get, bool* is_set, |
bool* is_static, bool* is_computed_name, |
@@ -700,8 +707,29 @@ class ParserBase : public Traits { |
typename Traits::Type::ExpressionList ParseArguments( |
Scanner::Location* first_spread_pos, ExpressionClassifier* classifier, |
bool* ok); |
+ |
+ enum AssignmentFlags { |
+ kIsRightHandSide = 1 << 0, |
+ kIsPatternElement = 1 << 1, |
+ kMaybeBindingPattern = 1 << 2 |
+ }; |
ExpressionT ParseAssignmentExpression(bool accept_IN, |
ExpressionClassifier* classifier, |
+ bool* ok) { |
+ bool seen_destructuring = false; |
+ return ParseAssignmentExpression(accept_IN, 0, &seen_destructuring, |
+ classifier, ok); |
+ } |
+ ExpressionT ParseAssignmentExpression(bool accept_IN, int flags, |
+ ExpressionClassifier* classifier, |
+ bool* ok) { |
+ bool seen_destructuring = false; |
+ return ParseAssignmentExpression(accept_IN, flags, &seen_destructuring, |
+ classifier, ok); |
+ } |
+ ExpressionT ParseAssignmentExpression(bool accept_IN, int flags, |
+ bool* seen_destructuring, |
+ ExpressionClassifier* classifier, |
bool* ok); |
ExpressionT ParseYieldExpression(ExpressionClassifier* classifier, bool* ok); |
ExpressionT ParseConditionalExpression(bool accept_IN, |
@@ -754,6 +782,8 @@ class ParserBase : public Traits { |
ExpressionT expression, int beg_pos, int end_pos, |
MessageTemplate::Template message, ParseErrorType type, bool* ok); |
+ bool IsValidReferenceExpression(ExpressionT expression); |
+ |
// Used to validate property names in object literals and class literals |
enum PropertyKind { |
kAccessorProperty, |
@@ -843,6 +873,7 @@ class ParserBase : public Traits { |
bool allow_harmony_default_parameters_; |
bool allow_harmony_spread_calls_; |
bool allow_harmony_destructuring_; |
+ bool allow_harmony_destructuring_assignment_; |
bool allow_harmony_spread_arrays_; |
bool allow_harmony_new_target_; |
bool allow_strong_mode_; |
@@ -957,6 +988,17 @@ class PreParserExpression { |
right->IsSpreadExpression())); |
} |
+ static PreParserExpression Assignment() { |
+ return PreParserExpression(TypeField::encode(kAssignmentExpression)); |
+ } |
+ |
+ static PreParserExpression ObjectLiteral( |
+ bool has_cover_initialized_name = false) { |
+ return PreParserExpression( |
+ TypeField::encode(kObjectLiteralExpression) | |
+ HasCoverInitializedNameField::encode(has_cover_initialized_name)); |
+ } |
+ |
static PreParserExpression StringLiteral() { |
return PreParserExpression(TypeField::encode(kStringLiteralExpression)); |
} |
@@ -1005,6 +1047,10 @@ class PreParserExpression { |
ExpressionTypeField::encode(kNoTemplateTagExpression)); |
} |
+ bool IsAssignment() const { |
+ return TypeField::decode(code_) == kAssignmentExpression; |
+ } |
+ |
bool IsIdentifier() const { |
return TypeField::decode(code_) == kIdentifierExpression; |
} |
@@ -1014,6 +1060,19 @@ class PreParserExpression { |
return PreParserIdentifier(IdentifierTypeField::decode(code_)); |
} |
+ PreParserExpression AsObjectLiteral() const { |
+ DCHECK(IsObjectLiteral()); |
+ return *this; |
+ } |
+ |
+ bool IsObjectLiteral() const { |
+ return TypeField::decode(code_) == kObjectLiteralExpression; |
+ } |
+ |
+ bool IsArrayLiteral() const { |
+ return TypeField::decode(code_) == kObjectLiteralExpression; |
+ } |
+ |
bool IsStringLiteral() const { |
return TypeField::decode(code_) == kStringLiteralExpression; |
} |
@@ -1102,7 +1161,9 @@ class PreParserExpression { |
kIdentifierExpression, |
kStringLiteralExpression, |
kBinaryOperationExpression, |
- kSpreadExpression |
+ kSpreadExpression, |
+ kObjectLiteralExpression, |
+ kAssignmentExpression |
}; |
enum ExpressionType { |
@@ -1128,6 +1189,7 @@ class PreParserExpression { |
typedef BitField<PreParserIdentifier::Type, TypeField::kNext, 10> |
IdentifierTypeField; |
typedef BitField<bool, TypeField::kNext, 1> HasRestField; |
+ typedef BitField<bool, TypeField::kNext, 1> HasCoverInitializedNameField; |
uint32_t code_; |
}; |
@@ -1240,12 +1302,12 @@ class PreParserFactory { |
int literal_index, |
bool is_strong, |
int pos) { |
- return PreParserExpression::Default(); |
+ return PreParserExpression::ObjectLiteral(); |
} |
PreParserExpression NewArrayLiteral(PreParserExpressionList values, |
int first_spread_index, int literal_index, |
bool is_strong, int pos) { |
- return PreParserExpression::Default(); |
+ return PreParserExpression::ObjectLiteral(); |
} |
PreParserExpression NewObjectLiteralProperty(PreParserExpression key, |
PreParserExpression value, |
@@ -1266,7 +1328,7 @@ class PreParserFactory { |
bool has_function, |
bool is_strong, |
int pos) { |
- return PreParserExpression::Default(); |
+ return PreParserExpression::ObjectLiteral(); |
} |
PreParserExpression NewVariableProxy(void* variable) { |
return PreParserExpression::Default(); |
@@ -1298,7 +1360,7 @@ class PreParserFactory { |
PreParserExpression left, |
PreParserExpression right, |
int pos) { |
- return PreParserExpression::Default(); |
+ return PreParserExpression::Assignment(); |
} |
PreParserExpression NewYield(PreParserExpression generator_object, |
PreParserExpression expression, |
@@ -1730,6 +1792,11 @@ class PreParserTraits { |
PreParserExpressionList args, |
int pos); |
+ inline PreParserExpression RewriteDestructuringAssignmentExpression( |
+ PreParserExpression expr) { |
+ return expr; |
+ } |
+ |
private: |
PreParser* pre_parser_; |
}; |
@@ -2375,8 +2442,17 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier, |
// Heuristically try to detect immediately called functions before |
// seeing the call parentheses. |
parenthesized_function_ = (peek() == Token::FUNCTION); |
- result = this->ParseExpression(true, classifier, CHECK_OK); |
+ result = this->ParseExpression(true, kMaybeBindingPattern, classifier, |
+ CHECK_OK); |
Expect(Token::RPAREN, CHECK_OK); |
+ |
+ if (peek() != Token::ARROW) { |
+ if (allow_harmony_destructuring_assignment()) { |
+ ValidateAssignmentPattern(classifier, CHECK_OK); |
+ } else { |
+ ValidateExpression(classifier, CHECK_OK); |
+ } |
+ } |
} |
break; |
@@ -2450,17 +2526,26 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression( |
} |
-// Precedence = 1 |
template <class Traits> |
typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression( |
bool accept_IN, ExpressionClassifier* classifier, bool* ok) { |
+ ExpressionT result = ParseExpression(accept_IN, 0, classifier, CHECK_OK); |
+ return result; |
+} |
+ |
+ |
+// Precedence = 1 |
+template <class Traits> |
+typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression( |
+ bool accept_IN, int flags, ExpressionClassifier* classifier, bool* ok) { |
// Expression :: |
// AssignmentExpression |
// Expression ',' AssignmentExpression |
ExpressionClassifier binding_classifier; |
- ExpressionT result = |
- this->ParseAssignmentExpression(accept_IN, &binding_classifier, CHECK_OK); |
+ bool seen_destructuring = false; |
+ ExpressionT result = this->ParseAssignmentExpression( |
+ accept_IN, flags, &seen_destructuring, &binding_classifier, CHECK_OK); |
classifier->Accumulate(binding_classifier, |
ExpressionClassifier::AllProductions); |
bool is_simple_parameter_list = this->IsIdentifier(result); |
@@ -2485,7 +2570,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression( |
} |
int pos = position(); |
ExpressionT right = this->ParseAssignmentExpression( |
- accept_IN, &binding_classifier, CHECK_OK); |
+ accept_IN, flags, &seen_destructuring, &binding_classifier, CHECK_OK); |
if (is_rest) right = factory()->NewSpread(right, pos); |
is_simple_parameter_list = |
is_simple_parameter_list && this->IsIdentifier(right); |
@@ -2496,6 +2581,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression( |
if (!is_simple_parameter_list || seen_rest) { |
classifier->RecordNonSimpleParameter(); |
} |
+ |
return result; |
} |
@@ -2523,20 +2609,43 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral( |
} |
elem = this->GetLiteralTheHole(peek_position(), factory()); |
} else if (peek() == Token::ELLIPSIS) { |
- if (!allow_harmony_spread_arrays()) { |
+ if (!allow_harmony_spread_arrays() && !allow_harmony_destructuring() && |
+ !allow_harmony_destructuring_assignment()) { |
ExpressionUnexpectedToken(classifier); |
} |
int start_pos = peek_position(); |
Consume(Token::ELLIPSIS); |
ExpressionT argument = |
this->ParseAssignmentExpression(true, classifier, CHECK_OK); |
+ if ((argument->IsArrayLiteral() || argument->IsObjectLiteral()) && |
+ !classifier->is_valid_assignment_pattern()) { |
+ classifier->RecordPatternError( |
+ Scanner::Location(start_pos, scanner()->location().end_pos), |
+ MessageTemplate::kInvalidDestructuringTarget); |
+ } |
elem = factory()->NewSpread(argument, start_pos); |
seen_spread = true; |
if (first_spread_index < 0) { |
first_spread_index = values->length(); |
} |
+ if (argument->IsAssignment()) { |
+ classifier->RecordPatternError( |
+ Scanner::Location(start_pos, scanner()->location().end_pos), |
+ MessageTemplate::kInvalidRestInitializer); |
+ } else if (peek() == Token::COMMA) { |
+ classifier->RecordPatternError( |
+ Scanner::Location(start_pos, scanner()->location().end_pos), |
+ MessageTemplate::kElementAfterRest); |
+ } |
} else { |
- elem = this->ParseAssignmentExpression(true, classifier, CHECK_OK); |
+ elem = this->ParseAssignmentExpression(true, kIsPatternElement, |
+ classifier, CHECK_OK); |
+ if (!this->IsValidReferenceExpression(elem) && |
+ !classifier->is_valid_assignment_pattern()) { |
+ classifier->RecordPatternError( |
+ Scanner::Location(pos, scanner()->location().end_pos), |
+ MessageTemplate::kInvalidDestructuringTarget); |
+ } |
} |
values->Add(elem, zone_); |
if (peek() != Token::RBRACK) { |
@@ -2652,8 +2761,18 @@ ParserBase<Traits>::ParsePropertyDefinition( |
CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
} |
Consume(Token::COLON); |
+ int pos = peek_position(); |
value = this->ParseAssignmentExpression( |
- true, classifier, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
+ true, kIsPatternElement, classifier, |
+ CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
+ |
+ if (!this->IsValidReferenceExpression(value) && |
+ !classifier->is_valid_assignment_pattern()) { |
+ classifier->RecordPatternError( |
+ Scanner::Location(pos, scanner()->location().end_pos), |
+ MessageTemplate::kInvalidDestructuringTarget); |
+ } |
+ |
return factory()->NewObjectLiteralProperty(name_expression, value, false, |
*is_computed_name); |
} |
@@ -2681,15 +2800,18 @@ ParserBase<Traits>::ParsePropertyDefinition( |
name, next_beg_pos, next_end_pos, scope_, factory()); |
if (peek() == Token::ASSIGN) { |
- this->ExpressionUnexpectedToken(classifier); |
Consume(Token::ASSIGN); |
ExpressionClassifier rhs_classifier; |
ExpressionT rhs = this->ParseAssignmentExpression( |
- true, &rhs_classifier, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
+ true, kIsRightHandSide, &rhs_classifier, |
+ CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); |
classifier->Accumulate(rhs_classifier, |
ExpressionClassifier::ExpressionProductions); |
value = factory()->NewAssignment(Token::ASSIGN, lhs, rhs, |
RelocInfo::kNoPosition); |
+ classifier->RecordCoverInitializedNameError( |
+ Scanner::Location(next_beg_pos, scanner()->location().end_pos), |
+ MessageTemplate::kInvalidCoverInitializedName); |
} else { |
value = lhs; |
} |
@@ -2700,6 +2822,11 @@ ParserBase<Traits>::ParsePropertyDefinition( |
} |
} |
+ // Method definitions are never valid in patterns. |
+ classifier->RecordPatternError( |
+ Scanner::Location(next_beg_pos, scanner()->location().end_pos), |
+ MessageTemplate::kInvalidDestructuringTarget); |
+ |
if (is_generator || peek() == Token::LPAREN) { |
// MethodDefinition |
@@ -2925,7 +3052,8 @@ typename Traits::Type::ExpressionList ParserBase<Traits>::ParseArguments( |
// Precedence = 2 |
template <class Traits> |
typename ParserBase<Traits>::ExpressionT |
-ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, |
+ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, int flags, |
+ bool* seen_destructuring, |
ExpressionClassifier* classifier, |
bool* ok) { |
// AssignmentExpression :: |
@@ -2935,6 +3063,12 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, |
// LeftHandSideExpression AssignmentOperator AssignmentExpression |
int lhs_beg_pos = peek_position(); |
+ bool is_rhs = flags & kIsRightHandSide; |
+ bool is_pattern_element = flags & kIsPatternElement; |
+ bool maybe_binding_pattern = flags & kMaybeBindingPattern; |
+ USE(maybe_binding_pattern); |
+ flags = |
+ flags & ~(kIsPatternElement | kMaybeBindingPattern) | kIsRightHandSide; |
if (peek() == Token::YIELD && is_generator()) { |
return this->ParseYieldExpression(classifier, ok); |
@@ -2975,18 +3109,37 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, |
} |
expression = this->ParseArrowFunctionLiteral( |
accept_IN, parameters, arrow_formals_classifier, CHECK_OK); |
+ if (is_pattern_element) { |
+ classifier->RecordPatternError( |
+ Scanner::Location(lhs_beg_pos, scanner()->location().end_pos), |
+ MessageTemplate::kInvalidDestructuringTarget); |
+ } |
return expression; |
} |
// "expression" was not itself an arrow function parameter list, but it might |
// form part of one. Propagate speculative formal parameter error locations. |
- classifier->Accumulate(arrow_formals_classifier, |
- ExpressionClassifier::StandardProductions | |
- ExpressionClassifier::FormalParametersProductions); |
+ classifier->Accumulate( |
+ arrow_formals_classifier, |
+ ExpressionClassifier::StandardProductions | |
+ ExpressionClassifier::FormalParametersProductions | |
+ ExpressionClassifier::CoverInitializedNameProduction); |
+ |
+ bool maybe_pattern = |
+ expression->IsObjectLiteral() || expression->IsArrayLiteral(); |
if (!Token::IsAssignmentOp(peek())) { |
if (fni_ != NULL) fni_->Leave(); |
// Parsed conditional expression only (no assignment). |
+ if (is_pattern_element && !this->IsValidReferenceExpression(expression) && |
+ !maybe_pattern) { |
+ classifier->RecordPatternError( |
+ Scanner::Location(lhs_beg_pos, scanner()->location().end_pos), |
+ MessageTemplate::kInvalidDestructuringTarget); |
+ } else if (is_rhs && !is_pattern_element && maybe_pattern) { |
+ ValidateExpression(classifier, CHECK_OK); |
+ } |
+ |
return expression; |
} |
@@ -2994,9 +3147,22 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, |
BindingPatternUnexpectedToken(classifier); |
} |
- expression = this->CheckAndRewriteReferenceExpression( |
- expression, lhs_beg_pos, scanner()->location().end_pos, |
- MessageTemplate::kInvalidLhsInAssignment, CHECK_OK); |
+ bool maybe_destructuring_assignment = |
+ allow_harmony_destructuring_assignment() && maybe_pattern && |
+ peek() == Token::ASSIGN; |
+ bool maybe_destructuring_binding = allow_harmony_destructuring() && |
+ maybe_pattern && !is_rhs && |
+ peek() == Token::ASSIGN; |
+ |
+ if (maybe_destructuring_assignment) { |
+ classifier->ForgiveCoverInitializedNameError(); |
+ ValidateAssignmentPattern(classifier, CHECK_OK); |
+ if (!is_pattern_element) *seen_destructuring = true; |
+ } else if (!maybe_destructuring_binding) { |
+ expression = this->CheckAndRewriteReferenceExpression( |
+ expression, lhs_beg_pos, scanner()->location().end_pos, |
+ MessageTemplate::kInvalidLhsInAssignment, CHECK_OK); |
+ } |
expression = this->MarkExpressionAsAssigned(expression); |
Token::Value op = Next(); // Get assignment operator. |
@@ -3008,10 +3174,11 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, |
int pos = position(); |
ExpressionClassifier rhs_classifier; |
- ExpressionT right = |
- this->ParseAssignmentExpression(accept_IN, &rhs_classifier, CHECK_OK); |
- classifier->Accumulate(rhs_classifier, |
- ExpressionClassifier::ExpressionProductions); |
+ ExpressionT right = this->ParseAssignmentExpression( |
+ accept_IN, flags, seen_destructuring, &rhs_classifier, CHECK_OK); |
+ classifier->Accumulate( |
+ rhs_classifier, ExpressionClassifier::ExpressionProductions | |
+ ExpressionClassifier::CoverInitializedNameProduction); |
// TODO(1231235): We try to estimate the set of properties set by |
// constructors. We define a new property whenever there is an |
@@ -3039,7 +3206,14 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, |
fni_->Leave(); |
} |
- return factory()->NewAssignment(op, expression, right, pos); |
+ ExpressionT result = factory()->NewAssignment(op, expression, right, pos); |
+ |
+ if (!is_rhs && *seen_destructuring && !maybe_binding_pattern && |
+ !is_pattern_element) { |
+ return Traits::RewriteDestructuringAssignmentExpression(result); |
+ } |
+ |
+ return result; |
} |
template <class Traits> |
@@ -4160,6 +4334,26 @@ ParserBase<Traits>::CheckAndRewriteReferenceExpression( |
} |
+template <typename Traits> |
+bool ParserBase<Traits>::IsValidReferenceExpression(ExpressionT expression) { |
+ // TODO(caitp): do this in a less redundant way :( |
+ if (expression->IsValidReferenceExpression()) { |
+ if (this->IsIdentifier(expression)) { |
+ if (is_strict(language_mode()) && |
+ this->IsEvalOrArguments(this->AsIdentifier(expression))) { |
+ return false; |
+ } |
+ if (is_strong(language_mode()) && |
+ this->IsUndefined(this->AsIdentifier(expression))) { |
+ return false; |
+ } |
+ } |
+ return true; |
+ } |
+ return false; |
+} |
+ |
+ |
#undef CHECK_OK |
#undef CHECK_OK_CUSTOM |