[parser] Refactor of Parse*Statement*, part 6

This patch moves the following parsing method to ParserBase:

- ParseSwitchStatement

It also removes ParseCaseClause and merges it with ParseSwitchStatement,
mainly to avoid the complexity of introducing one more abstract typedef
to be shared between parser implementations, but also because the merged
ParseSwitchStatement is now only 59 lines.

R=adamk@chromium.org, marja@chromium.org
BUG=
LOG=N

Review-Url: https://codereview.chromium.org/2324843005
Cr-Commit-Position: refs/heads/master@{#39337}
This commit is contained in:
nikolaos 2016-09-12 02:39:34 -07:00 committed by Commit bot
parent 1247b0b296
commit e850ed2a1e
6 changed files with 109 additions and 125 deletions

View File

@ -138,6 +138,8 @@ struct FormalParametersBase {
// typedef Statement;
// typedef StatementList;
// typedef Block;
// typedef BreakableStatement;
// typedef IterationStatement;
// // For constructing objects returned by the traversing functions.
// typedef Factory;
// // For other implementation-specific tasks.
@ -1217,6 +1219,8 @@ class ParserBase {
StatementT ParseWhileStatement(ZoneList<const AstRawString*>* labels,
bool* ok);
StatementT ParseThrowStatement(bool* ok);
StatementT ParseSwitchStatement(ZoneList<const AstRawString*>* labels,
bool* ok);
bool IsNextLetKeyword();
bool IsTrivialExpression();
@ -4282,7 +4286,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement(
case Token::WITH:
return ParseWithStatement(labels, ok);
case Token::SWITCH:
return impl()->ParseSwitchStatement(labels, ok);
return ParseSwitchStatement(labels, ok);
case Token::FUNCTION:
// FunctionDeclaration only allowed as a StatementListItem, not in
// an arbitrary Statement position. Exceptions such as
@ -4519,7 +4523,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseContinueStatement(
// ECMA allows "eval" or "arguments" as labels even in strict mode.
label = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
}
typename Types::IterationStatementT target =
typename Types::IterationStatement target =
impl()->LookupContinueTarget(label, CHECK_OK);
if (impl()->IsNullStatement(target)) {
// Illegal continue statement.
@ -4557,7 +4561,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseBreakStatement(
ExpectSemicolon(CHECK_OK);
return factory()->NewEmptyStatement(pos);
}
typename Types::BreakableStatementT target =
typename Types::BreakableStatement target =
impl()->LookupBreakTarget(label, CHECK_OK);
if (impl()->IsNullStatement(target)) {
// Illegal break statement.
@ -4718,6 +4722,66 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseThrowStatement(
return impl()->NewThrowStatement(exception, pos);
}
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseSwitchStatement(
ZoneList<const AstRawString*>* labels, bool* ok) {
// SwitchStatement ::
// 'switch' '(' Expression ')' '{' CaseClause* '}'
// CaseClause ::
// 'case' Expression ':' StatementList
// 'default' ':' StatementList
int switch_pos = peek_position();
Expect(Token::SWITCH, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
ExpressionT tag = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
auto switch_statement = factory()->NewSwitchStatement(labels, switch_pos);
{
BlockState cases_block_state(&scope_state_);
cases_block_state.set_start_position(scanner()->location().beg_pos);
cases_block_state.SetNonlinear();
typename Types::Target target(this, switch_statement);
bool default_seen = false;
auto cases = impl()->NewCaseClauseList(4);
Expect(Token::LBRACE, CHECK_OK);
while (peek() != Token::RBRACE) {
// An empty label indicates the default case.
ExpressionT label = impl()->EmptyExpression();
if (Check(Token::CASE)) {
label = ParseExpression(true, CHECK_OK);
} else {
Expect(Token::DEFAULT, CHECK_OK);
if (default_seen) {
ReportMessage(MessageTemplate::kMultipleDefaultsInSwitch);
*ok = false;
return impl()->NullStatement();
}
default_seen = true;
}
Expect(Token::COLON, CHECK_OK);
int clause_pos = position();
StatementListT statements = impl()->NewStatementList(5);
while (peek() != Token::CASE && peek() != Token::DEFAULT &&
peek() != Token::RBRACE) {
StatementT stat = ParseStatementListItem(CHECK_OK);
statements->Add(stat, zone());
}
auto clause = factory()->NewCaseClause(label, statements, clause_pos);
cases->Add(clause, zone());
}
Expect(Token::RBRACE, CHECK_OK);
cases_block_state.set_end_position(scanner()->location().end_pos);
return impl()->RewriteSwitchStatement(
tag, switch_statement, cases, cases_block_state.FinalizedBlockScope());
}
}
#undef CHECK_OK
#undef CHECK_OK_CUSTOM

View File

@ -1729,43 +1729,10 @@ Statement* Parser::ParseFunctionDeclaration(bool* ok) {
return ParseHoistableDeclaration(pos, flags, nullptr, false, CHECK_OK);
}
CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) {
// CaseClause ::
// 'case' Expression ':' StatementList
// 'default' ':' StatementList
Expression* label = NULL; // NULL expression indicates default case
if (peek() == Token::CASE) {
Expect(Token::CASE, CHECK_OK);
label = ParseExpression(true, CHECK_OK);
} else {
Expect(Token::DEFAULT, CHECK_OK);
if (*default_seen_ptr) {
ReportMessage(MessageTemplate::kMultipleDefaultsInSwitch);
*ok = false;
return NULL;
}
*default_seen_ptr = true;
}
Expect(Token::COLON, CHECK_OK);
int pos = position();
ZoneList<Statement*>* statements =
new(zone()) ZoneList<Statement*>(5, zone());
Statement* stat = NULL;
while (peek() != Token::CASE &&
peek() != Token::DEFAULT &&
peek() != Token::RBRACE) {
stat = ParseStatementListItem(CHECK_OK);
statements->Add(stat, zone());
}
return factory()->NewCaseClause(label, statements, pos);
}
Statement* Parser::ParseSwitchStatement(ZoneList<const AstRawString*>* labels,
bool* ok) {
// SwitchStatement ::
// 'switch' '(' Expression ')' '{' CaseClause* '}'
Statement* Parser::RewriteSwitchStatement(Expression* tag,
SwitchStatement* switch_statement,
ZoneList<CaseClause*>* cases,
Scope* scope) {
// In order to get the CaseClauses to execute in their own lexical scope,
// but without requiring downstream code to have special scope handling
// code for switch statements, desugar into blocks as follows:
@ -1777,12 +1744,6 @@ Statement* Parser::ParseSwitchStatement(ZoneList<const AstRawString*>* labels,
// }
Block* switch_block = factory()->NewBlock(NULL, 2, false, kNoSourcePosition);
int switch_pos = peek_position();
Expect(Token::SWITCH, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
Expression* tag = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
Variable* tag_variable =
NewTemporary(ast_value_factory()->dot_switch_tag_string());
@ -1801,37 +1762,12 @@ Statement* Parser::ParseSwitchStatement(ZoneList<const AstRawString*>* labels,
factory()->NewUndefinedLiteral(kNoSourcePosition), kNoSourcePosition),
zone());
Expression* tag_read = factory()->NewVariableProxy(tag_variable);
switch_statement->Initialize(tag_read, cases);
Block* cases_block = factory()->NewBlock(NULL, 1, false, kNoSourcePosition);
SwitchStatement* switch_statement =
factory()->NewSwitchStatement(labels, switch_pos);
{
BlockState cases_block_state(&scope_state_);
cases_block_state.set_start_position(scanner()->location().beg_pos);
cases_block_state.SetNonlinear();
ParserTarget target(this, switch_statement);
Expression* tag_read = factory()->NewVariableProxy(tag_variable);
bool default_seen = false;
ZoneList<CaseClause*>* cases =
new (zone()) ZoneList<CaseClause*>(4, zone());
Expect(Token::LBRACE, CHECK_OK);
while (peek() != Token::RBRACE) {
CaseClause* clause = ParseCaseClause(&default_seen, CHECK_OK);
cases->Add(clause, zone());
}
switch_statement->Initialize(tag_read, cases);
cases_block->statements()->Add(switch_statement, zone());
Expect(Token::RBRACE, CHECK_OK);
cases_block_state.set_end_position(scanner()->location().end_pos);
cases_block->set_scope(cases_block_state.FinalizedBlockScope());
}
cases_block->statements()->Add(switch_statement, zone());
cases_block->set_scope(scope);
switch_block->statements()->Add(cases_block, zone());
return switch_block;
}

View File

@ -157,8 +157,8 @@ struct ParserTypes<Parser> {
typedef v8::internal::Statement* Statement;
typedef ZoneList<v8::internal::Statement*>* StatementList;
typedef v8::internal::Block* Block;
typedef v8::internal::BreakableStatement* BreakableStatementT;
typedef v8::internal::IterationStatement* IterationStatementT;
typedef v8::internal::BreakableStatement* BreakableStatement;
typedef v8::internal::IterationStatement* IterationStatement;
// For constructing objects returned by the traversing functions.
typedef AstNodeFactory Factory;
@ -281,6 +281,9 @@ class Parser : public ParserBase<Parser> {
bool ContainsLabel(ZoneList<const AstRawString*>* labels,
const AstRawString* label);
Expression* RewriteReturn(Expression* return_value, int pos);
Statement* RewriteSwitchStatement(Expression* tag,
SwitchStatement* switch_statement,
ZoneList<CaseClause*>* cases, Scope* scope);
Statement* DeclareFunction(const AstRawString* variable_name,
FunctionLiteral* function, int pos,
@ -370,9 +373,6 @@ class Parser : public ParserBase<Parser> {
DEFINE_AST_VISITOR_MEMBERS_WITHOUT_STACKOVERFLOW()
};
CaseClause* ParseCaseClause(bool* default_seen_ptr, bool* ok);
Statement* ParseSwitchStatement(ZoneList<const AstRawString*>* labels,
bool* ok);
Statement* ParseForStatement(ZoneList<const AstRawString*>* labels, bool* ok);
Expression* MakeCatchContext(Handle<String> id, VariableProxy* value);
TryStatement* ParseTryStatement(bool* ok);
@ -939,6 +939,9 @@ class Parser : public ParserBase<Parser> {
V8_INLINE ZoneList<Statement*>* NewStatementList(int size) const {
return new (zone()) ZoneList<Statement*>(size, zone());
}
V8_INLINE ZoneList<CaseClause*>* NewCaseClauseList(int size) const {
return new (zone()) ZoneList<CaseClause*>(size, zone());
}
V8_INLINE Block* NewBlock(ZoneList<const AstRawString*>* labels, int capacity,
bool ignore_completion_value, int pos) {

View File

@ -164,42 +164,6 @@ PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) {
return ParseHoistableDeclaration(pos, flags, nullptr, false, ok);
}
PreParser::Statement PreParser::ParseSwitchStatement(
ZoneList<const AstRawString*>* labels, bool* ok) {
// SwitchStatement ::
// 'switch' '(' Expression ')' '{' CaseClause* '}'
Expect(Token::SWITCH, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
{
BlockState cases_block_state(&scope_state_);
Expect(Token::LBRACE, CHECK_OK);
Token::Value token = peek();
while (token != Token::RBRACE) {
if (token == Token::CASE) {
Expect(Token::CASE, CHECK_OK);
ParseExpression(true, CHECK_OK);
} else {
Expect(Token::DEFAULT, CHECK_OK);
}
Expect(Token::COLON, CHECK_OK);
token = peek();
Statement statement = Statement::Jump();
while (token != Token::CASE &&
token != Token::DEFAULT &&
token != Token::RBRACE) {
statement = ParseStatementListItem(CHECK_OK);
token = peek();
}
}
}
Expect(Token::RBRACE, ok);
return Statement::Default();
}
PreParser::Statement PreParser::ParseForStatement(
ZoneList<const AstRawString*>* labels, bool* ok) {
// ForStatement ::

View File

@ -651,6 +651,16 @@ class PreParserFactory {
return PreParserStatement::Default();
}
PreParserStatement NewSwitchStatement(ZoneList<const AstRawString*>* labels,
int pos) {
return PreParserStatement::Default();
}
PreParserStatement NewCaseClause(PreParserExpression label,
PreParserStatementList statements, int pos) {
return PreParserStatement::Default();
}
// Return the object itself as AstVisitor and implement the needed
// dummy method right in this class.
PreParserFactory* visitor() { return this; }
@ -704,8 +714,8 @@ struct ParserTypes<PreParser> {
typedef PreParserStatement Statement;
typedef PreParserStatementList StatementList;
typedef PreParserStatement Block;
typedef PreParserStatement BreakableStatementT;
typedef PreParserStatement IterationStatementT;
typedef PreParserStatement BreakableStatement;
typedef PreParserStatement IterationStatement;
// For constructing objects returned by the traversing functions.
typedef PreParserFactory Factory;
@ -814,8 +824,6 @@ class PreParser : public ParserBase<PreParser> {
Expression ParseAsyncFunctionExpression(bool* ok);
Statement ParseClassDeclaration(ZoneList<const AstRawString*>* names,
bool default_export, bool* ok);
Statement ParseSwitchStatement(ZoneList<const AstRawString*>* labels,
bool* ok);
Statement ParseForStatement(ZoneList<const AstRawString*>* labels, bool* ok);
Statement ParseTryStatement(bool* ok);
Expression ParseConditionalExpression(bool accept_IN, bool* ok);
@ -933,6 +941,11 @@ class PreParser : public ParserBase<PreParser> {
int pos) {
return return_value;
}
V8_INLINE PreParserStatement RewriteSwitchStatement(
PreParserExpression tag, PreParserStatement switch_statement,
PreParserStatementList cases, Scope* scope) {
return PreParserStatement::Default();
}
V8_INLINE PreParserExpression RewriteDoExpression(PreParserStatement body,
int pos, bool* ok) {
@ -1256,6 +1269,10 @@ class PreParser : public ParserBase<PreParser> {
return PreParserStatementList();
}
PreParserStatementList NewCaseClauseList(int size) {
return PreParserStatementList();
}
V8_INLINE static PreParserStatement NewBlock(
ZoneList<const AstRawString*>* labels, int capacity,
bool ignore_completion_value, int pos) {

View File

@ -485,9 +485,9 @@ bytecodes: [
/* 30 E> */ B(StackCheck),
/* 42 S> */ B(LdaSmi), U8(1),
B(Star), R(0),
B(Star), R(1),
B(Star), R(2),
/* 45 S> */ B(LdaSmi), U8(1),
B(TestEqualStrict), R(1), U8(4),
B(TestEqualStrict), R(2), U8(4),
B(Mov), R(0), R(3),
B(JumpIfToBooleanTrue), U8(11),
B(LdaSmi), U8(2),
@ -495,10 +495,10 @@ bytecodes: [
B(JumpIfTrue), U8(34),
B(Jump), U8(36),
/* 77 E> */ B(AddSmi), U8(1), R(0), U8(1),
B(Star), R(2),
B(Star), R(1),
/* 70 S> */ B(LdaSmi), U8(2),
B(TestEqualStrict), R(2), U8(2),
B(Mov), R(2), R(4),
B(TestEqualStrict), R(1), U8(2),
B(Mov), R(1), R(4),
B(JumpIfToBooleanTrue), U8(4),
B(Jump), U8(8),
/* 101 S> */ B(LdaSmi), U8(1),