Thrift supports arbitrarily typed constants across all languages

Summary: Hot! Now you can defined your maps to strings and other constnats things in your .thrift file, so you can have the same symbols and useful defaults defined in your client as in your server.


git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@664881 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/generate/t_cpp_generator.cc b/compiler/cpp/src/generate/t_cpp_generator.cc
index ff176a5..9188955 100644
--- a/compiler/cpp/src/generate/t_cpp_generator.cc
+++ b/compiler/cpp/src/generate/t_cpp_generator.cc
@@ -143,6 +143,196 @@
 }
 
 /**
+ * Generates a class that holds all the constants.
+ */
+void t_cpp_generator::generate_consts(std::vector<t_const*> consts) {
+  string f_consts_name = string(T_CPP_DIR)+"/"+program_name_+"_constants.h";
+  ofstream f_consts;
+  f_consts.open(f_consts_name.c_str());
+
+  string f_consts_impl_name = string(T_CPP_DIR)+"/"+program_name_+"_constants.cpp";
+  ofstream f_consts_impl;
+  f_consts_impl.open(f_consts_impl_name.c_str());
+
+  // Print header
+  f_consts <<
+    autogen_comment();
+  f_consts_impl <<
+    autogen_comment();
+
+  // Start ifndef
+  f_consts <<
+    "#ifndef " << program_name_ << "_CONSTANTS_H" << endl <<
+    "#define " << program_name_ << "_CONSTANTS_H" << endl <<
+    endl <<
+    "#include \"" << program_name_ << "_types.h\"" << endl <<
+    endl <<
+    ns_open_ << endl <<
+    endl;
+
+  f_consts_impl <<
+    "#include \"" << program_name_ << "_constants.h\"" << endl <<
+    endl <<
+    ns_open_ << endl <<
+    endl;
+
+  f_consts <<
+    "class " << program_name_ << "Constants {" << endl <<
+    " public:" << endl <<
+    "  " << program_name_ << "Constants();" << endl <<
+    endl;
+  indent_up();
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    string name = (*c_iter)->get_name();
+    t_type* type = (*c_iter)->get_type();
+    f_consts <<
+      indent() << type_name(type) << " " << name << ";" << endl;
+  }
+  indent_down();
+  f_consts <<
+    "};" << endl;  
+
+  f_consts_impl <<
+    "const " << program_name_ << "Constants g_" << program_name_ << "_constants;" << endl <<
+    endl <<
+    program_name_ << "Constants::" << program_name_ << "Constants() {" << endl;
+  indent_up();
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    print_const_value(f_consts_impl,
+                      (*c_iter)->get_name(),
+                      (*c_iter)->get_type(),
+                      (*c_iter)->get_value());
+  }
+  indent_down();
+  indent(f_consts_impl) <<
+    "}" << endl;
+
+  f_consts <<
+    endl <<
+    "extern const " << program_name_ << "Constants g_" << program_name_ << "_constants;" << endl <<
+    endl <<
+    ns_close_ << endl <<
+    endl <<
+    "#endif" << endl;
+  f_consts.close();
+
+  f_consts_impl <<
+    endl <<
+    ns_close_ << endl <<
+    endl;
+}
+
+/**
+ * Prints the value of a constant with the given type. Note that type checking
+ * is NOT performed in this function as it is always run beforehand using the
+ * validate_types method in main.cc
+ */
+void t_cpp_generator::print_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
+  if (type->is_base_type()) {
+    string v2 = render_const_value(out, name, type, value);
+    indent(out) << name << " = " << v2 << ";" << endl <<
+      endl;
+  } else if (type->is_enum()) {
+    indent(out) << name << " = (" << type->get_name() << ")" << value->get_integer() << ";" << endl <<
+      endl;
+  } else if (type->is_struct() || type->is_xception()) {
+    const vector<t_field*>& fields = ((t_struct*)type)->get_members();
+    vector<t_field*>::const_iterator f_iter;
+    const map<t_const_value*, t_const_value*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      t_type* field_type = NULL;
+      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        if ((*f_iter)->get_name() == v_iter->first->get_string()) {
+          field_type = (*f_iter)->get_type();
+        }
+      }
+      if (field_type == NULL) {
+        throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
+      }
+      string val = render_const_value(out, name, field_type, v_iter->second);
+      indent(out) << name << "." << v_iter->first->get_string() << " = " << val << ";" << endl;
+      indent(out) << name << ".__isset." << v_iter->first->get_string() << " = true;" << endl;
+    }
+    out << endl;
+  } else if (type->is_map()) {
+    t_type* ktype = ((t_map*)type)->get_key_type();
+    t_type* vtype = ((t_map*)type)->get_val_type();
+    const map<t_const_value*, t_const_value*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string key = render_const_value(out, name, ktype, v_iter->first);
+      string val = render_const_value(out, name, vtype, v_iter->second);
+      indent(out) << name << "[" << key << "] = " << val << ";" << endl;
+    }
+    out << endl;
+  } else if (type->is_list()) {
+    t_type* etype = ((t_list*)type)->get_elem_type();
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    int i = 0;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string val = render_const_value(out, name, etype, *v_iter);
+      indent(out) << name << "[" << (i++) << "] = " << val << ";" << endl;
+    }
+    out << endl;
+  } else if (type->is_set()) {
+    t_type* etype = ((t_set*)type)->get_elem_type();
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string val = render_const_value(out, name, etype, *v_iter);
+      indent(out) << name << ".insert(" << val << ");" << endl;
+    }
+    out << endl;
+  }
+}
+
+/**
+ *
+ */
+string t_cpp_generator::render_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
+  std::ostringstream render;
+
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_STRING:
+      render << "\"" + value->get_string() + "\"";
+      break;
+    case t_base_type::TYPE_BOOL:
+      render << ((value->get_integer() > 0) ? "true" : "false");
+      break;
+    case t_base_type::TYPE_BYTE:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      render << value->get_integer();
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        render << value->get_integer();
+      } else {
+        render << value->get_double();
+      }
+      break;
+    default:
+      throw "compiler error: no const of base type " + tbase;
+    }
+  } else if (type->is_enum()) {
+    render << value->get_integer();
+  } else {
+    string t = tmp("tmp");
+    indent(out) << type_name(type) << " " << t << ";" << endl;
+    print_const_value(out, t, type, value);
+    render << t;
+  }
+
+  return render.str();
+}
+
+/**
  * Generates a struct definition for a thrift data type. This is a class
  * with data members and a read/write() function, plus a mirroring isset
  * inner class.
diff --git a/compiler/cpp/src/generate/t_cpp_generator.h b/compiler/cpp/src/generate/t_cpp_generator.h
index 6070e37..435b0c6 100644
--- a/compiler/cpp/src/generate/t_cpp_generator.h
+++ b/compiler/cpp/src/generate/t_cpp_generator.h
@@ -28,6 +28,8 @@
   void init_generator();
   void close_generator();
 
+  void generate_consts(std::vector<t_const*> consts);
+
   /**
    * Program-level generation functions
    */
@@ -37,6 +39,9 @@
   void generate_struct   (t_struct*   tstruct);
   void generate_service  (t_service*  tservice);
 
+  void print_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value);
+  std::string render_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value);
+
   void generate_struct_definition    (std::ofstream& out, t_struct* tstruct);
   void generate_struct_reader        (std::ofstream& out, t_struct* tstruct);
   void generate_struct_writer        (std::ofstream& out, t_struct* tstruct);
diff --git a/compiler/cpp/src/generate/t_generator.cc b/compiler/cpp/src/generate/t_generator.cc
index 30830d6..e4e010a 100644
--- a/compiler/cpp/src/generate/t_generator.cc
+++ b/compiler/cpp/src/generate/t_generator.cc
@@ -27,6 +27,10 @@
     generate_enum(*en_iter);
   }
 
+  // Generate constants
+  vector<t_const*> consts = program_->get_consts();
+  generate_consts(consts);
+
   // Generate structs
   vector<t_struct*> structs = program_->get_structs();
   vector<t_struct*>::iterator st_iter;
@@ -52,3 +56,10 @@
   // Close the generator
   close_generator();
 }
+
+void t_generator::generate_consts(vector<t_const*> consts) {
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    generate_const(*c_iter);
+  }
+}
diff --git a/compiler/cpp/src/generate/t_generator.h b/compiler/cpp/src/generate/t_generator.h
index 18a2247..50f7bf6 100644
--- a/compiler/cpp/src/generate/t_generator.h
+++ b/compiler/cpp/src/generate/t_generator.h
@@ -41,12 +41,15 @@
   virtual void init_generator() {}
   virtual void close_generator() {}
 
+  virtual void generate_consts(std::vector<t_const*> consts);
+
   /**
    * Pure virtual methods implemented by the generator subclasses.
    */
 
   virtual void generate_typedef  (t_typedef*  ttypedef)  = 0;
   virtual void generate_enum     (t_enum*     tenum)     = 0;
+  virtual void generate_const    (t_const*    tconst) {}
   virtual void generate_struct   (t_struct*   tstruct)   = 0;
   virtual void generate_service  (t_service*  tservice)  = 0;
   virtual void generate_xception (t_struct*   txception) {
diff --git a/compiler/cpp/src/generate/t_java_generator.cc b/compiler/cpp/src/generate/t_java_generator.cc
index e2e9b71..ea2d22a 100644
--- a/compiler/cpp/src/generate/t_java_generator.cc
+++ b/compiler/cpp/src/generate/t_java_generator.cc
@@ -109,6 +109,173 @@
 }
 
 /**
+ * Generates a class that holds all the constants.
+ */
+void t_java_generator::generate_consts(std::vector<t_const*> consts) {
+  string f_consts_name = string(T_JAVA_DIR)+"/Constants.java";
+  ofstream f_consts;
+  f_consts.open(f_consts_name.c_str());
+
+  // Print header
+  f_consts <<
+    autogen_comment() <<
+    java_package() << 
+    java_type_imports();
+
+  f_consts <<
+    "public class Constants {" << endl <<
+    endl;
+  indent_up();
+  vector<t_const*>::iterator c_iter;
+  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
+    print_const_value(f_consts,
+                      (*c_iter)->get_name(),
+                      (*c_iter)->get_type(),
+                      (*c_iter)->get_value(),
+                      false);
+  }
+  indent_down();
+  indent(f_consts) <<
+    "}" << endl;
+  f_consts.close();
+}
+
+
+/**
+ * Prints the value of a constant with the given type. Note that type checking
+ * is NOT performed in this function as it is always run beforehand using the
+ * validate_types method in main.cc
+ */
+void t_java_generator::print_const_value(ofstream& out, string name, t_type* type, t_const_value* value, bool in_static) {
+  if (type->is_base_type()) {
+    string v2 = render_const_value(out, name, type, value);
+    indent(out) << "public static final " << type_name(type) << " " << name << " = " << v2 << ";" << endl <<
+      endl;
+  } else if (type->is_enum()) {
+    indent(out) << "public static final int " << name << " = " << value->get_integer() << ";" << endl <<
+      endl;
+  } else if (type->is_struct() || type->is_xception()) {
+    const vector<t_field*>& fields = ((t_struct*)type)->get_members();
+    vector<t_field*>::const_iterator f_iter;
+    const map<t_const_value*, t_const_value*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+    indent(out) <<
+      (in_static ? "" : "public static final ") <<
+      type_name(type) << " " << name <<
+      " = new " << type_name(type) << "();" << endl;
+    if (!in_static) {
+      indent(out) << "static {" << endl;
+      indent_up();
+    }
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      t_type* field_type = NULL;
+      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        if ((*f_iter)->get_name() == v_iter->first->get_string()) {
+          field_type = (*f_iter)->get_type();
+        }
+      }
+      if (field_type == NULL) {
+        throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
+      }
+      string val = render_const_value(out, name, field_type, v_iter->second);
+      indent(out) << name << "." << v_iter->first->get_string() << " = " << val << ";" << endl;
+      indent(out) << name << ".__isset." << v_iter->first->get_string() << " = true;" << endl;
+    }
+    if (!in_static) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    out << endl;
+  } else if (type->is_map()) {
+    indent(out) <<
+      (in_static ? "" : "public static final ") <<
+      type_name(type, true, true) << " " << name << " = new " << type_name(type, true, true) << "();" << endl;
+    if (!in_static) {
+      indent(out) << "static {" << endl;
+      indent_up();
+    }
+    t_type* ktype = ((t_map*)type)->get_key_type();
+    t_type* vtype = ((t_map*)type)->get_val_type();
+    const map<t_const_value*, t_const_value*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string key = render_const_value(out, name, ktype, v_iter->first);
+      string val = render_const_value(out, name, vtype, v_iter->second);
+      indent(out) << name << ".put(" << key << ", " << val << ");" << endl;
+    }
+    if (!in_static) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    out << endl;
+  } else if (type->is_list() || type->is_set()) {
+    indent(out) <<
+      (in_static ? "" : "public static final ") <<
+      type_name(type) << " " << name << " = new " << type_name(type) << "();" << endl;
+    if (!in_static) {
+      indent(out) << "static {" << endl;
+      indent_up();
+    }
+    t_type* etype;
+    if (type->is_list()) {
+      etype = ((t_list*)type)->get_elem_type();
+    } else {
+      etype = ((t_set*)type)->get_elem_type();
+    }
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      string val = render_const_value(out, name, etype, *v_iter);
+      indent(out) << name << ".add(" << val << ");" << endl;
+    }
+    if (!in_static) {
+      indent_down();
+      indent(out) << "}" << endl;
+    }
+    out << endl;
+  }
+}
+
+string t_java_generator::render_const_value(ofstream& out, string name, t_type* type, t_const_value* value) {
+  std::ostringstream render;
+
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_STRING:
+      render << "\"" + value->get_string() + "\"";
+      break;
+    case t_base_type::TYPE_BOOL:
+      render << ((value->get_integer() > 0) ? "TRUE" : "FALSE");
+      break;
+    case t_base_type::TYPE_BYTE:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      render << value->get_integer();
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        render << value->get_integer();
+      } else {
+        render << value->get_double();
+      }
+      break;
+    default:
+      throw "compiler error: no const of base type " + tbase;
+    }
+  } else if (type->is_enum()) {
+    render << value->get_integer();
+  } else {
+    string t = tmp("tmp");
+    print_const_value(out, t, type, value, true);
+    render << t;
+  }
+
+  return render.str();
+}
+
+/**
  * Generates a struct definition for a thrift data type. This is a class
  * with data members, read(), write(), and an inner Isset class.
  *
diff --git a/compiler/cpp/src/generate/t_java_generator.h b/compiler/cpp/src/generate/t_java_generator.h
index b319ab4..b21c76a 100644
--- a/compiler/cpp/src/generate/t_java_generator.h
+++ b/compiler/cpp/src/generate/t_java_generator.h
@@ -28,6 +28,8 @@
   void init_generator();
   void close_generator();
 
+  void generate_consts(std::vector<t_const*> consts);
+
   /**
    * Program-level generation functions
    */
@@ -38,6 +40,9 @@
   void generate_xception(t_struct*   txception);
   void generate_service (t_service*  tservice);
 
+  void print_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value, bool in_static);
+  std::string render_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value);
+
   /**
    * Service-level generation functions
    */
diff --git a/compiler/cpp/src/generate/t_php_generator.cc b/compiler/cpp/src/generate/t_php_generator.cc
index f76b66f..afadf06 100644
--- a/compiler/cpp/src/generate/t_php_generator.cc
+++ b/compiler/cpp/src/generate/t_php_generator.cc
@@ -17,12 +17,23 @@
   // Make output file
   string f_types_name = string(T_PHP_DIR)+"/"+program_name_+"_types.php";
   f_types_.open(f_types_name.c_str());
+  string f_consts_name = string(T_PHP_DIR)+"/"+program_name_+"_constants.php";
+  f_consts_.open(f_consts_name.c_str());
 
   // Print header
   f_types_ <<
     "<?php" << endl <<
     autogen_comment() <<
     php_includes();
+
+  // Print header
+  f_consts_ <<
+    "<?php" << endl <<
+    autogen_comment() <<
+    "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" + program_name_ + "/" + program_name_ + "_types.php';" << endl <<
+    endl <<
+    "$GLOBALS['" << program_name_ << "_CONSTANTS'] = array(); " << endl <<
+    endl;
 }
 
 /**
@@ -40,6 +51,9 @@
   // Close types file
   f_types_ << "?>" << endl;
   f_types_.close();
+
+  f_consts_ << "?>" << endl;
+  f_consts_.close();
 }
 
 /**
@@ -105,6 +119,114 @@
 }
 
 /**
+ * Generate a constant value
+ */
+void t_php_generator::generate_const(t_const* tconst) {
+  t_type* type = tconst->get_type();
+  string name = tconst->get_name();
+  t_const_value* value = tconst->get_value();
+  
+  f_consts_ << "$GLOBALS['" << program_name_ << "_CONSTANTS']['" << name << "'] = "; 
+  print_const_value(type, value);
+  f_consts_ << ";" << endl << endl;
+}
+
+/**
+ * Prints the value of a constant with the given type. Note that type checking
+ * is NOT performed in this function as it is always run beforehand using the
+ * validate_types method in main.cc
+ */
+void t_php_generator::print_const_value(t_type* type, t_const_value* value) {
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_STRING:
+      f_consts_ << "'" << value->get_string() << "'";
+      break;
+    case t_base_type::TYPE_BOOL:
+      f_consts_ << (value->get_integer() > 0 ? "true" : "false");
+      break;
+    case t_base_type::TYPE_BYTE:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      f_consts_ << value->get_integer();
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        f_consts_ << value->get_integer();
+      } else {
+        f_consts_ << value->get_double();
+      }
+      break;
+    default:
+      throw "compiler error: no const of base type " + tbase;
+    }
+  } else if (type->is_enum()) {
+    indent(f_consts_) << value->get_integer();
+  } else if (type->is_struct() || type->is_xception()) {
+    f_consts_ << "new " << type->get_name() << "(array(" << endl;
+    indent_up();
+    const vector<t_field*>& fields = ((t_struct*)type)->get_members();
+    vector<t_field*>::const_iterator f_iter;
+    const map<t_const_value*, t_const_value*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      t_type* field_type = NULL;
+      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        if ((*f_iter)->get_name() == v_iter->first->get_string()) {
+          field_type = (*f_iter)->get_type();
+        }
+      }
+      if (field_type == NULL) {
+        throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
+      }
+      f_consts_ << indent();
+      print_const_value(g_type_string, v_iter->first);
+      f_consts_ << " => ";
+      print_const_value(field_type, v_iter->second);
+      f_consts_ << endl;
+    }
+    indent_down();
+    indent(f_consts_) << "))";
+  } else if (type->is_map()) {
+    t_type* ktype = ((t_map*)type)->get_key_type();
+    t_type* vtype = ((t_map*)type)->get_val_type();
+    f_consts_ << "array(" << endl;
+    indent_up();
+    const map<t_const_value*, t_const_value*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      f_consts_ << indent();
+      print_const_value(ktype, v_iter->first);
+      f_consts_ << " => ";
+      print_const_value(vtype, v_iter->second);
+      f_consts_ << "," << endl;
+    }
+    indent_down();
+    indent(f_consts_) << ")";
+  } else if (type->is_list() || type->is_set()) {
+    t_type* etype;
+    if (type->is_list()) {
+      etype = ((t_list*)type)->get_elem_type();
+    } else {
+      etype = ((t_set*)type)->get_elem_type();
+    }
+    f_consts_ << "array(" << endl;
+    indent_up();
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      f_consts_ << indent();
+      print_const_value(etype, *v_iter);
+      f_consts_ << "," << endl;
+    }
+    indent_down();
+    indent(f_consts_) << ")";
+  }
+}
+
+/**
  * Make a struct
  */
 void t_php_generator::generate_struct(t_struct* tstruct) {
diff --git a/compiler/cpp/src/generate/t_php_generator.h b/compiler/cpp/src/generate/t_php_generator.h
index e74321d..e276eb4 100644
--- a/compiler/cpp/src/generate/t_php_generator.h
+++ b/compiler/cpp/src/generate/t_php_generator.h
@@ -38,10 +38,13 @@
 
   void generate_typedef  (t_typedef*  ttypedef);
   void generate_enum     (t_enum*     tenum);
+  void generate_const    (t_const*    tconst);
   void generate_struct   (t_struct*   tstruct);
   void generate_xception (t_struct*   txception);
   void generate_service  (t_service*  tservice);
 
+  void print_const_value (t_type* type, t_const_value* value);
+
   /**
    * Structs!
    */
@@ -138,6 +141,7 @@
    * File streams
    */
   std::ofstream f_types_;
+  std::ofstream f_consts_;
   std::ofstream f_helpers_;
   std::ofstream f_service_;
 
diff --git a/compiler/cpp/src/generate/t_py_generator.cc b/compiler/cpp/src/generate/t_py_generator.cc
index e29de80..bb375cc 100644
--- a/compiler/cpp/src/generate/t_py_generator.cc
+++ b/compiler/cpp/src/generate/t_py_generator.cc
@@ -19,11 +19,20 @@
   string f_types_name = string(T_PY_DIR)+"/"+program_name_+"_types.py";
   f_types_.open(f_types_name.c_str());
 
+  string f_consts_name = string(T_PY_DIR)+"/"+program_name_+"_constants.py";
+  f_consts_.open(f_consts_name.c_str());
+
   // Print header
   f_types_ <<
     py_autogen_comment() << endl <<
     py_imports() << endl <<
     render_includes() << endl;
+
+  f_consts_ <<
+    py_autogen_comment() << endl <<
+    py_imports() << endl <<
+    "from " << program_name_ << "_types import *" << endl <<
+    endl;
 }
 
 /**
@@ -68,6 +77,7 @@
 void t_py_generator::close_generator() {
   // Close types file
   f_types_.close();
+  f_consts_.close();
 }
 
 /**
@@ -107,6 +117,114 @@
 }
 
 /**
+ * Generate a constant value
+ */
+void t_py_generator::generate_const(t_const* tconst) {
+  t_type* type = tconst->get_type();
+  string name = tconst->get_name();
+  t_const_value* value = tconst->get_value();
+  
+  indent(f_consts_) << name << " = "; 
+  print_const_value(type, value);
+  f_consts_ << endl << endl;
+}
+
+/**
+ * Prints the value of a constant with the given type. Note that type checking
+ * is NOT performed in this function as it is always run beforehand using the
+ * validate_types method in main.cc
+ */
+void t_py_generator::print_const_value(t_type* type, t_const_value* value) {
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_STRING:
+      f_consts_ << "'" << value->get_string() << "'";
+      break;
+    case t_base_type::TYPE_BOOL:
+      f_consts_ << (value->get_integer() > 0 ? "True" : "False");
+      break;
+    case t_base_type::TYPE_BYTE:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      f_consts_ << value->get_integer();
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        f_consts_ << value->get_integer();
+      } else {
+        f_consts_ << value->get_double();
+      }
+      break;
+    default:
+      throw "compiler error: no const of base type " + tbase;
+    }
+  } else if (type->is_enum()) {
+    indent(f_consts_) << value->get_integer();
+  } else if (type->is_struct() || type->is_xception()) {
+    f_consts_ << type->get_name() << "({" << endl;
+    indent_up();
+    const vector<t_field*>& fields = ((t_struct*)type)->get_members();
+    vector<t_field*>::const_iterator f_iter;
+    const map<t_const_value*, t_const_value*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      t_type* field_type = NULL;
+      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        if ((*f_iter)->get_name() == v_iter->first->get_string()) {
+          field_type = (*f_iter)->get_type();
+        }
+      }
+      if (field_type == NULL) {
+        throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
+      }
+      f_consts_ << indent();
+      print_const_value(g_type_string, v_iter->first);
+      f_consts_ << " : ";
+      print_const_value(field_type, v_iter->second);
+      f_consts_ << "," << endl;
+    }
+    indent_down();
+    indent(f_consts_) << "})";
+  } else if (type->is_map()) {
+    t_type* ktype = ((t_map*)type)->get_key_type();
+    t_type* vtype = ((t_map*)type)->get_val_type();
+    f_consts_ << "{" << endl;
+    indent_up();
+    const map<t_const_value*, t_const_value*>& val = value->get_map();
+    map<t_const_value*, t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      f_consts_ << indent();
+      print_const_value(ktype, v_iter->first);
+      f_consts_ << " : ";
+      print_const_value(vtype, v_iter->second);
+      f_consts_ << "," << endl;
+    }
+    indent_down();
+    indent(f_consts_) << "}";
+  } else if (type->is_list() || type->is_set()) {
+    t_type* etype;
+    if (type->is_list()) {
+      etype = ((t_list*)type)->get_elem_type();
+    } else {
+      etype = ((t_set*)type)->get_elem_type();
+    }
+    f_consts_ << "[" << endl;
+    indent_up();
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      f_consts_ << indent();
+      print_const_value(etype, *v_iter);
+      f_consts_ << "," << endl;
+    }
+    indent_down();
+    indent(f_consts_) << "]";
+  }
+}
+
+/**
  * Generates a python struct
  */
 void t_py_generator::generate_struct(t_struct* tstruct) {
@@ -157,7 +275,7 @@
   out << endl;
 
   out <<
-    indent() << "def __init__(self):" << endl;
+    indent() << "def __init__(self, d=None):" << endl;
   indent_up();
 
   if (members.size() == 0) {
@@ -174,6 +292,16 @@
           declare_field(*m_iter, true) << endl;
       }
     }
+
+    indent(out) <<
+      "if isinstance(d, dict):" << endl;
+    indent_up();
+    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+      out <<
+        indent() << "if '" << (*m_iter)->get_name() << "' in d:" << endl <<
+        indent() << "  self." << (*m_iter)->get_name() << " = d['" << (*m_iter)->get_name() << "']" << endl;
+    }
+    indent_down();
   }
 
   indent_down();
diff --git a/compiler/cpp/src/generate/t_py_generator.h b/compiler/cpp/src/generate/t_py_generator.h
index 9cbc4a6..c0afe60 100644
--- a/compiler/cpp/src/generate/t_py_generator.h
+++ b/compiler/cpp/src/generate/t_py_generator.h
@@ -33,10 +33,13 @@
 
   void generate_typedef  (t_typedef*  ttypedef);
   void generate_enum     (t_enum*     tenum);
+  void generate_const    (t_const*    tconst);
   void generate_struct   (t_struct*   tstruct);
   void generate_xception (t_struct*   txception);
   void generate_service  (t_service*  tservice);
 
+  void print_const_value (t_type* type, t_const_value* value);
+
   /**
    * Struct generation code
    */
@@ -132,6 +135,7 @@
    */
 
   std::ofstream f_types_;
+  std::ofstream f_consts_; 
   std::ofstream f_service_;
 
 };
diff --git a/compiler/cpp/src/thrift.y b/compiler/cpp/src/thrift.y
index 06b71e1..c5db20b 100644
--- a/compiler/cpp/src/thrift.y
+++ b/compiler/cpp/src/thrift.y
@@ -345,8 +345,12 @@
   tok_const FieldType tok_identifier '=' ConstValue CommaOrSemicolonOptional
     {
       pdebug("Const -> tok_const FieldType tok_identifier = ConstValue");
-      $$ = new t_const($2, $3, $5);
-      validate_const_type($$);
+      if (g_parse_mode == PROGRAM) {
+        $$ = new t_const($2, $3, $5);
+        validate_const_type($$);
+      } else {
+        $$ = NULL;
+      }
     }
 
 ConstValue: