Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(18)

Unified Diff: src/preparser.h

Issue 1138153003: Use ExpressionClassifier to identify valid arrow function formals (Closed) Base URL: https://chromium.googlesource.com/v8/v8@master
Patch Set: Fix ASAN stack-check regression by bumping stack limit in test Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« src/parser.cc ('K') | « src/parser.cc ('k') | src/preparser.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/preparser.h
diff --git a/src/preparser.h b/src/preparser.h
index 541da23af1acfb83b59426c34e664195844bb9d5..3be19aa49eb1f76258c8e020ba160529bb6c175d 100644
--- a/src/preparser.h
+++ b/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())) {
« src/parser.cc ('K') | « src/parser.cc ('k') | src/preparser.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698