1// Copyright 2017 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_AST_AST_SOURCE_RANGES_H_
6#define V8_AST_AST_SOURCE_RANGES_H_
7
8#include "src/ast/ast.h"
9#include "src/zone/zone-containers.h"
10
11namespace v8 {
12namespace internal {
13
14// Specifies a range within the source code. {start} is 0-based and inclusive,
15// {end} is 0-based and exclusive.
16struct SourceRange {
17  SourceRange() : SourceRange(kNoSourcePosition, kNoSourcePosition) {}
18  SourceRange(int start, int end) : start(start), end(end) {}
19  bool IsEmpty() const { return start == kNoSourcePosition; }
20  static SourceRange Empty() { return SourceRange(); }
21  static SourceRange OpenEnded(int32_t start) {
22    return SourceRange(start, kNoSourcePosition);
23  }
24  static SourceRange ContinuationOf(const SourceRange& that,
25                                    int end = kNoSourcePosition) {
26    return that.IsEmpty() ? Empty() : SourceRange(that.end, end);
27  }
28
29  static constexpr int kFunctionLiteralSourcePosition = -2;
30  STATIC_ASSERT(kFunctionLiteralSourcePosition == kNoSourcePosition - 1);
31
32  // Source ranges associated with a function literal do not contain real
33  // source positions; instead, they are created with special marker values.
34  // These are later recognized and rewritten during processing in
35  // Coverage::Collect().
36  static SourceRange FunctionLiteralMarkerRange() {
37    return {kFunctionLiteralSourcePosition, kFunctionLiteralSourcePosition};
38  }
39
40  int32_t start, end;
41};
42
43// The list of ast node kinds that have associated source ranges. Note that this
44// macro is not undefined at the end of this file.
45#define AST_SOURCE_RANGE_LIST(V) \
46  V(BinaryOperation)             \
47  V(Block)                       \
48  V(CaseClause)                  \
49  V(Conditional)                 \
50  V(Expression)                  \
51  V(FunctionLiteral)             \
52  V(IfStatement)                 \
53  V(IterationStatement)          \
54  V(JumpStatement)               \
55  V(NaryOperation)               \
56  V(Suspend)                     \
57  V(SwitchStatement)             \
58  V(Throw)                       \
59  V(TryCatchStatement)           \
60  V(TryFinallyStatement)
61
62enum class SourceRangeKind {
63  kBody,
64  kCatch,
65  kContinuation,
66  kElse,
67  kFinally,
68  kRight,
69  kThen,
70};
71
72class AstNodeSourceRanges : public ZoneObject {
73 public:
74  virtual ~AstNodeSourceRanges() = default;
75  virtual SourceRange GetRange(SourceRangeKind kind) = 0;
76  virtual bool HasRange(SourceRangeKind kind) = 0;
77  virtual void RemoveContinuationRange() { UNREACHABLE(); }
78};
79
80class BinaryOperationSourceRanges final : public AstNodeSourceRanges {
81 public:
82  explicit BinaryOperationSourceRanges(const SourceRange& right_range)
83      : right_range_(right_range) {}
84
85  SourceRange GetRange(SourceRangeKind kind) override {
86    DCHECK(HasRange(kind));
87    return right_range_;
88  }
89
90  bool HasRange(SourceRangeKind kind) override {
91    return kind == SourceRangeKind::kRight;
92  }
93
94 private:
95  SourceRange right_range_;
96};
97
98class ContinuationSourceRanges : public AstNodeSourceRanges {
99 public:
100  explicit ContinuationSourceRanges(int32_t continuation_position)
101      : continuation_position_(continuation_position) {}
102
103  SourceRange GetRange(SourceRangeKind kind) override {
104    DCHECK(HasRange(kind));
105    return SourceRange::OpenEnded(continuation_position_);
106  }
107
108  bool HasRange(SourceRangeKind kind) override {
109    return kind == SourceRangeKind::kContinuation;
110  }
111
112  void RemoveContinuationRange() override {
113    DCHECK(HasRange(SourceRangeKind::kContinuation));
114    continuation_position_ = kNoSourcePosition;
115  }
116
117 private:
118  int32_t continuation_position_;
119};
120
121class BlockSourceRanges final : public ContinuationSourceRanges {
122 public:
123  explicit BlockSourceRanges(int32_t continuation_position)
124      : ContinuationSourceRanges(continuation_position) {}
125};
126
127class CaseClauseSourceRanges final : public AstNodeSourceRanges {
128 public:
129  explicit CaseClauseSourceRanges(const SourceRange& body_range)
130      : body_range_(body_range) {}
131
132  SourceRange GetRange(SourceRangeKind kind) override {
133    DCHECK(HasRange(kind));
134    return body_range_;
135  }
136
137  bool HasRange(SourceRangeKind kind) override {
138    return kind == SourceRangeKind::kBody;
139  }
140
141 private:
142  SourceRange body_range_;
143};
144
145class ConditionalSourceRanges final : public AstNodeSourceRanges {
146 public:
147  explicit ConditionalSourceRanges(const SourceRange& then_range,
148                                   const SourceRange& else_range)
149      : then_range_(then_range), else_range_(else_range) {}
150
151  SourceRange GetRange(SourceRangeKind kind) override {
152    DCHECK(HasRange(kind));
153    switch (kind) {
154      case SourceRangeKind::kThen:
155        return then_range_;
156      case SourceRangeKind::kElse:
157        return else_range_;
158      default:
159        UNREACHABLE();
160    }
161  }
162
163  bool HasRange(SourceRangeKind kind) override {
164    return kind == SourceRangeKind::kThen || kind == SourceRangeKind::kElse;
165  }
166
167 private:
168  SourceRange then_range_;
169  SourceRange else_range_;
170};
171
172class FunctionLiteralSourceRanges final : public AstNodeSourceRanges {
173 public:
174  SourceRange GetRange(SourceRangeKind kind) override {
175    DCHECK(HasRange(kind));
176    return SourceRange::FunctionLiteralMarkerRange();
177  }
178
179  bool HasRange(SourceRangeKind kind) override {
180    return kind == SourceRangeKind::kBody;
181  }
182};
183
184class IfStatementSourceRanges final : public AstNodeSourceRanges {
185 public:
186  explicit IfStatementSourceRanges(const SourceRange& then_range,
187                                   const SourceRange& else_range)
188      : then_range_(then_range), else_range_(else_range) {}
189
190  SourceRange GetRange(SourceRangeKind kind) override {
191    DCHECK(HasRange(kind));
192    switch (kind) {
193      case SourceRangeKind::kElse:
194        return else_range_;
195      case SourceRangeKind::kThen:
196        return then_range_;
197      case SourceRangeKind::kContinuation: {
198        if (!has_continuation_) return SourceRange::Empty();
199        const SourceRange& trailing_range =
200            else_range_.IsEmpty() ? then_range_ : else_range_;
201        return SourceRange::ContinuationOf(trailing_range);
202      }
203      default:
204        UNREACHABLE();
205    }
206  }
207
208  bool HasRange(SourceRangeKind kind) override {
209    return kind == SourceRangeKind::kThen || kind == SourceRangeKind::kElse ||
210           kind == SourceRangeKind::kContinuation;
211  }
212
213  void RemoveContinuationRange() override {
214    DCHECK(HasRange(SourceRangeKind::kContinuation));
215    has_continuation_ = false;
216  }
217
218 private:
219  SourceRange then_range_;
220  SourceRange else_range_;
221  bool has_continuation_ = true;
222};
223
224class IterationStatementSourceRanges final : public AstNodeSourceRanges {
225 public:
226  explicit IterationStatementSourceRanges(const SourceRange& body_range)
227      : body_range_(body_range) {}
228
229  SourceRange GetRange(SourceRangeKind kind) override {
230    DCHECK(HasRange(kind));
231    switch (kind) {
232      case SourceRangeKind::kBody:
233        return body_range_;
234      case SourceRangeKind::kContinuation:
235        if (!has_continuation_) return SourceRange::Empty();
236        return SourceRange::ContinuationOf(body_range_);
237      default:
238        UNREACHABLE();
239    }
240  }
241
242  bool HasRange(SourceRangeKind kind) override {
243    return kind == SourceRangeKind::kBody ||
244           kind == SourceRangeKind::kContinuation;
245  }
246
247  void RemoveContinuationRange() override {
248    DCHECK(HasRange(SourceRangeKind::kContinuation));
249    has_continuation_ = false;
250  }
251
252 private:
253  SourceRange body_range_;
254  bool has_continuation_ = true;
255};
256
257class JumpStatementSourceRanges final : public ContinuationSourceRanges {
258 public:
259  explicit JumpStatementSourceRanges(int32_t continuation_position)
260      : ContinuationSourceRanges(continuation_position) {}
261};
262
263class NaryOperationSourceRanges final : public AstNodeSourceRanges {
264 public:
265  NaryOperationSourceRanges(Zone* zone, const SourceRange& range)
266      : ranges_(zone) {
267    AddRange(range);
268  }
269
270  SourceRange GetRangeAtIndex(size_t index) {
271    DCHECK(index < ranges_.size());
272    return ranges_[index];
273  }
274
275  void AddRange(const SourceRange& range) { ranges_.push_back(range); }
276  size_t RangeCount() const { return ranges_.size(); }
277
278  SourceRange GetRange(SourceRangeKind kind) override { UNREACHABLE(); }
279  bool HasRange(SourceRangeKind kind) override { return false; }
280
281 private:
282  ZoneVector<SourceRange> ranges_;
283};
284
285class ExpressionSourceRanges final : public AstNodeSourceRanges {
286 public:
287  explicit ExpressionSourceRanges(const SourceRange& right_range)
288      : right_range_(right_range) {}
289
290  SourceRange GetRange(SourceRangeKind kind) override {
291    DCHECK(HasRange(kind));
292    return right_range_;
293  }
294
295  bool HasRange(SourceRangeKind kind) override {
296    return kind == SourceRangeKind::kRight;
297  }
298
299 private:
300  SourceRange right_range_;
301};
302
303class SuspendSourceRanges final : public ContinuationSourceRanges {
304 public:
305  explicit SuspendSourceRanges(int32_t continuation_position)
306      : ContinuationSourceRanges(continuation_position) {}
307};
308
309class SwitchStatementSourceRanges final : public ContinuationSourceRanges {
310 public:
311  explicit SwitchStatementSourceRanges(int32_t continuation_position)
312      : ContinuationSourceRanges(continuation_position) {}
313};
314
315class ThrowSourceRanges final : public ContinuationSourceRanges {
316 public:
317  explicit ThrowSourceRanges(int32_t continuation_position)
318      : ContinuationSourceRanges(continuation_position) {}
319};
320
321class TryCatchStatementSourceRanges final : public AstNodeSourceRanges {
322 public:
323  explicit TryCatchStatementSourceRanges(const SourceRange& catch_range)
324      : catch_range_(catch_range) {}
325
326  SourceRange GetRange(SourceRangeKind kind) override {
327    DCHECK(HasRange(kind));
328    switch (kind) {
329      case SourceRangeKind::kCatch:
330        return catch_range_;
331      case SourceRangeKind::kContinuation:
332        if (!has_continuation_) return SourceRange::Empty();
333        return SourceRange::ContinuationOf(catch_range_);
334      default:
335        UNREACHABLE();
336    }
337  }
338
339  bool HasRange(SourceRangeKind kind) override {
340    return kind == SourceRangeKind::kCatch ||
341           kind == SourceRangeKind::kContinuation;
342  }
343
344  void RemoveContinuationRange() override {
345    DCHECK(HasRange(SourceRangeKind::kContinuation));
346    has_continuation_ = false;
347  }
348
349 private:
350  SourceRange catch_range_;
351  bool has_continuation_ = true;
352};
353
354class TryFinallyStatementSourceRanges final : public AstNodeSourceRanges {
355 public:
356  explicit TryFinallyStatementSourceRanges(const SourceRange& finally_range)
357      : finally_range_(finally_range) {}
358
359  SourceRange GetRange(SourceRangeKind kind) override {
360    DCHECK(HasRange(kind));
361    switch (kind) {
362      case SourceRangeKind::kFinally:
363        return finally_range_;
364      case SourceRangeKind::kContinuation:
365        if (!has_continuation_) return SourceRange::Empty();
366        return SourceRange::ContinuationOf(finally_range_);
367      default:
368        UNREACHABLE();
369    }
370  }
371
372  bool HasRange(SourceRangeKind kind) override {
373    return kind == SourceRangeKind::kFinally ||
374           kind == SourceRangeKind::kContinuation;
375  }
376
377  void RemoveContinuationRange() override {
378    DCHECK(HasRange(SourceRangeKind::kContinuation));
379    has_continuation_ = false;
380  }
381
382 private:
383  SourceRange finally_range_;
384  bool has_continuation_ = true;
385};
386
387// Maps ast node pointers to associated source ranges. The parser creates these
388// mappings and the bytecode generator consumes them.
389class SourceRangeMap final : public ZoneObject {
390 public:
391  explicit SourceRangeMap(Zone* zone) : map_(zone) {}
392
393  AstNodeSourceRanges* Find(ZoneObject* node) {
394    auto it = map_.find(node);
395    if (it == map_.end()) return nullptr;
396    return it->second;
397  }
398
399// Type-checked insertion.
400#define DEFINE_MAP_INSERT(type)                         \
401  void Insert(type* node, type##SourceRanges* ranges) { \
402    DCHECK_NOT_NULL(node);                              \
403    map_.emplace(node, ranges);                         \
404  }
405  AST_SOURCE_RANGE_LIST(DEFINE_MAP_INSERT)
406#undef DEFINE_MAP_INSERT
407
408 private:
409  ZoneMap<ZoneObject*, AstNodeSourceRanges*> map_;
410};
411
412}  // namespace internal
413}  // namespace v8
414
415#endif  // V8_AST_AST_SOURCE_RANGES_H_
416