| Index: src/parsing/parser-base.h
|
| diff --git a/src/parsing/parser-base.h b/src/parsing/parser-base.h
|
| index 2b8c10c5f84999f1a15d662b3e73b05866e574d4..2539fb7d1d56283b9f2fedb6dd88b13b14d0ae5c 100644
|
| --- a/src/parsing/parser-base.h
|
| +++ b/src/parsing/parser-base.h
|
| @@ -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
|
|
|
|
|