Commit a7fce186 authored by dslomov's avatar dslomov Committed by Commit bot

[destructuring] Parse binding patterns in formal parameters.

R=arv@chromium.org,wingo@igalia.com,caitpotter88@gmail.com
LOG=N
BUG=v8:811

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

Cr-Commit-Position: refs/heads/master@{#29029}
parent 6e5b9ffe
...@@ -1183,13 +1183,19 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info, ...@@ -1183,13 +1183,19 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
scope->set_start_position(shared_info->start_position()); scope->set_start_position(shared_info->start_position());
ExpressionClassifier formals_classifier; ExpressionClassifier formals_classifier;
bool has_rest = false; bool has_rest = false;
if (Check(Token::LPAREN)) { {
// '(' StrictFormalParameters ')' // Parsing patterns as variable reference expression creates
ParseFormalParameterList(scope, &has_rest, &formals_classifier, &ok); // NewUnresolved references in current scope. Entrer arrow function
if (ok) ok = Check(Token::RPAREN); // scope for formal parameter parsing.
} else { BlockState block_state(&scope_, scope);
// BindingIdentifier if (Check(Token::LPAREN)) {
ParseFormalParameter(scope, has_rest, &formals_classifier, &ok); // '(' StrictFormalParameters ')'
ParseFormalParameterList(scope, &has_rest, &formals_classifier, &ok);
if (ok) ok = Check(Token::RPAREN);
} else {
// BindingIdentifier
ParseFormalParameter(scope, has_rest, &formals_classifier, &ok);
}
} }
if (ok) { if (ok) {
...@@ -3805,7 +3811,10 @@ void ParserTraits::ParseArrowFunctionFormalParameters( ...@@ -3805,7 +3811,10 @@ void ParserTraits::ParseArrowFunctionFormalParameters(
expr = expr->AsSpread()->expression(); expr = expr->AsSpread()->expression();
} }
DCHECK(expr->IsVariableProxy()); if (!expr->IsVariableProxy()) {
// TODO(dslomov): support pattern desugaring
return;
}
DCHECK(!expr->AsVariableProxy()->is_this()); DCHECK(!expr->AsVariableProxy()->is_this());
const AstRawString* raw_name = expr->AsVariableProxy()->raw_name(); const AstRawString* raw_name = expr->AsVariableProxy()->raw_name();
...@@ -3818,7 +3827,7 @@ void ParserTraits::ParseArrowFunctionFormalParameters( ...@@ -3818,7 +3827,7 @@ void ParserTraits::ParseArrowFunctionFormalParameters(
parser_->scope_->RemoveUnresolved(expr->AsVariableProxy()); parser_->scope_->RemoveUnresolved(expr->AsVariableProxy());
ExpressionClassifier classifier; ExpressionClassifier classifier;
DeclareFormalParameter(scope, raw_name, &classifier, *has_rest); DeclareFormalParameter(scope, expr, &classifier, *has_rest);
if (!duplicate_loc->IsValid()) { if (!duplicate_loc->IsValid()) {
*duplicate_loc = classifier.duplicate_formal_parameter_error().location; *duplicate_loc = classifier.duplicate_formal_parameter_error().location;
} }
......
...@@ -754,7 +754,7 @@ class ParserTraits { ...@@ -754,7 +754,7 @@ class ParserTraits {
V8_INLINE Scope* NewScope(Scope* parent_scope, ScopeType scope_type, V8_INLINE Scope* NewScope(Scope* parent_scope, ScopeType scope_type,
FunctionKind kind = kNormalFunction); FunctionKind kind = kNormalFunction);
V8_INLINE void DeclareFormalParameter(Scope* scope, const AstRawString* name, V8_INLINE void DeclareFormalParameter(Scope* scope, Expression* name,
ExpressionClassifier* classifier, ExpressionClassifier* classifier,
bool is_rest); bool is_rest);
void ParseArrowFunctionFormalParameters(Scope* scope, Expression* params, void ParseArrowFunctionFormalParameters(Scope* scope, Expression* params,
...@@ -1270,11 +1270,16 @@ Expression* ParserTraits::SpreadCallNew( ...@@ -1270,11 +1270,16 @@ Expression* ParserTraits::SpreadCallNew(
} }
void ParserTraits::DeclareFormalParameter(Scope* scope, void ParserTraits::DeclareFormalParameter(Scope* scope, Expression* pattern,
const AstRawString* name,
ExpressionClassifier* classifier, ExpressionClassifier* classifier,
bool is_rest) { bool is_rest) {
bool is_duplicate = false; bool is_duplicate = false;
if (!pattern->IsVariableProxy()) {
// TODO(dslomov): implement.
DCHECK(parser_->allow_harmony_destructuring());
return;
}
auto name = pattern->AsVariableProxy()->raw_name();
Variable* var = scope->DeclareParameter(name, VAR, is_rest, &is_duplicate); Variable* var = scope->DeclareParameter(name, VAR, is_rest, &is_duplicate);
if (is_sloppy(scope->language_mode())) { if (is_sloppy(scope->language_mode())) {
// TODO(sigurds) Mark every parameter as maybe assigned. This is a // TODO(sigurds) Mark every parameter as maybe assigned. This is a
......
...@@ -549,7 +549,7 @@ PreParser::Statement PreParser::ParseVariableDeclarations( ...@@ -549,7 +549,7 @@ 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 (!FLAG_harmony_destructuring && !pattern.IsIdentifier()) { if (!allow_harmony_destructuring() && !pattern.IsIdentifier()) {
ReportUnexpectedToken(next); ReportUnexpectedToken(next);
*ok = false; *ok = false;
return Statement::Default(); return Statement::Default();
......
...@@ -555,7 +555,7 @@ class ParserBase : public Traits { ...@@ -555,7 +555,7 @@ class ParserBase : public Traits {
ExpressionT expr, bool* ok) { ExpressionT expr, bool* ok) {
if (classifier->is_valid_binding_pattern()) { if (classifier->is_valid_binding_pattern()) {
// A simple arrow formal parameter: IDENTIFIER => BODY. // A simple arrow formal parameter: IDENTIFIER => BODY.
if (!this->IsIdentifier(expr)) { if (!allow_harmony_destructuring() && !this->IsIdentifier(expr)) {
Traits::ReportMessageAt(scanner()->location(), Traits::ReportMessageAt(scanner()->location(),
MessageTemplate::kUnexpectedToken, MessageTemplate::kUnexpectedToken,
Token::String(scanner()->current_token())); Token::String(scanner()->current_token()));
...@@ -1555,7 +1555,7 @@ class PreParserTraits { ...@@ -1555,7 +1555,7 @@ class PreParserTraits {
return !tag.IsNoTemplateTag(); return !tag.IsNoTemplateTag();
} }
void DeclareFormalParameter(Scope* scope, PreParserIdentifier param, void DeclareFormalParameter(Scope* scope, PreParserExpression pattern,
ExpressionClassifier* classifier, bool is_rest) {} ExpressionClassifier* classifier, bool is_rest) {}
void CheckConflictingVarDeclarations(Scope* scope, bool* ok) {} void CheckConflictingVarDeclarations(Scope* scope, bool* ok) {}
...@@ -3487,10 +3487,21 @@ void ParserBase<Traits>::ParseFormalParameter(Scope* scope, bool is_rest, ...@@ -3487,10 +3487,21 @@ void ParserBase<Traits>::ParseFormalParameter(Scope* scope, bool is_rest,
bool* ok) { bool* ok) {
// FormalParameter[Yield,GeneratorParameter] : // FormalParameter[Yield,GeneratorParameter] :
// BindingElement[?Yield, ?GeneratorParameter] // BindingElement[?Yield, ?GeneratorParameter]
IdentifierT name = ParseAndClassifyIdentifier(classifier, ok);
Token::Value next = peek();
ExpressionT pattern = ParsePrimaryExpression(classifier, ok);
if (!*ok) return;
ValidateBindingPattern(classifier, ok);
if (!*ok) return; if (!*ok) return;
Traits::DeclareFormalParameter(scope, name, classifier, is_rest); if (!allow_harmony_destructuring() && !Traits::IsIdentifier(pattern)) {
ReportUnexpectedToken(next);
*ok = false;
return;
}
Traits::DeclareFormalParameter(scope, pattern, classifier, is_rest);
} }
......
...@@ -6380,11 +6380,17 @@ TEST(StrongModeFreeVariablesNotDeclared) { ...@@ -6380,11 +6380,17 @@ TEST(StrongModeFreeVariablesNotDeclared) {
TEST(DestructuringPositiveTests) { TEST(DestructuringPositiveTests) {
i::FLAG_harmony_destructuring = true; i::FLAG_harmony_destructuring = true;
i::FLAG_harmony_arrow_functions = true;
i::FLAG_harmony_computed_property_names = true; i::FLAG_harmony_computed_property_names = true;
const char* context_data[][2] = {{"'use strict'; let ", " = {};"}, const char* context_data[][2] = {{"'use strict'; let ", " = {};"},
{"var ", " = {};"}, {"var ", " = {};"},
{"'use strict'; const ", " = {};"}, {"'use strict'; const ", " = {};"},
{"function f(", ") {}"},
{"function f(argument1, ", ") {}"},
{"var f = (", ") => {};"},
{"var f = ", " => {};"},
{"var f = (argument1,", ") => {};"},
{NULL, NULL}}; {NULL, NULL}};
// clang-format off // clang-format off
...@@ -6424,9 +6430,9 @@ TEST(DestructuringPositiveTests) { ...@@ -6424,9 +6430,9 @@ TEST(DestructuringPositiveTests) {
"[a,,...rest]", "[a,,...rest]",
NULL}; NULL};
// clang-format on // clang-format on
static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals, static const ParserFlag always_flags[] = {
kAllowHarmonyComputedPropertyNames, kAllowHarmonyObjectLiterals, kAllowHarmonyComputedPropertyNames,
kAllowHarmonyDestructuring}; kAllowHarmonyArrowFunctions, kAllowHarmonyDestructuring};
RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags, RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
arraysize(always_flags)); arraysize(always_flags));
} }
...@@ -6434,15 +6440,21 @@ TEST(DestructuringPositiveTests) { ...@@ -6434,15 +6440,21 @@ TEST(DestructuringPositiveTests) {
TEST(DestructuringNegativeTests) { TEST(DestructuringNegativeTests) {
i::FLAG_harmony_destructuring = true; i::FLAG_harmony_destructuring = true;
i::FLAG_harmony_arrow_functions = true;
i::FLAG_harmony_computed_property_names = true; i::FLAG_harmony_computed_property_names = true;
static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals, static const ParserFlag always_flags[] = {
kAllowHarmonyComputedPropertyNames, kAllowHarmonyObjectLiterals, kAllowHarmonyComputedPropertyNames,
kAllowHarmonyDestructuring}; kAllowHarmonyArrowFunctions, kAllowHarmonyDestructuring};
{ // All modes. { // All modes.
const char* context_data[][2] = {{"'use strict'; let ", " = {};"}, const char* context_data[][2] = {{"'use strict'; let ", " = {};"},
{"var ", " = {};"}, {"var ", " = {};"},
{"'use strict'; const ", " = {};"}, {"'use strict'; const ", " = {};"},
{"function f(", ") {}"},
{"function f(argument1, ", ") {}"},
{"var f = (", ") => {};"},
{"var f = ", " => {};"},
{"var f = (argument1,", ") => {};"},
{NULL, NULL}}; {NULL, NULL}};
// clang-format off // clang-format off
...@@ -6475,7 +6487,6 @@ TEST(DestructuringNegativeTests) { ...@@ -6475,7 +6487,6 @@ TEST(DestructuringNegativeTests) {
"a >>> a", "a >>> a",
"function a() {}", "function a() {}",
"a`bcd`", "a`bcd`",
"x => x",
"this", "this",
"null", "null",
"true", "true",
...@@ -6483,7 +6494,6 @@ TEST(DestructuringNegativeTests) { ...@@ -6483,7 +6494,6 @@ TEST(DestructuringNegativeTests) {
"1", "1",
"'abc'", "'abc'",
"class {}", "class {}",
"() => x",
"{+2 : x}", "{+2 : x}",
"{-2 : x}", "{-2 : x}",
"var", "var",
...@@ -6509,11 +6519,34 @@ TEST(DestructuringNegativeTests) { ...@@ -6509,11 +6519,34 @@ TEST(DestructuringNegativeTests) {
arraysize(always_flags)); arraysize(always_flags));
} }
{ // Strict mode. { // All modes.
const char* context_data[][2] = {{"'use strict'; let ", " = {};"}, const char* context_data[][2] = {{"'use strict'; let ", " = {};"},
{"var ", " = {};"},
{"'use strict'; const ", " = {};"}, {"'use strict'; const ", " = {};"},
{"function f(", ") {}"},
{"function f(argument1, ", ") {}"},
{"var f = (", ") => {};"},
{"var f = (argument1,", ") => {};"},
{NULL, NULL}}; {NULL, NULL}};
// clang-format off
const char* data[] = {
"x => x",
"() => x",
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 ", " = {};"},
{"'use strict'; function f(", ") {}"},
{"'use strict'; function f(argument1, ", ") {}"},
{NULL, NULL}};
// clang-format off // clang-format off
const char* data[] = { const char* data[] = {
"[eval]", "[eval]",
......
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