• 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 #include "src/writer/text_generator.h"
16 
17 #include <algorithm>
18 #include <limits>
19 
20 #include "src/utils/map.h"
21 
22 namespace tint {
23 namespace writer {
24 
TextGenerator(const Program * program)25 TextGenerator::TextGenerator(const Program* program)
26     : program_(program), builder_(ProgramBuilder::Wrap(program)) {}
27 
28 TextGenerator::~TextGenerator() = default;
29 
UniqueIdentifier(const std::string & prefix)30 std::string TextGenerator::UniqueIdentifier(const std::string& prefix) {
31   return builder_.Symbols().NameFor(builder_.Symbols().New(prefix));
32 }
33 
StructName(const sem::Struct * s)34 std::string TextGenerator::StructName(const sem::Struct* s) {
35   auto name = builder_.Symbols().NameFor(s->Name());
36   if (name.size() > 1 && name[0] == '_' && name[1] == '_') {
37     name = utils::GetOrCreate(builtin_struct_names_, s,
38                               [&] { return UniqueIdentifier(name.substr(2)); });
39   }
40   return name;
41 }
42 
TrimSuffix(std::string str,const std::string & suffix)43 std::string TextGenerator::TrimSuffix(std::string str,
44                                       const std::string& suffix) {
45   if (str.size() >= suffix.size()) {
46     if (str.substr(str.size() - suffix.size(), suffix.size()) == suffix) {
47       return str.substr(0, str.size() - suffix.size());
48     }
49   }
50   return str;
51 }
52 
LineWriter(TextBuffer * buf)53 TextGenerator::LineWriter::LineWriter(TextBuffer* buf) : buffer(buf) {}
54 
LineWriter(LineWriter && other)55 TextGenerator::LineWriter::LineWriter(LineWriter&& other) {
56   buffer = other.buffer;
57   other.buffer = nullptr;
58 }
59 
~LineWriter()60 TextGenerator::LineWriter::~LineWriter() {
61   if (buffer) {
62     buffer->Append(os.str());
63   }
64 }
65 
66 TextGenerator::TextBuffer::TextBuffer() = default;
67 TextGenerator::TextBuffer::~TextBuffer() = default;
68 
IncrementIndent()69 void TextGenerator::TextBuffer::IncrementIndent() {
70   current_indent += 2;
71 }
72 
DecrementIndent()73 void TextGenerator::TextBuffer::DecrementIndent() {
74   current_indent = std::max(2u, current_indent) - 2u;
75 }
76 
Append(const std::string & line)77 void TextGenerator::TextBuffer::Append(const std::string& line) {
78   lines.emplace_back(Line{current_indent, line});
79 }
80 
Insert(const std::string & line,size_t before,uint32_t indent)81 void TextGenerator::TextBuffer::Insert(const std::string& line,
82                                        size_t before,
83                                        uint32_t indent) {
84   if (before >= lines.size()) {
85     diag::List d;
86     TINT_ICE(Writer, d)
87         << "TextBuffer::Insert() called with before >= lines.size()\n"
88         << "  before:" << before << "\n"
89         << "  lines.size(): " << lines.size();
90     return;
91   }
92   lines.insert(lines.begin() + before, Line{indent, line});
93 }
94 
Append(const TextBuffer & tb)95 void TextGenerator::TextBuffer::Append(const TextBuffer& tb) {
96   for (auto& line : tb.lines) {
97     // TODO(bclayton): inefficent, consider optimizing
98     lines.emplace_back(Line{current_indent + line.indent, line.content});
99   }
100 }
101 
Insert(const TextBuffer & tb,size_t before,uint32_t indent)102 void TextGenerator::TextBuffer::Insert(const TextBuffer& tb,
103                                        size_t before,
104                                        uint32_t indent) {
105   if (before >= lines.size()) {
106     diag::List d;
107     TINT_ICE(Writer, d)
108         << "TextBuffer::Insert() called with before >= lines.size()\n"
109         << "  before:" << before << "\n"
110         << "  lines.size(): " << lines.size();
111     return;
112   }
113   size_t idx = 0;
114   for (auto& line : tb.lines) {
115     // TODO(bclayton): inefficent, consider optimizing
116     lines.insert(lines.begin() + before + idx,
117                  Line{indent + line.indent, line.content});
118     idx++;
119   }
120 }
121 
String(uint32_t indent) const122 std::string TextGenerator::TextBuffer::String(uint32_t indent /* = 0 */) const {
123   std::stringstream ss;
124   for (auto& line : lines) {
125     if (!line.content.empty()) {
126       for (uint32_t i = 0; i < indent + line.indent; i++) {
127         ss << " ";
128       }
129       ss << line.content;
130     }
131     ss << std::endl;
132   }
133   return ss.str();
134 }
135 
ScopedParen(std::ostream & stream)136 TextGenerator::ScopedParen::ScopedParen(std::ostream& stream) : s(stream) {
137   s << "(";
138 }
~ScopedParen()139 TextGenerator::ScopedParen::~ScopedParen() {
140   s << ")";
141 }
142 
ScopedIndent(TextGenerator * generator)143 TextGenerator::ScopedIndent::ScopedIndent(TextGenerator* generator)
144     : ScopedIndent(generator->current_buffer_) {}
145 
ScopedIndent(TextBuffer * buffer)146 TextGenerator::ScopedIndent::ScopedIndent(TextBuffer* buffer)
147     : buffer_(buffer) {
148   buffer_->IncrementIndent();
149 }
~ScopedIndent()150 TextGenerator::ScopedIndent::~ScopedIndent() {
151   buffer_->DecrementIndent();
152 }
153 
154 }  // namespace writer
155 }  // namespace tint
156