blob: 1585d468cb75d910b47af0178e16b9c2b231eb88 [file] [log] [blame]
Austin Engcc2516a2023-10-17 20:57:54 +00001// Copyright 2020 The Dawn & Tint Authors
Ryan Harrisondbc13af2022-02-21 15:19:07 +00002//
Austin Engcc2516a2023-10-17 20:57:54 +00003// Redistribution and use in source and binary forms, with or without
4// modification, are permitted provided that the following conditions are met:
Ryan Harrisondbc13af2022-02-21 15:19:07 +00005//
Austin Engcc2516a2023-10-17 20:57:54 +00006// 1. Redistributions of source code must retain the above copyright notice, this
7// list of conditions and the following disclaimer.
Ryan Harrisondbc13af2022-02-21 15:19:07 +00008//
Austin Engcc2516a2023-10-17 20:57:54 +00009// 2. Redistributions in binary form must reproduce the above copyright notice,
10// this list of conditions and the following disclaimer in the documentation
11// and/or other materials provided with the distribution.
12//
13// 3. Neither the name of the copyright holder nor the names of its
14// contributors may be used to endorse or promote products derived from
15// this software without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
21// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Ryan Harrisondbc13af2022-02-21 15:19:07 +000027
Ben Clayton7fd1c2a2023-08-01 00:37:35 +000028#ifndef SRC_TINT_UTILS_GENERATOR_TEXT_GENERATOR_H_
29#define SRC_TINT_UTILS_GENERATOR_TEXT_GENERATOR_H_
Ryan Harrisondbc13af2022-02-21 15:19:07 +000030
Ryan Harrisondbc13af2022-02-21 15:19:07 +000031#include <string>
Ryan Harrisondbc13af2022-02-21 15:19:07 +000032#include <utility>
33#include <vector>
34
dan sinclair22b4dd22023-07-21 00:40:07 +000035#include "src/tint/utils/diagnostic/diagnostic.h"
36#include "src/tint/utils/text/string_stream.h"
Ryan Harrisondbc13af2022-02-21 15:19:07 +000037
dan sinclairbae54e72023-07-28 15:01:54 +000038namespace tint {
Ryan Harrisondbc13af2022-02-21 15:19:07 +000039
40/// Helper methods for generators which are creating text output
41class TextGenerator {
dan sinclair41e4d9a2022-05-01 14:40:55 +000042 public:
dan sinclair67a18932023-06-26 19:54:49 +000043 /// LineInfo holds a single line of text
44 struct LineInfo {
dan sinclair41e4d9a2022-05-01 14:40:55 +000045 /// The indentation of the line in blankspace
46 uint32_t indent = 0;
47 /// The content of the line, without a trailing newline character
48 std::string content;
49 };
Ryan Harrisondbc13af2022-02-21 15:19:07 +000050
dan sinclair41e4d9a2022-05-01 14:40:55 +000051 /// TextBuffer holds a list of lines of text.
52 struct TextBuffer {
53 // Constructor
54 TextBuffer();
Ryan Harrisondbc13af2022-02-21 15:19:07 +000055
dan sinclair41e4d9a2022-05-01 14:40:55 +000056 // Destructor
57 ~TextBuffer();
Ryan Harrisondbc13af2022-02-21 15:19:07 +000058
dan sinclair41e4d9a2022-05-01 14:40:55 +000059 /// IncrementIndent increases the indentation of lines that will be written
60 /// to the TextBuffer
61 void IncrementIndent();
Ryan Harrisondbc13af2022-02-21 15:19:07 +000062
dan sinclair41e4d9a2022-05-01 14:40:55 +000063 /// DecrementIndent decreases the indentation of lines that will be written
64 /// to the TextBuffer
65 void DecrementIndent();
Ryan Harrisondbc13af2022-02-21 15:19:07 +000066
dan sinclair41e4d9a2022-05-01 14:40:55 +000067 /// Appends the line to the end of the TextBuffer
68 /// @param line the line to append to the TextBuffer
69 void Append(const std::string& line);
Ryan Harrisondbc13af2022-02-21 15:19:07 +000070
dan sinclair41e4d9a2022-05-01 14:40:55 +000071 /// Inserts the line to the TextBuffer before the line with index `before`
72 /// @param line the line to append to the TextBuffer
73 /// @param before the zero-based index of the line to insert the text before
74 /// @param indent the indentation to apply to the inserted lines
75 void Insert(const std::string& line, size_t before, uint32_t indent);
Ryan Harrisondbc13af2022-02-21 15:19:07 +000076
dan sinclair41e4d9a2022-05-01 14:40:55 +000077 /// Appends the lines of `tb` to the end of this TextBuffer
78 /// @param tb the TextBuffer to append to the end of this TextBuffer
79 void Append(const TextBuffer& tb);
Ryan Harrisondbc13af2022-02-21 15:19:07 +000080
dan sinclair41e4d9a2022-05-01 14:40:55 +000081 /// Inserts the lines of `tb` to the TextBuffer before the line with index
82 /// `before`
83 /// @param tb the TextBuffer to insert into this TextBuffer
84 /// @param before the zero-based index of the line to insert the text before
85 /// @param indent the indentation to apply to the inserted lines
86 void Insert(const TextBuffer& tb, size_t before, uint32_t indent);
Ryan Harrisondbc13af2022-02-21 15:19:07 +000087
dan sinclair41e4d9a2022-05-01 14:40:55 +000088 /// @returns the buffer's content as a single string
89 /// @param indent additional indentation to apply to each line
90 std::string String(uint32_t indent = 0) const;
Ryan Harrisondbc13af2022-02-21 15:19:07 +000091
dan sinclair41e4d9a2022-05-01 14:40:55 +000092 /// The current indentation of the TextBuffer. Lines appended to the
93 /// TextBuffer will use this indentation.
94 uint32_t current_indent = 0;
Ryan Harrisondbc13af2022-02-21 15:19:07 +000095
dan sinclair41e4d9a2022-05-01 14:40:55 +000096 /// The lines
dan sinclair67a18932023-06-26 19:54:49 +000097 std::vector<LineInfo> lines;
dan sinclair41e4d9a2022-05-01 14:40:55 +000098 };
dan sinclair41e4d9a2022-05-01 14:40:55 +000099 /// LineWriter is a helper that acts as a string buffer, who's content is
100 /// emitted to the TextBuffer as a single line on destruction.
101 struct LineWriter {
102 public:
103 /// Constructor
104 /// @param buffer the TextBuffer that the LineWriter will append its
105 /// content to on destruction, at the end of the buffer.
106 explicit LineWriter(TextBuffer* buffer);
107
108 /// Move constructor
109 /// @param rhs the LineWriter to move
110 LineWriter(LineWriter&& rhs);
111 /// Destructor
112 ~LineWriter();
113
dan sinclairbae54e72023-07-28 15:01:54 +0000114 /// @returns the StringStream
115 operator StringStream&() { return os; }
dan sinclair41e4d9a2022-05-01 14:40:55 +0000116
117 /// @param rhs the value to write to the line
dan sinclairbae54e72023-07-28 15:01:54 +0000118 /// @returns the StringStream so calls can be chained
dan sinclair41e4d9a2022-05-01 14:40:55 +0000119 template <typename T>
dan sinclairbae54e72023-07-28 15:01:54 +0000120 StringStream& operator<<(T&& rhs) {
dan sinclair41e4d9a2022-05-01 14:40:55 +0000121 return os << std::forward<T>(rhs);
122 }
123
124 private:
125 LineWriter(const LineWriter&) = delete;
126 LineWriter& operator=(const LineWriter&) = delete;
127
dan sinclairbae54e72023-07-28 15:01:54 +0000128 StringStream os;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000129 TextBuffer* buffer;
130 };
131
dan sinclair9d8229b2023-06-26 16:35:07 +0000132 /// Increment the emitter indent level
dan sinclair67a18932023-06-26 19:54:49 +0000133 void IncrementIndent() { current_buffer_->IncrementIndent(); }
dan sinclair9d8229b2023-06-26 16:35:07 +0000134 /// Decrement the emitter indent level
dan sinclair67a18932023-06-26 19:54:49 +0000135 void DecrementIndent() { current_buffer_->DecrementIndent(); }
dan sinclair9d8229b2023-06-26 16:35:07 +0000136
137 /// @returns a new LineWriter, used for buffering and writing a line to
138 /// the end of #current_buffer_.
dan sinclair67a18932023-06-26 19:54:49 +0000139 LineWriter Line() { return LineWriter(current_buffer_); }
140 /// @param buffer the TextBuffer to write the line to
141 /// @returns a new LineWriter, used for buffering and writing a line to
142 /// the end of `buffer`.
143 static LineWriter Line(TextBuffer* buffer) { return LineWriter(buffer); }
dan sinclair9d8229b2023-06-26 16:35:07 +0000144
145 /// @returns the result data
dan sinclair67a18932023-06-26 19:54:49 +0000146 virtual std::string Result() const { return main_buffer_.String(); }
dan sinclair9d8229b2023-06-26 16:35:07 +0000147
148 /// @returns the list of diagnostics raised by the generator.
149 const diag::List& Diagnostics() const { return diagnostics_; }
150
151 protected:
dan sinclair41e4d9a2022-05-01 14:40:55 +0000152 /// Helper for writing a '(' on construction and a ')' destruction.
153 struct ScopedParen {
154 /// Constructor
dan sinclairbae54e72023-07-28 15:01:54 +0000155 /// @param stream the StringStream that will be written to
156 explicit ScopedParen(StringStream& stream);
dan sinclair41e4d9a2022-05-01 14:40:55 +0000157 /// Destructor
158 ~ScopedParen();
159
160 private:
161 ScopedParen(ScopedParen&& rhs) = delete;
162 ScopedParen(const ScopedParen&) = delete;
163 ScopedParen& operator=(const ScopedParen&) = delete;
dan sinclairbae54e72023-07-28 15:01:54 +0000164 StringStream& s;
dan sinclair41e4d9a2022-05-01 14:40:55 +0000165 };
166
167 /// Helper for incrementing indentation on construction and decrementing
168 /// indentation on destruction.
169 struct ScopedIndent {
170 /// Constructor
171 /// @param buffer the TextBuffer that the ScopedIndent will indent
172 explicit ScopedIndent(TextBuffer* buffer);
173 /// Constructor
174 /// @param generator ScopedIndent will indent the generator's
175 /// `current_buffer_`
176 explicit ScopedIndent(TextGenerator* generator);
177 /// Destructor
178 ~ScopedIndent();
179
180 private:
181 ScopedIndent(ScopedIndent&& rhs) = delete;
182 ScopedIndent(const ScopedIndent&) = delete;
183 ScopedIndent& operator=(const ScopedIndent&) = delete;
184 TextBuffer* buffer_;
185 };
186
dan sinclair67a18932023-06-26 19:54:49 +0000187 /// Constructor
188 TextGenerator();
189 virtual ~TextGenerator();
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000190
dan sinclair41e4d9a2022-05-01 14:40:55 +0000191 /// Diagnostics generated by the generator
192 diag::List diagnostics_;
193 /// The buffer the TextGenerator is currently appending lines to
194 TextBuffer* current_buffer_ = &main_buffer_;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000195
dan sinclair41e4d9a2022-05-01 14:40:55 +0000196 /// The primary text buffer that the generator will emit
197 TextBuffer main_buffer_;
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000198};
199
dan sinclairbae54e72023-07-28 15:01:54 +0000200} // namespace tint
Ryan Harrisondbc13af2022-02-21 15:19:07 +0000201
Ben Clayton7fd1c2a2023-08-01 00:37:35 +0000202#endif // SRC_TINT_UTILS_GENERATOR_TEXT_GENERATOR_H_