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 #ifndef TENSORFLOW_JAVA_SRC_GEN_CC_SOURCE_WRITER_H_ 17 #define TENSORFLOW_JAVA_SRC_GEN_CC_SOURCE_WRITER_H_ 18 19 #include <string> 20 #include <stack> 21 #include <list> 22 #include <set> 23 24 #include "tensorflow/core/lib/core/stringpiece.h" 25 #include "tensorflow/core/platform/env.h" 26 #include "tensorflow/java/src/gen/cc/java_defs.h" 27 28 namespace tensorflow { 29 namespace java { 30 31 // A class for writing Java source code. 32 class SourceWriter { 33 public: 34 SourceWriter(); 35 36 virtual ~SourceWriter(); 37 38 // Indents following lines with white spaces. 39 // 40 // Indentation is cumulative, i.e. the provided tabulation is added to the 41 // current indentation value. If the tabulation is negative, the operation 42 // will outdent the source code, until the indentation reaches 0 again. 43 // 44 // For example, calling Indent(2) twice will indent code with 4 white 45 // spaces. Then calling Indent(-2) will outdent the code back to 2 white 46 // spaces. 47 SourceWriter& Indent(int tab); 48 49 // Prefixes following lines with provided character(s). 50 // 51 // A common use case of a prefix is for commenting or documenting the code. 52 // 53 // The prefix is written after the indentation, For example, invoking 54 // Indent(2)->Prefix("//") will result in prefixing lines with " //". 55 // 56 // An empty value ("") will remove any line prefix that was previously set. 57 SourceWriter& Prefix(const char* line_prefix); 58 59 // Writes a source code snippet. 60 // 61 // The data might potentially contain newline characters, therefore it will 62 // be scanned to ensure that each line is indented and prefixed properly, 63 // making it a bit slower than Append(). 64 SourceWriter& Write(const StringPiece& str); 65 66 // Writes a source code snippet read from a file. 67 // 68 // All lines of the file at the provided path will be read and written back 69 // to the output of this writer in regard of its current attributes (e.g. 70 // the indentation, prefix, etc.) 71 SourceWriter& WriteFromFile(const string& fname, Env* env = Env::Default()); 72 73 // Appends a piece of source code. 74 // 75 // It is expected that no newline character is present in the data provided, 76 // otherwise Write() must be used. 77 SourceWriter& Append(const StringPiece& str); 78 79 // Appends a type to the current line. 80 // 81 // The type is written in its simple form (i.e. not prefixed by its package) 82 // and followed by any parameter types it has enclosed in brackets (<>). 83 SourceWriter& AppendType(const Type& type); 84 85 // Appends a newline character. 86 // 87 // Data written after calling this method will start on a new line, in respect 88 // of the current indentation. 89 SourceWriter& EndLine(); 90 91 // Begins a block of source code. 92 // 93 // This method appends a new opening brace to the current data and indent the 94 // next lines according to Google Java Style Guide. The block can optionally 95 // be preceded by an expression (e.g. Append("if(true)").BeginBlock();) 96 SourceWriter& BeginBlock(const string& expression = ""); 97 98 // Ends the current block of source code. 99 // 100 // This method appends a new closing brace to the current data and outdent the 101 // next lines back to the margin used before BeginBlock() was invoked. 102 SourceWriter& EndBlock(); 103 104 // Begins to write a method. 105 // 106 // This method outputs the signature of the Java method from the data passed 107 // in the 'method' parameter and starts a new block. Modifiers are also passed 108 // in parameter to define the access scope of this method and, optionally, 109 // a Javadoc. 110 SourceWriter& BeginMethod(const Method& method, int modifiers, 111 const Javadoc* javadoc = nullptr); 112 113 // Ends the current method. 114 // 115 // This method ends the block of code that has begun when invoking 116 // BeginMethod() prior to this. 117 SourceWriter& EndMethod(); 118 119 // Begins to write the main type of a source file. 120 // 121 // This method outputs the declaration of the Java type from the data passed 122 // in the 'type' parameter and starts a new block. Modifiers are also passed 123 // in parameter to define the access scope of this type and, optionally, 124 // a Javadoc. 125 // 126 // If not null, all types found in the 'extra_dependencies' list will be 127 // imported before declaring the new type. 128 SourceWriter& BeginType(const Type& type, int modifiers, 129 const std::list<Type>* extra_dependencies = nullptr, 130 const Javadoc* javadoc = nullptr); 131 132 // Begins to write a new inner type. 133 // 134 // This method outputs the declaration of the Java type from the data passed 135 // in the 'type' parameter and starts a new block. Modifiers are also passed 136 // in parameter to define the accesses and the scope of this type and, 137 // optionally, a Javadoc. 138 SourceWriter& BeginInnerType(const Type& type, int modifiers, 139 const Javadoc* javadoc = nullptr); 140 141 // Ends the current type. 142 // 143 // This method ends the block of code that has begun when invoking 144 // BeginType() or BeginInnerType() prior to this. 145 SourceWriter& EndType(); 146 147 // Writes a variable as fields of a type. 148 // 149 // This method must be called within the definition of a type (see BeginType() 150 // or BeginInnerType()). Modifiers are also be passed in parameter to define 151 // the accesses and the scope of this field and, optionally, a Javadoc. 152 SourceWriter& WriteField(const Variable& field, int modifiers, 153 const Javadoc* javadoc = nullptr); 154 155 protected: 156 virtual void DoAppend(const StringPiece& str) = 0; 157 158 private: 159 // A utility base class for visiting elements of a type. 160 class TypeVisitor { 161 public: 162 virtual ~TypeVisitor() = default; 163 void Visit(const Type& type); 164 165 protected: 166 virtual void DoVisit(const Type& type) = 0; 167 }; 168 169 // A utility class for keeping track of declared generics in a given scope. 170 class GenericNamespace : public TypeVisitor { 171 public: 172 GenericNamespace() = default; GenericNamespace(const GenericNamespace * parent)173 explicit GenericNamespace(const GenericNamespace* parent) 174 : generic_names_(parent->generic_names_) {} declared_types()175 std::list<const Type*> declared_types() { 176 return declared_types_; 177 } 178 protected: 179 virtual void DoVisit(const Type& type); 180 181 private: 182 std::list<const Type*> declared_types_; 183 std::set<string> generic_names_; 184 }; 185 186 // A utility class for collecting a list of import statements to declare. 187 class TypeImporter : public TypeVisitor { 188 public: TypeImporter(const string & current_package)189 explicit TypeImporter(const string& current_package) 190 : current_package_(current_package) {} 191 virtual ~TypeImporter() = default; imports()192 const std::set<string> imports() { 193 return imports_; 194 } 195 protected: 196 virtual void DoVisit(const Type& type); 197 198 private: 199 string current_package_; 200 std::set<string> imports_; 201 }; 202 203 string left_margin_; 204 string line_prefix_; 205 bool newline_ = true; 206 std::stack<GenericNamespace*> generic_namespaces_; 207 208 SourceWriter& WriteModifiers(int modifiers); 209 SourceWriter& WriteJavadoc(const Javadoc& javadoc); 210 SourceWriter& WriteAnnotations(const std::list<Annotation>& annotations); 211 SourceWriter& WriteGenerics(const std::list<const Type*>& generics); 212 GenericNamespace* PushGenericNamespace(int modifiers); 213 void PopGenericNamespace(); 214 }; 215 216 // A writer that outputs source code into a file. 217 // 218 // Note: the writer does not acquire the ownership of the file being passed in 219 // parameter. 220 class SourceFileWriter : public SourceWriter { 221 public: SourceFileWriter(WritableFile * file)222 explicit SourceFileWriter(WritableFile* file) : file_(file) {} 223 virtual ~SourceFileWriter() = default; 224 225 protected: DoAppend(const StringPiece & str)226 void DoAppend(const StringPiece& str) override { 227 TF_CHECK_OK(file_->Append(str)); 228 } 229 230 private: 231 WritableFile* file_; 232 }; 233 234 // A writer that outputs source code into a string buffer. 235 class SourceBufferWriter : public SourceWriter { 236 public: SourceBufferWriter()237 SourceBufferWriter() : owns_buffer_(true), buffer_(new string()) {} SourceBufferWriter(string * buffer)238 explicit SourceBufferWriter(string* buffer) 239 : owns_buffer_(false), buffer_(buffer) {} ~SourceBufferWriter()240 virtual ~SourceBufferWriter() { 241 if (owns_buffer_) delete buffer_; 242 } str()243 const string& str() { return *buffer_; } 244 245 protected: DoAppend(const StringPiece & str)246 void DoAppend(const StringPiece& str) override { 247 buffer_->append(str.begin(), str.end()); 248 } 249 250 private: 251 bool owns_buffer_; 252 string* buffer_; 253 }; 254 255 } // namespace java 256 } // namespace tensorflow 257 258 #endif // TENSORFLOW_JAVA_SRC_GEN_CC_SOURCE_WRITER_H_ 259