NewScope(scope_, ARROW_SCOPE, FunctionKind::kArrowFunction);
scope->set_start_position(shared_info->start_position());
ExpressionClassifier formals_classifier;
- bool has_rest = false;
+ ParserFormalParameterParsingState parsing_state(scope);
{
// Parsing patterns as variable reference expression creates
// NewUnresolved references in current scope. Entrer arrow function
BlockState block_state(&scope_, scope);
if (Check(Token::LPAREN)) {
// '(' StrictFormalParameters ')'
- ParseFormalParameterList(scope, &has_rest, &formals_classifier, &ok);
+ ParseFormalParameterList(&parsing_state, &formals_classifier, &ok);
if (ok) ok = Check(Token::RPAREN);
} else {
// BindingIdentifier
- ParseFormalParameter(scope, has_rest, &formals_classifier, &ok);
+ const bool is_rest = false;
+ ParseFormalParameter(is_rest, &parsing_state, &formals_classifier,
+ &ok);
}
}
if (ok) {
Expression* expression =
- ParseArrowFunctionLiteral(scope, has_rest, formals_classifier, &ok);
+ ParseArrowFunctionLiteral(parsing_state, 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
VariableProxy* proxy = NewUnresolved(local_name, IMPORT);
ImportDeclaration* declaration =
factory()->NewImportDeclaration(proxy, import_name, NULL, scope_, pos);
- Declare(declaration, true, CHECK_OK);
+ Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
result->Add(declaration, zone());
if (peek() == Token::RBRACE) break;
Expect(Token::COMMA, CHECK_OK);
VariableProxy* proxy = NewUnresolved(local_name, IMPORT);
import_default_declaration = factory()->NewImportDeclaration(
proxy, ast_value_factory()->default_string(), NULL, scope_, pos);
- Declare(import_default_declaration, true, CHECK_OK);
+ Declare(import_default_declaration, DeclarationDescriptor::NORMAL, true,
+ CHECK_OK);
}
const AstRawString* module_instance_binding = NULL;
}
-Variable* Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
+Variable* Parser::Declare(Declaration* declaration,
+ DeclarationDescriptor::Kind declaration_kind,
+ bool resolve, bool* ok) {
VariableProxy* proxy = declaration->proxy();
DCHECK(proxy->raw_name() != NULL);
const AstRawString* name = proxy->raw_name();
if (is_strict(language_mode())) {
// In harmony we treat re-declarations as early errors. See
// ES5 16 for a definition of early errors.
- ParserTraits::ReportMessage(MessageTemplate::kVarRedeclaration, name);
+ if (declaration_kind == DeclarationDescriptor::NORMAL) {
+ ParserTraits::ReportMessage(MessageTemplate::kVarRedeclaration, name);
+ } else {
+ ParserTraits::ReportMessage(MessageTemplate::kStrictParamDupe);
+ }
*ok = false;
return nullptr;
}
- Expression* expression = NewThrowTypeError(
+ Expression* expression = NewThrowSyntaxError(
MessageTemplate::kVarRedeclaration, name, declaration->position());
declaration_scope->SetIllegalRedeclaration(expression);
} else if (mode == VAR) {
VariableProxy* proxy = NewUnresolved(name, VAR);
Declaration* declaration =
factory()->NewVariableDeclaration(proxy, VAR, scope_, pos);
- Declare(declaration, true, CHECK_OK);
+ Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
NativeFunctionLiteral* lit = factory()->NewNativeFunctionLiteral(
name, extension_, RelocInfo::kNoPosition);
return factory()->NewExpressionStatement(
VariableProxy* proxy = NewUnresolved(name, mode);
Declaration* declaration =
factory()->NewFunctionDeclaration(proxy, mode, fun, scope_, pos);
- Declare(declaration, true, CHECK_OK);
+ Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
if (names) names->Add(name, zone());
return factory()->NewEmptyStatement(RelocInfo::kNoPosition);
}
Declaration* declaration = factory()->NewVariableDeclaration(
proxy, mode, scope_, pos, is_class_declaration,
scope_->class_declaration_group_start());
- Variable* outer_class_variable = Declare(declaration, true, CHECK_OK);
+ Variable* outer_class_variable =
+ Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
proxy->var()->set_initializer_position(position());
// This is needed because a class ("class Name { }") creates two bindings (one
// in the outer scope, and one in the class scope). The method is a function
// BindingPattern '=' AssignmentExpression
parsing_result->descriptor.parser = this;
+ parsing_result->descriptor.declaration_kind = DeclarationDescriptor::NORMAL;
parsing_result->descriptor.declaration_pos = peek_position();
parsing_result->descriptor.initialization_pos = peek_position();
parsing_result->descriptor.mode = VAR;
VariableProxy* proxy = NewUnresolved(names->at(i), mode);
Declaration* declaration = factory()->NewVariableDeclaration(
proxy, mode, scope_, RelocInfo::kNoPosition);
- Declare(declaration, true, CHECK_OK);
+ Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
inner_vars.Add(declaration->proxy()->var(), zone());
VariableProxy* temp_proxy = factory()->NewVariableProxy(temps.at(i));
Assignment* assignment =
void ParserTraits::ParseArrowFunctionFormalParameters(
- Scope* scope, Expression* expr, const Scanner::Location& params_loc,
- bool* has_rest, Scanner::Location* duplicate_loc, bool* ok) {
- if (scope->num_parameters() >= Code::kMaxArguments) {
+ ParserFormalParameterParsingState* parsing_state, Expression* expr,
+ const Scanner::Location& params_loc, Scanner::Location* duplicate_loc,
+ bool* ok) {
+ if (parsing_state->scope->num_parameters() >= Code::kMaxArguments) {
ReportMessageAt(params_loc, MessageTemplate::kMalformedArrowFunParamList);
*ok = false;
return;
DCHECK_EQ(binop->op(), Token::COMMA);
Expression* left = binop->left();
Expression* right = binop->right();
- ParseArrowFunctionFormalParameters(scope, left, params_loc, has_rest,
+ ParseArrowFunctionFormalParameters(parsing_state, left, params_loc,
duplicate_loc, ok);
if (!*ok) return;
// LHS of comma expression should be unparenthesized.
}
// Only the right-most expression may be a rest parameter.
- DCHECK(!*has_rest);
+ DCHECK(!parsing_state->has_rest);
+ bool is_rest = false;
if (expr->IsSpread()) {
- *has_rest = true;
+ is_rest = true;
expr = expr->AsSpread()->expression();
}
- if (!expr->IsVariableProxy()) {
- // TODO(dslomov): support pattern desugaring
- return;
+ if (expr->IsVariableProxy()) {
+ // When the formal parameter was originally seen, it was parsed as a
+ // VariableProxy and recorded as unresolved in the scope. Here we undo that
+ // parse-time side-effect for parameters that are single-names (not
+ // patterns; for patterns that happens uniformly in
+ // PatternRewriter::VisitVariableProxy).
+ parser_->scope_->RemoveUnresolved(expr->AsVariableProxy());
}
- DCHECK(!expr->AsVariableProxy()->is_this());
-
- const AstRawString* raw_name = expr->AsVariableProxy()->raw_name();
- Scanner::Location param_location(expr->position(),
- expr->position() + raw_name->length());
-
- // When the formal parameter was originally seen, it was parsed as a
- // VariableProxy and recorded as unresolved in the scope. Here we undo that
- // parse-time side-effect.
- parser_->scope_->RemoveUnresolved(expr->AsVariableProxy());
ExpressionClassifier classifier;
- DeclareFormalParameter(scope, expr, &classifier, *has_rest);
+ DeclareFormalParameter(parsing_state, expr, &classifier, is_rest);
if (!duplicate_loc->IsValid()) {
*duplicate_loc = classifier.duplicate_formal_parameter_error().location;
}
ZoneList<Statement*>* body = NULL;
int materialized_literal_count = -1;
int expected_property_count = -1;
- ExpressionClassifier formals_classifier;
+ DuplicateFinder duplicate_finder(scanner()->unicode_cache());
+ ExpressionClassifier formals_classifier(&duplicate_finder);
FunctionLiteral::EagerCompileHint eager_compile_hint =
parenthesized_function_ ? FunctionLiteral::kShouldEagerCompile
: FunctionLiteral::kShouldLazyCompile;
function_state.set_generator_object_variable(temp);
}
- bool has_rest = false;
Expect(Token::LPAREN, CHECK_OK);
int start_position = scanner()->location().beg_pos;
scope_->set_start_position(start_position);
- num_parameters = ParseFormalParameterList(scope, &has_rest,
- &formals_classifier, CHECK_OK);
+ ParserFormalParameterParsingState parsing_state(scope);
+ num_parameters =
+ ParseFormalParameterList(&parsing_state, &formals_classifier, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
int formals_end_position = scanner()->location().end_pos;
- CheckArityRestrictions(num_parameters, arity_restriction, has_rest,
- start_position, formals_end_position, CHECK_OK);
-
+ CheckArityRestrictions(num_parameters, arity_restriction,
+ parsing_state.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
}
}
if (!is_lazily_parsed) {
- body = ParseEagerFunctionBody(function_name, pos, fvar, fvar_init_op,
- kind, CHECK_OK);
+ body = ParseEagerFunctionBody(function_name, pos, parsing_state, fvar,
+ fvar_init_op, kind, CHECK_OK);
materialized_literal_count = function_state.materialized_literal_count();
expected_property_count = function_state.expected_property_count();
CheckFunctionName(language_mode(), kind, function_name,
name_is_strict_reserved, function_name_location,
CHECK_OK);
- const bool use_strict_params = has_rest || IsConciseMethod(kind);
+ const bool use_strict_params =
+ !parsing_state.is_simple_parameter_list || IsConciseMethod(kind);
const bool allow_duplicate_parameters =
is_sloppy(language_mode()) && !use_strict_params;
ValidateFormalParameters(&formals_classifier, language_mode(),
}
+Block* Parser::BuildParameterInitializationBlock(
+ const ParserFormalParameterParsingState& formal_parameters, bool* ok) {
+ 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);
+ }
+
+ DeclarationDescriptor descriptor;
+ descriptor.declaration_kind = DeclarationDescriptor::PARAMETER;
+ descriptor.parser = this;
+ descriptor.declaration_scope = scope_;
+ descriptor.scope = scope_;
+ descriptor.mode = LET;
+ descriptor.is_const = false;
+ descriptor.needs_init = true;
+ descriptor.declaration_pos = parameter.pattern->position();
+ descriptor.initialization_pos = parameter.pattern->position();
+ descriptor.init_op = Token::INIT_LET;
+ DeclarationParsingResult::Declaration decl(
+ parameter.pattern, parameter.pattern->position(),
+ factory()->NewVariableProxy(parameter.var));
+ PatternRewriter::DeclareAndInitializeVariables(init_block, &descriptor,
+ &decl, nullptr, CHECK_OK);
+ }
+ return init_block;
+}
+
+
ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
- const AstRawString* function_name, int pos, Variable* fvar,
+ const AstRawString* function_name, int pos,
+ const ParserFormalParameterParsingState& formal_parameters, Variable* fvar,
Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
// Everything inside an eagerly parsed function will be parsed eagerly
// (see comment above).
AddAssertIsConstruct(body, pos);
}
+ auto init_block =
+ BuildParameterInitializationBlock(formal_parameters, CHECK_OK);
+ if (init_block != nullptr) {
+ body->Add(init_block, zone());
+ }
+
// For generators, allocate and yield an iterator on function entry.
if (IsGeneratorFunction(kind)) {
ZoneList<Expression*>* arguments =
Declaration* declaration = factory()->NewVariableDeclaration(
proxy, CONST, block_scope, pos, is_class_declaration,
scope_->class_declaration_group_start());
- Declare(declaration, true, CHECK_OK);
+ Declare(declaration, DeclarationDescriptor::NORMAL, true, CHECK_OK);
}
Expression* extends = NULL;
class Parser;
class SingletonLogger;
+
+struct ParserFormalParameterParsingState
+ : public PreParserFormalParameterParsingState {
+ struct Parameter {
+ Parameter(Variable* var, Expression* pattern)
+ : var(var), pattern(pattern) {}
+ Variable* var;
+ Expression* pattern;
+ };
+
+ explicit ParserFormalParameterParsingState(Scope* scope)
+ : PreParserFormalParameterParsingState(scope), params(4, scope->zone()) {}
+
+ ZoneList<Parameter> params;
+
+ void AddParameter(Variable* var, Expression* pattern) {
+ params.Add(Parameter(var, pattern), scope->zone());
+ }
+};
+
+
class ParserTraits {
public:
struct Type {
typedef ZoneList<v8::internal::Expression*>* ExpressionList;
typedef ZoneList<ObjectLiteral::Property*>* PropertyList;
typedef const v8::internal::AstRawString* FormalParameter;
- typedef Scope FormalParameterScope;
+ typedef ParserFormalParameterParsingState FormalParameterParsingState;
typedef ZoneList<v8::internal::Statement*>* StatementList;
// For constructing objects returned by the traversing functions.
ZoneList<v8::internal::Statement*>* NewStatementList(int size, Zone* zone) {
return new(zone) ZoneList<v8::internal::Statement*>(size, zone);
}
+
+ V8_INLINE void AddParameterInitializationBlock(
+ const ParserFormalParameterParsingState& formal_parameters,
+ ZoneList<v8::internal::Statement*>* body, bool* ok);
+
V8_INLINE Scope* NewScope(Scope* parent_scope, ScopeType scope_type,
FunctionKind kind = kNormalFunction);
- V8_INLINE void DeclareFormalParameter(Scope* scope, Expression* name,
- ExpressionClassifier* classifier,
- bool is_rest);
- void ParseArrowFunctionFormalParameters(Scope* scope, Expression* params,
- const Scanner::Location& params_loc,
- bool* has_rest,
- Scanner::Location* duplicate_loc,
- bool* ok);
+ V8_INLINE void DeclareFormalParameter(
+ ParserFormalParameterParsingState* parsing_state, Expression* name,
+ ExpressionClassifier* classifier, bool is_rest);
+ void ParseArrowFunctionFormalParameters(
+ ParserFormalParameterParsingState* scope, Expression* params,
+ const Scanner::Location& params_loc, Scanner::Location* duplicate_loc,
+ bool* ok);
// Temporary glue; these functions will move to ParserBase.
Expression* ParseV8Intrinsic(bool* ok);
int* materialized_literal_count, int* expected_property_count, bool* ok,
Scanner::BookmarkScope* bookmark = nullptr);
V8_INLINE ZoneList<Statement*>* ParseEagerFunctionBody(
- const AstRawString* name, int pos, Variable* fvar,
- Token::Value fvar_init_op, FunctionKind kind, bool* ok);
+ const AstRawString* name, int pos,
+ const ParserFormalParameterParsingState& formal_parameters,
+ Variable* fvar, Token::Value fvar_init_op, FunctionKind kind, bool* ok);
ClassLiteral* ParseClassLiteral(const AstRawString* name,
Scanner::Location class_name_location,
bool* ok);
struct DeclarationDescriptor {
+ enum Kind { NORMAL, PARAMETER };
Parser* parser;
Scope* declaration_scope;
Scope* scope;
int declaration_pos;
int initialization_pos;
Token::Value init_op;
+ Kind declaration_kind;
};
struct DeclarationParsingResult {
// Parser support
VariableProxy* NewUnresolved(const AstRawString* name, VariableMode mode);
- Variable* Declare(Declaration* declaration, bool resolve, bool* ok);
+ Variable* Declare(Declaration* declaration,
+ DeclarationDescriptor::Kind declaration_kind, bool resolve,
+ bool* ok);
bool TargetStackContainsLabel(const AstRawString* label);
BreakableStatement* LookupBreakTarget(const AstRawString* label, bool* ok);
PreParser::PreParseResult ParseLazyFunctionBodyWithPreParser(
SingletonLogger* logger, Scanner::BookmarkScope* bookmark = nullptr);
+ Block* BuildParameterInitializationBlock(
+ const ParserFormalParameterParsingState& formal_parameters, bool* ok);
+
// Consumes the ending }.
ZoneList<Statement*>* ParseEagerFunctionBody(
- const AstRawString* function_name, int pos, Variable* fvar,
- Token::Value fvar_init_op, FunctionKind kind, bool* ok);
+ const AstRawString* function_name, int pos,
+ const ParserFormalParameterParsingState& formal_parameters,
+ Variable* fvar, Token::Value fvar_init_op, FunctionKind kind, bool* ok);
void ThrowPendingError(Isolate* isolate, Handle<Script> script);
ZoneList<Statement*>* ParserTraits::ParseEagerFunctionBody(
- const AstRawString* name, int pos, Variable* fvar,
+ const AstRawString* name, int pos,
+ const ParserFormalParameterParsingState& formal_parameters, Variable* fvar,
Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
- return parser_->ParseEagerFunctionBody(name, pos, fvar, fvar_init_op, kind,
- ok);
+ return parser_->ParseEagerFunctionBody(name, pos, formal_parameters, fvar,
+ fvar_init_op, kind, ok);
}
void ParserTraits::CheckConflictingVarDeclarations(v8::internal::Scope* scope,
}
-void ParserTraits::DeclareFormalParameter(Scope* scope, Expression* pattern,
- ExpressionClassifier* classifier,
- bool is_rest) {
+void ParserTraits::DeclareFormalParameter(
+ ParserFormalParameterParsingState* parsing_state, Expression* pattern,
+ ExpressionClassifier* classifier, bool is_rest) {
bool is_duplicate = false;
- if (!pattern->IsVariableProxy()) {
- // TODO(dslomov): implement.
- DCHECK(parser_->allow_harmony_destructuring());
- return;
- }
- auto name = pattern->AsVariableProxy()->raw_name();
- Variable* var = scope->DeclareParameter(name, VAR, is_rest, &is_duplicate);
- if (is_sloppy(scope->language_mode())) {
+ bool is_simple_name = pattern->IsVariableProxy();
+ DCHECK(parser_->allow_harmony_destructuring() || is_simple_name);
+
+ const AstRawString* name = is_simple_name
+ ? pattern->AsVariableProxy()->raw_name()
+ : parser_->ast_value_factory()->empty_string();
+ Variable* var =
+ parsing_state->scope->DeclareParameter(name, VAR, is_rest, &is_duplicate);
+ parsing_state->AddParameter(var, is_simple_name ? nullptr : pattern);
+ if (is_sloppy(parsing_state->scope->language_mode())) {
// TODO(sigurds) Mark every parameter as maybe assigned. This is a
// conservative approximation necessary to account for parameters
// that are assigned via the arguments array.
parser_->scanner()->location());
}
}
+
+
+void ParserTraits::AddParameterInitializationBlock(
+ const ParserFormalParameterParsingState& formal_parameters,
+ ZoneList<v8::internal::Statement*>* body, bool* ok) {
+ auto* init_block =
+ parser_->BuildParameterInitializationBlock(formal_parameters, ok);
+ if (!*ok) return;
+ if (init_block != nullptr) {
+ body->Add(init_block, parser_->zone());
+ }
+}
} } // namespace v8::internal
#endif // V8_PARSER_H_
Declaration* declaration = factory()->NewVariableDeclaration(
proxy, descriptor_->mode, descriptor_->scope,
descriptor_->declaration_pos);
- Variable* var = parser->Declare(declaration, descriptor_->mode != VAR, ok_);
+ Variable* var = parser->Declare(declaration, descriptor_->declaration_kind,
+ descriptor_->mode != VAR, ok_);
if (!*ok_) return;
DCHECK_NOT_NULL(var);
DCHECK(!proxy->is_resolved() || proxy->var() == var);
DuplicateFinder duplicate_finder(scanner()->unicode_cache());
ExpressionClassifier formals_classifier(&duplicate_finder);
- bool has_rest = false;
Expect(Token::LPAREN, CHECK_OK);
int start_position = scanner()->location().beg_pos;
function_scope->set_start_position(start_position);
- int num_parameters = ParseFormalParameterList(nullptr, &has_rest,
- &formals_classifier, CHECK_OK);
+ PreParserFormalParameterParsingState parsing_state(nullptr);
+ int num_parameters =
+ ParseFormalParameterList(&parsing_state, &formals_classifier, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
int formals_end_position = scanner()->location().end_pos;
- CheckArityRestrictions(num_parameters, arity_restriction, has_rest,
- start_position, formals_end_position, CHECK_OK);
+ CheckArityRestrictions(num_parameters, arity_restriction,
+ parsing_state.has_rest, start_position,
+ formals_end_position, CHECK_OK);
// See Parser::ParseFunctionLiteral for more information about lazy parsing
// and lazy compilation.
// 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 strict_formal_parameters = has_rest || IsConciseMethod(kind);
+ const bool strict_formal_parameters =
+ !parsing_state.is_simple_parameter_list || IsConciseMethod(kind);
const bool allow_duplicate_parameters =
is_sloppy(language_mode()) && !strict_formal_parameters;
ValidateFormalParameters(&formals_classifier, language_mode(),
typedef typename Traits::Type::FunctionLiteral FunctionLiteralT;
typedef typename Traits::Type::Literal LiteralT;
typedef typename Traits::Type::ObjectLiteralProperty ObjectLiteralPropertyT;
+ typedef typename Traits::Type::FormalParameterParsingState
+ FormalParameterParsingStateT;
ParserBase(Zone* zone, Scanner* scanner, uintptr_t stack_limit,
v8::Extension* extension, AstValueFactory* ast_value_factory,
ExpressionT expr, bool* ok) {
if (classifier->is_valid_binding_pattern()) {
// A simple arrow formal parameter: IDENTIFIER => BODY.
- if (!allow_harmony_destructuring() && !this->IsIdentifier(expr)) {
+ if (!this->IsIdentifier(expr)) {
Traits::ReportMessageAt(scanner()->location(),
MessageTemplate::kUnexpectedToken,
Token::String(scanner()->current_token()));
ExpressionT ParseMemberExpression(ExpressionClassifier* classifier, bool* ok);
ExpressionT ParseMemberExpressionContinuation(
ExpressionT expression, ExpressionClassifier* classifier, bool* ok);
- ExpressionT ParseArrowFunctionLiteral(Scope* function_scope, bool has_rest,
- const ExpressionClassifier& classifier,
- bool* ok);
+ ExpressionT ParseArrowFunctionLiteral(
+ const FormalParameterParsingStateT& parsing_state,
+ const ExpressionClassifier& classifier, bool* ok);
ExpressionT ParseTemplateLiteral(ExpressionT tag, int start,
ExpressionClassifier* classifier, bool* ok);
void AddTemplateExpression(ExpressionT);
ExpressionT ParseStrongSuperCallExpression(ExpressionClassifier* classifier,
bool* ok);
- void ParseFormalParameter(Scope* scope, bool is_rest,
+ void ParseFormalParameter(bool is_rest,
+ FormalParameterParsingStateT* parsing_result,
ExpressionClassifier* classifier, bool* ok);
- int ParseFormalParameterList(Scope* scope, bool* has_rest,
+ int ParseFormalParameterList(FormalParameterParsingStateT* parsing_state,
ExpressionClassifier* classifier, bool* ok);
void CheckArityRestrictions(
int param_count, FunctionLiteral::ArityRestriction arity_restriction,
};
+struct PreParserFormalParameterParsingState {
+ explicit PreParserFormalParameterParsingState(Scope* scope)
+ : scope(scope), has_rest(false), is_simple_parameter_list(true) {}
+ Scope* scope;
+ bool has_rest;
+ bool is_simple_parameter_list;
+};
+
+
class PreParser;
class PreParserTraits {
typedef PreParserExpressionList PropertyList;
typedef PreParserIdentifier FormalParameter;
typedef PreParserStatementList StatementList;
+ typedef PreParserFormalParameterParsingState FormalParameterParsingState;
// For constructing objects returned by the traversing functions.
typedef PreParserFactory Factory;
return PreParserExpressionList();
}
+ static void AddParameterInitializationBlock(
+ const PreParserFormalParameterParsingState& formal_parameters,
+ PreParserStatementList list, bool* ok) {}
+
V8_INLINE void SkipLazyFunctionBody(int* materialized_literal_count,
int* expected_property_count, bool* ok) {
UNREACHABLE();
}
- V8_INLINE PreParserStatementList
- ParseEagerFunctionBody(PreParserIdentifier function_name, int pos,
- Variable* fvar, Token::Value fvar_init_op,
- FunctionKind kind, bool* ok);
+ V8_INLINE PreParserStatementList ParseEagerFunctionBody(
+ PreParserIdentifier function_name, int pos,
+ const PreParserFormalParameterParsingState& formal_parameters,
+ Variable* fvar, Token::Value fvar_init_op, FunctionKind kind, bool* ok);
V8_INLINE void ParseArrowFunctionFormalParameters(
- Scope* scope, PreParserExpression expression,
- const Scanner::Location& params_loc, bool* has_rest,
+ PreParserFormalParameterParsingState* parsing_state,
+ PreParserExpression expression, const Scanner::Location& params_loc,
Scanner::Location* duplicate_loc, bool* ok);
struct TemplateLiteralState {};
return !tag.IsNoTemplateTag();
}
- void DeclareFormalParameter(Scope* scope, PreParserExpression pattern,
+ void DeclareFormalParameter(void* parsing_state, PreParserExpression pattern,
ExpressionClassifier* classifier, bool is_rest) {}
void CheckConflictingVarDeclarations(Scope* scope, bool* ok) {}
int* expected_property_count, bool* ok);
V8_INLINE PreParserStatementList
ParseEagerFunctionBody(PreParserIdentifier function_name, int pos,
+ const FormalParameterParsingStateT& formal_parameters,
Variable* fvar, Token::Value fvar_init_op,
FunctionKind kind, bool* ok);
void PreParserTraits::ParseArrowFunctionFormalParameters(
- Scope* scope, PreParserExpression params,
- const Scanner::Location& params_loc, bool* has_rest,
+ PreParserFormalParameterParsingState* parsing_state,
+ PreParserExpression params, const Scanner::Location& params_loc,
Scanner::Location* duplicate_loc, bool* ok) {
// TODO(wingo): Detect duplicated identifiers in paramlists. Detect parameter
// lists that are too long.
PreParserStatementList PreParser::ParseEagerFunctionBody(
- PreParserIdentifier function_name, int pos, Variable* fvar,
- Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
+ PreParserIdentifier function_name, int pos,
+ const PreParserFormalParameterParsingState& formal_parameters,
+ Variable* fvar, Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
ParsingModeScope parsing_mode(this, PARSE_EAGERLY);
ParseStatementList(Token::RBRACE, ok);
PreParserStatementList PreParserTraits::ParseEagerFunctionBody(
- PreParserIdentifier function_name, int pos, Variable* fvar,
- Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
- return pre_parser_->ParseEagerFunctionBody(function_name, pos, fvar,
- fvar_init_op, kind, ok);
+ PreParserIdentifier function_name, int pos,
+ const PreParserFormalParameterParsingState& formal_parameters,
+ Variable* fvar, Token::Value fvar_init_op, FunctionKind kind, bool* ok) {
+ return pre_parser_->ParseEagerFunctionBody(
+ function_name, pos, formal_parameters, fvar, fvar_init_op, kind, ok);
}
}
Scope* scope =
this->NewScope(scope_, ARROW_SCOPE, FunctionKind::kArrowFunction);
+ FormalParameterParsingStateT parsing_state(scope);
scope->set_start_position(beg_pos);
ExpressionClassifier args_classifier;
- bool has_rest = false;
- result = this->ParseArrowFunctionLiteral(scope, has_rest,
- args_classifier, CHECK_OK);
+ result = this->ParseArrowFunctionLiteral(parsing_state, args_classifier,
+ CHECK_OK);
} else if (allow_harmony_arrow_functions() &&
allow_harmony_rest_params() && Check(Token::ELLIPSIS)) {
// (...x) => y
Scope* scope =
this->NewScope(scope_, ARROW_SCOPE, FunctionKind::kArrowFunction);
+ FormalParameterParsingStateT parsing_state(scope);
scope->set_start_position(beg_pos);
ExpressionClassifier args_classifier;
- const bool has_rest = true;
- this->ParseFormalParameter(scope, has_rest, &args_classifier, CHECK_OK);
+ const bool is_rest = true;
+ this->ParseFormalParameter(is_rest, &parsing_state, &args_classifier,
+ CHECK_OK);
if (peek() == Token::COMMA) {
ReportMessageAt(scanner()->peek_location(),
MessageTemplate::kParamAfterRest);
return this->EmptyExpression();
}
Expect(Token::RPAREN, CHECK_OK);
- result = this->ParseArrowFunctionLiteral(scope, has_rest,
- args_classifier, CHECK_OK);
+ result = this->ParseArrowFunctionLiteral(parsing_state, args_classifier,
+ CHECK_OK);
} else {
// Heuristically try to detect immediately called functions before
// seeing the call parentheses.
DCHECK(!*is_computed_name);
DCHECK(!is_static);
+ if (classifier->duplicate_finder() != nullptr &&
+ scanner()->FindSymbol(classifier->duplicate_finder(), 1) != 0) {
+ classifier->RecordDuplicateFormalParameterError(scanner()->location());
+ }
+
ExpressionT lhs = this->ExpressionFromIdentifier(
name, next_beg_pos, next_end_pos, scope_, factory());
if (peek() == Token::ASSIGN) {
if (fni_ != NULL) fni_->Enter();
ParserBase<Traits>::Checkpoint checkpoint(this);
- ExpressionClassifier arrow_formals_classifier;
+ ExpressionClassifier arrow_formals_classifier(classifier->duplicate_finder());
if (peek() != Token::LPAREN) {
// The expression we are going to read is not a parenthesized arrow function
// formal parameter list.
this->NewScope(scope_, ARROW_SCOPE, FunctionKind::kArrowFunction);
scope->set_start_position(lhs_location.beg_pos);
Scanner::Location duplicate_loc = Scanner::Location::invalid();
- bool has_rest = false;
- this->ParseArrowFunctionFormalParameters(scope, expression, loc, &has_rest,
+ FormalParameterParsingStateT parsing_state(scope);
+ this->ParseArrowFunctionFormalParameters(&parsing_state, expression, loc,
&duplicate_loc, CHECK_OK);
if (duplicate_loc.IsValid()) {
arrow_formals_classifier.RecordDuplicateFormalParameterError(
duplicate_loc);
}
expression = this->ParseArrowFunctionLiteral(
- scope, has_rest, arrow_formals_classifier, CHECK_OK);
+ parsing_state, arrow_formals_classifier, CHECK_OK);
return expression;
}
template <class Traits>
-void ParserBase<Traits>::ParseFormalParameter(Scope* scope, bool is_rest,
- ExpressionClassifier* classifier,
- bool* ok) {
+void ParserBase<Traits>::ParseFormalParameter(
+ bool is_rest, FormalParameterParsingStateT* parsing_state,
+ ExpressionClassifier* classifier, bool* ok) {
// FormalParameter[Yield,GeneratorParameter] :
// BindingElement[?Yield, ?GeneratorParameter]
return;
}
- Traits::DeclareFormalParameter(scope, pattern, classifier, is_rest);
+ if (parsing_state->is_simple_parameter_list) {
+ parsing_state->is_simple_parameter_list =
+ !is_rest && Traits::IsIdentifier(pattern);
+ }
+ parsing_state->has_rest = is_rest;
+ if (is_rest && !Traits::IsIdentifier(pattern)) {
+ ReportUnexpectedToken(next);
+ *ok = false;
+ return;
+ }
+ Traits::DeclareFormalParameter(parsing_state, pattern, classifier, is_rest);
}
template <class Traits>
int ParserBase<Traits>::ParseFormalParameterList(
- Scope* scope, bool* is_rest, ExpressionClassifier* classifier, bool* ok) {
+ FormalParameterParsingStateT* parsing_state,
+ ExpressionClassifier* classifier, bool* ok) {
// FormalParameters[Yield,GeneratorParameter] :
// [empty]
// FormalParameterList[?Yield, ?GeneratorParameter]
*ok = false;
return -1;
}
- *is_rest = allow_harmony_rest_params() && Check(Token::ELLIPSIS);
- ParseFormalParameter(scope, *is_rest, classifier, ok);
+ bool is_rest = allow_harmony_rest_params() && Check(Token::ELLIPSIS);
+ ParseFormalParameter(is_rest, parsing_state, classifier, ok);
if (!*ok) return -1;
- } while (!*is_rest && Check(Token::COMMA));
+ } while (!parsing_state->has_rest && Check(Token::COMMA));
- if (*is_rest && peek() == Token::COMMA) {
+ if (parsing_state->has_rest && peek() == Token::COMMA) {
ReportMessageAt(scanner()->peek_location(),
MessageTemplate::kParamAfterRest);
*ok = false;
template <class Traits>
typename ParserBase<Traits>::ExpressionT
ParserBase<Traits>::ParseArrowFunctionLiteral(
- Scope* scope, bool has_rest, const ExpressionClassifier& formals_classifier,
- bool* ok) {
+ const FormalParameterParsingStateT& formal_parameters,
+ const ExpressionClassifier& formals_classifier, bool* ok) {
if (peek() == Token::ARROW && scanner_->HasAnyLineTerminatorBeforeNext()) {
// ASI inserts `;` after arrow parameters if a line terminator is found.
// `=> ...` is never a valid expression, so report as syntax error.
}
typename Traits::Type::StatementList body;
- int num_parameters = scope->num_parameters();
+ int num_parameters = formal_parameters.scope->num_parameters();
int materialized_literal_count = -1;
int expected_property_count = -1;
Scanner::Location super_loc;
{
typename Traits::Type::Factory function_factory(ast_value_factory());
- FunctionState function_state(&function_state_, &scope_, scope,
- kArrowFunction, &function_factory);
+ FunctionState function_state(&function_state_, &scope_,
+ formal_parameters.scope, kArrowFunction,
+ &function_factory);
Expect(Token::ARROW, CHECK_OK);
&expected_property_count, CHECK_OK);
} else {
body = this->ParseEagerFunctionBody(
- this->EmptyIdentifier(), RelocInfo::kNoPosition, NULL,
- Token::INIT_VAR, kArrowFunction, CHECK_OK);
+ this->EmptyIdentifier(), RelocInfo::kNoPosition, formal_parameters,
+ NULL, Token::INIT_VAR, kArrowFunction, CHECK_OK);
materialized_literal_count =
function_state.materialized_literal_count();
expected_property_count = function_state.expected_property_count();
ParseAssignmentExpression(true, &classifier, CHECK_OK);
ValidateExpression(&classifier, CHECK_OK);
body = this->NewStatementList(1, zone());
+ this->AddParameterInitializationBlock(formal_parameters, body, CHECK_OK);
body->Add(factory()->NewReturnStatement(expression, pos), zone());
materialized_literal_count = function_state.materialized_literal_count();
expected_property_count = function_state.expected_property_count();
}
super_loc = function_state.super_location();
- scope->set_end_position(scanner()->location().end_pos);
+ formal_parameters.scope->set_end_position(scanner()->location().end_pos);
// Arrow function formal parameters are parsed as StrictFormalParameterList,
// which is not the same as "parameters of a strict function"; it only means
// Validate strict mode.
if (is_strict(language_mode())) {
- CheckStrictOctalLiteral(scope->start_position(),
+ CheckStrictOctalLiteral(formal_parameters.scope->start_position(),
scanner()->location().end_pos, CHECK_OK);
- this->CheckConflictingVarDeclarations(scope, CHECK_OK);
+ this->CheckConflictingVarDeclarations(formal_parameters.scope, CHECK_OK);
}
}
FunctionLiteralT function_literal = factory()->NewFunctionLiteral(
- this->EmptyIdentifierString(), ast_value_factory(), scope, body,
- materialized_literal_count, expected_property_count, num_parameters,
+ this->EmptyIdentifierString(), ast_value_factory(),
+ formal_parameters.scope, body, materialized_literal_count,
+ expected_property_count, num_parameters,
FunctionLiteral::kNoDuplicateParameters,
FunctionLiteral::ANONYMOUS_EXPRESSION, FunctionLiteral::kIsFunction,
FunctionLiteral::kShouldLazyCompile, FunctionKind::kArrowFunction,
- scope->start_position());
+ formal_parameters.scope->start_position());
- function_literal->set_function_token_position(scope->start_position());
+ function_literal->set_function_token_position(
+ formal_parameters.scope->start_position());
if (super_loc.IsValid()) function_state_->set_super_location(super_loc);
if (fni_ != NULL) this->InferFunctionName(fni_, function_literal);
bool is_rest, bool* is_duplicate) {
DCHECK(!already_resolved());
DCHECK(is_function_scope());
- Variable* var = variables_.Declare(this, name, mode, Variable::NORMAL,
- kCreatedInitialized);
+
+ Variable* var;
+ if (!name->IsEmpty()) {
+ var = variables_.Declare(this, name, mode, Variable::NORMAL,
+ kCreatedInitialized);
+ // TODO(wingo): Avoid O(n^2) check.
+ *is_duplicate = IsDeclaredParameter(name);
+ } else {
+ var = new (zone())
+ Variable(this, name, TEMPORARY, Variable::NORMAL, kCreatedInitialized);
+ }
if (is_rest) {
DCHECK_NULL(rest_parameter_);
rest_parameter_ = var;
rest_index_ = num_parameters();
}
- // TODO(wingo): Avoid O(n^2) check.
- *is_duplicate = IsDeclaredParameter(name);
params_.Add(var, zone());
return var;
}
{"function f(", ") {}"},
{"function f(argument1, ", ") {}"},
{"var f = (", ") => {};"},
- {"var f = ", " => {};"},
{"var f = (argument1,", ") => {};"},
{NULL, NULL}};
"{42 : x = 42}",
"{42e-2 : x}",
"{42e-2 : x = 42}",
+ "{x : y, x : z}",
"{'hi' : x}",
"{'hi' : x = 42}",
"{var: x}",
}
+TEST(DestructuringDuplicateParams) {
+ i::FLAG_harmony_destructuring = true;
+ i::FLAG_harmony_arrow_functions = true;
+ i::FLAG_harmony_computed_property_names = true;
+ static const ParserFlag always_flags[] = {
+ kAllowHarmonyObjectLiterals, kAllowHarmonyComputedPropertyNames,
+ kAllowHarmonyArrowFunctions, kAllowHarmonyDestructuring};
+ const char* context_data[][2] = {{"'use strict';", ""},
+ {"function outer() { 'use strict';", "}"},
+ {nullptr, nullptr}};
+
+
+ // clang-format off
+ const char* error_data[] = {
+ "function f(x,x){}",
+ "function f(x, {x : x}){}",
+ "function f(x, {x}){}",
+ "function f({x,x}) {}",
+ "function f([x,x]) {}",
+ "function f(x, [y,{z:x}]) {}",
+ "function f([x,{y:x}]) {}",
+ // non-simple parameter list causes duplicates to be errors in sloppy mode.
+ "function f(x, x, {a}) {}",
+ nullptr};
+ // clang-format on
+ RunParserSyncTest(context_data, error_data, kError, NULL, 0, always_flags,
+ arraysize(always_flags));
+}
+
+
+TEST(DestructuringDuplicateParamsSloppy) {
+ i::FLAG_harmony_destructuring = true;
+ i::FLAG_harmony_arrow_functions = true;
+ i::FLAG_harmony_computed_property_names = true;
+ static const ParserFlag always_flags[] = {
+ kAllowHarmonyObjectLiterals, kAllowHarmonyComputedPropertyNames,
+ kAllowHarmonyArrowFunctions, kAllowHarmonyDestructuring};
+ const char* context_data[][2] = {
+ {"", ""}, {"function outer() {", "}"}, {nullptr, nullptr}};
+
+
+ // clang-format off
+ const char* error_data[] = {
+ // non-simple parameter list causes duplicates to be errors in sloppy mode.
+ "function f(x, {x : x}){}",
+ "function f(x, {x}){}",
+ "function f({x,x}) {}",
+ "function f(x, x, {a}) {}",
+ nullptr};
+ // clang-format on
+ RunParserSyncTest(context_data, error_data, kError, NULL, 0, always_flags,
+ arraysize(always_flags));
+}
+
+
+TEST(DestructuringDisallowPatternsInSingleParamArrows) {
+ i::FLAG_harmony_destructuring = true;
+ i::FLAG_harmony_arrow_functions = true;
+ i::FLAG_harmony_computed_property_names = true;
+ static const ParserFlag always_flags[] = {
+ kAllowHarmonyObjectLiterals, kAllowHarmonyComputedPropertyNames,
+ kAllowHarmonyArrowFunctions, kAllowHarmonyDestructuring};
+ const char* context_data[][2] = {{"'use strict';", ""},
+ {"function outer() { 'use strict';", "}"},
+ {"", ""},
+ {"function outer() { ", "}"},
+ {nullptr, nullptr}};
+
+ // clang-format off
+ const char* error_data[] = {
+ "var f = {x} => {};",
+ "var f = {x,y} => {};",
+ nullptr};
+ // clang-format on
+ RunParserSyncTest(context_data, error_data, kError, NULL, 0, always_flags,
+ arraysize(always_flags));
+}
+
+
+TEST(DestructuringDisallowPatternsInRestParams) {
+ i::FLAG_harmony_destructuring = true;
+ i::FLAG_harmony_arrow_functions = true;
+ i::FLAG_harmony_rest_parameters = true;
+ i::FLAG_harmony_computed_property_names = true;
+ static const ParserFlag always_flags[] = {
+ kAllowHarmonyObjectLiterals, kAllowHarmonyComputedPropertyNames,
+ kAllowHarmonyArrowFunctions, kAllowHarmonyRestParameters,
+ kAllowHarmonyDestructuring};
+ const char* context_data[][2] = {{"'use strict';", ""},
+ {"function outer() { 'use strict';", "}"},
+ {"", ""},
+ {"function outer() { ", "}"},
+ {nullptr, nullptr}};
+
+ // clang-format off
+ const char* error_data[] = {
+ "function(...{}) {}",
+ "function(...{x}) {}",
+ "function(...[x]) {}",
+ "(...{}) => {}",
+ "(...{x}) => {}",
+ "(...[x]) => {}",
+ nullptr};
+ // clang-format on
+ RunParserSyncTest(context_data, error_data, kError, NULL, 0, always_flags,
+ arraysize(always_flags));
+}
+
+
TEST(SpreadArray) {
i::FLAG_harmony_spread_arrays = true;
// found in the LICENSE file.
//
// Flags: --harmony-destructuring --harmony-computed-property-names
+// Flags: --harmony-arrow-functions
(function TestObjectLiteralPattern() {
var { x : x, y : y } = { x : 1, y : 2 };
assertEquals('ab', sx);
assertEquals('12', sy);
}());
+
+
+(function TestParameters() {
+ function f({a, b}) { return a - b; }
+ assertEquals(1, f({a : 6, b : 5}));
+
+ function f1(c, {a, b}) { return c + a - b; }
+ assertEquals(8, f1(7, {a : 6, b : 5}));
+
+ function f2({c, d}, {a, b}) { return c - d + a - b; }
+ assertEquals(7, f2({c : 7, d : 1}, {a : 6, b : 5}));
+
+ function f3([{a, b}]) { return a - b; }
+ assertEquals(1, f3([{a : 6, b : 5}]));
+
+ var g = ({a, b}) => { return a - b; };
+ assertEquals(1, g({a : 6, b : 5}));
+
+ var g1 = (c, {a, b}) => { return c + a - b; };
+ assertEquals(8, g1(7, {a : 6, b : 5}));
+
+ var g2 = ({c, d}, {a, b}) => { return c - d + a - b; };
+ assertEquals(7, g2({c : 7, d : 1}, {a : 6, b : 5}));
+
+ var g3 = ([{a, b}]) => { return a - b; };
+ assertEquals(1, g3([{a : 6, b : 5}]));
+}());
+
+
+(function TestDuplicatesInParameters() {
+ assertThrows("'use strict';function f(x,x){}", SyntaxError);
+ assertThrows("'use strict';function f({x,x}){}", SyntaxError);
+ assertThrows("'use strict';function f(x, {x}){}", SyntaxError);
+ assertThrows("'use strict';var f = (x,x) => {};", SyntaxError);
+ assertThrows("'use strict';var f = ({x,x}) => {};", SyntaxError);
+ assertThrows("'use strict';var f = (x, {x}) => {};", SyntaxError);
+
+ function ok(x) { var x; }; ok();
+ assertThrows("function f({x}) { var x; }; f({});", SyntaxError);
+ assertThrows("'use strict'; function f({x}) { let x = 0; }; f({});", SyntaxError);
+}());
eval("(function() { const x; var x })")();
} catch (e) {
exception = true;
- assertTrue(e instanceof TypeError);
+ assertTrue(e instanceof SyntaxError);
}
assertTrue(exception);
}
%OptimizeFunctionOnNextCall(g);
-assertThrows(function() { g(42); }, TypeError);
+assertThrows(function() { g(42); }, SyntaxError);
PASS argumentsParam(true) is true
PASS argumentsFunctionConstructorParam(true) is true
PASS argumentsVarUndefined() is '[object Arguments]'
-FAIL argumentsConstUndefined() should be [object Arguments]. Threw exception TypeError: Identifier 'arguments' has already been declared
+FAIL argumentsConstUndefined() should be [object Arguments]. Threw exception SyntaxError: Identifier 'arguments' has already been declared
PASS argumentCalleeInException() is argumentCalleeInException
PASS shadowedArgumentsApply([true]) is true
PASS shadowedArgumentsLength([]) is 0