php_generator.cc 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443
  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. #include <google/protobuf/compiler/php/php_generator.h>
  31. #include <google/protobuf/compiler/code_generator.h>
  32. #include <google/protobuf/compiler/plugin.h>
  33. #include <google/protobuf/descriptor.h>
  34. #include <google/protobuf/descriptor.pb.h>
  35. #include <google/protobuf/io/printer.h>
  36. #include <google/protobuf/io/zero_copy_stream.h>
  37. #include <google/protobuf/stubs/strutil.h>
  38. #include <sstream>
  39. using google::protobuf::internal::scoped_ptr;
  40. const std::string kDescriptorFile = "google/protobuf/descriptor.proto";
  41. const std::string kEmptyFile = "google/protobuf/empty.proto";
  42. const std::string kEmptyMetadataFile = "GPBMetadata/Google/Protobuf/GPBEmpty.php";
  43. const std::string kDescriptorMetadataFile =
  44. "GPBMetadata/Google/Protobuf/Internal/Descriptor.php";
  45. const std::string kDescriptorDirName = "Google/Protobuf/Internal";
  46. const std::string kDescriptorPackageName = "Google\\Protobuf\\Internal";
  47. const char* const kReservedNames[] = {
  48. "abstract", "and", "array", "as", "break",
  49. "callable", "case", "catch", "class", "clone",
  50. "const", "continue", "declare", "default", "die",
  51. "do", "echo", "else", "elseif", "empty",
  52. "enddeclare", "endfor", "endforeach", "endif", "endswitch",
  53. "endwhile", "eval", "exit", "extends", "final",
  54. "for", "foreach", "function", "global", "goto",
  55. "if", "implements", "include", "include_once", "instanceof",
  56. "insteadof", "interface", "isset", "list", "namespace",
  57. "new", "or", "print", "private", "protected",
  58. "public", "require", "require_once", "return", "static",
  59. "switch", "throw", "trait", "try", "unset",
  60. "use", "var", "while", "xor", "int",
  61. "float", "bool", "string", "true", "false",
  62. "null", "void", "iterable"};
  63. const char* const kValidConstantNames[] = {
  64. "int", "float", "bool", "string", "true",
  65. "false", "null", "void", "iterable",
  66. };
  67. const int kReservedNamesSize = 73;
  68. const int kValidConstantNamesSize = 9;
  69. const int kFieldSetter = 1;
  70. const int kFieldGetter = 2;
  71. const int kFieldProperty = 3;
  72. namespace google {
  73. namespace protobuf {
  74. namespace compiler {
  75. namespace php {
  76. // Forward decls.
  77. std::string PhpName(const std::string& full_name, bool is_descriptor);
  78. std::string DefaultForField(FieldDescriptor* field);
  79. std::string IntToString(int32 value);
  80. std::string FilenameToClassname(const string& filename);
  81. std::string GeneratedMetadataFileName(const std::string& proto_file,
  82. bool is_descriptor);
  83. std::string LabelForField(FieldDescriptor* field);
  84. std::string TypeName(FieldDescriptor* field);
  85. std::string UnderscoresToCamelCase(const string& name, bool cap_first_letter);
  86. std::string EscapeDollor(const string& to_escape);
  87. std::string BinaryToHex(const string& binary);
  88. void Indent(io::Printer* printer);
  89. void Outdent(io::Printer* printer);
  90. void GenerateMessageDocComment(io::Printer* printer, const Descriptor* message,
  91. int is_descriptor);
  92. void GenerateFieldDocComment(io::Printer* printer, const FieldDescriptor* field,
  93. int is_descriptor, int function_type);
  94. void GenerateEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_,
  95. int is_descriptor);
  96. void GenerateEnumValueDocComment(io::Printer* printer,
  97. const EnumValueDescriptor* value);
  98. void GenerateServiceDocComment(io::Printer* printer,
  99. const ServiceDescriptor* service);
  100. void GenerateServiceMethodDocComment(io::Printer* printer,
  101. const MethodDescriptor* method);
  102. std::string RenameEmpty(const std::string& name) {
  103. if (name == "Empty") {
  104. return "GPBEmpty";
  105. } else {
  106. return name;
  107. }
  108. }
  109. std::string MessageFullName(const Descriptor* message, bool is_descriptor) {
  110. if (is_descriptor) {
  111. return StringReplace(message->full_name(),
  112. "google.protobuf",
  113. "google.protobuf.internal", false);
  114. } else {
  115. return message->full_name();
  116. }
  117. }
  118. std::string EnumFullName(const EnumDescriptor* envm, bool is_descriptor) {
  119. if (is_descriptor) {
  120. return StringReplace(envm->full_name(),
  121. "google.protobuf",
  122. "google.protobuf.internal", false);
  123. } else {
  124. return envm->full_name();
  125. }
  126. }
  127. template <typename DescriptorType>
  128. std::string ClassNamePrefix(const string& classname,
  129. const DescriptorType* desc) {
  130. const string& prefix = (desc->file()->options()).php_class_prefix();
  131. if (prefix != "") {
  132. return prefix;
  133. }
  134. bool is_reserved = false;
  135. string lower = classname;
  136. transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
  137. for (int i = 0; i < kReservedNamesSize; i++) {
  138. if (lower == kReservedNames[i]) {
  139. is_reserved = true;
  140. break;
  141. }
  142. }
  143. if (is_reserved) {
  144. if (desc->file()->package() == "google.protobuf") {
  145. return "GPB";
  146. } else {
  147. return "PB";
  148. }
  149. }
  150. return "";
  151. }
  152. std::string ConstantNamePrefix(const string& classname) {
  153. bool is_reserved = false;
  154. string lower = classname;
  155. transform(lower.begin(), lower.end(), lower.begin(), ::tolower);
  156. for (int i = 0; i < kReservedNamesSize; i++) {
  157. if (lower == kReservedNames[i]) {
  158. is_reserved = true;
  159. break;
  160. }
  161. }
  162. for (int i = 0; i < kValidConstantNamesSize; i++) {
  163. if (lower == kValidConstantNames[i]) {
  164. is_reserved = false;
  165. break;
  166. }
  167. }
  168. if (is_reserved) {
  169. return "PB";
  170. }
  171. return "";
  172. }
  173. template <typename DescriptorType>
  174. std::string NamespacedName(const string& classname,
  175. const DescriptorType* desc, bool is_descriptor) {
  176. if (desc->file()->options().has_php_namespace()) {
  177. const string& php_namespace = desc->file()->options().php_namespace();
  178. if (php_namespace != "") {
  179. return php_namespace + '\\' + classname;
  180. } else {
  181. return classname;
  182. }
  183. }
  184. if (desc->file()->package() == "") {
  185. return classname;
  186. } else {
  187. return PhpName(desc->file()->package(), is_descriptor) + '\\' +
  188. classname;
  189. }
  190. }
  191. template <typename DescriptorType>
  192. std::string FullClassName(const DescriptorType* desc, bool is_descriptor) {
  193. string classname = GeneratedClassName(desc);
  194. return NamespacedName(classname, desc, is_descriptor);
  195. }
  196. std::string FullClassName(const ServiceDescriptor* desc, bool is_descriptor) {
  197. string classname = GeneratedClassName(desc);
  198. return NamespacedName(classname, desc, is_descriptor);
  199. }
  200. std::string PhpName(const std::string& full_name, bool is_descriptor) {
  201. if (is_descriptor) {
  202. return kDescriptorPackageName;
  203. }
  204. std::string result;
  205. bool cap_next_letter = true;
  206. for (int i = 0; i < full_name.size(); i++) {
  207. if ('a' <= full_name[i] && full_name[i] <= 'z' && cap_next_letter) {
  208. result += full_name[i] + ('A' - 'a');
  209. cap_next_letter = false;
  210. } else if (full_name[i] == '.') {
  211. result += '\\';
  212. cap_next_letter = true;
  213. } else {
  214. result += full_name[i];
  215. cap_next_letter = false;
  216. }
  217. }
  218. return result;
  219. }
  220. std::string DefaultForField(const FieldDescriptor* field) {
  221. switch (field->type()) {
  222. case FieldDescriptor::TYPE_INT32:
  223. case FieldDescriptor::TYPE_INT64:
  224. case FieldDescriptor::TYPE_UINT32:
  225. case FieldDescriptor::TYPE_UINT64:
  226. case FieldDescriptor::TYPE_SINT32:
  227. case FieldDescriptor::TYPE_SINT64:
  228. case FieldDescriptor::TYPE_FIXED32:
  229. case FieldDescriptor::TYPE_FIXED64:
  230. case FieldDescriptor::TYPE_SFIXED32:
  231. case FieldDescriptor::TYPE_SFIXED64:
  232. case FieldDescriptor::TYPE_ENUM: return "0";
  233. case FieldDescriptor::TYPE_DOUBLE:
  234. case FieldDescriptor::TYPE_FLOAT: return "0.0";
  235. case FieldDescriptor::TYPE_BOOL: return "false";
  236. case FieldDescriptor::TYPE_STRING:
  237. case FieldDescriptor::TYPE_BYTES: return "''";
  238. case FieldDescriptor::TYPE_MESSAGE:
  239. case FieldDescriptor::TYPE_GROUP: return "null";
  240. default: assert(false); return "";
  241. }
  242. }
  243. std::string GeneratedMetadataFileName(const std::string& proto_file,
  244. bool is_descriptor) {
  245. int start_index = 0;
  246. int first_index = proto_file.find_first_of("/", start_index);
  247. std::string result = "GPBMetadata/";
  248. if (proto_file == kEmptyFile) {
  249. return kEmptyMetadataFile;
  250. }
  251. if (is_descriptor) {
  252. return kDescriptorMetadataFile;
  253. }
  254. // Append directory name.
  255. std::string file_no_suffix;
  256. int lastindex = proto_file.find_last_of(".");
  257. if (proto_file == kEmptyFile) {
  258. return kEmptyMetadataFile;
  259. } else {
  260. file_no_suffix = proto_file.substr(0, lastindex);
  261. }
  262. while (first_index != string::npos) {
  263. result += UnderscoresToCamelCase(
  264. file_no_suffix.substr(start_index, first_index - start_index), true);
  265. result += "/";
  266. start_index = first_index + 1;
  267. first_index = file_no_suffix.find_first_of("/", start_index);
  268. }
  269. // Append file name.
  270. result += RenameEmpty(UnderscoresToCamelCase(
  271. file_no_suffix.substr(start_index, first_index - start_index), true));
  272. return result += ".php";
  273. }
  274. std::string GeneratedMessageFileName(const Descriptor* message,
  275. bool is_descriptor) {
  276. std::string result = FullClassName(message, is_descriptor);
  277. for (int i = 0; i < result.size(); i++) {
  278. if (result[i] == '\\') {
  279. result[i] = '/';
  280. }
  281. }
  282. return result + ".php";
  283. }
  284. std::string GeneratedEnumFileName(const EnumDescriptor* en,
  285. bool is_descriptor) {
  286. std::string result = FullClassName(en, is_descriptor);
  287. for (int i = 0; i < result.size(); i++) {
  288. if (result[i] == '\\') {
  289. result[i] = '/';
  290. }
  291. }
  292. return result + ".php";
  293. }
  294. std::string GeneratedServiceFileName(const ServiceDescriptor* service,
  295. bool is_descriptor) {
  296. std::string result = FullClassName(service, is_descriptor) + "Interface";
  297. for (int i = 0; i < result.size(); i++) {
  298. if (result[i] == '\\') {
  299. result[i] = '/';
  300. }
  301. }
  302. return result + ".php";
  303. }
  304. std::string IntToString(int32 value) {
  305. std::ostringstream os;
  306. os << value;
  307. return os.str();
  308. }
  309. std::string LabelForField(const FieldDescriptor* field) {
  310. switch (field->label()) {
  311. case FieldDescriptor::LABEL_OPTIONAL: return "optional";
  312. case FieldDescriptor::LABEL_REQUIRED: return "required";
  313. case FieldDescriptor::LABEL_REPEATED: return "repeated";
  314. default: assert(false); return "";
  315. }
  316. }
  317. std::string TypeName(const FieldDescriptor* field) {
  318. switch (field->type()) {
  319. case FieldDescriptor::TYPE_INT32: return "int32";
  320. case FieldDescriptor::TYPE_INT64: return "int64";
  321. case FieldDescriptor::TYPE_UINT32: return "uint32";
  322. case FieldDescriptor::TYPE_UINT64: return "uint64";
  323. case FieldDescriptor::TYPE_SINT32: return "sint32";
  324. case FieldDescriptor::TYPE_SINT64: return "sint64";
  325. case FieldDescriptor::TYPE_FIXED32: return "fixed32";
  326. case FieldDescriptor::TYPE_FIXED64: return "fixed64";
  327. case FieldDescriptor::TYPE_SFIXED32: return "sfixed32";
  328. case FieldDescriptor::TYPE_SFIXED64: return "sfixed64";
  329. case FieldDescriptor::TYPE_DOUBLE: return "double";
  330. case FieldDescriptor::TYPE_FLOAT: return "float";
  331. case FieldDescriptor::TYPE_BOOL: return "bool";
  332. case FieldDescriptor::TYPE_ENUM: return "enum";
  333. case FieldDescriptor::TYPE_STRING: return "string";
  334. case FieldDescriptor::TYPE_BYTES: return "bytes";
  335. case FieldDescriptor::TYPE_MESSAGE: return "message";
  336. case FieldDescriptor::TYPE_GROUP: return "group";
  337. default: assert(false); return "";
  338. }
  339. }
  340. std::string PhpSetterTypeName(const FieldDescriptor* field, bool is_descriptor) {
  341. if (field->is_map()) {
  342. return "array|\\Google\\Protobuf\\Internal\\MapField";
  343. }
  344. string type;
  345. switch (field->type()) {
  346. case FieldDescriptor::TYPE_INT32:
  347. case FieldDescriptor::TYPE_UINT32:
  348. case FieldDescriptor::TYPE_SINT32:
  349. case FieldDescriptor::TYPE_FIXED32:
  350. case FieldDescriptor::TYPE_SFIXED32:
  351. case FieldDescriptor::TYPE_ENUM:
  352. type = "int";
  353. break;
  354. case FieldDescriptor::TYPE_INT64:
  355. case FieldDescriptor::TYPE_UINT64:
  356. case FieldDescriptor::TYPE_SINT64:
  357. case FieldDescriptor::TYPE_FIXED64:
  358. case FieldDescriptor::TYPE_SFIXED64:
  359. type = "int|string";
  360. break;
  361. case FieldDescriptor::TYPE_DOUBLE:
  362. case FieldDescriptor::TYPE_FLOAT:
  363. type = "float";
  364. break;
  365. case FieldDescriptor::TYPE_BOOL:
  366. type = "bool";
  367. break;
  368. case FieldDescriptor::TYPE_STRING:
  369. case FieldDescriptor::TYPE_BYTES:
  370. type = "string";
  371. break;
  372. case FieldDescriptor::TYPE_MESSAGE:
  373. type = "\\" + FullClassName(field->message_type(), is_descriptor);
  374. break;
  375. case FieldDescriptor::TYPE_GROUP:
  376. return "null";
  377. default: assert(false); return "";
  378. }
  379. if (field->is_repeated()) {
  380. // accommodate for edge case with multiple types.
  381. size_t start_pos = type.find("|");
  382. if (start_pos != std::string::npos) {
  383. type.replace(start_pos, 1, "[]|");
  384. }
  385. type += "[]|\\Google\\Protobuf\\Internal\\RepeatedField";
  386. }
  387. return type;
  388. }
  389. std::string PhpGetterTypeName(const FieldDescriptor* field, bool is_descriptor) {
  390. if (field->is_map()) {
  391. return "\\Google\\Protobuf\\Internal\\MapField";
  392. }
  393. if (field->is_repeated()) {
  394. return "\\Google\\Protobuf\\Internal\\RepeatedField";
  395. }
  396. switch (field->type()) {
  397. case FieldDescriptor::TYPE_INT32:
  398. case FieldDescriptor::TYPE_UINT32:
  399. case FieldDescriptor::TYPE_SINT32:
  400. case FieldDescriptor::TYPE_FIXED32:
  401. case FieldDescriptor::TYPE_SFIXED32:
  402. case FieldDescriptor::TYPE_ENUM: return "int";
  403. case FieldDescriptor::TYPE_INT64:
  404. case FieldDescriptor::TYPE_UINT64:
  405. case FieldDescriptor::TYPE_SINT64:
  406. case FieldDescriptor::TYPE_FIXED64:
  407. case FieldDescriptor::TYPE_SFIXED64: return "int|string";
  408. case FieldDescriptor::TYPE_DOUBLE:
  409. case FieldDescriptor::TYPE_FLOAT: return "float";
  410. case FieldDescriptor::TYPE_BOOL: return "bool";
  411. case FieldDescriptor::TYPE_STRING:
  412. case FieldDescriptor::TYPE_BYTES: return "string";
  413. case FieldDescriptor::TYPE_MESSAGE:
  414. return "\\" + FullClassName(field->message_type(), is_descriptor);
  415. case FieldDescriptor::TYPE_GROUP: return "null";
  416. default: assert(false); return "";
  417. }
  418. }
  419. std::string EnumOrMessageSuffix(
  420. const FieldDescriptor* field, bool is_descriptor) {
  421. if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
  422. return ", '" + MessageFullName(field->message_type(), is_descriptor) + "'";
  423. }
  424. if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
  425. return ", '" + EnumFullName(field->enum_type(), is_descriptor) + "'";
  426. }
  427. return "";
  428. }
  429. // Converts a name to camel-case. If cap_first_letter is true, capitalize the
  430. // first letter.
  431. std::string UnderscoresToCamelCase(const string& input, bool cap_first_letter) {
  432. std::string result;
  433. for (int i = 0; i < input.size(); i++) {
  434. if ('a' <= input[i] && input[i] <= 'z') {
  435. if (cap_first_letter) {
  436. result += input[i] + ('A' - 'a');
  437. } else {
  438. result += input[i];
  439. }
  440. cap_first_letter = false;
  441. } else if ('A' <= input[i] && input[i] <= 'Z') {
  442. if (i == 0 && !cap_first_letter) {
  443. // Force first letter to lower-case unless explicitly told to
  444. // capitalize it.
  445. result += input[i] + ('a' - 'A');
  446. } else {
  447. // Capital letters after the first are left as-is.
  448. result += input[i];
  449. }
  450. cap_first_letter = false;
  451. } else if ('0' <= input[i] && input[i] <= '9') {
  452. result += input[i];
  453. cap_first_letter = true;
  454. } else {
  455. cap_first_letter = true;
  456. }
  457. }
  458. // Add a trailing "_" if the name should be altered.
  459. if (input[input.size() - 1] == '#') {
  460. result += '_';
  461. }
  462. return result;
  463. }
  464. std::string EscapeDollor(const string& to_escape) {
  465. return StringReplace(to_escape, "$", "\\$", true);
  466. }
  467. std::string BinaryToHex(const string& src) {
  468. string dest;
  469. size_t i;
  470. unsigned char symbol[16] = {
  471. '0', '1', '2', '3',
  472. '4', '5', '6', '7',
  473. '8', '9', 'a', 'b',
  474. 'c', 'd', 'e', 'f',
  475. };
  476. dest.resize(src.size() * 2);
  477. char* append_ptr = &dest[0];
  478. for (i = 0; i < src.size(); i++) {
  479. *append_ptr++ = symbol[(src[i] & 0xf0) >> 4];
  480. *append_ptr++ = symbol[src[i] & 0x0f];
  481. }
  482. return dest;
  483. }
  484. void Indent(io::Printer* printer) {
  485. printer->Indent();
  486. printer->Indent();
  487. }
  488. void Outdent(io::Printer* printer) {
  489. printer->Outdent();
  490. printer->Outdent();
  491. }
  492. void GenerateField(const FieldDescriptor* field, io::Printer* printer,
  493. bool is_descriptor) {
  494. if (field->is_repeated()) {
  495. GenerateFieldDocComment(printer, field, is_descriptor, kFieldProperty);
  496. printer->Print(
  497. "private $^name^;\n",
  498. "name", field->name());
  499. } else if (field->containing_oneof()) {
  500. // Oneof fields are handled by GenerateOneofField.
  501. return;
  502. } else {
  503. GenerateFieldDocComment(printer, field, is_descriptor, kFieldProperty);
  504. printer->Print(
  505. "private $^name^ = ^default^;\n",
  506. "name", field->name(),
  507. "default", DefaultForField(field));
  508. }
  509. if (is_descriptor) {
  510. printer->Print(
  511. "private $has_^name^ = false;\n",
  512. "name", field->name());
  513. }
  514. }
  515. void GenerateOneofField(const OneofDescriptor* oneof, io::Printer* printer) {
  516. // Oneof property needs to be protected in order to be accessed by parent
  517. // class in implementation.
  518. printer->Print(
  519. "protected $^name^;\n",
  520. "name", oneof->name());
  521. }
  522. void GenerateFieldAccessor(const FieldDescriptor* field, bool is_descriptor,
  523. io::Printer* printer) {
  524. const OneofDescriptor* oneof = field->containing_oneof();
  525. // Generate getter.
  526. if (oneof != NULL) {
  527. GenerateFieldDocComment(printer, field, is_descriptor, kFieldGetter);
  528. printer->Print(
  529. "public function get^camel_name^()\n"
  530. "{\n"
  531. " return $this->readOneof(^number^);\n"
  532. "}\n\n",
  533. "camel_name", UnderscoresToCamelCase(field->name(), true),
  534. "number", IntToString(field->number()));
  535. } else {
  536. GenerateFieldDocComment(printer, field, is_descriptor, kFieldGetter);
  537. printer->Print(
  538. "public function get^camel_name^()\n"
  539. "{\n"
  540. " return $this->^name^;\n"
  541. "}\n\n",
  542. "camel_name", UnderscoresToCamelCase(field->name(), true), "name",
  543. field->name());
  544. }
  545. // Generate setter.
  546. GenerateFieldDocComment(printer, field, is_descriptor, kFieldSetter);
  547. printer->Print(
  548. "public function set^camel_name^($var)\n"
  549. "{\n",
  550. "camel_name", UnderscoresToCamelCase(field->name(), true));
  551. Indent(printer);
  552. // Type check.
  553. if (field->is_map()) {
  554. const Descriptor* map_entry = field->message_type();
  555. const FieldDescriptor* key = map_entry->FindFieldByName("key");
  556. const FieldDescriptor* value = map_entry->FindFieldByName("value");
  557. printer->Print(
  558. "$arr = GPBUtil::checkMapField($var, "
  559. "\\Google\\Protobuf\\Internal\\GPBType::^key_type^, "
  560. "\\Google\\Protobuf\\Internal\\GPBType::^value_type^",
  561. "key_type", ToUpper(key->type_name()),
  562. "value_type", ToUpper(value->type_name()));
  563. if (value->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
  564. printer->Print(
  565. ", \\^class_name^);\n",
  566. "class_name",
  567. FullClassName(value->message_type(), is_descriptor) + "::class");
  568. } else if (value->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
  569. printer->Print(
  570. ", \\^class_name^);\n",
  571. "class_name",
  572. FullClassName(value->enum_type(), is_descriptor) + "::class");
  573. } else {
  574. printer->Print(");\n");
  575. }
  576. } else if (field->is_repeated()) {
  577. printer->Print(
  578. "$arr = GPBUtil::checkRepeatedField($var, "
  579. "\\Google\\Protobuf\\Internal\\GPBType::^type^",
  580. "type", ToUpper(field->type_name()));
  581. if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
  582. printer->Print(
  583. ", \\^class_name^);\n",
  584. "class_name",
  585. FullClassName(field->message_type(), is_descriptor) + "::class");
  586. } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
  587. printer->Print(
  588. ", \\^class_name^);\n",
  589. "class_name",
  590. FullClassName(field->enum_type(), is_descriptor) + "::class");
  591. } else {
  592. printer->Print(");\n");
  593. }
  594. } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
  595. printer->Print(
  596. "GPBUtil::checkMessage($var, \\^class_name^::class);\n",
  597. "class_name", FullClassName(field->message_type(), is_descriptor));
  598. } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) {
  599. printer->Print(
  600. "GPBUtil::checkEnum($var, \\^class_name^::class);\n",
  601. "class_name", FullClassName(field->enum_type(), is_descriptor));
  602. } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
  603. printer->Print(
  604. "GPBUtil::checkString($var, ^utf8^);\n",
  605. "utf8",
  606. field->type() == FieldDescriptor::TYPE_STRING ? "True": "False");
  607. } else {
  608. printer->Print(
  609. "GPBUtil::check^type^($var);\n",
  610. "type", UnderscoresToCamelCase(field->cpp_type_name(), true));
  611. }
  612. if (oneof != NULL) {
  613. printer->Print(
  614. "$this->writeOneof(^number^, $var);\n",
  615. "number", IntToString(field->number()));
  616. } else if (field->is_repeated()) {
  617. printer->Print(
  618. "$this->^name^ = $arr;\n",
  619. "name", field->name());
  620. } else {
  621. printer->Print(
  622. "$this->^name^ = $var;\n",
  623. "name", field->name());
  624. }
  625. // Set has bit for proto2 only.
  626. if (is_descriptor) {
  627. printer->Print(
  628. "$this->has_^field_name^ = true;\n",
  629. "field_name", field->name());
  630. }
  631. printer->Print("\nreturn $this;\n");
  632. Outdent(printer);
  633. printer->Print(
  634. "}\n\n");
  635. // Generate has method for proto2 only.
  636. if (is_descriptor) {
  637. printer->Print(
  638. "public function has^camel_name^()\n"
  639. "{\n"
  640. " return $this->has_^field_name^;\n"
  641. "}\n\n",
  642. "camel_name", UnderscoresToCamelCase(field->name(), true),
  643. "field_name", field->name());
  644. }
  645. }
  646. void GenerateEnumToPool(const EnumDescriptor* en, io::Printer* printer) {
  647. printer->Print(
  648. "$pool->addEnum('^name^', "
  649. "\\Google\\Protobuf\\Internal\\^class_name^::class)\n",
  650. "name", EnumFullName(en, true),
  651. "class_name", en->name());
  652. Indent(printer);
  653. for (int i = 0; i < en->value_count(); i++) {
  654. const EnumValueDescriptor* value = en->value(i);
  655. printer->Print(
  656. "->value(\"^name^\", ^number^)\n",
  657. "name", ConstantNamePrefix(value->name()) + value->name(),
  658. "number", IntToString(value->number()));
  659. }
  660. printer->Print("->finalizeToPool();\n\n");
  661. Outdent(printer);
  662. }
  663. void GenerateServiceMethod(const MethodDescriptor* method,
  664. io::Printer* printer) {
  665. printer->Print(
  666. "public function ^camel_name^(\\^request_name^ $request);\n\n",
  667. "camel_name", UnderscoresToCamelCase(method->name(), false),
  668. "request_name", FullClassName(
  669. method->input_type(), false)
  670. );
  671. }
  672. void GenerateMessageToPool(const string& name_prefix, const Descriptor* message,
  673. io::Printer* printer) {
  674. // Don't generate MapEntry messages -- we use the PHP extension's native
  675. // support for map fields instead.
  676. if (message->options().map_entry()) {
  677. return;
  678. }
  679. string class_name = name_prefix.empty()?
  680. message->name() : name_prefix + "_" + message->name();
  681. printer->Print(
  682. "$pool->addMessage('^message^', "
  683. "\\Google\\Protobuf\\Internal\\^class_name^::class)\n",
  684. "message", MessageFullName(message, true),
  685. "class_name", class_name);
  686. Indent(printer);
  687. for (int i = 0; i < message->field_count(); i++) {
  688. const FieldDescriptor* field = message->field(i);
  689. if (field->is_map()) {
  690. const FieldDescriptor* key =
  691. field->message_type()->FindFieldByName("key");
  692. const FieldDescriptor* val =
  693. field->message_type()->FindFieldByName("value");
  694. printer->Print(
  695. "->map('^field^', \\Google\\Protobuf\\Internal\\GPBType::^key^, "
  696. "\\Google\\Protobuf\\Internal\\GPBType::^value^, ^number^^other^)\n",
  697. "field", field->name(),
  698. "key", ToUpper(key->type_name()),
  699. "value", ToUpper(val->type_name()),
  700. "number", SimpleItoa(field->number()),
  701. "other", EnumOrMessageSuffix(val, true));
  702. } else if (!field->containing_oneof()) {
  703. printer->Print(
  704. "->^label^('^field^', "
  705. "\\Google\\Protobuf\\Internal\\GPBType::^type^, ^number^^other^)\n",
  706. "field", field->name(),
  707. "label", LabelForField(field),
  708. "type", ToUpper(field->type_name()),
  709. "number", SimpleItoa(field->number()),
  710. "other", EnumOrMessageSuffix(field, true));
  711. }
  712. }
  713. // oneofs.
  714. for (int i = 0; i < message->oneof_decl_count(); i++) {
  715. const OneofDescriptor* oneof = message->oneof_decl(i);
  716. printer->Print("->oneof(^name^)\n",
  717. "name", oneof->name());
  718. Indent(printer);
  719. for (int index = 0; index < oneof->field_count(); index++) {
  720. const FieldDescriptor* field = oneof->field(index);
  721. printer->Print(
  722. "->value('^field^', "
  723. "\\Google\\Protobuf\\Internal\\GPBType::^type^, ^number^^other^)\n",
  724. "field", field->name(),
  725. "type", ToUpper(field->type_name()),
  726. "number", SimpleItoa(field->number()),
  727. "other", EnumOrMessageSuffix(field, true));
  728. }
  729. printer->Print("->finish()\n");
  730. Outdent(printer);
  731. }
  732. printer->Print(
  733. "->finalizeToPool();\n");
  734. Outdent(printer);
  735. printer->Print(
  736. "\n");
  737. for (int i = 0; i < message->nested_type_count(); i++) {
  738. GenerateMessageToPool(class_name, message->nested_type(i), printer);
  739. }
  740. for (int i = 0; i < message->enum_type_count(); i++) {
  741. GenerateEnumToPool(message->enum_type(i), printer);
  742. }
  743. }
  744. void GenerateAddFileToPool(const FileDescriptor* file, bool is_descriptor,
  745. io::Printer* printer) {
  746. printer->Print(
  747. "public static $is_initialized = false;\n\n"
  748. "public static function initOnce() {\n");
  749. Indent(printer);
  750. printer->Print(
  751. "$pool = \\Google\\Protobuf\\Internal\\"
  752. "DescriptorPool::getGeneratedPool();\n\n"
  753. "if (static::$is_initialized == true) {\n"
  754. " return;\n"
  755. "}\n");
  756. if (is_descriptor) {
  757. for (int i = 0; i < file->message_type_count(); i++) {
  758. GenerateMessageToPool("", file->message_type(i), printer);
  759. }
  760. for (int i = 0; i < file->enum_type_count(); i++) {
  761. GenerateEnumToPool(file->enum_type(i), printer);
  762. }
  763. printer->Print(
  764. "$pool->finish();\n");
  765. } else {
  766. for (int i = 0; i < file->dependency_count(); i++) {
  767. const std::string& name = file->dependency(i)->name();
  768. // Currently, descriptor.proto is not ready for external usage. Skip to
  769. // import it for now, so that its dependencies can still work as long as
  770. // they don't use protos defined in descriptor.proto.
  771. if (name == kDescriptorFile) {
  772. continue;
  773. }
  774. std::string dependency_filename =
  775. GeneratedMetadataFileName(name, is_descriptor);
  776. printer->Print(
  777. "\\^name^::initOnce();\n",
  778. "name", FilenameToClassname(dependency_filename));
  779. }
  780. // Add messages and enums to descriptor pool.
  781. FileDescriptorSet files;
  782. FileDescriptorProto* file_proto = files.add_file();
  783. file->CopyTo(file_proto);
  784. // Filter out descriptor.proto as it cannot be depended on for now.
  785. RepeatedPtrField<string>* dependency = file_proto->mutable_dependency();
  786. for (RepeatedPtrField<string>::iterator it = dependency->begin();
  787. it != dependency->end(); ++it) {
  788. if (*it != kDescriptorFile) {
  789. dependency->erase(it);
  790. break;
  791. }
  792. }
  793. // Filter out all extensions, since we do not support extension yet.
  794. file_proto->clear_extension();
  795. RepeatedPtrField<DescriptorProto>* message_type =
  796. file_proto->mutable_message_type();
  797. for (RepeatedPtrField<DescriptorProto>::iterator it = message_type->begin();
  798. it != message_type->end(); ++it) {
  799. it->clear_extension();
  800. }
  801. string files_data;
  802. files.SerializeToString(&files_data);
  803. printer->Print("$pool->internalAddGeneratedFile(hex2bin(\n");
  804. Indent(printer);
  805. // Only write 30 bytes per line.
  806. static const int kBytesPerLine = 30;
  807. for (int i = 0; i < files_data.size(); i += kBytesPerLine) {
  808. printer->Print(
  809. "\"^data^\"^dot^\n",
  810. "data", BinaryToHex(files_data.substr(i, kBytesPerLine)),
  811. "dot", i + kBytesPerLine < files_data.size() ? " ." : "");
  812. }
  813. Outdent(printer);
  814. printer->Print(
  815. "));\n\n");
  816. }
  817. printer->Print(
  818. "static::$is_initialized = true;\n");
  819. Outdent(printer);
  820. printer->Print("}\n");
  821. }
  822. void GenerateUseDeclaration(bool is_descriptor, io::Printer* printer) {
  823. if (!is_descriptor) {
  824. printer->Print(
  825. "use Google\\Protobuf\\Internal\\GPBType;\n"
  826. "use Google\\Protobuf\\Internal\\RepeatedField;\n"
  827. "use Google\\Protobuf\\Internal\\GPBUtil;\n\n");
  828. } else {
  829. printer->Print(
  830. "use Google\\Protobuf\\Internal\\GPBType;\n"
  831. "use Google\\Protobuf\\Internal\\GPBWire;\n"
  832. "use Google\\Protobuf\\Internal\\RepeatedField;\n"
  833. "use Google\\Protobuf\\Internal\\InputStream;\n"
  834. "use Google\\Protobuf\\Internal\\GPBUtil;\n\n");
  835. }
  836. }
  837. void GenerateHead(const FileDescriptor* file, io::Printer* printer) {
  838. printer->Print(
  839. "<?php\n"
  840. "# Generated by the protocol buffer compiler. DO NOT EDIT!\n"
  841. "# source: ^filename^\n"
  842. "\n",
  843. "filename", file->name());
  844. }
  845. std::string FilenameToClassname(const string& filename) {
  846. int lastindex = filename.find_last_of(".");
  847. std::string result = filename.substr(0, lastindex);
  848. for (int i = 0; i < result.size(); i++) {
  849. if (result[i] == '/') {
  850. result[i] = '\\';
  851. }
  852. }
  853. return result;
  854. }
  855. void GenerateMetadataFile(const FileDescriptor* file,
  856. bool is_descriptor,
  857. GeneratorContext* generator_context) {
  858. std::string filename = GeneratedMetadataFileName(file->name(), is_descriptor);
  859. scoped_ptr<io::ZeroCopyOutputStream> output(
  860. generator_context->Open(filename));
  861. io::Printer printer(output.get(), '^');
  862. GenerateHead(file, &printer);
  863. std::string fullname = FilenameToClassname(filename);
  864. int lastindex = fullname.find_last_of("\\");
  865. printer.Print(
  866. "namespace ^name^;\n\n",
  867. "name", fullname.substr(0, lastindex));
  868. if (lastindex != string::npos) {
  869. printer.Print(
  870. "class ^name^\n"
  871. "{\n",
  872. "name", fullname.substr(lastindex + 1));
  873. } else {
  874. printer.Print(
  875. "class ^name^\n"
  876. "{\n",
  877. "name", fullname);
  878. }
  879. Indent(&printer);
  880. GenerateAddFileToPool(file, is_descriptor, &printer);
  881. Outdent(&printer);
  882. printer.Print("}\n\n");
  883. }
  884. void GenerateEnumFile(const FileDescriptor* file, const EnumDescriptor* en,
  885. bool is_descriptor, GeneratorContext* generator_context) {
  886. std::string filename = GeneratedEnumFileName(en, is_descriptor);
  887. scoped_ptr<io::ZeroCopyOutputStream> output(
  888. generator_context->Open(filename));
  889. io::Printer printer(output.get(), '^');
  890. GenerateHead(file, &printer);
  891. std::string fullname = FilenameToClassname(filename);
  892. int lastindex = fullname.find_last_of("\\");
  893. if (file->options().has_php_namespace()) {
  894. const string& php_namespace = file->options().php_namespace();
  895. if (!php_namespace.empty()) {
  896. printer.Print(
  897. "namespace ^name^;\n\n",
  898. "name", php_namespace);
  899. }
  900. } else if (!file->package().empty()) {
  901. printer.Print(
  902. "namespace ^name^;\n\n",
  903. "name", fullname.substr(0, lastindex));
  904. }
  905. GenerateEnumDocComment(&printer, en, is_descriptor);
  906. if (lastindex != string::npos) {
  907. printer.Print(
  908. "class ^name^\n"
  909. "{\n",
  910. "name", fullname.substr(lastindex + 1));
  911. } else {
  912. printer.Print(
  913. "class ^name^\n"
  914. "{\n",
  915. "name", fullname);
  916. }
  917. Indent(&printer);
  918. for (int i = 0; i < en->value_count(); i++) {
  919. const EnumValueDescriptor* value = en->value(i);
  920. GenerateEnumValueDocComment(&printer, value);
  921. printer.Print("const ^name^ = ^number^;\n",
  922. "name", ConstantNamePrefix(value->name()) + value->name(),
  923. "number", IntToString(value->number()));
  924. }
  925. Outdent(&printer);
  926. printer.Print("}\n\n");
  927. }
  928. void GenerateMessageFile(const FileDescriptor* file, const Descriptor* message,
  929. bool is_descriptor,
  930. GeneratorContext* generator_context) {
  931. // Don't generate MapEntry messages -- we use the PHP extension's native
  932. // support for map fields instead.
  933. if (message->options().map_entry()) {
  934. return;
  935. }
  936. std::string filename = GeneratedMessageFileName(message, is_descriptor);
  937. scoped_ptr<io::ZeroCopyOutputStream> output(
  938. generator_context->Open(filename));
  939. io::Printer printer(output.get(), '^');
  940. GenerateHead(file, &printer);
  941. std::string fullname = FilenameToClassname(filename);
  942. int lastindex = fullname.find_last_of("\\");
  943. if (file->options().has_php_namespace()) {
  944. const string& php_namespace = file->options().php_namespace();
  945. if (!php_namespace.empty()) {
  946. printer.Print(
  947. "namespace ^name^;\n\n",
  948. "name", php_namespace);
  949. }
  950. } else if (!file->package().empty()) {
  951. printer.Print(
  952. "namespace ^name^;\n\n",
  953. "name", fullname.substr(0, lastindex));
  954. }
  955. GenerateUseDeclaration(is_descriptor, &printer);
  956. GenerateMessageDocComment(&printer, message, is_descriptor);
  957. if (lastindex != string::npos) {
  958. printer.Print(
  959. "class ^name^ extends \\Google\\Protobuf\\Internal\\Message\n"
  960. "{\n",
  961. "name", fullname.substr(lastindex + 1));
  962. } else {
  963. printer.Print(
  964. "class ^name^ extends \\Google\\Protobuf\\Internal\\Message\n"
  965. "{\n",
  966. "name", fullname);
  967. }
  968. Indent(&printer);
  969. // Field and oneof definitions.
  970. for (int i = 0; i < message->field_count(); i++) {
  971. const FieldDescriptor* field = message->field(i);
  972. GenerateField(field, &printer, is_descriptor);
  973. }
  974. for (int i = 0; i < message->oneof_decl_count(); i++) {
  975. const OneofDescriptor* oneof = message->oneof_decl(i);
  976. GenerateOneofField(oneof, &printer);
  977. }
  978. printer.Print("\n");
  979. printer.Print(
  980. "public function __construct() {\n");
  981. Indent(&printer);
  982. std::string metadata_filename =
  983. GeneratedMetadataFileName(file->name(), is_descriptor);
  984. std::string metadata_fullname = FilenameToClassname(metadata_filename);
  985. printer.Print(
  986. "\\^fullname^::initOnce();\n"
  987. "parent::__construct();\n",
  988. "fullname", metadata_fullname);
  989. Outdent(&printer);
  990. printer.Print("}\n\n");
  991. // Field and oneof accessors.
  992. for (int i = 0; i < message->field_count(); i++) {
  993. const FieldDescriptor* field = message->field(i);
  994. GenerateFieldAccessor(field, is_descriptor, &printer);
  995. }
  996. for (int i = 0; i < message->oneof_decl_count(); i++) {
  997. const OneofDescriptor* oneof = message->oneof_decl(i);
  998. printer.Print(
  999. "/**\n"
  1000. " * @return string\n"
  1001. " */\n"
  1002. "public function get^camel_name^()\n"
  1003. "{\n"
  1004. " return $this->whichOneof(\"^name^\");\n"
  1005. "}\n\n",
  1006. "camel_name", UnderscoresToCamelCase(oneof->name(), true), "name",
  1007. oneof->name());
  1008. }
  1009. Outdent(&printer);
  1010. printer.Print("}\n\n");
  1011. // Nested messages and enums.
  1012. for (int i = 0; i < message->nested_type_count(); i++) {
  1013. GenerateMessageFile(file, message->nested_type(i), is_descriptor,
  1014. generator_context);
  1015. }
  1016. for (int i = 0; i < message->enum_type_count(); i++) {
  1017. GenerateEnumFile(file, message->enum_type(i), is_descriptor,
  1018. generator_context);
  1019. }
  1020. }
  1021. void GenerateServiceFile(const FileDescriptor* file,
  1022. const ServiceDescriptor* service, bool is_descriptor,
  1023. GeneratorContext* generator_context) {
  1024. std::string filename = GeneratedServiceFileName(service, is_descriptor);
  1025. scoped_ptr<io::ZeroCopyOutputStream> output(
  1026. generator_context->Open(filename));
  1027. io::Printer printer(output.get(), '^');
  1028. GenerateHead(file, &printer);
  1029. std::string fullname = FilenameToClassname(filename);
  1030. int lastindex = fullname.find_last_of("\\");
  1031. if (file->options().has_php_namespace()) {
  1032. const string& php_namespace = file->options().php_namespace();
  1033. if (!php_namespace.empty()) {
  1034. printer.Print(
  1035. "namespace ^name^;\n\n",
  1036. "name", php_namespace);
  1037. }
  1038. } else if (!file->package().empty()) {
  1039. printer.Print(
  1040. "namespace ^name^;\n\n",
  1041. "name", fullname.substr(0, lastindex));
  1042. }
  1043. GenerateServiceDocComment(&printer, service);
  1044. if (lastindex != string::npos) {
  1045. printer.Print(
  1046. "interface ^name^\n"
  1047. "{\n",
  1048. "name", fullname.substr(lastindex + 1));
  1049. } else {
  1050. printer.Print(
  1051. "interface ^name^\n"
  1052. "{\n",
  1053. "name", fullname);
  1054. }
  1055. Indent(&printer);
  1056. for (int i = 0; i < service->method_count(); i++) {
  1057. const MethodDescriptor* method = service->method(i);
  1058. GenerateServiceMethodDocComment(&printer, method);
  1059. GenerateServiceMethod(method, &printer);
  1060. }
  1061. Outdent(&printer);
  1062. printer.Print("}\n\n");
  1063. }
  1064. void GenerateFile(const FileDescriptor* file, bool is_descriptor,
  1065. GeneratorContext* generator_context) {
  1066. GenerateMetadataFile(file, is_descriptor, generator_context);
  1067. for (int i = 0; i < file->message_type_count(); i++) {
  1068. GenerateMessageFile(file, file->message_type(i), is_descriptor,
  1069. generator_context);
  1070. }
  1071. for (int i = 0; i < file->enum_type_count(); i++) {
  1072. GenerateEnumFile(file, file->enum_type(i), is_descriptor,
  1073. generator_context);
  1074. }
  1075. if (file->options().php_generic_services()) {
  1076. for (int i = 0; i < file->service_count(); i++) {
  1077. GenerateServiceFile(file, file->service(i), is_descriptor,
  1078. generator_context);
  1079. }
  1080. }
  1081. }
  1082. static string EscapePhpdoc(const string& input) {
  1083. string result;
  1084. result.reserve(input.size() * 2);
  1085. char prev = '*';
  1086. for (string::size_type i = 0; i < input.size(); i++) {
  1087. char c = input[i];
  1088. switch (c) {
  1089. case '*':
  1090. // Avoid "/*".
  1091. if (prev == '/') {
  1092. result.append("&#42;");
  1093. } else {
  1094. result.push_back(c);
  1095. }
  1096. break;
  1097. case '/':
  1098. // Avoid "*/".
  1099. if (prev == '*') {
  1100. result.append("&#47;");
  1101. } else {
  1102. result.push_back(c);
  1103. }
  1104. break;
  1105. case '@':
  1106. // '@' starts phpdoc tags including the @deprecated tag, which will
  1107. // cause a compile-time error if inserted before a declaration that
  1108. // does not have a corresponding @Deprecated annotation.
  1109. result.append("&#64;");
  1110. break;
  1111. default:
  1112. result.push_back(c);
  1113. break;
  1114. }
  1115. prev = c;
  1116. }
  1117. return result;
  1118. }
  1119. static void GenerateDocCommentBodyForLocation(
  1120. io::Printer* printer, const SourceLocation& location) {
  1121. string comments = location.leading_comments.empty() ?
  1122. location.trailing_comments : location.leading_comments;
  1123. if (!comments.empty()) {
  1124. // TODO(teboring): Ideally we should parse the comment text as Markdown and
  1125. // write it back as HTML, but this requires a Markdown parser. For now
  1126. // we just use the proto comments unchanged.
  1127. // If the comment itself contains block comment start or end markers,
  1128. // HTML-escape them so that they don't accidentally close the doc comment.
  1129. comments = EscapePhpdoc(comments);
  1130. std::vector<string> lines = Split(comments, "\n");
  1131. while (!lines.empty() && lines.back().empty()) {
  1132. lines.pop_back();
  1133. }
  1134. for (int i = 0; i < lines.size(); i++) {
  1135. // Most lines should start with a space. Watch out for lines that start
  1136. // with a /, since putting that right after the leading asterisk will
  1137. // close the comment.
  1138. if (!lines[i].empty() && lines[i][0] == '/') {
  1139. printer->Print(" * ^line^\n", "line", lines[i]);
  1140. } else {
  1141. printer->Print(" *^line^\n", "line", lines[i]);
  1142. }
  1143. }
  1144. printer->Print(
  1145. " *\n");
  1146. }
  1147. }
  1148. template <typename DescriptorType>
  1149. static void GenerateDocCommentBody(
  1150. io::Printer* printer, const DescriptorType* descriptor) {
  1151. SourceLocation location;
  1152. if (descriptor->GetSourceLocation(&location)) {
  1153. GenerateDocCommentBodyForLocation(printer, location);
  1154. }
  1155. }
  1156. static string FirstLineOf(const string& value) {
  1157. string result = value;
  1158. string::size_type pos = result.find_first_of('\n');
  1159. if (pos != string::npos) {
  1160. result.erase(pos);
  1161. }
  1162. return result;
  1163. }
  1164. void GenerateMessageDocComment(io::Printer* printer,
  1165. const Descriptor* message, int is_descriptor) {
  1166. printer->Print("/**\n");
  1167. GenerateDocCommentBody(printer, message);
  1168. printer->Print(
  1169. " * Generated from protobuf message <code>^messagename^</code>\n"
  1170. " */\n",
  1171. "fullname", EscapePhpdoc(PhpName(message->full_name(), is_descriptor)),
  1172. "messagename", EscapePhpdoc(message->full_name()));
  1173. }
  1174. void GenerateServiceDocComment(io::Printer* printer,
  1175. const ServiceDescriptor* service) {
  1176. printer->Print("/**\n");
  1177. GenerateDocCommentBody(printer, service);
  1178. printer->Print(
  1179. " * Protobuf type <code>^fullname^</code>\n"
  1180. " */\n",
  1181. "fullname", EscapePhpdoc(service->full_name()));
  1182. }
  1183. void GenerateFieldDocComment(io::Printer* printer, const FieldDescriptor* field,
  1184. int is_descriptor, int function_type) {
  1185. // In theory we should have slightly different comments for setters, getters,
  1186. // etc., but in practice everyone already knows the difference between these
  1187. // so it's redundant information.
  1188. // We start the comment with the main body based on the comments from the
  1189. // .proto file (if present). We then end with the field declaration, e.g.:
  1190. // optional string foo = 5;
  1191. // If the field is a group, the debug string might end with {.
  1192. printer->Print("/**\n");
  1193. GenerateDocCommentBody(printer, field);
  1194. printer->Print(
  1195. " * Generated from protobuf field <code>^def^</code>\n",
  1196. "def", EscapePhpdoc(FirstLineOf(field->DebugString())));
  1197. if (function_type == kFieldSetter) {
  1198. printer->Print(" * @param ^php_type^ $var\n",
  1199. "php_type", PhpSetterTypeName(field, is_descriptor));
  1200. printer->Print(" * @return $this\n");
  1201. } else if (function_type == kFieldGetter) {
  1202. printer->Print(" * @return ^php_type^\n",
  1203. "php_type", PhpGetterTypeName(field, is_descriptor));
  1204. }
  1205. printer->Print(" */\n");
  1206. }
  1207. void GenerateEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_,
  1208. int is_descriptor) {
  1209. printer->Print("/**\n");
  1210. GenerateDocCommentBody(printer, enum_);
  1211. printer->Print(
  1212. " * Protobuf enum <code>^fullname^</code>\n"
  1213. " */\n",
  1214. "fullname", EscapePhpdoc(PhpName(enum_->full_name(), is_descriptor)));
  1215. }
  1216. void GenerateEnumValueDocComment(io::Printer* printer,
  1217. const EnumValueDescriptor* value) {
  1218. printer->Print("/**\n");
  1219. GenerateDocCommentBody(printer, value);
  1220. printer->Print(
  1221. " * Generated from protobuf enum <code>^def^</code>\n"
  1222. " */\n",
  1223. "def", EscapePhpdoc(FirstLineOf(value->DebugString())));
  1224. }
  1225. void GenerateServiceMethodDocComment(io::Printer* printer,
  1226. const MethodDescriptor* method) {
  1227. printer->Print("/**\n");
  1228. GenerateDocCommentBody(printer, method);
  1229. printer->Print(
  1230. " * Method <code>^method_name^</code>\n"
  1231. " *\n",
  1232. "method_name", EscapePhpdoc(UnderscoresToCamelCase(method->name(), false)));
  1233. printer->Print(
  1234. " * @param \\^input_type^ $request\n",
  1235. "input_type", EscapePhpdoc(FullClassName(method->input_type(), false)));
  1236. printer->Print(
  1237. " * @return \\^return_type^\n"
  1238. " */\n",
  1239. "return_type", EscapePhpdoc(FullClassName(method->output_type(), false)));
  1240. }
  1241. bool Generator::Generate(const FileDescriptor* file, const string& parameter,
  1242. GeneratorContext* generator_context,
  1243. string* error) const {
  1244. bool is_descriptor = parameter == "internal";
  1245. if (is_descriptor && file->name() != kDescriptorFile) {
  1246. *error =
  1247. "Can only generate PHP code for google/protobuf/descriptor.proto.\n";
  1248. return false;
  1249. }
  1250. if (!is_descriptor && file->syntax() != FileDescriptor::SYNTAX_PROTO3) {
  1251. *error =
  1252. "Can only generate PHP code for proto3 .proto files.\n"
  1253. "Please add 'syntax = \"proto3\";' to the top of your .proto file.\n";
  1254. return false;
  1255. }
  1256. GenerateFile(file, is_descriptor, generator_context);
  1257. return true;
  1258. }
  1259. std::string GeneratedClassName(const Descriptor* desc) {
  1260. std::string classname = desc->name();
  1261. const Descriptor* containing = desc->containing_type();
  1262. while (containing != NULL) {
  1263. classname = containing->name() + '_' + classname;
  1264. containing = containing->containing_type();
  1265. }
  1266. return ClassNamePrefix(classname, desc) + classname;
  1267. }
  1268. std::string GeneratedClassName(const EnumDescriptor* desc) {
  1269. std::string classname = desc->name();
  1270. const Descriptor* containing = desc->containing_type();
  1271. while (containing != NULL) {
  1272. classname = containing->name() + '_' + classname;
  1273. containing = containing->containing_type();
  1274. }
  1275. return ClassNamePrefix(classname, desc) + classname;
  1276. }
  1277. std::string GeneratedClassName(const ServiceDescriptor* desc) {
  1278. std::string classname = desc->name();
  1279. return ClassNamePrefix(classname, desc) + classname;
  1280. }
  1281. } // namespace php
  1282. } // namespace compiler
  1283. } // namespace protobuf
  1284. } // namespace google