diff options
Diffstat (limited to 'deps/v8/src/parsing/expression-classifier.h')
-rw-r--r-- | deps/v8/src/parsing/expression-classifier.h | 568 |
1 files changed, 0 insertions, 568 deletions
diff --git a/deps/v8/src/parsing/expression-classifier.h b/deps/v8/src/parsing/expression-classifier.h deleted file mode 100644 index 2eed75b939..0000000000 --- a/deps/v8/src/parsing/expression-classifier.h +++ /dev/null @@ -1,568 +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 <type_traits> - -#include "src/messages.h" -#include "src/parsing/scanner.h" - -namespace v8 { -namespace internal { - -class DuplicateFinder; - -#define ERROR_CODES(T) \ - T(ExpressionProduction, 0) \ - T(FormalParameterInitializerProduction, 1) \ - T(BindingPatternProduction, 2) \ - T(AssignmentPatternProduction, 3) \ - T(DistinctFormalParametersProduction, 4) \ - T(StrictModeFormalParametersProduction, 5) \ - T(ArrowFormalParametersProduction, 6) \ - T(LetPatternProduction, 7) \ - T(AsyncArrowFormalParametersProduction, 8) - -// 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 <typename Types> -class ExpressionClassifier; - -template <typename Types, typename ErrorTracker> -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(MessageTemplate::kNone), - kind(kUnusedError), - arg(nullptr) {} - V8_INLINE explicit Error(Scanner::Location loc, - MessageTemplate::Template msg, ErrorKind k, - const char* a = nullptr) - : location(loc), message(msg), kind(k), arg(a) {} - - Scanner::Location location; - MessageTemplate::Template message : 28; - unsigned kind : 4; - const char* arg; - }; - - // 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, - DuplicateFinder* duplicate_finder = nullptr) - : base_(base), - duplicate_finder_(duplicate_finder), - 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 DuplicateFinder* duplicate_finder() const { - return duplicate_finder_; - } - - 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_binding_pattern() const { - return is_valid(BindingPatternProduction); - } - - V8_INLINE bool is_valid_assignment_pattern() const { - return is_valid(AssignmentPatternProduction); - } - - V8_INLINE bool is_valid_arrow_formal_parameters() const { - return is_valid(ArrowFormalParametersProduction); - } - - V8_INLINE bool is_valid_formal_parameter_list_without_duplicates() const { - return is_valid(DistinctFormalParametersProduction); - } - - // Note: callers should also check - // is_valid_formal_parameter_list_without_duplicates(). - 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<Types>* const inner, - unsigned productions) { -#ifdef DEBUG - static_cast<ErrorTracker*>(this)->CheckErrorPositions(inner); -#endif - // Propagate errors from inner, but don't overwrite already recorded - // errors. - unsigned non_arrow_inner_invalid_productions = - inner->invalid_productions_ & ~ArrowFormalParametersProduction; - if (non_arrow_inner_invalid_productions) { - unsigned errors = non_arrow_inner_invalid_productions & productions & - ~this->invalid_productions_; - // The result will continue to be a valid arrow formal parameters if the - // inner expression is a valid binding pattern. - bool copy_BP_to_AFP = false; - if (productions & ArrowFormalParametersProduction && - this->is_valid_arrow_formal_parameters()) { - // Also whether we've seen any non-simple parameters - // if expecting an arrow function parameter. - this->is_non_simple_parameter_list_ |= - inner->is_non_simple_parameter_list_; - if (!inner->is_valid_binding_pattern()) { - copy_BP_to_AFP = true; - this->invalid_productions_ |= ArrowFormalParametersProduction; - } - } - if (errors != 0 || copy_BP_to_AFP) { - this->invalid_productions_ |= errors; - static_cast<ErrorTracker*>(this)->AccumulateErrorImpl( - inner, productions, errors, copy_BP_to_AFP); - } - } - static_cast<ErrorTracker*>(this)->RewindErrors(inner); - } - - protected: - typename Types::Base* base_; - DuplicateFinder* duplicate_finder_; - unsigned invalid_productions_ : kUnusedError; - STATIC_ASSERT(kUnusedError <= 15); - unsigned is_non_simple_parameter_list_ : 1; -}; - -template <typename Types> -class ExpressionClassifierErrorTracker - : public ExpressionClassifierBase<Types, - ExpressionClassifierErrorTracker<Types>> { - public: - using BaseClassType = - ExpressionClassifierBase<Types, ExpressionClassifierErrorTracker<Types>>; - using typename BaseClassType::Error; - using typename BaseClassType::ErrorKind; - using TP = typename BaseClassType::TargetProduction; - - ExpressionClassifierErrorTracker(typename Types::Base* base, - DuplicateFinder* duplicate_finder) - : BaseClassType(base, duplicate_finder), - reported_errors_(base->impl()->GetReportedErrorList()) { - reported_errors_begin_ = reported_errors_end_ = reported_errors_->length(); - } - - ~ExpressionClassifierErrorTracker() override { Discard(); } - - V8_INLINE void Discard() { - 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->invalid_productions_ & (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(const Error& e) { - 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<Types>* 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<Types>* 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<Types>* const inner, - unsigned productions, unsigned errors, - bool copy_BP_to_AFP) { - // Traverse the list of errors reported by the inner classifier - // to copy what's necessary. - int binding_pattern_index = inner->reported_errors_end_; - for (int i = inner->reported_errors_begin_; i < inner->reported_errors_end_; - i++) { - int k = this->reported_errors_->at(i).kind; - if (errors & (1 << k)) this->Copy(i); - // Check if it's a BP error that has to be copied to an AFP error. - if (k == ErrorKind::kBindingPatternProduction && copy_BP_to_AFP) { - if (this->reported_errors_end_ <= i) { - // If the BP error itself has not already been copied, - // copy it now and change it to an AFP error. - this->Copy(i); - this->reported_errors_->at(this->reported_errors_end_ - 1).kind = - ErrorKind::kArrowFormalParametersProduction; - } else { - // Otherwise, if the BP error was already copied, keep its - // position and wait until the end of the traversal. - DCHECK_EQ(this->reported_errors_end_, i + 1); - binding_pattern_index = i; - } - } - } - // Do we still have to copy the BP error to an AFP error? - if (binding_pattern_index < inner->reported_errors_end_) { - // If there's still unused space in the list of the inner - // classifier, copy it there, otherwise add it to the end - // of the list. - if (this->reported_errors_end_ < inner->reported_errors_end_) - this->Copy(binding_pattern_index); - else - Add(this->reported_errors_->at(binding_pattern_index)); - this->reported_errors_->at(this->reported_errors_end_ - 1).kind = - ErrorKind::kArrowFormalParametersProduction; - } - } - - private: - ZoneList<Error>* 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 <typename Types> -class ExpressionClassifierEmptyErrorTracker - : public ExpressionClassifierBase< - Types, ExpressionClassifierEmptyErrorTracker<Types>> { - public: - using BaseClassType = - ExpressionClassifierBase<Types, - ExpressionClassifierEmptyErrorTracker<Types>>; - using typename BaseClassType::Error; - using typename BaseClassType::ErrorKind; - using TP = typename BaseClassType::TargetProduction; - - ExpressionClassifierEmptyErrorTracker(typename Types::Base* base, - DuplicateFinder* duplicate_finder) - : BaseClassType(base, duplicate_finder) {} - - V8_INLINE void Discard() {} - - protected: - V8_INLINE const Error& reported_error(ErrorKind kind) const { - static Error none; - return none; - } - - V8_INLINE void Add(const Error& e) {} - - private: -#ifdef DEBUG - V8_INLINE void CheckErrorPositions(ExpressionClassifier<Types>* const inner) { - } -#endif - V8_INLINE void RewindErrors(ExpressionClassifier<Types>* const inner) {} - V8_INLINE void AccumulateErrorImpl(ExpressionClassifier<Types>* const inner, - unsigned productions, unsigned errors, - bool copy_BP_to_AFP) {} - - friend BaseClassType; -}; - -template <typename Types> -class ExpressionClassifier - : public std::conditional< - Types::ExpressionClassifierReportErrors, - ExpressionClassifierErrorTracker<Types>, - ExpressionClassifierEmptyErrorTracker<Types>>::type { - static constexpr bool ReportErrors = Types::ExpressionClassifierReportErrors; - - public: - using BaseClassType = typename std::conditional< - Types::ExpressionClassifierReportErrors, - typename ExpressionClassifierErrorTracker<Types>::BaseClassType, - typename ExpressionClassifierEmptyErrorTracker<Types>::BaseClassType>:: - type; - using typename BaseClassType::Error; - using typename BaseClassType::ErrorKind; - using TP = typename BaseClassType::TargetProduction; - - explicit ExpressionClassifier(typename Types::Base* base, - DuplicateFinder* duplicate_finder = nullptr) - : std::conditional<Types::ExpressionClassifierReportErrors, - ExpressionClassifierErrorTracker<Types>, - ExpressionClassifierEmptyErrorTracker<Types>>:: - type(base, duplicate_finder), - 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& binding_pattern_error() const { - return this->reported_error(ErrorKind::kBindingPatternProduction); - } - - V8_INLINE const Error& assignment_pattern_error() const { - return this->reported_error(ErrorKind::kAssignmentPatternProduction); - } - - V8_INLINE const Error& arrow_formal_parameters_error() const { - return this->reported_error(ErrorKind::kArrowFormalParametersProduction); - } - - V8_INLINE const Error& duplicate_formal_parameter_error() const { - return this->reported_error(ErrorKind::kDistinctFormalParametersProduction); - } - - 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::Template message, - const char* arg = nullptr) { - if (!this->is_valid_expression()) return; - this->invalid_productions_ |= TP::ExpressionProduction; - this->Add(Error(loc, message, ErrorKind::kExpressionProduction, arg)); - } - - void RecordFormalParameterInitializerError(const Scanner::Location& loc, - MessageTemplate::Template message, - const char* arg = nullptr) { - if (!this->is_valid_formal_parameter_initializer()) return; - this->invalid_productions_ |= TP::FormalParameterInitializerProduction; - this->Add(Error(loc, message, - ErrorKind::kFormalParameterInitializerProduction, arg)); - } - - void RecordBindingPatternError(const Scanner::Location& loc, - MessageTemplate::Template message, - const char* arg = nullptr) { - if (!this->is_valid_binding_pattern()) return; - this->invalid_productions_ |= TP::BindingPatternProduction; - this->Add(Error(loc, message, ErrorKind::kBindingPatternProduction, arg)); - } - - void RecordAssignmentPatternError(const Scanner::Location& loc, - MessageTemplate::Template message, - const char* arg = nullptr) { - if (!this->is_valid_assignment_pattern()) return; - this->invalid_productions_ |= TP::AssignmentPatternProduction; - this->Add( - Error(loc, message, ErrorKind::kAssignmentPatternProduction, arg)); - } - - void RecordPatternError(const Scanner::Location& loc, - MessageTemplate::Template message, - const char* arg = nullptr) { - RecordBindingPatternError(loc, message, arg); - RecordAssignmentPatternError(loc, message, arg); - } - - void RecordArrowFormalParametersError(const Scanner::Location& loc, - MessageTemplate::Template message, - const char* arg = nullptr) { - if (!this->is_valid_arrow_formal_parameters()) return; - this->invalid_productions_ |= TP::ArrowFormalParametersProduction; - this->Add( - Error(loc, message, ErrorKind::kArrowFormalParametersProduction, arg)); - } - - void RecordAsyncArrowFormalParametersError(const Scanner::Location& loc, - MessageTemplate::Template message, - const char* arg = nullptr) { - if (!this->is_valid_async_arrow_formal_parameters()) return; - this->invalid_productions_ |= TP::AsyncArrowFormalParametersProduction; - this->Add(Error(loc, message, - ErrorKind::kAsyncArrowFormalParametersProduction, arg)); - } - - void RecordDuplicateFormalParameterError(const Scanner::Location& loc) { - if (!this->is_valid_formal_parameter_list_without_duplicates()) return; - this->invalid_productions_ |= TP::DistinctFormalParametersProduction; - this->Add(Error(loc, MessageTemplate::kParamDupe, - ErrorKind::kDistinctFormalParametersProduction)); - } - - // Record a binding that would be invalid in strict mode. Confusingly this - // is not the same as StrictFormalParameterList, which simply forbids - // duplicate bindings. - void RecordStrictModeFormalParameterError(const Scanner::Location& loc, - MessageTemplate::Template message, - const char* arg = nullptr) { - if (!this->is_valid_strict_mode_formal_parameters()) return; - this->invalid_productions_ |= TP::StrictModeFormalParametersProduction; - this->Add(Error(loc, message, - ErrorKind::kStrictModeFormalParametersProduction, arg)); - } - - void RecordLetPatternError(const Scanner::Location& loc, - MessageTemplate::Template message, - const char* arg = nullptr) { - if (!this->is_valid_let_pattern()) return; - this->invalid_productions_ |= TP::LetPatternProduction; - this->Add(Error(loc, message, ErrorKind::kLetPatternProduction, arg)); - } - - 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_ |