mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-06 10:54:49 +01:00
Expand use of IndexBase (#2436)
Initially I'd added this to lexer, this includes parser and semantics. Also adds ComparableIndexBase to unify a few common cases where <> comparisons are supported. Co-authored-by: Richard Smith <richard@metafoo.co.uk>
This commit is contained in:
co-authored by
Richard Smith
parent
94cf343b05
commit
d50fef1736
@@ -40,8 +40,8 @@ auto ParseTree::postorder(Node n) const
|
||||
CARBON_CHECK(n.is_valid());
|
||||
// The postorder ends after this node, the root, and begins at the start of
|
||||
// its subtree.
|
||||
int end_index = n.index_ + 1;
|
||||
int start_index = end_index - node_impls_[n.index_].subtree_size;
|
||||
int end_index = n.index + 1;
|
||||
int start_index = end_index - node_impls_[n.index].subtree_size;
|
||||
return {PostorderIterator(Node(start_index)),
|
||||
PostorderIterator(Node(end_index))};
|
||||
}
|
||||
@@ -49,8 +49,8 @@ auto ParseTree::postorder(Node n) const
|
||||
auto ParseTree::children(Node n) const
|
||||
-> llvm::iterator_range<SiblingIterator> {
|
||||
CARBON_CHECK(n.is_valid());
|
||||
int end_index = n.index_ - node_impls_[n.index_].subtree_size;
|
||||
return {SiblingIterator(*this, Node(n.index_ - 1)),
|
||||
int end_index = n.index - node_impls_[n.index].subtree_size;
|
||||
return {SiblingIterator(*this, Node(n.index - 1)),
|
||||
SiblingIterator(*this, Node(end_index))};
|
||||
}
|
||||
|
||||
@@ -62,38 +62,38 @@ auto ParseTree::roots() const -> llvm::iterator_range<SiblingIterator> {
|
||||
|
||||
auto ParseTree::node_has_error(Node n) const -> bool {
|
||||
CARBON_CHECK(n.is_valid());
|
||||
return node_impls_[n.index_].has_error;
|
||||
return node_impls_[n.index].has_error;
|
||||
}
|
||||
|
||||
auto ParseTree::node_kind(Node n) const -> ParseNodeKind {
|
||||
CARBON_CHECK(n.is_valid());
|
||||
return node_impls_[n.index_].kind;
|
||||
return node_impls_[n.index].kind;
|
||||
}
|
||||
|
||||
auto ParseTree::node_token(Node n) const -> TokenizedBuffer::Token {
|
||||
CARBON_CHECK(n.is_valid());
|
||||
return node_impls_[n.index_].token;
|
||||
return node_impls_[n.index].token;
|
||||
}
|
||||
|
||||
auto ParseTree::node_subtree_size(Node n) const -> int32_t {
|
||||
CARBON_CHECK(n.is_valid());
|
||||
return node_impls_[n.index_].subtree_size;
|
||||
return node_impls_[n.index].subtree_size;
|
||||
}
|
||||
|
||||
auto ParseTree::GetNodeText(Node n) const -> llvm::StringRef {
|
||||
CARBON_CHECK(n.is_valid());
|
||||
return tokens_->GetTokenText(node_impls_[n.index_].token);
|
||||
return tokens_->GetTokenText(node_impls_[n.index].token);
|
||||
}
|
||||
|
||||
auto ParseTree::PrintNode(llvm::raw_ostream& output, Node n, int depth,
|
||||
bool preorder) const -> bool {
|
||||
const auto& n_impl = node_impls_[n.index()];
|
||||
const auto& n_impl = node_impls_[n.index];
|
||||
output.indent(2 * depth);
|
||||
output << "{";
|
||||
// If children are being added, include node_index in order to disambiguate
|
||||
// nodes.
|
||||
if (preorder) {
|
||||
output << "node_index: " << n.index_ << ", ";
|
||||
output << "node_index: " << n << ", ";
|
||||
}
|
||||
output << "kind: '" << n_impl.kind.name() << "', text: '"
|
||||
<< tokens_->GetTokenText(n_impl.token) << "'";
|
||||
@@ -128,14 +128,14 @@ auto ParseTree::Print(llvm::raw_ostream& output) const -> void {
|
||||
int depth;
|
||||
std::tie(n, depth) = node_stack.pop_back_val();
|
||||
for (Node sibling_n : children(n)) {
|
||||
indents[sibling_n.index()] = depth + 1;
|
||||
indents[sibling_n.index] = depth + 1;
|
||||
node_stack.push_back({sibling_n, depth + 1});
|
||||
}
|
||||
}
|
||||
|
||||
output << "[\n";
|
||||
for (Node n : postorder()) {
|
||||
PrintNode(output, n, indents[n.index()], /*adding_children=*/false);
|
||||
PrintNode(output, n, indents[n.index], /*adding_children=*/false);
|
||||
output << ",\n";
|
||||
}
|
||||
output << "]\n";
|
||||
@@ -192,12 +192,12 @@ auto ParseTree::Verify() const -> std::optional<Error> {
|
||||
llvm::SmallVector<ParseTree::Node> nodes;
|
||||
// Traverse the tree in postorder.
|
||||
for (Node n : postorder()) {
|
||||
const auto& n_impl = node_impls_[n.index()];
|
||||
const auto& n_impl = node_impls_[n.index];
|
||||
|
||||
if (n_impl.has_error && !has_errors_) {
|
||||
return Error(llvm::formatv(
|
||||
"Node #{0} has errors, but the tree is not marked as having any.",
|
||||
n.index()));
|
||||
n.index));
|
||||
}
|
||||
|
||||
int subtree_size = 1;
|
||||
@@ -207,9 +207,9 @@ auto ParseTree::Verify() const -> std::optional<Error> {
|
||||
return Error(
|
||||
llvm::formatv("Node #{0} is a {1} with bracket {2}, but didn't "
|
||||
"find the bracket.",
|
||||
n.index(), n_impl.kind, n_impl.kind.bracket()));
|
||||
n, n_impl.kind, n_impl.kind.bracket()));
|
||||
}
|
||||
auto child_impl = node_impls_[nodes.pop_back_val().index()];
|
||||
auto child_impl = node_impls_[nodes.pop_back_val().index];
|
||||
subtree_size += child_impl.subtree_size;
|
||||
if (n_impl.kind.bracket() == child_impl.kind) {
|
||||
break;
|
||||
@@ -221,35 +221,35 @@ auto ParseTree::Verify() const -> std::optional<Error> {
|
||||
return Error(llvm::formatv(
|
||||
"Node #{0} is a {1} with child_count {2}, but only had {3} "
|
||||
"nodes to consume.",
|
||||
n.index(), n_impl.kind, n_impl.kind.child_count(), i));
|
||||
n, n_impl.kind, n_impl.kind.child_count(), i));
|
||||
}
|
||||
auto child_impl = node_impls_[nodes.pop_back_val().index()];
|
||||
auto child_impl = node_impls_[nodes.pop_back_val().index];
|
||||
subtree_size += child_impl.subtree_size;
|
||||
}
|
||||
}
|
||||
if (n_impl.subtree_size != subtree_size) {
|
||||
return Error(llvm::formatv(
|
||||
"Node #{0} is a {1} with subtree_size of {2}, but calculated {3}.",
|
||||
n.index(), n_impl.kind, n_impl.subtree_size, subtree_size));
|
||||
"Node #{0} is a {1} with subtree_size of {2}, but calculated {3}.", n,
|
||||
n_impl.kind, n_impl.subtree_size, subtree_size));
|
||||
}
|
||||
nodes.push_back(n);
|
||||
}
|
||||
|
||||
// Remaining nodes should all be roots in the tree; make sure they line up.
|
||||
CARBON_CHECK(nodes.back().index() ==
|
||||
CARBON_CHECK(nodes.back().index ==
|
||||
static_cast<int32_t>(node_impls_.size()) - 1)
|
||||
<< nodes.back().index() << " " << node_impls_.size() - 1;
|
||||
<< nodes.back() << " " << node_impls_.size() - 1;
|
||||
int prev_index = -1;
|
||||
for (const auto& n : nodes) {
|
||||
const auto& n_impl = node_impls_[n.index()];
|
||||
const auto& n_impl = node_impls_[n.index];
|
||||
|
||||
if (n.index() - n_impl.subtree_size != prev_index) {
|
||||
return Error(llvm::formatv(
|
||||
"Node #{0} is a root {1} with subtree_size {2}, but "
|
||||
"previous root was at #{3}.",
|
||||
n.index(), n_impl.kind, n_impl.subtree_size, prev_index));
|
||||
if (n.index - n_impl.subtree_size != prev_index) {
|
||||
return Error(
|
||||
llvm::formatv("Node #{0} is a root {1} with subtree_size {2}, but "
|
||||
"previous root was at #{3}.",
|
||||
n, n_impl.kind, n_impl.subtree_size, prev_index));
|
||||
}
|
||||
prev_index = n.index();
|
||||
prev_index = n.index;
|
||||
}
|
||||
|
||||
if (!has_errors_ &&
|
||||
@@ -262,18 +262,14 @@ auto ParseTree::Verify() const -> std::optional<Error> {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto ParseTree::Node::Print(llvm::raw_ostream& output) const -> void {
|
||||
output << index();
|
||||
}
|
||||
|
||||
auto ParseTree::PostorderIterator::Print(llvm::raw_ostream& output) const
|
||||
-> void {
|
||||
output << node_.index();
|
||||
output << node_;
|
||||
}
|
||||
|
||||
auto ParseTree::SiblingIterator::Print(llvm::raw_ostream& output) const
|
||||
-> void {
|
||||
output << node_.index();
|
||||
output << node_;
|
||||
}
|
||||
|
||||
} // namespace Carbon
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace Carbon {
|
||||
// applied.
|
||||
class ParseTree {
|
||||
public:
|
||||
class Node;
|
||||
struct Node;
|
||||
class PostorderIterator;
|
||||
class SiblingIterator;
|
||||
|
||||
@@ -241,60 +241,8 @@ class ParseTree {
|
||||
//
|
||||
// That said, nodes can be compared and are part of a depth-first pre-order
|
||||
// sequence across all nodes in the parse tree.
|
||||
class ParseTree::Node {
|
||||
public:
|
||||
// Node handles are default constructable, but such a node cannot be used
|
||||
// for anything. It just allows it to be initialized later through
|
||||
// assignment. Any other operation on a default constructed node is an
|
||||
// error.
|
||||
Node() = default;
|
||||
|
||||
friend auto operator==(Node lhs, Node rhs) -> bool {
|
||||
return lhs.index_ == rhs.index_;
|
||||
}
|
||||
friend auto operator!=(Node lhs, Node rhs) -> bool {
|
||||
return lhs.index_ != rhs.index_;
|
||||
}
|
||||
friend auto operator<(Node lhs, Node rhs) -> bool {
|
||||
return lhs.index_ < rhs.index_;
|
||||
}
|
||||
friend auto operator<=(Node lhs, Node rhs) -> bool {
|
||||
return lhs.index_ <= rhs.index_;
|
||||
}
|
||||
friend auto operator>(Node lhs, Node rhs) -> bool {
|
||||
return lhs.index_ > rhs.index_;
|
||||
}
|
||||
friend auto operator>=(Node lhs, Node rhs) -> bool {
|
||||
return lhs.index_ >= rhs.index_;
|
||||
}
|
||||
|
||||
// Returns an opaque integer identifier of the node in the tree. Clients
|
||||
// should not expect any particular semantics from this value.
|
||||
//
|
||||
// TODO: Maybe we can switch to stream operator overloads?
|
||||
[[nodiscard]] auto index() const -> int { return index_; }
|
||||
|
||||
// Prints the node index.
|
||||
auto Print(llvm::raw_ostream& output) const -> void;
|
||||
|
||||
// Returns true if the node is valid; in other words, it was not default
|
||||
// initialized.
|
||||
auto is_valid() -> bool { return index_ != InvalidValue; }
|
||||
|
||||
private:
|
||||
friend ParseTree;
|
||||
friend PostorderIterator;
|
||||
friend SiblingIterator;
|
||||
|
||||
// Value for uninitialized nodes.
|
||||
static constexpr int InvalidValue = -1;
|
||||
|
||||
// Constructs a node with a specific index into the parse tree's postorder
|
||||
// sequence of node implementations.
|
||||
explicit Node(int index) : index_(index) {}
|
||||
|
||||
// The index of this node's implementation in the postorder sequence.
|
||||
int32_t index_ = InvalidValue;
|
||||
struct ParseTree::Node : public ComparableIndexBase {
|
||||
using ComparableIndexBase::ComparableIndexBase;
|
||||
};
|
||||
|
||||
// A random-access iterator to the depth-first postorder sequence of parse nodes
|
||||
@@ -320,15 +268,15 @@ class ParseTree::PostorderIterator
|
||||
auto operator*() const -> Node { return node_; }
|
||||
|
||||
auto operator-(const PostorderIterator& rhs) const -> int {
|
||||
return node_.index_ - rhs.node_.index_;
|
||||
return node_.index - rhs.node_.index;
|
||||
}
|
||||
|
||||
auto operator+=(int offset) -> PostorderIterator& {
|
||||
node_.index_ += offset;
|
||||
node_.index += offset;
|
||||
return *this;
|
||||
}
|
||||
auto operator-=(int offset) -> PostorderIterator& {
|
||||
node_.index_ -= offset;
|
||||
node_.index -= offset;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -373,7 +321,7 @@ class ParseTree::SiblingIterator
|
||||
|
||||
using iterator_facade_base::operator++;
|
||||
auto operator++() -> SiblingIterator& {
|
||||
node_.index_ -= std::abs(tree_->node_impls_[node_.index_].subtree_size);
|
||||
node_.index -= std::abs(tree_->node_impls_[node_.index].subtree_size);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user