Commit 40ba1db5 authored by nikolaos's avatar nikolaos Committed by Commit bot

[parser] Refactor of Parse*Statement*, part 4

This patch moves the following parsing methods to ParserBase:

- ParseExpressionOrLabelledStatement
- ParseIfStatement
- ParseContinueStatement
- ParseBreakStatement
- ParseReturnStatement
- ParseWithStatement

R=adamk@chromium.org, marja@chromium.org
BUG=
LOG=N

Review-Url: https://codereview.chromium.org/2323763002
Cr-Commit-Position: refs/heads/master@{#39325}
parent b4c9706e
......@@ -674,6 +674,13 @@ class ParserBase {
return result;
}
V8_INLINE DeclarationScope* GetDeclarationScope() const {
return scope()->GetDeclarationScope();
}
V8_INLINE DeclarationScope* GetClosureScope() const {
return scope()->GetClosureScope();
}
Scanner* scanner() const { return scanner_; }
AstValueFactory* ast_value_factory() const { return ast_value_factory_; }
int position() const { return scanner_->location().beg_pos; }
......@@ -881,13 +888,14 @@ class ParserBase {
bool is_resumable() const { return function_state_->is_resumable(); }
// Report syntax errors.
void ReportMessage(MessageTemplate::Template message, const char* arg = NULL,
ParseErrorType error_type = kSyntaxError) {
void ReportMessage(MessageTemplate::Template message) {
Scanner::Location source_location = scanner()->location();
impl()->ReportMessageAt(source_location, message, arg, error_type);
impl()->ReportMessageAt(source_location, message,
static_cast<const char*>(nullptr), kSyntaxError);
}
void ReportMessage(MessageTemplate::Template message, const AstRawString* arg,
template <typename T>
void ReportMessage(MessageTemplate::Template message, T arg,
ParseErrorType error_type = kSyntaxError) {
Scanner::Location source_location = scanner()->location();
impl()->ReportMessageAt(source_location, message, arg, error_type);
......@@ -1192,6 +1200,17 @@ class ParserBase {
StatementT ParseDebuggerStatement(bool* ok);
StatementT ParseExpressionOrLabelledStatement(
ZoneList<const AstRawString*>* labels,
AllowLabelledFunctionStatement allow_function, bool* ok);
StatementT ParseIfStatement(ZoneList<const AstRawString*>* labels, bool* ok);
StatementT ParseContinueStatement(bool* ok);
StatementT ParseBreakStatement(ZoneList<const AstRawString*>* labels,
bool* ok);
StatementT ParseReturnStatement(bool* ok);
StatementT ParseWithStatement(ZoneList<const AstRawString*>* labels,
bool* ok);
bool IsNextLetKeyword();
bool IsTrivialExpression();
......@@ -4065,7 +4084,7 @@ ParserBase<Impl>::ParseStatementList(StatementListT body, int end_token,
StatementT stat = impl()->ParseStatementListItem(
CHECK_OK_CUSTOM(Return, kLazyParsingComplete));
if (impl()->IsNullOrEmptyStatement(stat)) {
if (impl()->IsNullStatement(stat) || impl()->IsEmptyStatement(stat)) {
directive_prologue = false; // End of directive prologue.
continue;
}
......@@ -4214,7 +4233,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement(
Next();
return factory()->NewEmptyStatement(kNoSourcePosition);
case Token::IF:
return impl()->ParseIfStatement(labels, ok);
return ParseIfStatement(labels, ok);
case Token::DO:
return impl()->ParseDoWhileStatement(labels, ok);
case Token::WHILE:
......@@ -4242,7 +4261,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement(
}
}
case Token::WITH:
return impl()->ParseWithStatement(labels, ok);
return ParseWithStatement(labels, ok);
case Token::SWITCH:
return impl()->ParseSwitchStatement(labels, ok);
case Token::FUNCTION:
......@@ -4262,8 +4281,7 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseStatement(
case Token::VAR:
return ParseVariableStatement(kStatement, nullptr, ok);
default:
return impl()->ParseExpressionOrLabelledStatement(labels, allow_function,
ok);
return ParseExpressionOrLabelledStatement(labels, allow_function, ok);
}
}
......@@ -4276,11 +4294,11 @@ ParserBase<Impl>::ParseStatementAsUnlabelled(
ZoneList<const AstRawString*>* labels, bool* ok) {
switch (peek()) {
case Token::CONTINUE:
return impl()->ParseContinueStatement(ok);
return ParseContinueStatement(ok);
case Token::BREAK:
return impl()->ParseBreakStatement(labels, ok);
return ParseBreakStatement(labels, ok);
case Token::RETURN:
return impl()->ParseReturnStatement(ok);
return ParseReturnStatement(ok);
case Token::THROW:
return impl()->ParseThrowStatement(ok);
case Token::TRY:
......@@ -4309,7 +4327,7 @@ typename ParserBase<Impl>::BlockT ParserBase<Impl>::ParseBlock(
while (peek() != Token::RBRACE) {
StatementT stat = ParseStatementListItem(CHECK_OK_CUSTOM(NullBlock));
if (!impl()->IsNullOrEmptyStatement(stat)) {
if (!impl()->IsNullStatement(stat) && !impl()->IsEmptyStatement(stat)) {
body->statements()->Add(stat, zone());
}
}
......@@ -4385,6 +4403,237 @@ typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseDebuggerStatement(
return factory()->NewDebuggerStatement(pos);
}
template <typename Impl>
typename ParserBase<Impl>::StatementT
ParserBase<Impl>::ParseExpressionOrLabelledStatement(
ZoneList<const AstRawString*>* labels,
AllowLabelledFunctionStatement allow_function, bool* ok) {
// ExpressionStatement | LabelledStatement ::
// Expression ';'
// Identifier ':' Statement
//
// ExpressionStatement[Yield] :
// [lookahead ∉ {{, function, class, let [}] Expression[In, ?Yield] ;
int pos = peek_position();
switch (peek()) {
case Token::FUNCTION:
case Token::LBRACE:
UNREACHABLE(); // Always handled by the callers.
case Token::CLASS:
ReportUnexpectedToken(Next());
*ok = false;
return impl()->NullStatement();
default:
break;
}
bool starts_with_identifier = peek_any_identifier();
ExpressionT expr = ParseExpression(true, CHECK_OK);
if (peek() == Token::COLON && starts_with_identifier &&
impl()->IsIdentifier(expr)) {
// The whole expression was a single identifier, and not, e.g.,
// something starting with an identifier or a parenthesized identifier.
labels = impl()->DeclareLabel(labels, impl()->AsIdentifierExpression(expr),
CHECK_OK);
Consume(Token::COLON);
// ES#sec-labelled-function-declarations Labelled Function Declarations
if (peek() == Token::FUNCTION && is_sloppy(language_mode())) {
if (allow_function == kAllowLabelledFunctionStatement) {
return impl()->ParseFunctionDeclaration(ok);
} else {
return ParseScopedStatement(labels, true, ok);
}
}
return ParseStatement(labels, kDisallowLabelledFunctionStatement, ok);
}
// If we have an extension, we allow a native function declaration.
// A native function declaration starts with "native function" with
// no line-terminator between the two words.
if (extension_ != nullptr && peek() == Token::FUNCTION &&
!scanner()->HasAnyLineTerminatorBeforeNext() && impl()->IsNative(expr) &&
!scanner()->literal_contains_escapes()) {
return impl()->ParseNativeDeclaration(ok);
}
// Parsed expression statement, followed by semicolon.
ExpectSemicolon(CHECK_OK);
return factory()->NewExpressionStatement(expr, pos);
}
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseIfStatement(
ZoneList<const AstRawString*>* labels, bool* ok) {
// IfStatement ::
// 'if' '(' Expression ')' Statement ('else' Statement)?
int pos = peek_position();
Expect(Token::IF, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
ExpressionT condition = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
StatementT then_statement = ParseScopedStatement(labels, false, CHECK_OK);
StatementT else_statement = impl()->NullStatement();
if (Check(Token::ELSE)) {
else_statement = ParseScopedStatement(labels, false, CHECK_OK);
} else {
else_statement = factory()->NewEmptyStatement(kNoSourcePosition);
}
return factory()->NewIfStatement(condition, then_statement, else_statement,
pos);
}
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseContinueStatement(
bool* ok) {
// ContinueStatement ::
// 'continue' Identifier? ';'
int pos = peek_position();
Expect(Token::CONTINUE, CHECK_OK);
IdentifierT label = impl()->EmptyIdentifier();
Token::Value tok = peek();
if (!scanner()->HasAnyLineTerminatorBeforeNext() && tok != Token::SEMICOLON &&
tok != Token::RBRACE && tok != Token::EOS) {
// ECMA allows "eval" or "arguments" as labels even in strict mode.
label = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
}
typename Types::IterationStatementT target =
impl()->LookupContinueTarget(label, CHECK_OK);
if (impl()->IsNullStatement(target)) {
// Illegal continue statement.
MessageTemplate::Template message = MessageTemplate::kIllegalContinue;
if (!impl()->IsEmptyIdentifier(label)) {
message = MessageTemplate::kUnknownLabel;
}
ReportMessage(message, label);
*ok = false;
return impl()->NullStatement();
}
ExpectSemicolon(CHECK_OK);
return factory()->NewContinueStatement(target, pos);
}
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseBreakStatement(
ZoneList<const AstRawString*>* labels, bool* ok) {
// BreakStatement ::
// 'break' Identifier? ';'
int pos = peek_position();
Expect(Token::BREAK, CHECK_OK);
IdentifierT label = impl()->EmptyIdentifier();
Token::Value tok = peek();
if (!scanner()->HasAnyLineTerminatorBeforeNext() && tok != Token::SEMICOLON &&
tok != Token::RBRACE && tok != Token::EOS) {
// ECMA allows "eval" or "arguments" as labels even in strict mode.
label = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
}
// Parse labeled break statements that target themselves into
// empty statements, e.g. 'l1: l2: l3: break l2;'
if (!impl()->IsEmptyIdentifier(label) &&
impl()->ContainsLabel(labels, label)) {
ExpectSemicolon(CHECK_OK);
return factory()->NewEmptyStatement(pos);
}
typename Types::BreakableStatementT target =
impl()->LookupBreakTarget(label, CHECK_OK);
if (impl()->IsNullStatement(target)) {
// Illegal break statement.
MessageTemplate::Template message = MessageTemplate::kIllegalBreak;
if (!impl()->IsEmptyIdentifier(label)) {
message = MessageTemplate::kUnknownLabel;
}
ReportMessage(message, label);
*ok = false;
return impl()->NullStatement();
}
ExpectSemicolon(CHECK_OK);
return factory()->NewBreakStatement(target, pos);
}
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseReturnStatement(
bool* ok) {
// ReturnStatement ::
// 'return' [no line terminator] Expression? ';'
// Consume the return token. It is necessary to do that before
// reporting any errors on it, because of the way errors are
// reported (underlining).
Expect(Token::RETURN, CHECK_OK);
Scanner::Location loc = scanner()->location();
Token::Value tok = peek();
ExpressionT return_value = impl()->EmptyExpression();
if (scanner()->HasAnyLineTerminatorBeforeNext() || tok == Token::SEMICOLON ||
tok == Token::RBRACE || tok == Token::EOS) {
if (IsSubclassConstructor(function_state_->kind())) {
return_value = impl()->ThisExpression(loc.beg_pos);
} else {
return_value = impl()->GetLiteralUndefined(position());
}
} else {
if (IsSubclassConstructor(function_state_->kind())) {
// Because of the return code rewriting that happens in case of a subclass
// constructor we don't want to accept tail calls, therefore we don't set
// ReturnExprScope to kInsideValidReturnStatement here.
return_value = ParseExpression(true, CHECK_OK);
} else {
ReturnExprScope maybe_allow_tail_calls(
function_state_, ReturnExprContext::kInsideValidReturnStatement);
return_value = ParseExpression(true, CHECK_OK);
if (allow_tailcalls() && !is_sloppy(language_mode()) && !is_resumable()) {
// ES6 14.6.1 Static Semantics: IsInTailPosition
function_state_->AddImplicitTailCallExpression(return_value);
}
}
}
ExpectSemicolon(CHECK_OK);
return_value = impl()->RewriteReturn(return_value, loc.beg_pos);
DeclarationScope* decl_scope = GetDeclarationScope();
if (decl_scope->is_script_scope() || decl_scope->is_eval_scope()) {
impl()->ReportMessageAt(loc, MessageTemplate::kIllegalReturn);
*ok = false;
return impl()->NullStatement();
}
return factory()->NewReturnStatement(return_value, loc.beg_pos);
}
template <typename Impl>
typename ParserBase<Impl>::StatementT ParserBase<Impl>::ParseWithStatement(
ZoneList<const AstRawString*>* labels, bool* ok) {
// WithStatement ::
// 'with' '(' Expression ')' Statement
Expect(Token::WITH, CHECK_OK);
int pos = position();
if (is_strict(language_mode())) {
ReportMessage(MessageTemplate::kStrictWith);
*ok = false;
return impl()->NullStatement();
}
Expect(Token::LPAREN, CHECK_OK);
ExpressionT expr = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
Scope* with_scope = NewScope(WITH_SCOPE);
StatementT body = impl()->NullStatement();
{
BlockState block_state(&scope_state_, with_scope);
with_scope->set_start_position(scanner()->peek_location().beg_pos);
body = ParseScopedStatement(labels, true, CHECK_OK);
with_scope->set_end_position(scanner()->location().end_pos);
}
return factory()->NewWithStatement(with_scope, expr, body, pos);
}
#undef CHECK_OK
#undef CHECK_OK_CUSTOM
......
......@@ -1620,19 +1620,88 @@ Statement* Parser::DeclareFunction(const AstRawString* variable_name,
return factory()->NewEmptyStatement(kNoSourcePosition);
}
static bool ContainsLabel(ZoneList<const AstRawString*>* labels,
const AstRawString* label) {
DCHECK(label != NULL);
if (labels != NULL) {
for (int i = labels->length(); i-- > 0; ) {
if (labels->at(i) == label) {
return true;
}
ZoneList<const AstRawString*>* Parser::DeclareLabel(
ZoneList<const AstRawString*>* labels, VariableProxy* var, bool* ok) {
const AstRawString* label = var->raw_name();
// TODO(1240780): We don't check for redeclaration of labels
// during preparsing since keeping track of the set of active
// labels requires nontrivial changes to the way scopes are
// structured. However, these are probably changes we want to
// make later anyway so we should go back and fix this then.
if (ContainsLabel(labels, label) || TargetStackContainsLabel(label)) {
ReportMessage(MessageTemplate::kLabelRedeclaration, label);
*ok = false;
return nullptr;
}
if (labels == nullptr) {
labels = new (zone()) ZoneList<const AstRawString*>(1, zone());
}
labels->Add(label, zone());
// Remove the "ghost" variable that turned out to be a label
// from the top scope. This way, we don't try to resolve it
// during the scope processing.
scope()->RemoveUnresolved(var);
return labels;
}
bool Parser::ContainsLabel(ZoneList<const AstRawString*>* labels,
const AstRawString* label) {
DCHECK_NOT_NULL(label);
if (labels != nullptr) {
for (int i = labels->length(); i-- > 0;) {
if (labels->at(i) == label) return true;
}
}
return false;
}
Expression* Parser::RewriteReturn(Expression* return_value, int pos) {
if (IsSubclassConstructor(function_state_->kind())) {
// For subclass constructors we need to return this in case of undefined
// return a Smi (transformed into an exception in the ConstructStub)
// for a non object.
//
// return expr;
//
// Is rewritten as:
//
// return (temp = expr) === undefined ? this :
// %_IsJSReceiver(temp) ? temp : 1;
// temp = expr
Variable* temp = NewTemporary(ast_value_factory()->empty_string());
Assignment* assign = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(temp), return_value, pos);
// %_IsJSReceiver(temp)
ZoneList<Expression*>* is_spec_object_args =
new (zone()) ZoneList<Expression*>(1, zone());
is_spec_object_args->Add(factory()->NewVariableProxy(temp), zone());
Expression* is_spec_object_call = factory()->NewCallRuntime(
Runtime::kInlineIsJSReceiver, is_spec_object_args, pos);
// %_IsJSReceiver(temp) ? temp : 1;
Expression* is_object_conditional = factory()->NewConditional(
is_spec_object_call, factory()->NewVariableProxy(temp),
factory()->NewSmiLiteral(1, pos), pos);
// temp === undefined
Expression* is_undefined = factory()->NewCompareOperation(
Token::EQ_STRICT, assign,
factory()->NewUndefinedLiteral(kNoSourcePosition), pos);
// is_undefined ? this : is_object_conditional
return_value = factory()->NewConditional(is_undefined, ThisExpression(pos),
is_object_conditional, pos);
}
if (is_generator()) {
return_value = BuildIteratorResult(return_value, true);
} else if (is_async_function()) {
return_value = BuildResolvePromise(return_value, return_value->position());
}
return return_value;
}
Statement* Parser::ParseFunctionDeclaration(bool* ok) {
Consume(Token::FUNCTION);
int pos = position();
......@@ -1650,304 +1719,6 @@ Statement* Parser::ParseFunctionDeclaration(bool* ok) {
return ParseHoistableDeclaration(pos, flags, nullptr, false, CHECK_OK);
}
Statement* Parser::ParseExpressionOrLabelledStatement(
ZoneList<const AstRawString*>* labels,
AllowLabelledFunctionStatement allow_function, bool* ok) {
// ExpressionStatement | LabelledStatement ::
// Expression ';'
// Identifier ':' Statement
//
// ExpressionStatement[Yield] :
// [lookahead ∉ {{, function, class, let [}] Expression[In, ?Yield] ;
int pos = peek_position();
switch (peek()) {
case Token::FUNCTION:
case Token::LBRACE:
UNREACHABLE(); // Always handled by the callers.
case Token::CLASS:
ReportUnexpectedToken(Next());
*ok = false;
return nullptr;
default:
break;
}
bool starts_with_idenfifier = peek_any_identifier();
Expression* expr = ParseExpression(true, CHECK_OK);
if (peek() == Token::COLON && starts_with_idenfifier && expr != NULL &&
expr->AsVariableProxy() != NULL &&
!expr->AsVariableProxy()->is_this()) {
// Expression is a single identifier, and not, e.g., a parenthesized
// identifier.
VariableProxy* var = expr->AsVariableProxy();
const AstRawString* label = var->raw_name();
// TODO(1240780): We don't check for redeclaration of labels
// during preparsing since keeping track of the set of active
// labels requires nontrivial changes to the way scopes are
// structured. However, these are probably changes we want to
// make later anyway so we should go back and fix this then.
if (ContainsLabel(labels, label) || TargetStackContainsLabel(label)) {
ReportMessage(MessageTemplate::kLabelRedeclaration, label);
*ok = false;
return NULL;
}
if (labels == NULL) {
labels = new(zone()) ZoneList<const AstRawString*>(4, zone());
}
labels->Add(label, zone());
// Remove the "ghost" variable that turned out to be a label
// from the top scope. This way, we don't try to resolve it
// during the scope processing.
scope()->RemoveUnresolved(var);
Expect(Token::COLON, CHECK_OK);
// ES#sec-labelled-function-declarations Labelled Function Declarations
if (peek() == Token::FUNCTION && is_sloppy(language_mode())) {
if (allow_function == kAllowLabelledFunctionStatement) {
return ParseFunctionDeclaration(ok);
} else {
return ParseScopedStatement(labels, true, ok);
}
}
return ParseStatement(labels, kDisallowLabelledFunctionStatement, ok);
}
// If we have an extension, we allow a native function declaration.
// A native function declaration starts with "native function" with
// no line-terminator between the two words.
if (extension_ != NULL && peek() == Token::FUNCTION &&
!scanner()->HasAnyLineTerminatorBeforeNext() && expr != NULL &&
expr->AsVariableProxy() != NULL &&
expr->AsVariableProxy()->raw_name() ==
ast_value_factory()->native_string() &&
!scanner()->literal_contains_escapes()) {
return ParseNativeDeclaration(ok);
}
// Parsed expression statement, followed by semicolon.
ExpectSemicolon(CHECK_OK);
return factory()->NewExpressionStatement(expr, pos);
}
IfStatement* Parser::ParseIfStatement(ZoneList<const AstRawString*>* labels,
bool* ok) {
// IfStatement ::
// 'if' '(' Expression ')' Statement ('else' Statement)?
int pos = peek_position();
Expect(Token::IF, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
Expression* condition = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
Statement* then_statement = ParseScopedStatement(labels, false, CHECK_OK);
Statement* else_statement = NULL;
if (peek() == Token::ELSE) {
Next();
else_statement = ParseScopedStatement(labels, false, CHECK_OK);
} else {
else_statement = factory()->NewEmptyStatement(kNoSourcePosition);
}
return factory()->NewIfStatement(
condition, then_statement, else_statement, pos);
}
Statement* Parser::ParseContinueStatement(bool* ok) {
// ContinueStatement ::
// 'continue' Identifier? ';'
int pos = peek_position();
Expect(Token::CONTINUE, CHECK_OK);
const AstRawString* label = NULL;
Token::Value tok = peek();
if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
// ECMA allows "eval" or "arguments" as labels even in strict mode.
label = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
}
IterationStatement* target = LookupContinueTarget(label, CHECK_OK);
if (target == NULL) {
// Illegal continue statement.
MessageTemplate::Template message = MessageTemplate::kIllegalContinue;
if (label != NULL) {
message = MessageTemplate::kUnknownLabel;
}
ReportMessage(message, label);
*ok = false;
return NULL;
}
ExpectSemicolon(CHECK_OK);
return factory()->NewContinueStatement(target, pos);
}
Statement* Parser::ParseBreakStatement(ZoneList<const AstRawString*>* labels,
bool* ok) {
// BreakStatement ::
// 'break' Identifier? ';'
int pos = peek_position();
Expect(Token::BREAK, CHECK_OK);
const AstRawString* label = NULL;
Token::Value tok = peek();
if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
tok != Token::SEMICOLON && tok != Token::RBRACE && tok != Token::EOS) {
// ECMA allows "eval" or "arguments" as labels even in strict mode.
label = ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
}
// Parse labeled break statements that target themselves into
// empty statements, e.g. 'l1: l2: l3: break l2;'
if (label != NULL && ContainsLabel(labels, label)) {
ExpectSemicolon(CHECK_OK);
return factory()->NewEmptyStatement(pos);
}
BreakableStatement* target = NULL;
target = LookupBreakTarget(label, CHECK_OK);
if (target == NULL) {
// Illegal break statement.
MessageTemplate::Template message = MessageTemplate::kIllegalBreak;
if (label != NULL) {
message = MessageTemplate::kUnknownLabel;
}
ReportMessage(message, label);
*ok = false;
return NULL;
}
ExpectSemicolon(CHECK_OK);
return factory()->NewBreakStatement(target, pos);
}
Statement* Parser::ParseReturnStatement(bool* ok) {
// ReturnStatement ::
// 'return' Expression? ';'
// Consume the return token. It is necessary to do that before
// reporting any errors on it, because of the way errors are
// reported (underlining).
Expect(Token::RETURN, CHECK_OK);
Scanner::Location loc = scanner()->location();
Token::Value tok = peek();
Statement* result;
Expression* return_value;
if (scanner()->HasAnyLineTerminatorBeforeNext() ||
tok == Token::SEMICOLON ||
tok == Token::RBRACE ||
tok == Token::EOS) {
if (IsSubclassConstructor(function_state_->kind())) {
return_value = ThisExpression(loc.beg_pos);
} else {
return_value = GetLiteralUndefined(position());
}
} else {
int pos = peek_position();
if (IsSubclassConstructor(function_state_->kind())) {
// Because of the return code rewriting that happens in case of a subclass
// constructor we don't want to accept tail calls, therefore we don't set
// ReturnExprScope to kInsideValidReturnStatement here.
return_value = ParseExpression(true, CHECK_OK);
// For subclass constructors we need to return this in case of undefined
// return a Smi (transformed into an exception in the ConstructStub)
// for a non object.
//
// return expr;
//
// Is rewritten as:
//
// return (temp = expr) === undefined ? this :
// %_IsJSReceiver(temp) ? temp : 1;
// temp = expr
Variable* temp = NewTemporary(ast_value_factory()->empty_string());
Assignment* assign = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(temp), return_value, pos);
// %_IsJSReceiver(temp)
ZoneList<Expression*>* is_spec_object_args =
new (zone()) ZoneList<Expression*>(1, zone());
is_spec_object_args->Add(factory()->NewVariableProxy(temp), zone());
Expression* is_spec_object_call = factory()->NewCallRuntime(
Runtime::kInlineIsJSReceiver, is_spec_object_args, pos);
// %_IsJSReceiver(temp) ? temp : 1;
Expression* is_object_conditional = factory()->NewConditional(
is_spec_object_call, factory()->NewVariableProxy(temp),
factory()->NewSmiLiteral(1, pos), pos);
// temp === undefined
Expression* is_undefined = factory()->NewCompareOperation(
Token::EQ_STRICT, assign,
factory()->NewUndefinedLiteral(kNoSourcePosition), pos);
// is_undefined ? this : is_object_conditional
return_value = factory()->NewConditional(
is_undefined, ThisExpression(pos), is_object_conditional, pos);
} else {
ReturnExprScope maybe_allow_tail_calls(
function_state_, ReturnExprContext::kInsideValidReturnStatement);
return_value = ParseExpression(true, CHECK_OK);
if (allow_tailcalls() && !is_sloppy(language_mode()) && !is_resumable()) {
// ES6 14.6.1 Static Semantics: IsInTailPosition
function_state_->AddImplicitTailCallExpression(return_value);
}
}
}
ExpectSemicolon(CHECK_OK);
if (is_generator()) {
return_value = BuildIteratorResult(return_value, true);
} else if (is_async_function()) {
return_value = BuildResolvePromise(return_value, return_value->position());
}
result = factory()->NewReturnStatement(return_value, loc.beg_pos);
DeclarationScope* decl_scope = GetDeclarationScope();
if (decl_scope->is_script_scope() || decl_scope->is_eval_scope()) {
ReportMessageAt(loc, MessageTemplate::kIllegalReturn);
*ok = false;
return NULL;
}
return result;
}
Statement* Parser::ParseWithStatement(ZoneList<const AstRawString*>* labels,
bool* ok) {
// WithStatement ::
// 'with' '(' Expression ')' Statement
Expect(Token::WITH, CHECK_OK);
int pos = position();
if (is_strict(language_mode())) {
ReportMessage(MessageTemplate::kStrictWith);
*ok = false;
return NULL;
}
Expect(Token::LPAREN, CHECK_OK);
Expression* expr = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
Scope* with_scope = NewScope(WITH_SCOPE);
Statement* body;
{
BlockState block_state(&scope_state_, with_scope);
with_scope->set_start_position(scanner()->peek_location().beg_pos);
body = ParseScopedStatement(labels, true, CHECK_OK);
with_scope->set_end_position(scanner()->location().end_pos);
}
return factory()->NewWithStatement(with_scope, expr, body, pos);
}
CaseClause* Parser::ParseCaseClause(bool* default_seen_ptr, bool* ok) {
// CaseClause ::
// 'case' Expression ':' StatementList
......
......@@ -157,6 +157,8 @@ struct ParserTypes<Parser> {
typedef v8::internal::Statement* Statement;
typedef ZoneList<v8::internal::Statement*>* StatementList;
typedef v8::internal::Block* Block;
typedef v8::internal::BreakableStatement* BreakableStatementT;
typedef v8::internal::IterationStatement* IterationStatementT;
// For constructing objects returned by the traversing functions.
typedef AstNodeFactory Factory;
......@@ -203,12 +205,6 @@ class Parser : public ParserBase<Parser> {
enum class FunctionBodyType { kNormal, kSingleExpression };
DeclarationScope* GetDeclarationScope() const {
return scope()->GetDeclarationScope();
}
DeclarationScope* GetClosureScope() const {
return scope()->GetClosureScope();
}
Variable* NewTemporary(const AstRawString* name) {
return scope()->NewTemporary(name);
}
......@@ -280,6 +276,11 @@ class Parser : public ParserBase<Parser> {
Block* block, const DeclarationDescriptor* declaration_descriptor,
const DeclarationParsingResult::Declaration* declaration,
ZoneList<const AstRawString*>* names, bool* ok);
ZoneList<const AstRawString*>* DeclareLabel(
ZoneList<const AstRawString*>* labels, VariableProxy* expr, bool* ok);
bool ContainsLabel(ZoneList<const AstRawString*>* labels,
const AstRawString* label);
Expression* RewriteReturn(Expression* return_value, int pos);
Statement* DeclareFunction(const AstRawString* variable_name,
FunctionLiteral* function, int pos,
......@@ -370,17 +371,6 @@ class Parser : public ParserBase<Parser> {
DEFINE_AST_VISITOR_MEMBERS_WITHOUT_STACKOVERFLOW()
};
Statement* ParseExpressionOrLabelledStatement(
ZoneList<const AstRawString*>* labels,
AllowLabelledFunctionStatement allow_function, bool* ok);
IfStatement* ParseIfStatement(ZoneList<const AstRawString*>* labels,
bool* ok);
Statement* ParseContinueStatement(bool* ok);
Statement* ParseBreakStatement(ZoneList<const AstRawString*>* labels,
bool* ok);
Statement* ParseReturnStatement(bool* ok);
Statement* ParseWithStatement(ZoneList<const AstRawString*>* labels,
bool* ok);
CaseClause* ParseCaseClause(bool* default_seen_ptr, bool* ok);
Statement* ParseSwitchStatement(ZoneList<const AstRawString*>* labels,
bool* ok);
......@@ -641,9 +631,13 @@ class Parser : public ParserBase<Parser> {
property->obj()->AsVariableProxy()->is_this();
}
// This returns true if the expression is an indentifier (wrapped
// inside a variable proxy). We exclude the case of 'this', which
// has been converted to a variable proxy.
V8_INLINE static bool IsIdentifier(Expression* expression) {
DCHECK_NOT_NULL(expression);
VariableProxy* operand = expression->AsVariableProxy();
return operand != NULL && !operand->is_this();
return operand != nullptr && !operand->is_this();
}
V8_INLINE static const AstRawString* AsIdentifier(Expression* expression) {
......@@ -651,6 +645,10 @@ class Parser : public ParserBase<Parser> {
return expression->AsVariableProxy()->raw_name();
}
V8_INLINE VariableProxy* AsIdentifierExpression(Expression* expression) {
return expression->AsVariableProxy();
}
V8_INLINE bool IsPrototype(const AstRawString* identifier) const {
return identifier == ast_value_factory()->prototype_string();
}
......@@ -670,6 +668,13 @@ class Parser : public ParserBase<Parser> {
return ObjectLiteral::IsBoilerplateProperty(property);
}
V8_INLINE bool IsNative(Expression* expr) const {
DCHECK_NOT_NULL(expr);
return expr->IsVariableProxy() &&
expr->AsVariableProxy()->raw_name() ==
ast_value_factory()->native_string();
}
V8_INLINE static bool IsArrayIndex(const AstRawString* string,
uint32_t* index) {
return string->AsArrayIndex(index);
......@@ -835,6 +840,9 @@ class Parser : public ParserBase<Parser> {
// "null" return type creators.
V8_INLINE static const AstRawString* EmptyIdentifier() { return nullptr; }
V8_INLINE static bool IsEmptyIdentifier(const AstRawString* name) {
return name == nullptr;
}
V8_INLINE static Expression* EmptyExpression() { return nullptr; }
V8_INLINE static Literal* EmptyLiteral() { return nullptr; }
V8_INLINE static ObjectLiteralProperty* EmptyObjectLiteralProperty() {
......@@ -862,8 +870,10 @@ class Parser : public ParserBase<Parser> {
return stmts == nullptr;
}
V8_INLINE static Statement* NullStatement() { return nullptr; }
V8_INLINE bool IsNullOrEmptyStatement(Statement* stmt) {
return stmt == nullptr || stmt->IsEmpty();
V8_INLINE bool IsNullStatement(Statement* stmt) { return stmt == nullptr; }
V8_INLINE bool IsEmptyStatement(Statement* stmt) {
DCHECK_NOT_NULL(stmt);
return stmt->IsEmpty();
}
// Non-NULL empty string.
......
......@@ -164,175 +164,6 @@ PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) {
return ParseHoistableDeclaration(pos, flags, nullptr, false, ok);
}
PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(
ZoneList<const AstRawString*>* names,
AllowLabelledFunctionStatement allow_function, bool* ok) {
// ExpressionStatement | LabelledStatement ::
// Expression ';'
// Identifier ':' Statement
switch (peek()) {
case Token::FUNCTION:
case Token::LBRACE:
UNREACHABLE(); // Always handled by the callers.
case Token::CLASS:
ReportUnexpectedToken(Next());
*ok = false;
return Statement::Default();
default:
break;
}
bool starts_with_identifier = peek_any_identifier();
ExpressionClassifier classifier(this);
Expression expr = ParseExpressionCoverGrammar(true, CHECK_OK);
ValidateExpression(CHECK_OK);
// Even if the expression starts with an identifier, it is not necessarily an
// identifier. For example, "foo + bar" starts with an identifier but is not
// an identifier.
if (starts_with_identifier && expr.IsIdentifier() && peek() == Token::COLON) {
// Expression is a single identifier, and not, e.g., a parenthesized
// identifier.
DCHECK(!expr.AsIdentifier().IsEnum());
DCHECK(!parsing_module_ || !expr.AsIdentifier().IsAwait());
DCHECK(is_sloppy(language_mode()) ||
!IsFutureStrictReserved(expr.AsIdentifier()));
Consume(Token::COLON);
// ES#sec-labelled-function-declarations Labelled Function Declarations
if (peek() == Token::FUNCTION && is_sloppy(language_mode())) {
if (allow_function == kAllowLabelledFunctionStatement) {
return ParseFunctionDeclaration(ok);
} else {
return ParseScopedStatement(names, true, ok);
}
}
Statement statement =
ParseStatement(nullptr, kDisallowLabelledFunctionStatement, ok);
return statement.IsJumpStatement() ? Statement::Default() : statement;
// Preparsing is disabled for extensions (because the extension details
// aren't passed to lazily compiled functions), so we don't
// accept "native function" in the preparser.
}
// Parsed expression statement.
ExpectSemicolon(CHECK_OK);
return Statement::ExpressionStatement(expr);
}
PreParser::Statement PreParser::ParseIfStatement(
ZoneList<const AstRawString*>* labels, bool* ok) {
// IfStatement ::
// 'if' '(' Expression ')' Statement ('else' Statement)?
Expect(Token::IF, CHECK_OK);
Expect(Token::LPAREN, CHECK_OK);
ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
Statement stat = ParseScopedStatement(labels, false, CHECK_OK);
if (peek() == Token::ELSE) {
Next();
Statement else_stat = ParseScopedStatement(labels, false, CHECK_OK);
stat = (stat.IsJumpStatement() && else_stat.IsJumpStatement()) ?
Statement::Jump() : Statement::Default();
} else {
stat = Statement::Default();
}
return stat;
}
PreParser::Statement PreParser::ParseContinueStatement(bool* ok) {
// ContinueStatement ::
// 'continue' [no line terminator] Identifier? ';'
Expect(Token::CONTINUE, CHECK_OK);
Token::Value tok = peek();
if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
tok != Token::SEMICOLON &&
tok != Token::RBRACE &&
tok != Token::EOS) {
// ECMA allows "eval" or "arguments" as labels even in strict mode.
ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
}
ExpectSemicolon(CHECK_OK);
return Statement::Jump();
}
PreParser::Statement PreParser::ParseBreakStatement(
ZoneList<const AstRawString*>* labels, bool* ok) {
// BreakStatement ::
// 'break' [no line terminator] Identifier? ';'
Expect(Token::BREAK, CHECK_OK);
Token::Value tok = peek();
if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
tok != Token::SEMICOLON &&
tok != Token::RBRACE &&
tok != Token::EOS) {
// ECMA allows "eval" or "arguments" as labels even in strict mode.
ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
}
ExpectSemicolon(CHECK_OK);
return Statement::Jump();
}
PreParser::Statement PreParser::ParseReturnStatement(bool* ok) {
// ReturnStatement ::
// 'return' [no line terminator] Expression? ';'
// Consume the return token. It is necessary to do before
// reporting any errors on it, because of the way errors are
// reported (underlining).
Expect(Token::RETURN, CHECK_OK);
// An ECMAScript program is considered syntactically incorrect if it
// contains a return statement that is not within the body of a
// function. See ECMA-262, section 12.9, page 67.
// This is not handled during preparsing.
Token::Value tok = peek();
if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
tok != Token::SEMICOLON &&
tok != Token::RBRACE &&
tok != Token::EOS) {
// Because of the return code rewriting that happens in case of a subclass
// constructor we don't want to accept tail calls, therefore we don't set
// ReturnExprScope to kInsideValidReturnStatement here.
ReturnExprContext return_expr_context =
IsSubclassConstructor(function_state_->kind())
? function_state_->return_expr_context()
: ReturnExprContext::kInsideValidReturnStatement;
ReturnExprScope maybe_allow_tail_calls(function_state_,
return_expr_context);
ParseExpression(true, CHECK_OK);
}
ExpectSemicolon(CHECK_OK);
return Statement::Jump();
}
PreParser::Statement PreParser::ParseWithStatement(
ZoneList<const AstRawString*>* labels, bool* ok) {
// WithStatement ::
// 'with' '(' Expression ')' Statement
Expect(Token::WITH, CHECK_OK);
if (is_strict(language_mode())) {
ReportMessageAt(scanner()->location(), MessageTemplate::kStrictWith);
*ok = false;
return Statement::Default();
}
Expect(Token::LPAREN, CHECK_OK);
ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
Scope* with_scope = NewScope(WITH_SCOPE);
BlockState block_state(&scope_state_, with_scope);
ParseScopedStatement(labels, true, CHECK_OK);
return Statement::Default();
}
PreParser::Statement PreParser::ParseSwitchStatement(
ZoneList<const AstRawString*>* labels, bool* ok) {
// SwitchStatement ::
......
......@@ -25,6 +25,9 @@ class PreParserIdentifier {
static PreParserIdentifier Default() {
return PreParserIdentifier(kUnknownIdentifier);
}
static PreParserIdentifier Empty() {
return PreParserIdentifier(kEmptyIdentifier);
}
static PreParserIdentifier Eval() {
return PreParserIdentifier(kEvalIdentifier);
}
......@@ -64,6 +67,7 @@ class PreParserIdentifier {
static PreParserIdentifier Async() {
return PreParserIdentifier(kAsyncIdentifier);
}
bool IsEmpty() const { return type_ == kEmptyIdentifier; }
bool IsEval() const { return type_ == kEvalIdentifier; }
bool IsArguments() const { return type_ == kArgumentsIdentifier; }
bool IsEvalOrArguments() const { return IsEval() || IsArguments(); }
......@@ -91,6 +95,7 @@ class PreParserIdentifier {
private:
enum Type {
kEmptyIdentifier,
kUnknownIdentifier,
kFutureReservedIdentifier,
kFutureStrictReservedIdentifier,
......@@ -389,6 +394,14 @@ class PreParserStatement {
return PreParserStatement(kUnknownStatement);
}
static PreParserStatement Null() {
return PreParserStatement(kNullStatement);
}
static PreParserStatement Empty() {
return PreParserStatement(kEmptyStatement);
}
static PreParserStatement Jump() {
return PreParserStatement(kJumpStatement);
}
......@@ -425,6 +438,10 @@ class PreParserStatement {
return code_ == kJumpStatement;
}
bool IsNullStatement() { return code_ == kNullStatement; }
bool IsEmptyStatement() { return code_ == kEmptyStatement; }
// Dummy implementation for making statement->somefunc() work in both Parser
// and PreParser.
PreParserStatement* operator->() { return this; }
......@@ -434,6 +451,8 @@ class PreParserStatement {
private:
enum Type {
kNullStatement,
kEmptyStatement,
kUnknownStatement,
kJumpStatement,
kStringLiteralExpressionStatement,
......@@ -559,7 +578,7 @@ class PreParserFactory {
}
PreParserStatement NewReturnStatement(PreParserExpression expression,
int pos) {
return PreParserStatement::Default();
return PreParserStatement::Jump();
}
PreParserExpression NewFunctionLiteral(
PreParserIdentifier name, Scope* scope, PreParserStatementList body,
......@@ -595,6 +614,32 @@ class PreParserFactory {
return PreParserStatement::Default();
}
PreParserStatement NewExpressionStatement(PreParserExpression expr, int pos) {
return PreParserStatement::ExpressionStatement(expr);
}
PreParserStatement NewIfStatement(PreParserExpression condition,
PreParserStatement then_statement,
PreParserStatement else_statement,
int pos) {
// This must return a jump statement iff both clauses are jump statements.
return else_statement.IsJumpStatement() ? then_statement : else_statement;
}
PreParserStatement NewBreakStatement(PreParserStatement target, int pos) {
return PreParserStatement::Jump();
}
PreParserStatement NewContinueStatement(PreParserStatement target, int pos) {
return PreParserStatement::Jump();
}
PreParserStatement NewWithStatement(Scope* scope,
PreParserExpression expression,
PreParserStatement statement, int pos) {
return PreParserStatement::Default();
}
// Return the object itself as AstVisitor and implement the needed
// dummy method right in this class.
PreParserFactory* visitor() { return this; }
......@@ -648,6 +693,8 @@ struct ParserTypes<PreParser> {
typedef PreParserStatement Statement;
typedef PreParserStatementList StatementList;
typedef PreParserStatement Block;
typedef PreParserStatement BreakableStatementT;
typedef PreParserStatement IterationStatementT;
// For constructing objects returned by the traversing functions.
typedef PreParserFactory Factory;
......@@ -756,15 +803,6 @@ class PreParser : public ParserBase<PreParser> {
Expression ParseAsyncFunctionExpression(bool* ok);
Statement ParseClassDeclaration(ZoneList<const AstRawString*>* names,
bool default_export, bool* ok);
Statement ParseExpressionOrLabelledStatement(
ZoneList<const AstRawString*>* names,
AllowLabelledFunctionStatement allow_function, bool* ok);
Statement ParseIfStatement(ZoneList<const AstRawString*>* labels, bool* ok);
Statement ParseContinueStatement(bool* ok);
Statement ParseBreakStatement(ZoneList<const AstRawString*>* labels,
bool* ok);
Statement ParseReturnStatement(bool* ok);
Statement ParseWithStatement(ZoneList<const AstRawString*>* labels, bool* ok);
Statement ParseSwitchStatement(ZoneList<const AstRawString*>* labels,
bool* ok);
Statement ParseDoWhileStatement(ZoneList<const AstRawString*>* labels,
......@@ -865,6 +903,42 @@ class PreParser : public ParserBase<PreParser> {
const DeclarationDescriptor* declaration_descriptor,
const DeclarationParsingResult::Declaration* declaration,
ZoneList<const AstRawString*>* names, bool* ok) {}
V8_INLINE ZoneList<const AstRawString*>* DeclareLabel(
ZoneList<const AstRawString*>* labels, PreParserExpression expr,
bool* ok) {
DCHECK(!expr.AsIdentifier().IsEnum());
DCHECK(!parsing_module_ || !expr.AsIdentifier().IsAwait());
DCHECK(is_sloppy(language_mode()) ||
!IsFutureStrictReserved(expr.AsIdentifier()));
return labels;
}
V8_INLINE PreParserStatement ParseNativeDeclaration(bool* ok) {
UNREACHABLE();
return PreParserStatement::Default();
}
// TODO(nikolaos): The preparser currently does not keep track of labels.
V8_INLINE bool ContainsLabel(ZoneList<const AstRawString*>* labels,
PreParserIdentifier label) {
return false;
}
V8_INLINE PreParserExpression RewriteReturn(PreParserExpression return_value,
int pos) {
return return_value;
}
// TODO(nikolaos): The preparser currently does not keep track of labels
// and targets.
V8_INLINE PreParserStatement LookupBreakTarget(PreParserIdentifier label,
bool* ok) {
return PreParserStatement::Default();
}
V8_INLINE PreParserStatement LookupContinueTarget(PreParserIdentifier label,
bool* ok) {
return PreParserStatement::Default();
}
V8_INLINE PreParserStatement DeclareFunction(
PreParserIdentifier variable_name, PreParserExpression function, int pos,
......@@ -917,6 +991,11 @@ class PreParser : public ParserBase<PreParser> {
return expression.AsIdentifier();
}
V8_INLINE static PreParserExpression AsIdentifierExpression(
PreParserExpression expression) {
return expression;
}
V8_INLINE bool IsPrototype(PreParserIdentifier identifier) const {
return identifier.IsPrototype();
}
......@@ -934,6 +1013,14 @@ class PreParser : public ParserBase<PreParser> {
return false;
}
V8_INLINE bool IsNative(PreParserExpression expr) const {
// Preparsing is disabled for extensions (because the extension
// details aren't passed to lazily compiled functions), so we
// don't accept "native function" in the preparser and there is
// no need to keep track of "native".
return false;
}
V8_INLINE static bool IsArrayIndex(PreParserIdentifier string,
uint32_t* index) {
return false;
......@@ -1021,14 +1108,17 @@ class PreParser : public ParserBase<PreParser> {
V8_INLINE void ReportMessageAt(Scanner::Location source_location,
MessageTemplate::Template message,
const AstRawString* arg,
PreParserIdentifier arg,
ParseErrorType error_type = kSyntaxError) {
UNREACHABLE();
}
// "null" return type creators.
V8_INLINE static PreParserIdentifier EmptyIdentifier() {
return PreParserIdentifier::Default();
return PreParserIdentifier::Empty();
}
V8_INLINE static bool IsEmptyIdentifier(PreParserIdentifier name) {
return name.IsEmpty();
}
V8_INLINE static PreParserExpression EmptyExpression() {
return PreParserExpression::Empty();
......@@ -1070,9 +1160,12 @@ class PreParser : public ParserBase<PreParser> {
return PreParserStatement::Default();
}
V8_INLINE bool IsNullOrEmptyStatement(PreParserStatement stmt) {
// TODO(nikolaos): See if this needs to be consistent for the preparser.
return false;
V8_INLINE bool IsNullStatement(PreParserStatement stmt) {
return stmt.IsNullStatement();
}
V8_INLINE bool IsEmptyStatement(PreParserStatement stmt) {
return stmt.IsEmptyStatement();
}
V8_INLINE static PreParserStatement NullBlock() {
......
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