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()) {
|
if (shared_info->is_arrow()) {
|
||||||
Scope* scope = NewScope(scope_, ARROW_SCOPE);
|
Scope* scope = NewScope(scope_, ARROW_SCOPE);
|
||||||
scope->set_start_position(shared_info->start_position());
|
scope->set_start_position(shared_info->start_position());
|
||||||
FormalParameterErrorLocations error_locs;
|
ExpressionClassifier formals_classifier;
|
||||||
bool has_rest = false;
|
bool has_rest = false;
|
||||||
if (Check(Token::LPAREN)) {
|
if (Check(Token::LPAREN)) {
|
||||||
// '(' StrictFormalParameters ')'
|
// '(' StrictFormalParameters ')'
|
||||||
ParseFormalParameterList(scope, &error_locs, &has_rest, &ok);
|
ParseFormalParameterList(scope, &has_rest, &formals_classifier, &ok);
|
||||||
if (ok) ok = Check(Token::RPAREN);
|
if (ok) ok = Check(Token::RPAREN);
|
||||||
} else {
|
} else {
|
||||||
// BindingIdentifier
|
// BindingIdentifier
|
||||||
ParseFormalParameter(scope, &error_locs, has_rest, &ok);
|
ParseFormalParameter(scope, has_rest, &formals_classifier, &ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
ExpressionClassifier classifier;
|
Expression* expression =
|
||||||
Expression* expression = ParseArrowFunctionLiteral(
|
ParseArrowFunctionLiteral(scope, has_rest, formals_classifier, &ok);
|
||||||
scope, error_locs, has_rest, &classifier, &ok);
|
|
||||||
ValidateExpression(&classifier, &ok);
|
|
||||||
if (ok) {
|
if (ok) {
|
||||||
// Scanning must end at the same position that was recorded
|
// Scanning must end at the same position that was recorded
|
||||||
// previously. If not, parsing has been interrupted due to a stack
|
// 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(
|
void ParserTraits::DeclareArrowFunctionParameters(
|
||||||
Scope* scope, Expression* expr, const Scanner::Location& params_loc,
|
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) {
|
if (scope->num_parameters() >= Code::kMaxArguments) {
|
||||||
ReportMessageAt(params_loc, "malformed_arrow_function_parameter_list");
|
ReportMessageAt(params_loc, "malformed_arrow_function_parameter_list");
|
||||||
*ok = false;
|
*ok = false;
|
||||||
@ -3739,6 +3737,7 @@ void ParserTraits::DeclareArrowFunctionParameters(
|
|||||||
// need to match the pre-parser's behavior.
|
// need to match the pre-parser's behavior.
|
||||||
if (expr->IsBinaryOperation()) {
|
if (expr->IsBinaryOperation()) {
|
||||||
BinaryOperation* binop = expr->AsBinaryOperation();
|
BinaryOperation* binop = expr->AsBinaryOperation();
|
||||||
|
// TODO(wingo): These checks are now unnecessary, given the classifier.
|
||||||
if (binop->op() != Token::COMMA) {
|
if (binop->op() != Token::COMMA) {
|
||||||
ReportMessageAt(params_loc, "malformed_arrow_function_parameter_list");
|
ReportMessageAt(params_loc, "malformed_arrow_function_parameter_list");
|
||||||
*ok = false;
|
*ok = false;
|
||||||
@ -3751,7 +3750,7 @@ void ParserTraits::DeclareArrowFunctionParameters(
|
|||||||
*ok = false;
|
*ok = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DeclareArrowFunctionParameters(scope, left, params_loc, error_locs, ok);
|
DeclareArrowFunctionParameters(scope, left, params_loc, duplicate_loc, ok);
|
||||||
if (!*ok) return;
|
if (!*ok) return;
|
||||||
// LHS of comma expression should be unparenthesized.
|
// LHS of comma expression should be unparenthesized.
|
||||||
expr = right;
|
expr = right;
|
||||||
@ -3774,13 +3773,6 @@ void ParserTraits::DeclareArrowFunctionParameters(
|
|||||||
return;
|
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
|
// When the formal parameter was originally seen, it was parsed as a
|
||||||
// VariableProxy and recorded as unresolved in the scope. Here we undo that
|
// VariableProxy and recorded as unresolved in the scope. Here we undo that
|
||||||
// parse-time side-effect.
|
// parse-time side-effect.
|
||||||
@ -3789,22 +3781,15 @@ void ParserTraits::DeclareArrowFunctionParameters(
|
|||||||
bool is_rest = false;
|
bool is_rest = false;
|
||||||
bool is_duplicate = DeclareFormalParameter(scope, raw_name, is_rest);
|
bool is_duplicate = DeclareFormalParameter(scope, raw_name, is_rest);
|
||||||
|
|
||||||
if (is_duplicate) {
|
if (is_duplicate && !duplicate_loc->IsValid()) {
|
||||||
// Arrow function parameter lists are parsed as StrictFormalParameters,
|
*duplicate_loc = param_location;
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ParserTraits::ParseArrowFunctionFormalParameters(
|
void ParserTraits::ParseArrowFunctionFormalParameters(
|
||||||
Scope* scope, Expression* params, const Scanner::Location& params_loc,
|
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:
|
// Too many parentheses around expression:
|
||||||
// (( ... )) => ...
|
// (( ... )) => ...
|
||||||
if (params->is_multi_parenthesized()) {
|
if (params->is_multi_parenthesized()) {
|
||||||
@ -3814,7 +3799,7 @@ void ParserTraits::ParseArrowFunctionFormalParameters(
|
|||||||
return;
|
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 materialized_literal_count = -1;
|
||||||
int expected_property_count = -1;
|
int expected_property_count = -1;
|
||||||
int handler_count = 0;
|
int handler_count = 0;
|
||||||
FormalParameterErrorLocations error_locs;
|
ExpressionClassifier formals_classifier;
|
||||||
FunctionLiteral::EagerCompileHint eager_compile_hint =
|
FunctionLiteral::EagerCompileHint eager_compile_hint =
|
||||||
parenthesized_function_ ? FunctionLiteral::kShouldEagerCompile
|
parenthesized_function_ ? FunctionLiteral::kShouldEagerCompile
|
||||||
: FunctionLiteral::kShouldLazyCompile;
|
: FunctionLiteral::kShouldLazyCompile;
|
||||||
@ -3917,8 +3902,8 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
|||||||
Expect(Token::LPAREN, CHECK_OK);
|
Expect(Token::LPAREN, CHECK_OK);
|
||||||
int start_position = scanner()->location().beg_pos;
|
int start_position = scanner()->location().beg_pos;
|
||||||
scope_->set_start_position(start_position);
|
scope_->set_start_position(start_position);
|
||||||
num_parameters =
|
num_parameters = ParseFormalParameterList(scope, &has_rest,
|
||||||
ParseFormalParameterList(scope, &error_locs, &has_rest, CHECK_OK);
|
&formals_classifier, CHECK_OK);
|
||||||
Expect(Token::RPAREN, CHECK_OK);
|
Expect(Token::RPAREN, CHECK_OK);
|
||||||
int formals_end_position = scanner()->location().end_pos;
|
int formals_end_position = scanner()->location().end_pos;
|
||||||
|
|
||||||
@ -4041,8 +4026,10 @@ FunctionLiteral* Parser::ParseFunctionLiteral(
|
|||||||
name_is_strict_reserved, function_name_location,
|
name_is_strict_reserved, function_name_location,
|
||||||
CHECK_OK);
|
CHECK_OK);
|
||||||
const bool use_strict_params = has_rest || IsConciseMethod(kind);
|
const bool use_strict_params = has_rest || IsConciseMethod(kind);
|
||||||
CheckFunctionParameterNames(language_mode(), use_strict_params, error_locs,
|
const bool allow_duplicate_parameters =
|
||||||
CHECK_OK);
|
is_sloppy(language_mode()) && !use_strict_params;
|
||||||
|
ValidateFormalParameters(&formals_classifier, language_mode(),
|
||||||
|
allow_duplicate_parameters, CHECK_OK);
|
||||||
|
|
||||||
if (is_strict(language_mode())) {
|
if (is_strict(language_mode())) {
|
||||||
CheckStrictOctalLiteral(scope->start_position(), scope->end_position(),
|
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 =
|
FunctionLiteral::ParameterFlag duplicate_parameters =
|
||||||
error_locs.duplicate.IsValid() ? FunctionLiteral::kHasDuplicateParameters
|
has_duplicate_parameters ? FunctionLiteral::kHasDuplicateParameters
|
||||||
: FunctionLiteral::kNoDuplicateParameters;
|
: FunctionLiteral::kNoDuplicateParameters;
|
||||||
|
|
||||||
FunctionLiteral* function_literal = factory()->NewFunctionLiteral(
|
FunctionLiteral* function_literal = factory()->NewFunctionLiteral(
|
||||||
function_name, ast_value_factory(), scope, body,
|
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,
|
void DeclareArrowFunctionParameters(Scope* scope, Expression* expr,
|
||||||
const Scanner::Location& params_loc,
|
const Scanner::Location& params_loc,
|
||||||
FormalParameterErrorLocations* error_locs,
|
Scanner::Location* duplicate_loc,
|
||||||
bool* ok);
|
bool* ok);
|
||||||
void ParseArrowFunctionFormalParameters(
|
void ParseArrowFunctionFormalParameters(Scope* scope, Expression* params,
|
||||||
Scope* scope, Expression* params, const Scanner::Location& params_loc,
|
const Scanner::Location& params_loc,
|
||||||
FormalParameterErrorLocations* error_locs, bool* is_rest, bool* ok);
|
bool* is_rest,
|
||||||
|
Scanner::Location* duplicate_loc,
|
||||||
|
bool* ok);
|
||||||
|
|
||||||
// Temporary glue; these functions will move to ParserBase.
|
// Temporary glue; these functions will move to ParserBase.
|
||||||
Expression* ParseV8Intrinsic(bool* ok);
|
Expression* ParseV8Intrinsic(bool* ok);
|
||||||
|
@ -1024,7 +1024,7 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
|
|||||||
PreParserFactory factory(NULL);
|
PreParserFactory factory(NULL);
|
||||||
FunctionState function_state(&function_state_, &scope_, function_scope, kind,
|
FunctionState function_state(&function_state_, &scope_, function_scope, kind,
|
||||||
&factory);
|
&factory);
|
||||||
FormalParameterErrorLocations error_locs;
|
ExpressionClassifier formals_classifier;
|
||||||
|
|
||||||
bool is_rest = false;
|
bool is_rest = false;
|
||||||
Expect(Token::LPAREN, CHECK_OK);
|
Expect(Token::LPAREN, CHECK_OK);
|
||||||
@ -1033,8 +1033,8 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
|
|||||||
int num_parameters;
|
int num_parameters;
|
||||||
{
|
{
|
||||||
DuplicateFinder duplicate_finder(scanner()->unicode_cache());
|
DuplicateFinder duplicate_finder(scanner()->unicode_cache());
|
||||||
num_parameters = ParseFormalParameterList(&duplicate_finder, &error_locs,
|
num_parameters = ParseFormalParameterList(&duplicate_finder, &is_rest,
|
||||||
&is_rest, CHECK_OK);
|
&formals_classifier, CHECK_OK);
|
||||||
}
|
}
|
||||||
Expect(Token::RPAREN, CHECK_OK);
|
Expect(Token::RPAREN, CHECK_OK);
|
||||||
int formals_end_position = scanner()->location().end_pos;
|
int formals_end_position = scanner()->location().end_pos;
|
||||||
@ -1060,9 +1060,11 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
|
|||||||
// function, since the function can declare itself strict.
|
// function, since the function can declare itself strict.
|
||||||
CheckFunctionName(language_mode(), kind, function_name,
|
CheckFunctionName(language_mode(), kind, function_name,
|
||||||
name_is_strict_reserved, function_name_location, CHECK_OK);
|
name_is_strict_reserved, function_name_location, CHECK_OK);
|
||||||
const bool use_strict_params = is_rest || IsConciseMethod(kind);
|
const bool strict_formal_parameters = is_rest || IsConciseMethod(kind);
|
||||||
CheckFunctionParameterNames(language_mode(), use_strict_params, error_locs,
|
const bool allow_duplicate_parameters =
|
||||||
CHECK_OK);
|
is_sloppy(language_mode()) && !strict_formal_parameters;
|
||||||
|
ValidateFormalParameters(&formals_classifier, language_mode(),
|
||||||
|
allow_duplicate_parameters, CHECK_OK);
|
||||||
|
|
||||||
if (is_strict(language_mode())) {
|
if (is_strict(language_mode())) {
|
||||||
int end_position = scanner()->location().end_pos;
|
int end_position = scanner()->location().end_pos;
|
||||||
|
483
src/preparser.h
483
src/preparser.h
@ -18,25 +18,6 @@ namespace v8 {
|
|||||||
namespace internal {
|
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
|
// Common base class shared between parser and pre-parser. Traits encapsulate
|
||||||
// the differences between Parser and PreParser:
|
// 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.
|
// Determine precedence of given token.
|
||||||
static int Precedence(Token::Value token, bool accept_IN) {
|
static int Precedence(Token::Value token, bool accept_IN) {
|
||||||
if (token == Token::IN && !accept_IN)
|
if (token == Token::IN && !accept_IN)
|
||||||
@ -615,6 +565,26 @@ class ParserBase : public Traits {
|
|||||||
return !assignment_pattern_error_.HasError();
|
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& expression_error() const { return expression_error_; }
|
||||||
|
|
||||||
const Error& binding_pattern_error() const {
|
const Error& binding_pattern_error() const {
|
||||||
@ -625,6 +595,22 @@ class ParserBase : public Traits {
|
|||||||
return assignment_pattern_error_;
|
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,
|
void RecordExpressionError(const Scanner::Location& loc,
|
||||||
const char* message, const char* arg = nullptr) {
|
const char* message, const char* arg = nullptr) {
|
||||||
if (!is_valid_expression()) return;
|
if (!is_valid_expression()) return;
|
||||||
@ -651,10 +637,98 @@ class ParserBase : public Traits {
|
|||||||
assignment_pattern_error_.arg = arg;
|
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:
|
private:
|
||||||
Error expression_error_;
|
Error expression_error_;
|
||||||
Error binding_pattern_error_;
|
Error binding_pattern_error_;
|
||||||
Error assignment_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(
|
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) {
|
void BindingPatternUnexpectedToken(ExpressionClassifier* classifier) {
|
||||||
classifier->RecordBindingPatternError(
|
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:
|
// Recursive descent functions:
|
||||||
@ -750,9 +862,9 @@ class ParserBase : public Traits {
|
|||||||
ExpressionT ParseMemberExpression(ExpressionClassifier* classifier, bool* ok);
|
ExpressionT ParseMemberExpression(ExpressionClassifier* classifier, bool* ok);
|
||||||
ExpressionT ParseMemberExpressionContinuation(
|
ExpressionT ParseMemberExpressionContinuation(
|
||||||
ExpressionT expression, ExpressionClassifier* classifier, bool* ok);
|
ExpressionT expression, ExpressionClassifier* classifier, bool* ok);
|
||||||
ExpressionT ParseArrowFunctionLiteral(
|
ExpressionT ParseArrowFunctionLiteral(Scope* function_scope, bool has_rest,
|
||||||
Scope* function_scope, const FormalParameterErrorLocations& error_locs,
|
const ExpressionClassifier& classifier,
|
||||||
bool has_rest, ExpressionClassifier* classifier, bool* ok);
|
bool* ok);
|
||||||
ExpressionT ParseTemplateLiteral(ExpressionT tag, int start,
|
ExpressionT ParseTemplateLiteral(ExpressionT tag, int start,
|
||||||
ExpressionClassifier* classifier, bool* ok);
|
ExpressionClassifier* classifier, bool* ok);
|
||||||
void AddTemplateExpression(ExpressionT);
|
void AddTemplateExpression(ExpressionT);
|
||||||
@ -763,12 +875,10 @@ class ParserBase : public Traits {
|
|||||||
ExpressionT ParseStrongSuperCallExpression(ExpressionClassifier* classifier,
|
ExpressionT ParseStrongSuperCallExpression(ExpressionClassifier* classifier,
|
||||||
bool* ok);
|
bool* ok);
|
||||||
|
|
||||||
void ParseFormalParameter(FormalParameterScopeT* scope,
|
void ParseFormalParameter(FormalParameterScopeT* scope, bool is_rest,
|
||||||
FormalParameterErrorLocations* locs, bool is_rest,
|
ExpressionClassifier* classifier, bool* ok);
|
||||||
bool* ok);
|
int ParseFormalParameterList(FormalParameterScopeT* scope, bool* has_rest,
|
||||||
int ParseFormalParameterList(FormalParameterScopeT* scope,
|
ExpressionClassifier* classifier, bool* ok);
|
||||||
FormalParameterErrorLocations* locs,
|
|
||||||
bool* has_rest, bool* ok);
|
|
||||||
void CheckArityRestrictions(
|
void CheckArityRestrictions(
|
||||||
int param_count, FunctionLiteral::ArityRestriction arity_restriction,
|
int param_count, FunctionLiteral::ArityRestriction arity_restriction,
|
||||||
int formals_start_pos, int formals_end_pos, bool* ok);
|
int formals_start_pos, int formals_end_pos, bool* ok);
|
||||||
@ -973,14 +1083,7 @@ class PreParserExpression {
|
|||||||
static PreParserExpression BinaryOperation(PreParserExpression left,
|
static PreParserExpression BinaryOperation(PreParserExpression left,
|
||||||
Token::Value op,
|
Token::Value op,
|
||||||
PreParserExpression right) {
|
PreParserExpression right) {
|
||||||
ValidArrowParam valid_arrow_param_list =
|
return PreParserExpression(TypeField::encode(kBinaryOperationExpression));
|
||||||
(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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PreParserExpression StringLiteral() {
|
static PreParserExpression StringLiteral() {
|
||||||
@ -1073,30 +1176,6 @@ class PreParserExpression {
|
|||||||
return IsIdentifier() || IsProperty();
|
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.
|
// At the moment PreParser doesn't track these expression types.
|
||||||
bool IsFunctionLiteral() const { return false; }
|
bool IsFunctionLiteral() const { return false; }
|
||||||
bool IsCallNew() const { return false; }
|
bool IsCallNew() const { return false; }
|
||||||
@ -1160,43 +1239,9 @@ class PreParserExpression {
|
|||||||
kNoTemplateTagExpression
|
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)
|
explicit PreParserExpression(uint32_t expression_code)
|
||||||
: code_(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.
|
// The first five bits are for the Type and Parenthesization.
|
||||||
typedef BitField<Type, 0, 3> TypeField;
|
typedef BitField<Type, 0, 3> TypeField;
|
||||||
typedef BitField<Parenthesization, TypeField::kNext, 2> ParenthesizationField;
|
typedef BitField<Parenthesization, TypeField::kNext, 2> ParenthesizationField;
|
||||||
@ -1207,8 +1252,6 @@ class PreParserExpression {
|
|||||||
ExpressionTypeField;
|
ExpressionTypeField;
|
||||||
typedef BitField<bool, ParenthesizationField::kNext, 1> IsUseStrictField;
|
typedef BitField<bool, ParenthesizationField::kNext, 1> IsUseStrictField;
|
||||||
typedef BitField<bool, IsUseStrictField::kNext, 1> IsUseStrongField;
|
typedef BitField<bool, IsUseStrictField::kNext, 1> IsUseStrongField;
|
||||||
typedef BitField<ValidArrowParam, ParenthesizationField::kNext, 3>
|
|
||||||
IsValidArrowParamListField;
|
|
||||||
typedef BitField<PreParserIdentifier::Type, ParenthesizationField::kNext, 10>
|
typedef BitField<PreParserIdentifier::Type, ParenthesizationField::kNext, 10>
|
||||||
IdentifierTypeField;
|
IdentifierTypeField;
|
||||||
|
|
||||||
@ -1696,8 +1739,8 @@ class PreParserTraits {
|
|||||||
|
|
||||||
V8_INLINE void ParseArrowFunctionFormalParameters(
|
V8_INLINE void ParseArrowFunctionFormalParameters(
|
||||||
Scope* scope, PreParserExpression expression,
|
Scope* scope, PreParserExpression expression,
|
||||||
const Scanner::Location& params_loc,
|
const Scanner::Location& params_loc, bool* is_rest,
|
||||||
FormalParameterErrorLocations* error_locs, bool* is_rest, bool* ok);
|
Scanner::Location* duplicate_loc, bool* ok);
|
||||||
|
|
||||||
struct TemplateLiteralState {};
|
struct TemplateLiteralState {};
|
||||||
|
|
||||||
@ -1928,15 +1971,10 @@ bool PreParserTraits::DeclareFormalParameter(
|
|||||||
|
|
||||||
void PreParserTraits::ParseArrowFunctionFormalParameters(
|
void PreParserTraits::ParseArrowFunctionFormalParameters(
|
||||||
Scope* scope, PreParserExpression params,
|
Scope* scope, PreParserExpression params,
|
||||||
const Scanner::Location& params_loc,
|
const Scanner::Location& params_loc, bool* is_rest,
|
||||||
FormalParameterErrorLocations* error_locs, bool* is_rest, bool* ok) {
|
Scanner::Location* duplicate_loc, bool* ok) {
|
||||||
// TODO(wingo): Detect duplicated identifiers in paramlists. Detect parameter
|
// TODO(wingo): Detect duplicated identifiers in paramlists. Detect parameter
|
||||||
// lists that are too long.
|
// 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();
|
Token::Value next = Next();
|
||||||
if (next == Token::IDENTIFIER) {
|
if (next == Token::IDENTIFIER) {
|
||||||
IdentifierT name = this->GetSymbol(scanner());
|
IdentifierT name = this->GetSymbol(scanner());
|
||||||
if (is_strict(language_mode()) && this->IsEvalOrArguments(name)) {
|
// When this function is used to read a formal parameter, we don't always
|
||||||
classifier->RecordBindingPatternError(scanner()->location(),
|
// know whether the function is going to be strict or sloppy. Indeed for
|
||||||
"strict_eval_arguments");
|
// 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)) {
|
if (this->IsArguments(name)) {
|
||||||
// TODO(dslomov): allow 'undefined' in nested patterns.
|
scope_->RecordArgumentsUsage();
|
||||||
classifier->RecordBindingPatternError(scanner()->location(),
|
classifier->RecordStrictModeFormalParameterError(scanner()->location(),
|
||||||
"strong_undefined");
|
"strict_eval_arguments");
|
||||||
classifier->RecordAssignmentPatternError(scanner()->location(),
|
if (is_strict(language_mode())) {
|
||||||
"strong_undefined");
|
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)) {
|
if (this->IsUndefined(name)) {
|
||||||
classifier->RecordExpressionError(scanner()->location(),
|
classifier->RecordStrongModeFormalParameterError(scanner()->location(),
|
||||||
"strong_arguments");
|
"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;
|
return name;
|
||||||
} else if (is_sloppy(language_mode()) &&
|
} else if (is_sloppy(language_mode()) &&
|
||||||
(next == Token::FUTURE_STRICT_RESERVED_WORD ||
|
(next == Token::FUTURE_STRICT_RESERVED_WORD ||
|
||||||
next == Token::LET || next == Token::STATIC ||
|
next == Token::LET || next == Token::STATIC ||
|
||||||
(next == Token::YIELD && !is_generator()))) {
|
(next == Token::YIELD && !is_generator()))) {
|
||||||
|
classifier->RecordStrictModeFormalParameterError(
|
||||||
|
scanner()->location(), "unexpected_strict_reserved");
|
||||||
return this->GetSymbol(scanner());
|
return this->GetSymbol(scanner());
|
||||||
} else {
|
} else {
|
||||||
this->ReportUnexpectedToken(next);
|
this->ReportUnexpectedToken(next);
|
||||||
@ -2270,24 +2332,41 @@ ParserBase<Traits>::ParsePrimaryExpression(ExpressionClassifier* classifier,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Token::LBRACK:
|
case Token::LBRACK:
|
||||||
|
if (!allow_harmony_destructuring()) {
|
||||||
|
BindingPatternUnexpectedToken(classifier);
|
||||||
|
}
|
||||||
result = this->ParseArrayLiteral(classifier, CHECK_OK);
|
result = this->ParseArrayLiteral(classifier, CHECK_OK);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token::LBRACE:
|
case Token::LBRACE:
|
||||||
|
if (!allow_harmony_destructuring()) {
|
||||||
|
BindingPatternUnexpectedToken(classifier);
|
||||||
|
}
|
||||||
result = this->ParseObjectLiteral(classifier, CHECK_OK);
|
result = this->ParseObjectLiteral(classifier, CHECK_OK);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Token::LPAREN:
|
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);
|
BindingPatternUnexpectedToken(classifier);
|
||||||
Consume(Token::LPAREN);
|
Consume(Token::LPAREN);
|
||||||
if (allow_harmony_arrow_functions() && Check(Token::RPAREN)) {
|
if (allow_harmony_arrow_functions() && Check(Token::RPAREN)) {
|
||||||
// As a primary expression, the only thing that can follow "()" is "=>".
|
// 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* scope = this->NewScope(scope_, ARROW_SCOPE);
|
||||||
scope->set_start_position(beg_pos);
|
scope->set_start_position(beg_pos);
|
||||||
FormalParameterErrorLocations error_locs;
|
ExpressionClassifier args_classifier;
|
||||||
bool has_rest = false;
|
bool has_rest = false;
|
||||||
result = this->ParseArrowFunctionLiteral(scope, error_locs, has_rest,
|
result = this->ParseArrowFunctionLiteral(scope, has_rest,
|
||||||
classifier, CHECK_OK);
|
args_classifier, CHECK_OK);
|
||||||
} else {
|
} else {
|
||||||
// Heuristically try to detect immediately called functions before
|
// Heuristically try to detect immediately called functions before
|
||||||
// seeing the call parentheses.
|
// seeing the call parentheses.
|
||||||
@ -2364,13 +2443,18 @@ typename ParserBase<Traits>::ExpressionT ParserBase<Traits>::ParseExpression(
|
|||||||
// AssignmentExpression
|
// AssignmentExpression
|
||||||
// Expression ',' AssignmentExpression
|
// Expression ',' AssignmentExpression
|
||||||
|
|
||||||
|
ExpressionClassifier binding_classifier;
|
||||||
ExpressionT result =
|
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) {
|
while (peek() == Token::COMMA) {
|
||||||
Expect(Token::COMMA, CHECK_OK);
|
Expect(Token::COMMA, CHECK_OK);
|
||||||
int pos = position();
|
int pos = position();
|
||||||
ExpressionT right =
|
ExpressionT right = this->ParseAssignmentExpression(
|
||||||
this->ParseAssignmentExpression(accept_IN, classifier, CHECK_OK);
|
accept_IN, &binding_classifier, CHECK_OK);
|
||||||
|
classifier->Accumulate(binding_classifier,
|
||||||
|
ExpressionClassifier::AllProductions);
|
||||||
result = factory()->NewBinaryOperation(Token::COMMA, result, right, pos);
|
result = factory()->NewBinaryOperation(Token::COMMA, result, right, pos);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -2756,29 +2840,52 @@ ParserBase<Traits>::ParseAssignmentExpression(bool accept_IN,
|
|||||||
|
|
||||||
if (fni_ != NULL) fni_->Enter();
|
if (fni_ != NULL) fni_->Enter();
|
||||||
ParserBase<Traits>::Checkpoint checkpoint(this);
|
ParserBase<Traits>::Checkpoint checkpoint(this);
|
||||||
ExpressionT expression =
|
ExpressionClassifier arrow_formals_classifier;
|
||||||
this->ParseConditionalExpression(accept_IN, classifier, CHECK_OK);
|
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) {
|
if (allow_harmony_arrow_functions() && peek() == Token::ARROW) {
|
||||||
checkpoint.Restore();
|
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);
|
Scanner::Location loc(lhs_location.beg_pos, scanner()->location().end_pos);
|
||||||
bool has_rest = false;
|
bool has_rest = false;
|
||||||
Scope* scope = this->NewScope(scope_, ARROW_SCOPE);
|
Scope* scope = this->NewScope(scope_, ARROW_SCOPE);
|
||||||
scope->set_start_position(lhs_location.beg_pos);
|
scope->set_start_position(lhs_location.beg_pos);
|
||||||
this->ParseArrowFunctionFormalParameters(scope, expression, loc,
|
Scanner::Location duplicate_loc = Scanner::Location::invalid();
|
||||||
&error_locs, &has_rest, CHECK_OK);
|
this->ParseArrowFunctionFormalParameters(scope, expression, loc, &has_rest,
|
||||||
expression = this->ParseArrowFunctionLiteral(scope, error_locs, has_rest,
|
&duplicate_loc, CHECK_OK);
|
||||||
classifier, 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;
|
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 (!Token::IsAssignmentOp(peek())) {
|
||||||
if (fni_ != NULL) fni_->Leave();
|
if (fni_ != NULL) fni_->Leave();
|
||||||
// Parsed conditional expression only (no assignment).
|
// Parsed conditional expression only (no assignment).
|
||||||
return expression;
|
return expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!allow_harmony_destructuring()) {
|
||||||
|
BindingPatternUnexpectedToken(classifier);
|
||||||
|
}
|
||||||
|
|
||||||
expression = this->CheckAndRewriteReferenceExpression(
|
expression = this->CheckAndRewriteReferenceExpression(
|
||||||
expression, lhs_location, "invalid_lhs_in_assignment", CHECK_OK);
|
expression, lhs_location, "invalid_lhs_in_assignment", CHECK_OK);
|
||||||
expression = this->MarkExpressionAsAssigned(expression);
|
expression = this->MarkExpressionAsAssigned(expression);
|
||||||
@ -2880,6 +2987,7 @@ ParserBase<Traits>::ParseConditionalExpression(bool accept_IN,
|
|||||||
ExpressionT expression =
|
ExpressionT expression =
|
||||||
this->ParseBinaryExpression(4, accept_IN, classifier, CHECK_OK);
|
this->ParseBinaryExpression(4, accept_IN, classifier, CHECK_OK);
|
||||||
if (peek() != Token::CONDITIONAL) return expression;
|
if (peek() != Token::CONDITIONAL) return expression;
|
||||||
|
BindingPatternUnexpectedToken(classifier);
|
||||||
Consume(Token::CONDITIONAL);
|
Consume(Token::CONDITIONAL);
|
||||||
// In parsing the first assignment expression in conditional
|
// In parsing the first assignment expression in conditional
|
||||||
// expressions we always accept the 'in' keyword; see ECMA-262,
|
// 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--) {
|
for (int prec1 = Precedence(peek(), accept_IN); prec1 >= prec; prec1--) {
|
||||||
// prec1 >= 4
|
// prec1 >= 4
|
||||||
while (Precedence(peek(), accept_IN) == prec1) {
|
while (Precedence(peek(), accept_IN) == prec1) {
|
||||||
|
BindingPatternUnexpectedToken(classifier);
|
||||||
Token::Value op = Next();
|
Token::Value op = Next();
|
||||||
Scanner::Location op_location = scanner()->location();
|
Scanner::Location op_location = scanner()->location();
|
||||||
int pos = position();
|
int pos = position();
|
||||||
@ -3469,37 +3578,26 @@ ParserBase<Traits>::ParseMemberExpressionContinuation(
|
|||||||
|
|
||||||
|
|
||||||
template <class Traits>
|
template <class Traits>
|
||||||
void ParserBase<Traits>::ParseFormalParameter(
|
void ParserBase<Traits>::ParseFormalParameter(FormalParameterScopeT* scope,
|
||||||
FormalParameterScopeT* scope, FormalParameterErrorLocations* locs,
|
bool is_rest,
|
||||||
bool is_rest, bool* ok) {
|
ExpressionClassifier* classifier,
|
||||||
|
bool* ok) {
|
||||||
// FormalParameter[Yield,GeneratorParameter] :
|
// FormalParameter[Yield,GeneratorParameter] :
|
||||||
// BindingElement[?Yield, ?GeneratorParameter]
|
// BindingElement[?Yield, ?GeneratorParameter]
|
||||||
bool is_strict_reserved;
|
IdentifierT name = ParseAndClassifyIdentifier(classifier, ok);
|
||||||
IdentifierT name =
|
|
||||||
ParseIdentifierOrStrictReservedWord(&is_strict_reserved, ok);
|
|
||||||
if (!*ok) return;
|
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);
|
bool was_declared = Traits::DeclareFormalParameter(scope, name, is_rest);
|
||||||
if (!locs->duplicate.IsValid() && was_declared) {
|
if (was_declared) {
|
||||||
locs->duplicate = scanner()->location();
|
classifier->RecordDuplicateFormalParameterError(scanner()->location());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <class Traits>
|
template <class Traits>
|
||||||
int ParserBase<Traits>::ParseFormalParameterList(
|
int ParserBase<Traits>::ParseFormalParameterList(
|
||||||
FormalParameterScopeT* scope, FormalParameterErrorLocations* locs,
|
FormalParameterScopeT* scope, bool* is_rest,
|
||||||
bool* is_rest, bool* ok) {
|
ExpressionClassifier* classifier, bool* ok) {
|
||||||
// FormalParameters[Yield,GeneratorParameter] :
|
// FormalParameters[Yield,GeneratorParameter] :
|
||||||
// [empty]
|
// [empty]
|
||||||
// FormalParameterList[?Yield, ?GeneratorParameter]
|
// FormalParameterList[?Yield, ?GeneratorParameter]
|
||||||
@ -3524,7 +3622,7 @@ int ParserBase<Traits>::ParseFormalParameterList(
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
*is_rest = allow_harmony_rest_params() && Check(Token::ELLIPSIS);
|
*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;
|
if (!*ok) return -1;
|
||||||
} while (!*is_rest && Check(Token::COMMA));
|
} while (!*is_rest && Check(Token::COMMA));
|
||||||
|
|
||||||
@ -3567,8 +3665,8 @@ void ParserBase<Traits>::CheckArityRestrictions(
|
|||||||
template <class Traits>
|
template <class Traits>
|
||||||
typename ParserBase<Traits>::ExpressionT
|
typename ParserBase<Traits>::ExpressionT
|
||||||
ParserBase<Traits>::ParseArrowFunctionLiteral(
|
ParserBase<Traits>::ParseArrowFunctionLiteral(
|
||||||
Scope* scope, const FormalParameterErrorLocations& error_locs,
|
Scope* scope, bool has_rest, const ExpressionClassifier& formals_classifier,
|
||||||
bool has_rest, ExpressionClassifier* classifier, bool* ok) {
|
bool* ok) {
|
||||||
if (peek() == Token::ARROW && scanner_->HasAnyLineTerminatorBeforeNext()) {
|
if (peek() == Token::ARROW && scanner_->HasAnyLineTerminatorBeforeNext()) {
|
||||||
// ASI inserts `;` after arrow parameters if a line terminator is found.
|
// ASI inserts `;` after arrow parameters if a line terminator is found.
|
||||||
// `=> ...` is never a valid expression, so report as syntax error.
|
// `=> ...` is never a valid expression, so report as syntax error.
|
||||||
@ -3590,9 +3688,6 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
|
|||||||
FunctionState function_state(&function_state_, &scope_, scope,
|
FunctionState function_state(&function_state_, &scope_, scope,
|
||||||
kArrowFunction, &function_factory);
|
kArrowFunction, &function_factory);
|
||||||
|
|
||||||
if (peek() == Token::ARROW) {
|
|
||||||
BindingPatternUnexpectedToken(classifier);
|
|
||||||
}
|
|
||||||
Expect(Token::ARROW, CHECK_OK);
|
Expect(Token::ARROW, CHECK_OK);
|
||||||
|
|
||||||
if (peek() == Token::LBRACE) {
|
if (peek() == Token::LBRACE) {
|
||||||
@ -3617,8 +3712,10 @@ ParserBase<Traits>::ParseArrowFunctionLiteral(
|
|||||||
// Single-expression body
|
// Single-expression body
|
||||||
int pos = position();
|
int pos = position();
|
||||||
parenthesized_function_ = false;
|
parenthesized_function_ = false;
|
||||||
|
ExpressionClassifier classifier;
|
||||||
ExpressionT expression =
|
ExpressionT expression =
|
||||||
ParseAssignmentExpression(true, classifier, CHECK_OK);
|
ParseAssignmentExpression(true, &classifier, CHECK_OK);
|
||||||
|
ValidateExpression(&classifier, CHECK_OK);
|
||||||
body = this->NewStatementList(1, zone());
|
body = this->NewStatementList(1, zone());
|
||||||
body->Add(factory()->NewReturnStatement(expression, pos), zone());
|
body->Add(factory()->NewReturnStatement(expression, pos), zone());
|
||||||
materialized_literal_count = function_state.materialized_literal_count();
|
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
|
// 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
|
// that duplicates are not allowed. Of course, the arrow function may
|
||||||
// itself be strict as well.
|
// itself be strict as well.
|
||||||
const bool use_strict_params = true;
|
const bool allow_duplicate_parameters = false;
|
||||||
this->CheckFunctionParameterNames(language_mode(), use_strict_params,
|
this->ValidateFormalParameters(&formals_classifier, language_mode(),
|
||||||
error_locs, CHECK_OK);
|
allow_duplicate_parameters, CHECK_OK);
|
||||||
|
|
||||||
// Validate strict mode.
|
// Validate strict mode.
|
||||||
if (is_strict(language_mode())) {
|
if (is_strict(language_mode())) {
|
||||||
|
@ -3563,6 +3563,10 @@ TEST(ErrorsArrowFunctions) {
|
|||||||
"(foo ? bar : baz) => {}",
|
"(foo ? bar : baz) => {}",
|
||||||
"(a, foo ? bar : baz) => {}",
|
"(a, foo ? bar : baz) => {}",
|
||||||
"(foo ? bar : baz, a) => {}",
|
"(foo ? bar : baz, a) => {}",
|
||||||
|
"(a.b, c) => {}",
|
||||||
|
"(c, a.b) => {}",
|
||||||
|
"(a['b'], c) => {}",
|
||||||
|
"(c, a['b']) => {}",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
// Test the case when exception is thrown from the parser when lazy
|
// Test the case when exception is thrown from the parser when lazy
|
||||||
// compiling a function.
|
// compiling a function.
|
||||||
|
|
||||||
// Flags: --stack_size=32
|
// Flags: --stack_size=42
|
||||||
// NOTE: stack size constant above has been empirically chosen.
|
// NOTE: stack size constant above has been empirically chosen.
|
||||||
// If the test starts to fail in Genesis, consider increasing this constant.
|
// If the test starts to fail in Genesis, consider increasing this constant.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user