Chromium Code Reviews| 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 |