From d1b4e31bc5a55556de1c9d72905cc0f3af26b080 Mon Sep 17 00:00:00 2001 From: Toon Verwaest Date: Mon, 17 Dec 2018 10:28:27 +0100 Subject: [PATCH] [parser] Replacing ExpressionClassifier with ExpressionScope that knows what it's tracking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since it's explicit what we're tracking, we can immediately throw errors in certain cases, and ignore irrelevant errors. We don't need to use the classifier itself to track "let let", since we know whether we're parsing a "let". Errors that were previously (almost) always accumulated are now immediately pushed to the scopes that care (parameter initialization errors). This CL drops avoiding allocation of classified errors, at least for now, but that doesn't affect performance anymore since we don't aggressively blacklist anymore. Classified errors are even less likely with the more precise approach. ParseAssignmentExpression doesn't introduce its own scope immediately, but reuses the outer scope. Rather than using full ExpressionClassifiers + Accumulate to separate expressions/patterns from each other while keeping track of the overall error state, this now uses an explicit AccumulationScope. When we parse (async) arrow functions we introduce new scopes that track that they may be (async) arrow functions. We track StrictModeFormal parameters in 2 different ways if it isn't immediately certain that it is a strict-mode formal error: Either directly on the (Pre)ParserFormalParameters, or on the NextArrowFunctionInfo in the case we're not yet certain that we'll have an arrow function. In the latter case we don't have a FormalParameter object yet, and we'll copy it over once we know we're parsing an arrow function. The latter works because it's not allowed to change strictness of a function with non-simple parameters. Design doc: https://docs.google.com/document/d/1FAvEp9EUK-G8kHfDIEo_385Hs2SUBCYbJ5H-NnLvq8M/ Change-Id: If4ecd717c9780095c7ddc859c8945b3d7d268a9d Reviewed-on: https://chromium-review.googlesource.com/c/1367809 Commit-Queue: Toon Verwaest Reviewed-by: Adam Klein Reviewed-by: Marja Hölttä Cr-Commit-Position: refs/heads/master@{#58307} --- BUILD.gn | 2 +- src/ast/scopes.cc | 1 + src/parsing/expression-classifier.h | 459 ----------- src/parsing/expression-scope.h | 516 ++++++++++++ src/parsing/parser-base.h | 743 +++++++++--------- src/parsing/parser.cc | 21 +- src/parsing/parser.h | 24 +- src/parsing/preparser.cc | 21 +- src/parsing/preparser.h | 27 +- test/message/regress/fail/regress-903874.out | 5 - .../es8/async-arrow-default-function-await.js | 5 + .../regress}/regress-903874.js | 2 +- 12 files changed, 948 insertions(+), 878 deletions(-) delete mode 100644 src/parsing/expression-classifier.h create mode 100644 src/parsing/expression-scope.h delete mode 100644 test/message/regress/fail/regress-903874.out create mode 100644 test/mjsunit/es8/async-arrow-default-function-await.js rename test/{message/regress/fail => mjsunit/regress}/regress-903874.js (86%) diff --git a/BUILD.gn b/BUILD.gn index a9ae7260f1..21b22f5131 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -2433,9 +2433,9 @@ v8_source_set("v8_base") { "src/optimized-compilation-info.h", "src/ostreams.cc", "src/ostreams.h", - "src/parsing/expression-classifier.h", "src/parsing/expression-scope-reparenter.cc", "src/parsing/expression-scope-reparenter.h", + "src/parsing/expression-scope.h", "src/parsing/func-name-inferrer.cc", "src/parsing/func-name-inferrer.h", "src/parsing/parse-info.cc", diff --git a/src/ast/scopes.cc b/src/ast/scopes.cc index 76d3d9bde4..3da700ce0a 100644 --- a/src/ast/scopes.cc +++ b/src/ast/scopes.cc @@ -844,6 +844,7 @@ void DeclarationScope::AddLocal(Variable* var) { } void Scope::Snapshot::Reparent(DeclarationScope* new_parent) { + DCHECK(!IsCleared()); DCHECK_EQ(new_parent, outer_scope_and_calls_eval_.GetPointer()->inner_scope_); DCHECK_EQ(new_parent->outer_scope_, outer_scope_and_calls_eval_.GetPointer()); DCHECK_EQ(new_parent, new_parent->GetClosureScope()); diff --git a/src/parsing/expression-classifier.h b/src/parsing/expression-classifier.h deleted file mode 100644 index 5407b468cf..0000000000 --- a/src/parsing/expression-classifier.h +++ /dev/null @@ -1,459 +0,0 @@ -// 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_PARSING_EXPRESSION_CLASSIFIER_H_ -#define V8_PARSING_EXPRESSION_CLASSIFIER_H_ - -#include - -#include "src/message-template.h" -#include "src/parsing/scanner.h" - -namespace v8 { -namespace internal { - -template -class ZoneList; - -#define ERROR_CODES(T) \ - T(ExpressionProduction, 0) \ - T(FormalParameterInitializerProduction, 1) \ - T(PatternProduction, 2) \ - T(BindingPatternProduction, 3) \ - T(StrictModeFormalParametersProduction, 4) \ - T(LetPatternProduction, 5) \ - T(AsyncArrowFormalParametersProduction, 6) - -// Expression classifiers serve two purposes: -// -// 1) They keep track of error messages that are pending (and other -// related information), waiting for the parser to decide whether -// the parsed expression is a pattern or not. -// 2) They keep track of expressions that may need to be rewritten, if -// the parser decides that they are not patterns. (A different -// mechanism implements the rewriting of patterns.) -// -// Expression classifiers are used by the parser in a stack fashion. -// Each new classifier is pushed on top of the stack. This happens -// automatically by the class's constructor. While on top of the -// stack, the classifier records pending error messages and tracks the -// pending non-patterns of the expression that is being parsed. -// -// At the end of its life, a classifier is either "accumulated" to the -// one that is below it on the stack, or is "discarded". The former -// is achieved by calling the method Accumulate. The latter is -// achieved automatically by the destructor, but it can happen earlier -// by calling the method Discard. Both actions result in removing the -// classifier from the parser's stack. - -// Expression classifier is split into four parts. The base implementing the -// general expression classifier logic. Two parts that implement the error -// tracking interface, where one is the actual implementation and the other is -// an empty class providing only the interface without logic. The expression -// classifier class then combines the other parts and provides the full -// expression classifier interface by inheriting conditionally, controlled by -// Types::ExpressionClassifierReportErrors, either from the ErrorTracker or the -// EmptyErrorTracker. -// -// Base -// / \ -// / \ -// / \ -// / \ -// ErrorTracker EmptyErrorTracker -// \ / -// \ / -// \ / -// \ / -// ExpressionClassifier - -template -class ExpressionClassifier; - -template -class ExpressionClassifierBase { - public: - enum ErrorKind : unsigned { -#define DEFINE_ERROR_KIND(NAME, CODE) k##NAME = CODE, - ERROR_CODES(DEFINE_ERROR_KIND) -#undef DEFINE_ERROR_KIND - kUnusedError = 15 // Larger than error codes; should fit in 4 bits - }; - - struct Error { - V8_INLINE Error() - : location(Scanner::Location::invalid()), - message_(static_cast(MessageTemplate::kNone)), - kind(kUnusedError) {} - V8_INLINE explicit Error(Scanner::Location loc, MessageTemplate msg, - ErrorKind k, const char* a = nullptr) - : location(loc), message_(static_cast(msg)), kind(k) {} - - Scanner::Location location; - // GCC doesn't like storing the enum class directly in 28 bits, so we - // have to wrap it in a getter. - MessageTemplate message() const { - STATIC_ASSERT(static_cast(MessageTemplate::kLastMessage) < - (1 << 28)); - return static_cast(message_); - } - int message_ : 28; - unsigned kind : 4; - }; - - // clang-format off - enum TargetProduction : unsigned { -#define DEFINE_PRODUCTION(NAME, CODE) NAME = 1 << CODE, - ERROR_CODES(DEFINE_PRODUCTION) -#undef DEFINE_PRODUCTION - -#define DEFINE_ALL_PRODUCTIONS(NAME, CODE) NAME | - AllProductions = ERROR_CODES(DEFINE_ALL_PRODUCTIONS) /* | */ 0 -#undef DEFINE_ALL_PRODUCTIONS - }; - // clang-format on - - explicit ExpressionClassifierBase(typename Types::Base* base) - : base_(base), - invalid_productions_(0), - is_non_simple_parameter_list_(0) {} - - virtual ~ExpressionClassifierBase() = default; - - V8_INLINE bool is_valid(unsigned productions) const { - return (invalid_productions_ & productions) == 0; - } - - V8_INLINE bool is_valid_expression() const { - return is_valid(ExpressionProduction); - } - - V8_INLINE bool is_valid_formal_parameter_initializer() const { - return is_valid(FormalParameterInitializerProduction); - } - - V8_INLINE bool is_valid_pattern() const { - return is_valid(PatternProduction); - } - - V8_INLINE bool is_valid_binding_pattern() const { - return is_valid(BindingPatternProduction); - } - - // Note: callers should also check - // is_valid_formal_parameter_list_without_duplicates(). - V8_INLINE bool is_valid_strict_mode_formal_parameters() const { - return is_valid(StrictModeFormalParametersProduction); - } - - V8_INLINE bool is_valid_let_pattern() const { - return is_valid(LetPatternProduction); - } - - bool is_valid_async_arrow_formal_parameters() const { - return is_valid(AsyncArrowFormalParametersProduction); - } - - V8_INLINE bool is_simple_parameter_list() const { - return !is_non_simple_parameter_list_; - } - - V8_INLINE void RecordNonSimpleParameter() { - is_non_simple_parameter_list_ = 1; - } - - V8_INLINE void Accumulate(ExpressionClassifier* const inner, - unsigned productions) { -#ifdef DEBUG - static_cast(this)->CheckErrorPositions(inner); -#endif - // Propagate errors from inner, but don't overwrite already recorded - // errors. - unsigned filter = productions & ~this->invalid_productions_; - unsigned errors = inner->invalid_productions_ & filter; - static_cast(this)->AccumulateErrorImpl(inner, productions, - errors); - this->invalid_productions_ |= errors; - } - - protected: - typename Types::Base* base_; - unsigned invalid_productions_ : kUnusedError; - STATIC_ASSERT(kUnusedError <= 15); - unsigned is_non_simple_parameter_list_ : 1; -}; - -template -class ExpressionClassifierErrorTracker - : public ExpressionClassifierBase> { - public: - using BaseClassType = - ExpressionClassifierBase>; - using typename BaseClassType::Error; - using typename BaseClassType::ErrorKind; - using TP = typename BaseClassType::TargetProduction; - - explicit ExpressionClassifierErrorTracker(typename Types::Base* base) - : BaseClassType(base), - reported_errors_(base->impl()->GetReportedErrorList()) { - reported_errors_begin_ = reported_errors_end_ = reported_errors_->length(); - } - - ~ExpressionClassifierErrorTracker() override { - if (reported_errors_end_ == reported_errors_->length()) { - reported_errors_->Rewind(reported_errors_begin_); - reported_errors_end_ = reported_errors_begin_; - } - DCHECK_EQ(reported_errors_begin_, reported_errors_end_); - } - - protected: - V8_INLINE const Error& reported_error(ErrorKind kind) const { - if (!this->is_valid(1 << kind)) { - for (int i = reported_errors_begin_; i < reported_errors_end_; i++) { - if (reported_errors_->at(i).kind == kind) - return reported_errors_->at(i); - } - UNREACHABLE(); - } - // We should only be looking for an error when we know that one has - // been reported. But we're not... So this is to make sure we have - // the same behaviour. - UNREACHABLE(); - - // Make MSVC happy by returning an error from this inaccessible path. - static Error none; - return none; - } - - // Adds e to the end of the list of reported errors for this classifier. - // It is expected that this classifier is the last one in the stack. - V8_INLINE void Add(TP production, const Error& e) { - if (!this->is_valid(production)) return; - this->invalid_productions_ |= production; - DCHECK_EQ(reported_errors_end_, reported_errors_->length()); - reported_errors_->Add(e, this->base_->impl()->zone()); - reported_errors_end_++; - } - - // Copies the error at position i of the list of reported errors, so that - // it becomes the last error reported for this classifier. Position i - // could be either after the existing errors of this classifier (i.e., - // in an inner classifier) or it could be an existing error (in case a - // copy is needed). - V8_INLINE void Copy(int i) { - DCHECK_LT(i, reported_errors_->length()); - if (reported_errors_end_ != i) - reported_errors_->at(reported_errors_end_) = reported_errors_->at(i); - reported_errors_end_++; - } - - private: -#ifdef DEBUG - V8_INLINE void CheckErrorPositions(ExpressionClassifier* const inner) { - DCHECK_EQ(inner->reported_errors_, this->reported_errors_); - DCHECK_EQ(inner->reported_errors_begin_, this->reported_errors_end_); - DCHECK_EQ(inner->reported_errors_end_, this->reported_errors_->length()); - } -#endif - - V8_INLINE void RewindErrors(ExpressionClassifier* const inner) { - this->reported_errors_->Rewind(this->reported_errors_end_); - inner->reported_errors_begin_ = inner->reported_errors_end_ = - this->reported_errors_end_; - } - - void AccumulateErrorImpl(ExpressionClassifier* const inner, - unsigned productions, unsigned errors) { - // Traverse the list of errors reported by the inner classifier - // to copy what's necessary. - for (int i = inner->reported_errors_begin_; errors != 0; i++) { - int mask = 1 << this->reported_errors_->at(i).kind; - if ((errors & mask) != 0) { - errors ^= mask; - this->Copy(i); - } - } - - RewindErrors(inner); - } - - private: - ZoneList* reported_errors_; - // The uint16_t for reported_errors_begin_ and reported_errors_end_ will - // not be enough in the case of a long series of expressions using nested - // classifiers, e.g., a long sequence of assignments, as in: - // literals with spreads, as in: - // var N=65536; eval("var x;" + "x=".repeat(N) + "42"); - // This should not be a problem, as such things currently fail with a - // stack overflow while parsing. - uint16_t reported_errors_begin_; - uint16_t reported_errors_end_; - - friend BaseClassType; -}; - -template -class ExpressionClassifierEmptyErrorTracker - : public ExpressionClassifierBase< - Types, ExpressionClassifierEmptyErrorTracker> { - public: - using BaseClassType = - ExpressionClassifierBase>; - using typename BaseClassType::Error; - using typename BaseClassType::ErrorKind; - using TP = typename BaseClassType::TargetProduction; - - explicit ExpressionClassifierEmptyErrorTracker(typename Types::Base* base) - : BaseClassType(base) {} - - protected: - V8_INLINE const Error& reported_error(ErrorKind kind) const { - static Error none; - return none; - } - - V8_INLINE void Add(TP production, const Error& e) { - this->invalid_productions_ |= production; - } - - private: -#ifdef DEBUG - V8_INLINE void CheckErrorPositions(ExpressionClassifier* const inner) { - } -#endif - V8_INLINE void AccumulateErrorImpl(ExpressionClassifier* const inner, - unsigned productions, unsigned errors) {} - - friend BaseClassType; -}; - -template -class ExpressionClassifier - : public std::conditional< - Types::ExpressionClassifierReportErrors, - ExpressionClassifierErrorTracker, - ExpressionClassifierEmptyErrorTracker>::type { - static constexpr bool ReportErrors = Types::ExpressionClassifierReportErrors; - - public: - using BaseClassType = typename std::conditional< - Types::ExpressionClassifierReportErrors, - typename ExpressionClassifierErrorTracker::BaseClassType, - typename ExpressionClassifierEmptyErrorTracker::BaseClassType>:: - type; - using typename BaseClassType::Error; - using typename BaseClassType::ErrorKind; - using TP = typename BaseClassType::TargetProduction; - - explicit ExpressionClassifier(typename Types::Base* base) - : std::conditional< - Types::ExpressionClassifierReportErrors, - ExpressionClassifierErrorTracker, - ExpressionClassifierEmptyErrorTracker>::type(base), - previous_(base->classifier_) { - base->classifier_ = this; - } - - V8_INLINE ~ExpressionClassifier() override { - if (this->base_->classifier_ == this) this->base_->classifier_ = previous_; - } - - V8_INLINE const Error& expression_error() const { - return this->reported_error(ErrorKind::kExpressionProduction); - } - - V8_INLINE const Error& formal_parameter_initializer_error() const { - return this->reported_error( - ErrorKind::kFormalParameterInitializerProduction); - } - - V8_INLINE const Error& pattern_error() const { - return this->reported_error(ErrorKind::kPatternProduction); - } - - V8_INLINE const Error& binding_pattern_error() const { - return this->reported_error(ErrorKind::kBindingPatternProduction); - } - - V8_INLINE const Error& strict_mode_formal_parameter_error() const { - return this->reported_error( - ErrorKind::kStrictModeFormalParametersProduction); - } - - V8_INLINE const Error& let_pattern_error() const { - return this->reported_error(ErrorKind::kLetPatternProduction); - } - - V8_INLINE const Error& async_arrow_formal_parameters_error() const { - return this->reported_error( - ErrorKind::kAsyncArrowFormalParametersProduction); - } - - V8_INLINE bool does_error_reporting() { return ReportErrors; } - - void RecordExpressionError(const Scanner::Location& loc, - MessageTemplate message) { - this->Add(TP::ExpressionProduction, - Error(loc, message, ErrorKind::kExpressionProduction)); - } - - void RecordFormalParameterInitializerError(const Scanner::Location& loc, - MessageTemplate message) { - this->Add( - TP::FormalParameterInitializerProduction, - Error(loc, message, ErrorKind::kFormalParameterInitializerProduction)); - } - - void RecordPatternError(const Scanner::Location& loc, - MessageTemplate message) { - this->Add(TP::PatternProduction, - Error(loc, message, ErrorKind::kPatternProduction)); - } - - void RecordBindingPatternError(const Scanner::Location& loc, - MessageTemplate message) { - this->Add(TP::BindingPatternProduction, - Error(loc, message, ErrorKind::kBindingPatternProduction)); - } - - void RecordAsyncArrowFormalParametersError(const Scanner::Location& loc, - MessageTemplate message) { - this->Add( - TP::AsyncArrowFormalParametersProduction, - Error(loc, message, ErrorKind::kAsyncArrowFormalParametersProduction)); - } - - // 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 message) { - this->Add( - TP::StrictModeFormalParametersProduction, - Error(loc, message, ErrorKind::kStrictModeFormalParametersProduction)); - } - - void RecordLetPatternError(const Scanner::Location& loc, - MessageTemplate message) { - this->Add(TP::LetPatternProduction, - Error(loc, message, ErrorKind::kLetPatternProduction)); - } - - ExpressionClassifier* previous() const { return previous_; } - - private: - ExpressionClassifier* previous_; - - DISALLOW_COPY_AND_ASSIGN(ExpressionClassifier); -}; - -#undef ERROR_CODES - -} // namespace internal -} // namespace v8 - -#endif // V8_PARSING_EXPRESSION_CLASSIFIER_H_ diff --git a/src/parsing/expression-scope.h b/src/parsing/expression-scope.h new file mode 100644 index 0000000000..3102fc1714 --- /dev/null +++ b/src/parsing/expression-scope.h @@ -0,0 +1,516 @@ +// Copyright 2018 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_PARSING_EXPRESSION_SCOPE_H_ +#define V8_PARSING_EXPRESSION_SCOPE_H_ + +#include "src/message-template.h" +#include "src/parsing/scanner.h" + +namespace v8 { +namespace internal { + +template +class ExpressionParsingScope; +template +class AccumulationScope; +template +class ArrowHeadParsingScope; + +// ExpressionScope is used in a stack fashion, and is used to specialize +// expression parsing for the task at hand. It allows the parser to reuse the +// same code to parse destructuring declarations, assignment patterns, +// expressions, and (async) arrow function heads. +// +// One of the specific subclasses needs to be instantiated to tell the parser +// the meaning of the expression it will parse next. The parser then calls +// Record* on the expression_scope() to indicate errors. The expression_scope +// will either discard those errors, immediately report those errors, or +// classify the errors for later validation. +// TODO(verwaest): Record is a slightly odd name since it will directly throw +// for unambiguous scopes. +template +class ExpressionScope { + public: + typedef typename Types::Impl ParserT; + typedef typename Types::Expression ExpressionT; + + enum ScopeType : uint8_t { + // Expression or assignment target. + kExpression, + + // Declaration or expression or assignment target. + kMaybeArrowParameterDeclaration, + kMaybeAsyncArrowParameterDeclaration, + + // Declarations. + kParameterDeclaration, + kVarDeclaration, + kLexicalDeclaration, + }; + + void ValidateAsPattern(ExpressionT expression, int begin, int end) { + if (!CanBeExpression()) return; + AsExpressionParsingScope()->ValidatePattern(expression, begin, end); + AsExpressionParsingScope()->ClearExpressionError(); + } + + // Record async arrow parameters errors in all ambiguous async arrow scopes in + // the chain up to the first unambiguous scope. + void RecordAsyncArrowParametersError(const Scanner::Location& loc, + MessageTemplate message) { + // Only ambiguous scopes (ExpressionParsingScope, *ArrowHeadParsingScope) + // need to propagate errors to a possible kAsyncArrowHeadParsingScope, so + // immediately return if the current scope is not ambiguous. + if (!CanBeExpression()) return; + AsExpressionParsingScope()->RecordAsyncArrowParametersError(loc, message); + } + + // Record initializer errors in all scopes that can turn into parameter scopes + // (ArrowHeadParsingScopes) up to the first known unambiguous parameter scope. + void RecordParameterInitializerError(const Scanner::Location& loc, + MessageTemplate message) { + ExpressionScope* scope = this; + while (!scope->IsCertainlyParameterDeclaration()) { + if (!has_possible_parameter_in_scope_chain_) return; + if (scope->CanBeParameterDeclaration()) { + scope->AsArrowHeadParsingScope()->RecordDeclarationError(loc, message); + } + scope = scope->parent(); + if (scope == nullptr) return; + } + Report(loc, message); + } + + void RecordPatternError(const Scanner::Location& loc, + MessageTemplate message) { + // TODO(verwaest): Non-assigning expression? + if (IsCertainlyPattern()) { + Report(loc, message); + } else { + AsExpressionParsingScope()->RecordPatternError(loc, message); + } + } + + void RecordStrictModeParameterError(const Scanner::Location& loc, + MessageTemplate message) { + DCHECK_IMPLIES(!has_error(), loc.IsValid()); + if (!CanBeParameterDeclaration()) return; + if (IsCertainlyParameterDeclaration()) { + if (is_strict(parser_->language_mode())) { + Report(loc, message); + } else { + parser_->parameters_->set_strict_parameter_error(loc, message); + } + } else { + parser_->next_arrow_function_info_.strict_parameter_error_location = loc; + parser_->next_arrow_function_info_.strict_parameter_error_message = + message; + } + } + + void RecordDeclarationError(const Scanner::Location& loc, + MessageTemplate message) { + if (!CanBeDeclaration()) return; + if (IsCertainlyDeclaration()) { + Report(loc, message); + } else { + AsArrowHeadParsingScope()->RecordDeclarationError(loc, message); + } + } + + void RecordExpressionError(const Scanner::Location& loc, + MessageTemplate message) { + if (!CanBeExpression()) return; + // TODO(verwaest): Non-assigning expression? + // if (IsCertainlyExpression()) Report(loc, message); + AsExpressionParsingScope()->RecordExpressionError(loc, message); + } + + void RecordLexicalDeclarationError(const Scanner::Location& loc, + MessageTemplate message) { + if (IsLexicalDeclaration()) Report(loc, message); + } + + void RecordNonSimpleParameter() { + if (!IsArrowHeadParsingScope()) return; + AsArrowHeadParsingScope()->RecordNonSimpleParameter(); + } + + protected: + ParserT* parser() const { return parser_; } + ExpressionScope* parent() const { return parent_; } + + void Report(const Scanner::Location& loc, MessageTemplate message) const { + parser_->ReportMessageAt(loc, message); + } + + ExpressionScope(ParserT* parser, ScopeType type) + : parser_(parser), + parent_(parser->expression_scope_), + type_(type), + has_possible_parameter_in_scope_chain_( + CanBeParameterDeclaration() || + (parent_ && parent_->has_possible_parameter_in_scope_chain_)) { + parser->expression_scope_ = this; + } + + ~ExpressionScope() { + DCHECK(parser_->expression_scope_ == this || + parser_->expression_scope_ == parent_); + parser_->expression_scope_ = parent_; + } + + ExpressionParsingScope* AsExpressionParsingScope() { + DCHECK(CanBeExpression()); + return static_cast*>(this); + } + +#ifdef DEBUG + bool has_error() const { return parser_->has_error(); } +#endif + + bool CanBeExpression() const { + return IsInRange(type_, kExpression, kMaybeAsyncArrowParameterDeclaration); + } + bool CanBeDeclaration() const { + return IsInRange(type_, kMaybeArrowParameterDeclaration, + kLexicalDeclaration); + } + bool IsCertainlyDeclaration() const { + return IsInRange(type_, kParameterDeclaration, kLexicalDeclaration); + } + + private: + friend class AccumulationScope; + friend class ExpressionParsingScope; + + ArrowHeadParsingScope* AsArrowHeadParsingScope() { + DCHECK(IsArrowHeadParsingScope()); + return static_cast*>(this); + } + + bool IsArrowHeadParsingScope() const { + return IsInRange(type_, kMaybeArrowParameterDeclaration, + kMaybeAsyncArrowParameterDeclaration); + } + bool IsCertainlyPattern() const { return IsCertainlyDeclaration(); } + bool CanBeParameterDeclaration() const { + return IsInRange(type_, kMaybeArrowParameterDeclaration, + kParameterDeclaration); + } + bool IsCertainlyParameterDeclaration() const { + return type_ == kParameterDeclaration; + } + bool IsLexicalDeclaration() const { return type_ == kLexicalDeclaration; } + + ParserT* parser_; + ExpressionScope* parent_; + ScopeType type_; + bool has_possible_parameter_in_scope_chain_; + + DISALLOW_COPY_AND_ASSIGN(ExpressionScope); +}; + +// Used to parse var, let, const declarations and declarations known up-front to +// be parameters. +template +class DeclarationParsingScope : public ExpressionScope { + public: + typedef typename Types::Impl ParserT; + typedef typename ExpressionScope::ScopeType ScopeType; + + DeclarationParsingScope(ParserT* parser, ScopeType type) + : ExpressionScope(parser, type) { + DCHECK(this->IsCertainlyDeclaration()); + } + + private: + DISALLOW_COPY_AND_ASSIGN(DeclarationParsingScope); +}; + +// Parsing expressions is always ambiguous between at least left-hand-side and +// right-hand-side of assignments. This class is used to keep track of errors +// relevant for either side until it is clear what was being parsed. +template +class ExpressionParsingScope : public ExpressionScope { + public: + typedef typename Types::Impl ParserT; + typedef typename Types::Expression ExpressionT; + typedef class ExpressionScope ExpressionScopeT; + typedef typename ExpressionScopeT::ScopeType ScopeType; + + ExpressionParsingScope(ParserT* parser, + ScopeType type = ExpressionScopeT::kExpression) + : ExpressionScopeT(parser, type), + has_async_arrow_in_scope_chain_( + type == ExpressionScopeT::kMaybeAsyncArrowParameterDeclaration || + (this->parent() && this->parent()->CanBeExpression() && + this->parent() + ->AsExpressionParsingScope() + ->has_async_arrow_in_scope_chain_)) { + DCHECK(this->CanBeExpression()); + clear(kExpressionIndex); + clear(kPatternIndex); + } + + void RecordAsyncArrowParametersError(const Scanner::Location& loc, + MessageTemplate message) { + for (ExpressionScopeT* scope = this; scope != nullptr; + scope = scope->parent()) { + if (!has_async_arrow_in_scope_chain_) break; + if (scope->type_ == + ExpressionScopeT::kMaybeAsyncArrowParameterDeclaration) { + scope->AsArrowHeadParsingScope()->RecordDeclarationError(loc, message); + } + } + } + + ~ExpressionParsingScope() { DCHECK(this->has_error() || verified_); } + + ExpressionT ValidateAndRewriteReference(ExpressionT expression, int beg_pos, + int end_pos) { + if (V8_LIKELY(this->parser()->IsAssignableIdentifier(expression))) { + this->mark_verified(); + return expression; + } else if (V8_LIKELY(expression->IsProperty())) { + ValidateExpression(); + return expression; + } + this->mark_verified(); + return this->parser()->RewriteInvalidReferenceExpression( + expression, beg_pos, end_pos, MessageTemplate::kInvalidLhsInFor, + kSyntaxError); + } + + void RecordExpressionError(const Scanner::Location& loc, + MessageTemplate message) { + Record(kExpressionIndex, loc, message); + } + + void RecordPatternError(const Scanner::Location& loc, + MessageTemplate message) { + Record(kPatternIndex, loc, message); + } + + void ValidateExpression() { Validate(kExpressionIndex); } + + void ValidatePattern(ExpressionT expression, int begin, int end) { + Validate(kPatternIndex); + if (expression->is_parenthesized()) { + ExpressionScopeT::Report(Scanner::Location(begin, end), + MessageTemplate::kInvalidDestructuringTarget); + } + } + + void ClearExpressionError() { + DCHECK(verified_); +#ifdef DEBUG + verified_ = false; +#endif + clear(kExpressionIndex); + } + + protected: + bool is_verified() const { +#ifdef DEBUG + return verified_; +#else + return false; +#endif + } + + void ValidatePattern() { Validate(kPatternIndex); } + + private: + friend class AccumulationScope; + + enum ErrorNumber : uint8_t { + kExpressionIndex = 0, + kPatternIndex = 1, + kNumberOfErrors = 2, + }; + void clear(int index) { + messages_[index] = MessageTemplate::kNone; + locations_[index] = Scanner::Location::invalid(); + } + bool is_valid(int index) const { return !locations_[index].IsValid(); } + void Record(int index, const Scanner::Location& loc, + MessageTemplate message) { + DCHECK_IMPLIES(!this->has_error(), loc.IsValid()); + if (!is_valid(index)) return; + messages_[index] = message; + locations_[index] = loc; + } + void Validate(int index) { + DCHECK(!this->is_verified()); + if (!is_valid(index)) Report(index); + this->mark_verified(); + } + void Report(int index) const { + ExpressionScopeT::Report(locations_[index], messages_[index]); + } + + // Debug verification to make sure every scope is validated exactly once. + void mark_verified() { +#ifdef DEBUG + verified_ = true; +#endif + } + void clear_verified() { +#ifdef DEBUG + verified_ = false; +#endif + } +#ifdef DEBUG + bool verified_ = false; +#endif + + MessageTemplate messages_[kNumberOfErrors]; + Scanner::Location locations_[kNumberOfErrors]; + bool has_async_arrow_in_scope_chain_; + + DISALLOW_COPY_AND_ASSIGN(ExpressionParsingScope); +}; + +// This class is used to parse multiple ambiguous expressions and declarations +// in the same scope. E.g., in async(X,Y,Z) or [X,Y,Z], X and Y and Z will all +// be parsed in the respective outer ArrowHeadParsingScope and +// ExpressionParsingScope. It provides a clean error state in the underlying +// scope to parse the individual expressions, while keeping track of the +// expression and pattern errors since the start. The AccumulationScope is only +// used to keep track of the errors so far, and the underlying ExpressionScope +// keeps being used as the expression_scope(). If the expression_scope() isn't +// ambiguous, this class does not do anything. +template +class AccumulationScope { + public: + typedef typename Types::Impl ParserT; + + static const int kNumberOfErrors = + ExpressionParsingScope::kNumberOfErrors; + explicit AccumulationScope(ExpressionScope* scope) : scope_(nullptr) { + if (!scope->CanBeExpression()) return; + scope_ = scope->AsExpressionParsingScope(); + for (int i = 0; i < kNumberOfErrors; i++) { + // If the underlying scope is already invalid at the start, stop + // accumulating. That means an error was found outside of an + // accumulating path. + if (!scope_->is_valid(i)) { + scope_ = nullptr; + break; + } + copy(i); + } + } + + // Merge errors from the underlying ExpressionParsingScope into this scope. + // Only keeps the first error across all accumulate calls, and removes the + // error from the underlying scope. + void Accumulate() { + if (scope_ == nullptr) return; + DCHECK(!scope_->is_verified()); + for (int i = 0; i < kNumberOfErrors; i++) { + if (!locations_[i].IsValid()) copy(i); + scope_->clear(i); + } + } + + // This is called instead of Accumulate in case the parsed member is already + // known to be an expression. In that case we don't need to accumulate the + // expression but rather validate it immediately. We also ignore the pattern + // error since the parsed member is known to not be a pattern. This is + // necessary for "{x:1}.y" parsed as part of an assignment pattern. {x:1} will + // record a pattern error, but "{x:1}.y" is actually a valid as part of an + // assignment pattern since it's a property access. + void ValidateExpression() { + if (scope_ == nullptr) return; + DCHECK(!scope_->is_verified()); + scope_->ValidateExpression(); + DCHECK(scope_->is_verified()); + scope_->clear(ExpressionParsingScope::kPatternIndex); +#ifdef DEBUG + scope_->clear_verified(); +#endif + } + + ~AccumulationScope() { + if (scope_ == nullptr) return; + for (int i = 0; i < kNumberOfErrors; i++) copy_back(i); + } + + private: + void copy(int entry) { + messages_[entry] = scope_->messages_[entry]; + locations_[entry] = scope_->locations_[entry]; + } + + void copy_back(int entry) { + if (!locations_[entry].IsValid()) return; + scope_->messages_[entry] = messages_[entry]; + scope_->locations_[entry] = locations_[entry]; + } + + ExpressionParsingScope* scope_; + MessageTemplate messages_[2]; + Scanner::Location locations_[2]; + + DISALLOW_COPY_AND_ASSIGN(AccumulationScope); +}; + +// The head of an arrow function is ambiguous between expression, assignment +// pattern and declaration. This keeps track of the additional declaration +// error and allows the scope to be validated as a declaration rather than an +// expression or a pattern. +template +class ArrowHeadParsingScope : public ExpressionParsingScope { + public: + typedef typename Types::Impl ParserT; + typedef typename ExpressionScope::ScopeType ScopeType; + + ArrowHeadParsingScope(ParserT* parser, ScopeType type) + : ExpressionParsingScope(parser, type) { + DCHECK(this->CanBeDeclaration()); + DCHECK(!this->IsCertainlyDeclaration()); + } + + void ValidateExpression() { + // Turns out this is not an arrow head. Clear any possible tracked strict + // parameter errors. + this->parser()->next_arrow_function_info_.ClearStrictParameterError(); + ExpressionParsingScope::ValidateExpression(); + } + + void ValidateDeclaration() { + DCHECK(!this->is_verified()); + if (declaration_error_location.IsValid()) { + ExpressionScope::Report(declaration_error_location, + declaration_error_message); + } + this->ValidatePattern(); + } + + void RecordDeclarationError(const Scanner::Location& loc, + MessageTemplate message) { + DCHECK_IMPLIES(!this->has_error(), loc.IsValid()); + declaration_error_location = loc; + declaration_error_message = message; + } + + bool has_simple_parameter_list() const { return has_simple_parameter_list_; } + + void RecordNonSimpleParameter() { has_simple_parameter_list_ = false; } + + private: + Scanner::Location declaration_error_location = Scanner::Location::invalid(); + MessageTemplate declaration_error_message = MessageTemplate::kNone; + bool has_simple_parameter_list_ = true; + + DISALLOW_COPY_AND_ASSIGN(ArrowHeadParsingScope); +}; + +} // namespace internal +} // namespace v8 + +#endif // V8_PARSING_EXPRESSION_SCOPE_H_ diff --git a/src/parsing/parser-base.h b/src/parsing/parser-base.h index 7c4eac254a..851501b659 100644 --- a/src/parsing/parser-base.h +++ b/src/parsing/parser-base.h @@ -19,7 +19,7 @@ #include "src/globals.h" #include "src/log.h" #include "src/message-template.h" -#include "src/parsing/expression-classifier.h" +#include "src/parsing/expression-scope.h" #include "src/parsing/func-name-inferrer.h" #include "src/parsing/scanner.h" #include "src/parsing/token.h" @@ -40,6 +40,8 @@ enum AllowLabelledFunctionStatement { kDisallowLabelledFunctionStatement, }; +enum ParsingArrowHeadFlag { kCertainlyNotArrowHead, kMaybeArrowHead }; + enum class ParseFunctionFlag : uint8_t { kIsNormal = 0, kIsGenerator = 1 << 0, @@ -193,8 +195,14 @@ class ParserBase { public: // Shorten type names defined by ParserTypes. typedef ParserTypes Types; - typedef typename v8::internal::ExpressionClassifier - ExpressionClassifier; + typedef typename v8::internal::ExpressionScope ExpressionScope; + typedef typename v8::internal::ExpressionParsingScope + ExpressionParsingScope; + typedef typename v8::internal::AccumulationScope AccumulationScope; + typedef typename v8::internal::ArrowHeadParsingScope + ArrowHeadParsingScope; + typedef typename v8::internal::DeclarationParsingScope + DeclarationParsingScope; // Return types for traversing functions. typedef typename Types::Block BlockT; @@ -247,7 +255,7 @@ class ParserBase { stack_limit_(stack_limit), pending_error_handler_(pending_error_handler), zone_(zone), - classifier_(nullptr), + expression_scope_(nullptr), scanner_(scanner), function_literal_id_(0), script_id_(script_id), @@ -263,7 +271,7 @@ class ParserBase { pointer_buffer_.reserve(128); } - ~ParserBase() { scope_snapshot_.Clear(); } + ~ParserBase() { next_arrow_function_info_.scope_snapshot.Clear(); } #define ALLOW_ACCESSORS(name) \ bool allow_##name() const { return allow_##name##_; } \ @@ -279,7 +287,9 @@ class ParserBase { #undef ALLOW_ACCESSORS - void set_rewritable_length(int i) { rewritable_length_ = i; } + void set_rewritable_length(int i) { + next_arrow_function_info_.rewritable_length = i; + } V8_INLINE bool has_error() const { return scanner()->has_parser_error(); } bool allow_harmony_numeric_separator() const { return scanner()->allow_harmony_numeric_separator(); @@ -322,7 +332,9 @@ class ParserBase { Zone* zone() const { return zone_; } protected: - friend class v8::internal::ExpressionClassifier>; + friend class v8::internal::ExpressionScope>; + friend class v8::internal::ExpressionParsingScope>; + friend class v8::internal::ArrowHeadParsingScope>; enum LazyParsingResult { kLazyParsingComplete, kLazyParsingAborted }; @@ -402,10 +414,6 @@ class ParserBase { return destructuring_assignments_to_rewrite_; } - ZoneList* GetReportedErrorList() { - return &reported_errors_; - } - bool next_function_is_likely_called() const { return next_function_is_likely_called_; } @@ -458,8 +466,6 @@ class ParserBase { ZoneChunkList destructuring_assignments_to_rewrite_; - ZoneList reported_errors_; - // A reason, if any, why this function should not be optimized. BailoutReason dont_optimize_reason_; @@ -579,8 +585,10 @@ class ParserBase { enum class PropertyPosition { kObjectLiteral, kClassLiteral }; struct ParsePropertyInfo { public: - explicit ParsePropertyInfo(ParserBase* parser) - : name(parser->impl()->NullIdentifier()), + explicit ParsePropertyInfo(ParserBase* parser, + AccumulationScope* accumulation_scope = nullptr) + : accumulation_scope(accumulation_scope), + name(parser->impl()->NullIdentifier()), position(PropertyPosition::kClassLiteral), function_flags(ParseFunctionFlag::kIsNormal), kind(ParsePropertyKind::kNotSet), @@ -620,6 +628,7 @@ class ParserBase { return false; } + AccumulationScope* accumulation_scope; IdentifierT name; PropertyPosition position; ParseFunctionFlags function_flags; @@ -863,9 +872,11 @@ class ParserBase { return should_throw; } + ExpressionT ParsePossibleDestructuringSubPattern(AccumulationScope* scope); void CheckDestructuringElement(ExpressionT element, int beg_pos, int end_pos); - void ClassifyFormalParameter(IdentifierT formal, int beg_pos, int end_pos); - void ClassifyArrowFormalParameter(ExpressionT formal); + void ClassifyParameter(IdentifierT parameter, int beg_pos, int end_pos); + void ClassifyArrowParameter(AccumulationScope* accumulation_scope, + int position, ExpressionT parameter); // Checking the name of a function literal. This has to be done after parsing // the function, since the function can declare itself strict. @@ -945,84 +956,14 @@ class ParserBase { Scanner::Location location, Token::Value token, MessageTemplate message = MessageTemplate::kUnexpectedToken); - V8_NOINLINE void ReportClassifierError( - const typename ExpressionClassifier::Error& error) { - if (classifier()->does_error_reporting()) { - impl()->ReportMessageAt(error.location, error.message()); - } else { - impl()->ReportUnidentifiableError(); - } - } - - void ValidateExpression() { - if (!classifier()->is_valid_expression()) { - ReportClassifierError(classifier()->expression_error()); - } - } - - void ValidateFormalParameterInitializer() { - if (!classifier()->is_valid_formal_parameter_initializer()) { - ReportClassifierError(classifier()->formal_parameter_initializer_error()); - } - } - - void ValidateBindingPattern() { - if (!classifier()->is_valid_binding_pattern()) { - ReportClassifierError(classifier()->binding_pattern_error()); - } - ValidatePattern(); - } - - void ValidatePattern() { - if (!classifier()->is_valid_pattern()) { - ReportClassifierError(classifier()->pattern_error()); - } - } - - void ValidatePattern(ExpressionT expression) { - if (expression->is_parenthesized()) { - impl()->ReportMessageAt( - Scanner::Location(expression->position(), end_position()), - MessageTemplate::kInvalidDestructuringTarget); - } - ValidatePattern(); - } - void ValidateFormalParameters(LanguageMode language_mode, const FormalParametersT& parameters, bool allow_duplicates) { - if (!allow_duplicates && parameters.has_duplicate()) { - if (classifier()->does_error_reporting()) { - impl()->ReportMessageAt(parameters.duplicate_location(), - MessageTemplate::kParamDupe); - } else { - impl()->ReportUnidentifiableError(); - } - } else if (is_strict(language_mode) && - !classifier()->is_valid_strict_mode_formal_parameters()) { - ReportClassifierError(classifier()->strict_mode_formal_parameter_error()); - } + if (!allow_duplicates) parameters.ValidateDuplicate(impl()); + if (is_strict(language_mode)) parameters.ValidateStrictMode(impl()); } - void ValidateArrowFormalParameters(ExpressionT expression) { - ValidateBindingPattern(); - if (!expression->is_parenthesized() && !impl()->IsIdentifier(expression)) { - // Non-parenthesized destructuring param. - impl()->ReportMessageAt( - Scanner::Location(expression->position(), position()), - MessageTemplate::kMalformedArrowFunParamList); - } - DCHECK_IMPLIES(IsAsyncFunction(next_arrow_function_kind_), - classifier()->is_valid_async_arrow_formal_parameters()); - } - - void ValidateLetPattern() { - if (!classifier()->is_valid_let_pattern()) { - ReportClassifierError(classifier()->let_pattern_error()); - } - } - - V8_INLINE IdentifierT ParseAndClassifyIdentifier(); + V8_INLINE IdentifierT ParseAndClassifyIdentifier(Token::Value token); // Parses an identifier or a strict mode future reserved word. Allows passing // in function_kind for the case of parsing the identifier in a function // expression, where the relevant "function_kind" bit is of the function being @@ -1044,19 +985,23 @@ class ParserBase { ExpressionT ParseBindingPattern(); ExpressionT ParsePrimaryExpression(); - // Use when parsing an expression that is known to not be a pattern or part - // of a pattern. + // Use when parsing an expression that is known to not be a pattern or part of + // a pattern. V8_INLINE ExpressionT ParseExpression(); + V8_INLINE ExpressionT ParseAssignmentExpression(); - // This method does not wrap the parsing of the expression inside a - // new expression classifier; it uses the top-level classifier instead. - // It should be used whenever we're parsing something with the "cover" - // grammar that recognizes both patterns and non-patterns (which roughly - // corresponds to what's inside the parentheses generated by the symbol + // These methods do not wrap the parsing of the expression inside a new + // expression_scope; they use the outer expression_scope instead. They should + // be used whenever we're parsing something with the "cover" grammar that + // recognizes both patterns and non-patterns (which roughly corresponds to + // what's inside the parentheses generated by the symbol // "CoverParenthesizedExpressionAndArrowParameterList" in the ES 2017 // specification). ExpressionT ParseExpressionCoverGrammar(); - ExpressionT ParseArrowFormalsWithRest(ExpressionListT* list); + ExpressionT ParseAssignmentExpressionCoverGrammar(); + + ExpressionT ParseArrowParametersWithRest(ExpressionListT* list, + AccumulationScope* scope); ExpressionT ParseArrayLiteral(); @@ -1077,13 +1022,10 @@ class ParserBase { bool is_static); ObjectLiteralPropertyT ParseObjectPropertyDefinition( ParsePropertyInfo* prop_info, bool* has_seen_proto); - void ParseArguments(ExpressionListT* args, bool* has_spread, - bool maybe_arrow); - void ParseArguments(ExpressionListT* args, bool* has_spread) { - ParseArguments(args, has_spread, false); - } + void ParseArguments( + ExpressionListT* args, bool* has_spread, + ParsingArrowHeadFlag maybe_arrow = kCertainlyNotArrowHead); - ExpressionT ParseAssignmentExpression(); ExpressionT ParseYieldExpression(); V8_INLINE ExpressionT ParseConditionalExpression(); ExpressionT ParseConditionalContinuation(ExpressionT expression, int pos); @@ -1364,21 +1306,11 @@ class ParserBase { } Scope* scope() const { return scope_; } - // Stack of expression classifiers. - // The top of the stack is always pointed to by classifier(). - V8_INLINE ExpressionClassifier* classifier() const { - DCHECK_NOT_NULL(classifier_); - return classifier_; - } - - // Accumulates the classifier that is on top of the stack (inner) to - // the one that is right below (outer) and pops the inner. - V8_INLINE void Accumulate(unsigned productions) { - DCHECK_NOT_NULL(classifier_); - ExpressionClassifier* previous = classifier_->previous(); - DCHECK_NOT_NULL(previous); - previous->Accumulate(classifier_, productions); - classifier_ = previous; + // Stack of expression expression_scopes. + // The top of the stack is always pointed to by expression_scope(). + V8_INLINE ExpressionScope* expression_scope() const { + DCHECK_NOT_NULL(expression_scope_); + return expression_scope_; } class AcceptINScope final { @@ -1395,18 +1327,35 @@ class ParserBase { bool previous_accept_IN_; }; - // Accumulate errors that can be arbitrarily deep in an expression. - // These correspond to the ECMAScript spec's 'Contains' operation - // on productions. This includes: - // - // - YieldExpression is disallowed in arrow parameters in a generator. - // - AwaitExpression is disallowed in arrow parameters in an async function. - // - AwaitExpression is disallowed in async arrow parameters. - // - V8_INLINE void AccumulateFormalParameterContainmentErrors() { - Accumulate(ExpressionClassifier::FormalParameterInitializerProduction | - ExpressionClassifier::AsyncArrowFormalParametersProduction); - } + class ParameterParsingScope { + public: + ParameterParsingScope(Impl* parser, FormalParametersT* parameters) + : parser_(parser), parent_parameters_(parser_->parameters_) { + parser_->parameters_ = parameters; + } + + ~ParameterParsingScope() { parser_->parameters_ = parent_parameters_; } + + private: + Impl* parser_; + FormalParametersT* parent_parameters_; + }; + + class FunctionBodyParsingScope { + public: + explicit FunctionBodyParsingScope(Impl* parser) + : parser_(parser), expression_scope_(parser_->expression_scope_) { + parser_->expression_scope_ = nullptr; + } + + ~FunctionBodyParsingScope() { + parser_->expression_scope_ = expression_scope_; + } + + private: + Impl* parser_; + ExpressionScope* expression_scope_; + }; std::vector* pointer_buffer() { return &pointer_buffer_; } @@ -1430,24 +1379,53 @@ class ParserBase { private: Zone* zone_; - ExpressionClassifier* classifier_; + ExpressionScope* expression_scope_; std::vector pointer_buffer_; Scanner* scanner_; - Scope::Snapshot scope_snapshot_; - // `rewritable_length_`: length of the destructuring_assignments_to_rewrite() - // queue in the parent function state, prior to parsing of formal parameters. - // If the arrow function is lazy, any items added during formal parameter - // parsing are removed from the queue. - int rewritable_length_ = -1; - int function_literal_id_; int script_id_; FunctionLiteral::EagerCompileHint default_eager_compile_hint_; - FunctionKind next_arrow_function_kind_ = FunctionKind::kArrowFunction; + + // This struct is used to move information about the next arrow function from + // the place where the arrow head was parsed to where the body will be parsed. + // Nothing can be parsed between the head and the body, so it will be consumed + // immediately after it's produced. + // Preallocating the struct as part of the parser minimizes the cost of + // supporting arrow functions on non-arrow expressions. + struct NextArrowFunctionInfo { + Scope::Snapshot scope_snapshot; + // `rewritable_length`: length of the destructuring_assignments_to_rewrite() + // queue in the parent function state, prior to parsing of formal + // parameters. If the arrow function is lazy, any items added during formal + // parameter parsing are removed from the queue. + int rewritable_length = -1; + Scanner::Location strict_parameter_error_location = + Scanner::Location::invalid(); + MessageTemplate strict_parameter_error_message = MessageTemplate::kNone; + FunctionKind kind = FunctionKind::kArrowFunction; + bool has_simple_parameter_list = true; + + bool HasInitialState() const { + return rewritable_length == -1 && scope_snapshot.IsCleared() && + kind == FunctionKind::kArrowFunction && has_simple_parameter_list; + } + + // Tracks strict-mode parameter violations of sloppy-mode arrow heads in + // case the function ends up becoming strict mode. Only one global place to + // track this is necessary since arrow functions with none-simple parameters + // cannot become strict-mode later on. + void ClearStrictParameterError() { + strict_parameter_error_location = Scanner::Location::invalid(); + strict_parameter_error_message = MessageTemplate::kNone; + } + }; + + FormalParametersT* parameters_; + NextArrowFunctionInfo next_arrow_function_info_; bool accept_IN_ = true; @@ -1472,7 +1450,6 @@ ParserBase::FunctionState::FunctionState( outer_function_state_(*function_state_stack), scope_(scope), destructuring_assignments_to_rewrite_(scope->zone()), - reported_errors_(16, scope->zone()), dont_optimize_reason_(BailoutReason::kNoReason), next_function_is_likely_called_(false), previous_function_was_likely_called_(false), @@ -1510,9 +1487,8 @@ void ParserBase::ReportUnexpectedTokenAt( template typename ParserBase::IdentifierT -ParserBase::ParseAndClassifyIdentifier() { - Token::Value next = Next(); - +ParserBase::ParseAndClassifyIdentifier(Token::Value next) { + DCHECK_EQ(scanner()->current_token(), next); STATIC_ASSERT(Token::IDENTIFIER + 1 == Token::ASYNC); if (V8_LIKELY(IsInRange(next, Token::IDENTIFIER, Token::ASYNC))) { IdentifierT name = impl()->GetSymbol(); @@ -1531,13 +1507,13 @@ ParserBase::ParseAndClassifyIdentifier() { } if (next == Token::AWAIT) { - classifier()->RecordAsyncArrowFormalParametersError( + expression_scope()->RecordAsyncArrowParametersError( scanner()->location(), MessageTemplate::kAwaitBindingIdentifier); return impl()->GetSymbol(); } DCHECK(Token::IsStrictReservedWord(next)); - classifier()->RecordStrictModeFormalParameterError( + expression_scope()->RecordStrictModeParameterError( scanner()->location(), MessageTemplate::kUnexpectedStrictReserved); return impl()->GetSymbol(); } @@ -1637,7 +1613,7 @@ typename ParserBase::ExpressionT ParserBase::ParseBindingPattern() { ExpressionT result; if (Token::IsAnyIdentifier(token)) { - IdentifierT name = ParseAndClassifyIdentifier(); + IdentifierT name = ParseAndClassifyIdentifier(Next()); if (V8_UNLIKELY(is_strict(language_mode()) && impl()->IsEvalOrArguments(name))) { impl()->ReportMessageAt(scanner()->location(), @@ -1648,7 +1624,6 @@ typename ParserBase::ExpressionT ParserBase::ParseBindingPattern() { } CheckStackOverflow(); - classifier()->RecordNonSimpleParameter(); if (token == Token::LBRACK) { result = ParseArrayLiteral(); @@ -1659,7 +1634,6 @@ typename ParserBase::ExpressionT ParserBase::ParseBindingPattern() { return impl()->FailureExpression(); } - ValidateBindingPattern(); return result; } @@ -1689,36 +1663,41 @@ ParserBase::ParsePrimaryExpression() { Token::Value token = peek(); if (Token::IsAnyIdentifier(token)) { - // Using eval or arguments in this context is OK even in strict mode. - IdentifierT name = ParseAndClassifyIdentifier(); + Consume(token); + + IdentifierT name; InferName infer = InferName::kYes; - if (V8_UNLIKELY(impl()->IsAsync(name) && + + if (V8_UNLIKELY(token == Token::ASYNC && !scanner()->HasLineTerminatorBeforeNext())) { - if (peek() == Token::FUNCTION) { - return ParseAsyncFunctionLiteral(); - } - // async Identifier => AsyncConciseBody + // async function ... + if (peek() == Token::FUNCTION) return ParseAsyncFunctionLiteral(); + + // async Identifier => ... if (peek_any_identifier() && PeekAhead() == Token::ARROW) { - beg_pos = peek_position(); - name = ParseAndClassifyIdentifier(); - - if (!classifier()->is_valid_async_arrow_formal_parameters()) { - ReportClassifierError( - classifier()->async_arrow_formal_parameters_error()); - return impl()->FailureExpression(); - } - - next_arrow_function_kind_ = FunctionKind::kAsyncArrowFunction; + token = Next(); + beg_pos = position(); + next_arrow_function_info_.kind = FunctionKind::kAsyncArrowFunction; infer = InferName::kNo; } } - if (peek() == Token::ARROW) { - ClassifyFormalParameter(name, beg_pos, end_position()); - scope_snapshot_ = std::move(Scope::Snapshot(scope())); - rewritable_length_ = static_cast( + if (V8_UNLIKELY(peek() == Token::ARROW)) { + ArrowHeadParsingScope parsing_scope( + impl(), next_arrow_function_info_.kind == FunctionKind::kArrowFunction + ? ExpressionScope::kMaybeArrowParameterDeclaration + : ExpressionScope::kMaybeAsyncArrowParameterDeclaration); + next_arrow_function_info_.scope_snapshot = + std::move(Scope::Snapshot(scope())); + next_arrow_function_info_.rewritable_length = static_cast( function_state_->destructuring_assignments_to_rewrite().size()); + name = ParseAndClassifyIdentifier(token); + ClassifyParameter(name, beg_pos, end_position()); + parsing_scope.ValidateDeclaration(); + } else { + name = ParseAndClassifyIdentifier(token); } + return impl()->ExpressionFromIdentifier(name, beg_pos, infer); } @@ -1749,12 +1728,14 @@ ParserBase::ParsePrimaryExpression() { function_state_->destructuring_assignments_to_rewrite().size()); if (Check(Token::RPAREN)) { // ()=>x. The continuation that consumes the => is in - // ParseAssignmentExpression. + // ParseAssignmentExpressionCoverGrammar. if (peek() != Token::ARROW) ReportUnexpectedToken(Token::RPAREN); - scope_snapshot_ = std::move(scope_snapshot); - rewritable_length_ = rewritable_length; + next_arrow_function_info_.scope_snapshot = std::move(scope_snapshot); + next_arrow_function_info_.rewritable_length = rewritable_length; return factory()->NewEmptyParentheses(beg_pos); } + ArrowHeadParsingScope maybe_arrow( + impl(), ExpressionScope::kMaybeArrowParameterDeclaration); // Heuristically try to detect immediately called functions before // seeing the call parentheses. if (peek() == Token::FUNCTION || @@ -1767,8 +1748,13 @@ ParserBase::ParsePrimaryExpression() { Expect(Token::RPAREN); if (peek() == Token::ARROW) { - scope_snapshot_ = std::move(scope_snapshot); - rewritable_length_ = rewritable_length; + next_arrow_function_info_.scope_snapshot = std::move(scope_snapshot); + next_arrow_function_info_.has_simple_parameter_list = + maybe_arrow.has_simple_parameter_list(); + next_arrow_function_info_.rewritable_length = rewritable_length; + maybe_arrow.ValidateDeclaration(); + } else { + maybe_arrow.ValidateExpression(); } return expr; @@ -1781,7 +1767,7 @@ ParserBase::ParsePrimaryExpression() { bool is_strict_reserved_name = false; Scanner::Location class_name_location = Scanner::Location::invalid(); if (peek_any_identifier()) { - name = ParseAndClassifyIdentifier(); + name = ParseAndClassifyIdentifier(Next()); class_name_location = scanner()->location(); is_strict_reserved_name = Token::IsStrictReservedWord(scanner()->current_token()); @@ -1810,10 +1796,19 @@ ParserBase::ParsePrimaryExpression() { template typename ParserBase::ExpressionT ParserBase::ParseExpression() { - ExpressionClassifier classifier(this); + ExpressionParsingScope expression_scope(impl()); AcceptINScope scope(this, true); ExpressionT result = ParseExpressionCoverGrammar(); - ValidateExpression(); + expression_scope.ValidateExpression(); + return result; +} + +template +typename ParserBase::ExpressionT +ParserBase::ParseAssignmentExpression() { + ExpressionParsingScope expression_scope(impl()); + ExpressionT result = ParseAssignmentExpressionCoverGrammar(); + expression_scope.ValidateExpression(); return result; } @@ -1826,13 +1821,16 @@ ParserBase::ParseExpressionCoverGrammar() { ExpressionListT list(pointer_buffer()); ExpressionT expression; + AccumulationScope accumulation_scope(expression_scope()); while (true) { if (V8_UNLIKELY(peek() == Token::ELLIPSIS)) { - return ParseArrowFormalsWithRest(&list); + return ParseArrowParametersWithRest(&list, &accumulation_scope); } - expression = ParseAssignmentExpression(); - ClassifyArrowFormalParameter(expression); + int expr_pos = peek_position(); + expression = ParseAssignmentExpressionCoverGrammar(); + + ClassifyArrowParameter(&accumulation_scope, expr_pos, expression); list.Add(expression); if (!Check(Token::COMMA)) break; @@ -1860,15 +1858,17 @@ ParserBase::ParseExpressionCoverGrammar() { template typename ParserBase::ExpressionT -ParserBase::ParseArrowFormalsWithRest( - typename ParserBase::ExpressionListT* list) { +ParserBase::ParseArrowParametersWithRest( + typename ParserBase::ExpressionListT* list, + AccumulationScope* accumulation_scope) { Consume(Token::ELLIPSIS); Scanner::Location ellipsis = scanner()->location(); int pattern_pos = peek_position(); ExpressionT pattern = ParseBindingPattern(); + ClassifyArrowParameter(accumulation_scope, pattern_pos, pattern); - classifier()->RecordNonSimpleParameter(); + expression_scope()->RecordNonSimpleParameter(); if (V8_UNLIKELY(peek() == Token::ASSIGN)) { ReportMessage(MessageTemplate::kRestDefaultInitializer); @@ -1903,6 +1903,9 @@ typename ParserBase::ExpressionT ParserBase::ParseArrayLiteral() { ExpressionListT values(pointer_buffer()); int first_spread_index = -1; Consume(Token::LBRACK); + + AccumulationScope accumulation_scope(expression_scope()); + while (!Check(Token::RBRACK)) { ExpressionT elem; if (peek() == Token::COMMA) { @@ -1911,7 +1914,8 @@ typename ParserBase::ExpressionT ParserBase::ParseArrayLiteral() { int start_pos = position(); int expr_pos = peek_position(); AcceptINScope scope(this, true); - ExpressionT argument = ParseAssignmentExpression(); + ExpressionT argument = + ParsePossibleDestructuringSubPattern(&accumulation_scope); elem = factory()->NewSpread(argument, start_pos, expr_pos); if (first_spread_index < 0) { @@ -1919,7 +1923,7 @@ typename ParserBase::ExpressionT ParserBase::ParseArrayLiteral() { } if (argument->IsAssignment()) { - classifier()->RecordPatternError( + expression_scope()->RecordPatternError( Scanner::Location(start_pos, end_position()), MessageTemplate::kInvalidDestructuringTarget); } else { @@ -1927,14 +1931,14 @@ typename ParserBase::ExpressionT ParserBase::ParseArrayLiteral() { } if (peek() == Token::COMMA) { - classifier()->RecordPatternError( + expression_scope()->RecordPatternError( Scanner::Location(start_pos, end_position()), MessageTemplate::kElementAfterRest); } } else { int beg_pos = peek_position(); AcceptINScope scope(this, true); - elem = ParseAssignmentExpression(); + elem = ParsePossibleDestructuringSubPattern(&accumulation_scope); CheckDestructuringElement(elem, beg_pos, end_position()); } values.Add(elem); @@ -2045,11 +2049,8 @@ typename ParserBase::ExpressionT ParserBase::ParseProperty( prop_info->name = impl()->NullIdentifier(); prop_info->is_computed_name = true; Consume(Token::LBRACK); - ExpressionClassifier computed_name_classifier(this); AcceptINScope scope(this, true); ExpressionT expression = ParseAssignmentExpression(); - ValidateExpression(); - AccumulateFormalParameterContainmentErrors(); Expect(Token::RBRACK); if (prop_info->kind == ParsePropertyKind::kNotSet) { prop_info->ParsePropertyKindFromToken(peek()); @@ -2062,23 +2063,25 @@ typename ParserBase::ExpressionT ParserBase::ParseProperty( prop_info->name = impl()->NullIdentifier(); Consume(Token::ELLIPSIS); AcceptINScope scope(this, true); - ExpressionT expression = ParseAssignmentExpression(); + int start_pos = peek_position(); + ExpressionT expression = + ParsePossibleDestructuringSubPattern(prop_info->accumulation_scope); prop_info->kind = ParsePropertyKind::kSpread; - CheckDestructuringElement(expression, expression->position(), - end_position()); + CheckDestructuringElement(expression, start_pos, end_position()); + if (!IsValidReferenceExpression(expression)) { - classifier()->RecordBindingPatternError( - Scanner::Location(expression->position(), end_position()), + expression_scope()->RecordDeclarationError( + Scanner::Location(start_pos, end_position()), MessageTemplate::kInvalidRestBindingPattern); - classifier()->RecordPatternError( - Scanner::Location(expression->position(), end_position()), + expression_scope()->RecordPatternError( + Scanner::Location(start_pos, end_position()), MessageTemplate::kInvalidRestAssignmentPattern); } if (peek() != Token::RBRACE) { - classifier()->RecordPatternError(scanner()->location(), - MessageTemplate::kElementAfterRest); + expression_scope()->RecordPatternError( + scanner()->location(), MessageTemplate::kElementAfterRest); } return expression; } @@ -2283,11 +2286,9 @@ typename ParserBase::ExpressionT ParserBase::ParseMemberInitializer( if (Check(Token::ASSIGN)) { FunctionState initializer_state(&function_state_, &scope_, initializer_scope); - ExpressionClassifier expression_classifier(this); AcceptINScope scope(this, true); initializer = ParseAssignmentExpression(); - ValidateExpression(); // TODO(gsathya): In the future, this could be changed to be // called once for all the class field initializers, instead of @@ -2342,15 +2343,16 @@ ParserBase::ParseObjectPropertyDefinition(ParsePropertyInfo* prop_info, if (!prop_info->is_computed_name && impl()->IdentifierEquals(name, ast_value_factory()->proto_string())) { if (*has_seen_proto) { - classifier()->RecordExpressionError(scanner()->location(), - MessageTemplate::kDuplicateProto); + expression_scope()->RecordExpressionError( + scanner()->location(), MessageTemplate::kDuplicateProto); } *has_seen_proto = true; } Consume(Token::COLON); int beg_pos = peek_position(); AcceptINScope scope(this, true); - ExpressionT value = ParseAssignmentExpression(); + ExpressionT value = + ParsePossibleDestructuringSubPattern(prop_info->accumulation_scope); CheckDestructuringElement(value, beg_pos, end_position()); ObjectLiteralPropertyT result = factory()->NewObjectLiteralProperty( @@ -2379,36 +2381,34 @@ ParserBase::ParseObjectPropertyDefinition(ParsePropertyInfo* prop_info, DCHECK(!prop_info->is_computed_name); if (name_token == Token::LET) { - classifier()->RecordLetPatternError( + expression_scope()->RecordLexicalDeclarationError( scanner()->location(), MessageTemplate::kLetInLexicalBinding); } if (name_token == Token::AWAIT) { DCHECK(!is_async_function()); - classifier()->RecordAsyncArrowFormalParametersError( + expression_scope()->RecordAsyncArrowParametersError( next_loc, MessageTemplate::kAwaitBindingIdentifier); } ExpressionT lhs = impl()->ExpressionFromIdentifier(name, next_loc.beg_pos); if (!IsAssignableIdentifier(lhs)) { - classifier()->RecordPatternError(next_loc, - MessageTemplate::kStrictEvalArguments); + expression_scope()->RecordPatternError( + next_loc, MessageTemplate::kStrictEvalArguments); } ExpressionT value; if (peek() == Token::ASSIGN) { Consume(Token::ASSIGN); - ExpressionClassifier rhs_classifier(this); - AcceptINScope scope(this, true); - ExpressionT rhs = ParseAssignmentExpression(); - ValidateExpression(); - AccumulateFormalParameterContainmentErrors(); - value = factory()->NewAssignment(Token::ASSIGN, lhs, rhs, - kNoSourcePosition); - classifier()->RecordExpressionError( + { + AcceptINScope scope(this, true); + ExpressionT rhs = ParseAssignmentExpression(); + value = factory()->NewAssignment(Token::ASSIGN, lhs, rhs, + kNoSourcePosition); + impl()->SetFunctionNameFromIdentifierRef(rhs, lhs); + } + expression_scope()->RecordExpressionError( Scanner::Location(next_loc.beg_pos, end_position()), MessageTemplate::kInvalidCoverInitializedName); - - impl()->SetFunctionNameFromIdentifierRef(rhs, lhs); } else { value = lhs; } @@ -2424,7 +2424,7 @@ ParserBase::ParseObjectPropertyDefinition(ParsePropertyInfo* prop_info, // PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}' // '*' PropertyName '(' StrictFormalParameters ')' '{' FunctionBody '}' - classifier()->RecordPatternError( + expression_scope()->RecordPatternError( Scanner::Location(next_loc.beg_pos, end_position()), MessageTemplate::kInvalidDestructuringTarget); @@ -2447,7 +2447,7 @@ ParserBase::ParseObjectPropertyDefinition(ParsePropertyInfo* prop_info, DCHECK_EQ(function_flags, ParseFunctionFlag::kIsNormal); bool is_get = kind == ParsePropertyKind::kAccessorGetter; - classifier()->RecordPatternError( + expression_scope()->RecordPatternError( Scanner::Location(next_loc.beg_pos, end_position()), MessageTemplate::kInvalidDestructuringTarget); @@ -2501,11 +2501,12 @@ typename ParserBase::ExpressionT ParserBase::ParseObjectLiteral() { bool has_seen_proto = false; Consume(Token::LBRACE); + AccumulationScope accumulation_scope(expression_scope()); while (!Check(Token::RBRACE)) { FuncNameInferrerState fni_state(&fni_); - ParsePropertyInfo prop_info(this); + ParsePropertyInfo prop_info(this, &accumulation_scope); prop_info.position = PropertyPosition::kObjectLiteral; ObjectLiteralPropertyT property = ParseObjectPropertyDefinition(&prop_info, &has_seen_proto); @@ -2540,7 +2541,7 @@ typename ParserBase::ExpressionT ParserBase::ParseObjectLiteral() { // properties is less than number of arguments allowed for a runtime // call. if (has_rest_property && properties.length() > Code::kMaxArguments) { - this->classifier()->RecordPatternError(Scanner::Location(pos, position()), + expression_scope()->RecordPatternError(Scanner::Location(pos, position()), MessageTemplate::kTooManyArguments); } @@ -2551,12 +2552,13 @@ typename ParserBase::ExpressionT ParserBase::ParseObjectLiteral() { template void ParserBase::ParseArguments( typename ParserBase::ExpressionListT* args, bool* has_spread, - bool maybe_arrow) { + ParsingArrowHeadFlag maybe_arrow) { // Arguments :: // '(' (AssignmentExpression)*[','] ')' *has_spread = false; Consume(Token::LPAREN); + AccumulationScope accumulation_scope(expression_scope()); while (peek() != Token::RPAREN) { int start_pos = peek_position(); @@ -2564,18 +2566,18 @@ void ParserBase::ParseArguments( int expr_pos = peek_position(); AcceptINScope scope(this, true); - ExpressionT argument = ParseAssignmentExpression(); + ExpressionT argument = ParseAssignmentExpressionCoverGrammar(); - if (V8_UNLIKELY(maybe_arrow)) { - ClassifyArrowFormalParameter(argument); + if (V8_UNLIKELY(maybe_arrow == kMaybeArrowHead)) { + ClassifyArrowParameter(&accumulation_scope, expr_pos, argument); if (is_spread) { - classifier()->RecordNonSimpleParameter(); + expression_scope()->RecordNonSimpleParameter(); if (argument->IsAssignment()) { - classifier()->RecordAsyncArrowFormalParametersError( + expression_scope()->RecordAsyncArrowParametersError( scanner()->location(), MessageTemplate::kRestDefaultInitializer); } if (peek() == Token::COMMA) { - classifier()->RecordAsyncArrowFormalParametersError( + expression_scope()->RecordAsyncArrowParametersError( scanner()->peek_location(), MessageTemplate::kParamAfterRest); } } @@ -2602,7 +2604,7 @@ void ParserBase::ParseArguments( // Precedence = 2 template typename ParserBase::ExpressionT -ParserBase::ParseAssignmentExpression() { +ParserBase::ParseAssignmentExpressionCoverGrammar() { // AssignmentExpression :: // ConditionalExpression // ArrowFunction @@ -2615,50 +2617,49 @@ ParserBase::ParseAssignmentExpression() { } FuncNameInferrerState fni_state(&fni_); - ExpressionClassifier arrow_formals_classifier(this); - DCHECK_IMPLIES(!has_error(), -1 == rewritable_length_); - DCHECK_IMPLIES(!has_error(), scope_snapshot_.IsCleared()); - DCHECK_IMPLIES(!has_error(), - FunctionKind::kArrowFunction == next_arrow_function_kind_); + DCHECK_IMPLIES(!has_error(), next_arrow_function_info_.HasInitialState()); + ExpressionT expression = ParseConditionalExpression(); Token::Value op = peek(); - if (!Token::IsArrowOrAssignmentOp(op)) { - if (expression->IsProperty()) { - Accumulate(~ExpressionClassifier::PatternProduction); - } else { - Accumulate(ExpressionClassifier::AllProductions); - } - return expression; - } + if (!Token::IsArrowOrAssignmentOp(op)) return expression; // Arrow functions. if (V8_UNLIKELY(op == Token::ARROW)) { - ValidateArrowFormalParameters(expression); Scanner::Location loc(lhs_beg_pos, end_position()); - DeclarationScope* scope = NewFunctionScope(next_arrow_function_kind_); + DeclarationScope* scope = NewFunctionScope(next_arrow_function_info_.kind); + + if (!impl()->IsIdentifier(expression) && !expression->is_parenthesized()) { + impl()->ReportMessageAt( + Scanner::Location(expression->position(), position()), + MessageTemplate::kMalformedArrowFunParamList); + return impl()->FailureExpression(); + } // Reset to default. - next_arrow_function_kind_ = FunctionKind::kArrowFunction; + next_arrow_function_info_.kind = FunctionKind::kArrowFunction; - if (has_error()) return impl()->FailureExpression(); // Because the arrow's parameters were parsed in the outer scope, // we need to fix up the scope chain appropriately. - scope_snapshot_.Reparent(scope); + next_arrow_function_info_.scope_snapshot.Reparent(scope); FormalParametersT parameters(scope); - if (!classifier()->is_simple_parameter_list()) { + parameters.set_strict_parameter_error( + next_arrow_function_info_.strict_parameter_error_location, + next_arrow_function_info_.strict_parameter_error_message); + next_arrow_function_info_.ClearStrictParameterError(); + if (!next_arrow_function_info_.has_simple_parameter_list) { scope->SetHasNonSimpleParameters(); parameters.is_simple = false; + next_arrow_function_info_.has_simple_parameter_list = true; } scope->set_start_position(lhs_beg_pos); impl()->DeclareArrowFunctionFormalParameters(¶meters, expression, loc); expression = ParseArrowFunctionLiteral(parameters); - Accumulate(ExpressionClassifier::AsyncArrowFormalParametersProduction); fni_.Infer(); @@ -2667,20 +2668,15 @@ ParserBase::ParseAssignmentExpression() { // Destructuring assignmment. if (V8_UNLIKELY(expression->IsPattern() && op == Token::ASSIGN)) { - ValidatePattern(expression); + expression_scope()->ValidateAsPattern(expression, lhs_beg_pos, + end_position()); - // This is definitely not an expression so don't accumulate - // expression-related errors. - Accumulate(~ExpressionClassifier::ExpressionProduction); impl()->MarkPatternAsAssigned(expression); Consume(op); int pos = position(); - ExpressionClassifier rhs_classifier(this); ExpressionT right = ParseAssignmentExpression(); - ValidateExpression(); - AccumulateFormalParameterContainmentErrors(); ExpressionT result = factory()->NewAssignment(op, expression, right, pos); auto rewritable = factory()->NewRewritableExpression(result, scope()); @@ -2692,17 +2688,18 @@ ParserBase::ParseAssignmentExpression() { expression = RewriteInvalidReferenceExpression( expression, lhs_beg_pos, end_position(), MessageTemplate::kInvalidLhsInAssignment); + } else if (expression->IsProperty()) { + expression_scope()->RecordDeclarationError( + Scanner::Location(lhs_beg_pos, end_position()), + MessageTemplate::kInvalidPropertyBindingPattern); } + impl()->MarkExpressionAsAssigned(expression); Consume(op); int op_position = position(); ExpressionT right = ParseAssignmentExpression(); - // This is definitely not an assignment pattern, so don't accumulate - // assignment pattern-related errors. - ValidateExpression(); - AccumulateFormalParameterContainmentErrors(); if (op == Token::ASSIGN) { // We try to estimate the set of properties set by constructors. We define a @@ -2723,15 +2720,9 @@ ParserBase::ParseAssignmentExpression() { } impl()->SetFunctionNameFromIdentifierRef(right, expression); - - if (expression->IsProperty()) { - classifier()->RecordBindingPatternError( - Scanner::Location(expression->position(), end_position()), - MessageTemplate::kInvalidPropertyBindingPattern); - } } else { - classifier()->RecordPatternError( - Scanner::Location(expression->position(), end_position()), + expression_scope()->RecordPatternError( + Scanner::Location(lhs_beg_pos, end_position()), MessageTemplate::kInvalidDestructuringTarget); fni_.RemoveLastFunction(); } @@ -2745,7 +2736,7 @@ ParserBase::ParseYieldExpression() { // YieldExpression :: // 'yield' ([no line terminator] '*'? AssignmentExpression)? int pos = peek_position(); - classifier()->RecordFormalParameterInitializerError( + expression_scope()->RecordParameterInitializerError( scanner()->peek_location(), MessageTemplate::kYieldInParameter); Consume(Token::YIELD); @@ -2773,7 +2764,7 @@ ParserBase::ParseYieldExpression() { // Delegating yields require an RHS; fall through. V8_FALLTHROUGH; default: - expression = ParseAssignmentExpression(); + expression = ParseAssignmentExpressionCoverGrammar(); break; } } @@ -2961,7 +2952,7 @@ ParserBase::ParseUnaryOrPrefixExpression() { template typename ParserBase::ExpressionT ParserBase::ParseAwaitExpression() { - classifier()->RecordFormalParameterInitializerError( + expression_scope()->RecordParameterInitializerError( scanner()->peek_location(), MessageTemplate::kAwaitExpressionFormalParameter); int await_pos = peek_position(); @@ -3049,27 +3040,27 @@ ParserBase::ParseLeftHandSideContinuation(ExpressionT result) { DCHECK(impl()->IsAsync(impl()->AsIdentifier(result))); int pos = position(); + ArrowHeadParsingScope maybe_arrow( + impl(), ExpressionScope::kMaybeAsyncArrowParameterDeclaration); Scope::Snapshot scope_snapshot(scope()); int rewritable_length = static_cast( function_state_->destructuring_assignments_to_rewrite().size()); ExpressionListT args(pointer_buffer()); bool has_spread; - ParseArguments(&args, &has_spread, true); + ParseArguments(&args, &has_spread, kMaybeArrowHead); if (V8_LIKELY(peek() == Token::ARROW)) { + maybe_arrow.ValidateDeclaration(); fni_.RemoveAsyncKeywordFromEnd(); - if (!classifier()->is_valid_async_arrow_formal_parameters()) { - ReportClassifierError( - classifier()->async_arrow_formal_parameters_error()); - return impl()->FailureExpression(); - } - next_arrow_function_kind_ = FunctionKind::kAsyncArrowFunction; - scope_snapshot_ = std::move(scope_snapshot); - rewritable_length_ = rewritable_length; + next_arrow_function_info_.kind = FunctionKind::kAsyncArrowFunction; + next_arrow_function_info_.scope_snapshot = std::move(scope_snapshot); + next_arrow_function_info_.rewritable_length = rewritable_length; // async () => ... if (!args.length()) return factory()->NewEmptyParentheses(pos); // async ( Arguments ) => ... ExpressionT result = impl()->ExpressionListToExpression(args); + next_arrow_function_info_.has_simple_parameter_list = + maybe_arrow.has_simple_parameter_list(); result->mark_parenthesized(); return result; } @@ -3080,6 +3071,8 @@ ParserBase::ParseLeftHandSideContinuation(ExpressionT result) { result = factory()->NewCall(result, args, pos, Call::NOT_EVAL); } + maybe_arrow.ValidateExpression(); + fni_.RemoveLastFunction(); if (!Token::IsPropertyOrCall(peek())) return result; } @@ -3324,7 +3317,7 @@ ParserBase::ParseImportExpressions() { return impl()->FailureExpression(); } AcceptINScope scope(this, true); - ExpressionT arg = ParseAssignmentExpression(); + ExpressionT arg = ParseAssignmentExpressionCoverGrammar(); Expect(Token::RPAREN); return factory()->NewImportCallExpression(arg, pos); @@ -3438,29 +3431,25 @@ void ParserBase::ParseFormalParameter(FormalParametersT* parameters) { bool is_rest = parameters->has_rest; FuncNameInferrerState fni_state(&fni_); + int pos = peek_position(); ExpressionT pattern = ParseBindingPattern(); if (impl()->IsIdentifier(pattern)) { - ClassifyFormalParameter(impl()->AsIdentifier(pattern), pattern->position(), - end_position()); + ClassifyParameter(impl()->AsIdentifier(pattern), pos, end_position()); } else { parameters->is_simple = false; } ExpressionT initializer = impl()->NullExpression(); if (Check(Token::ASSIGN)) { + parameters->is_simple = false; + if (is_rest) { ReportMessage(MessageTemplate::kRestDefaultInitializer); return; } - { - ExpressionClassifier init_classifier(this); - AcceptINScope scope(this, true); - initializer = ParseAssignmentExpression(); - ValidateExpression(); - parameters->is_simple = false; - Accumulate(ExpressionClassifier::FormalParameterInitializerProduction); - } - classifier()->RecordNonSimpleParameter(); + + AcceptINScope scope(this, true); + initializer = ParseAssignmentExpression(); impl()->SetFunctionNameFromIdentifierRef(initializer, pattern); } @@ -3480,6 +3469,7 @@ void ParserBase::ParseFormalParameterList(FormalParametersT* parameters) { // FormalParameterList[Yield] : // FormalParameter[?Yield] // FormalParameterList[?Yield] , FormalParameter[?Yield] + ParameterParsingScope scope(impl(), parameters); DCHECK_EQ(0, parameters->arity); @@ -3495,7 +3485,6 @@ void ParserBase::ParseFormalParameterList(FormalParametersT* parameters) { if (parameters->has_rest) { parameters->is_simple = false; - classifier()->RecordNonSimpleParameter(); if (peek() == Token::COMMA) { impl()->ReportMessageAt(scanner()->peek_location(), MessageTemplate::kParamAfterRest); @@ -3566,7 +3555,10 @@ typename ParserBase::BlockT ParserBase::ParseVariableDeclarations( ExpressionT pattern = impl()->NullExpression(); int decl_pos = peek_position(); { - ExpressionClassifier pattern_classifier(this); + DeclarationParsingScope declaration( + impl(), IsLexicalVariableMode(parsing_result->descriptor.mode) + ? ExpressionScope::kLexicalDeclaration + : ExpressionScope::kVarDeclaration); pattern = ParseBindingPattern(); if (IsLexicalVariableMode(parsing_result->descriptor.mode)) { @@ -3576,8 +3568,6 @@ typename ParserBase::BlockT ParserBase::ParseVariableDeclarations( Scanner::Location(bindings_start, end_position()), MessageTemplate::kLetInLexicalBinding); } - } else { - ValidateLetPattern(); } } } @@ -3594,10 +3584,10 @@ typename ParserBase::BlockT ParserBase::ParseVariableDeclarations( if (Check(Token::ASSIGN)) { value_beg_position = peek_position(); - ExpressionClassifier classifier(this); - AcceptINScope scope(this, var_context != kForStatement); - value = ParseAssignmentExpression(); - ValidateExpression(); + { + AcceptINScope scope(this, var_context != kForStatement); + value = ParseAssignmentExpression(); + } variable_loc.end_pos = end_position(); if (!parsing_result->first_initializer_loc.IsValid()) { @@ -3790,10 +3780,10 @@ typename ParserBase::StatementT ParserBase::ParseClassDeclaration( variable_name = name; } - ExpressionClassifier no_classifier(this); + ExpressionParsingScope no_expression_scope(impl()); ExpressionT value = ParseClassLiteral(name, scanner()->location(), is_strict_reserved, class_token_pos); - ValidateExpression(); + no_expression_scope.ValidateExpression(); int end_pos = position(); return impl()->DeclareClass(variable_name, value, names, class_token_pos, end_pos); @@ -3843,6 +3833,8 @@ void ParserBase::ParseFunctionBody( typename ParserBase::StatementListT* body, IdentifierT function_name, int pos, const FormalParametersT& parameters, FunctionKind kind, FunctionLiteral::FunctionType function_type, FunctionBodyType body_type) { + FunctionBodyParsingScope body_scope(impl()); + DeclarationScope* function_scope = scope()->AsDeclarationScope(); DeclarationScope* inner_scope = function_scope; @@ -3857,9 +3849,7 @@ void ParserBase::ParseFunctionBody( if (IsResumableFunction(kind)) impl()->PrepareGeneratorVariables(); if (body_type == FunctionBodyType::kExpression) { - ExpressionClassifier classifier(this); ExpressionT expression = ParseAssignmentExpression(); - ValidateExpression(); if (IsAsyncFunction(kind)) { BlockT block = factory()->NewBlock(1, true); @@ -4048,12 +4038,13 @@ ParserBase::ParseArrowFunctionLiteral( FunctionState function_state(&function_state_, &scope_, formal_parameters.scope); - DCHECK_IMPLIES(!has_error(), -1 != rewritable_length_); + DCHECK_IMPLIES(!has_error(), + next_arrow_function_info_.rewritable_length != -1); // Move any queued destructuring assignments which appeared // in this function's parameter list into its own function_state. function_state.AdoptDestructuringAssignmentsFromParentState( - rewritable_length_); - rewritable_length_ = -1; + next_arrow_function_info_.rewritable_length); + next_arrow_function_info_.rewritable_length = -1; Consume(Token::ARROW); @@ -4075,13 +4066,13 @@ ParserBase::ParseArrowFunctionLiteral( formal_parameters.scope, &dummy_num_parameters, &produced_preparsed_scope_data, false, &hint); - // Validate parameter names. We can do this only after preparsing the - // function, since the function can declare itself strict. - ValidateFormalParameters(language_mode(), formal_parameters, false); - DCHECK_NULL(produced_preparsed_scope_data); if (did_preparse_successfully) { + // Validate parameter names. We can do this only after preparsing the + // function, since the function can declare itself strict. + ValidateFormalParameters(language_mode(), formal_parameters, false); + // Discard any queued destructuring assignments which appeared // in this function's parameter list, and which were adopted // into this function state, above. @@ -4190,7 +4181,6 @@ typename ParserBase::ExpressionT ParserBase::ParseClassLiteral( if (Check(Token::EXTENDS)) { FuncNameInferrerState fni_state(&fni_); class_info.extends = ParseLeftHandSideExpression(); - ValidateExpression(); } Expect(Token::LBRACE); @@ -4407,34 +4397,54 @@ ParserBase::RewriteInvalidReferenceExpression(ExpressionT expression, } template -void ParserBase::ClassifyFormalParameter(IdentifierT formal, int begin, - int end) { - if (impl()->IsEvalOrArguments(formal)) { - classifier()->RecordStrictModeFormalParameterError( +void ParserBase::ClassifyParameter(IdentifierT parameter, int begin, + int end) { + if (impl()->IsEvalOrArguments(parameter)) { + expression_scope()->RecordStrictModeParameterError( Scanner::Location(begin, end), MessageTemplate::kStrictEvalArguments); } } template -void ParserBase::ClassifyArrowFormalParameter(ExpressionT formal) { - if (formal->is_parenthesized() || - !(impl()->IsIdentifier(formal) || formal->IsPattern() || - formal->IsAssignment())) { - classifier()->RecordBindingPatternError( - Scanner::Location(formal->position(), end_position()), +void ParserBase::ClassifyArrowParameter( + AccumulationScope* accumulation_scope, int position, + ExpressionT parameter) { + accumulation_scope->Accumulate(); + if (parameter->is_parenthesized() || + !(impl()->IsIdentifier(parameter) || parameter->IsPattern() || + parameter->IsAssignment())) { + expression_scope()->RecordDeclarationError( + Scanner::Location(position, end_position()), MessageTemplate::kInvalidDestructuringTarget); - } else if (impl()->IsIdentifier(formal)) { - ClassifyFormalParameter(impl()->AsIdentifier(formal), formal->position(), - end_position()); + } else if (impl()->IsIdentifier(parameter)) { + ClassifyParameter(impl()->AsIdentifier(parameter), position, + end_position()); } else { - classifier()->RecordNonSimpleParameter(); + expression_scope()->RecordNonSimpleParameter(); } } template bool ParserBase::IsValidReferenceExpression(ExpressionT expression) { - return IsAssignableIdentifier(expression) || - (expression->IsProperty() && classifier()->is_valid_expression()); + return IsAssignableIdentifier(expression) || expression->IsProperty(); +} + +template +typename ParserBase::ExpressionT +ParserBase::ParsePossibleDestructuringSubPattern( + AccumulationScope* scope) { + int begin = peek_position(); + ExpressionT result = ParseAssignmentExpressionCoverGrammar(); + if (scope == nullptr) return result; + if (result->IsProperty()) { + expression_scope()->RecordDeclarationError( + Scanner::Location(begin, end_position()), + MessageTemplate::kInvalidPropertyBindingPattern); + scope->ValidateExpression(); + } else { + scope->Accumulate(); + } + return result; } template @@ -4445,15 +4455,11 @@ void ParserBase::CheckDestructuringElement(ExpressionT expression, // a larger assignment pattern, even though parenthesized patterns // themselves are not allowed, e.g., "[(x)] = []". Only accumulate // assignment pattern errors if the parsed expression is more complex. - if (expression->IsProperty()) { - classifier()->RecordBindingPatternError( - Scanner::Location(begin, end), - MessageTemplate::kInvalidPropertyBindingPattern); - } else if (impl()->IsIdentifier(expression)) { + if (impl()->IsIdentifier(expression)) { IdentifierT identifier = impl()->AsIdentifier(expression); - ClassifyFormalParameter(identifier, begin, end); + ClassifyParameter(identifier, begin, end); if (impl()->IsLet(identifier)) { - classifier()->RecordLetPatternError( + expression_scope()->RecordLexicalDeclarationError( Scanner::Location(begin, end), MessageTemplate::kLetInLexicalBinding); } @@ -4462,7 +4468,7 @@ void ParserBase::CheckDestructuringElement(ExpressionT expression, } if (expression->is_parenthesized() || (!expression->IsPattern() && !expression->IsAssignment())) { - classifier()->RecordPatternError( + expression_scope()->RecordPatternError( Scanner::Location(begin, end), MessageTemplate::kInvalidDestructuringTarget); } @@ -5278,7 +5284,8 @@ typename ParserBase::StatementT ParserBase::ParseTryStatement() { if (peek_any_identifier()) { catch_info.name = ParseNonRestrictedIdentifier(); } else { - ExpressionClassifier pattern_classifier(this); + DeclarationParsingScope declaration( + impl(), ExpressionScope::kVarDeclaration); catch_info.pattern = ParseBindingPattern(); } @@ -5397,21 +5404,26 @@ typename ParserBase::StatementT ParserBase::ParseForStatement( } else if (peek() != Token::SEMICOLON) { // The initializer does not contain declarations. int lhs_beg_pos = peek_position(); - ExpressionClassifier classifier(this); + int lhs_end_pos; + bool is_for_each; ExpressionT expression; { + ExpressionParsingScope parsing_scope(impl()); AcceptINScope scope(this, false); expression = ParseExpressionCoverGrammar(); - } - int lhs_end_pos = end_position(); - - bool is_for_each = CheckInOrOf(&for_info.mode); - bool is_destructuring = is_for_each && expression->IsPattern(); - - if (is_destructuring) { - ValidatePattern(expression); - } else { - ValidateExpression(); + // Initializer is reference followed by in/of. + lhs_end_pos = end_position(); + is_for_each = CheckInOrOf(&for_info.mode); + if (is_for_each) { + if (expression->IsPattern()) { + parsing_scope.ValidatePattern(expression, lhs_beg_pos, lhs_end_pos); + } else { + expression = parsing_scope.ValidateAndRewriteReference( + expression, lhs_beg_pos, lhs_end_pos); + } + } else { + parsing_scope.ValidateExpression(); + } } if (is_for_each) { @@ -5472,10 +5484,8 @@ ParserBase::ParseForEachStatementWithDeclarations( ExpressionT enumerable = impl()->NullExpression(); if (for_info->mode == ForEachStatement::ITERATE) { - ExpressionClassifier classifier(this); AcceptINScope scope(this, true); enumerable = ParseAssignmentExpression(); - ValidateExpression(); } else { enumerable = ParseExpression(); } @@ -5540,29 +5550,14 @@ ParserBase::ParseForEachStatementWithoutDeclarations( int stmt_pos, ExpressionT expression, int lhs_beg_pos, int lhs_end_pos, ForInfo* for_info, ZonePtrList* labels, ZonePtrList* own_labels) { - // Initializer is reference followed by in/of. - if (expression->IsPattern()) { - if (expression->is_parenthesized()) { - impl()->ReportMessageAt( - Scanner::Location(expression->position(), end_position()), - MessageTemplate::kInvalidDestructuringTarget); - } - } else if (V8_UNLIKELY(!IsValidReferenceExpression(expression))) { - expression = RewriteInvalidReferenceExpression( - expression, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor, - kSyntaxError); - } - auto loop = factory()->NewForEachStatement(for_info->mode, labels, own_labels, stmt_pos); TargetT target(this, loop); ExpressionT enumerable = impl()->NullExpression(); if (for_info->mode == ForEachStatement::ITERATE) { - ExpressionClassifier classifier(this); AcceptINScope scope(this, true); enumerable = ParseAssignmentExpression(); - ValidateExpression(); } else { enumerable = ParseExpression(); } @@ -5744,19 +5739,15 @@ typename ParserBase::StatementT ParserBase::ParseForAwaitStatement( // Statement int lhs_beg_pos = peek_position(); BlockState inner_state(&scope_, inner_block_scope); - ExpressionClassifier classifier(this); + ExpressionParsingScope parsing_scope(impl()); ExpressionT lhs = each_variable = ParseLeftHandSideExpression(); int lhs_end_pos = end_position(); if (lhs->IsPattern()) { - ValidatePattern(lhs); + parsing_scope.ValidatePattern(lhs, lhs_beg_pos, lhs_end_pos); } else { - ValidateExpression(); - if (V8_UNLIKELY(!IsValidReferenceExpression(lhs))) { - each_variable = RewriteInvalidReferenceExpression( - lhs, lhs_beg_pos, lhs_end_pos, MessageTemplate::kInvalidLhsInFor, - kSyntaxError); - } + each_variable = parsing_scope.ValidateAndRewriteReference( + lhs, lhs_beg_pos, lhs_end_pos); } } @@ -5767,10 +5758,8 @@ typename ParserBase::StatementT ParserBase::ParseForAwaitStatement( ExpressionT iterable = impl()->NullExpression(); { - ExpressionClassifier classifier(this); AcceptINScope scope(this, kAllowIn); iterable = ParseAssignmentExpression(); - ValidateExpression(); } Expect(Token::RPAREN); diff --git a/src/parsing/parser.cc b/src/parsing/parser.cc index 7b8f0734eb..7866fab3a0 100644 --- a/src/parsing/parser.cc +++ b/src/parsing/parser.cc @@ -758,12 +758,13 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info, SetLanguageMode(scope, info->language_mode()); scope->set_start_position(info->start_position()); - ExpressionClassifier formals_classifier(this); ParserFormalParameters formals(scope); // The outer FunctionState should not contain destructuring assignments. DCHECK_EQ(0, function_state.destructuring_assignments_to_rewrite().size()); { + DeclarationParsingScope formals_scope( + this, ExpressionScope::kParameterDeclaration); // Parsing patterns as variable reference expression creates // NewUnresolved references in current scope. Enter arrow function // scope for formal parameter parsing. @@ -774,6 +775,7 @@ FunctionLiteral* Parser::DoParseFunction(Isolate* isolate, ParseInfo* info, Expect(Token::RPAREN); } else { // BindingIdentifier + ParameterParsingScope scope(impl(), &formals); ParseFormalParameter(&formals); DeclareFormalParameters(&formals); } @@ -1131,10 +1133,8 @@ Statement* Parser::ParseExportDefault() { default: { int pos = position(); - ExpressionClassifier classifier(this); AcceptINScope scope(this, true); Expression* value = ParseAssignmentExpression(); - ValidateExpression(); SetFunctionName(value, ast_value_factory()->default_string()); const AstRawString* local_name = @@ -2319,6 +2319,17 @@ Statement* Parser::DesugarLexicalBindingsInForStatement( return outer_block; } +void ParserFormalParameters::ValidateDuplicate(Parser* parser) const { + if (has_duplicate()) { + parser->ReportMessageAt(duplicate_loc, MessageTemplate::kParamDupe); + } +} +void ParserFormalParameters::ValidateStrictMode(Parser* parser) const { + if (strict_error_loc.IsValid()) { + parser->ReportMessageAt(strict_error_loc, strict_error_message); + } +} + void Parser::AddArrowFunctionFormalParameters( ParserFormalParameters* parameters, Expression* expr, int end_pos) { // ArrowFunctionFormals :: @@ -2941,8 +2952,6 @@ void Parser::ParseFunction( bool is_wrapped = function_type == FunctionLiteral::kWrapped; - ExpressionClassifier formals_classifier(this); - int expected_parameters_end_pos = parameters_end_pos_; if (expected_parameters_end_pos != kNoSourcePosition) { // This is the first function encountered in a CreateDynamicFunction eval. @@ -2971,6 +2980,8 @@ void Parser::ParseFunction( } else { // For a regular function, the function arguments are parsed from source. DCHECK_NULL(arguments_for_wrapped_function); + DeclarationParsingScope formals_scope( + this, ExpressionScope::kParameterDeclaration); ParseFormalParameterList(&formals); if (expected_parameters_end_pos != kNoSourcePosition) { // Check for '(' or ')' shenanigans in the parameter string for dynamic diff --git a/src/parsing/parser.h b/src/parsing/parser.h index 172707d028..81dcc65de9 100644 --- a/src/parsing/parser.h +++ b/src/parsing/parser.h @@ -113,13 +113,23 @@ struct ParserFormalParameters : FormalParametersBase { Parameter* const* next() const { return &next_parameter; } }; - Scanner::Location duplicate_location() const { return duplicate_loc; } + void set_strict_parameter_error(const Scanner::Location& loc, + MessageTemplate message) { + strict_error_loc = loc; + strict_error_message = message; + } + bool has_duplicate() const { return duplicate_loc.IsValid(); } + void ValidateDuplicate(Parser* parser) const; + void ValidateStrictMode(Parser* parser) const; explicit ParserFormalParameters(DeclarationScope* scope) : FormalParametersBase(scope) {} + base::ThreadedList params; Scanner::Location duplicate_loc = Scanner::Location::invalid(); + Scanner::Location strict_error_loc = Scanner::Location::invalid(); + MessageTemplate strict_error_message = MessageTemplate::kNone; }; template <> @@ -155,8 +165,6 @@ struct ParserTypes { typedef v8::internal::SourceRangeScope SourceRangeScope; typedef ParserTarget Target; typedef ParserTargetScope TargetScope; - - static constexpr bool ExpressionClassifierReportErrors = true; }; class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase) { @@ -192,8 +200,8 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase) { private: friend class ParserBase; - friend class v8::internal::ExpressionClassifierErrorTracker< - ParserTypes>; + friend struct ParserFormalParameters; + friend class i::ExpressionScope>; friend bool v8::internal::parsing::ParseProgram(ParseInfo*, Isolate*); friend bool v8::internal::parsing::ParseFunction( ParseInfo*, Handle shared_info, Isolate*); @@ -915,7 +923,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase) { } V8_INLINE void DeclareFormalParameters(ParserFormalParameters* parameters) { - ValidateFormalParameterInitializer(); bool is_simple = parameters->is_simple; DeclarationScope* scope = parameters->scope; if (!is_simple) scope->SetHasNonSimpleParameters(); @@ -955,11 +962,6 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase) { void SetFunctionNameFromIdentifierRef(Expression* value, Expression* identifier); - V8_INLINE ZoneList* - GetReportedErrorList() const { - return function_state_->GetReportedErrorList(); - } - V8_INLINE void CountUsage(v8::Isolate::UseCounterFeature feature) { ++use_counts_[feature]; } diff --git a/src/parsing/preparser.cc b/src/parsing/preparser.cc index ad36596e8e..60dc70d90c 100644 --- a/src/parsing/preparser.cc +++ b/src/parsing/preparser.cc @@ -96,6 +96,14 @@ PreParser::PreParseResult PreParser::PreParseProgram() { return kPreParseSuccess; } +void PreParserFormalParameters::ValidateDuplicate(PreParser* preparser) const { + if (has_duplicate_) preparser->ReportUnidentifiableError(); +} + +void PreParserFormalParameters::ValidateStrictMode(PreParser* preparser) const { + if (strict_parameter_error_) preparser->ReportUnidentifiableError(); +} + PreParser::PreParseResult PreParser::PreParseFunction( const AstRawString* function_name, FunctionKind kind, FunctionLiteral::FunctionType function_type, @@ -131,12 +139,12 @@ PreParser::PreParseResult PreParser::PreParseFunction( FunctionState function_state(&function_state_, &scope_, function_scope); PreParserFormalParameters formals(function_scope); - std::unique_ptr formals_classifier; // Parse non-arrow function parameters. For arrow functions, the parameters // have already been parsed. if (!IsArrowFunction(kind)) { - formals_classifier.reset(new ExpressionClassifier(this)); + DeclarationParsingScope formals_scope( + this, ExpressionScope::kParameterDeclaration); // We return kPreParseSuccess in failure cases too - errors are retrieved // separately by Parser::SkipLazyFunctionBody. ParseFormalParameterList(&formals); @@ -291,13 +299,16 @@ PreParser::Expression PreParser::ParseFunctionLiteral( } FunctionState function_state(&function_state_, &scope_, function_scope); - ExpressionClassifier formals_classifier(this); Expect(Token::LPAREN); int start_position = position(); function_scope->set_start_position(start_position); PreParserFormalParameters formals(function_scope); - ParseFormalParameterList(&formals); + { + DeclarationParsingScope formals_scope( + this, ExpressionScope::kParameterDeclaration); + ParseFormalParameterList(&formals); + } Expect(Token::RPAREN); int formals_end_position = scanner()->location().end_pos; @@ -406,7 +417,7 @@ bool PreParser::IdentifierEquals(const PreParserIdentifier& identifier, PreParserExpression PreParser::ExpressionFromIdentifier( const PreParserIdentifier& name, int start_position, InferName infer) { VariableProxy* proxy = nullptr; - DCHECK_EQ(name.string_ == nullptr, has_error()); + DCHECK_IMPLIES(name.string_ == nullptr, has_error()); if (name.string_ == nullptr) return PreParserExpression::Default(); proxy = scope()->NewUnresolved(factory()->ast_node_factory(), name.string_, start_position, NORMAL_VARIABLE); diff --git a/src/parsing/preparser.h b/src/parsing/preparser.h index 72c006e1d1..ff247f2dda 100644 --- a/src/parsing/preparser.h +++ b/src/parsing/preparser.h @@ -832,21 +832,28 @@ class PreParserFactory { Zone* zone_; }; +class PreParser; + class PreParserFormalParameters : public FormalParametersBase { public: explicit PreParserFormalParameters(DeclarationScope* scope) : FormalParametersBase(scope) {} - Scanner::Location duplicate_location() const { UNREACHABLE(); } - bool has_duplicate() const { return has_duplicate_; } void set_has_duplicate() { has_duplicate_ = true; } + bool has_duplicate() { return has_duplicate_; } + void ValidateDuplicate(PreParser* preparser) const; + + void set_strict_parameter_error(const Scanner::Location& loc, + MessageTemplate message) { + strict_parameter_error_ = loc.IsValid(); + } + void ValidateStrictMode(PreParser* preparser) const; private: bool has_duplicate_ = false; + bool strict_parameter_error_ = false; }; -class PreParser; - class PreParserTarget { public: PreParserTarget(ParserBase* preparser, @@ -935,8 +942,6 @@ struct ParserTypes { typedef PreParserSourceRangeScope SourceRangeScope; typedef PreParserTarget Target; typedef PreParserTargetScope TargetScope; - - static constexpr bool ExpressionClassifierReportErrors = false; }; @@ -954,7 +959,6 @@ struct ParserTypes { // it is used) are generally omitted. class PreParser : public ParserBase { friend class ParserBase; - friend class v8::internal::ExpressionClassifier>; public: typedef PreParserIdentifier Identifier; @@ -1016,6 +1020,8 @@ class PreParser : public ParserBase { } private: + friend class i::ExpressionScope>; + friend class PreParserFormalParameters; // These types form an algebra over syntactic categories that is just // rich enough to let us recognize and propagate the constructs that // are either being counted in the preparser data, or is important @@ -1677,14 +1683,12 @@ class PreParser : public ParserBase { V8_INLINE void DeclareFormalParameters( const PreParserFormalParameters* parameters) { - ValidateFormalParameterInitializer(); if (!parameters->is_simple) parameters->scope->SetHasNonSimpleParameters(); } V8_INLINE void DeclareArrowFunctionFormalParameters( PreParserFormalParameters* parameters, const PreParserExpression& params, const Scanner::Location& params_loc) { - ValidateFormalParameterInitializer(); if (params.variables_ != nullptr) { Scope* scope = parameters->scope; for (auto variable : *params.variables_) { @@ -1709,11 +1713,6 @@ class PreParser : public ParserBase { const PreParserExpression& value, const PreParserExpression& identifier) { } - V8_INLINE ZoneList* - GetReportedErrorList() const { - return function_state_->GetReportedErrorList(); - } - V8_INLINE void CountUsage(v8::Isolate::UseCounterFeature feature) { if (use_counts_ != nullptr) ++use_counts_[feature]; } diff --git a/test/message/regress/fail/regress-903874.out b/test/message/regress/fail/regress-903874.out deleted file mode 100644 index a5966a2854..0000000000 --- a/test/message/regress/fail/regress-903874.out +++ /dev/null @@ -1,5 +0,0 @@ -*%(basename)s:6: RangeError: Maximum call stack size exceeded -eval(code); - ^ -RangeError: Maximum call stack size exceeded - at *%(basename)s:6:6 diff --git a/test/mjsunit/es8/async-arrow-default-function-await.js b/test/mjsunit/es8/async-arrow-default-function-await.js new file mode 100644 index 0000000000..6c4d00e61a --- /dev/null +++ b/test/mjsunit/es8/async-arrow-default-function-await.js @@ -0,0 +1,5 @@ +// Copyright 2018 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. + +async(o = (function(await) {})) => 0 diff --git a/test/message/regress/fail/regress-903874.js b/test/mjsunit/regress/regress-903874.js similarity index 86% rename from test/message/regress/fail/regress-903874.js rename to test/mjsunit/regress/regress-903874.js index f27627d2b8..c1301eb2aa 100644 --- a/test/message/regress/fail/regress-903874.js +++ b/test/mjsunit/regress/regress-903874.js @@ -3,4 +3,4 @@ // found in the LICENSE file. var code = "function f(" + ("{o(".repeat(10000)); -eval(code); +assertThrows(code, SyntaxError);