blob: cf7bab53daa6070d5d7bfb7412dd077a9c3fd207 [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) {
return that.IsEmpty() ? Empty() : OpenEnded(that.end);
}
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(Conditional) \
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() {}
virtual SourceRange GetRange(SourceRangeKind kind) = 0;
};
class BinaryOperationSourceRanges final : public AstNodeSourceRanges {
public:
explicit BinaryOperationSourceRanges(const SourceRange& right_range)
: right_range_(right_range) {}
SourceRange GetRange(SourceRangeKind kind) {
DCHECK_EQ(kind, SourceRangeKind::kRight);
return right_range_;
}
private:
SourceRange right_range_;
};
class ContinuationSourceRanges : public AstNodeSourceRanges {
public:
explicit ContinuationSourceRanges(int32_t continuation_position)
: continuation_position_(continuation_position) {}
SourceRange GetRange(SourceRangeKind kind) {
DCHECK_EQ(kind, SourceRangeKind::kContinuation);
return SourceRange::OpenEnded(continuation_position_);
}
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) {
DCHECK_EQ(kind, SourceRangeKind::kBody);
return body_range_;
}
private:
SourceRange body_range_;
};
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) {
switch (kind) {
case SourceRangeKind::kThen:
return then_range_;
case SourceRangeKind::kElse:
return else_range_;
default:
UNREACHABLE();
}
}
private:
SourceRange then_range_;
SourceRange else_range_;
};
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) {
switch (kind) {
case SourceRangeKind::kElse:
return else_range_;
case SourceRangeKind::kThen:
return then_range_;
case SourceRangeKind::kContinuation: {
const SourceRange& trailing_range =
else_range_.IsEmpty() ? then_range_ : else_range_;
return SourceRange::ContinuationOf(trailing_range);
}
default:
UNREACHABLE();
}
}
private:
SourceRange then_range_;
SourceRange else_range_;
};
class IterationStatementSourceRanges final : public AstNodeSourceRanges {
public:
explicit IterationStatementSourceRanges(const SourceRange& body_range)
: body_range_(body_range) {}
SourceRange GetRange(SourceRangeKind kind) {
switch (kind) {
case SourceRangeKind::kBody:
return body_range_;
case SourceRangeKind::kContinuation:
return SourceRange::ContinuationOf(body_range_);
default:
UNREACHABLE();
}
}
private:
SourceRange body_range_;
};
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) { UNREACHABLE(); }
private:
ZoneVector<SourceRange> ranges_;
};
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) {
switch (kind) {
case SourceRangeKind::kCatch:
return catch_range_;
case SourceRangeKind::kContinuation:
return SourceRange::ContinuationOf(catch_range_);
default:
UNREACHABLE();
}
}
private:
SourceRange catch_range_;
};
class TryFinallyStatementSourceRanges final : public AstNodeSourceRanges {
public:
explicit TryFinallyStatementSourceRanges(const SourceRange& finally_range)
: finally_range_(finally_range) {}
SourceRange GetRange(SourceRangeKind kind) {
switch (kind) {
case SourceRangeKind::kFinally:
return finally_range_;
case SourceRangeKind::kContinuation:
return SourceRange::ContinuationOf(finally_range_);
default:
UNREACHABLE();
}
}
private:
SourceRange finally_range_;
};
// 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_