[parser] Build parameter initialization block before parsing the body
Later we want to automatically declare the parameters while parsing, which moves the declaration before body parsing anyway. This is just a step in that direction, making sure that it works. Change-Id: I0645269aa26643de138848c599cfe5d1ad4bf32c Reviewed-on: https://chromium-review.googlesource.com/c/1384319 Reviewed-by: Igor Sheludko <ishell@chromium.org> Commit-Queue: Igor Sheludko <ishell@chromium.org> Cr-Commit-Position: refs/heads/master@{#58376}
This commit is contained in:
parent
704c050a6b
commit
886713e7c8
@ -1077,7 +1077,7 @@ class ParserBase {
|
||||
// Whether we're parsing a single-expression arrow function or something else.
|
||||
enum class FunctionBodyType { kExpression, kBlock };
|
||||
// Consumes the ending }.
|
||||
void ParseFunctionBody(StatementListT* result, IdentifierT function_name,
|
||||
void ParseFunctionBody(StatementListT* body, IdentifierT function_name,
|
||||
int pos, const FormalParametersT& parameters,
|
||||
FunctionKind kind,
|
||||
FunctionLiteral::FunctionType function_type,
|
||||
@ -3816,111 +3816,114 @@ ParserBase<Impl>::ParseAsyncFunctionDeclaration(
|
||||
|
||||
template <typename Impl>
|
||||
void ParserBase<Impl>::ParseFunctionBody(
|
||||
typename ParserBase<Impl>::StatementListT* body, IdentifierT function_name,
|
||||
int pos, const FormalParametersT& parameters, FunctionKind kind,
|
||||
StatementListT* body, IdentifierT function_name, int pos,
|
||||
const FormalParametersT& parameters, FunctionKind kind,
|
||||
FunctionLiteral::FunctionType function_type, FunctionBodyType body_type) {
|
||||
FunctionBodyParsingScope body_scope(impl());
|
||||
|
||||
DeclarationScope* function_scope = scope()->AsDeclarationScope();
|
||||
DeclarationScope* inner_scope = function_scope;
|
||||
|
||||
if (IsResumableFunction(kind)) impl()->PrepareGeneratorVariables();
|
||||
// Building the parameter initialization block declares the parameters.
|
||||
// TODO(verwaest): Rely on ArrowHeadParsingScope instead.
|
||||
if (!parameters.is_simple) {
|
||||
inner_scope = NewVarblockScope();
|
||||
inner_scope->set_start_position(scanner()->location().beg_pos);
|
||||
}
|
||||
|
||||
{
|
||||
BlockState block_state(&scope_, inner_scope);
|
||||
|
||||
if (IsResumableFunction(kind)) impl()->PrepareGeneratorVariables();
|
||||
|
||||
if (body_type == FunctionBodyType::kExpression) {
|
||||
ExpressionT expression = ParseAssignmentExpression();
|
||||
|
||||
if (IsAsyncFunction(kind)) {
|
||||
BlockT block = factory()->NewBlock(1, true);
|
||||
impl()->RewriteAsyncFunctionBody(body, block, expression);
|
||||
} else {
|
||||
body->Add(BuildReturnStatement(expression, expression->position()));
|
||||
}
|
||||
} else {
|
||||
DCHECK(accept_IN_);
|
||||
DCHECK_EQ(FunctionBodyType::kBlock, body_type);
|
||||
// If we are parsing the source as if it is wrapped in a function, the
|
||||
// source ends without a closing brace.
|
||||
Token::Value closing_token = function_type == FunctionLiteral::kWrapped
|
||||
? Token::EOS
|
||||
: Token::RBRACE;
|
||||
|
||||
if (IsAsyncGeneratorFunction(kind)) {
|
||||
impl()->ParseAndRewriteAsyncGeneratorFunctionBody(pos, kind, body);
|
||||
} else if (IsGeneratorFunction(kind)) {
|
||||
impl()->ParseAndRewriteGeneratorFunctionBody(pos, kind, body);
|
||||
} else if (IsAsyncFunction(kind)) {
|
||||
ParseAsyncFunctionBody(inner_scope, body);
|
||||
} else {
|
||||
ParseStatementList(body, closing_token);
|
||||
}
|
||||
|
||||
if (IsDerivedConstructor(kind)) {
|
||||
body->Add(factory()->NewReturnStatement(impl()->ThisExpression(),
|
||||
kNoSourcePosition));
|
||||
}
|
||||
Expect(closing_token);
|
||||
}
|
||||
}
|
||||
|
||||
scope()->set_end_position(end_position());
|
||||
|
||||
bool allow_duplicate_parameters = false;
|
||||
|
||||
if (parameters.is_simple) {
|
||||
DCHECK_EQ(inner_scope, function_scope);
|
||||
if (is_sloppy(function_scope->language_mode())) {
|
||||
impl()->InsertSloppyBlockFunctionVarBindings(function_scope);
|
||||
}
|
||||
allow_duplicate_parameters = is_sloppy(function_scope->language_mode()) &&
|
||||
!IsConciseMethod(kind) &&
|
||||
!IsArrowFunction(kind);
|
||||
} else {
|
||||
BlockT inner_block = factory()->NewBlock(true, *body);
|
||||
inner_block->set_scope(inner_scope);
|
||||
body->Rewind();
|
||||
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());
|
||||
// TODO(verwaest): Disable DCHECKs in failure mode?
|
||||
if (has_error()) return;
|
||||
BlockT init_block = impl()->BuildParameterInitializationBlock(parameters);
|
||||
|
||||
if (is_sloppy(inner_scope->language_mode())) {
|
||||
impl()->InsertSloppyBlockFunctionVarBindings(inner_scope);
|
||||
}
|
||||
|
||||
// TODO(littledan): Merge the two rejection blocks into one
|
||||
if (IsAsyncFunction(kind) && !IsAsyncGeneratorFunction(kind)) {
|
||||
init_block = impl()->BuildRejectPromiseOnException(init_block);
|
||||
}
|
||||
|
||||
inner_scope->set_end_position(end_position());
|
||||
if (inner_scope->FinalizeBlockScope() != nullptr) {
|
||||
const AstRawString* conflict = inner_scope->FindVariableDeclaredIn(
|
||||
function_scope, VariableMode::kLastLexicalVariableMode);
|
||||
if (conflict != nullptr) {
|
||||
impl()->ReportVarRedeclarationIn(conflict, inner_scope);
|
||||
}
|
||||
impl()->CheckConflictingVarDeclarations(inner_scope);
|
||||
impl()->InsertShadowingVarBindingInitializers(inner_block);
|
||||
} else {
|
||||
inner_block->set_scope(nullptr);
|
||||
}
|
||||
inner_scope = nullptr;
|
||||
|
||||
body->Add(init_block);
|
||||
body->Add(inner_block);
|
||||
if (has_error()) return;
|
||||
}
|
||||
|
||||
DeclarationScope* function_scope = scope()->AsDeclarationScope();
|
||||
bool allow_duplicate_parameters = false;
|
||||
BlockT inner_block = impl()->NullBlock();
|
||||
{
|
||||
StatementListT inner_body(pointer_buffer());
|
||||
DeclarationScope* inner_scope = function_scope;
|
||||
|
||||
if (!parameters.is_simple) {
|
||||
inner_scope = NewVarblockScope();
|
||||
inner_scope->set_start_position(scanner()->location().beg_pos);
|
||||
}
|
||||
|
||||
{
|
||||
BlockState block_state(&scope_, inner_scope);
|
||||
|
||||
if (body_type == FunctionBodyType::kExpression) {
|
||||
ExpressionT expression = ParseAssignmentExpression();
|
||||
|
||||
if (IsAsyncFunction(kind)) {
|
||||
BlockT block = factory()->NewBlock(1, true);
|
||||
impl()->RewriteAsyncFunctionBody(&inner_body, block, expression);
|
||||
} else {
|
||||
inner_body.Add(
|
||||
BuildReturnStatement(expression, expression->position()));
|
||||
}
|
||||
} else {
|
||||
DCHECK(accept_IN_);
|
||||
DCHECK_EQ(FunctionBodyType::kBlock, body_type);
|
||||
// If we are parsing the source as if it is wrapped in a function, the
|
||||
// source ends without a closing brace.
|
||||
Token::Value closing_token = function_type == FunctionLiteral::kWrapped
|
||||
? Token::EOS
|
||||
: Token::RBRACE;
|
||||
|
||||
if (IsAsyncGeneratorFunction(kind)) {
|
||||
impl()->ParseAndRewriteAsyncGeneratorFunctionBody(pos, kind,
|
||||
&inner_body);
|
||||
} else if (IsGeneratorFunction(kind)) {
|
||||
impl()->ParseAndRewriteGeneratorFunctionBody(pos, kind, &inner_body);
|
||||
} else if (IsAsyncFunction(kind)) {
|
||||
ParseAsyncFunctionBody(inner_scope, &inner_body);
|
||||
} else {
|
||||
ParseStatementList(&inner_body, closing_token);
|
||||
}
|
||||
|
||||
if (IsDerivedConstructor(kind)) {
|
||||
inner_body.Add(factory()->NewReturnStatement(impl()->ThisExpression(),
|
||||
kNoSourcePosition));
|
||||
}
|
||||
Expect(closing_token);
|
||||
}
|
||||
}
|
||||
|
||||
scope()->set_end_position(end_position());
|
||||
|
||||
if (parameters.is_simple) {
|
||||
DCHECK_EQ(inner_scope, function_scope);
|
||||
if (is_sloppy(function_scope->language_mode())) {
|
||||
impl()->InsertSloppyBlockFunctionVarBindings(function_scope);
|
||||
}
|
||||
allow_duplicate_parameters = is_sloppy(function_scope->language_mode()) &&
|
||||
!IsConciseMethod(kind) &&
|
||||
!IsArrowFunction(kind);
|
||||
} else {
|
||||
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());
|
||||
|
||||
if (is_sloppy(inner_scope->language_mode())) {
|
||||
impl()->InsertSloppyBlockFunctionVarBindings(inner_scope);
|
||||
}
|
||||
|
||||
inner_scope->set_end_position(end_position());
|
||||
if (inner_scope->FinalizeBlockScope() != nullptr) {
|
||||
inner_block = factory()->NewBlock(true, inner_body);
|
||||
inner_body.Rewind();
|
||||
inner_block->set_scope(inner_scope);
|
||||
const AstRawString* conflict = inner_scope->FindVariableDeclaredIn(
|
||||
function_scope, VariableMode::kLastLexicalVariableMode);
|
||||
if (conflict != nullptr) {
|
||||
impl()->ReportVarRedeclarationIn(conflict, inner_scope);
|
||||
}
|
||||
impl()->CheckConflictingVarDeclarations(inner_scope);
|
||||
impl()->InsertShadowingVarBindingInitializers(inner_block);
|
||||
}
|
||||
}
|
||||
inner_body.MergeInto(body);
|
||||
}
|
||||
|
||||
if (!impl()->IsNull(inner_block)) body->Add(inner_block);
|
||||
|
||||
ValidateFormalParameters(language_mode(), parameters,
|
||||
allow_duplicate_parameters);
|
||||
|
||||
@ -4042,6 +4045,7 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
|
||||
if (peek() == Token::LBRACE) {
|
||||
// Multiple statement body
|
||||
DCHECK_EQ(scope(), formal_parameters.scope);
|
||||
|
||||
if (is_lazy_top_level_function) {
|
||||
// FIXME(marja): Arrow function parameters will be parsed even if the
|
||||
// body is preparsed; move relevant parts of parameter handling to
|
||||
|
@ -147,6 +147,10 @@ PreParser::PreParseResult PreParser::PreParseFunction(
|
||||
// We return kPreParseSuccess in failure cases too - errors are retrieved
|
||||
// separately by Parser::SkipLazyFunctionBody.
|
||||
ParseFormalParameterList(&formals);
|
||||
if (!formals.is_simple) {
|
||||
BuildParameterInitializationBlock(formals);
|
||||
}
|
||||
|
||||
Expect(Token::RPAREN);
|
||||
int formals_end_position = scanner()->location().end_pos;
|
||||
|
||||
@ -180,8 +184,6 @@ PreParser::PreParseResult PreParser::PreParseFunction(
|
||||
!IsConciseMethod(kind) &&
|
||||
!IsArrowFunction(kind);
|
||||
} else {
|
||||
BuildParameterInitializationBlock(formals);
|
||||
|
||||
if (is_sloppy(inner_scope->language_mode())) {
|
||||
inner_scope->HoistSloppyBlockFunctions(nullptr);
|
||||
}
|
||||
|
@ -430,6 +430,7 @@ class PreParserScopedStatementList {
|
||||
public:
|
||||
explicit PreParserScopedStatementList(std::vector<void*>* buffer) {}
|
||||
void Rewind() {}
|
||||
void MergeInto(const PreParserScopedStatementList* other) {}
|
||||
void Add(const PreParserStatement& element) {}
|
||||
};
|
||||
|
||||
|
@ -335,6 +335,13 @@ class ScopedPtrList final {
|
||||
end_ = start_;
|
||||
}
|
||||
|
||||
void MergeInto(ScopedPtrList* parent) {
|
||||
DCHECK_EQ(parent->end_, start_);
|
||||
parent->end_ = end_;
|
||||
start_ = end_;
|
||||
DCHECK_EQ(0, length());
|
||||
}
|
||||
|
||||
int length() const { return static_cast<int>(end_ - start_); }
|
||||
T* at(int i) const {
|
||||
size_t index = start_ + i;
|
||||
|
Loading…
Reference in New Issue
Block a user