Thrift: Smalltalk prefix support.

Reviewed By: mcslee

Test Plan: Built the compiler.

Revert Plan: ok

Other Notes:
Contributed by Ben Matasar.
Signed off by Patrick Collison.


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665391 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/generate/t_st_generator.cc b/compiler/cpp/src/generate/t_st_generator.cc
index 62a3e5b..413e8ae 100644
--- a/compiler/cpp/src/generate/t_st_generator.cc
+++ b/compiler/cpp/src/generate/t_st_generator.cc
@@ -47,6 +47,13 @@
   return capitalize(program_name_);
 }
 
+string t_st_generator::prefix(string class_name) {
+  string prefix = program_->get_smalltalk_prefix();
+  string name = capitalize(class_name);
+  name = prefix.empty() ? name : (prefix + name);
+  return name;
+}
+
 string t_st_generator::client_class_name() {
   return capitalize(service_name_) + "Client";
 }
@@ -64,11 +71,11 @@
 }
 
 void t_st_generator::generate_force_consts() {
-  f_ << class_name() << " enums keysAndValuesDo: [:k :v | " <<
-    class_name() << " enums at: k put: v value].!" << endl;
+  f_ << prefix(class_name()) << " enums keysAndValuesDo: [:k :v | " <<
+    prefix(class_name()) << " enums at: k put: v value].!" << endl;
 
-  f_ << class_name() << " constants keysAndValuesDo: [:k :v | " <<
-    class_name() << " constants at: k put: v value].!" << endl;
+  f_ << prefix(class_name()) << " constants keysAndValuesDo: [:k :v | " <<
+    prefix(class_name()) << " constants at: k put: v value].!" << endl;
 
 }
 
@@ -90,7 +97,7 @@
 void t_st_generator::generate_typedef(t_typedef* ttypedef) {}
 
 void t_st_generator::st_class_def(std::ofstream &out, string name) {
-  out << "Object subclass: #" << capitalize(name) << endl;
+  out << "Object subclass: #" << prefix(name) << endl;
   indent_up();
   out << indent() << "instanceVariableNames: ''" << endl <<
     indent() << "classVariableNames: ''" << endl <<
@@ -119,7 +126,7 @@
   tinfo = localtime(&rawtime);
   strftime(timestr, 50, "%m/%d/%Y %H:%M", tinfo);
 
-  out << "!" << capitalize(cls) <<
+  out << "!" << prefix(cls) <<
     " methodsFor: '"+category+"' stamp: 'thrift " << timestr << "'!\n" <<
     name << endl;
 
@@ -150,14 +157,14 @@
 }
 
 void t_st_generator::generate_class_side_definition() {
-  f_ << class_name() << " class" << endl <<
+  f_ << prefix(class_name()) << " class" << endl <<
     "\tinstanceVariableNames: 'constants enums'!" << endl << endl;
 
   st_accessors(f_, class_name() + " class", "enums");
   st_accessors(f_, class_name() + " class", "constants");
 
-  f_ << class_name() << " enums: Dictionary new!" << endl;
-  f_ << class_name() << " constants: Dictionary new!" << endl;
+  f_ << prefix(class_name()) << " enums: Dictionary new!" << endl;
+  f_ << prefix(class_name()) << " constants: Dictionary new!" << endl;
 
   f_ << endl;
 }
@@ -171,7 +178,7 @@
 void t_st_generator::generate_enum(t_enum* tenum) {
   string cls_name = program_name_ + capitalize(tenum->get_name());
 
-  f_ << class_name() << " enums at: '" << tenum->get_name() << "' put: [" <<
+  f_ << prefix(class_name()) << " enums at: '" << tenum->get_name() << "' put: [" <<
     "(Dictionary new " << endl;
 
   vector<t_enum_value*> constants = tenum->get_constants();
@@ -198,7 +205,7 @@
   string name = tconst->get_name();
   t_const_value* value = tconst->get_value();
 
-  f_ << class_name() << " constants at: '" << name << "' put: [" <<
+  f_ << prefix(class_name()) << " constants at: '" << name << "' put: [" <<
     render_const_value(type, value) << "]!" << endl << endl;
 }
 
@@ -337,7 +344,7 @@
   else
     out << "Object";
 
-  out << " subclass: #" << capitalize(type_name(tstruct)) << endl <<
+  out << " subclass: #" << prefix(type_name(tstruct)) << endl <<
     "\tinstanceVariableNames: '";
 
   if (members.size() > 0) {
@@ -598,9 +605,10 @@
   out << "[|" << desc << " " << val << "|" << endl;
   indent_up();
 
-  out << indent() << val << " := " <<
-    capitalize(clsName) << " new." << endl;
-
+  //This is nasty, but without it we'll break things by prefixing TResult.
+  string name = ((capitalize(clsName) == "TResult") ? capitalize(clsName) : prefix(clsName));
+  out << indent() << val << " := " << name << " new." << endl;
+    
   out << indent() << "iprot readStructBegin." << endl <<
     indent() << "[" << desc << " := iprot readFieldBegin." << endl <<
     indent() << desc << " type = TType stop] whileFalse: [|" << found << "|" << endl;
@@ -785,7 +793,7 @@
     extends_client = extends + "Client";
   }
 
-  f_ << extends_client << " subclass: #" << client_class_name() << endl <<
+  f_ << extends_client << " subclass: #" << prefix(client_class_name()) << endl <<
     "\tinstanceVariableNames: ''\n" <<
     "\tclassVariableNames: ''\n" <<
     "\tpoolDictionaries: ''\n" <<
diff --git a/compiler/cpp/src/generate/t_st_generator.h b/compiler/cpp/src/generate/t_st_generator.h
index 6491cbd..fd20456 100644
--- a/compiler/cpp/src/generate/t_st_generator.h
+++ b/compiler/cpp/src/generate/t_st_generator.h
@@ -99,16 +99,17 @@
 
   std::string class_name();
   std::string client_class_name();
+  std::string prefix(std::string name);
   std::string declare_field(t_field* tfield);
-	std::string sanitize(std::string s);
+  std::string sanitize(std::string s);
   std::string type_name(t_type* ttype);
 
-	std::string function_signature(t_function* tfunction);
+  std::string function_signature(t_function* tfunction);
   std::string argument_list(t_struct* tstruct);
-	std::string function_types_comment(t_function* fn);
+  std::string function_types_comment(t_function* fn);
 
   std::string type_to_enum(t_type* ttype);
-	std::string a_type(t_type* type);
+  std::string a_type(t_type* type);
   bool is_vowel(char c);
   std::string temp_name();
   std::string generated_category();
diff --git a/compiler/cpp/src/parse/t_program.h b/compiler/cpp/src/parse/t_program.h
index ddc121c..dc8c80c 100644
--- a/compiler/cpp/src/parse/t_program.h
+++ b/compiler/cpp/src/parse/t_program.h
@@ -200,6 +200,14 @@
     return smalltalk_category_;
   }
 
+  void set_smalltalk_prefix(std::string smalltalk_prefix) {
+    smalltalk_prefix_ = smalltalk_prefix;
+  }
+  
+  const std::string& get_smalltalk_prefix() const {
+    return smalltalk_prefix_;
+  }
+
  private:
 
   // File path
@@ -257,7 +265,8 @@
 
   // Smalltalk category
   std::string smalltalk_category_;
-
+  // Smalltalk prefix
+  std::string smalltalk_prefix_;
 };
 
 #endif
diff --git a/compiler/cpp/src/thriftl.ll b/compiler/cpp/src/thriftl.ll
index d371658..320d28f 100644
--- a/compiler/cpp/src/thriftl.ll
+++ b/compiler/cpp/src/thriftl.ll
@@ -78,6 +78,7 @@
 "perl_package"       { return tok_perl_package;         }
 "ruby_namespace"     { return tok_ruby_namespace;       }
 "smalltalk_category" { return tok_smalltalk_category;   }
+"smalltalk_prefix"   { return tok_smalltalk_prefix;     }
 "xsd_all"            { return tok_xsd_all;              }
 "xsd_optional"       { return tok_xsd_optional;         }
 "xsd_nillable"       { return tok_xsd_nillable;         }
diff --git a/compiler/cpp/src/thrifty.yy b/compiler/cpp/src/thrifty.yy
index 21828ff..e46d0ef 100644
--- a/compiler/cpp/src/thrifty.yy
+++ b/compiler/cpp/src/thrifty.yy
@@ -87,6 +87,7 @@
 %token tok_xsd_attrs
 %token tok_ruby_namespace
 %token tok_smalltalk_category
+%token tok_smalltalk_prefix
 %token tok_cocoa_prefix
 
 /**
@@ -302,6 +303,13 @@
         g_program->set_smalltalk_category($2);
       }
     }
+| tok_smalltalk_prefix tok_identifier
+    {
+      pdebug("Header -> tok_smalltalk_prefix tok_identifier");
+      if (g_parse_mode == PROGRAM) {
+        g_program->set_smalltalk_prefix($2);
+      }
+    }
 | tok_java_package tok_identifier
     {
       pdebug("Header -> tok_java_package tok_identifier");