Revert of [parser] Refactor of Parse*Statement*, part 1 (patchset #2 id:20001 of https://codereview.chromium.org/2307073002/ )

Reason for revert:
https://build.chromium.org/p/client.v8.ports/builders/V8%20Mips%20-%20builder

Original issue's description:
> [parser] Refactor of Parse*Statement*, part 1
>
> This patch moves the following parsing methods to ParserBase:
>
> - ParseStatementList
> - ParseStatementListItem
> - ParseStatement
> - ParseSubStatement (subsumed in ParseStatement)
> - ParseStatementAsUnlabeled
>
> It also refactors the Target and TargetScope objects, used by the
> parser.
>
> R=adamk@chromium.org, marja@chromium.org
> BUG=
> LOG=N
>
> Committed: https://crrev.com/df29f3fda25660075a273cc27ad9f7787f321072
> Cr-Commit-Position: refs/heads/master@{#39167}

TBR=adamk@chromium.org,marja@chromium.org,nikolaos@chromium.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=

Review-Url: https://codereview.chromium.org/2313703002
Cr-Commit-Position: refs/heads/master@{#39169}
This commit is contained in:
machenbach 2016-09-05 06:06:02 -07:00 committed by Commit bot
parent 68b47f5e0f
commit 02164afd81
5 changed files with 588 additions and 534 deletions

View File

@ -187,14 +187,10 @@ struct FormalParametersBase {
// typedef ExpressionList;
// typedef PropertyList;
// typedef FormalParameters;
// typedef Statement;
// typedef StatementList;
// typedef Block;
// // For constructing objects returned by the traversing functions.
// typedef Factory;
// // For other implementation-specific tasks.
// typedef Target;
// typedef TargetScope;
// };
template <typename Impl>
@ -212,7 +208,6 @@ class ParserBase {
typedef typename Types::ExpressionList ExpressionListT;
typedef typename Types::PropertyList PropertyListT;
typedef typename Types::FormalParameters FormalParametersT;
typedef typename Types::Statement StatementT;
typedef typename Types::StatementList StatementListT;
typedef typename Types::Block BlockT;
typedef typename v8::internal::ExpressionClassifier<Types>
@ -922,10 +917,6 @@ class ParserBase {
return scope()->GetReceiverScope();
}
LanguageMode language_mode() { return scope()->language_mode(); }
void RaiseLanguageMode(LanguageMode mode) {
LanguageMode old = scope()->language_mode();
impl()->SetLanguageMode(scope(), old > mode ? old : mode);
}
bool is_generator() const { return function_state_->is_generator(); }
bool is_async_function() const {
return function_state_->is_async_function();
@ -1082,12 +1073,7 @@ class ParserBase {
classifier()->RecordArrowFormalParametersError(location, message, arg);
}
// Recursive descent functions.
// All ParseXXX functions take as the last argument an *ok parameter
// which is set to false if parsing failed; it is unchanged otherwise.
// By making the 'exception handling' explicit, we are forced to check
// for failure at the call sites. The family of CHECK_OK* macros can
// be useful for this.
// Recursive descent functions:
// Parses an identifier that is valid for the current scope, in particular it
// fails on strict mode future reserved keywords in a strict scope. If
@ -1194,32 +1180,6 @@ class ParserBase {
ZoneList<const AstRawString*>* names,
bool* ok);
// Under some circumstances, we allow preparsing to abort if the preparsed
// function is "long and trivial", and fully parse instead. Our current
// definition of "long and trivial" is:
// - over kLazyParseTrialLimit statements
// - all starting with an identifier (i.e., no if, for, while, etc.)
static const int kLazyParseTrialLimit = 200;
// TODO(nikolaos, marja): The first argument should not really be passed
// by value. The method is expected to add the parsed statements to the
// list. This works because in the case of the parser, StatementListT is
// a pointer whereas the preparser does not really modify the body.
V8_INLINE void ParseStatementList(StatementListT body, int end_token,
bool* ok) {
LazyParsingResult result = ParseStatementList(body, end_token, false, ok);
USE(result);
DCHECK_EQ(result, kLazyParsingComplete);
}
LazyParsingResult ParseStatementList(StatementListT body, int end_token,
bool may_abort, bool* ok);
StatementT ParseStatementListItem(bool* ok);
StatementT ParseStatement(ZoneList<const AstRawString*>* labels,
AllowLabelledFunctionStatement allow_function,
bool* ok);
StatementT ParseStatementAsUnlabelled(ZoneList<const AstRawString*>* labels,
bool* ok);
bool IsNextLetKeyword();
bool IsTrivialExpression();
@ -3944,263 +3904,6 @@ void ParserBase<Impl>::CheckDestructuringElement(ExpressionT expression,
}
}
// Redefinition of CHECK_OK for parsing statements.
#undef CHECK_OK
#define CHECK_OK CHECK_OK_CUSTOM(NullStatement)
template <typename Impl>
typename ParserBase<Impl>::LazyParsingResult
ParserBase<Impl>::ParseStatementList(StatementListT body, int end_token,
bool may_abort, bool* ok) {
// StatementList ::
// (StatementListItem)* <end_token>
// Allocate a target stack to use for this set of source
// elements. This way, all scripts and functions get their own
// target stack thus avoiding illegal breaks and continues across
// functions.
typename Types::TargetScope target_scope(this);
int count_statements = 0;
DCHECK(!impl()->IsNullStatementList(body));
bool directive_prologue = true; // Parsing directive prologue.
while (peek() != end_token) {
if (directive_prologue && peek() != Token::STRING) {
directive_prologue = false;
}
bool starts_with_identifier = peek() == Token::IDENTIFIER;
Scanner::Location token_loc = scanner()->peek_location();
StatementT stat = impl()->ParseStatementListItem(
CHECK_OK_CUSTOM(Return, kLazyParsingComplete));
if (impl()->IsNullOrEmptyStatement(stat)) {
directive_prologue = false; // End of directive prologue.
continue;
}
if (directive_prologue) {
// The length of the token is used to distinguish between strings literals
// that evaluate equal to directives but contain either escape sequences
// (e.g., "use \x73trict") or line continuations (e.g., "use \
// strict").
if (impl()->IsUseStrictDirective(stat) &&
token_loc.end_pos - token_loc.beg_pos == sizeof("use strict") + 1) {
// Directive "use strict" (ES5 14.1).
RaiseLanguageMode(STRICT);
if (!scope()->HasSimpleParameters()) {
// TC39 deemed "use strict" directives to be an error when occurring
// in the body of a function with non-simple parameter list, on
// 29/7/2015. https://goo.gl/ueA7Ln
impl()->ReportMessageAt(
token_loc, MessageTemplate::kIllegalLanguageModeDirective,
"use strict");
*ok = false;
return kLazyParsingComplete;
}
// Because declarations in strict eval code don't leak into the scope
// of the eval call, it is likely that functions declared in strict
// eval code will be used within the eval code, so lazy parsing is
// probably not a win.
if (scope()->is_eval_scope()) mode_ = PARSE_EAGERLY;
} else if (impl()->IsUseAsmDirective(stat) &&
token_loc.end_pos - token_loc.beg_pos ==
sizeof("use asm") + 1) {
// Directive "use asm".
impl()->SetAsmModule();
} else if (impl()->IsStringLiteral(stat)) {
// Possibly an unknown directive.
// TODO(nikolaos): Check if the following is really what we want!
// """Should not change mode, but will increment UseCounter
// if appropriate. Ditto usages below.""" ???
RaiseLanguageMode(SLOPPY);
} else {
// End of the directive prologue.
directive_prologue = false;
// TODO(nikolaos): Check if the following is really what we want!
RaiseLanguageMode(SLOPPY);
}
} else {
// TODO(nikolaos): Check if the following is really what we want!
RaiseLanguageMode(SLOPPY);
}
// If we're allowed to abort, we will do so when we see a "long and
// trivial" function. Our current definition of "long and trivial" is:
// - over kLazyParseTrialLimit statements
// - all starting with an identifier (i.e., no if, for, while, etc.)
if (may_abort) {
if (!starts_with_identifier) {
may_abort = false;
} else if (++count_statements > kLazyParseTrialLimit) {
return kLazyParsingAborted;
}
}
body->Add(stat, zone());
}
return kLazyParsingComplete;
}
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatementListItem(
bool* ok) {
// ECMA 262 6th Edition
// StatementListItem[Yield, Return] :
// Statement[?Yield, ?Return]
// Declaration[?Yield]
//
// Declaration[Yield] :
// HoistableDeclaration[?Yield]
// ClassDeclaration[?Yield]
// LexicalDeclaration[In, ?Yield]
//
// HoistableDeclaration[Yield, Default] :
// FunctionDeclaration[?Yield, ?Default]
// GeneratorDeclaration[?Yield, ?Default]
//
// LexicalDeclaration[In, Yield] :
// LetOrConst BindingList[?In, ?Yield] ;
switch (peek()) {
case Token::FUNCTION:
return impl()->ParseHoistableDeclaration(nullptr, false, ok);
case Token::CLASS:
Consume(Token::CLASS);
return impl()->ParseClassDeclaration(nullptr, false, ok);
case Token::VAR:
case Token::CONST:
return impl()->ParseVariableStatement(kStatementListItem, nullptr, ok);
case Token::LET:
if (IsNextLetKeyword()) {
return impl()->ParseVariableStatement(kStatementListItem, nullptr, ok);
}
break;
case Token::ASYNC:
if (allow_harmony_async_await() && PeekAhead() == Token::FUNCTION &&
!scanner()->HasAnyLineTerminatorAfterNext()) {
Consume(Token::ASYNC);
return impl()->ParseAsyncFunctionDeclaration(nullptr, false, ok);
}
/* falls through */
default:
break;
}
return impl()->ParseStatement(nullptr, kAllowLabelledFunctionStatement, ok);
}
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement(
ZoneList<const AstRawString*>* labels,
AllowLabelledFunctionStatement allow_function, bool* ok) {
// Statement ::
// Block
// VariableStatement
// EmptyStatement
// ExpressionStatement
// IfStatement
// IterationStatement
// ContinueStatement
// BreakStatement
// ReturnStatement
// WithStatement
// LabelledStatement
// SwitchStatement
// ThrowStatement
// TryStatement
// DebuggerStatement
// Note: Since labels can only be used by 'break' and 'continue'
// statements, which themselves are only valid within blocks,
// iterations or 'switch' statements (i.e., BreakableStatements),
// labels can be simply ignored in all other cases; except for
// trivial labeled break statements 'label: break label' which is
// parsed into an empty statement.
switch (peek()) {
case Token::LBRACE:
return impl()->ParseBlock(labels, ok);
case Token::SEMICOLON:
Next();
return factory()->NewEmptyStatement(kNoSourcePosition);
case Token::IF:
return impl()->ParseIfStatement(labels, ok);
case Token::DO:
return impl()->ParseDoWhileStatement(labels, ok);
case Token::WHILE:
return impl()->ParseWhileStatement(labels, ok);
case Token::FOR:
return impl()->ParseForStatement(labels, ok);
case Token::CONTINUE:
case Token::BREAK:
case Token::RETURN:
case Token::THROW:
case Token::TRY: {
// These statements must have their labels preserved in an enclosing
// block, as the corresponding AST nodes do not currently store their
// labels.
// TODO(nikolaos, marja): Consider adding the labels to the AST nodes.
if (labels == nullptr) {
return ParseStatementAsUnlabelled(labels, ok);
} else {
BlockT result =
factory()->NewBlock(labels, 1, false, kNoSourcePosition);
typename Types::Target target(this, result);
StatementT statement = ParseStatementAsUnlabelled(labels, CHECK_OK);
result->statements()->Add(statement, zone());
return result;
}
}
case Token::WITH:
return impl()->ParseWithStatement(labels, ok);
case Token::SWITCH:
return impl()->ParseSwitchStatement(labels, ok);
case Token::FUNCTION:
// FunctionDeclaration only allowed as a StatementListItem, not in
// an arbitrary Statement position. Exceptions such as
// ES#sec-functiondeclarations-in-ifstatement-statement-clauses
// are handled by calling ParseScopedStatement rather than
// ParseStatement directly.
impl()->ReportMessageAt(scanner()->peek_location(),
is_strict(language_mode())
? MessageTemplate::kStrictFunction
: MessageTemplate::kSloppyFunction);
*ok = false;
return impl()->NullStatement();
case Token::DEBUGGER:
return impl()->ParseDebuggerStatement(ok);
case Token::VAR:
return impl()->ParseVariableStatement(kStatement, nullptr, ok);
default:
return impl()->ParseExpressionOrLabelledStatement(labels, allow_function,
ok);
}
}
// This method parses a subset of statements (break, continue, return, throw,
// try) which are to be grouped because they all require their labeles to be
// preserved in an enclosing block.
template <typename Impl>
typename ParserBase<Impl>::StatementT
ParserBase<Impl>::ParseStatementAsUnlabelled(
ZoneList<const AstRawString*>* labels, bool* ok) {
switch (peek()) {
case Token::CONTINUE:
return impl()->ParseContinueStatement(ok);
case Token::BREAK:
return impl()->ParseBreakStatement(labels, ok);
case Token::RETURN:
return impl()->ParseReturnStatement(ok);
case Token::THROW:
return impl()->ParseThrowStatement(ok);
case Token::TRY:
return impl()->ParseTryStatement(ok);
default:
UNREACHABLE();
return impl()->NullStatement();
}
}
#undef CHECK_OK
#undef CHECK_OK_CUSTOM

View File

@ -231,39 +231,41 @@ FunctionLiteral* Parser::DefaultConstructor(const AstRawString* name,
// 'continue' statement targets). Upon construction, a new target is
// added; it is removed upon destruction.
class ParserTarget BASE_EMBEDDED {
class Target BASE_EMBEDDED {
public:
ParserTarget(ParserBase<Parser>* parser, BreakableStatement* statement)
: variable_(&parser->impl()->target_stack_),
statement_(statement),
previous_(parser->impl()->target_stack_) {
parser->impl()->target_stack_ = this;
Target(Target** variable, BreakableStatement* statement)
: variable_(variable), statement_(statement), previous_(*variable) {
*variable = this;
}
~ParserTarget() { *variable_ = previous_; }
~Target() {
*variable_ = previous_;
}
ParserTarget* previous() { return previous_; }
Target* previous() { return previous_; }
BreakableStatement* statement() { return statement_; }
private:
ParserTarget** variable_;
Target** variable_;
BreakableStatement* statement_;
ParserTarget* previous_;
Target* previous_;
};
class ParserTargetScope BASE_EMBEDDED {
class TargetScope BASE_EMBEDDED {
public:
explicit ParserTargetScope(ParserBase<Parser>* parser)
: variable_(&parser->impl()->target_stack_),
previous_(parser->impl()->target_stack_) {
parser->impl()->target_stack_ = nullptr;
explicit TargetScope(Target** variable)
: variable_(variable), previous_(*variable) {
*variable = NULL;
}
~ParserTargetScope() { *variable_ = previous_; }
~TargetScope() {
*variable_ = previous_;
}
private:
ParserTarget** variable_;
ParserTarget* previous_;
Target** variable_;
Target* previous_;
};
@ -929,6 +931,131 @@ FunctionLiteral* Parser::DoParseLazy(ParseInfo* info,
return result;
}
void Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token,
bool* ok) {
// StatementList ::
// (StatementListItem)* <end_token>
// Allocate a target stack to use for this set of source
// elements. This way, all scripts and functions get their own
// target stack thus avoiding illegal breaks and continues across
// functions.
TargetScope scope(&this->target_stack_);
DCHECK(body != NULL);
bool directive_prologue = true; // Parsing directive prologue.
while (peek() != end_token) {
if (directive_prologue && peek() != Token::STRING) {
directive_prologue = false;
}
Scanner::Location token_loc = scanner()->peek_location();
Statement* stat = ParseStatementListItem(CHECK_OK_VOID);
if (stat == NULL || stat->IsEmpty()) {
directive_prologue = false; // End of directive prologue.
continue;
}
if (directive_prologue) {
// A shot at a directive.
ExpressionStatement* e_stat;
Literal* literal;
// Still processing directive prologue?
if ((e_stat = stat->AsExpressionStatement()) != NULL &&
(literal = e_stat->expression()->AsLiteral()) != NULL &&
literal->raw_value()->IsString()) {
// Check "use strict" directive (ES5 14.1), "use asm" directive.
bool use_strict_found =
literal->raw_value()->AsString() ==
ast_value_factory()->use_strict_string() &&
token_loc.end_pos - token_loc.beg_pos ==
ast_value_factory()->use_strict_string()->length() + 2;
if (use_strict_found) {
if (is_sloppy(language_mode())) {
RaiseLanguageMode(STRICT);
}
if (!this->scope()->HasSimpleParameters()) {
// TC39 deemed "use strict" directives to be an error when occurring
// in the body of a function with non-simple parameter list, on
// 29/7/2015. https://goo.gl/ueA7Ln
const AstRawString* string = literal->raw_value()->AsString();
ReportMessageAt(token_loc,
MessageTemplate::kIllegalLanguageModeDirective,
string);
*ok = false;
return;
}
// Because declarations in strict eval code don't leak into the scope
// of the eval call, it is likely that functions declared in strict
// eval code will be used within the eval code, so lazy parsing is
// probably not a win.
if (this->scope()->is_eval_scope()) mode_ = PARSE_EAGERLY;
} else if (literal->raw_value()->AsString() ==
ast_value_factory()->use_asm_string() &&
token_loc.end_pos - token_loc.beg_pos ==
ast_value_factory()->use_asm_string()->length() + 2) {
// Store the usage count; The actual use counter on the isolate is
// incremented after parsing is done.
++use_counts_[v8::Isolate::kUseAsm];
DCHECK(this->scope()->is_declaration_scope());
this->scope()->AsDeclarationScope()->set_asm_module();
} else {
// Should not change mode, but will increment UseCounter
// if appropriate. Ditto usages below.
RaiseLanguageMode(SLOPPY);
}
} else {
// End of the directive prologue.
directive_prologue = false;
RaiseLanguageMode(SLOPPY);
}
} else {
RaiseLanguageMode(SLOPPY);
}
body->Add(stat, zone());
}
}
Statement* Parser::ParseStatementListItem(bool* ok) {
// (Ecma 262 6th Edition, 13.1):
// StatementListItem:
// Statement
// Declaration
const Token::Value peeked = peek();
switch (peeked) {
case Token::FUNCTION:
return ParseHoistableDeclaration(NULL, false, ok);
case Token::CLASS:
Consume(Token::CLASS);
return ParseClassDeclaration(NULL, false, ok);
case Token::CONST:
return ParseVariableStatement(kStatementListItem, NULL, ok);
case Token::VAR:
return ParseVariableStatement(kStatementListItem, NULL, ok);
case Token::LET:
if (IsNextLetKeyword()) {
return ParseVariableStatement(kStatementListItem, NULL, ok);
}
break;
case Token::ASYNC:
if (allow_harmony_async_await() && PeekAhead() == Token::FUNCTION &&
!scanner()->HasAnyLineTerminatorAfterNext()) {
Consume(Token::ASYNC);
return ParseAsyncFunctionDeclaration(NULL, false, ok);
}
/* falls through */
default:
break;
}
return ParseStatement(NULL, kAllowLabelledFunctionStatement, ok);
}
Statement* Parser::ParseModuleItem(bool* ok) {
// ecma262/#prod-ModuleItem
// ModuleItem :
@ -1359,6 +1486,139 @@ Statement* Parser::ParseExportDeclaration(bool* ok) {
return result;
}
Statement* Parser::ParseStatement(ZoneList<const AstRawString*>* labels,
AllowLabelledFunctionStatement allow_function,
bool* ok) {
// Statement ::
// EmptyStatement
// ...
if (peek() == Token::SEMICOLON) {
Next();
return factory()->NewEmptyStatement(kNoSourcePosition);
}
return ParseSubStatement(labels, allow_function, ok);
}
Statement* Parser::ParseSubStatement(
ZoneList<const AstRawString*>* labels,
AllowLabelledFunctionStatement allow_function, bool* ok) {
// Statement ::
// Block
// VariableStatement
// EmptyStatement
// ExpressionStatement
// IfStatement
// IterationStatement
// ContinueStatement
// BreakStatement
// ReturnStatement
// WithStatement
// LabelledStatement
// SwitchStatement
// ThrowStatement
// TryStatement
// DebuggerStatement
// Note: Since labels can only be used by 'break' and 'continue'
// statements, which themselves are only valid within blocks,
// iterations or 'switch' statements (i.e., BreakableStatements),
// labels can be simply ignored in all other cases; except for
// trivial labeled break statements 'label: break label' which is
// parsed into an empty statement.
switch (peek()) {
case Token::LBRACE:
return ParseBlock(labels, ok);
case Token::SEMICOLON:
Next();
return factory()->NewEmptyStatement(kNoSourcePosition);
case Token::IF:
return ParseIfStatement(labels, ok);
case Token::DO:
return ParseDoWhileStatement(labels, ok);
case Token::WHILE:
return ParseWhileStatement(labels, ok);
case Token::FOR:
return ParseForStatement(labels, ok);
case Token::CONTINUE:
case Token::BREAK:
case Token::RETURN:
case Token::THROW:
case Token::TRY: {
// These statements must have their labels preserved in an enclosing
// block
if (labels == NULL) {
return ParseStatementAsUnlabelled(labels, ok);
} else {
Block* result =
factory()->NewBlock(labels, 1, false, kNoSourcePosition);
Target target(&this->target_stack_, result);
Statement* statement = ParseStatementAsUnlabelled(labels, CHECK_OK);
if (result) result->statements()->Add(statement, zone());
return result;
}
}
case Token::WITH:
return ParseWithStatement(labels, ok);
case Token::SWITCH:
return ParseSwitchStatement(labels, ok);
case Token::FUNCTION:
// FunctionDeclaration only allowed as a StatementListItem, not in
// an arbitrary Statement position. Exceptions such as
// ES#sec-functiondeclarations-in-ifstatement-statement-clauses
// are handled by calling ParseScopedStatement rather than
// ParseSubStatement directly.
ReportMessageAt(scanner()->peek_location(),
is_strict(language_mode())
? MessageTemplate::kStrictFunction
: MessageTemplate::kSloppyFunction);
*ok = false;
return nullptr;
case Token::DEBUGGER:
return ParseDebuggerStatement(ok);
case Token::VAR:
return ParseVariableStatement(kStatement, NULL, ok);
default:
return ParseExpressionOrLabelledStatement(labels, allow_function, ok);
}
}
Statement* Parser::ParseStatementAsUnlabelled(
ZoneList<const AstRawString*>* labels, bool* ok) {
switch (peek()) {
case Token::CONTINUE:
return ParseContinueStatement(ok);
case Token::BREAK:
return ParseBreakStatement(labels, ok);
case Token::RETURN:
return ParseReturnStatement(ok);
case Token::THROW:
return ParseThrowStatement(ok);
case Token::TRY:
return ParseTryStatement(ok);
default:
UNREACHABLE();
return NULL;
}
}
VariableProxy* Parser::NewUnresolved(const AstRawString* name, int begin_pos,
int end_pos, Variable::Kind kind) {
return scope()->NewUnresolved(factory(), name, begin_pos, end_pos, kind);
@ -1618,7 +1878,7 @@ Block* Parser::ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok) {
{
BlockState block_state(&scope_state_);
block_state.set_start_position(scanner()->location().beg_pos);
ParserTarget target(this, body);
Target target(&this->target_stack_, body);
while (peek() != Token::RBRACE) {
Statement* stat = ParseStatementListItem(CHECK_OK);
@ -2090,7 +2350,7 @@ Statement* Parser::ParseSwitchStatement(ZoneList<const AstRawString*>* labels,
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);
Target target(&this->target_stack_, switch_statement);
Expression* tag_read = factory()->NewVariableProxy(tag_variable);
@ -2196,7 +2456,7 @@ TryStatement* Parser::ParseTryStatement(bool* ok) {
{
BlockState block_state(&scope_state_);
block_state.set_start_position(scanner()->location().beg_pos);
ParserTarget target(this, catch_block);
Target target(&this->target_stack_, catch_block);
const AstRawString* name = ast_value_factory()->dot_catch_string();
Expression* pattern = nullptr;
@ -2335,7 +2595,7 @@ DoWhileStatement* Parser::ParseDoWhileStatement(
DoWhileStatement* loop =
factory()->NewDoWhileStatement(labels, peek_position());
ParserTarget target(this, loop);
Target target(&this->target_stack_, loop);
Expect(Token::DO, CHECK_OK);
Statement* body = ParseScopedStatement(NULL, true, CHECK_OK);
@ -2362,7 +2622,7 @@ WhileStatement* Parser::ParseWhileStatement(
// 'while' '(' Expression ')' Statement
WhileStatement* loop = factory()->NewWhileStatement(labels, peek_position());
ParserTarget target(this, loop);
Target target(&this->target_stack_, loop);
Expect(Token::WHILE, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
@ -2810,7 +3070,7 @@ Statement* Parser::ParseScopedStatement(ZoneList<const AstRawString*>* labels,
bool legacy, bool* ok) {
if (is_strict(language_mode()) || peek() != Token::FUNCTION ||
(legacy && allow_harmony_restrictive_declarations())) {
return ParseStatement(labels, kDisallowLabelledFunctionStatement, ok);
return ParseSubStatement(labels, kDisallowLabelledFunctionStatement, ok);
} else {
if (legacy) {
++use_counts_[v8::Isolate::kLegacyFunctionDeclaration];
@ -2919,7 +3179,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
Variable* temp = NewTemporary(ast_value_factory()->dot_for_string());
ForEachStatement* loop =
factory()->NewForEachStatement(mode, labels, stmt_pos);
ParserTarget target(this, loop);
Target target(&this->target_stack_, loop);
int each_keyword_position = scanner()->location().beg_pos;
@ -3065,7 +3325,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
ForEachStatement* loop =
factory()->NewForEachStatement(mode, labels, stmt_pos);
ParserTarget target(this, loop);
Target target(&this->target_stack_, loop);
int each_keyword_position = scanner()->location().beg_pos;
@ -3097,7 +3357,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
// Standard 'for' loop
ForStatement* loop = factory()->NewForStatement(labels, stmt_pos);
ParserTarget target(this, loop);
Target target(&this->target_stack_, loop);
// Parsed initializer at this point.
Expect(Token::SEMICOLON, CHECK_OK);
@ -4518,7 +4778,7 @@ void Parser::InsertSloppyBlockFunctionVarBindings(DeclarationScope* scope,
// Parser support
bool Parser::TargetStackContainsLabel(const AstRawString* label) {
for (ParserTarget* t = target_stack_; t != NULL; t = t->previous()) {
for (Target* t = target_stack_; t != NULL; t = t->previous()) {
if (ContainsLabel(t->statement()->labels(), label)) return true;
}
return false;
@ -4528,7 +4788,7 @@ bool Parser::TargetStackContainsLabel(const AstRawString* label) {
BreakableStatement* Parser::LookupBreakTarget(const AstRawString* label,
bool* ok) {
bool anonymous = label == NULL;
for (ParserTarget* t = target_stack_; t != NULL; t = t->previous()) {
for (Target* t = target_stack_; t != NULL; t = t->previous()) {
BreakableStatement* stat = t->statement();
if ((anonymous && stat->is_target_for_anonymous()) ||
(!anonymous && ContainsLabel(stat->labels(), label))) {
@ -4542,7 +4802,7 @@ BreakableStatement* Parser::LookupBreakTarget(const AstRawString* label,
IterationStatement* Parser::LookupContinueTarget(const AstRawString* label,
bool* ok) {
bool anonymous = label == NULL;
for (ParserTarget* t = target_stack_; t != NULL; t = t->previous()) {
for (Target* t = target_stack_; t != NULL; t = t->previous()) {
IterationStatement* stat = t->statement()->AsIterationStatement();
if (stat == NULL) continue;
@ -4936,12 +5196,10 @@ void Parser::SetLanguageMode(Scope* scope, LanguageMode mode) {
scope->SetLanguageMode(mode);
}
void Parser::SetAsmModule() {
// Store the usage count; The actual use counter on the isolate is
// incremented after parsing is done.
++use_counts_[v8::Isolate::kUseAsm];
DCHECK(scope()->is_declaration_scope());
scope()->AsDeclarationScope()->set_asm_module();
void Parser::RaiseLanguageMode(LanguageMode mode) {
LanguageMode old = scope()->language_mode();
SetLanguageMode(scope(), old > mode ? old : mode);
}
void Parser::MarkCollectedTailCallExpressions() {

View File

@ -21,8 +21,7 @@ namespace internal {
class ParseInfo;
class ScriptData;
class ParserTarget;
class ParserTargetScope;
class Target;
class FunctionEntry BASE_EMBEDDED {
public:
@ -153,15 +152,11 @@ struct ParserTypes<Parser> {
typedef ZoneList<v8::internal::Expression*>* ExpressionList;
typedef ZoneList<ObjectLiteral::Property*>* PropertyList;
typedef ParserFormalParameters FormalParameters;
typedef v8::internal::Statement* Statement;
typedef ZoneList<v8::internal::Statement*>* StatementList;
typedef v8::internal::Block* Block;
// For constructing objects returned by the traversing functions.
typedef AstNodeFactory Factory;
typedef ParserTarget Target;
typedef ParserTargetScope TargetScope;
};
class Parser : public ParserBase<Parser> {
@ -244,6 +239,12 @@ class Parser : public ParserBase<Parser> {
return compile_options_ == ScriptCompiler::kProduceParserCache;
}
// All ParseXXX functions take as the last argument an *ok parameter
// which is set to false if parsing failed; it is unchanged otherwise.
// By making the 'exception handling' explicit, we are forced to check
// for failure at the call sites.
void ParseStatementList(ZoneList<Statement*>* body, int end_token, bool* ok);
Statement* ParseStatementListItem(bool* ok);
void ParseModuleItemList(ZoneList<Statement*>* body, bool* ok);
Statement* ParseModuleItem(bool* ok);
const AstRawString* ParseModuleSpecifier(bool* ok);
@ -265,6 +266,14 @@ class Parser : public ParserBase<Parser> {
location(location) {}
};
ZoneList<const NamedImport*>* ParseNamedImports(int pos, bool* ok);
Statement* ParseStatement(ZoneList<const AstRawString*>* labels,
AllowLabelledFunctionStatement allow_function,
bool* ok);
Statement* ParseSubStatement(ZoneList<const AstRawString*>* labels,
AllowLabelledFunctionStatement allow_function,
bool* ok);
Statement* ParseStatementAsUnlabelled(ZoneList<const AstRawString*>* labels,
bool* ok);
Statement* ParseFunctionDeclaration(bool* ok);
Statement* ParseHoistableDeclaration(ZoneList<const AstRawString*>* names,
bool default_export, bool* ok);
@ -571,7 +580,7 @@ class Parser : public ParserBase<Parser> {
int pos);
void SetLanguageMode(Scope* scope, LanguageMode mode);
void SetAsmModule();
void RaiseLanguageMode(LanguageMode mode);
V8_INLINE void MarkCollectedTailCallExpressions();
V8_INLINE void MarkTailPosition(Expression* expression);
@ -693,26 +702,6 @@ class Parser : public ParserBase<Parser> {
return string->AsArrayIndex(index);
}
V8_INLINE bool IsUseStrictDirective(Statement* statement) const {
return IsStringLiteral(statement, ast_value_factory()->use_strict_string());
}
V8_INLINE bool IsUseAsmDirective(Statement* statement) const {
return IsStringLiteral(statement, ast_value_factory()->use_asm_string());
}
// Returns true if the statement is an expression statement containing
// a single string literal. If a second argument is given, the literal
// is also compared with it and the result is true only if they are equal.
V8_INLINE bool IsStringLiteral(Statement* statement,
const AstRawString* arg = nullptr) const {
ExpressionStatement* e_stat = statement->AsExpressionStatement();
if (e_stat == nullptr) return false;
Literal* literal = e_stat->expression()->AsLiteral();
if (literal == nullptr || !literal->raw_value()->IsString()) return false;
return arg == nullptr || literal->raw_value()->AsString() == arg;
}
V8_INLINE static Expression* GetPropertyValue(
ObjectLiteral::Property* property) {
return property->value();
@ -858,17 +847,7 @@ class Parser : public ParserBase<Parser> {
V8_INLINE static ZoneList<Expression*>* NullExpressionList() {
return nullptr;
}
V8_INLINE static bool IsNullExpressionList(ZoneList<Expression*>* exprs) {
return exprs == nullptr;
}
V8_INLINE static ZoneList<Statement*>* NullStatementList() { return nullptr; }
V8_INLINE static bool IsNullStatementList(ZoneList<Statement*>* stmts) {
return stmts == nullptr;
}
V8_INLINE static Statement* NullStatement() { return nullptr; }
V8_INLINE bool IsNullOrEmptyStatement(Statement* stmt) {
return stmt == nullptr || stmt->IsEmpty();
}
// Non-NULL empty string.
V8_INLINE const AstRawString* EmptyIdentifierString() const {
@ -1030,11 +1009,7 @@ class Parser : public ParserBase<Parser> {
Scanner scanner_;
PreParser* reusable_preparser_;
Scope* original_scope_; // for ES5 function declarations in sloppy eval
friend class ParserTarget;
friend class ParserTargetScope;
ParserTarget* target_stack_; // for break, continue statements
Target* target_stack_; // for break, continue statements
ScriptCompiler::CompileOptions compile_options_;
ParseData* cached_parse_data_;

View File

@ -122,19 +122,223 @@ PreParser::PreParseResult PreParser::PreParseLazyFunction(
// it is used) are generally omitted.
PreParser::Statement PreParser::ParseStatementListItem(bool* ok) {
// ECMA 262 6th Edition
// StatementListItem[Yield, Return] :
// Statement[?Yield, ?Return]
// Declaration[?Yield]
//
// Declaration[Yield] :
// HoistableDeclaration[?Yield]
// ClassDeclaration[?Yield]
// LexicalDeclaration[In, ?Yield]
//
// HoistableDeclaration[Yield, Default] :
// FunctionDeclaration[?Yield, ?Default]
// GeneratorDeclaration[?Yield, ?Default]
//
// LexicalDeclaration[In, Yield] :
// LetOrConst BindingList[?In, ?Yield] ;
switch (peek()) {
case Token::FUNCTION:
return ParseHoistableDeclaration(ok);
case Token::CLASS:
return ParseClassDeclaration(ok);
case Token::CONST:
return ParseVariableStatement(kStatementListItem, ok);
case Token::LET:
if (IsNextLetKeyword()) {
return ParseVariableStatement(kStatementListItem, ok);
}
break;
case Token::ASYNC:
if (allow_harmony_async_await() && PeekAhead() == Token::FUNCTION &&
!scanner()->HasAnyLineTerminatorAfterNext()) {
Consume(Token::ASYNC);
return ParseAsyncFunctionDeclaration(ok);
}
/* falls through */
default:
break;
}
return ParseStatement(kAllowLabelledFunctionStatement, ok);
}
PreParser::LazyParsingResult PreParser::ParseStatementList(int end_token,
bool may_abort,
bool* ok) {
// SourceElements ::
// (Statement)* <end_token>
int count_statements = 0;
bool directive_prologue = true;
while (peek() != end_token) {
if (directive_prologue && peek() != Token::STRING) {
directive_prologue = false;
}
bool starts_with_identifier = peek() == Token::IDENTIFIER;
Scanner::Location token_loc = scanner()->peek_location();
Statement statement =
ParseStatementListItem(CHECK_OK_VALUE(kLazyParsingComplete));
if (directive_prologue) {
bool use_strict_found = statement.IsUseStrictLiteral();
if (use_strict_found) {
scope()->SetLanguageMode(
static_cast<LanguageMode>(scope()->language_mode() | STRICT));
} else if (!statement.IsStringLiteral()) {
directive_prologue = false;
}
if (use_strict_found && !scope()->HasSimpleParameters()) {
// TC39 deemed "use strict" directives to be an error when occurring
// in the body of a function with non-simple parameter list, on
// 29/7/2015. https://goo.gl/ueA7Ln
ReportMessageAt(token_loc,
MessageTemplate::kIllegalLanguageModeDirective,
"use strict");
*ok = false;
return kLazyParsingComplete;
}
}
// If we're allowed to reset to a bookmark, we will do so when we see a long
// and trivial function.
// Our current definition of 'long and trivial' is:
// - over 200 statements
// - all starting with an identifier (i.e., no if, for, while, etc.)
if (may_abort) {
if (!starts_with_identifier) {
may_abort = false;
} else if (++count_statements > kLazyParseTrialLimit) {
return kLazyParsingAborted;
}
}
}
return kLazyParsingComplete;
}
PreParser::Statement PreParser::ParseStatement(
AllowLabelledFunctionStatement allow_function, bool* ok) {
// Statement ::
// EmptyStatement
// ...
if (peek() == Token::SEMICOLON) {
Next();
return Statement::Default();
}
return ParseSubStatement(allow_function, ok);
}
PreParser::Statement PreParser::ParseScopedStatement(bool legacy, bool* ok) {
if (is_strict(language_mode()) || peek() != Token::FUNCTION ||
(legacy && allow_harmony_restrictive_declarations())) {
return ParseStatement(nullptr, kDisallowLabelledFunctionStatement, ok);
return ParseSubStatement(kDisallowLabelledFunctionStatement, ok);
} else {
BlockState block_state(&scope_state_);
return ParseFunctionDeclaration(ok);
}
}
PreParser::Statement PreParser::ParseSubStatement(
AllowLabelledFunctionStatement allow_function, bool* ok) {
// Statement ::
// Block
// VariableStatement
// EmptyStatement
// ExpressionStatement
// IfStatement
// IterationStatement
// ContinueStatement
// BreakStatement
// ReturnStatement
// WithStatement
// LabelledStatement
// SwitchStatement
// ThrowStatement
// TryStatement
// DebuggerStatement
// Note: Since labels can only be used by 'break' and 'continue'
// statements, which themselves are only valid within blocks,
// iterations or 'switch' statements (i.e., BreakableStatements),
// labels can be simply ignored in all other cases; except for
// trivial labeled break statements 'label: break label' which is
// parsed into an empty statement.
// Keep the source position of the statement
switch (peek()) {
case Token::LBRACE:
return ParseBlock(ok);
case Token::SEMICOLON:
Next();
return Statement::Default();
case Token::IF:
return ParseIfStatement(ok);
case Token::DO:
return ParseDoWhileStatement(ok);
case Token::WHILE:
return ParseWhileStatement(ok);
case Token::FOR:
return ParseForStatement(ok);
case Token::CONTINUE:
return ParseContinueStatement(ok);
case Token::BREAK:
return ParseBreakStatement(ok);
case Token::RETURN:
return ParseReturnStatement(ok);
case Token::WITH:
return ParseWithStatement(ok);
case Token::SWITCH:
return ParseSwitchStatement(ok);
case Token::THROW:
return ParseThrowStatement(ok);
case Token::TRY:
return ParseTryStatement(ok);
case Token::FUNCTION:
// FunctionDeclaration only allowed as a StatementListItem, not in
// an arbitrary Statement position. Exceptions such as
// ES#sec-functiondeclarations-in-ifstatement-statement-clauses
// are handled by calling ParseScopedStatement rather than
// ParseSubStatement directly.
ReportMessageAt(scanner()->peek_location(),
is_strict(language_mode())
? MessageTemplate::kStrictFunction
: MessageTemplate::kSloppyFunction);
*ok = false;
return Statement::Default();
case Token::DEBUGGER:
return ParseDebuggerStatement(ok);
case Token::VAR:
return ParseVariableStatement(kStatement, ok);
default:
return ParseExpressionOrLabelledStatement(allow_function, ok);
}
}
PreParser::Statement PreParser::ParseHoistableDeclaration(
int pos, ParseFunctionFlags flags, ZoneList<const AstRawString*>* names,
bool default_export, bool* ok) {
int pos, ParseFunctionFlags flags, bool* ok) {
const bool is_generator = flags & ParseFunctionFlags::kIsGenerator;
const bool is_async = flags & ParseFunctionFlags::kIsAsync;
DCHECK(!is_generator || !is_async);
@ -154,8 +358,7 @@ PreParser::Statement PreParser::ParseHoistableDeclaration(
return Statement::FunctionDeclaration();
}
PreParser::Statement PreParser::ParseAsyncFunctionDeclaration(
ZoneList<const AstRawString*>* names, bool default_export, bool* ok) {
PreParser::Statement PreParser::ParseAsyncFunctionDeclaration(bool* ok) {
// AsyncFunctionDeclaration ::
// async [no LineTerminator here] function BindingIdentifier[Await]
// ( FormalParameters[Await] ) { AsyncFunctionBody }
@ -163,11 +366,10 @@ PreParser::Statement PreParser::ParseAsyncFunctionDeclaration(
int pos = position();
Expect(Token::FUNCTION, CHECK_OK);
ParseFunctionFlags flags = ParseFunctionFlags::kIsAsync;
return ParseHoistableDeclaration(pos, flags, names, default_export, ok);
return ParseHoistableDeclaration(pos, flags, ok);
}
PreParser::Statement PreParser::ParseHoistableDeclaration(
ZoneList<const AstRawString*>* names, bool default_export, bool* ok) {
PreParser::Statement PreParser::ParseHoistableDeclaration(bool* ok) {
// FunctionDeclaration ::
// 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
// GeneratorDeclaration ::
@ -180,11 +382,13 @@ PreParser::Statement PreParser::ParseHoistableDeclaration(
if (Check(Token::MUL)) {
flags |= ParseFunctionFlags::kIsGenerator;
}
return ParseHoistableDeclaration(pos, flags, names, default_export, ok);
return ParseHoistableDeclaration(pos, flags, ok);
}
PreParser::Statement PreParser::ParseClassDeclaration(
ZoneList<const AstRawString*>* names, bool default_export, bool* ok) {
PreParser::Statement PreParser::ParseClassDeclaration(bool* ok) {
Expect(Token::CLASS, CHECK_OK);
int pos = position();
bool is_strict_reserved = false;
Identifier name =
@ -195,8 +399,8 @@ PreParser::Statement PreParser::ParseClassDeclaration(
return Statement::Default();
}
PreParser::Statement PreParser::ParseBlock(
ZoneList<const AstRawString*>* labels, bool* ok) {
PreParser::Statement PreParser::ParseBlock(bool* ok) {
// Block ::
// '{' StatementList '}'
@ -212,14 +416,15 @@ PreParser::Statement PreParser::ParseBlock(
return final;
}
PreParser::Statement PreParser::ParseVariableStatement(
VariableDeclarationContext var_context,
ZoneList<const AstRawString*>* names, bool* ok) {
bool* ok) {
// VariableStatement ::
// VariableDeclarations ';'
Statement result =
ParseVariableDeclarations(var_context, nullptr, names, CHECK_OK);
ParseVariableDeclarations(var_context, nullptr, nullptr, CHECK_OK);
ExpectSemicolon(CHECK_OK);
return result;
}
@ -237,11 +442,10 @@ PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) {
return Statement::Default();
}
}
return ParseHoistableDeclaration(pos, flags, nullptr, false, ok);
return ParseHoistableDeclaration(pos, flags, ok);
}
PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(
ZoneList<const AstRawString*>* names,
AllowLabelledFunctionStatement allow_function, bool* ok) {
// ExpressionStatement | LabelledStatement ::
// Expression ';'
@ -285,7 +489,7 @@ PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(
}
}
Statement statement =
ParseStatement(nullptr, kDisallowLabelledFunctionStatement, ok);
ParseStatement(kDisallowLabelledFunctionStatement, ok);
return statement.IsJumpStatement() ? Statement::Default() : statement;
// Preparsing is disabled for extensions (because the extension details
// aren't passed to lazily compiled functions), so we don't
@ -296,8 +500,8 @@ PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(
return Statement::ExpressionStatement(expr);
}
PreParser::Statement PreParser::ParseIfStatement(
ZoneList<const AstRawString*>* labels, bool* ok) {
PreParser::Statement PreParser::ParseIfStatement(bool* ok) {
// IfStatement ::
// 'if' '(' Expression ')' Statement ('else' Statement)?
@ -335,8 +539,8 @@ PreParser::Statement PreParser::ParseContinueStatement(bool* ok) {
return Statement::Jump();
}
PreParser::Statement PreParser::ParseBreakStatement(
ZoneList<const AstRawString*>* labels, bool* ok) {
PreParser::Statement PreParser::ParseBreakStatement(bool* ok) {
// BreakStatement ::
// 'break' [no line terminator] Identifier? ';'
@ -389,8 +593,8 @@ PreParser::Statement PreParser::ParseReturnStatement(bool* ok) {
return Statement::Jump();
}
PreParser::Statement PreParser::ParseWithStatement(
ZoneList<const AstRawString*>* labels, bool* ok) {
PreParser::Statement PreParser::ParseWithStatement(bool* ok) {
// WithStatement ::
// 'with' '(' Expression ')' Statement
Expect(Token::WITH, CHECK_OK);
@ -409,8 +613,8 @@ PreParser::Statement PreParser::ParseWithStatement(
return Statement::Default();
}
PreParser::Statement PreParser::ParseSwitchStatement(
ZoneList<const AstRawString*>* labels, bool* ok) {
PreParser::Statement PreParser::ParseSwitchStatement(bool* ok) {
// SwitchStatement ::
// 'switch' '(' Expression ')' '{' CaseClause* '}'
@ -445,8 +649,8 @@ PreParser::Statement PreParser::ParseSwitchStatement(
return Statement::Default();
}
PreParser::Statement PreParser::ParseDoWhileStatement(
ZoneList<const AstRawString*>* labels, bool* ok) {
PreParser::Statement PreParser::ParseDoWhileStatement(bool* ok) {
// DoStatement ::
// 'do' Statement 'while' '(' Expression ')' ';'
@ -460,8 +664,8 @@ PreParser::Statement PreParser::ParseDoWhileStatement(
return Statement::Default();
}
PreParser::Statement PreParser::ParseWhileStatement(
ZoneList<const AstRawString*>* labels, bool* ok) {
PreParser::Statement PreParser::ParseWhileStatement(bool* ok) {
// WhileStatement ::
// 'while' '(' Expression ')' Statement
@ -473,8 +677,8 @@ PreParser::Statement PreParser::ParseWhileStatement(
return Statement::Default();
}
PreParser::Statement PreParser::ParseForStatement(
ZoneList<const AstRawString*>* labels, bool* ok) {
PreParser::Statement PreParser::ParseForStatement(bool* ok) {
// ForStatement ::
// 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
@ -640,7 +844,7 @@ PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
{
ReturnExprScope no_tail_calls(function_state_,
ReturnExprContext::kInsideTryBlock);
ParseBlock(nullptr, CHECK_OK);
ParseBlock(CHECK_OK);
}
Token::Value tok = peek();
@ -666,7 +870,7 @@ PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
BlockState block_state(&scope_state_, catch_scope);
{
BlockState block_state(&scope_state_);
ParseBlock(nullptr, CHECK_OK);
ParseBlock(CHECK_OK);
}
}
catch_block_exists = true;
@ -674,7 +878,7 @@ PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
}
if (tok == Token::FINALLY) {
Consume(Token::FINALLY);
ParseBlock(nullptr, CHECK_OK);
ParseBlock(CHECK_OK);
if (FLAG_harmony_explicit_tailcalls && catch_block_exists &&
tail_call_expressions_in_catch_block.has_explicit_tail_calls()) {
// TODO(ishell): update chapter number.
@ -715,7 +919,6 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
// '(' FormalParameterList? ')' '{' FunctionBody '}'
// Parse function body.
PreParserStatementList body;
bool outer_is_script_scope = scope()->is_script_scope();
DeclarationScope* function_scope = NewFunctionScope(kind);
function_scope->SetLanguageMode(language_mode);
@ -744,7 +947,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
if (is_lazily_parsed) {
ParseLazyFunctionLiteralBody(false, CHECK_OK);
} else {
ParseStatementList(body, Token::RBRACE, CHECK_OK);
ParseStatementList(Token::RBRACE, CHECK_OK);
}
Expect(Token::RBRACE, CHECK_OK);
@ -799,9 +1002,8 @@ PreParser::Expression PreParser::ParseAsyncFunctionExpression(bool* ok) {
PreParser::LazyParsingResult PreParser::ParseLazyFunctionLiteralBody(
bool may_abort, bool* ok) {
int body_start = position();
PreParserStatementList body;
LazyParsingResult result = ParseStatementList(
body, Token::RBRACE, may_abort, CHECK_OK_VALUE(kLazyParsingComplete));
Token::RBRACE, may_abort, CHECK_OK_VALUE(kLazyParsingComplete));
if (result == kLazyParsingAborted) return result;
// Position right after terminal '}'.

View File

@ -161,11 +161,6 @@ class PreParserExpression {
IsUseStrictField::encode(true));
}
static PreParserExpression UseAsmStringLiteral() {
return PreParserExpression(TypeField::encode(kStringLiteralExpression) |
IsUseAsmField::encode(true));
}
static PreParserExpression This() {
return PreParserExpression(TypeField::encode(kExpression) |
ExpressionTypeField::encode(kThisExpression));
@ -239,11 +234,6 @@ class PreParserExpression {
IsUseStrictField::decode(code_);
}
bool IsUseAsmLiteral() const {
return TypeField::decode(code_) == kStringLiteralExpression &&
IsUseAsmField::decode(code_);
}
bool IsThis() const {
return TypeField::decode(code_) == kExpression &&
ExpressionTypeField::decode(code_) == kThisExpression;
@ -351,7 +341,6 @@ class PreParserExpression {
// of the Type field, so they can share the storage.
typedef BitField<ExpressionType, TypeField::kNext, 3> ExpressionTypeField;
typedef BitField<bool, TypeField::kNext, 1> IsUseStrictField;
typedef BitField<bool, IsUseStrictField::kNext, 1> IsUseAsmField;
typedef BitField<PreParserIdentifier::Type, TypeField::kNext, 10>
IdentifierTypeField;
typedef BitField<bool, TypeField::kNext, 1> HasCoverInitializedNameField;
@ -370,18 +359,13 @@ class PreParserList {
PreParserList* operator->() { return this; }
void Add(T, void*) { ++length_; }
int length() const { return length_; }
static PreParserList Null() { return PreParserList(-1); }
bool IsNull() const { return length_ == -1; }
private:
explicit PreParserList(int n) : length_(n) {}
int length_;
};
typedef PreParserList<PreParserExpression> PreParserExpressionList;
class PreParserStatement;
typedef PreParserList<PreParserStatement> PreParserStatementList;
class PreParserStatement {
public:
@ -405,9 +389,6 @@ class PreParserStatement {
if (expression.IsUseStrictLiteral()) {
return PreParserStatement(kUseStrictExpressionStatement);
}
if (expression.IsUseAsmLiteral()) {
return PreParserStatement(kUseAsmExpressionStatement);
}
if (expression.IsStringLiteral()) {
return PreParserStatement(kStringLiteralExpressionStatement);
}
@ -415,16 +396,13 @@ class PreParserStatement {
}
bool IsStringLiteral() {
return code_ == kStringLiteralExpressionStatement || IsUseStrictLiteral() ||
IsUseAsmLiteral();
return code_ == kStringLiteralExpressionStatement || IsUseStrictLiteral();
}
bool IsUseStrictLiteral() {
return code_ == kUseStrictExpressionStatement;
}
bool IsUseAsmLiteral() { return code_ == kUseAsmExpressionStatement; }
bool IsFunctionDeclaration() {
return code_ == kFunctionDeclaration;
}
@ -433,19 +411,12 @@ class PreParserStatement {
return code_ == kJumpStatement;
}
// Dummy implementation for making statement->somefunc() work in both Parser
// and PreParser.
PreParserStatement* operator->() { return this; }
PreParserStatementList statements() { return PreParserStatementList(); }
private:
enum Type {
kUnknownStatement,
kJumpStatement,
kStringLiteralExpressionStatement,
kUseStrictExpressionStatement,
kUseAsmExpressionStatement,
kFunctionDeclaration
};
@ -454,6 +425,9 @@ class PreParserStatement {
};
typedef PreParserList<PreParserStatement> PreParserStatementList;
class PreParserFactory {
public:
explicit PreParserFactory(void* unused_value_factory) {}
@ -595,16 +569,6 @@ class PreParserFactory {
return PreParserExpression::Default();
}
PreParserStatement NewEmptyStatement(int pos) {
return PreParserStatement::Default();
}
PreParserStatement NewBlock(ZoneList<const AstRawString*>* labels,
int capacity, bool ignore_completion_value,
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; }
@ -627,17 +591,6 @@ struct PreParserFormalParameters : FormalParametersBase {
class PreParser;
class PreParserTarget {
public:
PreParserTarget(ParserBase<PreParser>* preparser,
PreParserStatement statement) {}
};
class PreParserTargetScope {
public:
explicit PreParserTargetScope(ParserBase<PreParser>* preparser) {}
};
template <>
struct ParserTypes<PreParser> {
typedef ParserBase<PreParser> Base;
@ -654,15 +607,11 @@ struct ParserTypes<PreParser> {
typedef PreParserExpressionList ExpressionList;
typedef PreParserExpressionList PropertyList;
typedef PreParserFormalParameters FormalParameters;
typedef PreParserStatement Statement;
typedef PreParserStatementList StatementList;
typedef PreParserStatement Block;
// For constructing objects returned by the traversing functions.
typedef PreParserFactory Factory;
typedef PreParserTarget Target;
typedef PreParserTargetScope TargetScope;
};
@ -718,8 +667,7 @@ class PreParser : public ParserBase<PreParser> {
bool ok = true;
int start_position = scanner()->peek_location().beg_pos;
parsing_module_ = is_module;
PreParserStatementList body;
ParseStatementList(body, Token::EOS, &ok);
ParseStatementList(Token::EOS, &ok);
if (stack_overflow()) return kPreParseStackOverflow;
if (!ok) {
ReportUnexpectedToken(scanner()->current_token());
@ -750,6 +698,8 @@ class PreParser : public ParserBase<PreParser> {
bool may_abort, int* use_counts);
private:
static const int kLazyParseTrialLimit = 200;
// These types form an algebra over syntactic categories that is just
// rich enough to let us recognize and propagate the constructs that
// are either being counted in the preparser data, or is important
@ -759,38 +709,39 @@ class PreParser : public ParserBase<PreParser> {
// which is set to false if parsing failed; it is unchanged otherwise.
// By making the 'exception handling' explicit, we are forced to check
// for failure at the call sites.
Statement ParseStatementListItem(bool* ok);
V8_INLINE void ParseStatementList(int end_token, bool* ok) {
LazyParsingResult result = ParseStatementList(end_token, false, ok);
USE(result); // The result is just used in debug modes.
DCHECK_EQ(result, kLazyParsingComplete);
}
LazyParsingResult ParseStatementList(int end_token, bool may_abort, bool* ok);
Statement ParseStatement(AllowLabelledFunctionStatement allow_function,
bool* ok);
Statement ParseSubStatement(AllowLabelledFunctionStatement allow_function,
bool* ok);
Statement ParseScopedStatement(bool legacy, bool* ok);
Statement ParseHoistableDeclaration(ZoneList<const AstRawString*>* names,
bool default_export, bool* ok);
Statement ParseHoistableDeclaration(bool* ok);
Statement ParseHoistableDeclaration(int pos, ParseFunctionFlags flags,
ZoneList<const AstRawString*>* names,
bool default_export, bool* ok);
bool* ok);
Statement ParseFunctionDeclaration(bool* ok);
Statement ParseAsyncFunctionDeclaration(ZoneList<const AstRawString*>* names,
bool default_export, bool* ok);
Statement ParseAsyncFunctionDeclaration(bool* ok);
Expression ParseAsyncFunctionExpression(bool* ok);
Statement ParseClassDeclaration(ZoneList<const AstRawString*>* names,
bool default_export, bool* ok);
Statement ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok);
Statement ParseClassDeclaration(bool* ok);
Statement ParseBlock(bool* ok);
Statement ParseVariableStatement(VariableDeclarationContext var_context,
ZoneList<const AstRawString*>* names,
bool* ok);
Statement ParseExpressionOrLabelledStatement(
ZoneList<const AstRawString*>* names,
AllowLabelledFunctionStatement allow_function, bool* ok);
Statement ParseIfStatement(ZoneList<const AstRawString*>* labels, bool* ok);
Statement ParseIfStatement(bool* ok);
Statement ParseContinueStatement(bool* ok);
Statement ParseBreakStatement(ZoneList<const AstRawString*>* labels,
bool* ok);
Statement ParseBreakStatement(bool* ok);
Statement ParseReturnStatement(bool* ok);
Statement ParseWithStatement(ZoneList<const AstRawString*>* labels, bool* ok);
Statement ParseSwitchStatement(ZoneList<const AstRawString*>* labels,
bool* ok);
Statement ParseDoWhileStatement(ZoneList<const AstRawString*>* labels,
bool* ok);
Statement ParseWhileStatement(ZoneList<const AstRawString*>* labels,
bool* ok);
Statement ParseForStatement(ZoneList<const AstRawString*>* labels, bool* ok);
Statement ParseWithStatement(bool* ok);
Statement ParseSwitchStatement(bool* ok);
Statement ParseDoWhileStatement(bool* ok);
Statement ParseWhileStatement(bool* ok);
Statement ParseForStatement(bool* ok);
Statement ParseThrowStatement(bool* ok);
Statement ParseTryStatement(bool* ok);
Statement ParseDebuggerStatement(bool* ok);
@ -834,11 +785,6 @@ class PreParser : public ParserBase<PreParser> {
TemplateLiteralState* state, int start, PreParserExpression tag);
V8_INLINE void CheckConflictingVarDeclarations(Scope* scope, bool* ok) {}
V8_INLINE void SetLanguageMode(Scope* scope, LanguageMode mode) {
scope->SetLanguageMode(mode);
}
V8_INLINE void SetAsmModule() {}
V8_INLINE void MarkCollectedTailCallExpressions() {}
V8_INLINE void MarkTailPosition(PreParserExpression expression) {}
@ -953,18 +899,6 @@ class PreParser : public ParserBase<PreParser> {
return false;
}
V8_INLINE bool IsUseStrictDirective(PreParserStatement statement) const {
return statement.IsUseStrictLiteral();
}
V8_INLINE bool IsUseAsmDirective(PreParserStatement statement) const {
return statement.IsUseAsmLiteral();
}
V8_INLINE bool IsStringLiteral(PreParserStatement statement) const {
return statement.IsStringLiteral();
}
V8_INLINE static PreParserExpression GetPropertyValue(
PreParserExpression property) {
return PreParserExpression::Default();
@ -1057,28 +991,11 @@ class PreParser : public ParserBase<PreParser> {
}
V8_INLINE static PreParserExpressionList NullExpressionList() {
return PreParserExpressionList::Null();
}
V8_INLINE static bool IsNullExpressionList(PreParserExpressionList exprs) {
return exprs.IsNull();
return PreParserExpressionList();
}
V8_INLINE static PreParserStatementList NullStatementList() {
return PreParserStatementList::Null();
}
V8_INLINE static bool IsNullStatementList(PreParserStatementList stmts) {
return stmts.IsNull();
}
V8_INLINE static PreParserStatement NullStatement() {
return PreParserStatement::Default();
}
V8_INLINE bool IsNullOrEmptyStatement(PreParserStatement stmt) {
// TODO(nikolaos): See if this needs to be consistent for the preparser.
return false;
return PreParserStatementList();
}
V8_INLINE static PreParserStatement NullBlock() {
@ -1250,19 +1167,18 @@ PreParserStatementList PreParser::ParseEagerFunctionBody(
const PreParserFormalParameters& parameters, FunctionKind kind,
FunctionLiteral::FunctionType function_type, bool* ok) {
ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
PreParserStatementList result;
Scope* inner_scope = scope();
if (!parameters.is_simple) inner_scope = NewScope(BLOCK_SCOPE);
{
BlockState block_state(&scope_state_, inner_scope);
ParseStatementList(result, Token::RBRACE, ok);
ParseStatementList(Token::RBRACE, ok);
if (!*ok) return PreParserStatementList();
}
Expect(Token::RBRACE, ok);
return result;
return PreParserStatementList();
}
PreParserExpression PreParser::CloseTemplateLiteral(TemplateLiteralState* state,