summaryrefslogtreecommitdiffstats
path: root/contrib/libs/protoc/src/google/protobuf/compiler/perlxs
diff options
context:
space:
mode:
authorDevtools Arcadia <[email protected]>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <[email protected]>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /contrib/libs/protoc/src/google/protobuf/compiler/perlxs
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'contrib/libs/protoc/src/google/protobuf/compiler/perlxs')
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/perlxs/perlxs_generator.cc2045
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/perlxs/perlxs_generator.h153
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/perlxs/perlxs_helpers.cc35
-rw-r--r--contrib/libs/protoc/src/google/protobuf/compiler/perlxs/perlxs_helpers.h19
4 files changed, 2252 insertions, 0 deletions
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/perlxs/perlxs_generator.cc b/contrib/libs/protoc/src/google/protobuf/compiler/perlxs/perlxs_generator.cc
new file mode 100644
index 00000000000..3ae4a39fd5a
--- /dev/null
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/perlxs/perlxs_generator.cc
@@ -0,0 +1,2045 @@
+#include <iostream>
+#include <sstream>
+#include <memory>
+
+#include <google/protobuf/compiler/perlxs/perlxs_generator.h>
+#include <google/protobuf/compiler/perlxs/perlxs_helpers.h>
+#include <google/protobuf/descriptor.h>
+#include "google/protobuf/descriptor.pb.h"
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace perlxs {
+
+inline bool HasFieldPresence(const FileDescriptor* file) {
+ return file->syntax() != FileDescriptor::SYNTAX_PROTO3;
+}
+
+bool HasHasMethod(const FieldDescriptor* field) {
+ if (HasFieldPresence(field->file())) {
+ // In proto1/proto2, every field has a has_$name$() method.
+ return true;
+ }
+ // For message types without true field presence, only fields with a message
+ // type have a has_$name$() method.
+ return field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE;
+}
+
+
+PerlXSGenerator::PerlXSGenerator() {}
+PerlXSGenerator::~PerlXSGenerator() {}
+
+
+bool
+PerlXSGenerator::Generate(const FileDescriptor* file,
+ const TProtoStringType& parameter,
+ OutputDirectory* outdir,
+ TProtoStringType* error) const
+{
+ // Each top-level message get its own XS source file, Perl module,
+ // and typemap. Each top-level enum gets its own Perl module. The
+ // files are generated in the perlxs_out directory.
+
+ for ( int i = 0; i < file->message_type_count(); i++ ) {
+ const Descriptor* message_type = file->message_type(i);
+
+ GenerateMessageXS(message_type, outdir);
+ GenerateMessagePOD(message_type, outdir);
+ GenerateMessageModule(message_type, outdir);
+ }
+
+ for ( int i = 0; i < file->enum_type_count(); i++ ) {
+ const EnumDescriptor* enum_type = file->enum_type(i);
+
+ GenerateEnumModule(enum_type, outdir);
+ }
+
+ return true;
+}
+
+bool
+PerlXSGenerator::ProcessOption(const TProtoStringType& option)
+{
+ size_t equals;
+ bool recognized = false;
+
+ equals = option.find_first_of('=');
+ if (equals != TProtoStringType::npos) {
+ TProtoStringType name = option.substr(0, equals);
+ TProtoStringType value;
+
+ if (option.length() > equals) {
+ value = option.substr(equals + 1);
+ }
+
+ // Right now, we only recognize the --perlxs-package option.
+ if (name == "--perlxs-package") {
+ perlxs_package_ = value;
+ recognized = true;
+ }
+ }
+
+ return recognized;
+}
+
+void
+PerlXSGenerator::GenerateMessageXS(const Descriptor* descriptor,
+ OutputDirectory* outdir) const
+{
+ TProtoStringType filename = descriptor->name() + ".xs";
+ std::unique_ptr<io::ZeroCopyOutputStream> output(outdir->Open(filename));
+ io::Printer printer(output.get(), '$'); // '$' works well in the .xs file
+
+ TProtoStringType base = cpp::StripProto(descriptor->file()->name());
+
+ // Boilerplate at the top of the file.
+
+ printer.Print(
+ "#include <stdint.h>\n"
+ "#include <sstream>\n"
+ "#include <google/protobuf/stubs/common.h>\n"
+ "#include <google/protobuf/io/zero_copy_stream.h>\n"
+ "#include \"$base$.pb.h\"\n"
+ "#ifdef __cplusplus\n"
+ "extern \"C\" {\n"
+ "#endif\n"
+ "#include \"EXTERN.h\"\n"
+ "#include \"perl.h\"\n"
+ "#include \"XSUB.h\"\n"
+ "#ifdef __cplusplus\n"
+ "}\n"
+ "#endif\n"
+ "#ifdef do_open\n"
+ "#undef do_open\n"
+ "#endif\n"
+ "#ifdef do_close\n"
+ "#undef do_close\n"
+ "#endif\n"
+ "#ifdef New\n"
+ "#undef New\n"
+ "#endif\n"
+ "\n"
+ // "using namespace std;\n"
+ "\n",
+ "base",
+ base);
+
+ // ZeroCopyOutputStream implementation (for improved pack() performance)
+
+ printer.Print("class $base$_OutputStream :\n"
+ " public google::protobuf::io::ZeroCopyOutputStream {\n"
+ "public:\n"
+ " explicit $base$_OutputStream(SV * sv) :\n"
+ " sv_(sv), len_(0) {}\n"
+ " ~$base$_OutputStream() {}\n"
+ "\n"
+ " bool Next(void** data, int* size)\n"
+ " {\n"
+ " STRLEN nlen = len_ << 1;\n"
+ "\n"
+ " if ( nlen < 16 ) nlen = 16;\n"
+ " SvGROW(sv_, nlen);\n"
+ " *data = SvEND(sv_) + len_;\n"
+ " *size = SvLEN(sv_) - len_;\n"
+ " len_ = nlen;\n"
+ "\n"
+ " return true;\n"
+ " }\n"
+ "\n"
+ " void BackUp(int count)\n"
+ " {\n"
+ " SvCUR_set(sv_, SvLEN(sv_) - count);\n"
+ " len_ -= count;\n"
+ " }\n"
+ "\n"
+ " void Sync() {\n"
+ " if ( SvCUR(sv_) == 0 ) {\n"
+ " SvCUR_set(sv_, len_);\n"
+ " }\n"
+ " }\n"
+ "\n"
+ " int64_t ByteCount() const\n"
+ " {\n"
+ " return (int64_t)SvCUR(sv_);\n"
+ " }\n"
+ "\n"
+ "private:\n"
+ " SV * sv_;\n"
+ " STRLEN len_;\n"
+ "\n"
+ " GOOGLE_DISALLOW_EVIL_CONSTRUCTORS($base$_OutputStream);\n"
+ "};\n"
+ "\n"
+ "\n",
+ "base",
+ base);
+
+ // Typedefs, Statics, and XS packages
+
+ std::set<const Descriptor*> seen;
+
+ GenerateFileXSTypedefs(descriptor->file(), printer, seen);
+
+ printer.Print("\n\n");
+
+ GenerateMessageStatics(descriptor, printer);
+
+ printer.Print("\n\n");
+
+ GenerateMessageXSPackage(descriptor, printer);
+}
+
+
+void
+PerlXSGenerator::GenerateMessageModule(const Descriptor* descriptor,
+ OutputDirectory* outdir) const
+{
+ TProtoStringType filename = descriptor->name() + ".pm";
+ std::unique_ptr<io::ZeroCopyOutputStream> output(outdir->Open(filename));
+ io::Printer printer(output.get(), '*'); // '*' works well in the .pm file
+
+ std::map<TProtoStringType, TProtoStringType> vars;
+
+ vars["package"] = MessageModuleName(descriptor);
+ vars["message"] = descriptor->full_name();
+ vars["name"] = descriptor->name();
+
+ printer.Print(vars,
+ "package *package*;\n"
+ "\n"
+ "use strict;\n"
+ "use warnings;\n"
+ "use vars qw(@ISA $AUTOLOAD $VERSION);\n"
+ "\n"
+ "$VERSION = '1.0';\n"
+ "\n"
+ "use Exporter;\n"
+ "\n"
+ "require DynaLoader;\n"
+ "require AutoLoader;\n"
+ "\n"
+ "@ISA = qw(DynaLoader Exporter);\n"
+ "\n"
+ "bootstrap *package* $VERSION;\n"
+ "\n"
+ "1;\n"
+ "\n"
+ "__END__\n"
+ "\n");
+}
+
+
+void
+PerlXSGenerator::GenerateMessagePOD(const Descriptor* descriptor,
+ OutputDirectory* outdir) const
+{
+ TProtoStringType filename = descriptor->name() + ".pod";
+ std::unique_ptr<io::ZeroCopyOutputStream> output(outdir->Open(filename));
+ io::Printer printer(output.get(), '*'); // '*' works well in the .pod file
+
+ std::map<TProtoStringType, TProtoStringType> vars;
+
+ vars["package"] = MessageModuleName(descriptor);
+ vars["message"] = descriptor->full_name();
+ vars["name"] = descriptor->name();
+
+ // Generate POD documentation for the module.
+
+ printer.Print(vars,
+ "=pod\n"
+ "\n"
+ "=head1 NAME\n"
+ "\n"
+ "*package* - Perl/XS interface to *message*\n"
+ "\n"
+ "=head1 SYNOPSIS\n"
+ "\n"
+ "=head2 Serializing messages\n"
+ "\n"
+ " #!/usr/bin/perl\n"
+ "\n"
+ " use strict;\n"
+ " use warnings;\n"
+ " use *package*;\n"
+ "\n"
+ " my $*name* = *package*->new;\n"
+ " # Set fields in $*name*...\n"
+ " my $pack*name* = $*name*->pack();\n"
+ "\n"
+ "=head2 Unserializing messages\n"
+ "\n"
+ " #!/usr/bin/perl\n"
+ "\n"
+ " use strict;\n"
+ " use warnings;\n"
+ " use *package*;\n"
+ "\n"
+ " my $pack*name*; # Read this from somewhere...\n"
+ " my $*name* = *package*->new;\n"
+ " if ( $*name*->unpack($pack*name*) ) {\n"
+ " print \"OK\"\n"
+ " } else {\n"
+ " print \"NOT OK\"\n"
+ " }\n"
+ "\n"
+ "=head1 DESCRIPTION\n"
+ "\n"
+ "*package* defines the following classes:\n"
+ "\n"
+ "=over 5\n"
+ "\n");
+
+ // List of classes
+
+ GenerateDescriptorClassNamePOD(descriptor, printer);
+
+ printer.Print("\n"
+ "=back\n"
+ "\n");
+
+ GenerateDescriptorMethodPOD(descriptor, printer);
+
+ printer.Print(vars,
+ "=head1 AUTHOR\n"
+ "\n"
+ "Generated from *message* by the protoc compiler.\n"
+ "\n"
+ "=head1 SEE ALSO\n"
+ "\n");
+
+ // Top-level messages in dependency files (recursively expanded)
+
+ printer.Print("http://code.google.com/p/protobuf\n"
+ "\n"
+ "=cut\n"
+ "\n");
+}
+
+
+void
+PerlXSGenerator::GenerateDescriptorClassNamePOD(const Descriptor* descriptor,
+ io::Printer& printer) const
+{
+ for ( int i = 0; i < descriptor->enum_type_count(); i++ ) {
+ printer.Print("=item C<*name*>\n"
+ "\n"
+ "A wrapper around the *enum* enum\n"
+ "\n",
+ "name", EnumClassName(descriptor->enum_type(i)),
+ "enum", descriptor->enum_type(i)->full_name());
+ }
+
+ for ( int i = 0; i < descriptor->nested_type_count(); i++ ) {
+ GenerateDescriptorClassNamePOD(descriptor->nested_type(i), printer);
+ }
+
+ printer.Print("=item C<*name*>\n"
+ "\n"
+ "A wrapper around the *message* message\n"
+ "\n",
+ "name", MessageClassName(descriptor),
+ "message", descriptor->full_name());
+}
+
+
+void
+PerlXSGenerator::GenerateDescriptorMethodPOD(const Descriptor* descriptor,
+ io::Printer& printer) const
+{
+ for ( int i = 0; i < descriptor->enum_type_count(); i++ ) {
+ const EnumDescriptor * enum_descriptor = descriptor->enum_type(i);
+ printer.Print("=head1 C<*name*> values\n"
+ "\n"
+ "=over 4\n"
+ "\n",
+ "name", EnumClassName(enum_descriptor));
+
+ for ( int j = 0; j < enum_descriptor->value_count(); j++ ) {
+ PODPrintEnumValue(enum_descriptor->value(j), printer);
+ }
+
+ printer.Print("\n"
+ "=back\n"
+ "\n");
+ }
+
+ for ( int i = 0; i < descriptor->nested_type_count(); i++ ) {
+ GenerateDescriptorMethodPOD(descriptor->nested_type(i), printer);
+ }
+
+ // Constructor
+
+ std::map<TProtoStringType, TProtoStringType> vars;
+
+ vars["name"] = MessageClassName(descriptor);
+ vars["value"] = descriptor->name();
+
+ printer.Print(vars,
+ "=head1 *name* Constructor\n"
+ "\n"
+ "=over 4\n"
+ "\n"
+ "=item B<$*value* = *name*-E<gt>new( [$arg] )>\n"
+ "\n"
+ "Constructs an instance of C<*name*>. If a hashref argument\n"
+ "is supplied, it is copied into the message instance as if\n"
+ "the copy_from() method were called immediately after\n"
+ "construction. Otherwise, if a scalar argument is supplied,\n"
+ "it is interpreted as a serialized instance of the message\n"
+ "type, and the scalar is parsed to populate the message\n"
+ "fields. Otherwise, if no argument is supplied, an empty\n"
+ "message instance is constructed.\n"
+ "\n"
+ "=back\n"
+ "\n"
+ "=head1 *name* Methods\n"
+ "\n"
+ "=over 4\n"
+ "\n");
+
+ // Common message methods
+
+ printer.Print(vars,
+ "=item B<$*value*2-E<gt>copy_from($*value*1)>\n"
+ "\n"
+ "Copies the contents of C<*value*1> into C<*value*2>.\n"
+ "C<*value*2> is another instance of the same message type.\n"
+ "\n"
+ "=item B<$*value*2-E<gt>copy_from($hashref)>\n"
+ "\n"
+ "Copies the contents of C<hashref> into C<*value*2>.\n"
+ "C<hashref> is a Data::Dumper-style representation of an\n"
+ "instance of the message type.\n"
+ "\n"
+ "=item B<$*value*2-E<gt>merge_from($*value*1)>\n"
+ "\n"
+ "Merges the contents of C<*value*1> into C<*value*2>.\n"
+ "C<*value*2> is another instance of the same message type.\n"
+ "\n"
+ "=item B<$*value*2-E<gt>merge_from($hashref)>\n"
+ "\n"
+ "Merges the contents of C<hashref> into C<*value*2>.\n"
+ "C<hashref> is a Data::Dumper-style representation of an\n"
+ "instance of the message type.\n"
+ "\n"
+ "=item B<$*value*-E<gt>clear()>\n"
+ "\n"
+ "Clears the contents of C<*value*>.\n"
+ "\n"
+ "=item B<$init = $*value*-E<gt>is_initialized()>\n"
+ "\n"
+ "Returns 1 if C<*value*> has been initialized with data.\n"
+ "\n"
+ "=item B<$errstr = $*value*-E<gt>error_string()>\n"
+ "\n"
+ "Returns a comma-delimited TProtoStringType of initialization errors.\n"
+ "\n"
+ "=item B<$*value*-E<gt>discard_unknown_fields()>\n"
+ "\n"
+ "Discards unknown fields from C<*value*>.\n"
+ "\n"
+ "=item B<$dstr = $*value*-E<gt>debug_string()>\n"
+ "\n"
+ "Returns a TProtoStringType representation of C<*value*>.\n"
+ "\n"
+ "=item B<$dstr = $*value*-E<gt>short_debug_string()>\n"
+ "\n"
+ "Returns a short TProtoStringType representation of C<*value*>.\n"
+ "\n"
+ "=item B<$ok = $*value*-E<gt>unpack($TProtoStringType)>\n"
+ "\n"
+ "Attempts to parse C<TProtoStringType> into C<*value*>, returning 1 "
+ "on success and 0 on failure.\n"
+ "\n"
+ "=item B<$TProtoStringType = $*value*-E<gt>pack()>\n"
+ "\n"
+ "Serializes C<*value*> into C<TProtoStringType>.\n"
+ "\n"
+ "=item B<$length = $*value*-E<gt>length()>\n"
+ "\n"
+ "Returns the serialized length of C<*value*>.\n"
+ "\n"
+ "=item B<@fields = $*value*-E<gt>fields()>\n"
+ "\n"
+ "Returns the defined fields of C<*value*>.\n"
+ "\n"
+ "=item B<$hashref = $*value*-E<gt>to_hashref()>\n"
+ "\n"
+ "Exports the message to a hashref suitable for use in the\n"
+ "C<copy_from> or C<merge_from> methods.\n"
+ "\n");
+
+ // Message field accessors
+
+ for ( int i = 0; i < descriptor->field_count(); i++ ) {
+ const FieldDescriptor* field = descriptor->field(i);
+
+ vars["field"] = field->name();
+ vars["type"] = PODFieldTypeString(field);
+
+ // has_blah or blah_size methods
+
+ if ( field->is_repeated() ) {
+ printer.Print(vars,
+ "=item B<$*field*_size = $*value*-E<gt>*field*_size()>\n"
+ "\n"
+ "Returns the number of C<*field*> elements present "
+ "in C<*value*>.\n"
+ "\n");
+ } else {
+ printer.Print(vars,
+ "=item B<$has_*field* = $*value*-E<gt>has_*field*()>\n"
+ "\n"
+ "Returns 1 if the C<*field*> element of C<*value*> "
+ "is set, 0 otherwise.\n"
+ "\n");
+ }
+
+ // clear_blah method
+
+ printer.Print(vars,
+ "=item B<$*value*-E<gt>clear_*field*()>\n"
+ "\n"
+ "Clears the C<*field*> element(s) of C<*value*>.\n"
+ "\n");
+
+ // getters
+
+ if ( field->is_repeated() ) {
+ printer.Print(vars,
+ "=item B<@*field*_list = $*value*-E<gt>*field*()>\n"
+ "\n"
+ "Returns all values of C<*field*> in an array. Each "
+ "element of C<*field*_list> will be *type*.\n"
+ "\n"
+ "=item B<$*field*_elem = $*value*-E<gt>*field*($index)>\n"
+ "\n"
+ "Returns C<*field*> element C<index> from C<*value*>. "
+ "C<*field*> will be *type*, unless C<index> is out of "
+ "range, in which case it will be undef.\n"
+ "\n");
+ } else {
+ printer.Print(vars,
+ "=item B<$*field* = $*value*-E<gt>*field*()>\n"
+ "\n"
+ "Returns C<*field*> from C<*value*>. C<*field*> will "
+ "be *type*.\n"
+ "\n");
+ }
+
+ // setters
+
+ if ( field->is_repeated() ) {
+ printer.Print(vars,
+ "=item B<$*value*-E<gt>add_*field*($value)>\n"
+ "\n"
+ "Adds C<value> to the list of C<*field*> in C<*value*>. "
+ "C<value> must be *type*.\n"
+ "\n");
+ } else {
+ printer.Print(vars,
+ "=item B<$*value*-E<gt>set_*field*($value)>\n"
+ "\n"
+ "Sets the value of C<*field*> in C<*value*> to "
+ "C<value>. C<value> must be *type*.\n"
+ "\n");
+ }
+ }
+
+ printer.Print("\n"
+ "=back\n"
+ "\n");
+}
+
+
+void
+PerlXSGenerator::GenerateEnumModule(const EnumDescriptor* enum_descriptor,
+ OutputDirectory* outdir) const
+{
+ TProtoStringType filename = enum_descriptor->name() + ".pm";
+ std::unique_ptr<io::ZeroCopyOutputStream> output(outdir->Open(filename));
+ io::Printer printer(output.get(), '*'); // '*' works well in the .pm file
+
+ std::map<TProtoStringType, TProtoStringType> vars;
+
+ vars["package"] = EnumClassName(enum_descriptor);
+ vars["enum"] = enum_descriptor->full_name();
+
+ printer.Print(vars,
+ "package *package*;\n"
+ "\n"
+ "use strict;\n"
+ "use warnings;\n"
+ "\n");
+
+ // Each enum value is exported as a constant.
+
+ for ( int i = 0; i < enum_descriptor->value_count(); i++ ) {
+ std::ostringstream ost;
+ ost << enum_descriptor->value(i)->number();
+ printer.Print("use constant *value* => *number*;\n",
+ "value", enum_descriptor->value(i)->name(),
+ "number", ost.str().c_str());
+ }
+
+ printer.Print("\n"
+ "1;\n"
+ "\n"
+ "__END__\n"
+ "\n");
+
+ // Now generate POD for the enum.
+
+ printer.Print(vars,
+ "=pod\n"
+ "\n"
+ "=head1 NAME\n"
+ "\n"
+ "*package* - Perl interface to *enum*\n"
+ "\n"
+ "=head1 SYNOPSIS\n"
+ "\n"
+ " use *package*;\n"
+ "\n");
+
+ for ( int i = 0; i < enum_descriptor->value_count(); i++ ) {
+ printer.Print(" my $*value* = *package*::*value*;\n",
+ "package", vars["package"],
+ "value", enum_descriptor->value(i)->name());
+ }
+
+ printer.Print(vars,
+ "\n"
+ "=head1 DESCRIPTION\n"
+ "\n"
+ "*package* defines the following constants:\n"
+ "\n"
+ "=over 4\n"
+ "\n");
+
+ for ( int i = 0; i < enum_descriptor->value_count(); i++ ) {
+ PODPrintEnumValue(enum_descriptor->value(i), printer);
+ }
+
+ printer.Print(vars,
+ "\n"
+ "=back\n"
+ "\n"
+ "=head1 AUTHOR\n"
+ "\n"
+ "Generated from *enum* by the protoc compiler.\n"
+ "\n"
+ "=head1 SEE ALSO\n"
+ "\n"
+ "http://code.google.com/p/protobuf\n"
+ "\n"
+ "=cut\n"
+ "\n");
+}
+
+
+void
+PerlXSGenerator::GenerateFileXSTypedefs(const FileDescriptor* file,
+ io::Printer& printer,
+ std::set<const Descriptor*>& seen) const
+{
+ for ( int i = 0; i < file->dependency_count(); i++ ) {
+ GenerateFileXSTypedefs(file->dependency(i), printer, seen);
+ }
+
+ for ( int i = 0; i < file->message_type_count(); i++ ) {
+ GenerateMessageXSTypedefs(file->message_type(i), printer, seen);
+ }
+}
+
+
+void
+PerlXSGenerator::GenerateMessageXSTypedefs(const Descriptor* descriptor,
+ io::Printer& printer,
+ std::set<const Descriptor*>& seen) const
+{
+ for ( int i = 0; i < descriptor->nested_type_count(); i++ ) {
+ GenerateMessageXSTypedefs(descriptor->nested_type(i), printer, seen);
+ }
+
+ if ( seen.find(descriptor) == seen.end() ) {
+ TProtoStringType cn = cpp::ClassName(descriptor, true);
+ TProtoStringType un = StringReplace(cn, "::", "__", true);
+
+ seen.insert(descriptor);
+ printer.Print("typedef $classname$ $underscores$;\n",
+ "classname", cn,
+ "underscores", un);
+ }
+}
+
+
+void
+PerlXSGenerator::GenerateMessageStatics(const Descriptor* descriptor,
+ io::Printer& printer) const
+{
+ for ( int i = 0; i < descriptor->nested_type_count(); i++ ) {
+ GenerateMessageStatics(descriptor->nested_type(i), printer);
+ }
+
+ std::map<TProtoStringType, TProtoStringType> vars;
+
+ TProtoStringType cn = cpp::ClassName(descriptor, true);
+ TProtoStringType un = StringReplace(cn, "::", "__", true);
+
+ vars["depth"] = "0";
+ vars["fieldtype"] = cn;
+ vars["classname"] = cn;
+ vars["underscores"] = un;
+
+ // from_hashref static helper
+
+ printer.Print(vars,
+ "static $classname$ *\n"
+ "$underscores$_from_hashref ( SV * sv0 )\n"
+ "{\n"
+ " $fieldtype$ * msg$depth$ = new $fieldtype$;\n"
+ "\n");
+
+ printer.Indent();
+ MessageFromHashref(descriptor, printer, vars, 0);
+ printer.Outdent();
+
+ printer.Print("\n"
+ " return msg0;\n"
+ "}\n"
+ "\n");
+}
+
+
+void
+PerlXSGenerator::GenerateMessageXSFieldAccessors(const FieldDescriptor* field,
+ io::Printer& printer,
+ const TProtoStringType& classname) const
+{
+ const Descriptor* descriptor = field->containing_type();
+ TProtoStringType cppname = cpp::FieldName(field);
+ TProtoStringType perlclass = MessageClassName(descriptor);
+ bool repeated = field->is_repeated();
+
+ std::map<TProtoStringType, TProtoStringType> vars;
+
+ vars["classname"] = classname;
+ vars["cppname"] = cppname;
+ vars["perlname"] = field->name();
+ vars["perlclass"] = perlclass;
+
+ FieldDescriptor::CppType fieldtype = field->cpp_type();
+ FieldDescriptor::Type type = field->type();
+
+ if ( fieldtype == FieldDescriptor::CPPTYPE_MESSAGE ) {
+ vars["fieldtype"] = cpp::ClassName(field->message_type(), true);
+ vars["fieldclass"] = MessageClassName(field->message_type());
+ }
+
+ // For repeated fields, we need an index argument.
+
+ if ( repeated ) {
+ vars["i"] = "index";
+ } else {
+ vars["i"] = "";
+ }
+
+ // -------------------------------------------------------------------
+ // First, the has_X method or X_size method.
+ // -------------------------------------------------------------------
+
+ if ( repeated ) {
+ printer.Print(vars,
+ "I32\n"
+ "$perlname$_size(svTHIS)\n"
+ " SV * svTHIS;\n"
+ " CODE:\n");
+ GenerateTypemapInput(descriptor, printer, "THIS");
+ printer.Print(vars,
+ " RETVAL = THIS->$cppname$_size();\n"
+ "\n"
+ " OUTPUT:\n"
+ " RETVAL\n");
+ } else if ( HasHasMethod(field) ) {
+ printer.Print(vars,
+ "I32\n"
+ "has_$perlname$(svTHIS)\n"
+ " SV * svTHIS;\n"
+ " CODE:\n");
+ GenerateTypemapInput(descriptor, printer, "THIS");
+ printer.Print(vars,
+ " RETVAL = THIS->has_$cppname$();\n"
+ "\n"
+ " OUTPUT:\n"
+ " RETVAL\n");
+ }
+
+ printer.Print("\n\n");
+
+ // -------------------------------------------------------------------
+ // Next, the "clear" method.
+ // -------------------------------------------------------------------
+
+ printer.Print(vars,
+ "void\n"
+ "clear_$perlname$(svTHIS)\n"
+ " SV * svTHIS;\n"
+ " CODE:\n");
+ GenerateTypemapInput(descriptor, printer, "THIS");
+ printer.Print(vars,
+ " THIS->clear_$cppname$();\n"
+ "\n"
+ "\n");
+
+ // -------------------------------------------------------------------
+ // Next, the "get" method.
+ // -------------------------------------------------------------------
+
+ // Repeated fields have an optional index argument.
+
+ if ( repeated ) {
+ printer.Print(vars,
+ "void\n"
+ "$perlname$(svTHIS, ...)\n");
+ } else {
+ printer.Print(vars,
+ "void\n"
+ "$perlname$(svTHIS)\n");
+ }
+
+ printer.Print(" SV * svTHIS;\n"
+ "PREINIT:\n"
+ " SV * sv;\n");
+
+ if ( repeated ) {
+ printer.Print(" int index = 0;\n");
+ }
+
+ // We need to store 64-bit integers as strings in Perl.
+
+ if ( fieldtype == FieldDescriptor::CPPTYPE_INT64 ||
+ fieldtype == FieldDescriptor::CPPTYPE_UINT64 ) {
+ printer.Print(" std::ostringstream ost;\n");
+ }
+
+ if ( fieldtype == FieldDescriptor::CPPTYPE_MESSAGE ) {
+ printer.Print(vars,
+ " $fieldtype$ * val = NULL;\n");
+ }
+
+ // We'll use PPCODE in either case, just to make this a little
+ // simpler.
+
+ printer.Print("\n"
+ " PPCODE:\n");
+
+ GenerateTypemapInput(descriptor, printer, "THIS");
+
+ // For repeated fields, we need to check the usage ourselves.
+
+ if ( repeated ) {
+ printer.Print(vars,
+ " if ( items == 2 ) {\n"
+ " index = SvIV(ST(1));\n"
+ " } else if ( items > 2 ) {\n"
+ " croak(\"Usage: $perlclass$::$perlname$(CLASS, [index])\");\n"
+ " }\n");
+ }
+
+ // There are three possibilities now:
+ //
+ // 1) The user wants a particular element of a repeated field.
+ // 2) The user wants all elements of a repeated field.
+ // 3) The user wants the value of a non-repeated field.
+
+ if ( repeated ) {
+ printer.Print(vars,
+ " if ( THIS != NULL ) {\n"
+ " if ( items == 1 ) {\n"
+ " int count = THIS->$cppname$_size();\n"
+ "\n"
+ " EXTEND(SP, count);\n"
+ " for ( int index = 0; index < count; index++ ) {\n");
+ PerlSVGetHelper(printer,vars,fieldtype,5);
+ printer.Print(vars,
+ " PUSHs(sv);\n"
+ " }\n"
+ " } else if ( index >= 0 &&\n"
+ " index < THIS->$cppname$_size() ) {\n"
+ " EXTEND(SP,1);\n");
+ PerlSVGetHelper(printer,vars,fieldtype,4);
+ printer.Print(" PUSHs(sv);\n"
+ " } else {\n"
+ " EXTEND(SP,1);\n"
+ " PUSHs(&PL_sv_undef);\n"
+ " }\n"
+ " }\n");
+ } else {
+ printer.Print(" if ( THIS != NULL ) {\n"
+ " EXTEND(SP,1);\n");
+ PerlSVGetHelper(printer,vars,fieldtype,3);
+ printer.Print(" PUSHs(sv);\n"
+ " }\n");
+ }
+
+ printer.Print("\n\n");
+
+ // -------------------------------------------------------------------
+ // Finally, the "set" method.
+ // -------------------------------------------------------------------
+
+ if ( repeated ) {
+ printer.Print(vars,
+ "void\n"
+ "add_$perlname$(svTHIS, svVAL)\n");
+ } else {
+ printer.Print(vars,
+ "void\n"
+ "set_$perlname$(svTHIS, svVAL)\n");
+ }
+
+ printer.Print(" SV * svTHIS\n");
+
+ // What is the incoming type?
+
+ switch ( fieldtype ) {
+ case FieldDescriptor::CPPTYPE_ENUM:
+ vars["etype"] = cpp::ClassName(field->enum_type(), true);
+ // Fall through
+ case FieldDescriptor::CPPTYPE_INT32:
+ case FieldDescriptor::CPPTYPE_BOOL:
+ vars["value"] = "svVAL";
+ printer.Print(" IV svVAL\n"
+ "\n"
+ " CODE:\n");
+ break;
+ case FieldDescriptor::CPPTYPE_UINT32:
+ vars["value"] = "svVAL";
+ printer.Print(" UV svVAL\n"
+ "\n"
+ " CODE:\n");
+ break;
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ vars["value"] = "svVAL";
+ printer.Print(" NV svVAL\n"
+ "\n"
+ " CODE:\n");
+ break;
+ case FieldDescriptor::CPPTYPE_INT64:
+ vars["value"] = "lval";
+ printer.Print(" char *svVAL\n"
+ "\n"
+ " PREINIT:\n"
+ " long long lval;\n"
+ "\n"
+ " CODE:\n"
+ " lval = strtoll((svVAL) ? svVAL : \"\", NULL, 0);\n");
+ break;
+ case FieldDescriptor::CPPTYPE_UINT64:
+ vars["value"] = "lval";
+ printer.Print(" char *svVAL\n"
+ "\n"
+ " PREINIT:\n"
+ " unsigned long long lval;\n"
+ "\n"
+ " CODE:\n"
+ " lval = strtoull((svVAL) ? svVAL : \"\", NULL, 0);\n");
+ break;
+ case FieldDescriptor::CPPTYPE_STRING:
+ vars["value"] = "sval";
+ printer.Print(" SV *svVAL\n"
+ "\n"
+ " PREINIT:\n"
+ " char * str;\n"
+ " STRLEN len;\n");
+ if ( type == FieldDescriptor::TYPE_STRING ) {
+ printer.Print(vars,
+ " TString $value$;\n");
+ }
+ printer.Print("\n"
+ " CODE:\n");
+ break;
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ printer.Print(vars,
+ " SV * svVAL\n"
+ " CODE:\n");
+ break;
+ default:
+ vars["value"] = "svVAL";
+ break;
+ }
+
+ GenerateTypemapInput(descriptor, printer, "THIS");
+
+ if ( fieldtype == FieldDescriptor::CPPTYPE_MESSAGE ) {
+ GenerateTypemapInput(field->message_type(), printer, "VAL");
+ }
+
+ if ( repeated ) {
+ if ( fieldtype == FieldDescriptor::CPPTYPE_MESSAGE ) {
+ printer.Print(vars,
+ " if ( VAL != NULL ) {\n"
+ " $fieldtype$ * mval = THIS->add_$cppname$();\n"
+ " mval->CopyFrom(*VAL);\n"
+ " }\n");
+ } else if ( fieldtype == FieldDescriptor::CPPTYPE_ENUM ) {
+ printer.Print(vars,
+ " if ( $etype$_IsValid(svVAL) ) {\n"
+ " THIS->add_$cppname$(($etype$)svVAL);\n"
+ " }\n");
+ } else if ( fieldtype == FieldDescriptor::CPPTYPE_STRING ) {
+ printer.Print(" str = SvPV(svVAL, len);\n");
+ if ( type == FieldDescriptor::TYPE_BYTES ) {
+ printer.Print(vars,
+ " THIS->add_$cppname$(str, len);\n");
+ } else if ( type == FieldDescriptor::TYPE_STRING ) {
+ printer.Print(vars,
+ " $value$.assign(str, len);\n"
+ " THIS->add_$cppname$($value$);\n");
+ }
+ } else {
+ printer.Print(vars,
+ " THIS->add_$cppname$($value$);\n");
+ }
+ } else {
+ if ( fieldtype == FieldDescriptor::CPPTYPE_MESSAGE ) {
+ printer.Print(vars,
+ " if ( VAL != NULL ) {\n"
+ " $fieldtype$ * mval = THIS->mutable_$cppname$();\n"
+ " mval->CopyFrom(*VAL);\n"
+ " }\n");
+ } else if ( fieldtype == FieldDescriptor::CPPTYPE_ENUM ) {
+ printer.Print(vars,
+ " if ( $etype$_IsValid(svVAL) ) {\n"
+ " THIS->set_$cppname$(($etype$)svVAL);\n"
+ " }\n");
+ } else if ( fieldtype == FieldDescriptor::CPPTYPE_STRING ) {
+ printer.Print(" str = SvPV(svVAL, len);\n");
+ if ( type == FieldDescriptor::TYPE_STRING ) {
+ printer.Print(vars,
+ " sval.assign(str, len);\n"
+ " THIS->set_$cppname$($value$);\n");
+ } else if ( type == FieldDescriptor::TYPE_BYTES ) {
+ printer.Print(vars,
+ " THIS->set_$cppname$(str, len);\n");
+ } else {
+ // Can't get here
+ }
+ } else {
+ printer.Print(vars,
+ " THIS->set_$cppname$($value$);\n");
+ }
+ }
+
+ printer.Print("\n\n");
+}
+
+
+void
+PerlXSGenerator::GenerateMessageXSCommonMethods(const Descriptor* descriptor,
+ io::Printer& printer,
+ const TProtoStringType& classname) const
+{
+ std::map<TProtoStringType, TProtoStringType> vars;
+#if (GOOGLE_PROTOBUF_VERSION >= 2002000)
+ FileOptions::OptimizeMode mode;
+#endif // GOOGLE_PROTOBUF_VERSION
+ TProtoStringType cn = cpp::ClassName(descriptor, true);
+ TProtoStringType un = StringReplace(cn, "::", "__", true);
+
+#if (GOOGLE_PROTOBUF_VERSION >= 2002000)
+ mode = descriptor->file()->options().optimize_for();
+#endif // GOOGLE_PROTOBUF_VERSION
+
+ vars["classname"] = classname;
+ vars["perlclass"] = MessageClassName(descriptor);
+ vars["underscores"] = un;
+
+ // copy_from
+
+ printer.Print(vars,
+ "void\n"
+ "copy_from(svTHIS, sv)\n"
+ " SV * svTHIS\n"
+ " SV * sv\n"
+ " CODE:\n");
+ GenerateTypemapInput(descriptor, printer, "THIS");
+ printer.Print(vars,
+ " if ( THIS != NULL && sv != NULL ) {\n"
+ " if ( sv_derived_from(sv, \"$perlclass$\") ) {\n"
+ " IV tmp = SvIV((SV *)SvRV(sv));\n"
+ " $classname$ * other = "
+ "INT2PTR($underscores$ *, tmp);\n"
+ "\n"
+ " THIS->CopyFrom(*other);\n"
+ " } else if ( SvROK(sv) &&\n"
+ " SvTYPE(SvRV(sv)) == SVt_PVHV ) {\n"
+ " $classname$ * other = "
+ "$underscores$_from_hashref(sv);\n"
+ " THIS->CopyFrom(*other);\n"
+ " delete other;\n"
+ " }\n"
+ " }\n"
+ "\n"
+ "\n");
+
+ // merge_from
+
+ printer.Print(vars,
+ "void\n"
+ "merge_from(svTHIS, sv)\n"
+ " SV * svTHIS\n"
+ " SV * sv\n"
+ " CODE:\n");
+ GenerateTypemapInput(descriptor, printer, "THIS");
+ printer.Print(vars,
+ " if ( THIS != NULL && sv != NULL ) {\n"
+ " if ( sv_derived_from(sv, \"$perlclass$\") ) {\n"
+ " IV tmp = SvIV((SV *)SvRV(sv));\n"
+ " $classname$ * other = "
+ "INT2PTR($underscores$ *, tmp);\n"
+ "\n"
+ " THIS->MergeFrom(*other);\n"
+ " } else if ( SvROK(sv) &&\n"
+ " SvTYPE(SvRV(sv)) == SVt_PVHV ) {\n"
+ " $classname$ * other = "
+ "$underscores$_from_hashref(sv);\n"
+ " THIS->MergeFrom(*other);\n"
+ " delete other;\n"
+ " }\n"
+ " }\n"
+ "\n"
+ "\n");
+
+ // clear
+
+ printer.Print(vars,
+ "void\n"
+ "clear(svTHIS)\n"
+ " SV * svTHIS\n"
+ " CODE:\n");
+ GenerateTypemapInput(descriptor, printer, "THIS");
+ printer.Print(vars,
+ " if ( THIS != NULL ) {\n"
+ " THIS->Clear();\n"
+ " }\n"
+ "\n"
+ "\n");
+
+ // is_initialized
+
+ printer.Print(vars,
+ "int\n"
+ "is_initialized(svTHIS)\n"
+ " SV * svTHIS\n"
+ " CODE:\n");
+ GenerateTypemapInput(descriptor, printer, "THIS");
+ printer.Print(vars,
+ " if ( THIS != NULL ) {\n"
+ " RETVAL = THIS->IsInitialized();\n"
+ " } else {\n"
+ " RETVAL = 0;\n"
+ " }\n"
+ "\n"
+ " OUTPUT:\n"
+ " RETVAL\n"
+ "\n"
+ "\n");
+
+ // error_string
+
+ printer.Print(vars,
+ "SV *\n"
+ "error_string(svTHIS)\n"
+ " SV * svTHIS\n"
+ " PREINIT:\n"
+ " TString estr;\n"
+ "\n"
+ " CODE:\n");
+ GenerateTypemapInput(descriptor, printer, "THIS");
+ printer.Print(vars,
+ " if ( THIS != NULL ) {\n"
+ " estr = THIS->InitializationErrorString();\n"
+ " }\n"
+ " RETVAL = newSVpv(estr.c_str(), estr.length());\n"
+ "\n"
+ " OUTPUT:\n"
+ " RETVAL\n"
+ "\n"
+ "\n");
+
+ // LITE_RUNTIME does not include certain methods.
+
+#if (GOOGLE_PROTOBUF_VERSION >= 2002000)
+ if (mode != FileOptions::LITE_RUNTIME) {
+#endif // GOOGLE_PROTOBUF_VERSION
+
+ // discard_unknown_fields
+
+ printer.Print(vars,
+ "void\n"
+ "discard_unkown_fields(svTHIS)\n"
+ " SV * svTHIS\n"
+ " CODE:\n");
+ GenerateTypemapInput(descriptor, printer, "THIS");
+ printer.Print(vars,
+ " if ( THIS != NULL ) {\n"
+ " THIS->DiscardUnknownFields();\n"
+ " }\n"
+ "\n"
+ "\n");
+
+ // debug_string
+
+ printer.Print(vars,
+ "SV *\n"
+ "debug_string(svTHIS)\n"
+ " SV * svTHIS\n"
+ " PREINIT:\n"
+ " TString dstr;\n"
+ "\n"
+ " CODE:\n");
+ GenerateTypemapInput(descriptor, printer, "THIS");
+ printer.Print(vars,
+ " if ( THIS != NULL ) {\n"
+ " dstr = THIS->DebugString();\n"
+ " }\n"
+ " RETVAL = newSVpv(dstr.c_str(), dstr.length());\n"
+ "\n"
+ " OUTPUT:\n"
+ " RETVAL\n"
+ "\n"
+ "\n");
+
+ // short_debug_string
+
+ printer.Print(vars,
+ "SV *\n"
+ "short_debug_string(svTHIS)\n"
+ " SV * svTHIS\n"
+ " PREINIT:\n"
+ " TString dstr;\n"
+ "\n"
+ " CODE:\n");
+ GenerateTypemapInput(descriptor, printer, "THIS");
+ printer.Print(vars,
+ " if ( THIS != NULL ) {\n"
+ " dstr = THIS->ShortDebugString();\n"
+ " }\n"
+ " RETVAL = newSVpv(dstr.c_str(), dstr.length());\n"
+ "\n"
+ " OUTPUT:\n"
+ " RETVAL\n"
+ "\n"
+ "\n");
+#if (GOOGLE_PROTOBUF_VERSION >= 2002000)
+ }
+#endif // GOOGLE_PROTOBUF_VERSION
+
+ // unpack
+
+ printer.Print(vars,
+ "int\n"
+ "unpack(svTHIS, arg)\n"
+ " SV * svTHIS\n"
+ " SV * arg\n"
+ " PREINIT:\n"
+ " STRLEN len;\n"
+ " char * str;\n"
+ "\n"
+ " CODE:\n");
+ GenerateTypemapInput(descriptor, printer, "THIS");
+ printer.Print(vars,
+ " if ( THIS != NULL ) {\n"
+ " str = SvPV(arg, len);\n"
+ " if ( str != NULL ) {\n"
+ " RETVAL = THIS->ParseFromArray(str, len);\n"
+ " } else {\n"
+ " RETVAL = 0;\n"
+ " }\n"
+ " } else {\n"
+ " RETVAL = 0;\n"
+ " }\n"
+ "\n"
+ " OUTPUT:\n"
+ " RETVAL\n"
+ "\n"
+ "\n");
+
+ // pack
+
+ printer.Print(vars,
+ "SV *\n"
+ "pack(svTHIS)\n"
+ " SV * svTHIS\n");
+
+ // This may be controlled by a custom option at some point.
+#if NO_ZERO_COPY
+ printer.Print(vars,
+ " PREINIT:\n"
+ " TProtoStringType output;\n"
+ "\n");
+#endif
+
+ printer.Print(vars,
+ " CODE:\n");
+ GenerateTypemapInput(descriptor, printer, "THIS");
+ printer.Print(vars,
+ " if ( THIS != NULL ) {\n");
+
+ vars["base"] = cpp::StripProto(descriptor->file()->name());
+
+ printer.Print(vars,
+ " RETVAL = newSVpvn(\"\", 0);\n"
+ " $base$_OutputStream os(RETVAL);\n"
+ " if ( THIS->IsInitialized() ) {\n"
+ " if ( THIS->SerializePartialToZeroCopyStream(&os)"
+ "!= true ) {\n"
+ " SvREFCNT_dec(RETVAL);\n"
+ " RETVAL = Nullsv;\n"
+ " } else {\n"
+ " os.Sync();\n"
+ " }\n"
+ " } else {\n"
+ " croak(\"Can't serialize message of type "
+ "'$perlclass$' because it is missing required fields: %s\",\n"
+ " THIS->InitializationErrorString().c_str());\n"
+ " }\n");
+
+ printer.Print(vars,
+ " } else {\n"
+ " RETVAL = Nullsv;\n"
+ " }\n"
+ "\n"
+ " OUTPUT:\n"
+ " RETVAL\n"
+ "\n"
+ "\n");
+
+ // length
+
+ printer.Print(vars,
+ "int\n"
+ "length(svTHIS)\n"
+ " SV * svTHIS\n"
+ " CODE:\n");
+ GenerateTypemapInput(descriptor, printer, "THIS");
+ printer.Print(vars,
+ " if ( THIS != NULL ) {\n"
+ " RETVAL = THIS->ByteSize();\n"
+ " } else {\n"
+ " RETVAL = 0;\n"
+ " }\n"
+ "\n"
+ " OUTPUT:\n"
+ " RETVAL\n"
+ "\n"
+ "\n");
+
+ // fields
+
+ std::ostringstream field_count;
+
+ field_count << descriptor->field_count();
+ vars["field_count"] = field_count.str();
+ printer.Print(vars,
+ "void\n"
+ "fields(svTHIS)\n"
+ " SV * svTHIS\n"
+ " PPCODE:\n"
+ " (void)svTHIS;\n"
+ " EXTEND(SP, $field_count$);\n");
+
+ for ( int i = 0; i < descriptor->field_count(); i++ ) {
+ const FieldDescriptor* field = descriptor->field(i);
+ vars["field"] = field->name();
+ printer.Print(vars,
+ " PUSHs(sv_2mortal(newSVpv(\"$field$\",0)));\n"
+ );
+ }
+
+ printer.Print("\n\n");
+
+ // to_hashref
+
+ printer.Print(vars,
+ "SV *\n"
+ "to_hashref(svTHIS)\n"
+ " SV * svTHIS\n"
+ " CODE:\n");
+ GenerateTypemapInput(descriptor, printer, "THIS");
+ printer.Print(vars,
+ " if ( THIS != NULL ) {\n"
+ " HV * hv0 = newHV();\n"
+ " $classname$ * msg0 = THIS;\n"
+ "\n");
+
+ vars["depth"] = "0";
+ vars["fieldtype"] = classname;
+
+ printer.Indent();
+ printer.Indent();
+ printer.Indent();
+ MessageToHashref(descriptor, printer, vars, 0);
+ printer.Outdent();
+ printer.Outdent();
+ printer.Outdent();
+
+ printer.Print(" RETVAL = newRV_noinc((SV *)hv0);\n"
+ " } else {\n"
+ " RETVAL = Nullsv;\n"
+ " }\n"
+ "\n"
+ " OUTPUT:\n"
+ " RETVAL\n"
+ "\n"
+ "\n");
+}
+
+void
+PerlXSGenerator::GenerateMessageXSPackage(const Descriptor* descriptor,
+ io::Printer& printer) const
+{
+ for ( int i = 0; i < descriptor->nested_type_count(); i++ ) {
+ GenerateMessageXSPackage(descriptor->nested_type(i), printer);
+ }
+
+ std::map<TProtoStringType, TProtoStringType> vars;
+
+ TProtoStringType cn = cpp::ClassName(descriptor, true);
+ TProtoStringType mn = MessageModuleName(descriptor);
+ TProtoStringType pn = MessageClassName(descriptor);
+ TProtoStringType un = StringReplace(cn, "::", "__", true);
+
+ vars["module"] = mn;
+ vars["classname"] = cn;
+ vars["package"] = pn;
+ vars["underscores"] = un;
+
+ printer.Print(vars,
+ "MODULE = $module$ PACKAGE = $package$\n"
+ "PROTOTYPES: ENABLE\n"
+ "\n"
+ "\n");
+
+ // BOOT (if there are enum types)
+
+ int enum_count = descriptor->enum_type_count();
+
+ if ( enum_count > 0 ) {
+ printer.Print("BOOT:\n"
+ " {\n"
+ " HV * stash;\n\n");
+
+ printer.Indent();
+ printer.Indent();
+ for ( int i = 0; i < enum_count; i++ ) {
+ const EnumDescriptor * etype = descriptor->enum_type(i);
+ int vcount = etype->value_count();
+
+ printer.Print("stash = gv_stashpv(\"$package$::$name$\", TRUE);\n",
+ "package", pn,
+ "name", etype->name());
+ for ( int j = 0; j < vcount; j++ ) {
+ const EnumValueDescriptor * vdesc = etype->value(j);
+ printer.Print(
+ "newCONSTSUB(stash, \"$name$\", newSViv($classname$::$name$));\n",
+ "classname", cn,
+ "name", vdesc->name()
+ );
+ }
+ }
+ printer.Outdent();
+ printer.Outdent();
+ printer.Print(" }\n\n\n");
+ }
+
+ // Constructor
+
+ printer.Print(vars,
+ "SV *\n"
+ "$classname$::new (...)\n"
+ " PREINIT:\n"
+ " $classname$ * rv = NULL;\n"
+ "\n"
+ " CODE:\n"
+ " if ( strcmp(CLASS,\"$package$\") ) {\n"
+ " croak(\"invalid class %s\",CLASS);\n"
+ " }\n"
+ " if ( items == 2 && ST(1) != Nullsv ) {\n"
+ " if ( SvROK(ST(1)) && "
+ "SvTYPE(SvRV(ST(1))) == SVt_PVHV ) {\n"
+ " rv = $underscores$_from_hashref(ST(1));\n"
+ " } else {\n"
+ " STRLEN len;\n"
+ " char * str;\n"
+ "\n"
+ " rv = new $classname$;\n"
+ " str = SvPV(ST(1), len);\n"
+ " if ( str != NULL ) {\n"
+ " rv->ParseFromArray(str, len);\n"
+ " }\n"
+ " }\n"
+ " } else {\n"
+ " rv = new $classname$;\n"
+ " }\n"
+ " RETVAL = newSV(0);\n"
+ " sv_setref_pv(RETVAL, \"$package$\", (void *)rv);\n"
+ "\n"
+ " OUTPUT:\n"
+ " RETVAL\n"
+ "\n"
+ "\n");
+
+ // Destructor
+
+ printer.Print(vars,
+ "void\n"
+ "DESTROY(svTHIS)\n"
+ " SV * svTHIS;\n"
+ " CODE:\n");
+ GenerateTypemapInput(descriptor, printer, "THIS");
+ printer.Print(" if ( THIS != NULL ) {\n"
+ " delete THIS;\n"
+ " }\n"
+ "\n"
+ "\n");
+
+ // Message methods (copy_from, parse_from, etc).
+
+ GenerateMessageXSCommonMethods(descriptor, printer, cn);
+
+ // Field accessors
+
+ for ( int i = 0; i < descriptor->field_count(); i++ ) {
+ GenerateMessageXSFieldAccessors(descriptor->field(i), printer, cn);
+ }
+}
+
+
+void
+PerlXSGenerator::GenerateTypemapInput(const Descriptor* descriptor,
+ io::Printer& printer,
+ const TProtoStringType& svname) const
+{
+ std::map<TProtoStringType, TProtoStringType> vars;
+
+ TProtoStringType cn = cpp::ClassName(descriptor, true);
+
+ vars["classname"] = cn;
+ vars["perlclass"] = MessageClassName(descriptor);
+ vars["underscores"] = StringReplace(cn, "::", "__", true);
+ vars["svname"] = svname;
+
+ printer.Print(vars,
+ " $classname$ * $svname$;\n"
+ " if ( sv_derived_from(sv$svname$, \"$perlclass$\") ) {\n"
+ " IV tmp = SvIV((SV *)SvRV(sv$svname$));\n"
+ " $svname$ = INT2PTR($underscores$ *, tmp);\n"
+ " } else {\n"
+ " croak(\"$svname$ is not of type $perlclass$\");\n"
+ " }\n");
+}
+
+// Returns the containing Perl module name for a message descriptor.
+
+TProtoStringType
+PerlXSGenerator::MessageModuleName(const Descriptor* descriptor) const
+{
+ const Descriptor *container = descriptor;
+
+ while (container->containing_type() != NULL) {
+ container = container->containing_type();
+ }
+
+ return MessageClassName(container);
+}
+
+// Returns the Perl class name for a message descriptor.
+
+TProtoStringType
+PerlXSGenerator::MessageClassName(const Descriptor* descriptor) const
+{
+ return PackageName(descriptor->full_name(), descriptor->file()->package());
+}
+
+// Returns the Perl class name for a message descriptor.
+
+TProtoStringType
+PerlXSGenerator::EnumClassName(const EnumDescriptor* descriptor) const
+{
+ return PackageName(descriptor->full_name(), descriptor->file()->package());
+}
+
+// Possibly replace the package prefix with the --perlxs-package value
+
+TProtoStringType
+PerlXSGenerator::PackageName(const TProtoStringType& name, const TProtoStringType& package) const
+{
+ TProtoStringType output;
+
+ if (!perlxs_package_.empty()) {
+ output = StringReplace(name, package.c_str(), perlxs_package_.c_str(), false);
+ output = StringReplace(output, ".", "::", true);
+ } else {
+ output = StringReplace(name, ".", "::", true);
+ }
+
+ return output;
+}
+
+void
+PerlXSGenerator::PerlSVGetHelper(io::Printer& printer,
+ const std::map<TProtoStringType, TProtoStringType>& vars,
+ FieldDescriptor::CppType fieldtype,
+ int depth) const
+{
+ for ( int i = 0; i < depth; i++ ) {
+ printer.Indent();
+ }
+
+ switch ( fieldtype ) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ case FieldDescriptor::CPPTYPE_BOOL:
+ case FieldDescriptor::CPPTYPE_ENUM:
+ printer.Print(vars,
+ "sv = sv_2mortal(newSViv(THIS->$cppname$($i$)));\n");
+ break;
+ case FieldDescriptor::CPPTYPE_UINT32:
+ printer.Print(vars,
+ "sv = sv_2mortal(newSVuv(THIS->$cppname$($i$)));\n");
+ break;
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ printer.Print(vars,
+ "sv = sv_2mortal(newSVnv(THIS->$cppname$($i$)));\n");
+ break;
+ case FieldDescriptor::CPPTYPE_INT64:
+ case FieldDescriptor::CPPTYPE_UINT64:
+ printer.Print(vars,
+ "ost.str(\"\");\n"
+ "ost << THIS->$cppname$($i$);\n"
+ "sv = sv_2mortal(newSVpv(ost.str().c_str(),\n"
+ " ost.str().length()));\n");
+ break;
+ case FieldDescriptor::CPPTYPE_STRING:
+ printer.Print(vars,
+ "sv = sv_2mortal(newSVpv(THIS->$cppname$($i$).c_str(),\n"
+ " "
+ "THIS->$cppname$($i$).length()));\n");
+ break;
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ printer.Print(vars,
+ "val = new $fieldtype$;\n"
+ "val->CopyFrom(THIS->$cppname$($i$));\n"
+ "sv = sv_newmortal();\n"
+ "sv_setref_pv(sv, \"$fieldclass$\", (void *)val);\n");
+ break;
+ default:
+ printer.Print("sv = &PL_sv_undef;\n");
+ break;
+ }
+
+ for ( int i = 0; i < depth; i++ ) {
+ printer.Outdent();
+ }
+}
+
+void
+PerlXSGenerator::PODPrintEnumValue(const EnumValueDescriptor *value,
+ io::Printer& printer) const
+{
+ std::ostringstream ost;
+ printer.Print("=item B<*value*>\n"
+ "\n",
+ "value", value->name());
+ ost << value->number();
+ printer.Print("This constant has a value of *number*.\n"
+ "\n",
+ "number", ost.str().c_str());
+}
+
+TProtoStringType
+PerlXSGenerator::PODFieldTypeString(const FieldDescriptor* field) const
+{
+ TProtoStringType type;
+
+ switch ( field->cpp_type() ) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ type = "a 32-bit signed integer";
+ break;
+ case FieldDescriptor::CPPTYPE_BOOL:
+ type = "a Boolean value";
+ break;
+ case FieldDescriptor::CPPTYPE_ENUM:
+ type = "a value of " + EnumClassName(field->enum_type());
+ break;
+ case FieldDescriptor::CPPTYPE_UINT32:
+ type = "a 32-bit unsigned integer";
+ break;
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ type = "a floating point number";
+ break;
+ case FieldDescriptor::CPPTYPE_INT64:
+ type = "a 64-bit signed integer";
+ break;
+ case FieldDescriptor::CPPTYPE_UINT64:
+ type = "a 64-bit unsigned integer";
+ break;
+ case FieldDescriptor::CPPTYPE_STRING:
+ type = "a TProtoStringType";
+ break;
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ type = "an instance of " + MessageClassName(field->message_type());
+ break;
+ default:
+ type = "an unknown type";
+ break;
+ }
+
+ return type;
+}
+
+void
+PerlXSGenerator::StartFieldToHashref(const FieldDescriptor * field,
+ io::Printer& printer,
+ std::map<TProtoStringType, TProtoStringType>& vars,
+ int depth) const
+{
+ SetupDepthVars(vars, depth);
+
+ if ( field->is_repeated() ) {
+ vars["i"] = "i" + vars["pdepth"];
+ printer.Print(vars,
+ "if ( msg$pdepth$->$cppname$_size() > 0 ) {\n");
+ printer.Indent();
+ printer.Print(vars,
+ "AV * av$pdepth$ = newAV();\n"
+ "SV * sv$pdepth$ = newRV_noinc((SV *)av$pdepth$);\n"
+ "\n"
+ "for ( int $i$ = 0; "
+ "$i$ < msg$pdepth$->$cppname$_size(); $i$++ ) {\n");
+ } else {
+ vars["i"] = "";
+ if ( HasHasMethod(field) ) {
+ printer.Print(vars,
+ "if ( msg$pdepth$->has_$cppname$() ) {\n");
+ }
+ else {
+ printer.Print(vars,
+ "{\n");
+ }
+ }
+ printer.Indent();
+}
+
+void
+PerlXSGenerator::FieldToHashrefHelper(io::Printer& printer,
+ std::map<TProtoStringType, TProtoStringType>& vars,
+ const FieldDescriptor* field) const
+{
+ vars["msg"] = "msg" + vars["pdepth"];
+ if ( field->is_repeated() ) {
+ vars["sv"] = "sv" + vars["depth"];
+ } else {
+ vars["sv"] = "sv" + vars["pdepth"];
+ }
+
+ switch ( field->cpp_type() ) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ case FieldDescriptor::CPPTYPE_BOOL:
+ case FieldDescriptor::CPPTYPE_ENUM:
+ printer.Print(vars,
+ "SV * $sv$ = newSViv($msg$->$cppname$($i$));\n");
+ break;
+ case FieldDescriptor::CPPTYPE_UINT32:
+ printer.Print(vars,
+ "SV * $sv$ = newSVuv($msg$->$cppname$($i$));\n");
+ break;
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ printer.Print(vars,
+ "SV * $sv$ = newSVnv($msg$->$cppname$($i$));\n");
+ break;
+ case FieldDescriptor::CPPTYPE_INT64:
+ case FieldDescriptor::CPPTYPE_UINT64:
+ printer.Print(vars,
+ "std::ostringstream ost$pdepth$;\n"
+ "\n"
+ "ost$pdepth$ << $msg$->$cppname$($i$);\n"
+ "SV * $sv$ = newSVpv(ost$pdepth$.str().c_str(),"
+ " ost$pdepth$.str().length());\n");
+ break;
+ case FieldDescriptor::CPPTYPE_STRING:
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ default:
+ printer.Print(vars,
+ "SV * $sv$ = newSVpv($msg$->"
+ "$cppname$($i$).c_str(), $msg$->"
+ "$cppname$($i$).length());\n");
+ break;
+ }
+}
+
+void
+PerlXSGenerator::EndFieldToHashref(const FieldDescriptor * field,
+ io::Printer& printer,
+ std::map<TProtoStringType, TProtoStringType>& vars,
+ int depth) const
+{
+ vars["field"] = field->name();
+
+ SetupDepthVars(vars, depth);
+
+ if ( field->is_repeated() ) {
+ printer.Print(vars,
+ "av_push(av$pdepth$, sv$depth$);\n");
+ printer.Outdent();
+ printer.Print(vars,
+ "}\n"
+ "hv_store(hv$pdepth$, \"$field$\", "
+ "sizeof(\"$field$\") - 1, sv$pdepth$, 0);\n");
+ } else {
+ if ( field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ) {
+ printer.Print(vars,
+ "hv_store(hv$pdepth$, \"$field$\", "
+ "sizeof(\"$field$\") - 1, sv$depth$, 0);\n");
+ } else {
+ printer.Print(vars,
+ "hv_store(hv$pdepth$, \"$field$\", "
+ "sizeof(\"$field$\") - 1, sv$pdepth$, 0);\n");
+ }
+ }
+ printer.Outdent();
+ printer.Print("}\n");
+}
+
+void
+PerlXSGenerator::MessageToHashref(const Descriptor * descriptor,
+ io::Printer& printer,
+ std::map<TProtoStringType, TProtoStringType>& vars,
+ int depth) const
+{
+ int i;
+
+ // Iterate the fields
+
+ for ( i = 0; i < descriptor->field_count(); i++ ) {
+ const FieldDescriptor* field = descriptor->field(i);
+ FieldDescriptor::CppType fieldtype = field->cpp_type();
+
+ vars["field"] = field->name();
+ vars["cppname"] = cpp::FieldName(field);
+
+ StartFieldToHashref(field, printer, vars, depth);
+
+ if ( fieldtype == FieldDescriptor::CPPTYPE_MESSAGE ) {
+ vars["fieldtype"] = cpp::ClassName(field->message_type(), true);
+ printer.Print(vars,
+ "$fieldtype$ * msg$ndepth$ = msg$pdepth$->"
+ "mutable_$cppname$($i$);\n"
+ "HV * hv$ndepth$ = newHV();\n"
+ "SV * sv$depth$ = newRV_noinc((SV *)hv$ndepth$);\n"
+ "\n");
+ MessageToHashref(field->message_type(), printer, vars, depth + 2);
+ SetupDepthVars(vars, depth);
+ } else {
+ FieldToHashrefHelper(printer, vars, field);
+ }
+
+ EndFieldToHashref(field, printer, vars, depth);
+ }
+}
+
+void
+PerlXSGenerator::FieldFromHashrefHelper(io::Printer& printer,
+ std::map<TProtoStringType, TProtoStringType>& vars,
+ const FieldDescriptor * field) const
+{
+ vars["msg"] = "msg" + vars["pdepth"];
+ vars["var"] = "*sv" + vars["depth"];
+
+ if ( field->is_repeated() ) {
+ vars["do"] = "add";
+ } else {
+ vars["do"] = "set";
+ }
+
+ switch ( field->cpp_type() ) {
+ case FieldDescriptor::CPPTYPE_INT32:
+ case FieldDescriptor::CPPTYPE_BOOL:
+ printer.Print(vars,
+ "$msg$->$do$_$cppname$(SvIV($var$));\n");
+ break;
+ case FieldDescriptor::CPPTYPE_ENUM:
+ vars["etype"] = cpp::ClassName(field->enum_type(), true);
+ printer.Print(vars,
+ "$msg$->$do$_$cppname$"
+ "(($etype$)SvIV($var$));\n");
+ break;
+ case FieldDescriptor::CPPTYPE_UINT32:
+ printer.Print(vars,
+ "$msg$->$do$_$cppname$(SvUV($var$));\n");
+ break;
+ case FieldDescriptor::CPPTYPE_FLOAT:
+ case FieldDescriptor::CPPTYPE_DOUBLE:
+ printer.Print(vars,
+ "$msg$->$do$_$cppname$(SvNV($var$));\n");
+ break;
+ case FieldDescriptor::CPPTYPE_INT64:
+ printer.Print(vars,
+ "int64_t iv$pdepth$ = "
+ "strtoll(SvPV_nolen($var$), NULL, 0);\n"
+ "\n"
+ "$msg$->$do$_$cppname$(iv$pdepth$);\n");
+ break;
+ case FieldDescriptor::CPPTYPE_UINT64:
+ printer.Print(vars,
+ "uint64_t uv$pdepth$ = "
+ "strtoull(SvPV_nolen($var$), NULL, 0);\n"
+ "\n"
+ "$msg$->$do$_$cppname$(uv$pdepth$);\n");
+ break;
+ case FieldDescriptor::CPPTYPE_STRING:
+ printer.Print("STRLEN len;\n"
+ "char * str;\n");
+
+ if ( field->type() == FieldDescriptor::TYPE_STRING ) {
+ printer.Print("TString sval;\n");
+ }
+
+ printer.Print(vars,
+ "\n"
+ "str = SvPV($var$, len);\n");
+
+ if ( field->type() == FieldDescriptor::TYPE_STRING ) {
+ printer.Print(vars,
+ "sval.assign(str, len);\n"
+ "$msg$->$do$_$cppname$(sval);\n");
+ } else if ( field->type() == FieldDescriptor::TYPE_BYTES ) {
+ printer.Print(vars,
+ "$msg$->$do$_$cppname$(str, len);\n");
+ } else {
+ // Can't get here
+ }
+ break;
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ // Should never get here.
+ default:
+ break;
+ }
+}
+
+void
+PerlXSGenerator::MessageFromHashref(const Descriptor * descriptor,
+ io::Printer& printer,
+ std::map<TProtoStringType, TProtoStringType>& vars,
+ int depth) const
+{
+ int i;
+
+ SetupDepthVars(vars, depth);
+
+ printer.Print(vars,
+ "if ( SvROK(sv$pdepth$) && "
+ "SvTYPE(SvRV(sv$pdepth$)) == SVt_PVHV ) {\n");
+ printer.Indent();
+ printer.Print(vars,
+ "HV * hv$pdepth$ = (HV *)SvRV(sv$pdepth$);\n"
+ "SV ** sv$depth$;\n"
+ "\n");
+
+ // Iterate the fields
+
+ for ( i = 0; i < descriptor->field_count(); i++ ) {
+ const FieldDescriptor* field = descriptor->field(i);
+
+ vars["field"] = field->name();
+ vars["cppname"] = cpp::FieldName(field);
+
+ if ( field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ) {
+ vars["fieldtype"] = cpp::ClassName(field->message_type(), true);
+ }
+
+ printer.Print(vars,
+ "if ( (sv$depth$ = hv_fetch(hv$pdepth$, "
+ "\"$field$\", sizeof(\"$field$\") - 1, 0)) != NULL ) {\n");
+
+ printer.Indent();
+
+ if ( field->is_repeated() ) {
+ printer.Print(vars,
+ "if ( SvROK(*sv$depth$) && "
+ "SvTYPE(SvRV(*sv$depth$)) == SVt_PVAV ) {\n");
+ printer.Indent();
+ printer.Print(vars,
+ "AV * av$depth$ = (AV *)SvRV(*sv$depth$);\n"
+ "\n"
+ "for ( int i$depth$ = 0; "
+ "i$depth$ <= av_len(av$depth$); i$depth$++ ) {\n");
+ printer.Indent();
+
+ if ( field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ) {
+ printer.Print(vars,
+ "$fieldtype$ * msg$ndepth$ = "
+ "msg$pdepth$->add_$cppname$();\n"
+ "SV ** sv$depth$;\n"
+ "SV * sv$ndepth$;\n"
+ "\n"
+ "if ( (sv$depth$ = "
+ "av_fetch(av$depth$, i$depth$, 0)) != NULL ) {\n"
+ " sv$ndepth$ = *sv$depth$;\n");
+ } else {
+ printer.Print(vars,
+ "SV ** sv$depth$;\n"
+ "\n"
+ "if ( (sv$depth$ = "
+ "av_fetch(av$depth$, i$depth$, 0)) != NULL ) {\n");
+ }
+ printer.Indent();
+ } else {
+ if ( field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ) {
+ printer.Print(vars,
+ "$fieldtype$ * msg$ndepth$ = "
+ "msg$pdepth$->mutable_$cppname$();\n"
+ "SV * sv$ndepth$ = *sv$depth$;\n"
+ "\n");
+ }
+ }
+
+ if ( field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ) {
+ MessageFromHashref(field->message_type(), printer, vars, depth + 2);
+ SetupDepthVars(vars, depth);
+ } else {
+ FieldFromHashrefHelper(printer, vars, field);
+ }
+
+ if ( field->is_repeated() ) {
+ printer.Outdent();
+ printer.Print("}\n");
+ printer.Outdent();
+ printer.Print("}\n");
+ printer.Outdent();
+ printer.Print("}\n");
+ }
+
+ printer.Outdent();
+ printer.Print("}\n");
+ }
+
+ printer.Outdent();
+ printer.Print("}\n");
+}
+
+} // namespace perlxs
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/perlxs/perlxs_generator.h b/contrib/libs/protoc/src/google/protobuf/compiler/perlxs/perlxs_generator.h
new file mode 100644
index 00000000000..c29eac03e3a
--- /dev/null
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/perlxs/perlxs_generator.h
@@ -0,0 +1,153 @@
+#ifndef GOOGLE_PROTOBUF_COMPILER_PERLXS_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_PERLXS_GENERATOR_H__
+
+#include <iostream>
+#include <vector>
+#include <map>
+#include <set>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+
+class Descriptor;
+class EnumDescriptor;
+class EnumValueDescriptor;
+class FieldDescriptor;
+class ServiceDescriptor;
+
+namespace io { class Printer; }
+
+namespace compiler {
+namespace perlxs {
+
+// CodeGenerator implementation for generated Perl/XS protocol buffer
+// classes. If you create your own protocol compiler binary and you
+// want it to support Perl/XS output, you can do so by registering an
+// instance of this CodeGenerator with the CommandLineInterface in
+// your main() function.
+class LIBPROTOC_EXPORT PerlXSGenerator : public CodeGenerator {
+ public:
+ PerlXSGenerator();
+ virtual ~PerlXSGenerator();
+
+ // implements CodeGenerator ----------------------------------------
+ virtual bool Generate(const FileDescriptor* file,
+ const TProtoStringType& parameter,
+ OutputDirectory* output_directory,
+ TProtoStringType* error) const;
+
+ bool ProcessOption(const TProtoStringType& option);
+
+ private:
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PerlXSGenerator);
+
+ private:
+ void GenerateXS(const FileDescriptor* file,
+ OutputDirectory* output_directory,
+ TProtoStringType& base) const;
+
+ void GenerateMessageXS(const Descriptor* descriptor,
+ OutputDirectory* outdir) const;
+
+ void GenerateMessageModule(const Descriptor* descriptor,
+ OutputDirectory* outdir) const;
+
+ void GenerateMessagePOD(const Descriptor* descriptor,
+ OutputDirectory* outdir) const;
+
+ void GenerateDescriptorClassNamePOD(const Descriptor* descriptor,
+ io::Printer& printer) const;
+
+ void GenerateDescriptorMethodPOD(const Descriptor* descriptor,
+ io::Printer& printer) const;
+
+ void GenerateEnumModule(const EnumDescriptor* enum_descriptor,
+ OutputDirectory* outdir) const;
+
+ void GenerateMessageXSFieldAccessors(const FieldDescriptor* field,
+ io::Printer& printer,
+ const TProtoStringType& classname) const;
+
+ void GenerateMessageXSCommonMethods(const Descriptor* descriptor,
+ io::Printer& printer,
+ const TProtoStringType& classname) const;
+
+ void GenerateFileXSTypedefs(const FileDescriptor* file,
+ io::Printer& printer,
+ std::set<const Descriptor*>& seen) const;
+
+ void GenerateMessageXSTypedefs(const Descriptor* descriptor,
+ io::Printer& printer,
+ std::set<const Descriptor*>& seen) const;
+
+ void GenerateMessageStatics(const Descriptor* descriptor,
+ io::Printer& printer) const;
+
+ void GenerateMessageXSPackage(const Descriptor* descriptor,
+ io::Printer& printer) const;
+
+ void GenerateTypemapInput(const Descriptor* descriptor,
+ io::Printer& printer,
+ const TProtoStringType& svname) const;
+
+ TProtoStringType MessageModuleName(const Descriptor* descriptor) const;
+
+ TProtoStringType MessageClassName(const Descriptor* descriptor) const;
+
+ TProtoStringType EnumClassName(const EnumDescriptor* descriptor) const;
+
+ TProtoStringType PackageName(const TProtoStringType& name, const TProtoStringType& package) const;
+
+ void PerlSVGetHelper(io::Printer& printer,
+ const std::map<TProtoStringType, TProtoStringType>& vars,
+ FieldDescriptor::CppType fieldtype,
+ int depth) const;
+
+ void PODPrintEnumValue(const EnumValueDescriptor *value,
+ io::Printer& printer) const;
+
+ TProtoStringType PODFieldTypeString(const FieldDescriptor* field) const;
+
+ void StartFieldToHashref(const FieldDescriptor * field,
+ io::Printer& printer,
+ std::map<TProtoStringType, TProtoStringType>& vars,
+ int depth) const;
+
+ void FieldToHashrefHelper(io::Printer& printer,
+ std::map<TProtoStringType, TProtoStringType>& vars,
+ const FieldDescriptor* field) const;
+
+ void EndFieldToHashref(const FieldDescriptor * field,
+ io::Printer& printer,
+ std::map<TProtoStringType, TProtoStringType>& vars,
+ int depth) const;
+
+ void MessageToHashref(const Descriptor * descriptor,
+ io::Printer& printer,
+ std::map<TProtoStringType, TProtoStringType>& vars,
+ int depth) const;
+
+ void FieldFromHashrefHelper(io::Printer& printer,
+ std::map<TProtoStringType, TProtoStringType>& vars,
+ const FieldDescriptor * field) const;
+
+ void MessageFromHashref(const Descriptor * descriptor,
+ io::Printer& printer,
+ std::map<TProtoStringType, TProtoStringType>& vars,
+ int depth) const;
+
+ private:
+ // --perlxs-package option (if given)
+ TProtoStringType perlxs_package_;
+};
+
+} // namespace perlxs
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_PERLXS_GENERATOR_H__
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/perlxs/perlxs_helpers.cc b/contrib/libs/protoc/src/google/protobuf/compiler/perlxs/perlxs_helpers.cc
new file mode 100644
index 00000000000..a1e5b5d340d
--- /dev/null
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/perlxs/perlxs_helpers.cc
@@ -0,0 +1,35 @@
+#include <sstream>
+#include <vector>
+#include <google/protobuf/compiler/perlxs/perlxs_helpers.h>
+#include "google/protobuf/descriptor.pb.h"
+#include <google/protobuf/io/printer.h>
+
+namespace google {
+namespace protobuf {
+
+extern TProtoStringType StringReplace(const TProtoStringType& s, const TProtoStringType& oldsub,
+ const TProtoStringType& newsub, bool replace_all);
+
+namespace compiler {
+namespace perlxs {
+
+void
+SetupDepthVars(std::map<TProtoStringType, TProtoStringType>& vars, int depth)
+{
+ std::ostringstream ost_pdepth;
+ std::ostringstream ost_depth;
+ std::ostringstream ost_ndepth;
+
+ ost_pdepth << depth;
+ ost_depth << depth + 1;
+ ost_ndepth << depth + 2;
+
+ vars["pdepth"] = ost_pdepth.str();
+ vars["depth"] = ost_depth.str();
+ vars["ndepth"] = ost_ndepth.str();
+}
+
+} // namespace perlxs
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/perlxs/perlxs_helpers.h b/contrib/libs/protoc/src/google/protobuf/compiler/perlxs/perlxs_helpers.h
new file mode 100644
index 00000000000..5454877f5a3
--- /dev/null
+++ b/contrib/libs/protoc/src/google/protobuf/compiler/perlxs/perlxs_helpers.h
@@ -0,0 +1,19 @@
+#ifndef GOOGLE_PROTOBUF_COMPILER_PERLXS_HELPERS_H__
+#define GOOGLE_PROTOBUF_COMPILER_PERLXS_HELPERS_H__
+
+#include <map>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace perlxs {
+
+void SetupDepthVars(std::map<TProtoStringType, TProtoStringType>& vars, int depth);
+
+} // namespace perlxs
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_PERLXS_HELPERS_H__