Update thrift compiler for new syntax, generate new form of C++ code
Reviewed By: wayne, he loves less warnings
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@664840 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/src/generate/t_cpp_generator.cc b/compiler/cpp/src/generate/t_cpp_generator.cc
index 28c9913..c59112c 100644
--- a/compiler/cpp/src/generate/t_cpp_generator.cc
+++ b/compiler/cpp/src/generate/t_cpp_generator.cc
@@ -10,7 +10,7 @@
*
* @param tprogram The program to generate
*/
-void t_cpp_generator::init_generator(t_program* tprogram) {
+void t_cpp_generator::init_generator() {
// Make output directory
mkdir(T_CPP_DIR, S_IREAD | S_IWRITE | S_IEXEC);
@@ -40,14 +40,31 @@
"#include <transport/TTransport.h>" << endl <<
endl;
+ // Include other Thrift includes
+ const vector<t_program*>& includes = program_->get_includes();
+ for (size_t i = 0; i < includes.size(); ++i) {
+ f_types_ <<
+ "#include \"" << includes[i]->get_name() << "_types.h\"" << endl;
+ }
+ f_types_ << endl;
+
+ // Include custom headers
+ const vector<string>& cpp_includes = program_->get_cpp_includes();
+ for (size_t i = 0; i < cpp_includes.size(); ++i) {
+ f_types_ <<
+ "#include \"" << cpp_includes[i] << "\"" << endl;
+ }
+ f_types_ <<
+ endl;
+
// Include the types file
f_types_impl_ <<
- "#include \"" << program_name_ <<"_types.h\"" << endl <<
+ "#include \"" << program_name_ << "_types.h\"" << endl <<
endl;
// Open namespace
- ns_open_ = namespace_open(tprogram->get_namespace());
- ns_close_ = namespace_close(tprogram->get_namespace());
+ ns_open_ = namespace_open(program_->get_cpp_namespace());
+ ns_close_ = namespace_close(program_->get_cpp_namespace());
f_types_ <<
ns_open_ << endl <<
@@ -61,7 +78,7 @@
/**
* Closes the output files.
*/
-void t_cpp_generator::close_generator(t_program* tprogram) {
+void t_cpp_generator::close_generator() {
// Close namespace
f_types_ <<
ns_close_ << endl <<
@@ -171,8 +188,9 @@
indent(out) <<
tstruct->get_name() << "() : ";
out << (*m_iter)->get_name() << "(0)";
- } else
+ } else {
out << ", " << (*m_iter)->get_name() << "(0)";
+ }
}
}
if (init_ctor) {
@@ -219,8 +237,8 @@
out <<
endl <<
- indent() << "uint32_t read(boost::shared_ptr<const facebook::thrift::protocol::TProtocol> iprot, boost::shared_ptr<facebook::thrift::transport::TTransport> itrans);" << endl <<
- indent() << "uint32_t write(boost::shared_ptr<const facebook::thrift::protocol::TProtocol> oprot, boost::shared_ptr<facebook::thrift::transport::TTransport> otrans) const;" << endl <<
+ indent() << "uint32_t read(boost::shared_ptr<facebook::thrift::protocol::TProtocol> iprot);" << endl <<
+ indent() << "uint32_t write(boost::shared_ptr<facebook::thrift::protocol::TProtocol> oprot) const;" << endl <<
endl;
indent_down();
@@ -238,7 +256,7 @@
void t_cpp_generator::generate_struct_reader(ofstream& out,
t_struct* tstruct) {
indent(out) <<
- "uint32_t " << tstruct->get_name() << "::read(boost::shared_ptr<const facebook::thrift::protocol::TProtocol> iprot, boost::shared_ptr<facebook::thrift::transport::TTransport> itrans) {" << endl;
+ "uint32_t " << tstruct->get_name() << "::read(boost::shared_ptr<facebook::thrift::protocol::TProtocol> iprot) {" << endl;
indent_up();
const vector<t_field*>& fields = tstruct->get_members();
@@ -252,7 +270,7 @@
indent() << "facebook::thrift::protocol::TType ftype;" << endl <<
indent() << "int16_t fid;" << endl <<
endl <<
- indent() << "xfer += iprot->readStructBegin(itrans, fname);" << endl <<
+ indent() << "xfer += iprot->readStructBegin(fname);" << endl <<
endl;
// Loop over reading in fields
@@ -262,7 +280,7 @@
// Read beginning field marker
indent(out) <<
- "xfer += iprot->readFieldBegin(itrans, fname, ftype, fid);" << endl;
+ "xfer += iprot->readFieldBegin(fname, ftype, fid);" << endl;
// Check for field STOP marker
out <<
@@ -291,20 +309,20 @@
// In the default case we skip the field
out <<
indent() << "default:" << endl <<
- indent() << " xfer += iprot->skip(itrans, ftype);" << endl <<
+ indent() << " xfer += iprot->skip(ftype);" << endl <<
indent() << " break;" << endl;
scope_down(out);
// Read field end marker
indent(out) <<
- "xfer += iprot->readFieldEnd(itrans);" << endl;
+ "xfer += iprot->readFieldEnd();" << endl;
scope_down(out);
out <<
endl <<
- indent() << "xfer += iprot->readStructEnd(itrans);" << endl <<
+ indent() << "xfer += iprot->readStructEnd();" << endl <<
indent() <<"return xfer;" << endl;
indent_down();
@@ -325,18 +343,18 @@
vector<t_field*>::const_iterator f_iter;
indent(out) <<
- "uint32_t " << tstruct->get_name() << "::write(boost::shared_ptr<const facebook::thrift::protocol::TProtocol> oprot, boost::shared_ptr<facebook::thrift::transport::TTransport> otrans) const {" << endl;
+ "uint32_t " << tstruct->get_name() << "::write(boost::shared_ptr<facebook::thrift::protocol::TProtocol> oprot) const {" << endl;
indent_up();
out <<
indent() << "uint32_t xfer = 0;" << endl;
indent(out) <<
- "xfer += oprot->writeStructBegin(otrans, \"" << name << "\");" << endl;
+ "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl;
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
// Write field header
out <<
- indent() << "xfer += oprot->writeFieldBegin(otrans, " <<
+ indent() << "xfer += oprot->writeFieldBegin(" <<
"\"" << (*f_iter)->get_name() << "\", " <<
type_to_enum((*f_iter)->get_type()) << ", " <<
(*f_iter)->get_key() << ");" << endl;
@@ -344,12 +362,12 @@
generate_serialize_field(out, *f_iter, "this->");
// Write field closer
indent(out) <<
- "xfer += oprot->writeFieldEnd(otrans);" << endl;
+ "xfer += oprot->writeFieldEnd();" << endl;
}
// Write the struct map
out <<
- indent() << "xfer += oprot->writeFieldStop(otrans);" << endl <<
- indent() << "xfer += oprot->writeStructEnd(otrans);" << endl <<
+ indent() << "xfer += oprot->writeFieldStop();" << endl <<
+ indent() << "xfer += oprot->writeStructEnd();" << endl <<
indent() << "return xfer;" << endl;
indent_down();
@@ -373,7 +391,7 @@
vector<t_field*>::const_iterator f_iter;
indent(out) <<
- "uint32_t " << tstruct->get_name() << "::write(boost::shared_ptr<const facebook::thrift::protocol::TProtocol> oprot, boost::shared_ptr<facebook::thrift::transport::TTransport> otrans) const {" << endl;
+ "uint32_t " << tstruct->get_name() << "::write(boost::shared_ptr<facebook::thrift::protocol::TProtocol> oprot) const {" << endl;
indent_up();
out <<
@@ -382,7 +400,7 @@
endl;
indent(out) <<
- "xfer += oprot->writeStructBegin(otrans, \"" << name << "\");" << endl;
+ "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl;
bool first = true;
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
@@ -402,14 +420,14 @@
// Write field header
out <<
- indent() << "xfer += oprot->writeFieldBegin(otrans, " <<
+ indent() << "xfer += oprot->writeFieldBegin(" <<
"\"" << (*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, "this->");
// Write field closer
- indent(out) << "xfer += oprot->writeFieldEnd(otrans);" << endl;
+ indent(out) << "xfer += oprot->writeFieldEnd();" << endl;
indent_down();
indent(out) << "}";
@@ -418,8 +436,8 @@
// Write the struct map
out <<
endl <<
- indent() << "xfer += oprot->writeFieldStop(otrans);" << endl <<
- indent() << "xfer += oprot->writeStructEnd(otrans);" << endl <<
+ indent() << "xfer += oprot->writeFieldStop();" << endl <<
+ indent() << "xfer += oprot->writeStructEnd();" << endl <<
indent() << "return xfer;" << endl;
indent_down();
@@ -451,7 +469,14 @@
"#define " << svcname << "_H" << endl <<
endl <<
"#include <TProcessor.h>" << endl <<
- "#include \"" << program_name_ << "_types.h\"" << endl <<
+ "#include \"" << program_name_ << "_types.h\"" << endl;
+
+ if (tservice->get_extends() != NULL) {
+ f_header_ <<
+ "#include \"" << tservice->get_extends()->get_name() << ".h\"" << endl;
+ }
+
+ f_header_ <<
endl <<
ns_open_ << endl <<
endl;
@@ -471,8 +496,9 @@
generate_service_interface(tservice);
generate_service_helpers(tservice);
generate_service_client(tservice);
- generate_service_server(tservice);
+ generate_service_processor(tservice);
generate_service_multiface(tservice);
+ generate_service_skeleton(tservice);
// Close the namespace
f_service_ <<
@@ -513,8 +539,12 @@
* @param tservice The service to generate a header definition for
*/
void t_cpp_generator::generate_service_interface(t_service* tservice) {
+ string extends = "";
+ if (tservice->get_extends() != NULL) {
+ extends = " : virtual public " + type_name(tservice->get_extends()) + "If";
+ }
f_header_ <<
- "class " << service_name_ << "If {" << endl <<
+ "class " << service_name_ << "If" << extends << " {" << endl <<
" public: " << endl;
indent_up();
f_header_ <<
@@ -542,16 +572,33 @@
vector<t_function*> functions = tservice->get_functions();
vector<t_function*>::iterator f_iter;
+ string extends = "";
+ string extends_multiface = "";
+ if (tservice->get_extends() != NULL) {
+ extends = type_name(tservice->get_extends());
+ extends_multiface = ", public " + extends + "Multiface";
+ }
+
string list_type = string("std::vector<boost::shared_ptr<") + service_name_ + "If> >";
// Generate the header portion
f_header_ <<
"class " << service_name_ << "Multiface : " <<
- "public " << service_name_ << "If {" << endl <<
+ "virtual public " << service_name_ << "If" <<
+ extends_multiface << " {" << endl <<
" public: " << endl;
indent_up();
f_header_ <<
- indent() << service_name_ << "Multiface(" << list_type << "& ifaces) : _ifaces(ifaces) {}" << endl <<
+ indent() << service_name_ << "Multiface(" << list_type << "& ifaces) : ifaces_(ifaces) {" << endl;
+ if (!extends.empty()) {
+ f_header_ <<
+ indent() << " std::vector<boost::shared_ptr<" + service_name_ + "If> >::iterator iter;" << endl <<
+ indent() << " for (iter = ifaces.begin(); iter != ifaces.end(); ++iter) {" << endl <<
+ indent() << " " << extends << "Multiface::add(*iter);" << endl <<
+ indent() << " }" << endl;
+ }
+ f_header_ <<
+ indent() << "}" << endl <<
indent() << "virtual ~" << service_name_ << "Multiface() {}" << endl;
indent_down();
@@ -560,7 +607,16 @@
" protected:" << endl;
indent_up();
f_header_ <<
- indent() << list_type << "& _ifaces;" << endl;
+ indent() << list_type << " ifaces_;" << endl <<
+ indent() << service_name_ << "Multiface() {}" << endl <<
+ indent() << "void add(boost::shared_ptr<" << service_name_ << "If> iface) { " << endl;
+ if (!extends.empty()) {
+ f_header_ <<
+ indent() << " " << extends << "Multiface::add(iface);" << endl;
+ }
+ f_header_ <<
+ indent() << " ifaces_.push_back(iface);" << endl <<
+ indent() << "}" << endl;
indent_down();
f_header_ <<
@@ -572,7 +628,7 @@
const vector<t_field*>& args = arglist->get_members();
vector<t_field*>::const_iterator a_iter;
- string call = string("_ifaces[i]->") + (*f_iter)->get_name() + "(";
+ string call = string("ifaces_[i]->") + (*f_iter)->get_name() + "(";
bool first = true;
for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
if (first) {
@@ -588,7 +644,7 @@
indent() << function_signature(*f_iter) << " {" << endl;
indent_up();
f_header_ <<
- indent() << "uint32_t sz = _ifaces.size();" << endl <<
+ indent() << "uint32_t sz = ifaces_.size();" << endl <<
indent() << "for (uint32_t i = 0; i < sz; ++i) {" << endl;
if (!(*f_iter)->get_returntype()->is_void()) {
f_header_ <<
@@ -623,37 +679,53 @@
* @param tservice The service to generate a server for.
*/
void t_cpp_generator::generate_service_client(t_service* tservice) {
+ string extends = "";
+ string extends_client = "";
+ if (tservice->get_extends() != NULL) {
+ extends = type_name(tservice->get_extends());
+ extends_client = ", public " + extends + "Client";
+ }
+
// Generate the header portion
f_header_ <<
"class " << service_name_ << "Client : " <<
- "public " << service_name_ << "If {" << endl <<
+ "virtual public " << service_name_ << "If" <<
+ extends_client << " {" << endl <<
" public:" << endl;
indent_up();
f_header_ <<
- indent() << service_name_ << "Client(boost::shared_ptr<facebook::thrift::transport::TTransport> trans, boost::shared_ptr<const facebook::thrift::protocol::TProtocol> prot) : " << endl <<
- indent() << " _itrans(trans)," << endl <<
- indent() << " _otrans(trans)," << endl <<
- indent() << " _iprot(prot)," << endl <<
- indent() << " _oprot(prot) {}" << endl;
+ indent() << service_name_ << "Client(boost::shared_ptr<facebook::thrift::protocol::TProtocol> prot) : " << endl;
+ if (extends.empty()) {
+ f_header_ <<
+ indent() << " iprot_(prot)," << endl <<
+ indent() << " oprot_(prot) {}" << endl;
+ } else {
+ f_header_ <<
+ indent() << " " << extends << "Client(prot, prot) {}" << endl;
+ }
f_header_ <<
- indent() << service_name_ << "Client(boost::shared_ptr<facebook::thrift::transport::TTransport> itrans, boost::shared_ptr<facebook::thrift::transport::TTransport> otrans, boost::shared_ptr<const facebook::thrift::protocol::TProtocol> iprot, boost::shared_ptr<const facebook::thrift::protocol::TProtocol> oprot) : " << endl <<
- indent() << " _itrans(itrans)," << endl <<
- indent() << " _otrans(otrans)," << endl <<
- indent() << " _iprot(iprot)," << endl <<
- indent() << " _oprot(oprot) {}" << endl;
+ indent() << service_name_ << "Client(boost::shared_ptr<facebook::thrift::protocol::TProtocol> iprot, boost::shared_ptr<facebook::thrift::protocol::TProtocol> oprot) : " << endl;
+ if (extends.empty()) {
+ f_header_ <<
+ indent() << " iprot_(iprot)," << endl <<
+ indent() << " oprot_(oprot) {}" << endl;
+ } else {
+ f_header_ <<
+ indent() << " " << extends << "Client(iprot, oprot) {}" << endl;
+ }
vector<t_function*> functions = tservice->get_functions();
vector<t_function*>::const_iterator f_iter;
for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
- t_function send_function(g_program->get_void_type(),
+ t_function send_function(g_type_void,
string("send_") + (*f_iter)->get_name(),
(*f_iter)->get_arglist());
indent(f_header_) << function_signature(*f_iter) << ";" << endl;
indent(f_header_) << function_signature(&send_function) << ";" << endl;
if (!(*f_iter)->is_async()) {
- t_struct noargs;
+ t_struct noargs(program_);
t_function recv_function((*f_iter)->get_returntype(),
string("recv_") + (*f_iter)->get_name(),
&noargs);
@@ -662,15 +734,15 @@
}
indent_down();
- f_header_ <<
- " protected:" << endl;
- indent_up();
- f_header_ <<
- indent() << "boost::shared_ptr<facebook::thrift::transport::TTransport> _itrans;" << endl <<
- indent() << "boost::shared_ptr<facebook::thrift::transport::TTransport> _otrans;" << endl <<
- indent() << "boost::shared_ptr<const facebook::thrift::protocol::TProtocol> _iprot;" << endl <<
- indent() << "boost::shared_ptr<const facebook::thrift::protocol::TProtocol> _oprot;" << endl;
- indent_down();
+ if (extends.empty()) {
+ f_header_ <<
+ " protected:" << endl;
+ indent_up();
+ f_header_ <<
+ indent() << "boost::shared_ptr<facebook::thrift::protocol::TProtocol> iprot_;" << endl <<
+ indent() << "boost::shared_ptr<facebook::thrift::protocol::TProtocol> oprot_;" << endl;
+ indent_down();
+ }
f_header_ <<
"};" << endl <<
@@ -718,7 +790,7 @@
f_service_ << endl;
// Function for sending
- t_function send_function(g_program->get_void_type(),
+ t_function send_function(g_type_void,
string("send_") + (*f_iter)->get_name(),
(*f_iter)->get_arglist());
@@ -734,27 +806,27 @@
// Serialize the request
f_service_ <<
indent() << "int32_t cseqid = 0;" << endl <<
- indent() << "_oprot->writeMessageBegin(_otrans, \"" << (*f_iter)->get_name() << "\", facebook::thrift::protocol::T_CALL, cseqid);" << endl <<
+ indent() << "oprot_->writeMessageBegin(\"" << (*f_iter)->get_name() << "\", facebook::thrift::protocol::T_CALL, cseqid);" << endl <<
endl <<
- indent() << argsname << " __args;" << endl;
+ indent() << argsname << " args;" << endl;
for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
f_service_ <<
- indent() << "__args." << (*fld_iter)->get_name() << " = " << (*fld_iter)->get_name() << ";" << endl;
+ indent() << "args." << (*fld_iter)->get_name() << " = " << (*fld_iter)->get_name() << ";" << endl;
}
f_service_ <<
- indent() << "__args.write(_oprot, _otrans);" << endl <<
+ indent() << "args.write(oprot_);" << endl <<
endl <<
- indent() << "_oprot->writeMessageEnd(_otrans);" << endl <<
- indent() << "_otrans->flush();" << endl;
+ indent() << "oprot_->writeMessageEnd();" << endl <<
+ indent() << "oprot_->getOutputTransport()->flush();" << endl;
scope_down(f_service_);
f_service_ << endl;
// Generate recv function only if not an async function
if (!(*f_iter)->is_async()) {
- t_struct noargs;
+ t_struct noargs(program_);
t_function recv_function((*f_iter)->get_returntype(),
string("recv_") + (*f_iter)->get_name(),
&noargs);
@@ -769,7 +841,7 @@
indent() << "std::string fname;" << endl <<
indent() << "facebook::thrift::protocol::TMessageType mtype;" << endl <<
endl <<
- indent() << "_iprot->readMessageBegin(_itrans, fname, mtype, rseqid);" << endl <<
+ indent() << "iprot_->readMessageBegin(fname, mtype, rseqid);" << endl <<
indent() << "if (mtype != facebook::thrift::protocol::T_REPLY || fname.compare(\"" << (*f_iter)->get_name() << "\") != 0) {" << endl;
indent_up();
f_service_ <<
@@ -778,16 +850,16 @@
f_service_ <<
indent() << "}" << endl <<
- indent() << resultname << " __result;" << endl <<
- indent() << "__result.read(_iprot, _itrans);" << endl <<
- indent() << "_iprot->readMessageEnd(_itrans);" << endl <<
+ indent() << resultname << " result;" << endl <<
+ indent() << "result.read(iprot_);" << endl <<
+ indent() << "iprot_->readMessageEnd();" << endl <<
endl;
// 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 <<
- indent() << " return __result.success;" << endl <<
+ indent() << "if (result.__isset.success) {" << endl <<
+ indent() << " return result.success;" << endl <<
indent() << "}" << endl;
}
@@ -796,8 +868,8 @@
vector<t_field*>::const_iterator x_iter;
for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
f_service_ <<
- indent() << "if (__result.__isset." << (*x_iter)->get_name() << ") {" << endl <<
- indent() << " throw __result." << (*x_iter)->get_name() << ";" << endl <<
+ indent() << "if (result.__isset." << (*x_iter)->get_name() << ") {" << endl <<
+ indent() << " throw result." << (*x_iter)->get_name() << ";" << endl <<
indent() << "}" << endl;
}
@@ -822,43 +894,53 @@
*
* @param tservice The service to generate a server for.
*/
-void t_cpp_generator::generate_service_server(t_service* tservice) {
+void t_cpp_generator::generate_service_processor(t_service* tservice) {
// Generate the dispatch methods
vector<t_function*> functions = tservice->get_functions();
vector<t_function*>::iterator f_iter;
+ string extends = "";
+ string extends_processor = "";
+ if (tservice->get_extends() != NULL) {
+ extends = type_name(tservice->get_extends());
+ extends_processor = ", public " + extends + "Processor";
+ }
+
// Generate the header portion
f_header_ <<
"class " << service_name_ << "Processor : " <<
- "public facebook::thrift::TProcessor {" << endl;
+ "virtual public facebook::thrift::TProcessor" <<
+ extends_processor << " {" << endl;
// Protected data members
f_header_ <<
" protected:" << endl;
indent_up();
f_header_ <<
- indent() << "boost::shared_ptr<" << service_name_ << "If> _iface;" << endl <<
- indent() << "boost::shared_ptr<const facebook::thrift::protocol::TProtocol> _iprot;" << endl <<
- indent() << "boost::shared_ptr<const facebook::thrift::protocol::TProtocol> _oprot;" << endl <<
- indent() << "std::map<std::string, void (" << service_name_ << "Processor::*)(int32_t, boost::shared_ptr<facebook::thrift::transport::TTransport>, boost::shared_ptr<facebook::thrift::transport::TTransport>)> _processMap;" << endl;
+ indent() << "boost::shared_ptr<" << service_name_ << "If> iface_;" << endl;
+ f_header_ <<
+ indent() << "virtual bool process_fn(boost::shared_ptr<facebook::thrift::protocol::TProtocol> iprot, boost::shared_ptr<facebook::thrift::protocol::TProtocol> oprot, std::string& fname, int32_t seqid);" << endl;
indent_down();
// Process function declarations
f_header_ <<
" private:" << endl;
indent_up();
+ f_header_ <<
+ indent() << "std::map<std::string, void (" << service_name_ << "Processor::*)(int32_t, boost::shared_ptr<facebook::thrift::protocol::TProtocol>, boost::shared_ptr<facebook::thrift::protocol::TProtocol>)> processMap_;" << endl;
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<facebook::thrift::transport::TTransport> _itrans, boost::shared_ptr<facebook::thrift::transport::TTransport> _otrans);" << endl;
+ "void process_" << (*f_iter)->get_name() << "(int32_t seqid, boost::shared_ptr<facebook::thrift::protocol::TProtocol> iprot, boost::shared_ptr<facebook::thrift::protocol::TProtocol> oprot);" << endl;
}
indent_down();
indent_up();
string declare_map = "";
indent_up();
+
for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
declare_map += indent();
- declare_map += "_processMap[\"";
+ declare_map += "processMap_[\"";
declare_map += (*f_iter)->get_name();
declare_map += "\"] = &";
declare_map += service_name_;
@@ -870,20 +952,20 @@
f_header_ <<
" public: " << endl <<
- indent() << service_name_ << "Processor(boost::shared_ptr<" << service_name_ << "If> iface, boost::shared_ptr<const facebook::thrift::protocol::TProtocol> 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<const facebook::thrift::protocol::TProtocol> iprot, boost::shared_ptr<const facebook::thrift::protocol::TProtocol> oprot) :" << endl <<
- indent() << " _iface(iface)," << endl <<
- indent() << " _iprot(iprot)," << endl <<
- indent() << " _oprot(oprot) {" << endl <<
+ indent() << service_name_ << "Processor(boost::shared_ptr<" << service_name_ << "If> iface) :" << endl;
+ if (extends.empty()) {
+ f_header_ <<
+ indent() << " iface_(iface) {" << endl;
+ } else {
+ f_header_ <<
+ indent() << " " << extends << "Processor(iface)," << endl <<
+ indent() << " iface_(iface) {" << endl;
+ }
+ f_header_ <<
declare_map <<
indent() << "}" << endl <<
endl <<
- indent() << "bool process(boost::shared_ptr<facebook::thrift::transport::TTransport> _itrans, boost::shared_ptr<facebook::thrift::transport::TTransport> _otrans);" << endl <<
+ indent() << "virtual bool process(boost::shared_ptr<facebook::thrift::protocol::TProtocol> iprot, boost::shared_ptr<facebook::thrift::protocol::TProtocol> oprot);" << endl <<
indent() << "virtual ~" << service_name_ << "Processor() {}" << endl;
indent_down();
f_header_ <<
@@ -891,7 +973,7 @@
// Generate the server implementation
f_service_ <<
- "bool " << service_name_ << "Processor::process(boost::shared_ptr<facebook::thrift::transport::TTransport> itrans, boost::shared_ptr<facebook::thrift::transport::TTransport> otrans) {" << endl;
+ "bool " << service_name_ << "Processor::process(boost::shared_ptr<facebook::thrift::protocol::TProtocol> iprot, boost::shared_ptr<facebook::thrift::protocol::TProtocol> oprot) {" << endl;
indent_up();
f_service_ <<
@@ -900,21 +982,39 @@
indent() << "facebook::thrift::protocol::TMessageType mtype;" << endl <<
indent() << "int32_t seqid;" << endl <<
endl <<
- indent() << "_iprot->readMessageBegin(itrans, fname, mtype, seqid);" << endl <<
+ indent() << "iprot->readMessageBegin(fname, mtype, seqid);" << endl <<
endl <<
indent() << "if (mtype != facebook::thrift::protocol::T_CALL) {" << endl <<
indent() << " throw facebook::thrift::Exception(\"Unexpected message type\");" << endl <<
indent() << "}" << endl <<
+ endl <<
+ indent() << "return process_fn(iprot, oprot, fname, seqid);" <<
endl;
+ indent_down();
+ f_service_ <<
+ indent() << "}" << endl <<
+ endl;
+
+ f_service_ <<
+ "bool " << service_name_ << "Processor::process_fn(boost::shared_ptr<facebook::thrift::protocol::TProtocol> iprot, boost::shared_ptr<facebook::thrift::protocol::TProtocol> oprot, std::string& fname, int32_t seqid) {" << endl;
+ indent_up();
+
// HOT: member function pointer map
f_service_ <<
- indent() << "std::map<std::string, void (" << service_name_ << "Processor::*)(int32_t, boost::shared_ptr<facebook::thrift::transport::TTransport>, boost::shared_ptr<facebook::thrift::transport::TTransport>)>::iterator pfn;" << endl <<
- indent() << "pfn = _processMap.find(fname);" << endl <<
- indent() << "if (pfn == _processMap.end()) {" << endl <<
- indent() << " throw facebook::thrift::Exception(\"Unknown function name: '\"+fname+\"'\");" << endl <<
+ indent() << "std::map<std::string, void (" << service_name_ << "Processor::*)(int32_t, boost::shared_ptr<facebook::thrift::protocol::TProtocol>, boost::shared_ptr<facebook::thrift::protocol::TProtocol>)>::iterator pfn;" << endl <<
+ indent() << "pfn = processMap_.find(fname);" << endl <<
+ indent() << "if (pfn == processMap_.end()) {" << endl;
+ if (extends.empty()) {
+ f_service_ <<
+ indent() << " throw facebook::thrift::Exception(\"Unknown function name: '\"+fname+\"'\");" << endl;
+ } else {
+ f_service_ <<
+ indent() << " return " << extends << "Processor::process_fn(iprot, oprot, fname, seqid);" << endl;
+ }
+ f_service_ <<
indent() << "} else {" << endl <<
- indent() << " (this->*(pfn->second))(seqid, itrans, otrans);" << endl <<
+ indent() << " (this->*(pfn->second))(seqid, iprot, oprot);" << endl <<
indent() << "}" << endl;
// Read end of args field, the T_STOP, and the struct close
@@ -942,7 +1042,7 @@
return;
}
- t_struct result(tfunction->get_name() + "_result");
+ t_struct result(program_, tfunction->get_name() + "_result");
t_field success(tfunction->get_returntype(), "success", 0);
if (!tfunction->get_returntype()->is_void()) {
result.append(&success);
@@ -971,17 +1071,17 @@
f_service_ <<
"void " << tservice->get_name() << "Processor::" <<
"process_" << tfunction->get_name() <<
- "(int32_t seqid, boost::shared_ptr<facebook::thrift::transport::TTransport> itrans, boost::shared_ptr<facebook::thrift::transport::TTransport> otrans)" << endl;
+ "(int32_t seqid, boost::shared_ptr<facebook::thrift::protocol::TProtocol> iprot, boost::shared_ptr<facebook::thrift::protocol::TProtocol> oprot)" << endl;
scope_up(f_service_);
string argsname = tfunction->get_name() + "_args";
string resultname = tfunction->get_name() + "_result";
f_service_ <<
- indent() << argsname << " __args;" << endl <<
- indent() << "__args.read(_iprot, itrans);" << endl <<
- indent() << "_iprot->readMessageEnd(itrans);" << endl <<
- indent() << "itrans->readEnd();" << endl <<
+ indent() << argsname << " args;" << endl <<
+ indent() << "args.read(iprot);" << endl <<
+ indent() << "iprot->readMessageEnd();" << endl <<
+ indent() << "iprot->getInputTransport()->readEnd();" << endl <<
endl;
t_struct* xs = tfunction->get_xceptions();
@@ -991,7 +1091,7 @@
// Declare result
if (!tfunction->is_async()) {
f_service_ <<
- indent() << resultname << " __result;" << endl;
+ indent() << resultname << " result;" << endl;
}
// Try block for functions with exceptions
@@ -1008,10 +1108,10 @@
f_service_ << indent();
if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) {
- f_service_ << "__result.success = ";
+ f_service_ << "result.success = ";
}
f_service_ <<
- "_iface->" << tfunction->get_name() << "(";
+ "iface_->" << tfunction->get_name() << "(";
bool first = true;
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
if (first) {
@@ -1019,14 +1119,14 @@
} else {
f_service_ << ", ";
}
- f_service_ << "__args." << (*f_iter)->get_name();
+ f_service_ << "args." << (*f_iter)->get_name();
}
f_service_ << ");" << endl;
// Set isset on success field
if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) {
f_service_ <<
- indent() << "__result.__isset.success = true;" << endl;
+ indent() << "result.__isset.success = true;" << endl;
}
if (!tfunction->is_async() && xceptions.size() > 0) {
@@ -1037,8 +1137,8 @@
if (!tfunction->is_async()) {
indent_up();
f_service_ <<
- indent() << "__result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << ";" << endl <<
- indent() << "__result.__isset." << (*x_iter)->get_name() << " = true;" << endl;
+ indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << ";" << endl <<
+ indent() << "result.__isset." << (*x_iter)->get_name() << " = true;" << endl;
indent_down();
f_service_ << indent() << "}";
} else {
@@ -1061,11 +1161,11 @@
// Serialize the result into a struct
f_service_ <<
endl <<
- indent() << "_oprot->writeMessageBegin(otrans, \"" << tfunction->get_name() << "\", facebook::thrift::protocol::T_REPLY, seqid);" << endl <<
- indent() << "__result.write(_oprot, otrans);" << endl <<
- indent() << "_oprot->writeMessageEnd(otrans);" << endl <<
- indent() << "otrans->flush();" << endl <<
- indent() << "otrans->writeEnd();" << endl;
+ indent() << "oprot->writeMessageBegin(\"" << tfunction->get_name() << "\", facebook::thrift::protocol::T_REPLY, seqid);" << endl <<
+ indent() << "result.write(oprot);" << endl <<
+ indent() << "oprot->writeMessageEnd();" << endl <<
+ indent() << "oprot->getOutputTransport()->flush();" << endl <<
+ indent() << "oprot->getOutputTransport()->writeEnd();" << endl;
// Close function
scope_down(f_service_);
@@ -1073,6 +1173,92 @@
}
/**
+ * Generates a skeleton file of a server
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_cpp_generator::generate_service_skeleton(t_service* tservice) {
+ string svcname = tservice->get_name();
+
+ // Service implementation file includes
+ string f_skeleton_name = string(T_CPP_DIR)+"/"+svcname+"_server.skeleton.cpp";
+
+ string ns = namespace_prefix(tservice->get_program()->get_cpp_namespace());
+
+ ofstream f_skeleton;
+ f_skeleton.open(f_skeleton_name.c_str());
+ f_skeleton <<
+ "// This autogenerated skeleton file illustrates how to build a server." << endl <<
+ "// You should copy it to another filename to avoid overwriting it." << endl <<
+ endl <<
+ "#include \"" << svcname << ".h\"" << endl <<
+ "#include <protocol/TBinaryProtocol.h>" << endl <<
+ "#include <server/TSimpleServer.h>" << endl <<
+ "#include <transport/TServerSocket.h>" << endl <<
+ "#include <transport/TBufferedTransportFactory.h>" << endl <<
+ endl <<
+ "using namespace facebook::thrift;" << endl <<
+ "using namespace facebook::thrift::protocol;" << endl <<
+ "using namespace facebook::thrift::transport;" << endl <<
+ "using namespace facebook::thrift::server;" << endl <<
+ endl;
+
+ if (!ns.empty()) {
+ f_skeleton <<
+ "using namespace " << string(ns, 0, ns.size()-2) << ";" << endl <<
+ endl;
+ }
+
+ f_skeleton <<
+ "class " << svcname << "Handler : public " << svcname << "If {" << endl <<
+ " public:" << endl;
+ indent_up();
+ f_skeleton <<
+ indent() << svcname << "Handler() {" << endl <<
+ indent() << " // Your initialization goes here" << endl <<
+ indent() << "}" << endl <<
+ 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_skeleton <<
+ indent() << function_signature(*f_iter) << " {" << endl <<
+ indent() << " // Your implementation goes here" << endl <<
+ indent() << " printf(\"" << (*f_iter)->get_name() << "\\n\");" << endl <<
+ indent() << "}" << endl <<
+ endl;
+ }
+
+ indent_down();
+ f_skeleton <<
+ "};" << endl <<
+ endl;
+
+ f_skeleton <<
+ indent() << "int main(int argc, char **argv) {" << endl;
+ indent_up();
+ f_skeleton <<
+ indent() << "int port = 9090;" << endl <<
+ indent() << "shared_ptr<" << svcname << "Handler> handler(new " << svcname << "Handler());" << endl <<
+ indent() << "shared_ptr<TProcessor> processor(new " << svcname << "Processor(handler));" << endl <<
+ indent() << "shared_ptr<TServerTransport> serverTransport(new TServerSocket(port));" << endl <<
+ indent() << "shared_ptr<TTransportFactory> transportFactory(new TBufferedTransportFactory());" << endl <<
+ indent() << "shared_ptr<TProtocolFactory> protocolFactory(new TBinaryProtocolFactory());" << endl <<
+ endl <<
+ indent() << "TSimpleServer server(processor, serverTransport, transportFactory, protocolFactory);" << endl <<
+ indent() << "server.serve();" << endl <<
+ indent() << "return 0;" << endl;
+ indent_down();
+ f_skeleton <<
+ "}" << endl <<
+ endl;
+
+ // Close the files
+ f_skeleton.close();
+}
+
+/**
* Deserializes a field of any type.
*/
void t_cpp_generator::generate_deserialize_field(ofstream& out,
@@ -1106,31 +1292,31 @@
name;
break;
case t_base_type::TYPE_STRING:
- out << "readString(itrans, " << name << ");";
+ out << "readString(" << name << ");";
break;
case t_base_type::TYPE_BOOL:
- out << "readBool(itrans, " << name << ");";
+ out << "readBool(" << name << ");";
break;
case t_base_type::TYPE_BYTE:
- out << "readByte(itrans, " << name << ");";
+ out << "readByte(" << name << ");";
break;
case t_base_type::TYPE_I16:
- out << "readI16(itrans, " << name << ");";
+ out << "readI16(" << name << ");";
break;
case t_base_type::TYPE_I32:
- out << "readI32(itrans, " << name << ");";
+ out << "readI32(" << name << ");";
break;
case t_base_type::TYPE_I64:
- out << "readI64(itrans, " << name << ");";
+ out << "readI64(" << name << ");";
break;
case t_base_type::TYPE_DOUBLE:
- out << "readDouble(itrans, " << name << ");";
+ out << "readDouble(" << name << ");";
break;
default:
throw "compiler error: no C++ reader for base type " + tbase + name;
}
} else if (type->is_enum()) {
- out << "readI32(itrans, (int32_t&)" << name << ");";
+ out << "readI32((int32_t&)" << name << ");";
}
out <<
endl;
@@ -1150,7 +1336,7 @@
t_struct* tstruct,
string prefix) {
indent(out) <<
- "xfer += " << prefix << ".read(iprot, itrans);" << endl;
+ "xfer += " << prefix << ".read(iprot);" << endl;
}
void t_cpp_generator::generate_deserialize_container(ofstream& out,
@@ -1171,17 +1357,17 @@
out <<
indent() << "facebook::thrift::protocol::TType " << ktype << ";" << endl <<
indent() << "facebook::thrift::protocol::TType " << vtype << ";" << endl <<
- indent() << "iprot->readMapBegin(itrans, " <<
+ indent() << "iprot->readMapBegin(" <<
ktype << ", " << vtype << ", " << size << ");" << endl;
} else if (ttype->is_set()) {
out <<
indent() << "facebook::thrift::protocol::TType " << etype << ";" << endl <<
- indent() << "iprot->readSetBegin(itrans, " <<
+ indent() << "iprot->readSetBegin(" <<
etype << ", " << size << ");" << endl;
} else if (ttype->is_list()) {
out <<
indent() << "facebook::thrift::protocol::TType " << etype << ";" << endl <<
- indent() << "iprot->readListBegin(itrans, " <<
+ indent() << "iprot->readListBegin(" <<
etype << ", " << size << ");" << endl;
}
@@ -1206,11 +1392,11 @@
// Read container end
if (ttype->is_map()) {
- indent(out) << "iprot->readMapEnd(itrans);" << endl;
+ indent(out) << "iprot->readMapEnd();" << endl;
} else if (ttype->is_set()) {
- indent(out) << "iprot->readSetEnd(itrans);" << endl;
+ indent(out) << "iprot->readSetEnd();" << endl;
} else if (ttype->is_list()) {
- indent(out) << "iprot->readListEnd(itrans);" << endl;
+ indent(out) << "iprot->readListEnd();" << endl;
}
scope_down(out);
@@ -1312,31 +1498,31 @@
"compiler error: cannot serialize void field in a struct: " + name;
break;
case t_base_type::TYPE_STRING:
- out << "writeString(otrans, " << name << ");";
+ out << "writeString(" << name << ");";
break;
case t_base_type::TYPE_BOOL:
- out << "writeBool(otrans, " << name << ");";
+ out << "writeBool(" << name << ");";
break;
case t_base_type::TYPE_BYTE:
- out << "writeByte(otrans, " << name << ");";
+ out << "writeByte(" << name << ");";
break;
case t_base_type::TYPE_I16:
- out << "writeI16(otrans, " << name << ");";
+ out << "writeI16(" << name << ");";
break;
case t_base_type::TYPE_I32:
- out << "writeI32(otrans, " << name << ");";
+ out << "writeI32(" << name << ");";
break;
case t_base_type::TYPE_I64:
- out << "writeI64(otrans, " << name << ");";
+ out << "writeI64(" << name << ");";
break;
case t_base_type::TYPE_DOUBLE:
- out << "writeDouble(otrans, " << name << ");";
+ out << "writeDouble(" << name << ");";
break;
default:
throw "compiler error: no C++ writer for base type " + tbase + name;
}
} else if (type->is_enum()) {
- out << "writeI32(otrans, (int32_t)" << name << ");";
+ out << "writeI32((int32_t)" << name << ");";
}
out << endl;
} else {
@@ -1357,7 +1543,7 @@
t_struct* tstruct,
string prefix) {
indent(out) <<
- "xfer += " << prefix << ".write(oprot, otrans);" << endl;
+ "xfer += " << prefix << ".write(oprot);" << endl;
}
void t_cpp_generator::generate_serialize_container(ofstream& out,
@@ -1367,18 +1553,18 @@
if (ttype->is_map()) {
indent(out) <<
- "xfer += oprot->writeMapBegin(otrans, " <<
+ "xfer += oprot->writeMapBegin(" <<
type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
prefix << ".size());" << endl;
} else if (ttype->is_set()) {
indent(out) <<
- "xfer += oprot->writeSetBegin(otrans, " <<
+ "xfer += oprot->writeSetBegin(" <<
type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
prefix << ".size());" << endl;
} else if (ttype->is_list()) {
indent(out) <<
- "xfer += oprot->writeListBegin(otrans, " <<
+ "xfer += oprot->writeListBegin(" <<
type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
prefix << ".size());" << endl;
}
@@ -1399,13 +1585,13 @@
if (ttype->is_map()) {
indent(out) <<
- "xfer += oprot->writeMapEnd(otrans);" << endl;
+ "xfer += oprot->writeMapEnd();" << endl;
} else if (ttype->is_set()) {
indent(out) <<
- "xfer += oprot->writeSetEnd(otrans);" << endl;
+ "xfer += oprot->writeSetEnd();" << endl;
} else if (ttype->is_list()) {
indent(out) <<
- "xfer += oprot->writeListEnd(otrans);" << endl;
+ "xfer += oprot->writeListEnd();" << endl;
}
scope_down(out);
@@ -1446,6 +1632,29 @@
}
/**
+ * Makes a :: prefix for a namespace
+ *
+ * @param ns The namepsace, w/ periods in it
+ * @return Namespaces
+ */
+string t_cpp_generator::namespace_prefix(string ns) {
+ if (ns.size() == 0) {
+ return "";
+ }
+ string result = "";
+ string::size_type loc;
+ while ((loc = ns.find(".")) != string::npos) {
+ result += ns.substr(0, loc);
+ result += "::";
+ ns = ns.substr(loc+1);
+ }
+ if (ns.size() > 0) {
+ result += ns + "::";
+ }
+ return result;
+}
+
+/**
* Opens namespace.
*
* @param ns The namepsace, w/ periods in it
@@ -1523,6 +1732,14 @@
return "std::vector<" + type_name(tlist->get_elem_type()) + "> ";
}
+ // Check if it needs to be namespaced
+ t_program* program = ttype->get_program();
+ if (program != NULL && program != program_) {
+ return
+ namespace_prefix(program->get_cpp_namespace()) +
+ ttype->get_name();
+ }
+
return ttype->get_name();
}
diff --git a/compiler/cpp/src/generate/t_cpp_generator.h b/compiler/cpp/src/generate/t_cpp_generator.h
index 37c36a1..45cbdac 100644
--- a/compiler/cpp/src/generate/t_cpp_generator.h
+++ b/compiler/cpp/src/generate/t_cpp_generator.h
@@ -18,14 +18,15 @@
*/
class t_cpp_generator : public t_oop_generator {
public:
- t_cpp_generator() {}
+ t_cpp_generator(t_program* program) :
+ t_oop_generator(program) {}
/**
* Init and close methods
*/
- void init_generator(t_program *tprogram);
- void close_generator(t_program *tprogram);
+ void init_generator();
+ void close_generator();
/**
* Program-level generation functions
@@ -49,7 +50,8 @@
void generate_service_multiface (t_service* tservice);
void generate_service_helpers (t_service* tservice);
void generate_service_client (t_service* tservice);
- void generate_service_server (t_service* tservice);
+ void generate_service_processor (t_service* tservice);
+ void generate_service_skeleton (t_service* tservice);
void generate_process_function (t_service* tservice, t_function* tfunction);
void generate_function_helpers (t_function* tfunction);
@@ -109,6 +111,7 @@
* Helper rendering functions
*/
+ std::string namespace_prefix(std::string ns);
std::string namespace_open(std::string ns);
std::string namespace_close(std::string ns);
std::string type_name(t_type* ttype);
diff --git a/compiler/cpp/src/generate/t_generator.cc b/compiler/cpp/src/generate/t_generator.cc
index dc09ba1..30830d6 100644
--- a/compiler/cpp/src/generate/t_generator.cc
+++ b/compiler/cpp/src/generate/t_generator.cc
@@ -9,43 +9,40 @@
* @param program The thrift program to compile into C++ source
* @author Mark Slee <mcslee@facebook.com>
*/
-void t_generator::generate_program(t_program *tprogram) {
- // Set program name
- program_name_ = get_program_name(tprogram);
-
+void t_generator::generate_program() {
// Initialize the generator
- init_generator(tprogram);
+ init_generator();
// Generate typedefs
- vector<t_typedef*> typedefs = tprogram->get_typedefs();
+ vector<t_typedef*> typedefs = program_->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*> enums = program_->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*> structs = program_->get_structs();
vector<t_struct*>::iterator st_iter;
for (st_iter = structs.begin(); st_iter != structs.end(); ++st_iter) {
generate_struct(*st_iter);
}
// Generate xceptions
- vector<t_struct*> xceptions = tprogram->get_xceptions();
+ vector<t_struct*> xceptions = program_->get_xceptions();
vector<t_struct*>::iterator x_iter;
for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
generate_xception(*x_iter);
}
// Generate services
- vector<t_service*> services = tprogram->get_services();
+ vector<t_service*> services = program_->get_services();
vector<t_service*>::iterator sv_iter;
for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
service_name_ = get_service_name(*sv_iter);
@@ -53,5 +50,5 @@
}
// Close the generator
- close_generator(tprogram);
+ close_generator();
}
diff --git a/compiler/cpp/src/generate/t_generator.h b/compiler/cpp/src/generate/t_generator.h
index 07eaf38..18a2247 100644
--- a/compiler/cpp/src/generate/t_generator.h
+++ b/compiler/cpp/src/generate/t_generator.h
@@ -15,8 +15,11 @@
*/
class t_generator {
public:
- t_generator() {
+ t_generator(t_program* program) {
tmp_ = 0;
+ indent_ = 0;
+ program_ = program;
+ program_name_ = get_program_name(program);
}
virtual ~t_generator() {}
@@ -26,7 +29,7 @@
* 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);
+ void generate_program();
protected:
@@ -35,8 +38,8 @@
* steps at the beginning or end of code generation.
*/
- virtual void init_generator (t_program* tprogram) {}
- virtual void close_generator (t_program* tprogram) {}
+ virtual void init_generator() {}
+ virtual void close_generator() {}
/**
* Pure virtual methods implemented by the generator subclasses.
@@ -108,6 +111,11 @@
protected:
/**
+ * The program being generated
+ */
+ t_program* program_;
+
+ /**
* Quick accessor for formatted program name that is currently being
* generated.
*/
diff --git a/compiler/cpp/src/generate/t_java_generator.cc b/compiler/cpp/src/generate/t_java_generator.cc
index b99c748..1c43fdb 100644
--- a/compiler/cpp/src/generate/t_java_generator.cc
+++ b/compiler/cpp/src/generate/t_java_generator.cc
@@ -10,10 +10,10 @@
*
* @param tprogram The program to generate
*/
-void t_java_generator::init_generator(t_program* tprogram) {
+void t_java_generator::init_generator() {
// Make output directory
mkdir(T_JAVA_DIR, S_IREAD | S_IWRITE | S_IEXEC);
- package_name_ = tprogram->get_namespace();
+ package_name_ = program_->get_java_package();
}
/**
@@ -22,7 +22,10 @@
* @return String of the package, i.e. "package com.facebook.thriftdemo;"
*/
string t_java_generator::java_package() {
- return string("package ") + package_name_ + ";\n\n";
+ if (!package_name_.empty()) {
+ return string("package ") + package_name_ + ";\n\n";
+ }
+ return "";
}
/**
@@ -54,7 +57,7 @@
/**
* Nothing in Java
*/
-void t_java_generator::close_generator(t_program *tprogram) {}
+void t_java_generator::close_generator() {}
/**
* Generates a typedef. This is not done in Java, since it does
@@ -163,7 +166,7 @@
bool is_exception,
bool in_class,
bool is_result) {
- out <<
+ indent(out) <<
"public " << (in_class ? "static " : "") << "class " << tstruct->get_name() << " ";
if (is_exception) {
@@ -441,8 +444,15 @@
* @param tservice The service to generate a header definition for
*/
void t_java_generator::generate_service_interface(t_service* tservice) {
+ string extends = "";
+ string extends_iface = "";
+ if (tservice->get_extends() != NULL) {
+ extends = type_name(tservice->get_extends());
+ extends_iface = " extends " + extends + ".Iface";
+ }
+
f_service_ <<
- indent() << "public interface Iface {" << endl;
+ indent() << "public interface Iface" << extends_iface << " {" << endl;
indent_up();
vector<t_function*> functions = tservice->get_functions();
vector<t_function*>::iterator f_iter;
@@ -477,8 +487,15 @@
* @param tservice The service to generate a server for.
*/
void t_java_generator::generate_service_client(t_service* tservice) {
- f_service_ <<
- "public static class Client implements Iface {" << endl;
+ string extends = "";
+ string extends_client = "";
+ if (tservice->get_extends() != NULL) {
+ extends = type_name(tservice->get_extends());
+ extends_client = " extends " + extends + ".Client";
+ }
+
+ indent(f_service_) <<
+ "public static class Client" << extends_client << " implements Iface {" << endl;
indent_up();
indent(f_service_) <<
@@ -493,22 +510,29 @@
"public Client(TTransport itrans, TTransport otrans," <<
" TProtocol iprot, TProtocol oprot)" << endl;
scope_up(f_service_);
- f_service_ <<
- indent() << "_itrans = itrans;" << endl <<
- indent() << "_otrans = otrans;" << endl <<
- indent() << "_iprot = iprot;" << endl <<
- indent() << "_oprot = oprot;" << endl;
+ if (extends.empty()) {
+ f_service_ <<
+ indent() << "_itrans = itrans;" << endl <<
+ indent() << "_otrans = otrans;" << endl <<
+ indent() << "_iprot = iprot;" << endl <<
+ indent() << "_oprot = oprot;" << endl;
+ } else {
+ f_service_ <<
+ indent() << "super(itrans, otrans, iprot, oprot);" << endl;
+ }
scope_down(f_service_);
f_service_ << endl;
- f_service_ <<
- indent() << "private TTransport _itrans;" << endl <<
- indent() << "private TTransport _otrans;" << endl <<
- indent() << "private TProtocol _iprot;" << endl <<
- indent() << "private TProtocol _oprot;" << endl <<
- endl <<
- indent() << "private int _seqid;" << endl <<
- endl;
+ if (extends.empty()) {
+ f_service_ <<
+ indent() << "protected TTransport _itrans;" << endl <<
+ indent() << "protected TTransport _otrans;" << endl <<
+ indent() << "protected TProtocol _iprot;" << endl <<
+ indent() << "protected TProtocol _oprot;" << endl <<
+ endl <<
+ indent() << "protected int _seqid;" << endl <<
+ endl;
+ }
// Generate client method implementations
vector<t_function*> functions = tservice->get_functions();
@@ -551,7 +575,7 @@
scope_down(f_service_);
f_service_ << endl;
- t_function send_function(g_program->get_void_type(),
+ t_function send_function(g_type_void,
string("send_") + (*f_iter)->get_name(),
(*f_iter)->get_arglist());
@@ -583,7 +607,7 @@
if (!(*f_iter)->is_async()) {
string resultname = (*f_iter)->get_name() + "_result";
- t_struct noargs;
+ t_struct noargs(program_);
t_function recv_function((*f_iter)->get_returntype(),
string("recv_") + (*f_iter)->get_name(),
&noargs,
@@ -635,7 +659,7 @@
}
indent_down();
- f_service_ <<
+ indent(f_service_) <<
"}" << endl;
}
@@ -649,9 +673,17 @@
vector<t_function*> functions = tservice->get_functions();
vector<t_function*>::iterator f_iter;
+ // Extends stuff
+ string extends = "";
+ string extends_processor = "";
+ if (tservice->get_extends() != NULL) {
+ extends = type_name(tservice->get_extends());
+ extends_processor = " extends " + extends + ".Processor";
+ }
+
// Generate the header portion
- f_service_ <<
- "public static class Processor implements TProcessor {" << endl;
+ indent(f_service_) <<
+ "public static class Processor" << extends_processor << " implements TProcessor {" << endl;
indent_up();
indent(f_service_) <<
@@ -665,17 +697,48 @@
indent(f_service_) <<
"public Processor(Iface iface, TProtocol iprot, TProtocol oprot)" << endl;
scope_up(f_service_);
+ if (extends.empty()) {
+ f_service_ <<
+ indent() << "_iprot = iprot;" << endl <<
+ indent() << "_oprot = oprot;" << endl;
+ } else {
+ f_service_ <<
+ indent() << "super(iface, iprot, oprot);" << endl;
+ }
f_service_ <<
- indent() << "_iface = iface;" << endl <<
- indent() << "_iprot = iprot;" << endl <<
- indent() << "_oprot = oprot;" << endl;
+ indent() << "_iface = iface;" << endl;
+
+ for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+ f_service_ <<
+ indent() << "_processMap.put(\"" << (*f_iter)->get_name() << "\", new " << (*f_iter)->get_name() << "());" << endl;
+ }
+
scope_down(f_service_);
f_service_ << endl;
-
+
+ if (extends.empty()) {
+ f_service_ <<
+ indent() << "private static interface ProcessFunction {" << endl <<
+ indent() << " public void process(int seqid, TTransport _itrans, TTransport _otrans) throws TException;" << endl <<
+ indent() << "}" << endl <<
+ endl;
+ }
+
f_service_ <<
- indent() << "private Iface _iface;" << endl <<
- indent() << "private TProtocol _iprot;" << endl <<
- indent() << "private TProtocol _oprot;" << endl << endl;
+ indent() << "private Iface _iface;" << endl;
+
+ if (extends.empty()) {
+ f_service_ <<
+ indent() << "protected final HashMap<String,ProcessFunction> _processMap = new HashMap<String,ProcessFunction>();" << endl;
+ }
+
+ if (extends.empty()) {
+ f_service_ <<
+ indent() << "protected TProtocol _iprot;" << endl <<
+ indent() << "protected TProtocol _oprot;" << endl;
+ }
+
+ f_service_ << endl;
// Generate the server implementation
indent(f_service_) <<
@@ -683,34 +746,17 @@
scope_up(f_service_);
f_service_ <<
- indent() << "TMessage _msg = _iprot.readMessageBegin(_itrans);" << endl;
+ indent() << "TMessage msg = _iprot.readMessageBegin(_itrans);" << endl;
// TODO(mcslee): validate message, was the seqid etc. legit?
- 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 (_msg.name.equals(\"" << (*f_iter)->get_name() <<"\")) {" << endl;
- indent_up();
- indent(f_service_) <<
- "process_" << (*f_iter)->get_name() << "(_msg.seqid, _itrans, _otrans);" << endl;
- indent_down();
- indent(f_service_) << "}";
- }
f_service_ <<
- " else {" << endl;
- indent_up();
- indent(f_service_) <<
- "System.err.println(\"Unknown function: '\" + _msg.name + \"'\");" << endl;
- indent_down();
- indent(f_service_) <<
- "}" << endl;
+ indent() << "ProcessFunction fn = _processMap.get(msg.name);" << endl <<
+ indent() << "if (fn == null) {" << endl <<
+ indent() << " System.err.println(\"Unknown function: '\" + msg.name + \"'\");" << endl <<
+ indent() << "} else {" << endl <<
+ indent() << " fn.process(msg.seqid, _itrans, _otrans);" << endl <<
+ indent() << "}" << endl;
// Read end of args field, the T_STOP, and the struct close
f_service_ <<
@@ -725,7 +771,7 @@
}
indent_down();
- f_service_ <<
+ indent(f_service_) <<
"}" << endl <<
endl;
}
@@ -740,7 +786,7 @@
return;
}
- t_struct result(tfunction->get_name() + "_result");
+ t_struct result(program_, tfunction->get_name() + "_result");
t_field success(tfunction->get_returntype(), "success", 0);
if (!tfunction->get_returntype()->is_void()) {
result.append(&success);
@@ -763,9 +809,14 @@
*/
void t_java_generator::generate_process_function(t_service* tservice,
t_function* tfunction) {
+ // Open class
+ indent(f_service_) <<
+ "private class " << tfunction->get_name() << " implements ProcessFunction {" << endl;
+ indent_up();
+
// Open function
indent(f_service_) <<
- "private void process_" << tfunction->get_name() << "(int seqid, TTransport _itrans, TTransport _otrans) throws TException" << endl;
+ "public void process(int seqid, TTransport _itrans, TTransport _otrans) throws TException" << endl;
scope_up(f_service_);
string argsname = tfunction->get_name() + "_args";
@@ -859,6 +910,12 @@
// Close function
scope_down(f_service_);
f_service_ << endl;
+
+ // Close class
+ indent_down();
+ f_service_ <<
+ indent() << "}" << endl <<
+ endl;
}
/**
@@ -942,7 +999,7 @@
t_struct* tstruct,
string prefix) {
out <<
- indent() << prefix << " = new " << tstruct->get_name() << "();" << endl <<
+ indent() << prefix << " = new " << type_name(tstruct) << "();" << endl <<
indent() << prefix << ".read(_iprot, _itrans);" << endl;
}
@@ -1296,9 +1353,18 @@
} else if (ttype->is_list()) {
t_list* tlist = (t_list*) ttype;
return "ArrayList<" + type_name(tlist->get_elem_type(), true) + ">";
- } else {
- return ttype->get_name();
}
+
+ // Check for namespacing
+ t_program* program = ttype->get_program();
+ if (program != NULL && program != program_) {
+ string package = program->get_java_package();
+ if (!package.empty()) {
+ return package + "." + ttype->get_name();
+ }
+ }
+
+ return ttype->get_name();
}
/**
diff --git a/compiler/cpp/src/generate/t_java_generator.h b/compiler/cpp/src/generate/t_java_generator.h
index e528c34..2b60e73 100644
--- a/compiler/cpp/src/generate/t_java_generator.h
+++ b/compiler/cpp/src/generate/t_java_generator.h
@@ -18,14 +18,15 @@
*/
class t_java_generator : public t_oop_generator {
public:
- t_java_generator() {}
+ t_java_generator(t_program* program) :
+ t_oop_generator(program) {}
/**
* Init and close methods
*/
- void init_generator(t_program *tprogram);
- void close_generator(t_program *tprogram);
+ void init_generator();
+ void close_generator();
/**
* Program-level generation functions
diff --git a/compiler/cpp/src/generate/t_oop_generator.h b/compiler/cpp/src/generate/t_oop_generator.h
index fc47bc6..d0d2946 100644
--- a/compiler/cpp/src/generate/t_oop_generator.h
+++ b/compiler/cpp/src/generate/t_oop_generator.h
@@ -12,6 +12,8 @@
*/
class t_oop_generator : public t_generator {
public:
+ t_oop_generator(t_program* program) :
+ t_generator(program) {}
/**
* Scoping, using curly braces!
diff --git a/compiler/cpp/src/generate/t_php_generator.cc b/compiler/cpp/src/generate/t_php_generator.cc
index 61df589..5a6b8ac 100644
--- a/compiler/cpp/src/generate/t_php_generator.cc
+++ b/compiler/cpp/src/generate/t_php_generator.cc
@@ -10,7 +10,7 @@
*
* @param tprogram The program to generate
*/
-void t_php_generator::init_generator(t_program* tprogram) {
+void t_php_generator::init_generator() {
// Make output directory
mkdir(T_PHP_DIR, S_IREAD | S_IWRITE | S_IEXEC);
@@ -36,7 +36,7 @@
/**
* Close up (or down) some filez.
*/
-void t_php_generator::close_generator(t_program *tprogram) {
+void t_php_generator::close_generator() {
// Close types file
f_types_ << "?>" << endl;
f_types_.close();
@@ -80,7 +80,6 @@
// We're also doing it this way to see how it performs. It's more legible
// code but you can't do things like an 'extract' on it, which is a bit of
// a downer.
-
f_types_ <<
"final class " << tenum->get_name() << " {" << endl;
indent_up();
@@ -97,6 +96,10 @@
"const " << (*c_iter)->get_name() << " = " << value << ";" << endl;
}
+ // Prevent instantiation of this class
+ f_types_ <<
+ indent() << "private function __construct() {}" << endl;
+
indent_down();
f_types_ << "}" << endl << endl;
}
@@ -201,8 +204,8 @@
// Read beginning field marker
if (binary_inline_) {
- t_field fftype(g_program->get_byte_type(), "ftype");
- t_field ffid(g_program->get_i16_type(), "fid");
+ t_field fftype(g_type_byte, "ftype");
+ t_field ffid(g_type_i16, "fid");
generate_deserialize_field(out, &fftype);
out <<
indent() << "if ($ftype == TType::STOP) {" << endl <<
@@ -364,7 +367,15 @@
php_includes();
f_service_ <<
- "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << program_name_ << "/" << program_name_ << "_types.php';" << endl << endl;
+ "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << program_name_ << "/" << program_name_ << "_types.php';" << endl;
+
+ if (tservice->get_extends() != NULL) {
+ f_service_ <<
+ "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << tservice->get_extends()->get_program()->get_name() << "/" << tservice->get_extends()->get_name() << ".php';" << endl;
+ }
+
+ f_service_ <<
+ endl;
// Generate the three main parts of the service (well, two for now in PHP)
generate_service_interface(tservice);
@@ -387,32 +398,55 @@
vector<t_function*> functions = tservice->get_functions();
vector<t_function*>::iterator f_iter;
+ string extends = "";
+ string extends_processor = "";
+ if (tservice->get_extends() != NULL) {
+ extends = tservice->get_extends()->get_name();
+ extends_processor = " extends " + extends + "Processor";
+ }
+
// Generate the header portion
f_service_ <<
- "class " << service_name_ << "Processor {" << endl;
+ "class " << service_name_ << "Processor" << extends_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 (extends.empty()) {
+ f_service_ <<
+ indent() << "protected $_handler = null;" << endl;
+ if (!binary_inline_) {
+ f_service_ <<
+ indent() << "protected $_iprot = null;" << endl <<
+ indent() << "protected $_oprot = null;" << endl <<
+ endl;
+ }
}
if (binary_inline_) {
f_service_ <<
- indent() << "public function __construct($handler) {" << endl <<
- indent() << " $this->_handler = $handler;" << endl <<
+ indent() << "public function __construct($handler) {" << endl;
+ if (extends.empty()) {
+ f_service_ <<
+ indent() << " $this->_handler = $handler;" << endl;
+ } else {
+ f_service_ <<
+ indent() << " parent::__construct($handler);" << endl;
+ }
+ f_service_ <<
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() << "public function __construct($handler, $iprot, $oprot=null) {" << endl;
+ if (extends.empty()) {
+ f_service_ <<
+ indent() << " $this->_handler = $handler;" << endl <<
+ indent() << " $this->_iprot = $iprot;" << endl <<
+ indent() << " $this->_oprot = $oprot ? $oprot : $iprot;" << endl;
+ } else {
+ f_service_ <<
+ indent() << " parent::__construct($handler, $iprot, $oprot);" << endl;
+ }
+ f_service_ <<
indent() << "}" << endl <<
endl;
}
@@ -429,9 +463,9 @@
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");
+ t_field ffname(g_type_string, "fname");
+ t_field fmtype(g_type_byte, "mtype");
+ t_field fseqid(g_type_i32, "rseqid");
generate_deserialize_field(f_service_, &ffname, "", true);
generate_deserialize_field(f_service_, &fmtype, "", true);
generate_deserialize_field(f_service_, &fseqid, "", true);
@@ -602,7 +636,7 @@
* @param tfunction The function
*/
void t_php_generator::generate_php_function_helpers(t_function* tfunction) {
- t_struct result(service_name_ + "_" + tfunction->get_name() + "_result");
+ t_struct result(program_, service_name_ + "_" + tfunction->get_name() + "_result");
t_field success(tfunction->get_returntype(), "success", 0);
if (!tfunction->get_returntype()->is_void()) {
result.append(&success);
@@ -624,14 +658,20 @@
* @param tservice The service to generate a header definition for
*/
void t_php_generator::generate_service_interface(t_service* tservice) {
+ string extends = "";
+ string extends_if = "";
+ if (tservice->get_extends() != NULL) {
+ extends = " extends " + tservice->get_extends()->get_name();
+ extends_if = " extends " + tservice->get_extends()->get_name() + "If";
+ }
f_service_ <<
- "abstract class " << service_name_ << "If {" << endl;
+ "interface " << service_name_ << "If" << extends_if << " {" << 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) {
indent(f_service_) <<
- "public abstract function " << function_signature(*f_iter) << ";" << endl;
+ "public function " << function_signature(*f_iter) << ";" << endl;
}
indent_down();
f_service_ <<
@@ -644,53 +684,59 @@
* @param tservice The service to generate a server for.
*/
void t_php_generator::generate_service_client(t_service* tservice) {
- f_service_ <<
- "class " << service_name_ << "Client " <<
- "extends " << service_name_ << "If {" << endl;
- indent_up();
-
- // Private members
- f_service_ <<
- indent() << "private $_itrans = null;" << endl <<
- indent() << "private $_otrans = null;" << endl <<
- endl;
-
- if (!binary_inline_) {
- f_service_ <<
- indent() << "private $_iprot = null;" << endl <<
- indent() << "private $_oprot = null;" << endl <<
- endl;
+ string extends = "";
+ string extends_client = "";
+ if (tservice->get_extends() != NULL) {
+ extends = tservice->get_extends()->get_name();
+ extends_client = " extends " + extends + "Client";
}
f_service_ <<
- indent() << "private $_seqid = 0;" << endl <<
- endl;
+ "class " << service_name_ << "Client" << extends_client << " implements " << service_name_ << "If {" << endl;
+ indent_up();
+
+ // Private members
+ if (extends.empty()) {
+ f_service_ <<
+ indent() << "protected $_itrans = null;" << endl <<
+ indent() << "protected $_otrans = null;" << endl <<
+ endl;
+ if (!binary_inline_) {
+ f_service_ <<
+ indent() << "protected $_iprot = null;" << endl <<
+ indent() << "protected $_oprot = null;" << endl <<
+ endl;
+ }
+ f_service_ <<
+ indent() << "protected $_seqid = 0;" << endl <<
+ endl;
+ }
// Constructor function
f_service_ <<
- indent() << "public function __construct() {" << endl <<
- indent() << " $argv = func_get_args();" << endl <<
- indent() << " $argc = count($argv);" << endl;
-
- if (binary_inline_) {
+ indent() << "public function __construct() {" << endl;
+ f_service_ <<
+ indent() << " $argv = func_get_args();" << endl;
+ if (!extends.empty()) {
f_service_ <<
- indent() << " if ($argc == 1) {" << endl <<
- indent() << " $this->_itrans = $this->_otrans = $argv[0];" << endl <<
- indent() << " } else if ($argc == 2) {" << endl <<
- indent() << " $this->_itrans = $argv[0];" << endl <<
- indent() << " $this->_otrans = $argv[1];" << endl <<
- indent() << " }" << endl;
+ indent() << " parent::__construct($argv[0], $argv[1], $argv[2], $argv[3]);" << endl;
} else {
- f_service_ <<
- indent() << " if ($argc == 2) {" << endl <<
- indent() << " $this->_itrans = $this->_otrans = $argv[0];" << endl <<
- indent() << " $this->_iprot = $this->_oprot = $argv[1];" << endl <<
- indent() << " } else if ($argc == 4) {" << endl <<
- indent() << " $this->_itrans = $argv[0];" << endl <<
- indent() << " $this->_otrans = $argv[1];" << endl <<
- indent() << " $this->_iprot = $argv[2];" << endl <<
- indent() << " $this->_oprot = $argv[3];" << endl <<
- indent() << " }" << endl;
+ if (binary_inline_) {
+ f_service_ <<
+ indent() << " $this->_itrans = $this->_otrans = $argv[0];" << endl <<
+ indent() << " if ($argv[1]) {" << endl <<
+ indent() << " $this->_otrans = $argv[1];" << endl <<
+ indent() << " }" << endl;
+ } else {
+ f_service_ <<
+ indent() << " $this->_itrans = $this->_otrans = $argv[0];" << endl <<
+ indent() << " $this->_iprot = $this->_oprot = $argv[1];" << endl <<
+ indent() << " if ($argv[2]) {" << endl <<
+ indent() << " $this->_otrans = $argv[1];" << endl <<
+ indent() << " $this->_iprot = $argv[2];" << endl <<
+ indent() << " $this->_oprot = $argv[3];" << endl <<
+ indent() << " }" << endl;
+ }
}
f_service_ <<
indent() << "}" << endl << endl;
@@ -780,7 +826,7 @@
if (!(*f_iter)->is_async()) {
std::string resultname = service_name_ + "_" + (*f_iter)->get_name() + "_result";
- t_struct noargs;
+ t_struct noargs(program_);
t_function recv_function((*f_iter)->get_returntype(),
string("recv_") + (*f_iter)->get_name(),
@@ -798,9 +844,9 @@
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");
+ t_field ffname(g_type_string, "fname");
+ t_field fmtype(g_type_byte, "mtype");
+ t_field fseqid(g_type_i32, "rseqid");
generate_deserialize_field(f_service_, &ffname, "", true);
generate_deserialize_field(f_service_, &fmtype, "", true);
generate_deserialize_field(f_service_, &fseqid, "", true);
@@ -1046,10 +1092,10 @@
string vtype = tmp("_vtype");
string etype = tmp("_etype");
- t_field fsize(g_program->get_i32_type(), size);
- t_field fktype(g_program->get_byte_type(), ktype);
- t_field fvtype(g_program->get_byte_type(), vtype);
- t_field fetype(g_program->get_byte_type(), etype);
+ t_field fsize(g_type_i32, size);
+ t_field fktype(g_type_byte, ktype);
+ t_field fvtype(g_type_byte, vtype);
+ t_field fetype(g_type_byte, etype);
out <<
indent() << "$" << prefix << " = array();" << endl <<
diff --git a/compiler/cpp/src/generate/t_php_generator.h b/compiler/cpp/src/generate/t_php_generator.h
index 0e6869b..609cbae 100644
--- a/compiler/cpp/src/generate/t_php_generator.h
+++ b/compiler/cpp/src/generate/t_php_generator.h
@@ -15,8 +15,9 @@
*/
class t_php_generator : public t_oop_generator {
public:
- t_php_generator(bool binary_inline=false) {
- binary_inline_ = binary_inline;
+ t_php_generator(t_program* program, bool binary_inline=false) :
+ t_oop_generator(program),
+ binary_inline_(binary_inline) {
if (binary_inline_) {
T_PHP_DIR = "gen-phpi";
} else {
@@ -28,8 +29,8 @@
* Init and close methods
*/
- void init_generator(t_program *tprogram);
- void close_generator(t_program *tprogram);
+ void init_generator();
+ void close_generator();
/**
* Program-level generation functions
diff --git a/compiler/cpp/src/generate/t_py_generator.cc b/compiler/cpp/src/generate/t_py_generator.cc
index 9838df6..6398f11 100644
--- a/compiler/cpp/src/generate/t_py_generator.cc
+++ b/compiler/cpp/src/generate/t_py_generator.cc
@@ -11,7 +11,7 @@
*
* @param tprogram The program to generate
*/
-void t_py_generator::init_generator(t_program* tprogram) {
+void t_py_generator::init_generator() {
// Make output directory
mkdir(T_PY_DIR, S_IREAD | S_IWRITE | S_IEXEC);
@@ -23,7 +23,22 @@
f_types_ <<
py_autogen_comment() << endl <<
py_imports() << endl <<
- endl;
+ render_includes() << endl;
+}
+
+/**
+ * Renders all the imports necessary for including another Thrift program
+ */
+string t_py_generator::render_includes() {
+ const vector<t_program*>& includes = program_->get_includes();
+ string result = "";
+ for (size_t i = 0; i < includes.size(); ++i) {
+ result += "import " + includes[i]->get_name() + "_types\n";
+ }
+ if (includes.size() > 0) {
+ result += "\n";
+ }
+ return result;
}
/**
@@ -50,7 +65,7 @@
/**
* Closes the type files
*/
-void t_py_generator::close_generator(t_program *tprogram) {
+void t_py_generator::close_generator() {
// Close types file
f_types_.close();
}
@@ -307,6 +322,11 @@
py_autogen_comment() << endl <<
py_imports() << endl;
+ if (tservice->get_extends() != NULL) {
+ f_service_ <<
+ "import " << tservice->get_extends()->get_name() << endl;
+ }
+
f_service_ <<
"from " << program_name_ << "_types import *" << endl <<
"from thrift.Thrift import TProcessor" << endl <<
@@ -315,8 +335,8 @@
// Generate the three main parts of the service (well, two for now in PHP)
generate_service_interface(tservice);
generate_service_client(tservice);
- generate_service_helpers(tservice);
generate_service_server(tservice);
+ generate_service_helpers(tservice);
generate_service_remote(tservice);
// Close service file
@@ -349,7 +369,7 @@
* @param tfunction The function
*/
void t_py_generator::generate_py_function_helpers(t_function* tfunction) {
- t_struct result(tfunction->get_name() + "_result");
+ t_struct result(program_, tfunction->get_name() + "_result");
t_field success(tfunction->get_returntype(), "success", 0);
if (!tfunction->get_returntype()->is_void()) {
result.append(&success);
@@ -370,8 +390,15 @@
* @param tservice The service to generate a header definition for
*/
void t_py_generator::generate_service_interface(t_service* tservice) {
+ string extends = "";
+ string extends_if = "";
+ if (tservice->get_extends() != NULL) {
+ extends = type_name(tservice->get_extends());
+ extends_if = "(" + extends + ".Iface)";
+ }
+
f_service_ <<
- "class Iface:" << endl;
+ "class Iface" << extends_if << ":" << endl;
indent_up();
vector<t_function*> functions = tservice->get_functions();
vector<t_function*>::iterator f_iter;
@@ -391,25 +418,39 @@
* @param tservice The service to generate a server for.
*/
void t_py_generator::generate_service_client(t_service* tservice) {
+ string extends = "";
+ string extends_client = "";
+ if (tservice->get_extends() != NULL) {
+ extends = type_name(tservice->get_extends());
+ extends_client = extends + ".Client, ";
+ }
+
f_service_ <<
- "class Client(Iface):" << endl;
+ "class Client(" << extends_client << "Iface):" << endl;
indent_up();
// Constructor function
f_service_ <<
- indent() << "def __init__(self, one, two, three=None, four=None):" << endl <<
- indent() << " if three == None or four == None:" << endl <<
- indent() << " self.__otrans = one" << endl <<
- indent() << " self.__itrans = one" << endl <<
- indent() << " self.__iprot = two" << endl <<
- indent() << " self.__oprot = two" << endl <<
- indent() << " else:" << endl <<
- indent() << " self.__otrans = one" << endl <<
- indent() << " self.__itrans = two" << endl <<
- indent() << " self.__iprot = three" << endl <<
- indent() << " self.__oprot = four" << endl <<
- indent() << " self.__seqid = 0" << endl <<
- endl;
+ indent() << "def __init__(self, one, two, three=None, four=None):" << endl;
+ if (extends.empty()) {
+ f_service_ <<
+ indent() << " if three == None or four == None:" << endl <<
+ indent() << " self._otrans = one" << endl <<
+ indent() << " self._itrans = one" << endl <<
+ indent() << " self._iprot = two" << endl <<
+ indent() << " self._oprot = two" << endl <<
+ indent() << " else:" << endl <<
+ indent() << " self._otrans = one" << endl <<
+ indent() << " self._itrans = two" << endl <<
+ indent() << " self._iprot = three" << endl <<
+ indent() << " self._oprot = four" << endl <<
+ indent() << " self._seqid = 0" << endl <<
+ endl;
+ } else {
+ f_service_ <<
+ indent() << " " << extends << ".Client.__init__(self, one, two, three, four)" << endl <<
+ endl;
+ }
// Generate client method implementations
vector<t_function*> functions = tservice->get_functions();
@@ -457,7 +498,7 @@
// Serialize the request header
f_service_ <<
- indent() << "self.__oprot.writeMessageBegin(self.__otrans, '" << (*f_iter)->get_name() << "', TMessageType.CALL, self.__seqid)" << endl;
+ indent() << "self._oprot.writeMessageBegin(self._otrans, '" << (*f_iter)->get_name() << "', TMessageType.CALL, self._seqid)" << endl;
f_service_ <<
indent() << "__args = " << argsname << "()" << endl;
@@ -469,16 +510,16 @@
// Write to the stream
f_service_ <<
- indent() << "__args.write(self.__oprot, self.__otrans)" << endl <<
- indent() << "self.__oprot.writeMessageEnd(self.__otrans)" << endl <<
- indent() << "self.__otrans.flush()" << endl;
+ indent() << "__args.write(self._oprot, self._otrans)" << endl <<
+ indent() << "self._oprot.writeMessageEnd(self._otrans)" << endl <<
+ indent() << "self._otrans.flush()" << endl;
indent_down();
if (!(*f_iter)->is_async()) {
std::string resultname = (*f_iter)->get_name() + "_result";
- t_struct noargs;
+ t_struct noargs(program_);
t_function recv_function((*f_iter)->get_returntype(),
string("recv_") + (*f_iter)->get_name(),
@@ -490,14 +531,14 @@
indent_up();
f_service_ <<
- indent() << "(fname, mtype, rseqid) = self.__iprot.readMessageBegin(self.__itrans)" << endl;
+ indent() << "(fname, mtype, rseqid) = self._iprot.readMessageBegin(self._itrans)" << endl;
// TODO(mcslee): Validate message reply here, seq ids etc.
f_service_ <<
indent() << "__result = " << resultname << "()" << endl <<
- indent() << "__result.read(self.__iprot, self.__otrans)" << endl <<
- indent() << "self.__iprot.readMessageEnd(self.__itrans)" << endl;
+ indent() << "__result.read(self._iprot, self._otrans)" << endl <<
+ indent() << "self._iprot.readMessageEnd(self._itrans)" << endl;
// Careful, only return _result if not a void function
if (!(*f_iter)->get_returntype()->is_void()) {
@@ -645,7 +686,7 @@
" sys.exit(1)" << endl <<
" pp.pprint(client." << (*f_iter)->get_name() << "(";
for (int i = 0; i < num_args; ++i) {
- if (args[i]->get_type() == g_program->get_string_type()) {
+ if (args[i]->get_type() == g_type_string) {
f_remote << "args[" << i << "],";
} else {
f_remote << "eval(args[" << i << "]),";
@@ -682,29 +723,35 @@
vector<t_function*> functions = tservice->get_functions();
vector<t_function*>::iterator f_iter;
+ string extends = "";
+ string extends_processor = "";
+ if (tservice->get_extends() != NULL) {
+ extends = type_name(tservice->get_extends());
+ extends_processor = extends + ".Processor, ";
+ }
+
// Generate the header portion
f_service_ <<
- "class Processor(Iface, TProcessor):" << endl;
+ "class Processor(" << extends_processor << "Iface, TProcessor):" << endl;
indent_up();
indent(f_service_) <<
"def __init__(self, handler, iprot, oprot=None):" << endl;
indent_up();
- f_service_ <<
- indent() << "self.__handler = handler" << endl <<
- indent() << "self.__iprot = iprot" << endl <<
- indent() << "if oprot == None:" << endl <<
- indent() << " self.__oprot = iprot" << endl <<
- indent() << "else:" << endl <<
- indent() << " self.__oprot = oprot" << endl <<
- indent() << "self.__processMap = {" << endl;
+ if (extends.empty()) {
+ f_service_ <<
+ indent() << "self._handler = handler" << endl <<
+ indent() << "self._iprot = iprot" << endl <<
+ indent() << "if oprot == None:" << endl <<
+ indent() << " self._oprot = iprot" << endl <<
+ indent() << "else:" << endl <<
+ indent() << " self._oprot = oprot" << endl <<
+ indent() << "self._processMap = {}" << endl;
+ }
for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
f_service_ <<
- indent() << " \"" << (*f_iter)->get_name() << "\" : Processor.process_" << (*f_iter)->get_name() << "," << endl;
- }
- f_service_ <<
- indent() << "}" << endl;
-
+ indent() << "self._processMap[\"" << (*f_iter)->get_name() << "\"] = Processor.process_" << (*f_iter)->get_name() << endl;
+ }
indent_down();
f_service_ << endl;
@@ -714,16 +761,16 @@
indent_up();
f_service_ <<
- indent() << "(name, type, seqid) = self.__iprot.readMessageBegin(itrans)" << endl;
+ indent() << "(name, type, seqid) = self._iprot.readMessageBegin(itrans)" << endl;
// TODO(mcslee): validate message
// HOT: dictionary function lookup
f_service_ <<
- indent() << "if name not in self.__processMap:" << endl <<
+ 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;
+ indent() << " self._processMap[name](self, seqid, itrans, otrans)" << endl;
// Read end of args field, the T_STOP, and the struct close
f_service_ <<
@@ -759,8 +806,8 @@
f_service_ <<
indent() << "__args = " << argsname << "()" << endl <<
- indent() << "__args.read(self.__iprot, itrans)" << endl <<
- indent() << "self.__iprot.readMessageEnd(itrans)" << endl;
+ indent() << "__args.read(self._iprot, itrans)" << endl <<
+ indent() << "self._iprot.readMessageEnd(itrans)" << endl;
t_struct* xs = tfunction->get_xceptions();
const std::vector<t_field*>& xceptions = xs->get_members();
@@ -789,7 +836,7 @@
f_service_ << "__result.success = ";
}
f_service_ <<
- "self.__handler." << tfunction->get_name() << "(";
+ "self._handler." << tfunction->get_name() << "(";
bool first = true;
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
if (first) {
@@ -828,9 +875,9 @@
}
f_service_ <<
- indent() << "self.__oprot.writeMessageBegin(otrans, \"" << tfunction->get_name() << "\", TMessageType.REPLY, seqid)" << endl <<
- indent() << "__result.write(self.__oprot, otrans)" << endl <<
- indent() << "self.__oprot.writeMessageEnd(otrans)" << endl <<
+ indent() << "self._oprot.writeMessageBegin(otrans, \"" << tfunction->get_name() << "\", TMessageType.REPLY, seqid)" << endl <<
+ indent() << "__result.write(self._oprot, otrans)" << endl <<
+ indent() << "self._oprot.writeMessageEnd(otrans)" << endl <<
indent() << "otrans.flush()" << endl;
// Close function
@@ -916,7 +963,7 @@
t_struct* tstruct,
string prefix) {
out <<
- indent() << prefix << " = " << tstruct->get_name() << "()" << endl <<
+ indent() << prefix << " = " << type_name(tstruct) << "()" << endl <<
indent() << prefix << ".read(iprot, itrans)" << endl;
}
@@ -932,10 +979,10 @@
string vtype = tmp("_vtype");
string etype = tmp("_etype");
- t_field fsize(g_program->get_i32_type(), size);
- t_field fktype(g_program->get_byte_type(), ktype);
- t_field fvtype(g_program->get_byte_type(), vtype);
- t_field fetype(g_program->get_byte_type(), etype);
+ t_field fsize(g_type_i32, size);
+ t_field fktype(g_type_byte, ktype);
+ t_field fvtype(g_type_byte, vtype);
+ t_field fetype(g_type_byte, etype);
// Declare variables, read header
if (ttype->is_map()) {
@@ -991,13 +1038,6 @@
t_field fkey(tmap->get_key_type(), key);
t_field fval(tmap->get_val_type(), val);
- /*
- indent(out) <<
- declare_field(&fkey, true, true) << endl;
- indent(out) <<
- declare_field(&fval, true, true) << endl;
- */
-
generate_deserialize_field(out, &fkey);
generate_deserialize_field(out, &fval);
@@ -1264,7 +1304,7 @@
}
} else if (type->is_struct() || type->is_xception()) {
if (obj) {
- result += " = " + type->get_name() + "()";
+ result += " = " + type_name((t_struct*)type) + "()";
} else {
result += " = None";
}
@@ -1307,6 +1347,18 @@
return result;
}
+string t_py_generator::type_name(t_type* ttype) {
+ t_program* program = ttype->get_program();
+ if (program != NULL && program != program_) {
+ if (ttype->is_service()) {
+ return ttype->get_name();
+ } else {
+ return program->get_name() + "_types." + ttype->get_name();
+ }
+ }
+ return ttype->get_name();
+}
+
/**
* Converts the parse type to a Python tyoe
*/
diff --git a/compiler/cpp/src/generate/t_py_generator.h b/compiler/cpp/src/generate/t_py_generator.h
index 238d10e..9cbc4a6 100644
--- a/compiler/cpp/src/generate/t_py_generator.h
+++ b/compiler/cpp/src/generate/t_py_generator.h
@@ -17,14 +17,15 @@
*/
class t_py_generator : public t_oop_generator {
public:
- t_py_generator() {}
+ t_py_generator(t_program* program) :
+ t_oop_generator(program) {}
/**
* Init and close methods
*/
- void init_generator(t_program *tprogram);
- void close_generator(t_program *tprogram);
+ void init_generator();
+ void close_generator();
/**
* Program-level generation functions
@@ -117,7 +118,9 @@
std::string py_autogen_comment();
std::string py_imports();
+ std::string render_includes();
std::string declare_field(t_field* tfield, bool init=false, bool obj=false);
+ std::string type_name(t_type* ttype);
std::string function_signature(t_function* tfunction, std::string prefix="");
std::string argument_list(t_struct* tstruct);
std::string type_to_enum(t_type* ttype);
diff --git a/compiler/cpp/src/globals.h b/compiler/cpp/src/globals.h
index 7385565..51502c7 100644
--- a/compiler/cpp/src/globals.h
+++ b/compiler/cpp/src/globals.h
@@ -1,7 +1,39 @@
#ifndef T_GLOBALS_H
#define T_GLOBALS_H
+#include <set>
+#include <queue>
+#include <stack>
+#include <vector>
+#include <string>
+
+/**
+ * This module contains all the global variables (slap on the wrist) that are
+ * shared throughout the program. The reason for this is to facilitate simple
+ * interaction between the parser and the rest of the program. Before calling
+ * yyparse(), the main.cc program will make necessary adjustments to these
+ * global variables such that the parser does the right thing and puts entries
+ * into the right containers, etc.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+
+/**
+ * Hooray for forward declaration of types!
+ */
+
class t_program;
+class t_scope;
+class t_type;
+
+/**
+ * Parsing mode, two passes up in this gin rummy!
+ */
+
+enum PARSE_MODE {
+ INCLUDES = 1,
+ PROGRAM = 2
+};
/**
* The master program parse tree. This is accessed from within the parser code
@@ -10,9 +42,37 @@
extern t_program* g_program;
/**
- * Global debug state
+ * Global types for the parser to be able to reference
*/
-extern int g_debug;
+
+extern t_type* g_type_void;
+extern t_type* g_type_string;
+extern t_type* g_type_bool;
+extern t_type* g_type_byte;
+extern t_type* g_type_i16;
+extern t_type* g_type_i32;
+extern t_type* g_type_i64;
+extern t_type* g_type_double;
+
+/**
+ * The scope that we are currently parsing into
+ */
+extern t_scope* g_scope;
+
+/**
+ * The parent scope to also load symbols into
+ */
+extern t_scope* g_parent_scope;
+
+/**
+ * The prefix for the parent scope entries
+ */
+extern std::string g_parent_prefix;
+
+/**
+ * The parsing pass that we are on. We do different things on each pass.
+ */
+extern PARSE_MODE g_parse_mode;
/**
* Global time string, used in formatting error messages etc.
diff --git a/compiler/cpp/src/main.cc b/compiler/cpp/src/main.cc
index 9a8e29e..aee89ae 100644
--- a/compiler/cpp/src/main.cc
+++ b/compiler/cpp/src/main.cc
@@ -13,12 +13,15 @@
#include <stdio.h>
#include <stdarg.h>
#include <string>
+#include <sys/types.h>
+#include <sys/stat.h>
-// Careful: must include globals first here for extern/global definitions
+// Careful: must include globals first for extern definitions
#include "globals.h"
#include "main.h"
#include "parse/t_program.h"
+#include "parse/t_scope.h"
#include "generate/t_cpp_generator.h"
#include "generate/t_java_generator.h"
#include "generate/t_php_generator.h"
@@ -32,16 +35,79 @@
t_program* g_program;
/**
+ * Global types
+ */
+
+t_type* g_type_void;
+t_type* g_type_string;
+t_type* g_type_bool;
+t_type* g_type_byte;
+t_type* g_type_i16;
+t_type* g_type_i32;
+t_type* g_type_i64;
+t_type* g_type_double;
+
+/**
+ * Global scope
+ */
+t_scope* g_scope;
+
+/**
+ * Parent scope to also parse types
+ */
+t_scope* g_parent_scope;
+
+/**
+ * Prefix for putting types in parent scope
+ */
+string g_parent_prefix;
+
+/**
+ * Parsing pass
+ */
+PARSE_MODE g_parse_mode;
+
+/**
+ * Current directory of file being parsed
+ */
+string g_curdir;
+
+/**
+ * Current file being parsed
+ */
+string g_curpath;
+
+/**
* Global debug state
*/
int g_debug = 0;
/**
+ * Warning level
+ */
+int g_warn = 1;
+
+/**
+ * Verbose output
+ */
+int g_verbose = 0;
+
+/**
* Global time string
*/
char* g_time_str;
/**
+ * Flags to control code generation
+ */
+bool gen_cpp = false;
+bool gen_java = false;
+bool gen_py = false;
+bool gen_php = false;
+bool gen_phpi = false;
+bool gen_recurse = false;
+
+/**
* Report an error to the user. This is called yyerror for historical
* reasons (lex and yacc expect the error reporting routine to be called
* this). Call this function to report any errors to the user.
@@ -52,10 +118,10 @@
void yyerror(char* fmt, ...) {
va_list args;
fprintf(stderr,
- "\n!!! Error: line %d (last token was '%s')",
+ "[ERROR:%s:%d] (last token was '%s')\n",
+ g_curpath.c_str(),
yylineno,
yytext);
- fprintf(stderr, "\n!!! ");
va_start(args, fmt);
vfprintf(stderr, fmt, args);
@@ -74,7 +140,39 @@
return;
}
va_list args;
- printf("[Parse] ");
+ printf("[PARSE] ");
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+ printf("\n");
+}
+
+/**
+ * Prints a verbose output mode message
+ *
+ * @param fmt C format string followed by additional arguments
+ */
+void pverbose(char* fmt, ...) {
+ if (g_verbose == 0) {
+ return;
+ }
+ va_list args;
+ va_start(args, fmt);
+ vprintf(fmt, args);
+ va_end(args);
+}
+
+/**
+ * Prints a warning message
+ *
+ * @param fmt C format string followed by additional arguments
+ */
+void pwarning(int level, char* fmt, ...) {
+ if (g_warn < level) {
+ return;
+ }
+ va_list args;
+ printf("[WARNING:%s:%d] ", g_curpath.c_str(), yylineno);
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
@@ -88,7 +186,7 @@
*/
void failure(char* fmt, ...) {
va_list args;
- fprintf(stderr, "\n!!! Failure: ");
+ fprintf(stderr, "[FAILURE:%s:%d] ", g_curpath.c_str(), yylineno);
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
@@ -97,38 +195,201 @@
}
/**
+ * Converts a string filename into a thrift program name
+ */
+string program_name(string filename) {
+ string::size_type slash = filename.rfind("/");
+ if (slash != string::npos) {
+ filename = filename.substr(slash+1);
+ }
+ string::size_type dot = filename.rfind(".");
+ if (dot != string::npos) {
+ filename = filename.substr(0, dot);
+ }
+ return filename;
+}
+
+/**
+ * Gets the directory path of a filename
+ */
+string directory_name(string filename) {
+ string::size_type slash = filename.rfind("/");
+ // No slash, just use the current directory
+ if (slash == string::npos) {
+ return ".";
+ }
+ return filename.substr(0, slash);
+}
+
+/**
+ * Finds the appropriate file path for the given filename
+ */
+string include_file(string filename) {
+ // Absolute path? Just try that
+ if (filename[0] != '/') {
+ filename = g_curdir + "/" + filename;
+ }
+
+ // Realpath!
+ char rp[PATH_MAX];
+ if (realpath(filename.c_str(), rp) == NULL) {
+ pwarning(0, "Cannot open include file %s\n", filename.c_str());
+ return std::string();
+ }
+
+ // Stat this files
+ struct stat finfo;
+ if (stat(rp, &finfo) == 0) {
+ return rp;
+ }
+
+ // Uh oh
+ pwarning(0, "Could not find include file %s\n", filename.c_str());
+ return std::string();
+}
+
+/**
* Diplays the usage message and then exits with an error code.
*/
void usage() {
fprintf(stderr, "Usage: thrift [options] file\n");
fprintf(stderr, "Options:\n");
- fprintf(stderr, " --cpp Generate C++ output files\n");
- fprintf(stderr, " --java Generate Java output files\n");
- fprintf(stderr, " --php Generate PHP output files\n");
- fprintf(stderr, " --phpi Generate PHP inlined files\n");
- fprintf(stderr, " --py Generate Python output files\n");
- fprintf(stderr, " --debug Print parse debugging to standard output\n");
+ fprintf(stderr, " --cpp Generate C++ output files\n");
+ fprintf(stderr, " --java Generate Java output files\n");
+ fprintf(stderr, " --php Generate PHP output files\n");
+ fprintf(stderr, " --phpi Generate PHP inlined files\n");
+ fprintf(stderr, " --py Generate Python output files\n");
+ fprintf(stderr, " --nowarn Suppress all compiler warnings (BAD!)\n");
+ fprintf(stderr, " --strict Strict compiler warnings on\n");
+ fprintf(stderr, " --v[erbose] Verbose mode\n");
+ fprintf(stderr, " --r[ecurse] Also generate included files\n");
+ fprintf(stderr, " --debug Parse debug trace to stdout\n");
exit(1);
}
/**
+ * Parses a program
+ */
+void parse(t_program* program, t_program* parent_program) {
+ // Get scope file path
+ string path = program->get_path();
+
+ // Set current dir global, which is used in the include_file function
+ g_curdir = directory_name(path);
+ g_curpath = path;
+
+ // Open the file
+ yyin = fopen(path.c_str(), "r");
+ if (yyin == 0) {
+ failure("Could not open input file: \"%s\"", path.c_str());
+ }
+
+ // Create new scope and scan for includes
+ pverbose("Scanning %s for includes\n", path.c_str());
+ g_parse_mode = INCLUDES;
+ g_program = program;
+ g_scope = program->scope();
+ if (yyparse() != 0) {
+ failure("Parser error during include pass.");
+ }
+ fclose(yyin);
+
+ // Recursively parse all the include programs
+ vector<t_program*>& includes = program->get_includes();
+ vector<t_program*>::iterator iter;
+ for (iter = includes.begin(); iter != includes.end(); ++iter) {
+ parse(*iter, program);
+ }
+
+ // Parse the program the file
+ g_parse_mode = PROGRAM;
+ g_program = program;
+ g_scope = program->scope();
+ g_parent_scope = (parent_program != NULL) ? parent_program->scope() : NULL;
+ g_parent_prefix = program->get_name() + ".";
+ g_curpath = path;
+ yyin = fopen(path.c_str(), "r");
+ if (yyin == 0) {
+ failure("Could not open input file: \"%s\"", path.c_str());
+ }
+ pverbose("Parsing %s for types\n", path.c_str());
+ if (yyparse() != 0) {
+ failure("Parser error during types pass.");
+ }
+ fclose(yyin);
+}
+
+/**
+ * Generate code
+ */
+void generate(t_program* program) {
+ // Oooohh, recursive code generation, hot!!
+ if (gen_recurse) {
+ const vector<t_program*>& includes = program->get_includes();
+ for (size_t i = 0; i < includes.size(); ++i) {
+ generate(includes[i]);
+ }
+ }
+
+ // Generate code!
+ try {
+ pverbose("Program: %s\n", program->get_path().c_str());
+
+ if (gen_cpp) {
+ pverbose("Generating C++\n");
+ t_cpp_generator* cpp = new t_cpp_generator(program);
+ cpp->generate_program();
+ delete cpp;
+ }
+
+ if (gen_java) {
+ pverbose("Generating Java\n");
+ t_java_generator* java = new t_java_generator(program);
+ java->generate_program();
+ delete java;
+ }
+
+ if (gen_php) {
+ pverbose("Generating PHP\n");
+ t_php_generator* php = new t_php_generator(program, false);
+ php->generate_program();
+ delete php;
+ }
+
+ if (gen_phpi) {
+ pverbose("Generating PHP-inline\n");
+ t_php_generator* phpi = new t_php_generator(program, true);
+ phpi->generate_program();
+ delete phpi;
+ }
+
+ if (gen_py) {
+ pverbose("Generating Python\n");
+ t_py_generator* py = new t_py_generator(program);
+ py->generate_program();
+ delete py;
+ }
+ } catch (string s) {
+ printf("Error: %s\n", s.c_str());
+ } catch (const char* exc) {
+ printf("Error: %s\n", exc);
+ }
+
+}
+
+/**
* 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 gen_phpi = false;
-
// Setup time string
time_t now = time(NULL);
g_time_str = ctime(&now);
- // Check for necessary arguments
+ // Check for necessary arguments, you gotta have at least a filename and
+ // an output language flag
if (argc < 2) {
usage();
}
@@ -140,6 +401,14 @@
while (arg != NULL) {
if (strcmp(arg, "--debug") == 0) {
g_debug = 1;
+ } else if (strcmp(arg, "--nowarn") == 0) {
+ g_warn = 0;
+ } else if (strcmp(arg, "--strict") == 0) {
+ g_warn = 2;
+ } else if (strcmp(arg, "--v") == 0 || strcmp(arg, "--verbose") == 0 ) {
+ g_verbose = 1;
+ } else if (strcmp(arg, "--r") == 0 || strcmp(arg, "--recurse") == 0 ) {
+ gen_recurse = true;
} else if (strcmp(arg, "--cpp") == 0) {
gen_cpp = true;
} else if (strcmp(arg, "--java") == 0) {
@@ -160,77 +429,51 @@
}
}
+ // You gotta generate something!
if (!gen_cpp && !gen_java && !gen_php && !gen_phpi && !gen_py) {
fprintf(stderr, "!!! No output language(s) specified\n\n");
usage();
}
-
- // Open input file
- char* input_file = argv[i];
- yyin = fopen(input_file, "r");
- if (yyin == 0) {
- failure("Could not open input file: \"%s\"", input_file);
+
+ // Real-pathify it
+ char rp[PATH_MAX];
+ if (realpath(argv[i], rp) == NULL) {
+ failure("Could not open input file: %s", argv[i]);
}
-
- // Extract program name by dropping directory and .thrift from filename
- string name = input_file;
- string::size_type slash = name.rfind("/");
- if (slash != string::npos) {
- name = name.substr(slash+1);
- }
- string::size_type dot = name.find(".");
- if (dot != string::npos) {
- name = name.substr(0, dot);
- }
-
+ string input_file(rp);
+
// Instance of the global parse tree
- g_program = new t_program(name);
+ t_program* program = new t_program(input_file);
+
+ // Initialize global types
+ g_type_void = new t_base_type("void", t_base_type::TYPE_VOID);
+ g_type_string = new t_base_type("string", t_base_type::TYPE_STRING);
+ g_type_bool = new t_base_type("bool", t_base_type::TYPE_BOOL);
+ g_type_byte = new t_base_type("byte", t_base_type::TYPE_BYTE);
+ g_type_i16 = new t_base_type("i16", t_base_type::TYPE_I16);
+ g_type_i32 = new t_base_type("i32", t_base_type::TYPE_I32);
+ g_type_i64 = new t_base_type("i64", t_base_type::TYPE_I64);
+ g_type_double = new t_base_type("double", t_base_type::TYPE_DOUBLE);
// Parse it!
- if (yyparse() != 0) {
- failure("Parser error.");
- }
+ parse(program, NULL);
- // Generate code
- try {
- if (gen_cpp) {
- t_cpp_generator* cpp = new t_cpp_generator();
- cpp->generate_program(g_program);
- delete cpp;
- }
+ // Generate it!
+ generate(program);
- if (gen_java) {
- t_java_generator* java = new t_java_generator();
- java->generate_program(g_program);
- delete java;
- }
+ // Clean up. Who am I kidding... this program probably orphans heap memory
+ // all over the place, but who cares because it is about to exit and it is
+ // all referenced and used by this wacky parse tree up until now anyways.
- if (gen_php) {
- 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) {
- printf("Error: %s\n", exc);
- }
-
- // Clean up
- delete g_program;
+ delete program;
+ delete g_type_void;
+ delete g_type_string;
+ delete g_type_bool;
+ delete g_type_byte;
+ delete g_type_i16;
+ delete g_type_i32;
+ delete g_type_i64;
+ delete g_type_double;
// Finished
return 0;
diff --git a/compiler/cpp/src/main.h b/compiler/cpp/src/main.h
index 1281cc9..9a3a81e 100644
--- a/compiler/cpp/src/main.h
+++ b/compiler/cpp/src/main.h
@@ -1,22 +1,50 @@
#ifndef T_MAIN_H
#define T_MAIN_H
+#include <string>
+
/**
* Defined in the flex library
*/
-extern int yylex(void);
-extern int yyparse(void);
+int yylex(void);
+
+int yyparse(void);
/**
* Expected to be defined by Flex/Bison
*/
-extern void yyerror(char* fmt, ...);
+void yyerror(char* fmt, ...);
/**
- * Parse debugging output, used to print warnings etc.
+ * Parse debugging output, used to print helpful info
*/
-extern void pdebug(char* fmt, ...);
+void pdebug(char* fmt, ...);
+
+/**
+ * Parser warning
+ */
+void pwarning(int level, char* fmt, ...);
+
+/**
+ * Failure!
+ */
+void failure(char* fmt, ...);
+
+/**
+ * Converts a string filename into a thrift program name
+ */
+std::string program_name(std::string filename);
+
+/**
+ * Gets the directory path of a filename
+ */
+std::string directory_name(std::string filename);
+
+/**
+ * Get the absolute path for an include file
+ */
+std::string include_file(std::string filename);
/**
* Flex utilities
diff --git a/compiler/cpp/src/parse/t_enum.h b/compiler/cpp/src/parse/t_enum.h
index 4b6fe36..002ca82 100644
--- a/compiler/cpp/src/parse/t_enum.h
+++ b/compiler/cpp/src/parse/t_enum.h
@@ -11,7 +11,8 @@
*/
class t_enum : public t_type {
public:
- t_enum() {}
+ t_enum(t_program* program) :
+ t_type(program) {}
void set_name(std::string name) {
name_ = name;
diff --git a/compiler/cpp/src/parse/t_function.h b/compiler/cpp/src/parse/t_function.h
index 3d07171..6f06abe 100644
--- a/compiler/cpp/src/parse/t_function.h
+++ b/compiler/cpp/src/parse/t_function.h
@@ -22,7 +22,7 @@
name_(name),
arglist_(arglist),
async_(async) {
- xceptions_ = new t_struct;
+ xceptions_ = new t_struct(NULL);
}
t_function(t_type* returntype,
diff --git a/compiler/cpp/src/parse/t_program.h b/compiler/cpp/src/parse/t_program.h
index 5e58654..a3270ad 100644
--- a/compiler/cpp/src/parse/t_program.h
+++ b/compiler/cpp/src/parse/t_program.h
@@ -5,6 +5,10 @@
#include <string>
#include <vector>
+// For program_name()
+#include "main.h"
+
+#include "t_scope.h"
#include "t_base_type.h"
#include "t_typedef.h"
#include "t_enum.h"
@@ -30,38 +34,26 @@
*/
class t_program {
public:
- t_program(std::string name) :
- 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);
- type_byte = new t_base_type("byte", t_base_type::TYPE_BYTE);
- type_i16 = new t_base_type("i16", t_base_type::TYPE_I16);
- type_i32 = new t_base_type("i32", t_base_type::TYPE_I32);
- type_i64 = new t_base_type("i64", t_base_type::TYPE_I64);
- type_double = new t_base_type("double", t_base_type::TYPE_DOUBLE);
+ t_program(std::string path, std::string name) :
+ path_(path),
+ name_(name) {
+ scope_ = new t_scope();
}
- ~t_program() {
- delete type_string;
- delete type_bool;
- delete type_byte;
- delete type_i16;
- delete type_i32;
- delete type_i64;
- delete type_double;
+ t_program(std::string path) :
+ path_(path) {
+ name_ = program_name(path);
+ scope_ = new t_scope();
}
+ // Path accessor
+ const std::string& get_path() const { return path_; }
+
// 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<t_typedef*>& get_typedefs() const { return typedefs_; }
@@ -70,57 +62,67 @@
const std::vector<t_struct*>& get_xceptions() const { return xceptions_; }
const std::vector<t_service*>& get_services() const { return services_; }
- // Accessors for global types
- t_type* get_void_type() const { return type_void; }
- t_type* get_string_type() const { return type_string; }
- t_type* get_bool_type() const { return type_bool; }
- t_type* get_byte_type() const { return type_byte; }
- t_type* get_i16_type() const { return type_i16; }
- t_type* get_i32_type() const { return type_i32; }
- t_type* get_i64_type() const { return type_i64; }
- t_type* get_double_type() const { return type_double; }
+ // Program elements
+ void add_typedef (t_typedef* td) { typedefs_.push_back(td); }
+ void add_enum (t_enum* te) { enums_.push_back(te); }
+ void add_struct (t_struct* ts) { structs_.push_back(ts); }
+ void add_xception (t_struct* tx) { xceptions_.push_back(tx); }
+ void add_service (t_service* ts) { services_.push_back(ts); }
- // Custom data type lookup
- t_type* get_custom_type(std::string name) {
- return custom_types_[name];
- }
+ // Programs to include
+ const std::vector<t_program*>& get_includes() const { return includes_; }
- // New program element addition
-
+ // Scoping and namespacing
void set_namespace(std::string name) {
namespace_ = name;
}
- void add_typedef(t_typedef* td) {
- typedefs_.push_back(td);
- add_custom_type(td->get_symbolic(), td);
+ // Scope accessor
+ t_scope* scope() {
+ return scope_;
}
- void add_enum(t_enum* te) {
- enums_.push_back(te);
- add_custom_type(te->get_name(), te);
+ // Includes
+
+ void add_include(std::string path) {
+ includes_.push_back(new t_program(path));
}
- void add_struct(t_struct* ts) {
- structs_.push_back(ts);
- add_custom_type(ts->get_name(), ts);
+ std::vector<t_program*>& get_includes() {
+ return includes_;
}
- void add_xception(t_struct* tx) {
- xceptions_.push_back(tx);
- add_custom_type(tx->get_name(), tx);
+ // Language specific namespace / packaging
+
+ void set_cpp_namespace(std::string cpp_namespace) {
+ cpp_namespace_ = cpp_namespace;
}
- void add_service(t_service* ts) {
- services_.push_back(ts);
+ const std::string& get_cpp_namespace() const {
+ return cpp_namespace_;
}
+ void add_cpp_include(std::string path) {
+ cpp_includes_.push_back(path);
+ }
+
+ const std::vector<std::string>& get_cpp_includes() {
+ return cpp_includes_;
+ }
+
+ void set_java_package(std::string java_package) {
+ java_package_ = java_package;
+ }
+
+ const std::string& get_java_package() const {
+ return java_package_;
+ }
+
+
private:
- // Add custom type for lookup
- void add_custom_type(std::string name, t_type* type) {
- custom_types_[name] = type;
- }
+ // File path
+ std::string path_;
// Name
std::string name_;
@@ -128,25 +130,28 @@
// Namespace
std::string namespace_;
- // Components
- std::vector<t_typedef*> typedefs_;
- std::vector<t_enum*> enums_;
- std::vector<t_struct*> structs_;
- std::vector<t_struct*> xceptions_;
- std::vector<t_service*> services_;
+ // Included programs
+ std::vector<t_program*> includes_;
- // Type map
- std::map<std::string, t_type*> custom_types_;
+ // Identifier lookup scope
+ t_scope* scope_;
- // Global base types
- t_type* type_void;
- t_type* type_string;
- t_type* type_bool;
- t_type* type_byte;
- t_type* type_i16;
- t_type* type_i32;
- t_type* type_i64;
- t_type* type_double;
+ // Components to generate code for
+ std::vector<t_typedef*> typedefs_;
+ std::vector<t_enum*> enums_;
+ std::vector<t_struct*> structs_;
+ std::vector<t_struct*> xceptions_;
+ std::vector<t_service*> services_;
+
+ // C++ namespace
+ std::string cpp_namespace_;
+
+ // C++ extra includes
+ std::vector<std::string> cpp_includes_;
+
+ // Java package
+ std::string java_package_;
+
};
#endif
diff --git a/compiler/cpp/src/parse/t_scope.h b/compiler/cpp/src/parse/t_scope.h
new file mode 100644
index 0000000..504393b
--- /dev/null
+++ b/compiler/cpp/src/parse/t_scope.h
@@ -0,0 +1,57 @@
+#ifndef T_SCOPE_H
+#define T_SCOPE_H
+
+#include <map>
+#include <string>
+
+#include "t_type.h"
+#include "t_service.h"
+
+/**
+ * This represents a variable scope used for looking up predefined types and
+ * services. Typically, a scope is associated with a t_program. Scopes are not
+ * used to determine code generation, but rather to resolve identifiers at
+ * parse time.
+ *
+ * @author Mark Slee <mcslee@facebook.com>
+ */
+class t_scope {
+ public:
+ t_scope() {}
+
+ void add_type(std::string name, t_type* type) {
+ types_[name] = type;
+ }
+
+ t_type* get_type(std::string name) {
+ return types_[name];
+ }
+
+ void add_service(std::string name, t_service* service) {
+ services_[name] = service;
+ }
+
+ t_service* get_service(std::string name) {
+ return services_[name];
+ }
+
+ void print() {
+ std::map<std::string, t_type*>::iterator iter;
+ for (iter = types_.begin(); iter != types_.end(); ++iter) {
+ printf("%s => %s\n",
+ iter->first.c_str(),
+ iter->second->get_name().c_str());
+ }
+ }
+
+ private:
+
+ // Map of names to types
+ std::map<std::string, t_type*> types_;
+
+ // Map of names to services
+ std::map<std::string, t_service*> services_;
+
+};
+
+#endif
diff --git a/compiler/cpp/src/parse/t_service.h b/compiler/cpp/src/parse/t_service.h
index 6bb5e5d..52280a4 100644
--- a/compiler/cpp/src/parse/t_service.h
+++ b/compiler/cpp/src/parse/t_service.h
@@ -4,34 +4,42 @@
#include "t_function.h"
#include <vector>
+class t_program;
+
/**
* A service consists of a set of functions.
*
* @author Mark Slee <mcslee@facebook.com>
*/
-class t_service {
+class t_service : public t_type {
public:
- t_service() {}
+ t_service(t_program* program) :
+ t_type(program),
+ extends_(NULL) {}
- void set_name(std::string name) {
- name_ = name;
+ bool is_service() const {
+ return true;
+ }
+
+ void set_extends(t_service* extends) {
+ extends_ = extends;
}
void add_function(t_function* func) {
functions_.push_back(func);
}
- const std::string& get_name() const {
- return name_;
- }
-
const std::vector<t_function*>& get_functions() const {
return functions_;
}
+ t_service* get_extends() {
+ return extends_;
+ }
+
private:
- std::string name_;
std::vector<t_function*> functions_;
+ t_service* extends_;
};
#endif
diff --git a/compiler/cpp/src/parse/t_struct.h b/compiler/cpp/src/parse/t_struct.h
index 8768c5f..ce5f752 100644
--- a/compiler/cpp/src/parse/t_struct.h
+++ b/compiler/cpp/src/parse/t_struct.h
@@ -7,6 +7,9 @@
#include "t_type.h"
#include "t_field.h"
+// Forward declare that puppy
+class t_program;
+
/**
* A struct is a container for a set of member fields that has a name. Structs
* are also used to implement exception types.
@@ -15,11 +18,12 @@
*/
class t_struct : public t_type {
public:
- t_struct() :
+ t_struct(t_program* program) :
+ t_type(program),
is_xception_(false) {}
- t_struct(const std::string& name) :
- t_type(name),
+ t_struct(t_program* program, const std::string& name) :
+ t_type(program, name),
is_xception_(false) {}
void set_name(const std::string& name) {
diff --git a/compiler/cpp/src/parse/t_type.h b/compiler/cpp/src/parse/t_type.h
index 1d0a2ed..9589f02 100644
--- a/compiler/cpp/src/parse/t_type.h
+++ b/compiler/cpp/src/parse/t_type.h
@@ -3,6 +3,8 @@
#include <string>
+class t_program;
+
/**
* 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.
@@ -16,7 +18,13 @@
public:
virtual ~t_type() {}
- virtual const std::string& get_name() const { return name_; }
+ virtual void set_name(std::string name) {
+ name_ = name;
+ }
+
+ virtual const std::string& get_name() const {
+ return name_;
+ }
virtual bool is_void() const { return false; }
virtual bool is_base_type() const { return false; }
@@ -28,13 +36,26 @@
virtual bool is_list() const { return false; }
virtual bool is_set() const { return false; }
virtual bool is_map() const { return false; }
+ virtual bool is_service() const { return false; }
+
+ t_program* get_program() {
+ return program_;
+ }
protected:
t_type() {}
- t_type(std::string name) :
+ t_type(t_program* program) :
+ program_(program) {}
+
+ t_type(t_program* program, std::string name) :
+ program_(program),
name_(name) {}
+ t_type(std::string name) :
+ name_(name) {}
+
+ t_program* program_;
std::string name_;
};
diff --git a/compiler/cpp/src/parse/t_typedef.h b/compiler/cpp/src/parse/t_typedef.h
index 8973201..cc7f25c 100644
--- a/compiler/cpp/src/parse/t_typedef.h
+++ b/compiler/cpp/src/parse/t_typedef.h
@@ -14,8 +14,8 @@
*/
class t_typedef : public t_type {
public:
- t_typedef(t_type* type, std::string symbolic) :
- t_type(symbolic),
+ t_typedef(t_program* program, t_type* type, std::string symbolic) :
+ t_type(program, symbolic),
type_(type),
symbolic_(symbolic) {}
diff --git a/compiler/cpp/src/thrift.l b/compiler/cpp/src/thrift.l
index e72565e..839060e 100644
--- a/compiler/cpp/src/thrift.l
+++ b/compiler/cpp/src/thrift.l
@@ -33,8 +33,8 @@
multicomm ("/*""/"*([^*/]|[^*]"/"|"*"[^/])*"*"*"*/")
comment ("//"[^\n]*)
unixcomment ("#"[^\n]*)
-symbol ([\,\{\}\(\)\=<>])
-cpptype ("[cpp:".*"]")
+symbol ([:\,\{\}\(\)\=<>\[\]])
+literal ("\""[^"]*"\"")
%%
@@ -45,41 +45,47 @@
{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; }
+"namespace" { return tok_namespace; }
+"cpp_namespace" { return tok_cpp_namespace; }
+"cpp_include" { return tok_cpp_include; }
+"cpp_type" { return tok_cpp_type; }
+"java_package" { return tok_java_package; }
+"include" { return tok_include; }
+
+"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; }
+"extends" { return tok_extends; }
+"throws" { return tok_throws; }
+"service" { return tok_service; }
+"enum" { return tok_enum; }
{intconstant} {
yylval.iconst = atoi(yytext);
return tok_int_constant;
}
-{cpptype} {
- yylval.id = strdup(yytext+5);
- yylval.id[strlen(yylval.id)-1] = '\0';
- return tok_cpptype;
-}
-
{identifier} {
yylval.id = strdup(yytext);
return tok_identifier;
}
+{literal} {
+ yylval.id = strdup(yytext+1);
+ yylval.id[strlen(yylval.id)-1] = '\0';
+ return tok_literal;
+}
%%
diff --git a/compiler/cpp/src/thrift.y b/compiler/cpp/src/thrift.y
index 3bf8b53..7d1ba1e 100644
--- a/compiler/cpp/src/thrift.y
+++ b/compiler/cpp/src/thrift.y
@@ -12,6 +12,7 @@
#include "main.h"
#include "globals.h"
#include "parse/t_program.h"
+#include "parse/t_scope.h"
/**
* This global variable is used for automatic numbering of field indices etc.
@@ -44,7 +45,7 @@
* Strings identifier
*/
%token<id> tok_identifier
-%token<id> tok_cpptype
+%token<id> tok_literal
/**
* Integer constant value
@@ -52,9 +53,14 @@
%token<iconst> tok_int_constant
/**
- * Namespace keyword
+ * Header keywoards
*/
+%token tok_include
%token tok_namespace
+%token tok_cpp_namespace
+%token tok_cpp_include
+%token tok_cpp_type
+%token tok_java_package
/**
* Base datatype keywords
@@ -87,6 +93,7 @@
%token tok_struct
%token tok_xception
%token tok_throws
+%token tok_extends
%token tok_service
%token tok_enum
@@ -94,14 +101,14 @@
* Grammar nodes
*/
-%type<id> Namespace
-
%type<ttype> BaseType
%type<ttype> ContainerType
%type<ttype> MapType
%type<ttype> SetType
%type<ttype> ListType
+%type<ttype> TypeDefinition
+
%type<ttypedef> Typedef
%type<ttype> DefinitionType
@@ -122,6 +129,7 @@
%type<tservice> FunctionList
%type<tstruct> ThrowsOptional
+%type<tservice> ExtendsOptional
%type<tbool> AsyncOptional
%type<id> CppTypeOptional
@@ -136,10 +144,67 @@
*/
Program:
- DefinitionList
- {
- pdebug("Program -> DefinitionList");
- }
+ HeaderList DefinitionList
+ {
+ pdebug("Program -> Headers DefinitionList");
+ }
+
+HeaderList:
+ HeaderList Header
+ {
+ pdebug("HeaderList -> HeaderList Header");
+ }
+|
+ {
+ pdebug("HeaderList -> ");
+ }
+
+Header:
+ Include
+ {
+ pdebug("Header -> Include");
+ }
+| tok_namespace tok_identifier
+ {
+ pwarning(1, "'namespace' is deprecated. Use 'cpp_namespace' and/or 'java_package' instead");
+ if (g_parse_mode == PROGRAM) {
+ g_program->set_cpp_namespace($2);
+ g_program->set_java_package($2);
+ }
+ }
+| tok_cpp_namespace tok_identifier
+ {
+ pdebug("Header -> tok_cpp_namespace tok_identifier");
+ if (g_parse_mode == PROGRAM) {
+ g_program->set_cpp_namespace($2);
+ }
+ }
+| tok_cpp_include tok_literal
+ {
+ pdebug("Header -> tok_cpp_include tok_literal");
+ if (g_parse_mode == PROGRAM) {
+ g_program->add_cpp_include($2);
+ }
+ }
+| tok_java_package tok_identifier
+ {
+ pdebug("Header -> tok_java_package tok_identifier");
+ if (g_parse_mode == PROGRAM) {
+ g_program->set_java_package($2);
+ }
+ }
+
+Include:
+ tok_include tok_literal
+ {
+ pdebug("Include -> tok_include tok_literal");
+ if (g_parse_mode == INCLUDES) {
+ std::string path = include_file(std::string($2));
+ if (!path.empty()) {
+ g_program->add_include(path);
+ }
+ }
+ }
DefinitionList:
DefinitionList Definition
@@ -152,49 +217,63 @@
}
Definition:
- Namespace
+ TypeDefinition
{
- pdebug("Definition -> Namespace");
- g_program->set_namespace($1);
- }
-| Typedef
- {
- pdebug("Definition -> Typedef");
- g_program->add_typedef($1);
- }
-| Enum
- {
- pdebug("Definition -> Enum");
- g_program->add_enum($1);
- }
-| Struct
- {
- pdebug("Definition -> Struct");
- g_program->add_struct($1);
- }
-| Xception
- {
- pdebug("Definition -> Xception");
- g_program->add_xception($1);
+ pdebug("Definition -> TypeDefinition");
+ if (g_parse_mode == PROGRAM) {
+ g_scope->add_type($1->get_name(), $1);
+ if (g_parent_scope != NULL) {
+ g_parent_scope->add_type(g_parent_prefix + $1->get_name(), $1);
+ }
+ }
}
| Service
{
pdebug("Definition -> Service");
- g_program->add_service($1);
+ if (g_parse_mode == PROGRAM) {
+ g_scope->add_service($1->get_name(), $1);
+ if (g_parent_scope != NULL) {
+ g_parent_scope->add_service(g_parent_prefix + $1->get_name(), $1);
+ }
+ g_program->add_service($1);
+ }
}
-Namespace:
- tok_namespace tok_identifier
+TypeDefinition:
+ Typedef
{
- pdebug("Namespace -> tok_namespace tok_identifier");
- $$ = $2;
+ pdebug("TypeDefinition -> Typedef");
+ if (g_parse_mode == PROGRAM) {
+ g_program->add_typedef($1);
+ }
+ }
+| Enum
+ {
+ pdebug("TypeDefinition -> Enum");
+ if (g_parse_mode == PROGRAM) {
+ g_program->add_enum($1);
+ }
+ }
+| Struct
+ {
+ pdebug("TypeDefinition -> Struct");
+ if (g_parse_mode == PROGRAM) {
+ g_program->add_struct($1);
+ }
+ }
+| Xception
+ {
+ pdebug("TypeDefinition -> Xception");
+ if (g_parse_mode == PROGRAM) {
+ g_program->add_xception($1);
+ }
}
Typedef:
tok_typedef DefinitionType tok_identifier
{
pdebug("TypeDef -> tok_typedef DefinitionType tok_identifier");
- t_typedef *td = new t_typedef($2, $3);
+ t_typedef *td = new t_typedef(g_program, $2, $3);
$$ = td;
}
@@ -216,13 +295,13 @@
| EnumDef
{
pdebug("EnumDefList -> EnumDef");
- $$ = new t_enum;
+ $$ = new t_enum(g_program);
$$->append($1);
}
|
{
pdebug("EnumDefList -> ");
- $$ = new t_enum;
+ $$ = new t_enum(g_program);
}
EnumDef:
@@ -230,7 +309,7 @@
{
pdebug("EnumDef => tok_identifier = tok_int_constant");
if ($3 < 0) {
- printf("WARNING (%d): Negative value supplied for enum %s.\n", yylineno, $1);
+ pwarning(1, "Negative value supplied for enum %s.\n", $1);
}
$$ = new t_constant($1, $3);
}
@@ -261,11 +340,30 @@
}
Service:
- tok_service tok_identifier '{' FunctionList '}'
+ tok_service tok_identifier ExtendsOptional '{' FunctionList '}'
{
pdebug("Service -> tok_service tok_identifier { FunctionList }");
- $$ = $4;
+ $$ = $5;
$$->set_name($2);
+ $$->set_extends($3);
+ }
+
+ExtendsOptional:
+ tok_extends tok_identifier
+ {
+ pdebug("ExtendsOptional -> tok_extends tok_identifier");
+ $$ = NULL;
+ if (g_parse_mode == PROGRAM) {
+ $$ = g_scope->get_service($2);
+ if ($$ == NULL) {
+ yyerror("Service \"%s\" has not been defined.", $2);
+ exit(1);
+ }
+ }
+ }
+|
+ {
+ $$ = NULL;
}
FunctionList:
@@ -278,7 +376,7 @@
|
{
pdebug("FunctionList -> ");
- $$ = new t_service;
+ $$ = new t_service(g_program);
}
CommaOptional:
@@ -308,11 +406,12 @@
ThrowsOptional:
tok_throws '(' FieldList ')'
{
+ pdebug("ThrowsOptional -> tok_throws ( FieldList )");
$$ = $3;
}
|
{
- $$ = new t_struct;
+ $$ = new t_struct(g_program);
}
FieldList:
@@ -325,31 +424,41 @@
| Field
{
pdebug("FieldList -> Field");
- $$ = new t_struct;
+ $$ = new t_struct(g_program);
$$->append($1);
}
|
{
pdebug("FieldList -> ");
- $$ = new t_struct;
+ $$ = new t_struct(g_program);
}
Field:
- FieldType tok_identifier '=' tok_int_constant
+ tok_int_constant ':' FieldType tok_identifier
{
- pdebug("Field -> FieldType tok_identifier = tok_int_constant");
- if ($4 <= 0) {
- printf("WARNING (%d): Nonpositive value (%d) not allowed as a field key for '%s'.\n", yylineno, $4, $2);
- $4 = y_field_val--;
+ pdebug("tok_int_constant : Field -> FieldType tok_identifier");
+ if ($1 <= 0) {
+ pwarning(1, "Nonpositive value (%d) not allowed as a field key for '%s'.\n", $1, $4);
+ $1 = y_field_val--;
}
- $$ = new t_field($1, $2, $4);
+ $$ = new t_field($3, $4, $1);
}
| FieldType tok_identifier
{
pdebug("Field -> FieldType tok_identifier");
- printf("WARNING (%d): No field key specified for '%s', resulting protocol may have conflicts or not be backwards compatible!\n", yylineno, $2);
+ pwarning(2, "No field key specified for '%s', resulting protocol may have conflicts or not be backwards compatible!\n", $2);
$$ = new t_field($1, $2, y_field_val--);
}
+| FieldType tok_identifier '=' tok_int_constant
+ {
+ pwarning(1, "Trailing = id notation is deprecated. Use 'Id: Type Name' notatio instead");
+ pdebug("Field -> FieldType tok_identifier = tok_int_constant");
+ if ($4 <= 0) {
+ pwarning(1, "Nonpositive value (%d) not allowed as a field key for '%s'.\n", $4, $2);
+ $4 = y_field_val--;
+ }
+ $$ = new t_field($1, $2, $4);
+ }
DefinitionType:
BaseType
@@ -372,17 +481,23 @@
| tok_void
{
pdebug("FunctionType -> tok_void");
- $$ = g_program->get_void_type();
+ $$ = g_type_void;
}
FieldType:
tok_identifier
{
pdebug("FieldType -> tok_identifier");
- $$ = g_program->get_custom_type($1);
- if ($$ == NULL) {
- yyerror("Type \"%s\" has not been defined.", $1);
- exit(1);
+ if (g_parse_mode == INCLUDES) {
+ // Ignore identifiers in include mode
+ $$ = NULL;
+ } else {
+ // Lookup the identifier in the current scope
+ $$ = g_scope->get_type($1);
+ if ($$ == NULL) {
+ yyerror("Type \"%s\" has not been defined.", $1);
+ exit(1);
+ }
}
}
| BaseType
@@ -400,37 +515,37 @@
tok_string
{
pdebug("BaseType -> tok_string");
- $$ = g_program->get_string_type();
+ $$ = g_type_string;
}
| tok_bool
{
pdebug("BaseType -> tok_bool");
- $$ = g_program->get_bool_type();
+ $$ = g_type_bool;
}
| tok_byte
{
pdebug("BaseType -> tok_byte");
- $$ = g_program->get_byte_type();
+ $$ = g_type_byte;
}
| tok_i16
{
pdebug("BaseType -> tok_i16");
- $$ = g_program->get_i16_type();
+ $$ = g_type_i16;
}
| tok_i32
{
pdebug("BaseType -> tok_i32");
- $$ = g_program->get_i32_type();
+ $$ = g_type_i32;
}
| tok_i64
{
pdebug("BaseType -> tok_i64");
- $$ = g_program->get_i64_type();
+ $$ = g_type_i64;
}
| tok_double
{
pdebug("BaseType -> tok_double");
- $$ = g_program->get_double_type();
+ $$ = g_type_double;
}
ContainerType:
@@ -471,19 +586,19 @@
}
ListType:
- tok_list CppTypeOptional '<' FieldType '>'
+ tok_list '<' FieldType '>' CppTypeOptional
{
pdebug("ListType -> tok_list<FieldType>");
- $$ = new t_list($4);
- if ($2 != NULL) {
- ((t_container*)$$)->set_cpp_name(std::string($2));
+ $$ = new t_list($3);
+ if ($5 != NULL) {
+ ((t_container*)$$)->set_cpp_name(std::string($5));
}
}
CppTypeOptional:
- tok_cpptype
+ '[' tok_cpp_type tok_literal ']'
{
- $$ = $1;
+ $$ = $3;
}
|
{