Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1677)

Unified Diff: src/preparser.h

Issue 1411203002: [es6] implement destructuring assignment [clean diff] (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: rename `recorded_first()` to `FirstRecorded()` because non-accessor Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/parser.cc ('k') | test/cctest/test-parsing.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « src/parser.cc ('k') | test/cctest/test-parsing.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698