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 |