blob: b29f4cf07da5dc57884a340c25e7566050690284 [file] [log] [blame]
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_AST_AST_SOURCE_RANGES_H_
#define V8_AST_AST_SOURCE_RANGES_H_
#include "src/ast/ast.h"
#include "src/zone/zone-containers.h"
namespace v8 {
namespace internal {
// Specifies a range within the source code. {start} is 0-based and inclusive,
// {end} is 0-based and exclusive.
struct SourceRange {
SourceRange() : SourceRange(kNoSourcePosition, kNoSourcePosition) {}
SourceRange(int start, int end) : start(start), end(end) {}
bool IsEmpty() const { return start == kNoSourcePosition; }
static SourceRange Empty() { return SourceRange(); }
static SourceRange OpenEnded(int32_t start) {
return SourceRange(start, kNoSourcePosition);
}
static SourceRange ContinuationOf(const SourceRange& that,
int end = kNoSourcePosition) {
return that.IsEmpty() ? Empty() : SourceRange(that.end, end);
}
static constexpr int kFunctionLiteralSourcePosition = -2;
static_assert(kFunctionLiteralSourcePosition == kNoSourcePosition - 1);
// Source ranges associated with a function literal do not contain real
// source positions; instead, they are created with special marker values.
// These are later recognized and rewritten during processing in
// Coverage::Collect().
static SourceRange FunctionLiteralMarkerRange() {
return {kFunctionLiteralSourcePosition, kFunctionLiteralSourcePosition};
}
int32_t start, end;
};
// The list of ast node kinds that have associated source ranges. Note that this
// macro is not undefined at the end of this file.
#define AST_SOURCE_RANGE_LIST(V) \
V(BinaryOperation) \
V(Block) \
V(CaseClause) \
V(ConditionalChain) \
V(Conditional) \
V(Expression) \
V(FunctionLiteral) \
V(IfStatement) \
V(IterationStatement) \
V(JumpStatement) \
V(NaryOperation) \
V(Suspend) \
V(SwitchStatement) \
V(Throw) \
V(TryCatchStatement) \
V(TryFinallyStatement)
enum class SourceRangeKind {
kBody,
kCatch,
kContinuation,
kElse,
kFinally,
kRight,
kThen,
};
class AstNodeSourceRanges : public ZoneObject {
public:
virtual ~AstNodeSourceRanges() = default;
virtual SourceRange GetRange(SourceRangeKind kind) = 0;
virtual bool HasRange(SourceRangeKind kind) = 0;
virtual void RemoveContinuationRange() { UNREACHABLE(); }
};
class BinaryOperationSourceRanges final : public AstNodeSourceRanges {
public:
explicit BinaryOperationSourceRanges(const SourceRange& right_range)
: right_range_(right_range) {}
SourceRange GetRange(SourceRangeKind kind) override {
DCHECK(HasRange(kind));
return right_range_;
}
bool HasRange(SourceRangeKind kind) override {
return kind == SourceRangeKind::kRight;
}
private:
SourceRange right_range_;
};
class ContinuationSourceRanges : public AstNodeSourceRanges {
public:
explicit ContinuationSourceRanges(int32_t continuation_position)
: continuation_position_(continuation_position) {}
SourceRange GetRange(SourceRangeKind kind) override {
DCHECK(HasRange(kind));
return SourceRange::OpenEnded(continuation_position_);
}
bool HasRange(SourceRangeKind kind) override {
return kind == SourceRangeKind::kContinuation;
}
void RemoveContinuationRange() override {
DCHECK(HasRange(SourceRangeKind::kContinuation));
continuation_position_ = kNoSourcePosition;
}
private:
int32_t continuation_position_;
};
class BlockSourceRanges final : public ContinuationSourceRanges {
public:
explicit BlockSourceRanges(int32_t continuation_position)
: ContinuationSourceRanges(continuation_position) {}
};
class CaseClauseSourceRanges final : public AstNodeSourceRanges {
public:
explicit CaseClauseSourceRanges(const SourceRange& body_range)
: body_range_(body_range) {}
SourceRange GetRange(SourceRangeKind kind) override {
DCHECK(HasRange(kind));
return body_range_;
}
bool HasRange(SourceRangeKind kind) override {
return kind == SourceRangeKind::kBody;
}
private:
SourceRange body_range_;
};
class ConditionalChainSourceRanges final : public AstNodeSourceRanges {
public:
explicit ConditionalChainSourceRanges(Zone* zone)
: then_ranges_(zone), else_ranges_(zone) {}
SourceRange GetRangeAtIndex(SourceRangeKind kind, size_t index) {
if (kind == SourceRangeKind::kThen) {
DCHECK_LT(index, then_ranges_.size());
return then_ranges_[index];
}
DCHECK_EQ(kind, SourceRangeKind::kElse);
DCHECK_LT(index, else_ranges_.size());
return else_ranges_[index];
}
void AddThenRanges(const SourceRange& range) {
then_ranges_.push_back(range);
}
void AddElseRange(const SourceRange& else_range) {
else_ranges_.push_back(else_range);
}
size_t RangeCount() const { return then_ranges_.size(); }
SourceRange GetRange(SourceRangeKind kind) override { UNREACHABLE(); }
bool HasRange(SourceRangeKind kind) override { return false; }
private:
ZoneVector<SourceRange> then_ranges_;
ZoneVector<SourceRange> else_ranges_;
};
class ConditionalSourceRanges final : public AstNodeSourceRanges {
public:
explicit ConditionalSourceRanges(const SourceRange& then_range,
const SourceRange& else_range)
: then_range_(then_range), else_range_(else_range) {}
SourceRange GetRange(SourceRangeKind kind) override {
DCHECK(HasRange(kind));
switch (kind) {
case SourceRangeKind::kThen:
return then_range_;
case SourceRangeKind::kElse:
return else_range_;
default:
UNREACHABLE();
}
}
bool HasRange(SourceRangeKind kind) override {
return kind == SourceRangeKind::kThen || kind == SourceRangeKind::kElse;
}
private:
SourceRange then_range_;
SourceRange else_range_;
};
class FunctionLiteralSourceRanges final : public AstNodeSourceRanges {
public:
SourceRange GetRange(SourceRangeKind kind) override {
DCHECK(HasRange(kind));
return SourceRange::FunctionLiteralMarkerRange();
}
bool HasRange(SourceRangeKind kind) override {
return kind == SourceRangeKind::kBody;
}
};
class IfStatementSourceRanges final : public AstNodeSourceRanges {
public:
explicit IfStatementSourceRanges(const SourceRange& then_range,
const SourceRange& else_range)
: then_range_(then_range), else_range_(else_range) {}
SourceRange GetRange(SourceRangeKind kind) override {
DCHECK(HasRange(kind));
switch (kind) {
case SourceRangeKind::kElse:
return else_range_;
case SourceRangeKind::kThen:
return then_range_;
case SourceRangeKind::kContinuation: {
if (!has_continuation_) return SourceRange::Empty();
const SourceRange& trailing_range =
else_range_.IsEmpty() ? then_range_ : else_range_;
return SourceRange::ContinuationOf(trailing_range);
}
default:
UNREACHABLE();
}
}
bool HasRange(SourceRangeKind kind) override {
return kind == SourceRangeKind::kThen || kind == SourceRangeKind::kElse ||
kind == SourceRangeKind::kContinuation;
}
void RemoveContinuationRange() override {
DCHECK(HasRange(SourceRangeKind::kContinuation));
has_continuation_ = false;
}
private:
SourceRange then_range_;
SourceRange else_range_;
bool has_continuation_ = true;
};
class IterationStatementSourceRanges final : public AstNodeSourceRanges {
public:
explicit IterationStatementSourceRanges(const SourceRange& body_range)
: body_range_(body_range) {}
SourceRange GetRange(SourceRangeKind kind) override {
DCHECK(HasRange(kind));
switch (kind) {
case SourceRangeKind::kBody:
return body_range_;
case SourceRangeKind::kContinuation:
if (!has_continuation_) return SourceRange::Empty();
return SourceRange::ContinuationOf(body_range_);
default:
UNREACHABLE();
}
}
bool HasRange(SourceRangeKind kind) override {
return kind == SourceRangeKind::kBody ||
kind == SourceRangeKind::kContinuation;
}
void RemoveContinuationRange() override {
DCHECK(HasRange(SourceRangeKind::kContinuation));
has_continuation_ = false;
}
private:
SourceRange body_range_;
bool has_continuation_ = true;
};
class JumpStatementSourceRanges final : public ContinuationSourceRanges {
public:
explicit JumpStatementSourceRanges(int32_t continuation_position)
: ContinuationSourceRanges(continuation_position) {}
};
class NaryOperationSourceRanges final : public AstNodeSourceRanges {
public:
NaryOperationSourceRanges(Zone* zone, const SourceRange& range)
: ranges_(zone) {
AddRange(range);
}
SourceRange GetRangeAtIndex(size_t index) {
DCHECK(index < ranges_.size());
return ranges_[index];
}
void AddRange(const SourceRange& range) { ranges_.push_back(range); }
size_t RangeCount() const { return ranges_.size(); }
SourceRange GetRange(SourceRangeKind kind) override { UNREACHABLE(); }
bool HasRange(SourceRangeKind kind) override { return false; }
private:
ZoneVector<SourceRange> ranges_;
};
class ExpressionSourceRanges final : public AstNodeSourceRanges {
public:
explicit ExpressionSourceRanges(const SourceRange& right_range)
: right_range_(right_range) {}
SourceRange GetRange(SourceRangeKind kind) override {
DCHECK(HasRange(kind));
return right_range_;
}
bool HasRange(SourceRangeKind kind) override {
return kind == SourceRangeKind::kRight;
}
private:
SourceRange right_range_;
};
class SuspendSourceRanges final : public ContinuationSourceRanges {
public:
explicit SuspendSourceRanges(int32_t continuation_position)
: ContinuationSourceRanges(continuation_position) {}
};
class SwitchStatementSourceRanges final : public ContinuationSourceRanges {
public:
explicit SwitchStatementSourceRanges(int32_t continuation_position)
: ContinuationSourceRanges(continuation_position) {}
};
class ThrowSourceRanges final : public ContinuationSourceRanges {
public:
explicit ThrowSourceRanges(int32_t continuation_position)
: ContinuationSourceRanges(continuation_position) {}
};
class TryCatchStatementSourceRanges final : public AstNodeSourceRanges {
public:
explicit TryCatchStatementSourceRanges(const SourceRange& catch_range)
: catch_range_(catch_range) {}
SourceRange GetRange(SourceRangeKind kind) override {
DCHECK(HasRange(kind));
switch (kind) {
case SourceRangeKind::kCatch:
return catch_range_;
case SourceRangeKind::kContinuation:
if (!has_continuation_) return SourceRange::Empty();
return SourceRange::ContinuationOf(catch_range_);
default:
UNREACHABLE();
}
}
bool HasRange(SourceRangeKind kind) override {
return kind == SourceRangeKind::kCatch ||
kind == SourceRangeKind::kContinuation;
}
void RemoveContinuationRange() override {
DCHECK(HasRange(SourceRangeKind::kContinuation));
has_continuation_ = false;
}
private:
SourceRange catch_range_;
bool has_continuation_ = true;
};
class TryFinallyStatementSourceRanges final : public AstNodeSourceRanges {
public:
explicit TryFinallyStatementSourceRanges(const SourceRange& finally_range)
: finally_range_(finally_range) {}
SourceRange GetRange(SourceRangeKind kind) override {
DCHECK(HasRange(kind));
switch (kind) {
case SourceRangeKind::kFinally:
return finally_range_;
case SourceRangeKind::kContinuation:
if (!has_continuation_) return SourceRange::Empty();
return SourceRange::ContinuationOf(finally_range_);
default:
UNREACHABLE();
}
}
bool HasRange(SourceRangeKind kind) override {
return kind == SourceRangeKind::kFinally ||
kind == SourceRangeKind::kContinuation;
}
void RemoveContinuationRange() override {
DCHECK(HasRange(SourceRangeKind::kContinuation));
has_continuation_ = false;
}
private:
SourceRange finally_range_;
bool has_continuation_ = true;
};
// Maps ast node pointers to associated source ranges. The parser creates these
// mappings and the bytecode generator consumes them.
class SourceRangeMap final : public ZoneObject {
public:
explicit SourceRangeMap(Zone* zone) : map_(zone) {}
AstNodeSourceRanges* Find(ZoneObject* node) {
auto it = map_.find(node);
if (it == map_.end()) return nullptr;
return it->second;
}
// Type-checked insertion.
#define DEFINE_MAP_INSERT(type) \
void Insert(type* node, type##SourceRanges* ranges) { \
DCHECK_NOT_NULL(node); \
map_.emplace(node, ranges); \
}
AST_SOURCE_RANGE_LIST(DEFINE_MAP_INSERT)
#undef DEFINE_MAP_INSERT
private:
ZoneMap<ZoneObject*, AstNodeSourceRanges*> map_;
};
} // namespace internal
} // namespace v8
#endif // V8_AST_AST_SOURCE_RANGES_H_