Baseline commit for thrift, which is pillar v2
Reviewed By: aditya
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@664711 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/src/generate/t_cpp_generator.cc b/compiler/src/generate/t_cpp_generator.cc
new file mode 100644
index 0000000..b328a1a
--- /dev/null
+++ b/compiler/src/generate/t_cpp_generator.cc
@@ -0,0 +1,510 @@
+#include <sys/stat.h>
+#include "t_cpp_generator.h"
+#include "globals.h"
+using namespace std;
+
+/**
+ * Prepares for file generation by opening up the necessary file output
+ * streams.
+ *
+ * @param tprogram The program to generate
+ */
+void t_cpp_generator::init_generator(t_program* tprogram) {
+ // Make output directory
+ mkdir(T_CPP_DIR, S_IREAD | S_IWRITE | S_IEXEC);
+
+ // Make output file
+ string f_types_name = string(T_CPP_DIR)+"/"+tprogram->get_name()+"_types.h";
+ f_types_.open(f_types_name.c_str());
+
+ // Print header
+ f_types_ <<
+ autogen_comment();
+
+ // Start ifndef
+ f_types_ <<
+ "#ifndef thrift_" << tprogram->get_name() << "_types_h" << endl <<
+ "#define thrift_" << tprogram->get_name() << "_types_h" << endl <<
+ endl;
+
+ // Include base types
+ f_types_ <<
+ "#include <sys/types.h>" << endl <<
+ endl;
+}
+
+/**
+ * Closes the output files.
+ */
+void t_cpp_generator::close_generator() {
+ // Close ifndef
+ f_types_ <<
+ "#endif" << endl;
+
+ // Close output file
+ f_types_.close();
+}
+
+
+/**
+ * Generates a typedef. This is just a simple 1-liner in C++
+ *
+ * @param ttypedef The type definition
+ */
+void t_cpp_generator::generate_typedef(t_typedef* ttypedef) {
+ f_types_ <<
+ indent() << "typedef " << type_name(ttypedef->get_type()) << " " <<
+ ttypedef->get_symbolic() << ";" << endl <<
+ endl;
+}
+
+/**
+ * Generates code for an enumerated type. In C++, this is essentially the same
+ * as the thrift definition itself, using the enum keyword in C++.
+ *
+ * @param tenum The enumeration
+ */
+void t_cpp_generator::generate_enum(t_enum* tenum) {
+ f_types_ <<
+ indent() << "enum " << tenum->get_name() << " {" << endl;
+
+ indent_up();
+
+ vector<t_constant*> constants = tenum->get_constants();
+ vector<t_constant*>::iterator c_iter;
+ bool first = true;
+ for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+ if (first) {
+ first = false;
+ } else {
+ f_types_ <<
+ "," << endl;
+ }
+ f_types_ <<
+ indent() << (*c_iter)->get_name();
+ if ((*c_iter)->has_value()) {
+ f_types_ <<
+ " = " << (*c_iter)->get_value();
+ }
+ }
+
+ indent_down();
+
+ f_types_ <<
+ endl <<
+ "};" << endl <<
+ endl;
+}
+
+/**
+ * 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.
+ *
+ * @param tstruct The struct definition
+ */
+void t_cpp_generator::generate_struct(t_struct* tstruct) {
+ f_types_ <<
+ indent() << "struct " << tstruct->get_name() << " {" << endl;
+
+ indent_up();
+
+ const t_list* memberlist = tstruct->get_members();
+ vector<t_field*> members = memberlist->elems();
+ vector<t_field*>::iterator m_iter;
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ f_types_ <<
+ indent() << (*m_iter)->get_type()->get_name() << " " <<
+ (*m_iter)->get_name() << ";" << endl;
+ }
+
+ indent_down();
+
+ f_types_ <<
+ indent() << "};" << endl <<
+ endl;
+}
+
+/**
+ * Generates a thrift service. In C++, this comprises an entirely separate
+ * header and source file. The header file defines the methods and includes
+ * the data types defined in the main header file, and the implementation
+ * file contains implementations of the basic printer and default interfaces.
+ *
+ * @param tservice The service definition
+ */
+void t_cpp_generator::generate_service(t_service* tservice) {
+ // Make output files
+ string f_header_name = string(T_CPP_DIR)+"/"+tservice->get_name()+".h";
+ f_header_.open(f_header_name.c_str());
+ string f_service_name = string(T_CPP_DIR)+"/"+tservice->get_name()+".cc";
+ f_service_.open(f_service_name.c_str());
+
+ // Print header file includes
+ f_header_ << autogen_comment();
+ f_header_ <<
+ "#ifndef " << tservice->get_name() << "_h" << endl <<
+ "#define " << tservice->get_name() << "_h" << endl <<
+ endl <<
+ "#include \"TInterface.h\"" << endl <<
+ "#include \"TDispatcher.h\"" << endl <<
+ "#include \"TProtocol.h\"" << endl <<
+ endl;
+ f_service_ << autogen_comment();
+ f_service_ <<
+ "#include \"" << tservice->get_name() << "_h\"" << endl << endl;
+
+ // Generate the three main parts of the service
+ generate_service_interface(tservice);
+ generate_service_server(tservice);
+ generate_service_client(tservice);
+
+ f_header_ <<
+ "#endif" << endl;
+
+ // Close files
+ f_header_.close();
+ f_service_.close();
+}
+
+/**
+ * Generates a service interface definition.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_cpp_generator::generate_service_interface(t_service* tservice) {
+ f_header_ <<
+ "class " << tservice->get_name() << " : public TInterface {" << endl <<
+ " public: " << endl;
+ indent_up();
+ vector<t_function*> functions = tservice->get_functions();
+ vector<t_function*>::iterator f_iter;
+ for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+ f_header_ <<
+ indent() << "virtual " << function_signature(*f_iter) << " = 0;" << endl;
+ }
+ f_header_ <<
+ indent() << "virtual ~" << tservice->get_name() << "() = 0;" << endl;
+ indent_down();
+ f_header_ <<
+ "}; " << endl << endl;
+}
+
+/**
+ * Generates a service server definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_cpp_generator::generate_service_server(t_service* tservice) {
+ // Generate the header portion
+ f_header_ <<
+ "class " << tservice->get_name() << "Server : " <<
+ "public " << tservice->get_name() << ", " <<
+ "public TDispatcher {" << endl <<
+ " public: " << endl;
+ indent_up();
+ f_header_ <<
+ indent() << "std::string dispatch(const std::string& buff);" << endl <<
+ indent() << "virtual ~" << tservice->get_name() << "Server();" << endl;
+ indent_down();
+ f_header_ <<
+ "};" << endl << endl;
+
+ // Generate the dispatch methods
+ vector<t_function*> functions = tservice->get_functions();
+ vector<t_function*>::iterator f_iter;
+ for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+ generate_dispatch_function(tservice, *f_iter);
+ }
+}
+
+/**
+ * Generates a dispatch function definition.
+ *
+ * @param tfunction The function to write a dispatcher for
+ */
+void t_cpp_generator::generate_dispatch_function(t_service* tservice,
+ t_function* tfunction) {
+ f_service_ <<
+ "std::string dispatch_" << tfunction->get_name() <<
+ "(const char *_tbuf, " <<
+ tservice->get_name() << " *dispatcher, " <<
+ "TProtocol *protocol) {" << endl;
+ indent_up();
+
+ // Create a field to represent this function's arguments
+ t_field arg_field(tfunction->get_arglist(), "_targs", 0);
+
+ generate_deserialize_struct(&arg_field);
+
+ // Generate the function call
+ indent(f_service_) <<
+ type_name(tfunction->get_returntype()) << " _tresult = dispatcher." <<
+ tfunction->get_name() << "(";
+ vector<t_field*> fields = tfunction->get_arglist()->get_members()->elems();
+ vector<t_field*>::iterator f_iter;
+ bool first = true;
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ if (first) {
+ first = false;
+ } else {
+ f_service_ << ", ";
+ }
+ f_service_ << "_targs." << (*f_iter)->get_name();
+ }
+ f_service_ << ");" << endl;
+
+ // Serialize the result
+ indent(f_service_) <<
+ "std::string _tout = "";" << endl;
+ t_field out_field(tfunction->get_returntype(), "_tout", 0);
+ generate_serialize_field(&out_field);
+
+ indent_down();
+ f_service_ <<
+ "}" << endl <<
+ endl;
+}
+
+/**
+ * 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.
+ */
+void t_cpp_generator::generate_deserialize_struct(t_field* tfield) {
+ t_struct* tstruct = (t_struct*)(tfield->get_type());
+ vector<t_field*> fields = tstruct->get_members()->elems();
+ vector<t_field*>::iterator f_iter;
+
+ indent(f_service_) <<
+ declare_field(tfield) << endl;
+ indent(f_service_) <<
+ "map<uint32_t,const char*> fmap = protocol.readFieldMap(_tbuf);" << endl;
+
+ // Declare the fields up front
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ indent(f_service_) <<
+ declare_field(*f_iter) << endl;
+ indent(f_service_) <<
+ "if (fmap.find(" << tfield->get_key() << ") != fmap.end()) {" << endl;
+ indent_up();
+ indent(f_service_) <<
+ "_tbuf = fmap[" << tfield->get_key() << "];" << endl;
+ generate_deserialize_field(*f_iter);
+ indent_down();
+ indent(f_service_) <<
+ "}" << endl;
+ }
+}
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_cpp_generator::generate_deserialize_field(t_field* tfield) {
+ t_type* type = tfield->get_type();
+ while (type->is_typedef()) {
+ type = ((t_typedef*)type)->get_type();
+ }
+
+ if (type->is_struct()) {
+ generate_deserialize_struct(tfield);
+ }
+
+ if (type->is_base_type()) {
+ t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+ switch (tbase) {
+ case t_base_type::TYPE_VOID:
+ return;
+ case t_base_type::TYPE_STRING:
+ return;
+ case t_base_type::TYPE_BYTE:
+ return;
+ case t_base_type::TYPE_I32:
+ return;
+ case t_base_type::TYPE_U32:
+ return;
+ case t_base_type::TYPE_I64:
+ return;
+ case t_base_type::TYPE_U64:
+ return;
+ default:
+ throw "compiler error: no C++ name for base type " + tbase;
+ }
+ } else if (type->is_enum()) {
+
+ }
+}
+
+/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_cpp_generator::generate_service_client(t_service* tservice) {
+ // Generate the header portion
+ f_header_ <<
+ "class " << tservice->get_name() << "Client : " <<
+ "public " << tservice->get_name() << " {" << endl <<
+ " public:" << endl;
+
+ indent_up();
+ f_header_ <<
+ indent() << tservice->get_name() <<
+ "(TDispatcher& dispatcher, TProtocol& protocol);" << endl;
+ vector<t_function*> functions = tservice->get_functions();
+ vector<t_function*>::iterator f_iter;
+ for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+ f_header_ <<
+ indent() << function_signature(*f_iter) << ";" << endl;
+ }
+ indent_down();
+
+ f_header_ <<
+ " private:" << endl;
+ indent_up();
+ f_header_ <<
+ indent() << "TDispatcher& dispatcher;" << endl <<
+ indent() << "TProtocol& protocol;" << endl;
+ indent_down();
+ f_header_ <<
+ "};" << endl <<
+ endl;
+}
+
+/**
+ * Deserializes a field of any type.
+ */
+void t_cpp_generator::generate_serialize_field(t_field* tfield) {
+ t_type* type = tfield->get_type();
+ while (type->is_typedef()) {
+ type = ((t_typedef*)type)->get_type();
+ }
+
+ if (type->is_struct()) {
+
+ }
+
+ if (type->is_base_type()) {
+ t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+ switch (tbase) {
+ case t_base_type::TYPE_VOID:
+ return;
+ case t_base_type::TYPE_STRING:
+ return;
+ case t_base_type::TYPE_BYTE:
+ return;
+ case t_base_type::TYPE_I32:
+ return;
+ case t_base_type::TYPE_U32:
+ return;
+ case t_base_type::TYPE_I64:
+ return;
+ case t_base_type::TYPE_U64:
+ return;
+ default:
+ throw "compiler error: no C++ name for base type " + tbase;
+ }
+ } else if (type->is_enum()) {
+
+ }
+}
+
+
+/**
+ * Generates a comment about this code being autogenerated.
+ *
+ * @return C-style comment mentioning that this file is autogenerated.
+ */
+string t_cpp_generator::autogen_comment() {
+ string result = "";
+ return
+ result +
+ "/**\n" +
+ " * Autogenerated by Thrift\n" +
+ " * " + g_time_str +
+ " *\n" +
+ " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
+ " */\n";
+}
+
+/**
+ * Returns a C++ type name
+ *
+ * @param ttype The type
+ */
+string t_cpp_generator::type_name(t_type* ttype) {
+ if (ttype->is_base_type()) {
+ return base_type_name(((t_base_type*)ttype)->get_base());
+ } else {
+ return ttype->get_name();
+ }
+}
+
+/**
+ * Returns the C++ type that corresponds to the thrift type.
+ *
+ * @param tbase The base type
+ */
+string t_cpp_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 "std::string";
+ case t_base_type::TYPE_BYTE:
+ return "uint8_t";
+ case t_base_type::TYPE_I32:
+ return "int32_t";
+ case t_base_type::TYPE_U32:
+ return "uint32_t";
+ case t_base_type::TYPE_I64:
+ return "int64_t";
+ case t_base_type::TYPE_U64:
+ return "uint64_t";
+ default:
+ throw "compiler error: no C++ name for base type " + tbase;
+ }
+}
+
+/**
+ * Declares a field, which may include initialization as necessary.
+ *
+ * @param ttype The type
+ */
+string t_cpp_generator::declare_field(t_field* tfield) {
+ // TODO(mcslee): do we ever need to initialize the field?
+ return type_name(tfield->get_type()) + " " + tfield->get_name() + ";";
+}
+
+/**
+ * Renders a function signature of the form 'type name(args)'
+ *
+ * @param tfunction Function definition
+ * @return String of rendered function definition
+ */
+string t_cpp_generator::function_signature(t_function* tfunction) {
+ return
+ type_name(tfunction->get_returntype()) + " " + tfunction->get_name() +
+ "(" + field_list(tfunction->get_arglist()->get_members()) + ")";
+}
+
+/**
+ * Renders a field list
+ */
+string t_cpp_generator::field_list(t_list* tlist) {
+ string result = "";
+
+ vector<t_field*> fields = tlist->elems();
+ vector<t_field*>::iterator f_iter;
+ bool first = true;
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ if (first) {
+ first = false;
+ } else {
+ result += ", ";
+ }
+ result += type_name((*f_iter)->get_type()) + " " + (*f_iter)->get_name();
+ }
+ return result;
+}
diff --git a/compiler/src/generate/t_cpp_generator.h b/compiler/src/generate/t_cpp_generator.h
new file mode 100644
index 0000000..87eb72a
--- /dev/null
+++ b/compiler/src/generate/t_cpp_generator.h
@@ -0,0 +1,56 @@
+#ifndef T_CPP_GENERATOR_H
+#define T_CPP_GENERATOR_H
+
+#include <string>
+#include <fstream>
+
+#include "t_generator.h"
+
+#define T_CPP_DIR "gen-cpp"
+
+/**
+ * C++ code generator
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class t_cpp_generator : public t_generator {
+ public:
+ t_cpp_generator() {}
+ ~t_cpp_generator() {}
+
+ /** Init and close methods */
+ void init_generator(t_program *tprogram);
+ void close_generator();
+
+ /** 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);
+
+ /** Service-level generation functions */
+ void generate_service_interface (t_service* tservice);
+ void generate_service_server (t_service* tservice);
+ void generate_service_client (t_service* tservice);
+
+ /** Serialization constructs */
+ void generate_dispatch_function (t_service* tservice, t_function* tfunction);
+ void generate_deserialize_struct(t_field* tfield);
+ void generate_deserialize_field(t_field* tfield);
+
+ /** Helper rendering functions */
+ std::string autogen_comment();
+ 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);
+ std::string function_signature(t_function* tfunction);
+ std::string field_list(t_list* tlist);
+
+ private:
+ /** File streams */
+ std::ofstream f_types_;
+ std::ofstream f_header_;
+ std::ofstream f_service_;
+};
+
+#endif
diff --git a/compiler/src/generate/t_generator.cc b/compiler/src/generate/t_generator.cc
new file mode 100644
index 0000000..0ba44ac
--- /dev/null
+++ b/compiler/src/generate/t_generator.cc
@@ -0,0 +1,45 @@
+#include "t_generator.h"
+using namespace std;
+
+/**
+ * Top level program generation function. Calls the generator subclass methods
+ * for preparing file streams etc. then iterates over all the parts of the
+ * program to perform the correct actions.
+ *
+ * @param program The thrift program to compile into C++ source
+ */
+void t_generator::generate_program(t_program *tprogram) {
+ // Initialize the generator
+ init_generator(tprogram);
+
+ // Generate typedefs
+ vector<t_typedef*> typedefs = tprogram->get_typedefs();
+ vector<t_typedef*>::iterator td_iter;
+ for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) {
+ generate_typedef(*td_iter);
+ }
+
+ // Generate enums
+ vector<t_enum*> enums = tprogram->get_enums();
+ vector<t_enum*>::iterator en_iter;
+ for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
+ generate_enum(*en_iter);
+ }
+
+ // Generate structs
+ vector<t_struct*> structs = tprogram->get_structs();
+ vector<t_struct*>::iterator st_iter;
+ for (st_iter = structs.begin(); st_iter != structs.end(); ++st_iter) {
+ generate_struct(*st_iter);
+ }
+
+ // Generate services
+ vector<t_service*> services = tprogram->get_services();
+ vector<t_service*>::iterator sv_iter;
+ for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
+ generate_service(*sv_iter);
+ }
+
+ // Close the generator
+ close_generator();
+}
diff --git a/compiler/src/generate/t_generator.h b/compiler/src/generate/t_generator.h
new file mode 100644
index 0000000..71d0318
--- /dev/null
+++ b/compiler/src/generate/t_generator.h
@@ -0,0 +1,63 @@
+#ifndef T_GENERATOR_H
+#define T_GENERATOR_H
+
+#include <string>
+#include <iostream>
+#include "parse/t_program.h"
+
+/**
+ * Base class for a thrift code generator. This class defines the basic
+ * routines for code generation and contains the top level method that
+ * dispatches code generation across various components.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class t_generator {
+ public:
+ t_generator() {}
+ virtual ~t_generator() {}
+
+ /**
+ * Framework generator method that iterates over all the parts of a program
+ * and performs general actions. This is implemented by the base class and
+ * should not be overwritten in the subclasses.
+ */
+ void generate_program (t_program* tprogram);
+
+ protected:
+ /** Optional methods that may be imlemented by subclasses. */
+ virtual void init_generator (t_program* tprogram) {}
+ virtual void close_generator () {}
+
+ /** 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;
+
+ /** Indentation level modifiers */
+ void indent_up() { ++indent_; }
+ void indent_down() { --indent_; }
+
+ /** Indentation print function */
+ std::string indent() {
+ std::string ind = "";
+ int i;
+ for (i = 0; i < indent_; ++i) {
+ ind += " ";
+ }
+ return ind;
+ }
+
+ /** Indentation wrapper */
+ std::ostream& indent(std::ostream &os) {
+ return os << indent();
+ }
+
+ private:
+ /** Indentation level */
+ int indent_;
+
+};
+
+#endif