Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(659)

Unified Diff: src/parsing/parser.cc

Issue 2323763002: [parser] Refactor of Parse*Statement*, part 4 (Closed)
Patch Set: Rebase Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/parsing/parser.h ('k') | src/parsing/parser-base.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/parsing/parser.cc
diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc
index e8de111f6495d6bde686770fb2a104f084e6c28d..f8092e6837430404afdf5a887af0b22610f5ec22 100644
--- a/src/parsing/parser.cc
+++ b/src/parsing/parser.cc
@@ -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
« no previous file with comments | « src/parsing/parser.h ('k') | src/parsing/parser-base.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698