 Chromium Code Reviews
 Chromium Code Reviews Issue 1168643005:
  [es6] parse destructuring assignment  (Closed) 
  Base URL: https://chromium.googlesource.com/v8/v8.git@master
    
  
    Issue 1168643005:
  [es6] parse destructuring assignment  (Closed) 
  Base URL: https://chromium.googlesource.com/v8/v8.git@master| Index: src/preparser.h | 
| diff --git a/src/preparser.h b/src/preparser.h | 
| index 862b7fb40dd894b53dfcec80d36aedde5b441e3f..23cc57d41bb2676773b3c109786e13e02f5f5333 100644 | 
| --- a/src/preparser.h | 
| +++ b/src/preparser.h | 
| @@ -504,6 +504,29 @@ class ParserBase : public Traits { | 
| void ReportUnexpectedToken(Token::Value token); | 
| void ReportUnexpectedTokenAt(Scanner::Location location, Token::Value token); | 
| + ExpressionT CheckDestructuringAssignment(ExpressionT expr, | 
| + ExpressionClassifier* classifier, | 
| + bool needs_destructuring, | 
| + unsigned flags, bool* ok) { | 
| + // Don't rewrite AssignmentElement or RHS | 
| + // An AssignmentElement's optional initializer is parsed as a separate | 
| + // assignment expression. | 
| + const bool rewrite = | 
| + !(flags & (ASSIGNMENT_RHS | ASSIGNMENT_ELEMENT)) && needs_destructuring; | 
| + if (classifier->is_destructuring_assignment()) { | 
| + if (!classifier->is_valid_assignment_pattern()) { | 
| + this->ReportClassifierError(classifier->assignment_pattern_error()); | 
| + *ok = false; | 
| + return this->EmptyExpression(); | 
| + } | 
| + } else if (flags & ~ASSIGNMENT_ELEMENT) { | 
| + // If not a destructuring assignment, expect an expression | 
| + ValidateExpression(classifier, ok); | 
| + if (!*ok) return this->EmptyExpression(); | 
| + } | 
| + if (rewrite) return Traits::RewriteDestructuringAssignment(expr, ok); | 
| + return expr; | 
| + } | 
| void ReportClassifierError(const ExpressionClassifier::Error& error) { | 
| Traits::ReportMessageAt(error.location, error.message, error.arg, | 
| @@ -579,6 +602,17 @@ class ParserBase : public Traits { | 
| Token::String(peek())); | 
| } | 
| + void AssignmentPatternUnexpectedToken(ExpressionClassifier* classifier) { | 
| + classifier->RecordAssignmentPatternError(scanner()->peek_location(), | 
| + MessageTemplate::kUnexpectedToken, | 
| + Token::String(peek())); | 
| + } | 
| + | 
| + void PatternUnexpectedToken(ExpressionClassifier* classifier) { | 
| + BindingPatternUnexpectedToken(classifier); | 
| + AssignmentPatternUnexpectedToken(classifier); | 
| + } | 
| + | 
| void ArrowFormalParametersUnexpectedToken(ExpressionClassifier* classifier) { | 
| classifier->RecordArrowFormalParametersError( | 
| scanner()->peek_location(), MessageTemplate::kUnexpectedToken, | 
| @@ -625,9 +659,32 @@ 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 { | 
| + ACCEPT_IN = 1 << 0, | 
| + ASSIGNMENT_RHS = 1 << 1, | 
| + ASSIGNMENT_ELEMENT = 1 << 2 | 
| + }; | 
| + ExpressionT ParseAssignmentExpression(unsigned flags, | 
| + bool* needs_destructuring, | 
| ExpressionClassifier* classifier, | 
| bool* ok); | 
| + ExpressionT ParseAssignmentExpression(bool accept_IN, | 
| + ExpressionClassifier* classifier, | 
| + bool* ok) { | 
| + // Overloaded for legacy compat | 
| + bool destructuring = false; | 
| + unsigned flags = accept_IN ? ACCEPT_IN : 0; | 
| + return ParseAssignmentExpression(flags, &destructuring, classifier, ok); | 
| + } | 
| + ExpressionT ParseAssignmentElement(bool accept_IN, | 
| + ExpressionClassifier* classifier, | 
| + bool* ok) { | 
| + // Don't automatically rewrite AssignmentExpressions which are meant to be | 
| + // AssignmentElements | 
| + bool destructuring = false; | 
| + unsigned flags = (accept_IN ? ACCEPT_IN : 0) | ASSIGNMENT_ELEMENT; | 
| + return ParseAssignmentExpression(flags, &destructuring, classifier, ok); | 
| + } | 
| ExpressionT ParseYieldExpression(ExpressionClassifier* classifier, bool* ok); | 
| ExpressionT ParseConditionalExpression(bool accept_IN, | 
| ExpressionClassifier* classifier, | 
| @@ -1586,6 +1643,11 @@ class PreParserTraits { | 
| PreParserExpressionList args, | 
| int pos); | 
| + inline PreParserExpression RewriteDestructuringAssignment( | 
| + PreParserExpression expr, bool* ok) { | 
| + return expr; | 
| + } | 
| + | 
| private: | 
| PreParser* pre_parser_; | 
| }; | 
| @@ -2060,6 +2122,8 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier, | 
| int end_pos = scanner()->peek_location().end_pos; | 
| ExpressionT result = this->EmptyExpression(); | 
| Token::Value token = peek(); | 
| + typename ExpressionClassifier::AssignmentTargetType lhs_part = | 
| + ExpressionClassifier::TARGET_PRIMARY; | 
| switch (token) { | 
| case Token::THIS: { | 
| BindingPatternUnexpectedToken(classifier); | 
| @@ -2100,6 +2164,7 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier, | 
| case Token::YIELD: | 
| case Token::FUTURE_STRICT_RESERVED_WORD: { | 
| // Using eval or arguments in this context is OK even in strict mode. | 
| + lhs_part = ExpressionClassifier::TARGET_IDENTIFIER; | 
| IdentifierT name = ParseAndClassifyIdentifier(classifier, CHECK_OK); | 
| result = this->ExpressionFromIdentifier(name, beg_pos, end_pos, scope_, | 
| factory()); | 
| @@ -2181,6 +2246,7 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier, | 
| // Heuristically try to detect immediately called functions before | 
| // seeing the call parentheses. | 
| parenthesized_function_ = (peek() == Token::FUNCTION); | 
| + lhs_part = ExpressionClassifier::TARGET_NONE; | 
| result = this->ParseExpression(true, classifier, CHECK_OK); | 
| Expect(Token::RPAREN, CHECK_OK); | 
| } | 
| @@ -2218,6 +2284,7 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier, | 
| case Token::MOD: | 
| if (allow_natives() || extension_ != NULL) { | 
| result = this->ParseV8Intrinsic(CHECK_OK); | 
| + lhs_part = ExpressionClassifier::TARGET_CALL; | 
| break; | 
| } | 
| // If we're not allowing special syntax we fall-through to the | 
| @@ -2230,6 +2297,10 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier, | 
| } | 
| } | 
| + if (*ok && lhs_part != ExpressionClassifier::TARGET_NONE) { | 
| + classifier->AppendAssignmentTarget(lhs_part); | 
| + } | 
| + | 
| return result; | 
| } | 
| @@ -2252,13 +2323,19 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression( | 
| // AssignmentExpression | 
| // Expression ',' AssignmentExpression | 
| - ExpressionClassifier binding_classifier; | 
| + ExpressionClassifier expr_classifier; | 
| ExpressionT result = | 
| - this->ParseAssignmentExpression(accept_IN, &binding_classifier, CHECK_OK); | 
| - classifier->Accumulate(binding_classifier, | 
| - ExpressionClassifier::AllProductions); | 
| + this->ParseAssignmentExpression(accept_IN, &expr_classifier, CHECK_OK); | 
| + ExpressionClassifier::AssignmentTargetType lhs_type = | 
| + expr_classifier.AssignmentTarget(); | 
| + classifier->Accumulate(expr_classifier, | 
| + expr_classifier.is_destructuring_assignment() | 
| + ? ExpressionClassifier::PatternProductions | 
| + : ExpressionClassifier::AllProductions); | 
| bool seen_rest = false; | 
| while (peek() == Token::COMMA) { | 
| + ExpressionClassifier expr_classifier; | 
| + lhs_type = ExpressionClassifier::TARGET_PRIMARY; | 
| if (seen_rest) { | 
| // At this point the production can't possibly be valid, but we don't know | 
| // which error to signal. | 
| @@ -2277,13 +2354,17 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression( | 
| seen_rest = is_rest = true; | 
| } | 
| int pos = position(); | 
| - ExpressionT right = this->ParseAssignmentExpression( | 
| - accept_IN, &binding_classifier, CHECK_OK); | 
| + ExpressionT right = | 
| + this->ParseAssignmentExpression(accept_IN, &expr_classifier, CHECK_OK); | 
| if (is_rest) right = factory()->NewSpread(right, pos); | 
| - classifier->Accumulate(binding_classifier, | 
| - ExpressionClassifier::AllProductions); | 
| + classifier->Accumulate(expr_classifier, | 
| + expr_classifier.is_destructuring_assignment() | 
| + ? ExpressionClassifier::PatternProductions | 
| + : ExpressionClassifier::AllProductions); | 
| + | 
| result = factory()->NewBinaryOperation(Token::COMMA, result, right, pos); | 
| } | 
| + classifier->AppendAssignmentTarget(lhs_type); | 
| return result; | 
| } | 
| @@ -2301,6 +2382,9 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral( | 
| while (peek() != Token::RBRACK) { | 
| bool seen_spread = false; | 
| ExpressionT elem = this->EmptyExpression(); | 
| + ExpressionClassifier element_classifier; | 
| + bool accumulate_element = true; | 
| + int start_pos = peek_position(); | 
| if (peek() == Token::COMMA) { | 
| if (is_strong(language_mode())) { | 
| ReportMessageAt(scanner()->peek_location(), | 
| @@ -2309,23 +2393,40 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral( | 
| return this->EmptyExpression(); | 
| } | 
| elem = this->GetLiteralTheHole(peek_position(), factory()); | 
| + accumulate_element = false; | 
| } else if (peek() == Token::ELLIPSIS) { | 
| if (!allow_harmony_spread_arrays()) { | 
| ExpressionUnexpectedToken(classifier); | 
| } | 
| - int start_pos = peek_position(); | 
| Consume(Token::ELLIPSIS); | 
| ExpressionT argument = | 
| - this->ParseAssignmentExpression(true, classifier, CHECK_OK); | 
| + this->ParseAssignmentElement(true, &element_classifier, CHECK_OK); | 
| elem = factory()->NewSpread(argument, start_pos); | 
| seen_spread = true; | 
| + | 
| + // AssignmentRestElements may not have initializers | 
| + if (element_classifier.IsAssigned()) { | 
| + Scanner::Location location(start_pos, scanner()->location().end_pos); | 
| + classifier->RecordAssignmentPatternError( | 
| + location, MessageTemplate::kInitializedAssignmentRestElement); | 
| + } | 
| } else { | 
| - elem = this->ParseAssignmentExpression(true, classifier, CHECK_OK); | 
| + elem = this->ParseAssignmentElement(true, &element_classifier, CHECK_OK); | 
| } | 
| + if (accumulate_element) { | 
| + if (!element_classifier.IsValidSimpleAssignmentTarget() && | 
| + !element_classifier.IsValidPattern()) { | 
| + Scanner::Location location(start_pos, scanner()->location().end_pos); | 
| + classifier->RecordAssignmentPatternError( | 
| + location, MessageTemplate::kInvalidDestructuringAssignmentTarget); | 
| + } | 
| + classifier->Accumulate(element_classifier); | 
| + } | 
| + | 
| values->Add(elem, zone_); | 
| if (peek() != Token::RBRACK) { | 
| if (seen_spread) { | 
| - BindingPatternUnexpectedToken(classifier); | 
| + PatternUnexpectedToken(classifier); | 
| } | 
| Expect(Token::COMMA, CHECK_OK); | 
| } | 
| @@ -2414,13 +2515,16 @@ ParserBase<Traits>::ParsePropertyDefinition( | 
| bool is_set = false; | 
| bool name_is_static = false; | 
| bool is_generator = allow_harmony_object_literals_ && Check(Token::MUL); | 
| - | 
| + // Classify destructuring assignment target for ObjectAssignmentPattern | 
| + ExpressionClassifier property_classifier; | 
| Token::Value name_token = peek(); | 
| int next_beg_pos = scanner()->peek_location().beg_pos; | 
| int next_end_pos = scanner()->peek_location().end_pos; | 
| + int value_start = next_beg_pos; | 
| + int value_end = next_end_pos; | 
| ExpressionT name_expression = ParsePropertyName( | 
| - &name, &is_get, &is_set, &name_is_static, is_computed_name, classifier, | 
| - CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); | 
| + &name, &is_get, &is_set, &name_is_static, is_computed_name, | 
| + &property_classifier, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); | 
| if (fni_ != nullptr && !*is_computed_name) { | 
| this->PushLiteralName(fni_, name); | 
| @@ -2434,12 +2538,16 @@ ParserBase<Traits>::ParsePropertyDefinition( | 
| CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); | 
| } | 
| Consume(Token::COLON); | 
| - value = this->ParseAssignmentExpression( | 
| - true, classifier, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); | 
| - | 
| + property_classifier = ExpressionClassifier(); | 
| + value_start = peek_position(); | 
| + value = this->ParseAssignmentElement( | 
| + true, &property_classifier, | 
| + CHECK_OK_CUSTOM(EmptyObjectLiteralProperty)); | 
| + value_end = scanner()->location().end_pos; | 
| } else if (is_generator || | 
| (allow_harmony_object_literals_ && peek() == Token::LPAREN)) { | 
| // Concise Method | 
| + property_classifier.ReportInvalidSimpleAssignmentTarget(); | 
| if (!*is_computed_name) { | 
| checker->CheckProperty(name_token, kMethodProperty, is_static, | 
| is_generator, | 
| @@ -2470,10 +2578,12 @@ ParserBase<Traits>::ParsePropertyDefinition( | 
| } else if (in_class && name_is_static && !is_static) { | 
| // static MethodDefinition | 
| + property_classifier.ReportInvalidSimpleAssignmentTarget(); | 
| return ParsePropertyDefinition(checker, true, has_extends, true, | 
| is_computed_name, nullptr, classifier, ok); | 
| } else if (is_get || is_set) { | 
| // Accessor | 
| + property_classifier.ReportInvalidSimpleAssignmentTarget(); | 
| name = this->EmptyIdentifier(); | 
| bool dont_care = false; | 
| name_token = peek(); | 
| @@ -2505,6 +2615,11 @@ ParserBase<Traits>::ParsePropertyDefinition( | 
| factory()->NewStringLiteral(name, name_expression->position()); | 
| } | 
| + value_end = scanner()->location().end_pos; | 
| + Scanner::Location location(value_start, value_end); | 
| + classifier->RecordAssignmentPatternError( | 
| + location, MessageTemplate::kInvalidDestructuringAssignmentTarget); | 
| + | 
| return factory()->NewObjectLiteralProperty( | 
| name_expression, value, | 
| is_get ? ObjectLiteralProperty::GETTER : ObjectLiteralProperty::SETTER, | 
| @@ -2540,6 +2655,14 @@ ParserBase<Traits>::ParsePropertyDefinition( | 
| return this->EmptyObjectLiteralProperty(); | 
| } | 
| + if (!property_classifier.IsValidSimpleAssignmentTarget() && | 
| + !property_classifier.IsPatternAssignmentElement()) { | 
| + Scanner::Location location(value_start, value_end); | 
| + classifier->RecordAssignmentPatternError( | 
| + location, MessageTemplate::kInvalidDestructuringAssignmentTarget); | 
| + } | 
| + classifier->Accumulate(property_classifier); | 
| + | 
| return factory()->NewObjectLiteralProperty(name_expression, value, is_static, | 
| *is_computed_name); | 
| } | 
| @@ -2682,7 +2805,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(unsigned flags, | 
| + bool* needs_destructuring, | 
| ExpressionClassifier* classifier, | 
| bool* ok) { | 
| // AssignmentExpression :: | 
| @@ -2690,6 +2814,8 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, | 
| // ArrowFunction | 
| // YieldExpression | 
| // LeftHandSideExpression AssignmentOperator AssignmentExpression | 
| + bool accept_IN = flags & ACCEPT_IN; | 
| + bool is_assignment_element = flags & ASSIGNMENT_ELEMENT; | 
| Scanner::Location lhs_location = scanner()->peek_location(); | 
| @@ -2697,6 +2823,11 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, | 
| return this->ParseYieldExpression(classifier, ok); | 
| } | 
| + bool maybe_assignment_pattern = | 
| + allow_harmony_destructuring() && | 
| + classifier->is_valid_assignment_pattern() && | 
| + (peek() == Token::LBRACK || peek() == Token::LBRACE); | 
| + | 
| if (fni_ != NULL) fni_->Enter(); | 
| ParserBase<Traits>::Checkpoint checkpoint(this); | 
| ExpressionClassifier arrow_formals_classifier; | 
| @@ -2708,9 +2839,20 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, | 
| ExpressionT expression = this->ParseConditionalExpression( | 
| accept_IN, &arrow_formals_classifier, CHECK_OK); | 
| + if (!arrow_formals_classifier.is_valid_assignment_pattern()) { | 
| + if (maybe_assignment_pattern && peek() == Token::ASSIGN) { | 
| + // ObjectAssignmentPattern or ArrayAssignmentPattern contains an error | 
| + ReportClassifierError( | 
| + arrow_formals_classifier.assignment_pattern_error()); | 
| + *ok = false; | 
| + return this->EmptyExpression(); | 
| + } | 
| + } | 
| + | 
| if (allow_harmony_arrow_functions() && peek() == Token::ARROW) { | 
| checkpoint.Restore(); | 
| BindingPatternUnexpectedToken(classifier); | 
| + classifier->AppendAssignmentTarget(ExpressionClassifier::TARGET_PRIMARY); | 
| ValidateArrowFormalParameters(&arrow_formals_classifier, expression, | 
| CHECK_OK); | 
| Scanner::Location loc(lhs_location.beg_pos, scanner()->location().end_pos); | 
| @@ -2736,6 +2878,25 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, | 
| ExpressionClassifier::StandardProductions | | 
| ExpressionClassifier::FormalParametersProductions); | 
| + bool valid_destructuring_assignment_target = | 
| + arrow_formals_classifier.IsValidSimpleAssignmentTarget(); | 
| + if (valid_destructuring_assignment_target) { | 
| + classifier->AccumulateValidSimpleAssignmentTarget(arrow_formals_classifier); | 
| + } else if (!maybe_assignment_pattern || | 
| + !arrow_formals_classifier.is_valid_assignment_pattern()) { | 
| + // Potentially a bad DestructuringAssignmentTarget | 
| + classifier->RecordAssignmentPatternError( | 
| + Scanner::Location(lhs_location.beg_pos, scanner()->location().end_pos), | 
| + MessageTemplate::kInvalidDestructuringAssignmentTarget); | 
| + } | 
| + | 
| + if (maybe_assignment_pattern) { | 
| + classifier->AppendAssignmentTarget(ExpressionClassifier::TARGET_PATTERN); | 
| + if ((maybe_assignment_pattern = peek() == Token::ASSIGN)) { | 
| + *needs_destructuring = true; | 
| + } | 
| + } | 
| + | 
| if (!Token::IsAssignmentOp(peek())) { | 
| if (fni_ != NULL) fni_->Leave(); | 
| // Parsed conditional expression only (no assignment). | 
| @@ -2746,13 +2907,18 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, | 
| BindingPatternUnexpectedToken(classifier); | 
| } | 
| - expression = this->CheckAndRewriteReferenceExpression( | 
| - expression, lhs_location, MessageTemplate::kInvalidLhsInAssignment, | 
| - CHECK_OK); | 
| + if (!maybe_assignment_pattern) { | 
| + expression = this->CheckAndRewriteReferenceExpression( | 
| + expression, lhs_location, MessageTemplate::kInvalidLhsInAssignment, | 
| + CHECK_OK); | 
| + } | 
| + | 
| expression = this->MarkExpressionAsAssigned(expression); | 
| Token::Value op = Next(); // Get assignment operator. | 
| - if (op != Token::ASSIGN) { | 
| + if (op == Token::ASSIGN) { | 
| + classifier->set_assigned(); | 
| + } else { | 
| classifier->RecordBindingPatternError(scanner()->location(), | 
| MessageTemplate::kUnexpectedToken, | 
| Token::String(op)); | 
| @@ -2760,8 +2926,14 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, | 
| int pos = position(); | 
| ExpressionClassifier rhs_classifier; | 
| - ExpressionT right = | 
| - this->ParseAssignmentExpression(accept_IN, &rhs_classifier, CHECK_OK); | 
| + unsigned rhs_flags = flags | ASSIGNMENT_RHS; | 
| + if (is_assignment_element) { | 
| + // Parse an assignment element's initializer as a regular | 
| + // AssignmentExpression | 
| + rhs_flags &= ~(ASSIGNMENT_RHS | ASSIGNMENT_ELEMENT); | 
| + } | 
| + ExpressionT right = this->ParseAssignmentExpression( | 
| + rhs_flags, needs_destructuring, &rhs_classifier, CHECK_OK); | 
| 
arv (Not doing code reviews)
2015/06/19 18:49:05
Don't we need to pass in a new boolean here? The o
 | 
| classifier->AccumulateReclassifyingAsPattern(rhs_classifier); | 
| // TODO(1231235): We try to estimate the set of properties set by | 
| @@ -2790,7 +2962,9 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN, | 
| fni_->Leave(); | 
| } | 
| - return factory()->NewAssignment(op, expression, right, pos); | 
| + ExpressionT result = factory()->NewAssignment(op, expression, right, pos); | 
| + return this->CheckDestructuringAssignment( | 
| + result, classifier, *needs_destructuring, flags, CHECK_OK); | 
| } | 
| template <class Traits> | 
| @@ -2854,6 +3028,7 @@ ParserBase<Traits>::ParseConditionalExpression(bool accept_IN, | 
| this->ParseBinaryExpression(4, accept_IN, classifier, CHECK_OK); | 
| if (peek() != Token::CONDITIONAL) return expression; | 
| BindingPatternUnexpectedToken(classifier); | 
| + classifier->ReportInvalidSimpleAssignmentTarget(); | 
| Consume(Token::CONDITIONAL); | 
| // In parsing the first assignment expression in conditional | 
| // expressions we always accept the 'in' keyword; see ECMA-262, | 
| @@ -2878,6 +3053,7 @@ ParserBase<Traits>::ParseBinaryExpression(int prec, bool accept_IN, | 
| // prec1 >= 4 | 
| while (Precedence(peek(), accept_IN) == prec1) { | 
| BindingPatternUnexpectedToken(classifier); | 
| + classifier->ReportInvalidSimpleAssignmentTarget(); | 
| Token::Value op = Next(); | 
| Scanner::Location op_location = scanner()->location(); | 
| int pos = position(); | 
| @@ -2940,7 +3116,7 @@ ParserBase<Traits>::ParseUnaryExpression(ExpressionClassifier* classifier, | 
| Token::Value op = peek(); | 
| if (Token::IsUnaryOp(op)) { | 
| BindingPatternUnexpectedToken(classifier); | 
| - | 
| + classifier->ReportInvalidSimpleAssignmentTarget(); | 
| op = Next(); | 
| int pos = position(); | 
| ExpressionT expression = ParseUnaryExpression(classifier, CHECK_OK); | 
| @@ -2962,6 +3138,7 @@ ParserBase<Traits>::ParseUnaryExpression(ExpressionClassifier* classifier, | 
| return this->BuildUnaryExpression(expression, op, pos, factory()); | 
| } else if (Token::IsCountOp(op)) { | 
| BindingPatternUnexpectedToken(classifier); | 
| + classifier->ReportInvalidSimpleAssignmentTarget(); | 
| op = Next(); | 
| Scanner::Location lhs_location = scanner()->peek_location(); | 
| ExpressionT expression = this->ParseUnaryExpression(classifier, CHECK_OK); | 
| @@ -2994,7 +3171,7 @@ ParserBase<Traits>::ParsePostfixExpression(ExpressionClassifier* classifier, | 
| if (!scanner()->HasAnyLineTerminatorBeforeNext() && | 
| Token::IsCountOp(peek())) { | 
| BindingPatternUnexpectedToken(classifier); | 
| - | 
| + classifier->ReportInvalidSimpleAssignmentTarget(); | 
| expression = this->CheckAndRewriteReferenceExpression( | 
| expression, lhs_location, MessageTemplate::kInvalidLhsInPostfixOp, | 
| CHECK_OK); | 
| @@ -3025,9 +3202,11 @@ ParserBase<Traits>::ParseLeftHandSideExpression( | 
| switch (peek()) { | 
| case Token::LBRACK: { | 
| BindingPatternUnexpectedToken(classifier); | 
| + classifier->AppendAssignmentTarget( | 
| + ExpressionClassifier::TARGET_PROPERTY); | 
| Consume(Token::LBRACK); | 
| int pos = position(); | 
| - ExpressionT index = ParseExpression(true, classifier, CHECK_OK); | 
| + ExpressionT index = ParseExpression(true, CHECK_OK); | 
| result = factory()->NewProperty(result, index, pos); | 
| Expect(Token::RBRACK, CHECK_OK); | 
| break; | 
| @@ -3035,7 +3214,7 @@ ParserBase<Traits>::ParseLeftHandSideExpression( | 
| case Token::LPAREN: { | 
| BindingPatternUnexpectedToken(classifier); | 
| - | 
| + classifier->AppendAssignmentTarget(ExpressionClassifier::TARGET_CALL); | 
| if (is_strong(language_mode()) && this->IsIdentifier(result) && | 
| this->IsEval(this->AsIdentifier(result))) { | 
| ReportMessage(MessageTemplate::kStrongDirectEval); | 
| @@ -3086,6 +3265,8 @@ ParserBase<Traits>::ParseLeftHandSideExpression( | 
| case Token::PERIOD: { | 
| BindingPatternUnexpectedToken(classifier); | 
| + classifier->AppendAssignmentTarget( | 
| + ExpressionClassifier::TARGET_PROPERTY); | 
| Consume(Token::PERIOD); | 
| int pos = position(); | 
| IdentifierT name = ParseIdentifierName(CHECK_OK); | 
| @@ -3135,6 +3316,7 @@ ParserBase<Traits>::ParseMemberWithNewPrefixesExpression( | 
| if (peek() == Token::NEW) { | 
| BindingPatternUnexpectedToken(classifier); | 
| + classifier->AppendAssignmentTarget(ExpressionClassifier::TARGET_CALL); | 
| Consume(Token::NEW); | 
| int new_pos = position(); | 
| ExpressionT result = this->EmptyExpression(); | 
| @@ -3188,7 +3370,7 @@ ParserBase<Traits>::ParseMemberExpression(ExpressionClassifier* classifier, | 
| ExpressionT result = this->EmptyExpression(); | 
| if (peek() == Token::FUNCTION) { | 
| BindingPatternUnexpectedToken(classifier); | 
| - | 
| + classifier->AppendAssignmentTarget(ExpressionClassifier::TARGET_PRIMARY); | 
| Consume(Token::FUNCTION); | 
| int function_token_position = position(); | 
| bool is_generator = Check(Token::MUL); | 
| @@ -3376,12 +3558,14 @@ ParserBase<Traits>::ParseSuperExpression(bool is_new, | 
| if (IsConciseMethod(kind) || IsAccessorFunction(kind) || | 
| i::IsConstructor(kind)) { | 
| if (peek() == Token::PERIOD || peek() == Token::LBRACK) { | 
| + classifier->AppendAssignmentTarget(ExpressionClassifier::TARGET_PROPERTY); | 
| scope->RecordSuperPropertyUsage(); | 
| return this->SuperPropertyReference(scope_, factory(), pos); | 
| } | 
| // new super() is never allowed. | 
| // super() is only allowed in derived constructor | 
| if (!is_new && peek() == Token::LPAREN && IsSubclassConstructor(kind)) { | 
| + classifier->AppendAssignmentTarget(ExpressionClassifier::TARGET_CALL); | 
| if (is_strong(language_mode())) { | 
| // Super calls in strong mode are parsed separately. | 
| ReportMessageAt(scanner()->location(), | 
| @@ -3437,10 +3621,14 @@ ParserBase<Traits>::ParseMemberExpressionContinuation( | 
| switch (peek()) { | 
| case Token::LBRACK: { | 
| BindingPatternUnexpectedToken(classifier); | 
| - | 
| + classifier->AppendAssignmentTarget( | 
| + ExpressionClassifier::TARGET_PROPERTY); | 
| Consume(Token::LBRACK); | 
| int pos = position(); | 
| - ExpressionT index = this->ParseExpression(true, classifier, CHECK_OK); | 
| + // Ignore pattern errors within expression | 
| + ExpressionClassifier prop_classifier; | 
| + ExpressionT index = | 
| + this->ParseExpression(true, &prop_classifier, CHECK_OK); | 
| expression = factory()->NewProperty(expression, index, pos); | 
| if (fni_ != NULL) { | 
| this->PushPropertyName(fni_, index); | 
| @@ -3450,6 +3638,8 @@ ParserBase<Traits>::ParseMemberExpressionContinuation( | 
| } | 
| case Token::PERIOD: { | 
| BindingPatternUnexpectedToken(classifier); | 
| + classifier->AppendAssignmentTarget( | 
| + ExpressionClassifier::TARGET_PROPERTY); | 
| Consume(Token::PERIOD); | 
| int pos = position(); | 
| @@ -3464,6 +3654,7 @@ ParserBase<Traits>::ParseMemberExpressionContinuation( | 
| case Token::TEMPLATE_SPAN: | 
| case Token::TEMPLATE_TAIL: { | 
| BindingPatternUnexpectedToken(classifier); | 
| + classifier->AppendAssignmentTarget(ExpressionClassifier::TARGET_CALL); | 
| int pos; | 
| if (scanner()->current_token() == Token::IDENTIFIER) { | 
| pos = position(); | 
| @@ -3475,8 +3666,10 @@ ParserBase<Traits>::ParseMemberExpressionContinuation( | 
| expression->AsFunctionLiteral()->set_should_eager_compile(); | 
| } | 
| } | 
| + // Ignore classifying tagged template | 
| + ExpressionClassifier call_classifier; | 
| expression = | 
| - ParseTemplateLiteral(expression, pos, classifier, CHECK_OK); | 
| + ParseTemplateLiteral(expression, pos, &call_classifier, CHECK_OK); | 
| break; | 
| } | 
| default: |