blob: edd0b365e07cd51d2e14337a448b027140c67ae6 [file] [log] [blame]
Ryan Harrisondbc13af2022-02-21 15:19:07 +00001// Copyright 2020 The Tint Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Ben Clayton7fd1c2a2023-08-01 00:37:35 +000015#ifndef SRC_TINT_UTILS_GENERATOR_TEXT_GENERATOR_H_
16#define SRC_TINT_UTILS_GENERATOR_TEXT_GENERATOR_H_
Ryan Harrisondbc13af2022-02-21 15:19:07 +000017
Ryan Harrisondbc13af2022-02-21 15:19:07 +000018#include <string>
19#include <unordered_map>
20#include <utility>
21#include <vector>
22
dan sinclair22b4dd22023-07-21 00:40:07 +000023#include "src/tint/utils/diagnostic/diagnostic.h"
24#include "src/tint/utils/text/string_stream.h"
Ryan Harrisondbc13af2022-02-21 15:19:07 +000025
dan sinclairbae54e72023-07-28 15:01:54 +000026namespace tint {
Ryan Harrisondbc13af2022-02-21 15:19:07 +000027
28/// Helper methods for generators which are creating text output
29class TextGenerator {
dan sinclair41e4d9a2022-05-01 14:40:55 +000030 public:
dan sinclair67a18932023-06-26 19:54:49 +000031 /// LineInfo holds a single line of text
32 struct LineInfo {
dan sinclair41e4d9a2022-05-01 14:40:55 +000033 /// The indentation of the line in blankspace
34 uint32_t indent = 0;
35 /// The content of the line, without a trailing newline character
36 std::string content;
37 };
Ryan Harrisondbc13af2022-02-21 15:19:07 +000038
dan sinclair41e4d9a2022-05-01 14:40:55 +000039 /// TextBuffer holds a list of lines of text.
40 struct TextBuffer {
41 // Constructor
42 TextBuffer();
Ryan Harrisondbc13af2022-02-21 15:19:07 +000043
dan sinclair41e4d9a2022-05-01 14:40:55 +000044 // Destructor
45 ~TextBuffer();
Ryan Harrisondbc13af2022-02-21 15:19:07 +000046
dan sinclair41e4d9a2022-05-01 14:40:55 +000047 /// IncrementIndent increases the indentation of lines that will be written
48 /// to the TextBuffer
49 void IncrementIndent();
Ryan Harrisondbc13af2022-02-21 15:19:07 +000050
dan sinclair41e4d9a2022-05-01 14:40:55 +000051 /// DecrementIndent decreases the indentation of lines that will be written
52 /// to the TextBuffer
53 void DecrementIndent();
Ryan Harrisondbc13af2022-02-21 15:19:07 +000054
dan sinclair41e4d9a2022-05-01 14:40:55 +000055 /// Appends the line to the end of the TextBuffer
56 /// @param line the line to append to the TextBuffer
57 void Append(const std::string& line);
Ryan Harrisondbc13af2022-02-21 15:19:07 +000058
dan sinclair41e4d9a2022-05-01 14:40:55 +000059 /// Inserts the line to the TextBuffer before the line with index `before`
60 /// @param line the line to append to the TextBuffer
61 /// @param before the zero-based index of the line to insert the text before
62 /// @param indent the indentation to apply to the inserted lines
63 void Insert(const std::string& line, size_t before, uint32_t indent);
Ryan Harrisondbc13af2022-02-21 15:19:07 +000064
dan sinclair41e4d9a2022-05-01 14:40:55 +000065 /// Appends the lines of `tb` to the end of this TextBuffer
66 /// @param tb the TextBuffer to append to the end of this TextBuffer
67 void Append(const TextBuffer& tb);
Ryan Harrisondbc13af2022-02-21 15:19:07 +000068
dan sinclair41e4d9a2022-05-01 14:40:55 +000069 /// Inserts the lines of `tb` to the TextBuffer before the line with index
70 /// `before`
71 /// @param tb the TextBuffer to insert into this TextBuffer
72 /// @param before the zero-based index of the line to insert the text before
73 /// @param indent the indentation to apply to the inserted lines
74 void Insert(const TextBuffer& tb, size_t before, uint32_t indent);
Ryan Harrisondbc13af2022-02-21 15:19:07 +000075
dan sinclair41e4d9a2022-05-01 14:40:55 +000076 /// @returns the buffer's content as a single string
77 /// @param indent additional indentation to apply to each line
78 std::string String(uint32_t indent = 0) const;
Ryan Harrisondbc13af2022-02-21 15:19:07 +000079
dan sinclair41e4d9a2022-05-01 14:40:55 +000080 /// The current indentation of the TextBuffer. Lines appended to the
81 /// TextBuffer will use this indentation.
82 uint32_t current_indent = 0;
Ryan Harrisondbc13af2022-02-21 15:19:07 +000083
dan sinclair41e4d9a2022-05-01 14:40:55 +000084 /// The lines
dan sinclair67a18932023-06-26 19:54:49 +000085 std::vector<LineInfo> lines;
dan sinclair41e4d9a2022-05-01 14:40:55 +000086 };
dan sinclair41e4d9a2022-05-01 14:40:55 +000087 /// LineWriter is a helper that acts as a string buffer, who's content is
88 /// emitted to the TextBuffer as a single line on destruction.
89 struct LineWriter {
90 public:
91 /// Constructor
92 /// @param buffer the TextBuffer that the LineWriter will append its
93 /// content to on destruction, at the end of the buffer.
94 explicit LineWriter(TextBuffer* buffer);
95
96 /// Move constructor
97 /// @param rhs the LineWriter to move
98 LineWriter(LineWriter&& rhs);
99 /// Destructor
100 ~LineWriter();
101
dan sinclairbae54e72023-07-28 15:01:54 +0000102 /// @returns the StringStream
103 operator StringStream&() { return os; }
dan sinclair41e4d9a2022-05-01 14:40:55 +0000104
105 /// @param rhs the value to write to the line
dan sinclairbae54e72023-07-28 15:01:54 +0000106 /// @returns the StringStream so calls can be chained
dan sinclair41e4d9a2022-05-01 14:40:55 +0000107 template <typename T>
dan sinclairbae54e72023-07-28 15:01:54 +0000108 StringStream& operator<<(T&& rhs) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000109 return os << std::forward<T>(rhs);
110 }
111
112 private:
113 LineWriter(const LineWriter&) = delete;
114 LineWriter& operator=(const LineWriter&) = delete;
115
dan sinclairbae54e72023-07-28 15:01:54 +0000116 StringStream os;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000117 TextBuffer* buffer;
118 };
119
dan sinclair9d8229b2023-06-26 16:35:07 +0000120 /// Increment the emitter indent level
dan sinclair67a18932023-06-26 19:54:49 +0000121 void IncrementIndent() { current_buffer_->IncrementIndent(); }
dan sinclair9d8229b2023-06-26 16:35:07 +0000122 /// Decrement the emitter indent level
dan sinclair67a18932023-06-26 19:54:49 +0000123 void DecrementIndent() { current_buffer_->DecrementIndent(); }
dan sinclair9d8229b2023-06-26 16:35:07 +0000124
125 /// @returns a new LineWriter, used for buffering and writing a line to
126 /// the end of #current_buffer_.
dan sinclair67a18932023-06-26 19:54:49 +0000127 LineWriter Line() { return LineWriter(current_buffer_); }
128 /// @param buffer the TextBuffer to write the line to
129 /// @returns a new LineWriter, used for buffering and writing a line to
130 /// the end of `buffer`.
131 static LineWriter Line(TextBuffer* buffer) { return LineWriter(buffer); }
dan sinclair9d8229b2023-06-26 16:35:07 +0000132
133 /// @returns the result data
dan sinclair67a18932023-06-26 19:54:49 +0000134 virtual std::string Result() const { return main_buffer_.String(); }
dan sinclair9d8229b2023-06-26 16:35:07 +0000135
136 /// @returns the list of diagnostics raised by the generator.
137 const diag::List& Diagnostics() const { return diagnostics_; }
138
139 protected:
dan sinclair41e4d9a2022-05-01 14:40:55 +0000140 /// Helper for writing a '(' on construction and a ')' destruction.
141 struct ScopedParen {
142 /// Constructor
dan sinclairbae54e72023-07-28 15:01:54 +0000143 /// @param stream the StringStream that will be written to
144 explicit ScopedParen(StringStream& stream);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000145 /// Destructor
146 ~ScopedParen();
147
148 private:
149 ScopedParen(ScopedParen&& rhs) = delete;
150 ScopedParen(const ScopedParen&) = delete;
151 ScopedParen& operator=(const ScopedParen&) = delete;
dan sinclairbae54e72023-07-28 15:01:54 +0000152 StringStream& s;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000153 };
154
155 /// Helper for incrementing indentation on construction and decrementing
156 /// indentation on destruction.
157 struct ScopedIndent {
158 /// Constructor
159 /// @param buffer the TextBuffer that the ScopedIndent will indent
160 explicit ScopedIndent(TextBuffer* buffer);
161 /// Constructor
162 /// @param generator ScopedIndent will indent the generator's
163 /// `current_buffer_`
164 explicit ScopedIndent(TextGenerator* generator);
165 /// Destructor
166 ~ScopedIndent();
167
168 private:
169 ScopedIndent(ScopedIndent&& rhs) = delete;
170 ScopedIndent(const ScopedIndent&) = delete;
171 ScopedIndent& operator=(const ScopedIndent&) = delete;
172 TextBuffer* buffer_;
173 };
174
dan sinclair67a18932023-06-26 19:54:49 +0000175 /// Constructor
176 TextGenerator();
177 virtual ~TextGenerator();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000178
dan sinclair41e4d9a2022-05-01 14:40:55 +0000179 /// Diagnostics generated by the generator
180 diag::List diagnostics_;
181 /// The buffer the TextGenerator is currently appending lines to
182 TextBuffer* current_buffer_ = &main_buffer_;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000183
dan sinclair41e4d9a2022-05-01 14:40:55 +0000184 /// The primary text buffer that the generator will emit
185 TextBuffer main_buffer_;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000186};
187
dan sinclairbae54e72023-07-28 15:01:54 +0000188} // namespace tint
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000189
Ben Clayton7fd1c2a2023-08-01 00:37:35 +0000190#endif // SRC_TINT_UTILS_GENERATOR_TEXT_GENERATOR_H_