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:
parent
68b47f5e0f
commit
02164afd81
@ -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
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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_;
|
||||
|
||||
|
@ -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 '}'.
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user