Index: src/preparser.h |
diff --git a/src/preparser.h b/src/preparser.h |
index 17f55b9e385acc33c8819eba859b1800781e8ccb..2bd28035472c028f9ed2491687ada570f4ab05a6 100644 |
--- a/src/preparser.h |
+++ b/src/preparser.h |
@@ -114,6 +114,7 @@ class ParserBase : public Traits { |
allow_harmony_rest_parameters_(false), |
allow_harmony_default_parameters_(false), |
allow_harmony_destructuring_(false), |
+ allow_harmony_destructuring_assignment_(false), |
allow_strong_mode_(false), |
allow_legacy_const_(true), |
allow_harmony_do_expressions_(false) {} |
@@ -130,6 +131,7 @@ class ParserBase : public Traits { |
ALLOW_ACCESSORS(harmony_rest_parameters); |
ALLOW_ACCESSORS(harmony_default_parameters); |
ALLOW_ACCESSORS(harmony_destructuring); |
+ ALLOW_ACCESSORS(harmony_destructuring_assignment); |
ALLOW_ACCESSORS(strong_mode); |
ALLOW_ACCESSORS(legacy_const); |
ALLOW_ACCESSORS(harmony_do_expressions); |
@@ -175,6 +177,15 @@ class ParserBase : public Traits { |
Scope* outer_scope_; |
}; |
+ struct DestructuringAssignment { |
+ public: |
+ DestructuringAssignment(ExpressionT expression, Scope* scope) |
+ : assignment(expression), scope(scope) {} |
+ |
+ ExpressionT assignment; |
+ Scope* scope; |
+ }; |
+ |
class FunctionState BASE_EMBEDDED { |
public: |
FunctionState(FunctionState** function_state_stack, Scope** scope_stack, |
@@ -227,6 +238,15 @@ class ParserBase : public Traits { |
typename Traits::Type::Factory* factory() { return factory_; } |
+ const List<DestructuringAssignment>& destructuring_assignments_to_rewrite() |
+ const { |
+ return destructuring_assignments_to_rewrite_; |
+ } |
+ |
+ void AddDestructuringAssignment(DestructuringAssignment pair) { |
+ destructuring_assignments_to_rewrite_.Add(pair); |
+ } |
+ |
private: |
// Used to assign an index to each literal that needs materialization in |
// the function. Includes regexp literals, and boilerplate for object and |
@@ -255,6 +275,11 @@ class ParserBase : public Traits { |
FunctionState* outer_function_state_; |
Scope** scope_stack_; |
Scope* outer_scope_; |
+ |
+ List<DestructuringAssignment> destructuring_assignments_to_rewrite_; |
adamk
2015/11/20 22:42:59
Why does ParserBase need this List? Couldn't it ju
|
+ |
+ void RewriteDestructuringAssignments(); |
+ |
typename Traits::Type::Factory* factory_; |
friend class ParserTraits; |
@@ -460,6 +485,10 @@ class ParserBase : public Traits { |
ok); |
} |
+ void CheckDestructuringElement(ExpressionT element, |
+ ExpressionClassifier* classifier, int beg_pos, |
+ int end_pos); |
+ |
// Checking the name of a function literal. This has to be done after parsing |
// the function, since the function can declare itself strict. |
void CheckFunctionName(LanguageMode language_mode, IdentifierT function_name, |
@@ -542,8 +571,16 @@ 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()) { |
+ const Scanner::Location& a = classifier->expression_error().location; |
+ const Scanner::Location& b = |
+ classifier->cover_initialized_name_error().location; |
+ if (a.beg_pos < 0 || (b.beg_pos >= 0 && a.beg_pos > b.beg_pos)) { |
+ ReportClassifierError(classifier->cover_initialized_name_error()); |
+ } else { |
+ ReportClassifierError(classifier->expression_error()); |
+ } |
*ok = false; |
} |
} |
@@ -693,9 +730,22 @@ class ParserBase : public Traits { |
typename Traits::Type::ExpressionList ParseArguments( |
Scanner::Location* first_spread_pos, ExpressionClassifier* classifier, |
bool* ok); |
- ExpressionT ParseAssignmentExpression(bool accept_IN, |
+ |
+ enum AssignmentExpressionFlags { |
+ kIsLeftHandSide = 0, |
+ kIsRightHandSide = 1 << 0, |
+ kIsPatternElement = 1 << 1 |
+ }; |
+ |
+ ExpressionT ParseAssignmentExpression(bool accept_IN, int flags, |
ExpressionClassifier* classifier, |
bool* ok); |
+ ExpressionT ParseAssignmentExpression(bool accept_IN, |
+ ExpressionClassifier* classifier, |
+ bool* ok) { |
+ return ParseAssignmentExpression(accept_IN, kIsLeftHandSide, classifier, |
+ ok); |
+ } |
ExpressionT ParseYieldExpression(ExpressionClassifier* classifier, bool* ok); |
ExpressionT ParseConditionalExpression(bool accept_IN, |
ExpressionClassifier* classifier, |
@@ -747,6 +797,21 @@ class ParserBase : public Traits { |
ExpressionT expression, int beg_pos, int end_pos, |
MessageTemplate::Template message, ParseErrorType type, bool* ok); |
+ bool IsValidReferenceExpression(ExpressionT expression); |
+ |
+ bool IsAssignableIdentifier(ExpressionT expression) { |
+ if (!Traits::IsIdentifier(expression)) return false; |
+ if (is_strict(language_mode()) && |
+ Traits::IsEvalOrArguments(Traits::AsIdentifier(expression))) { |
+ return false; |
+ } |
+ if (is_strong(language_mode()) && |
+ Traits::IsUndefined(Traits::AsIdentifier(expression))) { |
+ return false; |
+ } |
+ return true; |
+ } |
+ |
// Used to validate property names in object literals and class literals |
enum PropertyKind { |
kAccessorProperty, |
@@ -835,6 +900,7 @@ class ParserBase : public Traits { |
bool allow_harmony_rest_parameters_; |
bool allow_harmony_default_parameters_; |
bool allow_harmony_destructuring_; |
+ bool allow_harmony_destructuring_assignment_; |
bool allow_strong_mode_; |
bool allow_legacy_const_; |
bool allow_harmony_do_expressions_; |
@@ -947,6 +1013,11 @@ class PreParserExpression { |
right->IsSpreadExpression())); |
} |
+ static PreParserExpression AssignmentPattern() { |
+ return PreParserExpression(TypeField::encode(kExpression) | |
+ ExpressionTypeField::encode(kAssignmentPattern)); |
+ } |
+ |
static PreParserExpression ObjectLiteral() { |
return PreParserExpression(TypeField::encode(kObjectLiteralExpression)); |
} |
@@ -1012,6 +1083,11 @@ class PreParserExpression { |
return PreParserIdentifier(IdentifierTypeField::decode(code_)); |
} |
+ bool IsAssignmentPattern() const { |
+ return TypeField::decode(code_) == kExpression && |
+ ExpressionTypeField::decode(code_) == kAssignmentPattern; |
+ } |
+ |
bool IsObjectLiteral() const { |
return TypeField::decode(code_) == kObjectLiteralExpression; |
} |
@@ -1119,7 +1195,8 @@ class PreParserExpression { |
kPropertyExpression, |
kCallExpression, |
kSuperCallReference, |
- kNoTemplateTagExpression |
+ kNoTemplateTagExpression, |
+ kAssignmentPattern |
}; |
explicit PreParserExpression(uint32_t expression_code) |
@@ -1136,6 +1213,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_; |
}; |
@@ -1308,6 +1386,11 @@ class PreParserFactory { |
int pos) { |
return PreParserExpression::Default(); |
} |
+ PreParserExpression NewAssignmentPattern(PreParserExpression pattern, |
+ int pos) { |
+ DCHECK(pattern->IsObjectLiteral() || pattern->IsArrayLiteral()); |
+ return PreParserExpression::AssignmentPattern(); |
+ } |
PreParserExpression NewYield(PreParserExpression generator_object, |
PreParserExpression expression, |
Yield::Kind yield_kind, |
@@ -1738,6 +1821,15 @@ class PreParserTraits { |
PreParserExpressionList args, |
int pos); |
+ inline PreParserExpression RewriteDestructuringAssignmentExpression( |
+ PreParserExpression expr) { |
+ return expr; |
+ } |
+ |
+ inline void RewriteDestructuringAssignments() {} |
+ |
+ inline void ShouldRewriteDestructuringAssignment(PreParserExpression) {} |
+ |
private: |
PreParser* pre_parser_; |
}; |
@@ -2369,6 +2461,9 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier, |
parenthesized_function_ = (peek() == Token::FUNCTION); |
ExpressionT expr = this->ParseExpression(true, classifier, CHECK_OK); |
Expect(Token::RPAREN, CHECK_OK); |
+ if (peek() != Token::ARROW) { |
+ ValidateExpression(classifier, CHECK_OK); |
+ } |
return expr; |
} |
@@ -2436,7 +2531,6 @@ 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) { |
@@ -2482,6 +2576,7 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression( |
if (!is_simple_parameter_list || seen_rest) { |
classifier->RecordNonSimpleParameter(); |
} |
+ |
return result; |
} |
@@ -2518,14 +2613,27 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral( |
if (first_spread_index < 0) { |
first_spread_index = values->length(); |
} |
+ |
+ CheckDestructuringElement(argument, classifier, start_pos, |
+ scanner()->location().end_pos); |
+ |
+ 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) { |
- if (seen_spread) { |
- BindingPatternUnexpectedToken(classifier); |
- } |
Expect(Token::COMMA, CHECK_OK); |
} |
} |
@@ -2635,8 +2743,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); |
} |
@@ -2664,7 +2782,6 @@ 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( |
@@ -2673,6 +2790,9 @@ ParserBase<Traits>::ParsePropertyDefinition( |
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; |
} |
@@ -2683,6 +2803,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 |
@@ -2906,7 +3031,7 @@ 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, |
ExpressionClassifier* classifier, |
bool* ok) { |
// AssignmentExpression :: |
@@ -2914,7 +3039,8 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, |
// ArrowFunction |
// YieldExpression |
// LeftHandSideExpression AssignmentOperator AssignmentExpression |
- |
+ bool is_rhs = flags & kIsRightHandSide; |
+ bool is_pattern_element = flags & kIsPatternElement; |
int lhs_beg_pos = peek_position(); |
if (peek() == Token::YIELD && is_generator()) { |
@@ -2960,18 +3086,43 @@ 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; |
} |
+ if (this->IsValidReferenceExpression(expression)) { |
+ arrow_formals_classifier.ForgiveAssignmentPatternError(); |
+ } |
+ |
// "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(); |
+ bool binding_pattern = |
+ allow_harmony_destructuring() && maybe_pattern && !is_rhs; |
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 && maybe_pattern) { |
+ ValidateExpression(classifier, CHECK_OK); |
+ } |
+ |
return expression; |
} |
@@ -2979,9 +3130,17 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, |
BindingPatternUnexpectedToken(classifier); |
} |
- expression = this->CheckAndRewriteReferenceExpression( |
- expression, lhs_beg_pos, scanner()->location().end_pos, |
- MessageTemplate::kInvalidLhsInAssignment, CHECK_OK); |
+ if (allow_harmony_destructuring_assignment() && maybe_pattern && |
+ peek() == Token::ASSIGN) { |
+ classifier->ForgiveCoverInitializedNameError(); |
+ ValidateAssignmentPattern(classifier, CHECK_OK); |
+ expression = factory()->NewAssignmentPattern(expression, lhs_beg_pos); |
+ } else if (!binding_pattern) { |
+ 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. |
@@ -2993,10 +3152,15 @@ 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); |
+ |
+ int rhs_flags = flags; |
+ rhs_flags &= ~kIsPatternElement; |
+ rhs_flags |= kIsRightHandSide; |
+ ExpressionT right = this->ParseAssignmentExpression( |
+ accept_IN, rhs_flags, &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 |
@@ -3024,7 +3188,13 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, |
fni_->Leave(); |
} |
- return factory()->NewAssignment(op, expression, right, pos); |
+ ExpressionT result = factory()->NewAssignment(op, expression, right, pos); |
+ |
+ if (expression->IsAssignmentPattern()) { |
+ Traits::ShouldRewriteDestructuringAssignment(result); |
+ } |
+ |
+ return result; |
} |
template <class Traits> |
@@ -3981,6 +4151,8 @@ ParserBase<Traits>::ParseArrowFunctionLiteral( |
if (is_strict(language_mode()) || allow_harmony_sloppy()) { |
this->CheckConflictingVarDeclarations(formal_parameters.scope, CHECK_OK); |
} |
+ |
+ Traits::RewriteDestructuringAssignments(); |
} |
FunctionLiteralT function_literal = factory()->NewFunctionLiteral( |
@@ -4129,7 +4301,8 @@ ParserBase<Traits>::CheckAndRewriteReferenceExpression( |
return this->EmptyExpression(); |
} |
} |
- if (expression->IsValidReferenceExpression()) { |
+ if (expression->IsValidReferenceExpression() || |
+ expression->IsAssignmentPattern()) { |
return expression; |
} else if (expression->IsCall()) { |
// If it is a call, make it a runtime error for legacy web compatibility. |
@@ -4145,6 +4318,28 @@ ParserBase<Traits>::CheckAndRewriteReferenceExpression( |
} |
+template <typename Traits> |
+bool ParserBase<Traits>::IsValidReferenceExpression(ExpressionT expression) { |
+ return this->IsAssignableIdentifier(expression) || expression->IsProperty(); |
+} |
+ |
+ |
+template <typename Traits> |
+void ParserBase<Traits>::CheckDestructuringElement( |
+ ExpressionT expression, ExpressionClassifier* classifier, int begin, |
+ int end) { |
+ static const MessageTemplate::Template message = |
+ MessageTemplate::kInvalidDestructuringTarget; |
+ if (!this->IsAssignableIdentifier(expression)) { |
+ const Scanner::Location location(begin, end); |
+ classifier->RecordBindingPatternError(location, message); |
+ if (!expression->IsProperty()) { |
+ classifier->RecordAssignmentPatternError(location, message); |
+ } |
+ } |
+} |
+ |
+ |
#undef CHECK_OK |
#undef CHECK_OK_CUSTOM |