Commit 80bf5686 authored by dslomov's avatar dslomov Committed by Commit bot

Parsing binding patterns.

Just parsing, no desugaring yet.

R=arv@chromium.org,rossberg@chromium.org
BUG=v8:811
LOG=N

Review URL: https://codereview.chromium.org/1107053002

Cr-Commit-Position: refs/heads/master@{#28112}
parent f39707cd
...@@ -872,6 +872,7 @@ Parser::Parser(ParseInfo* info) ...@@ -872,6 +872,7 @@ Parser::Parser(ParseInfo* info)
FLAG_harmony_computed_property_names); FLAG_harmony_computed_property_names);
set_allow_harmony_rest_params(FLAG_harmony_rest_parameters); set_allow_harmony_rest_params(FLAG_harmony_rest_parameters);
set_allow_harmony_spreadcalls(FLAG_harmony_spreadcalls); set_allow_harmony_spreadcalls(FLAG_harmony_spreadcalls);
set_allow_harmony_destructuring(FLAG_harmony_destructuring);
set_allow_strong_mode(FLAG_strong_mode); set_allow_strong_mode(FLAG_strong_mode);
for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount; for (int feature = 0; feature < v8::Isolate::kUseCounterFeatureCount;
++feature) { ++feature) {
...@@ -2387,6 +2388,9 @@ Block* Parser::ParseVariableDeclarations( ...@@ -2387,6 +2388,9 @@ Block* Parser::ParseVariableDeclarations(
pattern->AsVariableProxy()->IsValidReferenceExpression()) { pattern->AsVariableProxy()->IsValidReferenceExpression()) {
scope_->RemoveUnresolved(pattern->AsVariableProxy()); scope_->RemoveUnresolved(pattern->AsVariableProxy());
name = pattern->AsVariableProxy()->raw_name(); name = pattern->AsVariableProxy()->raw_name();
} else if (allow_harmony_destructuring()) {
// TODO(dslomov): really destructure.
name = ast_value_factory()->GetOneByteString(".temp.variable");
} else { } else {
ReportUnexpectedToken(next); ReportUnexpectedToken(next);
*ok = false; *ok = false;
...@@ -4335,6 +4339,8 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser( ...@@ -4335,6 +4339,8 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
allow_harmony_rest_params()); allow_harmony_rest_params());
reusable_preparser_->set_allow_harmony_spreadcalls( reusable_preparser_->set_allow_harmony_spreadcalls(
allow_harmony_spreadcalls()); allow_harmony_spreadcalls());
reusable_preparser_->set_allow_harmony_destructuring(
allow_harmony_destructuring());
reusable_preparser_->set_allow_strong_mode(allow_strong_mode()); reusable_preparser_->set_allow_strong_mode(allow_strong_mode());
} }
PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction( PreParser::PreParseResult result = reusable_preparser_->PreParseLazyFunction(
......
...@@ -511,7 +511,7 @@ PreParser::Statement PreParser::ParseVariableDeclarations( ...@@ -511,7 +511,7 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
int nvars = 0; // the number of variables declared int nvars = 0; // the number of variables declared
int bindings_start = peek_position(); int bindings_start = peek_position();
do { do {
// Parse variable name. // Parse binding pattern.
if (nvars > 0) Consume(Token::COMMA); if (nvars > 0) Consume(Token::COMMA);
{ {
ExpressionClassifier pattern_classifier; ExpressionClassifier pattern_classifier;
...@@ -520,12 +520,13 @@ PreParser::Statement PreParser::ParseVariableDeclarations( ...@@ -520,12 +520,13 @@ PreParser::Statement PreParser::ParseVariableDeclarations(
ParsePrimaryExpression(&pattern_classifier, CHECK_OK); ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
ValidateBindingPattern(&pattern_classifier, CHECK_OK); ValidateBindingPattern(&pattern_classifier, CHECK_OK);
if (!pattern.IsIdentifier()) { if (!FLAG_harmony_destructuring && !pattern.IsIdentifier()) {
ReportUnexpectedToken(next); ReportUnexpectedToken(next);
*ok = false; *ok = false;
return Statement::Default(); return Statement::Default();
} }
} }
Scanner::Location variable_loc = scanner()->location(); Scanner::Location variable_loc = scanner()->location();
nvars++; nvars++;
if (peek() == Token::ASSIGN || require_initializer || if (peek() == Token::ASSIGN || require_initializer ||
......
...@@ -138,6 +138,9 @@ class ParserBase : public Traits { ...@@ -138,6 +138,9 @@ class ParserBase : public Traits {
return allow_harmony_rest_params_; return allow_harmony_rest_params_;
} }
bool allow_harmony_spreadcalls() const { return allow_harmony_spreadcalls_; } bool allow_harmony_spreadcalls() const { return allow_harmony_spreadcalls_; }
bool allow_harmony_destructuring() const {
return allow_harmony_destructuring_;
}
bool allow_strong_mode() const { return allow_strong_mode_; } bool allow_strong_mode() const { return allow_strong_mode_; }
...@@ -173,6 +176,10 @@ class ParserBase : public Traits { ...@@ -173,6 +176,10 @@ class ParserBase : public Traits {
allow_harmony_spreadcalls_ = allow; allow_harmony_spreadcalls_ = allow;
} }
void set_allow_strong_mode(bool allow) { allow_strong_mode_ = allow; } void set_allow_strong_mode(bool allow) { allow_strong_mode_ = allow; }
void set_allow_harmony_destructuring(bool allow) {
allow_harmony_destructuring_ = allow;
}
protected: protected:
enum AllowRestrictedIdentifiers { enum AllowRestrictedIdentifiers {
...@@ -679,6 +686,10 @@ class ParserBase : public Traits { ...@@ -679,6 +686,10 @@ class ParserBase : public Traits {
} }
} }
void BindingPatternUnexpectedToken(ExpressionClassifier* classifier) {
classifier->RecordBindingPatternError(
scanner()->location(), "unexpected_token", Token::String(peek()));
}
// Recursive descent functions: // Recursive descent functions:
...@@ -857,6 +868,7 @@ class ParserBase : public Traits { ...@@ -857,6 +868,7 @@ class ParserBase : public Traits {
bool allow_harmony_computed_property_names_; bool allow_harmony_computed_property_names_;
bool allow_harmony_rest_params_; bool allow_harmony_rest_params_;
bool allow_harmony_spreadcalls_; bool allow_harmony_spreadcalls_;
bool allow_harmony_destructuring_;
bool allow_strong_mode_; bool allow_strong_mode_;
}; };
...@@ -2192,6 +2204,7 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier, ...@@ -2192,6 +2204,7 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
Token::Value token = peek(); Token::Value token = peek();
switch (token) { switch (token) {
case Token::THIS: { case Token::THIS: {
BindingPatternUnexpectedToken(classifier);
Consume(Token::THIS); Consume(Token::THIS);
if (is_strong(language_mode())) { if (is_strong(language_mode())) {
// Constructors' usages of 'this' in strong mode are parsed separately. // Constructors' usages of 'this' in strong mode are parsed separately.
...@@ -2210,8 +2223,15 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier, ...@@ -2210,8 +2223,15 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
case Token::NULL_LITERAL: case Token::NULL_LITERAL:
case Token::TRUE_LITERAL: case Token::TRUE_LITERAL:
case Token::FALSE_LITERAL: case Token::FALSE_LITERAL:
BindingPatternUnexpectedToken(classifier);
Next();
result =
this->ExpressionFromLiteral(token, beg_pos, scanner(), factory());
break;
case Token::SMI: case Token::SMI:
case Token::NUMBER: case Token::NUMBER:
classifier->RecordBindingPatternError(scanner()->location(),
"unexpected_token_number");
Next(); Next();
result = result =
this->ExpressionFromLiteral(token, beg_pos, scanner(), factory()); this->ExpressionFromLiteral(token, beg_pos, scanner(), factory());
...@@ -2230,6 +2250,8 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier, ...@@ -2230,6 +2250,8 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
} }
case Token::STRING: { case Token::STRING: {
classifier->RecordBindingPatternError(scanner()->location(),
"unexpected_token_string");
Consume(Token::STRING); Consume(Token::STRING);
result = this->ExpressionFromString(beg_pos, scanner(), factory()); result = this->ExpressionFromString(beg_pos, scanner(), factory());
break; break;
...@@ -2252,11 +2274,8 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier, ...@@ -2252,11 +2274,8 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
break; break;
case Token::LPAREN: case Token::LPAREN:
BindingPatternUnexpectedToken(classifier);
Consume(Token::LPAREN); Consume(Token::LPAREN);
classifier->RecordBindingPatternError(scanner()->location(),
"unexpected_token", "(");
classifier->RecordAssignmentPatternError(scanner()->location(),
"unexpected_token", "(");
if (allow_harmony_arrow_functions() && Check(Token::RPAREN)) { if (allow_harmony_arrow_functions() && Check(Token::RPAREN)) {
// As a primary expression, the only thing that can follow "()" is "=>". // As a primary expression, the only thing that can follow "()" is "=>".
Scope* scope = this->NewScope(scope_, ARROW_SCOPE); Scope* scope = this->NewScope(scope_, ARROW_SCOPE);
...@@ -2276,6 +2295,7 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier, ...@@ -2276,6 +2295,7 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
break; break;
case Token::CLASS: { case Token::CLASS: {
BindingPatternUnexpectedToken(classifier);
Consume(Token::CLASS); Consume(Token::CLASS);
if (!allow_harmony_sloppy() && is_sloppy(language_mode())) { if (!allow_harmony_sloppy() && is_sloppy(language_mode())) {
ReportMessage("sloppy_lexical"); ReportMessage("sloppy_lexical");
...@@ -2940,6 +2960,8 @@ ParserBase<Traits>::ParseUnaryExpression(ExpressionClassifier* classifier, ...@@ -2940,6 +2960,8 @@ ParserBase<Traits>::ParseUnaryExpression(ExpressionClassifier* classifier,
Token::Value op = peek(); Token::Value op = peek();
if (Token::IsUnaryOp(op)) { if (Token::IsUnaryOp(op)) {
BindingPatternUnexpectedToken(classifier);
op = Next(); op = Next();
int pos = position(); int pos = position();
ExpressionT expression = ParseUnaryExpression(classifier, CHECK_OK); ExpressionT expression = ParseUnaryExpression(classifier, CHECK_OK);
...@@ -2960,6 +2982,7 @@ ParserBase<Traits>::ParseUnaryExpression(ExpressionClassifier* classifier, ...@@ -2960,6 +2982,7 @@ ParserBase<Traits>::ParseUnaryExpression(ExpressionClassifier* classifier,
// Allow Traits do rewrite the expression. // Allow Traits do rewrite the expression.
return this->BuildUnaryExpression(expression, op, pos, factory()); return this->BuildUnaryExpression(expression, op, pos, factory());
} else if (Token::IsCountOp(op)) { } else if (Token::IsCountOp(op)) {
BindingPatternUnexpectedToken(classifier);
op = Next(); op = Next();
Scanner::Location lhs_location = scanner()->peek_location(); Scanner::Location lhs_location = scanner()->peek_location();
ExpressionT expression = this->ParseUnaryExpression(classifier, CHECK_OK); ExpressionT expression = this->ParseUnaryExpression(classifier, CHECK_OK);
...@@ -2990,6 +3013,8 @@ ParserBase<Traits>::ParsePostfixExpression(ExpressionClassifier* classifier, ...@@ -2990,6 +3013,8 @@ ParserBase<Traits>::ParsePostfixExpression(ExpressionClassifier* classifier,
this->ParseLeftHandSideExpression(classifier, CHECK_OK); this->ParseLeftHandSideExpression(classifier, CHECK_OK);
if (!scanner()->HasAnyLineTerminatorBeforeNext() && if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
Token::IsCountOp(peek())) { Token::IsCountOp(peek())) {
BindingPatternUnexpectedToken(classifier);
expression = this->CheckAndRewriteReferenceExpression( expression = this->CheckAndRewriteReferenceExpression(
expression, lhs_location, "invalid_lhs_in_postfix_op", CHECK_OK); expression, lhs_location, "invalid_lhs_in_postfix_op", CHECK_OK);
expression = this->MarkExpressionAsAssigned(expression); expression = this->MarkExpressionAsAssigned(expression);
...@@ -3018,6 +3043,7 @@ ParserBase<Traits>::ParseLeftHandSideExpression( ...@@ -3018,6 +3043,7 @@ ParserBase<Traits>::ParseLeftHandSideExpression(
while (true) { while (true) {
switch (peek()) { switch (peek()) {
case Token::LBRACK: { case Token::LBRACK: {
BindingPatternUnexpectedToken(classifier);
Consume(Token::LBRACK); Consume(Token::LBRACK);
int pos = position(); int pos = position();
ExpressionT index = ParseExpression(true, classifier, CHECK_OK); ExpressionT index = ParseExpression(true, classifier, CHECK_OK);
...@@ -3027,6 +3053,8 @@ ParserBase<Traits>::ParseLeftHandSideExpression( ...@@ -3027,6 +3053,8 @@ ParserBase<Traits>::ParseLeftHandSideExpression(
} }
case Token::LPAREN: { case Token::LPAREN: {
BindingPatternUnexpectedToken(classifier);
if (is_strong(language_mode()) && this->IsIdentifier(result) && if (is_strong(language_mode()) && this->IsIdentifier(result) &&
this->IsEval(this->AsIdentifier(result))) { this->IsEval(this->AsIdentifier(result))) {
ReportMessage("strong_direct_eval"); ReportMessage("strong_direct_eval");
...@@ -3076,6 +3104,7 @@ ParserBase<Traits>::ParseLeftHandSideExpression( ...@@ -3076,6 +3104,7 @@ ParserBase<Traits>::ParseLeftHandSideExpression(
} }
case Token::PERIOD: { case Token::PERIOD: {
BindingPatternUnexpectedToken(classifier);
Consume(Token::PERIOD); Consume(Token::PERIOD);
int pos = position(); int pos = position();
IdentifierT name = ParseIdentifierName(CHECK_OK); IdentifierT name = ParseIdentifierName(CHECK_OK);
...@@ -3114,6 +3143,7 @@ ParserBase<Traits>::ParseMemberWithNewPrefixesExpression( ...@@ -3114,6 +3143,7 @@ ParserBase<Traits>::ParseMemberWithNewPrefixesExpression(
// new new foo().bar().baz means (new (new foo()).bar()).baz // new new foo().bar().baz means (new (new foo()).bar()).baz
if (peek() == Token::NEW) { if (peek() == Token::NEW) {
BindingPatternUnexpectedToken(classifier);
Consume(Token::NEW); Consume(Token::NEW);
int new_pos = position(); int new_pos = position();
ExpressionT result = this->EmptyExpression(); ExpressionT result = this->EmptyExpression();
...@@ -3164,6 +3194,8 @@ ParserBase<Traits>::ParseMemberExpression(ExpressionClassifier* classifier, ...@@ -3164,6 +3194,8 @@ ParserBase<Traits>::ParseMemberExpression(ExpressionClassifier* classifier,
// Parse the initial primary or function expression. // Parse the initial primary or function expression.
ExpressionT result = this->EmptyExpression(); ExpressionT result = this->EmptyExpression();
if (peek() == Token::FUNCTION) { if (peek() == Token::FUNCTION) {
BindingPatternUnexpectedToken(classifier);
Consume(Token::FUNCTION); Consume(Token::FUNCTION);
int function_token_position = position(); int function_token_position = position();
bool is_generator = Check(Token::MUL); bool is_generator = Check(Token::MUL);
...@@ -3284,6 +3316,7 @@ ParserBase<Traits>::ParseStrongSuperCallExpression( ...@@ -3284,6 +3316,7 @@ ParserBase<Traits>::ParseStrongSuperCallExpression(
ExpressionClassifier* classifier, bool* ok) { ExpressionClassifier* classifier, bool* ok) {
// SuperCallExpression :: (strong mode) // SuperCallExpression :: (strong mode)
// 'super' '(' ExpressionList ')' // 'super' '(' ExpressionList ')'
BindingPatternUnexpectedToken(classifier);
Consume(Token::SUPER); Consume(Token::SUPER);
int pos = position(); int pos = position();
...@@ -3380,6 +3413,8 @@ ParserBase<Traits>::ParseMemberExpressionContinuation( ...@@ -3380,6 +3413,8 @@ ParserBase<Traits>::ParseMemberExpressionContinuation(
while (true) { while (true) {
switch (peek()) { switch (peek()) {
case Token::LBRACK: { case Token::LBRACK: {
BindingPatternUnexpectedToken(classifier);
Consume(Token::LBRACK); Consume(Token::LBRACK);
int pos = position(); int pos = position();
ExpressionT index = this->ParseExpression(true, classifier, CHECK_OK); ExpressionT index = this->ParseExpression(true, classifier, CHECK_OK);
...@@ -3391,6 +3426,8 @@ ParserBase<Traits>::ParseMemberExpressionContinuation( ...@@ -3391,6 +3426,8 @@ ParserBase<Traits>::ParseMemberExpressionContinuation(
break; break;
} }
case Token::PERIOD: { case Token::PERIOD: {
BindingPatternUnexpectedToken(classifier);
Consume(Token::PERIOD); Consume(Token::PERIOD);
int pos = position(); int pos = position();
IdentifierT name = ParseIdentifierName(CHECK_OK); IdentifierT name = ParseIdentifierName(CHECK_OK);
...@@ -3403,6 +3440,7 @@ ParserBase<Traits>::ParseMemberExpressionContinuation( ...@@ -3403,6 +3440,7 @@ ParserBase<Traits>::ParseMemberExpressionContinuation(
} }
case Token::TEMPLATE_SPAN: case Token::TEMPLATE_SPAN:
case Token::TEMPLATE_TAIL: { case Token::TEMPLATE_TAIL: {
BindingPatternUnexpectedToken(classifier);
int pos; int pos;
if (scanner()->current_token() == Token::IDENTIFIER) { if (scanner()->current_token() == Token::IDENTIFIER) {
pos = position(); pos = position();
...@@ -3549,6 +3587,9 @@ ParserBase<Traits>::ParseArrowFunctionLiteral( ...@@ -3549,6 +3587,9 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
FunctionState function_state(&function_state_, &scope_, scope, FunctionState function_state(&function_state_, &scope_, scope,
kArrowFunction, &function_factory); kArrowFunction, &function_factory);
if (peek() == Token::ARROW) {
BindingPatternUnexpectedToken(classifier);
}
Expect(Token::ARROW, CHECK_OK); Expect(Token::ARROW, CHECK_OK);
if (peek() == Token::LBRACE) { if (peek() == Token::LBRACE) {
......
...@@ -1381,8 +1381,9 @@ enum ParserFlag { ...@@ -1381,8 +1381,9 @@ enum ParserFlag {
kAllowHarmonySloppy, kAllowHarmonySloppy,
kAllowHarmonyUnicode, kAllowHarmonyUnicode,
kAllowHarmonyComputedPropertyNames, kAllowHarmonyComputedPropertyNames,
kAllowStrongMode, kAllowHarmonySpreadCalls,
kAllowHarmonySpreadCalls kAllowHarmonyDestructuring,
kAllowStrongMode
}; };
...@@ -1411,6 +1412,8 @@ void SetParserFlags(i::ParserBase<Traits>* parser, ...@@ -1411,6 +1412,8 @@ void SetParserFlags(i::ParserBase<Traits>* parser,
parser->set_allow_harmony_unicode(flags.Contains(kAllowHarmonyUnicode)); parser->set_allow_harmony_unicode(flags.Contains(kAllowHarmonyUnicode));
parser->set_allow_harmony_computed_property_names( parser->set_allow_harmony_computed_property_names(
flags.Contains(kAllowHarmonyComputedPropertyNames)); flags.Contains(kAllowHarmonyComputedPropertyNames));
parser->set_allow_harmony_destructuring(
flags.Contains(kAllowHarmonyDestructuring));
parser->set_allow_strong_mode(flags.Contains(kAllowStrongMode)); parser->set_allow_strong_mode(flags.Contains(kAllowStrongMode));
} }
...@@ -6344,3 +6347,129 @@ TEST(StrongModeFreeVariablesNotDeclared) { ...@@ -6344,3 +6347,129 @@ TEST(StrongModeFreeVariablesNotDeclared) {
*exception)); *exception));
} }
} }
TEST(DestructuringPositiveTests) {
i::FLAG_harmony_destructuring = true;
const char* context_data[][2] = {{"'use strict'; let ", " = {};"},
{"var ", " = {};"},
{"'use strict'; const ", " = {};"},
{NULL, NULL}};
// clang-format off
const char* data[] = {
"a",
"{ x : y }",
"[a]",
"[a,b,c]",
"{ x : x, y : y }",
"[]",
"{}",
"[{x:x, y:y}, [a,b,c]]",
"[a,,b]",
"{42 : x}",
"{'hi' : x}",
NULL};
// clang-format on
static const ParserFlag always_flags[] = {kAllowHarmonyDestructuring};
RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
arraysize(always_flags));
}
TEST(DestructuringNegativeTests) {
i::FLAG_harmony_destructuring = true;
static const ParserFlag always_flags[] = {kAllowHarmonyDestructuring};
{ // All modes.
const char* context_data[][2] = {{"'use strict'; let ", " = {};"},
{"var ", " = {};"},
{"'use strict'; const ", " = {};"},
{NULL, NULL}};
// clang-format off
const char* data[] = {
"a++",
"++a",
"delete a",
"void a",
"typeof a",
"--a",
"+a",
"-a",
"~a",
"!a",
"{ x : y++ }",
"[a++]",
"(x => y)",
"a[i]", "a()",
"a.b",
"new a",
"a + a",
"a - a",
"a * a",
"a / a",
"a == a",
"a != a",
"a > a",
"a < a",
"a <<< a",
"a >>> a",
"function a() {}",
"a`bcd`",
"x => x",
"this",
"null",
"true",
"false",
"1",
"'abc'",
"class {}",
"() => x",
"{+2 : x}",
"{-2 : x}",
"var",
"[var]",
"{x : {y : var}}",
NULL};
// clang-format on
RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
arraysize(always_flags));
}
{ // Strict mode.
const char* context_data[][2] = {{"'use strict'; let ", " = {};"},
{"'use strict'; const ", " = {};"},
{NULL, NULL}};
// clang-format off
const char* data[] = {
"[eval]",
"{ a : arguments }",
"[public]",
"{ x : private }",
NULL};
// clang-format on
RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
arraysize(always_flags));
}
{ // 'yield' in generators.
const char* context_data[][2] = {
{"function*() { var ", " = {};"},
{"function*() { 'use strict'; let ", " = {};"},
{"function*() { 'use strict'; const ", " = {};"},
{NULL, NULL}};
// clang-format off
const char* data[] = {
"yield",
"[yield]",
"{ x : yield }",
NULL};
// clang-format on
RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
arraysize(always_flags));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment