Home | History | Annotate | Download | only in parsing
      1 // Copyright 2015 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef V8_PARSING_EXPRESSION_CLASSIFIER_H
      6 #define V8_PARSING_EXPRESSION_CLASSIFIER_H
      7 
      8 #include "src/messages.h"
      9 #include "src/parsing/scanner.h"
     10 
     11 namespace v8 {
     12 namespace internal {
     13 
     14 class DuplicateFinder;
     15 
     16 #define ERROR_CODES(T)                       \
     17   T(ExpressionProduction, 0)                 \
     18   T(FormalParameterInitializerProduction, 1) \
     19   T(BindingPatternProduction, 2)             \
     20   T(AssignmentPatternProduction, 3)          \
     21   T(DistinctFormalParametersProduction, 4)   \
     22   T(StrictModeFormalParametersProduction, 5) \
     23   T(ArrowFormalParametersProduction, 6)      \
     24   T(LetPatternProduction, 7)                 \
     25   T(AsyncArrowFormalParametersProduction, 8)
     26 
     27 // Expression classifiers serve two purposes:
     28 //
     29 // 1) They keep track of error messages that are pending (and other
     30 //    related information), waiting for the parser to decide whether
     31 //    the parsed expression is a pattern or not.
     32 // 2) They keep track of expressions that may need to be rewritten, if
     33 //    the parser decides that they are not patterns.  (A different
     34 //    mechanism implements the rewriting of patterns.)
     35 //
     36 // Expression classifiers are used by the parser in a stack fashion.
     37 // Each new classifier is pushed on top of the stack.  This happens
     38 // automatically by the class's constructor.  While on top of the
     39 // stack, the classifier records pending error messages and tracks the
     40 // pending non-patterns of the expression that is being parsed.
     41 //
     42 // At the end of its life, a classifier is either "accumulated" to the
     43 // one that is below it on the stack, or is "discarded".  The former
     44 // is achieved by calling the method Accumulate.  The latter is
     45 // achieved automatically by the destructor, but it can happen earlier
     46 // by calling the method Discard.  Both actions result in removing the
     47 // classifier from the parser's stack.
     48 
     49 template <typename Types>
     50 class ExpressionClassifier {
     51  public:
     52   enum ErrorKind : unsigned {
     53 #define DEFINE_ERROR_KIND(NAME, CODE) k##NAME = CODE,
     54     ERROR_CODES(DEFINE_ERROR_KIND)
     55 #undef DEFINE_ERROR_KIND
     56     kUnusedError = 15  // Larger than error codes; should fit in 4 bits
     57   };
     58 
     59   struct Error {
     60     V8_INLINE Error()
     61         : location(Scanner::Location::invalid()),
     62           message(MessageTemplate::kNone),
     63           kind(kUnusedError),
     64           type(kSyntaxError),
     65           arg(nullptr) {}
     66     V8_INLINE explicit Error(Scanner::Location loc,
     67                              MessageTemplate::Template msg, ErrorKind k,
     68                              const char* a = nullptr,
     69                              ParseErrorType t = kSyntaxError)
     70         : location(loc), message(msg), kind(k), type(t), arg(a) {}
     71 
     72     Scanner::Location location;
     73     MessageTemplate::Template message : 26;
     74     unsigned kind : 4;
     75     ParseErrorType type : 2;
     76     const char* arg;
     77   };
     78 
     79   // clang-format off
     80   enum TargetProduction : unsigned {
     81 #define DEFINE_PRODUCTION(NAME, CODE) NAME = 1 << CODE,
     82     ERROR_CODES(DEFINE_PRODUCTION)
     83 #undef DEFINE_PRODUCTION
     84 
     85 #define DEFINE_ALL_PRODUCTIONS(NAME, CODE) NAME |
     86     AllProductions = ERROR_CODES(DEFINE_ALL_PRODUCTIONS) /* | */ 0
     87 #undef DEFINE_ALL_PRODUCTIONS
     88   };
     89   // clang-format on
     90 
     91   enum FunctionProperties : unsigned {
     92     NonSimpleParameter = 1 << 0
     93   };
     94 
     95   explicit ExpressionClassifier(typename Types::Base* base,
     96                                 DuplicateFinder* duplicate_finder = nullptr)
     97       : base_(base),
     98         previous_(base->classifier_),
     99         zone_(base->impl()->zone()),
    100         non_patterns_to_rewrite_(base->impl()->GetNonPatternList()),
    101         reported_errors_(base->impl()->GetReportedErrorList()),
    102         duplicate_finder_(duplicate_finder),
    103         invalid_productions_(0),
    104         function_properties_(0) {
    105     base->classifier_ = this;
    106     reported_errors_begin_ = reported_errors_end_ = reported_errors_->length();
    107     non_pattern_begin_ = non_patterns_to_rewrite_->length();
    108   }
    109 
    110   V8_INLINE ~ExpressionClassifier() {
    111     Discard();
    112     if (base_->classifier_ == this) base_->classifier_ = previous_;
    113   }
    114 
    115   V8_INLINE bool is_valid(unsigned productions) const {
    116     return (invalid_productions_ & productions) == 0;
    117   }
    118 
    119   V8_INLINE DuplicateFinder* duplicate_finder() const {
    120     return duplicate_finder_;
    121   }
    122 
    123   V8_INLINE bool is_valid_expression() const {
    124     return is_valid(ExpressionProduction);
    125   }
    126 
    127   V8_INLINE bool is_valid_formal_parameter_initializer() const {
    128     return is_valid(FormalParameterInitializerProduction);
    129   }
    130 
    131   V8_INLINE bool is_valid_binding_pattern() const {
    132     return is_valid(BindingPatternProduction);
    133   }
    134 
    135   V8_INLINE bool is_valid_assignment_pattern() const {
    136     return is_valid(AssignmentPatternProduction);
    137   }
    138 
    139   V8_INLINE bool is_valid_arrow_formal_parameters() const {
    140     return is_valid(ArrowFormalParametersProduction);
    141   }
    142 
    143   V8_INLINE bool is_valid_formal_parameter_list_without_duplicates() const {
    144     return is_valid(DistinctFormalParametersProduction);
    145   }
    146 
    147   // Note: callers should also check
    148   // is_valid_formal_parameter_list_without_duplicates().
    149   V8_INLINE bool is_valid_strict_mode_formal_parameters() const {
    150     return is_valid(StrictModeFormalParametersProduction);
    151   }
    152 
    153   V8_INLINE bool is_valid_let_pattern() const {
    154     return is_valid(LetPatternProduction);
    155   }
    156 
    157   bool is_valid_async_arrow_formal_parameters() const {
    158     return is_valid(AsyncArrowFormalParametersProduction);
    159   }
    160 
    161   V8_INLINE const Error& expression_error() const {
    162     return reported_error(kExpressionProduction);
    163   }
    164 
    165   V8_INLINE const Error& formal_parameter_initializer_error() const {
    166     return reported_error(kFormalParameterInitializerProduction);
    167   }
    168 
    169   V8_INLINE const Error& binding_pattern_error() const {
    170     return reported_error(kBindingPatternProduction);
    171   }
    172 
    173   V8_INLINE const Error& assignment_pattern_error() const {
    174     return reported_error(kAssignmentPatternProduction);
    175   }
    176 
    177   V8_INLINE const Error& arrow_formal_parameters_error() const {
    178     return reported_error(kArrowFormalParametersProduction);
    179   }
    180 
    181   V8_INLINE const Error& duplicate_formal_parameter_error() const {
    182     return reported_error(kDistinctFormalParametersProduction);
    183   }
    184 
    185   V8_INLINE const Error& strict_mode_formal_parameter_error() const {
    186     return reported_error(kStrictModeFormalParametersProduction);
    187   }
    188 
    189   V8_INLINE const Error& let_pattern_error() const {
    190     return reported_error(kLetPatternProduction);
    191   }
    192 
    193   V8_INLINE const Error& async_arrow_formal_parameters_error() const {
    194     return reported_error(kAsyncArrowFormalParametersProduction);
    195   }
    196 
    197   V8_INLINE bool is_simple_parameter_list() const {
    198     return !(function_properties_ & NonSimpleParameter);
    199   }
    200 
    201   V8_INLINE void RecordNonSimpleParameter() {
    202     function_properties_ |= NonSimpleParameter;
    203   }
    204 
    205   void RecordExpressionError(const Scanner::Location& loc,
    206                              MessageTemplate::Template message,
    207                              const char* arg = nullptr) {
    208     if (!is_valid_expression()) return;
    209     invalid_productions_ |= ExpressionProduction;
    210     Add(Error(loc, message, kExpressionProduction, arg));
    211   }
    212 
    213   void RecordExpressionError(const Scanner::Location& loc,
    214                              MessageTemplate::Template message,
    215                              ParseErrorType type, const char* arg = nullptr) {
    216     if (!is_valid_expression()) return;
    217     invalid_productions_ |= ExpressionProduction;
    218     Add(Error(loc, message, kExpressionProduction, arg, type));
    219   }
    220 
    221   void RecordFormalParameterInitializerError(const Scanner::Location& loc,
    222                                              MessageTemplate::Template message,
    223                                              const char* arg = nullptr) {
    224     if (!is_valid_formal_parameter_initializer()) return;
    225     invalid_productions_ |= FormalParameterInitializerProduction;
    226     Add(Error(loc, message, kFormalParameterInitializerProduction, arg));
    227   }
    228 
    229   void RecordBindingPatternError(const Scanner::Location& loc,
    230                                  MessageTemplate::Template message,
    231                                  const char* arg = nullptr) {
    232     if (!is_valid_binding_pattern()) return;
    233     invalid_productions_ |= BindingPatternProduction;
    234     Add(Error(loc, message, kBindingPatternProduction, arg));
    235   }
    236 
    237   void RecordAssignmentPatternError(const Scanner::Location& loc,
    238                                     MessageTemplate::Template message,
    239                                     const char* arg = nullptr) {
    240     if (!is_valid_assignment_pattern()) return;
    241     invalid_productions_ |= AssignmentPatternProduction;
    242     Add(Error(loc, message, kAssignmentPatternProduction, arg));
    243   }
    244 
    245   void RecordPatternError(const Scanner::Location& loc,
    246                           MessageTemplate::Template message,
    247                           const char* arg = nullptr) {
    248     RecordBindingPatternError(loc, message, arg);
    249     RecordAssignmentPatternError(loc, message, arg);
    250   }
    251 
    252   void RecordArrowFormalParametersError(const Scanner::Location& loc,
    253                                         MessageTemplate::Template message,
    254                                         const char* arg = nullptr) {
    255     if (!is_valid_arrow_formal_parameters()) return;
    256     invalid_productions_ |= ArrowFormalParametersProduction;
    257     Add(Error(loc, message, kArrowFormalParametersProduction, arg));
    258   }
    259 
    260   void RecordAsyncArrowFormalParametersError(const Scanner::Location& loc,
    261                                              MessageTemplate::Template message,
    262                                              const char* arg = nullptr) {
    263     if (!is_valid_async_arrow_formal_parameters()) return;
    264     invalid_productions_ |= AsyncArrowFormalParametersProduction;
    265     Add(Error(loc, message, kAsyncArrowFormalParametersProduction, arg));
    266   }
    267 
    268   void RecordDuplicateFormalParameterError(const Scanner::Location& loc) {
    269     if (!is_valid_formal_parameter_list_without_duplicates()) return;
    270     invalid_productions_ |= DistinctFormalParametersProduction;
    271     Add(Error(loc, MessageTemplate::kParamDupe,
    272               kDistinctFormalParametersProduction));
    273   }
    274 
    275   // Record a binding that would be invalid in strict mode.  Confusingly this
    276   // is not the same as StrictFormalParameterList, which simply forbids
    277   // duplicate bindings.
    278   void RecordStrictModeFormalParameterError(const Scanner::Location& loc,
    279                                             MessageTemplate::Template message,
    280                                             const char* arg = nullptr) {
    281     if (!is_valid_strict_mode_formal_parameters()) return;
    282     invalid_productions_ |= StrictModeFormalParametersProduction;
    283     Add(Error(loc, message, kStrictModeFormalParametersProduction, arg));
    284   }
    285 
    286   void RecordLetPatternError(const Scanner::Location& loc,
    287                              MessageTemplate::Template message,
    288                              const char* arg = nullptr) {
    289     if (!is_valid_let_pattern()) return;
    290     invalid_productions_ |= LetPatternProduction;
    291     Add(Error(loc, message, kLetPatternProduction, arg));
    292   }
    293 
    294   void Accumulate(ExpressionClassifier* inner, unsigned productions,
    295                   bool merge_non_patterns = true) {
    296     DCHECK_EQ(inner->reported_errors_, reported_errors_);
    297     DCHECK_EQ(inner->reported_errors_begin_, reported_errors_end_);
    298     DCHECK_EQ(inner->reported_errors_end_, reported_errors_->length());
    299     DCHECK_EQ(inner->non_patterns_to_rewrite_, non_patterns_to_rewrite_);
    300     DCHECK_LE(non_pattern_begin_, inner->non_pattern_begin_);
    301     DCHECK_LE(inner->non_pattern_begin_, non_patterns_to_rewrite_->length());
    302     // Merge non-patterns from the inner classifier, or discard them.
    303     if (merge_non_patterns)
    304       inner->non_pattern_begin_ = non_patterns_to_rewrite_->length();
    305     else
    306       non_patterns_to_rewrite_->Rewind(inner->non_pattern_begin_);
    307     // Propagate errors from inner, but don't overwrite already recorded
    308     // errors.
    309     unsigned non_arrow_inner_invalid_productions =
    310         inner->invalid_productions_ & ~ArrowFormalParametersProduction;
    311     if (non_arrow_inner_invalid_productions) {
    312       unsigned errors = non_arrow_inner_invalid_productions & productions &
    313                         ~invalid_productions_;
    314       // The result will continue to be a valid arrow formal parameters if the
    315       // inner expression is a valid binding pattern.
    316       bool copy_BP_to_AFP = false;
    317       if (productions & ArrowFormalParametersProduction &&
    318           is_valid_arrow_formal_parameters()) {
    319         // Also copy function properties if expecting an arrow function
    320         // parameter.
    321         function_properties_ |= inner->function_properties_;
    322         if (!inner->is_valid_binding_pattern()) {
    323           copy_BP_to_AFP = true;
    324           invalid_productions_ |= ArrowFormalParametersProduction;
    325         }
    326       }
    327       // Traverse the list of errors reported by the inner classifier
    328       // to copy what's necessary.
    329       if (errors != 0 || copy_BP_to_AFP) {
    330         invalid_productions_ |= errors;
    331         int binding_pattern_index = inner->reported_errors_end_;
    332         for (int i = inner->reported_errors_begin_;
    333              i < inner->reported_errors_end_; i++) {
    334           int k = reported_errors_->at(i).kind;
    335           if (errors & (1 << k)) Copy(i);
    336           // Check if it's a BP error that has to be copied to an AFP error.
    337           if (k == kBindingPatternProduction && copy_BP_to_AFP) {
    338             if (reported_errors_end_ <= i) {
    339               // If the BP error itself has not already been copied,
    340               // copy it now and change it to an AFP error.
    341               Copy(i);
    342               reported_errors_->at(reported_errors_end_-1).kind =
    343                   kArrowFormalParametersProduction;
    344             } else {
    345               // Otherwise, if the BP error was already copied, keep its
    346               // position and wait until the end of the traversal.
    347               DCHECK_EQ(reported_errors_end_, i+1);
    348               binding_pattern_index = i;
    349             }
    350           }
    351         }
    352         // Do we still have to copy the BP error to an AFP error?
    353         if (binding_pattern_index < inner->reported_errors_end_) {
    354           // If there's still unused space in the list of the inner
    355           // classifier, copy it there, otherwise add it to the end
    356           // of the list.
    357           if (reported_errors_end_ < inner->reported_errors_end_)
    358             Copy(binding_pattern_index);
    359           else
    360             Add(reported_errors_->at(binding_pattern_index));
    361           reported_errors_->at(reported_errors_end_-1).kind =
    362               kArrowFormalParametersProduction;
    363         }
    364       }
    365     }
    366     reported_errors_->Rewind(reported_errors_end_);
    367     inner->reported_errors_begin_ = inner->reported_errors_end_ =
    368         reported_errors_end_;
    369   }
    370 
    371   V8_INLINE int GetNonPatternBegin() const { return non_pattern_begin_; }
    372 
    373   V8_INLINE void Discard() {
    374     if (reported_errors_end_ == reported_errors_->length()) {
    375       reported_errors_->Rewind(reported_errors_begin_);
    376       reported_errors_end_ = reported_errors_begin_;
    377     }
    378     DCHECK_EQ(reported_errors_begin_, reported_errors_end_);
    379     DCHECK_LE(non_pattern_begin_, non_patterns_to_rewrite_->length());
    380     non_patterns_to_rewrite_->Rewind(non_pattern_begin_);
    381   }
    382 
    383   ExpressionClassifier* previous() const { return previous_; }
    384 
    385  private:
    386   V8_INLINE const Error& reported_error(ErrorKind kind) const {
    387     if (invalid_productions_ & (1 << kind)) {
    388       for (int i = reported_errors_begin_; i < reported_errors_end_; i++) {
    389         if (reported_errors_->at(i).kind == kind)
    390           return reported_errors_->at(i);
    391       }
    392       UNREACHABLE();
    393     }
    394     // We should only be looking for an error when we know that one has
    395     // been reported.  But we're not...  So this is to make sure we have
    396     // the same behaviour.
    397     UNREACHABLE();
    398 
    399     // Make MSVC happy by returning an error from this inaccessible path.
    400     static Error none;
    401     return none;
    402   }
    403 
    404   // Adds e to the end of the list of reported errors for this classifier.
    405   // It is expected that this classifier is the last one in the stack.
    406   V8_INLINE void Add(const Error& e) {
    407     DCHECK_EQ(reported_errors_end_, reported_errors_->length());
    408     reported_errors_->Add(e, zone_);
    409     reported_errors_end_++;
    410   }
    411 
    412   // Copies the error at position i of the list of reported errors, so that
    413   // it becomes the last error reported for this classifier.  Position i
    414   // could be either after the existing errors of this classifier (i.e.,
    415   // in an inner classifier) or it could be an existing error (in case a
    416   // copy is needed).
    417   V8_INLINE void Copy(int i) {
    418     DCHECK_LT(i, reported_errors_->length());
    419     if (reported_errors_end_ != i)
    420       reported_errors_->at(reported_errors_end_) = reported_errors_->at(i);
    421     reported_errors_end_++;
    422   }
    423 
    424   typename Types::Base* base_;
    425   ExpressionClassifier* previous_;
    426   Zone* zone_;
    427   ZoneList<typename Types::Expression>* non_patterns_to_rewrite_;
    428   ZoneList<Error>* reported_errors_;
    429   DuplicateFinder* duplicate_finder_;
    430   // The uint16_t for non_pattern_begin_ will not be enough in the case,
    431   // e.g., of an array literal containing more than 64K inner array
    432   // literals with spreads, as in:
    433   // var N=65536; eval("var x=[];" + "[" + "[...x],".repeat(N) + "].length");
    434   // An implementation limit error in ParserBase::AddNonPatternForRewriting
    435   // will be triggered in this case.
    436   uint16_t non_pattern_begin_;
    437   unsigned invalid_productions_ : 14;
    438   unsigned function_properties_ : 2;
    439   // The uint16_t for reported_errors_begin_ and reported_errors_end_ will
    440   // not be enough in the case of a long series of expressions using nested
    441   // classifiers, e.g., a long sequence of assignments, as in:
    442   // literals with spreads, as in:
    443   // var N=65536; eval("var x;" + "x=".repeat(N) + "42");
    444   // This should not be a problem, as such things currently fail with a
    445   // stack overflow while parsing.
    446   uint16_t reported_errors_begin_;
    447   uint16_t reported_errors_end_;
    448 
    449   DISALLOW_COPY_AND_ASSIGN(ExpressionClassifier);
    450 };
    451 
    452 
    453 #undef ERROR_CODES
    454 
    455 
    456 }  // namespace internal
    457 }  // namespace v8
    458 
    459 #endif  // V8_PARSING_EXPRESSION_CLASSIFIER_H
    460