*
* @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);
"#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 <<
/**
* 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 <<
indent(out) <<
tstruct->get_name() << "() : ";
out << (*m_iter)->get_name() << "(0)";
- } else
+ } else {
out << ", " << (*m_iter)->get_name() << "(0)";
+ }
}
}
if (init_ctor) {
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();
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();
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
// 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 <<
// 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();
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;
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();
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 <<
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) {
// 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) << "}";
// 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();
"#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;
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_ <<
* @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_ <<
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();
" 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_ <<
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) {
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_ <<
* @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);
}
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 <<
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());
// 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);
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_ <<
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;
}
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;
}
*
* @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_;
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_ <<
// 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_ <<
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
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);
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();
// Declare result
if (!tfunction->is_async()) {
f_service_ <<
- indent() << resultname << " __result;" << endl;
+ indent() << resultname << " result;" << endl;
}
// Try block for functions with exceptions
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) {
} 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) {
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 {
// 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_);
f_service_ << endl;
}
+/**
+ * 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.
*/
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;
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,
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;
}
// 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);
"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 {
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,
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;
}
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);
generate_serialize_field(out, &efield, "");
}
+/**
+ * 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.
*
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();
}
*/
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
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);
* 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);
* @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);
}
// Close the generator
- close_generator(tprogram);
+ close_generator();
}
*/
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() {}
* 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:
* 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.
}
protected:
+ /**
+ * The program being generated
+ */
+ t_program* program_;
+
/**
* Quick accessor for formatted program name that is currently being
* generated.
*
* @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();
}
/**
* @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 "";
}
/**
/**
* 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
bool is_exception,
bool in_class,
bool is_result) {
- out <<
+ indent(out) <<
"public " << (in_class ? "static " : "") << "class " << tstruct->get_name() << " ";
if (is_exception) {
* @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;
* @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_) <<
"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();
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());
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,
}
indent_down();
- f_service_ <<
+ indent(f_service_) <<
"}" << endl;
}
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_) <<
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_) <<
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_ <<
}
indent_down();
- f_service_ <<
+ indent(f_service_) <<
"}" << endl <<
endl;
}
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);
*/
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";
// Close function
scope_down(f_service_);
f_service_ << endl;
+
+ // Close class
+ indent_down();
+ f_service_ <<
+ indent() << "}" << endl <<
+ endl;
}
/**
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;
}
} 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();
}
/**
*/
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
*/
class t_oop_generator : public t_generator {
public:
+ t_oop_generator(t_program* program) :
+ t_generator(program) {}
/**
* Scoping, using curly braces!
*
* @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);
/**
* 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();
// 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();
"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;
}
// 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 <<
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);
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;
}
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);
* @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);
* @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_ <<
* @param tservice The service to generate a server for.
*/
void t_php_generator::generate_service_client(t_service* tservice) {
+ string extends = "";
+ string extends_client = "";
+ if (tservice->get_extends() != NULL) {
+ extends = tservice->get_extends()->get_name();
+ extends_client = " extends " + extends + "Client";
+ }
+
f_service_ <<
- "class " << service_name_ << "Client " <<
- "extends " << service_name_ << "If {" << endl;
+ "class " << service_name_ << "Client" << extends_client << " implements " << service_name_ << "If {" << endl;
indent_up();
// Private members
- f_service_ <<
- indent() << "private $_itrans = null;" << endl <<
- indent() << "private $_otrans = null;" << endl <<
- endl;
-
- if (!binary_inline_) {
+ 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() << "private $_iprot = null;" << endl <<
- indent() << "private $_oprot = null;" << endl <<
+ indent() << "protected $_seqid = 0;" << endl <<
endl;
}
- f_service_ <<
- indent() << "private $_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;
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(),
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);
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 <<
*/
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 {
* 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
*
* @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);
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;
}
/**
/**
* 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();
}
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 <<
// 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
* @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);
* @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;
* @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();
// 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;
// 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(),
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()) {
" 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 << "]),";
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;
- for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+ if (extends.empty()) {
f_service_ <<
- indent() << " \"" << (*f_iter)->get_name() << "\" : Processor.process_" << (*f_iter)->get_name() << "," << endl;
+ 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;
}
- f_service_ <<
- indent() << "}" << endl;
-
+ for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+ f_service_ <<
+ indent() << "self._processMap[\"" << (*f_iter)->get_name() << "\"] = Processor.process_" << (*f_iter)->get_name() << endl;
+ }
indent_down();
f_service_ << endl;
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_ <<
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();
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) {
}
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
t_struct* tstruct,
string prefix) {
out <<
- indent() << prefix << " = " << tstruct->get_name() << "()" << endl <<
+ indent() << prefix << " = " << type_name(tstruct) << "()" << endl <<
indent() << prefix << ".read(iprot, itrans)" << endl;
}
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()) {
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);
}
} else if (type->is_struct() || type->is_xception()) {
if (obj) {
- result += " = " + type->get_name() + "()";
+ result += " = " + type_name((t_struct*)type) + "()";
} else {
result += " = None";
}
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
*/
*/
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
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);
#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
extern t_program* g_program;
/**
- * Global debug state
+ * Global types for the parser to be able to reference
+ */
+
+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 int g_debug;
+extern PARSE_MODE g_parse_mode;
/**
* Global time string, used in formatting error messages etc.
#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"
*/
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
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);
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);
*/
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);
exit(1);
}
+/**
+ * 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();
}
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) {
}
}
+ // 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);
- }
-
- // 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);
- }
-
- // Instance of the global parse tree
- g_program = new t_program(name);
- // Parse it!
- if (yyparse() != 0) {
- failure("Parser error.");
+ // Real-pathify it
+ char rp[PATH_MAX];
+ if (realpath(argv[i], rp) == NULL) {
+ failure("Could not open input file: %s", argv[i]);
}
+ string input_file(rp);
- // Generate code
- try {
- if (gen_cpp) {
- t_cpp_generator* cpp = new t_cpp_generator();
- cpp->generate_program(g_program);
- delete cpp;
- }
-
- if (gen_java) {
- t_java_generator* java = new t_java_generator();
- java->generate_program(g_program);
- delete java;
- }
+ // Instance of the global parse tree
+ t_program* program = new t_program(input_file);
- if (gen_php) {
- t_php_generator* php = new t_php_generator(false);
- php->generate_program(g_program);
- delete php;
- }
+ // 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);
- if (gen_phpi) {
- t_php_generator* phpi = new t_php_generator(true);
- phpi->generate_program(g_program);
- delete phpi;
- }
+ // Parse it!
+ parse(program, NULL);
- if (gen_py) {
- t_py_generator* py = new t_py_generator();
- py->generate_program(g_program);
- delete py;
- }
+ // Generate it!
+ generate(program);
- } catch (string s) {
- printf("Error: %s\n", s.c_str());
- } catch (const char* exc) {
- printf("Error: %s\n", exc);
- }
+ // 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.
- // 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;
#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 helpful info
+ */
+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);
/**
- * Parse debugging output, used to print warnings etc.
+ * Get the absolute path for an include file
*/
-extern void pdebug(char* fmt, ...);
+std::string include_file(std::string filename);
/**
* Flex utilities
*/
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;
name_(name),
arglist_(arglist),
async_(async) {
- xceptions_ = new t_struct;
+ xceptions_ = new t_struct(NULL);
}
t_function(t_type* returntype,
#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"
*/
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_; }
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; }
-
- // Custom data type lookup
- t_type* get_custom_type(std::string name) {
- return custom_types_[name];
- }
+ // 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); }
- // New program element addition
+ // Programs to include
+ const std::vector<t_program*>& get_includes() const { return includes_; }
+ // 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_;
+ }
+
+ // Includes
+
+ void add_include(std::string path) {
+ includes_.push_back(new t_program(path));
}
- void add_enum(t_enum* te) {
- enums_.push_back(te);
- add_custom_type(te->get_name(), te);
+ std::vector<t_program*>& get_includes() {
+ return includes_;
}
- void add_struct(t_struct* ts) {
- structs_.push_back(ts);
- add_custom_type(ts->get_name(), ts);
+ // Language specific namespace / packaging
+
+ void set_cpp_namespace(std::string cpp_namespace) {
+ cpp_namespace_ = cpp_namespace;
}
- void add_xception(t_struct* tx) {
- xceptions_.push_back(tx);
- add_custom_type(tx->get_name(), tx);
+ const std::string& get_cpp_namespace() const {
+ return cpp_namespace_;
}
- void add_service(t_service* ts) {
- services_.push_back(ts);
+ void add_cpp_include(std::string path) {
+ cpp_includes_.push_back(path);
}
- private:
+ const std::vector<std::string>& get_cpp_includes() {
+ return cpp_includes_;
+ }
- // Add custom type for lookup
- void add_custom_type(std::string name, t_type* type) {
- custom_types_[name] = type;
+ void set_java_package(std::string java_package) {
+ java_package_ = java_package;
}
+ const std::string& get_java_package() const {
+ return java_package_;
+ }
+
+
+ private:
+
+ // File path
+ std::string path_;
+
// Name
std::string name_;
// 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_;
-
- // Type map
- std::map<std::string, t_type*> custom_types_;
-
- // 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;
+ // Included programs
+ std::vector<t_program*> includes_;
+
+ // Identifier lookup scope
+ t_scope* scope_;
+
+ // 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
--- /dev/null
+#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
#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 add_function(t_function* func) {
- functions_.push_back(func);
+ void set_extends(t_service* extends) {
+ extends_ = extends;
}
- const std::string& get_name() const {
- return name_;
+ void add_function(t_function* func) {
+ functions_.push_back(func);
}
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
#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.
*/
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) {
#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.
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; }
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_;
};
*/
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) {}
multicomm ("/*""/"*([^*/]|[^*]"/"|"*"[^/])*"*"*"*/")
comment ("//"[^\n]*)
unixcomment ("#"[^\n]*)
-symbol ([\,\{\}\(\)\=<>])
-cpptype ("[cpp:".*"]")
+symbol ([:\,\{\}\(\)\=<>\[\]])
+literal ("\""[^"]*"\"")
%%
{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;
+}
%%
#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.
* Strings identifier
*/
%token<id> tok_identifier
-%token<id> tok_cpptype
+%token<id> tok_literal
/**
* Integer constant value
%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
%token tok_struct
%token tok_xception
%token tok_throws
+%token tok_extends
%token tok_service
%token tok_enum
* 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
%type<tservice> FunctionList
%type<tstruct> ThrowsOptional
+%type<tservice> ExtendsOptional
%type<tbool> AsyncOptional
%type<id> CppTypeOptional
*/
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
}
Definition:
- Namespace
+ TypeDefinition
+ {
+ 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 -> Namespace");
- g_program->set_namespace($1);
+ pdebug("Definition -> Service");
+ 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);
+ }
}
-| Typedef
+
+TypeDefinition:
+ Typedef
{
- pdebug("Definition -> Typedef");
- g_program->add_typedef($1);
+ pdebug("TypeDefinition -> Typedef");
+ if (g_parse_mode == PROGRAM) {
+ g_program->add_typedef($1);
+ }
}
| Enum
{
- pdebug("Definition -> Enum");
- g_program->add_enum($1);
+ pdebug("TypeDefinition -> Enum");
+ if (g_parse_mode == PROGRAM) {
+ g_program->add_enum($1);
+ }
}
| Struct
{
- pdebug("Definition -> Struct");
- g_program->add_struct($1);
+ pdebug("TypeDefinition -> Struct");
+ if (g_parse_mode == PROGRAM) {
+ g_program->add_struct($1);
+ }
}
| Xception
{
- pdebug("Definition -> Xception");
- g_program->add_xception($1);
- }
-| Service
- {
- pdebug("Definition -> Service");
- g_program->add_service($1);
- }
-
-Namespace:
- tok_namespace tok_identifier
- {
- pdebug("Namespace -> tok_namespace tok_identifier");
- $$ = $2;
+ 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;
}
| 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:
{
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);
}
}
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:
|
{
pdebug("FunctionList -> ");
- $$ = new t_service;
+ $$ = new t_service(g_program);
}
CommaOptional:
ThrowsOptional:
tok_throws '(' FieldList ')'
{
+ pdebug("ThrowsOptional -> tok_throws ( FieldList )");
$$ = $3;
}
|
{
- $$ = new t_struct;
+ $$ = new t_struct(g_program);
}
FieldList:
| 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
| 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
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:
}
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;
}
|
{