Commit 886713e7 authored by Toon Verwaest's avatar Toon Verwaest Committed by Commit Bot

[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/1384319Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58376}
parent 704c050a
...@@ -1077,7 +1077,7 @@ class ParserBase { ...@@ -1077,7 +1077,7 @@ class ParserBase {
// Whether we're parsing a single-expression arrow function or something else. // Whether we're parsing a single-expression arrow function or something else.
enum class FunctionBodyType { kExpression, kBlock }; enum class FunctionBodyType { kExpression, kBlock };
// Consumes the ending }. // Consumes the ending }.
void ParseFunctionBody(StatementListT* result, IdentifierT function_name, void ParseFunctionBody(StatementListT* body, IdentifierT function_name,
int pos, const FormalParametersT& parameters, int pos, const FormalParametersT& parameters,
FunctionKind kind, FunctionKind kind,
FunctionLiteral::FunctionType function_type, FunctionLiteral::FunctionType function_type,
...@@ -3816,111 +3816,114 @@ ParserBase<Impl>::ParseAsyncFunctionDeclaration( ...@@ -3816,111 +3816,114 @@ ParserBase<Impl>::ParseAsyncFunctionDeclaration(
template <typename Impl> template <typename Impl>
void ParserBase<Impl>::ParseFunctionBody( void ParserBase<Impl>::ParseFunctionBody(
typename ParserBase<Impl>::StatementListT* body, IdentifierT function_name, StatementListT* body, IdentifierT function_name, int pos,
int pos, const FormalParametersT& parameters, FunctionKind kind, const FormalParametersT& parameters, FunctionKind kind,
FunctionLiteral::FunctionType function_type, FunctionBodyType body_type) { FunctionLiteral::FunctionType function_type, FunctionBodyType body_type) {
FunctionBodyParsingScope body_scope(impl()); if (IsResumableFunction(kind)) impl()->PrepareGeneratorVariables();
// Building the parameter initialization block declares the parameters.
DeclarationScope* function_scope = scope()->AsDeclarationScope(); // TODO(verwaest): Rely on ArrowHeadParsingScope instead.
DeclarationScope* inner_scope = function_scope;
if (!parameters.is_simple) { if (!parameters.is_simple) {
inner_scope = NewVarblockScope(); if (has_error()) return;
inner_scope->set_start_position(scanner()->location().beg_pos); BlockT init_block = impl()->BuildParameterInitializationBlock(parameters);
if (IsAsyncFunction(kind) && !IsAsyncGeneratorFunction(kind)) {
init_block = impl()->BuildRejectPromiseOnException(init_block);
}
body->Add(init_block);
if (has_error()) return;
} }
DeclarationScope* function_scope = scope()->AsDeclarationScope();
bool allow_duplicate_parameters = false;
BlockT inner_block = impl()->NullBlock();
{ {
BlockState block_state(&scope_, inner_scope); StatementListT inner_body(pointer_buffer());
DeclarationScope* inner_scope = function_scope;
if (IsResumableFunction(kind)) impl()->PrepareGeneratorVariables(); if (!parameters.is_simple) {
inner_scope = NewVarblockScope();
inner_scope->set_start_position(scanner()->location().beg_pos);
}
if (body_type == FunctionBodyType::kExpression) { {
ExpressionT expression = ParseAssignmentExpression(); BlockState block_state(&scope_, inner_scope);
if (IsAsyncFunction(kind)) { if (body_type == FunctionBodyType::kExpression) {
BlockT block = factory()->NewBlock(1, true); ExpressionT expression = ParseAssignmentExpression();
impl()->RewriteAsyncFunctionBody(body, block, expression);
} else { if (IsAsyncFunction(kind)) {
body->Add(BuildReturnStatement(expression, expression->position())); BlockT block = factory()->NewBlock(1, true);
} impl()->RewriteAsyncFunctionBody(&inner_body, block, expression);
} else { } else {
DCHECK(accept_IN_); inner_body.Add(
DCHECK_EQ(FunctionBodyType::kBlock, body_type); BuildReturnStatement(expression, expression->position()));
// 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 { } else {
ParseStatementList(body, closing_token); 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)) { if (IsDerivedConstructor(kind)) {
body->Add(factory()->NewReturnStatement(impl()->ThisExpression(), inner_body.Add(factory()->NewReturnStatement(impl()->ThisExpression(),
kNoSourcePosition)); kNoSourcePosition));
}
Expect(closing_token);
} }
Expect(closing_token);
} }
}
scope()->set_end_position(end_position());
bool allow_duplicate_parameters = false;
if (parameters.is_simple) { scope()->set_end_position(end_position());
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())) { if (parameters.is_simple) {
impl()->InsertSloppyBlockFunctionVarBindings(inner_scope); 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());
// TODO(littledan): Merge the two rejection blocks into one if (is_sloppy(inner_scope->language_mode())) {
if (IsAsyncFunction(kind) && !IsAsyncGeneratorFunction(kind)) { impl()->InsertSloppyBlockFunctionVarBindings(inner_scope);
init_block = impl()->BuildRejectPromiseOnException(init_block); }
}
inner_scope->set_end_position(end_position()); inner_scope->set_end_position(end_position());
if (inner_scope->FinalizeBlockScope() != nullptr) { if (inner_scope->FinalizeBlockScope() != nullptr) {
const AstRawString* conflict = inner_scope->FindVariableDeclaredIn( inner_block = factory()->NewBlock(true, inner_body);
function_scope, VariableMode::kLastLexicalVariableMode); inner_body.Rewind();
if (conflict != nullptr) { inner_block->set_scope(inner_scope);
impl()->ReportVarRedeclarationIn(conflict, 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);
} }
impl()->CheckConflictingVarDeclarations(inner_scope);
impl()->InsertShadowingVarBindingInitializers(inner_block);
} else {
inner_block->set_scope(nullptr);
} }
inner_scope = nullptr; inner_body.MergeInto(body);
body->Add(init_block);
body->Add(inner_block);
} }
if (!impl()->IsNull(inner_block)) body->Add(inner_block);
ValidateFormalParameters(language_mode(), parameters, ValidateFormalParameters(language_mode(), parameters,
allow_duplicate_parameters); allow_duplicate_parameters);
...@@ -4042,6 +4045,7 @@ ParserBase<Impl>::ParseArrowFunctionLiteral( ...@@ -4042,6 +4045,7 @@ ParserBase<Impl>::ParseArrowFunctionLiteral(
if (peek() == Token::LBRACE) { if (peek() == Token::LBRACE) {
// Multiple statement body // Multiple statement body
DCHECK_EQ(scope(), formal_parameters.scope); DCHECK_EQ(scope(), formal_parameters.scope);
if (is_lazy_top_level_function) { if (is_lazy_top_level_function) {
// FIXME(marja): Arrow function parameters will be parsed even if the // FIXME(marja): Arrow function parameters will be parsed even if the
// body is preparsed; move relevant parts of parameter handling to // body is preparsed; move relevant parts of parameter handling to
......
...@@ -147,6 +147,10 @@ PreParser::PreParseResult PreParser::PreParseFunction( ...@@ -147,6 +147,10 @@ PreParser::PreParseResult PreParser::PreParseFunction(
// We return kPreParseSuccess in failure cases too - errors are retrieved // We return kPreParseSuccess in failure cases too - errors are retrieved
// separately by Parser::SkipLazyFunctionBody. // separately by Parser::SkipLazyFunctionBody.
ParseFormalParameterList(&formals); ParseFormalParameterList(&formals);
if (!formals.is_simple) {
BuildParameterInitializationBlock(formals);
}
Expect(Token::RPAREN); Expect(Token::RPAREN);
int formals_end_position = scanner()->location().end_pos; int formals_end_position = scanner()->location().end_pos;
...@@ -180,8 +184,6 @@ PreParser::PreParseResult PreParser::PreParseFunction( ...@@ -180,8 +184,6 @@ PreParser::PreParseResult PreParser::PreParseFunction(
!IsConciseMethod(kind) && !IsConciseMethod(kind) &&
!IsArrowFunction(kind); !IsArrowFunction(kind);
} else { } else {
BuildParameterInitializationBlock(formals);
if (is_sloppy(inner_scope->language_mode())) { if (is_sloppy(inner_scope->language_mode())) {
inner_scope->HoistSloppyBlockFunctions(nullptr); inner_scope->HoistSloppyBlockFunctions(nullptr);
} }
......
...@@ -430,6 +430,7 @@ class PreParserScopedStatementList { ...@@ -430,6 +430,7 @@ class PreParserScopedStatementList {
public: public:
explicit PreParserScopedStatementList(std::vector<void*>* buffer) {} explicit PreParserScopedStatementList(std::vector<void*>* buffer) {}
void Rewind() {} void Rewind() {}
void MergeInto(const PreParserScopedStatementList* other) {}
void Add(const PreParserStatement& element) {} void Add(const PreParserStatement& element) {}
}; };
......
...@@ -335,6 +335,13 @@ class ScopedPtrList final { ...@@ -335,6 +335,13 @@ class ScopedPtrList final {
end_ = start_; 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_); } int length() const { return static_cast<int>(end_ - start_); }
T* at(int i) const { T* at(int i) const {
size_t index = start_ + i; size_t index = start_ + i;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment