From f5377b3e9947f39744831dd702e3df589bb0d30d Mon Sep 17 00:00:00 2001 From: Mark Slee Date: Tue, 10 Oct 2006 01:42:59 +0000 Subject: [PATCH] Thrift compiler code cleanup, comments, php inline generation, etc git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@664822 13f79535-47bb-0310-9956-ffa450edef68 --- compiler/cpp/src/generate/t_cpp_generator.cc | 196 +++++----- compiler/cpp/src/generate/t_cpp_generator.h | 41 ++- compiler/cpp/src/generate/t_generator.cc | 1 + compiler/cpp/src/generate/t_generator.h | 71 +++- compiler/cpp/src/generate/t_java_generator.cc | 121 +++++-- compiler/cpp/src/generate/t_java_generator.h | 27 +- compiler/cpp/src/generate/t_oop_generator.h | 8 +- compiler/cpp/src/generate/t_php_generator.cc | 334 +++++++++++++----- compiler/cpp/src/generate/t_php_generator.h | 48 ++- compiler/cpp/src/generate/t_py_generator.cc | 242 ++++--------- compiler/cpp/src/generate/t_py_generator.h | 45 ++- compiler/cpp/src/globals.h | 13 +- compiler/cpp/src/main.cc | 43 ++- compiler/cpp/src/main.h | 26 +- compiler/cpp/src/parse/t_base_type.h | 20 +- compiler/cpp/src/parse/t_constant.h | 29 +- compiler/cpp/src/parse/t_enum.h | 24 +- compiler/cpp/src/parse/t_field.h | 26 +- compiler/cpp/src/parse/t_function.h | 30 +- compiler/cpp/src/parse/t_list.h | 18 +- compiler/cpp/src/parse/t_map.h | 24 +- compiler/cpp/src/parse/t_program.h | 19 +- compiler/cpp/src/parse/t_service.h | 24 +- compiler/cpp/src/parse/t_set.h | 18 +- compiler/cpp/src/parse/t_struct.h | 17 +- compiler/cpp/src/parse/t_type.h | 10 +- compiler/cpp/src/parse/t_typedef.h | 26 +- compiler/cpp/src/thrift.l | 57 +-- compiler/cpp/src/thrift.y | 61 +++- 29 files changed, 1006 insertions(+), 613 deletions(-) diff --git a/compiler/cpp/src/generate/t_cpp_generator.cc b/compiler/cpp/src/generate/t_cpp_generator.cc index bda43ea9..1a2c8aed 100644 --- a/compiler/cpp/src/generate/t_cpp_generator.cc +++ b/compiler/cpp/src/generate/t_cpp_generator.cc @@ -40,10 +40,12 @@ void t_cpp_generator::init_generator(t_program* tprogram) { "#include " << endl << endl; + // Include the types file f_types_impl_ << "#include \"" << program_name_ <<"_types.h\"" << endl << endl; + // Open namespace ns_open_ = namespace_open(tprogram->get_namespace()); ns_close_ = namespace_close(tprogram->get_namespace()); @@ -60,7 +62,7 @@ void t_cpp_generator::init_generator(t_program* tprogram) { * Closes the output files. */ void t_cpp_generator::close_generator(t_program* tprogram) { - // Close ns + // Close namespace f_types_ << ns_close_ << endl << endl; @@ -83,8 +85,7 @@ void t_cpp_generator::close_generator(t_program* tprogram) { */ void t_cpp_generator::generate_typedef(t_typedef* ttypedef) { f_types_ << - indent() << "typedef " << type_name(ttypedef->get_type()) << " " << - ttypedef->get_symbolic() << ";" << endl << + indent() << "typedef " << type_name(ttypedef->get_type()) << " " << ttypedef->get_symbolic() << ";" << endl << endl; } @@ -97,7 +98,6 @@ void t_cpp_generator::generate_typedef(t_typedef* ttypedef) { void t_cpp_generator::generate_enum(t_enum* tenum) { f_types_ << indent() << "enum " << tenum->get_name() << " {" << endl; - indent_up(); vector constants = tenum->get_constants(); @@ -119,7 +119,6 @@ void t_cpp_generator::generate_enum(t_enum* tenum) { } indent_down(); - f_types_ << endl << "};" << endl << @@ -127,9 +126,9 @@ void t_cpp_generator::generate_enum(t_enum* tenum) { } /** - * Generates a struct definition for a thrift data type. In C++, this is just - * simple C struct with basic data members. There are no constructors, - * initializers, etc. + * 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. * * @param tstruct The struct definition */ @@ -140,7 +139,7 @@ void t_cpp_generator::generate_struct(t_struct* tstruct) { } /** - * Writes the struct def. + * Writes the struct definition into the header file * * @param out Output stream * @param tstruct The struct @@ -152,13 +151,12 @@ void t_cpp_generator::generate_struct_definition(ofstream& out, indent() << "class " << tstruct->get_name() << " {" << endl << indent() << " public:" << endl << endl; - indent_up(); // Get members vector::const_iterator m_iter; const vector& members = tstruct->get_members(); - + // Default constructor bool init_ctor = false; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { @@ -180,14 +178,14 @@ void t_cpp_generator::generate_struct_definition(ofstream& out, if (init_ctor) { out << " {} " << endl; } - + // Declare all fields for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { indent(out) << declare_field(*m_iter) << endl; } - - // Isset vector + + // Isset struct has boolean fields if (members.size() > 0) { out << endl << @@ -213,6 +211,7 @@ void t_cpp_generator::generate_struct_definition(ofstream& out, indent(out) << "bool " << (*m_iter)->get_name() << ";" << endl; } + indent_down(); indent(out) << "} __isset;" << endl; @@ -220,12 +219,8 @@ void t_cpp_generator::generate_struct_definition(ofstream& out, out << endl << - indent() << "uint32_t read(" << - "boost::shared_ptr iprot, " << - "boost::shared_ptr itrans);" << endl << - indent() << "uint32_t write(" << - "boost::shared_ptr oprot, " << - "boost::shared_ptr otrans) const;" << endl << + indent() << "uint32_t read(boost::shared_ptr iprot, boost::shared_ptr itrans);" << endl << + indent() << "uint32_t write(boost::shared_ptr oprot, boost::shared_ptr otrans) const;" << endl << endl; indent_down(); @@ -243,9 +238,7 @@ void t_cpp_generator::generate_struct_definition(ofstream& out, void t_cpp_generator::generate_struct_reader(ofstream& out, t_struct* tstruct) { indent(out) << - "uint32_t " << tstruct->get_name() << "::read(" << - "boost::shared_ptr iprot, " << - "boost::shared_ptr itrans) {" << endl; + "uint32_t " << tstruct->get_name() << "::read(boost::shared_ptr iprot, boost::shared_ptr itrans) {" << endl; indent_up(); const vector& fields = tstruct->get_members(); @@ -320,7 +313,7 @@ void t_cpp_generator::generate_struct_reader(ofstream& out, } /** - * Makes a helper function to gen a struct writer. + * Generates the write function. * * @param out Stream to write to * @param tstruct The struct @@ -332,9 +325,7 @@ void t_cpp_generator::generate_struct_writer(ofstream& out, vector::const_iterator f_iter; indent(out) << - "uint32_t " << tstruct->get_name() << "::write(" << - "boost::shared_ptr oprot, " << - "boost::shared_ptr otrans) const {" << endl; + "uint32_t " << tstruct->get_name() << "::write(boost::shared_ptr oprot, boost::shared_ptr otrans) const {" << endl; indent_up(); out << @@ -382,9 +373,7 @@ void t_cpp_generator::generate_struct_result_writer(ofstream& out, vector::const_iterator f_iter; indent(out) << - "uint32_t " << tstruct->get_name() << "::write(" << - "boost::shared_ptr oprot, " << - "boost::shared_ptr otrans) const {" << endl; + "uint32_t " << tstruct->get_name() << "::write(boost::shared_ptr oprot, boost::shared_ptr otrans) const {" << endl; indent_up(); out << @@ -478,13 +467,14 @@ void t_cpp_generator::generate_service(t_service* tservice) { ns_open_ << endl << endl; + // Generate all the components generate_service_interface(tservice); generate_service_helpers(tservice); generate_service_client(tservice); generate_service_server(tservice); generate_service_multiface(tservice); - + // Close the namespace f_service_ << ns_close_ << endl << endl; @@ -494,12 +484,14 @@ void t_cpp_generator::generate_service(t_service* tservice) { f_header_ << "#endif" << endl; + // Close the files f_service_.close(); f_header_.close(); } /** - * Generates helper functions for a service. + * Generates helper functions for a service. Basically, this generates types + * for all the arguments and results to functions. * * @param tservice The service to generate a header definition for */ @@ -546,7 +538,7 @@ void t_cpp_generator::generate_service_interface(t_service* tservice) { * @param tservice The service to generate a multiserver for. */ void t_cpp_generator::generate_service_multiface(t_service* tservice) { - // Generate the dispatch methods + // Generate the dispatch methods vector functions = tservice->get_functions(); vector::iterator f_iter; @@ -639,16 +631,18 @@ void t_cpp_generator::generate_service_client(t_service* tservice) { indent_up(); f_header_ << - indent() << service_name_ << "Client" << - "(boost::shared_ptr trans, boost::shared_ptr prot) : " << - "_itrans(trans), _otrans(trans), " << - "_iprot(prot), _oprot(prot) {}" << endl; + indent() << service_name_ << "Client(boost::shared_ptr trans, boost::shared_ptr prot) : " << endl << + indent() << " _itrans(trans)," << endl << + indent() << " _otrans(trans)," << endl << + indent() << " _iprot(prot)," << endl << + indent() << " _oprot(prot) {}" << endl; + f_header_ << - indent() << service_name_ << "Client" << - "(boost::shared_ptr itrans, boost::shared_ptr otrans," << - " boost::shared_ptr iprot, boost::shared_ptr oprot) : " << - "_itrans(itrans), _otrans(otrans), " << - "_iprot(iprot), _oprot(oprot) {}" << endl; + indent() << service_name_ << "Client(boost::shared_ptr itrans, boost::shared_ptr otrans, boost::shared_ptr iprot, boost::shared_ptr oprot) : " << endl << + indent() << " _itrans(itrans)," << endl << + indent() << " _otrans(otrans)," << endl << + indent() << " _iprot(iprot)," << endl << + indent() << " _oprot(oprot) {}" << endl; vector functions = tservice->get_functions(); vector::const_iterator f_iter; @@ -723,6 +717,7 @@ void t_cpp_generator::generate_service_client(t_service* tservice) { scope_down(f_service_); f_service_ << endl; + // Function for sending t_function send_function(g_program->get_void_type(), string("send_") + (*f_iter)->get_name(), (*f_iter)->get_arglist()); @@ -732,6 +727,7 @@ void t_cpp_generator::generate_service_client(t_service* tservice) { function_signature(&send_function, scope) << endl; scope_up(f_service_); + // Function arguments and results string argsname = (*f_iter)->get_name() + "_args"; string resultname = (*f_iter)->get_name() + "_result"; @@ -787,8 +783,7 @@ void t_cpp_generator::generate_service_client(t_service* tservice) { indent() << "_iprot->readMessageEnd(_itrans);" << endl << endl; - - // Careful, only return _result if not a void function + // Careful, only look for _result if not a void function if (!(*f_iter)->get_returntype()->is_void()) { f_service_ << indent() << "if (__result.__isset.success) {" << endl << @@ -806,7 +801,7 @@ void t_cpp_generator::generate_service_client(t_service* tservice) { indent() << "}" << endl; } - // Careful, only return _result if not a void function + // We only get here if we are a void function if ((*f_iter)->get_returntype()->is_void()) { indent(f_service_) << "return;" << endl; @@ -854,8 +849,7 @@ void t_cpp_generator::generate_service_server(t_service* tservice) { indent_up(); for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { indent(f_header_) << - "void process_" << (*f_iter)->get_name() << - "(int32_t seqid, boost::shared_ptr _itrans, boost::shared_ptr _otrans);" << endl; + "void process_" << (*f_iter)->get_name() << "(int32_t seqid, boost::shared_ptr _itrans, boost::shared_ptr _otrans);" << endl; } indent_down(); @@ -876,12 +870,16 @@ void t_cpp_generator::generate_service_server(t_service* tservice) { f_header_ << " public: " << endl << - indent() << service_name_ << "Processor(boost::shared_ptr<" << service_name_ << "If> iface, boost::shared_ptr prot) : " << - "_iface(iface), _iprot(prot), _oprot(prot) {" << endl << + indent() << service_name_ << "Processor(boost::shared_ptr<" << service_name_ << "If> iface, boost::shared_ptr prot) :" << endl << + indent() << " _iface(iface)," << endl << + indent() << " _iprot(prot)," << endl << + indent() << " _oprot(prot) {" << endl << declare_map << indent() << "}" << endl << - indent() << service_name_ << "Processor(boost::shared_ptr<" << service_name_ << "If> iface, boost::shared_ptr iprot, boost::shared_ptr oprot) : " << - "_iface(iface), _iprot(iprot), _oprot(oprot) {" << endl << + indent() << service_name_ << "Processor(boost::shared_ptr<" << service_name_ << "If> iface, boost::shared_ptr iprot, boost::shared_ptr oprot) :" << endl << + indent() << " _iface(iface)," << endl << + indent() << " _iprot(iprot)," << endl << + indent() << " _oprot(oprot) {" << endl << declare_map << indent() << "}" << endl << endl << @@ -891,11 +889,9 @@ void t_cpp_generator::generate_service_server(t_service* tservice) { f_header_ << "};" << endl << endl; - // Generate the server implementation f_service_ << - "bool " << service_name_ << "Processor::" << - "process(boost::shared_ptr itrans, boost::shared_ptr otrans) {" << endl; + "bool " << service_name_ << "Processor::process(boost::shared_ptr itrans, boost::shared_ptr otrans) {" << endl; indent_up(); f_service_ << @@ -921,35 +917,6 @@ void t_cpp_generator::generate_service_server(t_service* tservice) { indent() << " (this->*(pfn->second))(seqid, itrans, otrans);" << endl << indent() << "}" << endl; - // DEPRECATED: if else if bullshit - /* - bool first = true; - for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { - if (!first) { - f_service_ << " else "; - } else { - f_service_ << indent(); - first = false; - } - f_service_ << - "if (fname.compare(\"" << (*f_iter)->get_name() <<"\") == 0) {" << endl; - indent_up(); - indent(f_service_) << - "process_" << (*f_iter)->get_name() << - "(seqid, itrans, otrans);" << endl; - indent_down(); - indent(f_service_) << "}"; - } - indent(f_service_) << - " else {" << endl; - indent_up(); - indent(f_service_) << - "throw facebook::thrift::Exception(\"Unknown function name: '\"+fname+\"'\");" << endl; - indent_down(); - indent(f_service_) << - "}" << endl; - */ - // Read end of args field, the T_STOP, and the struct close f_service_ << indent() << "return true;" << endl; @@ -963,7 +930,6 @@ void t_cpp_generator::generate_service_server(t_service* tservice) { for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { generate_process_function(tservice, *f_iter); } - } /** @@ -1129,7 +1095,6 @@ void t_cpp_generator::generate_deserialize_field(ofstream& out, } else if (type->is_container()) { generate_deserialize_container(out, tfield->get_type(), name); } else if (type->is_base_type() || type->is_enum()) { - indent(out) << "xfer += iprot->"; @@ -1223,11 +1188,9 @@ void t_cpp_generator::generate_deserialize_container(ofstream& out, // For loop iterates over elements string i = tmp("_i"); - indent(out) << - "uint32_t " << i << ";" << endl; - indent(out) << - "for (" << - i << " = 0; " << i << " < " << size << "; ++" << i << ")" << endl; + out << + indent() << "uint32_t " << i << ";" << endl << + indent() << "for (" << i << " = 0; " << i << " < " << size << "; ++" << i << ")" << endl; scope_up(out); @@ -1265,10 +1228,9 @@ void t_cpp_generator::generate_deserialize_map_element(ofstream& out, t_field fkey(tmap->get_key_type(), key); t_field fval(tmap->get_val_type(), val); - indent(out) << - declare_field(&fkey) << endl; - indent(out) << - declare_field(&fval) << endl; + out << + indent() << declare_field(&fkey) << endl << + indent() << declare_field(&fval) << endl; generate_deserialize_field(out, &fkey); generate_deserialize_field(out, &fval); @@ -1422,15 +1384,10 @@ void t_cpp_generator::generate_serialize_container(ofstream& out, } string iter = tmp("_iter"); - indent(out) << - type_name(ttype) << "::const_iterator " << iter << ";" << endl; - indent(out) << - "for (" << iter << " = " << prefix << ".begin(); " << - iter << " != " << prefix << ".end(); " << - "++" << iter << ")" << endl; - - scope_up(out); - + out << + indent() << type_name(ttype) << "::const_iterator " << iter << ";" << endl << + indent() << "for (" << iter << " = " << prefix << ".begin(); " << iter << " != " << prefix << ".end(); ++" << iter << ")" << endl; + scope_up(out); if (ttype->is_map()) { generate_serialize_map_element(out, (t_map*)ttype, iter); } else if (ttype->is_set()) { @@ -1438,19 +1395,18 @@ void t_cpp_generator::generate_serialize_container(ofstream& out, } else if (ttype->is_list()) { generate_serialize_list_element(out, (t_list*)ttype, iter); } - - scope_down(out); + scope_down(out); - if (ttype->is_map()) { - indent(out) << - "xfer += oprot->writeMapEnd(otrans);" << endl; - } else if (ttype->is_set()) { - indent(out) << - "xfer += oprot->writeSetEnd(otrans);" << endl; - } else if (ttype->is_list()) { - indent(out) << - "xfer += oprot->writeListEnd(otrans);" << endl; - } + if (ttype->is_map()) { + indent(out) << + "xfer += oprot->writeMapEnd(otrans);" << endl; + } else if (ttype->is_set()) { + indent(out) << + "xfer += oprot->writeSetEnd(otrans);" << endl; + } else if (ttype->is_list()) { + indent(out) << + "xfer += oprot->writeListEnd(otrans);" << endl; + } scope_down(out); } @@ -1533,11 +1489,11 @@ string t_cpp_generator::namespace_close(string ns) { return result; } - /** * Returns a C++ type name * * @param ttype The type + * @return String of the type name, i.e. std::set */ string t_cpp_generator::type_name(t_type* ttype) { if (ttype->is_base_type()) { @@ -1562,6 +1518,7 @@ string t_cpp_generator::type_name(t_type* ttype) { * Returns the C++ type that corresponds to the thrift type. * * @param tbase The base type + * @return Explicit C++ type, i.e. "int32_t" */ string t_cpp_generator::base_type_name(t_base_type::t_base tbase) { switch (tbase) { @@ -1590,6 +1547,7 @@ string t_cpp_generator::base_type_name(t_base_type::t_base tbase) { * Declares a field, which may include initialization as necessary. * * @param ttype The type + * @return Field declaration, i.e. int x = 0; */ string t_cpp_generator::declare_field(t_field* tfield, bool init) { // TODO(mcslee): do we ever need to initialize the field? @@ -1646,6 +1604,9 @@ string t_cpp_generator::function_signature(t_function* tfunction, /** * Renders a field list + * + * @param tstruct The struct definition + * @return Comma sepearated list of all field names in that struct */ string t_cpp_generator::argument_list(t_struct* tstruct) { string result = ""; @@ -1666,6 +1627,9 @@ string t_cpp_generator::argument_list(t_struct* tstruct) { /** * Converts the parse type to a C++ enum string for the given type. + * + * @param type Thrift Type + * @return String of C++ code to definition of that type constant */ string t_cpp_generator::type_to_enum(t_type* type) { while (type->is_typedef()) { diff --git a/compiler/cpp/src/generate/t_cpp_generator.h b/compiler/cpp/src/generate/t_cpp_generator.h index 55c7c2f5..37c36a1e 100644 --- a/compiler/cpp/src/generate/t_cpp_generator.h +++ b/compiler/cpp/src/generate/t_cpp_generator.h @@ -8,7 +8,7 @@ #include "t_oop_generator.h" -// TODO(mcslee: Paramaterize the output dir +// TODO(mcslee): Paramaterize the output dir #define T_CPP_DIR "gen-cpp" /** @@ -19,27 +19,31 @@ class t_cpp_generator : public t_oop_generator { public: t_cpp_generator() {} - ~t_cpp_generator() {} - /** Init and close methods */ + /** + * Init and close methods + */ void init_generator(t_program *tprogram); void close_generator(t_program *tprogram); - /** Program-level generation functions */ + /** + * Program-level generation functions + */ void generate_typedef (t_typedef* ttypedef); void generate_enum (t_enum* tenum); void generate_struct (t_struct* tstruct); void generate_service (t_service* tservice); - 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); + 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); void generate_struct_result_writer (std::ofstream& out, t_struct* tstruct); - /** Service-level generation functions */ + /** + * Service-level generation functions + */ void generate_service_interface (t_service* tservice); void generate_service_multiface (t_service* tservice); @@ -47,10 +51,11 @@ class t_cpp_generator : public t_oop_generator { void generate_service_client (t_service* tservice); void generate_service_server (t_service* tservice); void generate_process_function (t_service* tservice, t_function* tfunction); - void generate_function_helpers (t_function* tfunction); - /** Serialization constructs */ + /** + * Serialization constructs + */ void generate_deserialize_field (std::ofstream& out, t_field* tfield, @@ -100,7 +105,9 @@ class t_cpp_generator : public t_oop_generator { t_list* tlist, std::string iter); - /** Helper rendering functions */ + /** + * Helper rendering functions + */ std::string namespace_open(std::string ns); std::string namespace_close(std::string ns); @@ -113,14 +120,20 @@ class t_cpp_generator : public t_oop_generator { private: - /** File streams */ + /** + * Strings for namespace, computed once up front then used directly + */ std::string ns_open_; std::string ns_close_; + /** + * File streams, stored here to avoid passing them as parameters to every + * function. + */ + std::ofstream f_types_; std::ofstream f_types_impl_; - std::ofstream f_header_; std::ofstream f_service_; }; diff --git a/compiler/cpp/src/generate/t_generator.cc b/compiler/cpp/src/generate/t_generator.cc index 99baf331..dc09ba10 100644 --- a/compiler/cpp/src/generate/t_generator.cc +++ b/compiler/cpp/src/generate/t_generator.cc @@ -7,6 +7,7 @@ using namespace std; * program to perform the correct actions. * * @param program The thrift program to compile into C++ source + * @author Mark Slee */ void t_generator::generate_program(t_program *tprogram) { // Set program name diff --git a/compiler/cpp/src/generate/t_generator.h b/compiler/cpp/src/generate/t_generator.h index 16d80848..07eaf386 100644 --- a/compiler/cpp/src/generate/t_generator.h +++ b/compiler/cpp/src/generate/t_generator.h @@ -15,7 +15,10 @@ */ class t_generator { public: - t_generator() { tmp_ = 0; } + t_generator() { + tmp_ = 0; + } + virtual ~t_generator() {} /** @@ -26,45 +29,67 @@ class t_generator { void generate_program (t_program* tprogram); protected: - /** Optional methods that may be imlemented by subclasses. */ + + /** + * Optional methods that may be imlemented by subclasses to take necessary + * steps at the beginning or end of code generation. + */ virtual void init_generator (t_program* tprogram) {} virtual void close_generator (t_program* tprogram) {} - /** Pure virtual methods implemented by the generator subclasses. */ + /** + * 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_struct (t_struct* tstruct) = 0; + virtual void generate_service (t_service* tservice) = 0; virtual void generate_xception (t_struct* txception) { + // By default exceptions are the same as structs generate_struct(txception); } - virtual void generate_service (t_service* tservice) = 0; - - /** Method to get the program name, may be overridden */ + /** + * Method to get the program name, may be overridden + */ virtual std::string get_program_name(t_program* tprogram) { return tprogram->get_name(); } - /** Method to get the service name, may be overridden */ + /** + * Method to get the service name, may be overridden + */ virtual std::string get_service_name(t_service* tservice) { return tservice->get_name(); } - /** Creates a unique temporary variable name. */ + /** + * Creates a unique temporary variable name, which is just "name" with a + * number appended to it (i.e. name35) + */ std::string tmp(std::string name) { std::ostringstream out; out << name << tmp_++; return out.str(); } - /** Indentation level modifiers */ + /** + * Indentation level modifiers + */ + + void indent_up(){ + ++indent_; + } - void indent_up() { ++indent_; } - void indent_down() { --indent_; } + void indent_down() { + --indent_; + } - /** Indentation print function */ + /** + * Indentation print function + */ std::string indent() { std::string ind = ""; int i; @@ -74,23 +99,35 @@ class t_generator { return ind; } - /** Indentation utility wrapper */ + /** + * Indentation utility wrapper + */ std::ostream& indent(std::ostream &os) { return os << indent(); } protected: - /** Quick accessor for formatted program name */ + /** + * Quick accessor for formatted program name that is currently being + * generated. + */ std::string program_name_; - /** Quick accessor for formatted service name */ + /** + * Quick accessor for formatted service name that is currently being + * generated. + */ std::string service_name_; private: - /** Indentation level */ + /** + * Current code indentation level + */ int indent_; - /** Temporary variable counter */ + /** + * Temporary variable counter, for making unique variable names + */ int tmp_; }; diff --git a/compiler/cpp/src/generate/t_java_generator.cc b/compiler/cpp/src/generate/t_java_generator.cc index 987a7557..b99c748d 100644 --- a/compiler/cpp/src/generate/t_java_generator.cc +++ b/compiler/cpp/src/generate/t_java_generator.cc @@ -18,14 +18,17 @@ void t_java_generator::init_generator(t_program* tprogram) { /** * Packages the generated file + * + * @return String of the package, i.e. "package com.facebook.thriftdemo;" */ string t_java_generator::java_package() { - // TODO(mcslee): Allow destination package to be specified in .thrift file return string("package ") + package_name_ + ";\n\n"; } /** * Prints standard java imports + * + * @return List of imports for Java types that are used in here */ string t_java_generator::java_type_imports() { return @@ -38,6 +41,8 @@ string t_java_generator::java_type_imports() { /** * Prints standard java imports + * + * @return List of imports necessary for thrift */ string t_java_generator::java_thrift_imports() { return @@ -47,20 +52,21 @@ string t_java_generator::java_thrift_imports() { } /** - * Does nothing in Java + * Nothing in Java */ void t_java_generator::close_generator(t_program *tprogram) {} /** - * Generates a typedef. This is not done in Java. + * Generates a typedef. This is not done in Java, since it does + * not support arbitrary name replacements, and it'd be a wacky waste + * of overhead to make wrapper classes. * * @param ttypedef The type definition */ void t_java_generator::generate_typedef(t_typedef* ttypedef) {} /** - * Generates code for an enumerated type. In C++, this is essentially the same - * as the thrift definition itself, using the enum keyword in C++. + * Enums are a class with a set of static constants. * * @param tenum The enumeration */ @@ -70,6 +76,7 @@ void t_java_generator::generate_enum(t_enum* tenum) { ofstream f_enum; f_enum.open(f_enum_name.c_str()); + // Comment and package it f_enum << autogen_comment() << java_package() << endl; @@ -94,12 +101,12 @@ void t_java_generator::generate_enum(t_enum* tenum) { } scope_down(f_enum); + f_enum.close(); } /** - * Generates a struct definition for a thrift data type. In C++, this is just - * simple C struct with basic data members. There are no constructors, - * initializers, etc. + * Generates a struct definition for a thrift data type. This is a class + * with data members, read(), write(), and an inner Isset class. * * @param tstruct The struct definition */ @@ -107,10 +114,21 @@ void t_java_generator::generate_struct(t_struct* tstruct) { generate_java_struct(tstruct, false); } +/** + * Exceptions are structs, but they inherit from Exception + * + * @param tstruct The struct definition + */ void t_java_generator::generate_xception(t_struct* txception) { generate_java_struct(txception, true); } + +/** + * Java struct definition. + * + * @param tstruct The struct definition + */ void t_java_generator::generate_java_struct(t_struct* tstruct, bool is_exception) { // Make output file @@ -130,6 +148,16 @@ void t_java_generator::generate_java_struct(t_struct* tstruct, f_struct.close(); } +/** + * Java struct definition. This has various parameters, as it could be + * generated standalone or inside another class as a helper. If it + * is a helper than it is a static class. + * + * @param tstruct The struct definition + * @param is_exception Is this an exception? + * @param in_class If inside a class, needs to be static class + * @param is_result If this is a result it needs a different writer + */ void t_java_generator::generate_java_struct_definition(ofstream &out, t_struct* tstruct, bool is_exception, @@ -144,6 +172,7 @@ void t_java_generator::generate_java_struct_definition(ofstream &out, scope_up(out); + // Members are public const vector& members = tstruct->get_members(); vector::const_iterator m_iter; for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { @@ -151,6 +180,7 @@ void t_java_generator::generate_java_struct_definition(ofstream &out, "public " << declare_field(*m_iter, true) << endl; } + // Inner Isset class if (members.size() > 0) { out << endl << @@ -177,6 +207,11 @@ void t_java_generator::generate_java_struct_definition(ofstream &out, out << endl; } +/** + * Generates a function to read all the fields of the struct. + * + * @param tstruct The struct definition + */ void t_java_generator::generate_java_struct_reader(ofstream& out, t_struct* tstruct) { out << @@ -194,7 +229,6 @@ void t_java_generator::generate_java_struct_reader(ofstream& out, // Loop over reading in fields indent(out) << "while (true)" << endl; - scope_up(out); // Read beginning field marker @@ -253,6 +287,11 @@ void t_java_generator::generate_java_struct_reader(ofstream& out, endl; } +/** + * Generates a function to write all the fields of the struct + * + * @param tstruct The struct definition + */ void t_java_generator::generate_java_struct_writer(ofstream& out, t_struct* tstruct) { out << @@ -292,6 +331,14 @@ void t_java_generator::generate_java_struct_writer(ofstream& out, indent() << "}" << endl; } +/** + * Generates a function to write all the fields of the struct, + * which is a function result. These fields are only written + * if they are set in the Isset array, and only one of them + * can be set at a time. + * + * @param tstruct The struct definition + */ void t_java_generator::generate_java_struct_result_writer(ofstream& out, t_struct* tstruct) { out << @@ -409,6 +456,11 @@ void t_java_generator::generate_service_interface(t_service* tservice) { endl; } +/** + * Generates structs for all the service args and return types + * + * @param tservice The service + */ void t_java_generator::generate_service_helpers(t_service* tservice) { vector functions = tservice->get_functions(); vector::iterator f_iter; @@ -541,14 +593,14 @@ void t_java_generator::generate_service_client(t_service* tservice) { "public " << function_signature(&recv_function) << endl; scope_up(f_service_); - // TODO(mcslee): Message validation here - f_service_ << indent() << "TMessage _msg = _iprot.readMessageBegin(_itrans);" << endl << indent() << resultname << " __result = new " << resultname << "();" << endl << indent() << "__result.read(_iprot, _itrans);" << endl << indent() << "_iprot.readMessageEnd(_itrans);" << endl; + // TODO(mcslee): Message validation here, was the seqid etc ok? + // Careful, only return _result if not a void function if (!(*f_iter)->get_returntype()->is_void()) { f_service_ << @@ -567,7 +619,7 @@ void t_java_generator::generate_service_client(t_service* tservice) { indent() << "}" << endl; } - // Careful, only return _result if not a void function + // If you get here it's an exception, unless a void function if ((*f_iter)->get_returntype()->is_void()) { indent(f_service_) << "return;" << endl; @@ -627,14 +679,13 @@ void t_java_generator::generate_service_server(t_service* tservice) { // Generate the server implementation indent(f_service_) << - "public boolean process(TTransport _itrans, TTransport _otrans) " << - "throws TException" << endl; + "public boolean process(TTransport _itrans, TTransport _otrans) throws TException" << endl; scope_up(f_service_); f_service_ << indent() << "TMessage _msg = _iprot.readMessageBegin(_itrans);" << endl; - // TODO(mcslee): validate message + // TODO(mcslee): validate message, was the seqid etc. legit? bool first = true; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { @@ -648,8 +699,7 @@ void t_java_generator::generate_service_server(t_service* tservice) { "if (_msg.name.equals(\"" << (*f_iter)->get_name() <<"\")) {" << endl; indent_up(); indent(f_service_) << - "process_" << (*f_iter)->get_name() << - "(_msg.seqid, _itrans, _otrans);" << endl; + "process_" << (*f_iter)->get_name() << "(_msg.seqid, _itrans, _otrans);" << endl; indent_down(); indent(f_service_) << "}"; } @@ -657,8 +707,7 @@ void t_java_generator::generate_service_server(t_service* tservice) { " else {" << endl; indent_up(); indent(f_service_) << - "System.err.println" << - "(\"Unknown function: '\" + _msg.name + \"'\");" << endl; + "System.err.println(\"Unknown function: '\" + _msg.name + \"'\");" << endl; indent_down(); indent(f_service_) << "}" << endl; @@ -716,8 +765,7 @@ void t_java_generator::generate_process_function(t_service* tservice, t_function* tfunction) { // Open function indent(f_service_) << - "private void process_" << tfunction->get_name() << - "(int seqid, TTransport _itrans, TTransport _otrans) throws TException" << endl; + "private void process_" << tfunction->get_name() << "(int seqid, TTransport _itrans, TTransport _otrans) throws TException" << endl; scope_up(f_service_); string argsname = tfunction->get_name() + "_args"; @@ -815,6 +863,9 @@ void t_java_generator::generate_process_function(t_service* tservice, /** * Deserializes a field of any type. + * + * @param tfield The field + * @param prefix The variable name or container for this field */ void t_java_generator::generate_deserialize_field(ofstream& out, t_field* tfield, @@ -885,10 +936,7 @@ void t_java_generator::generate_deserialize_field(ofstream& out, } /** - * Generates an unserializer for a variable. This makes two key assumptions, - * first that there is a const char* variable named data that points to the - * buffer for deserialization, and that there is a variable protocol which - * is a reference to a TProtocol serialization object. + * Generates an unserializer for a struct, invokes read() */ void t_java_generator::generate_deserialize_struct(ofstream& out, t_struct* tstruct, @@ -898,6 +946,9 @@ void t_java_generator::generate_deserialize_struct(ofstream& out, indent() << prefix << ".read(_iprot, _itrans);" << endl; } +/** + * Deserializes a container by reading its size and then iterating + */ void t_java_generator::generate_deserialize_container(ofstream& out, t_type* ttype, string prefix) { @@ -981,6 +1032,9 @@ void t_java_generator::generate_deserialize_map_element(ofstream& out, prefix << ".put(" << key << ", " << val << ");" << endl; } +/** + * Deserializes a set element + */ void t_java_generator::generate_deserialize_set_element(ofstream& out, t_set* tset, string prefix) { @@ -996,6 +1050,9 @@ void t_java_generator::generate_deserialize_set_element(ofstream& out, prefix << ".add(" << elem << ");" << endl; } +/** + * Deserializes a list element + */ void t_java_generator::generate_deserialize_list_element(ofstream& out, t_list* tlist, string prefix) { @@ -1102,6 +1159,12 @@ void t_java_generator::generate_serialize_struct(ofstream& out, indent() << prefix << ".write(_oprot, _otrans);" << endl; } +/** + * Serializes a container by writing its size then the elements. + * + * @param ttype The type of container + * @param prefix String prefix for fields + */ void t_java_generator::generate_serialize_container(ofstream& out, t_type* ttype, string prefix) { @@ -1174,7 +1237,6 @@ void t_java_generator::generate_serialize_container(ofstream& out, /** * Serializes the members of a map. - * */ void t_java_generator::generate_serialize_map_element(ofstream& out, t_map* tmap, @@ -1182,7 +1244,6 @@ void t_java_generator::generate_serialize_map_element(ofstream& out, string map) { t_field kfield(tmap->get_key_type(), iter); generate_serialize_field(out, &kfield, ""); - t_field vfield(tmap->get_val_type(), map + ".get(" + iter + ")"); generate_serialize_field(out, &vfield, ""); } @@ -1212,6 +1273,7 @@ void t_java_generator::generate_serialize_list_element(ofstream& out, * * @param ttype The type * @param container Is the type going inside a container? + * @return Java type name, i.e. HashMap */ string t_java_generator::type_name(t_type* ttype, bool in_container) { // In Java typedefs are just resolved to their real type @@ -1326,8 +1388,7 @@ string t_java_generator::function_signature(t_function* tfunction, string prefix) { t_type* ttype = tfunction->get_returntype(); std::string result = - type_name(ttype) + " " + prefix + tfunction->get_name() + - "(" + argument_list(tfunction->get_arglist()) + ") throws "; + type_name(ttype) + " " + prefix + tfunction->get_name() + "(" + argument_list(tfunction->get_arglist()) + ") throws "; t_struct* xs = tfunction->get_xceptions(); const std::vector& xceptions = xs->get_members(); vector::const_iterator x_iter; @@ -1339,7 +1400,7 @@ string t_java_generator::function_signature(t_function* tfunction, } /** - * Renders a field list + * Renders a comma separated field list, with type names */ string t_java_generator::argument_list(t_struct* tstruct) { string result = ""; diff --git a/compiler/cpp/src/generate/t_java_generator.h b/compiler/cpp/src/generate/t_java_generator.h index 2c8e2471..e528c342 100644 --- a/compiler/cpp/src/generate/t_java_generator.h +++ b/compiler/cpp/src/generate/t_java_generator.h @@ -19,14 +19,17 @@ class t_java_generator : public t_oop_generator { public: t_java_generator() {} - ~t_java_generator() {} - /** Init and close methods */ + /** + * Init and close methods + */ void init_generator(t_program *tprogram); void close_generator(t_program *tprogram); - /** Program-level generation functions */ + /** + * Program-level generation functions + */ void generate_typedef (t_typedef* ttypedef); void generate_enum (t_enum* tenum); @@ -34,7 +37,9 @@ class t_java_generator : public t_oop_generator { void generate_xception(t_struct* txception); void generate_service (t_service* tservice); - /** Service-level generation functions */ + /** + * Service-level generation functions + */ void generate_java_struct(t_struct* tstruct, bool is_exception); @@ -51,7 +56,9 @@ class t_java_generator : public t_oop_generator { void generate_service_server (t_service* tservice); void generate_process_function (t_service* tservice, t_function* tfunction); - /** Serialization constructs */ + /** + * Serialization constructs + */ void generate_deserialize_field (std::ofstream& out, t_field* tfield, @@ -102,7 +109,9 @@ class t_java_generator : public t_oop_generator { t_list* tlist, std::string iter); - /** Helper rendering functions */ + /** + * Helper rendering functions + */ std::string java_package(); std::string java_type_imports(); @@ -116,9 +125,11 @@ class t_java_generator : public t_oop_generator { private: - /** File streams */ - std::string package_name_; + /** + * File streams + */ + std::string package_name_; std::ofstream f_service_; }; diff --git a/compiler/cpp/src/generate/t_oop_generator.h b/compiler/cpp/src/generate/t_oop_generator.h index 7b7ada1a..fc47bc6d 100644 --- a/compiler/cpp/src/generate/t_oop_generator.h +++ b/compiler/cpp/src/generate/t_oop_generator.h @@ -6,13 +6,16 @@ /** * Class with utility methods shared across common object oriented languages. + * Specifically, most of this stuff is for C++/Java. * * @author Mark Slee */ class t_oop_generator : public t_generator { public: - /** Scoping */ + /** + * Scoping, using curly braces! + */ void scope_up(std::ostream& out) { indent(out) << "{" << std::endl; @@ -25,7 +28,8 @@ class t_oop_generator : public t_generator { } /** - * Generates a comment about this code being autogenerated. + * Generates a comment about this code being autogenerated, using C++ style + * comments, which are also fair game in Java / PHP, yay! * * @return C-style comment mentioning that this file is autogenerated. */ diff --git a/compiler/cpp/src/generate/t_php_generator.cc b/compiler/cpp/src/generate/t_php_generator.cc index 3507a702..61df5898 100644 --- a/compiler/cpp/src/generate/t_php_generator.cc +++ b/compiler/cpp/src/generate/t_php_generator.cc @@ -34,7 +34,7 @@ string t_php_generator::php_includes() { } /** - * Does nothing in PHP + * Close up (or down) some filez. */ void t_php_generator::close_generator(t_program *tprogram) { // Close types file @@ -101,6 +101,9 @@ void t_php_generator::generate_enum(t_enum* tenum) { f_types_ << "}" << endl << endl; } +/** + * Make a struct + */ void t_php_generator::generate_struct(t_struct* tstruct) { generate_php_struct(tstruct, false); } @@ -115,6 +118,9 @@ void t_php_generator::generate_xception(t_struct* txception) { generate_php_struct(txception, true); } +/** + * Structs can be normal or exceptions. + */ void t_php_generator::generate_php_struct(t_struct* tstruct, bool is_exception) { generate_php_struct_definition(f_types_, tstruct, is_exception); @@ -143,10 +149,6 @@ void t_php_generator::generate_php_struct_definition(ofstream& out, indent_up(); for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { - // This fills in default values, as opposed to nulls - //indent(out) << - //"public " << declare_field(*m_iter, true) << endl; - indent(out) << "public $" << (*m_iter)->get_name() << " = null;" << endl; } @@ -162,13 +164,21 @@ void t_php_generator::generate_php_struct_definition(ofstream& out, endl; } +/** + * Generates the read() method for a struct + */ void t_php_generator::generate_php_struct_reader(ofstream& out, t_struct* tstruct) { const vector& fields = tstruct->get_members(); vector::const_iterator f_iter; - indent(out) << - "public function read($iprot, $itrans) " << endl; + if (binary_inline_) { + indent(out) << + "public function read($itrans) " << endl; + } else { + indent(out) << + "public function read($iprot, $itrans) " << endl; + } scope_up(out); out << @@ -231,10 +241,13 @@ void t_php_generator::generate_php_struct_reader(ofstream& out, } // In the default case we skip the field - out << - indent() << "default:" << endl << - indent() << " $xfer += $iprot->skip($itrans, $ftype);" << endl << - indent() << " break;" << endl; + indent(out) << "default:" << endl; + if (binary_inline_) { + indent(out) << " $xfer += TProtocol::skipBinary($itrans, $ftype);" << endl; + } else { + indent(out) << " $xfer += $iprot->skip($itrans, $ftype);" << endl; + } + indent(out) << " break;" << endl; scope_down(out); @@ -260,6 +273,9 @@ void t_php_generator::generate_php_struct_reader(ofstream& out, endl; } +/** + * Generates the write() method for a struct + */ void t_php_generator::generate_php_struct_writer(ofstream& out, t_struct* tstruct) { string name = tstruct->get_name(); @@ -283,7 +299,11 @@ void t_php_generator::generate_php_struct_writer(ofstream& out, "$xfer += $oprot->writeStructBegin($otrans, '" << name << "');" << endl; } - for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + out << + indent() << "if ($this->" << (*f_iter)->get_name() << " !== null) {" << endl; + indent_up(); + // Write field header if (binary_inline_) { out << @@ -305,13 +325,16 @@ void t_php_generator::generate_php_struct_writer(ofstream& out, indent(out) << "$xfer += $oprot->writeFieldEnd($otrans);" << endl; } + + indent_down(); + indent(out) << + "}" << endl; } if (binary_inline_) { out << indent() << "$_output .= pack('c', TType::STOP);" << endl; } else { - // Write the struct map out << indent() << "$xfer += $oprot->writeFieldStop($otrans);" << endl << indent() << "$xfer += $oprot->writeStructEnd($otrans);" << endl; @@ -347,13 +370,210 @@ void t_php_generator::generate_service(t_service* tservice) { generate_service_interface(tservice); generate_service_client(tservice); generate_service_helpers(tservice); - // generate_service_server(tservice); + generate_service_processor(tservice); // Close service file f_service_ << "?>" << endl; f_service_.close(); } +/** + * Generates a service server definition. + * + * @param tservice The service to generate a server for. + */ +void t_php_generator::generate_service_processor(t_service* tservice) { + // Generate the dispatch methods + vector functions = tservice->get_functions(); + vector::iterator f_iter; + + // Generate the header portion + f_service_ << + "class " << service_name_ << "Processor {" << endl; + indent_up(); + + f_service_ << + indent() << "private $_handler = null;" << endl; + if (!binary_inline_) { + f_service_ << + indent() << "private $_iprot = null;" << endl << + indent() << "private $_oprot = null;" << endl << + endl; + } + + if (binary_inline_) { + f_service_ << + indent() << "public function __construct($handler) {" << endl << + indent() << " $this->_handler = $handler;" << endl << + indent() << "}" << endl << + endl; + } else { + f_service_ << + indent() << "public function __construct($handler, $iprot, $oprot=null) {" << endl << + indent() << " $this->_handler = $handler;" << endl << + indent() << " $this->_iprot = $iprot;" << endl << + indent() << " $this->_oprot = $oprot ? $oprot : $iprot;" << endl << + indent() << "}" << endl << + endl; + } + + // Generate the server implementation + indent(f_service_) << + "public function process($itrans, $otrans) {" << endl; + indent_up(); + + f_service_ << + indent() << "$rseqid = 0;" << endl << + indent() << "$fname = null;" << endl << + indent() << "$mtype = 0;" << endl << + endl; + + if (binary_inline_) { + t_field ffname(g_program->get_string_type(), "fname"); + t_field fmtype(g_program->get_byte_type(), "mtype"); + t_field fseqid(g_program->get_i32_type(), "rseqid"); + generate_deserialize_field(f_service_, &ffname, "", true); + generate_deserialize_field(f_service_, &fmtype, "", true); + generate_deserialize_field(f_service_, &fseqid, "", true); + } else { + f_service_ << + indent() << "$this->_iprot->readMessageBegin($itrans, $fname, $mtype, $rseqid);" << endl; + } + + // TODO(mcslee): validate message + + // HOT: check for method implementation + f_service_ << + indent() << "$methodname = 'process_'.$fname;" << endl << + indent() << "if (!method_exists($this, $methodname)) {" << endl << + indent() << " throw new Exception('Function '.$fname.' not implemented.');" << endl << + indent() << "}" << endl << + indent() << "$this->$methodname($rseqid, $itrans, $otrans);" << endl; + indent_down(); + f_service_ << + indent() << "}" << endl << + endl; + + // Generate the process subfunctions + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { + generate_process_function(tservice, *f_iter); + } + + indent_down(); + f_service_ << "}" << endl; +} + +/** + * Generates a process function definition. + * + * @param tfunction The function to write a dispatcher for + */ +void t_php_generator::generate_process_function(t_service* tservice, + t_function* tfunction) { + // Open function + indent(f_service_) << + "private function process_" << tfunction->get_name() << + "($seqid, $itrans, $otrans) {" << endl; + indent_up(); + + string argsname = service_name_ + "_" + tfunction->get_name() + "_args"; + string resultname = service_name_ + "_" + tfunction->get_name() + "_result"; + + f_service_ << + indent() << "$__args = new " << argsname << "();" << endl; + if (binary_inline_) { + f_service_ << + indent() << "$__args->read($itrans);" << endl; + } else { + f_service_ << + indent() << "$__args->read($this->_iprot, $itrans);" << endl << + indent() << "$this->_iprot->readMessageEnd($itrans);" << endl; + } + + t_struct* xs = tfunction->get_xceptions(); + const std::vector& xceptions = xs->get_members(); + vector::const_iterator x_iter; + + // Declare result for non async function + if (!tfunction->is_async()) { + f_service_ << + indent() << "$__result = new " << resultname << "();" << endl; + } + + // Try block for a function with exceptions + if (xceptions.size() > 0) { + f_service_ << + indent() << "try {" << endl; + indent_up(); + } + + // Generate the function call + t_struct* arg_struct = tfunction->get_arglist(); + const std::vector& fields = arg_struct->get_members(); + vector::const_iterator f_iter; + + f_service_ << indent(); + if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) { + f_service_ << "$__result->success = "; + } + f_service_ << + "$this->_handler->" << tfunction->get_name() << "("; + bool first = true; + for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { + if (first) { + first = false; + } else { + f_service_ << ", "; + } + 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() << "} catch (" << (*x_iter)->get_type()->get_name() << " $" << (*x_iter)->get_name() << ") {" << endl; + if (!tfunction->is_async()) { + indent_up(); + f_service_ << + indent() << "$__result->" << (*x_iter)->get_name() << " = $" << (*x_iter)->get_name() << ";" << endl; + indent_down(); + f_service_ << indent(); + } + } + f_service_ << "}" << endl; + } + + // Shortcut out here for async functions + if (tfunction->is_async()) { + f_service_ << + indent() << "return;" << endl; + indent_down(); + f_service_ << endl; + return; + } + + // Serialize the request header + if (binary_inline_) { + f_service_ << + indent() << "$_output = '';" << endl << + indent() << "$_output .= pack('N', strlen('" << tfunction->get_name() << "'));" << endl << + indent() << "$_output .= '" << tfunction->get_name() << "';" << endl << + indent() << "$_output .= pack('cN', TMessageType::REPLY, $seqid);" << endl; + } else { + f_service_ << + indent() << "$this->_oprot->writeMessageBegin($otrans, '" << tfunction->get_name() << "', TMessageType::REPLY, $seqid);" << endl << + indent() << "$__result->write($this->_oprot, $otrans);" << endl << + indent() << "$otrans->flush();" << endl; + } + + // Close function + indent_down(); + f_service_ << + indent() << "}" << endl; +} + /** * Generates helper functions for a service. * @@ -592,8 +812,14 @@ void t_php_generator::generate_service_client(t_service* tservice) { // TODO(mcslee): Validate message reply here f_service_ << - indent() << "$__result = new " << resultname << "();" << endl << - indent() << "$__result->read($this->_iprot, $this->_otrans);" << endl; + indent() << "$__result = new " << resultname << "();" << endl; + if (binary_inline_) { + f_service_ << + indent() << "$__result->read($this->_otrans);" << endl; + } else { + f_service_ << + indent() << "$__result->read($this->_iprot, $this->_otrans);" << endl; + } if (!binary_inline_) { f_service_ << @@ -786,7 +1012,7 @@ void t_php_generator::generate_deserialize_field(ofstream &out, } else { printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", - tfield->get_name().c_str(), type_name(type).c_str()); + tfield->get_name().c_str(), type->get_name().c_str()); } } @@ -800,8 +1026,14 @@ void t_php_generator::generate_deserialize_struct(ofstream &out, t_struct* tstruct, string prefix) { out << - indent() << "$" << prefix << " = new " << tstruct->get_name() << "();" << endl << - indent() << "$xfer += $" << prefix << "->read($iprot, $itrans);" << endl; + indent() << "$" << prefix << " = new " << tstruct->get_name() << "();" << endl; + if (binary_inline_) { + out << + indent() << "$xfer += $" << prefix << "->read($itrans);" << endl; + } else { + out << + indent() << "$xfer += $" << prefix << "->read($iprot, $itrans);" << endl; + } } void t_php_generator::generate_deserialize_container(ofstream &out, @@ -1067,7 +1299,7 @@ void t_php_generator::generate_serialize_field(ofstream &out, printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n", prefix.c_str(), tfield->get_name().c_str(), - type_name(type).c_str()); + type->get_name().c_str()); } } @@ -1089,6 +1321,9 @@ void t_php_generator::generate_serialize_struct(ofstream &out, } } +/** + * Writes out a container + */ void t_php_generator::generate_serialize_container(ofstream &out, t_type* ttype, string prefix) { @@ -1213,65 +1448,6 @@ void t_php_generator::generate_serialize_list_element(ofstream &out, generate_serialize_field(out, &efield, ""); } -/** - * Returns a Java type name - * - * @param ttype The type - */ -string t_php_generator::type_name(t_type* ttype) { - // In Java typedefs are just resolved to their real type - while (ttype->is_typedef()) { - ttype = ((t_typedef*)ttype)->get_type(); - } - - if (ttype->is_base_type()) { - return base_type_name(((t_base_type*)ttype)->get_base()); - } else if (ttype->is_enum()) { - return "Int32"; - } else if (ttype->is_map()) { - t_map* tmap = (t_map*) ttype; - return "HashMap<" + - type_name(tmap->get_key_type()) + "," + - type_name(tmap->get_val_type()) + ">"; - } else if (ttype->is_set()) { - t_set* tset = (t_set*) ttype; - return "HashSet<" + type_name(tset->get_elem_type()) + ">"; - } else if (ttype->is_list()) { - t_list* tlist = (t_list*) ttype; - return "ArrayList<" + type_name(tlist->get_elem_type()) + ">"; - } else { - return ttype->get_name(); - } -} - -/** - * Returns the C++ type that corresponds to the thrift type. - * - * @param tbase The base type - */ -string t_php_generator::base_type_name(t_base_type::t_base tbase) { - switch (tbase) { - case t_base_type::TYPE_VOID: - return "void"; - case t_base_type::TYPE_STRING: - return "TString"; - case t_base_type::TYPE_BOOL: - return "bool"; - case t_base_type::TYPE_BYTE: - return "UInt8"; - case t_base_type::TYPE_I16: - return "Int16"; - case t_base_type::TYPE_I32: - return "Int32"; - case t_base_type::TYPE_I64: - return "Int64"; - case t_base_type::TYPE_DOUBLE: - return "Double"; - default: - throw "compiler error: no PHP name for base type " + tbase; - } -} - /** * Declares a field, which may include initialization as necessary. * diff --git a/compiler/cpp/src/generate/t_php_generator.h b/compiler/cpp/src/generate/t_php_generator.h index 0cc837ff..0e6869b9 100644 --- a/compiler/cpp/src/generate/t_php_generator.h +++ b/compiler/cpp/src/generate/t_php_generator.h @@ -9,7 +9,7 @@ #include "t_oop_generator.h" /** - * Java code generator. + * PHP code generator. * * @author Mark Slee */ @@ -24,14 +24,16 @@ class t_php_generator : public t_oop_generator { } } - ~t_php_generator() {} - - /** Init and close methods */ + /** + * Init and close methods + */ void init_generator(t_program *tprogram); void close_generator(t_program *tprogram); - /** Program-level generation functions */ + /** + * Program-level generation functions + */ void generate_typedef (t_typedef* ttypedef); void generate_enum (t_enum* tenum); @@ -39,21 +41,29 @@ class t_php_generator : public t_oop_generator { void generate_xception (t_struct* txception); void generate_service (t_service* tservice); + /** + * Structs! + */ void generate_php_struct(t_struct* tstruct, bool is_exception); void generate_php_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false); void generate_php_struct_reader(std::ofstream& out, t_struct* tstruct); void generate_php_struct_writer(std::ofstream& out, t_struct* tstruct); + void generate_php_function_helpers(t_function* tfunction); - void generate_php_function_helpers (t_function* tfunction); - - /** Service-level generation functions */ + /** + * Service-level generation functions + */ - void generate_service_helpers(t_service* tservice); + void generate_service_helpers (t_service* tservice); void generate_service_interface (t_service* tservice); void generate_service_client (t_service* tservice); + void generate_service_processor (t_service* tservice); + void generate_process_function (t_service* tservice, t_function* tfunction); - /** Serialization constructs */ + /** + * Serialization constructs + */ void generate_deserialize_field (std::ofstream &out, t_field* tfield, @@ -105,11 +115,11 @@ class t_php_generator : public t_oop_generator { t_list* tlist, std::string iter); - /** Helper rendering functions */ + /** + * Helper rendering functions + */ std::string php_includes(); - std::string type_name(t_type* ttype); - std::string base_type_name(t_base_type::t_base tbase); std::string declare_field(t_field* tfield, bool init=false, bool obj=false); std::string function_signature(t_function* tfunction, std::string prefix=""); std::string argument_list(t_struct* tstruct); @@ -117,15 +127,21 @@ class t_php_generator : public t_oop_generator { private: - /** File streams */ + /** + * Output directory + */ char* T_PHP_DIR; + /** + * File streams + */ std::ofstream f_types_; std::ofstream f_helpers_; std::ofstream f_service_; - /** Generate protocol-independent template? Or Binary inline code? */ - + /** + * Generate protocol-independent template? Or Binary inline code? + */ bool binary_inline_; }; diff --git a/compiler/cpp/src/generate/t_py_generator.cc b/compiler/cpp/src/generate/t_py_generator.cc index b666e512..9838df61 100644 --- a/compiler/cpp/src/generate/t_py_generator.cc +++ b/compiler/cpp/src/generate/t_py_generator.cc @@ -40,7 +40,7 @@ string t_py_generator::py_autogen_comment() { } /** - * Prints standard java imports + * Prints standard thrift imports */ string t_py_generator::py_imports() { return @@ -48,7 +48,7 @@ string t_py_generator::py_imports() { } /** - * Does nothing in Python + * Closes the type files */ void t_py_generator::close_generator(t_program *tprogram) { // Close types file @@ -63,8 +63,8 @@ void t_py_generator::close_generator(t_program *tprogram) { void t_py_generator::generate_typedef(t_typedef* ttypedef) {} /** - * Generates code for an enumerated type. Since define is expensive to lookup - * in PHP, we use a global array for this. + * Generates code for an enumerated type. Done using a class to scope + * the values. * * @param tenum The enumeration */ @@ -91,6 +91,9 @@ void t_py_generator::generate_enum(t_enum* tenum) { f_types_ << endl; } +/** + * Generates a python struct + */ void t_py_generator::generate_struct(t_struct* tstruct) { generate_py_struct(tstruct, false); } @@ -105,6 +108,9 @@ void t_py_generator::generate_xception(t_struct* txception) { generate_py_struct(txception, true); } +/** + * Generates a python struct + */ void t_py_generator::generate_py_struct(t_struct* tstruct, bool is_exception) { generate_py_struct_definition(f_types_, tstruct, is_exception); @@ -160,12 +166,10 @@ void t_py_generator::generate_py_struct_definition(ofstream& out, out << endl; generate_py_struct_reader(out, tstruct); - if (is_result) { - generate_py_struct_result_writer(out, tstruct); - } else { - generate_py_struct_writer(out, tstruct); - } + generate_py_struct_writer(out, tstruct); + // Printing utilities so that on the command line thrift + // structs look pretty like dictionaries out << indent() << "def __str__(self): " << endl << indent() << " return str(self.__dict__)" << endl << @@ -177,6 +181,9 @@ void t_py_generator::generate_py_struct_definition(ofstream& out, indent_down(); } +/** + * Generates the read method for a struct + */ void t_py_generator::generate_py_struct_reader(ofstream& out, t_struct* tstruct) { const vector& fields = tstruct->get_members(); @@ -253,45 +260,6 @@ void t_py_generator::generate_py_struct_writer(ofstream& out, "def write(self, oprot, otrans):" << endl; indent_up(); - indent(out) << - "oprot.writeStructBegin(otrans, '" << name << "')" << endl; - - for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { - // Write field header - indent(out) << - "oprot.writeFieldBegin(otrans, " << - "'" << (*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."); - - // Write field closer - indent(out) << - "oprot.writeFieldEnd(otrans)" << endl; - } - - // Write the struct map - out << - indent() << "oprot.writeFieldStop(otrans)" << endl << - indent() << "oprot.writeStructEnd(otrans)" << endl; - - indent_down(); - out << - endl; -} - -void t_py_generator::generate_py_struct_result_writer(ofstream& out, - t_struct* tstruct) { - string name = tstruct->get_name(); - const vector& fields = tstruct->get_members(); - vector::const_iterator f_iter; - - indent(out) << - "def write(self, oprot, otrans):" << endl; - indent_up(); - indent(out) << "oprot.writeStructBegin(otrans, '" << name << "')" << endl; @@ -393,7 +361,6 @@ void t_py_generator::generate_py_function_helpers(t_function* tfunction) { for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { result.append(*f_iter); } - generate_py_struct_definition(f_service_, &result, false, true); } @@ -525,7 +492,7 @@ void t_py_generator::generate_service_client(t_service* tservice) { f_service_ << indent() << "(fname, mtype, rseqid) = self.__iprot.readMessageBegin(self.__itrans)" << endl; - // TODO(mcslee): Validate message reply here + // TODO(mcslee): Validate message reply here, seq ids etc. f_service_ << indent() << "__result = " << resultname << "()" << endl << @@ -560,8 +527,7 @@ void t_py_generator::generate_service_client(t_service* tservice) { // Close function indent_down(); - f_service_ << endl; - + f_service_ << endl; } indent_down(); @@ -695,7 +661,7 @@ void t_py_generator::generate_service_remote(t_service* tservice) { // Close service file f_remote.close(); - // Make file executable + // Make file executable, love that bitwise OR action chmod(f_remote_name.c_str(), S_IRUSR | S_IWUSR | @@ -752,34 +718,12 @@ void t_py_generator::generate_service_server(t_service* tservice) { // TODO(mcslee): validate message - // HOT: dictionary lookup + // HOT: dictionary function lookup f_service_ << indent() << "if name not in self.__processMap:" << endl << indent() << " print 'Unknown function %s' % (name)" << endl << indent() << "else:" << endl << indent() << " self.__processMap[name](self, seqid, itrans, otrans)" << endl; - // DEPRECATED: if else if bullshit - /* - bool first = true; - for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { - if (!first) { - f_service_ << indent() << "el"; - } else { - f_service_ << indent(); - first = false; - } - f_service_ << - "if name == \"" << (*f_iter)->get_name() << "\":" << endl; - indent_up(); - indent(f_service_) << - "self.process_" << (*f_iter)->get_name() << "(seqid, itrans, otrans)" << endl; - indent_down(); - } - f_service_ << - indent() << "else:" << endl << - indent() << " print 'Unknown function %s' % (name)" << endl; - f_service_ << endl; - */ // Read end of args field, the T_STOP, and the struct close f_service_ << @@ -961,15 +905,12 @@ void t_py_generator::generate_deserialize_field(ofstream &out, } else { printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", - tfield->get_name().c_str(), type_name(type).c_str()); + tfield->get_name().c_str(), type->get_name().c_str()); } } /** - * Generates an unserializer for a variable. This makes two key assumptions, - * first that there is a const char* variable named data that points to the - * buffer for deserialization, and that there is a variable protocol which - * is a reference to a TProtocol serialization object. + * Generates an unserializer for a struct, calling read() */ void t_py_generator::generate_deserialize_struct(ofstream &out, t_struct* tstruct, @@ -979,6 +920,10 @@ void t_py_generator::generate_deserialize_struct(ofstream &out, indent() << prefix << ".read(iprot, itrans)" << endl; } +/** + * Serialize a container by writing out the header followed by + * data and then a footer. + */ void t_py_generator::generate_deserialize_container(ofstream &out, t_type* ttype, string prefix) { @@ -1060,34 +1005,30 @@ void t_py_generator::generate_deserialize_map_element(ofstream &out, prefix << "[" << key << "] = " << val << endl; } +/** + * Write a set element + */ void t_py_generator::generate_deserialize_set_element(ofstream &out, t_set* tset, string prefix) { string elem = tmp("_elem"); t_field felem(tset->get_elem_type(), elem); - /* - indent(out) << - "$" << elem << " = null;" << endl; - */ - generate_deserialize_field(out, &felem); indent(out) << prefix << ".append(" << elem << ")" << endl; } +/** + * Write a list element + */ void t_py_generator::generate_deserialize_list_element(ofstream &out, t_list* tlist, string prefix) { string elem = tmp("_elem"); t_field felem(tlist->get_elem_type(), elem); - /* - indent(out) << - "$" << elem << " = null;" << endl; - */ - generate_deserialize_field(out, &felem); indent(out) << @@ -1169,7 +1110,7 @@ void t_py_generator::generate_serialize_field(ofstream &out, printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n", prefix.c_str(), tfield->get_name().c_str(), - type_name(type).c_str()); + type->get_name().c_str()); } } @@ -1180,15 +1121,15 @@ void t_py_generator::generate_serialize_field(ofstream &out, * @param prefix String prefix to attach to all fields */ void t_py_generator::generate_serialize_struct(ofstream &out, - t_struct* tstruct, - string prefix) { + t_struct* tstruct, + string prefix) { indent(out) << prefix << ".write(oprot, otrans)" << endl; } void t_py_generator::generate_serialize_container(ofstream &out, - t_type* ttype, - string prefix) { + t_type* ttype, + string prefix) { if (ttype->is_map()) { indent(out) << "oprot.writeMapBegin(otrans, " << @@ -1207,31 +1148,30 @@ void t_py_generator::generate_serialize_container(ofstream &out, "len(" << prefix << "))" << endl; } - if (ttype->is_map()) { - string kiter = tmp("_kiter"); - string viter = tmp("_viter"); - indent(out) << - "for " << kiter << "," << viter << " in " << prefix << ":" << endl; - indent_up(); - generate_serialize_map_element(out, (t_map*)ttype, kiter, viter); - indent_down(); - } else if (ttype->is_set()) { - string iter = tmp("_iter"); - indent(out) << - "for " << iter << " in " << prefix << ":" << endl; - indent_up(); - generate_serialize_set_element(out, (t_set*)ttype, iter); - indent_down(); - } else if (ttype->is_list()) { - string iter = tmp("_iter"); - indent(out) << - "for " << iter << " in " << prefix << ":" << endl; - indent_up(); - generate_serialize_list_element(out, (t_list*)ttype, iter); - indent_down(); - } + if (ttype->is_map()) { + string kiter = tmp("_kiter"); + string viter = tmp("_viter"); + indent(out) << + "for " << kiter << "," << viter << " in " << prefix << ":" << endl; + indent_up(); + generate_serialize_map_element(out, (t_map*)ttype, kiter, viter); + indent_down(); + } else if (ttype->is_set()) { + string iter = tmp("_iter"); + indent(out) << + "for " << iter << " in " << prefix << ":" << endl; + indent_up(); + generate_serialize_set_element(out, (t_set*)ttype, iter); + indent_down(); + } else if (ttype->is_list()) { + string iter = tmp("_iter"); + indent(out) << + "for " << iter << " in " << prefix << ":" << endl; + indent_up(); + generate_serialize_list_element(out, (t_list*)ttype, iter); + indent_down(); + } - if (ttype->is_map()) { indent(out) << "oprot.writeMapEnd(otrans)" << endl; @@ -1279,65 +1219,6 @@ void t_py_generator::generate_serialize_list_element(ofstream &out, generate_serialize_field(out, &efield, ""); } -/** - * Returns a Java type name - * - * @param ttype The type - */ -string t_py_generator::type_name(t_type* ttype) { - // In Java typedefs are just resolved to their real type - while (ttype->is_typedef()) { - ttype = ((t_typedef*)ttype)->get_type(); - } - - if (ttype->is_base_type()) { - return base_type_name(((t_base_type*)ttype)->get_base()); - } else if (ttype->is_enum()) { - return "int"; - } else if (ttype->is_map()) { - t_map* tmap = (t_map*) ttype; - return "map<" + - type_name(tmap->get_key_type()) + "," + - type_name(tmap->get_val_type()) + ">"; - } else if (ttype->is_set()) { - t_set* tset = (t_set*) ttype; - return "set<" + type_name(tset->get_elem_type()) + ">"; - } else if (ttype->is_list()) { - t_list* tlist = (t_list*) ttype; - return "list<" + type_name(tlist->get_elem_type()) + ">"; - } else { - return ttype->get_name(); - } -} - -/** - * Returns the C++ type that corresponds to the thrift type. - * - * @param tbase The base type - */ -string t_py_generator::base_type_name(t_base_type::t_base tbase) { - switch (tbase) { - case t_base_type::TYPE_VOID: - return "void"; - case t_base_type::TYPE_STRING: - return "TString"; - case t_base_type::TYPE_BOOL: - return "bool"; - case t_base_type::TYPE_BYTE: - return "UInt8"; - case t_base_type::TYPE_I16: - return "Int16"; - case t_base_type::TYPE_I32: - return "Int32"; - case t_base_type::TYPE_I64: - return "Int64"; - case t_base_type::TYPE_DOUBLE: - return "Double"; - default: - throw "compiler error: no PHP name for base type " + tbase; - } -} - /** * Declares a field, which may include initialization as necessary. * @@ -1400,6 +1281,7 @@ string t_py_generator::declare_field(t_field* tfield, bool init, bool obj) { */ string t_py_generator::function_signature(t_function* tfunction, string prefix) { + // TODO(mcslee): Nitpicky, no ',' if argument_list is empty return prefix + tfunction->get_name() + "(self, " + argument_list(tfunction->get_arglist()) + ")"; @@ -1426,7 +1308,7 @@ string t_py_generator::argument_list(t_struct* tstruct) { } /** - * Converts the parse type to a C++ enum string for the given type. + * Converts the parse type to a Python tyoe */ string t_py_generator::type_to_enum(t_type* type) { while (type->is_typedef()) { diff --git a/compiler/cpp/src/generate/t_py_generator.h b/compiler/cpp/src/generate/t_py_generator.h index 2f6c6ceb..238d10ee 100644 --- a/compiler/cpp/src/generate/t_py_generator.h +++ b/compiler/cpp/src/generate/t_py_generator.h @@ -18,14 +18,17 @@ class t_py_generator : public t_oop_generator { public: t_py_generator() {} - ~t_py_generator() {} - /** Init and close methods */ + /** + * Init and close methods + */ void init_generator(t_program *tprogram); void close_generator(t_program *tprogram); - /** Program-level generation functions */ + /** + * Program-level generation functions + */ void generate_typedef (t_typedef* ttypedef); void generate_enum (t_enum* tenum); @@ -33,27 +36,30 @@ class t_py_generator : public t_oop_generator { void generate_xception (t_struct* txception); void generate_service (t_service* tservice); + /** + * Struct generation code + */ void generate_py_struct(t_struct* tstruct, bool is_exception); void generate_py_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false, bool is_result=false); void generate_py_struct_reader(std::ofstream& out, t_struct* tstruct); - void generate_py_struct_result_writer(std::ofstream& out, t_struct* tstruct); void generate_py_struct_writer(std::ofstream& out, t_struct* tstruct); + void generate_py_function_helpers(t_function* tfunction); - void generate_py_function_helpers (t_function* tfunction); - - /** Service-level generation functions */ - - void generate_service_helpers(t_service* tservice); - void generate_service_interface(t_service* tservice); - void generate_service_client(t_service* tservice); - void generate_service_remote(t_service* tservice); - + /** + * Service-level generation functions + */ + void generate_service_helpers (t_service* tservice); + void generate_service_interface (t_service* tservice); + void generate_service_client (t_service* tservice); + void generate_service_remote (t_service* tservice); void generate_service_server (t_service* tservice); void generate_process_function (t_service* tservice, t_function* tfunction); - /** Serialization constructs */ + /** + * Serialization constructs + */ void generate_deserialize_field (std::ofstream &out, t_field* tfield, @@ -105,12 +111,12 @@ class t_py_generator : public t_oop_generator { t_list* tlist, std::string iter); - /** Helper rendering functions */ + /** + * Helper rendering functions + */ std::string py_autogen_comment(); std::string py_imports(); - std::string type_name(t_type* ttype); - std::string base_type_name(t_base_type::t_base tbase); std::string declare_field(t_field* tfield, bool init=false, bool obj=false); std::string function_signature(t_function* tfunction, std::string prefix=""); std::string argument_list(t_struct* tstruct); @@ -118,7 +124,10 @@ class t_py_generator : public t_oop_generator { private: - /** File streams */ + /** + * File streams + */ + std::ofstream f_types_; std::ofstream f_service_; diff --git a/compiler/cpp/src/globals.h b/compiler/cpp/src/globals.h index db7e3925..73855658 100644 --- a/compiler/cpp/src/globals.h +++ b/compiler/cpp/src/globals.h @@ -3,13 +3,20 @@ class t_program; -/** Global variable: the master program parse tree */ +/** + * The master program parse tree. This is accessed from within the parser code + * to build up the program elements. + */ extern t_program* g_program; -/** Global debug state */ +/** + * Global debug state + */ extern int g_debug; -/** Global time string */ +/** + * Global time string, used in formatting error messages etc. + */ extern char* g_time_str; #endif diff --git a/compiler/cpp/src/main.cc b/compiler/cpp/src/main.cc index 5cbf53e3..9a8e29ee 100644 --- a/compiler/cpp/src/main.cc +++ b/compiler/cpp/src/main.cc @@ -3,7 +3,8 @@ * * This file contains the main compiler engine for Thrift, which invokes the * scanner/parser to build the thrift object tree. The interface generation - * code for each language lives in a file by the language name. + * code for each language lives in a file by the language name under the + * generate/ folder, and all parse structures live in parse/ * * @author Mark Slee */ @@ -13,7 +14,7 @@ #include #include -// Careful: must include globals first +// Careful: must include globals first here for extern/global definitions #include "globals.h" #include "main.h" @@ -25,16 +26,21 @@ using namespace std; -/** Global program tree */ +/** + * Global program tree + */ t_program* g_program; -/** Global debug state */ +/** + * Global debug state + */ int g_debug = 0; -/** Global time string */ +/** + * Global time string + */ char* g_time_str; - /** * Report an error to the user. This is called yyerror for historical * reasons (lex and yacc expect the error reporting routine to be called @@ -106,15 +112,17 @@ void usage() { } /** - * Parse it up.. then spit it back out, in pretty much every language + * Parse it up.. then spit it back out, in pretty much every language. Alright + * not that many languages, but the cool ones that we care about. */ int main(int argc, char** argv) { int i; + bool gen_cpp = false; bool gen_java = false; bool gen_py = false; bool gen_php = false; - bool php_inline = false; + bool gen_phpi = false; // Setup time string time_t now = time(NULL); @@ -125,6 +133,7 @@ int main(int argc, char** argv) { usage(); } + // Hacky parameter handling... I didn't feel like using a library sorry! for (i = 1; i < argc-1; i++) { char* arg; arg = strtok(argv[i], " "); @@ -137,10 +146,8 @@ int main(int argc, char** argv) { gen_java = true; } else if (strcmp(arg, "--php") == 0) { gen_php = true; - php_inline = false; } else if (strcmp(arg, "--phpi") == 0) { - gen_php = true; - php_inline = true; + gen_phpi = true; } else if (strcmp(arg, "--py") == 0) { gen_py = true; } else { @@ -153,7 +160,7 @@ int main(int argc, char** argv) { } } - if (!gen_cpp && !gen_java && !gen_php && !gen_py) { + if (!gen_cpp && !gen_java && !gen_php && !gen_phpi && !gen_py) { fprintf(stderr, "!!! No output language(s) specified\n\n"); usage(); } @@ -176,9 +183,10 @@ int main(int argc, char** argv) { name = name.substr(0, dot); } - // Parse it + // Instance of the global parse tree g_program = new t_program(name); + // Parse it! if (yyparse() != 0) { failure("Parser error."); } @@ -198,16 +206,23 @@ int main(int argc, char** argv) { } if (gen_php) { - t_php_generator* php = new t_php_generator(php_inline); + t_php_generator* php = new t_php_generator(false); php->generate_program(g_program); delete php; } + if (gen_phpi) { + t_php_generator* phpi = new t_php_generator(true); + phpi->generate_program(g_program); + delete phpi; + } + if (gen_py) { t_py_generator* py = new t_py_generator(); py->generate_program(g_program); delete py; } + } catch (string s) { printf("Error: %s\n", s.c_str()); } catch (const char* exc) { diff --git a/compiler/cpp/src/main.h b/compiler/cpp/src/main.h index b26142c8..1281cc97 100644 --- a/compiler/cpp/src/main.h +++ b/compiler/cpp/src/main.h @@ -1,17 +1,27 @@ #ifndef T_MAIN_H #define T_MAIN_H -/** Defined in the flex library */ -extern int yylex(void); -extern int yyparse(void); +/** + * Defined in the flex library + */ -/** Expected to be defined by Flex/Bison */ -extern void yyerror(char* fmt, ...); +extern int yylex(void); +extern int yyparse(void); -/** Parse debug output */ -extern void pdebug(char* fmt, ...); +/** + * Expected to be defined by Flex/Bison + */ +extern void yyerror(char* fmt, ...); + +/** + * Parse debugging output, used to print warnings etc. + */ +extern void pdebug(char* fmt, ...); + +/** + * Flex utilities + */ -/** Flex utilities */ extern int yylineno; extern char yytext[]; extern FILE* yyin; diff --git a/compiler/cpp/src/parse/t_base_type.h b/compiler/cpp/src/parse/t_base_type.h index 0e97207a..837caa5e 100644 --- a/compiler/cpp/src/parse/t_base_type.h +++ b/compiler/cpp/src/parse/t_base_type.h @@ -4,7 +4,8 @@ #include "t_type.h" /** - * A thrift base type, which must be one of the defined enumerated types. + * A thrift base type, which must be one of the defined enumerated types inside + * this definition. * * @author Mark Slee */ @@ -25,11 +26,20 @@ class t_base_type : public t_type { }; t_base_type(std::string name, t_base base) : - t_type(name), base_(base) {} + t_type(name), + base_(base) {} - t_base get_base() const { return base_; } - bool is_void() const { return base_ == TYPE_VOID; } - bool is_base_type() const { return true; } + t_base get_base() const { + return base_; + } + + bool is_void() const { + return base_ == TYPE_VOID; + } + + bool is_base_type() const { + return true; + } private: t_base base_; diff --git a/compiler/cpp/src/parse/t_constant.h b/compiler/cpp/src/parse/t_constant.h index 1f3c868e..f502f750 100644 --- a/compiler/cpp/src/parse/t_constant.h +++ b/compiler/cpp/src/parse/t_constant.h @@ -3,19 +3,38 @@ #include +/** + * A constant. These are used inside of enum definitions. Constants are just + * symbol identifiers that may or may not have an explicit value associated + * with them. + * + * @author Mark Slee + */ class t_constant { public: t_constant(std::string name) : - name_(name), has_value_(false), value_(0) {} + name_(name), + has_value_(false), + value_(0) {} t_constant(std::string name, int value) : - name_(name), has_value_(true), value_(value) {} + name_(name), + has_value_(true), + value_(value) {} ~t_constant() {} - const std::string& get_name() { return name_; } - bool has_value() { return has_value_; } - int get_value() { return value_; } + const std::string& get_name() { + return name_; + } + + bool has_value() { + return has_value_; + } + + int get_value() { + return value_; + } private: std::string name_; diff --git a/compiler/cpp/src/parse/t_enum.h b/compiler/cpp/src/parse/t_enum.h index f0891509..4b6fe362 100644 --- a/compiler/cpp/src/parse/t_enum.h +++ b/compiler/cpp/src/parse/t_enum.h @@ -4,16 +4,30 @@ #include "t_constant.h" #include +/** + * An enumerated type. A list of t_constant objects with a name for the type. + * + * @author Mark Slee + */ class t_enum : public t_type { public: t_enum() {} - ~t_enum() {} - void set_name(std::string name) { name_ = name; } - void append(t_constant* constant) { constants_.push_back(constant); } + void set_name(std::string name) { + name_ = name; + } + + void append(t_constant* constant) { + constants_.push_back(constant); + } - const std::vector& get_constants() { return constants_; } - bool is_enum() const { return true; } + const std::vector& get_constants() { + return constants_; + } + + bool is_enum() const { + return true; + } private: std::vector constants_; diff --git a/compiler/cpp/src/parse/t_field.h b/compiler/cpp/src/parse/t_field.h index 7f4d0e97..93e14d84 100644 --- a/compiler/cpp/src/parse/t_field.h +++ b/compiler/cpp/src/parse/t_field.h @@ -4,24 +4,36 @@ #include /** - * Class to represent a field in a thrift structure or in a set of arguments - * to a thrift function. + * Class to represent a field in a thrift structure. A field has a data type, + * a symbolic name, and a numeric identifier. * * @author Mark Slee */ class t_field { public: t_field(t_type* type, std::string name) : - type_(type), name_(name), key_(0) {} + type_(type), + name_(name), + key_(0) {} t_field(t_type* type, std::string name, int32_t key) : - type_(type), name_(name), key_(key) {} + type_(type), + name_(name), + key_(key) {} ~t_field() {} - t_type* get_type() const { return type_; } - const std::string& get_name() const { return name_; } - int32_t get_key() const { return key_; } + t_type* get_type() const { + return type_; + } + + const std::string& get_name() const { + return name_; + } + + int32_t get_key() const { + return key_; + } private: t_type* type_; diff --git a/compiler/cpp/src/parse/t_function.h b/compiler/cpp/src/parse/t_function.h index 58667d89..3d071711 100644 --- a/compiler/cpp/src/parse/t_function.h +++ b/compiler/cpp/src/parse/t_function.h @@ -6,8 +6,9 @@ #include "t_struct.h" /** - * Representation of a function. Key parst are return type, function name, - * optional modifiers, and an argument list. + * Representation of a function. Key parts are return type, function name, + * optional modifiers, and an argument list, which is implemented as a thrift + * struct. * * @author Mark Slee */ @@ -24,7 +25,6 @@ class t_function { xceptions_ = new t_struct; } - t_function(t_type* returntype, std::string name, t_struct* arglist, @@ -38,11 +38,25 @@ class t_function { ~t_function() {} - t_type* get_returntype() const { return returntype_; } - const std::string& get_name() const { return name_; } - t_struct* get_arglist() const { return arglist_; } - t_struct* get_xceptions() const { return xceptions_; } - bool is_async() const { return async_; } + t_type* get_returntype() const { + return returntype_; + } + + const std::string& get_name() const { + return name_; + } + + t_struct* get_arglist() const { + return arglist_; + } + + t_struct* get_xceptions() const { + return xceptions_; + } + + bool is_async() const { + return async_; + } private: t_type* returntype_; diff --git a/compiler/cpp/src/parse/t_list.h b/compiler/cpp/src/parse/t_list.h index 65874ccc..5f9b5aa4 100644 --- a/compiler/cpp/src/parse/t_list.h +++ b/compiler/cpp/src/parse/t_list.h @@ -3,13 +3,23 @@ #include "t_type.h" +/** + * A list is a lightweight container type that just wraps another data type. + * + * @author Mark Slee + */ class t_list : public t_type { public: - t_list(t_type* elem_type) : elem_type_(elem_type) {} - ~t_list() {} + t_list(t_type* elem_type) : + elem_type_(elem_type) {} - t_type* get_elem_type() const { return elem_type_; } - bool is_list() const { return true; } + t_type* get_elem_type() const { + return elem_type_; + } + + bool is_list() const { + return true; + } private: t_type* elem_type_; diff --git a/compiler/cpp/src/parse/t_map.h b/compiler/cpp/src/parse/t_map.h index 1f61843f..ff1c5692 100644 --- a/compiler/cpp/src/parse/t_map.h +++ b/compiler/cpp/src/parse/t_map.h @@ -1,15 +1,29 @@ #ifndef T_MAP_H #define T_MAP_H +/** + * A map is a lightweight container type that just wraps another two data + * types. + * + * @author Mark Slee + */ class t_map : public t_type { public: t_map(t_type* key_type, t_type* val_type) : - key_type_(key_type), val_type_(val_type) {} - ~t_map() {} + key_type_(key_type), + val_type_(val_type) {} - t_type* get_key_type() const { return key_type_; } - t_type* get_val_type() const { return val_type_; } - bool is_map() const { return true; } + t_type* get_key_type() const { + return key_type_; + } + + t_type* get_val_type() const { + return val_type_; + } + + bool is_map() const { + return true; + } private: t_type* key_type_; diff --git a/compiler/cpp/src/parse/t_program.h b/compiler/cpp/src/parse/t_program.h index 74b9360e..5e586540 100644 --- a/compiler/cpp/src/parse/t_program.h +++ b/compiler/cpp/src/parse/t_program.h @@ -24,12 +24,15 @@ * Exceptions * Services * + * The program module also contains the definitions of the base types. + * * @author Mark Slee */ class t_program { public: t_program(std::string name) : - name_(name), namespace_() { + name_(name), + namespace_() { type_void = new t_base_type("void", t_base_type::TYPE_VOID); type_string = new t_base_type("string", t_base_type::TYPE_STRING); type_bool = new t_base_type("bool", t_base_type::TYPE_BOOL); @@ -51,10 +54,14 @@ class t_program { } // Name accessor - const std::string& get_name() const { return name_; } + const std::string& get_name() const { + return name_; + } // Namespace - const std::string& get_namespace() const { return namespace_; } + const std::string& get_namespace() const { + return namespace_; + } // Accessors for program elements const std::vector& get_typedefs() const { return typedefs_; } @@ -79,6 +86,7 @@ class t_program { } // New program element addition + void set_namespace(std::string name) { namespace_ = name; } @@ -87,23 +95,28 @@ class t_program { typedefs_.push_back(td); add_custom_type(td->get_symbolic(), td); } + void add_enum(t_enum* te) { enums_.push_back(te); add_custom_type(te->get_name(), te); } + void add_struct(t_struct* ts) { structs_.push_back(ts); add_custom_type(ts->get_name(), ts); } + void add_xception(t_struct* tx) { xceptions_.push_back(tx); add_custom_type(tx->get_name(), tx); } + void add_service(t_service* ts) { services_.push_back(ts); } private: + // Add custom type for lookup void add_custom_type(std::string name, t_type* type) { custom_types_[name] = type; diff --git a/compiler/cpp/src/parse/t_service.h b/compiler/cpp/src/parse/t_service.h index 92e59b2f..6bb5e5d4 100644 --- a/compiler/cpp/src/parse/t_service.h +++ b/compiler/cpp/src/parse/t_service.h @@ -4,16 +4,30 @@ #include "t_function.h" #include +/** + * A service consists of a set of functions. + * + * @author Mark Slee + */ class t_service { public: t_service() {} - ~t_service() {} - void set_name(std::string name) { name_ = name; } - void add_function(t_function* func) { functions_.push_back(func); } + void set_name(std::string name) { + name_ = name; + } - const std::string& get_name() const { return name_; } - const std::vector& get_functions() const { return functions_; } + void add_function(t_function* func) { + functions_.push_back(func); + } + + const std::string& get_name() const { + return name_; + } + + const std::vector& get_functions() const { + return functions_; + } private: std::string name_; diff --git a/compiler/cpp/src/parse/t_set.h b/compiler/cpp/src/parse/t_set.h index 3d34ace7..e39e4202 100644 --- a/compiler/cpp/src/parse/t_set.h +++ b/compiler/cpp/src/parse/t_set.h @@ -3,13 +3,23 @@ #include "t_type.h" +/** + * A set is a lightweight container type that just wraps another data type. + * + * @author Mark Slee + */ class t_set : public t_type { public: - t_set(t_type* elem_type) : elem_type_(elem_type) {} - ~t_set() {} + t_set(t_type* elem_type) : + elem_type_(elem_type) {} - t_type* get_elem_type() const { return elem_type_; } - bool is_set() const { return true; } + t_type* get_elem_type() const { + return elem_type_; + } + + bool is_set() const { + return true; + } private: t_type* elem_type_; diff --git a/compiler/cpp/src/parse/t_struct.h b/compiler/cpp/src/parse/t_struct.h index a365cd44..8768c5f9 100644 --- a/compiler/cpp/src/parse/t_struct.h +++ b/compiler/cpp/src/parse/t_struct.h @@ -7,24 +7,29 @@ #include "t_type.h" #include "t_field.h" +/** + * A struct is a container for a set of member fields that has a name. Structs + * are also used to implement exception types. + * + * @author Mark Slee + */ class t_struct : public t_type { public: - t_struct() : is_xception_(false) {} - t_struct(const std::string& name) : t_type(name), is_xception_(false) {} + t_struct() : + is_xception_(false) {} - ~t_struct() {} + t_struct(const std::string& name) : + t_type(name), + is_xception_(false) {} - /** Set the struct name */ void set_name(const std::string& name) { name_ = name; } - /** Mark as an exception */ void set_xception(bool is_xception) { is_xception_ = is_xception; } - /** Add a new field to the list */ void append(t_field* elem) { members_.push_back(elem); } diff --git a/compiler/cpp/src/parse/t_type.h b/compiler/cpp/src/parse/t_type.h index 6328961e..27b85a56 100644 --- a/compiler/cpp/src/parse/t_type.h +++ b/compiler/cpp/src/parse/t_type.h @@ -4,7 +4,11 @@ #include /** - * Generic representation of a thrift type. + * Generic representation of a thrift type. These objects are used by the + * parser module to build up a tree of object that are all explicitly typed. + * The generic t_type class exports a variety of useful methods that are + * used by the code generator to branch based upon different handling for the + * various types. * * @author Mark Slee */ @@ -24,7 +28,9 @@ class t_type { virtual bool is_set() const { return false; } virtual bool is_map() const { return false; } - bool is_container() const { return is_map() || is_set() || is_list(); } + bool is_container() const { + return is_map() || is_set() || is_list(); + } protected: t_type() {} diff --git a/compiler/cpp/src/parse/t_typedef.h b/compiler/cpp/src/parse/t_typedef.h index 97284be7..8973201c 100644 --- a/compiler/cpp/src/parse/t_typedef.h +++ b/compiler/cpp/src/parse/t_typedef.h @@ -5,26 +5,36 @@ #include "t_type.h" /** - * A typedef is a mapping from a symbolic name to another type. + * A typedef is a mapping from a symbolic name to another type. In dymanically + * typed languages (i.e. php/python) the code generator can actually usually + * ignore typedefs and just use the underlying type directly, though in C++ + * the symbolic naming can be quite useful for code clarity. * * @author Mark Slee */ class t_typedef : public t_type { public: t_typedef(t_type* type, std::string symbolic) : - t_type(symbolic), type_(type), symbolic_(symbolic) {} + t_type(symbolic), + type_(type), + symbolic_(symbolic) {} ~t_typedef() {} - t_type* get_type() const { return type_; } - const std::string& get_symbolic() const { return symbolic_; } - bool is_typedef() const { return true; } + t_type* get_type() const { + return type_; + } + + const std::string& get_symbolic() const { + return symbolic_; + } + + bool is_typedef() const { + return true; + } private: - /** Type that this definition inherits from */ t_type* type_; - - /** Symbolic name for this type */ std::string symbolic_; }; diff --git a/compiler/cpp/src/thrift.l b/compiler/cpp/src/thrift.l index 484e43b1..64a2bf8d 100644 --- a/compiler/cpp/src/thrift.l +++ b/compiler/cpp/src/thrift.l @@ -4,20 +4,29 @@ * Tokenizes a thrift definition file. * @author Mark Slee */ + %{ #include "main.h" #include "parse/t_program.h" -/** Must be included AFTER parse/t_program.h */ +/** + * Must be included AFTER parse/t_program.h, but I can't remember why anymore + * because I wrote this a while ago. + */ #include "thrift.tab.hh" %} -/** Provides yylineno global */ +/** + * Provides the yylineno global, useful for debugging output + */ %option lex-compat -/** Helper definitions */ +/** + * Helper definitions, comments, constants, and whatnot + */ + intconstant ([0-9]+) identifier ([a-zA-Z_][\.a-zA-Z_0-9]*) whitespace ([ \t\r\n]*) @@ -36,31 +45,27 @@ symbol ([\,\{\}\(\)\=<>]) {symbol} { return yytext[0]; } "namespace" { return tok_namespace; } - -"void" { return tok_void; } -"bool" { return tok_bool; } -"byte" { return tok_byte; } -"i16" { return tok_i16; } -"i32" { return tok_i32; } -"i64" { return tok_i64; } -"double" { return tok_double; } -"string" { return tok_string; } - -"map" { return tok_map; } -"list" { return tok_list; } -"set" { return tok_set; } - -"async" { return tok_async; } - -"typedef" { return tok_typedef; } -"struct" { return tok_struct; } -"exception" { return tok_xception; } -"throws" { return tok_throws; } -"service" { return tok_service; } -"enum" { return tok_enum; } - +"void" { return tok_void; } +"bool" { return tok_bool; } +"byte" { return tok_byte; } +"i16" { return tok_i16; } +"i32" { return tok_i32; } +"i64" { return tok_i64; } +"double" { return tok_double; } +"string" { return tok_string; } +"map" { return tok_map; } +"list" { return tok_list; } +"set" { return tok_set; } +"async" { return tok_async; } +"typedef" { return tok_typedef; } +"struct" { return tok_struct; } +"exception" { return tok_xception; } +"throws" { return tok_throws; } +"service" { return tok_service; } +"enum" { return tok_enum; } {intconstant} { yylval.iconst = atoi(yytext); return tok_int_constant; } + {identifier} { yylval.id = strdup(yytext); return tok_identifier; } %% diff --git a/compiler/cpp/src/thrift.y b/compiler/cpp/src/thrift.y index 4b2dde77..404c80b1 100644 --- a/compiler/cpp/src/thrift.y +++ b/compiler/cpp/src/thrift.y @@ -13,10 +13,19 @@ #include "globals.h" #include "parse/t_program.h" +/** + * This global variable is used for automatic numbering of field indices etc. + * when parsing the members of a struct. Field values are automatically + * assigned starting from -1 and working their way down. + */ int y_field_val = -1; %} +/** + * This structure is used by the parser to hold the data types associated with + * various parse nodes. + */ %union { char* id; int iconst; @@ -31,14 +40,25 @@ int y_field_val = -1; t_constant* tconstant; } -/** Strings and constants */ +/** + * Strings identifier + */ %token tok_identifier + +/** + * Integer constant value + */ %token tok_int_constant -/** Namespace */ +/** + * Namespace keyword + */ %token tok_namespace -/** Base datatypes */ +/** + * Base datatype keywords + */ +%token tok_void %token tok_bool %token tok_byte %token tok_string @@ -47,18 +67,21 @@ int y_field_val = -1; %token tok_i64 %token tok_double -/** Complex Types */ +/** + * Complex type keywords + */ %token tok_map %token tok_list %token tok_set -/** Function types */ -%token tok_void - -/** Modifiers */ +/** + * Function modifiers + */ %token tok_async -/** Thrift actions */ +/** + * Thrift language keywords + */ %token tok_typedef %token tok_struct %token tok_xception @@ -66,22 +89,24 @@ int y_field_val = -1; %token tok_service %token tok_enum -/** Types */ +/** + * Grammar nodes + */ + +%type Namespace + %type BaseType %type ContainerType %type MapType %type SetType %type ListType -%type Namespace - %type Typedef %type DefinitionType %type Field %type FieldType %type FieldList -%type ThrowsOptional %type Enum %type EnumDefList @@ -89,18 +114,24 @@ int y_field_val = -1; %type Struct %type Xception - %type Service %type Function %type FunctionType %type FunctionList +%type ThrowsOptional %type AsyncOptional %% -/** Thrift Grammar */ +/** + * Thrift Grammar Implementation. + * + * For the most part this source file works its way top down from what you + * might expect to find in a typical .thrift file, i.e. type definitions and + * namespaces up top followed by service definitions using those types. + */ Program: DefinitionList -- 2.17.1