• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 
15 #ifndef SRC_WRITER_TEXT_GENERATOR_H_
16 #define SRC_WRITER_TEXT_GENERATOR_H_
17 
18 #include <sstream>
19 #include <string>
20 #include <unordered_map>
21 #include <utility>
22 #include <vector>
23 
24 #include "src/diagnostic/diagnostic.h"
25 #include "src/program_builder.h"
26 
27 namespace tint {
28 namespace writer {
29 
30 /// Helper methods for generators which are creating text output
31 class TextGenerator {
32  public:
33   /// Line holds a single line of text
34   struct Line {
35     /// The indentation of the line in whitespaces
36     uint32_t indent = 0;
37     /// The content of the line, without a trailing newline character
38     std::string content;
39   };
40 
41   /// TextBuffer holds a list of lines of text.
42   struct TextBuffer {
43     // Constructor
44     TextBuffer();
45 
46     // Destructor
47     ~TextBuffer();
48 
49     /// IncrementIndent increases the indentation of lines that will be written
50     /// to the TextBuffer
51     void IncrementIndent();
52 
53     /// DecrementIndent decreases the indentation of lines that will be written
54     /// to the TextBuffer
55     void DecrementIndent();
56 
57     /// Appends the line to the end of the TextBuffer
58     /// @param line the line to append to the TextBuffer
59     void Append(const std::string& line);
60 
61     /// Inserts the line to the TextBuffer before the line with index `before`
62     /// @param line the line to append to the TextBuffer
63     /// @param before the zero-based index of the line to insert the text before
64     /// @param indent the indentation to apply to the inserted lines
65     void Insert(const std::string& line, size_t before, uint32_t indent);
66 
67     /// Appends the lines of `tb` to the end of this TextBuffer
68     /// @param tb the TextBuffer to append to the end of this TextBuffer
69     void Append(const TextBuffer& tb);
70 
71     /// Inserts the lines of `tb` to the TextBuffer before the line with index
72     /// `before`
73     /// @param tb the TextBuffer to insert into this TextBuffer
74     /// @param before the zero-based index of the line to insert the text before
75     /// @param indent the indentation to apply to the inserted lines
76     void Insert(const TextBuffer& tb, size_t before, uint32_t indent);
77 
78     /// @returns the buffer's content as a single string
79     /// @param indent additional indentation to apply to each line
80     std::string String(uint32_t indent = 0) const;
81 
82     /// The current indentation of the TextBuffer. Lines appended to the
83     /// TextBuffer will use this indentation.
84     uint32_t current_indent = 0;
85 
86     /// The lines
87     std::vector<Line> lines;
88   };
89 
90   /// Constructor
91   /// @param program the program used by the generator
92   explicit TextGenerator(const Program* program);
93   ~TextGenerator();
94 
95   /// Increment the emitter indent level
increment_indent()96   void increment_indent() { current_buffer_->IncrementIndent(); }
97   /// Decrement the emitter indent level
decrement_indent()98   void decrement_indent() { current_buffer_->DecrementIndent(); }
99 
100   /// @returns the result data
result()101   std::string result() const { return main_buffer_.String(); }
102 
103   /// @returns the list of diagnostics raised by the generator.
Diagnostics()104   const diag::List& Diagnostics() const { return diagnostics_; }
105 
106   /// @returns the error
error()107   std::string error() const { return diagnostics_.str(); }
108 
109   /// @return a new, unique identifier with the given prefix.
110   /// @param prefix optional prefix to apply to the generated identifier. If
111   /// empty "tint_symbol" will be used.
112   std::string UniqueIdentifier(const std::string& prefix = "");
113 
114   /// @param s the semantic structure
115   /// @returns the name of the structure, taking special care of builtin
116   /// structures that start with double underscores. If the structure is a
117   /// builtin, then the returned name will be a unique name without the leading
118   /// underscores.
119   std::string StructName(const sem::Struct* s);
120 
121   /// @param str the string
122   /// @param suffix the suffix to remove
123   /// @return returns str without the provided trailing suffix string. If str
124   /// doesn't end with suffix, str is returned unchanged.
125   std::string TrimSuffix(std::string str, const std::string& suffix);
126 
127  protected:
128   /// LineWriter is a helper that acts as a string buffer, who's content is
129   /// emitted to the TextBuffer as a single line on destruction.
130   struct LineWriter {
131    public:
132     /// Constructor
133     /// @param buffer the TextBuffer that the LineWriter will append its
134     /// content to on destruction, at the end of the buffer.
135     explicit LineWriter(TextBuffer* buffer);
136 
137     /// Move constructor
138     /// @param rhs the LineWriter to move
139     LineWriter(LineWriter&& rhs);
140     /// Destructor
141     ~LineWriter();
142 
143     /// @returns the ostringstream
144     operator std::ostream&() { return os; }
145 
146     /// @param rhs the value to write to the line
147     /// @returns the ostream so calls can be chained
148     template <typename T>
149     std::ostream& operator<<(T&& rhs) {
150       return os << std::forward<T>(rhs);
151     }
152 
153    private:
154     LineWriter(const LineWriter&) = delete;
155     LineWriter& operator=(const LineWriter&) = delete;
156 
157     std::ostringstream os;
158     TextBuffer* buffer;
159   };
160 
161   /// Helper for writing a '(' on construction and a ')' destruction.
162   struct ScopedParen {
163     /// Constructor
164     /// @param stream the std::ostream that will be written to
165     explicit ScopedParen(std::ostream& stream);
166     /// Destructor
167     ~ScopedParen();
168 
169    private:
170     ScopedParen(ScopedParen&& rhs) = delete;
171     ScopedParen(const ScopedParen&) = delete;
172     ScopedParen& operator=(const ScopedParen&) = delete;
173     std::ostream& s;
174   };
175 
176   /// Helper for incrementing indentation on construction and decrementing
177   /// indentation on destruction.
178   struct ScopedIndent {
179     /// Constructor
180     /// @param buffer the TextBuffer that the ScopedIndent will indent
181     explicit ScopedIndent(TextBuffer* buffer);
182     /// Constructor
183     /// @param generator ScopedIndent will indent the generator's
184     /// `current_buffer_`
185     explicit ScopedIndent(TextGenerator* generator);
186     /// Destructor
187     ~ScopedIndent();
188 
189    private:
190     ScopedIndent(ScopedIndent&& rhs) = delete;
191     ScopedIndent(const ScopedIndent&) = delete;
192     ScopedIndent& operator=(const ScopedIndent&) = delete;
193     TextBuffer* buffer_;
194   };
195 
196   /// @returns the resolved type of the ast::Expression `expr`
197   /// @param expr the expression
TypeOf(const ast::Expression * expr)198   const sem::Type* TypeOf(const ast::Expression* expr) const {
199     return builder_.TypeOf(expr);
200   }
201 
202   /// @returns the resolved type of the ast::Type `type`
203   /// @param type the type
TypeOf(const ast::Type * type)204   const sem::Type* TypeOf(const ast::Type* type) const {
205     return builder_.TypeOf(type);
206   }
207 
208   /// @returns the resolved type of the ast::TypeDecl `type_decl`
209   /// @param type_decl the type
TypeOf(const ast::TypeDecl * type_decl)210   const sem::Type* TypeOf(const ast::TypeDecl* type_decl) const {
211     return builder_.TypeOf(type_decl);
212   }
213 
214   /// @returns a new LineWriter, used for buffering and writing a line to
215   /// the end of #current_buffer_.
line()216   LineWriter line() { return LineWriter(current_buffer_); }
217 
218   /// @param buffer the TextBuffer to write the line to
219   /// @returns a new LineWriter, used for buffering and writing a line to
220   /// the end of `buffer`.
line(TextBuffer * buffer)221   static LineWriter line(TextBuffer* buffer) { return LineWriter(buffer); }
222 
223   /// The program
224   Program const* const program_;
225   /// A ProgramBuilder that thinly wraps program_
226   ProgramBuilder builder_;
227   /// Diagnostics generated by the generator
228   diag::List diagnostics_;
229   /// The buffer the TextGenerator is currently appending lines to
230   TextBuffer* current_buffer_ = &main_buffer_;
231 
232  private:
233   /// The primary text buffer that the generator will emit
234   TextBuffer main_buffer_;
235   /// Map of builtin structure to unique generated name
236   std::unordered_map<const sem::Struct*, std::string> builtin_struct_names_;
237 };
238 
239 }  // namespace writer
240 }  // namespace tint
241 
242 #endif  // SRC_WRITER_TEXT_GENERATOR_H_
243