Commit b64e13b0 authored by dslomov's avatar dslomov Committed by Commit bot

[destructuring] Refactor duplicate parameter name detection.

Pushed the detection logic down to ParseAndClassifyIdentifier in
preparation to having patterns in parameter positions.

R=arv@chromium.org,rossberg@chromium.org,wingo@igalia.com
BUG=v8:811
LOG=N

Review URL: https://codereview.chromium.org/1170153003

Cr-Commit-Position: refs/heads/master@{#28876}
parent 08a09d1b
......@@ -782,6 +782,7 @@ source_set("v8_base") {
"src/elements.h",
"src/execution.cc",
"src/execution.h",
"src/expression-classifier.h",
"src/extensions/externalize-string-extension.cc",
"src/extensions/externalize-string-extension.h",
"src/extensions/free-buffer-extension.cc",
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_EXPRESSION_CLASSIFIER_H
#define V8_EXPRESSION_CLASSIFIER_H
#include "src/v8.h"
#include "src/messages.h"
#include "src/scanner.h"
#include "src/token.h"
namespace v8 {
namespace internal {
class ExpressionClassifier {
public:
struct Error {
Error()
: location(Scanner::Location::invalid()),
message(MessageTemplate::kNone),
arg(nullptr) {}
Scanner::Location location;
MessageTemplate::Template message;
const char* arg;
};
enum TargetProduction {
ExpressionProduction = 1 << 0,
BindingPatternProduction = 1 << 1,
AssignmentPatternProduction = 1 << 2,
DistinctFormalParametersProduction = 1 << 3,
StrictModeFormalParametersProduction = 1 << 4,
StrongModeFormalParametersProduction = 1 << 5,
ArrowFormalParametersProduction = 1 << 6,
PatternProductions =
(BindingPatternProduction | AssignmentPatternProduction),
FormalParametersProductions = (DistinctFormalParametersProduction |
StrictModeFormalParametersProduction |
StrongModeFormalParametersProduction),
StandardProductions = ExpressionProduction | PatternProductions,
AllProductions = (StandardProductions | FormalParametersProductions |
ArrowFormalParametersProduction)
};
ExpressionClassifier()
: invalid_productions_(0), duplicate_finder_(nullptr) {}
explicit ExpressionClassifier(DuplicateFinder* duplicate_finder)
: invalid_productions_(0), duplicate_finder_(duplicate_finder) {}
bool is_valid(unsigned productions) const {
return (invalid_productions_ & productions) == 0;
}
DuplicateFinder* duplicate_finder() const { return duplicate_finder_; }
bool is_valid_expression() const { return is_valid(ExpressionProduction); }
bool is_valid_binding_pattern() const {
return is_valid(BindingPatternProduction);
}
bool is_valid_assignment_pattern() const {
return is_valid(AssignmentPatternProduction);
}
bool is_valid_arrow_formal_parameters() const {
return is_valid(ArrowFormalParametersProduction);
}
bool is_valid_formal_parameter_list_without_duplicates() const {
return is_valid(DistinctFormalParametersProduction);
}
// Note: callers should also check
// is_valid_formal_parameter_list_without_duplicates().
bool is_valid_strict_mode_formal_parameters() const {
return is_valid(StrictModeFormalParametersProduction);
}
// 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 is_valid(StrongModeFormalParametersProduction);
}
const Error& expression_error() const { return expression_error_; }
const Error& binding_pattern_error() const { return binding_pattern_error_; }
const Error& assignment_pattern_error() const {
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,
MessageTemplate::Template message,
const char* arg = nullptr) {
if (!is_valid_expression()) return;
invalid_productions_ |= ExpressionProduction;
expression_error_.location = loc;
class ExpressionClassifier {
public:
struct Error {
Error()
: location(Scanner::Location::invalid()),
message(MessageTemplate::kNone),
arg(nullptr) {}
Scanner::Location location;
MessageTemplate::Template message;
const char* arg;
bool HasError() const { return location.IsValid(); }
};
ExpressionClassifier() : duplicate_finder_(nullptr) {}
explicit ExpressionClassifier(DuplicateFinder* duplicate_finder)
: duplicate_finder_(duplicate_finder) {}
DuplicateFinder* duplicate_finder() const { return duplicate_finder_; }
bool is_valid_expression() const { return !expression_error_.HasError(); }
bool is_valid_binding_pattern() const {
return !binding_pattern_error_.HasError();
}
bool is_valid_assignment_pattern() const {
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 {
return binding_pattern_error_;
}
const Error& assignment_pattern_error() const {
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,
MessageTemplate::Template message,
const char* arg = nullptr) {
if (!is_valid_expression()) return;
expression_error_.location = loc;
expression_error_.message = message;
expression_error_.arg = arg;
}
void RecordBindingPatternError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
if (!is_valid_binding_pattern()) return;
binding_pattern_error_.location = loc;
binding_pattern_error_.message = message;
binding_pattern_error_.arg = arg;
}
void RecordAssignmentPatternError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
if (!is_valid_assignment_pattern()) return;
assignment_pattern_error_.location = loc;
assignment_pattern_error_.message = message;
assignment_pattern_error_.arg = arg;
}
void RecordArrowFormalParametersError(const Scanner::Location& loc,
MessageTemplate::Template 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 =
MessageTemplate::kStrictParamDupe;
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, MessageTemplate::Template 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, MessageTemplate::Template 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),
PatternProductions =
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_;
}
}
void AccumulateReclassifyingAsPattern(const ExpressionClassifier& inner) {
Accumulate(inner, AllProductions & ~PatternProductions);
if (!inner.is_valid_expression()) {
if (is_valid_binding_pattern()) {
binding_pattern_error_ = inner.expression_error();
}
if (is_valid_assignment_pattern()) {
assignment_pattern_error_ = inner.expression_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_;
DuplicateFinder* duplicate_finder_;
};
expression_error_.message = message;
expression_error_.arg = arg;
}
void RecordBindingPatternError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
if (!is_valid_binding_pattern()) return;
invalid_productions_ |= BindingPatternProduction;
binding_pattern_error_.location = loc;
binding_pattern_error_.message = message;
binding_pattern_error_.arg = arg;
}
void RecordAssignmentPatternError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
if (!is_valid_assignment_pattern()) return;
invalid_productions_ |= AssignmentPatternProduction;
assignment_pattern_error_.location = loc;
assignment_pattern_error_.message = message;
assignment_pattern_error_.arg = arg;
}
void RecordArrowFormalParametersError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
if (!is_valid_arrow_formal_parameters()) return;
invalid_productions_ |= ArrowFormalParametersProduction;
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;
invalid_productions_ |= DistinctFormalParametersProduction;
duplicate_formal_parameter_error_.location = loc;
duplicate_formal_parameter_error_.message =
MessageTemplate::kStrictParamDupe;
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,
MessageTemplate::Template message,
const char* arg = nullptr) {
if (!is_valid_strict_mode_formal_parameters()) return;
invalid_productions_ |= StrictModeFormalParametersProduction;
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,
MessageTemplate::Template message,
const char* arg = nullptr) {
if (!is_valid_strong_mode_formal_parameters()) return;
invalid_productions_ |= StrongModeFormalParametersProduction;
strong_mode_formal_parameter_error_.location = loc;
strong_mode_formal_parameter_error_.message = message;
strong_mode_formal_parameter_error_.arg = arg;
}
void Accumulate(const ExpressionClassifier& inner,
unsigned productions = StandardProductions) {
// Propagate errors from inner, but don't overwrite already recorded
// errors.
unsigned non_arrow_inner_invalid_productions =
inner.invalid_productions_ & ~ArrowFormalParametersProduction;
if (non_arrow_inner_invalid_productions == 0) return;
unsigned non_arrow_productions =
productions & ~ArrowFormalParametersProduction;
unsigned errors =
non_arrow_productions & non_arrow_inner_invalid_productions;
errors &= ~invalid_productions_;
if (errors != 0) {
invalid_productions_ |= errors;
if (errors & ExpressionProduction)
expression_error_ = inner.expression_error_;
if (errors & BindingPatternProduction)
binding_pattern_error_ = inner.binding_pattern_error_;
if (errors & AssignmentPatternProduction)
assignment_pattern_error_ = inner.assignment_pattern_error_;
if (errors & DistinctFormalParametersProduction)
duplicate_formal_parameter_error_ =
inner.duplicate_formal_parameter_error_;
if (errors & StrictModeFormalParametersProduction)
strict_mode_formal_parameter_error_ =
inner.strict_mode_formal_parameter_error_;
if (errors & StrongModeFormalParametersProduction)
strong_mode_formal_parameter_error_ =
inner.strong_mode_formal_parameter_error_;
}
// As an exception to the above, the result continues to be a valid arrow
// formal parameters if the inner expression is a valid binding pattern.
if (productions & ArrowFormalParametersProduction &&
is_valid_arrow_formal_parameters() &&
!inner.is_valid_binding_pattern()) {
invalid_productions_ |= ArrowFormalParametersProduction;
arrow_formal_parameters_error_ = inner.binding_pattern_error_;
}
}
void AccumulateReclassifyingAsPattern(const ExpressionClassifier& inner) {
Accumulate(inner, AllProductions & ~PatternProductions);
if (!inner.is_valid_expression()) {
if (is_valid_binding_pattern()) {
binding_pattern_error_ = inner.expression_error();
}
if (is_valid_assignment_pattern()) {
assignment_pattern_error_ = inner.expression_error();
}
}
}
private:
unsigned invalid_productions_;
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_;
DuplicateFinder* duplicate_finder_;
};
}
} // v8::internal
#endif // V8_EXPRESSION_CLASSIFIER_H
......@@ -3805,11 +3805,9 @@ void ParserTraits::DeclareArrowFunctionParameters(
parser_->scope_->RemoveUnresolved(expr->AsVariableProxy());
bool is_rest = false;
bool is_duplicate = DeclareFormalParameter(scope, raw_name, is_rest);
if (is_duplicate && !duplicate_loc->IsValid()) {
*duplicate_loc = param_location;
}
ExpressionClassifier classifier;
DeclareFormalParameter(scope, raw_name, &classifier, is_rest);
*duplicate_loc = classifier.duplicate_formal_parameter_error().location;
}
......
......@@ -754,19 +754,9 @@ class ParserTraits {
V8_INLINE Scope* NewScope(Scope* parent_scope, ScopeType scope_type,
FunctionKind kind = kNormalFunction);
bool DeclareFormalParameter(Scope* scope, const AstRawString* name,
bool is_rest) {
bool is_duplicate = false;
Variable* var = scope->DeclareParameter(name, VAR, is_rest, &is_duplicate);
if (is_sloppy(scope->language_mode())) {
// TODO(sigurds) Mark every parameter as maybe assigned. This is a
// conservative approximation necessary to account for parameters
// that are assigned via the arguments array.
var->set_maybe_assigned();
}
return is_duplicate;
}
V8_INLINE void DeclareFormalParameter(Scope* scope, const AstRawString* name,
ExpressionClassifier* classifier,
bool is_rest);
void DeclareArrowFunctionParameters(Scope* scope, Expression* expr,
const Scanner::Location& params_loc,
Scanner::Location* duplicate_loc,
......@@ -1282,6 +1272,25 @@ Expression* ParserTraits::SpreadCallNew(
Expression* function, ZoneList<v8::internal::Expression*>* args, int pos) {
return parser_->SpreadCallNew(function, args, pos);
}
void ParserTraits::DeclareFormalParameter(Scope* scope,
const AstRawString* name,
ExpressionClassifier* classifier,
bool is_rest) {
bool is_duplicate = false;
Variable* var = scope->DeclareParameter(name, VAR, is_rest, &is_duplicate);
if (is_sloppy(scope->language_mode())) {
// TODO(sigurds) Mark every parameter as maybe assigned. This is a
// conservative approximation necessary to account for parameters
// that are assigned via the arguments array.
var->set_maybe_assigned();
}
if (is_duplicate) {
classifier->RecordDuplicateFormalParameterError(
parser_->scanner()->location());
}
}
} } // namespace v8::internal
#endif // V8_PARSER_H_
......@@ -1033,18 +1033,15 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
PreParserFactory factory(NULL);
FunctionState function_state(&function_state_, &scope_, function_scope, kind,
&factory);
ExpressionClassifier formals_classifier;
DuplicateFinder duplicate_finder(scanner()->unicode_cache());
ExpressionClassifier formals_classifier(&duplicate_finder);
bool has_rest = false;
Expect(Token::LPAREN, CHECK_OK);
int start_position = scanner()->location().beg_pos;
function_scope->set_start_position(start_position);
int num_parameters;
{
DuplicateFinder duplicate_finder(scanner()->unicode_cache());
num_parameters = ParseFormalParameterList(&duplicate_finder, &has_rest,
int num_parameters = ParseFormalParameterList(nullptr, &has_rest,
&formals_classifier, CHECK_OK);
}
Expect(Token::RPAREN, CHECK_OK);
int formals_end_position = scanner()->location().end_pos;
......
......@@ -8,6 +8,7 @@
#include "src/v8.h"
#include "src/bailout-reason.h"
#include "src/expression-classifier.h"
#include "src/func-name-inferrer.h"
#include "src/hashmap.h"
#include "src/messages.h"
......@@ -18,7 +19,6 @@
namespace v8 {
namespace internal {
// Common base class shared between parser and pre-parser. Traits encapsulate
// the differences between Parser and PreParser:
......@@ -54,7 +54,6 @@ namespace internal {
// typedef ExpressionList;
// typedef PropertyList;
// typedef FormalParameter;
// typedef FormalParameterScope;
// // For constructing objects returned by the traversing functions.
// typedef Factory;
// };
......@@ -68,7 +67,6 @@ class ParserBase : public Traits {
typedef typename Traits::Type::Expression ExpressionT;
typedef typename Traits::Type::Identifier IdentifierT;
typedef typename Traits::Type::FormalParameter FormalParameterT;
typedef typename Traits::Type::FormalParameterScope FormalParameterScopeT;
typedef typename Traits::Type::FunctionLiteral FunctionLiteralT;
typedef typename Traits::Type::Literal LiteralT;
typedef typename Traits::Type::ObjectLiteralProperty ObjectLiteralPropertyT;
......@@ -506,238 +504,8 @@ class ParserBase : public Traits {
void ReportUnexpectedToken(Token::Value token);
void ReportUnexpectedTokenAt(Scanner::Location location, Token::Value token);
class ExpressionClassifier {
public:
struct Error {
Error()
: location(Scanner::Location::invalid()),
message(MessageTemplate::kNone),
arg(nullptr) {}
Scanner::Location location;
MessageTemplate::Template message;
const char* arg;
};
enum TargetProduction {
ExpressionProduction = 1 << 0,
BindingPatternProduction = 1 << 1,
AssignmentPatternProduction = 1 << 2,
DistinctFormalParametersProduction = 1 << 3,
StrictModeFormalParametersProduction = 1 << 4,
StrongModeFormalParametersProduction = 1 << 5,
ArrowFormalParametersProduction = 1 << 6,
PatternProductions =
(BindingPatternProduction | AssignmentPatternProduction),
FormalParametersProductions = (DistinctFormalParametersProduction |
StrictModeFormalParametersProduction |
StrongModeFormalParametersProduction),
StandardProductions = ExpressionProduction | PatternProductions,
AllProductions = (StandardProductions | FormalParametersProductions |
ArrowFormalParametersProduction)
};
ExpressionClassifier() : invalid_productions_(0) {}
bool is_valid(unsigned productions) const {
return (invalid_productions_ & productions) == 0;
}
bool is_valid_expression() const { return is_valid(ExpressionProduction); }
bool is_valid_binding_pattern() const {
return is_valid(BindingPatternProduction);
}
bool is_valid_assignment_pattern() const {
return is_valid(AssignmentPatternProduction);
}
bool is_valid_arrow_formal_parameters() const {
return is_valid(ArrowFormalParametersProduction);
}
bool is_valid_formal_parameter_list_without_duplicates() const {
return is_valid(DistinctFormalParametersProduction);
}
// Note: callers should also check
// is_valid_formal_parameter_list_without_duplicates().
bool is_valid_strict_mode_formal_parameters() const {
return is_valid(StrictModeFormalParametersProduction);
}
// 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 is_valid(StrongModeFormalParametersProduction);
}
const Error& expression_error() const { return expression_error_; }
const Error& binding_pattern_error() const {
return binding_pattern_error_;
}
const Error& assignment_pattern_error() const {
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,
MessageTemplate::Template message,
const char* arg = nullptr) {
if (!is_valid_expression()) return;
invalid_productions_ |= ExpressionProduction;
expression_error_.location = loc;
expression_error_.message = message;
expression_error_.arg = arg;
}
void RecordBindingPatternError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
if (!is_valid_binding_pattern()) return;
invalid_productions_ |= BindingPatternProduction;
binding_pattern_error_.location = loc;
binding_pattern_error_.message = message;
binding_pattern_error_.arg = arg;
}
void RecordAssignmentPatternError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
if (!is_valid_assignment_pattern()) return;
invalid_productions_ |= AssignmentPatternProduction;
assignment_pattern_error_.location = loc;
assignment_pattern_error_.message = message;
assignment_pattern_error_.arg = arg;
}
void RecordArrowFormalParametersError(const Scanner::Location& loc,
MessageTemplate::Template message,
const char* arg = nullptr) {
if (!is_valid_arrow_formal_parameters()) return;
invalid_productions_ |= ArrowFormalParametersProduction;
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;
invalid_productions_ |= DistinctFormalParametersProduction;
duplicate_formal_parameter_error_.location = loc;
duplicate_formal_parameter_error_.message =
MessageTemplate::kStrictParamDupe;
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,
MessageTemplate::Template message,
const char* arg = nullptr) {
if (!is_valid_strict_mode_formal_parameters()) return;
invalid_productions_ |= StrictModeFormalParametersProduction;
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,
MessageTemplate::Template message,
const char* arg = nullptr) {
if (!is_valid_strong_mode_formal_parameters()) return;
invalid_productions_ |= StrongModeFormalParametersProduction;
strong_mode_formal_parameter_error_.location = loc;
strong_mode_formal_parameter_error_.message = message;
strong_mode_formal_parameter_error_.arg = arg;
}
void Accumulate(const ExpressionClassifier& inner,
unsigned productions = StandardProductions) {
// Propagate errors from inner, but don't overwrite already recorded
// errors.
unsigned non_arrow_inner_invalid_productions =
inner.invalid_productions_ & ~ArrowFormalParametersProduction;
if (non_arrow_inner_invalid_productions == 0) return;
unsigned non_arrow_productions =
productions & ~ArrowFormalParametersProduction;
unsigned errors =
non_arrow_productions & non_arrow_inner_invalid_productions;
errors &= ~invalid_productions_;
if (errors != 0) {
invalid_productions_ |= errors;
if (errors & ExpressionProduction)
expression_error_ = inner.expression_error_;
if (errors & BindingPatternProduction)
binding_pattern_error_ = inner.binding_pattern_error_;
if (errors & AssignmentPatternProduction)
assignment_pattern_error_ = inner.assignment_pattern_error_;
if (errors & DistinctFormalParametersProduction)
duplicate_formal_parameter_error_ =
inner.duplicate_formal_parameter_error_;
if (errors & StrictModeFormalParametersProduction)
strict_mode_formal_parameter_error_ =
inner.strict_mode_formal_parameter_error_;
if (errors & StrongModeFormalParametersProduction)
strong_mode_formal_parameter_error_ =
inner.strong_mode_formal_parameter_error_;
}
// As an exception to the above, the result continues to be a valid arrow
// formal parameters if the inner expression is a valid binding pattern.
if (productions & ArrowFormalParametersProduction &&
is_valid_arrow_formal_parameters() &&
!inner.is_valid_binding_pattern()) {
invalid_productions_ |= ArrowFormalParametersProduction;
arrow_formal_parameters_error_ = inner.binding_pattern_error_;
}
}
void AccumulateReclassifyingAsPattern(const ExpressionClassifier& inner) {
Accumulate(inner, AllProductions & ~PatternProductions);
if (!inner.is_valid_expression()) {
if (is_valid_binding_pattern()) {
binding_pattern_error_ = inner.expression_error();
}
if (is_valid_assignment_pattern()) {
assignment_pattern_error_ = inner.expression_error();
}
}
}
private:
unsigned invalid_productions_;
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(
const typename ExpressionClassifier::Error& error) {
void ReportClassifierError(const ExpressionClassifier::Error& error) {
Traits::ReportMessageAt(error.location, error.message, error.arg,
kSyntaxError);
}
......@@ -890,9 +658,9 @@ class ParserBase : public Traits {
ExpressionT ParseStrongSuperCallExpression(ExpressionClassifier* classifier,
bool* ok);
void ParseFormalParameter(FormalParameterScopeT* scope, bool is_rest,
void ParseFormalParameter(Scope* scope, bool is_rest,
ExpressionClassifier* classifier, bool* ok);
int ParseFormalParameterList(FormalParameterScopeT* scope, bool* has_rest,
int ParseFormalParameterList(Scope* scope, bool* has_rest,
ExpressionClassifier* classifier, bool* ok);
void CheckArityRestrictions(
int param_count, FunctionLiteral::ArityRestriction arity_restriction,
......@@ -1509,7 +1277,6 @@ class PreParserTraits {
typedef PreParserExpressionList ExpressionList;
typedef PreParserExpressionList PropertyList;
typedef PreParserIdentifier FormalParameter;
typedef DuplicateFinder FormalParameterScope;
typedef PreParserStatementList StatementList;
// For constructing objects returned by the traversing functions.
......@@ -1788,9 +1555,8 @@ class PreParserTraits {
return !tag.IsNoTemplateTag();
}
V8_INLINE bool DeclareFormalParameter(DuplicateFinder* scope,
PreParserIdentifier param,
bool is_rest);
void DeclareFormalParameter(Scope* scope, PreParserIdentifier param,
ExpressionClassifier* classifier, bool is_rest) {}
void CheckConflictingVarDeclarations(Scope* scope, bool* ok) {}
......@@ -1984,13 +1750,6 @@ PreParserExpression PreParserTraits::SpreadCallNew(PreParserExpression function,
}
bool PreParserTraits::DeclareFormalParameter(
DuplicateFinder* duplicate_finder, PreParserIdentifier current_identifier,
bool is_rest) {
return pre_parser_->scanner()->FindSymbol(duplicate_finder, 1) != 0;
}
void PreParserTraits::ParseArrowFunctionFormalParameters(
Scope* scope, PreParserExpression params,
const Scanner::Location& params_loc, bool* is_rest,
......@@ -2163,6 +1922,11 @@ ParserBase<Traits>::ParseAndClassifyIdentifier(ExpressionClassifier* classifier,
scanner()->location(), MessageTemplate::kStrongUndefined);
}
}
if (classifier->duplicate_finder() != nullptr &&
scanner()->FindSymbol(classifier->duplicate_finder(), 1) != 0) {
classifier->RecordDuplicateFormalParameterError(scanner()->location());
}
return name;
} else if (is_sloppy(language_mode()) &&
(next == Token::FUTURE_STRICT_RESERVED_WORD ||
......@@ -3682,8 +3446,7 @@ ParserBase<Traits>::ParseMemberExpressionContinuation(
template <class Traits>
void ParserBase<Traits>::ParseFormalParameter(FormalParameterScopeT* scope,
bool is_rest,
void ParserBase<Traits>::ParseFormalParameter(Scope* scope, bool is_rest,
ExpressionClassifier* classifier,
bool* ok) {
// FormalParameter[Yield,GeneratorParameter] :
......@@ -3691,17 +3454,13 @@ void ParserBase<Traits>::ParseFormalParameter(FormalParameterScopeT* scope,
IdentifierT name = ParseAndClassifyIdentifier(classifier, ok);
if (!*ok) return;
bool was_declared = Traits::DeclareFormalParameter(scope, name, is_rest);
if (was_declared) {
classifier->RecordDuplicateFormalParameterError(scanner()->location());
}
Traits::DeclareFormalParameter(scope, name, classifier, is_rest);
}
template <class Traits>
int ParserBase<Traits>::ParseFormalParameterList(
FormalParameterScopeT* scope, bool* is_rest,
ExpressionClassifier* classifier, bool* ok) {
Scope* scope, bool* is_rest, ExpressionClassifier* classifier, bool* ok) {
// FormalParameters[Yield,GeneratorParameter] :
// [empty]
// FormalParameterList[?Yield, ?GeneratorParameter]
......
......@@ -616,6 +616,7 @@
'../../src/elements.h',
'../../src/execution.cc',
'../../src/execution.h',
'../../src/expression-classifier.h',
'../../src/extensions/externalize-string-extension.cc',
'../../src/extensions/externalize-string-extension.h',
'../../src/extensions/free-buffer-extension.cc',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment