Index: src/parsing/preparser.cc |
diff --git a/src/parsing/preparser.cc b/src/parsing/preparser.cc |
index 4a3f680f035d1384bb8d445bf5b40ec5b4ee2910..369ff2415efb8dbe3351b73dfb3c818147460c64 100644 |
--- a/src/parsing/preparser.cc |
+++ b/src/parsing/preparser.cc |
@@ -122,19 +122,223 @@ |
// 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); |
+} |
+ |
+PreParser::LazyParsingResult PreParser::ParseStatementList(int end_token, |
+ bool may_abort, |
+ bool* ok) { |
+ // SourceElements :: |
+ // (Statement)* <end_token> |
+ |
+ 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_VALUE(kLazyParsingComplete)); |
+ |
+ 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 kLazyParsingComplete; |
+ } |
+ } |
+ |
+ // 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 (may_abort) { |
+ if (!starts_with_identifier) { |
+ may_abort = false; |
+ } else if (++count_statements > kLazyParseTrialLimit) { |
+ return kLazyParsingAborted; |
+ } |
+ } |
+ } |
+ return kLazyParsingComplete; |
+} |
+ |
+ |
+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 ParseStatement(nullptr, kDisallowLabelledFunctionStatement, ok); |
+ 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, ZoneList<const AstRawString*>* names, |
- bool default_export, bool* ok) { |
+ 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); |
@@ -154,8 +358,7 @@ |
return Statement::FunctionDeclaration(); |
} |
-PreParser::Statement PreParser::ParseAsyncFunctionDeclaration( |
- ZoneList<const AstRawString*>* names, bool default_export, bool* ok) { |
+PreParser::Statement PreParser::ParseAsyncFunctionDeclaration(bool* ok) { |
// AsyncFunctionDeclaration :: |
// async [no LineTerminator here] function BindingIdentifier[Await] |
// ( FormalParameters[Await] ) { AsyncFunctionBody } |
@@ -163,11 +366,10 @@ |
int pos = position(); |
Expect(Token::FUNCTION, CHECK_OK); |
ParseFunctionFlags flags = ParseFunctionFlags::kIsAsync; |
- return ParseHoistableDeclaration(pos, flags, names, default_export, ok); |
-} |
- |
-PreParser::Statement PreParser::ParseHoistableDeclaration( |
- ZoneList<const AstRawString*>* names, bool default_export, bool* ok) { |
+ return ParseHoistableDeclaration(pos, flags, ok); |
+} |
+ |
+PreParser::Statement PreParser::ParseHoistableDeclaration(bool* ok) { |
// FunctionDeclaration :: |
// 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}' |
// GeneratorDeclaration :: |
@@ -180,11 +382,13 @@ |
if (Check(Token::MUL)) { |
flags |= ParseFunctionFlags::kIsGenerator; |
} |
- return ParseHoistableDeclaration(pos, flags, names, default_export, ok); |
-} |
- |
-PreParser::Statement PreParser::ParseClassDeclaration( |
- ZoneList<const AstRawString*>* names, bool default_export, bool* ok) { |
+ 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 = |
@@ -195,8 +399,8 @@ |
return Statement::Default(); |
} |
-PreParser::Statement PreParser::ParseBlock( |
- ZoneList<const AstRawString*>* labels, bool* ok) { |
+ |
+PreParser::Statement PreParser::ParseBlock(bool* ok) { |
// Block :: |
// '{' StatementList '}' |
@@ -212,14 +416,15 @@ |
return final; |
} |
+ |
PreParser::Statement PreParser::ParseVariableStatement( |
VariableDeclarationContext var_context, |
- ZoneList<const AstRawString*>* names, bool* ok) { |
+ bool* ok) { |
// VariableStatement :: |
// VariableDeclarations ';' |
Statement result = |
- ParseVariableDeclarations(var_context, nullptr, names, CHECK_OK); |
+ ParseVariableDeclarations(var_context, nullptr, nullptr, CHECK_OK); |
ExpectSemicolon(CHECK_OK); |
return result; |
} |
@@ -237,11 +442,10 @@ |
return Statement::Default(); |
} |
} |
- return ParseHoistableDeclaration(pos, flags, nullptr, false, ok); |
+ return ParseHoistableDeclaration(pos, flags, ok); |
} |
PreParser::Statement PreParser::ParseExpressionOrLabelledStatement( |
- ZoneList<const AstRawString*>* names, |
AllowLabelledFunctionStatement allow_function, bool* ok) { |
// ExpressionStatement | LabelledStatement :: |
// Expression ';' |
@@ -285,7 +489,7 @@ |
} |
} |
Statement statement = |
- ParseStatement(nullptr, kDisallowLabelledFunctionStatement, ok); |
+ 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 |
@@ -296,8 +500,8 @@ |
return Statement::ExpressionStatement(expr); |
} |
-PreParser::Statement PreParser::ParseIfStatement( |
- ZoneList<const AstRawString*>* labels, bool* ok) { |
+ |
+PreParser::Statement PreParser::ParseIfStatement(bool* ok) { |
// IfStatement :: |
// 'if' '(' Expression ')' Statement ('else' Statement)? |
@@ -335,8 +539,8 @@ |
return Statement::Jump(); |
} |
-PreParser::Statement PreParser::ParseBreakStatement( |
- ZoneList<const AstRawString*>* labels, bool* ok) { |
+ |
+PreParser::Statement PreParser::ParseBreakStatement(bool* ok) { |
// BreakStatement :: |
// 'break' [no line terminator] Identifier? ';' |
@@ -389,8 +593,8 @@ |
return Statement::Jump(); |
} |
-PreParser::Statement PreParser::ParseWithStatement( |
- ZoneList<const AstRawString*>* labels, bool* ok) { |
+ |
+PreParser::Statement PreParser::ParseWithStatement(bool* ok) { |
// WithStatement :: |
// 'with' '(' Expression ')' Statement |
Expect(Token::WITH, CHECK_OK); |
@@ -409,8 +613,8 @@ |
return Statement::Default(); |
} |
-PreParser::Statement PreParser::ParseSwitchStatement( |
- ZoneList<const AstRawString*>* labels, bool* ok) { |
+ |
+PreParser::Statement PreParser::ParseSwitchStatement(bool* ok) { |
// SwitchStatement :: |
// 'switch' '(' Expression ')' '{' CaseClause* '}' |
@@ -445,8 +649,8 @@ |
return Statement::Default(); |
} |
-PreParser::Statement PreParser::ParseDoWhileStatement( |
- ZoneList<const AstRawString*>* labels, bool* ok) { |
+ |
+PreParser::Statement PreParser::ParseDoWhileStatement(bool* ok) { |
// DoStatement :: |
// 'do' Statement 'while' '(' Expression ')' ';' |
@@ -460,8 +664,8 @@ |
return Statement::Default(); |
} |
-PreParser::Statement PreParser::ParseWhileStatement( |
- ZoneList<const AstRawString*>* labels, bool* ok) { |
+ |
+PreParser::Statement PreParser::ParseWhileStatement(bool* ok) { |
// WhileStatement :: |
// 'while' '(' Expression ')' Statement |
@@ -473,8 +677,8 @@ |
return Statement::Default(); |
} |
-PreParser::Statement PreParser::ParseForStatement( |
- ZoneList<const AstRawString*>* labels, bool* ok) { |
+ |
+PreParser::Statement PreParser::ParseForStatement(bool* ok) { |
// ForStatement :: |
// 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement |
@@ -640,7 +844,7 @@ |
{ |
ReturnExprScope no_tail_calls(function_state_, |
ReturnExprContext::kInsideTryBlock); |
- ParseBlock(nullptr, CHECK_OK); |
+ ParseBlock(CHECK_OK); |
} |
Token::Value tok = peek(); |
@@ -666,7 +870,7 @@ |
BlockState block_state(&scope_state_, catch_scope); |
{ |
BlockState block_state(&scope_state_); |
- ParseBlock(nullptr, CHECK_OK); |
+ ParseBlock(CHECK_OK); |
} |
} |
catch_block_exists = true; |
@@ -674,7 +878,7 @@ |
} |
if (tok == Token::FINALLY) { |
Consume(Token::FINALLY); |
- ParseBlock(nullptr, CHECK_OK); |
+ 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. |
@@ -715,7 +919,6 @@ |
// '(' 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); |
@@ -744,7 +947,7 @@ |
if (is_lazily_parsed) { |
ParseLazyFunctionLiteralBody(false, CHECK_OK); |
} else { |
- ParseStatementList(body, Token::RBRACE, CHECK_OK); |
+ ParseStatementList(Token::RBRACE, CHECK_OK); |
} |
Expect(Token::RBRACE, CHECK_OK); |
@@ -799,9 +1002,8 @@ |
PreParser::LazyParsingResult PreParser::ParseLazyFunctionLiteralBody( |
bool may_abort, bool* ok) { |
int body_start = position(); |
- PreParserStatementList body; |
LazyParsingResult result = ParseStatementList( |
- body, Token::RBRACE, may_abort, CHECK_OK_VALUE(kLazyParsingComplete)); |
+ Token::RBRACE, may_abort, CHECK_OK_VALUE(kLazyParsingComplete)); |
if (result == kLazyParsingAborted) return result; |
// Position right after terminal '}'. |