summaryrefslogtreecommitdiff
path: root/deps/v8/src/parser.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/parser.cc')
-rw-r--r--deps/v8/src/parser.cc519
1 files changed, 306 insertions, 213 deletions
diff --git a/deps/v8/src/parser.cc b/deps/v8/src/parser.cc
index aa0ec104a7..ecc6530135 100644
--- a/deps/v8/src/parser.cc
+++ b/deps/v8/src/parser.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "src/v8.h"
+#include "src/parser.h"
#include "src/api.h"
#include "src/ast.h"
@@ -14,7 +14,6 @@
#include "src/codegen.h"
#include "src/compiler.h"
#include "src/messages.h"
-#include "src/parser.h"
#include "src/preparser.h"
#include "src/runtime/runtime.h"
#include "src/scanner-character-streams.h"
@@ -346,7 +345,7 @@ FunctionLiteral* Parser::DefaultConstructor(bool call_super, Scope* scope,
: FunctionKind::kDefaultBaseConstructor;
Scope* function_scope = NewScope(scope, FUNCTION_SCOPE, kind);
function_scope->SetLanguageMode(
- static_cast<LanguageMode>(language_mode | STRICT_BIT));
+ static_cast<LanguageMode>(language_mode | STRICT));
// Set start and end position to the same value
function_scope->set_start_position(pos);
function_scope->set_end_position(pos);
@@ -789,9 +788,11 @@ Expression* ParserTraits::NewTargetExpression(Scope* scope,
AstNodeFactory* factory,
int pos) {
static const int kNewTargetStringLength = 10;
- return scope->NewUnresolved(
+ auto proxy = scope->NewUnresolved(
factory, parser_->ast_value_factory()->new_target_string(),
Variable::NORMAL, pos, pos + kNewTargetStringLength);
+ proxy->set_is_new_target();
+ return proxy;
}
@@ -873,12 +874,12 @@ Expression* ParserTraits::ParseV8Intrinsic(bool* ok) {
FunctionLiteral* ParserTraits::ParseFunctionLiteral(
const AstRawString* name, Scanner::Location function_name_location,
- bool name_is_strict_reserved, FunctionKind kind,
+ FunctionNameValidity function_name_validity, FunctionKind kind,
int function_token_position, FunctionLiteral::FunctionType type,
FunctionLiteral::ArityRestriction arity_restriction,
LanguageMode language_mode, bool* ok) {
return parser_->ParseFunctionLiteral(
- name, function_name_location, name_is_strict_reserved, kind,
+ name, function_name_location, function_name_validity, kind,
function_token_position, type, arity_restriction, language_mode, ok);
}
@@ -910,13 +911,12 @@ Parser::Parser(ParseInfo* info)
DCHECK(!info->script().is_null() || info->source_stream() != NULL);
set_allow_lazy(info->allow_lazy_parsing());
set_allow_natives(FLAG_allow_natives_syntax || info->is_native());
- set_allow_harmony_modules(!info->is_native() && FLAG_harmony_modules);
set_allow_harmony_arrow_functions(FLAG_harmony_arrow_functions);
set_allow_harmony_sloppy(FLAG_harmony_sloppy);
- set_allow_harmony_unicode(FLAG_harmony_unicode);
- set_allow_harmony_computed_property_names(
- FLAG_harmony_computed_property_names);
- set_allow_harmony_rest_params(FLAG_harmony_rest_parameters);
+ set_allow_harmony_sloppy_function(FLAG_harmony_sloppy_function);
+ set_allow_harmony_sloppy_let(FLAG_harmony_sloppy_let);
+ set_allow_harmony_rest_parameters(FLAG_harmony_rest_parameters);
+ set_allow_harmony_default_parameters(FLAG_harmony_default_parameters);
set_allow_harmony_spreadcalls(FLAG_harmony_spreadcalls);
set_allow_harmony_destructuring(FLAG_harmony_destructuring);
set_allow_harmony_spread_arrays(FLAG_harmony_spread_arrays);
@@ -989,7 +989,7 @@ FunctionLiteral* Parser::ParseProgram(Isolate* isolate, ParseInfo* info) {
PrintF("[parsing eval");
} else if (info->script()->name()->IsString()) {
String* name = String::cast(info->script()->name());
- SmartArrayPointer<char> name_chars = name->ToCString();
+ base::SmartArrayPointer<char> name_chars = name->ToCString();
PrintF("[parsing script: %s", name_chars.get());
} else {
PrintF("[parsing script");
@@ -1016,7 +1016,7 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) {
FunctionLiteral* result = NULL;
{
- // TODO(wingo): Add an outer GLOBAL_SCOPE corresponding to the native
+ // TODO(wingo): Add an outer SCRIPT_SCOPE corresponding to the native
// context, which will have the "this" binding for script scopes.
Scope* scope = NewScope(scope_, SCRIPT_SCOPE);
info->set_script_scope(scope);
@@ -1053,7 +1053,6 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) {
bool ok = true;
int beg_pos = scanner()->location().beg_pos;
if (info->is_module()) {
- DCHECK(allow_harmony_modules());
ParseModuleItemList(body, &ok);
} else {
ParseStatementList(body, Token::EOS, &ok);
@@ -1065,6 +1064,8 @@ FunctionLiteral* Parser::DoParseProgram(ParseInfo* info) {
if (ok && is_strict(language_mode())) {
CheckStrictOctalLiteral(beg_pos, scanner()->location().end_pos, &ok);
+ }
+ if (ok && (is_strict(language_mode()) || allow_harmony_sloppy())) {
CheckConflictingVarDeclarations(scope_, &ok);
}
@@ -1128,7 +1129,8 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info) {
if (FLAG_trace_parse && result != NULL) {
double ms = timer.Elapsed().InMillisecondsF();
- SmartArrayPointer<char> name_chars = result->debug_name()->ToCString();
+ base::SmartArrayPointer<char> name_chars =
+ result->debug_name()->ToCString();
PrintF("[parsing function: %s - took %0.3f ms]\n", name_chars.get(), ms);
}
return result;
@@ -1184,7 +1186,7 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
scope->SetLanguageMode(shared_info->language_mode());
scope->set_start_position(shared_info->start_position());
ExpressionClassifier formals_classifier;
- ParserFormalParameterParsingState parsing_state(scope);
+ ParserFormalParameters formals(scope);
Checkpoint checkpoint(this);
{
// Parsing patterns as variable reference expression creates
@@ -1193,20 +1195,23 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
BlockState block_state(&scope_, scope);
if (Check(Token::LPAREN)) {
// '(' StrictFormalParameters ')'
- ParseFormalParameterList(&parsing_state, &formals_classifier, &ok);
+ ParseFormalParameterList(&formals, &formals_classifier, &ok);
if (ok) ok = Check(Token::RPAREN);
} else {
// BindingIdentifier
- const bool is_rest = false;
- ParseFormalParameter(is_rest, &parsing_state, &formals_classifier,
- &ok);
+ ParseFormalParameter(&formals, &formals_classifier, &ok);
+ if (ok) {
+ DeclareFormalParameter(
+ formals.scope, formals.at(0), formals.is_simple,
+ &formals_classifier);
+ }
}
}
if (ok) {
- checkpoint.Restore(&parsing_state.materialized_literals_count);
+ checkpoint.Restore(&formals.materialized_literals_count);
Expression* expression =
- ParseArrowFunctionLiteral(parsing_state, formals_classifier, &ok);
+ ParseArrowFunctionLiteral(formals, formals_classifier, &ok);
if (ok) {
// Scanning must end at the same position that was recorded
// previously. If not, parsing has been interrupted due to a stack
@@ -1231,9 +1236,9 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
shared_info->language_mode());
} else {
result = ParseFunctionLiteral(
- raw_name, Scanner::Location::invalid(), false, shared_info->kind(),
- RelocInfo::kNoPosition, function_type, FunctionLiteral::NORMAL_ARITY,
- shared_info->language_mode(), &ok);
+ raw_name, Scanner::Location::invalid(), kSkipFunctionNameCheck,
+ shared_info->kind(), RelocInfo::kNoPosition, function_type,
+ FunctionLiteral::NORMAL_ARITY, shared_info->language_mode(), &ok);
}
// Make sure the results agree.
DCHECK(ok == (result != NULL));
@@ -1324,20 +1329,17 @@ void* Parser::ParseStatementList(ZoneList<Statement*>* body, int end_token,
// / "use strong" directives, do the strict mode changes only once.
if (is_sloppy(scope_->language_mode())) {
scope_->SetLanguageMode(static_cast<LanguageMode>(
- scope_->language_mode() | STRICT_BIT));
+ scope_->language_mode() | STRICT));
}
if (use_strong_found) {
scope_->SetLanguageMode(static_cast<LanguageMode>(
- scope_->language_mode() | STRONG_BIT));
+ scope_->language_mode() | STRONG));
}
// Because declarations in strict eval code don't leak into the scope
// of the eval call, it is likely that functions declared in strict
// eval code will be used within the eval code, so lazy parsing is
- // probably not a win. Also, resolution of "var" bindings defined in
- // strict eval code from within nested functions is currently broken
- // with the pre-parser; lazy parsing of strict eval code causes
- // regress/regress-crbug-135066.js to fail.
+ // probably not a win.
if (scope_->is_eval_scope()) mode_ = PARSE_EAGERLY;
} else if (literal->raw_value()->AsString() ==
ast_value_factory()->use_asm_string() &&
@@ -1390,7 +1392,7 @@ Statement* Parser::ParseStatementListItem(bool* ok) {
case Token::VAR:
return ParseVariableStatement(kStatementListItem, NULL, ok);
case Token::LET:
- if (is_strict(language_mode())) {
+ if (allow_let()) {
return ParseVariableStatement(kStatementListItem, NULL, ok);
}
break;
@@ -1429,7 +1431,7 @@ void* Parser::ParseModuleItemList(ZoneList<Statement*>* body, bool* ok) {
DCHECK(scope_->is_module_scope());
scope_->SetLanguageMode(
- static_cast<LanguageMode>(scope_->language_mode() | STRICT_BIT));
+ static_cast<LanguageMode>(scope_->language_mode() | STRICT));
while (peek() != Token::EOS) {
Statement* stat = ParseModuleItem(CHECK_OK);
@@ -2008,15 +2010,17 @@ Variable* Parser::Declare(Declaration* declaration,
// variable and also set its mode. In any case, a Declaration node
// will be added to the scope so that the declaration can be added
// to the corresponding activation frame at runtime if necessary.
- // For instance declarations inside an eval scope need to be added
- // to the calling function context.
- // Similarly, strict mode eval scope does not leak variable declarations to
- // the caller's scope so we declare all locals, too.
+ // For instance, var declarations inside a sloppy eval scope need
+ // to be added to the calling function context. Similarly, strict
+ // mode eval scope and lexical eval bindings do not leak variable
+ // declarations to the caller's scope so we declare all locals, too.
if (declaration_scope->is_function_scope() ||
- declaration_scope->is_strict_eval_scope() ||
declaration_scope->is_block_scope() ||
declaration_scope->is_module_scope() ||
- declaration_scope->is_script_scope()) {
+ declaration_scope->is_script_scope() ||
+ (declaration_scope->is_eval_scope() &&
+ (is_strict(declaration_scope->language_mode()) ||
+ IsLexicalVariableMode(mode)))) {
// Declare the variable in the declaration scope.
var = declaration_scope->LookupLocal(name);
if (var == NULL) {
@@ -2052,13 +2056,13 @@ Variable* Parser::Declare(Declaration* declaration,
// because the var declaration is hoisted to the function scope where 'x'
// is already bound.
DCHECK(IsDeclaredVariableMode(var->mode()));
- if (is_strict(language_mode())) {
+ if (is_strict(language_mode()) || allow_harmony_sloppy()) {
// In harmony we treat re-declarations as early errors. See
// ES5 16 for a definition of early errors.
if (declaration_kind == DeclarationDescriptor::NORMAL) {
ParserTraits::ReportMessage(MessageTemplate::kVarRedeclaration, name);
} else {
- ParserTraits::ReportMessage(MessageTemplate::kStrictParamDupe);
+ ParserTraits::ReportMessage(MessageTemplate::kParamDupe);
}
*ok = false;
return nullptr;
@@ -2069,8 +2073,22 @@ Variable* Parser::Declare(Declaration* declaration,
} else if (mode == VAR) {
var->set_maybe_assigned();
}
+ } else if (declaration_scope->is_eval_scope() &&
+ is_sloppy(declaration_scope->language_mode()) &&
+ !IsLexicalVariableMode(mode)) {
+ // In a var binding in a sloppy direct eval, pollute the enclosing scope
+ // with this new binding by doing the following:
+ // The proxy is bound to a lookup variable to force a dynamic declaration
+ // using the DeclareLookupSlot runtime function.
+ Variable::Kind kind = Variable::NORMAL;
+ // TODO(sigurds) figure out if kNotAssigned is OK here
+ var = new (zone()) Variable(declaration_scope, name, mode, kind,
+ declaration->initialization(), kNotAssigned);
+ var->AllocateTo(VariableLocation::LOOKUP, -1);
+ resolve = true;
}
+
// We add a declaration node for every declaration. The compiler
// will only generate code if necessary. In particular, declarations
// for inner local variables that do not represent functions won't
@@ -2095,17 +2113,6 @@ Variable* Parser::Declare(Declaration* declaration,
Variable::Kind kind = Variable::NORMAL;
var = new (zone()) Variable(declaration_scope, name, mode, kind,
kNeedsInitialization, kNotAssigned);
- } else if (declaration_scope->is_eval_scope() &&
- is_sloppy(declaration_scope->language_mode())) {
- // For variable declarations in a sloppy eval scope the proxy is bound
- // to a lookup variable to force a dynamic declaration using the
- // DeclareLookupSlot runtime function.
- Variable::Kind kind = Variable::NORMAL;
- // TODO(sigurds) figure out if kNotAssigned is OK here
- var = new (zone()) Variable(declaration_scope, name, mode, kind,
- declaration->initialization(), kNotAssigned);
- var->AllocateTo(VariableLocation::LOOKUP, -1);
- resolve = true;
}
// If requested and we have a local variable, bind the proxy to the variable
@@ -2196,12 +2203,21 @@ Statement* Parser::ParseFunctionDeclaration(
bool is_strict_reserved = false;
const AstRawString* name = ParseIdentifierOrStrictReservedWord(
&is_strict_reserved, CHECK_OK);
+
+ if (fni_ != NULL) {
+ fni_->Enter();
+ fni_->PushEnclosingName(name);
+ }
FunctionLiteral* fun = ParseFunctionLiteral(
- name, scanner()->location(), is_strict_reserved,
+ name, scanner()->location(),
+ is_strict_reserved ? kFunctionNameIsStrictReserved
+ : kFunctionNameValidityUnknown,
is_generator ? FunctionKind::kGeneratorFunction
: FunctionKind::kNormalFunction,
pos, FunctionLiteral::DECLARATION, FunctionLiteral::NORMAL_ARITY,
language_mode(), CHECK_OK);
+ if (fni_ != NULL) fni_->Leave();
+
// Even if we're not at the top-level of the global or a function
// scope, we treat it as such and introduce the function with its
// initial value upon entering the corresponding scope.
@@ -2210,9 +2226,8 @@ Statement* Parser::ParseFunctionDeclaration(
VariableMode mode =
is_strong(language_mode())
? CONST
- : is_strict(language_mode()) &&
- !(scope_->is_script_scope() || scope_->is_eval_scope() ||
- scope_->is_function_scope())
+ : (is_strict(language_mode()) || allow_harmony_sloppy_function()) &&
+ !scope_->is_declaration_scope()
? LET
: VAR;
VariableProxy* proxy = NewUnresolved(name, mode);
@@ -2290,7 +2305,7 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names,
Block* Parser::ParseBlock(ZoneList<const AstRawString*>* labels, bool* ok) {
- if (is_strict(language_mode())) {
+ if (is_strict(language_mode()) || allow_harmony_sloppy()) {
return ParseScopedBlock(labels, ok);
}
@@ -2442,14 +2457,14 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
parsing_result->descriptor.init_op = Token::INIT_CONST_LEGACY;
++use_counts_[v8::Isolate::kLegacyConst];
} else {
- DCHECK(is_strict(language_mode()));
+ DCHECK(is_strict(language_mode()) || allow_harmony_sloppy());
DCHECK(var_context != kStatement);
parsing_result->descriptor.mode = CONST;
parsing_result->descriptor.init_op = Token::INIT_CONST;
}
parsing_result->descriptor.is_const = true;
parsing_result->descriptor.needs_init = true;
- } else if (peek() == Token::LET && is_strict(language_mode())) {
+ } else if (peek() == Token::LET && allow_let()) {
Consume(Token::LET);
DCHECK(var_context != kStatement);
parsing_result->descriptor.mode = LET;
@@ -2823,7 +2838,7 @@ Statement* Parser::ParseReturnStatement(bool* ok) {
//
// return (temp = expr) === undefined ? this :
// %_IsSpecObject(temp) ? temp : throw new TypeError(...);
- Variable* temp = scope_->DeclarationScope()->NewTemporary(
+ Variable* temp = scope_->NewTemporary(
ast_value_factory()->empty_string());
Assignment* assign = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(temp), return_value, pos);
@@ -3177,9 +3192,9 @@ void Parser::InitializeForEachStatement(ForEachStatement* stmt,
ForOfStatement* for_of = stmt->AsForOfStatement();
if (for_of != NULL) {
- Variable* iterator = scope_->DeclarationScope()->NewTemporary(
+ Variable* iterator = scope_->NewTemporary(
ast_value_factory()->dot_iterator_string());
- Variable* result = scope_->DeclarationScope()->NewTemporary(
+ Variable* result = scope_->NewTemporary(
ast_value_factory()->dot_result_string());
Expression* assign_iterator;
@@ -3295,7 +3310,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
// make statement: temp_x = x.
for (int i = 0; i < names->length(); i++) {
VariableProxy* proxy = NewUnresolved(names->at(i), LET);
- Variable* temp = scope_->DeclarationScope()->NewTemporary(temp_name);
+ Variable* temp = scope_->NewTemporary(temp_name);
VariableProxy* temp_proxy = factory()->NewVariableProxy(temp);
Assignment* assignment = factory()->NewAssignment(
Token::ASSIGN, temp_proxy, proxy, RelocInfo::kNoPosition);
@@ -3308,7 +3323,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
Variable* first = NULL;
// Make statement: first = 1.
if (next) {
- first = scope_->DeclarationScope()->NewTemporary(temp_name);
+ first = scope_->NewTemporary(temp_name);
VariableProxy* first_proxy = factory()->NewVariableProxy(first);
Expression* const1 = factory()->NewSmiLiteral(1, RelocInfo::kNoPosition);
Assignment* assignment = factory()->NewAssignment(
@@ -3388,7 +3403,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
ignore_completion_block->AddStatement(clear_first_or_next, zone());
}
- Variable* flag = scope_->DeclarationScope()->NewTemporary(temp_name);
+ Variable* flag = scope_->NewTemporary(temp_name);
// Make statement: flag = 1.
{
VariableProxy* flag_proxy = factory()->NewVariableProxy(flag);
@@ -3501,7 +3516,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
DeclarationParsingResult parsing_result;
if (peek() != Token::SEMICOLON) {
if (peek() == Token::VAR || (peek() == Token::CONST && allow_const()) ||
- (peek() == Token::LET && is_strict(language_mode()))) {
+ (peek() == Token::LET && allow_let())) {
ParseVariableDeclarations(kForStatement, &parsing_result, CHECK_OK);
is_const = parsing_result.descriptor.mode == CONST;
@@ -3574,7 +3589,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
// let x; // for TDZ
// }
- Variable* temp = scope_->DeclarationScope()->NewTemporary(
+ Variable* temp = scope_->NewTemporary(
ast_value_factory()->dot_for_string());
ForEachStatement* loop =
factory()->NewForEachStatement(mode, labels, stmt_pos);
@@ -3665,8 +3680,9 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
CHECK_OK);
}
} else {
- Scanner::Location lhs_location = scanner()->peek_location();
+ int lhs_beg_pos = peek_position();
Expression* expression = ParseExpression(false, CHECK_OK);
+ int lhs_end_pos = scanner()->location().end_pos;
ForEachStatement::VisitMode mode;
bool accept_OF = expression->IsVariableProxy();
is_let_identifier_expression =
@@ -3677,8 +3693,8 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
if (CheckInOrOf(accept_OF, &mode, ok)) {
if (!*ok) return nullptr;
expression = this->CheckAndRewriteReferenceExpression(
- expression, lhs_location, MessageTemplate::kInvalidLhsInFor,
- CHECK_OK);
+ expression, lhs_beg_pos, lhs_end_pos,
+ MessageTemplate::kInvalidLhsInFor, kSyntaxError, CHECK_OK);
ForEachStatement* loop =
factory()->NewForEachStatement(mode, labels, stmt_pos);
@@ -3697,8 +3713,7 @@ Statement* Parser::ParseForStatement(ZoneList<const AstRawString*>* labels,
return loop;
} else {
- init =
- factory()->NewExpressionStatement(expression, lhs_location.beg_pos);
+ init = factory()->NewExpressionStatement(expression, lhs_beg_pos);
}
}
}
@@ -3839,10 +3854,10 @@ Handle<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) {
void ParserTraits::ParseArrowFunctionFormalParameters(
- ParserFormalParameterParsingState* parsing_state, Expression* expr,
- const Scanner::Location& params_loc, Scanner::Location* duplicate_loc,
- bool* ok) {
- if (parsing_state->scope->num_parameters() >= Code::kMaxArguments) {
+ ParserFormalParameters* parameters, Expression* expr,
+ const Scanner::Location& params_loc,
+ Scanner::Location* duplicate_loc, bool* ok) {
+ if (parameters->Arity() >= Code::kMaxArguments) {
ReportMessageAt(params_loc, MessageTemplate::kMalformedArrowFunParamList);
*ok = false;
return;
@@ -3868,7 +3883,7 @@ void ParserTraits::ParseArrowFunctionFormalParameters(
DCHECK_EQ(binop->op(), Token::COMMA);
Expression* left = binop->left();
Expression* right = binop->right();
- ParseArrowFunctionFormalParameters(parsing_state, left, params_loc,
+ ParseArrowFunctionFormalParameters(parameters, left, params_loc,
duplicate_loc, ok);
if (!*ok) return;
// LHS of comma expression should be unparenthesized.
@@ -3876,12 +3891,15 @@ void ParserTraits::ParseArrowFunctionFormalParameters(
}
// Only the right-most expression may be a rest parameter.
- DCHECK(!parsing_state->has_rest);
+ DCHECK(!parameters->has_rest);
- bool is_rest = false;
- if (expr->IsSpread()) {
- is_rest = true;
+ bool is_rest = expr->IsSpread();
+ if (is_rest) {
expr = expr->AsSpread()->expression();
+ parameters->has_rest = true;
+ }
+ if (parameters->is_simple) {
+ parameters->is_simple = !is_rest && expr->IsVariableProxy();
}
if (expr->IsVariableProxy()) {
@@ -3893,20 +3911,48 @@ void ParserTraits::ParseArrowFunctionFormalParameters(
parser_->scope_->RemoveUnresolved(expr->AsVariableProxy());
}
- ExpressionClassifier classifier;
- DeclareFormalParameter(parsing_state, expr, &classifier, is_rest);
- if (!duplicate_loc->IsValid()) {
- *duplicate_loc = classifier.duplicate_formal_parameter_error().location;
+ Expression* initializer = nullptr;
+ if (!is_rest && parser_->allow_harmony_default_parameters() &&
+ parser_->Check(Token::ASSIGN)) {
+ ExpressionClassifier init_classifier;
+ initializer =
+ parser_->ParseAssignmentExpression(true, &init_classifier, ok);
+ if (!*ok) return;
+ parser_->ValidateExpression(&init_classifier, ok);
+ if (!*ok) return;
+ parameters->is_simple = false;
+ }
+
+ AddFormalParameter(parameters, expr, initializer, is_rest);
+}
+
+
+void ParserTraits::ParseArrowFunctionFormalParameterList(
+ ParserFormalParameters* parameters, Expression* expr,
+ const Scanner::Location& params_loc,
+ Scanner::Location* duplicate_loc, bool* ok) {
+ ParseArrowFunctionFormalParameters(parameters, expr, params_loc,
+ duplicate_loc, ok);
+ if (!*ok) return;
+
+ for (int i = 0; i < parameters->Arity(); ++i) {
+ auto parameter = parameters->at(i);
+ ExpressionClassifier classifier;
+ DeclareFormalParameter(
+ parameters->scope, parameter, parameters->is_simple, &classifier);
+ if (!duplicate_loc->IsValid()) {
+ *duplicate_loc = classifier.duplicate_formal_parameter_error().location;
+ }
}
+ DCHECK_EQ(parameters->is_simple, parameters->scope->has_simple_parameters());
}
-void ParserTraits::ReindexLiterals(
- const ParserFormalParameterParsingState& parsing_state) {
+void ParserTraits::ReindexLiterals(const ParserFormalParameters& parameters) {
if (parser_->function_state_->materialized_literal_count() > 0) {
AstLiteralReindexer reindexer;
- for (const auto p : parsing_state.params) {
+ for (const auto p : parameters.params) {
if (p.pattern != nullptr) reindexer.Reindex(p.pattern);
}
DCHECK(reindexer.count() <=
@@ -3917,8 +3963,8 @@ void ParserTraits::ReindexLiterals(
FunctionLiteral* Parser::ParseFunctionLiteral(
const AstRawString* function_name, Scanner::Location function_name_location,
- bool name_is_strict_reserved, FunctionKind kind, int function_token_pos,
- FunctionLiteral::FunctionType function_type,
+ FunctionNameValidity function_name_validity, FunctionKind kind,
+ int function_token_pos, FunctionLiteral::FunctionType function_type,
FunctionLiteral::ArityRestriction arity_restriction,
LanguageMode language_mode, bool* ok) {
// Function ::
@@ -3945,7 +3991,6 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
function_name = ast_value_factory()->empty_string();
}
- int num_parameters = 0;
// Function declarations are function scoped in normal mode, so they are
// hoisted. In harmony block scoping mode they are block scoped, so they
// are not hoisted.
@@ -3976,13 +4021,14 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
Scope* declaration_scope = scope_->DeclarationScope();
Scope* original_declaration_scope = original_scope_->DeclarationScope();
Scope* scope = function_type == FunctionLiteral::DECLARATION &&
- is_sloppy(language_mode) &&
+ is_sloppy(language_mode) && !allow_harmony_sloppy() &&
(original_scope_ == original_declaration_scope ||
declaration_scope != original_declaration_scope)
? NewScope(declaration_scope, FUNCTION_SCOPE, kind)
: NewScope(scope_, FUNCTION_SCOPE, kind);
scope->SetLanguageMode(language_mode);
ZoneList<Statement*>* body = NULL;
+ int arity = -1;
int materialized_literal_count = -1;
int expected_property_count = -1;
DuplicateFinder duplicate_finder(scanner()->unicode_cache());
@@ -3991,7 +4037,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
parenthesized_function_ ? FunctionLiteral::kShouldEagerCompile
: FunctionLiteral::kShouldLazyCompile;
bool should_be_used_once_hint = false;
- // Parse function body.
+ // Parse function.
{
AstNodeFactory function_factory(ast_value_factory());
FunctionState function_state(&function_state_, &scope_, scope, kind,
@@ -4007,7 +4053,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
// Calling a generator returns a generator object. That object is stored
// in a temporary variable, a definition that is used by "yield"
// expressions. This also marks the FunctionState as a generator.
- Variable* temp = scope_->DeclarationScope()->NewTemporary(
+ Variable* temp = scope_->NewTemporary(
ast_value_factory()->dot_generator_object_string());
function_state.set_generator_object_variable(temp);
}
@@ -4015,40 +4061,17 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
Expect(Token::LPAREN, CHECK_OK);
int start_position = scanner()->location().beg_pos;
scope_->set_start_position(start_position);
- ParserFormalParameterParsingState parsing_state(scope);
- num_parameters =
- ParseFormalParameterList(&parsing_state, &formals_classifier, CHECK_OK);
+ ParserFormalParameters formals(scope);
+ ParseFormalParameterList(&formals, &formals_classifier, CHECK_OK);
+ arity = formals.Arity();
Expect(Token::RPAREN, CHECK_OK);
int formals_end_position = scanner()->location().end_pos;
- CheckArityRestrictions(num_parameters, arity_restriction,
- parsing_state.has_rest, start_position,
+ CheckArityRestrictions(arity, arity_restriction,
+ formals.has_rest, start_position,
formals_end_position, CHECK_OK);
Expect(Token::LBRACE, CHECK_OK);
- // If we have a named function expression, we add a local variable
- // declaration to the body of the function with the name of the
- // function and let it refer to the function itself (closure).
- // NOTE: We create a proxy and resolve it here so that in the
- // future we can change the AST to only refer to VariableProxies
- // instead of Variables and Proxis as is the case now.
- Variable* fvar = NULL;
- Token::Value fvar_init_op = Token::INIT_CONST_LEGACY;
- if (function_type == FunctionLiteral::NAMED_EXPRESSION) {
- if (is_strict(language_mode)) {
- fvar_init_op = Token::INIT_CONST;
- }
- VariableMode fvar_mode = is_strict(language_mode) ? CONST : CONST_LEGACY;
- DCHECK(function_name != NULL);
- fvar = new (zone())
- Variable(scope_, function_name, fvar_mode, Variable::NORMAL,
- kCreatedInitialized, kNotAssigned);
- VariableProxy* proxy = factory()->NewVariableProxy(fvar);
- VariableDeclaration* fvar_declaration = factory()->NewVariableDeclaration(
- proxy, fvar_mode, scope_, RelocInfo::kNoPosition);
- scope_->DeclareFunctionVar(fvar_declaration);
- }
-
// Determine if the function can be parsed lazily. Lazy parsing is different
// from lazy compilation; we need to parse more eagerly than we compile.
@@ -4112,8 +4135,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
}
}
if (!is_lazily_parsed) {
- body = ParseEagerFunctionBody(function_name, pos, parsing_state, fvar,
- fvar_init_op, kind, CHECK_OK);
+ body = ParseEagerFunctionBody(function_name, pos, formals, kind,
+ function_type, CHECK_OK);
materialized_literal_count = function_state.materialized_literal_count();
expected_property_count = function_state.expected_property_count();
}
@@ -4133,19 +4156,18 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
// Validate name and parameter names. We can do this only after parsing the
// function, since the function can declare itself strict.
- CheckFunctionName(language_mode, kind, function_name,
- name_is_strict_reserved, function_name_location,
- CHECK_OK);
- const bool use_strict_params =
- !parsing_state.is_simple_parameter_list || IsConciseMethod(kind);
+ CheckFunctionName(language_mode, function_name, function_name_validity,
+ function_name_location, CHECK_OK);
const bool allow_duplicate_parameters =
- is_sloppy(language_mode) && !use_strict_params;
+ is_sloppy(language_mode) && formals.is_simple && !IsConciseMethod(kind);
ValidateFormalParameters(&formals_classifier, language_mode,
allow_duplicate_parameters, CHECK_OK);
if (is_strict(language_mode)) {
CheckStrictOctalLiteral(scope->start_position(), scope->end_position(),
CHECK_OK);
+ }
+ if (is_strict(language_mode) || allow_harmony_sloppy()) {
CheckConflictingVarDeclarations(scope, CHECK_OK);
}
}
@@ -4158,7 +4180,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
FunctionLiteral* function_literal = factory()->NewFunctionLiteral(
function_name, ast_value_factory(), scope, body,
- materialized_literal_count, expected_property_count, num_parameters,
+ materialized_literal_count, expected_property_count, arity,
duplicate_parameters, function_type, FunctionLiteral::kIsFunction,
eager_compile_hint, kind, pos);
function_literal->set_function_token_position(function_token_pos);
@@ -4300,15 +4322,15 @@ Statement* Parser::BuildAssertIsCoercible(Variable* var) {
Block* Parser::BuildParameterInitializationBlock(
- const ParserFormalParameterParsingState& formal_parameters, bool* ok) {
+ const ParserFormalParameters& parameters, bool* ok) {
+ DCHECK(!parameters.is_simple);
DCHECK(scope_->is_function_scope());
- Block* init_block = nullptr;
- for (auto parameter : formal_parameters.params) {
- if (parameter.pattern == nullptr) continue;
- if (init_block == nullptr) {
- init_block = factory()->NewBlock(NULL, 1, true, RelocInfo::kNoPosition);
- }
-
+ Block* init_block =
+ factory()->NewBlock(NULL, 1, true, RelocInfo::kNoPosition);
+ for (int i = 0; i < parameters.params.length(); ++i) {
+ auto parameter = parameters.params[i];
+ // TODO(caitp,rossberg): Remove special handling for rest once desugared.
+ if (parameter.is_rest) break;
DeclarationDescriptor descriptor;
descriptor.declaration_kind = DeclarationDescriptor::PARAMETER;
descriptor.parser = this;
@@ -4320,9 +4342,22 @@ Block* Parser::BuildParameterInitializationBlock(
descriptor.declaration_pos = parameter.pattern->position();
descriptor.initialization_pos = parameter.pattern->position();
descriptor.init_op = Token::INIT_LET;
+ Expression* initial_value =
+ factory()->NewVariableProxy(parameters.scope->parameter(i));
+ if (parameter.initializer != nullptr) {
+ // IS_UNDEFINED($param) ? initializer : $param
+ auto condition = factory()->NewCompareOperation(
+ Token::EQ_STRICT,
+ factory()->NewVariableProxy(parameters.scope->parameter(i)),
+ factory()->NewUndefinedLiteral(RelocInfo::kNoPosition),
+ RelocInfo::kNoPosition);
+ initial_value = factory()->NewConditional(
+ condition, parameter.initializer, initial_value,
+ RelocInfo::kNoPosition);
+ descriptor.initialization_pos = parameter.initializer->position();
+ }
DeclarationParsingResult::Declaration decl(
- parameter.pattern, parameter.pattern->position(),
- factory()->NewVariableProxy(parameter.var));
+ parameter.pattern, parameter.pattern->position(), initial_value);
PatternRewriter::DeclareAndInitializeVariables(init_block, &descriptor,
&decl, nullptr, CHECK_OK);
}
@@ -4332,81 +4367,140 @@ Block* Parser::BuildParameterInitializationBlock(
ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
const AstRawString* function_name, int pos,
- const ParserFormalParameterParsingState& formal_parameters, Variable* fvar,
- Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
+ const ParserFormalParameters& parameters, FunctionKind kind,
+ FunctionLiteral::FunctionType function_type, bool* ok) {
// Everything inside an eagerly parsed function will be parsed eagerly
// (see comment above).
ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
- ZoneList<Statement*>* body = new(zone()) ZoneList<Statement*>(8, zone());
- if (fvar != NULL) {
- VariableProxy* fproxy = scope_->NewUnresolved(factory(), function_name);
- fproxy->BindTo(fvar);
- body->Add(factory()->NewExpressionStatement(
- factory()->NewAssignment(fvar_init_op,
- fproxy,
- factory()->NewThisFunction(pos),
- RelocInfo::kNoPosition),
- RelocInfo::kNoPosition), zone());
- }
+ ZoneList<Statement*>* result = new(zone()) ZoneList<Statement*>(8, zone());
+ static const int kFunctionNameAssignmentIndex = 0;
+ if (function_type == FunctionLiteral::NAMED_EXPRESSION) {
+ DCHECK(function_name != NULL);
+ // If we have a named function expression, we add a local variable
+ // declaration to the body of the function with the name of the
+ // function and let it refer to the function itself (closure).
+ // Not having parsed the function body, the language mode may still change,
+ // so we reserve a spot and create the actual const assignment later.
+ DCHECK_EQ(kFunctionNameAssignmentIndex, result->length());
+ result->Add(NULL, zone());
+ }
// For concise constructors, check that they are constructed,
// not called.
if (i::IsConstructor(kind)) {
- AddAssertIsConstruct(body, pos);
+ AddAssertIsConstruct(result, pos);
}
- auto init_block =
- BuildParameterInitializationBlock(formal_parameters, CHECK_OK);
- if (init_block != nullptr) {
- body->Add(init_block, zone());
+ ZoneList<Statement*>* body = result;
+ Scope* inner_scope = nullptr;
+ Block* inner_block = nullptr;
+ if (!parameters.is_simple) {
+ inner_scope = NewScope(scope_, BLOCK_SCOPE);
+ inner_scope->set_is_declaration_scope();
+ inner_scope->set_start_position(scanner()->location().beg_pos);
+ inner_block = factory()->NewBlock(NULL, 8, true, RelocInfo::kNoPosition);
+ inner_block->set_scope(inner_scope);
+ body = inner_block->statements();
}
- // For generators, allocate and yield an iterator on function entry.
- if (IsGeneratorFunction(kind)) {
- ZoneList<Expression*>* arguments =
- new(zone()) ZoneList<Expression*>(0, zone());
- CallRuntime* allocation = factory()->NewCallRuntime(
- ast_value_factory()->empty_string(),
- Runtime::FunctionForId(Runtime::kCreateJSGeneratorObject), arguments,
- pos);
- VariableProxy* init_proxy = factory()->NewVariableProxy(
- function_state_->generator_object_variable());
- Assignment* assignment = factory()->NewAssignment(
- Token::INIT_VAR, init_proxy, allocation, RelocInfo::kNoPosition);
- VariableProxy* get_proxy = factory()->NewVariableProxy(
- function_state_->generator_object_variable());
- Yield* yield = factory()->NewYield(
- get_proxy, assignment, Yield::kInitial, RelocInfo::kNoPosition);
- body->Add(factory()->NewExpressionStatement(
- yield, RelocInfo::kNoPosition), zone());
- }
+ {
+ BlockState block_state(&scope_, inner_scope ? inner_scope : scope_);
- ParseStatementList(body, Token::RBRACE, CHECK_OK);
+ // For generators, allocate and yield an iterator on function entry.
+ if (IsGeneratorFunction(kind)) {
+ ZoneList<Expression*>* arguments =
+ new(zone()) ZoneList<Expression*>(0, zone());
+ CallRuntime* allocation = factory()->NewCallRuntime(
+ ast_value_factory()->empty_string(),
+ Runtime::FunctionForId(Runtime::kCreateJSGeneratorObject), arguments,
+ pos);
+ VariableProxy* init_proxy = factory()->NewVariableProxy(
+ function_state_->generator_object_variable());
+ Assignment* assignment = factory()->NewAssignment(
+ Token::INIT_VAR, init_proxy, allocation, RelocInfo::kNoPosition);
+ VariableProxy* get_proxy = factory()->NewVariableProxy(
+ function_state_->generator_object_variable());
+ Yield* yield = factory()->NewYield(
+ get_proxy, assignment, Yield::kInitial, RelocInfo::kNoPosition);
+ body->Add(factory()->NewExpressionStatement(
+ yield, RelocInfo::kNoPosition), zone());
+ }
- if (IsGeneratorFunction(kind)) {
- VariableProxy* get_proxy = factory()->NewVariableProxy(
- function_state_->generator_object_variable());
- Expression* undefined =
- factory()->NewUndefinedLiteral(RelocInfo::kNoPosition);
- Yield* yield = factory()->NewYield(get_proxy, undefined, Yield::kFinal,
- RelocInfo::kNoPosition);
- body->Add(factory()->NewExpressionStatement(
- yield, RelocInfo::kNoPosition), zone());
- }
-
- if (IsSubclassConstructor(kind)) {
- body->Add(
- factory()->NewReturnStatement(
- this->ThisExpression(scope_, factory(), RelocInfo::kNoPosition),
- RelocInfo::kNoPosition),
- zone());
+ ParseStatementList(body, Token::RBRACE, CHECK_OK);
+
+ if (IsGeneratorFunction(kind)) {
+ VariableProxy* get_proxy = factory()->NewVariableProxy(
+ function_state_->generator_object_variable());
+ Expression* undefined =
+ factory()->NewUndefinedLiteral(RelocInfo::kNoPosition);
+ Yield* yield = factory()->NewYield(get_proxy, undefined, Yield::kFinal,
+ RelocInfo::kNoPosition);
+ body->Add(factory()->NewExpressionStatement(
+ yield, RelocInfo::kNoPosition), zone());
+ }
+
+ if (IsSubclassConstructor(kind)) {
+ body->Add(
+ factory()->NewReturnStatement(
+ this->ThisExpression(scope_, factory(), RelocInfo::kNoPosition),
+ RelocInfo::kNoPosition),
+ zone());
+ }
}
Expect(Token::RBRACE, CHECK_OK);
scope_->set_end_position(scanner()->location().end_pos);
- return body;
+ if (!parameters.is_simple) {
+ DCHECK_NOT_NULL(inner_scope);
+ DCHECK_EQ(body, inner_block->statements());
+ scope_->SetLanguageMode(inner_scope->language_mode());
+ Block* init_block = BuildParameterInitializationBlock(parameters, CHECK_OK);
+ DCHECK_NOT_NULL(init_block);
+
+ inner_scope->set_end_position(scanner()->location().end_pos);
+ inner_scope = inner_scope->FinalizeBlockScope();
+ if (inner_scope != nullptr) {
+ CheckConflictingVarDeclarations(inner_scope, CHECK_OK);
+ }
+
+ result->Add(init_block, zone());
+ result->Add(inner_block, zone());
+ }
+
+ if (function_type == FunctionLiteral::NAMED_EXPRESSION) {
+ // Now that we know the language mode, we can create the const assignment
+ // in the previously reserved spot.
+ // NOTE: We create a proxy and resolve it here so that in the
+ // future we can change the AST to only refer to VariableProxies
+ // instead of Variables and Proxies as is the case now.
+ Token::Value fvar_init_op = Token::INIT_CONST_LEGACY;
+ bool use_strict_const = is_strict(scope_->language_mode()) ||
+ (!allow_legacy_const() && allow_harmony_sloppy());
+ if (use_strict_const) {
+ fvar_init_op = Token::INIT_CONST;
+ }
+ VariableMode fvar_mode = use_strict_const ? CONST : CONST_LEGACY;
+ Variable* fvar = new (zone())
+ Variable(scope_, function_name, fvar_mode, Variable::NORMAL,
+ kCreatedInitialized, kNotAssigned);
+ VariableProxy* proxy = factory()->NewVariableProxy(fvar);
+ VariableDeclaration* fvar_declaration = factory()->NewVariableDeclaration(
+ proxy, fvar_mode, scope_, RelocInfo::kNoPosition);
+ scope_->DeclareFunctionVar(fvar_declaration);
+
+ VariableProxy* fproxy = scope_->NewUnresolved(factory(), function_name);
+ fproxy->BindTo(fvar);
+ result->Set(kFunctionNameAssignmentIndex,
+ factory()->NewExpressionStatement(
+ factory()->NewAssignment(fvar_init_op, fproxy,
+ factory()->NewThisFunction(pos),
+ RelocInfo::kNoPosition),
+ RelocInfo::kNoPosition));
+ }
+
+ return result;
}
@@ -4425,12 +4519,11 @@ PreParser::PreParseResult Parser::ParseLazyFunctionBodyWithPreParser(
reusable_preparser_->set_allow_lazy(true);
#define SET_ALLOW(name) reusable_preparser_->set_allow_##name(allow_##name());
SET_ALLOW(natives);
- SET_ALLOW(harmony_modules);
SET_ALLOW(harmony_arrow_functions);
SET_ALLOW(harmony_sloppy);
- SET_ALLOW(harmony_unicode);
- SET_ALLOW(harmony_computed_property_names);
- SET_ALLOW(harmony_rest_params);
+ SET_ALLOW(harmony_sloppy_let);
+ SET_ALLOW(harmony_rest_parameters);
+ SET_ALLOW(harmony_default_parameters);
SET_ALLOW(harmony_spreadcalls);
SET_ALLOW(harmony_destructuring);
SET_ALLOW(harmony_spread_arrays);
@@ -4472,7 +4565,7 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name,
Scope* block_scope = NewScope(scope_, BLOCK_SCOPE);
BlockState block_state(&scope_, block_scope);
scope_->SetLanguageMode(
- static_cast<LanguageMode>(scope_->language_mode() | STRICT_BIT));
+ static_cast<LanguageMode>(scope_->language_mode() | STRICT));
scope_->SetScopeName(name);
VariableProxy* proxy = NULL;
@@ -5634,7 +5727,7 @@ bool RegExpParser::ParseRegExp(Isolate* isolate, Zone* zone,
bool Parser::ParseStatic(ParseInfo* info) {
Parser parser(info);
if (parser.Parse(info)) {
- info->set_language_mode(info->function()->language_mode());
+ info->set_language_mode(info->literal()->language_mode());
return true;
}
return false;
@@ -5642,7 +5735,7 @@ bool Parser::ParseStatic(ParseInfo* info) {
bool Parser::Parse(ParseInfo* info) {
- DCHECK(info->function() == NULL);
+ DCHECK(info->literal() == NULL);
FunctionLiteral* result = NULL;
// Ok to use Isolate here; this function is only called in the main thread.
DCHECK(parsing_on_main_thread_);
@@ -5677,7 +5770,7 @@ bool Parser::Parse(ParseInfo* info) {
void Parser::ParseOnBackground(ParseInfo* info) {
parsing_on_main_thread_ = false;
- DCHECK(info->function() == NULL);
+ DCHECK(info->literal() == NULL);
FunctionLiteral* result = NULL;
fni_ = new (zone()) FuncNameInferrer(ast_value_factory(), zone());
@@ -5903,16 +5996,16 @@ Expression* Parser::SpreadCall(Expression* function,
int pos) {
if (function->IsSuperCallReference()) {
// Super calls
- // %_CallSuperWithSpread(%ReflectConstruct(<super>, args, new.target))
- args->InsertAt(0, function, zone());
+ // %ReflectConstruct(%GetPrototype(<this-function>), args, new.target))
+ ZoneList<Expression*>* tmp = new (zone()) ZoneList<Expression*>(1, zone());
+ tmp->Add(function->AsSuperCallReference()->this_function_var(), zone());
+ Expression* get_prototype = factory()->NewCallRuntime(
+ ast_value_factory()->empty_string(),
+ Runtime::FunctionForId(Runtime::kGetPrototype), tmp, pos);
+ args->InsertAt(0, get_prototype, zone());
args->Add(function->AsSuperCallReference()->new_target_var(), zone());
- Expression* result = factory()->NewCallRuntime(
- ast_value_factory()->reflect_construct_string(), NULL, args, pos);
- args = new (zone()) ZoneList<Expression*>(1, zone());
- args->Add(result, zone());
return factory()->NewCallRuntime(
- ast_value_factory()->empty_string(),
- Runtime::FunctionForId(Runtime::kInlineCallSuperWithSpread), args, pos);
+ ast_value_factory()->reflect_construct_string(), NULL, args, pos);
} else {
if (function->IsProperty()) {
// Method calls