1 /* Copyright 2017 The TensorFlow Authors. All Rights Reserved.
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
16 #include <string>
17 #include <algorithm>
18 #include <list>
19
20 #include "tensorflow/java/src/gen/cc/source_writer.h"
21
22 namespace tensorflow {
23 namespace java {
24
SourceWriter()25 SourceWriter::SourceWriter() {
26 // Push an empty generic namespace at start, for simplification.
27 generic_namespaces_.push(new GenericNamespace());
28 }
29
~SourceWriter()30 SourceWriter::~SourceWriter() {
31 // Remove empty generic namespace added at start as well as any other
32 // namespace objects that haven't been removed.
33 while (!generic_namespaces_.empty()) {
34 GenericNamespace* generic_namespace = generic_namespaces_.top();
35 generic_namespaces_.pop();
36 delete generic_namespace;
37 }
38 }
39
Indent(int tab)40 SourceWriter& SourceWriter::Indent(int tab) {
41 left_margin_.resize(
42 std::max(static_cast<int>(left_margin_.size() + tab), 0), ' ');
43 return *this;
44 }
45
Prefix(const char * line_prefix)46 SourceWriter& SourceWriter::Prefix(const char* line_prefix) {
47 line_prefix_ = line_prefix;
48 return *this;
49 }
50
Write(const StringPiece & str)51 SourceWriter& SourceWriter::Write(const StringPiece& str) {
52 size_t line_pos = 0;
53 do {
54 size_t start_pos = line_pos;
55 line_pos = str.find('\n', start_pos);
56 if (line_pos != string::npos) {
57 ++line_pos;
58 Append(str.substr(start_pos, line_pos - start_pos));
59 newline_ = true;
60 } else {
61 Append(str.substr(start_pos, str.size() - start_pos));
62 }
63 } while (line_pos != string::npos && line_pos < str.size());
64
65 return *this;
66 }
67
WriteFromFile(const string & fname,Env * env)68 SourceWriter& SourceWriter::WriteFromFile(const string& fname, Env* env) {
69 string data_;
70 TF_CHECK_OK(ReadFileToString(env, fname, &data_));
71 return Write(data_);
72 }
73
Append(const StringPiece & str)74 SourceWriter& SourceWriter::Append(const StringPiece& str) {
75 if (!str.empty()) {
76 if (newline_) {
77 DoAppend(left_margin_ + line_prefix_);
78 newline_ = false;
79 }
80 DoAppend(str);
81 }
82 return *this;
83 }
84
AppendType(const Type & type)85 SourceWriter& SourceWriter::AppendType(const Type& type) {
86 if (type.wildcard()) {
87 Append("?");
88 } else {
89 Append(type.name());
90 if (!type.parameters().empty()) {
91 Append("<");
92 bool first = true;
93 for (const Type& t : type.parameters()) {
94 if (!first) {
95 Append(", ");
96 }
97 AppendType(t);
98 first = false;
99 }
100 Append(">");
101 }
102 }
103 return *this;
104 }
105
EndLine()106 SourceWriter& SourceWriter::EndLine() {
107 Append("\n");
108 newline_ = true;
109 return *this;
110 }
111
BeginBlock(const string & expression)112 SourceWriter& SourceWriter::BeginBlock(const string& expression) {
113 if (!expression.empty()) {
114 Append(expression + " {");
115 } else {
116 Append(newline_ ? "{" : " {");
117 }
118 return EndLine().Indent(2);
119 }
120
EndBlock()121 SourceWriter& SourceWriter::EndBlock() {
122 return Indent(-2).Append("}").EndLine();
123 }
124
BeginMethod(const Method & method,int modifiers,const Javadoc * javadoc)125 SourceWriter& SourceWriter::BeginMethod(const Method& method, int modifiers,
126 const Javadoc* javadoc) {
127 GenericNamespace* generic_namespace = PushGenericNamespace(modifiers);
128 if (!method.constructor()) {
129 generic_namespace->Visit(method.return_type());
130 }
131 for (const Variable& v : method.arguments()) {
132 generic_namespace->Visit(v.type());
133 }
134 EndLine();
135 if (javadoc != nullptr) {
136 WriteJavadoc(*javadoc);
137 }
138 if (!method.annotations().empty()) {
139 WriteAnnotations(method.annotations());
140 }
141 WriteModifiers(modifiers);
142 if (!generic_namespace->declared_types().empty()) {
143 WriteGenerics(generic_namespace->declared_types());
144 Append(" ");
145 }
146 if (!method.constructor()) {
147 AppendType(method.return_type()).Append(" ");
148 }
149 Append(method.name()).Append("(");
150 bool first = true;
151 for (const Variable& v : method.arguments()) {
152 if (!first) {
153 Append(", ");
154 }
155 AppendType(v.type()).Append(v.variadic() ? "... " : " ").Append(v.name());
156 first = false;
157 }
158 return Append(")").BeginBlock();
159 }
160
EndMethod()161 SourceWriter& SourceWriter::EndMethod() {
162 EndBlock();
163 PopGenericNamespace();
164 return *this;
165 }
166
BeginType(const Type & type,int modifiers,const std::list<Type> * extra_dependencies,const Javadoc * javadoc)167 SourceWriter& SourceWriter::BeginType(const Type& type, int modifiers,
168 const std::list<Type>* extra_dependencies,
169 const Javadoc* javadoc) {
170 if (!type.package().empty()) {
171 Append("package ").Append(type.package()).Append(";").EndLine();
172 }
173 TypeImporter type_importer(type.package());
174 type_importer.Visit(type);
175 if (extra_dependencies != nullptr) {
176 for (const Type& t : *extra_dependencies) {
177 type_importer.Visit(t);
178 }
179 }
180 if (!type_importer.imports().empty()) {
181 EndLine();
182 for (const string& s : type_importer.imports()) {
183 Append("import ").Append(s).Append(";").EndLine();
184 }
185 }
186 return BeginInnerType(type, modifiers, javadoc);
187 }
188
BeginInnerType(const Type & type,int modifiers,const Javadoc * javadoc)189 SourceWriter& SourceWriter::BeginInnerType(const Type& type, int modifiers,
190 const Javadoc* javadoc) {
191 GenericNamespace* generic_namespace = PushGenericNamespace(modifiers);
192 generic_namespace->Visit(type);
193 EndLine();
194 if (javadoc != nullptr) {
195 WriteJavadoc(*javadoc);
196 }
197 if (!type.annotations().empty()) {
198 WriteAnnotations(type.annotations());
199 }
200 WriteModifiers(modifiers);
201 CHECK_EQ(Type::Kind::CLASS, type.kind()) << ": Not supported yet";
202 Append("class ").Append(type.name());
203 if (!generic_namespace->declared_types().empty()) {
204 WriteGenerics(generic_namespace->declared_types());
205 }
206 if (!type.supertypes().empty()) {
207 bool first_interface = true;
208 for (const Type& t : type.supertypes()) {
209 if (t.kind() == Type::CLASS) { // superclass is always first in list
210 Append(" extends ");
211 } else if (first_interface) {
212 Append(" implements ");
213 first_interface = false;
214 } else {
215 Append(", ");
216 }
217 AppendType(t);
218 }
219 }
220 return BeginBlock();
221 }
222
EndType()223 SourceWriter& SourceWriter::EndType() {
224 EndBlock();
225 PopGenericNamespace();
226 return *this;
227 }
228
WriteField(const Variable & field,int modifiers,const Javadoc * javadoc)229 SourceWriter& SourceWriter::WriteField(const Variable& field, int modifiers,
230 const Javadoc* javadoc) {
231 // If present, write field javadoc only as one brief line
232 if (javadoc != nullptr && !javadoc->brief().empty()) {
233 Append("/** ").Append(javadoc->brief()).Append(" */").EndLine();
234 }
235 WriteModifiers(modifiers);
236 AppendType(field.type()).Append(" ").Append(field.name()).Append(";");
237 EndLine();
238 return *this;
239 }
240
WriteModifiers(int modifiers)241 SourceWriter& SourceWriter::WriteModifiers(int modifiers) {
242 if (modifiers & PUBLIC) {
243 Append("public ");
244 } else if (modifiers & PROTECTED) {
245 Append("protected ");
246 } else if (modifiers & PRIVATE) {
247 Append("private ");
248 }
249 if (modifiers & STATIC) {
250 Append("static ");
251 }
252 if (modifiers & FINAL) {
253 Append("final ");
254 }
255 return *this;
256 }
257
WriteJavadoc(const Javadoc & javadoc)258 SourceWriter& SourceWriter::WriteJavadoc(const Javadoc& javadoc) {
259 Append("/**").Prefix(" * ").EndLine();
260 bool do_line_break = false;
261 if (!javadoc.brief().empty()) {
262 Write(javadoc.brief()).EndLine();
263 do_line_break = true;
264 }
265 if (!javadoc.details().empty()) {
266 if (do_line_break) {
267 Append("<p>").EndLine();
268 }
269 Write(javadoc.details()).EndLine();
270 do_line_break = true;
271 }
272 if (!javadoc.tags().empty()) {
273 if (do_line_break) {
274 EndLine();
275 }
276 for (const auto& p : javadoc.tags()) {
277 Append("@" + p.first);
278 if (!p.second.empty()) {
279 Append(" ").Write(p.second);
280 }
281 EndLine();
282 }
283 }
284 return Prefix("").Append(" */").EndLine();
285 }
286
WriteAnnotations(const std::list<Annotation> & annotations)287 SourceWriter& SourceWriter::WriteAnnotations(
288 const std::list<Annotation>& annotations) {
289 for (const Annotation& a : annotations) {
290 Append("@" + a.name());
291 if (!a.attributes().empty()) {
292 Append("(").Append(a.attributes()).Append(")");
293 }
294 EndLine();
295 }
296 return *this;
297 }
298
WriteGenerics(const std::list<const Type * > & generics)299 SourceWriter& SourceWriter::WriteGenerics(
300 const std::list<const Type*>& generics) {
301 Append("<");
302 bool first = true;
303 for (const Type* pt : generics) {
304 if (!first) {
305 Append(", ");
306 }
307 Append(pt->name());
308 if (!pt->supertypes().empty()) {
309 Append(" extends ").AppendType(pt->supertypes().front());
310 }
311 first = false;
312 }
313 return Append(">");
314 }
315
PushGenericNamespace(int modifiers)316 SourceWriter::GenericNamespace* SourceWriter::PushGenericNamespace(
317 int modifiers) {
318 GenericNamespace* generic_namespace;
319 if (modifiers & STATIC) {
320 generic_namespace = new GenericNamespace();
321 } else {
322 generic_namespace = new GenericNamespace(generic_namespaces_.top());
323 }
324 generic_namespaces_.push(generic_namespace);
325 return generic_namespace;
326 }
327
PopGenericNamespace()328 void SourceWriter::PopGenericNamespace() {
329 GenericNamespace* generic_namespace = generic_namespaces_.top();
330 generic_namespaces_.pop();
331 delete generic_namespace;
332 }
333
Visit(const Type & type)334 void SourceWriter::TypeVisitor::Visit(const Type& type) {
335 DoVisit(type);
336 for (const Type& t : type.parameters()) {
337 Visit(t);
338 }
339 for (const Annotation& t : type.annotations()) {
340 DoVisit(t);
341 }
342 for (const Type& t : type.supertypes()) {
343 Visit(t);
344 }
345 }
346
DoVisit(const Type & type)347 void SourceWriter::GenericNamespace::DoVisit(const Type& type) {
348 // ignore non-generic parameters, wildcards and generics already declared
349 if (type.kind() == Type::GENERIC && !type.wildcard() &&
350 generic_names_.find(type.name()) == generic_names_.end()) {
351 declared_types_.push_back(&type);
352 generic_names_.insert(type.name());
353 }
354 }
355
DoVisit(const Type & type)356 void SourceWriter::TypeImporter::DoVisit(const Type& type) {
357 if (!type.package().empty() && type.package() != current_package_) {
358 imports_.insert(type.canonical_name());
359 }
360 }
361
362 } // namespace java
363 } // namespace tensorflow
364