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

Unified Diff: src/parsing/parser-base.h

Issue 2351233002: [parser] Refactor of Parse*Statement*, part 8 (Closed)
Patch Set: The real patch 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
Index: src/parsing/parser-base.h
diff --git a/src/parsing/parser-base.h b/src/parsing/parser-base.h
index 3171e57144e09562b294fd26ff934481c981848d..b5801662a5d62253fc2144b0356297c9fe19f623 100644
--- a/src/parsing/parser-base.h
+++ b/src/parsing/parser-base.h
@@ -656,6 +656,21 @@ class ParserBase {
TailCallExpressionList tail_call_expressions;
};
+ struct ForInfo {
+ public:
+ explicit ForInfo(ParserBase* parser)
+ : bound_names(1, parser->zone()),
+ bound_names_are_lexical(false),
+ mode(ForEachStatement::ENUMERATE),
+ each_loc(),
+ parsing_result() {}
+ ZoneList<const AstRawString*> bound_names;
+ bool bound_names_are_lexical;
+ ForEachStatement::VisitMode mode;
+ Scanner::Location each_loc;
+ DeclarationParsingResult parsing_result;
+ };
+
DeclarationScope* NewScriptScope() const {
return new (zone()) DeclarationScope(zone(), ast_value_factory());
}
@@ -1250,7 +1265,7 @@ class ParserBase {
StatementT ParseSwitchStatement(ZoneList<const AstRawString*>* labels,
bool* ok);
StatementT ParseTryStatement(bool* ok);
- Statement* ParseForStatement(ZoneList<const AstRawString*>* labels, bool* ok);
+ StatementT ParseForStatement(ZoneList<const AstRawString*>* labels, bool* ok);
bool IsNextLetKeyword();
bool IsTrivialExpression();
@@ -4350,7 +4365,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement(
case Token::WHILE:
return ParseWhileStatement(labels, ok);
case Token::FOR:
- return impl()->ParseForStatement(labels, ok);
+ return ParseForStatement(labels, ok);
case Token::CONTINUE:
case Token::BREAK:
case Token::RETURN:
@@ -4977,12 +4992,11 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseTryStatement(
catch_info, pos);
}
-Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
- bool* ok) {
+template <typename Impl>
+typename ParserBase<Impl>::StatementT ParserBase<Impl>::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;
+ ForInfo for_info(this);
// Create an in-between scope for let-bound iteration variables.
BlockState for_state(&scope_state_);
@@ -4990,190 +5004,96 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
Expect(Token::LPAREN, CHECK_OK);
for_state.set_start_position(scanner()->location().beg_pos);
for_state.set_is_hidden();
- DeclarationParsingResult parsing_result;
+
+ StatementT init = impl()->NullStatement();
if (peek() != Token::SEMICOLON) {
+ // An initializer is present.
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));
+ // The initializer contains declarations.
+ ParseVariableDeclarations(kForStatement, &for_info.parsing_result,
+ nullptr, CHECK_OK);
+ for_info.bound_names_are_lexical =
marja 2016/09/20 19:36:30 bound_names_are_lexical is now redundant, right? M
nickie 2016/09/21 09:20:02 Yes. I'm removing it from ForInfo but I'm keeping
+ IsLexicalVariableMode(for_info.parsing_result.descriptor.mode);
+ for_info.each_loc = scanner()->location();
+
+ if (CheckInOrOf(&for_info.mode)) {
+ // Just one declaration followed by in/of.
+ if (for_info.parsing_result.declarations.length() != 1) {
+ impl()->ReportMessageAt(
+ for_info.parsing_result.bindings_loc,
+ MessageTemplate::kForInOfLoopMultiBindings,
+ ForEachStatement::VisitModeString(for_info.mode));
*ok = false;
- return nullptr;
+ return impl()->NullStatement();
}
- 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())) {
+ if (for_info.parsing_result.first_initializer_loc.IsValid() &&
+ (is_strict(language_mode()) ||
+ for_info.mode == ForEachStatement::ITERATE ||
marja 2016/09/21 08:23:21 Random whining unrelated to this CL: Why do we nee
nickie 2016/09/21 09:20:02 I agree. Also, it seems that this is used only lo
+ IsLexicalVariableMode(for_info.parsing_result.descriptor.mode) ||
+ !impl()->IsIdentifier(
+ for_info.parsing_result.declarations[0].pattern) ||
+ 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];
+ impl()->CountUsage(v8::Isolate::kForInInitializer);
}
- ReportMessageAt(parsing_result.first_initializer_loc,
- MessageTemplate::kForInOfLoopInitializer,
- ForEachStatement::VisitModeString(mode));
+ impl()->ReportMessageAt(
+ for_info.parsing_result.first_initializer_loc,
+ MessageTemplate::kForInOfLoopInitializer,
+ ForEachStatement::VisitModeString(for_info.mode));
*ok = false;
- return nullptr;
+ return impl()->NullStatement();
}
- 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());
- }
+ BlockT init_block = impl()->RewriteForVarInLegacy(&for_info);
+
+ auto loop =
marja 2016/09/20 19:36:30 I was thinking about the use of "auto" here (and b
nickie 2016/09/21 09:20:02 Yes, that's precisely what it does. (BTW, it's us
marja 2016/09/21 10:31:42 Ok, then it's fine.
+ factory()->NewForEachStatement(for_info.mode, labels, stmt_pos);
+ typename Types::Target target(this, loop);
+
+ int each_keyword_pos = scanner()->location().beg_pos;
- // 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) {
+ ExpressionT enumerable = impl()->EmptyExpression();
+ if (for_info.mode == ForEachStatement::ITERATE) {
ExpressionClassifier classifier(this);
enumerable = ParseAssignmentExpression(true, CHECK_OK);
- RewriteNonPattern(CHECK_OK);
+ impl()->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;
+ StatementT final_loop = impl()->NullStatement();
{
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();
- }
- }
- }
+ StatementT body = ParseScopedStatement(nullptr, true, CHECK_OK);
+
+ std::pair<BlockT, ExpressionT> body_block_and_each_variable =
+ impl()->DesugarBindingInForEachStatement(&for_info, CHECK_OK);
+ body_block_and_each_variable.first->statements()->Add(body, zone());
adamk 2016/09/20 16:34:31 Please create a variable for body_block, it'll mak
marja 2016/09/21 08:23:21 Why do we need the pair anyway, it looks like we'r
nickie 2016/09/21 09:20:02 After offline discussion, I'm removing the pair an
nickie 2016/09/21 09:20:02 See comment below.
+ final_loop = impl()->InitializeForEachStatement(
+ loop, body_block_and_each_variable.second, enumerable,
+ body_block_and_each_variable.first, each_keyword_pos);
- 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());
+ body_block_and_each_variable.first->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());
- }
- }
+ init_block =
+ impl()->CreateForEachStatementTDZ(init_block, &for_info, ok);
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) {
+ if (!impl()->IsNullStatement(init_block)) {
init_block->statements()->Add(final_loop, zone());
init_block->set_scope(for_scope);
return init_block;
@@ -5182,47 +5102,48 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
return final_loop;
}
} else {
- bound_names_are_lexical =
- IsLexicalVariableMode(parsing_result.descriptor.mode);
- init = BuildInitializationBlock(
- &parsing_result, bound_names_are_lexical ? &bound_names : nullptr,
+ // One or more declaration not followed by in/of.
+ init = impl()->BuildInitializationBlock(
+ &for_info.parsing_result,
+ for_info.bound_names_are_lexical ? &for_info.bound_names : nullptr,
CHECK_OK);
}
} else {
+ // The initializer does not contain declarations.
int lhs_beg_pos = peek_position();
ExpressionClassifier classifier(this);
- Expression* expression = ParseExpressionCoverGrammar(false, CHECK_OK);
+ ExpressionT 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_for_each = CheckInOrOf(&for_info.mode);
bool is_destructuring = is_for_each && (expression->IsArrayLiteral() ||
expression->IsObjectLiteral());
if (is_destructuring) {
ValidateAssignmentPattern(CHECK_OK);
} else {
- RewriteNonPattern(CHECK_OK);
+ impl()->RewriteNonPattern(CHECK_OK);
}
if (is_for_each) {
+ // Initializer is reference followed by in/of.
if (!is_destructuring) {
- expression = CheckAndRewriteReferenceExpression(
+ expression = impl()->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);
+ auto loop =
+ factory()->NewForEachStatement(for_info.mode, labels, stmt_pos);
+ typename Types::Target target(this, loop);
- int each_keyword_position = scanner()->location().beg_pos;
+ int each_keyword_pos = scanner()->location().beg_pos;
- Expression* enumerable;
- if (mode == ForEachStatement::ITERATE) {
+ ExpressionT enumerable = impl()->EmptyExpression();
+ if (for_info.mode == ForEachStatement::ITERATE) {
ExpressionClassifier classifier(this);
enumerable = ParseAssignmentExpression(true, CHECK_OK);
- RewriteNonPattern(CHECK_OK);
+ impl()->RewriteNonPattern(CHECK_OK);
} else {
enumerable = ParseExpression(true, CHECK_OK);
}
@@ -5237,10 +5158,10 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
// 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);
+ StatementT body = ParseScopedStatement(nullptr, true, CHECK_OK);
block_state.set_end_position(scanner()->location().end_pos);
- Statement* final_loop = InitializeForEachStatement(
- loop, expression, enumerable, body, each_keyword_position);
+ StatementT final_loop = impl()->InitializeForEachStatement(
+ loop, expression, enumerable, body, each_keyword_pos);
Scope* for_scope = for_state.FinalizedBlockScope();
DCHECK_NULL(for_scope);
@@ -5251,27 +5172,27 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
return final_loop;
}
} else {
+ // Initializer is just an expression.
init = factory()->NewExpressionStatement(expression, lhs_beg_pos);
}
}
}
- // Standard 'for' loop
- ForStatement* loop = factory()->NewForStatement(labels, stmt_pos);
- ParserTarget target(this, loop);
+ // Standard 'for' loop, we have parsed the initializer at this point.
+ auto loop = factory()->NewForStatement(labels, stmt_pos);
+ typename Types::Target target(this, loop);
- // Parsed initializer at this point.
Expect(Token::SEMICOLON, CHECK_OK);
- Expression* cond = NULL;
- Statement* next = NULL;
- Statement* body = NULL;
+ ExpressionT cond = impl()->EmptyExpression();
+ StatementT next = impl()->NullStatement();
+ StatementT body = impl()->NullStatement();
// 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) {
+ if (for_info.bound_names_are_lexical && for_info.bound_names.length() > 0) {
inner_scope = NewScopeWithParent(inner_scope, BLOCK_SCOPE);
inner_scope->set_start_position(scanner()->location().beg_pos);
}
@@ -5284,24 +5205,23 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
Expect(Token::SEMICOLON, CHECK_OK);
if (peek() != Token::RPAREN) {
- Expression* exp = ParseExpression(true, CHECK_OK);
+ ExpressionT exp = ParseExpression(true, CHECK_OK);
next = factory()->NewExpressionStatement(exp, exp->position());
}
Expect(Token::RPAREN, CHECK_OK);
- body = ParseScopedStatement(NULL, true, CHECK_OK);
+ body = ParseScopedStatement(nullptr, 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);
+ if (for_info.bound_names_are_lexical && for_info.bound_names.length() > 0) {
+ auto result = impl()->DesugarLexicalBindingsInForStatement(
+ loop, init, cond, next, body, inner_scope, &for_info, CHECK_OK);
for_state.set_end_position(scanner()->location().end_pos);
+ return result;
} else {
for_state.set_end_position(scanner()->location().end_pos);
Scope* for_scope = for_state.FinalizedBlockScope();
- if (for_scope) {
+ if (for_scope != nullptr) {
// Rewrite a for statement of the form
// for (const x = i; c; n) b
//
@@ -5320,20 +5240,19 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
// }
// 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) {
+ BlockT block = factory()->NewBlock(NULL, 2, false, kNoSourcePosition);
+ if (!impl()->IsNullStatement(init)) {
block->statements()->Add(init, zone());
}
block->statements()->Add(loop, zone());
block->set_scope(for_scope);
- loop->Initialize(NULL, cond, next, body);
- result = block;
+ loop->Initialize(init, cond, next, body);
+ return block;
} else {
loop->Initialize(init, cond, next, body);
- result = loop;
+ return loop;
}
}
- return result;
}
#undef CHECK_OK

Powered by Google App Engine
This is Rietveld 408576698