From f0712dc994e0f78423e8b99ba69fc2e2ed827bf1 Mon Sep 17 00:00:00 2001 From: Mark Slee Date: Wed, 25 Oct 2006 19:03:57 +0000 Subject: [PATCH] Update thrift compiler for new syntax, generate new form of C++ code Reviewed By: wayne, he loves less warnings git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@664840 13f79535-47bb-0310-9956-ffa450edef68 --- compiler/cpp/src/generate/t_cpp_generator.cc | 509 +++++++++++++----- compiler/cpp/src/generate/t_cpp_generator.h | 11 +- compiler/cpp/src/generate/t_generator.cc | 19 +- compiler/cpp/src/generate/t_generator.h | 16 +- compiler/cpp/src/generate/t_java_generator.cc | 192 ++++--- compiler/cpp/src/generate/t_java_generator.h | 7 +- compiler/cpp/src/generate/t_oop_generator.h | 2 + compiler/cpp/src/generate/t_php_generator.cc | 184 ++++--- compiler/cpp/src/generate/t_php_generator.h | 9 +- compiler/cpp/src/generate/t_py_generator.cc | 182 ++++--- compiler/cpp/src/generate/t_py_generator.h | 9 +- compiler/cpp/src/globals.h | 64 ++- compiler/cpp/src/main.cc | 397 +++++++++++--- compiler/cpp/src/main.h | 38 +- compiler/cpp/src/parse/t_enum.h | 3 +- compiler/cpp/src/parse/t_function.h | 2 +- compiler/cpp/src/parse/t_program.h | 159 +++--- compiler/cpp/src/parse/t_scope.h | 57 ++ compiler/cpp/src/parse/t_service.h | 26 +- compiler/cpp/src/parse/t_struct.h | 10 +- compiler/cpp/src/parse/t_type.h | 25 +- compiler/cpp/src/parse/t_typedef.h | 4 +- compiler/cpp/src/thrift.l | 60 ++- compiler/cpp/src/thrift.y | 249 ++++++--- 24 files changed, 1589 insertions(+), 645 deletions(-) create mode 100644 compiler/cpp/src/parse/t_scope.h diff --git a/compiler/cpp/src/generate/t_cpp_generator.cc b/compiler/cpp/src/generate/t_cpp_generator.cc index 28c9913a..c59112cb 100644 --- a/compiler/cpp/src/generate/t_cpp_generator.cc +++ b/compiler/cpp/src/generate/t_cpp_generator.cc @@ -10,7 +10,7 @@ using namespace std; * * @param tprogram The program to generate */ -void t_cpp_generator::init_generator(t_program* tprogram) { +void t_cpp_generator::init_generator() { // Make output directory mkdir(T_CPP_DIR, S_IREAD | S_IWRITE | S_IEXEC); @@ -40,14 +40,31 @@ void t_cpp_generator::init_generator(t_program* tprogram) { "#include " << endl << endl; + // Include other Thrift includes + const vector& 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& cpp_includes = program_->get_cpp_includes(); + for (size_t i = 0; i < cpp_includes.size(); ++i) { + f_types_ << + "#include \"" << cpp_includes[i] << "\"" << endl; + } + f_types_ << + endl; + // Include the types file f_types_impl_ << - "#include \"" << program_name_ <<"_types.h\"" << endl << + "#include \"" << program_name_ << "_types.h\"" << endl << endl; // Open namespace - ns_open_ = namespace_open(tprogram->get_namespace()); - ns_close_ = namespace_close(tprogram->get_namespace()); + ns_open_ = namespace_open(program_->get_cpp_namespace()); + ns_close_ = namespace_close(program_->get_cpp_namespace()); f_types_ << ns_open_ << endl << @@ -61,7 +78,7 @@ void t_cpp_generator::init_generator(t_program* tprogram) { /** * Closes the output files. */ -void t_cpp_generator::close_generator(t_program* tprogram) { +void t_cpp_generator::close_generator() { // Close namespace f_types_ << ns_close_ << endl << @@ -171,8 +188,9 @@ void t_cpp_generator::generate_struct_definition(ofstream& out, indent(out) << tstruct->get_name() << "() : "; out << (*m_iter)->get_name() << "(0)"; - } else + } else { out << ", " << (*m_iter)->get_name() << "(0)"; + } } } if (init_ctor) { @@ -219,8 +237,8 @@ void t_cpp_generator::generate_struct_definition(ofstream& out, out << endl << - indent() << "uint32_t read(boost::shared_ptr iprot, boost::shared_ptr itrans);" << endl << - indent() << "uint32_t write(boost::shared_ptr oprot, boost::shared_ptr otrans) const;" << endl << + indent() << "uint32_t read(boost::shared_ptr iprot);" << endl << + indent() << "uint32_t write(boost::shared_ptr oprot) const;" << endl << endl; indent_down(); @@ -238,7 +256,7 @@ void t_cpp_generator::generate_struct_definition(ofstream& out, void t_cpp_generator::generate_struct_reader(ofstream& out, t_struct* tstruct) { indent(out) << - "uint32_t " << tstruct->get_name() << "::read(boost::shared_ptr iprot, boost::shared_ptr itrans) {" << endl; + "uint32_t " << tstruct->get_name() << "::read(boost::shared_ptr iprot) {" << endl; indent_up(); const vector& fields = tstruct->get_members(); @@ -252,7 +270,7 @@ void t_cpp_generator::generate_struct_reader(ofstream& out, indent() << "facebook::thrift::protocol::TType ftype;" << endl << indent() << "int16_t fid;" << endl << endl << - indent() << "xfer += iprot->readStructBegin(itrans, fname);" << endl << + indent() << "xfer += iprot->readStructBegin(fname);" << endl << endl; // Loop over reading in fields @@ -262,7 +280,7 @@ void t_cpp_generator::generate_struct_reader(ofstream& out, // Read beginning field marker indent(out) << - "xfer += iprot->readFieldBegin(itrans, fname, ftype, fid);" << endl; + "xfer += iprot->readFieldBegin(fname, ftype, fid);" << endl; // Check for field STOP marker out << @@ -291,20 +309,20 @@ void t_cpp_generator::generate_struct_reader(ofstream& 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(); @@ -325,18 +343,18 @@ void t_cpp_generator::generate_struct_writer(ofstream& out, vector::const_iterator f_iter; indent(out) << - "uint32_t " << tstruct->get_name() << "::write(boost::shared_ptr oprot, boost::shared_ptr otrans) const {" << endl; + "uint32_t " << tstruct->get_name() << "::write(boost::shared_ptr oprot) const {" << endl; indent_up(); out << indent() << "uint32_t xfer = 0;" << endl; indent(out) << - "xfer += oprot->writeStructBegin(otrans, \"" << name << "\");" << endl; + "xfer += oprot->writeStructBegin(\"" << name << "\");" << endl; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { // Write field header out << - indent() << "xfer += oprot->writeFieldBegin(otrans, " << + indent() << "xfer += oprot->writeFieldBegin(" << "\"" << (*f_iter)->get_name() << "\", " << type_to_enum((*f_iter)->get_type()) << ", " << (*f_iter)->get_key() << ");" << endl; @@ -344,12 +362,12 @@ void t_cpp_generator::generate_struct_writer(ofstream& out, generate_serialize_field(out, *f_iter, "this->"); // Write field closer indent(out) << - "xfer += oprot->writeFieldEnd(otrans);" << endl; + "xfer += oprot->writeFieldEnd();" << endl; } // Write the struct map out << - indent() << "xfer += oprot->writeFieldStop(otrans);" << endl << - indent() << "xfer += oprot->writeStructEnd(otrans);" << endl << + indent() << "xfer += oprot->writeFieldStop();" << endl << + indent() << "xfer += oprot->writeStructEnd();" << endl << indent() << "return xfer;" << endl; indent_down(); @@ -373,7 +391,7 @@ void t_cpp_generator::generate_struct_result_writer(ofstream& out, vector::const_iterator f_iter; indent(out) << - "uint32_t " << tstruct->get_name() << "::write(boost::shared_ptr oprot, boost::shared_ptr otrans) const {" << endl; + "uint32_t " << tstruct->get_name() << "::write(boost::shared_ptr oprot) const {" << endl; indent_up(); out << @@ -382,7 +400,7 @@ void t_cpp_generator::generate_struct_result_writer(ofstream& 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) { @@ -402,14 +420,14 @@ void t_cpp_generator::generate_struct_result_writer(ofstream& out, // Write field header out << - indent() << "xfer += oprot->writeFieldBegin(otrans, " << + indent() << "xfer += oprot->writeFieldBegin(" << "\"" << (*f_iter)->get_name() << "\", " << type_to_enum((*f_iter)->get_type()) << ", " << (*f_iter)->get_key() << ");" << endl; // Write field contents generate_serialize_field(out, *f_iter, "this->"); // Write field closer - indent(out) << "xfer += oprot->writeFieldEnd(otrans);" << endl; + indent(out) << "xfer += oprot->writeFieldEnd();" << endl; indent_down(); indent(out) << "}"; @@ -418,8 +436,8 @@ void t_cpp_generator::generate_struct_result_writer(ofstream& 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(); @@ -451,7 +469,14 @@ void t_cpp_generator::generate_service(t_service* tservice) { "#define " << svcname << "_H" << endl << endl << "#include " << endl << - "#include \"" << program_name_ << "_types.h\"" << endl << + "#include \"" << program_name_ << "_types.h\"" << endl; + + if (tservice->get_extends() != NULL) { + f_header_ << + "#include \"" << tservice->get_extends()->get_name() << ".h\"" << endl; + } + + f_header_ << endl << ns_open_ << endl << endl; @@ -471,8 +496,9 @@ void t_cpp_generator::generate_service(t_service* tservice) { generate_service_interface(tservice); generate_service_helpers(tservice); generate_service_client(tservice); - generate_service_server(tservice); + generate_service_processor(tservice); generate_service_multiface(tservice); + generate_service_skeleton(tservice); // Close the namespace f_service_ << @@ -513,8 +539,12 @@ void t_cpp_generator::generate_service_helpers(t_service* tservice) { * @param tservice The service to generate a header definition for */ void t_cpp_generator::generate_service_interface(t_service* tservice) { + string extends = ""; + if (tservice->get_extends() != NULL) { + extends = " : virtual public " + type_name(tservice->get_extends()) + "If"; + } f_header_ << - "class " << service_name_ << "If {" << endl << + "class " << service_name_ << "If" << extends << " {" << endl << " public: " << endl; indent_up(); f_header_ << @@ -542,16 +572,33 @@ void t_cpp_generator::generate_service_multiface(t_service* tservice) { vector functions = tservice->get_functions(); vector::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 >"; // 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 >::iterator iter;" << endl << + indent() << " for (iter = ifaces.begin(); iter != ifaces.end(); ++iter) {" << endl << + indent() << " " << extends << "Multiface::add(*iter);" << endl << + indent() << " }" << endl; + } + f_header_ << + indent() << "}" << endl << indent() << "virtual ~" << service_name_ << "Multiface() {}" << endl; indent_down(); @@ -560,7 +607,16 @@ void t_cpp_generator::generate_service_multiface(t_service* tservice) { " protected:" << endl; indent_up(); f_header_ << - indent() << list_type << "& _ifaces;" << endl; + indent() << list_type << " ifaces_;" << endl << + indent() << service_name_ << "Multiface() {}" << endl << + indent() << "void add(boost::shared_ptr<" << service_name_ << "If> iface) { " << endl; + if (!extends.empty()) { + f_header_ << + indent() << " " << extends << "Multiface::add(iface);" << endl; + } + f_header_ << + indent() << " ifaces_.push_back(iface);" << endl << + indent() << "}" << endl; indent_down(); f_header_ << @@ -572,7 +628,7 @@ void t_cpp_generator::generate_service_multiface(t_service* tservice) { const vector& args = arglist->get_members(); vector::const_iterator a_iter; - string call = string("_ifaces[i]->") + (*f_iter)->get_name() + "("; + string call = string("ifaces_[i]->") + (*f_iter)->get_name() + "("; bool first = true; for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) { if (first) { @@ -588,7 +644,7 @@ void t_cpp_generator::generate_service_multiface(t_service* tservice) { indent() << function_signature(*f_iter) << " {" << endl; indent_up(); f_header_ << - indent() << "uint32_t sz = _ifaces.size();" << endl << + indent() << "uint32_t sz = ifaces_.size();" << endl << indent() << "for (uint32_t i = 0; i < sz; ++i) {" << endl; if (!(*f_iter)->get_returntype()->is_void()) { f_header_ << @@ -623,37 +679,53 @@ void t_cpp_generator::generate_service_multiface(t_service* tservice) { * @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 trans, boost::shared_ptr 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 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 itrans, boost::shared_ptr otrans, boost::shared_ptr iprot, boost::shared_ptr oprot) : " << endl << - indent() << " _itrans(itrans)," << endl << - indent() << " _otrans(otrans)," << endl << - indent() << " _iprot(iprot)," << endl << - indent() << " _oprot(oprot) {}" << endl; + indent() << service_name_ << "Client(boost::shared_ptr iprot, boost::shared_ptr 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 functions = tservice->get_functions(); vector::const_iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { - t_function send_function(g_program->get_void_type(), + t_function send_function(g_type_void, string("send_") + (*f_iter)->get_name(), (*f_iter)->get_arglist()); indent(f_header_) << function_signature(*f_iter) << ";" << endl; indent(f_header_) << function_signature(&send_function) << ";" << endl; if (!(*f_iter)->is_async()) { - t_struct noargs; + t_struct noargs(program_); t_function recv_function((*f_iter)->get_returntype(), string("recv_") + (*f_iter)->get_name(), &noargs); @@ -662,15 +734,15 @@ void t_cpp_generator::generate_service_client(t_service* tservice) { } indent_down(); - f_header_ << - " protected:" << endl; - indent_up(); - f_header_ << - indent() << "boost::shared_ptr _itrans;" << endl << - indent() << "boost::shared_ptr _otrans;" << endl << - indent() << "boost::shared_ptr _iprot;" << endl << - indent() << "boost::shared_ptr _oprot;" << endl; - indent_down(); + if (extends.empty()) { + f_header_ << + " protected:" << endl; + indent_up(); + f_header_ << + indent() << "boost::shared_ptr iprot_;" << endl << + indent() << "boost::shared_ptr oprot_;" << endl; + indent_down(); + } f_header_ << "};" << endl << @@ -718,7 +790,7 @@ void t_cpp_generator::generate_service_client(t_service* tservice) { f_service_ << endl; // Function for sending - t_function send_function(g_program->get_void_type(), + t_function send_function(g_type_void, string("send_") + (*f_iter)->get_name(), (*f_iter)->get_arglist()); @@ -734,27 +806,27 @@ void t_cpp_generator::generate_service_client(t_service* tservice) { // Serialize the request f_service_ << indent() << "int32_t cseqid = 0;" << endl << - indent() << "_oprot->writeMessageBegin(_otrans, \"" << (*f_iter)->get_name() << "\", facebook::thrift::protocol::T_CALL, cseqid);" << endl << + indent() << "oprot_->writeMessageBegin(\"" << (*f_iter)->get_name() << "\", facebook::thrift::protocol::T_CALL, cseqid);" << endl << endl << - indent() << argsname << " __args;" << endl; + indent() << argsname << " args;" << endl; for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { f_service_ << - indent() << "__args." << (*fld_iter)->get_name() << " = " << (*fld_iter)->get_name() << ";" << endl; + indent() << "args." << (*fld_iter)->get_name() << " = " << (*fld_iter)->get_name() << ";" << endl; } f_service_ << - indent() << "__args.write(_oprot, _otrans);" << endl << + indent() << "args.write(oprot_);" << endl << endl << - indent() << "_oprot->writeMessageEnd(_otrans);" << endl << - indent() << "_otrans->flush();" << endl; + indent() << "oprot_->writeMessageEnd();" << endl << + indent() << "oprot_->getOutputTransport()->flush();" << endl; scope_down(f_service_); f_service_ << endl; // Generate recv function only if not an async function if (!(*f_iter)->is_async()) { - t_struct noargs; + t_struct noargs(program_); t_function recv_function((*f_iter)->get_returntype(), string("recv_") + (*f_iter)->get_name(), &noargs); @@ -769,7 +841,7 @@ void t_cpp_generator::generate_service_client(t_service* tservice) { indent() << "std::string fname;" << endl << indent() << "facebook::thrift::protocol::TMessageType mtype;" << endl << endl << - indent() << "_iprot->readMessageBegin(_itrans, fname, mtype, rseqid);" << endl << + indent() << "iprot_->readMessageBegin(fname, mtype, rseqid);" << endl << indent() << "if (mtype != facebook::thrift::protocol::T_REPLY || fname.compare(\"" << (*f_iter)->get_name() << "\") != 0) {" << endl; indent_up(); f_service_ << @@ -778,16 +850,16 @@ void t_cpp_generator::generate_service_client(t_service* tservice) { f_service_ << indent() << "}" << endl << - indent() << resultname << " __result;" << endl << - indent() << "__result.read(_iprot, _itrans);" << endl << - indent() << "_iprot->readMessageEnd(_itrans);" << endl << + indent() << resultname << " result;" << endl << + indent() << "result.read(iprot_);" << endl << + indent() << "iprot_->readMessageEnd();" << endl << endl; // Careful, only look for _result if not a void function if (!(*f_iter)->get_returntype()->is_void()) { f_service_ << - indent() << "if (__result.__isset.success) {" << endl << - indent() << " return __result.success;" << endl << + indent() << "if (result.__isset.success) {" << endl << + indent() << " return result.success;" << endl << indent() << "}" << endl; } @@ -796,8 +868,8 @@ void t_cpp_generator::generate_service_client(t_service* tservice) { vector::const_iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { f_service_ << - indent() << "if (__result.__isset." << (*x_iter)->get_name() << ") {" << endl << - indent() << " throw __result." << (*x_iter)->get_name() << ";" << endl << + indent() << "if (result.__isset." << (*x_iter)->get_name() << ") {" << endl << + indent() << " throw result." << (*x_iter)->get_name() << ";" << endl << indent() << "}" << endl; } @@ -822,43 +894,53 @@ void t_cpp_generator::generate_service_client(t_service* tservice) { * * @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 functions = tservice->get_functions(); vector::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 _iprot;" << endl << - indent() << "boost::shared_ptr _oprot;" << endl << - indent() << "std::map, boost::shared_ptr)> _processMap;" << endl; + indent() << "boost::shared_ptr<" << service_name_ << "If> iface_;" << endl; + f_header_ << + indent() << "virtual bool process_fn(boost::shared_ptr iprot, boost::shared_ptr oprot, std::string& fname, int32_t seqid);" << endl; indent_down(); // Process function declarations f_header_ << " private:" << endl; indent_up(); + f_header_ << + indent() << "std::map, boost::shared_ptr)> 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 _itrans, boost::shared_ptr _otrans);" << endl; + "void process_" << (*f_iter)->get_name() << "(int32_t seqid, boost::shared_ptr iprot, boost::shared_ptr oprot);" << endl; } indent_down(); indent_up(); string declare_map = ""; indent_up(); + for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { declare_map += indent(); - declare_map += "_processMap[\""; + declare_map += "processMap_[\""; declare_map += (*f_iter)->get_name(); declare_map += "\"] = &"; declare_map += service_name_; @@ -870,20 +952,20 @@ void t_cpp_generator::generate_service_server(t_service* tservice) { f_header_ << " public: " << endl << - indent() << service_name_ << "Processor(boost::shared_ptr<" << service_name_ << "If> iface, boost::shared_ptr prot) :" << endl << - indent() << " _iface(iface)," << endl << - indent() << " _iprot(prot)," << endl << - indent() << " _oprot(prot) {" << endl << - declare_map << - indent() << "}" << endl << - indent() << service_name_ << "Processor(boost::shared_ptr<" << service_name_ << "If> iface, boost::shared_ptr iprot, boost::shared_ptr oprot) :" << 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 _itrans, boost::shared_ptr _otrans);" << endl << + indent() << "virtual bool process(boost::shared_ptr iprot, boost::shared_ptr oprot);" << endl << indent() << "virtual ~" << service_name_ << "Processor() {}" << endl; indent_down(); f_header_ << @@ -891,7 +973,7 @@ void t_cpp_generator::generate_service_server(t_service* tservice) { // Generate the server implementation f_service_ << - "bool " << service_name_ << "Processor::process(boost::shared_ptr itrans, boost::shared_ptr otrans) {" << endl; + "bool " << service_name_ << "Processor::process(boost::shared_ptr iprot, boost::shared_ptr oprot) {" << endl; indent_up(); f_service_ << @@ -900,21 +982,39 @@ void t_cpp_generator::generate_service_server(t_service* tservice) { 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 iprot, boost::shared_ptr oprot, std::string& fname, int32_t seqid) {" << endl; + indent_up(); + // HOT: member function pointer map f_service_ << - indent() << "std::map, boost::shared_ptr)>::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, boost::shared_ptr)>::iterator pfn;" << endl << + indent() << "pfn = processMap_.find(fname);" << endl << + indent() << "if (pfn == processMap_.end()) {" << endl; + if (extends.empty()) { + f_service_ << + indent() << " throw facebook::thrift::Exception(\"Unknown function name: '\"+fname+\"'\");" << endl; + } else { + f_service_ << + indent() << " return " << extends << "Processor::process_fn(iprot, oprot, fname, seqid);" << endl; + } + f_service_ << indent() << "} else {" << endl << - indent() << " (this->*(pfn->second))(seqid, itrans, otrans);" << endl << + indent() << " (this->*(pfn->second))(seqid, iprot, oprot);" << endl << indent() << "}" << endl; // Read end of args field, the T_STOP, and the struct close @@ -942,7 +1042,7 @@ void t_cpp_generator::generate_function_helpers(t_function* tfunction) { return; } - t_struct result(tfunction->get_name() + "_result"); + t_struct result(program_, tfunction->get_name() + "_result"); t_field success(tfunction->get_returntype(), "success", 0); if (!tfunction->get_returntype()->is_void()) { result.append(&success); @@ -971,17 +1071,17 @@ void t_cpp_generator::generate_process_function(t_service* tservice, f_service_ << "void " << tservice->get_name() << "Processor::" << "process_" << tfunction->get_name() << - "(int32_t seqid, boost::shared_ptr itrans, boost::shared_ptr otrans)" << endl; + "(int32_t seqid, boost::shared_ptr iprot, boost::shared_ptr oprot)" << endl; scope_up(f_service_); string argsname = tfunction->get_name() + "_args"; string resultname = tfunction->get_name() + "_result"; f_service_ << - indent() << argsname << " __args;" << endl << - indent() << "__args.read(_iprot, itrans);" << endl << - indent() << "_iprot->readMessageEnd(itrans);" << endl << - indent() << "itrans->readEnd();" << endl << + indent() << argsname << " args;" << endl << + indent() << "args.read(iprot);" << endl << + indent() << "iprot->readMessageEnd();" << endl << + indent() << "iprot->getInputTransport()->readEnd();" << endl << endl; t_struct* xs = tfunction->get_xceptions(); @@ -991,7 +1091,7 @@ void t_cpp_generator::generate_process_function(t_service* tservice, // Declare result if (!tfunction->is_async()) { f_service_ << - indent() << resultname << " __result;" << endl; + indent() << resultname << " result;" << endl; } // Try block for functions with exceptions @@ -1008,10 +1108,10 @@ void t_cpp_generator::generate_process_function(t_service* tservice, f_service_ << indent(); if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) { - f_service_ << "__result.success = "; + f_service_ << "result.success = "; } f_service_ << - "_iface->" << tfunction->get_name() << "("; + "iface_->" << tfunction->get_name() << "("; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { @@ -1019,14 +1119,14 @@ void t_cpp_generator::generate_process_function(t_service* tservice, } else { f_service_ << ", "; } - f_service_ << "__args." << (*f_iter)->get_name(); + f_service_ << "args." << (*f_iter)->get_name(); } f_service_ << ");" << endl; // Set isset on success field if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) { f_service_ << - indent() << "__result.__isset.success = true;" << endl; + indent() << "result.__isset.success = true;" << endl; } if (!tfunction->is_async() && xceptions.size() > 0) { @@ -1037,8 +1137,8 @@ void t_cpp_generator::generate_process_function(t_service* tservice, if (!tfunction->is_async()) { indent_up(); f_service_ << - indent() << "__result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << ";" << endl << - indent() << "__result.__isset." << (*x_iter)->get_name() << " = true;" << endl; + indent() << "result." << (*x_iter)->get_name() << " = " << (*x_iter)->get_name() << ";" << endl << + indent() << "result.__isset." << (*x_iter)->get_name() << " = true;" << endl; indent_down(); f_service_ << indent() << "}"; } else { @@ -1061,17 +1161,103 @@ void t_cpp_generator::generate_process_function(t_service* tservice, // 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 " << endl << + "#include " << endl << + "#include " << endl << + "#include " << 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 functions = tservice->get_functions(); + vector::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 processor(new " << svcname << "Processor(handler));" << endl << + indent() << "shared_ptr serverTransport(new TServerSocket(port));" << endl << + indent() << "shared_ptr transportFactory(new TBufferedTransportFactory());" << endl << + indent() << "shared_ptr 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. */ @@ -1106,31 +1292,31 @@ void t_cpp_generator::generate_deserialize_field(ofstream& out, name; break; case t_base_type::TYPE_STRING: - out << "readString(itrans, " << name << ");"; + out << "readString(" << name << ");"; break; case t_base_type::TYPE_BOOL: - out << "readBool(itrans, " << name << ");"; + out << "readBool(" << name << ");"; break; case t_base_type::TYPE_BYTE: - out << "readByte(itrans, " << name << ");"; + out << "readByte(" << name << ");"; break; case t_base_type::TYPE_I16: - out << "readI16(itrans, " << name << ");"; + out << "readI16(" << name << ");"; break; case t_base_type::TYPE_I32: - out << "readI32(itrans, " << name << ");"; + out << "readI32(" << name << ");"; break; case t_base_type::TYPE_I64: - out << "readI64(itrans, " << name << ");"; + out << "readI64(" << name << ");"; break; case t_base_type::TYPE_DOUBLE: - out << "readDouble(itrans, " << name << ");"; + out << "readDouble(" << name << ");"; break; default: throw "compiler error: no C++ reader for base type " + tbase + name; } } else if (type->is_enum()) { - out << "readI32(itrans, (int32_t&)" << name << ");"; + out << "readI32((int32_t&)" << name << ");"; } out << endl; @@ -1150,7 +1336,7 @@ void t_cpp_generator::generate_deserialize_struct(ofstream& out, t_struct* tstruct, string prefix) { indent(out) << - "xfer += " << prefix << ".read(iprot, itrans);" << endl; + "xfer += " << prefix << ".read(iprot);" << endl; } void t_cpp_generator::generate_deserialize_container(ofstream& out, @@ -1171,17 +1357,17 @@ 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; } @@ -1206,11 +1392,11 @@ void t_cpp_generator::generate_deserialize_container(ofstream& out, // Read container end if (ttype->is_map()) { - indent(out) << "iprot->readMapEnd(itrans);" << endl; + indent(out) << "iprot->readMapEnd();" << endl; } else if (ttype->is_set()) { - indent(out) << "iprot->readSetEnd(itrans);" << endl; + indent(out) << "iprot->readSetEnd();" << endl; } else if (ttype->is_list()) { - indent(out) << "iprot->readListEnd(itrans);" << endl; + indent(out) << "iprot->readListEnd();" << endl; } scope_down(out); @@ -1312,31 +1498,31 @@ void t_cpp_generator::generate_serialize_field(ofstream& 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 { @@ -1357,7 +1543,7 @@ void t_cpp_generator::generate_serialize_struct(ofstream& out, t_struct* tstruct, string prefix) { indent(out) << - "xfer += " << prefix << ".write(oprot, otrans);" << endl; + "xfer += " << prefix << ".write(oprot);" << endl; } void t_cpp_generator::generate_serialize_container(ofstream& out, @@ -1367,18 +1553,18 @@ 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; } @@ -1399,13 +1585,13 @@ void t_cpp_generator::generate_serialize_container(ofstream& out, 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); @@ -1445,6 +1631,29 @@ void t_cpp_generator::generate_serialize_list_element(ofstream& 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. * @@ -1523,6 +1732,14 @@ string t_cpp_generator::type_name(t_type* ttype) { return "std::vector<" + type_name(tlist->get_elem_type()) + "> "; } + // Check if it needs to be namespaced + t_program* program = ttype->get_program(); + if (program != NULL && program != program_) { + return + namespace_prefix(program->get_cpp_namespace()) + + ttype->get_name(); + } + return ttype->get_name(); } diff --git a/compiler/cpp/src/generate/t_cpp_generator.h b/compiler/cpp/src/generate/t_cpp_generator.h index 37c36a1e..45cbdac5 100644 --- a/compiler/cpp/src/generate/t_cpp_generator.h +++ b/compiler/cpp/src/generate/t_cpp_generator.h @@ -18,14 +18,15 @@ */ class t_cpp_generator : public t_oop_generator { public: - t_cpp_generator() {} + t_cpp_generator(t_program* program) : + t_oop_generator(program) {} /** * Init and close methods */ - void init_generator(t_program *tprogram); - void close_generator(t_program *tprogram); + void init_generator(); + void close_generator(); /** * Program-level generation functions @@ -49,7 +50,8 @@ class t_cpp_generator : public t_oop_generator { void generate_service_multiface (t_service* tservice); void generate_service_helpers (t_service* tservice); void generate_service_client (t_service* tservice); - void generate_service_server (t_service* tservice); + void generate_service_processor (t_service* tservice); + void generate_service_skeleton (t_service* tservice); void generate_process_function (t_service* tservice, t_function* tfunction); void generate_function_helpers (t_function* tfunction); @@ -109,6 +111,7 @@ class t_cpp_generator : public t_oop_generator { * Helper rendering functions */ + std::string namespace_prefix(std::string ns); std::string namespace_open(std::string ns); std::string namespace_close(std::string ns); std::string type_name(t_type* ttype); diff --git a/compiler/cpp/src/generate/t_generator.cc b/compiler/cpp/src/generate/t_generator.cc index dc09ba10..30830d63 100644 --- a/compiler/cpp/src/generate/t_generator.cc +++ b/compiler/cpp/src/generate/t_generator.cc @@ -9,43 +9,40 @@ using namespace std; * @param program The thrift program to compile into C++ source * @author Mark Slee */ -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 typedefs = tprogram->get_typedefs(); + vector typedefs = program_->get_typedefs(); vector::iterator td_iter; for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) { generate_typedef(*td_iter); } // Generate enums - vector enums = tprogram->get_enums(); + vector enums = program_->get_enums(); vector::iterator en_iter; for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) { generate_enum(*en_iter); } // Generate structs - vector structs = tprogram->get_structs(); + vector structs = program_->get_structs(); vector::iterator st_iter; for (st_iter = structs.begin(); st_iter != structs.end(); ++st_iter) { generate_struct(*st_iter); } // Generate xceptions - vector xceptions = tprogram->get_xceptions(); + vector xceptions = program_->get_xceptions(); vector::iterator x_iter; for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { generate_xception(*x_iter); } // Generate services - vector services = tprogram->get_services(); + vector services = program_->get_services(); vector::iterator sv_iter; for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) { service_name_ = get_service_name(*sv_iter); @@ -53,5 +50,5 @@ void t_generator::generate_program(t_program *tprogram) { } // Close the generator - close_generator(tprogram); + close_generator(); } diff --git a/compiler/cpp/src/generate/t_generator.h b/compiler/cpp/src/generate/t_generator.h index 07eaf386..18a2247d 100644 --- a/compiler/cpp/src/generate/t_generator.h +++ b/compiler/cpp/src/generate/t_generator.h @@ -15,8 +15,11 @@ */ class t_generator { public: - t_generator() { + t_generator(t_program* program) { tmp_ = 0; + indent_ = 0; + program_ = program; + program_name_ = get_program_name(program); } virtual ~t_generator() {} @@ -26,7 +29,7 @@ class 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: @@ -35,8 +38,8 @@ class t_generator { * 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. @@ -107,6 +110,11 @@ class t_generator { } protected: + /** + * The program being generated + */ + t_program* program_; + /** * Quick accessor for formatted program name that is currently being * generated. diff --git a/compiler/cpp/src/generate/t_java_generator.cc b/compiler/cpp/src/generate/t_java_generator.cc index b99c748d..1c43fdb0 100644 --- a/compiler/cpp/src/generate/t_java_generator.cc +++ b/compiler/cpp/src/generate/t_java_generator.cc @@ -10,10 +10,10 @@ using namespace std; * * @param tprogram The program to generate */ -void t_java_generator::init_generator(t_program* tprogram) { +void t_java_generator::init_generator() { // Make output directory mkdir(T_JAVA_DIR, S_IREAD | S_IWRITE | S_IEXEC); - package_name_ = tprogram->get_namespace(); + package_name_ = program_->get_java_package(); } /** @@ -22,7 +22,10 @@ void t_java_generator::init_generator(t_program* tprogram) { * @return String of the package, i.e. "package com.facebook.thriftdemo;" */ string t_java_generator::java_package() { - return string("package ") + package_name_ + ";\n\n"; + if (!package_name_.empty()) { + return string("package ") + package_name_ + ";\n\n"; + } + return ""; } /** @@ -54,7 +57,7 @@ string t_java_generator::java_thrift_imports() { /** * Nothing in Java */ -void t_java_generator::close_generator(t_program *tprogram) {} +void t_java_generator::close_generator() {} /** * Generates a typedef. This is not done in Java, since it does @@ -163,7 +166,7 @@ void t_java_generator::generate_java_struct_definition(ofstream &out, bool is_exception, bool in_class, bool is_result) { - out << + indent(out) << "public " << (in_class ? "static " : "") << "class " << tstruct->get_name() << " "; if (is_exception) { @@ -441,8 +444,15 @@ void t_java_generator::generate_service(t_service* tservice) { * @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 functions = tservice->get_functions(); vector::iterator f_iter; @@ -477,8 +487,15 @@ void t_java_generator::generate_service_helpers(t_service* tservice) { * @param tservice The service to generate a server for. */ void t_java_generator::generate_service_client(t_service* tservice) { - f_service_ << - "public static class Client implements Iface {" << endl; + string extends = ""; + string extends_client = ""; + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + extends_client = " extends " + extends + ".Client"; + } + + indent(f_service_) << + "public static class Client" << extends_client << " implements Iface {" << endl; indent_up(); indent(f_service_) << @@ -493,22 +510,29 @@ void t_java_generator::generate_service_client(t_service* tservice) { "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 functions = tservice->get_functions(); @@ -551,7 +575,7 @@ void t_java_generator::generate_service_client(t_service* tservice) { scope_down(f_service_); f_service_ << endl; - t_function send_function(g_program->get_void_type(), + t_function send_function(g_type_void, string("send_") + (*f_iter)->get_name(), (*f_iter)->get_arglist()); @@ -583,7 +607,7 @@ void t_java_generator::generate_service_client(t_service* tservice) { if (!(*f_iter)->is_async()) { string resultname = (*f_iter)->get_name() + "_result"; - t_struct noargs; + t_struct noargs(program_); t_function recv_function((*f_iter)->get_returntype(), string("recv_") + (*f_iter)->get_name(), &noargs, @@ -635,7 +659,7 @@ void t_java_generator::generate_service_client(t_service* tservice) { } indent_down(); - f_service_ << + indent(f_service_) << "}" << endl; } @@ -649,9 +673,17 @@ void t_java_generator::generate_service_server(t_service* tservice) { vector functions = tservice->get_functions(); vector::iterator f_iter; + // Extends stuff + string extends = ""; + string extends_processor = ""; + if (tservice->get_extends() != NULL) { + extends = type_name(tservice->get_extends()); + extends_processor = " extends " + extends + ".Processor"; + } + // Generate the header portion - f_service_ << - "public static class Processor implements TProcessor {" << endl; + indent(f_service_) << + "public static class Processor" << extends_processor << " implements TProcessor {" << endl; indent_up(); indent(f_service_) << @@ -665,17 +697,48 @@ void t_java_generator::generate_service_server(t_service* tservice) { 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 _processMap = new HashMap();" << endl; + } + + if (extends.empty()) { + f_service_ << + indent() << "protected TProtocol _iprot;" << endl << + indent() << "protected TProtocol _oprot;" << endl; + } + + f_service_ << endl; // Generate the server implementation indent(f_service_) << @@ -683,34 +746,17 @@ void t_java_generator::generate_service_server(t_service* tservice) { scope_up(f_service_); f_service_ << - indent() << "TMessage _msg = _iprot.readMessageBegin(_itrans);" << endl; + indent() << "TMessage msg = _iprot.readMessageBegin(_itrans);" << endl; // TODO(mcslee): validate message, was the seqid etc. legit? - bool first = true; - for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { - if (!first) { - f_service_ << " else "; - } else { - f_service_ << indent(); - first = false; - } - f_service_ << - "if (_msg.name.equals(\"" << (*f_iter)->get_name() <<"\")) {" << endl; - indent_up(); - indent(f_service_) << - "process_" << (*f_iter)->get_name() << "(_msg.seqid, _itrans, _otrans);" << endl; - indent_down(); - indent(f_service_) << "}"; - } f_service_ << - " else {" << endl; - indent_up(); - indent(f_service_) << - "System.err.println(\"Unknown function: '\" + _msg.name + \"'\");" << endl; - indent_down(); - indent(f_service_) << - "}" << endl; + indent() << "ProcessFunction fn = _processMap.get(msg.name);" << endl << + indent() << "if (fn == null) {" << endl << + indent() << " System.err.println(\"Unknown function: '\" + msg.name + \"'\");" << endl << + indent() << "} else {" << endl << + indent() << " fn.process(msg.seqid, _itrans, _otrans);" << endl << + indent() << "}" << endl; // Read end of args field, the T_STOP, and the struct close f_service_ << @@ -725,7 +771,7 @@ void t_java_generator::generate_service_server(t_service* tservice) { } indent_down(); - f_service_ << + indent(f_service_) << "}" << endl << endl; } @@ -740,7 +786,7 @@ void t_java_generator::generate_function_helpers(t_function* tfunction) { return; } - t_struct result(tfunction->get_name() + "_result"); + t_struct result(program_, tfunction->get_name() + "_result"); t_field success(tfunction->get_returntype(), "success", 0); if (!tfunction->get_returntype()->is_void()) { result.append(&success); @@ -763,9 +809,14 @@ void t_java_generator::generate_function_helpers(t_function* tfunction) { */ void t_java_generator::generate_process_function(t_service* tservice, t_function* tfunction) { + // Open class + indent(f_service_) << + "private class " << tfunction->get_name() << " implements ProcessFunction {" << endl; + indent_up(); + // Open function indent(f_service_) << - "private void process_" << tfunction->get_name() << "(int seqid, TTransport _itrans, TTransport _otrans) throws TException" << endl; + "public void process(int seqid, TTransport _itrans, TTransport _otrans) throws TException" << endl; scope_up(f_service_); string argsname = tfunction->get_name() + "_args"; @@ -859,6 +910,12 @@ void t_java_generator::generate_process_function(t_service* tservice, // Close function scope_down(f_service_); f_service_ << endl; + + // Close class + indent_down(); + f_service_ << + indent() << "}" << endl << + endl; } /** @@ -942,7 +999,7 @@ void t_java_generator::generate_deserialize_struct(ofstream& out, t_struct* tstruct, string prefix) { out << - indent() << prefix << " = new " << tstruct->get_name() << "();" << endl << + indent() << prefix << " = new " << type_name(tstruct) << "();" << endl << indent() << prefix << ".read(_iprot, _itrans);" << endl; } @@ -1296,9 +1353,18 @@ string t_java_generator::type_name(t_type* ttype, bool in_container) { } else if (ttype->is_list()) { t_list* tlist = (t_list*) ttype; return "ArrayList<" + type_name(tlist->get_elem_type(), true) + ">"; - } else { - return ttype->get_name(); } + + // Check for namespacing + t_program* program = ttype->get_program(); + if (program != NULL && program != program_) { + string package = program->get_java_package(); + if (!package.empty()) { + return package + "." + ttype->get_name(); + } + } + + return ttype->get_name(); } /** diff --git a/compiler/cpp/src/generate/t_java_generator.h b/compiler/cpp/src/generate/t_java_generator.h index e528c342..2b60e733 100644 --- a/compiler/cpp/src/generate/t_java_generator.h +++ b/compiler/cpp/src/generate/t_java_generator.h @@ -18,14 +18,15 @@ */ class t_java_generator : public t_oop_generator { public: - t_java_generator() {} + t_java_generator(t_program* program) : + t_oop_generator(program) {} /** * Init and close methods */ - void init_generator(t_program *tprogram); - void close_generator(t_program *tprogram); + void init_generator(); + void close_generator(); /** * Program-level generation functions diff --git a/compiler/cpp/src/generate/t_oop_generator.h b/compiler/cpp/src/generate/t_oop_generator.h index fc47bc6d..d0d29466 100644 --- a/compiler/cpp/src/generate/t_oop_generator.h +++ b/compiler/cpp/src/generate/t_oop_generator.h @@ -12,6 +12,8 @@ */ class t_oop_generator : public t_generator { public: + t_oop_generator(t_program* program) : + t_generator(program) {} /** * Scoping, using curly braces! diff --git a/compiler/cpp/src/generate/t_php_generator.cc b/compiler/cpp/src/generate/t_php_generator.cc index 61df5898..5a6b8acf 100644 --- a/compiler/cpp/src/generate/t_php_generator.cc +++ b/compiler/cpp/src/generate/t_php_generator.cc @@ -10,7 +10,7 @@ using namespace std; * * @param tprogram The program to generate */ -void t_php_generator::init_generator(t_program* tprogram) { +void t_php_generator::init_generator() { // Make output directory mkdir(T_PHP_DIR, S_IREAD | S_IWRITE | S_IEXEC); @@ -36,7 +36,7 @@ string t_php_generator::php_includes() { /** * Close up (or down) some filez. */ -void t_php_generator::close_generator(t_program *tprogram) { +void t_php_generator::close_generator() { // Close types file f_types_ << "?>" << endl; f_types_.close(); @@ -80,7 +80,6 @@ void t_php_generator::generate_enum(t_enum* tenum) { // We're also doing it this way to see how it performs. It's more legible // code but you can't do things like an 'extract' on it, which is a bit of // a downer. - f_types_ << "final class " << tenum->get_name() << " {" << endl; indent_up(); @@ -97,6 +96,10 @@ void t_php_generator::generate_enum(t_enum* tenum) { "const " << (*c_iter)->get_name() << " = " << value << ";" << endl; } + // Prevent instantiation of this class + f_types_ << + indent() << "private function __construct() {}" << endl; + indent_down(); f_types_ << "}" << endl << endl; } @@ -201,8 +204,8 @@ void t_php_generator::generate_php_struct_reader(ofstream& out, // Read beginning field marker if (binary_inline_) { - t_field fftype(g_program->get_byte_type(), "ftype"); - t_field ffid(g_program->get_i16_type(), "fid"); + t_field fftype(g_type_byte, "ftype"); + t_field ffid(g_type_i16, "fid"); generate_deserialize_field(out, &fftype); out << indent() << "if ($ftype == TType::STOP) {" << endl << @@ -364,7 +367,15 @@ void t_php_generator::generate_service(t_service* tservice) { php_includes(); f_service_ << - "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << program_name_ << "/" << program_name_ << "_types.php';" << endl << endl; + "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << program_name_ << "/" << program_name_ << "_types.php';" << endl; + + if (tservice->get_extends() != NULL) { + f_service_ << + "include_once $GLOBALS['THRIFT_ROOT'].'/packages/" << tservice->get_extends()->get_program()->get_name() << "/" << tservice->get_extends()->get_name() << ".php';" << endl; + } + + f_service_ << + endl; // Generate the three main parts of the service (well, two for now in PHP) generate_service_interface(tservice); @@ -387,32 +398,55 @@ void t_php_generator::generate_service_processor(t_service* tservice) { vector functions = tservice->get_functions(); vector::iterator f_iter; + string extends = ""; + string extends_processor = ""; + if (tservice->get_extends() != NULL) { + extends = tservice->get_extends()->get_name(); + extends_processor = " extends " + extends + "Processor"; + } + // Generate the header portion f_service_ << - "class " << service_name_ << "Processor {" << endl; + "class " << service_name_ << "Processor" << extends_processor << " {" << endl; indent_up(); - f_service_ << - indent() << "private $_handler = null;" << endl; - if (!binary_inline_) { - f_service_ << - indent() << "private $_iprot = null;" << endl << - indent() << "private $_oprot = null;" << endl << - endl; + if (extends.empty()) { + f_service_ << + indent() << "protected $_handler = null;" << endl; + if (!binary_inline_) { + f_service_ << + indent() << "protected $_iprot = null;" << endl << + indent() << "protected $_oprot = null;" << endl << + endl; + } } if (binary_inline_) { f_service_ << - indent() << "public function __construct($handler) {" << endl << - indent() << " $this->_handler = $handler;" << endl << + indent() << "public function __construct($handler) {" << endl; + if (extends.empty()) { + f_service_ << + indent() << " $this->_handler = $handler;" << endl; + } else { + f_service_ << + indent() << " parent::__construct($handler);" << endl; + } + f_service_ << indent() << "}" << endl << endl; } else { f_service_ << - indent() << "public function __construct($handler, $iprot, $oprot=null) {" << endl << - indent() << " $this->_handler = $handler;" << endl << - indent() << " $this->_iprot = $iprot;" << endl << - indent() << " $this->_oprot = $oprot ? $oprot : $iprot;" << endl << + indent() << "public function __construct($handler, $iprot, $oprot=null) {" << endl; + if (extends.empty()) { + f_service_ << + indent() << " $this->_handler = $handler;" << endl << + indent() << " $this->_iprot = $iprot;" << endl << + indent() << " $this->_oprot = $oprot ? $oprot : $iprot;" << endl; + } else { + f_service_ << + indent() << " parent::__construct($handler, $iprot, $oprot);" << endl; + } + f_service_ << indent() << "}" << endl << endl; } @@ -429,9 +463,9 @@ void t_php_generator::generate_service_processor(t_service* tservice) { endl; if (binary_inline_) { - t_field ffname(g_program->get_string_type(), "fname"); - t_field fmtype(g_program->get_byte_type(), "mtype"); - t_field fseqid(g_program->get_i32_type(), "rseqid"); + t_field ffname(g_type_string, "fname"); + t_field fmtype(g_type_byte, "mtype"); + t_field fseqid(g_type_i32, "rseqid"); generate_deserialize_field(f_service_, &ffname, "", true); generate_deserialize_field(f_service_, &fmtype, "", true); generate_deserialize_field(f_service_, &fseqid, "", true); @@ -602,7 +636,7 @@ void t_php_generator::generate_service_helpers(t_service* tservice) { * @param tfunction The function */ void t_php_generator::generate_php_function_helpers(t_function* tfunction) { - t_struct result(service_name_ + "_" + tfunction->get_name() + "_result"); + t_struct result(program_, service_name_ + "_" + tfunction->get_name() + "_result"); t_field success(tfunction->get_returntype(), "success", 0); if (!tfunction->get_returntype()->is_void()) { result.append(&success); @@ -624,14 +658,20 @@ void t_php_generator::generate_php_function_helpers(t_function* tfunction) { * @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 functions = tservice->get_functions(); vector::iterator f_iter; for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { indent(f_service_) << - "public abstract function " << function_signature(*f_iter) << ";" << endl; + "public function " << function_signature(*f_iter) << ";" << endl; } indent_down(); f_service_ << @@ -644,53 +684,59 @@ void t_php_generator::generate_service_interface(t_service* tservice) { * @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; @@ -780,7 +826,7 @@ void t_php_generator::generate_service_client(t_service* tservice) { if (!(*f_iter)->is_async()) { std::string resultname = service_name_ + "_" + (*f_iter)->get_name() + "_result"; - t_struct noargs; + t_struct noargs(program_); t_function recv_function((*f_iter)->get_returntype(), string("recv_") + (*f_iter)->get_name(), @@ -798,9 +844,9 @@ void t_php_generator::generate_service_client(t_service* tservice) { endl; if (binary_inline_) { - t_field ffname(g_program->get_string_type(), "fname"); - t_field fmtype(g_program->get_byte_type(), "mtype"); - t_field fseqid(g_program->get_i32_type(), "rseqid"); + t_field ffname(g_type_string, "fname"); + t_field fmtype(g_type_byte, "mtype"); + t_field fseqid(g_type_i32, "rseqid"); generate_deserialize_field(f_service_, &ffname, "", true); generate_deserialize_field(f_service_, &fmtype, "", true); generate_deserialize_field(f_service_, &fseqid, "", true); @@ -1046,10 +1092,10 @@ void t_php_generator::generate_deserialize_container(ofstream &out, string vtype = tmp("_vtype"); string etype = tmp("_etype"); - t_field fsize(g_program->get_i32_type(), size); - t_field fktype(g_program->get_byte_type(), ktype); - t_field fvtype(g_program->get_byte_type(), vtype); - t_field fetype(g_program->get_byte_type(), etype); + t_field fsize(g_type_i32, size); + t_field fktype(g_type_byte, ktype); + t_field fvtype(g_type_byte, vtype); + t_field fetype(g_type_byte, etype); out << indent() << "$" << prefix << " = array();" << endl << diff --git a/compiler/cpp/src/generate/t_php_generator.h b/compiler/cpp/src/generate/t_php_generator.h index 0e6869b9..609cbae0 100644 --- a/compiler/cpp/src/generate/t_php_generator.h +++ b/compiler/cpp/src/generate/t_php_generator.h @@ -15,8 +15,9 @@ */ class t_php_generator : public t_oop_generator { public: - t_php_generator(bool binary_inline=false) { - binary_inline_ = binary_inline; + t_php_generator(t_program* program, bool binary_inline=false) : + t_oop_generator(program), + binary_inline_(binary_inline) { if (binary_inline_) { T_PHP_DIR = "gen-phpi"; } else { @@ -28,8 +29,8 @@ class t_php_generator : public t_oop_generator { * Init and close methods */ - void init_generator(t_program *tprogram); - void close_generator(t_program *tprogram); + void init_generator(); + void close_generator(); /** * Program-level generation functions diff --git a/compiler/cpp/src/generate/t_py_generator.cc b/compiler/cpp/src/generate/t_py_generator.cc index 9838df61..6398f116 100644 --- a/compiler/cpp/src/generate/t_py_generator.cc +++ b/compiler/cpp/src/generate/t_py_generator.cc @@ -11,7 +11,7 @@ using namespace std; * * @param tprogram The program to generate */ -void t_py_generator::init_generator(t_program* tprogram) { +void t_py_generator::init_generator() { // Make output directory mkdir(T_PY_DIR, S_IREAD | S_IWRITE | S_IEXEC); @@ -23,7 +23,22 @@ void t_py_generator::init_generator(t_program* tprogram) { 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& includes = program_->get_includes(); + string result = ""; + for (size_t i = 0; i < includes.size(); ++i) { + result += "import " + includes[i]->get_name() + "_types\n"; + } + if (includes.size() > 0) { + result += "\n"; + } + return result; } /** @@ -50,7 +65,7 @@ string t_py_generator::py_imports() { /** * Closes the type files */ -void t_py_generator::close_generator(t_program *tprogram) { +void t_py_generator::close_generator() { // Close types file f_types_.close(); } @@ -307,6 +322,11 @@ void t_py_generator::generate_service(t_service* tservice) { py_autogen_comment() << endl << py_imports() << endl; + if (tservice->get_extends() != NULL) { + f_service_ << + "import " << tservice->get_extends()->get_name() << endl; + } + f_service_ << "from " << program_name_ << "_types import *" << endl << "from thrift.Thrift import TProcessor" << endl << @@ -315,8 +335,8 @@ void t_py_generator::generate_service(t_service* tservice) { // Generate the three main parts of the service (well, two for now in PHP) generate_service_interface(tservice); generate_service_client(tservice); - generate_service_helpers(tservice); generate_service_server(tservice); + generate_service_helpers(tservice); generate_service_remote(tservice); // Close service file @@ -349,7 +369,7 @@ void t_py_generator::generate_service_helpers(t_service* tservice) { * @param tfunction The function */ void t_py_generator::generate_py_function_helpers(t_function* tfunction) { - t_struct result(tfunction->get_name() + "_result"); + t_struct result(program_, tfunction->get_name() + "_result"); t_field success(tfunction->get_returntype(), "success", 0); if (!tfunction->get_returntype()->is_void()) { result.append(&success); @@ -370,8 +390,15 @@ void t_py_generator::generate_py_function_helpers(t_function* tfunction) { * @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 functions = tservice->get_functions(); vector::iterator f_iter; @@ -391,25 +418,39 @@ void t_py_generator::generate_service_interface(t_service* tservice) { * @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 functions = tservice->get_functions(); @@ -457,7 +498,7 @@ void t_py_generator::generate_service_client(t_service* tservice) { // Serialize the request header f_service_ << - indent() << "self.__oprot.writeMessageBegin(self.__otrans, '" << (*f_iter)->get_name() << "', TMessageType.CALL, self.__seqid)" << endl; + indent() << "self._oprot.writeMessageBegin(self._otrans, '" << (*f_iter)->get_name() << "', TMessageType.CALL, self._seqid)" << endl; f_service_ << indent() << "__args = " << argsname << "()" << endl; @@ -469,16 +510,16 @@ void t_py_generator::generate_service_client(t_service* tservice) { // Write to the stream f_service_ << - indent() << "__args.write(self.__oprot, self.__otrans)" << endl << - indent() << "self.__oprot.writeMessageEnd(self.__otrans)" << endl << - indent() << "self.__otrans.flush()" << endl; + indent() << "__args.write(self._oprot, self._otrans)" << endl << + indent() << "self._oprot.writeMessageEnd(self._otrans)" << endl << + indent() << "self._otrans.flush()" << endl; indent_down(); if (!(*f_iter)->is_async()) { std::string resultname = (*f_iter)->get_name() + "_result"; - t_struct noargs; + t_struct noargs(program_); t_function recv_function((*f_iter)->get_returntype(), string("recv_") + (*f_iter)->get_name(), @@ -490,14 +531,14 @@ void t_py_generator::generate_service_client(t_service* tservice) { indent_up(); f_service_ << - indent() << "(fname, mtype, rseqid) = self.__iprot.readMessageBegin(self.__itrans)" << endl; + indent() << "(fname, mtype, rseqid) = self._iprot.readMessageBegin(self._itrans)" << endl; // TODO(mcslee): Validate message reply here, seq ids etc. f_service_ << indent() << "__result = " << resultname << "()" << endl << - indent() << "__result.read(self.__iprot, self.__otrans)" << endl << - indent() << "self.__iprot.readMessageEnd(self.__itrans)" << endl; + indent() << "__result.read(self._iprot, self._otrans)" << endl << + indent() << "self._iprot.readMessageEnd(self._itrans)" << endl; // Careful, only return _result if not a void function if (!(*f_iter)->get_returntype()->is_void()) { @@ -645,7 +686,7 @@ void t_py_generator::generate_service_remote(t_service* tservice) { " sys.exit(1)" << endl << " pp.pprint(client." << (*f_iter)->get_name() << "("; for (int i = 0; i < num_args; ++i) { - if (args[i]->get_type() == g_program->get_string_type()) { + if (args[i]->get_type() == g_type_string) { f_remote << "args[" << i << "],"; } else { f_remote << "eval(args[" << i << "]),"; @@ -682,29 +723,35 @@ void t_py_generator::generate_service_server(t_service* tservice) { vector functions = tservice->get_functions(); vector::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; @@ -714,16 +761,16 @@ void t_py_generator::generate_service_server(t_service* tservice) { indent_up(); f_service_ << - indent() << "(name, type, seqid) = self.__iprot.readMessageBegin(itrans)" << endl; + indent() << "(name, type, seqid) = self._iprot.readMessageBegin(itrans)" << endl; // TODO(mcslee): validate message // HOT: dictionary function lookup f_service_ << - indent() << "if name not in self.__processMap:" << endl << + indent() << "if name not in self._processMap:" << endl << indent() << " print 'Unknown function %s' % (name)" << endl << indent() << "else:" << endl << - indent() << " self.__processMap[name](self, seqid, itrans, otrans)" << endl; + indent() << " self._processMap[name](self, seqid, itrans, otrans)" << endl; // Read end of args field, the T_STOP, and the struct close f_service_ << @@ -759,8 +806,8 @@ void t_py_generator::generate_process_function(t_service* tservice, 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& xceptions = xs->get_members(); @@ -789,7 +836,7 @@ void t_py_generator::generate_process_function(t_service* tservice, f_service_ << "__result.success = "; } f_service_ << - "self.__handler." << tfunction->get_name() << "("; + "self._handler." << tfunction->get_name() << "("; bool first = true; for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { if (first) { @@ -828,9 +875,9 @@ void t_py_generator::generate_process_function(t_service* tservice, } f_service_ << - indent() << "self.__oprot.writeMessageBegin(otrans, \"" << tfunction->get_name() << "\", TMessageType.REPLY, seqid)" << endl << - indent() << "__result.write(self.__oprot, otrans)" << endl << - indent() << "self.__oprot.writeMessageEnd(otrans)" << endl << + indent() << "self._oprot.writeMessageBegin(otrans, \"" << tfunction->get_name() << "\", TMessageType.REPLY, seqid)" << endl << + indent() << "__result.write(self._oprot, otrans)" << endl << + indent() << "self._oprot.writeMessageEnd(otrans)" << endl << indent() << "otrans.flush()" << endl; // Close function @@ -916,7 +963,7 @@ void t_py_generator::generate_deserialize_struct(ofstream &out, t_struct* tstruct, string prefix) { out << - indent() << prefix << " = " << tstruct->get_name() << "()" << endl << + indent() << prefix << " = " << type_name(tstruct) << "()" << endl << indent() << prefix << ".read(iprot, itrans)" << endl; } @@ -932,10 +979,10 @@ void t_py_generator::generate_deserialize_container(ofstream &out, string vtype = tmp("_vtype"); string etype = tmp("_etype"); - t_field fsize(g_program->get_i32_type(), size); - t_field fktype(g_program->get_byte_type(), ktype); - t_field fvtype(g_program->get_byte_type(), vtype); - t_field fetype(g_program->get_byte_type(), etype); + t_field fsize(g_type_i32, size); + t_field fktype(g_type_byte, ktype); + t_field fvtype(g_type_byte, vtype); + t_field fetype(g_type_byte, etype); // Declare variables, read header if (ttype->is_map()) { @@ -991,13 +1038,6 @@ void t_py_generator::generate_deserialize_map_element(ofstream &out, t_field fkey(tmap->get_key_type(), key); t_field fval(tmap->get_val_type(), val); - /* - indent(out) << - declare_field(&fkey, true, true) << endl; - indent(out) << - declare_field(&fval, true, true) << endl; - */ - generate_deserialize_field(out, &fkey); generate_deserialize_field(out, &fval); @@ -1264,7 +1304,7 @@ string t_py_generator::declare_field(t_field* tfield, bool init, bool obj) { } } else if (type->is_struct() || type->is_xception()) { if (obj) { - result += " = " + type->get_name() + "()"; + result += " = " + type_name((t_struct*)type) + "()"; } else { result += " = None"; } @@ -1307,6 +1347,18 @@ string t_py_generator::argument_list(t_struct* tstruct) { return result; } +string t_py_generator::type_name(t_type* ttype) { + t_program* program = ttype->get_program(); + if (program != NULL && program != program_) { + if (ttype->is_service()) { + return ttype->get_name(); + } else { + return program->get_name() + "_types." + ttype->get_name(); + } + } + return ttype->get_name(); +} + /** * Converts the parse type to a Python tyoe */ diff --git a/compiler/cpp/src/generate/t_py_generator.h b/compiler/cpp/src/generate/t_py_generator.h index 238d10ee..9cbc4a6f 100644 --- a/compiler/cpp/src/generate/t_py_generator.h +++ b/compiler/cpp/src/generate/t_py_generator.h @@ -17,14 +17,15 @@ */ class t_py_generator : public t_oop_generator { public: - t_py_generator() {} + t_py_generator(t_program* program) : + t_oop_generator(program) {} /** * Init and close methods */ - void init_generator(t_program *tprogram); - void close_generator(t_program *tprogram); + void init_generator(); + void close_generator(); /** * Program-level generation functions @@ -117,7 +118,9 @@ class t_py_generator : public t_oop_generator { std::string py_autogen_comment(); std::string py_imports(); + std::string render_includes(); std::string declare_field(t_field* tfield, bool init=false, bool obj=false); + std::string type_name(t_type* ttype); std::string function_signature(t_function* tfunction, std::string prefix=""); std::string argument_list(t_struct* tstruct); std::string type_to_enum(t_type* ttype); diff --git a/compiler/cpp/src/globals.h b/compiler/cpp/src/globals.h index 73855658..51502c75 100644 --- a/compiler/cpp/src/globals.h +++ b/compiler/cpp/src/globals.h @@ -1,7 +1,39 @@ #ifndef T_GLOBALS_H #define T_GLOBALS_H +#include +#include +#include +#include +#include + +/** + * 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 + */ + +/** + * Hooray for forward declaration of types! + */ + class t_program; +class t_scope; +class t_type; + +/** + * Parsing mode, two passes up in this gin rummy! + */ + +enum PARSE_MODE { + INCLUDES = 1, + PROGRAM = 2 +}; /** * The master program parse tree. This is accessed from within the parser code @@ -10,9 +42,37 @@ class t_program; 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. diff --git a/compiler/cpp/src/main.cc b/compiler/cpp/src/main.cc index 9a8e29ee..aee89ae3 100644 --- a/compiler/cpp/src/main.cc +++ b/compiler/cpp/src/main.cc @@ -13,12 +13,15 @@ #include #include #include +#include +#include -// 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" @@ -31,16 +34,79 @@ using namespace std; */ 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 @@ -52,10 +118,10 @@ char* g_time_str; void yyerror(char* fmt, ...) { va_list args; fprintf(stderr, - "\n!!! Error: line %d (last token was '%s')", + "[ERROR:%s:%d] (last token was '%s')\n", + g_curpath.c_str(), yylineno, yytext); - fprintf(stderr, "\n!!! "); va_start(args, fmt); vfprintf(stderr, fmt, args); @@ -74,7 +140,39 @@ void pdebug(char* fmt, ...) { return; } va_list args; - printf("[Parse] "); + printf("[PARSE] "); + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + printf("\n"); +} + +/** + * Prints a verbose output mode message + * + * @param fmt C format string followed by additional arguments + */ +void pverbose(char* fmt, ...) { + if (g_verbose == 0) { + return; + } + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); +} + +/** + * Prints a warning message + * + * @param fmt C format string followed by additional arguments + */ +void pwarning(int level, char* fmt, ...) { + if (g_warn < level) { + return; + } + va_list args; + printf("[WARNING:%s:%d] ", g_curpath.c_str(), yylineno); va_start(args, fmt); vprintf(fmt, args); va_end(args); @@ -88,7 +186,7 @@ void pdebug(char* fmt, ...) { */ 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); @@ -96,21 +194,189 @@ void failure(char* fmt, ...) { 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& includes = program->get_includes(); + vector::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& 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. @@ -118,17 +384,12 @@ void usage() { int main(int argc, char** argv) { int i; - bool gen_cpp = false; - bool gen_java = false; - bool gen_py = false; - bool gen_php = false; - bool gen_phpi = false; - // Setup time string time_t now = time(NULL); g_time_str = ctime(&now); - // Check for necessary arguments + // Check for necessary arguments, you gotta have at least a filename and + // an output language flag if (argc < 2) { usage(); } @@ -140,6 +401,14 @@ int main(int argc, char** argv) { while (arg != NULL) { if (strcmp(arg, "--debug") == 0) { g_debug = 1; + } else if (strcmp(arg, "--nowarn") == 0) { + g_warn = 0; + } else if (strcmp(arg, "--strict") == 0) { + g_warn = 2; + } else if (strcmp(arg, "--v") == 0 || strcmp(arg, "--verbose") == 0 ) { + g_verbose = 1; + } else if (strcmp(arg, "--r") == 0 || strcmp(arg, "--recurse") == 0 ) { + gen_recurse = true; } else if (strcmp(arg, "--cpp") == 0) { gen_cpp = true; } else if (strcmp(arg, "--java") == 0) { @@ -160,77 +429,51 @@ int main(int argc, char** argv) { } } + // 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; diff --git a/compiler/cpp/src/main.h b/compiler/cpp/src/main.h index 1281cc97..9a3a81ea 100644 --- a/compiler/cpp/src/main.h +++ b/compiler/cpp/src/main.h @@ -1,22 +1,50 @@ #ifndef T_MAIN_H #define T_MAIN_H +#include + /** * 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 diff --git a/compiler/cpp/src/parse/t_enum.h b/compiler/cpp/src/parse/t_enum.h index 4b6fe362..002ca828 100644 --- a/compiler/cpp/src/parse/t_enum.h +++ b/compiler/cpp/src/parse/t_enum.h @@ -11,7 +11,8 @@ */ class t_enum : public t_type { public: - t_enum() {} + t_enum(t_program* program) : + t_type(program) {} void set_name(std::string name) { name_ = name; diff --git a/compiler/cpp/src/parse/t_function.h b/compiler/cpp/src/parse/t_function.h index 3d071711..6f06abec 100644 --- a/compiler/cpp/src/parse/t_function.h +++ b/compiler/cpp/src/parse/t_function.h @@ -22,7 +22,7 @@ class t_function { name_(name), arglist_(arglist), async_(async) { - xceptions_ = new t_struct; + xceptions_ = new t_struct(NULL); } t_function(t_type* returntype, diff --git a/compiler/cpp/src/parse/t_program.h b/compiler/cpp/src/parse/t_program.h index 5e586540..a3270adc 100644 --- a/compiler/cpp/src/parse/t_program.h +++ b/compiler/cpp/src/parse/t_program.h @@ -5,6 +5,10 @@ #include #include +// For program_name() +#include "main.h" + +#include "t_scope.h" #include "t_base_type.h" #include "t_typedef.h" #include "t_enum.h" @@ -30,38 +34,26 @@ */ class t_program { public: - t_program(std::string name) : - name_(name), - namespace_() { - type_void = new t_base_type("void", t_base_type::TYPE_VOID); - type_string = new t_base_type("string", t_base_type::TYPE_STRING); - type_bool = new t_base_type("bool", t_base_type::TYPE_BOOL); - type_byte = new t_base_type("byte", t_base_type::TYPE_BYTE); - type_i16 = new t_base_type("i16", t_base_type::TYPE_I16); - type_i32 = new t_base_type("i32", t_base_type::TYPE_I32); - type_i64 = new t_base_type("i64", t_base_type::TYPE_I64); - type_double = new t_base_type("double", t_base_type::TYPE_DOUBLE); + t_program(std::string path, std::string name) : + path_(path), + name_(name) { + scope_ = new t_scope(); } - ~t_program() { - delete type_string; - delete type_bool; - delete type_byte; - delete type_i16; - delete type_i32; - delete type_i64; - delete type_double; + t_program(std::string path) : + path_(path) { + name_ = program_name(path); + scope_ = new t_scope(); } + // Path accessor + const std::string& get_path() const { return path_; } + // Name accessor - const std::string& get_name() const { - return name_; - } + const std::string& get_name() const { return name_; } // Namespace - const std::string& get_namespace() const { - return namespace_; - } + const std::string& get_namespace() const { return namespace_; } // Accessors for program elements const std::vector& get_typedefs() const { return typedefs_; } @@ -70,83 +62,96 @@ class t_program { const std::vector& get_xceptions() const { return xceptions_; } const std::vector& 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& 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& 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& 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 typedefs_; - std::vector enums_; - std::vector structs_; - std::vector xceptions_; - std::vector services_; - - // Type map - std::map 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 includes_; + + // Identifier lookup scope + t_scope* scope_; + + // Components to generate code for + std::vector typedefs_; + std::vector enums_; + std::vector structs_; + std::vector xceptions_; + std::vector services_; + + // C++ namespace + std::string cpp_namespace_; + + // C++ extra includes + std::vector cpp_includes_; + + // Java package + std::string java_package_; + }; #endif diff --git a/compiler/cpp/src/parse/t_scope.h b/compiler/cpp/src/parse/t_scope.h new file mode 100644 index 00000000..504393bb --- /dev/null +++ b/compiler/cpp/src/parse/t_scope.h @@ -0,0 +1,57 @@ +#ifndef T_SCOPE_H +#define T_SCOPE_H + +#include +#include + +#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 + */ +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::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 types_; + + // Map of names to services + std::map services_; + +}; + +#endif diff --git a/compiler/cpp/src/parse/t_service.h b/compiler/cpp/src/parse/t_service.h index 6bb5e5d4..52280a40 100644 --- a/compiler/cpp/src/parse/t_service.h +++ b/compiler/cpp/src/parse/t_service.h @@ -4,34 +4,42 @@ #include "t_function.h" #include +class t_program; + /** * A service consists of a set of functions. * * @author Mark Slee */ -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& get_functions() const { return functions_; } + t_service* get_extends() { + return extends_; + } + private: - std::string name_; std::vector functions_; + t_service* extends_; }; #endif diff --git a/compiler/cpp/src/parse/t_struct.h b/compiler/cpp/src/parse/t_struct.h index 8768c5f9..ce5f7524 100644 --- a/compiler/cpp/src/parse/t_struct.h +++ b/compiler/cpp/src/parse/t_struct.h @@ -7,6 +7,9 @@ #include "t_type.h" #include "t_field.h" +// Forward declare that puppy +class t_program; + /** * A struct is a container for a set of member fields that has a name. Structs * are also used to implement exception types. @@ -15,11 +18,12 @@ */ class t_struct : public t_type { public: - t_struct() : + t_struct(t_program* program) : + t_type(program), is_xception_(false) {} - t_struct(const std::string& name) : - t_type(name), + t_struct(t_program* program, const std::string& name) : + t_type(program, name), is_xception_(false) {} void set_name(const std::string& name) { diff --git a/compiler/cpp/src/parse/t_type.h b/compiler/cpp/src/parse/t_type.h index 1d0a2ed8..9589f02b 100644 --- a/compiler/cpp/src/parse/t_type.h +++ b/compiler/cpp/src/parse/t_type.h @@ -3,6 +3,8 @@ #include +class t_program; + /** * Generic representation of a thrift type. These objects are used by the * parser module to build up a tree of object that are all explicitly typed. @@ -16,7 +18,13 @@ class t_type { public: virtual ~t_type() {} - virtual const std::string& get_name() const { return name_; } + virtual void set_name(std::string name) { + name_ = name; + } + + virtual const std::string& get_name() const { + return name_; + } virtual bool is_void() const { return false; } virtual bool is_base_type() const { return false; } @@ -28,13 +36,26 @@ class t_type { virtual bool is_list() const { return false; } virtual bool is_set() const { return false; } virtual bool is_map() const { return false; } + virtual bool is_service() const { return false; } + + t_program* get_program() { + return program_; + } protected: t_type() {} - t_type(std::string name) : + t_type(t_program* program) : + program_(program) {} + + t_type(t_program* program, std::string name) : + program_(program), name_(name) {} + t_type(std::string name) : + name_(name) {} + + t_program* program_; std::string name_; }; diff --git a/compiler/cpp/src/parse/t_typedef.h b/compiler/cpp/src/parse/t_typedef.h index 8973201c..cc7f25c9 100644 --- a/compiler/cpp/src/parse/t_typedef.h +++ b/compiler/cpp/src/parse/t_typedef.h @@ -14,8 +14,8 @@ */ class t_typedef : public t_type { public: - t_typedef(t_type* type, std::string symbolic) : - t_type(symbolic), + t_typedef(t_program* program, t_type* type, std::string symbolic) : + t_type(program, symbolic), type_(type), symbolic_(symbolic) {} diff --git a/compiler/cpp/src/thrift.l b/compiler/cpp/src/thrift.l index e72565e4..839060e9 100644 --- a/compiler/cpp/src/thrift.l +++ b/compiler/cpp/src/thrift.l @@ -33,8 +33,8 @@ whitespace ([ \t\r\n]*) multicomm ("/*""/"*([^*/]|[^*]"/"|"*"[^/])*"*"*"*/") comment ("//"[^\n]*) unixcomment ("#"[^\n]*) -symbol ([\,\{\}\(\)\=<>]) -cpptype ("[cpp:".*"]") +symbol ([:\,\{\}\(\)\=<>\[\]]) +literal ("\""[^"]*"\"") %% @@ -45,41 +45,47 @@ cpptype ("[cpp:".*"]") {symbol} { return yytext[0]; } -"namespace" { return tok_namespace; } -"void" { return tok_void; } -"bool" { return tok_bool; } -"byte" { return tok_byte; } -"i16" { return tok_i16; } -"i32" { return tok_i32; } -"i64" { return tok_i64; } -"double" { return tok_double; } -"string" { return tok_string; } -"map" { return tok_map; } -"list" { return tok_list; } -"set" { return tok_set; } -"async" { return tok_async; } -"typedef" { return tok_typedef; } -"struct" { return tok_struct; } -"exception" { return tok_xception; } -"throws" { return tok_throws; } -"service" { return tok_service; } -"enum" { return tok_enum; } +"namespace" { return tok_namespace; } +"cpp_namespace" { return tok_cpp_namespace; } +"cpp_include" { return tok_cpp_include; } +"cpp_type" { return tok_cpp_type; } +"java_package" { return tok_java_package; } +"include" { return tok_include; } + +"void" { return tok_void; } +"bool" { return tok_bool; } +"byte" { return tok_byte; } +"i16" { return tok_i16; } +"i32" { return tok_i32; } +"i64" { return tok_i64; } +"double" { return tok_double; } +"string" { return tok_string; } +"map" { return tok_map; } +"list" { return tok_list; } +"set" { return tok_set; } +"async" { return tok_async; } +"typedef" { return tok_typedef; } +"struct" { return tok_struct; } +"exception" { return tok_xception; } +"extends" { return tok_extends; } +"throws" { return tok_throws; } +"service" { return tok_service; } +"enum" { return tok_enum; } {intconstant} { yylval.iconst = atoi(yytext); return tok_int_constant; } -{cpptype} { - yylval.id = strdup(yytext+5); - yylval.id[strlen(yylval.id)-1] = '\0'; - return tok_cpptype; -} - {identifier} { yylval.id = strdup(yytext); return tok_identifier; } +{literal} { + yylval.id = strdup(yytext+1); + yylval.id[strlen(yylval.id)-1] = '\0'; + return tok_literal; +} %% diff --git a/compiler/cpp/src/thrift.y b/compiler/cpp/src/thrift.y index 3bf8b539..7d1ba1e1 100644 --- a/compiler/cpp/src/thrift.y +++ b/compiler/cpp/src/thrift.y @@ -12,6 +12,7 @@ #include "main.h" #include "globals.h" #include "parse/t_program.h" +#include "parse/t_scope.h" /** * This global variable is used for automatic numbering of field indices etc. @@ -44,7 +45,7 @@ int y_field_val = -1; * Strings identifier */ %token tok_identifier -%token tok_cpptype +%token tok_literal /** * Integer constant value @@ -52,9 +53,14 @@ int y_field_val = -1; %token tok_int_constant /** - * Namespace keyword + * Header keywoards */ +%token tok_include %token tok_namespace +%token tok_cpp_namespace +%token tok_cpp_include +%token tok_cpp_type +%token tok_java_package /** * Base datatype keywords @@ -87,6 +93,7 @@ int y_field_val = -1; %token tok_struct %token tok_xception %token tok_throws +%token tok_extends %token tok_service %token tok_enum @@ -94,14 +101,14 @@ int y_field_val = -1; * Grammar nodes */ -%type Namespace - %type BaseType %type ContainerType %type MapType %type SetType %type ListType +%type TypeDefinition + %type Typedef %type DefinitionType @@ -122,6 +129,7 @@ int y_field_val = -1; %type FunctionList %type ThrowsOptional +%type ExtendsOptional %type AsyncOptional %type CppTypeOptional @@ -136,10 +144,67 @@ int y_field_val = -1; */ Program: - DefinitionList - { - pdebug("Program -> DefinitionList"); - } + HeaderList DefinitionList + { + pdebug("Program -> Headers DefinitionList"); + } + +HeaderList: + HeaderList Header + { + pdebug("HeaderList -> HeaderList Header"); + } +| + { + pdebug("HeaderList -> "); + } + +Header: + Include + { + pdebug("Header -> Include"); + } +| tok_namespace tok_identifier + { + pwarning(1, "'namespace' is deprecated. Use 'cpp_namespace' and/or 'java_package' instead"); + if (g_parse_mode == PROGRAM) { + g_program->set_cpp_namespace($2); + g_program->set_java_package($2); + } + } +| tok_cpp_namespace tok_identifier + { + pdebug("Header -> tok_cpp_namespace tok_identifier"); + if (g_parse_mode == PROGRAM) { + g_program->set_cpp_namespace($2); + } + } +| tok_cpp_include tok_literal + { + pdebug("Header -> tok_cpp_include tok_literal"); + if (g_parse_mode == PROGRAM) { + g_program->add_cpp_include($2); + } + } +| tok_java_package tok_identifier + { + pdebug("Header -> tok_java_package tok_identifier"); + if (g_parse_mode == PROGRAM) { + g_program->set_java_package($2); + } + } + +Include: + tok_include tok_literal + { + pdebug("Include -> tok_include tok_literal"); + if (g_parse_mode == INCLUDES) { + std::string path = include_file(std::string($2)); + if (!path.empty()) { + g_program->add_include(path); + } + } + } DefinitionList: DefinitionList Definition @@ -152,49 +217,63 @@ DefinitionList: } 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; } @@ -216,13 +295,13 @@ EnumDefList: | EnumDef { pdebug("EnumDefList -> EnumDef"); - $$ = new t_enum; + $$ = new t_enum(g_program); $$->append($1); } | { pdebug("EnumDefList -> "); - $$ = new t_enum; + $$ = new t_enum(g_program); } EnumDef: @@ -230,7 +309,7 @@ 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); } @@ -261,11 +340,30 @@ Xception: } Service: - tok_service tok_identifier '{' FunctionList '}' + tok_service tok_identifier ExtendsOptional '{' FunctionList '}' { pdebug("Service -> tok_service tok_identifier { FunctionList }"); - $$ = $4; + $$ = $5; $$->set_name($2); + $$->set_extends($3); + } + +ExtendsOptional: + tok_extends tok_identifier + { + pdebug("ExtendsOptional -> tok_extends tok_identifier"); + $$ = NULL; + if (g_parse_mode == PROGRAM) { + $$ = g_scope->get_service($2); + if ($$ == NULL) { + yyerror("Service \"%s\" has not been defined.", $2); + exit(1); + } + } + } +| + { + $$ = NULL; } FunctionList: @@ -278,7 +376,7 @@ FunctionList: | { pdebug("FunctionList -> "); - $$ = new t_service; + $$ = new t_service(g_program); } CommaOptional: @@ -308,11 +406,12 @@ AsyncOptional: ThrowsOptional: tok_throws '(' FieldList ')' { + pdebug("ThrowsOptional -> tok_throws ( FieldList )"); $$ = $3; } | { - $$ = new t_struct; + $$ = new t_struct(g_program); } FieldList: @@ -325,31 +424,41 @@ 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 @@ -372,17 +481,23 @@ FunctionType: | tok_void { pdebug("FunctionType -> tok_void"); - $$ = g_program->get_void_type(); + $$ = g_type_void; } FieldType: tok_identifier { pdebug("FieldType -> tok_identifier"); - $$ = g_program->get_custom_type($1); - if ($$ == NULL) { - yyerror("Type \"%s\" has not been defined.", $1); - exit(1); + if (g_parse_mode == INCLUDES) { + // Ignore identifiers in include mode + $$ = NULL; + } else { + // Lookup the identifier in the current scope + $$ = g_scope->get_type($1); + if ($$ == NULL) { + yyerror("Type \"%s\" has not been defined.", $1); + exit(1); + } } } | BaseType @@ -400,37 +515,37 @@ 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: @@ -471,19 +586,19 @@ SetType: } ListType: - tok_list CppTypeOptional '<' FieldType '>' + tok_list '<' FieldType '>' CppTypeOptional { pdebug("ListType -> tok_list"); - $$ = 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; } | { -- 2.17.1