Move ParseHoistableDeclaration to ParserBase.

BUG=

Review-Url: https://codereview.chromium.org/2311903003
Cr-Commit-Position: refs/heads/master@{#39300}
This commit is contained in:
marja 2016-09-09 00:57:59 -07:00 committed by Commit bot
parent 1d2574afe6
commit 751f8e99c9
5 changed files with 131 additions and 139 deletions

View File

@ -1141,6 +1141,11 @@ class ParserBase {
DeclarationParsingResult* parsing_result,
ZoneList<const AstRawString*>* names,
bool* ok);
StatementT ParseHoistableDeclaration(ZoneList<const AstRawString*>* names,
bool default_export, bool* ok);
StatementT ParseHoistableDeclaration(int pos, ParseFunctionFlags flags,
ZoneList<const AstRawString*>* names,
bool default_export, bool* ok);
// Under some circumstances, we allow preparsing to abort if the preparsed
// function is "long and trivial", and fully parse instead. Our current
@ -3592,6 +3597,68 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseVariableDeclarations(
return init_block;
}
template <typename Impl>
typename ParserBase<Impl>::StatementT
ParserBase<Impl>::ParseHoistableDeclaration(
ZoneList<const AstRawString*>* names, bool default_export, bool* ok) {
Expect(Token::FUNCTION, CHECK_OK_CUSTOM(NullStatement));
int pos = position();
ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
if (Check(Token::MUL)) {
flags |= ParseFunctionFlags::kIsGenerator;
}
return ParseHoistableDeclaration(pos, flags, names, default_export, ok);
}
template <typename Impl>
typename ParserBase<Impl>::StatementT
ParserBase<Impl>::ParseHoistableDeclaration(
int pos, ParseFunctionFlags flags, ZoneList<const AstRawString*>* names,
bool default_export, bool* ok) {
// FunctionDeclaration ::
// 'function' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
// 'function' '(' FormalParameters ')' '{' FunctionBody '}'
// GeneratorDeclaration ::
// 'function' '*' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
// 'function' '*' '(' FormalParameters ')' '{' FunctionBody '}'
//
// The anonymous forms are allowed iff [default_export] is true.
//
// 'function' and '*' (if present) have been consumed by the caller.
const bool is_generator = flags & ParseFunctionFlags::kIsGenerator;
const bool is_async = flags & ParseFunctionFlags::kIsAsync;
DCHECK(!is_generator || !is_async);
IdentifierT name;
FunctionNameValidity name_validity;
IdentifierT variable_name;
if (default_export && peek() == Token::LPAREN) {
impl()->GetDefaultStrings(&name, &variable_name);
name_validity = kSkipFunctionNameCheck;
} else {
bool is_strict_reserved;
name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved,
CHECK_OK_CUSTOM(NullStatement));
name_validity = is_strict_reserved ? kFunctionNameIsStrictReserved
: kFunctionNameValidityUnknown;
variable_name = name;
}
FuncNameInferrer::State fni_state(fni_);
impl()->PushEnclosingName(name);
FunctionLiteralT function = impl()->ParseFunctionLiteral(
name, scanner()->location(), name_validity,
is_generator ? FunctionKind::kGeneratorFunction
: is_async ? FunctionKind::kAsyncFunction
: FunctionKind::kNormalFunction,
pos, FunctionLiteral::kDeclaration, language_mode(),
CHECK_OK_CUSTOM(NullStatement));
return impl()->DeclareFunction(variable_name, function, pos, is_generator,
is_async, names, ok);
}
template <typename Impl>
void ParserBase<Impl>::CheckArityRestrictions(int param_count,
FunctionKind function_kind,

View File

@ -1504,17 +1504,6 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) {
pos);
}
Statement* Parser::ParseHoistableDeclaration(
ZoneList<const AstRawString*>* names, bool default_export, bool* ok) {
Expect(Token::FUNCTION, CHECK_OK);
int pos = position();
ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
if (Check(Token::MUL)) {
flags |= ParseFunctionFlags::kIsGenerator;
}
return ParseHoistableDeclaration(pos, flags, names, default_export, ok);
}
Statement* Parser::ParseAsyncFunctionDeclaration(
ZoneList<const AstRawString*>* names, bool default_export, bool* ok) {
DCHECK_EQ(scanner()->current_token(), Token::ASYNC);
@ -1529,76 +1518,6 @@ Statement* Parser::ParseAsyncFunctionDeclaration(
return ParseHoistableDeclaration(pos, flags, names, default_export, ok);
}
Statement* Parser::ParseHoistableDeclaration(
int pos, ParseFunctionFlags flags, ZoneList<const AstRawString*>* names,
bool default_export, bool* ok) {
// FunctionDeclaration ::
// 'function' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
// 'function' '(' FormalParameters ')' '{' FunctionBody '}'
// GeneratorDeclaration ::
// 'function' '*' Identifier '(' FormalParameters ')' '{' FunctionBody '}'
// 'function' '*' '(' FormalParameters ')' '{' FunctionBody '}'
//
// The anonymous forms are allowed iff [default_export] is true.
//
// 'function' and '*' (if present) have been consumed by the caller.
const bool is_generator = flags & ParseFunctionFlags::kIsGenerator;
const bool is_async = flags & ParseFunctionFlags::kIsAsync;
DCHECK(!is_generator || !is_async);
const AstRawString* name;
FunctionNameValidity name_validity;
const AstRawString* variable_name;
if (default_export && peek() == Token::LPAREN) {
name = ast_value_factory()->default_string();
name_validity = kSkipFunctionNameCheck;
variable_name = ast_value_factory()->star_default_star_string();
} else {
bool is_strict_reserved;
name = ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
name_validity = is_strict_reserved ? kFunctionNameIsStrictReserved
: kFunctionNameValidityUnknown;
variable_name = name;
}
FuncNameInferrer::State fni_state(fni_);
DCHECK_NOT_NULL(fni_);
fni_->PushEnclosingName(name);
FunctionLiteral* fun = ParseFunctionLiteral(
name, scanner()->location(), name_validity,
is_generator ? FunctionKind::kGeneratorFunction
: is_async ? FunctionKind::kAsyncFunction
: FunctionKind::kNormalFunction,
pos, FunctionLiteral::kDeclaration, language_mode(), CHECK_OK);
// In ES6, a function behaves as a lexical binding, except in
// a script scope, or the initial scope of eval or another function.
VariableMode mode =
(!scope()->is_declaration_scope() || scope()->is_module_scope()) ? LET
: VAR;
VariableProxy* proxy = NewUnresolved(variable_name);
Declaration* declaration =
factory()->NewFunctionDeclaration(proxy, fun, scope(), pos);
Declare(declaration, DeclarationDescriptor::NORMAL, mode, kCreatedInitialized,
CHECK_OK);
if (names) names->Add(variable_name, zone());
// Async functions don't undergo sloppy mode block scoped hoisting, and don't
// allow duplicates in a block. Both are represented by the
// sloppy_block_function_map. Don't add them to the map for async functions.
// Generators are also supposed to be prohibited; currently doing this behind
// a flag and UseCounting violations to assess web compatibility.
if (is_sloppy(language_mode()) && !scope()->is_declaration_scope() &&
!is_async && !(allow_harmony_restrictive_generators() && is_generator)) {
SloppyBlockFunctionStatement* delegate =
factory()->NewSloppyBlockFunctionStatement(scope());
DeclarationScope* target_scope = GetDeclarationScope();
target_scope->DeclareSloppyBlockFunction(variable_name, delegate);
return delegate;
}
return factory()->NewEmptyStatement(kNoSourcePosition);
}
Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names,
bool default_export, bool* ok) {
// ClassDeclaration ::
@ -1669,6 +1588,38 @@ void Parser::DeclareAndInitializeVariables(
this, block, declaration_descriptor, declaration, names, ok);
}
Statement* Parser::DeclareFunction(const AstRawString* variable_name,
FunctionLiteral* function, int pos,
bool is_generator, bool is_async,
ZoneList<const AstRawString*>* names,
bool* ok) {
// In ES6, a function behaves as a lexical binding, except in
// a script scope, or the initial scope of eval or another function.
VariableMode mode =
(!scope()->is_declaration_scope() || scope()->is_module_scope()) ? LET
: VAR;
VariableProxy* proxy = NewUnresolved(variable_name);
Declaration* declaration =
factory()->NewFunctionDeclaration(proxy, function, scope(), pos);
Declare(declaration, DeclarationDescriptor::NORMAL, mode, kCreatedInitialized,
CHECK_OK);
if (names) names->Add(variable_name, zone());
// Async functions don't undergo sloppy mode block scoped hoisting, and don't
// allow duplicates in a block. Both are represented by the
// sloppy_block_function_map. Don't add them to the map for async functions.
// Generators are also supposed to be prohibited; currently doing this behind
// a flag and UseCounting violations to assess web compatibility.
if (is_sloppy(language_mode()) && !scope()->is_declaration_scope() &&
!is_async && !(allow_harmony_restrictive_generators() && is_generator)) {
SloppyBlockFunctionStatement* delegate =
factory()->NewSloppyBlockFunctionStatement(scope());
DeclarationScope* target_scope = GetDeclarationScope();
target_scope->DeclareSloppyBlockFunction(variable_name, delegate);
return delegate;
}
return factory()->NewEmptyStatement(kNoSourcePosition);
}
static bool ContainsLabel(ZoneList<const AstRawString*>* labels,
const AstRawString* label) {
DCHECK(label != NULL);

View File

@ -267,11 +267,6 @@ class Parser : public ParserBase<Parser> {
};
ZoneList<const NamedImport*>* ParseNamedImports(int pos, bool* ok);
Statement* ParseFunctionDeclaration(bool* ok);
Statement* ParseHoistableDeclaration(ZoneList<const AstRawString*>* names,
bool default_export, bool* ok);
Statement* ParseHoistableDeclaration(int pos, ParseFunctionFlags flags,
ZoneList<const AstRawString*>* names,
bool default_export, bool* ok);
Statement* ParseAsyncFunctionDeclaration(ZoneList<const AstRawString*>* names,
bool default_export, bool* ok);
Expression* ParseAsyncFunctionExpression(bool* ok);
@ -286,6 +281,11 @@ class Parser : public ParserBase<Parser> {
const DeclarationParsingResult::Declaration* declaration,
ZoneList<const AstRawString*>* names, bool* ok);
Statement* DeclareFunction(const AstRawString* variable_name,
FunctionLiteral* function, int pos,
bool is_generator, bool is_async,
ZoneList<const AstRawString*>* names, bool* ok);
DoExpression* ParseDoExpression(bool* ok);
Expression* ParseYieldStarExpression(bool* ok);
@ -699,6 +699,13 @@ class Parser : public ParserBase<Parser> {
return property->value();
}
V8_INLINE void GetDefaultStrings(
const AstRawString** default_string,
const AstRawString** star_default_star_string) {
*default_string = ast_value_factory()->default_string();
*star_default_star_string = ast_value_factory()->star_default_star_string();
}
// Functions for encapsulating the differences between parsing and preparsing;
// operations interleaved with the recursive descent.
V8_INLINE void PushLiteralName(const AstRawString* id) {
@ -720,6 +727,11 @@ class Parser : public ParserBase<Parser> {
}
}
V8_INLINE void PushEnclosingName(const AstRawString* name) {
DCHECK_NOT_NULL(fni_);
fni_->PushEnclosingName(name);
}
V8_INLINE void InferFunctionName(FunctionLiteral* func_to_infer) {
fni_->AddFunction(func_to_infer);
}

View File

@ -121,28 +121,6 @@ PreParser::PreParseResult PreParser::PreParseLazyFunction(
// That means that contextual checks (like a label being declared where
// it is used) are generally omitted.
PreParser::Statement PreParser::ParseHoistableDeclaration(
int pos, ParseFunctionFlags flags, ZoneList<const AstRawString*>* names,
bool default_export, bool* ok) {
const bool is_generator = flags & ParseFunctionFlags::kIsGenerator;
const bool is_async = flags & ParseFunctionFlags::kIsAsync;
DCHECK(!is_generator || !is_async);
bool is_strict_reserved = false;
Identifier name = ParseIdentifierOrStrictReservedWord(
&is_strict_reserved, CHECK_OK);
ParseFunctionLiteral(name, scanner()->location(),
is_strict_reserved ? kFunctionNameIsStrictReserved
: kFunctionNameValidityUnknown,
is_generator ? FunctionKind::kGeneratorFunction
: is_async ? FunctionKind::kAsyncFunction
: FunctionKind::kNormalFunction,
pos, FunctionLiteral::kDeclaration, language_mode(),
CHECK_OK);
return Statement::FunctionDeclaration();
}
PreParser::Statement PreParser::ParseAsyncFunctionDeclaration(
ZoneList<const AstRawString*>* names, bool default_export, bool* ok) {
// AsyncFunctionDeclaration ::
@ -155,23 +133,6 @@ PreParser::Statement PreParser::ParseAsyncFunctionDeclaration(
return ParseHoistableDeclaration(pos, flags, names, default_export, ok);
}
PreParser::Statement PreParser::ParseHoistableDeclaration(
ZoneList<const AstRawString*>* names, bool default_export, bool* ok) {
// FunctionDeclaration ::
// 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
// GeneratorDeclaration ::
// 'function' '*' Identifier '(' FormalParameterListopt ')'
// '{' FunctionBody '}'
Expect(Token::FUNCTION, CHECK_OK);
int pos = position();
ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
if (Check(Token::MUL)) {
flags |= ParseFunctionFlags::kIsGenerator;
}
return ParseHoistableDeclaration(pos, flags, names, default_export, ok);
}
PreParser::Statement PreParser::ParseClassDeclaration(
ZoneList<const AstRawString*>* names, bool default_export, bool* ok) {
int pos = position();
@ -197,6 +158,9 @@ PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) {
return Statement::Default();
}
}
// PreParser is not able to parse "export default" yet (since PreParser is
// at the moment only used for functions, and it cannot occur
// there). TODO(marja): update this when it is.
return ParseHoistableDeclaration(pos, flags, nullptr, false, ok);
}

View File

@ -393,10 +393,6 @@ class PreParserStatement {
return PreParserStatement(kJumpStatement);
}
static PreParserStatement FunctionDeclaration() {
return PreParserStatement(kFunctionDeclaration);
}
// Creates expression statement from expression.
// Preserves being an unparenthesized string literal, possibly
// "use strict".
@ -425,10 +421,6 @@ class PreParserStatement {
bool IsUseAsmLiteral() { return code_ == kUseAsmExpressionStatement; }
bool IsFunctionDeclaration() {
return code_ == kFunctionDeclaration;
}
bool IsJumpStatement() {
return code_ == kJumpStatement;
}
@ -447,7 +439,6 @@ class PreParserStatement {
kStringLiteralExpressionStatement,
kUseStrictExpressionStatement,
kUseAsmExpressionStatement,
kFunctionDeclaration
};
explicit PreParserStatement(Type code) : code_(code) {}
@ -764,11 +755,6 @@ 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 ParseHoistableDeclaration(ZoneList<const AstRawString*>* names,
bool default_export, bool* ok);
Statement ParseHoistableDeclaration(int pos, ParseFunctionFlags flags,
ZoneList<const AstRawString*>* names,
bool default_export, bool* ok);
Statement ParseFunctionDeclaration(bool* ok);
Statement ParseAsyncFunctionDeclaration(ZoneList<const AstRawString*>* names,
bool default_export, bool* ok);
@ -885,6 +871,13 @@ class PreParser : public ParserBase<PreParser> {
const DeclarationParsingResult::Declaration* declaration,
ZoneList<const AstRawString*>* names, bool* ok) {}
V8_INLINE PreParserStatement DeclareFunction(
PreParserIdentifier variable_name, PreParserExpression function, int pos,
bool is_generator, bool is_async, ZoneList<const AstRawString*>* names,
bool* ok) {
return Statement::Default();
}
V8_INLINE void QueueDestructuringAssignmentForRewriting(
PreParserExpression assignment) {}
V8_INLINE void QueueNonPatternForRewriting(PreParserExpression expr,
@ -968,11 +961,16 @@ class PreParser : public ParserBase<PreParser> {
return PreParserExpression::Default();
}
V8_INLINE static void GetDefaultStrings(
PreParserIdentifier* default_string,
PreParserIdentifier* star_default_star_string) {}
// Functions for encapsulating the differences between parsing and preparsing;
// operations interleaved with the recursive descent.
V8_INLINE static void PushLiteralName(PreParserIdentifier id) {}
V8_INLINE static void PushVariableName(PreParserIdentifier id) {}
V8_INLINE void PushPropertyName(PreParserExpression expression) {}
V8_INLINE void PushEnclosingName(PreParserIdentifier name) {}
V8_INLINE static void InferFunctionName(PreParserExpression expression) {}
V8_INLINE static void CheckAssigningFunctionLiteralToProperty(