From aa7671d041f889f00a0ccc7dad2f806cf73a9a0d Mon Sep 17 00:00:00 2001 From: Mark Slee Date: Wed, 29 Nov 2006 03:19:31 +0000 Subject: [PATCH] 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 --- compiler/cpp/src/generate/t_cpp_generator.cc | 190 ++++++++++++++++++ compiler/cpp/src/generate/t_cpp_generator.h | 5 + compiler/cpp/src/generate/t_generator.cc | 11 + compiler/cpp/src/generate/t_generator.h | 3 + compiler/cpp/src/generate/t_java_generator.cc | 167 +++++++++++++++ compiler/cpp/src/generate/t_java_generator.h | 5 + compiler/cpp/src/generate/t_php_generator.cc | 122 +++++++++++ compiler/cpp/src/generate/t_php_generator.h | 4 + compiler/cpp/src/generate/t_py_generator.cc | 130 +++++++++++- compiler/cpp/src/generate/t_py_generator.h | 4 + compiler/cpp/src/thrift.y | 8 +- 11 files changed, 646 insertions(+), 3 deletions(-) diff --git a/compiler/cpp/src/generate/t_cpp_generator.cc b/compiler/cpp/src/generate/t_cpp_generator.cc index ff176a51..9188955f 100644 --- a/compiler/cpp/src/generate/t_cpp_generator.cc +++ b/compiler/cpp/src/generate/t_cpp_generator.cc @@ -142,6 +142,196 @@ void t_cpp_generator::generate_enum(t_enum* tenum) { endl; } +/** + * Generates a class that holds all the constants. + */ +void t_cpp_generator::generate_consts(std::vector 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::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& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::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& val = value->get_map(); + map::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& val = value->get_list(); + vector::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& val = value->get_list(); + vector::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 diff --git a/compiler/cpp/src/generate/t_cpp_generator.h b/compiler/cpp/src/generate/t_cpp_generator.h index 6070e37e..435b0c6e 100644 --- a/compiler/cpp/src/generate/t_cpp_generator.h +++ b/compiler/cpp/src/generate/t_cpp_generator.h @@ -28,6 +28,8 @@ class t_cpp_generator : public t_oop_generator { void init_generator(); void close_generator(); + void generate_consts(std::vector consts); + /** * Program-level generation functions */ @@ -37,6 +39,9 @@ class t_cpp_generator : public t_oop_generator { 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 30830d63..e4e010af 100644 --- a/compiler/cpp/src/generate/t_generator.cc +++ b/compiler/cpp/src/generate/t_generator.cc @@ -27,6 +27,10 @@ void t_generator::generate_program() { generate_enum(*en_iter); } + // Generate constants + vector consts = program_->get_consts(); + generate_consts(consts); + // Generate structs vector structs = program_->get_structs(); vector::iterator st_iter; @@ -52,3 +56,10 @@ void t_generator::generate_program() { // Close the generator close_generator(); } + +void t_generator::generate_consts(vector consts) { + vector::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 18a2247d..50f7bf6d 100644 --- a/compiler/cpp/src/generate/t_generator.h +++ b/compiler/cpp/src/generate/t_generator.h @@ -41,12 +41,15 @@ class t_generator { virtual void init_generator() {} virtual void close_generator() {} + virtual void generate_consts(std::vector 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 e2e9b713..ea2d22ab 100644 --- a/compiler/cpp/src/generate/t_java_generator.cc +++ b/compiler/cpp/src/generate/t_java_generator.cc @@ -108,6 +108,173 @@ void t_java_generator::generate_enum(t_enum* tenum) { f_enum.close(); } +/** + * Generates a class that holds all the constants. + */ +void t_java_generator::generate_consts(std::vector 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::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& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::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& val = value->get_map(); + map::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& val = value->get_list(); + vector::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 b319ab46..b21c76a9 100644 --- a/compiler/cpp/src/generate/t_java_generator.h +++ b/compiler/cpp/src/generate/t_java_generator.h @@ -28,6 +28,8 @@ class t_java_generator : public t_oop_generator { void init_generator(); void close_generator(); + void generate_consts(std::vector consts); + /** * Program-level generation functions */ @@ -38,6 +40,9 @@ class t_java_generator : public t_oop_generator { 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 f76b66f1..afadf068 100644 --- a/compiler/cpp/src/generate/t_php_generator.cc +++ b/compiler/cpp/src/generate/t_php_generator.cc @@ -17,12 +17,23 @@ void t_php_generator::init_generator() { // 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_ << "" << endl; f_types_.close(); + + f_consts_ << "?>" << endl; + f_consts_.close(); } /** @@ -104,6 +118,114 @@ void t_php_generator::generate_enum(t_enum* tenum) { f_types_ << "}" << endl << endl; } +/** + * 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& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::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& val = value->get_map(); + map::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& val = value->get_list(); + vector::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 */ diff --git a/compiler/cpp/src/generate/t_php_generator.h b/compiler/cpp/src/generate/t_php_generator.h index e74321d4..e276eb4f 100644 --- a/compiler/cpp/src/generate/t_php_generator.h +++ b/compiler/cpp/src/generate/t_php_generator.h @@ -38,10 +38,13 @@ class t_php_generator : public t_oop_generator { 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 @@ class t_php_generator : public t_oop_generator { * 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 e29de802..bb375cc3 100644 --- a/compiler/cpp/src/generate/t_py_generator.cc +++ b/compiler/cpp/src/generate/t_py_generator.cc @@ -19,11 +19,20 @@ void t_py_generator::init_generator() { 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 @@ string t_py_generator::py_imports() { void t_py_generator::close_generator() { // Close types file f_types_.close(); + f_consts_.close(); } /** @@ -106,6 +116,114 @@ void t_py_generator::generate_enum(t_enum* tenum) { f_types_ << endl; } +/** + * 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& fields = ((t_struct*)type)->get_members(); + vector::const_iterator f_iter; + const map& val = value->get_map(); + map::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& val = value->get_map(); + map::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& val = value->get_list(); + vector::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 */ @@ -157,7 +275,7 @@ void t_py_generator::generate_py_struct_definition(ofstream& out, 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 @@ void t_py_generator::generate_py_struct_definition(ofstream& out, 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 9cbc4a6f..c0afe60b 100644 --- a/compiler/cpp/src/generate/t_py_generator.h +++ b/compiler/cpp/src/generate/t_py_generator.h @@ -33,10 +33,13 @@ class t_py_generator : public t_oop_generator { 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 @@ class t_py_generator : public t_oop_generator { */ 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 06b71e12..c5db20b3 100644 --- a/compiler/cpp/src/thrift.y +++ b/compiler/cpp/src/thrift.y @@ -345,8 +345,12 @@ Const: 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: -- 2.17.1