V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
expression-classifier.h
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 <type_traits>
9 
10 #include "src/message-template.h"
11 #include "src/parsing/scanner.h"
12 
13 namespace v8 {
14 namespace internal {
15 
16 template <typename T>
17 class ZoneList;
18 
19 #define ERROR_CODES(T) \
20  T(ExpressionProduction, 0) \
21  T(FormalParameterInitializerProduction, 1) \
22  T(PatternProduction, 2) \
23  T(BindingPatternProduction, 3) \
24  T(StrictModeFormalParametersProduction, 4) \
25  T(LetPatternProduction, 5) \
26  T(AsyncArrowFormalParametersProduction, 6)
27 
28 // Expression classifiers serve two purposes:
29 //
30 // 1) They keep track of error messages that are pending (and other
31 // related information), waiting for the parser to decide whether
32 // the parsed expression is a pattern or not.
33 // 2) They keep track of expressions that may need to be rewritten, if
34 // the parser decides that they are not patterns. (A different
35 // mechanism implements the rewriting of patterns.)
36 //
37 // Expression classifiers are used by the parser in a stack fashion.
38 // Each new classifier is pushed on top of the stack. This happens
39 // automatically by the class's constructor. While on top of the
40 // stack, the classifier records pending error messages and tracks the
41 // pending non-patterns of the expression that is being parsed.
42 //
43 // At the end of its life, a classifier is either "accumulated" to the
44 // one that is below it on the stack, or is "discarded". The former
45 // is achieved by calling the method Accumulate. The latter is
46 // achieved automatically by the destructor, but it can happen earlier
47 // by calling the method Discard. Both actions result in removing the
48 // classifier from the parser's stack.
49 
50 // Expression classifier is split into four parts. The base implementing the
51 // general expression classifier logic. Two parts that implement the error
52 // tracking interface, where one is the actual implementation and the other is
53 // an empty class providing only the interface without logic. The expression
54 // classifier class then combines the other parts and provides the full
55 // expression classifier interface by inheriting conditionally, controlled by
56 // Types::ExpressionClassifierReportErrors, either from the ErrorTracker or the
57 // EmptyErrorTracker.
58 //
59 // Base
60 // / \
61 // / \
62 // / \
63 // / \
64 // ErrorTracker EmptyErrorTracker
65 // \ /
66 // \ /
67 // \ /
68 // \ /
69 // ExpressionClassifier
70 
71 template <typename Types>
73 
74 template <typename Types, typename ErrorTracker>
76  public:
77  enum ErrorKind : unsigned {
78 #define DEFINE_ERROR_KIND(NAME, CODE) k##NAME = CODE,
79  ERROR_CODES(DEFINE_ERROR_KIND)
80 #undef DEFINE_ERROR_KIND
81  kUnusedError = 15 // Larger than error codes; should fit in 4 bits
82  };
83 
84  struct Error {
85  V8_INLINE Error()
86  : location(Scanner::Location::invalid()),
87  message_(static_cast<int>(MessageTemplate::kNone)),
88  kind(kUnusedError),
89  arg(nullptr) {}
90  V8_INLINE explicit Error(Scanner::Location loc, MessageTemplate msg,
91  ErrorKind k, const char* a = nullptr)
92  : location(loc), message_(static_cast<int>(msg)), kind(k), arg(a) {}
93 
94  Scanner::Location location;
95  // GCC doesn't like storing the enum class directly in 28 bits, so we
96  // have to wrap it in a getter.
97  MessageTemplate message() const {
98  STATIC_ASSERT(static_cast<int>(MessageTemplate::kLastMessage) <
99  (1 << 28));
100  return static_cast<MessageTemplate>(message_);
101  }
102  int message_ : 28;
103  unsigned kind : 4;
104  const char* arg;
105  };
106 
107  // clang-format off
108  enum TargetProduction : unsigned {
109 #define DEFINE_PRODUCTION(NAME, CODE) NAME = 1 << CODE,
110  ERROR_CODES(DEFINE_PRODUCTION)
111 #undef DEFINE_PRODUCTION
112 
113 #define DEFINE_ALL_PRODUCTIONS(NAME, CODE) NAME |
114  AllProductions = ERROR_CODES(DEFINE_ALL_PRODUCTIONS) /* | */ 0
115 #undef DEFINE_ALL_PRODUCTIONS
116  };
117  // clang-format on
118 
119  explicit ExpressionClassifierBase(typename Types::Base* base)
120  : base_(base),
121  invalid_productions_(0),
122  is_non_simple_parameter_list_(0) {}
123 
124  virtual ~ExpressionClassifierBase() = default;
125 
126  V8_INLINE bool is_valid(unsigned productions) const {
127  return (invalid_productions_ & productions) == 0;
128  }
129 
130  V8_INLINE bool is_valid_expression() const {
131  return is_valid(ExpressionProduction);
132  }
133 
134  V8_INLINE bool is_valid_formal_parameter_initializer() const {
135  return is_valid(FormalParameterInitializerProduction);
136  }
137 
138  V8_INLINE bool is_valid_pattern() const {
139  return is_valid(PatternProduction);
140  }
141 
142  V8_INLINE bool is_valid_binding_pattern() const {
143  return is_valid(BindingPatternProduction);
144  }
145 
146  // Note: callers should also check
147  // is_valid_formal_parameter_list_without_duplicates().
148  V8_INLINE bool is_valid_strict_mode_formal_parameters() const {
149  return is_valid(StrictModeFormalParametersProduction);
150  }
151 
152  V8_INLINE bool is_valid_let_pattern() const {
153  return is_valid(LetPatternProduction);
154  }
155 
156  bool is_valid_async_arrow_formal_parameters() const {
157  return is_valid(AsyncArrowFormalParametersProduction);
158  }
159 
160  V8_INLINE bool is_simple_parameter_list() const {
161  return !is_non_simple_parameter_list_;
162  }
163 
164  V8_INLINE void RecordNonSimpleParameter() {
165  is_non_simple_parameter_list_ = 1;
166  }
167 
168  V8_INLINE void Accumulate(ExpressionClassifier<Types>* const inner,
169  unsigned productions) {
170 #ifdef DEBUG
171  static_cast<ErrorTracker*>(this)->CheckErrorPositions(inner);
172 #endif
173  // Propagate errors from inner, but don't overwrite already recorded
174  // errors.
175  unsigned filter = productions & ~this->invalid_productions_;
176  unsigned errors = inner->invalid_productions_ & filter;
177  static_cast<ErrorTracker*>(this)->AccumulateErrorImpl(inner, productions,
178  errors);
179  this->invalid_productions_ |= errors;
180  }
181 
182  protected:
183  typename Types::Base* base_;
184  unsigned invalid_productions_ : kUnusedError;
185  STATIC_ASSERT(kUnusedError <= 15);
186  unsigned is_non_simple_parameter_list_ : 1;
187 };
188 
189 template <typename Types>
191  : public ExpressionClassifierBase<Types,
192  ExpressionClassifierErrorTracker<Types>> {
193  public:
194  using BaseClassType =
196  using typename BaseClassType::Error;
197  using typename BaseClassType::ErrorKind;
198  using TP = typename BaseClassType::TargetProduction;
199 
200  explicit ExpressionClassifierErrorTracker(typename Types::Base* base)
201  : BaseClassType(base),
202  reported_errors_(base->impl()->GetReportedErrorList()) {
203  reported_errors_begin_ = reported_errors_end_ = reported_errors_->length();
204  }
205 
207  if (reported_errors_end_ == reported_errors_->length()) {
208  reported_errors_->Rewind(reported_errors_begin_);
209  reported_errors_end_ = reported_errors_begin_;
210  }
211  DCHECK_EQ(reported_errors_begin_, reported_errors_end_);
212  }
213 
214  protected:
215  V8_INLINE const Error& reported_error(ErrorKind kind) const {
216  if (!this->is_valid(1 << kind)) {
217  for (int i = reported_errors_begin_; i < reported_errors_end_; i++) {
218  if (reported_errors_->at(i).kind == kind)
219  return reported_errors_->at(i);
220  }
221  UNREACHABLE();
222  }
223  // We should only be looking for an error when we know that one has
224  // been reported. But we're not... So this is to make sure we have
225  // the same behaviour.
226  UNREACHABLE();
227 
228  // Make MSVC happy by returning an error from this inaccessible path.
229  static Error none;
230  return none;
231  }
232 
233  // Adds e to the end of the list of reported errors for this classifier.
234  // It is expected that this classifier is the last one in the stack.
235  V8_INLINE void Add(TP production, const Error& e) {
236  if (!this->is_valid(production)) return;
237  this->invalid_productions_ |= production;
238  DCHECK_EQ(reported_errors_end_, reported_errors_->length());
239  reported_errors_->Add(e, this->base_->impl()->zone());
240  reported_errors_end_++;
241  }
242 
243  // Copies the error at position i of the list of reported errors, so that
244  // it becomes the last error reported for this classifier. Position i
245  // could be either after the existing errors of this classifier (i.e.,
246  // in an inner classifier) or it could be an existing error (in case a
247  // copy is needed).
248  V8_INLINE void Copy(int i) {
249  DCHECK_LT(i, reported_errors_->length());
250  if (reported_errors_end_ != i)
251  reported_errors_->at(reported_errors_end_) = reported_errors_->at(i);
252  reported_errors_end_++;
253  }
254 
255  private:
256 #ifdef DEBUG
257  V8_INLINE void CheckErrorPositions(ExpressionClassifier<Types>* const inner) {
258  DCHECK_EQ(inner->reported_errors_, this->reported_errors_);
259  DCHECK_EQ(inner->reported_errors_begin_, this->reported_errors_end_);
260  DCHECK_EQ(inner->reported_errors_end_, this->reported_errors_->length());
261  }
262 #endif
263 
264  V8_INLINE void RewindErrors(ExpressionClassifier<Types>* const inner) {
265  this->reported_errors_->Rewind(this->reported_errors_end_);
266  inner->reported_errors_begin_ = inner->reported_errors_end_ =
267  this->reported_errors_end_;
268  }
269 
270  void AccumulateErrorImpl(ExpressionClassifier<Types>* const inner,
271  unsigned productions, unsigned errors) {
272  // Traverse the list of errors reported by the inner classifier
273  // to copy what's necessary.
274  for (int i = inner->reported_errors_begin_; errors != 0; i++) {
275  int mask = 1 << this->reported_errors_->at(i).kind;
276  if ((errors & mask) != 0) {
277  errors ^= mask;
278  this->Copy(i);
279  }
280  }
281 
282  RewindErrors(inner);
283  }
284 
285  private:
286  ZoneList<Error>* reported_errors_;
287  // The uint16_t for reported_errors_begin_ and reported_errors_end_ will
288  // not be enough in the case of a long series of expressions using nested
289  // classifiers, e.g., a long sequence of assignments, as in:
290  // literals with spreads, as in:
291  // var N=65536; eval("var x;" + "x=".repeat(N) + "42");
292  // This should not be a problem, as such things currently fail with a
293  // stack overflow while parsing.
294  uint16_t reported_errors_begin_;
295  uint16_t reported_errors_end_;
296 
297  friend BaseClassType;
298 };
299 
300 template <typename Types>
302  : public ExpressionClassifierBase<
303  Types, ExpressionClassifierEmptyErrorTracker<Types>> {
304  public:
305  using BaseClassType =
308  using typename BaseClassType::Error;
309  using typename BaseClassType::ErrorKind;
310  using TP = typename BaseClassType::TargetProduction;
311 
312  explicit ExpressionClassifierEmptyErrorTracker(typename Types::Base* base)
313  : BaseClassType(base) {}
314 
315  protected:
316  V8_INLINE const Error& reported_error(ErrorKind kind) const {
317  static Error none;
318  return none;
319  }
320 
321  V8_INLINE void Add(TP production, const Error& e) {
322  this->invalid_productions_ |= production;
323  }
324 
325  private:
326 #ifdef DEBUG
327  V8_INLINE void CheckErrorPositions(ExpressionClassifier<Types>* const inner) {
328  }
329 #endif
330  V8_INLINE void AccumulateErrorImpl(ExpressionClassifier<Types>* const inner,
331  unsigned productions, unsigned errors) {}
332 
333  friend BaseClassType;
334 };
335 
336 template <typename Types>
338  : public std::conditional<
339  Types::ExpressionClassifierReportErrors,
340  ExpressionClassifierErrorTracker<Types>,
341  ExpressionClassifierEmptyErrorTracker<Types>>::type {
342  static constexpr bool ReportErrors = Types::ExpressionClassifierReportErrors;
343 
344  public:
345  using BaseClassType = typename std::conditional<
346  Types::ExpressionClassifierReportErrors,
349  type;
350  using typename BaseClassType::Error;
351  using typename BaseClassType::ErrorKind;
352  using TP = typename BaseClassType::TargetProduction;
353 
354  explicit ExpressionClassifier(typename Types::Base* base)
355  : std::conditional<
356  Types::ExpressionClassifierReportErrors,
359  previous_(base->classifier_) {
360  base->classifier_ = this;
361  }
362 
363  V8_INLINE ~ExpressionClassifier() override {
364  if (this->base_->classifier_ == this) this->base_->classifier_ = previous_;
365  }
366 
367  V8_INLINE const Error& expression_error() const {
368  return this->reported_error(ErrorKind::kExpressionProduction);
369  }
370 
371  V8_INLINE const Error& formal_parameter_initializer_error() const {
372  return this->reported_error(
373  ErrorKind::kFormalParameterInitializerProduction);
374  }
375 
376  V8_INLINE const Error& pattern_error() const {
377  return this->reported_error(ErrorKind::kPatternProduction);
378  }
379 
380  V8_INLINE const Error& binding_pattern_error() const {
381  return this->reported_error(ErrorKind::kBindingPatternProduction);
382  }
383 
384  V8_INLINE const Error& strict_mode_formal_parameter_error() const {
385  return this->reported_error(
386  ErrorKind::kStrictModeFormalParametersProduction);
387  }
388 
389  V8_INLINE const Error& let_pattern_error() const {
390  return this->reported_error(ErrorKind::kLetPatternProduction);
391  }
392 
393  V8_INLINE const Error& async_arrow_formal_parameters_error() const {
394  return this->reported_error(
395  ErrorKind::kAsyncArrowFormalParametersProduction);
396  }
397 
398  V8_INLINE bool does_error_reporting() { return ReportErrors; }
399 
400  void RecordExpressionError(const Scanner::Location& loc,
401  MessageTemplate message,
402  const char* arg = nullptr) {
403  this->Add(TP::ExpressionProduction,
404  Error(loc, message, ErrorKind::kExpressionProduction, arg));
405  }
406 
407  void RecordFormalParameterInitializerError(const Scanner::Location& loc,
408  MessageTemplate message,
409  const char* arg = nullptr) {
410  this->Add(TP::FormalParameterInitializerProduction,
411  Error(loc, message,
412  ErrorKind::kFormalParameterInitializerProduction, arg));
413  }
414 
415  void RecordPatternError(const Scanner::Location& loc, MessageTemplate message,
416  const char* arg = nullptr) {
417  this->Add(TP::PatternProduction,
418  Error(loc, message, ErrorKind::kPatternProduction, arg));
419  }
420 
421  void RecordBindingPatternError(const Scanner::Location& loc,
422  MessageTemplate message,
423  const char* arg = nullptr) {
424  this->Add(TP::BindingPatternProduction,
425  Error(loc, message, ErrorKind::kBindingPatternProduction, arg));
426  }
427 
428  void RecordAsyncArrowFormalParametersError(const Scanner::Location& loc,
429  MessageTemplate message,
430  const char* arg = nullptr) {
431  this->Add(TP::AsyncArrowFormalParametersProduction,
432  Error(loc, message,
433  ErrorKind::kAsyncArrowFormalParametersProduction, arg));
434  }
435 
436  // Record a binding that would be invalid in strict mode. Confusingly this
437  // is not the same as StrictFormalParameterList, which simply forbids
438  // duplicate bindings.
439  void RecordStrictModeFormalParameterError(const Scanner::Location& loc,
440  MessageTemplate message,
441  const char* arg = nullptr) {
442  this->Add(TP::StrictModeFormalParametersProduction,
443  Error(loc, message,
444  ErrorKind::kStrictModeFormalParametersProduction, arg));
445  }
446 
447  void RecordLetPatternError(const Scanner::Location& loc,
448  MessageTemplate message,
449  const char* arg = nullptr) {
450  this->Add(TP::LetPatternProduction,
451  Error(loc, message, ErrorKind::kLetPatternProduction, arg));
452  }
453 
454  ExpressionClassifier* previous() const { return previous_; }
455 
456  private:
457  ExpressionClassifier* previous_;
458 
459  DISALLOW_COPY_AND_ASSIGN(ExpressionClassifier);
460 };
461 
462 #undef ERROR_CODES
463 
464 } // namespace internal
465 } // namespace v8
466 
467 #endif // V8_PARSING_EXPRESSION_CLASSIFIER_H_
STL namespace.
Definition: libplatform.h:13