Commit fa15ba5a authored by Adam Klein's avatar Adam Klein Committed by Commit Bot

[parser] Don't create scopes in for-loops that don't include declarations

This patch handles C-style, as well as for-in/of loops. for-await loops
will be changed in a followup.

Bug: v8:6724
Change-Id: I264b8c2d41c0318e796839bf204f7d77b6d24dd8
Reviewed-on: https://chromium-review.googlesource.com/617410Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Commit-Queue: Adam Klein <adamk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47404}
parent fbb46475
...@@ -197,9 +197,6 @@ class SourceRangeScope final { ...@@ -197,9 +197,6 @@ class SourceRangeScope final {
// // Synonyms for ParserBase<Impl> and Impl, respectively. // // Synonyms for ParserBase<Impl> and Impl, respectively.
// typedef Base; // typedef Base;
// typedef Impl; // typedef Impl;
// // TODO(nikolaos): this one will probably go away, as it is
// // not related to pure parsing.
// typedef Variable;
// // Return types for traversing functions. // // Return types for traversing functions.
// typedef Identifier; // typedef Identifier;
// typedef Expression; // typedef Expression;
...@@ -214,6 +211,7 @@ class SourceRangeScope final { ...@@ -214,6 +211,7 @@ class SourceRangeScope final {
// typedef StatementList; // typedef StatementList;
// typedef Block; // typedef Block;
// typedef BreakableStatement; // typedef BreakableStatement;
// typedef ForStatement;
// typedef IterationStatement; // typedef IterationStatement;
// // For constructing objects returned by the traversing functions. // // For constructing objects returned by the traversing functions.
// typedef Factory; // typedef Factory;
...@@ -241,6 +239,7 @@ class ParserBase { ...@@ -241,6 +239,7 @@ class ParserBase {
typedef typename Types::Statement StatementT; typedef typename Types::Statement StatementT;
typedef typename Types::StatementList StatementListT; typedef typename Types::StatementList StatementListT;
typedef typename Types::Block BlockT; typedef typename Types::Block BlockT;
typedef typename Types::ForStatement ForStatementT;
typedef typename v8::internal::ExpressionClassifier<Types> typedef typename v8::internal::ExpressionClassifier<Types>
ExpressionClassifier; ExpressionClassifier;
...@@ -1228,12 +1227,17 @@ class ParserBase { ...@@ -1228,12 +1227,17 @@ class ParserBase {
int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos, int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos,
ForInfo* for_info, ZoneList<const AstRawString*>* labels, bool* ok); ForInfo* for_info, ZoneList<const AstRawString*>* labels, bool* ok);
// Parse a C-style for loop: 'for (<init>; <cond>; <step>) { ... }' // Parse a C-style for loop: 'for (<init>; <cond>; <next>) { ... }'
StatementT ParseStandardForLoop(int stmt_pos, StatementT init, // "for (<init>;" is assumed to have been parser already.
bool bound_names_are_lexical, ForStatementT ParseStandardForLoop(int stmt_pos,
ForInfo* for_info,
ZoneList<const AstRawString*>* labels, ZoneList<const AstRawString*>* labels,
bool* ok); ExpressionT* cond, StatementT* next,
StatementT* body, bool* ok);
// Same as the above, but handles those cases where <init> is a
// variable declaration.
StatementT ParseStandardForLoopWithDeclarations(
int stmt_pos, StatementT init, bool bound_names_are_lexical,
ForInfo* for_info, ZoneList<const AstRawString*>* labels, bool* ok);
StatementT ParseForAwaitStatement(ZoneList<const AstRawString*>* labels, StatementT ParseForAwaitStatement(ZoneList<const AstRawString*>* labels,
bool* ok); bool* ok);
...@@ -5530,17 +5534,15 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( ...@@ -5530,17 +5534,15 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
ForInfo for_info(this); ForInfo for_info(this);
bool bound_names_are_lexical = false; bool bound_names_are_lexical = false;
// Create an in-between scope for let-bound iteration variables.
BlockState for_state(zone(), &scope_);
Expect(Token::FOR, CHECK_OK); Expect(Token::FOR, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK); Expect(Token::LPAREN, CHECK_OK);
scope()->set_start_position(scanner()->location().beg_pos);
StatementT init = impl()->NullStatement();
if (peek() == Token::VAR || peek() == Token::CONST || if (peek() == Token::VAR || peek() == Token::CONST ||
(peek() == Token::LET && IsNextLetKeyword())) { (peek() == Token::LET && IsNextLetKeyword())) {
// The initializer contains declarations. // The initializer contains declarations.
// Create an in-between scope for let-bound iteration variables.
BlockState for_state(zone(), &scope_);
scope()->set_start_position(scanner()->location().beg_pos);
// Create an inner block scope which will be the parent scope of scopes // Create an inner block scope which will be the parent scope of scopes
// possibly created by ParseVariableDeclarations. // possibly created by ParseVariableDeclarations.
...@@ -5559,8 +5561,10 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( ...@@ -5559,8 +5561,10 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
inner_block_scope, ok); inner_block_scope, ok);
} }
Expect(Token::SEMICOLON, CHECK_OK);
// One or more declaration not followed by in/of. // One or more declaration not followed by in/of.
init = impl()->BuildInitializationBlock( StatementT init = impl()->BuildInitializationBlock(
&for_info.parsing_result, &for_info.parsing_result,
bound_names_are_lexical ? &for_info.bound_names : nullptr, CHECK_OK); bound_names_are_lexical ? &for_info.bound_names : nullptr, CHECK_OK);
...@@ -5568,7 +5572,13 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( ...@@ -5568,7 +5572,13 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
// No variable declarations will have been created in inner_block_scope. // No variable declarations will have been created in inner_block_scope.
DCHECK_NULL(finalized); DCHECK_NULL(finalized);
USE(finalized); USE(finalized);
} else if (peek() != Token::SEMICOLON) { // Standard 'for' loop, we have parsed the initializer at this point.
return ParseStandardForLoopWithDeclarations(
stmt_pos, init, bound_names_are_lexical, &for_info, labels, ok);
}
StatementT init = impl()->NullStatement();
if (peek() != Token::SEMICOLON) {
// The initializer does not contain declarations. // The initializer does not contain declarations.
int lhs_beg_pos = peek_position(); int lhs_beg_pos = peek_position();
ExpressionClassifier classifier(this); ExpressionClassifier classifier(this);
...@@ -5594,9 +5604,16 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement( ...@@ -5594,9 +5604,16 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseForStatement(
init = factory()->NewExpressionStatement(expression, lhs_beg_pos); init = factory()->NewExpressionStatement(expression, lhs_beg_pos);
} }
Expect(Token::SEMICOLON, CHECK_OK);
// Standard 'for' loop, we have parsed the initializer at this point. // Standard 'for' loop, we have parsed the initializer at this point.
return ParseStandardForLoop(stmt_pos, init, bound_names_are_lexical, ExpressionT cond = impl()->EmptyExpression();
&for_info, labels, ok); StatementT next = impl()->NullStatement();
StatementT body = impl()->NullStatement();
ForStatementT loop =
ParseStandardForLoop(stmt_pos, labels, &cond, &next, &body, CHECK_OK);
loop->Initialize(init, cond, next, body);
return loop;
} }
template <typename Impl> template <typename Impl>
...@@ -5685,7 +5702,6 @@ typename ParserBase<Impl>::StatementT ...@@ -5685,7 +5702,6 @@ typename ParserBase<Impl>::StatementT
ParserBase<Impl>::ParseForEachStatementWithoutDeclarations( ParserBase<Impl>::ParseForEachStatementWithoutDeclarations(
int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos, int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos,
ForInfo* for_info, ZoneList<const AstRawString*>* labels, bool* ok) { ForInfo* for_info, ZoneList<const AstRawString*>* labels, bool* ok) {
scope()->set_is_hidden();
// Initializer is reference followed by in/of. // Initializer is reference followed by in/of.
if (!expression->IsArrayLiteral() && !expression->IsObjectLiteral()) { if (!expression->IsArrayLiteral() && !expression->IsObjectLiteral()) {
expression = impl()->CheckAndRewriteReferenceExpression( expression = impl()->CheckAndRewriteReferenceExpression(
...@@ -5709,43 +5725,20 @@ ParserBase<Impl>::ParseForEachStatementWithoutDeclarations( ...@@ -5709,43 +5725,20 @@ ParserBase<Impl>::ParseForEachStatementWithoutDeclarations(
StatementT body = impl()->NullStatement(); StatementT body = impl()->NullStatement();
{ {
BlockState block_state(zone(), &scope_);
scope()->set_start_position(scanner()->location().beg_pos);
SourceRange body_range; SourceRange body_range;
SourceRangeScope range_scope(scanner(), &body_range); SourceRangeScope range_scope(scanner(), &body_range);
body = ParseStatement(nullptr, CHECK_OK); body = ParseStatement(nullptr, CHECK_OK);
scope()->set_end_position(scanner()->location().end_pos);
impl()->RecordIterationStatementSourceRange(loop, range_scope.Finalize()); impl()->RecordIterationStatementSourceRange(loop, range_scope.Finalize());
Scope* block_scope = scope()->FinalizeBlockScope();
USE(block_scope);
DCHECK_NULL(block_scope);
} }
StatementT final_loop = return impl()->InitializeForEachStatement(loop, expression, enumerable, body);
impl()->InitializeForEachStatement(loop, expression, enumerable, body);
Scope* for_scope = scope()->FinalizeBlockScope();
USE(for_scope);
DCHECK_NULL(for_scope);
return final_loop;
} }
template <typename Impl> template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStandardForLoop( typename ParserBase<Impl>::StatementT
ParserBase<Impl>::ParseStandardForLoopWithDeclarations(
int stmt_pos, StatementT init, bool bound_names_are_lexical, int stmt_pos, StatementT init, bool bound_names_are_lexical,
ForInfo* for_info, ZoneList<const AstRawString*>* labels, bool* ok) { ForInfo* for_info, ZoneList<const AstRawString*>* labels, bool* ok) {
auto loop = factory()->NewForStatement(labels, stmt_pos);
typename Types::Target target(this, loop);
Expect(Token::SEMICOLON, CHECK_OK);
ExpressionT cond = impl()->EmptyExpression();
StatementT next = impl()->NullStatement();
StatementT body = impl()->NullStatement();
SourceRange body_range;
// If there are let bindings, then condition and the next statement of the // If there are let bindings, then condition and the next statement of the
// for loop must be parsed in a new scope. // for loop must be parsed in a new scope.
Scope* inner_scope = scope(); Scope* inner_scope = scope();
...@@ -5753,22 +5746,15 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStandardForLoop( ...@@ -5753,22 +5746,15 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStandardForLoop(
inner_scope = NewScopeWithParent(inner_scope, BLOCK_SCOPE); inner_scope = NewScopeWithParent(inner_scope, BLOCK_SCOPE);
inner_scope->set_start_position(scanner()->location().beg_pos); inner_scope->set_start_position(scanner()->location().beg_pos);
} }
ForStatementT loop = impl()->NullStatement();
ExpressionT cond = impl()->EmptyExpression();
StatementT next = impl()->NullStatement();
StatementT body = impl()->NullStatement();
{ {
BlockState block_state(&scope_, inner_scope); BlockState block_state(&scope_, inner_scope);
loop =
if (peek() != Token::SEMICOLON) { ParseStandardForLoop(stmt_pos, labels, &cond, &next, &body, CHECK_OK);
cond = ParseExpression(true, CHECK_OK);
}
Expect(Token::SEMICOLON, CHECK_OK);
if (peek() != Token::RPAREN) {
ExpressionT exp = ParseExpression(true, CHECK_OK);
next = factory()->NewExpressionStatement(exp, exp->position());
}
Expect(Token::RPAREN, CHECK_OK);
SourceRangeScope range_scope(scanner(), &body_range);
body = ParseStatement(nullptr, CHECK_OK);
} }
scope()->set_end_position(scanner()->location().end_pos); scope()->set_end_position(scanner()->location().end_pos);
...@@ -5812,12 +5798,38 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStandardForLoop( ...@@ -5812,12 +5798,38 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStandardForLoop(
block->statements()->Add(loop, zone()); block->statements()->Add(loop, zone());
block->set_scope(for_scope); block->set_scope(for_scope);
loop->Initialize(init, cond, next, body); loop->Initialize(init, cond, next, body);
impl()->RecordIterationStatementSourceRange(loop, body_range);
return block; return block;
} }
loop->Initialize(init, cond, next, body); loop->Initialize(init, cond, next, body);
return loop;
}
template <typename Impl>
typename ParserBase<Impl>::ForStatementT ParserBase<Impl>::ParseStandardForLoop(
int stmt_pos, ZoneList<const AstRawString*>* labels, ExpressionT* cond,
StatementT* next, StatementT* body, bool* ok) {
ForStatementT loop = factory()->NewForStatement(labels, stmt_pos);
typename Types::Target target(this, loop);
if (peek() != Token::SEMICOLON) {
*cond = ParseExpression(true, CHECK_OK);
}
Expect(Token::SEMICOLON, CHECK_OK);
if (peek() != Token::RPAREN) {
ExpressionT exp = ParseExpression(true, CHECK_OK);
*next = factory()->NewExpressionStatement(exp, exp->position());
}
Expect(Token::RPAREN, CHECK_OK);
SourceRange body_range;
{
SourceRangeScope range_scope(scanner(), &body_range);
*body = ParseStatement(nullptr, CHECK_OK);
}
impl()->RecordIterationStatementSourceRange(loop, body_range); impl()->RecordIterationStatementSourceRange(loop, body_range);
return loop; return loop;
} }
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#ifndef V8_PARSING_PARSER_H_ #ifndef V8_PARSING_PARSER_H_
#define V8_PARSING_PARSER_H_ #define V8_PARSING_PARSER_H_
#include <cstddef>
#include "src/ast/ast-source-ranges.h" #include "src/ast/ast-source-ranges.h"
#include "src/ast/ast.h" #include "src/ast/ast.h"
#include "src/ast/scopes.h" #include "src/ast/scopes.h"
...@@ -173,6 +175,7 @@ struct ParserTypes<Parser> { ...@@ -173,6 +175,7 @@ struct ParserTypes<Parser> {
typedef ZoneList<v8::internal::Statement*>* StatementList; typedef ZoneList<v8::internal::Statement*>* StatementList;
typedef v8::internal::Block* Block; typedef v8::internal::Block* Block;
typedef v8::internal::BreakableStatement* BreakableStatement; typedef v8::internal::BreakableStatement* BreakableStatement;
typedef v8::internal::ForStatement* ForStatement;
typedef v8::internal::IterationStatement* IterationStatement; typedef v8::internal::IterationStatement* IterationStatement;
// For constructing objects returned by the traversing functions. // For constructing objects returned by the traversing functions.
...@@ -870,7 +873,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) { ...@@ -870,7 +873,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
V8_INLINE static bool IsNullStatementList(ZoneList<Statement*>* stmts) { V8_INLINE static bool IsNullStatementList(ZoneList<Statement*>* stmts) {
return stmts == nullptr; return stmts == nullptr;
} }
V8_INLINE static Statement* NullStatement() { return nullptr; } // TODO(adamk): Use nullptr_t throughout more widely to remove redundant code.
V8_INLINE static std::nullptr_t NullStatement() { return nullptr; }
V8_INLINE bool IsNullStatement(Statement* stmt) { return stmt == nullptr; } V8_INLINE bool IsNullStatement(Statement* stmt) { return stmt == nullptr; }
V8_INLINE bool IsEmptyStatement(Statement* stmt) { V8_INLINE bool IsEmptyStatement(Statement* stmt) {
DCHECK_NOT_NULL(stmt); DCHECK_NOT_NULL(stmt);
......
...@@ -873,6 +873,7 @@ struct ParserTypes<PreParser> { ...@@ -873,6 +873,7 @@ struct ParserTypes<PreParser> {
typedef PreParserStatement Block; typedef PreParserStatement Block;
typedef PreParserStatement BreakableStatement; typedef PreParserStatement BreakableStatement;
typedef PreParserStatement IterationStatement; typedef PreParserStatement IterationStatement;
typedef PreParserStatement ForStatement;
// For constructing objects returned by the traversing functions. // For constructing objects returned by the traversing functions.
typedef PreParserFactory Factory; typedef PreParserFactory Factory;
......
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