printer.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc. All rights reserved.
  3. // https://developers.google.com/protocol-buffers/
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. // Author: kenton@google.com (Kenton Varda)
  31. // Based on original Protocol Buffers design by
  32. // Sanjay Ghemawat, Jeff Dean, and others.
  33. //
  34. // Utility class for writing text to a ZeroCopyOutputStream.
  35. #ifndef GOOGLE_PROTOBUF_IO_PRINTER_H__
  36. #define GOOGLE_PROTOBUF_IO_PRINTER_H__
  37. #include <map>
  38. #include <string>
  39. #include <vector>
  40. #include <google/protobuf/stubs/common.h>
  41. #include <google/protobuf/port_def.inc>
  42. namespace google {
  43. namespace protobuf {
  44. namespace io {
  45. class ZeroCopyOutputStream; // zero_copy_stream.h
  46. // Records annotations about a Printer's output.
  47. class PROTOBUF_EXPORT AnnotationCollector {
  48. public:
  49. // Annotation is a offset range and a payload pair.
  50. typedef std::pair<std::pair<size_t, size_t>, std::string> Annotation;
  51. // Records that the bytes in file_path beginning with begin_offset and ending
  52. // before end_offset are associated with the SourceCodeInfo-style path.
  53. virtual void AddAnnotation(size_t begin_offset, size_t end_offset,
  54. const std::string& file_path,
  55. const std::vector<int>& path) = 0;
  56. // TODO(gerbens) I don't see why we need virtuals here. Just a vector of
  57. // range, payload pairs stored in a context should suffice.
  58. virtual void AddAnnotationNew(Annotation& /* a */) {}
  59. virtual ~AnnotationCollector() {}
  60. };
  61. // Records annotations about a Printer's output to the given protocol buffer,
  62. // assuming that the buffer has an ::Annotation message exposing path,
  63. // source_file, begin and end fields.
  64. template <typename AnnotationProto>
  65. class AnnotationProtoCollector : public AnnotationCollector {
  66. public:
  67. // annotation_proto is the protocol buffer to which new Annotations should be
  68. // added. It is not owned by the AnnotationProtoCollector.
  69. explicit AnnotationProtoCollector(AnnotationProto* annotation_proto)
  70. : annotation_proto_(annotation_proto) {}
  71. // Override for AnnotationCollector::AddAnnotation.
  72. virtual void AddAnnotation(size_t begin_offset, size_t end_offset,
  73. const std::string& file_path,
  74. const std::vector<int>& path) override {
  75. typename AnnotationProto::Annotation* annotation =
  76. annotation_proto_->add_annotation();
  77. for (int i = 0; i < path.size(); ++i) {
  78. annotation->add_path(path[i]);
  79. }
  80. annotation->set_source_file(file_path);
  81. annotation->set_begin(begin_offset);
  82. annotation->set_end(end_offset);
  83. }
  84. // Override for AnnotationCollector::AddAnnotation.
  85. virtual void AddAnnotationNew(Annotation& a) override {
  86. auto* annotation = annotation_proto_->add_annotation();
  87. annotation->ParseFromString(a.second);
  88. annotation->set_begin(a.first.first);
  89. annotation->set_end(a.first.second);
  90. }
  91. private:
  92. // The protocol buffer to which new annotations should be added.
  93. AnnotationProto* const annotation_proto_;
  94. };
  95. // This simple utility class assists in code generation. It basically
  96. // allows the caller to define a set of variables and then output some
  97. // text with variable substitutions. Example usage:
  98. //
  99. // Printer printer(output, '$');
  100. // map<string, string> vars;
  101. // vars["name"] = "Bob";
  102. // printer.Print(vars, "My name is $name$.");
  103. //
  104. // The above writes "My name is Bob." to the output stream.
  105. //
  106. // Printer aggressively enforces correct usage, crashing (with assert failures)
  107. // in the case of undefined variables in debug builds. This helps greatly in
  108. // debugging code which uses it.
  109. //
  110. // If a Printer is constructed with an AnnotationCollector, it will provide it
  111. // with annotations that connect the Printer's output to paths that can identify
  112. // various descriptors. In the above example, if person_ is a descriptor that
  113. // identifies Bob, we can associate the output string "My name is Bob." with
  114. // a source path pointing to that descriptor with:
  115. //
  116. // printer.Annotate("name", person_);
  117. //
  118. // The AnnotationCollector will be sent an annotation linking the output range
  119. // covering "Bob" to the logical path provided by person_. Tools may use
  120. // this association to (for example) link "Bob" in the output back to the
  121. // source file that defined the person_ descriptor identifying Bob.
  122. //
  123. // Annotate can only examine variables substituted during the last call to
  124. // Print. It is invalid to refer to a variable that was used multiple times
  125. // in a single Print call.
  126. //
  127. // In full generality, one may specify a range of output text using a beginning
  128. // substitution variable and an ending variable. The resulting annotation will
  129. // span from the first character of the substituted value for the beginning
  130. // variable to the last character of the substituted value for the ending
  131. // variable. For example, the Annotate call above is equivalent to this one:
  132. //
  133. // printer.Annotate("name", "name", person_);
  134. //
  135. // This is useful if multiple variables combine to form a single span of output
  136. // that should be annotated with the same source path. For example:
  137. //
  138. // Printer printer(output, '$');
  139. // map<string, string> vars;
  140. // vars["first"] = "Alice";
  141. // vars["last"] = "Smith";
  142. // printer.Print(vars, "My name is $first$ $last$.");
  143. // printer.Annotate("first", "last", person_);
  144. //
  145. // This code would associate the span covering "Alice Smith" in the output with
  146. // the person_ descriptor.
  147. //
  148. // Note that the beginning variable must come before (or overlap with, in the
  149. // case of zero-sized substitution values) the ending variable.
  150. //
  151. // It is also sometimes useful to use variables with zero-sized values as
  152. // markers. This avoids issues with multiple references to the same variable
  153. // and also allows annotation ranges to span literal text from the Print
  154. // templates:
  155. //
  156. // Printer printer(output, '$');
  157. // map<string, string> vars;
  158. // vars["foo"] = "bar";
  159. // vars["function"] = "call";
  160. // vars["mark"] = "";
  161. // printer.Print(vars, "$function$($foo$,$foo$)$mark$");
  162. // printer.Annotate("function", "mark", call_);
  163. //
  164. // This code associates the span covering "call(bar,bar)" in the output with the
  165. // call_ descriptor.
  166. class PROTOBUF_EXPORT Printer {
  167. public:
  168. // Create a printer that writes text to the given output stream. Use the
  169. // given character as the delimiter for variables.
  170. Printer(ZeroCopyOutputStream* output, char variable_delimiter);
  171. // Create a printer that writes text to the given output stream. Use the
  172. // given character as the delimiter for variables. If annotation_collector
  173. // is not null, Printer will provide it with annotations about code written
  174. // to the stream. annotation_collector is not owned by Printer.
  175. Printer(ZeroCopyOutputStream* output, char variable_delimiter,
  176. AnnotationCollector* annotation_collector);
  177. ~Printer();
  178. // Link a substitution variable emitted by the last call to Print to the
  179. // object described by descriptor.
  180. template <typename SomeDescriptor>
  181. void Annotate(const char* varname, const SomeDescriptor* descriptor) {
  182. Annotate(varname, varname, descriptor);
  183. }
  184. // Link the output range defined by the substitution variables as emitted by
  185. // the last call to Print to the object described by descriptor. The range
  186. // begins at begin_varname's value and ends after the last character of the
  187. // value substituted for end_varname.
  188. template <typename SomeDescriptor>
  189. void Annotate(const char* begin_varname, const char* end_varname,
  190. const SomeDescriptor* descriptor) {
  191. if (annotation_collector_ == NULL) {
  192. // Annotations aren't turned on for this Printer, so don't pay the cost
  193. // of building the location path.
  194. return;
  195. }
  196. std::vector<int> path;
  197. descriptor->GetLocationPath(&path);
  198. Annotate(begin_varname, end_varname, descriptor->file()->name(), path);
  199. }
  200. // Link a substitution variable emitted by the last call to Print to the file
  201. // with path file_name.
  202. void Annotate(const char* varname, const std::string& file_name) {
  203. Annotate(varname, varname, file_name);
  204. }
  205. // Link the output range defined by the substitution variables as emitted by
  206. // the last call to Print to the file with path file_name. The range begins
  207. // at begin_varname's value and ends after the last character of the value
  208. // substituted for end_varname.
  209. void Annotate(const char* begin_varname, const char* end_varname,
  210. const std::string& file_name) {
  211. if (annotation_collector_ == NULL) {
  212. // Annotations aren't turned on for this Printer.
  213. return;
  214. }
  215. std::vector<int> empty_path;
  216. Annotate(begin_varname, end_varname, file_name, empty_path);
  217. }
  218. // Print some text after applying variable substitutions. If a particular
  219. // variable in the text is not defined, this will crash. Variables to be
  220. // substituted are identified by their names surrounded by delimiter
  221. // characters (as given to the constructor). The variable bindings are
  222. // defined by the given map.
  223. void Print(const std::map<std::string, std::string>& variables,
  224. const char* text);
  225. // Like the first Print(), except the substitutions are given as parameters.
  226. template <typename... Args>
  227. void Print(const char* text, const Args&... args) {
  228. std::map<std::string, std::string> vars;
  229. PrintInternal(&vars, text, args...);
  230. }
  231. // Indent text by two spaces. After calling Indent(), two spaces will be
  232. // inserted at the beginning of each line of text. Indent() may be called
  233. // multiple times to produce deeper indents.
  234. void Indent();
  235. // Reduces the current indent level by two spaces, or crashes if the indent
  236. // level is zero.
  237. void Outdent();
  238. // Write a string to the output buffer.
  239. // This method does not look for newlines to add indentation.
  240. void PrintRaw(const std::string& data);
  241. // Write a zero-delimited string to output buffer.
  242. // This method does not look for newlines to add indentation.
  243. void PrintRaw(const char* data);
  244. // Write some bytes to the output buffer.
  245. // This method does not look for newlines to add indentation.
  246. void WriteRaw(const char* data, int size);
  247. // FormatInternal is a helper function not meant to use directly, use
  248. // compiler::cpp::Formatter instead. This function is meant to support
  249. // formatting text using named variables (eq. "$foo$) from a lookup map (vars)
  250. // and variables directly supplied by arguments (eq "$1$" meaning first
  251. // argument which is the zero index element of args).
  252. void FormatInternal(const std::vector<std::string>& args,
  253. const std::map<std::string, std::string>& vars,
  254. const char* format);
  255. // True if any write to the underlying stream failed. (We don't just
  256. // crash in this case because this is an I/O failure, not a programming
  257. // error.)
  258. bool failed() const { return failed_; }
  259. private:
  260. // Link the output range defined by the substitution variables as emitted by
  261. // the last call to Print to the object found at the SourceCodeInfo-style path
  262. // in a file with path file_path. The range begins at the start of
  263. // begin_varname's value and ends after the last character of the value
  264. // substituted for end_varname. Note that begin_varname and end_varname
  265. // may refer to the same variable.
  266. void Annotate(const char* begin_varname, const char* end_varname,
  267. const std::string& file_path, const std::vector<int>& path);
  268. // Base case
  269. void PrintInternal(std::map<std::string, std::string>* vars,
  270. const char* text) {
  271. Print(*vars, text);
  272. }
  273. template <typename... Args>
  274. void PrintInternal(std::map<std::string, std::string>* vars, const char* text,
  275. const char* key, const std::string& value,
  276. const Args&... args) {
  277. (*vars)[key] = value;
  278. PrintInternal(vars, text, args...);
  279. }
  280. // Copy size worth of bytes from data to buffer_.
  281. void CopyToBuffer(const char* data, int size);
  282. void push_back(char c) {
  283. if (failed_) return;
  284. if (buffer_size_ == 0) {
  285. if (!Next()) return;
  286. }
  287. *buffer_++ = c;
  288. buffer_size_--;
  289. offset_++;
  290. }
  291. bool Next();
  292. inline void IndentIfAtStart();
  293. const char* WriteVariable(
  294. const std::vector<std::string>& args,
  295. const std::map<std::string, std::string>& vars, const char* format,
  296. int* arg_index,
  297. std::vector<AnnotationCollector::Annotation>* annotations);
  298. const char variable_delimiter_;
  299. ZeroCopyOutputStream* const output_;
  300. char* buffer_;
  301. int buffer_size_;
  302. // The current position, in bytes, in the output stream. This is equivalent
  303. // to the total number of bytes that have been written so far. This value is
  304. // used to calculate annotation ranges in the substitutions_ map below.
  305. size_t offset_;
  306. std::string indent_;
  307. bool at_start_of_line_;
  308. bool failed_;
  309. // A map from variable name to [start, end) offsets in the output buffer.
  310. // These refer to the offsets used for a variable after the last call to
  311. // Print. If a variable was used more than once, the entry used in
  312. // this map is set to a negative-length span. For singly-used variables, the
  313. // start offset is the beginning of the substitution; the end offset is the
  314. // last byte of the substitution plus one (such that (end - start) is the
  315. // length of the substituted string).
  316. std::map<std::string, std::pair<size_t, size_t> > substitutions_;
  317. // Keeps track of the keys in substitutions_ that need to be updated when
  318. // indents are inserted. These are keys that refer to the beginning of the
  319. // current line.
  320. std::vector<std::string> line_start_variables_;
  321. // Returns true and sets range to the substitution range in the output for
  322. // varname if varname was used once in the last call to Print. If varname
  323. // was not used, or if it was used multiple times, returns false (and
  324. // fails a debug assertion).
  325. bool GetSubstitutionRange(const char* varname,
  326. std::pair<size_t, size_t>* range);
  327. // If non-null, annotation_collector_ is used to store annotations about
  328. // generated code.
  329. AnnotationCollector* const annotation_collector_;
  330. GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Printer);
  331. };
  332. } // namespace io
  333. } // namespace protobuf
  334. } // namespace google
  335. #include <google/protobuf/port_undef.inc>
  336. #endif // GOOGLE_PROTOBUF_IO_PRINTER_H__