Index: src/expression-classifier.h |
diff --git a/src/expression-classifier.h b/src/expression-classifier.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..af761fb2bf66d74d0ab4ab031af8e8e32a7f8d37 |
--- /dev/null |
+++ b/src/expression-classifier.h |
@@ -0,0 +1,471 @@ |
+// 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_EXPRESSION_CLASSIFIER_H |
+#define V8_EXPRESSION_CLASSIFIER_H |
+ |
+#include "src/v8.h" |
+ |
+#include "src/messages.h" |
+#include "src/scanner.h" |
+#include "src/token.h" |
+ |
+namespace v8 { |
+namespace internal { |
+ |
+ |
+class ExpressionClassifier { |
+ public: |
+ struct Error { |
+ Error() |
+ : location(Scanner::Location::invalid()), |
+ message(MessageTemplate::kNone), |
+ arg(nullptr) {} |
+ |
+ Scanner::Location location; |
+ MessageTemplate::Template message; |
+ const char* arg; |
+ }; |
+ |
+ enum TargetProduction { |
+ ExpressionProduction = 1 << 0, |
+ BindingPatternProduction = 1 << 1, |
+ AssignmentPatternProduction = 1 << 2, |
+ DistinctFormalParametersProduction = 1 << 3, |
+ StrictModeFormalParametersProduction = 1 << 4, |
+ StrongModeFormalParametersProduction = 1 << 5, |
+ ArrowFormalParametersProduction = 1 << 6, |
+ |
+ PatternProductions = |
+ (BindingPatternProduction | AssignmentPatternProduction), |
+ FormalParametersProductions = (DistinctFormalParametersProduction | |
+ StrictModeFormalParametersProduction | |
+ StrongModeFormalParametersProduction), |
+ StandardProductions = ExpressionProduction | PatternProductions, |
+ AllProductions = (StandardProductions | FormalParametersProductions | |
+ ArrowFormalParametersProduction) |
+ }; |
+ |
+ ExpressionClassifier() |
+ : invalid_productions_(0), duplicate_finder_(nullptr) {} |
+ |
+ explicit ExpressionClassifier(DuplicateFinder* duplicate_finder) |
+ : invalid_productions_(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_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); |
+ } |
+ |
+ const Error& expression_error() const { return expression_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_; |
+ } |
+ |
+ 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; |
+ class ExpressionClassifier { |
+ public: |
+ struct Error { |
+ Error() |
+ : location(Scanner::Location::invalid()), |
+ message(MessageTemplate::kNone), |
+ arg(nullptr) {} |
+ |
+ Scanner::Location location; |
+ MessageTemplate::Template message; |
+ const char* arg; |
+ |
+ bool HasError() const { return location.IsValid(); } |
+ }; |
+ |
+ ExpressionClassifier() : duplicate_finder_(nullptr) {} |
+ |
+ explicit ExpressionClassifier(DuplicateFinder* duplicate_finder) |
+ : duplicate_finder_(duplicate_finder) {} |
+ |
+ DuplicateFinder* duplicate_finder() const { return duplicate_finder_; } |
+ |
+ bool is_valid_expression() const { return !expression_error_.HasError(); } |
+ |
+ bool is_valid_binding_pattern() const { |
+ return !binding_pattern_error_.HasError(); |
+ } |
+ |
+ bool is_valid_assignment_pattern() const { |
+ return !assignment_pattern_error_.HasError(); |
+ } |
+ |
+ bool is_valid_arrow_formal_parameters() const { |
+ return !arrow_formal_parameters_error_.HasError(); |
+ } |
+ |
+ bool is_valid_formal_parameter_list_without_duplicates() const { |
+ return !duplicate_formal_parameter_error_.HasError(); |
+ } |
+ |
+ // Note: callers should also check |
+ // is_valid_formal_parameter_list_without_duplicates(). |
+ bool is_valid_strict_mode_formal_parameters() const { |
+ return !strict_mode_formal_parameter_error_.HasError(); |
+ } |
+ |
+ // 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 !strong_mode_formal_parameter_error_.HasError(); |
+ } |
+ |
+ const Error& expression_error() const { return expression_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_; |
+ } |
+ |
+ void RecordExpressionError(const Scanner::Location& loc, |
+ MessageTemplate::Template message, |
+ const char* arg = nullptr) { |
+ if (!is_valid_expression()) return; |
+ expression_error_.location = loc; |
+ expression_error_.message = message; |
+ expression_error_.arg = arg; |
+ } |
+ |
+ void RecordBindingPatternError(const Scanner::Location& loc, |
+ MessageTemplate::Template message, |
+ const char* arg = nullptr) { |
+ if (!is_valid_binding_pattern()) return; |
+ 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; |
+ assignment_pattern_error_.location = loc; |
+ assignment_pattern_error_.message = message; |
+ assignment_pattern_error_.arg = arg; |
+ } |
+ |
+ void RecordArrowFormalParametersError(const Scanner::Location& loc, |
+ MessageTemplate::Template message, |
+ const char* arg = nullptr) { |
+ if (!is_valid_arrow_formal_parameters()) return; |
+ 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; |
+ duplicate_formal_parameter_error_.location = loc; |
+ duplicate_formal_parameter_error_.message = |
+ MessageTemplate::kStrictParamDupe; |
+ 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; |
+ 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; |
+ strong_mode_formal_parameter_error_.location = loc; |
+ strong_mode_formal_parameter_error_.message = message; |
+ strong_mode_formal_parameter_error_.arg = arg; |
+ } |
+ |
+ enum TargetProduction { |
+ ExpressionProduction = 1 << 0, |
+ BindingPatternProduction = 1 << 1, |
+ AssignmentPatternProduction = 1 << 2, |
+ FormalParametersProduction = 1 << 3, |
+ ArrowFormalParametersProduction = 1 << 4, |
+ StandardProductions = (ExpressionProduction | BindingPatternProduction | |
+ AssignmentPatternProduction), |
+ PatternProductions = |
+ BindingPatternProduction | AssignmentPatternProduction, |
+ AllProductions = (StandardProductions | FormalParametersProduction | |
+ ArrowFormalParametersProduction), |
+ }; |
+ |
+ void Accumulate(const ExpressionClassifier& inner, |
+ unsigned productions = StandardProductions) { |
+ if (productions & ExpressionProduction && is_valid_expression()) { |
+ expression_error_ = inner.expression_error_; |
+ } |
+ if (productions & BindingPatternProduction && |
+ is_valid_binding_pattern()) { |
+ binding_pattern_error_ = inner.binding_pattern_error_; |
+ } |
+ if (productions & AssignmentPatternProduction && |
+ is_valid_assignment_pattern()) { |
+ assignment_pattern_error_ = inner.assignment_pattern_error_; |
+ } |
+ if (productions & FormalParametersProduction) { |
+ if (is_valid_formal_parameter_list_without_duplicates()) { |
+ duplicate_formal_parameter_error_ = |
+ inner.duplicate_formal_parameter_error_; |
+ } |
+ if (is_valid_strict_mode_formal_parameters()) { |
+ strict_mode_formal_parameter_error_ = |
+ inner.strict_mode_formal_parameter_error_; |
+ } |
+ if (is_valid_strong_mode_formal_parameters()) { |
+ strong_mode_formal_parameter_error_ = |
+ inner.strong_mode_formal_parameter_error_; |
+ } |
+ } |
+ if (productions & ArrowFormalParametersProduction && |
+ is_valid_arrow_formal_parameters()) { |
+ // The result continues to be a valid arrow formal parameters if the |
+ // inner expression is a valid binding pattern. |
+ arrow_formal_parameters_error_ = inner.binding_pattern_error_; |
+ } |
+ } |
+ |
+ void AccumulateReclassifyingAsPattern(const ExpressionClassifier& inner) { |
+ Accumulate(inner, AllProductions & ~PatternProductions); |
+ if (!inner.is_valid_expression()) { |
+ if (is_valid_binding_pattern()) { |
+ binding_pattern_error_ = inner.expression_error(); |
+ } |
+ if (is_valid_assignment_pattern()) { |
+ assignment_pattern_error_ = inner.expression_error(); |
+ } |
+ } |
+ } |
+ |
+ private: |
+ Error expression_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_; |
+ DuplicateFinder* duplicate_finder_; |
+ }; |
+ expression_error_.message = message; |
+ expression_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 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::kStrictParamDupe; |
+ 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 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 & 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_; |
+ } |
+ |
+ // 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() && |
+ !inner.is_valid_binding_pattern()) { |
+ invalid_productions_ |= ArrowFormalParametersProduction; |
+ arrow_formal_parameters_error_ = inner.binding_pattern_error_; |
+ } |
+ } |
+ |
+ void AccumulateReclassifyingAsPattern(const ExpressionClassifier& inner) { |
+ Accumulate(inner, AllProductions & ~PatternProductions); |
+ if (!inner.is_valid_expression()) { |
+ if (is_valid_binding_pattern()) { |
+ binding_pattern_error_ = inner.expression_error(); |
+ } |
+ if (is_valid_assignment_pattern()) { |
+ assignment_pattern_error_ = inner.expression_error(); |
+ } |
+ } |
+ } |
+ |
+ private: |
+ unsigned invalid_productions_; |
+ Error expression_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_; |
+ DuplicateFinder* duplicate_finder_; |
+}; |
+} |
+} // v8::internal |
+ |
+#endif // V8_EXPRESSION_CLASSIFIER_H |