diff options
Diffstat (limited to 'src/google/protobuf/compiler/ruby/ruby_generator.cc')
-rw-r--r-- | src/google/protobuf/compiler/ruby/ruby_generator.cc | 139 |
1 files changed, 114 insertions, 25 deletions
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator.cc b/src/google/protobuf/compiler/ruby/ruby_generator.cc index bd737c02..6b9ea822 100644 --- a/src/google/protobuf/compiler/ruby/ruby_generator.cc +++ b/src/google/protobuf/compiler/ruby/ruby_generator.cc @@ -28,6 +28,7 @@ // (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 <iomanip> #include <sstream> #include <google/protobuf/compiler/code_generator.h> @@ -45,12 +46,13 @@ namespace compiler { namespace ruby { // Forward decls. -std::string IntToString(int32 value); +template<class numeric_type> std::string NumberToString(numeric_type value); std::string GetRequireName(const std::string& proto_file); std::string LabelForField(google::protobuf::FieldDescriptor* field); std::string TypeName(google::protobuf::FieldDescriptor* field); -void GenerateMessage(const google::protobuf::Descriptor* message, - google::protobuf::io::Printer* printer); +bool GenerateMessage(const google::protobuf::Descriptor* message, + google::protobuf::io::Printer* printer, + std::string* error); void GenerateEnum(const google::protobuf::EnumDescriptor* en, google::protobuf::io::Printer* printer); void GenerateMessageAssignment( @@ -61,8 +63,11 @@ void GenerateEnumAssignment( const std::string& prefix, const google::protobuf::EnumDescriptor* en, google::protobuf::io::Printer* printer); - -std::string IntToString(int32 value) { +std::string DefaultValueForField( + const google::protobuf::FieldDescriptor* field); + +template<class numeric_type> +std::string NumberToString(numeric_type value) { std::ostringstream os; os << value; return os.str(); @@ -110,6 +115,62 @@ std::string TypeName(const google::protobuf::FieldDescriptor* field) { } } +string StringifySyntax(FileDescriptor::Syntax syntax) { + switch (syntax) { + case FileDescriptor::SYNTAX_PROTO2: + return "proto2"; + case FileDescriptor::SYNTAX_PROTO3: + return "proto3"; + case FileDescriptor::SYNTAX_UNKNOWN: + default: + GOOGLE_LOG(FATAL) << "Unsupported syntax; this generator only supports " + "proto2 and proto3 syntax."; + return ""; + } +} + +std::string DefaultValueForField(const google::protobuf::FieldDescriptor* field) { + switch(field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + return NumberToString(field->default_value_int32()); + case FieldDescriptor::CPPTYPE_INT64: + return NumberToString(field->default_value_int64()); + case FieldDescriptor::CPPTYPE_UINT32: + return NumberToString(field->default_value_uint32()); + case FieldDescriptor::CPPTYPE_UINT64: + return NumberToString(field->default_value_uint64()); + case FieldDescriptor::CPPTYPE_FLOAT: + return NumberToString(field->default_value_float()); + case FieldDescriptor::CPPTYPE_DOUBLE: + return NumberToString(field->default_value_double()); + case FieldDescriptor::CPPTYPE_BOOL: + return field->default_value_bool() ? "true" : "false"; + case FieldDescriptor::CPPTYPE_ENUM: + return NumberToString(field->default_value_enum()->number()); + case FieldDescriptor::CPPTYPE_STRING: { + std::ostringstream os; + string default_str = field->default_value_string(); + + if (field->type() == FieldDescriptor::TYPE_STRING) { + os << "\"" << default_str << "\""; + } else if (field->type() == FieldDescriptor::TYPE_BYTES) { + os << "\""; + + os.fill('0'); + for (int i = 0; i < default_str.length(); ++i) { + // Write the hex form of each byte. + os << "\\x" << std::hex << std::setw(2) + << ((uint16) ((unsigned char) default_str.at(i))); + } + os << "\".force_encoding(\"ASCII-8BIT\")"; + } + + return os.str(); + } + default: assert(false); return ""; + } +} + void GenerateField(const google::protobuf::FieldDescriptor* field, google::protobuf::io::Printer* printer) { @@ -124,7 +185,7 @@ void GenerateField(const google::protobuf::FieldDescriptor* field, "name", field->name(), "key_type", TypeName(key_field), "value_type", TypeName(value_field), - "number", IntToString(field->number())); + "number", NumberToString(field->number())); if (value_field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { printer->Print( @@ -146,19 +207,25 @@ void GenerateField(const google::protobuf::FieldDescriptor* field, printer->Print( ":$type$, $number$", "type", TypeName(field), - "number", IntToString(field->number())); + "number", NumberToString(field->number())); if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { printer->Print( - ", \"$subtype$\"\n", + ", \"$subtype$\"", "subtype", field->message_type()->full_name()); } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { printer->Print( - ", \"$subtype$\"\n", + ", \"$subtype$\"", "subtype", field->enum_type()->full_name()); - } else { - printer->Print("\n"); } + + if (field->has_default_value()) { + printer->Print( + ", default: $default$", + "default", DefaultValueForField(field)); + } + + printer->Print("\n"); } } @@ -178,13 +245,18 @@ void GenerateOneof(const google::protobuf::OneofDescriptor* oneof, printer->Print("end\n"); } -void GenerateMessage(const google::protobuf::Descriptor* message, - google::protobuf::io::Printer* printer) { - +bool GenerateMessage(const google::protobuf::Descriptor* message, + google::protobuf::io::Printer* printer, + std::string* error) { + if (message->extension_range_count() > 0 || message->extension_count() > 0) { + *error = "Extensions are not yet supported for proto2 .proto files."; + return false; + } + // Don't generate MapEntry messages -- we use the Ruby extension's native // support for map fields instead. if (message->options().map_entry()) { - return; + return true; } printer->Print( @@ -208,11 +280,15 @@ void GenerateMessage(const google::protobuf::Descriptor* message, printer->Print("end\n"); for (int i = 0; i < message->nested_type_count(); i++) { - GenerateMessage(message->nested_type(i), printer); + if (!GenerateMessage(message->nested_type(i), printer, error)) { + return false; + } } for (int i = 0; i < message->enum_type_count(); i++) { GenerateEnum(message->enum_type(i), printer); } + + return true; } void GenerateEnum(const google::protobuf::EnumDescriptor* en, @@ -227,7 +303,7 @@ void GenerateEnum(const google::protobuf::EnumDescriptor* en, printer->Print( "value :$name$, $number$\n", "name", value->name(), - "number", IntToString(value->number())); + "number", NumberToString(value->number())); } printer->Outdent(); @@ -423,7 +499,8 @@ bool MaybeEmitDependency(const FileDescriptor* import, const FileDescriptor* from, io::Printer* printer, string* error) { - if (import->syntax() == FileDescriptor::SYNTAX_PROTO2) { + if (from->syntax() == FileDescriptor::SYNTAX_PROTO3 && + import->syntax() == FileDescriptor::SYNTAX_PROTO2) { for (int i = 0; i < from->message_type_count(); i++) { if (UsesTypeFromFile(from->message_type(i), import, error)) { // Error text was already set by UsesTypeFromFile(). @@ -462,16 +539,29 @@ bool GenerateFile(const FileDescriptor* file, io::Printer* printer, } } - printer->Print( - "Google::Protobuf::DescriptorPool.generated_pool.build do\n"); + // TODO: Remove this when ruby supports extensions for proto2 syntax. + if (file->extension_count() > 0) { + *error = "Extensions are not yet supported for proto2 .proto files."; + return false; + } + + printer->Print("Google::Protobuf::DescriptorPool.generated_pool.build do\n"); + printer->Indent(); + printer->Print("add_file(\"$filename$\", :syntax => :$syntax$) do\n", + "filename", file->name(), "syntax", + StringifySyntax(file->syntax())); printer->Indent(); for (int i = 0; i < file->message_type_count(); i++) { - GenerateMessage(file->message_type(i), printer); + if (!GenerateMessage(file->message_type(i), printer, error)) { + return false; + } } for (int i = 0; i < file->enum_type_count(); i++) { GenerateEnum(file->enum_type(i), printer); } printer->Outdent(); + printer->Print("end\n"); + printer->Outdent(); printer->Print( "end\n\n"); @@ -492,10 +582,9 @@ bool Generator::Generate( GeneratorContext* generator_context, string* error) const { - if (file->syntax() != FileDescriptor::SYNTAX_PROTO3) { - *error = - "Can only generate Ruby code for proto3 .proto files.\n" - "Please add 'syntax = \"proto3\";' to the top of your .proto file.\n"; + if (file->syntax() != FileDescriptor::SYNTAX_PROTO3 && + file->syntax() != FileDescriptor::SYNTAX_PROTO2) { + *error = "Invalid or unsupported proto syntax"; return false; } |