Merging Jake Luciani's latest perl code gen fixes

Reviewed By: dreiss

Test Plan: Watch for any weirdness on Thrift code gen, perl specific


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665206 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/generate/t_perl_generator.cc b/compiler/cpp/src/generate/t_perl_generator.cc
index c241a04..5f8b379 100644
--- a/compiler/cpp/src/generate/t_perl_generator.cc
+++ b/compiler/cpp/src/generate/t_perl_generator.cc
@@ -20,10 +20,17 @@
   // Make output directory
   mkdir(T_PERL_DIR, S_IREAD | S_IWRITE | S_IEXEC);
 
+  string outdir(T_PERL_DIR);
+  std::string ns = program_->get_perl_package();
+  if (ns.length() > 0) {
+    outdir += "/" + ns;
+    mkdir(outdir.c_str(), S_IREAD | S_IWRITE | S_IEXEC);
+  }
+
   // Make output file
-  string f_types_name = string(T_PERL_DIR)+"/"+program_name_+"_types.pm";
+  string f_types_name = outdir+"/Types.pm";
   f_types_.open(f_types_name.c_str());
-  string f_consts_name = string(T_PERL_DIR)+"/"+program_name_+"_constants.pm";
+  string f_consts_name = outdir+"/Constants.pm";
   f_consts_.open(f_consts_name.c_str());
 
   // Print header
@@ -47,7 +54,7 @@
   inc += "use strict;\n";
   inc += "use warnings;\n";
   inc += "use Thrift;\n\n";
-  
+
   return inc;
 }
 
@@ -88,7 +95,7 @@
     } else {
       ++value;
     }
-    
+
     f_types_ << "use constant "<<(*c_iter)->get_name() << " => " << value << ";" << endl;
   }
 }
@@ -359,15 +366,15 @@
 
     indent(out) << "/^" << (*f_iter)->get_key() << "$/ && do{";
     indent(out) << "if ($ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
-    
-    indent_up();   
+
+    indent_up();
     generate_deserialize_field(out, *f_iter, "self->");
     indent_down();
-    
+
     indent(out) << "} else {" << endl;
-    
+
     indent(out) <<  "  $xfer += $input->skip($ftype);" << endl;
-    
+
     out <<
       indent() << "}" << endl <<
       indent() << "last; };" << endl;
@@ -418,7 +425,7 @@
       "'" << (*f_iter)->get_name() << "', " <<
       type_to_enum((*f_iter)->get_type()) << ", " <<
       (*f_iter)->get_key() << ");" << endl;
-    
+
 
     // Write field contents
     generate_serialize_field(out, *f_iter, "self->");
@@ -456,9 +463,9 @@
     ///      "package "<<service_name_<<";"<<endl<<
     autogen_comment() <<
     perl_includes();
-  
+
   f_service_ <<
-    "use " << program_name_ << "_types;" << endl;
+    "use " << perl_namespace(tservice->get_program()) << "Types;" << endl;
 
   if (tservice->get_extends() != NULL) {
     f_service_ <<
@@ -516,7 +523,7 @@
 
     f_service_ <<
       indent() << "$self->{handler} = $handler;" << endl;
-    
+
     f_service_ <<
       indent() << "return bless($self,$classname);"<<endl;
 
@@ -561,7 +568,7 @@
     indent() <<  "}" << endl <<
     indent() <<  "$self->$methodname($rseqid, $input, $output);" << endl <<
     indent() <<  "return 1;" << endl;
-  
+
   indent_down();
 
   f_service_ <<
@@ -583,45 +590,45 @@
   // Open function
   f_service_ <<
     "sub process_" << tfunction->get_name() << "{"<<endl;
-  
+
   indent_up();
-  
+
   f_service_ <<
     indent() << "my $self = shift;"<<endl<<
     indent() << "my ($seqid, $input, $output); " << endl;
-  
+
   string argsname = perl_namespace(tservice->get_program()) + service_name_ + "_" + tfunction->get_name() + "_args";
   string resultname = perl_namespace(tservice->get_program()) + service_name_ + "_" + tfunction->get_name() + "_result";
-  
+
   f_service_ <<
     indent() << "my $args = new " << argsname << "();" << endl <<
     indent() << "$args->read($input);" << endl;
-  
+
   f_service_ <<
     indent() << "$input->readMessageEnd();" << endl;
-  
+
   t_struct* xs = tfunction->get_xceptions();
   const std::vector<t_field*>& xceptions = xs->get_members();
   vector<t_field*>::const_iterator x_iter;
-  
+
   // Declare result for non async function
   if (!tfunction->is_async()) {
     f_service_ <<
       indent() << "my $result = new " << resultname << "();" << endl;
   }
-  
+
   // Try block for a function with exceptions
   if (xceptions.size() > 0) {
     f_service_ <<
       indent() << "eval {" << endl;
     indent_up();
   }
-  
+
   // Generate the function call
   t_struct* arg_struct = tfunction->get_arglist();
   const std::vector<t_field*>& fields = arg_struct->get_members();
   vector<t_field*>::const_iterator f_iter;
-  
+
   f_service_ << indent();
   if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) {
     f_service_ << "$result->{success} = ";
@@ -638,13 +645,13 @@
     f_service_ << "$args->" << (*f_iter)->get_name();
   }
   f_service_ << ");" << endl;
-  
+
   if (!tfunction->is_async() && xceptions.size() > 0) {
     indent_down();
     for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
       f_service_ <<
         indent() << "}; if( UNIVERSAL::isa($@,'"<<(*x_iter)->get_type()->get_name()<<"') ){ "<<endl;
-      
+
       if (!tfunction->is_async()) {
         indent_up();
         f_service_ <<
@@ -673,7 +680,7 @@
     indent() << "$result->write($output);" << endl <<
     indent() << "$output->getTransport()->flush();" << endl;
   indent_down();
-  
+
   // Close function
   indent_down();
   f_service_ <<
@@ -766,40 +773,40 @@
   f_service_ <<
     "package " << service_name_ << "Rest;"<<endl<<
     extends_if << endl;
-  
-  
+
+
   if (extends.empty()) {
     f_service_ << "sub new {" << endl;
-    
+
     indent_up();
-    
+
     f_service_ <<
       indent() << "my $classname=shift;"<<endl <<
       indent() << "my $impl     =shift;"<<endl <<
       indent() << "my $self     ={ impl => $impl };"<<endl << endl<<
       indent() << "return bless($self,$classname);" << endl;
-    
-    
+
+
     indent_down();
 
     f_service_  <<
       indent() << "}" << endl << endl;
   }
-  
+
   vector<t_function*> functions = tservice->get_functions();
   vector<t_function*>::iterator f_iter;
   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
     f_service_ <<
       "sub " << (*f_iter)->get_name() <<
       "{"    <<endl;
-    
+
     indent_up();
-    
+
     f_service_ <<
       indent() << "my $self = shift;"<< endl <<
       indent() << "my $request = shift;" << endl << endl;
-    
-    
+
+
     const vector<t_field*>& args = (*f_iter)->get_arglist()->get_members();
     vector<t_field*>::const_iterator a_iter;
     for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
@@ -822,7 +829,7 @@
     indent_down();
     indent(f_service_) << "}" << endl <<endl;
   }
-  
+
 }
 
 /**
@@ -882,15 +889,15 @@
     const vector<t_field*>& fields = arg_struct->get_members();
     vector<t_field*>::const_iterator fld_iter;
     string funname = (*f_iter)->get_name();
-    
+
     // Open function
     f_service_ << "sub " << function_signature(*f_iter) << endl;
-    
+
     indent_up();
-    
+
     indent(f_service_) << indent() <<
       "$self->send_" << funname << "(";
-    
+
     bool first = true;
     for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
       if (first) {
@@ -901,7 +908,7 @@
       f_service_ << "$" << (*fld_iter)->get_name();
     }
     f_service_ << ");" << endl;
-    
+
     if (!(*f_iter)->is_async()) {
       f_service_ << indent();
       if (!(*f_iter)->get_returntype()->is_void()) {
@@ -910,42 +917,42 @@
       f_service_ <<
         "$self->recv_" << funname << "();" << endl;
     }
-    
+
     indent_down();
-    
-    f_service_ << "} "<<endl<<endl;
-    
+
+    f_service_ << "}" << endl << endl;
+
     f_service_ <<
       "sub send_" << function_signature(*f_iter) << endl;
-    
+
     indent_up();
-    
+
     std::string argsname = perl_namespace(tservice->get_program()) + service_name_ + "_" + (*f_iter)->get_name() + "_args";
-    
+
     // Serialize the request header
     f_service_ <<
       indent() << "$self->{output}->writeMessageBegin('" << (*f_iter)->get_name() << "', TMessageType::CALL, $self->{seqid});" << endl;
-    
+
     f_service_ <<
       indent() << "my $args = new " << argsname << "();" << endl;
-    
+
     for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
       f_service_ <<
         indent() << "$args->{" << (*fld_iter)->get_name() << "} = $" << (*fld_iter)->get_name() << ";" << endl;
     }
-    
+
     // Write to the stream
     f_service_ <<
       indent() << "$args->write($self->{output});" << endl <<
       indent() << "$self->{output}->writeMessageEnd();" << endl <<
       indent() << "$self->{output}->getTransport()->flush();" << endl;
-    
-    
+
+
     indent_down();
-    
-    f_service_ << "}"<<endl;
-    
-    
+
+    f_service_ << "}" << endl;
+
+
     if (!(*f_iter)->is_async()) {
       std::string resultname = perl_namespace(tservice->get_program()) + service_name_ + "_" + (*f_iter)->get_name() + "_result";
       t_struct noargs(program_);
@@ -1055,7 +1062,7 @@
   } else if (type->is_base_type() || type->is_enum()) {
     indent(out) <<
       "$xfer += $input->";
-    
+
     if (type->is_base_type()) {
       t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
       switch (tbase) {
@@ -1091,7 +1098,7 @@
       out << "readI32(\\$" << name << ");";
     }
     out << endl;
-    
+
   } else {
     printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
            tfield->get_name().c_str(), type->get_name().c_str());
@@ -1126,7 +1133,7 @@
   t_field fktype(g_type_byte, ktype);
   t_field fvtype(g_type_byte, vtype);
   t_field fetype(g_type_byte, etype);
-  
+
   out <<
     indent() << "my $" << size << " = 0;" << endl;
 
@@ -1136,27 +1143,27 @@
       indent() << "$" << prefix << " = {};" << endl <<
       indent() << "my $" << ktype << " = 0;" << endl <<
       indent() << "my $" << vtype << " = 0;" << endl;
-    
+
     out <<
       indent() << "$xfer += $input->readMapBegin(" <<
       "\\$" << ktype << ", \\$" << vtype << ", \\$" << size << ");" << endl;
-    
+
   } else if (ttype->is_set()) {
-    
+
     out <<
       indent() << "$" << prefix << " = {};" << endl <<
       indent() << "my $" << etype << " = 0;" << endl <<
       indent() << "$xfer += $input->readSetBegin(" <<
       "\\$" << etype << ", \\$" << size << ");" << endl;
-    
+
   } else if (ttype->is_list()) {
-    
+
     out <<
       indent() << "$" << prefix << " = [];" << endl <<
       indent() << "my $" << etype << " = 0;" << endl <<
       indent() << "$xfer += $input->readListBegin(" <<
       "\\$" << etype << ", \\$" << size << ");" << endl;
-    
+
   }
 
   // For loop iterates over elements
diff --git a/compiler/cpp/src/generate/t_perl_generator.h b/compiler/cpp/src/generate/t_perl_generator.h
index c1e7820..a023543 100644
--- a/compiler/cpp/src/generate/t_perl_generator.h
+++ b/compiler/cpp/src/generate/t_perl_generator.h
@@ -141,8 +141,8 @@
   }
 
   std::string perl_namespace(t_program* p) {
-    std::string ns = p->get_perl_namespace();
-    return ""; //ns.size() ? (ns + "::") : "";
+    std::string ns = p->get_perl_package();
+    return ns.empty() ? ns : (ns + "::");
   }
 
  private:
diff --git a/compiler/cpp/src/parse/t_program.h b/compiler/cpp/src/parse/t_program.h
index f54ed71..d516617 100644
--- a/compiler/cpp/src/parse/t_program.h
+++ b/compiler/cpp/src/parse/t_program.h
@@ -149,17 +149,17 @@
   void set_ruby_namespace(std::string ruby_namespace) {
     ruby_namespace_ = ruby_namespace;
   }
-  
+
   const std::string& get_ruby_namespace() const {
     return ruby_namespace_;
   }
 
-  void set_perl_namespace(std::string perl_namespace) {
-    perl_namespace_ = perl_namespace;
+  void set_perl_package(std::string perl_package) {
+    perl_package_ = perl_package;
   }
 
-  const std::string& get_perl_namespace() const {
-    return perl_namespace_;
+  const std::string& get_perl_package() const {
+    return perl_package_;
   }
 
  private:
@@ -206,7 +206,7 @@
   std::string ruby_namespace_;
 
   // Perl namespace
-  std::string perl_namespace_;
+  std::string perl_package_;
 
 };
 
diff --git a/compiler/cpp/src/thriftl.ll b/compiler/cpp/src/thriftl.ll
index 7693f33..d047acc 100644
--- a/compiler/cpp/src/thriftl.ll
+++ b/compiler/cpp/src/thriftl.ll
@@ -8,7 +8,7 @@
 
 /**
  * Thrift scanner.
- * 
+ *
  * Tokenizes a thrift definition file.
  * @author Mark Slee <mcslee@facebook.com>
  */
@@ -35,9 +35,9 @@
 /**
  * Provides the yylineno global, useful for debugging output
  */
-%option lex-compat 	
+%option lex-compat
 
-/** 
+/**
  * Helper definitions, comments, constants, and whatnot
  */
 
@@ -72,6 +72,7 @@
 "cpp_type"       { return tok_cpp_type;       }
 "java_package"   { return tok_java_package;   }
 "php_namespace"  { return tok_php_namespace;  }
+"perl_package"   { return tok_perl_package;   }
 "ruby_namespace" { return tok_ruby_namespace; }
 "xsd_all"        { return tok_xsd_all;        }
 "xsd_optional"   { return tok_xsd_optional;   }
diff --git a/compiler/cpp/src/thrifty.yy b/compiler/cpp/src/thrifty.yy
index e159ef0..38ca516 100644
--- a/compiler/cpp/src/thrifty.yy
+++ b/compiler/cpp/src/thrifty.yy
@@ -75,6 +75,7 @@
 %token tok_cpp_include
 %token tok_cpp_type
 %token tok_php_namespace
+%token tok_perl_package
 %token tok_java_package
 %token tok_xsd_all
 %token tok_xsd_optional
@@ -107,7 +108,7 @@
 
 /**
  * Function modifiers
- */ 
+ */
 %token tok_async
 
 /**
@@ -209,8 +210,7 @@
       if (g_parse_mode == PROGRAM) {
         $$ = g_doctext; 
         g_doctext = NULL;
-      }
-      else {
+      } else {
         $$ = NULL;
       }
     }
@@ -269,6 +269,13 @@
         g_program->set_php_namespace($2);
       }
     }
+| tok_perl_package tok_identifier
+    {
+      pdebug("Header -> tok_perl_namespace tok_identifier");
+      if (g_parse_mode == PROGRAM) {
+        g_program->set_perl_package($2);
+      }
+    }
 | tok_ruby_namespace tok_identifier
     {
       pdebug("Header -> tok_ruby_namespace tok_identifier");
@@ -294,7 +301,7 @@
 Include:
   tok_include tok_literal
     {
-      pdebug("Include -> tok_include tok_literal");     
+      pdebug("Include -> tok_include tok_literal");
       if (g_parse_mode == INCLUDES) {
         std::string path = include_file(std::string($2));
         if (!path.empty()) {
@@ -379,7 +386,7 @@
       }
     }
 | Xception
-    { 
+    {
       pdebug("TypeDefinition -> Xception");
       if (g_parse_mode == PROGRAM) {
         g_program->add_xception($1);
@@ -536,7 +543,7 @@
 | ConstMap
     {
       pdebug("ConstValue => ConstMap");
-      $$ = $1; 
+      $$ = $1;
     }
 
 ConstList:
@@ -780,7 +787,7 @@
 FieldValue:
   '=' ConstValue
     {
-      if (g_parse_mode == PROGRAM) {     
+      if (g_parse_mode == PROGRAM) {
         $$ = $2;
       } else {
         $$ = NULL;
diff --git a/test/ThriftTest.thrift b/test/ThriftTest.thrift
index 92a3d21..fd0ac97 100644
--- a/test/ThriftTest.thrift
+++ b/test/ThriftTest.thrift
@@ -1,6 +1,7 @@
 java_package thrift.test
 cpp_namespace thrift.test
 ruby_namespace Thrift.Test
+perl_package ThriftTest
 
 enum Numberz
 {
@@ -50,7 +51,7 @@
   1: i32 errorCode,
   2: Xtruct struct_thing
 }
- 
+
 struct EmptyStruct {}
 
 struct OneField {
@@ -79,8 +80,7 @@
   map<UserId, map<Numberz,Insanity>> testInsanity(1: Insanity argument),
 
   /* Multiple parameters */
-  
-  Xtruct	testMulti(byte arg0, i32 arg1, i64 arg2, map<i16, string> arg3, Numberz arg4, UserId arg5),
+  Xtruct testMulti(byte arg0, i32 arg1, i64 arg2, map<i16, string> arg3, Numberz arg4, UserId arg5),
 
   /* Exception specifier */
 
diff --git a/test/perl/TestClient.pl b/test/perl/TestClient.pl
index b3c9ca3..4e6278e 100644
--- a/test/perl/TestClient.pl
+++ b/test/perl/TestClient.pl
@@ -7,7 +7,7 @@
 use Time::HiRes qw(gettimeofday);
 
 use lib '../../lib/perl/lib';
-use lib 'gen-perl';
+use lib '../gen-perl';
 
 use Thrift;
 use Thrift::BinaryProtocol;
@@ -15,7 +15,7 @@
 use Thrift::BufferedTransport;
 
 use ThriftTest;
-use ThriftTest_types;
+use ThriftTest::Types;
 
 $|++;
 
diff --git a/thrift.el b/thrift.el
index 4abb04e..67485cf 100644
--- a/thrift.el
+++ b/thrift.el
@@ -10,7 +10,7 @@
 (defconst thrift-font-lock-keywords
   (list
    '("#.*$" . font-lock-comment-face)  ;; perl style comments
-   '("\\<\\(include\\|struct\\|exception\\|typedef\\|cpp_namespace\\|java_package\\|php_namespace\\|const\\|enum\\|service\\|extends\\|void\\|async\\|throws\\|optional\\|required\\)\\>" . font-lock-keyword-face)  ;; keywords
+   '("\\<\\(include\\|struct\\|exception\\|typedef\\|cpp_namespace\\|java_package\\|php_namespace\\|ruby_namespace\\|perl_package\\|const\\|enum\\|service\\|extends\\|void\\|async\\|throws\\|optional\\|required\\)\\>" . font-lock-keyword-face)  ;; keywords
    '("\\<\\(bool\\|byte\\|i16\\|i32\\|i64\\|double\\|string\\|binary\\|map\\|list\\|set\\)\\>" . font-lock-type-face)  ;; built-in types
    '("\\<\\([0-9]+\\)\\>" . font-lock-variable-name-face)   ;; ordinals
    '("\\<\\(\\w+\\)\\s-*(" (1 font-lock-function-name-face))  ;; functions
diff --git a/thrift.vim b/thrift.vim
index daec30e..c421cf3 100644
--- a/thrift.vim
+++ b/thrift.vim
@@ -30,7 +30,7 @@
 syn match thriftNumber "-\=\<\d\+\>" contained
 
 " Keywords
-syn keyword thriftKeyword namespace cpp_namespace java_package php_namespace ruby_namespace
+syn keyword thriftKeyword namespace cpp_namespace java_package php_namespace ruby_namespace perl_package
 syn keyword thriftKeyword xsd_all xsd_optional xsd_nillable xsd_namespace xsd_attrs
 syn keyword thriftKeyword include cpp_include cpp_type const optional required
 syn keyword thriftBasicTypes void bool byte i16 i32 i64 double string binary
diff --git a/tutorial/perl/PerlClient.pl b/tutorial/perl/PerlClient.pl
index ad9c1d6..10cb725 100644
--- a/tutorial/perl/PerlClient.pl
+++ b/tutorial/perl/PerlClient.pl
@@ -12,9 +12,9 @@
 use Thrift::BufferedTransport;
 
 use SharedService;
-use shared_types;
 use Calculator;
-use tutorial_types;
+use shared::Types;
+use tutorial::Types;
 
 use Data::Dumper;
 
diff --git a/tutorial/shared.thrift b/tutorial/shared.thrift
index 7596376..1ecfb0a 100755
--- a/tutorial/shared.thrift
+++ b/tutorial/shared.thrift
@@ -7,6 +7,7 @@
 
 cpp_namespace shared
 java_package shared
+perl_package shared
 
 struct SharedStruct {
   1: i32 key
diff --git a/tutorial/tutorial.thrift b/tutorial/tutorial.thrift
index 1cff343..8af016a 100644
--- a/tutorial/tutorial.thrift
+++ b/tutorial/tutorial.thrift
@@ -47,6 +47,7 @@
 cpp_namespace tutorial
 java_package tutorial
 php_namespace tutorial
+perl_package tutorial
 
 /**
  * Thrift lets you do typedefs to get pretty names for your types. Standard