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);