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