diff options
Diffstat (limited to 'deps/v8/src/parsing/expression-classifier.h')
-rw-r--r-- | deps/v8/src/parsing/expression-classifier.h | 528 |
1 files changed, 337 insertions, 191 deletions
diff --git a/deps/v8/src/parsing/expression-classifier.h b/deps/v8/src/parsing/expression-classifier.h index 7833dbc8d3..2eed75b939 100644 --- a/deps/v8/src/parsing/expression-classifier.h +++ b/deps/v8/src/parsing/expression-classifier.h @@ -5,9 +5,10 @@ #ifndef V8_PARSING_EXPRESSION_CLASSIFIER_H_ #define V8_PARSING_EXPRESSION_CLASSIFIER_H_ +#include <type_traits> + #include "src/messages.h" #include "src/parsing/scanner.h" -#include "src/zone/zone-containers.h" namespace v8 { namespace internal { @@ -47,14 +48,38 @@ class DuplicateFinder; // 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 { +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 + kUnusedError = 15 // Larger than error codes; should fit in 4 bits }; struct Error { @@ -86,23 +111,14 @@ class ExpressionClassifier { }; // clang-format on - explicit ExpressionClassifier(typename Types::Base* base, - DuplicateFinder* duplicate_finder = nullptr) + explicit ExpressionClassifierBase(typename Types::Base* base, + DuplicateFinder* duplicate_finder = nullptr) : base_(base), - previous_(base->classifier_), - zone_(base->impl()->zone()), - reported_errors_(base->impl()->GetReportedErrorList()), duplicate_finder_(duplicate_finder), invalid_productions_(0), - is_non_simple_parameter_list_(0) { - base->classifier_ = this; - reported_errors_begin_ = reported_errors_end_ = reported_errors_->size(); - } + is_non_simple_parameter_list_(0) {} - V8_INLINE ~ExpressionClassifier() { - Discard(); - if (base_->classifier_ == this) base_->classifier_ = previous_; - } + virtual ~ExpressionClassifierBase() = default; V8_INLINE bool is_valid(unsigned productions) const { return (invalid_productions_ & productions) == 0; @@ -150,80 +166,338 @@ class ExpressionClassifier { 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 reported_error(kExpressionProduction); + return this->reported_error(ErrorKind::kExpressionProduction); } V8_INLINE const Error& formal_parameter_initializer_error() const { - return reported_error(kFormalParameterInitializerProduction); + return this->reported_error( + ErrorKind::kFormalParameterInitializerProduction); } V8_INLINE const Error& binding_pattern_error() const { - return reported_error(kBindingPatternProduction); + return this->reported_error(ErrorKind::kBindingPatternProduction); } V8_INLINE const Error& assignment_pattern_error() const { - return reported_error(kAssignmentPatternProduction); + return this->reported_error(ErrorKind::kAssignmentPatternProduction); } V8_INLINE const Error& arrow_formal_parameters_error() const { - return reported_error(kArrowFormalParametersProduction); + return this->reported_error(ErrorKind::kArrowFormalParametersProduction); } V8_INLINE const Error& duplicate_formal_parameter_error() const { - return reported_error(kDistinctFormalParametersProduction); + return this->reported_error(ErrorKind::kDistinctFormalParametersProduction); } V8_INLINE const Error& strict_mode_formal_parameter_error() const { - return reported_error(kStrictModeFormalParametersProduction); + return this->reported_error( + ErrorKind::kStrictModeFormalParametersProduction); } V8_INLINE const Error& let_pattern_error() const { - return reported_error(kLetPatternProduction); + return this->reported_error(ErrorKind::kLetPatternProduction); } V8_INLINE const Error& async_arrow_formal_parameters_error() const { - return reported_error(kAsyncArrowFormalParametersProduction); - } - - V8_INLINE bool is_simple_parameter_list() const { - return !is_non_simple_parameter_list_; + return this->reported_error( + ErrorKind::kAsyncArrowFormalParametersProduction); } - V8_INLINE void RecordNonSimpleParameter() { - is_non_simple_parameter_list_ = 1; - } + V8_INLINE bool does_error_reporting() { return ReportErrors; } void RecordExpressionError(const Scanner::Location& loc, MessageTemplate::Template message, const char* arg = nullptr) { - if (!is_valid_expression()) return; - invalid_productions_ |= ExpressionProduction; - Add(Error(loc, message, kExpressionProduction, arg)); + 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 (!is_valid_formal_parameter_initializer()) return; - invalid_productions_ |= FormalParameterInitializerProduction; - Add(Error(loc, message, kFormalParameterInitializerProduction, arg)); + 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 (!is_valid_binding_pattern()) return; - invalid_productions_ |= BindingPatternProduction; - Add(Error(loc, message, kBindingPatternProduction, arg)); + 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 (!is_valid_assignment_pattern()) return; - invalid_productions_ |= AssignmentPatternProduction; - Add(Error(loc, message, kAssignmentPatternProduction, arg)); + 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, @@ -236,24 +510,26 @@ class ExpressionClassifier { void RecordArrowFormalParametersError(const Scanner::Location& loc, MessageTemplate::Template message, const char* arg = nullptr) { - if (!is_valid_arrow_formal_parameters()) return; - invalid_productions_ |= ArrowFormalParametersProduction; - Add(Error(loc, message, kArrowFormalParametersProduction, arg)); + 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 (!is_valid_async_arrow_formal_parameters()) return; - invalid_productions_ |= AsyncArrowFormalParametersProduction; - Add(Error(loc, message, kAsyncArrowFormalParametersProduction, arg)); + 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 (!is_valid_formal_parameter_list_without_duplicates()) return; - invalid_productions_ |= DistinctFormalParametersProduction; - Add(Error(loc, MessageTemplate::kParamDupe, - kDistinctFormalParametersProduction)); + 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 @@ -262,160 +538,30 @@ class ExpressionClassifier { void RecordStrictModeFormalParameterError(const Scanner::Location& loc, MessageTemplate::Template message, const char* arg = nullptr) { - if (!is_valid_strict_mode_formal_parameters()) return; - invalid_productions_ |= StrictModeFormalParametersProduction; - Add(Error(loc, message, kStrictModeFormalParametersProduction, arg)); + 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 (!is_valid_let_pattern()) return; - invalid_productions_ |= LetPatternProduction; - Add(Error(loc, message, kLetPatternProduction, arg)); - } - - void Accumulate(ExpressionClassifier* inner, unsigned productions) { - DCHECK_EQ(inner->reported_errors_, reported_errors_); - DCHECK_EQ(inner->reported_errors_begin_, reported_errors_end_); - DCHECK_EQ(inner->reported_errors_end_, reported_errors_->size()); - // 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 & - ~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 && - is_valid_arrow_formal_parameters()) { - // Also whether we've seen any non-simple parameters - // if expecting an arrow function parameter. - is_non_simple_parameter_list_ |= inner->is_non_simple_parameter_list_; - if (!inner->is_valid_binding_pattern()) { - copy_BP_to_AFP = true; - invalid_productions_ |= ArrowFormalParametersProduction; - } - } - // Traverse the list of errors reported by the inner classifier - // to copy what's necessary. - if (errors != 0 || copy_BP_to_AFP) { - invalid_productions_ |= errors; - int binding_pattern_index = inner->reported_errors_end_; - for (int i = inner->reported_errors_begin_; - i < inner->reported_errors_end_; i++) { - int k = reported_errors_->at(i).kind; - if (errors & (1 << k)) Copy(i); - // Check if it's a BP error that has to be copied to an AFP error. - if (k == kBindingPatternProduction && copy_BP_to_AFP) { - if (reported_errors_end_ <= i) { - // If the BP error itself has not already been copied, - // copy it now and change it to an AFP error. - Copy(i); - reported_errors_->at(reported_errors_end_-1).kind = - kArrowFormalParametersProduction; - } else { - // Otherwise, if the BP error was already copied, keep its - // position and wait until the end of the traversal. - DCHECK_EQ(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 (reported_errors_end_ < inner->reported_errors_end_) - Copy(binding_pattern_index); - else - Add(reported_errors_->at(binding_pattern_index)); - reported_errors_->at(reported_errors_end_-1).kind = - kArrowFormalParametersProduction; - } - } - } - reported_errors_->resize(reported_errors_end_); - inner->reported_errors_begin_ = inner->reported_errors_end_ = - reported_errors_end_; - } - - V8_INLINE void Discard() { - if (reported_errors_end_ == reported_errors_->size()) { - reported_errors_->resize(reported_errors_begin_); - reported_errors_end_ = reported_errors_begin_; - } - DCHECK_EQ(reported_errors_begin_, reported_errors_end_); + 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: - V8_INLINE const Error& reported_error(ErrorKind kind) const { - if (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_->size()); - reported_errors_->push_back(e); - 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_->size()); - if (reported_errors_end_ != i) - reported_errors_->at(reported_errors_end_) = reported_errors_->at(i); - reported_errors_end_++; - } - - typename Types::Base* base_; ExpressionClassifier* previous_; - Zone* zone_; - ZoneVector<Error>* reported_errors_; - DuplicateFinder* duplicate_finder_; - unsigned invalid_productions_ : 15; - unsigned is_non_simple_parameter_list_ : 1; - // 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_; DISALLOW_COPY_AND_ASSIGN(ExpressionClassifier); }; - #undef ERROR_CODES - } // namespace internal } // namespace v8 |