Use ExpressionClassifier to identify valid arrow function formals
R=dslomov@chromium.org LOG=N BUG= Review URL: https://codereview.chromium.org/1138153003 Cr-Commit-Position: refs/heads/master@{#28391}
This commit is contained in:
parent
6eea252463
commit
e73594c7fb
@ -1138,22 +1138,20 @@ FunctionLiteral* Parser::ParseLazy(Isolate* isolate, ParseInfo* info,
|
||||
if (shared_info->is_arrow()) {
|
||||
Scope* scope = NewScope(scope_, ARROW_SCOPE);
|
||||
scope->set_start_position(shared_info->start_position());
|
||||
FormalParameterErrorLocations error_locs;
|
||||
ExpressionClassifier formals_classifier;
|
||||
bool has_rest = false;
|
||||
if (Check(Token::LPAREN)) {
|
||||
// '(' StrictFormalParameters ')'
|
||||
ParseFormalParameterList(scope, &error_locs, &has_rest, &ok);
|
||||
ParseFormalParameterList(scope, &has_rest, &formals_classifier, &ok);
|
||||
if (ok) ok = Check(Token::RPAREN);
|
||||
} else {
|
||||
// BindingIdentifier
|
||||
ParseFormalParameter(scope, &error_locs, has_rest, &ok);
|
||||
ParseFormalParameter(scope, has_rest, &formals_classifier, &ok);
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
ExpressionClassifier classifier;
|
||||
Expression* expression = ParseArrowFunctionLiteral(
|
||||
scope, error_locs, has_rest, &classifier, &ok);
|
||||
ValidateExpression(&classifier, &ok);
|
||||
Expression* expression =
|
||||
ParseArrowFunctionLiteral(scope, has_rest, 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
|
||||
@ -3720,7 +3718,7 @@ Handle<FixedArray> CompileTimeValue::GetElements(Handle<FixedArray> value) {
|
||||
|
||||
void ParserTraits::DeclareArrowFunctionParameters(
|
||||
Scope* scope, Expression* expr, const Scanner::Location& params_loc,
|
||||
FormalParameterErrorLocations* error_locs, bool* ok) {
|
||||
Scanner::Location* duplicate_loc, bool* ok) {
|
||||
if (scope->num_parameters() >= Code::kMaxArguments) {
|
||||
ReportMessageAt(params_loc, "malformed_arrow_function_parameter_list");
|
||||
*ok = false;
|
||||
@ -3739,6 +3737,7 @@ void ParserTraits::DeclareArrowFunctionParameters(
|
||||
// need to match the pre-parser's behavior.
|
||||
if (expr->IsBinaryOperation()) {
|
||||
BinaryOperation* binop = expr->AsBinaryOperation();
|
||||
// TODO(wingo): These checks are now unnecessary, given the classifier.
|
||||
if (binop->op() != Token::COMMA) {
|
||||
ReportMessageAt(params_loc, "malformed_arrow_function_parameter_list");
|
||||
*ok = false;
|
||||
@ -3751,7 +3750,7 @@ void ParserTraits::DeclareArrowFunctionParameters(
|
||||
*ok = false;
|
||||
return;
|
||||
}
|
||||
DeclareArrowFunctionParameters(scope, left, params_loc, error_locs, ok);
|
||||
DeclareArrowFunctionParameters(scope, left, params_loc, duplicate_loc, ok);
|
||||
if (!*ok) return;
|
||||
// LHS of comma expression should be unparenthesized.
|
||||
expr = right;
|
||||
@ -3774,13 +3773,6 @@ void ParserTraits::DeclareArrowFunctionParameters(
|
||||
return;
|
||||
}
|
||||
|
||||
if (!error_locs->eval_or_arguments.IsValid() && IsEvalOrArguments(raw_name))
|
||||
error_locs->eval_or_arguments = param_location;
|
||||
if (!error_locs->reserved.IsValid() && IsFutureStrictReserved(raw_name))
|
||||
error_locs->reserved = param_location;
|
||||
if (!error_locs->undefined.IsValid() && IsUndefined(raw_name))
|
||||
error_locs->undefined = param_location;
|
||||
|
||||
// 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.
|
||||
@ -3789,22 +3781,15 @@ void ParserTraits::DeclareArrowFunctionParameters(
|
||||
bool is_rest = false;
|
||||
bool is_duplicate = DeclareFormalParameter(scope, raw_name, is_rest);
|
||||
|
||||
if (is_duplicate) {
|
||||
// Arrow function parameter lists are parsed as StrictFormalParameters,
|
||||
// which means that they cannot have duplicates. Note that this is a subset
|
||||
// of the restrictions placed on parameters to functions whose body is
|
||||
// strict.
|
||||
ReportMessageAt(param_location,
|
||||
"duplicate_arrow_function_formal_parameter");
|
||||
*ok = false;
|
||||
return;
|
||||
if (is_duplicate && !duplicate_loc->IsValid()) {
|
||||
*duplicate_loc = param_location;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ParserTraits::ParseArrowFunctionFormalParameters(
|
||||
Scope* scope, Expression* params, const Scanner::Location& params_loc,
|
||||
FormalParameterErrorLocations* error_locs, bool* is_rest, bool* ok) {
|
||||
bool* is_rest, Scanner::Location* duplicate_loc, bool* ok) {
|
||||
// Too many parentheses around expression:
|
||||
// (( ... )) => ...
|
||||
if (params->is_multi_parenthesized()) {
|
||||
@ -3814,7 +3799,7 @@ void ParserTraits::ParseArrowFunctionFormalParameters(
|
||||
return;
|
||||
}
|
||||
|
||||
DeclareArrowFunctionParameters(scope, params, params_loc, error_locs, ok);
|
||||
DeclareArrowFunctionParameters(scope, params, params_loc, duplicate_loc, ok);
|
||||
}
|
||||
|
||||
|
||||
@ -3887,7 +3872,7 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
||||
int materialized_literal_count = -1;
|
||||
int expected_property_count = -1;
|
||||
int handler_count = 0;
|
||||
FormalParameterErrorLocations error_locs;
|
||||
ExpressionClassifier formals_classifier;
|
||||
FunctionLiteral::EagerCompileHint eager_compile_hint =
|
||||
parenthesized_function_ ? FunctionLiteral::kShouldEagerCompile
|
||||
: FunctionLiteral::kShouldLazyCompile;
|
||||
@ -3917,8 +3902,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
||||
Expect(Token::LPAREN, CHECK_OK);
|
||||
int start_position = scanner()->location().beg_pos;
|
||||
scope_->set_start_position(start_position);
|
||||
num_parameters =
|
||||
ParseFormalParameterList(scope, &error_locs, &has_rest, CHECK_OK);
|
||||
num_parameters = ParseFormalParameterList(scope, &has_rest,
|
||||
&formals_classifier, CHECK_OK);
|
||||
Expect(Token::RPAREN, CHECK_OK);
|
||||
int formals_end_position = scanner()->location().end_pos;
|
||||
|
||||
@ -4041,8 +4026,10 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
||||
name_is_strict_reserved, function_name_location,
|
||||
CHECK_OK);
|
||||
const bool use_strict_params = has_rest || IsConciseMethod(kind);
|
||||
CheckFunctionParameterNames(language_mode(), use_strict_params, error_locs,
|
||||
CHECK_OK);
|
||||
const bool allow_duplicate_parameters =
|
||||
is_sloppy(language_mode()) && !use_strict_params;
|
||||
ValidateFormalParameters(&formals_classifier, language_mode(),
|
||||
allow_duplicate_parameters, CHECK_OK);
|
||||
|
||||
if (is_strict(language_mode())) {
|
||||
CheckStrictOctalLiteral(scope->start_position(), scope->end_position(),
|
||||
@ -4051,9 +4038,11 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
||||
}
|
||||
}
|
||||
|
||||
bool has_duplicate_parameters =
|
||||
!formals_classifier.is_valid_formal_parameter_list_without_duplicates();
|
||||
FunctionLiteral::ParameterFlag duplicate_parameters =
|
||||
error_locs.duplicate.IsValid() ? FunctionLiteral::kHasDuplicateParameters
|
||||
: FunctionLiteral::kNoDuplicateParameters;
|
||||
has_duplicate_parameters ? FunctionLiteral::kHasDuplicateParameters
|
||||
: FunctionLiteral::kNoDuplicateParameters;
|
||||
|
||||
FunctionLiteral* function_literal = factory()->NewFunctionLiteral(
|
||||
function_name, ast_value_factory(), scope, body,
|
||||
|
10
src/parser.h
10
src/parser.h
@ -760,11 +760,13 @@ class ParserTraits {
|
||||
|
||||
void DeclareArrowFunctionParameters(Scope* scope, Expression* expr,
|
||||
const Scanner::Location& params_loc,
|
||||
FormalParameterErrorLocations* error_locs,
|
||||
Scanner::Location* duplicate_loc,
|
||||
bool* ok);
|
||||
void ParseArrowFunctionFormalParameters(
|
||||
Scope* scope, Expression* params, const Scanner::Location& params_loc,
|
||||
FormalParameterErrorLocations* error_locs, bool* is_rest, bool* ok);
|
||||
void ParseArrowFunctionFormalParameters(Scope* scope, Expression* params,
|
||||
const Scanner::Location& params_loc,
|
||||
bool* is_rest,
|
||||
Scanner::Location* duplicate_loc,
|
||||
bool* ok);
|
||||
|
||||
// Temporary glue; these functions will move to ParserBase.
|
||||
Expression* ParseV8Intrinsic(bool* ok);
|
||||
|
@ -1024,7 +1024,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
|
||||
PreParserFactory factory(NULL);
|
||||
FunctionState function_state(&function_state_, &scope_, function_scope, kind,
|
||||
&factory);
|
||||
FormalParameterErrorLocations error_locs;
|
||||
ExpressionClassifier formals_classifier;
|
||||
|
||||
bool is_rest = false;
|
||||
Expect(Token::LPAREN, CHECK_OK);
|
||||
@ -1033,8 +1033,8 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
|
||||
int num_parameters;
|
||||
{
|
||||
DuplicateFinder duplicate_finder(scanner()->unicode_cache());
|
||||
num_parameters = ParseFormalParameterList(&duplicate_finder, &error_locs,
|
||||
&is_rest, CHECK_OK);
|
||||
num_parameters = ParseFormalParameterList(&duplicate_finder, &is_rest,
|
||||
&formals_classifier, CHECK_OK);
|
||||
}
|
||||
Expect(Token::RPAREN, CHECK_OK);
|
||||
int formals_end_position = scanner()->location().end_pos;
|
||||
@ -1060,9 +1060,11 @@ 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 use_strict_params = is_rest || IsConciseMethod(kind);
|
||||
CheckFunctionParameterNames(language_mode(), use_strict_params, error_locs,
|
||||
CHECK_OK);
|
||||
const bool strict_formal_parameters = is_rest || IsConciseMethod(kind);
|
||||
const bool allow_duplicate_parameters =
|
||||
is_sloppy(language_mode()) && !strict_formal_parameters;
|
||||
ValidateFormalParameters(&formals_classifier, language_mode(),
|
||||
allow_duplicate_parameters, CHECK_OK);
|
||||
|
||||
if (is_strict(language_mode())) {
|
||||
int end_position = scanner()->location().end_pos;
|
||||
|
483
src/preparser.h
483
src/preparser.h
@ -18,25 +18,6 @@ namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
// When parsing the formal parameters of a function, we usually don't yet know
|
||||
// if the function will be strict, so we cannot yet produce errors for
|
||||
// parameter names or duplicates. Instead, we remember the locations of these
|
||||
// errors if they occur and produce the errors later.
|
||||
class FormalParameterErrorLocations BASE_EMBEDDED {
|
||||
public:
|
||||
FormalParameterErrorLocations()
|
||||
: eval_or_arguments(Scanner::Location::invalid()),
|
||||
undefined(Scanner::Location::invalid()),
|
||||
duplicate(Scanner::Location::invalid()),
|
||||
reserved(Scanner::Location::invalid()) {}
|
||||
|
||||
Scanner::Location eval_or_arguments;
|
||||
Scanner::Location undefined;
|
||||
Scanner::Location duplicate;
|
||||
Scanner::Location reserved;
|
||||
};
|
||||
|
||||
|
||||
// Common base class shared between parser and pre-parser. Traits encapsulate
|
||||
// the differences between Parser and PreParser:
|
||||
|
||||
@ -527,37 +508,6 @@ class ParserBase : public Traits {
|
||||
}
|
||||
}
|
||||
|
||||
// Checking the parameter names of a function literal. This has to be done
|
||||
// after parsing the function, since the function can declare itself strict.
|
||||
void CheckFunctionParameterNames(LanguageMode language_mode,
|
||||
bool strict_params,
|
||||
const FormalParameterErrorLocations& locs,
|
||||
bool* ok) {
|
||||
if (is_sloppy(language_mode) && !strict_params) return;
|
||||
if (is_strict(language_mode) && locs.eval_or_arguments.IsValid()) {
|
||||
Traits::ReportMessageAt(locs.eval_or_arguments, "strict_eval_arguments");
|
||||
*ok = false;
|
||||
return;
|
||||
}
|
||||
if (is_strict(language_mode) && locs.reserved.IsValid()) {
|
||||
Traits::ReportMessageAt(locs.reserved, "unexpected_strict_reserved");
|
||||
*ok = false;
|
||||
return;
|
||||
}
|
||||
if (is_strong(language_mode) && locs.undefined.IsValid()) {
|
||||
Traits::ReportMessageAt(locs.undefined, "strong_undefined");
|
||||
*ok = false;
|
||||
return;
|
||||
}
|
||||
// TODO(arv): When we add support for destructuring in setters we also need
|
||||
// to check for duplicate names.
|
||||
if (locs.duplicate.IsValid()) {
|
||||
Traits::ReportMessageAt(locs.duplicate, "strict_param_dupe");
|
||||
*ok = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine precedence of given token.
|
||||
static int Precedence(Token::Value token, bool accept_IN) {
|
||||
if (token == Token::IN && !accept_IN)
|
||||
@ -615,6 +565,26 @@ class ParserBase : public Traits {
|
||||
return !assignment_pattern_error_.HasError();
|
||||
}
|
||||
|
||||
bool is_valid_arrow_formal_parameters() const {
|
||||
return !arrow_formal_parameters_error_.HasError();
|
||||
}
|
||||
|
||||
bool is_valid_formal_parameter_list_without_duplicates() const {
|
||||
return !duplicate_formal_parameter_error_.HasError();
|
||||
}
|
||||
|
||||
// Note: callers should also check
|
||||
// is_valid_formal_parameter_list_without_duplicates().
|
||||
bool is_valid_strict_mode_formal_parameters() const {
|
||||
return !strict_mode_formal_parameter_error_.HasError();
|
||||
}
|
||||
|
||||
// Note: callers should also check is_valid_strict_mode_formal_parameters()
|
||||
// and is_valid_formal_parameter_list_without_duplicates().
|
||||
bool is_valid_strong_mode_formal_parameters() const {
|
||||
return !strong_mode_formal_parameter_error_.HasError();
|
||||
}
|
||||
|
||||
const Error& expression_error() const { return expression_error_; }
|
||||
|
||||
const Error& binding_pattern_error() const {
|
||||
@ -625,6 +595,22 @@ class ParserBase : public Traits {
|
||||
return assignment_pattern_error_;
|
||||
}
|
||||
|
||||
const Error& arrow_formal_parameters_error() const {
|
||||
return arrow_formal_parameters_error_;
|
||||
}
|
||||
|
||||
const Error& duplicate_formal_parameter_error() const {
|
||||
return duplicate_formal_parameter_error_;
|
||||
}
|
||||
|
||||
const Error& strict_mode_formal_parameter_error() const {
|
||||
return strict_mode_formal_parameter_error_;
|
||||
}
|
||||
|
||||
const Error& strong_mode_formal_parameter_error() const {
|
||||
return strong_mode_formal_parameter_error_;
|
||||
}
|
||||
|
||||
void RecordExpressionError(const Scanner::Location& loc,
|
||||
const char* message, const char* arg = nullptr) {
|
||||
if (!is_valid_expression()) return;
|
||||
@ -651,10 +637,98 @@ class ParserBase : public Traits {
|
||||
assignment_pattern_error_.arg = arg;
|
||||
}
|
||||
|
||||
void RecordArrowFormalParametersError(const Scanner::Location& loc,
|
||||
const char* message,
|
||||
const char* arg = nullptr) {
|
||||
if (!is_valid_arrow_formal_parameters()) return;
|
||||
arrow_formal_parameters_error_.location = loc;
|
||||
arrow_formal_parameters_error_.message = message;
|
||||
arrow_formal_parameters_error_.arg = arg;
|
||||
}
|
||||
|
||||
void RecordDuplicateFormalParameterError(const Scanner::Location& loc) {
|
||||
if (!is_valid_formal_parameter_list_without_duplicates()) return;
|
||||
duplicate_formal_parameter_error_.location = loc;
|
||||
duplicate_formal_parameter_error_.message = "strict_param_dupe";
|
||||
duplicate_formal_parameter_error_.arg = nullptr;
|
||||
}
|
||||
|
||||
// Record a binding that would be invalid in strict mode. Confusingly this
|
||||
// is not the same as StrictFormalParameterList, which simply forbids
|
||||
// duplicate bindings.
|
||||
void RecordStrictModeFormalParameterError(const Scanner::Location& loc,
|
||||
const char* message,
|
||||
const char* arg = nullptr) {
|
||||
if (!is_valid_strict_mode_formal_parameters()) return;
|
||||
strict_mode_formal_parameter_error_.location = loc;
|
||||
strict_mode_formal_parameter_error_.message = message;
|
||||
strict_mode_formal_parameter_error_.arg = arg;
|
||||
}
|
||||
|
||||
void RecordStrongModeFormalParameterError(const Scanner::Location& loc,
|
||||
const char* message,
|
||||
const char* arg = nullptr) {
|
||||
if (!is_valid_strong_mode_formal_parameters()) return;
|
||||
strong_mode_formal_parameter_error_.location = loc;
|
||||
strong_mode_formal_parameter_error_.message = message;
|
||||
strong_mode_formal_parameter_error_.arg = arg;
|
||||
}
|
||||
|
||||
enum TargetProduction {
|
||||
ExpressionProduction = 1 << 0,
|
||||
BindingPatternProduction = 1 << 1,
|
||||
AssignmentPatternProduction = 1 << 2,
|
||||
FormalParametersProduction = 1 << 3,
|
||||
ArrowFormalParametersProduction = 1 << 4,
|
||||
StandardProductions = (ExpressionProduction | BindingPatternProduction |
|
||||
AssignmentPatternProduction),
|
||||
AllProductions = (StandardProductions | FormalParametersProduction |
|
||||
ArrowFormalParametersProduction)
|
||||
};
|
||||
|
||||
void Accumulate(const ExpressionClassifier& inner,
|
||||
unsigned productions = StandardProductions) {
|
||||
if (productions & ExpressionProduction && is_valid_expression()) {
|
||||
expression_error_ = inner.expression_error_;
|
||||
}
|
||||
if (productions & BindingPatternProduction &&
|
||||
is_valid_binding_pattern()) {
|
||||
binding_pattern_error_ = inner.binding_pattern_error_;
|
||||
}
|
||||
if (productions & AssignmentPatternProduction &&
|
||||
is_valid_assignment_pattern()) {
|
||||
assignment_pattern_error_ = inner.assignment_pattern_error_;
|
||||
}
|
||||
if (productions & FormalParametersProduction) {
|
||||
if (is_valid_formal_parameter_list_without_duplicates()) {
|
||||
duplicate_formal_parameter_error_ =
|
||||
inner.duplicate_formal_parameter_error_;
|
||||
}
|
||||
if (is_valid_strict_mode_formal_parameters()) {
|
||||
strict_mode_formal_parameter_error_ =
|
||||
inner.strict_mode_formal_parameter_error_;
|
||||
}
|
||||
if (is_valid_strong_mode_formal_parameters()) {
|
||||
strong_mode_formal_parameter_error_ =
|
||||
inner.strong_mode_formal_parameter_error_;
|
||||
}
|
||||
}
|
||||
if (productions & ArrowFormalParametersProduction &&
|
||||
is_valid_arrow_formal_parameters()) {
|
||||
// The result continues to be a valid arrow formal parameters if the
|
||||
// inner expression is a valid binding pattern.
|
||||
arrow_formal_parameters_error_ = inner.binding_pattern_error_;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Error expression_error_;
|
||||
Error binding_pattern_error_;
|
||||
Error assignment_pattern_error_;
|
||||
Error arrow_formal_parameters_error_;
|
||||
Error duplicate_formal_parameter_error_;
|
||||
Error strict_mode_formal_parameter_error_;
|
||||
Error strong_mode_formal_parameter_error_;
|
||||
};
|
||||
|
||||
void ReportClassifierError(
|
||||
@ -686,9 +760,47 @@ class ParserBase : public Traits {
|
||||
}
|
||||
}
|
||||
|
||||
void ValidateFormalParameters(const ExpressionClassifier* classifier,
|
||||
LanguageMode language_mode,
|
||||
bool allow_duplicates, bool* ok) {
|
||||
if (!allow_duplicates &&
|
||||
!classifier->is_valid_formal_parameter_list_without_duplicates()) {
|
||||
ReportClassifierError(classifier->duplicate_formal_parameter_error());
|
||||
*ok = false;
|
||||
} else if (is_strict(language_mode) &&
|
||||
!classifier->is_valid_strict_mode_formal_parameters()) {
|
||||
ReportClassifierError(classifier->strict_mode_formal_parameter_error());
|
||||
*ok = false;
|
||||
} else if (is_strong(language_mode) &&
|
||||
!classifier->is_valid_strong_mode_formal_parameters()) {
|
||||
ReportClassifierError(classifier->strong_mode_formal_parameter_error());
|
||||
*ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ValidateArrowFormalParameters(const ExpressionClassifier* classifier,
|
||||
ExpressionT expr, bool* ok) {
|
||||
if (classifier->is_valid_binding_pattern()) {
|
||||
// A simple arrow formal parameter: IDENTIFIER => BODY.
|
||||
if (!this->IsIdentifier(expr)) {
|
||||
Traits::ReportMessageAt(scanner()->location(), "unexpected_token",
|
||||
Token::String(scanner()->current_token()));
|
||||
*ok = false;
|
||||
}
|
||||
} else if (!classifier->is_valid_arrow_formal_parameters()) {
|
||||
ReportClassifierError(classifier->arrow_formal_parameters_error());
|
||||
*ok = false;
|
||||
}
|
||||
}
|
||||
|
||||
void BindingPatternUnexpectedToken(ExpressionClassifier* classifier) {
|
||||
classifier->RecordBindingPatternError(
|
||||
scanner()->location(), "unexpected_token", Token::String(peek()));
|
||||
scanner()->peek_location(), "unexpected_token", Token::String(peek()));
|
||||
}
|
||||
|
||||
void ArrowFormalParametersUnexpectedToken(ExpressionClassifier* classifier) {
|
||||
classifier->RecordArrowFormalParametersError(
|
||||
scanner()->peek_location(), "unexpected_token", Token::String(peek()));
|
||||
}
|
||||
|
||||
// Recursive descent functions:
|
||||
@ -750,9 +862,9 @@ class ParserBase : public Traits {
|
||||
ExpressionT ParseMemberExpression(ExpressionClassifier* classifier, bool* ok);
|
||||
ExpressionT ParseMemberExpressionContinuation(
|
||||
ExpressionT expression, ExpressionClassifier* classifier, bool* ok);
|
||||
ExpressionT ParseArrowFunctionLiteral(
|
||||
Scope* function_scope, const FormalParameterErrorLocations& error_locs,
|
||||
bool has_rest, ExpressionClassifier* classifier, bool* ok);
|
||||
ExpressionT ParseArrowFunctionLiteral(Scope* function_scope, bool has_rest,
|
||||
const ExpressionClassifier& classifier,
|
||||
bool* ok);
|
||||
ExpressionT ParseTemplateLiteral(ExpressionT tag, int start,
|
||||
ExpressionClassifier* classifier, bool* ok);
|
||||
void AddTemplateExpression(ExpressionT);
|
||||
@ -763,12 +875,10 @@ class ParserBase : public Traits {
|
||||
ExpressionT ParseStrongSuperCallExpression(ExpressionClassifier* classifier,
|
||||
bool* ok);
|
||||
|
||||
void ParseFormalParameter(FormalParameterScopeT* scope,
|
||||
FormalParameterErrorLocations* locs, bool is_rest,
|
||||
bool* ok);
|
||||
int ParseFormalParameterList(FormalParameterScopeT* scope,
|
||||
FormalParameterErrorLocations* locs,
|
||||
bool* has_rest, bool* ok);
|
||||
void ParseFormalParameter(FormalParameterScopeT* scope, bool is_rest,
|
||||
ExpressionClassifier* classifier, bool* ok);
|
||||
int ParseFormalParameterList(FormalParameterScopeT* scope, bool* has_rest,
|
||||
ExpressionClassifier* classifier, bool* ok);
|
||||
void CheckArityRestrictions(
|
||||
int param_count, FunctionLiteral::ArityRestriction arity_restriction,
|
||||
int formals_start_pos, int formals_end_pos, bool* ok);
|
||||
@ -973,14 +1083,7 @@ class PreParserExpression {
|
||||
static PreParserExpression BinaryOperation(PreParserExpression left,
|
||||
Token::Value op,
|
||||
PreParserExpression right) {
|
||||
ValidArrowParam valid_arrow_param_list =
|
||||
(op == Token::COMMA && !left.is_single_parenthesized() &&
|
||||
!right.is_single_parenthesized())
|
||||
? std::min(left.ValidateArrowParams(), right.ValidateArrowParams())
|
||||
: kInvalidArrowParam;
|
||||
return PreParserExpression(
|
||||
TypeField::encode(kBinaryOperationExpression) |
|
||||
IsValidArrowParamListField::encode(valid_arrow_param_list));
|
||||
return PreParserExpression(TypeField::encode(kBinaryOperationExpression));
|
||||
}
|
||||
|
||||
static PreParserExpression StringLiteral() {
|
||||
@ -1073,30 +1176,6 @@ class PreParserExpression {
|
||||
return IsIdentifier() || IsProperty();
|
||||
}
|
||||
|
||||
bool IsValidArrowParamList(FormalParameterErrorLocations* locs,
|
||||
const Scanner::Location& params_loc) const {
|
||||
ValidArrowParam valid = ValidateArrowParams();
|
||||
if (ParenthesizationField::decode(code_) == kMultiParenthesizedExpression) {
|
||||
return false;
|
||||
}
|
||||
switch (valid) {
|
||||
case kInvalidArrowParam:
|
||||
return false;
|
||||
case kInvalidStrongArrowParam:
|
||||
locs->undefined = params_loc;
|
||||
return true;
|
||||
case kInvalidStrictReservedArrowParam:
|
||||
locs->reserved = params_loc;
|
||||
return true;
|
||||
case kInvalidStrictEvalArgumentsArrowParam:
|
||||
locs->eval_or_arguments = params_loc;
|
||||
return true;
|
||||
default:
|
||||
DCHECK_EQ(valid, kValidArrowParam);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// At the moment PreParser doesn't track these expression types.
|
||||
bool IsFunctionLiteral() const { return false; }
|
||||
bool IsCallNew() const { return false; }
|
||||
@ -1160,43 +1239,9 @@ class PreParserExpression {
|
||||
kNoTemplateTagExpression
|
||||
};
|
||||
|
||||
// These validity constraints are ordered such that a value of N implies lack
|
||||
// of errors M < N.
|
||||
enum ValidArrowParam {
|
||||
kInvalidArrowParam,
|
||||
kInvalidStrictEvalArgumentsArrowParam,
|
||||
kInvalidStrictReservedArrowParam,
|
||||
kInvalidStrongArrowParam,
|
||||
kValidArrowParam
|
||||
};
|
||||
|
||||
explicit PreParserExpression(uint32_t expression_code)
|
||||
: code_(expression_code) {}
|
||||
|
||||
V8_INLINE ValidArrowParam ValidateArrowParams() const {
|
||||
if (IsBinaryOperation()) {
|
||||
return IsValidArrowParamListField::decode(code_);
|
||||
}
|
||||
if (!IsIdentifier()) {
|
||||
return kInvalidArrowParam;
|
||||
}
|
||||
PreParserIdentifier ident = AsIdentifier();
|
||||
// In strict mode, eval and arguments are not valid formal parameter names.
|
||||
if (ident.IsEval() || ident.IsArguments()) {
|
||||
return kInvalidStrictEvalArgumentsArrowParam;
|
||||
}
|
||||
// In strict mode, future reserved words are not valid either, and as they
|
||||
// produce different errors we allot them their own error code.
|
||||
if (ident.IsFutureStrictReserved()) {
|
||||
return kInvalidStrictReservedArrowParam;
|
||||
}
|
||||
// In strong mode, 'undefined' isn't a valid formal parameter name either.
|
||||
if (ident.IsUndefined()) {
|
||||
return kInvalidStrongArrowParam;
|
||||
}
|
||||
return kValidArrowParam;
|
||||
}
|
||||
|
||||
// The first five bits are for the Type and Parenthesization.
|
||||
typedef BitField<Type, 0, 3> TypeField;
|
||||
typedef BitField<Parenthesization, TypeField::kNext, 2> ParenthesizationField;
|
||||
@ -1207,8 +1252,6 @@ class PreParserExpression {
|
||||
ExpressionTypeField;
|
||||
typedef BitField<bool, ParenthesizationField::kNext, 1> IsUseStrictField;
|
||||
typedef BitField<bool, IsUseStrictField::kNext, 1> IsUseStrongField;
|
||||
typedef BitField<ValidArrowParam, ParenthesizationField::kNext, 3>
|
||||
IsValidArrowParamListField;
|
||||
typedef BitField<PreParserIdentifier::Type, ParenthesizationField::kNext, 10>
|
||||
IdentifierTypeField;
|
||||
|
||||
@ -1696,8 +1739,8 @@ class PreParserTraits {
|
||||
|
||||
V8_INLINE void ParseArrowFunctionFormalParameters(
|
||||
Scope* scope, PreParserExpression expression,
|
||||
const Scanner::Location& params_loc,
|
||||
FormalParameterErrorLocations* error_locs, bool* is_rest, bool* ok);
|
||||
const Scanner::Location& params_loc, bool* is_rest,
|
||||
Scanner::Location* duplicate_loc, bool* ok);
|
||||
|
||||
struct TemplateLiteralState {};
|
||||
|
||||
@ -1928,15 +1971,10 @@ bool PreParserTraits::DeclareFormalParameter(
|
||||
|
||||
void PreParserTraits::ParseArrowFunctionFormalParameters(
|
||||
Scope* scope, PreParserExpression params,
|
||||
const Scanner::Location& params_loc,
|
||||
FormalParameterErrorLocations* error_locs, bool* is_rest, bool* ok) {
|
||||
const Scanner::Location& params_loc, bool* is_rest,
|
||||
Scanner::Location* duplicate_loc, bool* ok) {
|
||||
// TODO(wingo): Detect duplicated identifiers in paramlists. Detect parameter
|
||||
// lists that are too long.
|
||||
if (!params.IsValidArrowParamList(error_locs, params_loc)) {
|
||||
*ok = false;
|
||||
ReportMessageAt(params_loc, "malformed_arrow_function_parameter_list");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2061,27 +2099,51 @@ ParserBase<Traits>::ParseAndClassifyIdentifier(ExpressionClassifier* classifier,
|
||||
Token::Value next = Next();
|
||||
if (next == Token::IDENTIFIER) {
|
||||
IdentifierT name = this->GetSymbol(scanner());
|
||||
if (is_strict(language_mode()) && this->IsEvalOrArguments(name)) {
|
||||
classifier->RecordBindingPatternError(scanner()->location(),
|
||||
"strict_eval_arguments");
|
||||
// When this function is used to read a formal parameter, we don't always
|
||||
// know whether the function is going to be strict or sloppy. Indeed for
|
||||
// arrow functions we don't always know that the identifier we are reading
|
||||
// is actually a formal parameter. Therefore besides the errors that we
|
||||
// must detect because we know we're in strict mode, we also record any
|
||||
// error that we might make in the future once we know the language mode.
|
||||
if (this->IsEval(name)) {
|
||||
classifier->RecordStrictModeFormalParameterError(scanner()->location(),
|
||||
"strict_eval_arguments");
|
||||
if (is_strict(language_mode())) {
|
||||
classifier->RecordBindingPatternError(scanner()->location(),
|
||||
"strict_eval_arguments");
|
||||
}
|
||||
}
|
||||
if (is_strong(language_mode()) && this->IsUndefined(name)) {
|
||||
// TODO(dslomov): allow 'undefined' in nested patterns.
|
||||
classifier->RecordBindingPatternError(scanner()->location(),
|
||||
"strong_undefined");
|
||||
classifier->RecordAssignmentPatternError(scanner()->location(),
|
||||
"strong_undefined");
|
||||
if (this->IsArguments(name)) {
|
||||
scope_->RecordArgumentsUsage();
|
||||
classifier->RecordStrictModeFormalParameterError(scanner()->location(),
|
||||
"strict_eval_arguments");
|
||||
if (is_strict(language_mode())) {
|
||||
classifier->RecordBindingPatternError(scanner()->location(),
|
||||
"strict_eval_arguments");
|
||||
}
|
||||
if (is_strong(language_mode())) {
|
||||
classifier->RecordExpressionError(scanner()->location(),
|
||||
"strong_arguments");
|
||||
}
|
||||
}
|
||||
if (is_strong(language_mode()) && this->IsArguments(name)) {
|
||||
classifier->RecordExpressionError(scanner()->location(),
|
||||
"strong_arguments");
|
||||
if (this->IsUndefined(name)) {
|
||||
classifier->RecordStrongModeFormalParameterError(scanner()->location(),
|
||||
"strong_undefined");
|
||||
if (is_strong(language_mode())) {
|
||||
// TODO(dslomov): allow 'undefined' in nested patterns.
|
||||
classifier->RecordBindingPatternError(scanner()->location(),
|
||||
"strong_undefined");
|
||||
classifier->RecordAssignmentPatternError(scanner()->location(),
|
||||
"strong_undefined");
|
||||
}
|
||||
}
|
||||
if (this->IsArguments(name)) scope_->RecordArgumentsUsage();
|
||||
return name;
|
||||
} else if (is_sloppy(language_mode()) &&
|
||||
(next == Token::FUTURE_STRICT_RESERVED_WORD ||
|
||||
next == Token::LET || next == Token::STATIC ||
|
||||
(next == Token::YIELD && !is_generator()))) {
|
||||
classifier->RecordStrictModeFormalParameterError(
|
||||
scanner()->location(), "unexpected_strict_reserved");
|
||||
return this->GetSymbol(scanner());
|
||||
} else {
|
||||
this->ReportUnexpectedToken(next);
|
||||
@ -2270,24 +2332,41 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
|
||||
break;
|
||||
|
||||
case Token::LBRACK:
|
||||
if (!allow_harmony_destructuring()) {
|
||||
BindingPatternUnexpectedToken(classifier);
|
||||
}
|
||||
result = this->ParseArrayLiteral(classifier, CHECK_OK);
|
||||
break;
|
||||
|
||||
case Token::LBRACE:
|
||||
if (!allow_harmony_destructuring()) {
|
||||
BindingPatternUnexpectedToken(classifier);
|
||||
}
|
||||
result = this->ParseObjectLiteral(classifier, CHECK_OK);
|
||||
break;
|
||||
|
||||
case Token::LPAREN:
|
||||
// Arrow function formal parameters are either a single identifier or a
|
||||
// list of BindingPattern productions enclosed in parentheses.
|
||||
// Parentheses are not valid on the LHS of a BindingPattern, so we use the
|
||||
// is_valid_binding_pattern() check to detect multiple levels of
|
||||
// parenthesization.
|
||||
if (!classifier->is_valid_binding_pattern()) {
|
||||
ArrowFormalParametersUnexpectedToken(classifier);
|
||||
}
|
||||
BindingPatternUnexpectedToken(classifier);
|
||||
Consume(Token::LPAREN);
|
||||
if (allow_harmony_arrow_functions() && Check(Token::RPAREN)) {
|
||||
// As a primary expression, the only thing that can follow "()" is "=>".
|
||||
classifier->RecordBindingPatternError(scanner()->location(),
|
||||
"unexpected_token",
|
||||
Token::String(Token::RPAREN));
|
||||
Scope* scope = this->NewScope(scope_, ARROW_SCOPE);
|
||||
scope->set_start_position(beg_pos);
|
||||
FormalParameterErrorLocations error_locs;
|
||||
ExpressionClassifier args_classifier;
|
||||
bool has_rest = false;
|
||||
result = this->ParseArrowFunctionLiteral(scope, error_locs, has_rest,
|
||||
classifier, CHECK_OK);
|
||||
result = this->ParseArrowFunctionLiteral(scope, has_rest,
|
||||
args_classifier, CHECK_OK);
|
||||
} else {
|
||||
// Heuristically try to detect immediately called functions before
|
||||
// seeing the call parentheses.
|
||||
@ -2364,13 +2443,18 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression(
|
||||
// AssignmentExpression
|
||||
// Expression ',' AssignmentExpression
|
||||
|
||||
ExpressionClassifier binding_classifier;
|
||||
ExpressionT result =
|
||||
this->ParseAssignmentExpression(accept_IN, classifier, CHECK_OK);
|
||||
this->ParseAssignmentExpression(accept_IN, &binding_classifier, CHECK_OK);
|
||||
classifier->Accumulate(binding_classifier,
|
||||
ExpressionClassifier::AllProductions);
|
||||
while (peek() == Token::COMMA) {
|
||||
Expect(Token::COMMA, CHECK_OK);
|
||||
int pos = position();
|
||||
ExpressionT right =
|
||||
this->ParseAssignmentExpression(accept_IN, classifier, CHECK_OK);
|
||||
ExpressionT right = this->ParseAssignmentExpression(
|
||||
accept_IN, &binding_classifier, CHECK_OK);
|
||||
classifier->Accumulate(binding_classifier,
|
||||
ExpressionClassifier::AllProductions);
|
||||
result = factory()->NewBinaryOperation(Token::COMMA, result, right, pos);
|
||||
}
|
||||
return result;
|
||||
@ -2756,29 +2840,52 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
||||
|
||||
if (fni_ != NULL) fni_->Enter();
|
||||
ParserBase<Traits>::Checkpoint checkpoint(this);
|
||||
ExpressionT expression =
|
||||
this->ParseConditionalExpression(accept_IN, classifier, CHECK_OK);
|
||||
ExpressionClassifier arrow_formals_classifier;
|
||||
if (peek() != Token::LPAREN) {
|
||||
// The expression we are going to read is not a parenthesized arrow function
|
||||
// formal parameter list.
|
||||
ArrowFormalParametersUnexpectedToken(&arrow_formals_classifier);
|
||||
}
|
||||
ExpressionT expression = this->ParseConditionalExpression(
|
||||
accept_IN, &arrow_formals_classifier, CHECK_OK);
|
||||
classifier->Accumulate(arrow_formals_classifier);
|
||||
|
||||
if (allow_harmony_arrow_functions() && peek() == Token::ARROW) {
|
||||
checkpoint.Restore();
|
||||
FormalParameterErrorLocations error_locs;
|
||||
BindingPatternUnexpectedToken(classifier);
|
||||
ValidateArrowFormalParameters(&arrow_formals_classifier, expression,
|
||||
CHECK_OK);
|
||||
Scanner::Location loc(lhs_location.beg_pos, scanner()->location().end_pos);
|
||||
bool has_rest = false;
|
||||
Scope* scope = this->NewScope(scope_, ARROW_SCOPE);
|
||||
scope->set_start_position(lhs_location.beg_pos);
|
||||
this->ParseArrowFunctionFormalParameters(scope, expression, loc,
|
||||
&error_locs, &has_rest, CHECK_OK);
|
||||
expression = this->ParseArrowFunctionLiteral(scope, error_locs, has_rest,
|
||||
classifier, CHECK_OK);
|
||||
Scanner::Location duplicate_loc = Scanner::Location::invalid();
|
||||
this->ParseArrowFunctionFormalParameters(scope, expression, loc, &has_rest,
|
||||
&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);
|
||||
return expression;
|
||||
}
|
||||
|
||||
// "expression" was not itself an arrow function parameter list, but it might
|
||||
// form part of one. Propagate speculative formal parameter error locations.
|
||||
classifier->Accumulate(arrow_formals_classifier,
|
||||
ExpressionClassifier::FormalParametersProduction);
|
||||
|
||||
if (!Token::IsAssignmentOp(peek())) {
|
||||
if (fni_ != NULL) fni_->Leave();
|
||||
// Parsed conditional expression only (no assignment).
|
||||
return expression;
|
||||
}
|
||||
|
||||
if (!allow_harmony_destructuring()) {
|
||||
BindingPatternUnexpectedToken(classifier);
|
||||
}
|
||||
|
||||
expression = this->CheckAndRewriteReferenceExpression(
|
||||
expression, lhs_location, "invalid_lhs_in_assignment", CHECK_OK);
|
||||
expression = this->MarkExpressionAsAssigned(expression);
|
||||
@ -2880,6 +2987,7 @@ ParserBase<Traits>::ParseConditionalExpression(bool accept_IN,
|
||||
ExpressionT expression =
|
||||
this->ParseBinaryExpression(4, accept_IN, classifier, CHECK_OK);
|
||||
if (peek() != Token::CONDITIONAL) return expression;
|
||||
BindingPatternUnexpectedToken(classifier);
|
||||
Consume(Token::CONDITIONAL);
|
||||
// In parsing the first assignment expression in conditional
|
||||
// expressions we always accept the 'in' keyword; see ECMA-262,
|
||||
@ -2903,6 +3011,7 @@ ParserBase<Traits>::ParseBinaryExpression(int prec, bool accept_IN,
|
||||
for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
|
||||
// prec1 >= 4
|
||||
while (Precedence(peek(), accept_IN) == prec1) {
|
||||
BindingPatternUnexpectedToken(classifier);
|
||||
Token::Value op = Next();
|
||||
Scanner::Location op_location = scanner()->location();
|
||||
int pos = position();
|
||||
@ -3469,37 +3578,26 @@ ParserBase<Traits>::ParseMemberExpressionContinuation(
|
||||
|
||||
|
||||
template <class Traits>
|
||||
void ParserBase<Traits>::ParseFormalParameter(
|
||||
FormalParameterScopeT* scope, FormalParameterErrorLocations* locs,
|
||||
bool is_rest, bool* ok) {
|
||||
void ParserBase<Traits>::ParseFormalParameter(FormalParameterScopeT* scope,
|
||||
bool is_rest,
|
||||
ExpressionClassifier* classifier,
|
||||
bool* ok) {
|
||||
// FormalParameter[Yield,GeneratorParameter] :
|
||||
// BindingElement[?Yield, ?GeneratorParameter]
|
||||
bool is_strict_reserved;
|
||||
IdentifierT name =
|
||||
ParseIdentifierOrStrictReservedWord(&is_strict_reserved, ok);
|
||||
IdentifierT name = ParseAndClassifyIdentifier(classifier, ok);
|
||||
if (!*ok) return;
|
||||
|
||||
// Store locations for possible future error reports.
|
||||
if (!locs->eval_or_arguments.IsValid() && this->IsEvalOrArguments(name)) {
|
||||
locs->eval_or_arguments = scanner()->location();
|
||||
}
|
||||
if (!locs->undefined.IsValid() && this->IsUndefined(name)) {
|
||||
locs->undefined = scanner()->location();
|
||||
}
|
||||
if (!locs->reserved.IsValid() && is_strict_reserved) {
|
||||
locs->reserved = scanner()->location();
|
||||
}
|
||||
bool was_declared = Traits::DeclareFormalParameter(scope, name, is_rest);
|
||||
if (!locs->duplicate.IsValid() && was_declared) {
|
||||
locs->duplicate = scanner()->location();
|
||||
if (was_declared) {
|
||||
classifier->RecordDuplicateFormalParameterError(scanner()->location());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class Traits>
|
||||
int ParserBase<Traits>::ParseFormalParameterList(
|
||||
FormalParameterScopeT* scope, FormalParameterErrorLocations* locs,
|
||||
bool* is_rest, bool* ok) {
|
||||
FormalParameterScopeT* scope, bool* is_rest,
|
||||
ExpressionClassifier* classifier, bool* ok) {
|
||||
// FormalParameters[Yield,GeneratorParameter] :
|
||||
// [empty]
|
||||
// FormalParameterList[?Yield, ?GeneratorParameter]
|
||||
@ -3524,7 +3622,7 @@ int ParserBase<Traits>::ParseFormalParameterList(
|
||||
return -1;
|
||||
}
|
||||
*is_rest = allow_harmony_rest_params() && Check(Token::ELLIPSIS);
|
||||
ParseFormalParameter(scope, locs, *is_rest, ok);
|
||||
ParseFormalParameter(scope, *is_rest, classifier, ok);
|
||||
if (!*ok) return -1;
|
||||
} while (!*is_rest && Check(Token::COMMA));
|
||||
|
||||
@ -3567,8 +3665,8 @@ void ParserBase<Traits>::CheckArityRestrictions(
|
||||
template <class Traits>
|
||||
typename ParserBase<Traits>::ExpressionT
|
||||
ParserBase<Traits>::ParseArrowFunctionLiteral(
|
||||
Scope* scope, const FormalParameterErrorLocations& error_locs,
|
||||
bool has_rest, ExpressionClassifier* classifier, bool* ok) {
|
||||
Scope* scope, bool has_rest, 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.
|
||||
@ -3590,9 +3688,6 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
|
||||
FunctionState function_state(&function_state_, &scope_, scope,
|
||||
kArrowFunction, &function_factory);
|
||||
|
||||
if (peek() == Token::ARROW) {
|
||||
BindingPatternUnexpectedToken(classifier);
|
||||
}
|
||||
Expect(Token::ARROW, CHECK_OK);
|
||||
|
||||
if (peek() == Token::LBRACE) {
|
||||
@ -3617,8 +3712,10 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
|
||||
// Single-expression body
|
||||
int pos = position();
|
||||
parenthesized_function_ = false;
|
||||
ExpressionClassifier classifier;
|
||||
ExpressionT expression =
|
||||
ParseAssignmentExpression(true, classifier, CHECK_OK);
|
||||
ParseAssignmentExpression(true, &classifier, CHECK_OK);
|
||||
ValidateExpression(&classifier, CHECK_OK);
|
||||
body = this->NewStatementList(1, zone());
|
||||
body->Add(factory()->NewReturnStatement(expression, pos), zone());
|
||||
materialized_literal_count = function_state.materialized_literal_count();
|
||||
@ -3633,9 +3730,9 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
|
||||
// which is not the same as "parameters of a strict function"; it only means
|
||||
// that duplicates are not allowed. Of course, the arrow function may
|
||||
// itself be strict as well.
|
||||
const bool use_strict_params = true;
|
||||
this->CheckFunctionParameterNames(language_mode(), use_strict_params,
|
||||
error_locs, CHECK_OK);
|
||||
const bool allow_duplicate_parameters = false;
|
||||
this->ValidateFormalParameters(&formals_classifier, language_mode(),
|
||||
allow_duplicate_parameters, CHECK_OK);
|
||||
|
||||
// Validate strict mode.
|
||||
if (is_strict(language_mode())) {
|
||||
|
@ -3563,6 +3563,10 @@ TEST(ErrorsArrowFunctions) {
|
||||
"(foo ? bar : baz) => {}",
|
||||
"(a, foo ? bar : baz) => {}",
|
||||
"(foo ? bar : baz, a) => {}",
|
||||
"(a.b, c) => {}",
|
||||
"(c, a.b) => {}",
|
||||
"(a['b'], c) => {}",
|
||||
"(c, a['b']) => {}",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
||||
// Test the case when exception is thrown from the parser when lazy
|
||||
// compiling a function.
|
||||
|
||||
// Flags: --stack_size=32
|
||||
// Flags: --stack_size=42
|
||||
// NOTE: stack size constant above has been empirically chosen.
|
||||
// If the test starts to fail in Genesis, consider increasing this constant.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user