| Index: src/preparser.h
|
| diff --git a/src/preparser.h b/src/preparser.h
|
| index 18fc2330eedd7f646683035bba73e311d6f8d12a..857ad0f942bf53ad7c37aca2d203151a168aea47 100644
|
| --- a/src/preparser.h
|
| +++ b/src/preparser.h
|
| @@ -88,11 +88,17 @@ class ParserBase : public Traits {
|
| typedef typename Traits::Type::Literal LiteralT;
|
| typedef typename Traits::Type::ObjectLiteralProperty ObjectLiteralPropertyT;
|
|
|
| + enum ExpressionFlavor {
|
| + VanillaExpression,
|
| + ElementExpression
|
| + };
|
| +
|
| ParserBase(Zone* zone, Scanner* scanner, uintptr_t stack_limit,
|
| v8::Extension* extension, AstValueFactory* ast_value_factory,
|
| ParserRecorder* log, typename Traits::Type::Parser this_object)
|
| : Traits(this_object),
|
| parenthesized_function_(false),
|
| + has_seen_assignment_pattern_(false),
|
| scope_(NULL),
|
| function_state_(NULL),
|
| extension_(extension),
|
| @@ -450,6 +456,18 @@ class ParserBase : public Traits {
|
| }
|
| }
|
|
|
| + bool CheckAssignmentPattern(ExpressionT value,
|
| + ExpressionClassifier* classifier, bool* ok) {
|
| + if (value->IsPatternOrLiteral()) {
|
| + if (!classifier->is_valid_assignment_pattern()) {
|
| + ReportClassifierError(classifier->assignment_pattern_error());
|
| + *ok = false;
|
| + }
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| inline void CheckStrictOctalLiteral(int beg_pos, int end_pos, bool* ok) {
|
| CheckOctalLiteral(beg_pos, end_pos, MessageTemplate::kStrictOctalLiteral,
|
| ok);
|
| @@ -671,7 +689,24 @@ class ParserBase : public Traits {
|
| bool* ok);
|
| ExpressionT ParseAssignmentExpression(bool accept_IN,
|
| ExpressionClassifier* classifier,
|
| - bool* ok);
|
| + ExpressionFlavor flavor, bool* ok);
|
| + ExpressionT ParseAssignmentExpression(bool accept_IN,
|
| + ExpressionClassifier* classifier,
|
| + bool* ok) {
|
| + return ParseAssignmentExpression(accept_IN, classifier, VanillaExpression,
|
| + ok);
|
| + }
|
| + ExpressionT ParseNestedAssignmentExpression(bool accept_IN,
|
| + ExpressionClassifier* classifier,
|
| + bool* ok) {
|
| + bool saved = has_seen_assignment_pattern_;
|
| + has_seen_assignment_pattern_ = false;
|
| + ExpressionT result = ParseAssignmentExpression(
|
| + accept_IN, classifier, ok);
|
| + if (!*ok) return this->EmptyExpression();
|
| + has_seen_assignment_pattern_ = saved;
|
| + return result;
|
| + }
|
| ExpressionT ParseYieldExpression(ExpressionClassifier* classifier, bool* ok);
|
| ExpressionT ParseConditionalExpression(bool accept_IN,
|
| ExpressionClassifier* classifier,
|
| @@ -720,6 +755,10 @@ class ParserBase : public Traits {
|
| ExpressionT expression, int beg_pos, int end_pos,
|
| MessageTemplate::Template message, ParseErrorType type, bool* ok);
|
|
|
| + void CheckPatternElement(
|
| + ExpressionT expression, int beg_pos, int end_pos,
|
| + ExpressionClassifier* classifier);
|
| +
|
| // Used to validate property names in object literals and class literals
|
| enum PropertyKind {
|
| kAccessorProperty,
|
| @@ -784,6 +823,7 @@ class ParserBase : public Traits {
|
| // Heuristically that means that the function will be called immediately,
|
| // so never lazily compile it.
|
| bool parenthesized_function_;
|
| + bool has_seen_assignment_pattern_;
|
|
|
| Scope* scope_; // Scope stack.
|
| FunctionState* function_state_; // Function state stack.
|
| @@ -905,6 +945,16 @@ class PreParserExpression {
|
| return PreParserExpression(TypeField::encode(kExpression));
|
| }
|
|
|
| + static PreParserExpression Assignment(PreParserExpression lhs,
|
| + Token::Value op) {
|
| + uint32_t code = TypeField::encode(kAssignment);
|
| + if (op == Token::ASSIGN &&
|
| + (lhs->IsObjectLiteral() || lhs->IsArrayLiteral())) {
|
| + code |= ExpressionTypeField::encode(kDestructuringAssignment);
|
| + }
|
| + return PreParserExpression(code);
|
| + }
|
| +
|
| static PreParserExpression Spread(PreParserExpression expression) {
|
| return PreParserExpression(TypeField::encode(kSpreadExpression));
|
| }
|
| @@ -921,19 +971,31 @@ class PreParserExpression {
|
| }
|
|
|
| static PreParserExpression StringLiteral() {
|
| - return PreParserExpression(TypeField::encode(kStringLiteralExpression));
|
| + return PreParserExpression(TypeField::encode(kStringLiteral));
|
| }
|
|
|
| static PreParserExpression UseStrictStringLiteral() {
|
| - return PreParserExpression(TypeField::encode(kStringLiteralExpression) |
|
| + return PreParserExpression(TypeField::encode(kStringLiteral) |
|
| IsUseStrictField::encode(true));
|
| }
|
|
|
| static PreParserExpression UseStrongStringLiteral() {
|
| - return PreParserExpression(TypeField::encode(kStringLiteralExpression) |
|
| + return PreParserExpression(TypeField::encode(kStringLiteral) |
|
| IsUseStrongField::encode(true));
|
| }
|
|
|
| + static PreParserExpression NumberLiteral() {
|
| + return PreParserExpression(TypeField::encode(kNumberLiteral));
|
| + }
|
| +
|
| + static PreParserExpression ArrayLiteral() {
|
| + return PreParserExpression(TypeField::encode(kArrayLiteral));
|
| + }
|
| +
|
| + static PreParserExpression ObjectLiteral() {
|
| + return PreParserExpression(TypeField::encode(kObjectLiteral));
|
| + }
|
| +
|
| static PreParserExpression This() {
|
| return PreParserExpression(TypeField::encode(kExpression) |
|
| ExpressionTypeField::encode(kThisExpression));
|
| @@ -978,19 +1040,35 @@ class PreParserExpression {
|
| }
|
|
|
| bool IsStringLiteral() const {
|
| - return TypeField::decode(code_) == kStringLiteralExpression;
|
| + return TypeField::decode(code_) == kStringLiteral;
|
| }
|
|
|
| bool IsUseStrictLiteral() const {
|
| - return TypeField::decode(code_) == kStringLiteralExpression &&
|
| + return TypeField::decode(code_) == kStringLiteral &&
|
| IsUseStrictField::decode(code_);
|
| }
|
|
|
| bool IsUseStrongLiteral() const {
|
| - return TypeField::decode(code_) == kStringLiteralExpression &&
|
| + return TypeField::decode(code_) == kStringLiteral &&
|
| IsUseStrongField::decode(code_);
|
| }
|
|
|
| + bool IsNumberLiteral() const {
|
| + return TypeField::decode(code_) == kNumberLiteral;
|
| + }
|
| +
|
| + bool IsArrayLiteral() const {
|
| + return TypeField::decode(code_) == kArrayLiteral;
|
| + }
|
| +
|
| + bool IsObjectLiteral() const {
|
| + return TypeField::decode(code_) == kObjectLiteral;
|
| + }
|
| +
|
| + inline bool IsPatternOrLiteral() const {
|
| + return IsObjectLiteral() || IsArrayLiteral();
|
| + }
|
| +
|
| bool IsThis() const {
|
| return TypeField::decode(code_) == kExpression &&
|
| ExpressionTypeField::decode(code_) == kThisExpression;
|
| @@ -1030,6 +1108,17 @@ class PreParserExpression {
|
| ExpressionTypeField::decode(code_) == kNoTemplateTagExpression;
|
| }
|
|
|
| + bool IsAssignment() const {
|
| + return TypeField::decode(code_) == kAssignment;
|
| + }
|
| +
|
| + PreParserExpression AsAssignment() const { return *this; }
|
| +
|
| + bool IsDestructuring() const {
|
| + return TypeField::decode(code_) == kAssignment &&
|
| + ExpressionTypeField::decode(code_) == kDestructuringAssignment;
|
| + }
|
| +
|
| bool IsSpreadExpression() const {
|
| return TypeField::decode(code_) == kSpreadExpression;
|
| }
|
| @@ -1055,9 +1144,13 @@ class PreParserExpression {
|
| enum Type {
|
| kExpression,
|
| kIdentifierExpression,
|
| - kStringLiteralExpression,
|
| + kStringLiteral,
|
| + kNumberLiteral,
|
| + kArrayLiteral,
|
| + kObjectLiteral,
|
| kBinaryOperationExpression,
|
| - kSpreadExpression
|
| + kSpreadExpression,
|
| + kAssignment
|
| };
|
|
|
| enum ExpressionType {
|
| @@ -1066,14 +1159,15 @@ class PreParserExpression {
|
| kPropertyExpression,
|
| kCallExpression,
|
| kSuperCallReference,
|
| - kNoTemplateTagExpression
|
| + kNoTemplateTagExpression,
|
| + kDestructuringAssignment
|
| };
|
|
|
| explicit PreParserExpression(uint32_t expression_code)
|
| : code_(expression_code) {}
|
|
|
| // The first three bits are for the Type.
|
| - typedef BitField<Type, 0, 3> TypeField;
|
| + typedef BitField<Type, 0, 4> TypeField;
|
|
|
| // The rest of the bits are interpreted depending on the value
|
| // of the Type field, so they can share the storage.
|
| @@ -1177,11 +1271,11 @@ class PreParserFactory {
|
| explicit PreParserFactory(void* unused_value_factory) {}
|
| PreParserExpression NewStringLiteral(PreParserIdentifier identifier,
|
| int pos) {
|
| - return PreParserExpression::Default();
|
| + return PreParserExpression::StringLiteral();
|
| }
|
| PreParserExpression NewNumberLiteral(double number,
|
| int pos) {
|
| - return PreParserExpression::Default();
|
| + return PreParserExpression::NumberLiteral();
|
| }
|
| PreParserExpression NewRegExpLiteral(PreParserIdentifier js_pattern,
|
| PreParserIdentifier js_flags,
|
| @@ -1194,12 +1288,12 @@ class PreParserFactory {
|
| int literal_index,
|
| bool is_strong,
|
| int pos) {
|
| - return PreParserExpression::Default();
|
| + return PreParserExpression::ArrayLiteral();
|
| }
|
| PreParserExpression NewArrayLiteral(PreParserExpressionList values,
|
| int first_spread_index, int literal_index,
|
| bool is_strong, int pos) {
|
| - return PreParserExpression::Default();
|
| + return PreParserExpression::ArrayLiteral();
|
| }
|
| PreParserExpression NewObjectLiteralProperty(PreParserExpression key,
|
| PreParserExpression value,
|
| @@ -1220,7 +1314,7 @@ class PreParserFactory {
|
| bool has_function,
|
| bool is_strong,
|
| int pos) {
|
| - return PreParserExpression::Default();
|
| + return PreParserExpression::ObjectLiteral();
|
| }
|
| PreParserExpression NewVariableProxy(void* variable) {
|
| return PreParserExpression::Default();
|
| @@ -1252,7 +1346,7 @@ class PreParserFactory {
|
| PreParserExpression left,
|
| PreParserExpression right,
|
| int pos) {
|
| - return PreParserExpression::Default();
|
| + return PreParserExpression::Assignment(left, op);
|
| }
|
| PreParserExpression NewYield(PreParserExpression generator_object,
|
| PreParserExpression expression,
|
| @@ -1612,6 +1706,11 @@ class PreParserTraits {
|
| PreParserExpression expression, const Scanner::Location& params_loc,
|
| Scanner::Location* duplicate_loc, bool* ok);
|
|
|
| + PreParserExpression RewriteDestructuringAssignment(
|
| + PreParserExpression expression) {
|
| + return expression;
|
| + }
|
| +
|
| void ReindexLiterals(const PreParserFormalParameters& paramaters) {}
|
|
|
| struct TemplateLiteralState {};
|
| @@ -2446,14 +2545,16 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseArrayLiteral(
|
| int start_pos = peek_position();
|
| Consume(Token::ELLIPSIS);
|
| ExpressionT argument =
|
| - this->ParseAssignmentExpression(true, classifier, CHECK_OK);
|
| + this->ParseAssignmentExpression(true, classifier, ElementExpression,
|
| + CHECK_OK);
|
| elem = factory()->NewSpread(argument, start_pos);
|
| seen_spread = true;
|
| if (first_spread_index < 0) {
|
| first_spread_index = values->length();
|
| }
|
| } else {
|
| - elem = this->ParseAssignmentExpression(true, classifier, CHECK_OK);
|
| + elem = this->ParseAssignmentExpression(true, classifier,
|
| + ElementExpression, CHECK_OK);
|
| }
|
| values->Add(elem, zone_);
|
| if (peek() != Token::RBRACK) {
|
| @@ -2567,10 +2668,16 @@ ParserBase<Traits>::ParsePropertyDefinition(
|
| }
|
| Consume(Token::COLON);
|
| value = this->ParseAssignmentExpression(
|
| - true, classifier, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
| + true, classifier, ElementExpression,
|
| + CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
|
|
| } else if (is_generator || peek() == Token::LPAREN) {
|
| // Concise Method
|
| + if (!in_class) {
|
| + classifier->RecordPatternError(
|
| + Scanner::Location(next_beg_pos, next_end_pos),
|
| + MessageTemplate::kInvalidDestructuringTarget);
|
| + }
|
| if (!*is_computed_name) {
|
| checker->CheckProperty(name_token, kMethodProperty, is_static,
|
| is_generator,
|
| @@ -2604,6 +2711,11 @@ ParserBase<Traits>::ParsePropertyDefinition(
|
| is_computed_name, nullptr, classifier, ok);
|
| } else if (is_get || is_set) {
|
| // Accessor
|
| + if (!in_class) {
|
| + classifier->RecordPatternError(
|
| + Scanner::Location(next_beg_pos, next_end_pos),
|
| + MessageTemplate::kInvalidDestructuringTarget);
|
| + }
|
| name = this->EmptyIdentifier();
|
| bool dont_care = false;
|
| name_token = peek();
|
| @@ -2641,6 +2753,7 @@ ParserBase<Traits>::ParsePropertyDefinition(
|
|
|
| } else if (!in_class && Token::IsIdentifier(name_token, language_mode(),
|
| this->is_generator())) {
|
| + // IdentifierReference | CoverInitializedName
|
| DCHECK(!*is_computed_name);
|
| DCHECK(!is_static);
|
|
|
| @@ -2652,11 +2765,15 @@ ParserBase<Traits>::ParsePropertyDefinition(
|
| ExpressionT lhs = this->ExpressionFromIdentifier(
|
| name, next_beg_pos, next_end_pos, scope_, factory());
|
| if (peek() == Token::ASSIGN) {
|
| + // TODO(caitp): don't report SyntaxError for CoverInitializedName when
|
| + // parsing Pattern.
|
| this->ExpressionUnexpectedToken(classifier);
|
| Consume(Token::ASSIGN);
|
| ExpressionClassifier rhs_classifier;
|
| - ExpressionT rhs = this->ParseAssignmentExpression(
|
| +
|
| + ExpressionT rhs = this->ParseNestedAssignmentExpression(
|
| true, &rhs_classifier, CHECK_OK_CUSTOM(EmptyObjectLiteralProperty));
|
| +
|
| classifier->Accumulate(rhs_classifier,
|
| ExpressionClassifier::ExpressionProduction);
|
| value = factory()->NewAssignment(Token::ASSIGN, lhs, rhs,
|
| @@ -2664,6 +2781,7 @@ ParserBase<Traits>::ParsePropertyDefinition(
|
| } else {
|
| value = lhs;
|
| }
|
| +
|
| return factory()->NewObjectLiteralProperty(
|
| name_expression, value, ObjectLiteralProperty::COMPUTED, false, false);
|
|
|
| @@ -2761,11 +2879,11 @@ typename Traits::Type::ExpressionList ParserBase<Traits>::ParseArguments(
|
| bool was_unspread = false;
|
| int unspread_sequences_count = 0;
|
| while (!done) {
|
| + DCHECK_EQ(has_seen_assignment_pattern_, false);
|
| bool is_spread = allow_harmony_spreadcalls() && (peek() == Token::ELLIPSIS);
|
| int start_pos = peek_position();
|
| if (is_spread) Consume(Token::ELLIPSIS);
|
| -
|
| - ExpressionT argument = this->ParseAssignmentExpression(
|
| + ExpressionT argument = this->ParseNestedAssignmentExpression(
|
| true, classifier, CHECK_OK_CUSTOM(NullExpressionList));
|
| if (is_spread) {
|
| if (!spread_arg.IsValid()) {
|
| @@ -2818,6 +2936,7 @@ template <class Traits>
|
| typename ParserBase<Traits>::ExpressionT
|
| ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
| ExpressionClassifier* classifier,
|
| + ExpressionFlavor flavor,
|
| bool* ok) {
|
| // AssignmentExpression ::
|
| // ConditionalExpression
|
| @@ -2861,6 +2980,9 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
| }
|
| expression = this->ParseArrowFunctionLiteral(
|
| parameters, arrow_formals_classifier, CHECK_OK);
|
| + classifier->RecordPatternError(
|
| + Scanner::Location(lhs_beg_pos, scanner()->location().end_pos),
|
| + MessageTemplate::kInvalidDestructuringTarget);
|
| return expression;
|
| }
|
|
|
| @@ -2870,7 +2992,13 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
| ExpressionClassifier::StandardProductions |
|
| ExpressionClassifier::FormalParametersProductions);
|
|
|
| + int lhs_end_pos = scanner()->location().end_pos;
|
| if (!Token::IsAssignmentOp(peek())) {
|
| + if (flavor == ElementExpression) {
|
| + CheckPatternElement(expression, lhs_beg_pos, lhs_end_pos, classifier);
|
| + }
|
| + ValidateExpression(classifier, CHECK_OK);
|
| +
|
| if (fni_ != NULL) fni_->Leave();
|
| // Parsed conditional expression only (no assignment).
|
| return expression;
|
| @@ -2880,17 +3008,26 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
| BindingPatternUnexpectedToken(classifier);
|
| }
|
|
|
| - expression = this->CheckAndRewriteReferenceExpression(
|
| - expression, lhs_beg_pos, scanner()->location().end_pos,
|
| - MessageTemplate::kInvalidLhsInAssignment, CHECK_OK);
|
| - expression = this->MarkExpressionAsAssigned(expression);
|
| + // Check that the LHS is a valid AssignmentPattern, or does not appear to be
|
| + // an ObjectLiteral or ArrayLiteral.
|
| + bool has_seen_assignment_pattern = has_seen_assignment_pattern_;
|
|
|
| Token::Value op = Next(); // Get assignment operator.
|
| +
|
| if (op != Token::ASSIGN) {
|
| - classifier->RecordBindingPatternError(scanner()->location(),
|
| - MessageTemplate::kUnexpectedToken,
|
| - Token::String(op));
|
| + classifier->RecordPatternError(scanner()->location(),
|
| + MessageTemplate::kUnexpectedToken,
|
| + Token::String(op));
|
| + }
|
| + bool was_pattern = CheckAssignmentPattern(expression, classifier, CHECK_OK);
|
| + has_seen_assignment_pattern_ |= was_pattern;
|
| + if (!was_pattern) {
|
| + expression = this->CheckAndRewriteReferenceExpression(
|
| + expression, lhs_beg_pos, lhs_end_pos,
|
| + MessageTemplate::kInvalidLhsInAssignment, CHECK_OK);
|
| + expression = this->MarkExpressionAsAssigned(expression);
|
| }
|
| +
|
| int pos = position();
|
|
|
| ExpressionClassifier rhs_classifier;
|
| @@ -2925,7 +3062,16 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
| fni_->Leave();
|
| }
|
|
|
| - return factory()->NewAssignment(op, expression, right, pos);
|
| + ExpressionT result = factory()->NewAssignment(op, expression, right, pos);
|
| +
|
| + if (has_seen_assignment_pattern_ && !has_seen_assignment_pattern) {
|
| + // Reset flag when assignment assignment chain has ended, and rewrite the
|
| + // entire chain.
|
| + has_seen_assignment_pattern_ = false;
|
| + return Traits::RewriteDestructuringAssignment(result);
|
| + }
|
| +
|
| + return result;
|
| }
|
|
|
| template <class Traits>
|
| @@ -2959,7 +3105,8 @@ ParserBase<Traits>::ParseYieldExpression(ExpressionClassifier* classifier,
|
| DCHECK_EQ(Yield::kDelegating, kind);
|
| // Delegating yields require an RHS; fall through.
|
| default:
|
| - expression = ParseAssignmentExpression(false, classifier, CHECK_OK);
|
| + expression = ParseNestedAssignmentExpression(false, classifier,
|
| + CHECK_OK);
|
| break;
|
| }
|
| }
|
| @@ -3993,6 +4140,23 @@ ParserBase<Traits>::CheckAndRewriteReferenceExpression(
|
| }
|
|
|
|
|
| +template <typename Traits>
|
| +void ParserBase<Traits>::CheckPatternElement(
|
| + ExpressionT expression, int beg_pos, int end_pos,
|
| + ExpressionClassifier* classifier) {
|
| + if (expression->IsPatternOrLiteral() &&
|
| + (classifier->is_valid_assignment_pattern() ||
|
| + classifier->is_valid_binding_pattern())) {
|
| + return;
|
| + }
|
| + if (!expression->IsValidReferenceExpression()) {
|
| + classifier->RecordPatternError(
|
| + Scanner::Location(beg_pos, end_pos),
|
| + MessageTemplate::kInvalidDestructuringTarget);
|
| + }
|
| +}
|
| +
|
| +
|
| #undef CHECK_OK
|
| #undef CHECK_OK_CUSTOM
|
|
|
|
|