// 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 "src/messages.h" #include "src/parsing/scanner.h" #include "src/parsing/token.h" namespace v8 { namespace internal { class ExpressionClassifier { public: struct Error { Error() : location(Scanner::Location::invalid()), message(MessageTemplate::kNone), type(kSyntaxError), arg(nullptr) {} Scanner::Location location; MessageTemplate::Template message : 30; ParseErrorType type : 2; const char* arg; }; enum TargetProduction { ExpressionProduction = 1 << 0, FormalParameterInitializerProduction = 1 << 1, BindingPatternProduction = 1 << 2, AssignmentPatternProduction = 1 << 3, DistinctFormalParametersProduction = 1 << 4, StrictModeFormalParametersProduction = 1 << 5, StrongModeFormalParametersProduction = 1 << 6, ArrowFormalParametersProduction = 1 << 7, LetPatternProduction = 1 << 8, CoverInitializedNameProduction = 1 << 9, ExpressionProductions = (ExpressionProduction | FormalParameterInitializerProduction), PatternProductions = (BindingPatternProduction | AssignmentPatternProduction | LetPatternProduction), FormalParametersProductions = (DistinctFormalParametersProduction | StrictModeFormalParametersProduction | StrongModeFormalParametersProduction), StandardProductions = ExpressionProductions | PatternProductions, AllProductions = (StandardProductions | FormalParametersProductions | ArrowFormalParametersProduction | CoverInitializedNameProduction) }; enum FunctionProperties { NonSimpleParameter = 1 << 0 }; ExpressionClassifier() : invalid_productions_(0), function_properties_(0), duplicate_finder_(nullptr) {} explicit ExpressionClassifier(DuplicateFinder* duplicate_finder) : invalid_productions_(0), function_properties_(0), duplicate_finder_(duplicate_finder) {} bool is_valid(unsigned productions) const { return (invalid_productions_ & productions) == 0; } DuplicateFinder* duplicate_finder() const { return duplicate_finder_; } bool is_valid_expression() const { return is_valid(ExpressionProduction); } bool is_valid_formal_parameter_initializer() const { return is_valid(FormalParameterInitializerProduction); } bool is_valid_binding_pattern() const { return is_valid(BindingPatternProduction); } bool is_valid_assignment_pattern() const { return is_valid(AssignmentPatternProduction); } bool is_valid_arrow_formal_parameters() const { return is_valid(ArrowFormalParametersProduction); } 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(). bool is_valid_strict_mode_formal_parameters() const { return is_valid(StrictModeFormalParametersProduction); } // Note: callers should also check is_valid_strict_mode_formal_parameters() // and is_valid_formal_parameter_list_without_duplicates(). bool is_valid_strong_mode_formal_parameters() const { return is_valid(StrongModeFormalParametersProduction); } bool is_valid_let_pattern() const { return is_valid(LetPatternProduction); } const Error& expression_error() const { return expression_error_; } const Error& formal_parameter_initializer_error() const { return formal_parameter_initializer_error_; } const Error& binding_pattern_error() const { return binding_pattern_error_; } const Error& assignment_pattern_error() const { return assignment_pattern_error_; } const Error& arrow_formal_parameters_error() const { return arrow_formal_parameters_error_; } const Error& duplicate_formal_parameter_error() const { return duplicate_formal_parameter_error_; } const Error& strict_mode_formal_parameter_error() const { return strict_mode_formal_parameter_error_; } const Error& strong_mode_formal_parameter_error() const { return strong_mode_formal_parameter_error_; } const Error& let_pattern_error() const { return let_pattern_error_; } bool has_cover_initialized_name() const { return !is_valid(CoverInitializedNameProduction); } const Error& cover_initialized_name_error() const { return cover_initialized_name_error_; } bool is_simple_parameter_list() const { return !(function_properties_ & NonSimpleParameter); } void RecordNonSimpleParameter() { function_properties_ |= NonSimpleParameter; } void RecordExpressionError(const Scanner::Location& loc, MessageTemplate::Template message, const char* arg = nullptr) { if (!is_valid_expression()) return; invalid_productions_ |= ExpressionProduction; expression_error_.location = loc; expression_error_.message = message; expression_error_.arg = arg; } void RecordExpressionError(const Scanner::Location& loc, MessageTemplate::Template message, ParseErrorType type, const char* arg = nullptr) { if (!is_valid_expression()) return; invalid_productions_ |= ExpressionProduction; expression_error_.location = loc; expression_error_.message = message; expression_error_.arg = arg; expression_error_.type = type; } void RecordFormalParameterInitializerError(const Scanner::Location& loc, MessageTemplate::Template message, const char* arg = nullptr) { if (!is_valid_formal_parameter_initializer()) return; invalid_productions_ |= FormalParameterInitializerProduction; formal_parameter_initializer_error_.location = loc; formal_parameter_initializer_error_.message = message; formal_parameter_initializer_error_.arg = arg; } void RecordBindingPatternError(const Scanner::Location& loc, MessageTemplate::Template message, const char* arg = nullptr) { if (!is_valid_binding_pattern()) return; invalid_productions_ |= BindingPatternProduction; binding_pattern_error_.location = loc; binding_pattern_error_.message = message; binding_pattern_error_.arg = arg; } void RecordAssignmentPatternError(const Scanner::Location& loc, MessageTemplate::Template message, const char* arg = nullptr) { if (!is_valid_assignment_pattern()) return; invalid_productions_ |= AssignmentPatternProduction; assignment_pattern_error_.location = loc; assignment_pattern_error_.message = message; assignment_pattern_error_.arg = 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 (!is_valid_arrow_formal_parameters()) return; invalid_productions_ |= ArrowFormalParametersProduction; arrow_formal_parameters_error_.location = loc; arrow_formal_parameters_error_.message = message; arrow_formal_parameters_error_.arg = arg; } void RecordDuplicateFormalParameterError(const Scanner::Location& loc) { if (!is_valid_formal_parameter_list_without_duplicates()) return; invalid_productions_ |= DistinctFormalParametersProduction; duplicate_formal_parameter_error_.location = loc; duplicate_formal_parameter_error_.message = MessageTemplate::kParamDupe; duplicate_formal_parameter_error_.arg = nullptr; } // Record a binding that would be invalid in strict mode. Confusingly this // is not the same as StrictFormalParameterList, which simply forbids // duplicate bindings. void RecordStrictModeFormalParameterError(const Scanner::Location& loc, MessageTemplate::Template message, const char* arg = nullptr) { if (!is_valid_strict_mode_formal_parameters()) return; invalid_productions_ |= StrictModeFormalParametersProduction; strict_mode_formal_parameter_error_.location = loc; strict_mode_formal_parameter_error_.message = message; strict_mode_formal_parameter_error_.arg = arg; } void RecordStrongModeFormalParameterError(const Scanner::Location& loc, MessageTemplate::Template message, const char* arg = nullptr) { if (!is_valid_strong_mode_formal_parameters()) return; invalid_productions_ |= StrongModeFormalParametersProduction; strong_mode_formal_parameter_error_.location = loc; strong_mode_formal_parameter_error_.message = message; strong_mode_formal_parameter_error_.arg = arg; } void RecordLetPatternError(const Scanner::Location& loc, MessageTemplate::Template message, const char* arg = nullptr) { if (!is_valid_let_pattern()) return; invalid_productions_ |= LetPatternProduction; let_pattern_error_.location = loc; let_pattern_error_.message = message; let_pattern_error_.arg = arg; } void RecordCoverInitializedNameError(const Scanner::Location& loc, MessageTemplate::Template message, const char* arg = nullptr) { if (has_cover_initialized_name()) return; invalid_productions_ |= CoverInitializedNameProduction; cover_initialized_name_error_.location = loc; cover_initialized_name_error_.message = message; cover_initialized_name_error_.arg = arg; } void ForgiveCoverInitializedNameError() { invalid_productions_ &= ~CoverInitializedNameProduction; cover_initialized_name_error_ = Error(); } void ForgiveAssignmentPatternError() { invalid_productions_ &= ~AssignmentPatternProduction; assignment_pattern_error_ = Error(); } void Accumulate(const ExpressionClassifier& inner, unsigned productions = StandardProductions) { // 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 == 0) return; unsigned non_arrow_productions = productions & ~ArrowFormalParametersProduction; unsigned errors = non_arrow_productions & non_arrow_inner_invalid_productions; errors &= ~invalid_productions_; if (errors != 0) { invalid_productions_ |= errors; if (errors & ExpressionProduction) expression_error_ = inner.expression_error_; if (errors & FormalParameterInitializerProduction) formal_parameter_initializer_error_ = inner.formal_parameter_initializer_error_; if (errors & BindingPatternProduction) binding_pattern_error_ = inner.binding_pattern_error_; if (errors & AssignmentPatternProduction) assignment_pattern_error_ = inner.assignment_pattern_error_; if (errors & DistinctFormalParametersProduction) duplicate_formal_parameter_error_ = inner.duplicate_formal_parameter_error_; if (errors & StrictModeFormalParametersProduction) strict_mode_formal_parameter_error_ = inner.strict_mode_formal_parameter_error_; if (errors & StrongModeFormalParametersProduction) strong_mode_formal_parameter_error_ = inner.strong_mode_formal_parameter_error_; if (errors & LetPatternProduction) let_pattern_error_ = inner.let_pattern_error_; if (errors & CoverInitializedNameProduction) cover_initialized_name_error_ = inner.cover_initialized_name_error_; } // As an exception to the above, the result continues to be a valid arrow // formal parameters if the inner expression is a valid binding pattern. if (productions & ArrowFormalParametersProduction && is_valid_arrow_formal_parameters()) { // Also copy function properties if expecting an arrow function // parameter. function_properties_ |= inner.function_properties_; if (!inner.is_valid_binding_pattern()) { invalid_productions_ |= ArrowFormalParametersProduction; arrow_formal_parameters_error_ = inner.binding_pattern_error_; } } } private: unsigned invalid_productions_; unsigned function_properties_; Error expression_error_; Error formal_parameter_initializer_error_; Error binding_pattern_error_; Error assignment_pattern_error_; Error arrow_formal_parameters_error_; Error duplicate_formal_parameter_error_; Error strict_mode_formal_parameter_error_; Error strong_mode_formal_parameter_error_; Error let_pattern_error_; Error cover_initialized_name_error_; DuplicateFinder* duplicate_finder_; }; } // namespace internal } // namespace v8 #endif // V8_PARSING_EXPRESSION_CLASSIFIER_H