summaryrefslogtreecommitdiff
path: root/deps/v8/src/parsing/preparser.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/parsing/preparser.cc')
-rw-r--r--deps/v8/src/parsing/preparser.cc1175
1 files changed, 82 insertions, 1093 deletions
diff --git a/deps/v8/src/parsing/preparser.cc b/deps/v8/src/parsing/preparser.cc
index b1bbbf60c8..88470f7fa9 100644
--- a/deps/v8/src/parsing/preparser.cc
+++ b/deps/v8/src/parsing/preparser.cc
@@ -10,6 +10,7 @@
#include "src/conversions.h"
#include "src/globals.h"
#include "src/list.h"
+#include "src/parsing/duplicate-finder.h"
#include "src/parsing/parser-base.h"
#include "src/parsing/preparse-data-format.h"
#include "src/parsing/preparse-data.h"
@@ -28,34 +29,18 @@ namespace internal {
// thus it must never be used where only a single statement
// is correct (e.g. an if statement branch w/o braces)!
-#define CHECK_OK ok); \
- if (!*ok) return Statement::Default(); \
+#define CHECK_OK_VALUE(x) ok); \
+ if (!*ok) return x; \
((void)0
#define DUMMY ) // to make indentation work
#undef DUMMY
-// Used in functions where the return type is not ExpressionT.
-#define CHECK_OK_CUSTOM(x) ok); \
- if (!*ok) return this->x(); \
- ((void)0
-#define DUMMY ) // to make indentation work
-#undef DUMMY
+#define CHECK_OK CHECK_OK_VALUE(Expression::Default())
+#define CHECK_OK_VOID CHECK_OK_VALUE(this->Void())
-void ParserBaseTraits<PreParser>::ReportMessageAt(
- Scanner::Location source_location, MessageTemplate::Template message,
- const char* arg, ParseErrorType error_type) {
- delegate()->log_->LogMessage(source_location.beg_pos, source_location.end_pos,
- message, arg, error_type);
-}
+namespace {
-void ParserBaseTraits<PreParser>::ReportMessageAt(
- Scanner::Location source_location, MessageTemplate::Template message,
- const AstRawString* arg, ParseErrorType error_type) {
- UNREACHABLE();
-}
-
-PreParserIdentifier ParserBaseTraits<PreParser>::GetSymbol(
- Scanner* scanner) const {
+PreParserIdentifier GetSymbolHelper(Scanner* scanner) {
switch (scanner->current_token()) {
case Token::ENUM:
return PreParserIdentifier::Enum();
@@ -86,49 +71,51 @@ PreParserIdentifier ParserBaseTraits<PreParser>::GetSymbol(
}
}
-PreParserExpression ParserBaseTraits<PreParser>::ExpressionFromString(
- int pos, Scanner* scanner, PreParserFactory* factory) const {
- if (scanner->UnescapedLiteralMatches("use strict", 10)) {
- return PreParserExpression::UseStrictStringLiteral();
+} // unnamed namespace
+
+PreParserIdentifier PreParser::GetSymbol() const {
+ PreParserIdentifier symbol = GetSymbolHelper(scanner());
+ if (track_unresolved_variables_) {
+ const AstRawString* result = scanner()->CurrentSymbol(ast_value_factory());
+ DCHECK_NOT_NULL(result);
+ symbol.string_ = result;
}
- return PreParserExpression::StringLiteral();
+ return symbol;
}
PreParser::PreParseResult PreParser::PreParseLazyFunction(
- LanguageMode language_mode, FunctionKind kind, bool has_simple_parameters,
- bool parsing_module, ParserRecorder* log, Scanner::BookmarkScope* bookmark,
- int* use_counts) {
+ DeclarationScope* function_scope, bool parsing_module, ParserRecorder* log,
+ bool is_inner_function, bool may_abort, int* use_counts) {
+ DCHECK_EQ(FUNCTION_SCOPE, function_scope->scope_type());
parsing_module_ = parsing_module;
log_ = log;
use_counts_ = use_counts;
- // Lazy functions always have trivial outer scopes (no with/catch scopes).
+ DCHECK(!track_unresolved_variables_);
+ track_unresolved_variables_ = is_inner_function;
+
+ // The caller passes the function_scope which is not yet inserted into the
+ // scope_state_. All scopes above the function_scope are ignored by the
+ // PreParser.
DCHECK_NULL(scope_state_);
- DeclarationScope* top_scope = NewScriptScope();
- FunctionState top_state(&function_state_, &scope_state_, top_scope,
- kNormalFunction);
- scope()->SetLanguageMode(language_mode);
- DeclarationScope* function_scope = NewFunctionScope(kind);
- if (!has_simple_parameters) function_scope->SetHasNonSimpleParameters();
- FunctionState function_state(&function_state_, &scope_state_, function_scope,
- kind);
+ FunctionState function_state(&function_state_, &scope_state_, function_scope);
DCHECK_EQ(Token::LBRACE, scanner()->current_token());
bool ok = true;
int start_position = peek_position();
- ParseLazyFunctionLiteralBody(&ok, bookmark);
+ LazyParsingResult result = ParseLazyFunctionLiteralBody(may_abort, &ok);
use_counts_ = nullptr;
- if (bookmark && bookmark->HasBeenReset()) {
- // Do nothing, as we've just aborted scanning this function.
+ track_unresolved_variables_ = false;
+ if (result == kLazyParsingAborted) {
+ return kPreParseAbort;
} else if (stack_overflow()) {
return kPreParseStackOverflow;
} else if (!ok) {
ReportUnexpectedToken(scanner()->current_token());
} else {
DCHECK_EQ(Token::RBRACE, scanner()->peek());
- if (is_strict(scope()->language_mode())) {
+ if (is_strict(function_scope->language_mode())) {
int end_pos = scanner()->location().end_pos;
CheckStrictOctalLiteral(start_position, end_pos, &ok);
- CheckDecimalLiteralWithLeadingZero(use_counts, start_position, end_pos);
- if (!ok) return kPreParseSuccess;
+ CheckDecimalLiteralWithLeadingZero(start_position, end_pos);
}
}
return kPreParseSuccess;
@@ -148,908 +135,6 @@ PreParser::PreParseResult PreParser::PreParseLazyFunction(
// That means that contextual checks (like a label being declared where
// it is used) are generally omitted.
-
-PreParser::Statement PreParser::ParseStatementListItem(bool* ok) {
- // ECMA 262 6th Edition
- // StatementListItem[Yield, Return] :
- // Statement[?Yield, ?Return]
- // Declaration[?Yield]
- //
- // Declaration[Yield] :
- // HoistableDeclaration[?Yield]
- // ClassDeclaration[?Yield]
- // LexicalDeclaration[In, ?Yield]
- //
- // HoistableDeclaration[Yield, Default] :
- // FunctionDeclaration[?Yield, ?Default]
- // GeneratorDeclaration[?Yield, ?Default]
- //
- // LexicalDeclaration[In, Yield] :
- // LetOrConst BindingList[?In, ?Yield] ;
-
- switch (peek()) {
- case Token::FUNCTION:
- return ParseHoistableDeclaration(ok);
- case Token::CLASS:
- return ParseClassDeclaration(ok);
- case Token::CONST:
- return ParseVariableStatement(kStatementListItem, ok);
- case Token::LET:
- if (IsNextLetKeyword()) {
- return ParseVariableStatement(kStatementListItem, ok);
- }
- break;
- case Token::ASYNC:
- if (allow_harmony_async_await() && PeekAhead() == Token::FUNCTION &&
- !scanner()->HasAnyLineTerminatorAfterNext()) {
- Consume(Token::ASYNC);
- return ParseAsyncFunctionDeclaration(ok);
- }
- /* falls through */
- default:
- break;
- }
- return ParseStatement(kAllowLabelledFunctionStatement, ok);
-}
-
-
-void PreParser::ParseStatementList(int end_token, bool* ok,
- Scanner::BookmarkScope* bookmark) {
- // SourceElements ::
- // (Statement)* <end_token>
-
- // Bookkeeping for trial parse if bookmark is set:
- DCHECK_IMPLIES(bookmark, bookmark->HasBeenSet());
- bool maybe_reset = bookmark != nullptr;
- int count_statements = 0;
-
- bool directive_prologue = true;
- while (peek() != end_token) {
- if (directive_prologue && peek() != Token::STRING) {
- directive_prologue = false;
- }
- bool starts_with_identifier = peek() == Token::IDENTIFIER;
- Scanner::Location token_loc = scanner()->peek_location();
- Statement statement = ParseStatementListItem(CHECK_OK_CUSTOM(Void));
-
- if (directive_prologue) {
- bool use_strict_found = statement.IsUseStrictLiteral();
-
- if (use_strict_found) {
- scope()->SetLanguageMode(
- static_cast<LanguageMode>(scope()->language_mode() | STRICT));
- } else if (!statement.IsStringLiteral()) {
- directive_prologue = false;
- }
-
- if (use_strict_found && !scope()->HasSimpleParameters()) {
- // TC39 deemed "use strict" directives to be an error when occurring
- // in the body of a function with non-simple parameter list, on
- // 29/7/2015. https://goo.gl/ueA7Ln
- ReportMessageAt(token_loc,
- MessageTemplate::kIllegalLanguageModeDirective,
- "use strict");
- *ok = false;
- return;
- }
- }
-
- // If we're allowed to reset to a bookmark, we will do so when we see a long
- // and trivial function.
- // Our current definition of 'long and trivial' is:
- // - over 200 statements
- // - all starting with an identifier (i.e., no if, for, while, etc.)
- if (maybe_reset && (!starts_with_identifier ||
- ++count_statements > kLazyParseTrialLimit)) {
- if (count_statements > kLazyParseTrialLimit) {
- bookmark->Reset();
- return;
- }
- maybe_reset = false;
- }
- }
-}
-
-
-PreParser::Statement PreParser::ParseStatement(
- AllowLabelledFunctionStatement allow_function, bool* ok) {
- // Statement ::
- // EmptyStatement
- // ...
-
- if (peek() == Token::SEMICOLON) {
- Next();
- return Statement::Default();
- }
- return ParseSubStatement(allow_function, ok);
-}
-
-PreParser::Statement PreParser::ParseScopedStatement(bool legacy, bool* ok) {
- if (is_strict(language_mode()) || peek() != Token::FUNCTION ||
- (legacy && allow_harmony_restrictive_declarations())) {
- return ParseSubStatement(kDisallowLabelledFunctionStatement, ok);
- } else {
- BlockState block_state(&scope_state_);
- return ParseFunctionDeclaration(ok);
- }
-}
-
-PreParser::Statement PreParser::ParseSubStatement(
- AllowLabelledFunctionStatement allow_function, bool* ok) {
- // Statement ::
- // Block
- // VariableStatement
- // EmptyStatement
- // ExpressionStatement
- // IfStatement
- // IterationStatement
- // ContinueStatement
- // BreakStatement
- // ReturnStatement
- // WithStatement
- // LabelledStatement
- // SwitchStatement
- // ThrowStatement
- // TryStatement
- // DebuggerStatement
-
- // Note: Since labels can only be used by 'break' and 'continue'
- // statements, which themselves are only valid within blocks,
- // iterations or 'switch' statements (i.e., BreakableStatements),
- // labels can be simply ignored in all other cases; except for
- // trivial labeled break statements 'label: break label' which is
- // parsed into an empty statement.
-
- // Keep the source position of the statement
- switch (peek()) {
- case Token::LBRACE:
- return ParseBlock(ok);
-
- case Token::SEMICOLON:
- Next();
- return Statement::Default();
-
- case Token::IF:
- return ParseIfStatement(ok);
-
- case Token::DO:
- return ParseDoWhileStatement(ok);
-
- case Token::WHILE:
- return ParseWhileStatement(ok);
-
- case Token::FOR:
- return ParseForStatement(ok);
-
- case Token::CONTINUE:
- return ParseContinueStatement(ok);
-
- case Token::BREAK:
- return ParseBreakStatement(ok);
-
- case Token::RETURN:
- return ParseReturnStatement(ok);
-
- case Token::WITH:
- return ParseWithStatement(ok);
-
- case Token::SWITCH:
- return ParseSwitchStatement(ok);
-
- case Token::THROW:
- return ParseThrowStatement(ok);
-
- case Token::TRY:
- return ParseTryStatement(ok);
-
- case Token::FUNCTION:
- // FunctionDeclaration only allowed as a StatementListItem, not in
- // an arbitrary Statement position. Exceptions such as
- // ES#sec-functiondeclarations-in-ifstatement-statement-clauses
- // are handled by calling ParseScopedStatement rather than
- // ParseSubStatement directly.
- ReportMessageAt(scanner()->peek_location(),
- is_strict(language_mode())
- ? MessageTemplate::kStrictFunction
- : MessageTemplate::kSloppyFunction);
- *ok = false;
- return Statement::Default();
-
- case Token::DEBUGGER:
- return ParseDebuggerStatement(ok);
-
- case Token::VAR:
- return ParseVariableStatement(kStatement, ok);
-
- default:
- return ParseExpressionOrLabelledStatement(allow_function, ok);
- }
-}
-
-PreParser::Statement PreParser::ParseHoistableDeclaration(
- int pos, ParseFunctionFlags flags, bool* ok) {
- const bool is_generator = flags & ParseFunctionFlags::kIsGenerator;
- const bool is_async = flags & ParseFunctionFlags::kIsAsync;
- DCHECK(!is_generator || !is_async);
-
- bool is_strict_reserved = false;
- Identifier name = ParseIdentifierOrStrictReservedWord(
- &is_strict_reserved, CHECK_OK);
-
- ParseFunctionLiteral(name, scanner()->location(),
- is_strict_reserved ? kFunctionNameIsStrictReserved
- : kFunctionNameValidityUnknown,
- is_generator ? FunctionKind::kGeneratorFunction
- : is_async ? FunctionKind::kAsyncFunction
- : FunctionKind::kNormalFunction,
- pos, FunctionLiteral::kDeclaration, language_mode(),
- CHECK_OK);
- return Statement::FunctionDeclaration();
-}
-
-PreParser::Statement PreParser::ParseAsyncFunctionDeclaration(bool* ok) {
- // AsyncFunctionDeclaration ::
- // async [no LineTerminator here] function BindingIdentifier[Await]
- // ( FormalParameters[Await] ) { AsyncFunctionBody }
- DCHECK_EQ(scanner()->current_token(), Token::ASYNC);
- int pos = position();
- Expect(Token::FUNCTION, CHECK_OK);
- ParseFunctionFlags flags = ParseFunctionFlags::kIsAsync;
- return ParseHoistableDeclaration(pos, flags, ok);
-}
-
-PreParser::Statement PreParser::ParseHoistableDeclaration(bool* ok) {
- // FunctionDeclaration ::
- // 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
- // GeneratorDeclaration ::
- // 'function' '*' Identifier '(' FormalParameterListopt ')'
- // '{' FunctionBody '}'
-
- Expect(Token::FUNCTION, CHECK_OK);
- int pos = position();
- ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
- if (Check(Token::MUL)) {
- flags |= ParseFunctionFlags::kIsGenerator;
- }
- return ParseHoistableDeclaration(pos, flags, ok);
-}
-
-
-PreParser::Statement PreParser::ParseClassDeclaration(bool* ok) {
- Expect(Token::CLASS, CHECK_OK);
-
- int pos = position();
- bool is_strict_reserved = false;
- Identifier name =
- ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
- ParseClassLiteral(nullptr, name, scanner()->location(), is_strict_reserved,
- pos, CHECK_OK);
- return Statement::Default();
-}
-
-
-PreParser::Statement PreParser::ParseBlock(bool* ok) {
- // Block ::
- // '{' StatementList '}'
-
- Expect(Token::LBRACE, CHECK_OK);
- Statement final = Statement::Default();
- {
- BlockState block_state(&scope_state_);
- while (peek() != Token::RBRACE) {
- final = ParseStatementListItem(CHECK_OK);
- }
- }
- Expect(Token::RBRACE, ok);
- return final;
-}
-
-
-PreParser::Statement PreParser::ParseVariableStatement(
- VariableDeclarationContext var_context,
- bool* ok) {
- // VariableStatement ::
- // VariableDeclarations ';'
-
- Statement result = ParseVariableDeclarations(
- var_context, nullptr, nullptr, nullptr, nullptr, nullptr, CHECK_OK);
- ExpectSemicolon(CHECK_OK);
- return result;
-}
-
-
-// If the variable declaration declares exactly one non-const
-// variable, then *var is set to that variable. In all other cases,
-// *var is untouched; in particular, it is the caller's responsibility
-// to initialize it properly. This mechanism is also used for the parsing
-// of 'for-in' loops.
-PreParser::Statement PreParser::ParseVariableDeclarations(
- VariableDeclarationContext var_context, int* num_decl, bool* is_lexical,
- bool* is_binding_pattern, Scanner::Location* first_initializer_loc,
- Scanner::Location* bindings_loc, bool* ok) {
- // VariableDeclarations ::
- // ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
- //
- // The ES6 Draft Rev3 specifies the following grammar for const declarations
- //
- // ConstDeclaration ::
- // const ConstBinding (',' ConstBinding)* ';'
- // ConstBinding ::
- // Identifier '=' AssignmentExpression
- //
- // TODO(ES6):
- // ConstBinding ::
- // BindingPattern '=' AssignmentExpression
- bool require_initializer = false;
- bool lexical = false;
- bool is_pattern = false;
- if (peek() == Token::VAR) {
- Consume(Token::VAR);
- } else if (peek() == Token::CONST) {
- // TODO(ES6): The ES6 Draft Rev4 section 12.2.2 reads:
- //
- // ConstDeclaration : const ConstBinding (',' ConstBinding)* ';'
- //
- // * It is a Syntax Error if the code that matches this production is not
- // contained in extended code.
- //
- // However disallowing const in sloppy mode will break compatibility with
- // existing pages. Therefore we keep allowing const with the old
- // non-harmony semantics in sloppy mode.
- Consume(Token::CONST);
- DCHECK(var_context != kStatement);
- require_initializer = true;
- lexical = true;
- } else if (peek() == Token::LET) {
- Consume(Token::LET);
- DCHECK(var_context != kStatement);
- lexical = true;
- } else {
- *ok = false;
- return Statement::Default();
- }
-
- // The scope of a var/const declared variable anywhere inside a function
- // is the entire function (ECMA-262, 3rd, 10.1.3, and 12.2). The scope
- // of a let declared variable is the scope of the immediately enclosing
- // block.
- int nvars = 0; // the number of variables declared
- int bindings_start = peek_position();
- do {
- // Parse binding pattern.
- if (nvars > 0) Consume(Token::COMMA);
- int decl_pos = peek_position();
- PreParserExpression pattern = PreParserExpression::Default();
- {
- ExpressionClassifier pattern_classifier(this);
- pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
-
- ValidateBindingPattern(&pattern_classifier, CHECK_OK);
- if (lexical) {
- ValidateLetPattern(&pattern_classifier, CHECK_OK);
- }
- }
-
- is_pattern = pattern.IsObjectLiteral() || pattern.IsArrayLiteral();
-
- Scanner::Location variable_loc = scanner()->location();
- nvars++;
- if (Check(Token::ASSIGN)) {
- ExpressionClassifier classifier(this);
- ParseAssignmentExpression(var_context != kForStatement, &classifier,
- CHECK_OK);
- ValidateExpression(&classifier, CHECK_OK);
-
- variable_loc.end_pos = scanner()->location().end_pos;
- if (first_initializer_loc && !first_initializer_loc->IsValid()) {
- *first_initializer_loc = variable_loc;
- }
- } else if ((require_initializer || is_pattern) &&
- (var_context != kForStatement || !PeekInOrOf())) {
- ReportMessageAt(
- Scanner::Location(decl_pos, scanner()->location().end_pos),
- MessageTemplate::kDeclarationMissingInitializer,
- is_pattern ? "destructuring" : "const");
- *ok = false;
- return Statement::Default();
- }
- } while (peek() == Token::COMMA);
-
- if (bindings_loc) {
- *bindings_loc =
- Scanner::Location(bindings_start, scanner()->location().end_pos);
- }
-
- if (num_decl != nullptr) *num_decl = nvars;
- if (is_lexical != nullptr) *is_lexical = lexical;
- if (is_binding_pattern != nullptr) *is_binding_pattern = is_pattern;
- return Statement::Default();
-}
-
-PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) {
- Consume(Token::FUNCTION);
- int pos = position();
- ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
- if (Check(Token::MUL)) {
- flags |= ParseFunctionFlags::kIsGenerator;
- if (allow_harmony_restrictive_declarations()) {
- ReportMessageAt(scanner()->location(),
- MessageTemplate::kGeneratorInLegacyContext);
- *ok = false;
- return Statement::Default();
- }
- }
- return ParseHoistableDeclaration(pos, flags, ok);
-}
-
-PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(
- 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 = ParseExpression(true, &classifier, CHECK_OK);
- ValidateExpression(&classifier, 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(true, ok);
- }
- }
- Statement statement =
- ParseStatement(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(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(false, CHECK_OK);
- if (peek() == Token::ELSE) {
- Next();
- Statement else_stat = ParseScopedStatement(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(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(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(true, CHECK_OK);
- return Statement::Default();
-}
-
-
-PreParser::Statement PreParser::ParseSwitchStatement(bool* ok) {
- // SwitchStatement ::
- // 'switch' '(' Expression ')' '{' CaseClause* '}'
-
- Expect(Token::SWITCH, CHECK_OK);
- Expect(Token::LPAREN, CHECK_OK);
- ParseExpression(true, CHECK_OK);
- Expect(Token::RPAREN, CHECK_OK);
-
- {
- BlockState cases_block_state(&scope_state_);
- Expect(Token::LBRACE, CHECK_OK);
- Token::Value token = peek();
- while (token != Token::RBRACE) {
- if (token == Token::CASE) {
- Expect(Token::CASE, CHECK_OK);
- ParseExpression(true, CHECK_OK);
- } else {
- Expect(Token::DEFAULT, CHECK_OK);
- }
- Expect(Token::COLON, CHECK_OK);
- token = peek();
- Statement statement = Statement::Jump();
- while (token != Token::CASE &&
- token != Token::DEFAULT &&
- token != Token::RBRACE) {
- statement = ParseStatementListItem(CHECK_OK);
- token = peek();
- }
- }
- }
- Expect(Token::RBRACE, ok);
- return Statement::Default();
-}
-
-
-PreParser::Statement PreParser::ParseDoWhileStatement(bool* ok) {
- // DoStatement ::
- // 'do' Statement 'while' '(' Expression ')' ';'
-
- Expect(Token::DO, CHECK_OK);
- ParseScopedStatement(true, CHECK_OK);
- Expect(Token::WHILE, CHECK_OK);
- Expect(Token::LPAREN, CHECK_OK);
- ParseExpression(true, CHECK_OK);
- Expect(Token::RPAREN, ok);
- if (peek() == Token::SEMICOLON) Consume(Token::SEMICOLON);
- return Statement::Default();
-}
-
-
-PreParser::Statement PreParser::ParseWhileStatement(bool* ok) {
- // WhileStatement ::
- // 'while' '(' Expression ')' Statement
-
- Expect(Token::WHILE, CHECK_OK);
- Expect(Token::LPAREN, CHECK_OK);
- ParseExpression(true, CHECK_OK);
- Expect(Token::RPAREN, CHECK_OK);
- ParseScopedStatement(true, ok);
- return Statement::Default();
-}
-
-
-PreParser::Statement PreParser::ParseForStatement(bool* ok) {
- // ForStatement ::
- // 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
-
- // Create an in-between scope for let-bound iteration variables.
- bool has_lexical = false;
-
- BlockState block_state(&scope_state_);
- Expect(Token::FOR, CHECK_OK);
- Expect(Token::LPAREN, CHECK_OK);
- if (peek() != Token::SEMICOLON) {
- ForEachStatement::VisitMode mode;
- if (peek() == Token::VAR || peek() == Token::CONST ||
- (peek() == Token::LET && IsNextLetKeyword())) {
- int decl_count;
- bool is_lexical;
- bool is_binding_pattern;
- Scanner::Location first_initializer_loc = Scanner::Location::invalid();
- Scanner::Location bindings_loc = Scanner::Location::invalid();
- ParseVariableDeclarations(kForStatement, &decl_count, &is_lexical,
- &is_binding_pattern, &first_initializer_loc,
- &bindings_loc, CHECK_OK);
- if (is_lexical) has_lexical = true;
- if (CheckInOrOf(&mode, ok)) {
- if (!*ok) return Statement::Default();
- if (decl_count != 1) {
- ReportMessageAt(bindings_loc,
- MessageTemplate::kForInOfLoopMultiBindings,
- ForEachStatement::VisitModeString(mode));
- *ok = false;
- return Statement::Default();
- }
- if (first_initializer_loc.IsValid() &&
- (is_strict(language_mode()) || mode == ForEachStatement::ITERATE ||
- is_lexical || is_binding_pattern || allow_harmony_for_in())) {
- // Only increment the use count if we would have let this through
- // without the flag.
- if (use_counts_ != nullptr && allow_harmony_for_in()) {
- ++use_counts_[v8::Isolate::kForInInitializer];
- }
- ReportMessageAt(first_initializer_loc,
- MessageTemplate::kForInOfLoopInitializer,
- ForEachStatement::VisitModeString(mode));
- *ok = false;
- return Statement::Default();
- }
-
- if (mode == ForEachStatement::ITERATE) {
- ExpressionClassifier classifier(this);
- ParseAssignmentExpression(true, &classifier, CHECK_OK);
- RewriteNonPattern(&classifier, CHECK_OK);
- } else {
- ParseExpression(true, CHECK_OK);
- }
-
- Expect(Token::RPAREN, CHECK_OK);
- {
- ReturnExprScope no_tail_calls(function_state_,
- ReturnExprContext::kInsideForInOfBody);
- ParseScopedStatement(true, CHECK_OK);
- }
- return Statement::Default();
- }
- } else {
- int lhs_beg_pos = peek_position();
- ExpressionClassifier classifier(this);
- Expression lhs = ParseExpression(false, &classifier, CHECK_OK);
- int lhs_end_pos = scanner()->location().end_pos;
- bool is_for_each = CheckInOrOf(&mode, CHECK_OK);
- bool is_destructuring = is_for_each &&
- (lhs->IsArrayLiteral() || lhs->IsObjectLiteral());
-
- if (is_destructuring) {
- ValidateAssignmentPattern(&classifier, CHECK_OK);
- } else {
- ValidateExpression(&classifier, CHECK_OK);
- }
-
- if (is_for_each) {
- if (!is_destructuring) {
- lhs = CheckAndRewriteReferenceExpression(
- lhs, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor,
- kSyntaxError, CHECK_OK);
- }
-
- if (mode == ForEachStatement::ITERATE) {
- ExpressionClassifier classifier(this);
- ParseAssignmentExpression(true, &classifier, CHECK_OK);
- RewriteNonPattern(&classifier, CHECK_OK);
- } else {
- ParseExpression(true, CHECK_OK);
- }
-
- Expect(Token::RPAREN, CHECK_OK);
- {
- BlockState block_state(&scope_state_);
- ParseScopedStatement(true, CHECK_OK);
- }
- return Statement::Default();
- }
- }
- }
-
- // Parsed initializer at this point.
- Expect(Token::SEMICOLON, CHECK_OK);
-
- // If there are let bindings, then condition and the next statement of the
- // for loop must be parsed in a new scope.
- Scope* inner_scope = scope();
- // TODO(verwaest): Allocate this through a ScopeState as well.
- if (has_lexical) inner_scope = NewScopeWithParent(inner_scope, BLOCK_SCOPE);
-
- {
- BlockState block_state(&scope_state_, inner_scope);
-
- if (peek() != Token::SEMICOLON) {
- ParseExpression(true, CHECK_OK);
- }
- Expect(Token::SEMICOLON, CHECK_OK);
-
- if (peek() != Token::RPAREN) {
- ParseExpression(true, CHECK_OK);
- }
- Expect(Token::RPAREN, CHECK_OK);
-
- ParseScopedStatement(true, ok);
- }
- return Statement::Default();
-}
-
-
-PreParser::Statement PreParser::ParseThrowStatement(bool* ok) {
- // ThrowStatement ::
- // 'throw' [no line terminator] Expression ';'
-
- Expect(Token::THROW, CHECK_OK);
- if (scanner()->HasAnyLineTerminatorBeforeNext()) {
- ReportMessageAt(scanner()->location(), MessageTemplate::kNewlineAfterThrow);
- *ok = false;
- return Statement::Default();
- }
- ParseExpression(true, CHECK_OK);
- ExpectSemicolon(ok);
- return Statement::Jump();
-}
-
-
-PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
- // TryStatement ::
- // 'try' Block Catch
- // 'try' Block Finally
- // 'try' Block Catch Finally
- //
- // Catch ::
- // 'catch' '(' Identifier ')' Block
- //
- // Finally ::
- // 'finally' Block
-
- Expect(Token::TRY, CHECK_OK);
-
- {
- ReturnExprScope no_tail_calls(function_state_,
- ReturnExprContext::kInsideTryBlock);
- ParseBlock(CHECK_OK);
- }
-
- Token::Value tok = peek();
- if (tok != Token::CATCH && tok != Token::FINALLY) {
- ReportMessageAt(scanner()->location(), MessageTemplate::kNoCatchOrFinally);
- *ok = false;
- return Statement::Default();
- }
- TailCallExpressionList tail_call_expressions_in_catch_block(zone());
- bool catch_block_exists = false;
- if (tok == Token::CATCH) {
- Consume(Token::CATCH);
- Expect(Token::LPAREN, CHECK_OK);
- Scope* catch_scope = NewScope(CATCH_SCOPE);
- ExpressionClassifier pattern_classifier(this);
- ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
- ValidateBindingPattern(&pattern_classifier, CHECK_OK);
- Expect(Token::RPAREN, CHECK_OK);
- {
- CollectExpressionsInTailPositionToListScope
- collect_tail_call_expressions_scope(
- function_state_, &tail_call_expressions_in_catch_block);
- BlockState block_state(&scope_state_, catch_scope);
- {
- BlockState block_state(&scope_state_);
- ParseBlock(CHECK_OK);
- }
- }
- catch_block_exists = true;
- tok = peek();
- }
- if (tok == Token::FINALLY) {
- Consume(Token::FINALLY);
- ParseBlock(CHECK_OK);
- if (FLAG_harmony_explicit_tailcalls && catch_block_exists &&
- tail_call_expressions_in_catch_block.has_explicit_tail_calls()) {
- // TODO(ishell): update chapter number.
- // ES8 XX.YY.ZZ
- ReportMessageAt(tail_call_expressions_in_catch_block.location(),
- MessageTemplate::kUnexpectedTailCallInCatchBlock);
- *ok = false;
- return Statement::Default();
- }
- }
- return Statement::Default();
-}
-
-
-PreParser::Statement PreParser::ParseDebuggerStatement(bool* ok) {
- // In ECMA-262 'debugger' is defined as a reserved keyword. In some browser
- // contexts this is used as a statement which invokes the debugger as if a
- // break point is present.
- // DebuggerStatement ::
- // 'debugger' ';'
-
- Expect(Token::DEBUGGER, CHECK_OK);
- ExpectSemicolon(ok);
- return Statement::Default();
-}
-
-
-// Redefinition of CHECK_OK for parsing expressions.
-#undef CHECK_OK
-#define CHECK_OK ok); \
- if (!*ok) return Expression::Default(); \
- ((void)0
-#define DUMMY ) // to make indentation work
-#undef DUMMY
-
-
PreParser::Expression PreParser::ParseFunctionLiteral(
Identifier function_name, Scanner::Location function_name_location,
FunctionNameValidity function_name_validity, FunctionKind kind,
@@ -1059,11 +144,11 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
// '(' FormalParameterList? ')' '{' FunctionBody '}'
// Parse function body.
+ PreParserStatementList body;
bool outer_is_script_scope = scope()->is_script_scope();
DeclarationScope* function_scope = NewFunctionScope(kind);
function_scope->SetLanguageMode(language_mode);
- FunctionState function_state(&function_state_, &scope_state_, function_scope,
- kind);
+ FunctionState function_state(&function_state_, &scope_state_, function_scope);
DuplicateFinder duplicate_finder(scanner()->unicode_cache());
ExpressionClassifier formals_classifier(this, &duplicate_finder);
@@ -1071,7 +156,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
int start_position = scanner()->location().beg_pos;
function_scope->set_start_position(start_position);
PreParserFormalParameters formals(function_scope);
- ParseFormalParameterList(&formals, &formals_classifier, CHECK_OK);
+ ParseFormalParameterList(&formals, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
int formals_end_position = scanner()->location().end_pos;
@@ -1085,9 +170,9 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
Expect(Token::LBRACE, CHECK_OK);
if (is_lazily_parsed) {
- ParseLazyFunctionLiteralBody(CHECK_OK);
+ ParseLazyFunctionLiteralBody(false, CHECK_OK);
} else {
- ParseStatementList(Token::RBRACE, CHECK_OK);
+ ParseStatementList(body, Token::RBRACE, CHECK_OK);
}
Expect(Token::RBRACE, CHECK_OK);
@@ -1100,52 +185,24 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
function_name_location, CHECK_OK);
const bool allow_duplicate_parameters =
is_sloppy(language_mode) && formals.is_simple && !IsConciseMethod(kind);
- ValidateFormalParameters(&formals_classifier, language_mode,
- allow_duplicate_parameters, CHECK_OK);
+ ValidateFormalParameters(language_mode, allow_duplicate_parameters, CHECK_OK);
if (is_strict(language_mode)) {
int end_position = scanner()->location().end_pos;
CheckStrictOctalLiteral(start_position, end_position, CHECK_OK);
- CheckDecimalLiteralWithLeadingZero(use_counts_, start_position,
- end_position);
- }
-
- return Expression::Default();
-}
-
-PreParser::Expression PreParser::ParseAsyncFunctionExpression(bool* ok) {
- // AsyncFunctionDeclaration ::
- // async [no LineTerminator here] function ( FormalParameters[Await] )
- // { AsyncFunctionBody }
- //
- // async [no LineTerminator here] function BindingIdentifier[Await]
- // ( FormalParameters[Await] ) { AsyncFunctionBody }
- int pos = position();
- Expect(Token::FUNCTION, CHECK_OK);
- bool is_strict_reserved = false;
- Identifier name;
- FunctionLiteral::FunctionType type = FunctionLiteral::kAnonymousExpression;
-
- if (peek_any_identifier()) {
- type = FunctionLiteral::kNamedExpression;
- name = ParseIdentifierOrStrictReservedWord(FunctionKind::kAsyncFunction,
- &is_strict_reserved, CHECK_OK);
+ CheckDecimalLiteralWithLeadingZero(start_position, end_position);
}
- ParseFunctionLiteral(name, scanner()->location(),
- is_strict_reserved ? kFunctionNameIsStrictReserved
- : kFunctionNameValidityUnknown,
- FunctionKind::kAsyncFunction, pos, type, language_mode(),
- CHECK_OK);
return Expression::Default();
}
-void PreParser::ParseLazyFunctionLiteralBody(bool* ok,
- Scanner::BookmarkScope* bookmark) {
+PreParser::LazyParsingResult PreParser::ParseLazyFunctionLiteralBody(
+ bool may_abort, bool* ok) {
int body_start = position();
- ParseStatementList(Token::RBRACE, ok, bookmark);
- if (!*ok) return;
- if (bookmark && bookmark->HasBeenReset()) return;
+ PreParserStatementList body;
+ LazyParsingResult result = ParseStatementList(
+ body, Token::RBRACE, may_abort, CHECK_OK_VALUE(kLazyParsingComplete));
+ if (result == kLazyParsingAborted) return result;
// Position right after terminal '}'.
DCHECK_EQ(Token::RBRACE, scanner()->peek());
@@ -1156,113 +213,45 @@ void PreParser::ParseLazyFunctionLiteralBody(bool* ok,
function_state_->materialized_literal_count(),
function_state_->expected_property_count(), language_mode(),
scope->uses_super_property(), scope->calls_eval());
-}
-
-PreParserExpression PreParser::ParseClassLiteral(
- ExpressionClassifier* classifier, PreParserIdentifier name,
- Scanner::Location class_name_location, bool name_is_strict_reserved,
- int pos, bool* ok) {
- // All parts of a ClassDeclaration and ClassExpression are strict code.
- if (name_is_strict_reserved) {
- ReportMessageAt(class_name_location,
- MessageTemplate::kUnexpectedStrictReserved);
- *ok = false;
- return EmptyExpression();
- }
- if (IsEvalOrArguments(name)) {
- ReportMessageAt(class_name_location, MessageTemplate::kStrictEvalArguments);
- *ok = false;
- return EmptyExpression();
- }
-
- LanguageMode class_language_mode = language_mode();
- BlockState block_state(&scope_state_);
- scope()->SetLanguageMode(
- static_cast<LanguageMode>(class_language_mode | STRICT));
- // TODO(marja): Make PreParser use scope names too.
- // this->scope()->SetScopeName(name);
-
- bool has_extends = Check(Token::EXTENDS);
- if (has_extends) {
- ExpressionClassifier extends_classifier(this);
- ParseLeftHandSideExpression(&extends_classifier, CHECK_OK);
- CheckNoTailCallExpressions(&extends_classifier, CHECK_OK);
- ValidateExpression(&extends_classifier, CHECK_OK);
- if (classifier != nullptr) {
- classifier->Accumulate(&extends_classifier,
- ExpressionClassifier::ExpressionProductions);
- }
- }
-
- ClassLiteralChecker checker(this);
- bool has_seen_constructor = false;
-
- Expect(Token::LBRACE, CHECK_OK);
- while (peek() != Token::RBRACE) {
- if (Check(Token::SEMICOLON)) continue;
- const bool in_class = true;
- bool is_computed_name = false; // Classes do not care about computed
- // property names here.
- Identifier name;
- ExpressionClassifier property_classifier(this);
- ParsePropertyDefinition(
- &checker, in_class, has_extends, MethodKind::kNormal, &is_computed_name,
- &has_seen_constructor, &property_classifier, &name, CHECK_OK);
- ValidateExpression(&property_classifier, CHECK_OK);
- if (classifier != nullptr) {
- classifier->Accumulate(&property_classifier,
- ExpressionClassifier::ExpressionProductions);
+ return kLazyParsingComplete;
+}
+
+PreParserExpression PreParser::ExpressionFromIdentifier(
+ PreParserIdentifier name, int start_position, int end_position,
+ InferName infer) {
+ if (track_unresolved_variables_) {
+ AstNodeFactory factory(ast_value_factory());
+ // Setting the Zone is necessary because zone_ might be the temp Zone, and
+ // AstValueFactory doesn't know about it.
+ factory.set_zone(zone());
+ DCHECK_NOT_NULL(name.string_);
+ scope()->NewUnresolved(&factory, name.string_, start_position, end_position,
+ NORMAL_VARIABLE);
+ }
+ return PreParserExpression::FromIdentifier(name);
+}
+
+void PreParser::DeclareAndInitializeVariables(
+ PreParserStatement block,
+ const DeclarationDescriptor* declaration_descriptor,
+ const DeclarationParsingResult::Declaration* declaration,
+ ZoneList<const AstRawString*>* names, bool* ok) {
+ if (declaration->pattern.string_) {
+ /* Mimic what Parser does when declaring variables (see
+ Parser::PatternRewriter::VisitVariableProxy).
+
+ var + no initializer -> RemoveUnresolved
+ let + no initializer -> RemoveUnresolved
+ var + initializer -> RemoveUnresolved followed by NewUnresolved
+ let + initializer -> RemoveUnresolved
+ */
+
+ if (declaration->initializer.IsEmpty() ||
+ declaration_descriptor->mode == VariableMode::LET) {
+ declaration_descriptor->scope->RemoveUnresolved(
+ declaration->pattern.string_);
}
}
-
- Expect(Token::RBRACE, CHECK_OK);
-
- return Expression::Default();
-}
-
-
-PreParser::Expression PreParser::ParseV8Intrinsic(bool* ok) {
- // CallRuntime ::
- // '%' Identifier Arguments
- Expect(Token::MOD, CHECK_OK);
- if (!allow_natives()) {
- *ok = false;
- return Expression::Default();
- }
- // Allow "eval" or "arguments" for backward compatibility.
- ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
- Scanner::Location spread_pos;
- ExpressionClassifier classifier(this);
- ParseArguments(&spread_pos, &classifier, ok);
- ValidateExpression(&classifier, CHECK_OK);
-
- DCHECK(!spread_pos.IsValid());
-
- return Expression::Default();
-}
-
-
-PreParserExpression PreParser::ParseDoExpression(bool* ok) {
- // AssignmentExpression ::
- // do '{' StatementList '}'
- Expect(Token::DO, CHECK_OK);
- Expect(Token::LBRACE, CHECK_OK);
- while (peek() != Token::RBRACE) {
- ParseStatementListItem(CHECK_OK);
- }
- Expect(Token::RBRACE, CHECK_OK);
- return PreParserExpression::Default();
-}
-
-void PreParser::ParseAsyncArrowSingleExpressionBody(
- PreParserStatementList body, bool accept_IN,
- ExpressionClassifier* classifier, int pos, bool* ok) {
- scope()->ForceContextAllocation();
-
- PreParserExpression return_value =
- ParseAssignmentExpression(accept_IN, classifier, CHECK_OK_CUSTOM(Void));
-
- body->Add(PreParserStatement::ExpressionStatement(return_value), zone());
}
#undef CHECK_OK