Index: third_party/protobuf/src/google/protobuf/compiler/php/php_generator.cc |
diff --git a/third_party/protobuf/src/google/protobuf/compiler/php/php_generator.cc b/third_party/protobuf/src/google/protobuf/compiler/php/php_generator.cc |
deleted file mode 100644 |
index be2739ff1c330a499028a3ec6dcaa9ad14d2fad4..0000000000000000000000000000000000000000 |
--- a/third_party/protobuf/src/google/protobuf/compiler/php/php_generator.cc |
+++ /dev/null |
@@ -1,1086 +0,0 @@ |
-// Protocol Buffers - Google's data interchange format |
-// Copyright 2008 Google Inc. All rights reserved. |
-// https://developers.google.com/protocol-buffers/ |
-// |
-// Redistribution and use in source and binary forms, with or without |
-// modification, are permitted provided that the following conditions are |
-// met: |
-// |
-// * Redistributions of source code must retain the above copyright |
-// notice, this list of conditions and the following disclaimer. |
-// * Redistributions in binary form must reproduce the above |
-// copyright notice, this list of conditions and the following disclaimer |
-// in the documentation and/or other materials provided with the |
-// distribution. |
-// * Neither the name of Google Inc. nor the names of its |
-// contributors may be used to endorse or promote products derived from |
-// this software without specific prior written permission. |
-// |
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
- |
-#include <google/protobuf/compiler/php/php_generator.h> |
- |
-#include <google/protobuf/compiler/code_generator.h> |
-#include <google/protobuf/compiler/plugin.h> |
-#include <google/protobuf/descriptor.h> |
-#include <google/protobuf/descriptor.pb.h> |
-#include <google/protobuf/io/printer.h> |
-#include <google/protobuf/io/zero_copy_stream.h> |
-#include <google/protobuf/stubs/strutil.h> |
- |
-#include <sstream> |
- |
-using google::protobuf::internal::scoped_ptr; |
- |
-const std::string kDescriptorFile = "google/protobuf/descriptor.proto"; |
-const std::string kEmptyFile = "google/protobuf/empty.proto"; |
-const std::string kEmptyMetadataFile = "GPBMetadata/Google/Protobuf/GPBEmpty.php"; |
-const std::string kDescriptorMetadataFile = |
- "GPBMetadata/Google/Protobuf/Internal/Descriptor.php"; |
-const std::string kDescriptorDirName = "Google/Protobuf/Internal"; |
-const std::string kDescriptorPackageName = "Google\\Protobuf\\Internal"; |
- |
-namespace google { |
-namespace protobuf { |
-namespace compiler { |
-namespace php { |
- |
-// Forward decls. |
-std::string PhpName(const std::string& full_name, bool is_descriptor); |
-std::string DefaultForField(FieldDescriptor* field); |
-std::string IntToString(int32 value); |
-std::string FilenameToClassname(const string& filename); |
-std::string GeneratedMetadataFileName(const std::string& proto_file, |
- bool is_descriptor); |
-std::string LabelForField(FieldDescriptor* field); |
-std::string TypeName(FieldDescriptor* field); |
-std::string UnderscoresToCamelCase(const string& name, bool cap_first_letter); |
-std::string EscapeDollor(const string& to_escape); |
-std::string BinaryToHex(const string& binary); |
-void Indent(io::Printer* printer); |
-void Outdent(io::Printer* printer); |
-void GenerateMessageDocComment(io::Printer* printer, const Descriptor* message); |
-void GenerateFieldDocComment(io::Printer* printer, |
- const FieldDescriptor* field); |
-void GenerateEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_); |
-void GenerateEnumValueDocComment(io::Printer* printer, |
- const EnumValueDescriptor* value); |
- |
-std::string RenameEmpty(const std::string& name) { |
- if (name == "Empty") { |
- return "GPBEmpty"; |
- } else { |
- return name; |
- } |
-} |
- |
-std::string MessagePrefix(const Descriptor* message) { |
- // Empty cannot be php class name. |
- if (message->name() == "Empty" && |
- message->file()->package() == "google.protobuf") { |
- return "GPB"; |
- } else { |
- return ""; |
- } |
-} |
- |
-std::string MessageName(const Descriptor* message, bool is_descriptor) { |
- string message_name = message->name(); |
- const Descriptor* descriptor = message->containing_type(); |
- while (descriptor != NULL) { |
- message_name = descriptor->name() + '_' + message_name; |
- descriptor = descriptor->containing_type(); |
- } |
- message_name = MessagePrefix(message) + message_name; |
- |
- return PhpName(message->file()->package(), is_descriptor) + '\\' + |
- message_name; |
-} |
- |
-std::string MessageFullName(const Descriptor* message, bool is_descriptor) { |
- if (is_descriptor) { |
- return StringReplace(message->full_name(), |
- "google.protobuf", |
- "google.protobuf.internal", false); |
- } else { |
- return message->full_name(); |
- } |
-} |
- |
-std::string EnumFullName(const EnumDescriptor* envm, bool is_descriptor) { |
- if (is_descriptor) { |
- return StringReplace(envm->full_name(), |
- "google.protobuf", |
- "google.protobuf.internal", false); |
- } else { |
- return envm->full_name(); |
- } |
-} |
- |
-std::string EnumClassName(const EnumDescriptor* envm) { |
- string enum_class_name = envm->name(); |
- const Descriptor* descriptor = envm->containing_type(); |
- while (descriptor != NULL) { |
- enum_class_name = descriptor->name() + '_' + enum_class_name; |
- descriptor = descriptor->containing_type(); |
- } |
- return enum_class_name; |
-} |
- |
-std::string EnumName(const EnumDescriptor* envm, bool is_descriptor) { |
- string enum_name = EnumClassName(envm); |
- return PhpName(envm->file()->package(), is_descriptor) + '\\' + enum_name; |
-} |
- |
-std::string PhpName(const std::string& full_name, bool is_descriptor) { |
- if (is_descriptor) { |
- return kDescriptorPackageName; |
- } |
- |
- std::string result; |
- bool cap_next_letter = true; |
- for (int i = 0; i < full_name.size(); i++) { |
- if ('a' <= full_name[i] && full_name[i] <= 'z' && cap_next_letter) { |
- result += full_name[i] + ('A' - 'a'); |
- cap_next_letter = false; |
- } else if (full_name[i] == '.') { |
- result += '\\'; |
- cap_next_letter = true; |
- } else { |
- result += full_name[i]; |
- cap_next_letter = false; |
- } |
- } |
- return result; |
-} |
- |
-std::string DefaultForField(const FieldDescriptor* field) { |
- switch (field->type()) { |
- case FieldDescriptor::TYPE_INT32: |
- case FieldDescriptor::TYPE_INT64: |
- case FieldDescriptor::TYPE_UINT32: |
- case FieldDescriptor::TYPE_UINT64: |
- case FieldDescriptor::TYPE_SINT32: |
- case FieldDescriptor::TYPE_SINT64: |
- case FieldDescriptor::TYPE_FIXED32: |
- case FieldDescriptor::TYPE_FIXED64: |
- case FieldDescriptor::TYPE_SFIXED32: |
- case FieldDescriptor::TYPE_SFIXED64: |
- case FieldDescriptor::TYPE_ENUM: return "0"; |
- case FieldDescriptor::TYPE_DOUBLE: |
- case FieldDescriptor::TYPE_FLOAT: return "0.0"; |
- case FieldDescriptor::TYPE_BOOL: return "false"; |
- case FieldDescriptor::TYPE_STRING: |
- case FieldDescriptor::TYPE_BYTES: return "''"; |
- case FieldDescriptor::TYPE_MESSAGE: |
- case FieldDescriptor::TYPE_GROUP: return "null"; |
- default: assert(false); return ""; |
- } |
-} |
- |
-std::string GeneratedMetadataFileName(const std::string& proto_file, |
- bool is_descriptor) { |
- int start_index = 0; |
- int first_index = proto_file.find_first_of("/", start_index); |
- std::string result = "GPBMetadata/"; |
- |
- if (proto_file == kEmptyFile) { |
- return kEmptyMetadataFile; |
- } |
- if (is_descriptor) { |
- return kDescriptorMetadataFile; |
- } |
- |
- // Append directory name. |
- std::string file_no_suffix; |
- int lastindex = proto_file.find_last_of("."); |
- if (proto_file == kEmptyFile) { |
- return kEmptyMetadataFile; |
- } else { |
- file_no_suffix = proto_file.substr(0, lastindex); |
- } |
- |
- while (first_index != string::npos) { |
- result += UnderscoresToCamelCase( |
- file_no_suffix.substr(start_index, first_index - start_index), true); |
- result += "/"; |
- start_index = first_index + 1; |
- first_index = file_no_suffix.find_first_of("/", start_index); |
- } |
- |
- // Append file name. |
- result += RenameEmpty(UnderscoresToCamelCase( |
- file_no_suffix.substr(start_index, first_index - start_index), true)); |
- |
- return result += ".php"; |
-} |
- |
-std::string GeneratedMessageFileName(const Descriptor* message, |
- bool is_descriptor) { |
- std::string result = MessageName(message, is_descriptor); |
- for (int i = 0; i < result.size(); i++) { |
- if (result[i] == '\\') { |
- result[i] = '/'; |
- } |
- } |
- return result + ".php"; |
-} |
- |
-std::string GeneratedEnumFileName(const EnumDescriptor* en, |
- bool is_descriptor) { |
- std::string result = EnumName(en, is_descriptor); |
- for (int i = 0; i < result.size(); i++) { |
- if (result[i] == '\\') { |
- result[i] = '/'; |
- } |
- } |
- return result + ".php"; |
-} |
- |
-std::string IntToString(int32 value) { |
- std::ostringstream os; |
- os << value; |
- return os.str(); |
-} |
- |
-std::string LabelForField(const FieldDescriptor* field) { |
- switch (field->label()) { |
- case FieldDescriptor::LABEL_OPTIONAL: return "optional"; |
- case FieldDescriptor::LABEL_REQUIRED: return "required"; |
- case FieldDescriptor::LABEL_REPEATED: return "repeated"; |
- default: assert(false); return ""; |
- } |
-} |
- |
-std::string TypeName(const FieldDescriptor* field) { |
- switch (field->type()) { |
- case FieldDescriptor::TYPE_INT32: return "int32"; |
- case FieldDescriptor::TYPE_INT64: return "int64"; |
- case FieldDescriptor::TYPE_UINT32: return "uint32"; |
- case FieldDescriptor::TYPE_UINT64: return "uint64"; |
- case FieldDescriptor::TYPE_SINT32: return "sint32"; |
- case FieldDescriptor::TYPE_SINT64: return "sint64"; |
- case FieldDescriptor::TYPE_FIXED32: return "fixed32"; |
- case FieldDescriptor::TYPE_FIXED64: return "fixed64"; |
- case FieldDescriptor::TYPE_SFIXED32: return "sfixed32"; |
- case FieldDescriptor::TYPE_SFIXED64: return "sfixed64"; |
- case FieldDescriptor::TYPE_DOUBLE: return "double"; |
- case FieldDescriptor::TYPE_FLOAT: return "float"; |
- case FieldDescriptor::TYPE_BOOL: return "bool"; |
- case FieldDescriptor::TYPE_ENUM: return "enum"; |
- case FieldDescriptor::TYPE_STRING: return "string"; |
- case FieldDescriptor::TYPE_BYTES: return "bytes"; |
- case FieldDescriptor::TYPE_MESSAGE: return "message"; |
- case FieldDescriptor::TYPE_GROUP: return "group"; |
- default: assert(false); return ""; |
- } |
-} |
- |
-std::string EnumOrMessageSuffix( |
- const FieldDescriptor* field, bool is_descriptor) { |
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
- return ", '" + MessageFullName(field->message_type(), is_descriptor) + "'"; |
- } |
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { |
- return ", '" + EnumFullName(field->enum_type(), is_descriptor) + "'"; |
- } |
- return ""; |
-} |
- |
-// Converts a name to camel-case. If cap_first_letter is true, capitalize the |
-// first letter. |
-std::string UnderscoresToCamelCase(const string& input, bool cap_first_letter) { |
- std::string result; |
- for (int i = 0; i < input.size(); i++) { |
- if ('a' <= input[i] && input[i] <= 'z') { |
- if (cap_first_letter) { |
- result += input[i] + ('A' - 'a'); |
- } else { |
- result += input[i]; |
- } |
- cap_first_letter = false; |
- } else if ('A' <= input[i] && input[i] <= 'Z') { |
- if (i == 0 && !cap_first_letter) { |
- // Force first letter to lower-case unless explicitly told to |
- // capitalize it. |
- result += input[i] + ('a' - 'A'); |
- } else { |
- // Capital letters after the first are left as-is. |
- result += input[i]; |
- } |
- cap_first_letter = false; |
- } else if ('0' <= input[i] && input[i] <= '9') { |
- result += input[i]; |
- cap_first_letter = true; |
- } else { |
- cap_first_letter = true; |
- } |
- } |
- // Add a trailing "_" if the name should be altered. |
- if (input[input.size() - 1] == '#') { |
- result += '_'; |
- } |
- return result; |
-} |
- |
-std::string EscapeDollor(const string& to_escape) { |
- return StringReplace(to_escape, "$", "\\$", true); |
-} |
- |
-std::string BinaryToHex(const string& src) { |
- string dest; |
- size_t i; |
- unsigned char symbol[16] = { |
- '0', '1', '2', '3', |
- '4', '5', '6', '7', |
- '8', '9', 'a', 'b', |
- 'c', 'd', 'e', 'f', |
- }; |
- |
- dest.resize(src.size() * 2); |
- char* append_ptr = &dest[0]; |
- |
- for (i = 0; i < src.size(); i++) { |
- *append_ptr++ = symbol[(src[i] & 0xf0) >> 4]; |
- *append_ptr++ = symbol[src[i] & 0x0f]; |
- } |
- |
- return dest; |
-} |
- |
-void Indent(io::Printer* printer) { |
- printer->Indent(); |
- printer->Indent(); |
-} |
-void Outdent(io::Printer* printer) { |
- printer->Outdent(); |
- printer->Outdent(); |
-} |
- |
-void GenerateField(const FieldDescriptor* field, io::Printer* printer, |
- bool is_descriptor) { |
- if (field->is_repeated()) { |
- GenerateFieldDocComment(printer, field); |
- printer->Print( |
- "private $^name^;\n", |
- "name", field->name()); |
- } else if (field->containing_oneof()) { |
- // Oneof fields are handled by GenerateOneofField. |
- return; |
- } else { |
- GenerateFieldDocComment(printer, field); |
- printer->Print( |
- "private $^name^ = ^default^;\n", |
- "name", field->name(), |
- "default", DefaultForField(field)); |
- } |
- |
- if (is_descriptor) { |
- printer->Print( |
- "private $has_^name^ = false;\n", |
- "name", field->name()); |
- } |
-} |
- |
-void GenerateOneofField(const OneofDescriptor* oneof, io::Printer* printer) { |
- // Oneof property needs to be protected in order to be accessed by parent |
- // class in implementation. |
- printer->Print( |
- "protected $^name^;\n", |
- "name", oneof->name()); |
-} |
- |
-void GenerateFieldAccessor(const FieldDescriptor* field, bool is_descriptor, |
- io::Printer* printer) { |
- const OneofDescriptor* oneof = field->containing_oneof(); |
- |
- // Generate getter. |
- if (oneof != NULL) { |
- GenerateFieldDocComment(printer, field); |
- printer->Print( |
- "public function get^camel_name^()\n" |
- "{\n" |
- " return $this->readOneof(^number^);\n" |
- "}\n\n", |
- "camel_name", UnderscoresToCamelCase(field->name(), true), |
- "number", IntToString(field->number())); |
- } else { |
- GenerateFieldDocComment(printer, field); |
- printer->Print( |
- "public function get^camel_name^()\n" |
- "{\n" |
- " return $this->^name^;\n" |
- "}\n\n", |
- "camel_name", UnderscoresToCamelCase(field->name(), true), "name", |
- field->name()); |
- } |
- |
- // Generate setter. |
- GenerateFieldDocComment(printer, field); |
- printer->Print( |
- "public function set^camel_name^(^var^)\n" |
- "{\n", |
- "camel_name", UnderscoresToCamelCase(field->name(), true), |
- "var", (field->is_repeated() || |
- field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ? |
- "&$var": "$var"); |
- |
- Indent(printer); |
- |
- // Type check. |
- if (field->is_map()) { |
- } else if (field->is_repeated()) { |
- printer->Print( |
- "GPBUtil::checkRepeatedField($var, " |
- "\\Google\\Protobuf\\Internal\\GPBType::^type^", |
- "type", ToUpper(field->type_name())); |
- if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
- printer->Print( |
- ", \\^class_name^);\n", |
- "class_name", |
- MessageName(field->message_type(), is_descriptor) + "::class"); |
- } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { |
- printer->Print( |
- ", ^class_name^);\n", |
- "class_name", |
- EnumName(field->enum_type(), is_descriptor) + "::class"); |
- } else { |
- printer->Print(");\n"); |
- } |
- } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
- printer->Print( |
- "GPBUtil::checkMessage($var, \\^class_name^::class);\n", |
- "class_name", MessageName(field->message_type(), is_descriptor)); |
- } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { |
- printer->Print( |
- "GPBUtil::checkEnum($var, \\^class_name^::class);\n", |
- "class_name", EnumName(field->enum_type(), is_descriptor)); |
- } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { |
- printer->Print( |
- "GPBUtil::checkString($var, ^utf8^);\n", |
- "utf8", |
- field->type() == FieldDescriptor::TYPE_STRING ? "True": "False"); |
- } else { |
- printer->Print( |
- "GPBUtil::check^type^($var);\n", |
- "type", UnderscoresToCamelCase(field->cpp_type_name(), true)); |
- } |
- |
- if (oneof != NULL) { |
- printer->Print( |
- "$this->writeOneof(^number^, $var);\n", |
- "number", IntToString(field->number())); |
- } else { |
- printer->Print( |
- "$this->^name^ = $var;\n", |
- "name", field->name()); |
- } |
- |
- // Set has bit for proto2 only. |
- if (is_descriptor) { |
- printer->Print( |
- "$this->has_^field_name^ = true;\n", |
- "field_name", field->name()); |
- } |
- |
- Outdent(printer); |
- |
- printer->Print( |
- "}\n\n"); |
- |
- // Generate has method for proto2 only. |
- if (is_descriptor) { |
- printer->Print( |
- "public function has^camel_name^()\n" |
- "{\n" |
- " return $this->has_^field_name^;\n" |
- "}\n\n", |
- "camel_name", UnderscoresToCamelCase(field->name(), true), |
- "field_name", field->name()); |
- } |
-} |
- |
-void GenerateEnumToPool(const EnumDescriptor* en, io::Printer* printer) { |
- printer->Print( |
- "$pool->addEnum('^name^', " |
- "\\Google\\Protobuf\\Internal\\^class_name^::class)\n", |
- "name", EnumFullName(en, true), |
- "class_name", en->name()); |
- Indent(printer); |
- |
- for (int i = 0; i < en->value_count(); i++) { |
- const EnumValueDescriptor* value = en->value(i); |
- printer->Print( |
- "->value(\"^name^\", ^number^)\n", |
- "name", value->name(), |
- "number", IntToString(value->number())); |
- } |
- printer->Print("->finalizeToPool();\n\n"); |
- Outdent(printer); |
-} |
- |
-void GenerateMessageToPool(const string& name_prefix, const Descriptor* message, |
- io::Printer* printer) { |
- // Don't generate MapEntry messages -- we use the PHP extension's native |
- // support for map fields instead. |
- if (message->options().map_entry()) { |
- return; |
- } |
- string class_name = name_prefix.empty()? |
- message->name() : name_prefix + "_" + message->name(); |
- |
- printer->Print( |
- "$pool->addMessage('^message^', " |
- "\\Google\\Protobuf\\Internal\\^class_name^::class)\n", |
- "message", MessageFullName(message, true), |
- "class_name", class_name); |
- |
- Indent(printer); |
- |
- for (int i = 0; i < message->field_count(); i++) { |
- const FieldDescriptor* field = message->field(i); |
- if (field->is_map()) { |
- const FieldDescriptor* key = |
- field->message_type()->FindFieldByName("key"); |
- const FieldDescriptor* val = |
- field->message_type()->FindFieldByName("value"); |
- printer->Print( |
- "->map('^field^', \\Google\\Protobuf\\Internal\\GPBType::^key^, " |
- "\\Google\\Protobuf\\Internal\\GPBType::^value^, ^number^^other^)\n", |
- "field", field->name(), |
- "key", ToUpper(key->type_name()), |
- "value", ToUpper(val->type_name()), |
- "number", SimpleItoa(field->number()), |
- "other", EnumOrMessageSuffix(val, true)); |
- } else if (!field->containing_oneof()) { |
- printer->Print( |
- "->^label^('^field^', " |
- "\\Google\\Protobuf\\Internal\\GPBType::^type^, ^number^^other^)\n", |
- "field", field->name(), |
- "label", LabelForField(field), |
- "type", ToUpper(field->type_name()), |
- "number", SimpleItoa(field->number()), |
- "other", EnumOrMessageSuffix(field, true)); |
- } |
- } |
- |
- // oneofs. |
- for (int i = 0; i < message->oneof_decl_count(); i++) { |
- const OneofDescriptor* oneof = message->oneof_decl(i); |
- printer->Print("->oneof(^name^)\n", |
- "name", oneof->name()); |
- Indent(printer); |
- for (int index = 0; index < oneof->field_count(); index++) { |
- const FieldDescriptor* field = oneof->field(index); |
- printer->Print( |
- "->value('^field^', " |
- "\\Google\\Protobuf\\Internal\\GPBType::^type^, ^number^^other^)\n", |
- "field", field->name(), |
- "type", ToUpper(field->type_name()), |
- "number", SimpleItoa(field->number()), |
- "other", EnumOrMessageSuffix(field, true)); |
- } |
- printer->Print("->finish()\n"); |
- Outdent(printer); |
- } |
- |
- printer->Print( |
- "->finalizeToPool();\n"); |
- |
- Outdent(printer); |
- |
- printer->Print( |
- "\n"); |
- |
- for (int i = 0; i < message->nested_type_count(); i++) { |
- GenerateMessageToPool(class_name, message->nested_type(i), printer); |
- } |
- for (int i = 0; i < message->enum_type_count(); i++) { |
- GenerateEnumToPool(message->enum_type(i), printer); |
- } |
-} |
- |
-void GenerateAddFileToPool(const FileDescriptor* file, bool is_descriptor, |
- io::Printer* printer) { |
- printer->Print( |
- "public static $is_initialized = false;\n\n" |
- "public static function initOnce() {\n"); |
- Indent(printer); |
- |
- printer->Print( |
- "$pool = \\Google\\Protobuf\\Internal\\" |
- "DescriptorPool::getGeneratedPool();\n\n" |
- "if (static::$is_initialized == true) {\n" |
- " return;\n" |
- "}\n"); |
- |
- if (is_descriptor) { |
- for (int i = 0; i < file->message_type_count(); i++) { |
- GenerateMessageToPool("", file->message_type(i), printer); |
- } |
- for (int i = 0; i < file->enum_type_count(); i++) { |
- GenerateEnumToPool(file->enum_type(i), printer); |
- } |
- |
- printer->Print( |
- "$pool->finish();\n"); |
- } else { |
- for (int i = 0; i < file->dependency_count(); i++) { |
- const std::string& name = file->dependency(i)->name(); |
- std::string dependency_filename = |
- GeneratedMetadataFileName(name, is_descriptor); |
- printer->Print( |
- "\\^name^::initOnce();\n", |
- "name", FilenameToClassname(dependency_filename)); |
- } |
- |
- // Add messages and enums to descriptor pool. |
- FileDescriptorSet files; |
- FileDescriptorProto* file_proto = files.add_file(); |
- file->CopyTo(file_proto); |
- string files_data; |
- files.SerializeToString(&files_data); |
- |
- printer->Print("$pool->internalAddGeneratedFile(hex2bin(\n"); |
- Indent(printer); |
- |
- // Only write 30 bytes per line. |
- static const int kBytesPerLine = 30; |
- for (int i = 0; i < files_data.size(); i += kBytesPerLine) { |
- printer->Print( |
- "\"^data^\"^dot^\n", |
- "data", BinaryToHex(files_data.substr(i, kBytesPerLine)), |
- "dot", i + kBytesPerLine < files_data.size() ? " ." : ""); |
- } |
- |
- Outdent(printer); |
- printer->Print( |
- "));\n\n"); |
- } |
- printer->Print( |
- "static::$is_initialized = true;\n"); |
- Outdent(printer); |
- printer->Print("}\n"); |
-} |
- |
-void GenerateUseDeclaration(bool is_descriptor, io::Printer* printer) { |
- if (!is_descriptor) { |
- printer->Print( |
- "use Google\\Protobuf\\Internal\\GPBType;\n" |
- "use Google\\Protobuf\\Internal\\RepeatedField;\n" |
- "use Google\\Protobuf\\Internal\\GPBUtil;\n\n"); |
- } else { |
- printer->Print( |
- "use Google\\Protobuf\\Internal\\GPBType;\n" |
- "use Google\\Protobuf\\Internal\\GPBWire;\n" |
- "use Google\\Protobuf\\Internal\\RepeatedField;\n" |
- "use Google\\Protobuf\\Internal\\InputStream;\n\n" |
- "use Google\\Protobuf\\Internal\\GPBUtil;\n\n"); |
- } |
-} |
- |
-void GenerateHead(const FileDescriptor* file, io::Printer* printer) { |
- printer->Print( |
- "<?php\n" |
- "# Generated by the protocol buffer compiler. DO NOT EDIT!\n" |
- "# source: ^filename^\n" |
- "\n", |
- "filename", file->name()); |
-} |
- |
-std::string FilenameToClassname(const string& filename) { |
- int lastindex = filename.find_last_of("."); |
- std::string result = filename.substr(0, lastindex); |
- for (int i = 0; i < result.size(); i++) { |
- if (result[i] == '/') { |
- result[i] = '\\'; |
- } |
- } |
- return result; |
-} |
- |
-void GenerateMetadataFile(const FileDescriptor* file, |
- bool is_descriptor, |
- GeneratorContext* generator_context) { |
- std::string filename = GeneratedMetadataFileName(file->name(), is_descriptor); |
- scoped_ptr<io::ZeroCopyOutputStream> output( |
- generator_context->Open(filename)); |
- io::Printer printer(output.get(), '^'); |
- |
- GenerateHead(file, &printer); |
- |
- std::string fullname = FilenameToClassname(filename); |
- int lastindex = fullname.find_last_of("\\"); |
- |
- printer.Print( |
- "namespace ^name^;\n\n", |
- "name", fullname.substr(0, lastindex)); |
- |
- if (lastindex != string::npos) { |
- printer.Print( |
- "class ^name^\n" |
- "{\n", |
- "name", fullname.substr(lastindex + 1)); |
- } else { |
- printer.Print( |
- "class ^name^\n" |
- "{\n", |
- "name", fullname); |
- } |
- Indent(&printer); |
- |
- GenerateAddFileToPool(file, is_descriptor, &printer); |
- |
- Outdent(&printer); |
- printer.Print("}\n\n"); |
-} |
- |
-void GenerateEnumFile(const FileDescriptor* file, const EnumDescriptor* en, |
- bool is_descriptor, GeneratorContext* generator_context) { |
- std::string filename = GeneratedEnumFileName(en, is_descriptor); |
- scoped_ptr<io::ZeroCopyOutputStream> output( |
- generator_context->Open(filename)); |
- io::Printer printer(output.get(), '^'); |
- |
- GenerateHead(file, &printer); |
- |
- std::string fullname = FilenameToClassname(filename); |
- int lastindex = fullname.find_last_of("\\"); |
- |
- GenerateEnumDocComment(&printer, en); |
- if (lastindex != string::npos) { |
- printer.Print( |
- "namespace ^name^;\n\n", |
- "name", fullname.substr(0, lastindex)); |
- |
- printer.Print( |
- "class ^name^\n" |
- "{\n", |
- "name", fullname.substr(lastindex + 1)); |
- } else { |
- printer.Print( |
- "class ^name^\n" |
- "{\n", |
- "name", fullname); |
- } |
- Indent(&printer); |
- |
- for (int i = 0; i < en->value_count(); i++) { |
- const EnumValueDescriptor* value = en->value(i); |
- GenerateEnumValueDocComment(&printer, value); |
- printer.Print("const ^name^ = ^number^;\n", |
- "name", value->name(), |
- "number", IntToString(value->number())); |
- } |
- |
- Outdent(&printer); |
- printer.Print("}\n\n"); |
-} |
- |
-void GenerateMessageFile(const FileDescriptor* file, const Descriptor* message, |
- bool is_descriptor, |
- GeneratorContext* generator_context) { |
- // Don't generate MapEntry messages -- we use the PHP extension's native |
- // support for map fields instead. |
- if (message->options().map_entry()) { |
- return; |
- } |
- |
- std::string filename = GeneratedMessageFileName(message, is_descriptor); |
- scoped_ptr<io::ZeroCopyOutputStream> output( |
- generator_context->Open(filename)); |
- io::Printer printer(output.get(), '^'); |
- |
- GenerateHead(file, &printer); |
- |
- std::string fullname = FilenameToClassname(filename); |
- int lastindex = fullname.find_last_of("\\"); |
- |
- if (!file->package().empty()) { |
- printer.Print( |
- "namespace ^name^;\n\n", |
- "name", fullname.substr(0, lastindex)); |
- } |
- |
- GenerateUseDeclaration(is_descriptor, &printer); |
- |
- GenerateMessageDocComment(&printer, message); |
- if (lastindex != string::npos) { |
- printer.Print( |
- "class ^name^ extends \\Google\\Protobuf\\Internal\\Message\n" |
- "{\n", |
- "name", fullname.substr(lastindex + 1)); |
- } else { |
- printer.Print( |
- "class ^name^ extends \\Google\\Protobuf\\Internal\\Message\n" |
- "{\n", |
- "name", fullname); |
- } |
- Indent(&printer); |
- |
- // Field and oneof definitions. |
- for (int i = 0; i < message->field_count(); i++) { |
- const FieldDescriptor* field = message->field(i); |
- GenerateField(field, &printer, is_descriptor); |
- } |
- for (int i = 0; i < message->oneof_decl_count(); i++) { |
- const OneofDescriptor* oneof = message->oneof_decl(i); |
- GenerateOneofField(oneof, &printer); |
- } |
- printer.Print("\n"); |
- |
- printer.Print( |
- "public function __construct() {\n"); |
- Indent(&printer); |
- |
- std::string metadata_filename = |
- GeneratedMetadataFileName(file->name(), is_descriptor); |
- std::string metadata_fullname = FilenameToClassname(metadata_filename); |
- printer.Print( |
- "\\^fullname^::initOnce();\n" |
- "parent::__construct();\n", |
- "fullname", metadata_fullname); |
- |
- Outdent(&printer); |
- printer.Print("}\n\n"); |
- |
- // Field and oneof accessors. |
- for (int i = 0; i < message->field_count(); i++) { |
- const FieldDescriptor* field = message->field(i); |
- GenerateFieldAccessor(field, is_descriptor, &printer); |
- } |
- for (int i = 0; i < message->oneof_decl_count(); i++) { |
- const OneofDescriptor* oneof = message->oneof_decl(i); |
- printer.Print( |
- "public function get^camel_name^()\n" |
- "{\n" |
- " return $this->^name^;\n" |
- "}\n\n", |
- "camel_name", UnderscoresToCamelCase(oneof->name(), true), "name", |
- oneof->name()); |
- } |
- |
- Outdent(&printer); |
- printer.Print("}\n\n"); |
- |
- // Nested messages and enums. |
- for (int i = 0; i < message->nested_type_count(); i++) { |
- GenerateMessageFile(file, message->nested_type(i), is_descriptor, |
- generator_context); |
- } |
- for (int i = 0; i < message->enum_type_count(); i++) { |
- GenerateEnumFile(file, message->enum_type(i), is_descriptor, |
- generator_context); |
- } |
-} |
- |
-void GenerateFile(const FileDescriptor* file, bool is_descriptor, |
- GeneratorContext* generator_context) { |
- GenerateMetadataFile(file, is_descriptor, generator_context); |
- for (int i = 0; i < file->message_type_count(); i++) { |
- GenerateMessageFile(file, file->message_type(i), is_descriptor, |
- generator_context); |
- } |
- for (int i = 0; i < file->enum_type_count(); i++) { |
- GenerateEnumFile(file, file->enum_type(i), is_descriptor, |
- generator_context); |
- } |
-} |
- |
-static string EscapePhpdoc(const string& input) { |
- string result; |
- result.reserve(input.size() * 2); |
- |
- char prev = '*'; |
- |
- for (string::size_type i = 0; i < input.size(); i++) { |
- char c = input[i]; |
- switch (c) { |
- case '*': |
- // Avoid "/*". |
- if (prev == '/') { |
- result.append("*"); |
- } else { |
- result.push_back(c); |
- } |
- break; |
- case '/': |
- // Avoid "*/". |
- if (prev == '*') { |
- result.append("/"); |
- } else { |
- result.push_back(c); |
- } |
- break; |
- case '@': |
- // '@' starts phpdoc tags including the @deprecated tag, which will |
- // cause a compile-time error if inserted before a declaration that |
- // does not have a corresponding @Deprecated annotation. |
- result.append("@"); |
- break; |
- case '<': |
- // Avoid interpretation as HTML. |
- result.append("<"); |
- break; |
- case '>': |
- // Avoid interpretation as HTML. |
- result.append(">"); |
- break; |
- case '&': |
- // Avoid interpretation as HTML. |
- result.append("&"); |
- break; |
- case '\\': |
- // Java interprets Unicode escape sequences anywhere! |
- result.append("\"); |
- break; |
- default: |
- result.push_back(c); |
- break; |
- } |
- |
- prev = c; |
- } |
- |
- return result; |
-} |
- |
-static void GenerateDocCommentBodyForLocation( |
- io::Printer* printer, const SourceLocation& location) { |
- string comments = location.leading_comments.empty() ? |
- location.trailing_comments : location.leading_comments; |
- if (!comments.empty()) { |
- // TODO(teboring): Ideally we should parse the comment text as Markdown and |
- // write it back as HTML, but this requires a Markdown parser. For now |
- // we just use <pre> to get fixed-width text formatting. |
- |
- // If the comment itself contains block comment start or end markers, |
- // HTML-escape them so that they don't accidentally close the doc comment. |
- comments = EscapePhpdoc(comments); |
- |
- vector<string> lines = Split(comments, "\n"); |
- while (!lines.empty() && lines.back().empty()) { |
- lines.pop_back(); |
- } |
- |
- printer->Print(" * <pre>\n"); |
- for (int i = 0; i < lines.size(); i++) { |
- // Most lines should start with a space. Watch out for lines that start |
- // with a /, since putting that right after the leading asterisk will |
- // close the comment. |
- if (!lines[i].empty() && lines[i][0] == '/') { |
- printer->Print(" * ^line^\n", "line", lines[i]); |
- } else { |
- printer->Print(" *^line^\n", "line", lines[i]); |
- } |
- } |
- printer->Print( |
- " * </pre>\n" |
- " *\n"); |
- } |
-} |
- |
-template <typename DescriptorType> |
-static void GenerateDocCommentBody( |
- io::Printer* printer, const DescriptorType* descriptor) { |
- SourceLocation location; |
- if (descriptor->GetSourceLocation(&location)) { |
- GenerateDocCommentBodyForLocation(printer, location); |
- } |
-} |
- |
-static string FirstLineOf(const string& value) { |
- string result = value; |
- |
- string::size_type pos = result.find_first_of('\n'); |
- if (pos != string::npos) { |
- result.erase(pos); |
- } |
- |
- return result; |
-} |
- |
-void GenerateMessageDocComment(io::Printer* printer, |
- const Descriptor* message) { |
- printer->Print("/**\n"); |
- GenerateDocCommentBody(printer, message); |
- printer->Print( |
- " * Protobuf type <code>^fullname^</code>\n" |
- " */\n", |
- "fullname", EscapePhpdoc(message->full_name())); |
-} |
- |
-void GenerateFieldDocComment(io::Printer* printer, |
- const FieldDescriptor* field) { |
- // In theory we should have slightly different comments for setters, getters, |
- // etc., but in practice everyone already knows the difference between these |
- // so it's redundant information. |
- |
- // We start the comment with the main body based on the comments from the |
- // .proto file (if present). We then end with the field declaration, e.g.: |
- // optional string foo = 5; |
- // If the field is a group, the debug string might end with {. |
- printer->Print("/**\n"); |
- GenerateDocCommentBody(printer, field); |
- printer->Print( |
- " * <code>^def^</code>\n", |
- "def", EscapePhpdoc(FirstLineOf(field->DebugString()))); |
- printer->Print(" */\n"); |
-} |
- |
-void GenerateEnumDocComment(io::Printer* printer, const EnumDescriptor* enum_) { |
- printer->Print("/**\n"); |
- GenerateDocCommentBody(printer, enum_); |
- printer->Print( |
- " * Protobuf enum <code>^fullname^</code>\n" |
- " */\n", |
- "fullname", EscapePhpdoc(enum_->full_name())); |
-} |
- |
-void GenerateEnumValueDocComment(io::Printer* printer, |
- const EnumValueDescriptor* value) { |
- printer->Print("/**\n"); |
- GenerateDocCommentBody(printer, value); |
- printer->Print( |
- " * <code>^def^</code>\n" |
- " */\n", |
- "def", EscapePhpdoc(FirstLineOf(value->DebugString()))); |
-} |
- |
-bool Generator::Generate(const FileDescriptor* file, const string& parameter, |
- GeneratorContext* generator_context, |
- string* error) const { |
- bool is_descriptor = parameter == "internal"; |
- |
- if (is_descriptor && file->name() != kDescriptorFile) { |
- *error = |
- "Can only generate PHP code for google/protobuf/descriptor.proto.\n"; |
- return false; |
- } |
- |
- if (!is_descriptor && file->syntax() != FileDescriptor::SYNTAX_PROTO3) { |
- *error = |
- "Can only generate PHP code for proto3 .proto files.\n" |
- "Please add 'syntax = \"proto3\";' to the top of your .proto file.\n"; |
- return false; |
- } |
- |
- GenerateFile(file, is_descriptor, generator_context); |
- |
- return true; |
-} |
- |
-} // namespace php |
-} // namespace compiler |
-} // namespace protobuf |
-} // namespace google |