Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1217)

Unified Diff: src/preparser.h

Issue 1168643005: [es6] parse destructuring assignment (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: WIP #1 Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/parser.cc ('k') | test/cctest/test-parsing.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « src/parser.cc ('k') | test/cctest/test-parsing.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698