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