formatter_chunks.h 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  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. #ifndef CARBON_TOOLCHAIN_SEM_IR_FORMATTER_CHUNKS_H_
  5. #define CARBON_TOOLCHAIN_SEM_IR_FORMATTER_CHUNKS_H_
  6. #include <string>
  7. #include "common/check.h"
  8. #include "llvm/ADT/SmallVector.h"
  9. #include "llvm/Support/raw_ostream.h"
  10. namespace Carbon::SemIR {
  11. // Manages the chunks created by the formatter.
  12. //
  13. // There are two kinds of `Chunk`s:
  14. // - Parent `Chunk`s, with children in a vector.
  15. // - Content `Chunk`s, with content in a string.
  16. //
  17. // The high level usage is:
  18. // 1. Calls to `AddParent` to prepare parent `Chunk`s.
  19. // 2. One call to `StartContent` to switch modes.
  20. // 3. Calls to `FormatChildContent`, `AppendChildToCurrentParent`, and `out`.
  21. // 4. Calls to `Write`.
  22. class FormatterChunks {
  23. public:
  24. // A type-safe index into `chunks_`.
  25. struct ChunkId {
  26. auto operator==(const ChunkId& other) const -> bool = default;
  27. size_t index;
  28. };
  29. // An empty `ChunkId`.
  30. static constexpr ChunkId None = ChunkId(-1);
  31. // Reserves space for at least `count` chunks.
  32. auto Reserve(size_t count) -> void { chunks_.reserve(count); }
  33. // Adds a parent `Chunk` and returns its `ChunkId`. If `child_chunk_id` isn't
  34. // `None`, it's added as a child. Must be called before `StartContent`.
  35. //
  36. // By default the parent `Chunk` will not be included in the output, and
  37. // `AppendChildToCurrentParent` must be called to include it.
  38. auto AddParent(ChunkId child_chunk_id = None) -> ChunkId;
  39. // Switches from adding parents to adding content.
  40. auto StartContent() -> void;
  41. // Calls `format` to add content conditionally included when `parent_chunk_id`
  42. // is included. Must be called after `StartContent`.
  43. //
  44. // During a `FormatChildContent` call where the `parent_chunk_id` is not
  45. // already included in output, a new content `Chunk` is created, marked as a
  46. // child of `parent_chunk_id`, and `out` is temporarily directed to it during
  47. // the duration of `format. Otherwise, `out` lazily creates a content `Chunk`
  48. // which is always included in output.
  49. auto FormatChildContent(ChunkId parent_chunk_id,
  50. llvm::function_ref<auto()->void> format) -> void;
  51. // Adds `child_chunk_id` to the children of a `FormatChildContent`'s
  52. // `parent_chunk_id` if called during `format`, or otherwise includes the
  53. // chunk in output.
  54. auto AppendChildToCurrentParent(ChunkId child_chunk_id) -> void;
  55. // Writes included chunks to the given stream.
  56. auto Write(llvm::raw_ostream& stream) -> void;
  57. // Returns a stream to write to a content `Chunk`. The returned reference is
  58. // only valid until the next `Chunk` starts. Must be called after
  59. // `StartContent`.
  60. //
  61. // See `FormatChildContent` for details of the target content `Chunk`.
  62. auto out() -> llvm::raw_ostream& {
  63. CARBON_CHECK(content_start_id_ != None);
  64. if (!out_) {
  65. AddContent(/*include_in_output=*/true);
  66. }
  67. return *out_;
  68. }
  69. auto size() -> size_t { return chunks_.size(); }
  70. private:
  71. // Either a parent or content.
  72. struct Chunk {
  73. // Whether this chunk is known to be included in the output.
  74. bool include_in_output;
  75. // Either children or content.
  76. std::variant<llvm::SmallVector<ChunkId>, std::string> data;
  77. };
  78. // Adds a `Chunk` that will have `content`, and directs `out_` to it.
  79. auto AddContent(bool include_in_output) -> ChunkId;
  80. // Adds `child_chunk_id` to the children of `parent_chunk_id`.
  81. auto AppendChildToParent(ChunkId child_chunk_id, ChunkId parent_chunk_id)
  82. -> void;
  83. // Indexes into `chunks_`.
  84. auto Get(ChunkId chunk_id) -> Chunk& { return chunks_[chunk_id.index]; }
  85. // An output stream pointing at the current content `Chunk`.
  86. std::unique_ptr<llvm::raw_string_ostream> out_;
  87. // The location where content started. Set by `StartContent`.
  88. ChunkId content_start_id_ = None;
  89. // The current parent `Chunk`. This is only set during calls to
  90. // `FormatChildContent`.
  91. ChunkId current_parent_id_ = None;
  92. // A sequential ordering of `Chunk`s. This will have all parent `Chunk`s
  93. // first, followed by content `Chunk`s at `content_start_`.
  94. llvm::SmallVector<Chunk> chunks_;
  95. };
  96. } // namespace Carbon::SemIR
  97. #endif // CARBON_TOOLCHAIN_SEM_IR_FORMATTER_CHUNKS_H_