Parsing: Create the same scopes for non-simple params in PreParser & Parser.
Rationale: - To do scope analysis based on PreParser, and use the result again when parsing later, PreParser and Parser need to produce the same Scopes and variable declarations in them. - This is not the case for non-simple parameters: Parser creates an additional inner Scope where the declarations were, whereas PreParser does DeclareVariableName directly in the function Scope. - So this CL fixes that by moving the Scope creation for non-simple parameters into ParserBase. - As a side product (and a partial proof that this change makes sense), PreParser::ParseEagerFunctionBody is now gone. BUG=v8:5516 Review-Url: https://codereview.chromium.org/2638333002 Cr-Commit-Position: refs/heads/master@{#42537}
This commit is contained in:
parent
8b8c8df05b
commit
3534091756
@ -101,6 +101,12 @@ struct FormalParametersBase {
|
|||||||
// Used in functions where the return type is ExpressionT.
|
// Used in functions where the return type is ExpressionT.
|
||||||
#define CHECK_OK CHECK_OK_CUSTOM(EmptyExpression)
|
#define CHECK_OK CHECK_OK_CUSTOM(EmptyExpression)
|
||||||
|
|
||||||
|
#define CHECK_OK_VOID ok); \
|
||||||
|
if (!*ok) return; \
|
||||||
|
((void)0
|
||||||
|
#define DUMMY ) // to make indentation work
|
||||||
|
#undef DUMMY
|
||||||
|
|
||||||
// Common base class template shared between parser and pre-parser.
|
// Common base class template shared between parser and pre-parser.
|
||||||
// The Impl parameter is the actual class of the parser/pre-parser,
|
// The Impl parameter is the actual class of the parser/pre-parser,
|
||||||
// following the Curiously Recurring Template Pattern (CRTP).
|
// following the Curiously Recurring Template Pattern (CRTP).
|
||||||
@ -1224,6 +1230,12 @@ class ParserBase {
|
|||||||
bool default_export, bool* ok);
|
bool default_export, bool* ok);
|
||||||
StatementT ParseNativeDeclaration(bool* ok);
|
StatementT ParseNativeDeclaration(bool* ok);
|
||||||
|
|
||||||
|
// Consumes the ending }.
|
||||||
|
void ParseFunctionBody(StatementListT result, IdentifierT function_name,
|
||||||
|
int pos, const FormalParametersT& parameters,
|
||||||
|
FunctionKind kind,
|
||||||
|
FunctionLiteral::FunctionType function_type, bool* ok);
|
||||||
|
|
||||||
// Under some circumstances, we allow preparsing to abort if the preparsed
|
// Under some circumstances, we allow preparsing to abort if the preparsed
|
||||||
// function is "long and trivial", and fully parse instead. Our current
|
// function is "long and trivial", and fully parse instead. Our current
|
||||||
// definition of "long and trivial" is:
|
// definition of "long and trivial" is:
|
||||||
@ -3901,6 +3913,105 @@ ParserBase<Impl>::ParseAsyncFunctionDeclaration(
|
|||||||
return ParseHoistableDeclaration(pos, flags, names, default_export, ok);
|
return ParseHoistableDeclaration(pos, flags, names, default_export, ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename Impl>
|
||||||
|
void ParserBase<Impl>::ParseFunctionBody(
|
||||||
|
typename ParserBase<Impl>::StatementListT result, IdentifierT function_name,
|
||||||
|
int pos, const FormalParametersT& parameters, FunctionKind kind,
|
||||||
|
FunctionLiteral::FunctionType function_type, bool* ok) {
|
||||||
|
static const int kFunctionNameAssignmentIndex = 0;
|
||||||
|
if (function_type == FunctionLiteral::kNamedExpression) {
|
||||||
|
DCHECK(!impl()->IsEmptyIdentifier(function_name));
|
||||||
|
// If we have a named function expression, we add a local variable
|
||||||
|
// declaration to the body of the function with the name of the
|
||||||
|
// function and let it refer to the function itself (closure).
|
||||||
|
// Not having parsed the function body, the language mode may still change,
|
||||||
|
// so we reserve a spot and create the actual const assignment later.
|
||||||
|
DCHECK_EQ(kFunctionNameAssignmentIndex, result->length());
|
||||||
|
result->Add(impl()->NullStatement(), zone());
|
||||||
|
}
|
||||||
|
|
||||||
|
DeclarationScope* function_scope = scope()->AsDeclarationScope();
|
||||||
|
DeclarationScope* inner_scope = function_scope;
|
||||||
|
BlockT inner_block = impl()->NullBlock();
|
||||||
|
|
||||||
|
StatementListT body = result;
|
||||||
|
if (!parameters.is_simple) {
|
||||||
|
inner_scope = NewVarblockScope();
|
||||||
|
inner_scope->set_start_position(scanner()->location().beg_pos);
|
||||||
|
inner_block = factory()->NewBlock(NULL, 8, true, kNoSourcePosition);
|
||||||
|
inner_block->set_scope(inner_scope);
|
||||||
|
body = inner_block->statements();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
BlockState block_state(&scope_state_, inner_scope);
|
||||||
|
|
||||||
|
if (IsGeneratorFunction(kind)) {
|
||||||
|
impl()->ParseAndRewriteGeneratorFunctionBody(pos, kind, body, ok);
|
||||||
|
} else if (IsAsyncFunction(kind)) {
|
||||||
|
const bool accept_IN = true;
|
||||||
|
ParseAsyncFunctionBody(inner_scope, body, kind, FunctionBodyType::kNormal,
|
||||||
|
accept_IN, pos, CHECK_OK_VOID);
|
||||||
|
} else {
|
||||||
|
ParseStatementList(body, Token::RBRACE, CHECK_OK_VOID);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsDerivedConstructor(kind)) {
|
||||||
|
body->Add(factory()->NewReturnStatement(impl()->ThisExpression(),
|
||||||
|
kNoSourcePosition),
|
||||||
|
zone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Expect(Token::RBRACE, CHECK_OK_VOID);
|
||||||
|
scope()->set_end_position(scanner()->location().end_pos);
|
||||||
|
|
||||||
|
if (!parameters.is_simple) {
|
||||||
|
DCHECK_NOT_NULL(inner_scope);
|
||||||
|
DCHECK_EQ(function_scope, scope());
|
||||||
|
DCHECK_EQ(function_scope, inner_scope->outer_scope());
|
||||||
|
impl()->SetLanguageMode(function_scope, inner_scope->language_mode());
|
||||||
|
BlockT init_block =
|
||||||
|
impl()->BuildParameterInitializationBlock(parameters, CHECK_OK_VOID);
|
||||||
|
|
||||||
|
if (is_sloppy(inner_scope->language_mode())) {
|
||||||
|
impl()->InsertSloppyBlockFunctionVarBindings(inner_scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(littledan): Merge the two rejection blocks into one
|
||||||
|
if (IsAsyncFunction(kind)) {
|
||||||
|
init_block = impl()->BuildRejectPromiseOnException(init_block);
|
||||||
|
}
|
||||||
|
|
||||||
|
inner_scope->set_end_position(scanner()->location().end_pos);
|
||||||
|
if (inner_scope->FinalizeBlockScope() != nullptr) {
|
||||||
|
impl()->CheckConflictingVarDeclarations(inner_scope, CHECK_OK_VOID);
|
||||||
|
impl()->InsertShadowingVarBindingInitializers(inner_block);
|
||||||
|
}
|
||||||
|
inner_scope = nullptr;
|
||||||
|
|
||||||
|
result->Add(init_block, zone());
|
||||||
|
result->Add(inner_block, zone());
|
||||||
|
} else {
|
||||||
|
DCHECK_EQ(inner_scope, function_scope);
|
||||||
|
if (is_sloppy(function_scope->language_mode())) {
|
||||||
|
impl()->InsertSloppyBlockFunctionVarBindings(function_scope);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsArrowFunction(kind)) {
|
||||||
|
// Declare arguments after parsing the function since lexical 'arguments'
|
||||||
|
// masks the arguments object. Declare arguments before declaring the
|
||||||
|
// function var since the arguments object masks 'function arguments'.
|
||||||
|
function_scope->DeclareArguments(ast_value_factory());
|
||||||
|
}
|
||||||
|
|
||||||
|
impl()->CreateFunctionNameAssignment(function_name, pos, function_type,
|
||||||
|
function_scope, result,
|
||||||
|
kFunctionNameAssignmentIndex);
|
||||||
|
impl()->MarkCollectedTailCallExpressions();
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Impl>
|
template <typename Impl>
|
||||||
void ParserBase<Impl>::CheckArityRestrictions(int param_count,
|
void ParserBase<Impl>::CheckArityRestrictions(int param_count,
|
||||||
FunctionKind function_kind,
|
FunctionKind function_kind,
|
||||||
@ -4064,9 +4175,11 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
|
|||||||
}
|
}
|
||||||
if (!is_lazy_top_level_function) {
|
if (!is_lazy_top_level_function) {
|
||||||
Consume(Token::LBRACE);
|
Consume(Token::LBRACE);
|
||||||
body = impl()->ParseEagerFunctionBody(
|
body = impl()->NewStatementList(8);
|
||||||
impl()->EmptyIdentifier(), kNoSourcePosition, formal_parameters,
|
impl()->ParseFunctionBody(body, impl()->EmptyIdentifier(),
|
||||||
kind, FunctionLiteral::kAnonymousExpression, CHECK_OK);
|
kNoSourcePosition, formal_parameters, kind,
|
||||||
|
FunctionLiteral::kAnonymousExpression,
|
||||||
|
CHECK_OK);
|
||||||
materialized_literal_count =
|
materialized_literal_count =
|
||||||
function_state.materialized_literal_count();
|
function_state.materialized_literal_count();
|
||||||
expected_property_count = function_state.expected_property_count();
|
expected_property_count = function_state.expected_property_count();
|
||||||
@ -5563,6 +5676,7 @@ void ParserBase<Impl>::ClassLiteralChecker::CheckClassMethodName(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef CHECK_OK_VOID
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
@ -1754,6 +1754,70 @@ Statement* Parser::RewriteTryStatement(Block* try_block, Block* catch_block,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Parser::ParseAndRewriteGeneratorFunctionBody(int pos, FunctionKind kind,
|
||||||
|
ZoneList<Statement*>* body,
|
||||||
|
bool* ok) {
|
||||||
|
// We produce:
|
||||||
|
//
|
||||||
|
// try { InitialYield; ...body...; return {value: undefined, done: true} }
|
||||||
|
// finally { %_GeneratorClose(generator) }
|
||||||
|
//
|
||||||
|
// - InitialYield yields the actual generator object.
|
||||||
|
// - Any return statement inside the body will have its argument wrapped
|
||||||
|
// in a "done" iterator result object.
|
||||||
|
// - If the generator terminates for whatever reason, we must close it.
|
||||||
|
// Hence the finally clause.
|
||||||
|
|
||||||
|
Block* try_block = factory()->NewBlock(nullptr, 3, false, kNoSourcePosition);
|
||||||
|
Expression* initial_yield = BuildInitialYield(pos, kind);
|
||||||
|
try_block->statements()->Add(
|
||||||
|
factory()->NewExpressionStatement(initial_yield, kNoSourcePosition),
|
||||||
|
zone());
|
||||||
|
ParseStatementList(try_block->statements(), Token::RBRACE, ok);
|
||||||
|
if (!*ok) return;
|
||||||
|
|
||||||
|
Statement* final_return = factory()->NewReturnStatement(
|
||||||
|
BuildIteratorResult(nullptr, true), kNoSourcePosition);
|
||||||
|
try_block->statements()->Add(final_return, zone());
|
||||||
|
|
||||||
|
Block* finally_block =
|
||||||
|
factory()->NewBlock(nullptr, 1, false, kNoSourcePosition);
|
||||||
|
ZoneList<Expression*>* args = new (zone()) ZoneList<Expression*>(1, zone());
|
||||||
|
VariableProxy* call_proxy =
|
||||||
|
factory()->NewVariableProxy(function_state_->generator_object_variable());
|
||||||
|
args->Add(call_proxy, zone());
|
||||||
|
Expression* call = factory()->NewCallRuntime(Runtime::kInlineGeneratorClose,
|
||||||
|
args, kNoSourcePosition);
|
||||||
|
finally_block->statements()->Add(
|
||||||
|
factory()->NewExpressionStatement(call, kNoSourcePosition), zone());
|
||||||
|
|
||||||
|
body->Add(factory()->NewTryFinallyStatement(try_block, finally_block,
|
||||||
|
kNoSourcePosition),
|
||||||
|
zone());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::CreateFunctionNameAssignment(
|
||||||
|
const AstRawString* function_name, int pos,
|
||||||
|
FunctionLiteral::FunctionType function_type,
|
||||||
|
DeclarationScope* function_scope, ZoneList<Statement*>* result, int index) {
|
||||||
|
if (function_type == FunctionLiteral::kNamedExpression) {
|
||||||
|
StatementT statement = factory()->NewEmptyStatement(kNoSourcePosition);
|
||||||
|
if (function_scope->LookupLocal(function_name) == nullptr) {
|
||||||
|
// Now that we know the language mode, we can create the const assignment
|
||||||
|
// in the previously reserved spot.
|
||||||
|
DCHECK_EQ(function_scope, scope());
|
||||||
|
Variable* fvar = function_scope->DeclareFunctionVar(function_name);
|
||||||
|
VariableProxy* fproxy = factory()->NewVariableProxy(fvar);
|
||||||
|
statement = factory()->NewExpressionStatement(
|
||||||
|
factory()->NewAssignment(Token::INIT, fproxy,
|
||||||
|
factory()->NewThisFunction(pos),
|
||||||
|
kNoSourcePosition),
|
||||||
|
kNoSourcePosition);
|
||||||
|
}
|
||||||
|
result->Set(index, statement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// !%_IsJSReceiver(result = iterator.next()) &&
|
// !%_IsJSReceiver(result = iterator.next()) &&
|
||||||
// %ThrowIteratorResultNotAnObject(result)
|
// %ThrowIteratorResultNotAnObject(result)
|
||||||
Expression* Parser::BuildIteratorNextResult(Expression* iterator,
|
Expression* Parser::BuildIteratorNextResult(Expression* iterator,
|
||||||
@ -2920,7 +2984,7 @@ Block* Parser::BuildParameterInitializationBlock(
|
|||||||
return init_block;
|
return init_block;
|
||||||
}
|
}
|
||||||
|
|
||||||
Block* Parser::BuildRejectPromiseOnException(Block* inner_block, bool* ok) {
|
Block* Parser::BuildRejectPromiseOnException(Block* inner_block) {
|
||||||
// .promise = %AsyncFunctionPromiseCreate();
|
// .promise = %AsyncFunctionPromiseCreate();
|
||||||
// try {
|
// try {
|
||||||
// <inner_block>
|
// <inner_block>
|
||||||
@ -3082,8 +3146,8 @@ ZoneList<Statement*>* Parser::ParseFunction(
|
|||||||
CHECK_OK);
|
CHECK_OK);
|
||||||
Expect(Token::LBRACE, CHECK_OK);
|
Expect(Token::LBRACE, CHECK_OK);
|
||||||
|
|
||||||
ZoneList<Statement*>* body = ParseEagerFunctionBody(
|
ZoneList<Statement*>* body = new (zone()) ZoneList<Statement*>(8, zone());
|
||||||
function_name, pos, formals, kind, function_type, ok);
|
ParseFunctionBody(body, function_name, pos, formals, kind, function_type, ok);
|
||||||
|
|
||||||
// Validate parameter names. We can do this only after parsing the function,
|
// Validate parameter names. We can do this only after parsing the function,
|
||||||
// since the function can declare itself strict.
|
// since the function can declare itself strict.
|
||||||
@ -3103,161 +3167,6 @@ ZoneList<Statement*>* Parser::ParseFunction(
|
|||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
|
|
||||||
const AstRawString* function_name, int pos,
|
|
||||||
const ParserFormalParameters& parameters, FunctionKind kind,
|
|
||||||
FunctionLiteral::FunctionType function_type, bool* ok) {
|
|
||||||
ZoneList<Statement*>* result = new(zone()) ZoneList<Statement*>(8, zone());
|
|
||||||
|
|
||||||
static const int kFunctionNameAssignmentIndex = 0;
|
|
||||||
if (function_type == FunctionLiteral::kNamedExpression) {
|
|
||||||
DCHECK(function_name != NULL);
|
|
||||||
// If we have a named function expression, we add a local variable
|
|
||||||
// declaration to the body of the function with the name of the
|
|
||||||
// function and let it refer to the function itself (closure).
|
|
||||||
// Not having parsed the function body, the language mode may still change,
|
|
||||||
// so we reserve a spot and create the actual const assignment later.
|
|
||||||
DCHECK_EQ(kFunctionNameAssignmentIndex, result->length());
|
|
||||||
result->Add(NULL, zone());
|
|
||||||
}
|
|
||||||
|
|
||||||
ZoneList<Statement*>* body = result;
|
|
||||||
DeclarationScope* function_scope = scope()->AsDeclarationScope();
|
|
||||||
DeclarationScope* inner_scope = function_scope;
|
|
||||||
Block* inner_block = nullptr;
|
|
||||||
if (!parameters.is_simple) {
|
|
||||||
inner_scope = NewVarblockScope();
|
|
||||||
inner_scope->set_start_position(scanner()->location().beg_pos);
|
|
||||||
inner_block = factory()->NewBlock(NULL, 8, true, kNoSourcePosition);
|
|
||||||
inner_block->set_scope(inner_scope);
|
|
||||||
body = inner_block->statements();
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
BlockState block_state(&scope_state_, inner_scope);
|
|
||||||
|
|
||||||
if (IsGeneratorFunction(kind)) {
|
|
||||||
// We produce:
|
|
||||||
//
|
|
||||||
// try { InitialYield; ...body...; return {value: undefined, done: true} }
|
|
||||||
// finally { %_GeneratorClose(generator) }
|
|
||||||
//
|
|
||||||
// - InitialYield yields the actual generator object.
|
|
||||||
// - Any return statement inside the body will have its argument wrapped
|
|
||||||
// in a "done" iterator result object.
|
|
||||||
// - If the generator terminates for whatever reason, we must close it.
|
|
||||||
// Hence the finally clause.
|
|
||||||
|
|
||||||
Block* try_block =
|
|
||||||
factory()->NewBlock(nullptr, 3, false, kNoSourcePosition);
|
|
||||||
Expression* initial_yield = BuildInitialYield(pos, kind);
|
|
||||||
try_block->statements()->Add(
|
|
||||||
factory()->NewExpressionStatement(initial_yield, kNoSourcePosition),
|
|
||||||
zone());
|
|
||||||
ParseStatementList(try_block->statements(), Token::RBRACE, CHECK_OK);
|
|
||||||
|
|
||||||
Statement* final_return = factory()->NewReturnStatement(
|
|
||||||
BuildIteratorResult(nullptr, true), kNoSourcePosition);
|
|
||||||
try_block->statements()->Add(final_return, zone());
|
|
||||||
|
|
||||||
Block* finally_block =
|
|
||||||
factory()->NewBlock(nullptr, 1, false, kNoSourcePosition);
|
|
||||||
ZoneList<Expression*>* args =
|
|
||||||
new (zone()) ZoneList<Expression*>(1, zone());
|
|
||||||
VariableProxy* call_proxy = factory()->NewVariableProxy(
|
|
||||||
function_state_->generator_object_variable());
|
|
||||||
args->Add(call_proxy, zone());
|
|
||||||
Expression* call = factory()->NewCallRuntime(
|
|
||||||
Runtime::kInlineGeneratorClose, args, kNoSourcePosition);
|
|
||||||
finally_block->statements()->Add(
|
|
||||||
factory()->NewExpressionStatement(call, kNoSourcePosition), zone());
|
|
||||||
|
|
||||||
body->Add(factory()->NewTryFinallyStatement(try_block, finally_block,
|
|
||||||
kNoSourcePosition),
|
|
||||||
zone());
|
|
||||||
} else if (IsAsyncFunction(kind)) {
|
|
||||||
const bool accept_IN = true;
|
|
||||||
ParseAsyncFunctionBody(inner_scope, body, kind, FunctionBodyType::kNormal,
|
|
||||||
accept_IN, pos, CHECK_OK);
|
|
||||||
} else {
|
|
||||||
ParseStatementList(body, Token::RBRACE, CHECK_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsDerivedConstructor(kind)) {
|
|
||||||
body->Add(factory()->NewReturnStatement(ThisExpression(kNoSourcePosition),
|
|
||||||
kNoSourcePosition),
|
|
||||||
zone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Expect(Token::RBRACE, CHECK_OK);
|
|
||||||
scope()->set_end_position(scanner()->location().end_pos);
|
|
||||||
|
|
||||||
if (!parameters.is_simple) {
|
|
||||||
DCHECK_NOT_NULL(inner_scope);
|
|
||||||
DCHECK_EQ(function_scope, scope());
|
|
||||||
DCHECK_EQ(function_scope, inner_scope->outer_scope());
|
|
||||||
DCHECK_EQ(body, inner_block->statements());
|
|
||||||
SetLanguageMode(function_scope, inner_scope->language_mode());
|
|
||||||
Block* init_block = BuildParameterInitializationBlock(parameters, CHECK_OK);
|
|
||||||
|
|
||||||
if (is_sloppy(inner_scope->language_mode())) {
|
|
||||||
InsertSloppyBlockFunctionVarBindings(inner_scope);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO(littledan): Merge the two rejection blocks into one
|
|
||||||
if (IsAsyncFunction(kind)) {
|
|
||||||
init_block = BuildRejectPromiseOnException(init_block, CHECK_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
DCHECK_NOT_NULL(init_block);
|
|
||||||
|
|
||||||
inner_scope->set_end_position(scanner()->location().end_pos);
|
|
||||||
if (inner_scope->FinalizeBlockScope() != nullptr) {
|
|
||||||
CheckConflictingVarDeclarations(inner_scope, CHECK_OK);
|
|
||||||
InsertShadowingVarBindingInitializers(inner_block);
|
|
||||||
}
|
|
||||||
inner_scope = nullptr;
|
|
||||||
|
|
||||||
result->Add(init_block, zone());
|
|
||||||
result->Add(inner_block, zone());
|
|
||||||
} else {
|
|
||||||
DCHECK_EQ(inner_scope, function_scope);
|
|
||||||
if (is_sloppy(function_scope->language_mode())) {
|
|
||||||
InsertSloppyBlockFunctionVarBindings(function_scope);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IsArrowFunction(kind)) {
|
|
||||||
// Declare arguments after parsing the function since lexical 'arguments'
|
|
||||||
// masks the arguments object. Declare arguments before declaring the
|
|
||||||
// function var since the arguments object masks 'function arguments'.
|
|
||||||
function_scope->DeclareArguments(ast_value_factory());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (function_type == FunctionLiteral::kNamedExpression) {
|
|
||||||
Statement* statement;
|
|
||||||
if (function_scope->LookupLocal(function_name) == nullptr) {
|
|
||||||
// Now that we know the language mode, we can create the const assignment
|
|
||||||
// in the previously reserved spot.
|
|
||||||
DCHECK_EQ(function_scope, scope());
|
|
||||||
Variable* fvar = function_scope->DeclareFunctionVar(function_name);
|
|
||||||
VariableProxy* fproxy = factory()->NewVariableProxy(fvar);
|
|
||||||
statement = factory()->NewExpressionStatement(
|
|
||||||
factory()->NewAssignment(Token::INIT, fproxy,
|
|
||||||
factory()->NewThisFunction(pos),
|
|
||||||
kNoSourcePosition),
|
|
||||||
kNoSourcePosition);
|
|
||||||
} else {
|
|
||||||
statement = factory()->NewEmptyStatement(kNoSourcePosition);
|
|
||||||
}
|
|
||||||
result->Set(kFunctionNameAssignmentIndex, statement);
|
|
||||||
}
|
|
||||||
|
|
||||||
MarkCollectedTailCallExpressions();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Parser::DeclareClassVariable(const AstRawString* name, Scope* block_scope,
|
void Parser::DeclareClassVariable(const AstRawString* name, Scope* block_scope,
|
||||||
ClassInfo* class_info, int class_token_pos,
|
ClassInfo* class_info, int class_token_pos,
|
||||||
bool* ok) {
|
bool* ok) {
|
||||||
@ -3880,7 +3789,7 @@ void Parser::RewriteAsyncFunctionBody(ZoneList<Statement*>* body, Block* block,
|
|||||||
block->statements()->Add(
|
block->statements()->Add(
|
||||||
factory()->NewReturnStatement(return_value, return_value->position()),
|
factory()->NewReturnStatement(return_value, return_value->position()),
|
||||||
zone());
|
zone());
|
||||||
block = BuildRejectPromiseOnException(block, CHECK_OK_VOID);
|
block = BuildRejectPromiseOnException(block);
|
||||||
body->Add(block, zone());
|
body->Add(block, zone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,6 +340,14 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
|
|||||||
Block* finally_block,
|
Block* finally_block,
|
||||||
const CatchInfo& catch_info, int pos);
|
const CatchInfo& catch_info, int pos);
|
||||||
|
|
||||||
|
void ParseAndRewriteGeneratorFunctionBody(int pos, FunctionKind kind,
|
||||||
|
ZoneList<Statement*>* body,
|
||||||
|
bool* ok);
|
||||||
|
void CreateFunctionNameAssignment(const AstRawString* function_name, int pos,
|
||||||
|
FunctionLiteral::FunctionType function_type,
|
||||||
|
DeclarationScope* function_scope,
|
||||||
|
ZoneList<Statement*>* result, int index);
|
||||||
|
|
||||||
Statement* DeclareFunction(const AstRawString* variable_name,
|
Statement* DeclareFunction(const AstRawString* variable_name,
|
||||||
FunctionLiteral* function, VariableMode mode,
|
FunctionLiteral* function, VariableMode mode,
|
||||||
int pos, bool is_generator, bool is_async,
|
int pos, bool is_generator, bool is_async,
|
||||||
@ -533,13 +541,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
|
|||||||
|
|
||||||
Block* BuildParameterInitializationBlock(
|
Block* BuildParameterInitializationBlock(
|
||||||
const ParserFormalParameters& parameters, bool* ok);
|
const ParserFormalParameters& parameters, bool* ok);
|
||||||
Block* BuildRejectPromiseOnException(Block* block, bool* ok);
|
Block* BuildRejectPromiseOnException(Block* block);
|
||||||
|
|
||||||
// Consumes the ending }.
|
|
||||||
ZoneList<Statement*>* ParseEagerFunctionBody(
|
|
||||||
const AstRawString* function_name, int pos,
|
|
||||||
const ParserFormalParameters& parameters, FunctionKind kind,
|
|
||||||
FunctionLiteral::FunctionType function_type, bool* ok);
|
|
||||||
|
|
||||||
ZoneList<Statement*>* ParseFunction(
|
ZoneList<Statement*>* ParseFunction(
|
||||||
const AstRawString* function_name, int pos, FunctionKind kind,
|
const AstRawString* function_name, int pos, FunctionKind kind,
|
||||||
@ -1025,8 +1027,7 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
|
|||||||
auto* init_block = BuildParameterInitializationBlock(parameters, ok);
|
auto* init_block = BuildParameterInitializationBlock(parameters, ok);
|
||||||
if (!*ok) return;
|
if (!*ok) return;
|
||||||
if (is_async) {
|
if (is_async) {
|
||||||
init_block = BuildRejectPromiseOnException(init_block, ok);
|
init_block = BuildRejectPromiseOnException(init_block);
|
||||||
if (!*ok) return;
|
|
||||||
}
|
}
|
||||||
if (init_block != nullptr) body->Add(init_block, zone());
|
if (init_block != nullptr) body->Add(init_block, zone());
|
||||||
}
|
}
|
||||||
|
@ -414,10 +414,11 @@ class PreParserList {
|
|||||||
// These functions make list->Add(some_expression) work (and do nothing).
|
// These functions make list->Add(some_expression) work (and do nothing).
|
||||||
PreParserList() : length_(0), variables_(nullptr) {}
|
PreParserList() : length_(0), variables_(nullptr) {}
|
||||||
PreParserList* operator->() { return this; }
|
PreParserList* operator->() { return this; }
|
||||||
void Add(T, Zone* zone);
|
void Add(const T& element, Zone* zone);
|
||||||
int length() const { return length_; }
|
int length() const { return length_; }
|
||||||
static PreParserList Null() { return PreParserList(-1); }
|
static PreParserList Null() { return PreParserList(-1); }
|
||||||
bool IsNull() const { return length_ == -1; }
|
bool IsNull() const { return length_ == -1; }
|
||||||
|
void Set(int index, const T& element) {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
explicit PreParserList(int n) : length_(n), variables_(nullptr) {}
|
explicit PreParserList(int n) : length_(n), variables_(nullptr) {}
|
||||||
@ -430,7 +431,7 @@ class PreParserList {
|
|||||||
|
|
||||||
template <>
|
template <>
|
||||||
inline void PreParserList<PreParserExpression>::Add(
|
inline void PreParserList<PreParserExpression>::Add(
|
||||||
PreParserExpression expression, Zone* zone) {
|
const PreParserExpression& expression, Zone* zone) {
|
||||||
if (expression.variables_ != nullptr) {
|
if (expression.variables_ != nullptr) {
|
||||||
DCHECK(FLAG_lazy_inner_functions);
|
DCHECK(FLAG_lazy_inner_functions);
|
||||||
DCHECK(zone != nullptr);
|
DCHECK(zone != nullptr);
|
||||||
@ -445,7 +446,7 @@ inline void PreParserList<PreParserExpression>::Add(
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void PreParserList<T>::Add(T, Zone* zone) {
|
void PreParserList<T>::Add(const T& element, Zone* zone) {
|
||||||
++length_;
|
++length_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -939,11 +940,6 @@ class PreParser : public ParserBase<PreParser> {
|
|||||||
// By making the 'exception handling' explicit, we are forced to check
|
// By making the 'exception handling' explicit, we are forced to check
|
||||||
// for failure at the call sites.
|
// for failure at the call sites.
|
||||||
|
|
||||||
V8_INLINE PreParserStatementList ParseEagerFunctionBody(
|
|
||||||
PreParserIdentifier function_name, int pos,
|
|
||||||
const PreParserFormalParameters& parameters, FunctionKind kind,
|
|
||||||
FunctionLiteral::FunctionType function_type, bool* ok);
|
|
||||||
|
|
||||||
// Indicates that we won't switch from the preparser to the preparser; we'll
|
// Indicates that we won't switch from the preparser to the preparser; we'll
|
||||||
// just stay where we are.
|
// just stay where we are.
|
||||||
bool AllowsLazyParsingWithoutUnresolvedVariables() const { return false; }
|
bool AllowsLazyParsingWithoutUnresolvedVariables() const { return false; }
|
||||||
@ -1075,6 +1071,16 @@ class PreParser : public ParserBase<PreParser> {
|
|||||||
return PreParserStatement::Default();
|
return PreParserStatement::Default();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
V8_INLINE void ParseAndRewriteGeneratorFunctionBody(
|
||||||
|
int pos, FunctionKind kind, PreParserStatementList body, bool* ok) {
|
||||||
|
ParseStatementList(body, Token::RBRACE, ok);
|
||||||
|
}
|
||||||
|
V8_INLINE void CreateFunctionNameAssignment(
|
||||||
|
PreParserIdentifier function_name, int pos,
|
||||||
|
FunctionLiteral::FunctionType function_type,
|
||||||
|
DeclarationScope* function_scope, PreParserStatementList result,
|
||||||
|
int index) {}
|
||||||
|
|
||||||
V8_INLINE PreParserExpression RewriteDoExpression(PreParserStatement body,
|
V8_INLINE PreParserExpression RewriteDoExpression(PreParserStatement body,
|
||||||
int pos, bool* ok) {
|
int pos, bool* ok) {
|
||||||
return PreParserExpression::Default();
|
return PreParserExpression::Default();
|
||||||
@ -1328,6 +1334,23 @@ class PreParser : public ParserBase<PreParser> {
|
|||||||
return loop;
|
return loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
V8_INLINE PreParserStatement BuildParameterInitializationBlock(
|
||||||
|
const PreParserFormalParameters& parameters, bool* ok) {
|
||||||
|
return PreParserStatement::Default();
|
||||||
|
}
|
||||||
|
|
||||||
|
V8_INLINE PreParserStatement
|
||||||
|
BuildRejectPromiseOnException(PreParserStatement init_block) {
|
||||||
|
return PreParserStatement::Default();
|
||||||
|
}
|
||||||
|
|
||||||
|
V8_INLINE void InsertSloppyBlockFunctionVarBindings(DeclarationScope* scope) {
|
||||||
|
scope->HoistSloppyBlockFunctions(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
V8_INLINE void InsertShadowingVarBindingInitializers(
|
||||||
|
PreParserStatement block) {}
|
||||||
|
|
||||||
V8_INLINE PreParserExpression
|
V8_INLINE PreParserExpression
|
||||||
NewThrowReferenceError(MessageTemplate::Template message, int pos) {
|
NewThrowReferenceError(MessageTemplate::Template message, int pos) {
|
||||||
return PreParserExpression::Default();
|
return PreParserExpression::Default();
|
||||||
@ -1623,29 +1646,6 @@ PreParserExpression PreParser::SpreadCallNew(PreParserExpression function,
|
|||||||
return factory()->NewCallNew(function, args, pos);
|
return factory()->NewCallNew(function, args, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
PreParserStatementList PreParser::ParseEagerFunctionBody(
|
|
||||||
PreParserIdentifier function_name, int pos,
|
|
||||||
const PreParserFormalParameters& parameters, FunctionKind kind,
|
|
||||||
FunctionLiteral::FunctionType function_type, bool* ok) {
|
|
||||||
PreParserStatementList result;
|
|
||||||
|
|
||||||
DeclarationScope* inner_scope = scope()->AsDeclarationScope();
|
|
||||||
if (!parameters.is_simple) inner_scope = NewVarblockScope();
|
|
||||||
|
|
||||||
{
|
|
||||||
BlockState block_state(&scope_state_, inner_scope);
|
|
||||||
ParseStatementList(result, Token::RBRACE, ok);
|
|
||||||
if (!*ok) return PreParserStatementList();
|
|
||||||
}
|
|
||||||
|
|
||||||
Expect(Token::RBRACE, ok);
|
|
||||||
|
|
||||||
if (is_sloppy(inner_scope->language_mode())) {
|
|
||||||
inner_scope->HoistSloppyBlockFunctions(nullptr);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
PreParserExpression PreParser::CloseTemplateLiteral(TemplateLiteralState* state,
|
PreParserExpression PreParser::CloseTemplateLiteral(TemplateLiteralState* state,
|
||||||
int start,
|
int start,
|
||||||
PreParserExpression tag) {
|
PreParserExpression tag) {
|
||||||
|
Loading…
Reference in New Issue
Block a user