| 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())) {
|
|
|