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

Unified Diff: src/parsing/parser.cc

Issue 2351233002: [parser] Refactor of Parse*Statement*, part 8 (Closed)
Patch Set: Change after reviewers' comments Created 4 years, 3 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/parsing/parser.h ('k') | src/parsing/parser-base.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/parsing/parser.cc
diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc
index 77e46685fa96772dea032f88e6ffcb98073f92b5..efba7f2754d877db9a8f3d95ef6208e67d511490 100644
--- a/src/parsing/parser.cc
+++ b/src/parsing/parser.cc
@@ -1995,6 +1995,138 @@ Statement* Parser::InitializeForEachStatement(ForEachStatement* stmt,
return stmt;
}
+// Special case for legacy for
+//
+// for (var x = initializer in enumerable) body
+//
+// An initialization block of the form
+//
+// {
+// x = initializer;
+// }
+//
+// is returned in this case. It has reserved space for two statements,
+// so that (later on during parsing), the equivalent of
+//
+// for (x in enumerable) body
+//
+// is added as a second statement to it.
+Block* Parser::RewriteForVarInLegacy(const ForInfo& for_info) {
+ const DeclarationParsingResult::Declaration& decl =
+ for_info.parsing_result.declarations[0];
+ if (!IsLexicalVariableMode(for_info.parsing_result.descriptor.mode) &&
+ decl.pattern->IsVariableProxy() && decl.initializer != nullptr) {
+ DCHECK(!allow_harmony_for_in());
+ ++use_counts_[v8::Isolate::kForInInitializer];
+ const AstRawString* name = decl.pattern->AsVariableProxy()->raw_name();
+ VariableProxy* single_var = NewUnresolved(name);
+ Block* init_block = factory()->NewBlock(
+ nullptr, 2, true, for_info.parsing_result.descriptor.declaration_pos);
+ init_block->statements()->Add(
+ factory()->NewExpressionStatement(
+ factory()->NewAssignment(Token::ASSIGN, single_var,
+ decl.initializer, kNoSourcePosition),
+ kNoSourcePosition),
+ zone());
+ return init_block;
+ }
+ return nullptr;
+}
+
+// Rewrite a for-in/of statement of the form
+//
+// for (let/const/var x in/of e) b
+//
+// into
+//
+// {
+// <let x' be a temporary variable>
+// for (x' in/of e) {
+// let/const/var x;
+// x = x';
+// b;
+// }
+// let x; // for TDZ
+// }
+void Parser::DesugarBindingInForEachStatement(ForInfo* for_info,
+ Block** body_block,
+ Expression** each_variable,
+ bool* ok) {
+ DeclarationParsingResult::Declaration& decl =
+ for_info->parsing_result.declarations[0];
+ Variable* temp = NewTemporary(ast_value_factory()->dot_for_string());
+ auto each_initialization_block =
+ factory()->NewBlock(nullptr, 1, true, kNoSourcePosition);
+ {
+ auto descriptor = for_info->parsing_result.descriptor;
+ descriptor.declaration_pos = kNoSourcePosition;
+ descriptor.initialization_pos = kNoSourcePosition;
+ decl.initializer = factory()->NewVariableProxy(temp);
+
+ bool is_for_var_of =
+ for_info->mode == ForEachStatement::ITERATE &&
+ for_info->parsing_result.descriptor.mode == VariableMode::VAR;
+
+ PatternRewriter::DeclareAndInitializeVariables(
+ this, each_initialization_block, &descriptor, &decl,
+ (IsLexicalVariableMode(for_info->parsing_result.descriptor.mode) ||
+ is_for_var_of)
+ ? &for_info->bound_names
+ : nullptr,
+ CHECK_OK_VOID);
+
+ // Annex B.3.5 prohibits the form
+ // `try {} catch(e) { for (var e of {}); }`
+ // So if we are parsing a statement like `for (var ... of ...)`
+ // we need to walk up the scope chain and look for catch scopes
+ // which have a simple binding, then compare their binding against
+ // all of the names declared in the init of the for-of we're
+ // parsing.
+ if (is_for_var_of) {
+ Scope* catch_scope = scope();
+ while (catch_scope != nullptr && !catch_scope->is_declaration_scope()) {
+ if (catch_scope->is_catch_scope()) {
+ auto name = catch_scope->catch_variable_name();
+ // If it's a simple binding and the name is declared in the for loop.
+ if (name != ast_value_factory()->dot_catch_string() &&
+ for_info->bound_names.Contains(name)) {
+ ReportMessageAt(for_info->parsing_result.bindings_loc,
+ MessageTemplate::kVarRedeclaration, name);
+ *ok = false;
+ return;
+ }
+ }
+ catch_scope = catch_scope->outer_scope();
+ }
+ }
+ }
+
+ *body_block = factory()->NewBlock(nullptr, 3, false, kNoSourcePosition);
+ (*body_block)->statements()->Add(each_initialization_block, zone());
+ *each_variable = factory()->NewVariableProxy(temp, for_info->each_loc.beg_pos,
+ for_info->each_loc.end_pos);
+}
+
+// Create a TDZ for any lexically-bound names in for in/of statements.
+Block* Parser::CreateForEachStatementTDZ(Block* init_block,
+ const ForInfo& for_info, bool* ok) {
+ if (IsLexicalVariableMode(for_info.parsing_result.descriptor.mode)) {
+ DCHECK_NULL(init_block);
+
+ init_block = factory()->NewBlock(nullptr, 1, false, kNoSourcePosition);
+
+ for (int i = 0; i < for_info.bound_names.length(); ++i) {
+ // TODO(adamk): This needs to be some sort of special
+ // INTERNAL variable that's invisible to the debugger
+ // but visible to everything else.
+ Declaration* tdz_decl = DeclareVariable(for_info.bound_names[i], LET,
+ kNoSourcePosition, CHECK_OK);
+ tdz_decl->proxy()->var()->set_initializer_position(position());
+ }
+ }
+ return init_block;
+}
+
Statement* Parser::InitializeForOfStatement(ForOfStatement* for_of,
Expression* each,
Expression* iterable,
@@ -2119,9 +2251,8 @@ Statement* Parser::InitializeForOfStatement(ForOfStatement* for_of,
}
Statement* Parser::DesugarLexicalBindingsInForStatement(
- Scope* inner_scope, VariableMode mode, ZoneList<const AstRawString*>* names,
ForStatement* loop, Statement* init, Expression* cond, Statement* next,
- Statement* body, bool* ok) {
+ Statement* body, Scope* inner_scope, const ForInfo& for_info, bool* ok) {
// ES6 13.7.4.8 specifies that on each loop iteration the let variables are
// copied into a new environment. Moreover, the "next" statement must be
// evaluated not in the environment of the just completed iteration but in
@@ -2159,11 +2290,11 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
// }
// }
- DCHECK(names->length() > 0);
- ZoneList<Variable*> temps(names->length(), zone());
+ DCHECK(for_info.bound_names.length() > 0);
+ ZoneList<Variable*> temps(for_info.bound_names.length(), zone());
- Block* outer_block =
- factory()->NewBlock(NULL, names->length() + 4, false, kNoSourcePosition);
+ Block* outer_block = factory()->NewBlock(
+ nullptr, for_info.bound_names.length() + 4, false, kNoSourcePosition);
// Add statement: let/const x = i.
outer_block->statements()->Add(init, zone());
@@ -2172,8 +2303,8 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
// For each lexical variable x:
// make statement: temp_x = x.
- for (int i = 0; i < names->length(); i++) {
- VariableProxy* proxy = NewUnresolved(names->at(i));
+ for (int i = 0; i < for_info.bound_names.length(); i++) {
+ VariableProxy* proxy = NewUnresolved(for_info.bound_names[i]);
Variable* temp = NewTemporary(temp_name);
VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
Assignment* assignment = factory()->NewAssignment(Token::ASSIGN, temp_proxy,
@@ -2217,14 +2348,15 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
{
BlockState block_state(&scope_state_, inner_scope);
- Block* ignore_completion_block =
- factory()->NewBlock(NULL, names->length() + 3, true, kNoSourcePosition);
- ZoneList<Variable*> inner_vars(names->length(), zone());
+ Block* ignore_completion_block = factory()->NewBlock(
+ nullptr, for_info.bound_names.length() + 3, true, kNoSourcePosition);
+ ZoneList<Variable*> inner_vars(for_info.bound_names.length(), zone());
// For each let variable x:
// make statement: let/const x = temp_x.
- for (int i = 0; i < names->length(); i++) {
- Declaration* decl =
- DeclareVariable(names->at(i), mode, kNoSourcePosition, CHECK_OK);
+ for (int i = 0; i < for_info.bound_names.length(); i++) {
+ Declaration* decl = DeclareVariable(
+ for_info.bound_names[i], for_info.parsing_result.descriptor.mode,
+ kNoSourcePosition, CHECK_OK);
inner_vars.Add(decl->proxy()->var(), zone());
VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
Assignment* assignment = factory()->NewAssignment(
@@ -2308,7 +2440,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
// Make the comma-separated list of temp_x = x assignments.
int inner_var_proxy_pos = scanner()->location().beg_pos;
- for (int i = 0; i < names->length(); i++) {
+ for (int i = 0; i < for_info.bound_names.length(); i++) {
VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
VariableProxy* proxy =
factory()->NewVariableProxy(inner_vars.at(i), inner_var_proxy_pos);
@@ -2358,365 +2490,6 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
return outer_block;
}
-Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
- bool* ok) {
- int stmt_pos = peek_position();
- Statement* init = NULL;
- ZoneList<const AstRawString*> bound_names(1, zone());
- bool bound_names_are_lexical = false;
-
- // Create an in-between scope for let-bound iteration variables.
- BlockState for_state(&scope_state_);
- Expect(Token::FOR, CHECK_OK);
- Expect(Token::LPAREN, CHECK_OK);
- for_state.set_start_position(scanner()->location().beg_pos);
- for_state.set_is_hidden();
- DeclarationParsingResult parsing_result;
- if (peek() != Token::SEMICOLON) {
- if (peek() == Token::VAR || peek() == Token::CONST ||
- (peek() == Token::LET && IsNextLetKeyword())) {
- ParseVariableDeclarations(kForStatement, &parsing_result, nullptr,
- CHECK_OK);
-
- ForEachStatement::VisitMode mode = ForEachStatement::ENUMERATE;
- int each_beg_pos = scanner()->location().beg_pos;
- int each_end_pos = scanner()->location().end_pos;
-
- if (CheckInOrOf(&mode)) {
- if (parsing_result.declarations.length() != 1) {
- ReportMessageAt(parsing_result.bindings_loc,
- MessageTemplate::kForInOfLoopMultiBindings,
- ForEachStatement::VisitModeString(mode));
- *ok = false;
- return nullptr;
- }
- DeclarationParsingResult::Declaration& decl =
- parsing_result.declarations[0];
- if (parsing_result.first_initializer_loc.IsValid() &&
- (is_strict(language_mode()) || mode == ForEachStatement::ITERATE ||
- IsLexicalVariableMode(parsing_result.descriptor.mode) ||
- !decl.pattern->IsVariableProxy() || allow_harmony_for_in())) {
- // Only increment the use count if we would have let this through
- // without the flag.
- if (allow_harmony_for_in()) {
- ++use_counts_[v8::Isolate::kForInInitializer];
- }
- ReportMessageAt(parsing_result.first_initializer_loc,
- MessageTemplate::kForInOfLoopInitializer,
- ForEachStatement::VisitModeString(mode));
- *ok = false;
- return nullptr;
- }
-
- Block* init_block = nullptr;
- bound_names_are_lexical =
- IsLexicalVariableMode(parsing_result.descriptor.mode);
-
- // special case for legacy for (var ... = ... in ...)
- if (!bound_names_are_lexical && decl.pattern->IsVariableProxy() &&
- decl.initializer != nullptr) {
- DCHECK(!allow_harmony_for_in());
- ++use_counts_[v8::Isolate::kForInInitializer];
- const AstRawString* name =
- decl.pattern->AsVariableProxy()->raw_name();
- VariableProxy* single_var = NewUnresolved(name);
- init_block = factory()->NewBlock(
- nullptr, 2, true, parsing_result.descriptor.declaration_pos);
- init_block->statements()->Add(
- factory()->NewExpressionStatement(
- factory()->NewAssignment(Token::ASSIGN, single_var,
- decl.initializer, kNoSourcePosition),
- kNoSourcePosition),
- zone());
- }
-
- // Rewrite a for-in/of statement of the form
- //
- // for (let/const/var x in/of e) b
- //
- // into
- //
- // {
- // <let x' be a temporary variable>
- // for (x' in/of e) {
- // let/const/var x;
- // x = x';
- // b;
- // }
- // let x; // for TDZ
- // }
-
- Variable* temp = NewTemporary(ast_value_factory()->dot_for_string());
- ForEachStatement* loop =
- factory()->NewForEachStatement(mode, labels, stmt_pos);
- ParserTarget target(this, loop);
-
- int each_keyword_position = scanner()->location().beg_pos;
-
- Expression* enumerable;
- if (mode == ForEachStatement::ITERATE) {
- ExpressionClassifier classifier(this);
- enumerable = ParseAssignmentExpression(true, CHECK_OK);
- RewriteNonPattern(CHECK_OK);
- } else {
- enumerable = ParseExpression(true, CHECK_OK);
- }
-
- Expect(Token::RPAREN, CHECK_OK);
-
-
- Block* body_block =
- factory()->NewBlock(NULL, 3, false, kNoSourcePosition);
-
- Statement* final_loop;
- {
- ReturnExprScope no_tail_calls(function_state_,
- ReturnExprContext::kInsideForInOfBody);
- BlockState block_state(&scope_state_);
- block_state.set_start_position(scanner()->location().beg_pos);
-
- Statement* body = ParseScopedStatement(NULL, true, CHECK_OK);
-
- auto each_initialization_block =
- factory()->NewBlock(nullptr, 1, true, kNoSourcePosition);
- {
- auto descriptor = parsing_result.descriptor;
- descriptor.declaration_pos = kNoSourcePosition;
- descriptor.initialization_pos = kNoSourcePosition;
- decl.initializer = factory()->NewVariableProxy(temp);
-
- bool is_for_var_of =
- mode == ForEachStatement::ITERATE &&
- parsing_result.descriptor.mode == VariableMode::VAR;
-
- PatternRewriter::DeclareAndInitializeVariables(
- this, each_initialization_block, &descriptor, &decl,
- bound_names_are_lexical || is_for_var_of ? &bound_names
- : nullptr,
- CHECK_OK);
-
- // Annex B.3.5 prohibits the form
- // `try {} catch(e) { for (var e of {}); }`
- // So if we are parsing a statement like `for (var ... of ...)`
- // we need to walk up the scope chain and look for catch scopes
- // which have a simple binding, then compare their binding against
- // all of the names declared in the init of the for-of we're
- // parsing.
- if (is_for_var_of) {
- Scope* catch_scope = scope();
- while (catch_scope != nullptr &&
- !catch_scope->is_declaration_scope()) {
- if (catch_scope->is_catch_scope()) {
- auto name = catch_scope->catch_variable_name();
- if (name !=
- ast_value_factory()
- ->dot_catch_string()) { // i.e. is a simple binding
- if (bound_names.Contains(name)) {
- ReportMessageAt(parsing_result.bindings_loc,
- MessageTemplate::kVarRedeclaration, name);
- *ok = false;
- return nullptr;
- }
- }
- }
- catch_scope = catch_scope->outer_scope();
- }
- }
- }
-
- body_block->statements()->Add(each_initialization_block, zone());
- body_block->statements()->Add(body, zone());
- VariableProxy* temp_proxy =
- factory()->NewVariableProxy(temp, each_beg_pos, each_end_pos);
- final_loop = InitializeForEachStatement(
- loop, temp_proxy, enumerable, body_block, each_keyword_position);
- block_state.set_end_position(scanner()->location().end_pos);
- body_block->set_scope(block_state.FinalizedBlockScope());
- }
-
- // Create a TDZ for any lexically-bound names.
- if (bound_names_are_lexical) {
- DCHECK_NULL(init_block);
-
- init_block =
- factory()->NewBlock(nullptr, 1, false, kNoSourcePosition);
-
- for (int i = 0; i < bound_names.length(); ++i) {
- // TODO(adamk): This needs to be some sort of special
- // INTERNAL variable that's invisible to the debugger
- // but visible to everything else.
- Declaration* tdz_decl = DeclareVariable(
- bound_names[i], LET, kNoSourcePosition, CHECK_OK);
- tdz_decl->proxy()->var()->set_initializer_position(position());
- }
- }
-
- for_state.set_end_position(scanner()->location().end_pos);
- Scope* for_scope = for_state.FinalizedBlockScope();
- // Parsed for-in loop w/ variable declarations.
- if (init_block != nullptr) {
- init_block->statements()->Add(final_loop, zone());
- init_block->set_scope(for_scope);
- return init_block;
- } else {
- DCHECK_NULL(for_scope);
- return final_loop;
- }
- } else {
- bound_names_are_lexical =
- IsLexicalVariableMode(parsing_result.descriptor.mode);
- init = BuildInitializationBlock(
- &parsing_result, bound_names_are_lexical ? &bound_names : nullptr,
- CHECK_OK);
- }
- } else {
- int lhs_beg_pos = peek_position();
- ExpressionClassifier classifier(this);
- Expression* expression = ParseExpressionCoverGrammar(false, CHECK_OK);
- int lhs_end_pos = scanner()->location().end_pos;
- ForEachStatement::VisitMode mode = ForEachStatement::ENUMERATE;
-
- bool is_for_each = CheckInOrOf(&mode);
- bool is_destructuring = is_for_each && (expression->IsArrayLiteral() ||
- expression->IsObjectLiteral());
-
- if (is_destructuring) {
- ValidateAssignmentPattern(CHECK_OK);
- } else {
- RewriteNonPattern(CHECK_OK);
- }
-
- if (is_for_each) {
- if (!is_destructuring) {
- expression = CheckAndRewriteReferenceExpression(
- expression, lhs_beg_pos, lhs_end_pos,
- MessageTemplate::kInvalidLhsInFor, kSyntaxError, CHECK_OK);
- }
-
- ForEachStatement* loop =
- factory()->NewForEachStatement(mode, labels, stmt_pos);
- ParserTarget target(this, loop);
-
- int each_keyword_position = scanner()->location().beg_pos;
-
- Expression* enumerable;
- if (mode == ForEachStatement::ITERATE) {
- ExpressionClassifier classifier(this);
- enumerable = ParseAssignmentExpression(true, CHECK_OK);
- RewriteNonPattern(CHECK_OK);
- } else {
- enumerable = ParseExpression(true, CHECK_OK);
- }
-
- Expect(Token::RPAREN, CHECK_OK);
-
- {
- ReturnExprScope no_tail_calls(function_state_,
- ReturnExprContext::kInsideForInOfBody);
- BlockState block_state(&scope_state_);
- block_state.set_start_position(scanner()->location().beg_pos);
-
- // For legacy compat reasons, give for loops similar treatment to
- // if statements in allowing a function declaration for a body
- Statement* body = ParseScopedStatement(NULL, true, CHECK_OK);
- block_state.set_end_position(scanner()->location().end_pos);
- Statement* final_loop = InitializeForEachStatement(
- loop, expression, enumerable, body, each_keyword_position);
-
- Scope* for_scope = for_state.FinalizedBlockScope();
- DCHECK_NULL(for_scope);
- USE(for_scope);
- Scope* block_scope = block_state.FinalizedBlockScope();
- DCHECK_NULL(block_scope);
- USE(block_scope);
- return final_loop;
- }
- } else {
- init = factory()->NewExpressionStatement(expression, lhs_beg_pos);
- }
- }
- }
-
- // Standard 'for' loop
- ForStatement* loop = factory()->NewForStatement(labels, stmt_pos);
- ParserTarget target(this, loop);
-
- // Parsed initializer at this point.
- Expect(Token::SEMICOLON, CHECK_OK);
-
- Expression* cond = NULL;
- Statement* next = NULL;
- Statement* body = NULL;
-
- // If there are let bindings, then condition and the next statement of the
- // for loop must be parsed in a new scope.
- Scope* inner_scope = scope();
- // TODO(verwaest): Allocate this through a ScopeState as well.
- if (bound_names_are_lexical && bound_names.length() > 0) {
- inner_scope = NewScopeWithParent(inner_scope, BLOCK_SCOPE);
- inner_scope->set_start_position(scanner()->location().beg_pos);
- }
- {
- BlockState block_state(&scope_state_, inner_scope);
-
- if (peek() != Token::SEMICOLON) {
- cond = ParseExpression(true, CHECK_OK);
- }
- Expect(Token::SEMICOLON, CHECK_OK);
-
- if (peek() != Token::RPAREN) {
- Expression* exp = ParseExpression(true, CHECK_OK);
- next = factory()->NewExpressionStatement(exp, exp->position());
- }
- Expect(Token::RPAREN, CHECK_OK);
-
- body = ParseScopedStatement(NULL, true, CHECK_OK);
- }
-
- Statement* result = NULL;
- if (bound_names_are_lexical && bound_names.length() > 0) {
- result = DesugarLexicalBindingsInForStatement(
- inner_scope, parsing_result.descriptor.mode, &bound_names, loop, init,
- cond, next, body, CHECK_OK);
- for_state.set_end_position(scanner()->location().end_pos);
- } else {
- for_state.set_end_position(scanner()->location().end_pos);
- Scope* for_scope = for_state.FinalizedBlockScope();
- if (for_scope) {
- // Rewrite a for statement of the form
- // for (const x = i; c; n) b
- //
- // into
- //
- // {
- // const x = i;
- // for (; c; n) b
- // }
- //
- // or, desugar
- // for (; c; n) b
- // into
- // {
- // for (; c; n) b
- // }
- // just in case b introduces a lexical binding some other way, e.g., if b
- // is a FunctionDeclaration.
- Block* block = factory()->NewBlock(NULL, 2, false, kNoSourcePosition);
- if (init != nullptr) {
- block->statements()->Add(init, zone());
- }
- block->statements()->Add(loop, zone());
- block->set_scope(for_scope);
- loop->Initialize(NULL, cond, next, body);
- result = block;
- } else {
- loop->Initialize(init, cond, next, body);
- result = loop;
- }
- }
- return result;
-}
-
void Parser::ParseArrowFunctionFormalParameters(
ParserFormalParameters* parameters, Expression* expr, int end_pos,
bool* ok) {
« no previous file with comments | « src/parsing/parser.h ('k') | src/parsing/parser-base.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698