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