mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 22:02:23 +01:00
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>`.
90 lines
3.0 KiB
C++
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
|