formatter_chunks.cpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "toolchain/sem_ir/formatter_chunks.h"
  5. #include "common/check.h"
  6. namespace Carbon::SemIR {
  7. auto FormatterChunks::StartContent() -> void {
  8. CARBON_CHECK(content_start_id_ == None);
  9. content_start_id_ = ChunkId{.index = chunks_.size()};
  10. }
  11. auto FormatterChunks::AddContent(bool include_in_output) -> ChunkId {
  12. CARBON_CHECK(content_start_id_ != None, "Must call StartContent first");
  13. auto chunk_id = ChunkId{.index = chunks_.size()};
  14. chunks_.push_back(
  15. {.include_in_output = include_in_output, .data = std::string()});
  16. out_ = std::make_unique<llvm::raw_string_ostream>(
  17. std::get<std::string>(Get(chunk_id).data));
  18. return chunk_id;
  19. }
  20. auto FormatterChunks::AddParent(ChunkId child_chunk_id) -> ChunkId {
  21. CARBON_CHECK(content_start_id_ == None, "Already called StartContent");
  22. llvm::SmallVector<ChunkId> children;
  23. if (child_chunk_id != None) {
  24. children.push_back(child_chunk_id);
  25. }
  26. auto chunk_id = ChunkId{.index = chunks_.size()};
  27. chunks_.push_back({.include_in_output = false, .data = std::move(children)});
  28. return chunk_id;
  29. }
  30. auto FormatterChunks::FormatChildContent(
  31. ChunkId parent_chunk_id, llvm::function_ref<auto()->void> format) -> void {
  32. CARBON_CHECK(content_start_id_ != None, "Must call StartContent first");
  33. CARBON_CHECK(current_parent_id_ == None, "Cannot nest FormatChildContent");
  34. // We only need to call `AddContent` for non-included content because `out()`
  35. // is included by default.
  36. if (Get(parent_chunk_id).include_in_output) {
  37. format();
  38. return;
  39. }
  40. // Otherwise, create a content `Chunk` and include it only if the parent is
  41. // later found to be used.
  42. AppendChildToParent(AddContent(/*include_in_output=*/false), parent_chunk_id);
  43. current_parent_id_ = parent_chunk_id;
  44. format();
  45. current_parent_id_ = None;
  46. // Reset the output stream so that the next call to `out()` creates a new
  47. // chunk.
  48. out_.reset();
  49. }
  50. auto FormatterChunks::AppendChildToParent(ChunkId child_chunk_id,
  51. ChunkId parent_chunk_id) -> void {
  52. CARBON_CHECK(!Get(parent_chunk_id).include_in_output);
  53. auto* children =
  54. std::get_if<llvm::SmallVector<ChunkId>>(&Get(parent_chunk_id).data);
  55. CARBON_CHECK(children);
  56. children->push_back(child_chunk_id);
  57. }
  58. auto FormatterChunks::AppendChildToCurrentParent(ChunkId child_chunk_id)
  59. -> void {
  60. if (current_parent_id_ != None) {
  61. // If the parent is not included, add the `chunk` to the parent's children
  62. // for conditional inclusion.
  63. if (!Get(current_parent_id_).include_in_output) {
  64. AppendChildToParent(child_chunk_id, current_parent_id_);
  65. return;
  66. }
  67. }
  68. // If the parent is already included, or there is no parent (this is not
  69. // currently a tentative chunk), include the chunk and all of its children.
  70. llvm::SmallVector<ChunkId> to_include = {child_chunk_id};
  71. while (!to_include.empty()) {
  72. auto& chunk_ref = Get(to_include.pop_back_val());
  73. if (chunk_ref.include_in_output) {
  74. continue;
  75. }
  76. chunk_ref.include_in_output = true;
  77. if (auto* children =
  78. std::get_if<llvm::SmallVector<ChunkId>>(&chunk_ref.data)) {
  79. to_include.append(*children);
  80. children->clear();
  81. }
  82. }
  83. }
  84. auto FormatterChunks::Write(llvm::raw_ostream& stream) -> void {
  85. CARBON_CHECK(content_start_id_ != None);
  86. for (const auto& chunk :
  87. llvm::ArrayRef(chunks_).drop_front(content_start_id_.index)) {
  88. if (chunk.include_in_output) {
  89. stream << std::get<std::string>(chunk.data);
  90. }
  91. }
  92. }
  93. } // namespace Carbon::SemIR