2011-05-19 09:22:32 +00:00
|
|
|
// Copyright 2011 the V8 project authors. All rights reserved.
|
2014-04-29 06:42:26 +00:00
|
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
|
|
// found in the LICENSE file.
|
2010-11-23 11:46:36 +00:00
|
|
|
|
2013-04-19 13:26:47 +00:00
|
|
|
#include <cmath>
|
2011-09-07 12:39:53 +00:00
|
|
|
|
2014-06-03 08:12:43 +00:00
|
|
|
#include "src/allocation.h"
|
2014-06-30 13:25:46 +00:00
|
|
|
#include "src/base/logging.h"
|
2014-06-03 08:12:43 +00:00
|
|
|
#include "src/conversions-inl.h"
|
2014-06-20 08:40:11 +00:00
|
|
|
#include "src/conversions.h"
|
2014-06-03 08:12:43 +00:00
|
|
|
#include "src/globals.h"
|
|
|
|
#include "src/list.h"
|
2015-12-07 14:26:25 +00:00
|
|
|
#include "src/parsing/parser-base.h"
|
2015-11-26 16:22:34 +00:00
|
|
|
#include "src/parsing/preparse-data-format.h"
|
2016-04-26 17:30:21 +00:00
|
|
|
#include "src/parsing/preparse-data.h"
|
2015-11-26 16:22:34 +00:00
|
|
|
#include "src/parsing/preparser.h"
|
2014-06-03 08:12:43 +00:00
|
|
|
#include "src/unicode.h"
|
|
|
|
#include "src/utils.h"
|
2011-07-05 11:54:11 +00:00
|
|
|
|
2013-04-19 13:26:47 +00:00
|
|
|
namespace v8 {
|
2013-10-14 13:07:20 +00:00
|
|
|
namespace internal {
|
2010-11-23 11:46:36 +00:00
|
|
|
|
2014-02-11 09:35:32 +00:00
|
|
|
void PreParserTraits::ReportMessageAt(Scanner::Location location,
|
2015-05-18 08:34:05 +00:00
|
|
|
MessageTemplate::Template message,
|
|
|
|
const char* arg,
|
2015-02-20 21:19:43 +00:00
|
|
|
ParseErrorType error_type) {
|
|
|
|
ReportMessageAt(location.beg_pos, location.end_pos, message, arg, error_type);
|
2014-02-11 09:35:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-02-20 21:19:43 +00:00
|
|
|
void PreParserTraits::ReportMessageAt(int start_pos, int end_pos,
|
2015-05-18 08:34:05 +00:00
|
|
|
MessageTemplate::Template message,
|
|
|
|
const char* arg,
|
2015-02-20 21:19:43 +00:00
|
|
|
ParseErrorType error_type) {
|
|
|
|
pre_parser_->log_->LogMessage(start_pos, end_pos, message, arg, error_type);
|
2014-02-11 09:35:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-02-14 11:24:26 +00:00
|
|
|
PreParserIdentifier PreParserTraits::GetSymbol(Scanner* scanner) {
|
2016-04-29 18:12:57 +00:00
|
|
|
if (scanner->current_token() == Token::ENUM) {
|
|
|
|
return PreParserIdentifier::Enum();
|
|
|
|
} else if (scanner->current_token() == Token::AWAIT) {
|
|
|
|
return PreParserIdentifier::Await();
|
2014-02-11 09:35:32 +00:00
|
|
|
} else if (scanner->current_token() ==
|
|
|
|
Token::FUTURE_STRICT_RESERVED_WORD) {
|
|
|
|
return PreParserIdentifier::FutureStrictReserved();
|
2014-07-10 14:06:37 +00:00
|
|
|
} else if (scanner->current_token() == Token::LET) {
|
|
|
|
return PreParserIdentifier::Let();
|
2014-11-03 19:53:36 +00:00
|
|
|
} else if (scanner->current_token() == Token::STATIC) {
|
|
|
|
return PreParserIdentifier::Static();
|
2014-02-11 09:35:32 +00:00
|
|
|
} else if (scanner->current_token() == Token::YIELD) {
|
|
|
|
return PreParserIdentifier::Yield();
|
2016-05-16 23:17:13 +00:00
|
|
|
} else if (scanner->current_token() == Token::ASYNC) {
|
|
|
|
return PreParserIdentifier::Async();
|
2014-02-11 09:35:32 +00:00
|
|
|
}
|
2014-03-12 14:03:25 +00:00
|
|
|
if (scanner->UnescapedLiteralMatches("eval", 4)) {
|
|
|
|
return PreParserIdentifier::Eval();
|
|
|
|
}
|
|
|
|
if (scanner->UnescapedLiteralMatches("arguments", 9)) {
|
|
|
|
return PreParserIdentifier::Arguments();
|
2014-02-11 09:35:32 +00:00
|
|
|
}
|
2015-04-10 12:04:51 +00:00
|
|
|
if (scanner->UnescapedLiteralMatches("undefined", 9)) {
|
|
|
|
return PreParserIdentifier::Undefined();
|
|
|
|
}
|
2014-10-24 15:02:29 +00:00
|
|
|
if (scanner->LiteralMatches("prototype", 9)) {
|
2014-09-16 22:15:39 +00:00
|
|
|
return PreParserIdentifier::Prototype();
|
|
|
|
}
|
2014-10-24 15:02:29 +00:00
|
|
|
if (scanner->LiteralMatches("constructor", 11)) {
|
2014-09-16 22:15:39 +00:00
|
|
|
return PreParserIdentifier::Constructor();
|
|
|
|
}
|
2014-02-11 09:35:32 +00:00
|
|
|
return PreParserIdentifier::Default();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-08-22 14:40:38 +00:00
|
|
|
PreParserIdentifier PreParserTraits::GetNumberAsSymbol(Scanner* scanner) {
|
|
|
|
return PreParserIdentifier::Default();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-02-14 11:24:26 +00:00
|
|
|
PreParserExpression PreParserTraits::ExpressionFromString(
|
|
|
|
int pos, Scanner* scanner, PreParserFactory* factory) {
|
2014-03-12 14:03:25 +00:00
|
|
|
if (scanner->UnescapedLiteralMatches("use strict", 10)) {
|
2014-02-14 11:24:26 +00:00
|
|
|
return PreParserExpression::UseStrictStringLiteral();
|
|
|
|
}
|
|
|
|
return PreParserExpression::StringLiteral();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
PreParserExpression PreParserTraits::ParseV8Intrinsic(bool* ok) {
|
|
|
|
return pre_parser_->ParseV8Intrinsic(ok);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-11 15:40:41 +00:00
|
|
|
PreParserExpression PreParserTraits::ParseFunctionLiteral(
|
2014-09-10 16:39:42 +00:00
|
|
|
PreParserIdentifier name, Scanner::Location function_name_location,
|
2015-07-09 21:31:11 +00:00
|
|
|
FunctionNameValidity function_name_validity, FunctionKind kind,
|
2014-09-10 16:39:42 +00:00
|
|
|
int function_token_position, FunctionLiteral::FunctionType type,
|
2015-07-15 09:14:49 +00:00
|
|
|
LanguageMode language_mode, bool* ok) {
|
2014-03-11 15:40:41 +00:00
|
|
|
return pre_parser_->ParseFunctionLiteral(
|
2015-07-09 21:31:11 +00:00
|
|
|
name, function_name_location, function_name_validity, kind,
|
2016-02-19 02:50:58 +00:00
|
|
|
function_token_position, type, language_mode, ok);
|
2014-03-11 15:40:41 +00:00
|
|
|
}
|
|
|
|
|
2011-11-25 09:36:31 +00:00
|
|
|
PreParser::PreParseResult PreParser::PreParseLazyFunction(
|
2015-08-26 14:59:05 +00:00
|
|
|
LanguageMode language_mode, FunctionKind kind, bool has_simple_parameters,
|
2016-04-29 18:12:57 +00:00
|
|
|
bool parsing_module, ParserRecorder* log, Scanner::BookmarkScope* bookmark,
|
|
|
|
int* use_counts) {
|
|
|
|
parsing_module_ = parsing_module;
|
2011-11-25 09:36:31 +00:00
|
|
|
log_ = log;
|
2016-04-26 00:29:37 +00:00
|
|
|
use_counts_ = use_counts;
|
2011-11-25 09:36:31 +00:00
|
|
|
// Lazy functions always have trivial outer scopes (no with/catch scopes).
|
2015-02-10 13:27:08 +00:00
|
|
|
Scope* top_scope = NewScope(scope_, SCRIPT_SCOPE);
|
2014-10-21 12:16:37 +00:00
|
|
|
PreParserFactory top_factory(NULL);
|
2015-02-10 13:27:08 +00:00
|
|
|
FunctionState top_state(&function_state_, &scope_, top_scope, kNormalFunction,
|
|
|
|
&top_factory);
|
2015-02-04 09:34:05 +00:00
|
|
|
scope_->SetLanguageMode(language_mode);
|
2015-10-07 14:55:38 +00:00
|
|
|
Scope* function_scope = NewScope(scope_, FUNCTION_SCOPE, kind);
|
2015-08-26 14:59:05 +00:00
|
|
|
if (!has_simple_parameters) function_scope->SetHasNonSimpleParameters();
|
2014-10-21 12:16:37 +00:00
|
|
|
PreParserFactory function_factory(NULL);
|
2015-02-10 13:27:08 +00:00
|
|
|
FunctionState function_state(&function_state_, &scope_, function_scope, kind,
|
2014-10-09 08:16:13 +00:00
|
|
|
&function_factory);
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK_EQ(Token::LBRACE, scanner()->current_token());
|
2011-11-25 09:36:31 +00:00
|
|
|
bool ok = true;
|
2013-10-15 08:32:58 +00:00
|
|
|
int start_position = peek_position();
|
2015-05-06 10:21:20 +00:00
|
|
|
ParseLazyFunctionLiteralBody(&ok, bookmark);
|
2016-04-26 00:29:37 +00:00
|
|
|
use_counts_ = nullptr;
|
2015-05-06 10:21:20 +00:00
|
|
|
if (bookmark && bookmark->HasBeenReset()) {
|
2015-09-28 08:18:29 +00:00
|
|
|
// Do nothing, as we've just aborted scanning this function.
|
2015-05-06 10:21:20 +00:00
|
|
|
} else if (stack_overflow()) {
|
|
|
|
return kPreParseStackOverflow;
|
|
|
|
} else if (!ok) {
|
2013-10-14 16:46:51 +00:00
|
|
|
ReportUnexpectedToken(scanner()->current_token());
|
2011-11-25 09:36:31 +00:00
|
|
|
} else {
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK_EQ(Token::RBRACE, scanner()->peek());
|
2015-02-04 09:34:05 +00:00
|
|
|
if (is_strict(scope_->language_mode())) {
|
2013-10-14 16:46:51 +00:00
|
|
|
int end_pos = scanner()->location().end_pos;
|
2014-12-18 22:01:25 +00:00
|
|
|
CheckStrictOctalLiteral(start_position, end_pos, &ok);
|
2016-05-16 23:20:29 +00:00
|
|
|
CheckDecimalLiteralWithLeadingZero(use_counts, start_position, end_pos);
|
2015-04-22 11:04:25 +00:00
|
|
|
if (!ok) return kPreParseSuccess;
|
2011-11-25 09:36:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return kPreParseSuccess;
|
|
|
|
}
|
|
|
|
|
2014-11-14 15:05:05 +00:00
|
|
|
PreParserExpression PreParserTraits::ParseClassLiteral(
|
2016-05-03 01:55:27 +00:00
|
|
|
Type::ExpressionClassifier* classifier, PreParserIdentifier name,
|
|
|
|
Scanner::Location class_name_location, bool name_is_strict_reserved,
|
|
|
|
int pos, bool* ok) {
|
|
|
|
return pre_parser_->ParseClassLiteral(classifier, name, class_name_location,
|
2014-11-14 15:05:05 +00:00
|
|
|
name_is_strict_reserved, pos, ok);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-23 11:46:36 +00:00
|
|
|
// Preparsing checks a JavaScript program and emits preparse-data that helps
|
|
|
|
// a later parsing to be faster.
|
|
|
|
// See preparser-data.h for the data.
|
|
|
|
|
|
|
|
// The PreParser checks that the syntax follows the grammar for JavaScript,
|
|
|
|
// and collects some information about the program along the way.
|
|
|
|
// The grammar check is only performed in order to understand the program
|
|
|
|
// sufficiently to deduce some information about it, that can be used
|
|
|
|
// to speed up later parsing. Finding errors is not the goal of pre-parsing,
|
|
|
|
// rather it is to speed up properly written and correct programs.
|
|
|
|
// That means that contextual checks (like a label being declared where
|
|
|
|
// it is used) are generally omitted.
|
|
|
|
|
|
|
|
|
2015-02-06 23:26:18 +00:00
|
|
|
PreParser::Statement PreParser::ParseStatementListItem(bool* ok) {
|
2015-01-30 03:09:57 +00:00
|
|
|
// ECMA 262 6th Edition
|
|
|
|
// StatementListItem[Yield, Return] :
|
|
|
|
// Statement[?Yield, ?Return]
|
|
|
|
// Declaration[?Yield]
|
2011-09-21 12:27:07 +00:00
|
|
|
//
|
2015-01-30 03:09:57 +00:00
|
|
|
// 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] ;
|
2011-09-21 12:27:07 +00:00
|
|
|
|
2011-08-16 14:24:12 +00:00
|
|
|
switch (peek()) {
|
2013-10-15 08:57:36 +00:00
|
|
|
case Token::FUNCTION:
|
2016-04-27 19:18:13 +00:00
|
|
|
return ParseHoistableDeclaration(ok);
|
2014-09-16 22:15:39 +00:00
|
|
|
case Token::CLASS:
|
|
|
|
return ParseClassDeclaration(ok);
|
2013-10-15 08:57:36 +00:00
|
|
|
case Token::CONST:
|
2016-04-08 00:29:37 +00:00
|
|
|
return ParseVariableStatement(kStatementListItem, ok);
|
2014-07-10 14:06:37 +00:00
|
|
|
case Token::LET:
|
2015-08-28 18:47:30 +00:00
|
|
|
if (IsNextLetKeyword()) {
|
2015-02-12 15:12:32 +00:00
|
|
|
return ParseVariableStatement(kStatementListItem, ok);
|
2014-07-10 14:06:37 +00:00
|
|
|
}
|
2015-07-07 21:57:09 +00:00
|
|
|
break;
|
2016-05-16 23:17:13 +00:00
|
|
|
case Token::ASYNC:
|
|
|
|
if (allow_harmony_async_await() && PeekAhead() == Token::FUNCTION &&
|
|
|
|
!scanner()->HasAnyLineTerminatorAfterNext()) {
|
|
|
|
Consume(Token::ASYNC);
|
|
|
|
return ParseAsyncFunctionDeclaration(ok);
|
|
|
|
}
|
|
|
|
/* falls through */
|
2011-08-16 14:24:12 +00:00
|
|
|
default:
|
2015-07-07 21:57:09 +00:00
|
|
|
break;
|
2011-08-16 14:24:12 +00:00
|
|
|
}
|
2016-03-24 01:57:53 +00:00
|
|
|
return ParseStatement(kAllowLabelledFunctionStatement, ok);
|
2011-08-16 14:24:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-05-06 10:21:20 +00:00
|
|
|
void PreParser::ParseStatementList(int end_token, bool* ok,
|
|
|
|
Scanner::BookmarkScope* bookmark) {
|
2010-11-23 11:46:36 +00:00
|
|
|
// SourceElements ::
|
|
|
|
// (Statement)* <end_token>
|
|
|
|
|
2015-05-06 10:21:20 +00:00
|
|
|
// Bookkeeping for trial parse if bookmark is set:
|
|
|
|
DCHECK_IMPLIES(bookmark, bookmark->HasBeenSet());
|
|
|
|
bool maybe_reset = bookmark != nullptr;
|
|
|
|
int count_statements = 0;
|
|
|
|
|
2014-02-06 13:12:10 +00:00
|
|
|
bool directive_prologue = true;
|
2010-11-23 11:46:36 +00:00
|
|
|
while (peek() != end_token) {
|
2014-02-06 13:12:10 +00:00
|
|
|
if (directive_prologue && peek() != Token::STRING) {
|
|
|
|
directive_prologue = false;
|
|
|
|
}
|
2015-05-06 10:21:20 +00:00
|
|
|
bool starts_with_identifier = peek() == Token::IDENTIFIER;
|
2015-04-22 11:04:25 +00:00
|
|
|
Scanner::Location token_loc = scanner()->peek_location();
|
2015-02-06 23:26:18 +00:00
|
|
|
Statement statement = ParseStatementListItem(ok);
|
|
|
|
if (!*ok) return;
|
2015-04-22 11:04:25 +00:00
|
|
|
|
2014-02-06 13:12:10 +00:00
|
|
|
if (directive_prologue) {
|
2015-08-26 14:59:05 +00:00
|
|
|
bool use_strict_found = statement.IsUseStrictLiteral();
|
|
|
|
|
|
|
|
if (use_strict_found) {
|
2015-02-04 09:34:05 +00:00
|
|
|
scope_->SetLanguageMode(
|
2015-07-20 14:31:30 +00:00
|
|
|
static_cast<LanguageMode>(scope_->language_mode() | STRICT));
|
2011-05-19 09:01:46 +00:00
|
|
|
} else if (!statement.IsStringLiteral()) {
|
2014-02-06 13:12:10 +00:00
|
|
|
directive_prologue = false;
|
2011-05-06 11:41:15 +00:00
|
|
|
}
|
2015-08-26 14:59:05 +00:00
|
|
|
|
2016-03-10 12:43:51 +00:00
|
|
|
if (use_strict_found && !scope_->HasSimpleParameters()) {
|
2015-08-26 14:59:05 +00:00
|
|
|
// 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
|
|
|
|
PreParserTraits::ReportMessageAt(
|
|
|
|
token_loc, MessageTemplate::kIllegalLanguageModeDirective,
|
2016-03-10 12:43:51 +00:00
|
|
|
"use strict");
|
2015-08-26 14:59:05 +00:00
|
|
|
*ok = false;
|
|
|
|
return;
|
|
|
|
}
|
2011-05-06 11:41:15 +00:00
|
|
|
}
|
2015-05-06 10:21:20 +00:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-05-19 09:01:46 +00:00
|
|
|
#define CHECK_OK ok); \
|
|
|
|
if (!*ok) return Statement::Default(); \
|
|
|
|
((void)0
|
|
|
|
#define DUMMY ) // to make indentation work
|
|
|
|
#undef DUMMY
|
|
|
|
|
2016-03-24 01:57:53 +00:00
|
|
|
PreParser::Statement PreParser::ParseStatement(
|
|
|
|
AllowLabelledFunctionStatement allow_function, bool* ok) {
|
2015-02-17 16:25:49 +00:00
|
|
|
// Statement ::
|
|
|
|
// EmptyStatement
|
|
|
|
// ...
|
2015-04-16 13:29:29 +00:00
|
|
|
|
|
|
|
if (peek() == Token::SEMICOLON) {
|
|
|
|
Next();
|
|
|
|
return Statement::Default();
|
|
|
|
}
|
2016-03-24 01:57:53 +00:00
|
|
|
return ParseSubStatement(allow_function, ok);
|
2015-02-17 16:25:49 +00:00
|
|
|
}
|
|
|
|
|
Restrict FunctionDeclarations in Statement position
ES2015 generally bans FunctionDeclarations in positions which expect a Statement,
as opposed to a StatementListItem, such as a FunctionDeclaration which constitutes
the body of a for loop. However, Annex B 3.2 and 3.4 make exceptions for labeled
function declarations and function declarations as the body of an if statement in
sloppy mode, in the latter case specifying that the semantics are as if the
function declaration occurred in a block. Chrome has historically permitted
further extensions, for the body of any flow control construct.
This patch addresses both the syntactic and semantic mismatches between V8 and
the spec. For the semantic mismatch, function declarations as the body of if
statements change from unconditionally hoisting in certain cases to acquiring
the sloppy mode function in block semantics (based on Annex B 3.3). For the
extra syntax permitted, this patch adds a flag,
--harmony-restrictive-declarations, which excludes disallowed function declaration
cases. A new UseCounter, LegacyFunctionDeclaration, is added to count how often
function declarations occur as the body of other constructs in sloppy mode. With
this patch, the code generally follows the form of the specification with respect
to parsing FunctionDeclarations, rather than allowing them in arbitrary Statement
positions, and makes it more clear where our extensions occur.
BUG=v8:4647
R=adamk
LOG=Y
Review URL: https://codereview.chromium.org/1757543003
Cr-Commit-Position: refs/heads/master@{#34470}
2016-03-03 21:33:53 +00:00
|
|
|
PreParser::Statement PreParser::ParseScopedStatement(bool legacy, bool* ok) {
|
|
|
|
if (is_strict(language_mode()) || peek() != Token::FUNCTION ||
|
|
|
|
(legacy && allow_harmony_restrictive_declarations())) {
|
2016-03-24 01:57:53 +00:00
|
|
|
return ParseSubStatement(kDisallowLabelledFunctionStatement, ok);
|
Restrict FunctionDeclarations in Statement position
ES2015 generally bans FunctionDeclarations in positions which expect a Statement,
as opposed to a StatementListItem, such as a FunctionDeclaration which constitutes
the body of a for loop. However, Annex B 3.2 and 3.4 make exceptions for labeled
function declarations and function declarations as the body of an if statement in
sloppy mode, in the latter case specifying that the semantics are as if the
function declaration occurred in a block. Chrome has historically permitted
further extensions, for the body of any flow control construct.
This patch addresses both the syntactic and semantic mismatches between V8 and
the spec. For the semantic mismatch, function declarations as the body of if
statements change from unconditionally hoisting in certain cases to acquiring
the sloppy mode function in block semantics (based on Annex B 3.3). For the
extra syntax permitted, this patch adds a flag,
--harmony-restrictive-declarations, which excludes disallowed function declaration
cases. A new UseCounter, LegacyFunctionDeclaration, is added to count how often
function declarations occur as the body of other constructs in sloppy mode. With
this patch, the code generally follows the form of the specification with respect
to parsing FunctionDeclarations, rather than allowing them in arbitrary Statement
positions, and makes it more clear where our extensions occur.
BUG=v8:4647
R=adamk
LOG=Y
Review URL: https://codereview.chromium.org/1757543003
Cr-Commit-Position: refs/heads/master@{#34470}
2016-03-03 21:33:53 +00:00
|
|
|
} else {
|
2016-04-21 13:41:07 +00:00
|
|
|
Scope* body_scope = NewScope(scope_, BLOCK_SCOPE);
|
|
|
|
BlockState block_state(&scope_, body_scope);
|
2016-05-02 22:55:09 +00:00
|
|
|
return ParseFunctionDeclaration(ok);
|
Restrict FunctionDeclarations in Statement position
ES2015 generally bans FunctionDeclarations in positions which expect a Statement,
as opposed to a StatementListItem, such as a FunctionDeclaration which constitutes
the body of a for loop. However, Annex B 3.2 and 3.4 make exceptions for labeled
function declarations and function declarations as the body of an if statement in
sloppy mode, in the latter case specifying that the semantics are as if the
function declaration occurred in a block. Chrome has historically permitted
further extensions, for the body of any flow control construct.
This patch addresses both the syntactic and semantic mismatches between V8 and
the spec. For the semantic mismatch, function declarations as the body of if
statements change from unconditionally hoisting in certain cases to acquiring
the sloppy mode function in block semantics (based on Annex B 3.3). For the
extra syntax permitted, this patch adds a flag,
--harmony-restrictive-declarations, which excludes disallowed function declaration
cases. A new UseCounter, LegacyFunctionDeclaration, is added to count how often
function declarations occur as the body of other constructs in sloppy mode. With
this patch, the code generally follows the form of the specification with respect
to parsing FunctionDeclarations, rather than allowing them in arbitrary Statement
positions, and makes it more clear where our extensions occur.
BUG=v8:4647
R=adamk
LOG=Y
Review URL: https://codereview.chromium.org/1757543003
Cr-Commit-Position: refs/heads/master@{#34470}
2016-03-03 21:33:53 +00:00
|
|
|
}
|
|
|
|
}
|
2015-02-17 16:25:49 +00:00
|
|
|
|
2016-03-24 01:57:53 +00:00
|
|
|
PreParser::Statement PreParser::ParseSubStatement(
|
|
|
|
AllowLabelledFunctionStatement allow_function, bool* ok) {
|
2010-11-23 11:46:36 +00:00
|
|
|
// 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()) {
|
2013-10-15 08:57:36 +00:00
|
|
|
case Token::LBRACE:
|
2010-11-23 11:46:36 +00:00
|
|
|
return ParseBlock(ok);
|
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
case Token::SEMICOLON:
|
2010-11-23 11:46:36 +00:00
|
|
|
Next();
|
2011-05-19 09:01:46 +00:00
|
|
|
return Statement::Default();
|
2010-11-23 11:46:36 +00:00
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
case Token::IF:
|
2011-05-19 09:01:46 +00:00
|
|
|
return ParseIfStatement(ok);
|
2010-11-23 11:46:36 +00:00
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
case Token::DO:
|
2010-11-23 11:46:36 +00:00
|
|
|
return ParseDoWhileStatement(ok);
|
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
case Token::WHILE:
|
2010-11-23 11:46:36 +00:00
|
|
|
return ParseWhileStatement(ok);
|
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
case Token::FOR:
|
2010-11-23 11:46:36 +00:00
|
|
|
return ParseForStatement(ok);
|
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
case Token::CONTINUE:
|
2010-11-23 11:46:36 +00:00
|
|
|
return ParseContinueStatement(ok);
|
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
case Token::BREAK:
|
2010-11-23 11:46:36 +00:00
|
|
|
return ParseBreakStatement(ok);
|
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
case Token::RETURN:
|
2010-11-23 11:46:36 +00:00
|
|
|
return ParseReturnStatement(ok);
|
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
case Token::WITH:
|
2010-11-23 11:46:36 +00:00
|
|
|
return ParseWithStatement(ok);
|
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
case Token::SWITCH:
|
2010-11-23 11:46:36 +00:00
|
|
|
return ParseSwitchStatement(ok);
|
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
case Token::THROW:
|
2010-11-23 11:46:36 +00:00
|
|
|
return ParseThrowStatement(ok);
|
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
case Token::TRY:
|
2010-11-23 11:46:36 +00:00
|
|
|
return ParseTryStatement(ok);
|
|
|
|
|
Restrict FunctionDeclarations in Statement position
ES2015 generally bans FunctionDeclarations in positions which expect a Statement,
as opposed to a StatementListItem, such as a FunctionDeclaration which constitutes
the body of a for loop. However, Annex B 3.2 and 3.4 make exceptions for labeled
function declarations and function declarations as the body of an if statement in
sloppy mode, in the latter case specifying that the semantics are as if the
function declaration occurred in a block. Chrome has historically permitted
further extensions, for the body of any flow control construct.
This patch addresses both the syntactic and semantic mismatches between V8 and
the spec. For the semantic mismatch, function declarations as the body of if
statements change from unconditionally hoisting in certain cases to acquiring
the sloppy mode function in block semantics (based on Annex B 3.3). For the
extra syntax permitted, this patch adds a flag,
--harmony-restrictive-declarations, which excludes disallowed function declaration
cases. A new UseCounter, LegacyFunctionDeclaration, is added to count how often
function declarations occur as the body of other constructs in sloppy mode. With
this patch, the code generally follows the form of the specification with respect
to parsing FunctionDeclarations, rather than allowing them in arbitrary Statement
positions, and makes it more clear where our extensions occur.
BUG=v8:4647
R=adamk
LOG=Y
Review URL: https://codereview.chromium.org/1757543003
Cr-Commit-Position: refs/heads/master@{#34470}
2016-03-03 21:33:53 +00:00
|
|
|
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();
|
2010-11-23 11:46:36 +00:00
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
case Token::DEBUGGER:
|
2010-11-23 11:46:36 +00:00
|
|
|
return ParseDebuggerStatement(ok);
|
|
|
|
|
2014-07-10 14:06:37 +00:00
|
|
|
case Token::VAR:
|
|
|
|
return ParseVariableStatement(kStatement, ok);
|
|
|
|
|
2010-11-23 11:46:36 +00:00
|
|
|
default:
|
2016-03-24 01:57:53 +00:00
|
|
|
return ParseExpressionOrLabelledStatement(allow_function, ok);
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-04-27 19:18:13 +00:00
|
|
|
PreParser::Statement PreParser::ParseHoistableDeclaration(
|
2016-05-16 23:17:13 +00:00
|
|
|
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);
|
|
|
|
|
2014-02-07 10:47:01 +00:00
|
|
|
bool is_strict_reserved = false;
|
|
|
|
Identifier name = ParseIdentifierOrStrictReservedWord(
|
|
|
|
&is_strict_reserved, CHECK_OK);
|
2016-05-16 23:17:13 +00:00
|
|
|
|
|
|
|
if (V8_UNLIKELY(is_async_function() && this->IsAwait(name))) {
|
|
|
|
ReportMessageAt(scanner()->location(),
|
|
|
|
MessageTemplate::kAwaitBindingIdentifier);
|
|
|
|
*ok = false;
|
|
|
|
return Statement::Default();
|
|
|
|
}
|
|
|
|
|
2015-07-09 21:31:11 +00:00
|
|
|
ParseFunctionLiteral(name, scanner()->location(),
|
|
|
|
is_strict_reserved ? kFunctionNameIsStrictReserved
|
|
|
|
: kFunctionNameValidityUnknown,
|
2014-09-10 16:39:42 +00:00
|
|
|
is_generator ? FunctionKind::kGeneratorFunction
|
2016-05-16 23:17:13 +00:00
|
|
|
: is_async ? FunctionKind::kAsyncFunction
|
|
|
|
: FunctionKind::kNormalFunction,
|
2016-02-19 02:50:58 +00:00
|
|
|
pos, FunctionLiteral::kDeclaration, language_mode(),
|
2015-07-15 09:14:49 +00:00
|
|
|
CHECK_OK);
|
2011-05-24 14:02:59 +00:00
|
|
|
return Statement::FunctionDeclaration();
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
|
2016-05-16 23:17:13 +00:00
|
|
|
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);
|
|
|
|
}
|
2010-11-23 11:46:36 +00:00
|
|
|
|
2016-04-27 19:18:13 +00:00
|
|
|
PreParser::Statement PreParser::ParseHoistableDeclaration(bool* ok) {
|
|
|
|
// FunctionDeclaration ::
|
|
|
|
// 'function' Identifier '(' FormalParameterListopt ')' '{' FunctionBody '}'
|
|
|
|
// GeneratorDeclaration ::
|
|
|
|
// 'function' '*' Identifier '(' FormalParameterListopt ')'
|
|
|
|
// '{' FunctionBody '}'
|
2016-05-16 23:17:13 +00:00
|
|
|
|
2016-04-27 19:18:13 +00:00
|
|
|
Expect(Token::FUNCTION, CHECK_OK);
|
|
|
|
int pos = position();
|
2016-05-16 23:17:13 +00:00
|
|
|
ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
|
|
|
|
if (Check(Token::MUL)) {
|
|
|
|
flags |= ParseFunctionFlags::kIsGenerator;
|
|
|
|
}
|
|
|
|
return ParseHoistableDeclaration(pos, flags, ok);
|
2016-04-27 19:18:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-09-16 22:15:39 +00:00
|
|
|
PreParser::Statement PreParser::ParseClassDeclaration(bool* ok) {
|
|
|
|
Expect(Token::CLASS, CHECK_OK);
|
2014-11-20 10:51:49 +00:00
|
|
|
|
2014-09-16 22:15:39 +00:00
|
|
|
int pos = position();
|
|
|
|
bool is_strict_reserved = false;
|
|
|
|
Identifier name =
|
|
|
|
ParseIdentifierOrStrictReservedWord(&is_strict_reserved, CHECK_OK);
|
2016-05-03 01:55:27 +00:00
|
|
|
ParseClassLiteral(nullptr, name, scanner()->location(), is_strict_reserved,
|
|
|
|
pos, CHECK_OK);
|
2014-09-16 22:15:39 +00:00
|
|
|
return Statement::Default();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-29 13:24:37 +00:00
|
|
|
PreParser::Statement PreParser::ParseBlock(bool* ok) {
|
2010-11-23 11:46:36 +00:00
|
|
|
// Block ::
|
2015-11-12 17:41:27 +00:00
|
|
|
// '{' StatementList '}'
|
2010-11-23 11:46:36 +00:00
|
|
|
|
2016-04-21 13:41:07 +00:00
|
|
|
Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::LBRACE, CHECK_OK);
|
2015-04-16 13:29:29 +00:00
|
|
|
Statement final = Statement::Default();
|
2016-04-21 13:41:07 +00:00
|
|
|
{
|
|
|
|
BlockState block_state(&scope_, block_scope);
|
|
|
|
while (peek() != Token::RBRACE) {
|
|
|
|
final = ParseStatementListItem(CHECK_OK);
|
|
|
|
}
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::RBRACE, ok);
|
2015-04-16 13:29:29 +00:00
|
|
|
return final;
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-08-16 14:24:12 +00:00
|
|
|
PreParser::Statement PreParser::ParseVariableStatement(
|
|
|
|
VariableDeclarationContext var_context,
|
|
|
|
bool* ok) {
|
2010-11-23 11:46:36 +00:00
|
|
|
// VariableStatement ::
|
|
|
|
// VariableDeclarations ';'
|
|
|
|
|
2015-11-25 01:14:58 +00:00
|
|
|
Statement result = ParseVariableDeclarations(
|
|
|
|
var_context, nullptr, nullptr, nullptr, nullptr, nullptr, CHECK_OK);
|
2010-11-23 11:46:36 +00:00
|
|
|
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.
|
2011-08-16 14:24:12 +00:00
|
|
|
PreParser::Statement PreParser::ParseVariableDeclarations(
|
2015-11-25 01:14:58 +00:00
|
|
|
VariableDeclarationContext var_context, int* num_decl, bool* is_lexical,
|
|
|
|
bool* is_binding_pattern, Scanner::Location* first_initializer_loc,
|
|
|
|
Scanner::Location* bindings_loc, bool* ok) {
|
2010-11-23 11:46:36 +00:00
|
|
|
// VariableDeclarations ::
|
|
|
|
// ('var' | 'const') (Identifier ('=' AssignmentExpression)?)+[',']
|
2011-10-25 08:33:08 +00:00
|
|
|
//
|
|
|
|
// 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;
|
2015-10-05 20:28:45 +00:00
|
|
|
bool lexical = false;
|
2015-11-25 01:14:58 +00:00
|
|
|
bool is_pattern = false;
|
2013-10-15 08:57:36 +00:00
|
|
|
if (peek() == Token::VAR) {
|
|
|
|
Consume(Token::VAR);
|
2016-04-08 00:29:37 +00:00
|
|
|
} else if (peek() == Token::CONST) {
|
2011-11-29 06:38:04 +00:00
|
|
|
// 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.
|
|
|
|
//
|
2014-03-11 14:39:08 +00:00
|
|
|
// However disallowing const in sloppy mode will break compatibility with
|
2011-11-29 06:38:04 +00:00
|
|
|
// existing pages. Therefore we keep allowing const with the old
|
2014-03-11 14:39:08 +00:00
|
|
|
// non-harmony semantics in sloppy mode.
|
2013-10-15 08:57:36 +00:00
|
|
|
Consume(Token::CONST);
|
2016-04-08 00:29:37 +00:00
|
|
|
DCHECK(var_context != kStatement);
|
|
|
|
require_initializer = true;
|
|
|
|
lexical = true;
|
|
|
|
} else if (peek() == Token::LET) {
|
2013-10-15 08:57:36 +00:00
|
|
|
Consume(Token::LET);
|
2015-01-30 03:09:57 +00:00
|
|
|
DCHECK(var_context != kStatement);
|
2015-10-05 20:28:45 +00:00
|
|
|
lexical = true;
|
2010-11-23 11:46:36 +00:00
|
|
|
} else {
|
|
|
|
*ok = false;
|
2011-05-19 09:01:46 +00:00
|
|
|
return Statement::Default();
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
|
2011-08-16 14:24:12 +00:00
|
|
|
// 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.
|
2010-11-23 11:46:36 +00:00
|
|
|
int nvars = 0; // the number of variables declared
|
2015-04-08 18:47:36 +00:00
|
|
|
int bindings_start = peek_position();
|
2010-11-23 11:46:36 +00:00
|
|
|
do {
|
2015-04-28 15:15:03 +00:00
|
|
|
// Parse binding pattern.
|
2013-10-15 08:57:36 +00:00
|
|
|
if (nvars > 0) Consume(Token::COMMA);
|
2015-11-04 19:26:13 +00:00
|
|
|
int decl_pos = peek_position();
|
|
|
|
PreParserExpression pattern = PreParserExpression::Default();
|
2015-04-27 14:35:45 +00:00
|
|
|
{
|
2016-02-19 15:58:57 +00:00
|
|
|
ExpressionClassifier pattern_classifier(this);
|
2015-11-04 19:26:13 +00:00
|
|
|
pattern = ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
|
|
|
|
|
2015-04-27 14:35:45 +00:00
|
|
|
ValidateBindingPattern(&pattern_classifier, CHECK_OK);
|
2015-10-05 20:28:45 +00:00
|
|
|
if (lexical) {
|
|
|
|
ValidateLetPattern(&pattern_classifier, CHECK_OK);
|
|
|
|
}
|
2015-04-27 14:35:45 +00:00
|
|
|
}
|
2015-04-28 15:15:03 +00:00
|
|
|
|
2016-02-04 18:43:55 +00:00
|
|
|
is_pattern = pattern.IsObjectLiteral() || pattern.IsArrayLiteral();
|
2015-11-04 19:26:13 +00:00
|
|
|
|
2015-04-07 19:28:33 +00:00
|
|
|
Scanner::Location variable_loc = scanner()->location();
|
2010-11-23 11:46:36 +00:00
|
|
|
nvars++;
|
2015-11-04 19:26:13 +00:00
|
|
|
if (Check(Token::ASSIGN)) {
|
2016-02-19 15:58:57 +00:00
|
|
|
ExpressionClassifier classifier(this);
|
2015-04-22 12:35:05 +00:00
|
|
|
ParseAssignmentExpression(var_context != kForStatement, &classifier,
|
|
|
|
CHECK_OK);
|
2015-04-27 14:35:45 +00:00
|
|
|
ValidateExpression(&classifier, CHECK_OK);
|
2015-04-07 19:28:33 +00:00
|
|
|
|
|
|
|
variable_loc.end_pos = scanner()->location().end_pos;
|
|
|
|
if (first_initializer_loc && !first_initializer_loc->IsValid()) {
|
|
|
|
*first_initializer_loc = variable_loc;
|
|
|
|
}
|
2015-11-04 19:26:13 +00:00
|
|
|
} else if ((require_initializer || is_pattern) &&
|
2016-02-04 18:43:55 +00:00
|
|
|
(var_context != kForStatement || !PeekInOrOf())) {
|
2015-11-04 19:26:13 +00:00
|
|
|
PreParserTraits::ReportMessageAt(
|
|
|
|
Scanner::Location(decl_pos, scanner()->location().end_pos),
|
|
|
|
MessageTemplate::kDeclarationMissingInitializer,
|
|
|
|
is_pattern ? "destructuring" : "const");
|
|
|
|
*ok = false;
|
|
|
|
return Statement::Default();
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
2013-10-15 08:57:36 +00:00
|
|
|
} while (peek() == Token::COMMA);
|
2010-11-23 11:46:36 +00:00
|
|
|
|
2015-04-08 18:47:36 +00:00
|
|
|
if (bindings_loc) {
|
|
|
|
*bindings_loc =
|
|
|
|
Scanner::Location(bindings_start, scanner()->location().end_pos);
|
|
|
|
}
|
|
|
|
|
2015-11-25 01:14:58 +00:00
|
|
|
if (num_decl != nullptr) *num_decl = nvars;
|
|
|
|
if (is_lexical != nullptr) *is_lexical = lexical;
|
|
|
|
if (is_binding_pattern != nullptr) *is_binding_pattern = is_pattern;
|
2011-05-19 09:01:46 +00:00
|
|
|
return Statement::Default();
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
|
2016-04-27 19:18:13 +00:00
|
|
|
PreParser::Statement PreParser::ParseFunctionDeclaration(bool* ok) {
|
|
|
|
Consume(Token::FUNCTION);
|
|
|
|
int pos = position();
|
2016-05-16 23:17:13 +00:00
|
|
|
ParseFunctionFlags flags = ParseFunctionFlags::kIsNormal;
|
|
|
|
if (Check(Token::MUL)) {
|
|
|
|
flags |= ParseFunctionFlags::kIsGenerator;
|
|
|
|
if (allow_harmony_restrictive_declarations()) {
|
|
|
|
PreParserTraits::ReportMessageAt(
|
|
|
|
scanner()->location(), MessageTemplate::kGeneratorInLegacyContext);
|
|
|
|
*ok = false;
|
|
|
|
return Statement::Default();
|
|
|
|
}
|
2016-04-27 19:18:13 +00:00
|
|
|
}
|
2016-05-16 23:17:13 +00:00
|
|
|
return ParseHoistableDeclaration(pos, flags, ok);
|
2016-04-27 19:18:13 +00:00
|
|
|
}
|
|
|
|
|
2016-03-24 01:57:53 +00:00
|
|
|
PreParser::Statement PreParser::ParseExpressionOrLabelledStatement(
|
|
|
|
AllowLabelledFunctionStatement allow_function, bool* ok) {
|
2010-11-23 11:46:36 +00:00
|
|
|
// ExpressionStatement | LabelledStatement ::
|
|
|
|
// Expression ';'
|
|
|
|
// Identifier ':' Statement
|
|
|
|
|
2015-01-30 03:09:57 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2014-02-06 13:12:10 +00:00
|
|
|
bool starts_with_identifier = peek_any_identifier();
|
2016-02-19 15:58:57 +00:00
|
|
|
ExpressionClassifier classifier(this);
|
2015-04-22 12:35:05 +00:00
|
|
|
Expression expr = ParseExpression(true, &classifier, CHECK_OK);
|
2015-04-27 14:35:45 +00:00
|
|
|
ValidateExpression(&classifier, CHECK_OK);
|
2015-04-22 12:35:05 +00:00
|
|
|
|
2014-02-06 13:12:10 +00:00
|
|
|
// 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.
|
2016-04-29 18:12:57 +00:00
|
|
|
DCHECK(!expr.AsIdentifier().IsEnum());
|
|
|
|
DCHECK(!parsing_module_ || !expr.AsIdentifier().IsAwait());
|
2015-02-04 09:34:05 +00:00
|
|
|
DCHECK(is_sloppy(language_mode()) ||
|
2014-11-03 19:53:36 +00:00
|
|
|
!IsFutureStrictReserved(expr.AsIdentifier()));
|
2014-02-06 13:12:10 +00:00
|
|
|
Consume(Token::COLON);
|
Restrict FunctionDeclarations in Statement position
ES2015 generally bans FunctionDeclarations in positions which expect a Statement,
as opposed to a StatementListItem, such as a FunctionDeclaration which constitutes
the body of a for loop. However, Annex B 3.2 and 3.4 make exceptions for labeled
function declarations and function declarations as the body of an if statement in
sloppy mode, in the latter case specifying that the semantics are as if the
function declaration occurred in a block. Chrome has historically permitted
further extensions, for the body of any flow control construct.
This patch addresses both the syntactic and semantic mismatches between V8 and
the spec. For the semantic mismatch, function declarations as the body of if
statements change from unconditionally hoisting in certain cases to acquiring
the sloppy mode function in block semantics (based on Annex B 3.3). For the
extra syntax permitted, this patch adds a flag,
--harmony-restrictive-declarations, which excludes disallowed function declaration
cases. A new UseCounter, LegacyFunctionDeclaration, is added to count how often
function declarations occur as the body of other constructs in sloppy mode. With
this patch, the code generally follows the form of the specification with respect
to parsing FunctionDeclarations, rather than allowing them in arbitrary Statement
positions, and makes it more clear where our extensions occur.
BUG=v8:4647
R=adamk
LOG=Y
Review URL: https://codereview.chromium.org/1757543003
Cr-Commit-Position: refs/heads/master@{#34470}
2016-03-03 21:33:53 +00:00
|
|
|
// ES#sec-labelled-function-declarations Labelled Function Declarations
|
|
|
|
if (peek() == Token::FUNCTION && is_sloppy(language_mode())) {
|
2016-03-24 01:57:53 +00:00
|
|
|
if (allow_function == kAllowLabelledFunctionStatement) {
|
|
|
|
return ParseFunctionDeclaration(ok);
|
|
|
|
} else {
|
|
|
|
return ParseScopedStatement(true, ok);
|
|
|
|
}
|
Restrict FunctionDeclarations in Statement position
ES2015 generally bans FunctionDeclarations in positions which expect a Statement,
as opposed to a StatementListItem, such as a FunctionDeclaration which constitutes
the body of a for loop. However, Annex B 3.2 and 3.4 make exceptions for labeled
function declarations and function declarations as the body of an if statement in
sloppy mode, in the latter case specifying that the semantics are as if the
function declaration occurred in a block. Chrome has historically permitted
further extensions, for the body of any flow control construct.
This patch addresses both the syntactic and semantic mismatches between V8 and
the spec. For the semantic mismatch, function declarations as the body of if
statements change from unconditionally hoisting in certain cases to acquiring
the sloppy mode function in block semantics (based on Annex B 3.3). For the
extra syntax permitted, this patch adds a flag,
--harmony-restrictive-declarations, which excludes disallowed function declaration
cases. A new UseCounter, LegacyFunctionDeclaration, is added to count how often
function declarations occur as the body of other constructs in sloppy mode. With
this patch, the code generally follows the form of the specification with respect
to parsing FunctionDeclarations, rather than allowing them in arbitrary Statement
positions, and makes it more clear where our extensions occur.
BUG=v8:4647
R=adamk
LOG=Y
Review URL: https://codereview.chromium.org/1757543003
Cr-Commit-Position: refs/heads/master@{#34470}
2016-03-03 21:33:53 +00:00
|
|
|
}
|
2016-03-24 01:57:53 +00:00
|
|
|
Statement statement =
|
|
|
|
ParseStatement(kDisallowLabelledFunctionStatement, ok);
|
2015-04-16 13:29:29 +00:00
|
|
|
return statement.IsJumpStatement() ? Statement::Default() : statement;
|
2011-06-20 10:20:57 +00:00
|
|
|
// 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.
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
// Parsed expression statement.
|
|
|
|
ExpectSemicolon(CHECK_OK);
|
2011-05-19 09:01:46 +00:00
|
|
|
return Statement::ExpressionStatement(expr);
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-29 13:24:37 +00:00
|
|
|
PreParser::Statement PreParser::ParseIfStatement(bool* ok) {
|
2010-11-23 11:46:36 +00:00
|
|
|
// IfStatement ::
|
|
|
|
// 'if' '(' Expression ')' Statement ('else' Statement)?
|
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::IF, CHECK_OK);
|
|
|
|
Expect(Token::LPAREN, CHECK_OK);
|
2010-11-23 11:46:36 +00:00
|
|
|
ParseExpression(true, CHECK_OK);
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::RPAREN, CHECK_OK);
|
Restrict FunctionDeclarations in Statement position
ES2015 generally bans FunctionDeclarations in positions which expect a Statement,
as opposed to a StatementListItem, such as a FunctionDeclaration which constitutes
the body of a for loop. However, Annex B 3.2 and 3.4 make exceptions for labeled
function declarations and function declarations as the body of an if statement in
sloppy mode, in the latter case specifying that the semantics are as if the
function declaration occurred in a block. Chrome has historically permitted
further extensions, for the body of any flow control construct.
This patch addresses both the syntactic and semantic mismatches between V8 and
the spec. For the semantic mismatch, function declarations as the body of if
statements change from unconditionally hoisting in certain cases to acquiring
the sloppy mode function in block semantics (based on Annex B 3.3). For the
extra syntax permitted, this patch adds a flag,
--harmony-restrictive-declarations, which excludes disallowed function declaration
cases. A new UseCounter, LegacyFunctionDeclaration, is added to count how often
function declarations occur as the body of other constructs in sloppy mode. With
this patch, the code generally follows the form of the specification with respect
to parsing FunctionDeclarations, rather than allowing them in arbitrary Statement
positions, and makes it more clear where our extensions occur.
BUG=v8:4647
R=adamk
LOG=Y
Review URL: https://codereview.chromium.org/1757543003
Cr-Commit-Position: refs/heads/master@{#34470}
2016-03-03 21:33:53 +00:00
|
|
|
Statement stat = ParseScopedStatement(false, CHECK_OK);
|
2013-10-15 08:57:36 +00:00
|
|
|
if (peek() == Token::ELSE) {
|
2010-11-23 11:46:36 +00:00
|
|
|
Next();
|
Restrict FunctionDeclarations in Statement position
ES2015 generally bans FunctionDeclarations in positions which expect a Statement,
as opposed to a StatementListItem, such as a FunctionDeclaration which constitutes
the body of a for loop. However, Annex B 3.2 and 3.4 make exceptions for labeled
function declarations and function declarations as the body of an if statement in
sloppy mode, in the latter case specifying that the semantics are as if the
function declaration occurred in a block. Chrome has historically permitted
further extensions, for the body of any flow control construct.
This patch addresses both the syntactic and semantic mismatches between V8 and
the spec. For the semantic mismatch, function declarations as the body of if
statements change from unconditionally hoisting in certain cases to acquiring
the sloppy mode function in block semantics (based on Annex B 3.3). For the
extra syntax permitted, this patch adds a flag,
--harmony-restrictive-declarations, which excludes disallowed function declaration
cases. A new UseCounter, LegacyFunctionDeclaration, is added to count how often
function declarations occur as the body of other constructs in sloppy mode. With
this patch, the code generally follows the form of the specification with respect
to parsing FunctionDeclarations, rather than allowing them in arbitrary Statement
positions, and makes it more clear where our extensions occur.
BUG=v8:4647
R=adamk
LOG=Y
Review URL: https://codereview.chromium.org/1757543003
Cr-Commit-Position: refs/heads/master@{#34470}
2016-03-03 21:33:53 +00:00
|
|
|
Statement else_stat = ParseScopedStatement(false, CHECK_OK);
|
2015-04-16 13:29:29 +00:00
|
|
|
stat = (stat.IsJumpStatement() && else_stat.IsJumpStatement()) ?
|
|
|
|
Statement::Jump() : Statement::Default();
|
|
|
|
} else {
|
|
|
|
stat = Statement::Default();
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
2015-04-16 13:29:29 +00:00
|
|
|
return stat;
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-29 13:24:37 +00:00
|
|
|
PreParser::Statement PreParser::ParseContinueStatement(bool* ok) {
|
2010-11-23 11:46:36 +00:00
|
|
|
// ContinueStatement ::
|
|
|
|
// 'continue' [no line terminator] Identifier? ';'
|
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::CONTINUE, CHECK_OK);
|
|
|
|
Token::Value tok = peek();
|
2013-10-14 16:46:51 +00:00
|
|
|
if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
|
2013-10-15 08:57:36 +00:00
|
|
|
tok != Token::SEMICOLON &&
|
|
|
|
tok != Token::RBRACE &&
|
|
|
|
tok != Token::EOS) {
|
2014-02-05 16:26:48 +00:00
|
|
|
// ECMA allows "eval" or "arguments" as labels even in strict mode.
|
2015-04-10 12:04:51 +00:00
|
|
|
ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
ExpectSemicolon(CHECK_OK);
|
2015-04-16 13:29:29 +00:00
|
|
|
return Statement::Jump();
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-29 13:24:37 +00:00
|
|
|
PreParser::Statement PreParser::ParseBreakStatement(bool* ok) {
|
2010-11-23 11:46:36 +00:00
|
|
|
// BreakStatement ::
|
|
|
|
// 'break' [no line terminator] Identifier? ';'
|
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::BREAK, CHECK_OK);
|
|
|
|
Token::Value tok = peek();
|
2013-10-14 16:46:51 +00:00
|
|
|
if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
|
2013-10-15 08:57:36 +00:00
|
|
|
tok != Token::SEMICOLON &&
|
|
|
|
tok != Token::RBRACE &&
|
|
|
|
tok != Token::EOS) {
|
2014-02-05 16:26:48 +00:00
|
|
|
// ECMA allows "eval" or "arguments" as labels even in strict mode.
|
2015-04-10 12:04:51 +00:00
|
|
|
ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
ExpectSemicolon(CHECK_OK);
|
2015-04-16 13:29:29 +00:00
|
|
|
return Statement::Jump();
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-29 13:24:37 +00:00
|
|
|
PreParser::Statement PreParser::ParseReturnStatement(bool* ok) {
|
2010-11-23 11:46:36 +00:00
|
|
|
// ReturnStatement ::
|
|
|
|
// 'return' [no line terminator] Expression? ';'
|
|
|
|
|
2014-04-02 12:38:01 +00:00
|
|
|
// Consume the return token. It is necessary to do before
|
2010-11-23 11:46:36 +00:00
|
|
|
// reporting any errors on it, because of the way errors are
|
|
|
|
// reported (underlining).
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::RETURN, CHECK_OK);
|
2015-03-19 19:39:53 +00:00
|
|
|
function_state_->set_return_location(scanner()->location());
|
2010-11-23 11:46:36 +00:00
|
|
|
|
|
|
|
// 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.
|
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
Token::Value tok = peek();
|
2013-10-14 16:46:51 +00:00
|
|
|
if (!scanner()->HasAnyLineTerminatorBeforeNext() &&
|
2013-10-15 08:57:36 +00:00
|
|
|
tok != Token::SEMICOLON &&
|
|
|
|
tok != Token::RBRACE &&
|
|
|
|
tok != Token::EOS) {
|
2016-05-04 13:42:52 +00:00
|
|
|
// 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);
|
2010-11-23 11:46:36 +00:00
|
|
|
ParseExpression(true, CHECK_OK);
|
|
|
|
}
|
|
|
|
ExpectSemicolon(CHECK_OK);
|
2015-04-16 13:29:29 +00:00
|
|
|
return Statement::Jump();
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-29 13:24:37 +00:00
|
|
|
PreParser::Statement PreParser::ParseWithStatement(bool* ok) {
|
2010-11-23 11:46:36 +00:00
|
|
|
// WithStatement ::
|
|
|
|
// 'with' '(' Expression ')' Statement
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::WITH, CHECK_OK);
|
2015-02-04 09:34:05 +00:00
|
|
|
if (is_strict(language_mode())) {
|
2015-05-18 08:34:05 +00:00
|
|
|
ReportMessageAt(scanner()->location(), MessageTemplate::kStrictWith);
|
2011-05-19 09:01:46 +00:00
|
|
|
*ok = false;
|
|
|
|
return Statement::Default();
|
|
|
|
}
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::LPAREN, CHECK_OK);
|
2010-11-23 11:46:36 +00:00
|
|
|
ParseExpression(true, CHECK_OK);
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::RPAREN, CHECK_OK);
|
2010-11-23 11:46:36 +00:00
|
|
|
|
2015-02-10 13:27:08 +00:00
|
|
|
Scope* with_scope = NewScope(scope_, WITH_SCOPE);
|
|
|
|
BlockState block_state(&scope_, with_scope);
|
Restrict FunctionDeclarations in Statement position
ES2015 generally bans FunctionDeclarations in positions which expect a Statement,
as opposed to a StatementListItem, such as a FunctionDeclaration which constitutes
the body of a for loop. However, Annex B 3.2 and 3.4 make exceptions for labeled
function declarations and function declarations as the body of an if statement in
sloppy mode, in the latter case specifying that the semantics are as if the
function declaration occurred in a block. Chrome has historically permitted
further extensions, for the body of any flow control construct.
This patch addresses both the syntactic and semantic mismatches between V8 and
the spec. For the semantic mismatch, function declarations as the body of if
statements change from unconditionally hoisting in certain cases to acquiring
the sloppy mode function in block semantics (based on Annex B 3.3). For the
extra syntax permitted, this patch adds a flag,
--harmony-restrictive-declarations, which excludes disallowed function declaration
cases. A new UseCounter, LegacyFunctionDeclaration, is added to count how often
function declarations occur as the body of other constructs in sloppy mode. With
this patch, the code generally follows the form of the specification with respect
to parsing FunctionDeclarations, rather than allowing them in arbitrary Statement
positions, and makes it more clear where our extensions occur.
BUG=v8:4647
R=adamk
LOG=Y
Review URL: https://codereview.chromium.org/1757543003
Cr-Commit-Position: refs/heads/master@{#34470}
2016-03-03 21:33:53 +00:00
|
|
|
ParseScopedStatement(true, CHECK_OK);
|
2011-05-19 09:01:46 +00:00
|
|
|
return Statement::Default();
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-29 13:24:37 +00:00
|
|
|
PreParser::Statement PreParser::ParseSwitchStatement(bool* ok) {
|
2010-11-23 11:46:36 +00:00
|
|
|
// SwitchStatement ::
|
|
|
|
// 'switch' '(' Expression ')' '{' CaseClause* '}'
|
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::SWITCH, CHECK_OK);
|
|
|
|
Expect(Token::LPAREN, CHECK_OK);
|
2010-11-23 11:46:36 +00:00
|
|
|
ParseExpression(true, CHECK_OK);
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::RPAREN, CHECK_OK);
|
2010-11-23 11:46:36 +00:00
|
|
|
|
2016-04-21 13:41:07 +00:00
|
|
|
Scope* cases_scope = NewScope(scope_, BLOCK_SCOPE);
|
|
|
|
{
|
|
|
|
BlockState cases_block_state(&scope_, cases_scope);
|
|
|
|
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);
|
2012-07-11 07:47:29 +00:00
|
|
|
token = peek();
|
2016-04-21 13:41:07 +00:00
|
|
|
Statement statement = Statement::Jump();
|
|
|
|
while (token != Token::CASE &&
|
|
|
|
token != Token::DEFAULT &&
|
|
|
|
token != Token::RBRACE) {
|
|
|
|
statement = ParseStatementListItem(CHECK_OK);
|
|
|
|
token = peek();
|
|
|
|
}
|
2012-07-11 07:47:29 +00:00
|
|
|
}
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::RBRACE, ok);
|
2011-05-19 09:01:46 +00:00
|
|
|
return Statement::Default();
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-29 13:24:37 +00:00
|
|
|
PreParser::Statement PreParser::ParseDoWhileStatement(bool* ok) {
|
2010-11-23 11:46:36 +00:00
|
|
|
// DoStatement ::
|
|
|
|
// 'do' Statement 'while' '(' Expression ')' ';'
|
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::DO, CHECK_OK);
|
Restrict FunctionDeclarations in Statement position
ES2015 generally bans FunctionDeclarations in positions which expect a Statement,
as opposed to a StatementListItem, such as a FunctionDeclaration which constitutes
the body of a for loop. However, Annex B 3.2 and 3.4 make exceptions for labeled
function declarations and function declarations as the body of an if statement in
sloppy mode, in the latter case specifying that the semantics are as if the
function declaration occurred in a block. Chrome has historically permitted
further extensions, for the body of any flow control construct.
This patch addresses both the syntactic and semantic mismatches between V8 and
the spec. For the semantic mismatch, function declarations as the body of if
statements change from unconditionally hoisting in certain cases to acquiring
the sloppy mode function in block semantics (based on Annex B 3.3). For the
extra syntax permitted, this patch adds a flag,
--harmony-restrictive-declarations, which excludes disallowed function declaration
cases. A new UseCounter, LegacyFunctionDeclaration, is added to count how often
function declarations occur as the body of other constructs in sloppy mode. With
this patch, the code generally follows the form of the specification with respect
to parsing FunctionDeclarations, rather than allowing them in arbitrary Statement
positions, and makes it more clear where our extensions occur.
BUG=v8:4647
R=adamk
LOG=Y
Review URL: https://codereview.chromium.org/1757543003
Cr-Commit-Position: refs/heads/master@{#34470}
2016-03-03 21:33:53 +00:00
|
|
|
ParseScopedStatement(true, CHECK_OK);
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::WHILE, CHECK_OK);
|
|
|
|
Expect(Token::LPAREN, CHECK_OK);
|
2010-11-23 11:46:36 +00:00
|
|
|
ParseExpression(true, CHECK_OK);
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::RPAREN, ok);
|
|
|
|
if (peek() == Token::SEMICOLON) Consume(Token::SEMICOLON);
|
2011-05-19 09:01:46 +00:00
|
|
|
return Statement::Default();
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-29 13:24:37 +00:00
|
|
|
PreParser::Statement PreParser::ParseWhileStatement(bool* ok) {
|
2010-11-23 11:46:36 +00:00
|
|
|
// WhileStatement ::
|
|
|
|
// 'while' '(' Expression ')' Statement
|
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::WHILE, CHECK_OK);
|
|
|
|
Expect(Token::LPAREN, CHECK_OK);
|
2010-11-23 11:46:36 +00:00
|
|
|
ParseExpression(true, CHECK_OK);
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::RPAREN, CHECK_OK);
|
Restrict FunctionDeclarations in Statement position
ES2015 generally bans FunctionDeclarations in positions which expect a Statement,
as opposed to a StatementListItem, such as a FunctionDeclaration which constitutes
the body of a for loop. However, Annex B 3.2 and 3.4 make exceptions for labeled
function declarations and function declarations as the body of an if statement in
sloppy mode, in the latter case specifying that the semantics are as if the
function declaration occurred in a block. Chrome has historically permitted
further extensions, for the body of any flow control construct.
This patch addresses both the syntactic and semantic mismatches between V8 and
the spec. For the semantic mismatch, function declarations as the body of if
statements change from unconditionally hoisting in certain cases to acquiring
the sloppy mode function in block semantics (based on Annex B 3.3). For the
extra syntax permitted, this patch adds a flag,
--harmony-restrictive-declarations, which excludes disallowed function declaration
cases. A new UseCounter, LegacyFunctionDeclaration, is added to count how often
function declarations occur as the body of other constructs in sloppy mode. With
this patch, the code generally follows the form of the specification with respect
to parsing FunctionDeclarations, rather than allowing them in arbitrary Statement
positions, and makes it more clear where our extensions occur.
BUG=v8:4647
R=adamk
LOG=Y
Review URL: https://codereview.chromium.org/1757543003
Cr-Commit-Position: refs/heads/master@{#34470}
2016-03-03 21:33:53 +00:00
|
|
|
ParseScopedStatement(true, ok);
|
2011-05-19 09:01:46 +00:00
|
|
|
return Statement::Default();
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-29 13:24:37 +00:00
|
|
|
PreParser::Statement PreParser::ParseForStatement(bool* ok) {
|
2010-11-23 11:46:36 +00:00
|
|
|
// ForStatement ::
|
|
|
|
// 'for' '(' Expression? ';' Expression? ';' Expression? ')' Statement
|
|
|
|
|
2016-04-21 13:41:07 +00:00
|
|
|
// Create an in-between scope for let-bound iteration variables.
|
|
|
|
Scope* for_scope = NewScope(scope_, BLOCK_SCOPE);
|
|
|
|
bool has_lexical = false;
|
|
|
|
|
|
|
|
BlockState block_state(&scope_, for_scope);
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::FOR, CHECK_OK);
|
|
|
|
Expect(Token::LPAREN, CHECK_OK);
|
|
|
|
if (peek() != Token::SEMICOLON) {
|
2015-04-07 19:28:33 +00:00
|
|
|
ForEachStatement::VisitMode mode;
|
2016-04-08 00:29:37 +00:00
|
|
|
if (peek() == Token::VAR || peek() == Token::CONST ||
|
2015-08-28 18:47:30 +00:00
|
|
|
(peek() == Token::LET && IsNextLetKeyword())) {
|
2010-11-23 11:46:36 +00:00
|
|
|
int decl_count;
|
2015-11-25 01:14:58 +00:00
|
|
|
bool is_lexical;
|
|
|
|
bool is_binding_pattern;
|
2015-04-07 19:28:33 +00:00
|
|
|
Scanner::Location first_initializer_loc = Scanner::Location::invalid();
|
2015-04-08 18:47:36 +00:00
|
|
|
Scanner::Location bindings_loc = Scanner::Location::invalid();
|
2015-11-25 01:14:58 +00:00
|
|
|
ParseVariableDeclarations(kForStatement, &decl_count, &is_lexical,
|
|
|
|
&is_binding_pattern, &first_initializer_loc,
|
|
|
|
&bindings_loc, CHECK_OK);
|
2016-04-21 13:41:07 +00:00
|
|
|
if (is_lexical) has_lexical = true;
|
2016-02-04 18:39:05 +00:00
|
|
|
if (CheckInOrOf(&mode, ok)) {
|
2015-02-19 13:50:33 +00:00
|
|
|
if (!*ok) return Statement::Default();
|
2015-04-08 18:47:36 +00:00
|
|
|
if (decl_count != 1) {
|
|
|
|
PreParserTraits::ReportMessageAt(
|
2015-05-18 08:34:05 +00:00
|
|
|
bindings_loc, MessageTemplate::kForInOfLoopMultiBindings,
|
2016-02-04 18:39:05 +00:00
|
|
|
ForEachStatement::VisitModeString(mode));
|
2015-04-08 18:47:36 +00:00
|
|
|
*ok = false;
|
|
|
|
return Statement::Default();
|
|
|
|
}
|
2015-04-07 19:28:33 +00:00
|
|
|
if (first_initializer_loc.IsValid() &&
|
2015-11-25 01:14:58 +00:00
|
|
|
(is_strict(language_mode()) || mode == ForEachStatement::ITERATE ||
|
2016-04-26 00:29:37 +00:00
|
|
|
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];
|
|
|
|
}
|
2016-02-04 18:39:05 +00:00
|
|
|
PreParserTraits::ReportMessageAt(
|
|
|
|
first_initializer_loc, MessageTemplate::kForInOfLoopInitializer,
|
|
|
|
ForEachStatement::VisitModeString(mode));
|
2015-04-07 19:28:33 +00:00
|
|
|
*ok = false;
|
|
|
|
return Statement::Default();
|
|
|
|
}
|
2016-01-20 22:04:58 +00:00
|
|
|
|
|
|
|
if (mode == ForEachStatement::ITERATE) {
|
2016-02-19 15:58:57 +00:00
|
|
|
ExpressionClassifier classifier(this);
|
|
|
|
ParseAssignmentExpression(true, &classifier, CHECK_OK);
|
|
|
|
RewriteNonPattern(&classifier, CHECK_OK);
|
2016-01-20 22:04:58 +00:00
|
|
|
} else {
|
|
|
|
ParseExpression(true, CHECK_OK);
|
|
|
|
}
|
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::RPAREN, CHECK_OK);
|
2016-04-27 13:02:28 +00:00
|
|
|
{
|
|
|
|
ReturnExprScope no_tail_calls(function_state_,
|
|
|
|
ReturnExprContext::kInsideForInOfBody);
|
|
|
|
ParseScopedStatement(true, CHECK_OK);
|
|
|
|
}
|
2011-05-19 09:01:46 +00:00
|
|
|
return Statement::Default();
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
} else {
|
2015-08-13 19:10:59 +00:00
|
|
|
int lhs_beg_pos = peek_position();
|
2016-02-19 15:58:57 +00:00
|
|
|
ExpressionClassifier classifier(this);
|
2015-12-11 19:38:57 +00:00
|
|
|
Expression lhs = ParseExpression(false, &classifier, CHECK_OK);
|
2015-08-13 19:10:59 +00:00
|
|
|
int lhs_end_pos = scanner()->location().end_pos;
|
2015-12-11 19:38:57 +00:00
|
|
|
bool is_for_each = CheckInOrOf(&mode, ok);
|
|
|
|
if (!*ok) return Statement::Default();
|
|
|
|
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);
|
|
|
|
}
|
2016-01-20 22:04:58 +00:00
|
|
|
|
|
|
|
if (mode == ForEachStatement::ITERATE) {
|
2016-02-19 15:58:57 +00:00
|
|
|
ExpressionClassifier classifier(this);
|
|
|
|
ParseAssignmentExpression(true, &classifier, CHECK_OK);
|
|
|
|
RewriteNonPattern(&classifier, CHECK_OK);
|
2016-01-20 22:04:58 +00:00
|
|
|
} else {
|
|
|
|
ParseExpression(true, CHECK_OK);
|
|
|
|
}
|
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::RPAREN, CHECK_OK);
|
2016-04-21 13:41:07 +00:00
|
|
|
Scope* body_scope = NewScope(scope_, BLOCK_SCOPE);
|
|
|
|
{
|
|
|
|
BlockState block_state(&scope_, body_scope);
|
|
|
|
ParseScopedStatement(true, CHECK_OK);
|
|
|
|
}
|
2011-05-19 09:01:46 +00:00
|
|
|
return Statement::Default();
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parsed initializer at this point.
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::SEMICOLON, CHECK_OK);
|
2010-11-23 11:46:36 +00:00
|
|
|
|
2016-04-21 13:41:07 +00:00
|
|
|
// 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_;
|
|
|
|
if (has_lexical) inner_scope = NewScope(for_scope, BLOCK_SCOPE);
|
2010-11-23 11:46:36 +00:00
|
|
|
|
2016-04-21 13:41:07 +00:00
|
|
|
{
|
|
|
|
BlockState block_state(&scope_, inner_scope);
|
2010-11-23 11:46:36 +00:00
|
|
|
|
2016-04-21 13:41:07 +00:00
|
|
|
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);
|
|
|
|
}
|
2011-05-19 09:01:46 +00:00
|
|
|
return Statement::Default();
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-29 13:24:37 +00:00
|
|
|
PreParser::Statement PreParser::ParseThrowStatement(bool* ok) {
|
2010-11-23 11:46:36 +00:00
|
|
|
// ThrowStatement ::
|
|
|
|
// 'throw' [no line terminator] Expression ';'
|
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::THROW, CHECK_OK);
|
2013-10-14 16:46:51 +00:00
|
|
|
if (scanner()->HasAnyLineTerminatorBeforeNext()) {
|
2015-05-18 08:34:05 +00:00
|
|
|
ReportMessageAt(scanner()->location(), MessageTemplate::kNewlineAfterThrow);
|
2010-11-23 11:46:36 +00:00
|
|
|
*ok = false;
|
2011-05-19 09:01:46 +00:00
|
|
|
return Statement::Default();
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
ParseExpression(true, CHECK_OK);
|
2011-05-19 09:01:46 +00:00
|
|
|
ExpectSemicolon(ok);
|
2015-04-16 13:29:29 +00:00
|
|
|
return Statement::Jump();
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-29 13:24:37 +00:00
|
|
|
PreParser::Statement PreParser::ParseTryStatement(bool* ok) {
|
2010-11-23 11:46:36 +00:00
|
|
|
// TryStatement ::
|
|
|
|
// 'try' Block Catch
|
|
|
|
// 'try' Block Finally
|
|
|
|
// 'try' Block Catch Finally
|
|
|
|
//
|
|
|
|
// Catch ::
|
|
|
|
// 'catch' '(' Identifier ')' Block
|
|
|
|
//
|
|
|
|
// Finally ::
|
|
|
|
// 'finally' Block
|
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::TRY, CHECK_OK);
|
2010-11-23 11:46:36 +00:00
|
|
|
|
2016-04-26 17:30:21 +00:00
|
|
|
{
|
2016-04-27 13:02:28 +00:00
|
|
|
ReturnExprScope no_tail_calls(function_state_,
|
|
|
|
ReturnExprContext::kInsideTryBlock);
|
2016-04-26 17:30:21 +00:00
|
|
|
ParseBlock(CHECK_OK);
|
|
|
|
}
|
2010-11-23 11:46:36 +00:00
|
|
|
|
2014-02-10 08:45:13 +00:00
|
|
|
Token::Value tok = peek();
|
|
|
|
if (tok != Token::CATCH && tok != Token::FINALLY) {
|
2015-05-18 08:34:05 +00:00
|
|
|
ReportMessageAt(scanner()->location(), MessageTemplate::kNoCatchOrFinally);
|
2014-02-10 08:45:13 +00:00
|
|
|
*ok = false;
|
|
|
|
return Statement::Default();
|
|
|
|
}
|
2016-05-04 13:42:52 +00:00
|
|
|
TailCallExpressionList tail_call_expressions_in_catch_block(zone());
|
2016-04-26 17:30:21 +00:00
|
|
|
bool catch_block_exists = false;
|
2014-02-10 08:45:13 +00:00
|
|
|
if (tok == Token::CATCH) {
|
2013-10-15 08:57:36 +00:00
|
|
|
Consume(Token::CATCH);
|
|
|
|
Expect(Token::LPAREN, CHECK_OK);
|
2016-04-21 13:41:07 +00:00
|
|
|
Scope* catch_scope = NewScope(scope_, CATCH_SCOPE);
|
2016-02-19 15:58:57 +00:00
|
|
|
ExpressionClassifier pattern_classifier(this);
|
2015-11-05 20:21:20 +00:00
|
|
|
ParsePrimaryExpression(&pattern_classifier, CHECK_OK);
|
|
|
|
ValidateBindingPattern(&pattern_classifier, CHECK_OK);
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::RPAREN, CHECK_OK);
|
2014-02-12 12:02:07 +00:00
|
|
|
{
|
2016-04-26 17:30:21 +00:00
|
|
|
CollectExpressionsInTailPositionToListScope
|
2016-05-04 13:42:52 +00:00
|
|
|
collect_tail_call_expressions_scope(
|
|
|
|
function_state_, &tail_call_expressions_in_catch_block);
|
2016-04-21 13:41:07 +00:00
|
|
|
BlockState block_state(&scope_, catch_scope);
|
|
|
|
Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
|
|
|
|
{
|
|
|
|
BlockState block_state(&scope_, block_scope);
|
|
|
|
ParseBlock(CHECK_OK);
|
|
|
|
}
|
2012-04-30 13:04:08 +00:00
|
|
|
}
|
2016-04-26 17:30:21 +00:00
|
|
|
catch_block_exists = true;
|
2014-02-10 08:45:13 +00:00
|
|
|
tok = peek();
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
2014-02-10 08:45:13 +00:00
|
|
|
if (tok == Token::FINALLY) {
|
2013-10-15 08:57:36 +00:00
|
|
|
Consume(Token::FINALLY);
|
2010-11-23 11:46:36 +00:00
|
|
|
ParseBlock(CHECK_OK);
|
2016-04-26 17:30:21 +00:00
|
|
|
if (FLAG_harmony_explicit_tailcalls && catch_block_exists &&
|
2016-05-10 10:18:00 +00:00
|
|
|
tail_call_expressions_in_catch_block.has_explicit_tail_calls()) {
|
2016-04-26 17:30:21 +00:00
|
|
|
// TODO(ishell): update chapter number.
|
|
|
|
// ES8 XX.YY.ZZ
|
2016-05-04 13:42:52 +00:00
|
|
|
ReportMessageAt(tail_call_expressions_in_catch_block.location(),
|
|
|
|
MessageTemplate::kUnexpectedTailCallInCatchBlock);
|
2016-04-26 17:30:21 +00:00
|
|
|
*ok = false;
|
|
|
|
return Statement::Default();
|
|
|
|
}
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
2011-05-19 09:01:46 +00:00
|
|
|
return Statement::Default();
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-29 13:24:37 +00:00
|
|
|
PreParser::Statement PreParser::ParseDebuggerStatement(bool* ok) {
|
2010-11-23 11:46:36 +00:00
|
|
|
// 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' ';'
|
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::DEBUGGER, CHECK_OK);
|
2011-05-19 09:01:46 +00:00
|
|
|
ExpectSemicolon(ok);
|
|
|
|
return Statement::Default();
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-05-19 09:01:46 +00:00
|
|
|
#undef CHECK_OK
|
|
|
|
#define CHECK_OK ok); \
|
|
|
|
if (!*ok) return Expression::Default(); \
|
|
|
|
((void)0
|
|
|
|
#define DUMMY ) // to make indentation work
|
|
|
|
#undef DUMMY
|
|
|
|
|
|
|
|
|
2014-02-07 10:47:01 +00:00
|
|
|
PreParser::Expression PreParser::ParseFunctionLiteral(
|
2014-09-10 16:39:42 +00:00
|
|
|
Identifier function_name, Scanner::Location function_name_location,
|
2015-07-09 21:31:11 +00:00
|
|
|
FunctionNameValidity function_name_validity, FunctionKind kind,
|
|
|
|
int function_token_pos, FunctionLiteral::FunctionType function_type,
|
2015-07-15 09:14:49 +00:00
|
|
|
LanguageMode language_mode, bool* ok) {
|
2010-11-23 11:46:36 +00:00
|
|
|
// Function ::
|
|
|
|
// '(' FormalParameterList? ')' '{' FunctionBody '}'
|
|
|
|
|
|
|
|
// Parse function body.
|
2015-02-10 13:27:08 +00:00
|
|
|
bool outer_is_script_scope = scope_->is_script_scope();
|
2015-05-26 20:29:47 +00:00
|
|
|
Scope* function_scope = NewScope(scope_, FUNCTION_SCOPE, kind);
|
2015-07-15 09:14:49 +00:00
|
|
|
function_scope->SetLanguageMode(language_mode);
|
2014-10-21 12:16:37 +00:00
|
|
|
PreParserFactory factory(NULL);
|
2015-02-10 13:27:08 +00:00
|
|
|
FunctionState function_state(&function_state_, &scope_, function_scope, kind,
|
2014-10-09 08:16:13 +00:00
|
|
|
&factory);
|
2015-06-09 17:13:35 +00:00
|
|
|
DuplicateFinder duplicate_finder(scanner()->unicode_cache());
|
2016-02-19 15:58:57 +00:00
|
|
|
ExpressionClassifier formals_classifier(this, &duplicate_finder);
|
2015-04-10 12:04:51 +00:00
|
|
|
|
2015-04-21 11:09:53 +00:00
|
|
|
Expect(Token::LPAREN, CHECK_OK);
|
|
|
|
int start_position = scanner()->location().beg_pos;
|
|
|
|
function_scope->set_start_position(start_position);
|
2015-08-26 14:59:05 +00:00
|
|
|
PreParserFormalParameters formals(function_scope);
|
2015-08-04 14:24:13 +00:00
|
|
|
ParseFormalParameterList(&formals, &formals_classifier, CHECK_OK);
|
2015-04-17 09:51:22 +00:00
|
|
|
Expect(Token::RPAREN, CHECK_OK);
|
2015-04-21 11:09:53 +00:00
|
|
|
int formals_end_position = scanner()->location().end_pos;
|
|
|
|
|
2016-02-19 02:50:58 +00:00
|
|
|
CheckArityRestrictions(formals.arity, kind, formals.has_rest, start_position,
|
2015-06-22 14:15:53 +00:00
|
|
|
formals_end_position, CHECK_OK);
|
2010-11-23 11:46:36 +00:00
|
|
|
|
2014-02-19 14:50:33 +00:00
|
|
|
// See Parser::ParseFunctionLiteral for more information about lazy parsing
|
|
|
|
// and lazy compilation.
|
2016-04-20 09:33:01 +00:00
|
|
|
bool is_lazily_parsed = (outer_is_script_scope && allow_lazy() &&
|
|
|
|
!function_state_->this_function_is_parenthesized());
|
2010-11-23 11:46:36 +00:00
|
|
|
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::LBRACE, CHECK_OK);
|
2014-02-19 14:50:33 +00:00
|
|
|
if (is_lazily_parsed) {
|
2011-11-25 09:36:31 +00:00
|
|
|
ParseLazyFunctionLiteralBody(CHECK_OK);
|
2010-11-23 11:46:36 +00:00
|
|
|
} else {
|
2015-02-06 23:26:18 +00:00
|
|
|
ParseStatementList(Token::RBRACE, CHECK_OK);
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::RBRACE, CHECK_OK);
|
2011-05-06 11:41:15 +00:00
|
|
|
|
2015-07-15 09:14:49 +00:00
|
|
|
// Parsing the body may change the language mode in our scope.
|
|
|
|
language_mode = function_scope->language_mode();
|
|
|
|
|
2015-02-06 18:04:11 +00:00
|
|
|
// Validate name and parameter names. We can do this only after parsing the
|
|
|
|
// function, since the function can declare itself strict.
|
2015-07-15 09:14:49 +00:00
|
|
|
CheckFunctionName(language_mode, function_name, function_name_validity,
|
2015-07-09 21:31:11 +00:00
|
|
|
function_name_location, CHECK_OK);
|
2015-05-13 11:45:04 +00:00
|
|
|
const bool allow_duplicate_parameters =
|
2015-07-23 11:53:31 +00:00
|
|
|
is_sloppy(language_mode) && formals.is_simple && !IsConciseMethod(kind);
|
2015-07-15 09:14:49 +00:00
|
|
|
ValidateFormalParameters(&formals_classifier, language_mode,
|
2015-05-13 11:45:04 +00:00
|
|
|
allow_duplicate_parameters, CHECK_OK);
|
2014-02-07 10:47:01 +00:00
|
|
|
|
2015-07-15 09:14:49 +00:00
|
|
|
if (is_strict(language_mode)) {
|
2013-10-14 16:46:51 +00:00
|
|
|
int end_position = scanner()->location().end_pos;
|
2014-12-18 22:01:25 +00:00
|
|
|
CheckStrictOctalLiteral(start_position, end_position, CHECK_OK);
|
2016-05-16 23:20:29 +00:00
|
|
|
CheckDecimalLiteralWithLeadingZero(use_counts_, start_position,
|
|
|
|
end_position);
|
2011-05-06 11:41:15 +00:00
|
|
|
}
|
|
|
|
|
2011-05-19 09:01:46 +00:00
|
|
|
return Expression::Default();
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
|
2016-05-16 23:17:13 +00:00
|
|
|
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(&is_strict_reserved, CHECK_OK);
|
|
|
|
if (this->IsAwait(name)) {
|
|
|
|
ReportMessageAt(scanner()->location(),
|
|
|
|
MessageTemplate::kAwaitBindingIdentifier);
|
|
|
|
*ok = false;
|
|
|
|
return Expression::Default();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ParseFunctionLiteral(name, scanner()->location(),
|
|
|
|
is_strict_reserved ? kFunctionNameIsStrictReserved
|
|
|
|
: kFunctionNameValidityUnknown,
|
|
|
|
FunctionKind::kAsyncFunction, pos, type, language_mode(),
|
|
|
|
CHECK_OK);
|
|
|
|
return Expression::Default();
|
|
|
|
}
|
2010-11-23 11:46:36 +00:00
|
|
|
|
2015-05-06 10:21:20 +00:00
|
|
|
void PreParser::ParseLazyFunctionLiteralBody(bool* ok,
|
|
|
|
Scanner::BookmarkScope* bookmark) {
|
2013-10-15 08:32:58 +00:00
|
|
|
int body_start = position();
|
2015-05-06 10:21:20 +00:00
|
|
|
ParseStatementList(Token::RBRACE, ok, bookmark);
|
2011-11-25 09:36:31 +00:00
|
|
|
if (!*ok) return;
|
2015-05-06 10:21:20 +00:00
|
|
|
if (bookmark && bookmark->HasBeenReset()) return;
|
2011-11-25 09:36:31 +00:00
|
|
|
|
|
|
|
// Position right after terminal '}'.
|
2014-08-04 11:34:54 +00:00
|
|
|
DCHECK_EQ(Token::RBRACE, scanner()->peek());
|
2013-10-14 16:46:51 +00:00
|
|
|
int body_end = scanner()->peek_location().end_pos;
|
2015-02-13 18:34:52 +00:00
|
|
|
log_->LogFunction(body_start, body_end,
|
|
|
|
function_state_->materialized_literal_count(),
|
|
|
|
function_state_->expected_property_count(), language_mode(),
|
2015-06-04 21:16:18 +00:00
|
|
|
scope_->uses_super_property(), scope_->calls_eval());
|
2011-11-25 09:36:31 +00:00
|
|
|
}
|
|
|
|
|
2014-11-14 15:05:05 +00:00
|
|
|
PreParserExpression PreParser::ParseClassLiteral(
|
2016-05-03 01:55:27 +00:00
|
|
|
ExpressionClassifier* classifier, PreParserIdentifier name,
|
|
|
|
Scanner::Location class_name_location, bool name_is_strict_reserved,
|
|
|
|
int pos, bool* ok) {
|
2014-11-14 15:05:05 +00:00
|
|
|
// All parts of a ClassDeclaration and ClassExpression are strict code.
|
|
|
|
if (name_is_strict_reserved) {
|
2015-05-18 08:34:05 +00:00
|
|
|
ReportMessageAt(class_name_location,
|
|
|
|
MessageTemplate::kUnexpectedStrictReserved);
|
2014-11-14 15:05:05 +00:00
|
|
|
*ok = false;
|
|
|
|
return EmptyExpression();
|
|
|
|
}
|
|
|
|
if (IsEvalOrArguments(name)) {
|
2015-05-18 08:34:05 +00:00
|
|
|
ReportMessageAt(class_name_location, MessageTemplate::kStrictEvalArguments);
|
2014-11-14 15:05:05 +00:00
|
|
|
*ok = false;
|
|
|
|
return EmptyExpression();
|
|
|
|
}
|
|
|
|
|
2016-03-10 12:43:51 +00:00
|
|
|
LanguageMode class_language_mode = language_mode();
|
2015-02-10 13:27:08 +00:00
|
|
|
Scope* scope = NewScope(scope_, BLOCK_SCOPE);
|
|
|
|
BlockState block_state(&scope_, scope);
|
2015-02-04 09:34:05 +00:00
|
|
|
scope_->SetLanguageMode(
|
2015-07-20 14:31:30 +00:00
|
|
|
static_cast<LanguageMode>(class_language_mode | STRICT));
|
2015-02-10 13:27:08 +00:00
|
|
|
// TODO(marja): Make PreParser use scope names too.
|
|
|
|
// scope_->SetScopeName(name);
|
2014-11-14 15:05:05 +00:00
|
|
|
|
2015-02-03 17:42:41 +00:00
|
|
|
bool has_extends = Check(Token::EXTENDS);
|
|
|
|
if (has_extends) {
|
2016-05-03 01:55:27 +00:00
|
|
|
ExpressionClassifier extends_classifier(this);
|
|
|
|
ParseLeftHandSideExpression(&extends_classifier, CHECK_OK);
|
2016-05-04 13:42:52 +00:00
|
|
|
CheckNoTailCallExpressions(&extends_classifier, CHECK_OK);
|
2016-05-03 01:55:27 +00:00
|
|
|
ValidateExpression(&extends_classifier, CHECK_OK);
|
|
|
|
if (classifier != nullptr) {
|
|
|
|
classifier->Accumulate(&extends_classifier,
|
|
|
|
ExpressionClassifier::ExpressionProductions);
|
|
|
|
}
|
2014-11-14 15:05:05 +00:00
|
|
|
}
|
|
|
|
|
2015-01-29 23:12:25 +00:00
|
|
|
ClassLiteralChecker checker(this);
|
2014-11-14 15:05:05 +00:00
|
|
|
bool has_seen_constructor = false;
|
|
|
|
|
|
|
|
Expect(Token::LBRACE, CHECK_OK);
|
|
|
|
while (peek() != Token::RBRACE) {
|
|
|
|
if (Check(Token::SEMICOLON)) continue;
|
|
|
|
const bool in_class = true;
|
2015-01-15 20:02:20 +00:00
|
|
|
bool is_computed_name = false; // Classes do not care about computed
|
|
|
|
// property names here.
|
2016-01-06 23:38:28 +00:00
|
|
|
Identifier name;
|
2016-05-04 23:24:05 +00:00
|
|
|
ExpressionClassifier property_classifier(this);
|
2016-05-16 23:17:13 +00:00
|
|
|
ParsePropertyDefinition(&checker, in_class, has_extends, MethodKind::Normal,
|
2015-04-22 12:35:05 +00:00
|
|
|
&is_computed_name, &has_seen_constructor,
|
2016-05-04 23:24:05 +00:00
|
|
|
&property_classifier, &name, CHECK_OK);
|
|
|
|
ValidateExpression(&property_classifier, CHECK_OK);
|
|
|
|
if (classifier != nullptr) {
|
|
|
|
classifier->Accumulate(&property_classifier,
|
|
|
|
ExpressionClassifier::ExpressionProductions);
|
|
|
|
}
|
2014-11-14 15:05:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Expect(Token::RBRACE, CHECK_OK);
|
|
|
|
|
|
|
|
return Expression::Default();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-29 13:24:37 +00:00
|
|
|
PreParser::Expression PreParser::ParseV8Intrinsic(bool* ok) {
|
2010-11-23 11:46:36 +00:00
|
|
|
// CallRuntime ::
|
|
|
|
// '%' Identifier Arguments
|
2013-10-15 08:57:36 +00:00
|
|
|
Expect(Token::MOD, CHECK_OK);
|
2014-11-20 10:51:49 +00:00
|
|
|
if (!allow_natives()) {
|
2011-10-17 12:45:52 +00:00
|
|
|
*ok = false;
|
|
|
|
return Expression::Default();
|
|
|
|
}
|
2014-02-05 16:26:48 +00:00
|
|
|
// Allow "eval" or "arguments" for backward compatibility.
|
2015-04-10 12:04:51 +00:00
|
|
|
ParseIdentifier(kAllowRestrictedIdentifiers, CHECK_OK);
|
2015-04-09 19:37:14 +00:00
|
|
|
Scanner::Location spread_pos;
|
2016-02-19 15:58:57 +00:00
|
|
|
ExpressionClassifier classifier(this);
|
2015-04-22 12:35:05 +00:00
|
|
|
ParseArguments(&spread_pos, &classifier, ok);
|
2015-04-27 14:35:45 +00:00
|
|
|
ValidateExpression(&classifier, CHECK_OK);
|
2015-04-09 19:37:14 +00:00
|
|
|
|
|
|
|
DCHECK(!spread_pos.IsValid());
|
2010-11-23 11:46:36 +00:00
|
|
|
|
2011-05-19 09:01:46 +00:00
|
|
|
return Expression::Default();
|
2010-11-23 11:46:36 +00:00
|
|
|
}
|
|
|
|
|
2015-10-21 02:55:47 +00:00
|
|
|
|
|
|
|
PreParserExpression PreParser::ParseDoExpression(bool* ok) {
|
|
|
|
// AssignmentExpression ::
|
|
|
|
// do '{' StatementList '}'
|
|
|
|
Expect(Token::DO, CHECK_OK);
|
|
|
|
Expect(Token::LBRACE, CHECK_OK);
|
2016-04-21 13:41:07 +00:00
|
|
|
while (peek() != Token::RBRACE) {
|
|
|
|
ParseStatementListItem(CHECK_OK);
|
2015-10-21 02:55:47 +00:00
|
|
|
}
|
2016-04-21 13:41:07 +00:00
|
|
|
Expect(Token::RBRACE, CHECK_OK);
|
|
|
|
return PreParserExpression::Default();
|
2015-10-21 02:55:47 +00:00
|
|
|
}
|
|
|
|
|
2016-05-17 00:26:53 +00:00
|
|
|
void PreParserTraits::ParseAsyncArrowSingleExpressionBody(
|
|
|
|
PreParserStatementList body, bool accept_IN,
|
|
|
|
Type::ExpressionClassifier* classifier, int pos, bool* ok) {
|
|
|
|
Scope* scope = pre_parser_->scope_;
|
|
|
|
scope->ForceContextAllocation();
|
|
|
|
|
|
|
|
PreParserExpression return_value =
|
|
|
|
pre_parser_->ParseAssignmentExpression(accept_IN, classifier, ok);
|
|
|
|
if (!*ok) return;
|
|
|
|
|
|
|
|
body->Add(PreParserStatement::ExpressionStatement(return_value), zone());
|
|
|
|
}
|
|
|
|
|
2011-05-19 09:01:46 +00:00
|
|
|
#undef CHECK_OK
|
|
|
|
|
2010-11-23 11:46:36 +00:00
|
|
|
|
2015-09-30 13:46:56 +00:00
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|