[destructuring] Implement parameter pattern matching.
Scoping for initializers is yet incorrect. Defaults are not supported. R=arv@chromium.org,rossberg@chromium.org BUG=v8:811 LOG=N Review URL: https://codereview.chromium.org/1189743003 Cr-Commit-Position: refs/heads/master@{#29184}
This commit is contained in:
parent
5fe960a966
commit
42f30f4ded
137
src/parser.cc
137
src/parser.cc
@ -1182,7 +1182,7 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
|
||||
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
|
||||
@ -1190,17 +1190,19 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
|
||||
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
|
||||
@ -1547,7 +1549,7 @@ ZoneList<ImportDeclaration*>* Parser::ParseNamedImports(int pos, bool* ok) {
|
||||
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);
|
||||
@ -1595,7 +1597,8 @@ Statement* Parser::ParseImportDeclaration(bool* 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;
|
||||
@ -1982,7 +1985,9 @@ VariableProxy* Parser::NewUnresolved(const AstRawString* name,
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
@ -2041,11 +2046,15 @@ Variable* Parser::Declare(Declaration* declaration, bool resolve, bool* ok) {
|
||||
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) {
|
||||
@ -2155,7 +2164,7 @@ Statement* Parser::ParseNativeDeclaration(bool* ok) {
|
||||
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(
|
||||
@ -2200,7 +2209,7 @@ Statement* Parser::ParseFunctionDeclaration(
|
||||
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);
|
||||
}
|
||||
@ -2241,7 +2250,8 @@ Statement* Parser::ParseClassDeclaration(ZoneList<const AstRawString*>* names,
|
||||
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
|
||||
@ -2397,6 +2407,7 @@ void Parser::ParseVariableDeclarations(VariableDeclarationContext var_context,
|
||||
// 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;
|
||||
@ -3328,7 +3339,7 @@ Statement* Parser::DesugarLexicalBindingsInForStatement(
|
||||
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 =
|
||||
@ -3784,9 +3795,10 @@ Handle<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) {
|
||||
|
||||
|
||||
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;
|
||||
@ -3812,7 +3824,7 @@ void ParserTraits::ParseArrowFunctionFormalParameters(
|
||||
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.
|
||||
@ -3820,30 +3832,25 @@ void ParserTraits::ParseArrowFunctionFormalParameters(
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
@ -3918,7 +3925,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
||||
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;
|
||||
@ -3944,18 +3952,18 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
||||
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
|
||||
@ -4050,8 +4058,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
||||
}
|
||||
}
|
||||
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();
|
||||
|
||||
@ -4071,7 +4079,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
||||
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(),
|
||||
@ -4233,8 +4242,40 @@ Statement* Parser::BuildAssertIsCoercible(Variable* var) {
|
||||
}
|
||||
|
||||
|
||||
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).
|
||||
@ -4258,6 +4299,12 @@ ZoneList<Statement*>* Parser::ParseEagerFunctionBody(
|
||||
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 =
|
||||
@ -4384,7 +4431,7 @@ ClassLiteral* Parser::ParseClassLiteral(const AstRawString* name,
|
||||
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;
|
||||
|
105
src/parser.h
105
src/parser.h
@ -538,6 +538,27 @@ class RegExpParser BASE_EMBEDDED {
|
||||
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 {
|
||||
@ -560,7 +581,7 @@ class ParserTraits {
|
||||
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.
|
||||
@ -751,17 +772,21 @@ class ParserTraits {
|
||||
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);
|
||||
@ -774,8 +799,9 @@ class ParserTraits {
|
||||
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,
|
||||
@ -936,6 +962,7 @@ class Parser : public ParserBase<ParserTraits> {
|
||||
bool* ok);
|
||||
|
||||
struct DeclarationDescriptor {
|
||||
enum Kind { NORMAL, PARAMETER };
|
||||
Parser* parser;
|
||||
Scope* declaration_scope;
|
||||
Scope* scope;
|
||||
@ -945,6 +972,7 @@ class Parser : public ParserBase<ParserTraits> {
|
||||
int declaration_pos;
|
||||
int initialization_pos;
|
||||
Token::Value init_op;
|
||||
Kind declaration_kind;
|
||||
};
|
||||
|
||||
struct DeclarationParsingResult {
|
||||
@ -1095,7 +1123,9 @@ class Parser : public ParserBase<ParserTraits> {
|
||||
|
||||
// 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);
|
||||
@ -1121,10 +1151,14 @@ class Parser : public ParserBase<ParserTraits> {
|
||||
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);
|
||||
|
||||
@ -1188,10 +1222,11 @@ void ParserTraits::SkipLazyFunctionBody(int* materialized_literal_count,
|
||||
|
||||
|
||||
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,
|
||||
@ -1270,18 +1305,20 @@ Expression* ParserTraits::SpreadCallNew(
|
||||
}
|
||||
|
||||
|
||||
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.
|
||||
@ -1292,6 +1329,18 @@ void ParserTraits::DeclareFormalParameter(Scope* scope, Expression* pattern,
|
||||
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_
|
||||
|
@ -53,7 +53,8 @@ void Parser::PatternRewriter::VisitVariableProxy(VariableProxy* pattern) {
|
||||
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);
|
||||
|
@ -1038,17 +1038,18 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
|
||||
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.
|
||||
@ -1068,7 +1069,8 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
|
||||
// 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(),
|
||||
|
152
src/preparser.h
152
src/preparser.h
@ -70,6 +70,8 @@ class ParserBase : public Traits {
|
||||
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,
|
||||
@ -557,7 +559,7 @@ class ParserBase : public Traits {
|
||||
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()));
|
||||
@ -646,9 +648,9 @@ class ParserBase : public Traits {
|
||||
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);
|
||||
@ -660,9 +662,10 @@ class ParserBase : public Traits {
|
||||
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,
|
||||
@ -1254,6 +1257,15 @@ class PreParserFactory {
|
||||
};
|
||||
|
||||
|
||||
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 {
|
||||
@ -1280,6 +1292,7 @@ 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;
|
||||
@ -1518,19 +1531,23 @@ class PreParserTraits {
|
||||
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 {};
|
||||
@ -1557,7 +1574,7 @@ class PreParserTraits {
|
||||
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) {}
|
||||
@ -1708,6 +1725,7 @@ class PreParser : public ParserBase<PreParserTraits> {
|
||||
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);
|
||||
|
||||
@ -1753,8 +1771,8 @@ PreParserExpression PreParserTraits::SpreadCallNew(PreParserExpression function,
|
||||
|
||||
|
||||
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.
|
||||
@ -1762,8 +1780,9 @@ void PreParserTraits::ParseArrowFunctionFormalParameters(
|
||||
|
||||
|
||||
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);
|
||||
@ -1775,10 +1794,11 @@ PreParserStatementList PreParser::ParseEagerFunctionBody(
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@ -2162,20 +2182,22 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
|
||||
}
|
||||
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);
|
||||
@ -2183,8 +2205,8 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
|
||||
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.
|
||||
@ -2524,6 +2546,11 @@ ParserBase<Traits>::ParsePropertyDefinition(
|
||||
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) {
|
||||
@ -2707,7 +2734,7 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
||||
|
||||
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.
|
||||
@ -2726,15 +2753,15 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
||||
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;
|
||||
}
|
||||
|
||||
@ -3497,9 +3524,9 @@ ParserBase<Traits>::ParseMemberExpressionContinuation(
|
||||
|
||||
|
||||
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]
|
||||
|
||||
@ -3516,13 +3543,24 @@ void ParserBase<Traits>::ParseFormalParameter(Scope* scope, bool is_rest,
|
||||
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]
|
||||
@ -3546,12 +3584,12 @@ int ParserBase<Traits>::ParseFormalParameterList(
|
||||
*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;
|
||||
@ -3596,8 +3634,8 @@ void ParserBase<Traits>::CheckArityRestrictions(
|
||||
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.
|
||||
@ -3608,15 +3646,16 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@ -3631,8 +3670,8 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
|
||||
&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();
|
||||
@ -3646,13 +3685,14 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
|
||||
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
|
||||
@ -3664,21 +3704,23 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
|
||||
|
||||
// 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);
|
||||
|
@ -466,15 +466,22 @@ Variable* Scope::DeclareParameter(const AstRawString* name, VariableMode mode,
|
||||
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;
|
||||
}
|
||||
|
@ -6389,7 +6389,6 @@ TEST(DestructuringPositiveTests) {
|
||||
{"function f(", ") {}"},
|
||||
{"function f(argument1, ", ") {}"},
|
||||
{"var f = (", ") => {};"},
|
||||
{"var f = ", " => {};"},
|
||||
{"var f = (argument1,", ") => {};"},
|
||||
{NULL, NULL}};
|
||||
|
||||
@ -6417,6 +6416,7 @@ TEST(DestructuringPositiveTests) {
|
||||
"{42 : x = 42}",
|
||||
"{42e-2 : x}",
|
||||
"{42e-2 : x = 42}",
|
||||
"{x : y, x : z}",
|
||||
"{'hi' : x}",
|
||||
"{'hi' : x = 42}",
|
||||
"{var: x}",
|
||||
@ -6605,6 +6605,115 @@ TEST(DestructuringDisallowPatternsInForVarIn) {
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
// 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 };
|
||||
@ -686,3 +687,44 @@
|
||||
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);
|
||||
}());
|
||||
|
@ -35,6 +35,6 @@ try {
|
||||
eval("(function() { const x; var x })")();
|
||||
} catch (e) {
|
||||
exception = true;
|
||||
assertTrue(e instanceof TypeError);
|
||||
assertTrue(e instanceof SyntaxError);
|
||||
}
|
||||
assertTrue(exception);
|
||||
|
@ -14,4 +14,4 @@ function g(x) {
|
||||
}
|
||||
|
||||
%OptimizeFunctionOnNextCall(g);
|
||||
assertThrows(function() { g(42); }, TypeError);
|
||||
assertThrows(function() { g(42); }, SyntaxError);
|
||||
|
@ -157,7 +157,7 @@ PASS access_after_delete_extra_5(1, 2, 3, 4, 5) is 5
|
||||
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
|
||||
|
Loading…
Reference in New Issue
Block a user