THRIFT-2166 Delphi compiler should generate constant class name prefixed with thrift file name (similar to Java and C#)

Patch: Jens Geyer
diff --git a/compiler/cpp/src/generate/t_delphi_generator.cc b/compiler/cpp/src/generate/t_delphi_generator.cc
index 03f08f5..f8f2a1c 100644
--- a/compiler/cpp/src/generate/t_delphi_generator.cc
+++ b/compiler/cpp/src/generate/t_delphi_generator.cc
@@ -21,6 +21,8 @@
  * details.
  */
 
+#include <cassert>
+
 #include <string>
 #include <fstream>
 #include <iostream>
@@ -62,6 +64,9 @@
       ansistr_binary_ = (iter != parsed_options.end());
       iter = parsed_options.find("register_types");
 	  register_types_ = (iter != parsed_options.end());
+      iter = parsed_options.find("constprefix");
+	  constprefix_ = (iter != parsed_options.end());
+      
 
       out_dir_base_ = "gen-delphi";
       escape_.clear();
@@ -107,6 +112,7 @@
     void finalize_field(std::ostream& out, std::string name, t_type* type, t_const_value* value, std::string cls_nm = "");
     std::string render_const_value( std::ostream& local_vars, std::ostream& out, std::string name, t_type* type, t_const_value* value);
     void print_const_def_value( std::ostream& vars, std::ostream& out, std::string name, t_type* type, t_const_value* value, std::string cls_nm = "");
+    std::string make_constants_classname();
 
     void generate_delphi_struct(t_struct* tstruct, bool is_exception);
     void generate_delphi_struct_impl( ostream& out, std::string cls_prefix, t_struct* tstruct, bool is_exception, bool is_result = false, bool is_x_factory = false);
@@ -146,6 +152,7 @@
 
     std::string type_name( t_type* ttype, bool b_cls=false, bool b_no_postfix=false, bool b_exception_factory=false, bool b_full_exception_factory = false);
     std::string normalize_clsnm(std::string name, std::string prefix, bool b_no_check_keyword = false);
+    std::string make_valid_delphi_identifier( std::string const & fromName);
     std::string input_arg_prefix( t_type* ttype);
   
     std::string base_type_name(t_base_type* tbase);
@@ -215,6 +222,7 @@
     int indent_impl_;
     bool ansistr_binary_;
 	bool register_types_;
+    bool constprefix_;
     void indent_up_impl(){
       ++indent_impl_;
     };
@@ -536,10 +544,12 @@
   }
   f_all  << endl;
 
+  string constants_class = make_constants_classname();
+
   f_all  << "initialization" << endl;
   if ( has_const ) {    
 	f_all  << "{$IF CompilerVersion < 21.0}" << endl;
-    f_all  << "  TConstants_Initialize;" << endl;
+    f_all  << "  " << constants_class.c_str() << "_Initialize;" << endl;
 	f_all  << "{$IFEND}" << endl;
   }
   if (register_types_) {
@@ -550,7 +560,7 @@
   f_all  << "finalization" << endl;
   if ( has_const ) {    
 	f_all  << "{$IF CompilerVersion < 21.0}" << endl;
-    f_all  << "  TConstants_Finalize;" << endl;
+    f_all  << "  " << constants_class.c_str() << "_Finalize;" << endl;
 	f_all  << "{$IFEND}" << endl;
   }
   f_all  << endl << endl;
@@ -692,16 +702,57 @@
   indent_down();
 }
 
+
+std::string t_delphi_generator::make_valid_delphi_identifier( std::string const & fromName) {
+    std::string str = fromName;
+    if( str.empty()) {
+        return str;
+    }
+
+    // tests rely on this
+    assert( ('A' < 'Z') && ('a' < 'z') && ('0' < '9'));
+    
+    // if the first letter is a number, we add an additional underscore in front of it
+    char c = str.at(0);
+    if( ('0' <= c) && (c <= '9')) {
+        str = "_" + str;
+    }
+
+    // following chars: letter, number or underscore
+    for( size_t i = 0;  i < str.size();  ++i) {
+        c = str.at(i);        
+        if( (('A' > c) || (c > 'Z')) && 
+            (('a' > c) || (c > 'z')) && 
+            (('0' > c) || (c > '9')) && 
+            ('_' != c) ) {
+            str.replace( i, 1, "_");
+        }
+    }
+
+    return str;
+}
+
+
+std::string t_delphi_generator::make_constants_classname() {
+  if( constprefix_) {
+    return make_valid_delphi_identifier( "T" + program_name_ + "Constants");
+  } else {
+    return "TConstants";  // compatibility 
+  }
+}
+
+
 void t_delphi_generator::generate_consts(std::vector<t_const*> consts) {
   if (consts.empty()){
     return;
   }
 
   has_const = true;
+  string constants_class = make_constants_classname();
 
   indent_up();
   indent(s_const) <<
-    "TConstants = class" << endl;
+    constants_class.c_str() << " = class" << endl;
   indent(s_const) << "private" << endl;
   indent_up();
   vector<t_const*>::iterator c_iter;
@@ -734,7 +785,7 @@
   indent_down_impl();
 
   indent_impl(s_const_impl) << "{$IF CompilerVersion >= 21.0}" << endl;
-  indent_impl(s_const_impl) << "class constructor TConstants.Create;" << endl;
+  indent_impl(s_const_impl) << "class constructor " << constants_class.c_str() << ".Create;" << endl;
 
   if ( ! vars.str().empty() ) {
     indent_impl(s_const_impl) << "var" << endl;
@@ -745,7 +796,7 @@
     s_const_impl << code.str();
   }
   indent_impl(s_const_impl) << "end;" << endl << endl;
-  indent_impl(s_const_impl) << "class destructor TConstants.Destroy;" << endl;
+  indent_impl(s_const_impl) << "class destructor " << constants_class.c_str() << ".Destroy;" << endl;
   indent_impl(s_const_impl) << "begin" << endl;
   indent_up_impl();
   for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
@@ -762,12 +813,12 @@
 
   indent_up_impl();
   for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
-    initialize_field( vars, code, "TConstants.F" + prop_name( (*c_iter)->get_name()),
+    initialize_field( vars, code, constants_class + ".F" + prop_name( (*c_iter)->get_name()),
       (*c_iter)->get_type(), (*c_iter)->get_value());
   }
   indent_down_impl();
 
-  indent_impl(s_const_impl) << "procedure TConstants_Initialize;" << endl;
+  indent_impl(s_const_impl) << "procedure " << constants_class.c_str() << "_Initialize;" << endl;
   if ( ! vars.str().empty() ) {
     indent_impl(s_const_impl) << "var" << endl;
     s_const_impl << vars.str();
@@ -778,12 +829,12 @@
   }
   indent_impl(s_const_impl) << "end;" << endl << endl;
 
-  indent_impl(s_const_impl) << "procedure TConstants_Finalize;" << endl;
+  indent_impl(s_const_impl) << "procedure " << constants_class.c_str() << "_Finalize;" << endl;
   indent_impl(s_const_impl) << "begin" << endl;
   indent_up_impl();
   for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
     finalize_field(s_const_impl, normalize_name( (*c_iter)->get_name()),
-      (*c_iter)->get_type(), (*c_iter)->get_value(), "TConstants" );
+      (*c_iter)->get_type(), (*c_iter)->get_value(), constants_class);
   }
   indent_down_impl();
   indent_impl(s_const_impl) << "end;" << endl;
@@ -3126,5 +3177,6 @@
 THRIFT_REGISTER_GENERATOR(delphi, "delphi", 
 "    ansistr_binary:  Use AnsiString for binary datatype (default is TBytes).\n" 
 "    register_types:  Enable TypeRegistry, allows for creation of struct, union\n" 
-"                     and container instances by interface or TypeInfo()\n");
+"                     and container instances by interface or TypeInfo()\n"
+"    constprefix:     Name TConstants classes after IDL to reduce ambiguities\n");