Files
carbon-lang/toolchain/parse/tree.cpp
T
Dana Jansens 361efa90a8 Always call MemUsage::Collect to collect metrics from a field (#4480)
Previously Collect() was used for types that implemented
CollectMemUsage() but otherwise Add() was used. This required the caller
to think about the type of the field and know/decide which method to
use.

Now, the caller always uses Collect() unless they are adding specific
byte values, in which case Add is used. Typically then, Add will only be
used to implement the CollectMemUsage() function.

To do this we require all Collect() methods to be templates so that they
all be a single overload set. The Collect on BumpPtrAllocator is
converted to a template that checks
`std::same_as<llvm::BumpPtrAllocator, T>`.
2024-11-05 19:31:14 +00:00

90 lines
3.0 KiB
C++

// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include "toolchain/parse/tree.h"
#include "common/check.h"
#include "common/error.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/SmallVector.h"
#include "toolchain/lex/tokenized_buffer.h"
#include "toolchain/parse/node_kind.h"
#include "toolchain/parse/tree_and_subtrees.h"
#include "toolchain/parse/typed_nodes.h"
namespace Carbon::Parse {
auto Tree::postorder() const -> llvm::iterator_range<PostorderIterator> {
return llvm::iterator_range<PostorderIterator>(
PostorderIterator(NodeId(0)),
PostorderIterator(NodeId(node_impls_.size())));
}
auto Tree::node_token(NodeId n) const -> Lex::TokenIndex {
CARBON_CHECK(n.is_valid());
return node_impls_[n.index].token;
}
auto Tree::Print(llvm::raw_ostream& output) const -> void {
TreeAndSubtrees(*tokens_, *this).Print(output);
}
auto Tree::Verify() const -> ErrorOr<Success> {
llvm::SmallVector<NodeId> nodes;
// Traverse the tree in postorder.
for (NodeId n : postorder()) {
if (node_has_error(n) && !has_errors()) {
return Error(llvm::formatv(
"Node {0} has errors, but the tree is not marked as having any.", n));
}
if (node_kind(n) == NodeKind::Placeholder) {
return Error(llvm::formatv(
"Node {0} is a placeholder node that wasn't replaced.", n));
}
}
// Not every token that can produce a virtual node will, so we only check that
// the number of nodes is in a range.
int32_t num_nodes = size();
if (!has_errors() && num_nodes > tokens_->expected_max_parse_tree_size()) {
return Error(llvm::formatv(
"Tree has {0} nodes and no errors, but "
"Lex::TokenizedBuffer expected up to {1} nodes for {2} tokens.",
num_nodes, tokens_->expected_max_parse_tree_size(), tokens_->size()));
}
if (!has_errors() && num_nodes < tokens_->size()) {
return Error(
llvm::formatv("Tree has {0} nodes and no errors, but expected at least "
"{1} nodes to match the number of tokens.",
num_nodes, tokens_->size()));
}
#ifndef NDEBUG
TreeAndSubtrees subtrees(*tokens_, *this);
CARBON_RETURN_IF_ERROR(subtrees.Verify());
#endif // NDEBUG
return Success();
}
auto Tree::CollectMemUsage(MemUsage& mem_usage, llvm::StringRef label) const
-> void {
mem_usage.Collect(MemUsage::ConcatLabel(label, "node_impls_"), node_impls_);
mem_usage.Collect(MemUsage::ConcatLabel(label, "imports_"), imports_);
}
auto Tree::PostorderIterator::MakeRange(NodeId begin, NodeId end)
-> llvm::iterator_range<PostorderIterator> {
CARBON_CHECK(begin.is_valid() && end.is_valid());
return llvm::iterator_range<PostorderIterator>(
PostorderIterator(begin), PostorderIterator(NodeId(end.index + 1)));
}
auto Tree::PostorderIterator::Print(llvm::raw_ostream& output) const -> void {
output << node_;
}
} // namespace Carbon::Parse