Thrift compiler improvements, two modes for PHP
Summary: Complete PHP generator and CPP generator to new formats, and offer PHP generator that generates inline code free of any TProtocol abstraction
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@664771 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/cpp/cpp.mk b/compiler/cpp/Makefile
similarity index 100%
rename from compiler/cpp/cpp.mk
rename to compiler/cpp/Makefile
diff --git a/compiler/cpp/src/generate/t_cpp_generator.cc b/compiler/cpp/src/generate/t_cpp_generator.cc
index 6014e5f..43f8021 100644
--- a/compiler/cpp/src/generate/t_cpp_generator.cc
+++ b/compiler/cpp/src/generate/t_cpp_generator.cc
@@ -15,7 +15,7 @@
mkdir(T_CPP_DIR, S_IREAD | S_IWRITE | S_IEXEC);
// Make output file
- string f_types_name = string(T_CPP_DIR)+"/"+program_name_+"Types.h";
+ string f_types_name = string(T_CPP_DIR)+"/"+program_name_+"_types.h";
f_types_.open(f_types_name.c_str());
// Print header
@@ -30,20 +30,75 @@
// Include base types
f_types_ <<
- "#include \"Thrift.h\"" << endl <<
+ "#include <Thrift.h>" << endl <<
+ endl;
+
+ string open_ns = namespace_open(tprogram->get_namespace());
+
+ f_types_ <<
+ open_ns << endl <<
+ endl;
+
+ // Make output files
+ string f_header_name = string(T_CPP_DIR)+"/"+program_name_+".h";
+ f_header_.open(f_header_name.c_str());
+ string f_service_name = string(T_CPP_DIR)+"/"+program_name_+".cc";
+ f_service_.open(f_service_name.c_str());
+
+ // Print header file includes
+ f_header_ <<
+ autogen_comment();
+ f_header_ <<
+ "#ifndef " << program_name_ << "_H" << endl <<
+ "#define " << program_name_ << "_H" << endl <<
+ endl <<
+ "#include <Thrift.h>" << endl <<
+ "#include <TProcessor.h>" << endl <<
+ "#include <protocol/TProtocol.h>" << endl <<
+ "#include <transport/TTransport.h>" << endl <<
+ "#include \"" << program_name_ << "_types.h\"" << endl <<
+ endl <<
+ open_ns << endl <<
+ endl;
+
+ // Service implementation file includes
+ f_service_ <<
+ autogen_comment();
+ f_service_ <<
+ "#include \"" << program_name_ << ".h\"" << endl <<
+ endl <<
+ open_ns << endl <<
endl;
}
/**
* Closes the output files.
*/
-void t_cpp_generator::close_generator() {
+void t_cpp_generator::close_generator(t_program* tprogram) {
+ // Close ns
+ string close_ns = namespace_close(tprogram->get_namespace());
+ f_types_ <<
+ close_ns << endl <<
+ endl;
+ f_header_ <<
+ close_ns << endl <<
+ endl;
+ f_service_ <<
+ close_ns << endl <<
+ endl;
+
// Close ifndef
f_types_ <<
"#endif" << endl;
+ f_header_ <<
+ "#endif" << endl;
// Close output file
f_types_.close();
+
+ // Close files
+ f_header_.close();
+ f_service_.close();
}
@@ -105,26 +160,305 @@
* @param tstruct The struct definition
*/
void t_cpp_generator::generate_struct(t_struct* tstruct) {
- f_types_ <<
- indent() << "struct " << tstruct->get_name() << " {" << endl;
+ generate_struct_definition(f_types_, tstruct);
+ generate_struct_reader(f_service_, tstruct);
+ generate_struct_writer(f_service_, tstruct);
+}
+
+/**
+ * Writes the struct def.
+ *
+ * @param out Output stream
+ * @param tstruct The struct
+ */
+void t_cpp_generator::generate_struct_definition(ofstream& out,
+ t_struct* tstruct) {
+ // Open struct def
+ out <<
+ indent() << "typedef struct _" << tstruct->get_name() << " {" << endl;
indent_up();
- const vector<t_field*>& members = tstruct->get_members();
+ // Get members
vector<t_field*>::const_iterator m_iter;
+ const vector<t_field*>& members = tstruct->get_members();
+
+ // Default constructor
+ bool init_ctor = false;
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
- indent(f_types_) <<
+ t_type* t = (*m_iter)->get_type();
+ while (t->is_typedef()) {
+ t = ((t_typedef*)t)->get_type();
+ }
+ if (t->is_base_type() &&
+ ((t_base_type*)t)->get_base() != t_base_type::TYPE_STRING) {
+ if (!init_ctor) {
+ init_ctor = true;
+ indent(out) <<
+ "_" << tstruct->get_name() << "() : ";
+ out << (*m_iter)->get_name() << "(0)";
+ } else
+ out << ", " << (*m_iter)->get_name() << "(0)";
+ }
+ }
+ if (init_ctor) {
+ out << " {} " << endl;
+ }
+
+ // Declare all fields
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ indent(out) <<
declare_field(*m_iter) << endl;
}
-
- indent_down();
-
- f_types_ <<
- indent() << "};" << endl <<
+
+ // Isset vector
+ if (members.size() > 0) {
+ indent(out) <<
+ "struct __isset {" << endl;
+ indent_up();
+
+ indent(out) <<
+ "__isset() : ";
+ bool first = true;
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ if (first) {
+ first = false;
+ out <<
+ (*m_iter)->get_name() << "(false)";
+ } else {
+ out <<
+ ", " << (*m_iter)->get_name() << "(false)";
+ }
+ }
+ out << " {}" << endl;
+
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ indent(out) <<
+ "bool " << (*m_iter)->get_name() << ";" << endl;
+ }
+ indent_down();
+ indent(out) <<
+ "} __isset;" << endl;
+ }
+
+ indent_down();
+ indent(out) <<
+ "} " << tstruct->get_name() << ";" << endl <<
endl;
}
/**
+ * Makes a helper function to gen a struct reader.
+ *
+ * @param out Stream to write to
+ * @param tstruct The struct
+ */
+void t_cpp_generator::generate_struct_reader(ofstream& out,
+ t_struct* tstruct) {
+ indent(out) <<
+ "uint32_t read_struct_" << tstruct->get_name() << "(" <<
+ "boost::shared_ptr<const facebook::thrift::protocol::TProtocol> iprot, " <<
+ "boost::shared_ptr<facebook::thrift::transport::TTransport> itrans, " <<
+ tstruct->get_name() << "& value) {" << endl;
+ indent_up();
+
+ const vector<t_field*>& fields = tstruct->get_members();
+ vector<t_field*>::const_iterator f_iter;
+
+ // Declare stack tmp variables
+ out <<
+ endl <<
+ indent() << "uint32_t xfer = 0;" << endl <<
+ indent() << "std::string fname;" << endl <<
+ indent() << "facebook::thrift::protocol::TType ftype;" << endl <<
+ indent() << "int16_t fid;" << endl <<
+ endl <<
+ indent() << "xfer += iprot->readStructBegin(itrans, fname);" << endl <<
+ endl;
+
+ // Loop over reading in fields
+ indent(out) <<
+ "while (true)" << endl;
+ scope_up(out);
+
+ // Read beginning field marker
+ indent(out) <<
+ "xfer += iprot->readFieldBegin(itrans, fname, ftype, fid);" << endl;
+
+ // Check for field STOP marker
+ out <<
+ indent() << "if (ftype == facebook::thrift::protocol::T_STOP) { " << endl <<
+ indent() << " break;" << endl <<
+ indent() << "}" << endl;
+
+ // Switch statement on the field we are reading
+ indent(out) <<
+ "switch (fid)" << endl;
+
+ scope_up(out);
+
+ // Generate deserialization code for known cases
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ indent(out) <<
+ "case " << (*f_iter)->get_key() << ":" << endl;
+ indent_up();
+ generate_deserialize_field(*f_iter, "value.");
+ out <<
+ indent() << "value.__isset." << (*f_iter)->get_name() << " = true;" << endl <<
+ indent() << "break;" << endl;
+ indent_down();
+ }
+
+ // In the default case we skip the field
+ out <<
+ indent() << "default:" << endl <<
+ indent() << " xfer += iprot->skip(itrans, ftype);" << endl <<
+ indent() << " break;" << endl;
+
+ scope_down(out);
+
+ // Read field end marker
+ indent(out) <<
+ "xfer += iprot->readFieldEnd(itrans);" << endl;
+
+ scope_down(out);
+
+ out <<
+ endl <<
+ indent() << "xfer += iprot->readStructEnd(itrans);" << endl <<
+ indent() <<"return xfer;" << endl;
+
+ indent_down();
+ indent(out) <<
+ "}" << endl << endl;
+}
+
+/**
+ * Makes a helper function to gen a struct writer.
+ *
+ * @param out Stream to write to
+ * @param tstruct The struct
+ */
+void t_cpp_generator::generate_struct_writer(ofstream& out,
+ t_struct* tstruct) {
+ string name = tstruct->get_name();
+ const vector<t_field*>& fields = tstruct->get_members();
+ vector<t_field*>::const_iterator f_iter;
+
+ indent(out) <<
+ "uint32_t write_struct_" << name << "(" <<
+ "boost::shared_ptr<const facebook::thrift::protocol::TProtocol> oprot, " <<
+ "boost::shared_ptr<facebook::thrift::transport::TTransport> otrans, " <<
+ "const " << name << "& value) {" << endl;
+ indent_up();
+
+ out <<
+ endl <<
+ indent() << "uint32_t xfer = 0;" << endl <<
+ endl;
+
+ indent(out) <<
+ "xfer += oprot->writeStructBegin(otrans, \"" << name << "\");" << endl;
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ // Write field header
+ out <<
+ endl <<
+ indent() << "xfer += oprot->writeFieldBegin(otrans, " <<
+ "\"" << (*f_iter)->get_name() << "\", " <<
+ type_to_enum((*f_iter)->get_type()) << ", " <<
+ (*f_iter)->get_key() << ");" << endl;
+ // Write field contents
+ generate_serialize_field(*f_iter, "value.");
+ // Write field closer
+ indent(out) <<
+ "xfer += oprot->writeFieldEnd(otrans);" << endl <<
+ endl;
+ }
+ // Write the struct map
+ out <<
+ indent() << "xfer += oprot->writeFieldStop(otrans);" << endl <<
+ endl <<
+ indent() << "xfer += oprot->writeStructEnd(otrans);" << endl <<
+ indent() << "return xfer;" << endl;
+
+ indent_down();
+ indent(out) <<
+ "}" << endl << endl;
+}
+
+/**
+ * Struct writer for result of a function, which can have only one of its
+ * fields set and does a conditional if else look up into the __isset field
+ * of the struct.
+ *
+ * @param out Output stream
+ * @param tstruct The result struct
+ */
+void t_cpp_generator::generate_struct_result_writer(ofstream& out,
+ t_struct* tstruct) {
+ string name = tstruct->get_name();
+ const vector<t_field*>& fields = tstruct->get_members();
+ vector<t_field*>::const_iterator f_iter;
+
+ indent(out) <<
+ "uint32_t write_struct_" << name << "(" <<
+ "boost::shared_ptr<const facebook::thrift::protocol::TProtocol> oprot, " <<
+ "boost::shared_ptr<facebook::thrift::transport::TTransport> otrans, " <<
+ "const " << name << "& value) {" << endl;
+ indent_up();
+
+ out <<
+ endl <<
+ indent() << "uint32_t xfer = 0;" << endl <<
+ endl;
+
+ indent(out) <<
+ "xfer += oprot->writeStructBegin(otrans, \"" << name << "\");" << endl;
+
+ bool first = true;
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ if (first) {
+ first = false;
+ out <<
+ endl <<
+ indent() << "if ";
+ } else {
+ out <<
+ " else if ";
+ }
+
+ out << "(value.__isset." << (*f_iter)->get_name() << ") {" << endl;
+
+ indent_up();
+
+ // Write field header
+ out <<
+ indent() << "xfer += oprot->writeFieldBegin(otrans, " <<
+ "\"" << (*f_iter)->get_name() << "\", " <<
+ type_to_enum((*f_iter)->get_type()) << ", " <<
+ (*f_iter)->get_key() << ");" << endl;
+ // Write field contents
+ generate_serialize_field(*f_iter, "value.");
+ // Write field closer
+ indent(out) << "xfer += oprot->writeFieldEnd(otrans);" << endl;
+
+ indent_down();
+ indent(out) << "}";
+ }
+
+ // Write the struct map
+ out <<
+ endl <<
+ indent() << "xfer += oprot->writeFieldStop(otrans);" << endl <<
+ indent() << "xfer += oprot->writeStructEnd(otrans);" << endl <<
+ indent() << "return xfer;" << endl;
+
+ indent_down();
+ indent(out) <<
+ "}" << endl << endl;
+}
+
+/**
* Generates a thrift service. In C++, this comprises an entirely separate
* header and source file. The header file defines the methods and includes
* the data types defined in the main header file, and the implementation
@@ -133,40 +467,27 @@
* @param tservice The service definition
*/
void t_cpp_generator::generate_service(t_service* tservice) {
- // Make output files
- string f_header_name = string(T_CPP_DIR)+"/"+service_name_+".h";
- f_header_.open(f_header_name.c_str());
- string f_service_name = string(T_CPP_DIR)+"/"+service_name_+".cc";
- f_service_.open(f_service_name.c_str());
-
- // Print header file includes
- f_header_ <<
- autogen_comment();
- f_header_ <<
- "#ifndef " << service_name_ << "_H" << endl <<
- "#define " << service_name_ << "_H" << endl <<
- endl <<
- "#include \"TProcessor.h\"" << endl <<
- "#include \"transport/TTransport.h\"" << endl <<
- "#include \"protocol/TProtocol.h\"" << endl <<
- "#include \"" << program_name_ << "Types.h\"" << endl <<
- endl;
- f_service_ <<
- autogen_comment();
- f_service_ <<
- "#include \"" << service_name_ << ".h\"" << endl << endl;
-
- // Generate the three main parts of the service
generate_service_interface(tservice);
+ generate_service_helpers(tservice);
generate_service_server(tservice);
generate_service_client(tservice);
+}
- f_header_ <<
- "#endif" << endl;
-
- // Close files
- f_header_.close();
- f_service_.close();
+/**
+ * Generates helper functions for a service.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_cpp_generator::generate_service_helpers(t_service* tservice) {
+ vector<t_function*> functions = tservice->get_functions();
+ vector<t_function*>::iterator f_iter;
+ for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+ t_struct* ts = (*f_iter)->get_arglist();
+ generate_struct_definition(f_service_, ts);
+ generate_struct_reader(f_service_, ts);
+ generate_struct_writer(f_service_, ts);
+ generate_function_helpers(*f_iter);
+ }
}
/**
@@ -179,14 +500,14 @@
"class " << service_name_ << "If {" << endl <<
" public: " << endl;
indent_up();
+ f_header_ <<
+ indent() << "virtual ~" << service_name_ << "If() {}" << endl;
vector<t_function*> functions = tservice->get_functions();
vector<t_function*>::iterator f_iter;
for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
f_header_ <<
indent() << "virtual " << function_signature(*f_iter) << " = 0;" << endl;
}
- f_header_ <<
- indent() << "virtual ~" << service_name_ << "If() {}" << endl;
indent_down();
f_header_ <<
"}; " << endl << endl;
@@ -207,13 +528,13 @@
indent_up();
f_header_ <<
indent() << service_name_ << "Client" <<
- "(boost::shared_ptr<facebook::thrift::transport::TTransport> trans, boost::shared_ptr<facebook::thrift::protocol::TProtocol> prot) : " <<
+ "(boost::shared_ptr<facebook::thrift::transport::TTransport> trans, boost::shared_ptr<const facebook::thrift::protocol::TProtocol> prot) : " <<
"_itrans(trans), _otrans(trans), " <<
"_iprot(prot), _oprot(prot) {}" << endl;
f_header_ <<
indent() << service_name_ << "Client" <<
"(boost::shared_ptr<facebook::thrift::transport::TTransport> itrans, boost::shared_ptr<facebook::thrift::transport::TTransport> otrans," <<
- " boost::shared_ptr<facebook::thrift::protocol::TProtocol> iprot, boost::shared_ptr<facebook::thrift::protocol::TProtocol> oprot) : " <<
+ " boost::shared_ptr<const facebook::thrift::protocol::TProtocol> iprot, boost::shared_ptr<const facebook::thrift::protocol::TProtocol> oprot) : " <<
"_itrans(itrans), _otrans(otrans), " <<
"_iprot(iprot), _oprot(oprot) {}" << endl;
@@ -241,8 +562,8 @@
f_header_ <<
indent() << "boost::shared_ptr<facebook::thrift::transport::TTransport> _itrans;" << endl <<
indent() << "boost::shared_ptr<facebook::thrift::transport::TTransport> _otrans;" << endl <<
- indent() << "boost::shared_ptr<facebook::thrift::protocol::TProtocol> _iprot;" << endl <<
- indent() << "boost::shared_ptr<facebook::thrift::protocol::TProtocol> _oprot;" << endl;
+ indent() << "boost::shared_ptr<const facebook::thrift::protocol::TProtocol> _iprot;" << endl <<
+ indent() << "boost::shared_ptr<const facebook::thrift::protocol::TProtocol> _oprot;" << endl;
indent_down();
f_header_ <<
@@ -294,39 +615,36 @@
string("send_") + (*f_iter)->get_name(),
(*f_iter)->get_arglist());
- // Open function
+ // Open the send function
indent(f_service_) <<
function_signature(&send_function, scope) << endl;
scope_up(f_service_);
+ string argsname = (*f_iter)->get_name() + "_args";
+ string resultname = (*f_iter)->get_name() + "_result";
+
// Serialize the request
f_service_ <<
- indent() <<
- "_oprot->writeStructBegin(_otrans, \"function\");" << endl <<
- indent() <<
- "_oprot->writeFieldBegin(_otrans, \"name\", facebook::thrift::protocol::T_STRING, 0);" << endl <<
- indent() <<
- "_oprot->writeString(_otrans, \"" << funname << "\");" << endl <<
- indent() <<
- "_oprot->writeFieldEnd(_otrans);" << endl <<
- indent() <<
- "_oprot->writeFieldBegin(_otrans, \"args\", facebook::thrift::protocol::T_STRUCT, 1);" << endl;
- generate_serialize_struct((*f_iter)->get_arglist());
+ indent() << "int32_t cseqid = 0;" << endl <<
+ indent() << "_oprot->writeMessageBegin(_otrans, \"" << (*f_iter)->get_name() << "\", facebook::thrift::protocol::T_CALL, cseqid);" << endl <<
+ 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;
+ }
+
f_service_ <<
- indent() <<
- "_oprot->writeFieldEnd(_otrans);" << endl <<
- indent() <<
- "_oprot->writeFieldStop(_otrans);" << endl <<
- indent() <<
- "_oprot->writeStructEnd(_otrans);" << endl;
-
- // Flush the request
- indent(f_service_) <<
- "_otrans->flush();" << endl;
-
+ indent() << "write_struct_" << argsname << "(_oprot, _otrans, __args);" << endl <<
+ endl <<
+ indent() << "_oprot->writeMessageEnd(_otrans);" << endl <<
+ indent() << "_otrans->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_function recv_function((*f_iter)->get_returntype(),
@@ -337,34 +655,63 @@
function_signature(&recv_function, scope) << endl;
scope_up(f_service_);
- // Read the response
- t_struct result_struct((*f_iter)->get_name() + "_result");
- t_field result_field((*f_iter)->get_returntype(), "_result");
-
+ f_service_ <<
+ endl <<
+ indent() << "int32_t rseqid = 0;" << endl <<
+ indent() << "std::string fname;" << endl <<
+ indent() << "facebook::thrift::protocol::TMessageType mtype;" << endl <<
+ endl <<
+ indent() << "_iprot->readMessageBegin(_itrans, fname, mtype, rseqid);" << endl <<
+ indent() << "if (mtype != facebook::thrift::protocol::T_REPLY || fname.compare(\"" << (*f_iter)->get_name() << "\") != 0) {" << endl;
+ indent_up();
+ f_service_ <<
+ indent() << "throw facebook::thrift::Exception(\"Unexpected message type, name, or id\");" << endl;
+ indent_down();
+ f_service_ <<
+ indent() << "}" << endl;
+
+ f_service_ <<
+ endl <<
+ indent() << resultname << " __result;" << endl;
+
// Add a field to the return struct if non void
- if (!(*f_iter)->get_returntype()->is_void()) {
- indent(f_service_) <<
- type_name((*f_iter)->get_returntype()) << " _result;" << endl;
- result_struct.append(&result_field);
- }
-
- // Deserialize response struct
- generate_deserialize_struct(&result_struct);
-
+ f_service_ <<
+ indent() << "read_struct_" << resultname << "(_iprot, _itrans, __result);" << endl <<
+ indent() << "_iprot->readMessageEnd(_itrans);" << endl <<
+ endl;
+
+
// Careful, only return _result if not a void function
if (!(*f_iter)->get_returntype()->is_void()) {
- indent(f_service_) <<
- "return _result;" << endl;
- } else {
+ f_service_ <<
+ indent() << "if (__result.__isset.success) {" << endl <<
+ indent() << " return __result.success;" << endl <<
+ indent() << "}" << endl;
+ }
+
+ t_struct* xs = (*f_iter)->get_xceptions();
+ const std::vector<t_field*>& xceptions = xs->get_members();
+ vector<t_field*>::const_iterator x_iter;
+ for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+ f_service_ <<
+ indent() << "if (__result.__isset." << (*x_iter)->get_name() << ") {" << endl <<
+ indent() << " throw __result." << (*x_iter)->get_name() << ";" << endl <<
+ indent() << "}" << endl;
+ }
+
+ // Careful, only return _result if not a void function
+ if ((*f_iter)->get_returntype()->is_void()) {
indent(f_service_) <<
"return;" << endl;
+ } else {
+ f_service_ <<
+ indent() << "throw facebook::thrift::Exception(\"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
}
-
+
// Close function
scope_down(f_service_);
f_service_ << endl;
}
-
}
}
@@ -387,10 +734,10 @@
indent_up();
f_header_ <<
indent() <<
- service_name_ << "ServerIf(boost::shared_ptr<facebook::thrift::protocol::TProtocol> protocol) : " <<
+ service_name_ << "ServerIf(boost::shared_ptr<const facebook::thrift::protocol::TProtocol> protocol) : " <<
"_iprot(protocol), _oprot(protocol) {}" << endl <<
indent() <<
- service_name_ << "ServerIf(boost::shared_ptr<facebook::thrift::protocol::TProtocol> iprot, boost::shared_ptr<facebook::thrift::protocol::TProtocol> oprot) : " <<
+ service_name_ << "ServerIf(boost::shared_ptr<const facebook::thrift::protocol::TProtocol> iprot, boost::shared_ptr<const facebook::thrift::protocol::TProtocol> oprot) : " <<
"_iprot(iprot), _oprot(oprot) {}" << endl <<
indent() << "bool process(boost::shared_ptr<facebook::thrift::transport::TTransport> _itrans, " <<
"boost::shared_ptr<facebook::thrift::transport::TTransport> _otrans);" << endl <<
@@ -402,8 +749,8 @@
" protected:" << endl;
indent_up();
f_header_ <<
- indent() << "boost::shared_ptr<facebook::thrift::protocol::TProtocol> _iprot;" << endl <<
- indent() << "boost::shared_ptr<facebook::thrift::protocol::TProtocol> _oprot;" << endl;
+ indent() << "boost::shared_ptr<const facebook::thrift::protocol::TProtocol> _iprot;" << endl <<
+ indent() << "boost::shared_ptr<const facebook::thrift::protocol::TProtocol> _oprot;" << endl;
indent_down();
// Process function declarations
@@ -413,7 +760,7 @@
for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
indent(f_header_) <<
"void process_" << (*f_iter)->get_name() <<
- "(boost::shared_ptr<facebook::thrift::transport::TTransport> _itrans, boost::shared_ptr<facebook::thrift::transport::TTransport> _otrans);" << endl;
+ "(int32_t seqid, boost::shared_ptr<facebook::thrift::transport::TTransport> _itrans, boost::shared_ptr<facebook::thrift::transport::TTransport> _otrans);" << endl;
}
indent_down();
f_header_ <<
@@ -422,29 +769,22 @@
// Generate the server implementation
f_service_ <<
"bool " << service_name_ << "ServerIf::" <<
- "process(boost::shared_ptr<facebook::thrift::transport::TTransport> _itrans, boost::shared_ptr<facebook::thrift::transport::TTransport> _otrans) {" << endl;
+ "process(boost::shared_ptr<facebook::thrift::transport::TTransport> itrans, boost::shared_ptr<facebook::thrift::transport::TTransport> otrans) {" << endl;
indent_up();
f_service_ <<
- indent() <<
- "std::string _name;" << endl <<
- indent() <<
- "std::string _fname;" << endl <<
- indent() <<
- "facebook::thrift::protocol::TType _ftype;" << endl <<
- indent() <<
- "uint16_t _fid;" << endl <<
- indent() <<
- "_iprot->readStructBegin(_itrans, _name);" << endl <<
- indent() <<
- "_iprot->readFieldBegin(_itrans, _name, _ftype, _fid);" << endl <<
- indent() <<
- "_iprot->readString(_itrans, _fname);" << endl <<
- indent() <<
- "_iprot->readFieldEnd(_itrans);" << endl <<
- indent() <<
- "_iprot->readFieldBegin(_itrans, _name, _ftype, _fid);" << endl;
-
+ endl <<
+ indent() << "std::string fname;" << endl <<
+ indent() << "facebook::thrift::protocol::TMessageType mtype;" << endl <<
+ indent() << "int32_t seqid;" << endl <<
+ endl <<
+ indent() << "_iprot->readMessageBegin(itrans, 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;
+
bool first = true;
for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
if (!first) {
@@ -454,11 +794,11 @@
first = false;
}
f_service_ <<
- "if (_fname.compare(\"" << (*f_iter)->get_name() <<"\") == 0) {" << endl;
+ "if (fname.compare(\"" << (*f_iter)->get_name() <<"\") == 0) {" << endl;
indent_up();
indent(f_service_) <<
"process_" << (*f_iter)->get_name() <<
- "(_itrans, _otrans);" << endl;
+ "(seqid, itrans, otrans);" << endl;
indent_down();
indent(f_service_) << "}";
}
@@ -466,22 +806,14 @@
" else {" << endl;
indent_up();
indent(f_service_) <<
- "fprintf(stderr, \"Unknown function: '%s'\\n\", " <<
- "_fname.c_str());" << endl;
+ "throw facebook::thrift::Exception(\"Unknown function name: '\"+fname+\"'\");" << endl;
indent_down();
indent(f_service_) <<
"}" << endl;
// Read end of args field, the T_STOP, and the struct close
f_service_ <<
- indent() <<
- "_iprot->readFieldEnd(_itrans);" << endl <<
- indent() <<
- "_iprot->readFieldBegin(_itrans, _name, _ftype, _fid);" << endl <<
- indent() <<
- "_iprot->readStructEnd(_itrans);" << endl <<
- indent() <<
- "return true;" << endl;
+ indent() << "return true;" << endl;
indent_down();
f_service_ <<
@@ -495,6 +827,30 @@
}
/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_cpp_generator::generate_function_helpers(t_function* tfunction) {
+ t_struct result(tfunction->get_name() + "_result");
+ t_field success(tfunction->get_returntype(), "success", 0);
+ if (!tfunction->get_returntype()->is_void()) {
+ result.append(&success);
+ }
+
+ t_struct* xs = tfunction->get_xceptions();
+ const vector<t_field*>& fields = xs->get_members();
+ vector<t_field*>::const_iterator f_iter;
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ result.append(*f_iter);
+ }
+
+ generate_struct_definition(f_service_, &result);
+ generate_struct_reader(f_service_, &result);
+ generate_struct_result_writer(f_service_, &result);
+}
+
+/**
* Generates a process function definition.
*
* @param tfunction The function to write a dispatcher for
@@ -505,27 +861,37 @@
f_service_ <<
"void " << tservice->get_name() << "ServerIf::" <<
"process_" << tfunction->get_name() <<
- "(boost::shared_ptr<facebook::thrift::transport::TTransport> _itrans, boost::shared_ptr<facebook::thrift::transport::TTransport> _otrans)" << endl;
+ "(int32_t seqid, boost::shared_ptr<facebook::thrift::transport::TTransport> itrans, boost::shared_ptr<facebook::thrift::transport::TTransport> otrans)" << endl;
scope_up(f_service_);
- // Get the struct of function call params
- t_struct* arg_struct = tfunction->get_arglist();
+ string argsname = tfunction->get_name() + "_args";
+ string resultname = tfunction->get_name() + "_result";
- // Declare the function arguments
- const vector<t_field*>& fields = arg_struct->get_members();
- vector<t_field*>::const_iterator f_iter;
- for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
- indent(f_service_) <<
- declare_field(*f_iter, true) << endl;
+ f_service_ <<
+ indent() << argsname << " __args;" << endl <<
+ indent() << "read_struct_" << argsname << "(_iprot, itrans, __args);" << endl <<
+ indent() << "_iprot->readMessageEnd(itrans);" << endl <<
+ endl <<
+ indent() << resultname << " __result;" << endl;
+
+ t_struct* xs = tfunction->get_xceptions();
+ const std::vector<t_field*>& xceptions = xs->get_members();
+ vector<t_field*>::const_iterator x_iter;
+
+ if (xceptions.size() > 0) {
+ f_service_ <<
+ indent() << "try {" << endl;
+ indent_up();
}
- // Deserialize the function arguments as a struct
- generate_deserialize_struct(arg_struct);
-
// Generate the function call
+ t_struct* arg_struct = tfunction->get_arglist();
+ const std::vector<t_field*>& fields = arg_struct->get_members();
+ vector<t_field*>::const_iterator f_iter;
+
f_service_ << indent();
if (!tfunction->get_returntype()->is_void()) {
- f_service_ << type_name(tfunction->get_returntype()) << " _result = ";
+ f_service_ << "__result.success = ";
}
f_service_ <<
tfunction->get_name() << "(";
@@ -536,22 +902,40 @@
} else {
f_service_ << ", ";
}
- f_service_ << (*f_iter)->get_name();
+ f_service_ << "__args." << (*f_iter)->get_name();
}
f_service_ << ");" << endl;
- // Serialize the result into a struct
- t_struct result_struct(tfunction->get_name() + "_result");
- t_field result_field(tfunction->get_returntype(), "_result");
-
- // Only append the field if non-void
+ // Set isset on success field
if (!tfunction->get_returntype()->is_void()) {
- result_struct.append(&result_field);
+ f_service_ <<
+ indent() << "__result.__isset.success = true;" << endl;
}
- generate_serialize_struct(&result_struct);
- indent(f_service_) <<
- "_otrans->flush();" << endl;
+ if (xceptions.size() > 0) {
+ indent_down();
+ f_service_ << indent() << "}";
+ for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+ f_service_ << " catch (" << (*x_iter)->get_type()->get_name() << " &" << (*x_iter)->get_name() << ") {" << endl;
+ 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_down();
+ f_service_ << indent() << "}";
+ }
+ f_service_ << endl;
+ }
+
+
+ // Serialize the result into a struct
+ f_service_ <<
+ endl <<
+ indent() << "_oprot->writeMessageBegin(otrans, \"" << tfunction->get_name() << "\", facebook::thrift::protocol::T_REPLY, seqid);" << endl <<
+ indent() << "write_struct_" << resultname << "(_oprot, otrans, __result);" << endl <<
+ indent() << "_oprot->writeMessageEnd(otrans);" << endl <<
+ indent() << "otrans->flush();" << endl;
+
// Close function
scope_down(f_service_);
f_service_ << endl;
@@ -574,15 +958,14 @@
string name = prefix + tfield->get_name();
- if (type->is_struct()) {
- generate_deserialize_struct((t_struct*)(tfield->get_type()),
- name + ".");
+ if (type->is_struct() || type->is_xception()) {
+ generate_deserialize_struct((t_struct*)(tfield->get_type()), name);
} else if (type->is_container()) {
generate_deserialize_container(tfield->get_type(), name);
} else if (type->is_base_type() || type->is_enum()) {
indent(f_service_) <<
- "_iprot->";
+ "xfer += iprot->";
if (type->is_base_type()) {
t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
@@ -592,28 +975,25 @@
name;
break;
case t_base_type::TYPE_STRING:
- f_service_ << "readString(_itrans, " << name << ");";
+ f_service_ << "readString(itrans, " << name << ");";
break;
case t_base_type::TYPE_BYTE:
- f_service_ << "readByte(_itrans, " << name << ");";
+ f_service_ << "readByte(itrans, " << name << ");";
+ break;
+ case t_base_type::TYPE_I16:
+ f_service_ << "readI16(itrans, " << name << ");";
break;
case t_base_type::TYPE_I32:
- f_service_ << "readI32(_itrans, " << name << ");";
- break;
- case t_base_type::TYPE_U32:
- f_service_ << "readU32(_itrans, " << name << ");";
+ f_service_ << "readI32(itrans, " << name << ");";
break;
case t_base_type::TYPE_I64:
- f_service_ << "readI64(_itrans, " << name << ");";
- break;
- case t_base_type::TYPE_U64:
- f_service_ << "readU64(_itrans, " << name << ");";
+ f_service_ << "readI64(itrans, " << name << ");";
break;
default:
- throw "compiler error: no C++ name for base type " + tbase;
+ throw "compiler error: no C++ reader for base type " + tbase + name;
}
} else if (type->is_enum()) {
- f_service_ << "readI32(_itrans, (int32_t&)" << name << ");";
+ f_service_ << "readI32(itrans, (int32_t&)" << name << ");";
}
f_service_ <<
endl;
@@ -631,73 +1011,8 @@
*/
void t_cpp_generator::generate_deserialize_struct(t_struct* tstruct,
string prefix) {
- const vector<t_field*>& fields = tstruct->get_members();
- vector<t_field*>::const_iterator f_iter;
-
- scope_up(f_service_);
-
- // Read the struct fields from the protocol
- string fid = tmp("_fid");
- string ftype = tmp("_ftype");
- string fname = tmp("_name");
-
- // Declare stack tmp variables
- f_service_ <<
- indent() << "std::string " << fname << ";" << endl <<
- indent() << "facebook::thrift::protocol::TType " << ftype << ";" << endl <<
- indent() << "uint16_t " << fid << ";" << endl <<
- indent() << "_iprot->readStructBegin(_itrans, " << fname << ");" << endl;
-
- // Loop over reading in fields
indent(f_service_) <<
- "while (true)" << endl;
-
- scope_up(f_service_);
-
- // Read beginning field marker
- indent(f_service_) <<
- "_iprot->readFieldBegin(_itrans, " <<
- fname << ", " << ftype << ", " << fid << ");" << endl;
-
- // Check for field STOP marker
- indent(f_service_) <<
- "if (" << ftype << " == facebook::thrift::protocol::T_STOP) { break; }" << endl;
-
- // Switch statement on the field we are reading
- indent(f_service_) <<
- "switch (" << fid << ")" << endl;
-
- scope_up(f_service_);
-
- // Generate deserialization code for known cases
- for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
- indent(f_service_) <<
- "case " << (*f_iter)->get_key() << ":" << endl;
- indent_up();
- generate_deserialize_field(*f_iter, prefix);
- indent(f_service_) <<
- "break;" << endl;
- indent_down();
- }
-
- // In the default case we skip the field
- f_service_ <<
- indent() << "default:" << endl <<
- indent() << " _iprot->skip(_itrans, " << ftype << ");" << endl <<
- indent() << " break;" << endl;
-
- scope_down(f_service_);
-
- // Read field end marker
- indent(f_service_) <<
- "_iprot->readFieldEnd(_itrans);" << endl;
-
- scope_down(f_service_);
-
- indent(f_service_) <<
- "_iprot->readStructEnd(_itrans);" << endl;
-
- scope_down(f_service_);
+ "xfer += read_struct_" << tstruct->get_name() << "(iprot, itrans, " << prefix << ");" << endl;
}
void t_cpp_generator::generate_deserialize_container(t_type* ttype,
@@ -710,24 +1025,24 @@
string etype = tmp("_etype");
indent(f_service_) <<
- "int32_t " << size << ";" << endl;
+ "uint32_t " << size << ";" << endl;
// Declare variables, read header
if (ttype->is_map()) {
f_service_ <<
indent() << "facebook::thrift::protocol::TType " << ktype << ";" << endl <<
indent() << "facebook::thrift::protocol::TType " << vtype << ";" << endl <<
- indent() << "_iprot->readMapBegin(_itrans, " <<
+ indent() << "iprot->readMapBegin(itrans, " <<
ktype << ", " << vtype << ", " << size << ");" << endl;
} else if (ttype->is_set()) {
f_service_ <<
indent() << "facebook::thrift::protocol::TType " << etype << ";" << endl <<
- indent() << "_iprot->readSetBegin(_itrans, " <<
+ indent() << "iprot->readSetBegin(itrans, " <<
etype << ", " << size << ");" << endl;
} else if (ttype->is_list()) {
f_service_ <<
indent() << "facebook::thrift::protocol::TType " << etype << ";" << endl <<
- indent() << "_iprot->readListBegin(_itrans, " <<
+ indent() << "iprot->readListBegin(itrans, " <<
etype << ", " << size << ");" << endl;
}
@@ -735,7 +1050,7 @@
// For loop iterates over elements
string i = tmp("_i");
indent(f_service_) <<
- "int32_t " << i << ";" << endl;
+ "uint32_t " << i << ";" << endl;
indent(f_service_) <<
"for (" <<
i << " = 0; " << i << " < " << size << "; ++" << i << ")" << endl;
@@ -754,11 +1069,11 @@
// Read container end
if (ttype->is_map()) {
- indent(f_service_) << "_iprot->readMapEnd(_itrans);" << endl;
+ indent(f_service_) << "iprot->readMapEnd(itrans);" << endl;
} else if (ttype->is_set()) {
- indent(f_service_) << "_iprot->readSetEnd(_itrans);" << endl;
+ indent(f_service_) << "iprot->readSetEnd(itrans);" << endl;
} else if (ttype->is_list()) {
- indent(f_service_) << "_iprot->readListEnd(_itrans);" << endl;
+ indent(f_service_) << "iprot->readListEnd(itrans);" << endl;
}
scope_down(f_service_);
@@ -835,9 +1150,9 @@
prefix + tfield->get_name();
}
- if (type->is_struct()) {
+ if (type->is_struct() || type->is_xception()) {
generate_serialize_struct((t_struct*)(tfield->get_type()),
- prefix + tfield->get_name() + ".");
+ prefix + tfield->get_name());
} else if (type->is_container()) {
generate_serialize_container(tfield->get_type(),
prefix + tfield->get_name());
@@ -845,7 +1160,7 @@
string name = prefix + tfield->get_name();
indent(f_service_) <<
- "_oprot->";
+ "xfer += oprot->";
if (type->is_base_type()) {
t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
@@ -855,28 +1170,25 @@
"compiler error: cannot serialize void field in a struct: " + name;
break;
case t_base_type::TYPE_STRING:
- f_service_ << "writeString(_otrans, " << name << ");";
+ f_service_ << "writeString(otrans, " << name << ");";
break;
case t_base_type::TYPE_BYTE:
- f_service_ << "writeByte(_otrans, " << name << ");";
+ f_service_ << "writeByte(otrans, " << name << ");";
+ break;
+ case t_base_type::TYPE_I16:
+ f_service_ << "writeI16(otrans, " << name << ");";
break;
case t_base_type::TYPE_I32:
- f_service_ << "writeI32(_otrans, " << name << ");";
- break;
- case t_base_type::TYPE_U32:
- f_service_ << "writeU32(_otrans, " << name << ");";
+ f_service_ << "writeI32(otrans, " << name << ");";
break;
case t_base_type::TYPE_I64:
- f_service_ << "writeI64(_otrans, " << name << ");";
- break;
- case t_base_type::TYPE_U64:
- f_service_ << "writeU64(_otrans, " << name << ");";
+ f_service_ << "writeI64(otrans, " << name << ");";
break;
default:
- throw "compiler error: no C++ name for base type " + tbase;
+ throw "compiler error: no C++ writer for base type " + tbase + name;
}
} else if (type->is_enum()) {
- f_service_ << "writeI32(_otrans, (int32_t)" << name << ");";
+ f_service_ << "writeI32(otrans, (int32_t)" << name << ");";
}
f_service_ << endl;
} else {
@@ -895,32 +1207,8 @@
*/
void t_cpp_generator::generate_serialize_struct(t_struct* tstruct,
string prefix) {
- string name = tstruct->get_name();
- const vector<t_field*>& fields = tstruct->get_members();
- vector<t_field*>::const_iterator f_iter;
-
- scope_up(f_service_);
indent(f_service_) <<
- "_oprot->writeStructBegin(_otrans, \"" << name << "\");" << endl;
- for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
- // Write field header
- indent(f_service_) <<
- "_oprot->writeFieldBegin(_otrans, " <<
- "\"" << (*f_iter)->get_name() << "\", " <<
- type_to_enum((*f_iter)->get_type()) << ", " <<
- (*f_iter)->get_key() << ");" << endl;
- // Write field contents
- generate_serialize_field(*f_iter, prefix);
- // Write field closer
- indent(f_service_) <<
- "_oprot->writeFieldEnd(_otrans);" << endl;
- }
- // Write the struct map
- f_service_ <<
- indent() << "_oprot->writeFieldStop(_otrans);" << endl <<
- indent() << "_oprot->writeStructEnd(_otrans);" << endl;
-
- scope_down(f_service_);
+ "xfer += write_struct_" << tstruct->get_name() << "(oprot, otrans, " << prefix << ");" << endl;
}
void t_cpp_generator::generate_serialize_container(t_type* ttype,
@@ -929,18 +1217,18 @@
if (ttype->is_map()) {
indent(f_service_) <<
- "_oprot->writeMapBegin(_otrans, " <<
+ "xfer += oprot->writeMapBegin(otrans, " <<
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(f_service_) <<
- "_oprot->writeSetBegin(_otrans, " <<
+ "xfer += oprot->writeSetBegin(otrans, " <<
type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
prefix << ".size());" << endl;
} else if (ttype->is_list()) {
indent(f_service_) <<
- "_oprot->writeListBegin(_otrans, " <<
+ "xfer += oprot->writeListBegin(otrans, " <<
type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
prefix << ".size());" << endl;
}
@@ -962,20 +1250,20 @@
} else if (ttype->is_list()) {
generate_serialize_list_element((t_list*)ttype, iter);
}
+
+ scope_down(f_service_);
if (ttype->is_map()) {
indent(f_service_) <<
- "_oprot->writeMapEnd(_otrans);" << endl;
+ "xfer += oprot->writeMapEnd(otrans);" << endl;
} else if (ttype->is_set()) {
indent(f_service_) <<
- "_oprot->writeSetEnd(_otrans);" << endl;
+ "xfer += oprot->writeSetEnd(otrans);" << endl;
} else if (ttype->is_list()) {
indent(f_service_) <<
- "_oprot->writeListEnd(_otrans);" << endl;
- }
-
- scope_down(f_service_);
-
+ "xfer += oprot->writeListEnd(otrans);" << endl;
+ }
+
scope_down(f_service_);
}
@@ -1011,6 +1299,51 @@
}
/**
+ * Opens namespace.
+ *
+ * @param ns The namepsace, w/ periods in it
+ * @return Namespaces
+ */
+string t_cpp_generator::namespace_open(string ns) {
+ if (ns.size() == 0) {
+ return "";
+ }
+ string result = "";
+ string::size_type loc;
+ while ((loc = ns.find(".")) != string::npos) {
+ result += "namespace ";
+ result += ns.substr(0, loc);
+ result += " { ";
+ ns = ns.substr(loc+1);
+ }
+ if (ns.size() > 0) {
+ result += "namespace " + ns + " { ";
+ }
+ return result;
+}
+
+/**
+ * Closes namespace.
+ *
+ * @param ns The namepsace, w/ periods in it
+ * @return Namespaces
+ */
+string t_cpp_generator::namespace_close(string ns) {
+ if (ns.size() == 0) {
+ return "";
+ }
+ string result = "}";
+ string::size_type loc;
+ while ((loc = ns.find(".")) != string::npos) {
+ result += "}";
+ ns = ns.substr(loc+1);
+ }
+ result += " // namespace";
+ return result;
+}
+
+
+/**
* Returns a C++ type name
*
* @param ttype The type
@@ -1046,17 +1379,15 @@
case t_base_type::TYPE_STRING:
return "std::string";
case t_base_type::TYPE_BYTE:
- return "uint8_t";
+ return "int8_t";
+ case t_base_type::TYPE_I16:
+ return "int16_t";
case t_base_type::TYPE_I32:
return "int32_t";
- case t_base_type::TYPE_U32:
- return "uint32_t";
case t_base_type::TYPE_I64:
return "int64_t";
- case t_base_type::TYPE_U64:
- return "uint64_t";
default:
- throw "compiler error: no C++ name for base type " + tbase;
+ throw "compiler error: no C++ base type name for base type " + tbase;
}
}
@@ -1083,10 +1414,9 @@
result += " = \"\"";
break;
case t_base_type::TYPE_BYTE:
+ case t_base_type::TYPE_I16:
case t_base_type::TYPE_I32:
- case t_base_type::TYPE_U32:
case t_base_type::TYPE_I64:
- case t_base_type::TYPE_U64:
result += " = 0";
break;
default:
@@ -1150,19 +1480,19 @@
return "facebook::thrift::protocol::T_STRING";
case t_base_type::TYPE_BYTE:
return "facebook::thrift::protocol::T_BYTE";
+ case t_base_type::TYPE_I16:
+ return "facebook::thrift::protocol::T_I16";
case t_base_type::TYPE_I32:
return "facebook::thrift::protocol::T_I32";
- case t_base_type::TYPE_U32:
- return "facebook::thrift::protocol::T_U32";
case t_base_type::TYPE_I64:
return "facebook::thrift::protocol::T_I64";
- case t_base_type::TYPE_U64:
- return "facebook::thrift::protocol::T_U64";
}
} else if (type->is_enum()) {
return "facebook::thrift::protocol::T_I32";
} else if (type->is_struct()) {
return "facebook::thrift::protocol::T_STRUCT";
+ } else if (type->is_xception()) {
+ return "facebook::thrift::protocol::T_STRUCT";
} else if (type->is_map()) {
return "facebook::thrift::protocol::T_MAP";
} else if (type->is_set()) {
diff --git a/compiler/cpp/src/generate/t_cpp_generator.h b/compiler/cpp/src/generate/t_cpp_generator.h
index 801c06c..48cdb4c 100644
--- a/compiler/cpp/src/generate/t_cpp_generator.h
+++ b/compiler/cpp/src/generate/t_cpp_generator.h
@@ -24,22 +24,30 @@
/** Init and close methods */
void init_generator(t_program *tprogram);
- void close_generator();
+ void close_generator(t_program *tprogram);
/** Program-level generation functions */
- void generate_typedef (t_typedef* ttypedef);
- void generate_enum (t_enum* tenum);
- void generate_struct (t_struct* tstruct);
- void generate_service (t_service* tservice);
+ void generate_typedef (t_typedef* ttypedef);
+ void generate_enum (t_enum* tenum);
+ void generate_struct (t_struct* tstruct);
+ void generate_service (t_service* tservice);
+
+ void generate_struct_definition (std::ofstream& out, t_struct* tstruct);
+ void generate_struct_reader (std::ofstream& out, t_struct* tstruct);
+ void generate_struct_writer (std::ofstream& out, t_struct* tstruct);
+ void generate_struct_result_writer (std::ofstream& out, t_struct* tstruct);
/** Service-level generation functions */
void generate_service_interface (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_process_function (t_service* tservice, t_function* tfunction);
+ void generate_function_helpers (t_function* tfunction);
+
/** Serialization constructs */
void generate_deserialize_field (t_field* tfield,
@@ -80,6 +88,8 @@
/** Helper rendering functions */
+ std::string namespace_open(std::string ns);
+ std::string namespace_close(std::string ns);
std::string type_name(t_type* ttype);
std::string base_type_name(t_base_type::t_base tbase);
std::string declare_field(t_field* tfield, bool init=false);
diff --git a/compiler/cpp/src/generate/t_generator.cc b/compiler/cpp/src/generate/t_generator.cc
index d68e66d..99baf33 100644
--- a/compiler/cpp/src/generate/t_generator.cc
+++ b/compiler/cpp/src/generate/t_generator.cc
@@ -36,6 +36,13 @@
generate_struct(*st_iter);
}
+ // Generate xceptions
+ vector<t_struct*> xceptions = tprogram->get_xceptions();
+ vector<t_struct*>::iterator x_iter;
+ for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+ generate_xception(*x_iter);
+ }
+
// Generate services
vector<t_service*> services = tprogram->get_services();
vector<t_service*>::iterator sv_iter;
@@ -45,5 +52,5 @@
}
// Close the generator
- close_generator();
+ close_generator(tprogram);
}
diff --git a/compiler/cpp/src/generate/t_generator.h b/compiler/cpp/src/generate/t_generator.h
index be0b83e..16d8084 100644
--- a/compiler/cpp/src/generate/t_generator.h
+++ b/compiler/cpp/src/generate/t_generator.h
@@ -29,14 +29,17 @@
/** Optional methods that may be imlemented by subclasses. */
virtual void init_generator (t_program* tprogram) {}
- virtual void close_generator () {}
+ virtual void close_generator (t_program* tprogram) {}
/** Pure virtual methods implemented by the generator subclasses. */
- virtual void generate_typedef (t_typedef* ttypedef) = 0;
- virtual void generate_enum (t_enum* tenum) = 0;
- virtual void generate_struct (t_struct* tstruct) = 0;
- virtual void generate_service (t_service* tservice) = 0;
+ virtual void generate_typedef (t_typedef* ttypedef) = 0;
+ virtual void generate_enum (t_enum* tenum) = 0;
+ virtual void generate_struct (t_struct* tstruct) = 0;
+ virtual void generate_xception (t_struct* txception) {
+ generate_struct(txception);
+ }
+ virtual void generate_service (t_service* tservice) = 0;
/** Method to get the program name, may be overridden */
diff --git a/compiler/cpp/src/generate/t_java_generator.cc b/compiler/cpp/src/generate/t_java_generator.cc
index 13b5022..f112407 100644
--- a/compiler/cpp/src/generate/t_java_generator.cc
+++ b/compiler/cpp/src/generate/t_java_generator.cc
@@ -49,7 +49,7 @@
/**
* Does nothing in Java
*/
-void t_java_generator::close_generator() {}
+void t_java_generator::close_generator(t_program *tprogram) {}
/**
* Generates a typedef. This is not done in Java.
@@ -583,15 +583,9 @@
case t_base_type::TYPE_I32:
f_service_ << "readI32(_itrans);";
break;
- case t_base_type::TYPE_U32:
- f_service_ << "readU32(_itrans);";
- break;
case t_base_type::TYPE_I64:
f_service_ << "readI64(_itrans);";
break;
- case t_base_type::TYPE_U64:
- f_service_ << "readU64(_itrans);";
- break;
default:
throw "compiler error: no C++ name for base type " + tbase;
}
@@ -846,15 +840,9 @@
case t_base_type::TYPE_I32:
f_service_ << "writeI32(_otrans, " << name << ");";
break;
- case t_base_type::TYPE_U32:
- f_service_ << "writeU32(_otrans, " << name << ");";
- break;
case t_base_type::TYPE_I64:
f_service_ << "writeI64(_otrans, " << name << ");";
break;
- case t_base_type::TYPE_U64:
- f_service_ << "writeU64(_otrans, " << name << ");";
- break;
default:
throw "compiler error: no C++ name for base type " + tbase;
}
@@ -1066,10 +1054,8 @@
case t_base_type::TYPE_BYTE:
return "byte";
case t_base_type::TYPE_I32:
- case t_base_type::TYPE_U32:
return (in_container ? "Integer" : "int");
case t_base_type::TYPE_I64:
- case t_base_type::TYPE_U64:
return (in_container ? "Long" : "long");
default:
throw "compiler error: no C++ name for base type " + tbase;
@@ -1099,9 +1085,7 @@
break;
case t_base_type::TYPE_BYTE:
case t_base_type::TYPE_I32:
- case t_base_type::TYPE_U32:
case t_base_type::TYPE_I64:
- case t_base_type::TYPE_U64:
result += " = 0";
break;
}
@@ -1168,12 +1152,8 @@
return "TType.BYTE";
case t_base_type::TYPE_I32:
return "TType.I32";
- case t_base_type::TYPE_U32:
- return "TType.U32";
case t_base_type::TYPE_I64:
return "TType.I64";
- case t_base_type::TYPE_U64:
- return "TType.U64";
}
} else if (type->is_enum()) {
return "TType.I32";
diff --git a/compiler/cpp/src/generate/t_java_generator.h b/compiler/cpp/src/generate/t_java_generator.h
index 3dd4dbd..0fa9074 100644
--- a/compiler/cpp/src/generate/t_java_generator.h
+++ b/compiler/cpp/src/generate/t_java_generator.h
@@ -24,7 +24,7 @@
/** Init and close methods */
void init_generator(t_program *tprogram);
- void close_generator();
+ void close_generator(t_program *tprogram);
/** Program-level generation functions */
diff --git a/compiler/cpp/src/generate/t_php_generator.cc b/compiler/cpp/src/generate/t_php_generator.cc
index 09a39a6..efd24c5 100644
--- a/compiler/cpp/src/generate/t_php_generator.cc
+++ b/compiler/cpp/src/generate/t_php_generator.cc
@@ -15,7 +15,7 @@
mkdir(T_PHP_DIR, S_IREAD | S_IWRITE | S_IEXEC);
// Make output file
- string f_types_name = string(T_PHP_DIR)+"/"+program_name_+"Types.php";
+ string f_types_name = string(T_PHP_DIR)+"/"+program_name_+"_types.php";
f_types_.open(f_types_name.c_str());
// Print header
@@ -30,13 +30,13 @@
*/
string t_php_generator::php_includes() {
return
- string("require_once THRIFT_ROOT.'/Thrift.php';\n\n");
+ string("require_once $GLOBALS['THRIFT_ROOT'].'/Thrift.php';\n\n");
}
/**
* Does nothing in PHP
*/
-void t_php_generator::close_generator() {
+void t_php_generator::close_generator(t_program *tprogram) {
// Close types file
f_types_ << "?>" << endl;
f_types_.close();
@@ -101,6 +101,27 @@
f_types_ << "}" << endl << endl;
}
+void t_php_generator::generate_struct(t_struct* tstruct) {
+ generate_php_struct(tstruct, false);
+}
+
+/**
+ * Generates a struct definition for a thrift exception. Basically the same
+ * as a struct but extends the Exception class.
+ *
+ * @param txception The struct definition
+ */
+void t_php_generator::generate_xception(t_struct* txception) {
+ generate_php_struct(txception, true);
+}
+
+void t_php_generator::generate_php_struct(t_struct* tstruct,
+ bool is_exception) {
+ generate_php_struct_definition(f_types_, tstruct, is_exception);
+ generate_php_struct_reader(f_types_, tstruct);
+ generate_php_struct_writer(f_types_, tstruct);
+}
+
/**
* Generates a struct definition for a thrift data type. This is nothing in PHP
* where the objects are all just associative arrays (unless of course we
@@ -108,30 +129,206 @@
*
* @param tstruct The struct definition
*/
-void t_php_generator::generate_struct(t_struct* tstruct) {
- f_types_ <<
- "class " << tstruct->get_name() << " {" << endl;
- indent_up();
-
+void t_php_generator::generate_php_struct_definition(ofstream& out,
+ t_struct* tstruct,
+ bool is_exception) {
const vector<t_field*>& members = tstruct->get_members();
vector<t_field*>::const_iterator m_iter;
+
+ out <<
+ "class " << tstruct->get_name();
+ if (is_exception) {
+ out << " extends Exception";
+ }
+ out <<
+ " {" << endl;
+ indent_up();
+
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
- indent(f_types_) <<
- "public " << declare_field(*m_iter, true) << endl;
+ // This fills in default values, as opposed to nulls
+ //indent(out) <<
+ //"public " << declare_field(*m_iter, true) << endl;
+
+ indent(out) <<
+ "public $" << (*m_iter)->get_name() << " = null;" << endl;
}
indent_down();
- f_types_ <<
+ out <<
+ indent() << "}" << endl <<
+ endl;
+}
+
+void t_php_generator::generate_php_struct_reader(ofstream& out,
+ t_struct* tstruct) {
+ const vector<t_field*>& fields = tstruct->get_members();
+ vector<t_field*>::const_iterator f_iter;
+
+ indent(out) <<
+ "function read_struct_" << tstruct->get_name() <<
+ "($iprot, $itrans, &$value) " << endl;
+ scope_up(out);
+
+ out <<
+ indent() << "$xfer = 0;" << endl <<
+ indent() << "$fname = null;" << endl <<
+ indent() << "$ftype = 0;" << endl <<
+ indent() << "$fid = 0;" << endl;
+
+ // Declare stack tmp variables
+ if (!binary_inline_) {
+ indent(out) <<
+ "$xfer += $iprot->readStructBegin($itrans, $fname);" << endl;
+ }
+
+ // Loop over reading in fields
+ indent(out) <<
+ "while (true)" << endl;
+
+ scope_up(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");
+ generate_deserialize_field(out, &fftype);
+ out <<
+ indent() << "if ($ftype == TType::STOP) {" << endl <<
+ indent() << " break;" << endl <<
+ indent() << "}" << endl;
+ generate_deserialize_field(out, &ffid);
+ } else {
+ indent(out) <<
+ "$xfer += $iprot->readFieldBegin($itrans, $fname, $ftype, $fid);" << endl;
+ // Check for field STOP marker and break
+ indent(out) <<
+ "if ($ftype == TType::STOP) {" << endl;
+ indent_up();
+ indent(out) <<
+ "break;" << endl;
+ indent_down();
+ indent(out) <<
+ "}" << endl;
+ }
+
+ // Switch statement on the field we are reading
+ indent(out) <<
+ "switch ($fid)" << endl;
+
+ scope_up(out);
+
+ // Generate deserialization code for known cases
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ indent(out) <<
+ "case " << (*f_iter)->get_key() << ":" << endl;
+ indent_up();
+ generate_deserialize_field(out, *f_iter, "value->");
+ indent(out) <<
+ "break;" << endl;
+ indent_down();
+ }
+
+ // In the default case we skip the field
+ out <<
+ indent() << "default:" << endl <<
+ indent() << " $xfer += $iprot->skip($itrans, $ftype);" << endl <<
+ indent() << " break;" << endl;
+
+ scope_down(out);
+
+ if (!binary_inline_) {
+ // Read field end marker
+ indent(out) <<
+ "$xfer += $iprot->readFieldEnd($itrans);" << endl;
+ }
+
+ scope_down(out);
+
+ if (!binary_inline_) {
+ indent(out) <<
+ "$xfer += $iprot->readStructEnd($itrans);" << endl;
+ }
+
+ indent(out) <<
+ "return $xfer;" << endl;
+
+ indent_down();
+ out <<
+ indent() << "}" << endl <<
+ endl;
+}
+
+void t_php_generator::generate_php_struct_writer(ofstream& out,
+ t_struct* tstruct) {
+ string name = tstruct->get_name();
+ const vector<t_field*>& fields = tstruct->get_members();
+ vector<t_field*>::const_iterator f_iter;
+
+ if (binary_inline_) {
+ indent(out) <<
+ "function write_struct_" << name <<
+ "(&$_output, &$value) {" << endl;
+ } else {
+ indent(out) <<
+ "function write_struct_" << name <<
+ "($oprot, $otrans, &$value) {" << endl;
+ }
+ indent_up();
+
+ indent(out) <<
+ "$xfer = 0;" << endl;
+
+ if (!binary_inline_) {
+ indent(out) <<
+ "$xfer += $oprot->writeStructBegin($otrans, '" << name << "');" << endl;
+ }
+
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ // Write field header
+ if (binary_inline_) {
+ out <<
+ indent() << "$_output .= pack('c', " << type_to_enum((*f_iter)->get_type()) << ");" << endl <<
+ indent() << "$_output .= pack('n', " << (*f_iter)->get_key() << ");" << endl;
+ } else {
+ indent(out) <<
+ "$xfer += $oprot->writeFieldBegin($otrans, " <<
+ "'" << (*f_iter)->get_name() << "', " <<
+ type_to_enum((*f_iter)->get_type()) << ", " <<
+ (*f_iter)->get_key() << ");" << endl;
+ }
+
+ // Write field contents
+ generate_serialize_field(out, *f_iter, "value->");
+
+ // Write field closer
+ if (!binary_inline_) {
+ indent(out) <<
+ "$xfer += $oprot->writeFieldEnd($otrans);" << endl;
+ }
+ }
+
+ if (binary_inline_) {
+ out <<
+ indent() << "$_output .= pack('c', TType::STOP);" << endl;
+ } else {
+ // Write the struct map
+ out <<
+ indent() << "$xfer += $oprot->writeFieldStop($otrans);" << endl <<
+ indent() << "$xfer += $oprot->writeStructEnd($otrans);" << endl;
+ }
+
+ out <<
+ indent() << "return $xfer;" << endl;
+
+ indent_down();
+ out <<
indent() << "}" << endl <<
endl;
}
/**
- * Generates a thrift service. In C++, this comprises an entirely separate
- * header and source file. The header file defines the methods and includes
- * the data types defined in the main header file, and the implementation
- * file contains implementations of the basic printer and default interfaces.
+ * Generates a thrift service.
*
* @param tservice The service definition
*/
@@ -145,12 +342,13 @@
php_includes();
f_service_ <<
- "require_once dirname(__FILE__).'/" << service_name_ << "Types.php';" << endl << endl;
+ "require_once dirname(__FILE__).'/" << service_name_ << "_types.php';" << endl << endl;
// Generate the three main parts of the service (well, two for now in PHP)
generate_service_interface(tservice);
- // generate_service_server(tservice);
generate_service_client(tservice);
+ generate_service_helpers(tservice);
+ // generate_service_server(tservice);
// Close service file
f_service_ << "?>" << endl;
@@ -158,6 +356,50 @@
}
/**
+ * Generates helper functions for a service.
+ *
+ * @param tservice The service to generate a header definition for
+ */
+void t_php_generator::generate_service_helpers(t_service* tservice) {
+ vector<t_function*> functions = tservice->get_functions();
+ vector<t_function*>::iterator f_iter;
+
+ f_service_ <<
+ "// HELPER FUNCTIONS AND STRUCTURES" << endl << endl;
+
+ for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+ t_struct* ts = (*f_iter)->get_arglist();
+ generate_php_struct_definition(f_service_, ts, false);
+ generate_php_struct_reader(f_service_, ts);
+ generate_php_struct_writer(f_service_, ts);
+ generate_php_function_helpers(*f_iter);
+ }
+}
+
+/**
+ * Generates a struct and helpers for a function.
+ *
+ * @param tfunction The function
+ */
+void t_php_generator::generate_php_function_helpers(t_function* tfunction) {
+ t_struct result(tfunction->get_name() + "_result");
+ t_field success(tfunction->get_returntype(), "success", 0);
+ if (!tfunction->get_returntype()->is_void()) {
+ result.append(&success);
+ }
+
+ t_struct* xs = tfunction->get_xceptions();
+ const vector<t_field*>& fields = xs->get_members();
+ vector<t_field*>::const_iterator f_iter;
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ result.append(*f_iter);
+ }
+
+ generate_php_struct_definition(f_service_, &result, false);
+ generate_php_struct_reader(f_service_, &result);
+}
+
+/**
* Generates a service interface definition.
*
* @param tservice The service to generate a header definition for
@@ -191,14 +433,20 @@
// Private members
f_service_ <<
indent() << "private $_itrans = null;" << endl <<
- indent() << "private $_otrans = null;" << endl << endl;
+ indent() << "private $_otrans = null;" << endl <<
+ endl;
if (!binary_inline_) {
f_service_ <<
- indent() << "private $_iprot = null;" << endl <<
- indent() << "private $_oprot = null;" << endl << endl;
+ indent() << "private $_iprot = null;" << endl <<
+ indent() << "private $_oprot = null;" << endl <<
+ endl;
}
+ f_service_ <<
+ indent() << "private $_seqid = 0;" << endl <<
+ endl;
+
// Constructor function
f_service_ <<
indent() << "public function __construct() {" << endl <<
@@ -230,92 +478,176 @@
// Generate client method implementations
vector<t_function*> functions = tservice->get_functions();
- vector<t_function*>::const_iterator f_iter;
+ vector<t_function*>::const_iterator f_iter;
for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+ t_struct* arg_struct = (*f_iter)->get_arglist();
+ const vector<t_field*>& fields = arg_struct->get_members();
+ vector<t_field*>::const_iterator fld_iter;
string funname = (*f_iter)->get_name();
// Open function
indent(f_service_) <<
"public function " << function_signature(*f_iter) << endl;
scope_up(f_service_);
+ indent(f_service_) <<
+ "$this->send_" << funname << "(";
- // Serialize the request header
- if (binary_inline_) {
- f_service_ <<
- indent() << "$_output = '';" << endl <<
- indent() << "$_output .= pack('c', TType::STRING);" << endl <<
- indent() << "$_output .= strrev(pack('l', 0));" << endl <<
- indent() << "$_output .= strrev(pack('l', strlen('" << funname << "')));" << endl <<
- indent() << "$_output .= '" << funname << "';" << endl <<
- indent() << "$_output .= pack('c', TType::STRUCT);" << endl <<
- indent() << "$_output .= strrev(pack('l', 1));" << endl;
- } else {
- f_service_ <<
- indent() << "$this->_oprot->writeStructBegin($this->_otrans, 'function');" << endl <<
- indent() << "$this->_oprot->writeFieldBegin($this->_otrans, 'name', TType::STRING, 0);" << endl <<
- indent() << "$this->_oprot->writeString($this->_otrans, '" << funname << "');" << endl <<
- indent() << "$this->_oprot->writeFieldEnd($this->_otrans);" << endl <<
- indent() << "$this->_oprot->writeFieldBegin($this->_otrans, 'args', TType::STRUCT, 1);" << endl;
- }
+ bool first = true;
+ for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
+ if (first) {
+ first = false;
+ } else {
+ f_service_ << ", ";
+ }
+ f_service_ << "$" << (*fld_iter)->get_name();
+ }
+ f_service_ << ");" << endl;
- // Serialize request arguments
- generate_serialize_struct((*f_iter)->get_arglist());
+ if (!(*f_iter)->is_async()) {
+ f_service_ << indent();
+ if (!(*f_iter)->get_returntype()->is_void()) {
+ f_service_ << "return ";
+ }
+ f_service_ <<
+ "$this->recv_" << funname << "();" << endl;
+ }
+ scope_down(f_service_);
+ f_service_ << endl;
- // Write to the stream
- if (binary_inline_) {
- f_service_ <<
- indent() << "$_output .= pack('c', TType::STOP);" << endl <<
- indent() << "$this->_otrans->write($_output);" << endl;
- } else {
- f_service_ <<
- indent() << "$this->_oprot->writeFieldEnd($this->_otrans);" << endl <<
- indent() << "$this->_oprot->writeFieldStop($this->_otrans);" << endl <<
- indent() << "$this->_oprot->writeStructEnd($this->_otrans);" << endl;
- }
-
- // Flush the request
indent(f_service_) <<
- "$this->_otrans->flush();" << endl;
+ "public function send_" << function_signature(*f_iter) << endl;
+ scope_up(f_service_);
- // Read the response
- t_struct result_struct((*f_iter)->get_name() + "_result");
- t_field result_field((*f_iter)->get_returntype(), "_result");
+ std::string argsname = (*f_iter)->get_name() + "_args";
- // Add a field to the return struct if non void
- if (!(*f_iter)->get_returntype()->is_void()) {
+ // Serialize the request header
+ if (binary_inline_) {
+ f_service_ <<
+ indent() << "$_output = '';" << endl <<
+ indent() << "$_output .= pack('N', strlen('" << funname << "'));" << endl <<
+ indent() << "$_output .= '" << funname << "';" << endl <<
+ indent() << "$_output .= pack('cN', TMessageType::CALL, $this->seqid);" << endl;
+ } else {
+ f_service_ <<
+ indent() << "$this->_oprot->writeMessageBegin($this->_otrans, '" << (*f_iter)->get_name() << "', TMessageType::CALL, $this->seqid);" << endl;
+ }
+
+ f_service_ <<
+ indent() << "$__args = new " << argsname << "();" << 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;
+ }
+
+ // Write to the stream
+ if (binary_inline_) {
+ f_service_ <<
+ indent() << "write_struct_" << argsname << "($_output, $__args);" << endl <<
+ indent() << "$this->_otrans->write($_output);" << endl;
+ } else {
+ f_service_ <<
+ indent() << "write_struct_" << argsname << "($this->_oprot, $this->_otrans, $__args);" << endl <<
+ indent() << "$this->_oprot->writeMessageEnd($this->_otrans);" << endl;
+ }
+
+ // Flush the request
indent(f_service_) <<
- declare_field(&result_field, true, true) << endl;
- result_struct.append(&result_field);
- }
+ "$this->_otrans->flush();" << endl;
+
+
+ scope_down(f_service_);
+
- // Deserialize response struct
- generate_deserialize_struct(&result_struct);
+ if (!(*f_iter)->is_async()) {
+ std::string resultname = (*f_iter)->get_name() + "_result";
+ t_struct noargs;
+
+ t_function recv_function((*f_iter)->get_returntype(),
+ string("recv_") + (*f_iter)->get_name(),
+ &noargs);
+ // Open function
+ f_service_ <<
+ endl <<
+ indent() << "public function " << function_signature(&recv_function) << endl;
+ scope_up(f_service_);
- // Careful, only return _result if not a void function
- if (!(*f_iter)->get_returntype()->is_void()) {
- indent(f_service_) <<
- "return $_result;" << endl;
- } else {
- indent(f_service_) <<
- "return;" << endl;
- }
+ f_service_ <<
+ indent() << "$rseqid = 0;" << endl <<
+ indent() << "$fname = null;" << endl <<
+ indent() << "$mtype = 0;" << endl <<
+ endl;
+
+ if (binary_inline_) {
+ t_field ffname(g_program->get_string_type(), "fname");
+ t_field fmtype(g_program->get_byte_type(), "mtype");
+ t_field fseqid(g_program->get_i32_type(), "rseqid");
+ generate_deserialize_field(f_service_, &ffname, "", true);
+ generate_deserialize_field(f_service_, &fmtype, "", true);
+ generate_deserialize_field(f_service_, &fseqid, "", true);
+ } else {
+ f_service_ <<
+ indent() << "$this->_iprot->readMessageBegin($this->_itrans, $fname, $mtype, $rseqid);" << endl;
+ }
+
+ // TODO(mcslee): Validate message reply here
+
+ f_service_ <<
+ indent() << "$__result = new " << resultname << "();" << endl <<
+ indent() << "read_struct_" << resultname << "($this->_iprot, $this->_otrans, $__result);" << endl;
+
+ if (!binary_inline_) {
+ f_service_ <<
+ indent() << "$this->_iprot->readMessageEnd($this->_itrans);" << endl <<
+ endl;
+ }
+
+ // Careful, only return _result if not a void function
+ if (!(*f_iter)->get_returntype()->is_void()) {
+ f_service_ <<
+ indent() << "if ($__result->success !== null) {" << endl <<
+ indent() << " return $__result->success;" << endl <<
+ indent() << "}" << endl;
+ }
+
+ t_struct* xs = (*f_iter)->get_xceptions();
+ const std::vector<t_field*>& xceptions = xs->get_members();
+ vector<t_field*>::const_iterator x_iter;
+ for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
+ f_service_ <<
+ indent() << "if ($__result->" << (*x_iter)->get_name() << " !== null) {" << endl <<
+ indent() << " throw $__result->" << (*x_iter)->get_name() << ";" << endl <<
+ indent() << "}" << endl;
+ }
+
+ // Careful, only return _result if not a void function
+ if ((*f_iter)->get_returntype()->is_void()) {
+ indent(f_service_) <<
+ "return;" << endl;
+ } else {
+ f_service_ <<
+ indent() << "throw Exception(\"" << (*f_iter)->get_name() << " failed: unknown result\");" << endl;
+ }
+ }
// Close function
scope_down(f_service_);
f_service_ << endl;
+
}
indent_down();
f_service_ <<
- "}" << endl;
- f_service_.close();
+ "}" << endl << endl;
}
/**
* Deserializes a field of any type.
*/
-void t_php_generator::generate_deserialize_field(t_field* tfield,
- string prefix) {
+void t_php_generator::generate_deserialize_field(ofstream &out,
+ t_field* tfield,
+ string prefix,
+ bool inclass) {
t_type* type = tfield->get_type();
while (type->is_typedef()) {
type = ((t_typedef*)type)->get_type();
@@ -328,14 +660,17 @@
string name = prefix + tfield->get_name();
- if (type->is_struct()) {
- generate_deserialize_struct((t_struct*)(tfield->get_type()),
- name + "->");
+ if (type->is_struct() || type->is_xception()) {
+ generate_deserialize_struct(out,
+ (t_struct*)(tfield->get_type()),
+ name);
} else if (type->is_container()) {
- generate_deserialize_container(tfield->get_type(), name);
+ generate_deserialize_container(out, tfield->get_type(), name);
} else if (type->is_base_type() || type->is_enum()) {
if (binary_inline_) {
+ std::string itrans = inclass ? "$this->_itrans" : "$itrans";
+
if (type->is_base_type()) {
t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
switch (tbase) {
@@ -343,28 +678,41 @@
throw "compiler error: cannot serialize void field in a struct: " +
name;
break;
- case t_base_type::TYPE_STRING:
- f_service_ <<
- indent() << "$_len = unpack('l', strrev($this->_itrans->readAll(4)));" << endl <<
+ case t_base_type::TYPE_STRING:
+ out <<
+ indent() << "$_len = unpack('N', " << itrans << "->readAll(4));" << endl <<
indent() << "$_len = $_len[1];" << endl <<
- indent() << "$" << name << " = $this->_itrans->readAll($_len);" << endl;
+ indent() << "if ($_len > 0x7fffffff) {" << endl <<
+ indent() << " $_len = 0 - (($len - 1) ^ 0xffffffff);" << endl <<
+ indent() << "}" << endl <<
+ indent() << "$" << name << " = " << itrans << "->readAll($_len);" << endl;
break;
case t_base_type::TYPE_BYTE:
- f_service_ <<
- indent() << "$" << name << " = unpack('c', $this->_itrans->readAll(1));" << endl <<
+ out <<
+ indent() << "$" << name << " = unpack('c', " << itrans << "->readAll(1));" << endl <<
indent() << "$" << name << " = $" << name << "[1];" << endl;
break;
+ case t_base_type::TYPE_I16:
+ out <<
+ indent() << "$_val = unpack('n', " << itrans << "->readAll(2));" << endl <<
+ indent() << "$_val = $_val[1];" << endl <<
+ indent() << "if ($_val > 0x7fff) {" << endl <<
+ indent() << " $_val = 0 - (($_val - 1) ^ 0xffff);" << endl <<
+ indent() << "}" << endl <<
+ indent() << "$" << name << " = $_val;" << endl;
+ break;
case t_base_type::TYPE_I32:
- f_service_ <<
- indent() << "$" << name << " = unpack('l', strrev($this->_itrans->readAll(4)));" << endl <<
- indent() << "$" << name << " = $" << name << "[1];" << endl;
- break;
- case t_base_type::TYPE_U32:
- f_service_ << "readU32($this->_itrans, $" << name << ");";
+ out <<
+ indent() << "$_val = unpack('N', " << itrans << "->readAll(4));" << endl <<
+ indent() << "$_val = $_val[1];" << endl <<
+ indent() << "if ($_val > 0x7fffffff) {" << endl <<
+ indent() << " $_val = 0 - (($_val - 1) ^ 0xffffffff);" << endl <<
+ indent() << "}" << endl <<
+ indent() << "$" << name << " = $_val;" << endl;
break;
case t_base_type::TYPE_I64:
- f_service_ <<
- indent() << "$_arr = unpack('N2', $this->_itrans->readAll(8));" << endl <<
+ out <<
+ indent() << "$_arr = unpack('N2', " << itrans << "->readAll(8));" << endl <<
indent() << "if ($_arr[1] & 0x80000000) {" << endl <<
indent() << " $_arr[1] = $_arr[1] ^ 0xFFFFFFFF;" << endl <<
indent() << " $_arr[2] = $_arr[2] ^ 0xFFFFFFFF;" << endl <<
@@ -373,22 +721,22 @@
indent() << " $" << name << " = $_arr[1]*4294967296 + $_arr[2];" << endl <<
indent() << "}" << endl;
break;
- case t_base_type::TYPE_U64:
- f_service_ << "readU64($this->_itrans, $" << name << ");";
- break;
default:
- throw "compiler error: no C++ name for base type " + tbase;
+ throw "compiler error: no PHP name for base type " + tbase + tfield->get_name();
}
} else if (type->is_enum()) {
- f_service_ <<
- indent() << "$" << name << " = unpack('l', strrev($this->_itrans->readAll(4)));" << endl <<
- indent() << "$" << name << " = $" << name << "[1];" << endl;
+ out <<
+ indent() << "$_val = unpack('N', " << itrans << "->readAll(4));" << endl <<
+ indent() << "$_val = $_val[1];" << endl <<
+ indent() << "if ($_val > 0x7fffffff) {" << endl <<
+ indent() << " $_val = 0 - (($_val - 1) ^ 0xffffffff);" << endl <<
+ indent() << "}" << endl <<
+ indent() << "$" << name << " = $_val;" << endl;
}
-
} else {
- indent(f_service_) <<
- "$this->_iprot->";
+ indent(out) <<
+ "$xfer += $iprot->";
if (type->is_base_type()) {
t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
@@ -398,30 +746,27 @@
name;
break;
case t_base_type::TYPE_STRING:
- f_service_ << "readString($this->_itrans, $" << name << ");";
+ out << "readString($itrans, $" << name << ");";
break;
case t_base_type::TYPE_BYTE:
- f_service_ << "readByte($this->_itrans, $" << name << ");";
+ out << "readByte($itrans, $" << name << ");";
+ break;
+ case t_base_type::TYPE_I16:
+ out << "readI16($itrans, $" << name << ");";
break;
case t_base_type::TYPE_I32:
- f_service_ << "readI32($this->_itrans, $" << name << ");";
- break;
- case t_base_type::TYPE_U32:
- f_service_ << "readU32($this->_itrans, $" << name << ");";
+ out << "readI32($itrans, $" << name << ");";
break;
case t_base_type::TYPE_I64:
- f_service_ << "readI64($this->_itrans, $" << name << ");";
- break;
- case t_base_type::TYPE_U64:
- f_service_ << "readU64($this->_itrans, $" << name << ");";
+ out << "readI64($itrans, $" << name << ");";
break;
default:
- throw "compiler error: no C++ name for base type " + tbase;
+ throw "compiler error: no PHP name for base type " + tbase;
}
} else if (type->is_enum()) {
- f_service_ << "readI32($this->_itrans, $" << name << ");";
+ out << "readI32($itrans, $" << name << ");";
}
- f_service_ << endl;
+ out << endl;
}
} else {
@@ -436,107 +781,18 @@
* buffer for deserialization, and that there is a variable protocol which
* is a reference to a TProtocol serialization object.
*/
-void t_php_generator::generate_deserialize_struct(t_struct* tstruct,
+void t_php_generator::generate_deserialize_struct(ofstream &out,
+ t_struct* tstruct,
string prefix) {
- const vector<t_field*>& fields = tstruct->get_members();
- vector<t_field*>::const_iterator f_iter;
-
- scope_up(f_service_);
-
- // Read the struct fields from the protocol
- string fid = tmp("_fid");
- string ftype = tmp("_ftype");
- string fname = tmp("_name");
-
- t_field ffid(g_program->get_i32_type(), fid);
- t_field fftype(g_program->get_byte_type(), ftype);
-
- f_service_ <<
- indent() << "$" << fname << " = null;" << endl <<
- indent() << "$" << ftype << " = null;" << endl <<
- indent() << "$" << fid << " = 0;" << endl;
-
- // Declare stack tmp variables
- if (!binary_inline_) {
- f_service_ <<
- indent() << "$this->_iprot->readStructBegin($this->_itrans, $" << fname << ");" << endl;
- }
-
- // Loop over reading in fields
- indent(f_service_) <<
- "while (true)" << endl;
-
- scope_up(f_service_);
-
- // Read beginning field marker
- if (binary_inline_) {
- generate_deserialize_field(&fftype);
- f_service_ <<
- indent() << "if ($" << ftype << " == TType::STOP) {" << endl <<
- indent() << " break;" << endl <<
- indent() << "}" << endl;
- generate_deserialize_field(&ffid);
- } else {
- indent(f_service_) <<
- "$this->_iprot->readFieldBegin($this->_itrans, " <<
- "$" << fname << ", $" << ftype << ", $" << fid << ");" << endl;
-
- // Check for field STOP marker and break
- indent(f_service_) <<
- "if ($" << ftype << " == TType::STOP) {" << endl;
- indent_up();
- indent(f_service_) <<
- "break;" << endl;
- indent_down();
- indent(f_service_) <<
- "}" << endl;
- }
-
-
- // Switch statement on the field we are reading
- indent(f_service_) <<
- "switch ($" << fid << ")" << endl;
-
- scope_up(f_service_);
-
- // Generate deserialization code for known cases
- for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
- indent(f_service_) <<
- "case " << (*f_iter)->get_key() << ":" << endl;
- indent_up();
- generate_deserialize_field(*f_iter, prefix);
- indent(f_service_) <<
- "break;" << endl;
- indent_down();
- }
-
- // In the default case we skip the field
- f_service_ <<
- indent() << "default:" << endl <<
- indent() << " $this->_iprot->skip($this->_itrans, $" << ftype << ");" << endl <<
- indent() << " break;" << endl;
-
- scope_down(f_service_);
-
- if (!binary_inline_) {
- // Read field end marker
- indent(f_service_) <<
- "$this->_iprot->readFieldEnd($this->_itrans);" << endl;
- }
-
- scope_down(f_service_);
-
- if (!binary_inline_) {
- indent(f_service_) <<
- "$this->_iprot->readStructEnd($this->_itrans);" << endl;
- }
-
- scope_down(f_service_);
+ out <<
+ indent() << "$" << prefix << " = new " << tstruct->get_name() << "();" << endl <<
+ indent() << "$xfer += read_struct_" << tstruct->get_name() << "($iprot, $itrans, $" << prefix << ");" << endl;
}
-void t_php_generator::generate_deserialize_container(t_type* ttype,
+void t_php_generator::generate_deserialize_container(ofstream &out,
+ t_type* ttype,
string prefix) {
- scope_up(f_service_);
+ scope_up(out);
string size = tmp("_size");
string ktype = tmp("_ktype");
@@ -548,125 +804,128 @@
t_field fvtype(g_program->get_byte_type(), vtype);
t_field fetype(g_program->get_byte_type(), etype);
- indent(f_service_) <<
+ indent(out) <<
"$" << size << " = 0;" << endl;
// Declare variables, read header
if (ttype->is_map()) {
- f_service_ <<
+ out <<
indent() << "$" << ktype << " = 0;" << endl <<
indent() << "$" << vtype << " = 0;" << endl;
if (binary_inline_) {
- generate_deserialize_field(&fktype);
- generate_deserialize_field(&fvtype);
- generate_deserialize_field(&fsize);
+ generate_deserialize_field(out, &fktype);
+ generate_deserialize_field(out, &fvtype);
+ generate_deserialize_field(out, &fsize);
} else {
- f_service_ <<
- indent() << "$this->_iprot->readMapBegin($this->_itrans, " <<
+ out <<
+ indent() << "$xfer += $iprot->readMapBegin($itrans, " <<
"$" << ktype << ", $" << vtype << ", $" << size << ");" << endl;
}
} else if (ttype->is_set()) {
if (binary_inline_) {
- generate_deserialize_field(&fetype);
- generate_deserialize_field(&fsize);
+ generate_deserialize_field(out, &fetype);
+ generate_deserialize_field(out, &fsize);
} else {
- f_service_ <<
+ out <<
indent() << "$" << etype << " = 0;" << endl <<
- indent() << "$this->_iprot->readSetBegin($this->_itrans, " <<
+ indent() << "$xfer += $iprot->readSetBegin($itrans, " <<
"$" << etype << ", $" << size << ");" << endl;
}
} else if (ttype->is_list()) {
if (binary_inline_) {
- generate_deserialize_field(&fetype);
- generate_deserialize_field(&fsize);
+ generate_deserialize_field(out, &fetype);
+ generate_deserialize_field(out, &fsize);
} else {
- f_service_ <<
+ out <<
indent() << "$" << etype << " = 0;" << endl <<
- indent() << "$this->_iprot->readListBegin($this->_itrans, " <<
+ indent() << "$xfer += $iprot->readListBegin($itrans, " <<
"$" << etype << ", $" << size << ");" << endl;
}
}
// For loop iterates over elements
string i = tmp("_i");
- indent(f_service_) <<
+ indent(out) <<
"for ($" <<
i << " = 0; $" << i << " < $" << size << "; ++$" << i << ")" << endl;
- scope_up(f_service_);
+ scope_up(out);
if (ttype->is_map()) {
- generate_deserialize_map_element((t_map*)ttype, prefix);
+ generate_deserialize_map_element(out, (t_map*)ttype, prefix);
} else if (ttype->is_set()) {
- generate_deserialize_set_element((t_set*)ttype, prefix);
+ generate_deserialize_set_element(out, (t_set*)ttype, prefix);
} else if (ttype->is_list()) {
- generate_deserialize_list_element((t_list*)ttype, prefix);
+ generate_deserialize_list_element(out, (t_list*)ttype, prefix);
}
- scope_down(f_service_);
+ scope_down(out);
if (!binary_inline_) {
// Read container end
if (ttype->is_map()) {
- indent(f_service_) << "$this->_iprot->readMapEnd($this->_itrans);" << endl;
+ indent(out) << "$xfer += $iprot->readMapEnd($itrans);" << endl;
} else if (ttype->is_set()) {
- indent(f_service_) << "$this->_iprot->readSetEnd($this->_itrans);" << endl;
+ indent(out) << "$xfer += $iprot->readSetEnd($itrans);" << endl;
} else if (ttype->is_list()) {
- indent(f_service_) << "$this->_iprot->readListEnd($this->_itrans);" << endl;
+ indent(out) << "$xfer += $iprot->readListEnd($itrans);" << endl;
}
}
- scope_down(f_service_);
+ scope_down(out);
}
/**
* Generates code to deserialize a map
*/
-void t_php_generator::generate_deserialize_map_element(t_map* tmap,
+void t_php_generator::generate_deserialize_map_element(ofstream &out,
+ t_map* tmap,
string prefix) {
string key = tmp("_key");
string val = tmp("_val");
t_field fkey(tmap->get_key_type(), key);
t_field fval(tmap->get_val_type(), val);
- indent(f_service_) <<
+ indent(out) <<
declare_field(&fkey, true, true) << endl;
- indent(f_service_) <<
+ indent(out) <<
declare_field(&fval, true, true) << endl;
- generate_deserialize_field(&fkey);
- generate_deserialize_field(&fval);
+ generate_deserialize_field(out, &fkey);
+ generate_deserialize_field(out, &fval);
- indent(f_service_) <<
+ indent(out) <<
"$" << prefix << "[$" << key << "] = $" << val << ";" << endl;
}
-void t_php_generator::generate_deserialize_set_element(t_set* tset,
+void t_php_generator::generate_deserialize_set_element(ofstream &out,
+ t_set* tset,
string prefix) {
string elem = tmp("_elem");
t_field felem(tset->get_elem_type(), elem);
- indent(f_service_) <<
+ indent(out) <<
"$" << elem << " = null;" << endl;
- generate_deserialize_field(&felem);
+ generate_deserialize_field(out, &felem);
- indent(f_service_) <<
+ indent(out) <<
"$" << prefix << " []= $" << elem << ";" << endl;
}
-void t_php_generator::generate_deserialize_list_element(t_list* tlist,
+void t_php_generator::generate_deserialize_list_element(ofstream &out,
+ t_list* tlist,
string prefix) {
string elem = tmp("_elem");
t_field felem(tlist->get_elem_type(), elem);
- indent(f_service_) <<
+ indent(out) <<
"$" << elem << " = null;" << endl;
- generate_deserialize_field(&felem);
+ generate_deserialize_field(out, &felem);
- indent(f_service_) <<
+ indent(out) <<
"$" << prefix << " []= $" << elem << ";" << endl;
}
@@ -677,7 +936,8 @@
* @param tfield The field to serialize
* @param prefix Name to prepend to field name
*/
-void t_php_generator::generate_serialize_field(t_field* tfield,
+void t_php_generator::generate_serialize_field(ofstream &out,
+ t_field* tfield,
string prefix) {
t_type* type = tfield->get_type();
while (type->is_typedef()) {
@@ -690,11 +950,13 @@
prefix + tfield->get_name();
}
- if (type->is_struct()) {
- generate_serialize_struct((t_struct*)(tfield->get_type()),
- prefix + tfield->get_name() + "->");
+ if (type->is_struct() || type->is_xception()) {
+ generate_serialize_struct(out,
+ (t_struct*)(tfield->get_type()),
+ prefix + tfield->get_name());
} else if (type->is_container()) {
- generate_serialize_container(tfield->get_type(),
+ generate_serialize_container(out,
+ tfield->get_type(),
prefix + tfield->get_name());
} else if (type->is_base_type() || type->is_enum()) {
@@ -709,40 +971,37 @@
"compiler error: cannot serialize void field in a struct: " + name;
break;
case t_base_type::TYPE_STRING:
- f_service_ <<
- indent() << "$_output .= strrev(pack('l', strlen($" << name << ")));" << endl <<
+ out <<
+ indent() << "$_output .= pack('N', strlen($" << name << "));" << endl <<
indent() << "$_output .= $" << name << ";" << endl;
break;
case t_base_type::TYPE_BYTE:
- f_service_ <<
+ out <<
indent() << "$_output .= pack('c', $" << name << ");" << endl;
break;
- case t_base_type::TYPE_I32:
- f_service_ <<
- indent() << "$_output .= strrev(pack('l', $" << name << "));" << endl;
+ case t_base_type::TYPE_I16:
+ out <<
+ indent() << "$_output .= pack('n', $" << name << ");" << endl;
break;
- case t_base_type::TYPE_U32:
- f_service_ <<
- indent() << "writeU32($this->_otrans, $" << name << ");" << endl;
+ case t_base_type::TYPE_I32:
+ out <<
+ indent() << "$_output .= pack('N', $" << name << ");" << endl;
break;
case t_base_type::TYPE_I64:
- f_service_ <<
+ out <<
indent() << "$_output .= pack('N2', $" << name << " >> 32, $" << name << " & 0xFFFFFFFF);" << endl;
break;
- case t_base_type::TYPE_U64:
- f_service_ << "writeU64($this->_otrans, $" << name << ");";
- break;
default:
- throw "compiler error: no C++ name for base type " + tbase;
+ throw "compiler error: no PHP name for base type " + tbase;
}
} else if (type->is_enum()) {
- f_service_ <<
- indent() << "$_output .= strrev(pack('l', $" << name << "));" << endl;
+ out <<
+ indent() << "$_output .= pack('N', $" << name << ");" << endl;
}
} else {
- indent(f_service_) <<
- "$this->_oprot->";
+ indent(out) <<
+ "$xfer += $oprot->";
if (type->is_base_type()) {
t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
@@ -752,30 +1011,27 @@
"compiler error: cannot serialize void field in a struct: " + name;
break;
case t_base_type::TYPE_STRING:
- f_service_ << "writeString($this->_otrans, $" << name << ");";
+ out << "writeString($otrans, $" << name << ");";
break;
case t_base_type::TYPE_BYTE:
- f_service_ << "writeByte($this->_otrans, $" << name << ");";
+ out << "writeByte($otrans, $" << name << ");";
+ break;
+ case t_base_type::TYPE_I16:
+ out << "writeI16($otrans, $" << name << ");";
break;
case t_base_type::TYPE_I32:
- f_service_ << "writeI32($this->_otrans, $" << name << ");";
- break;
- case t_base_type::TYPE_U32:
- f_service_ << "writeU32($this->_otrans, $" << name << ");";
+ out << "writeI32($otrans, $" << name << ");";
break;
case t_base_type::TYPE_I64:
- f_service_ << "writeI64($this->_otrans, $" << name << ");";
- break;
- case t_base_type::TYPE_U64:
- f_service_ << "writeU64($this->_otrans, $" << name << ");";
+ out << "writeI64($otrans, $" << name << ");";
break;
default:
- throw "compiler error: no C++ name for base type " + tbase;
+ throw "compiler error: no PHP name for base type " + tbase;
}
} else if (type->is_enum()) {
- f_service_ << "writeI32($this->_otrans, $" << name << ");";
+ out << "writeI32($otrans, $" << name << ");";
}
- f_service_ << endl;
+ out << endl;
}
} else {
printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
@@ -791,176 +1047,140 @@
* @param tstruct The struct to serialize
* @param prefix String prefix to attach to all fields
*/
-void t_php_generator::generate_serialize_struct(t_struct* tstruct,
- string prefix) {
- string name = tstruct->get_name();
- const vector<t_field*>& fields = tstruct->get_members();
- vector<t_field*>::const_iterator f_iter;
-
- scope_up(f_service_);
-
- if (!binary_inline_) {
- indent(f_service_) <<
- "$this->_oprot->writeStructBegin($this->_otrans, '" << name << "');" << endl;
- }
-
- for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
- // Write field header
- if (binary_inline_) {
- f_service_ <<
- indent() << "$_output .= pack('c', " << type_to_enum((*f_iter)->get_type()) << ");" << endl <<
- indent() << "$_output .= strrev(pack('l', " << (*f_iter)->get_key() << "));" << endl;
- } else {
- indent(f_service_) <<
- "$this->_oprot->writeFieldBegin($this->_otrans, " <<
- "'" << (*f_iter)->get_name() << "', " <<
- type_to_enum((*f_iter)->get_type()) << ", " <<
- (*f_iter)->get_key() << ");" << endl;
- }
-
- // Write field contents
- generate_serialize_field(*f_iter, prefix);
-
- // Write field closer
- if (binary_inline_) {
- } else {
- indent(f_service_) <<
- "$this->_oprot->writeFieldEnd($this->_otrans);" << endl;
- }
- }
-
+void t_php_generator::generate_serialize_struct(ofstream &out,
+ t_struct* tstruct,
+ string prefix) {
if (binary_inline_) {
- f_service_ <<
- indent() << "$_output .= pack('c', TType::STOP);" << endl;
+ indent(out) <<
+ "$xfer += write_struct_" << tstruct->get_name() << "($_output, $" << prefix << ");" << endl;
} else {
- // Write the struct map
- f_service_ <<
- indent() << "$this->_oprot->writeFieldStop($this->_otrans);" << endl <<
- indent() << "$this->_oprot->writeStructEnd($this->_otrans);" << endl;
+ indent(out) <<
+ "$xfer += write_struct_" << tstruct->get_name() << "($oprot, $otrans, $" << prefix << ");" << endl;
}
-
- scope_down(f_service_);
}
-void t_php_generator::generate_serialize_container(t_type* ttype,
+void t_php_generator::generate_serialize_container(ofstream &out,
+ t_type* ttype,
string prefix) {
- scope_up(f_service_);
+ scope_up(out);
if (ttype->is_map()) {
if (binary_inline_) {
- f_service_ <<
+ out <<
indent() << "$_output .= pack('c', " << type_to_enum(((t_map*)ttype)->get_key_type()) << ");" << endl <<
indent() << "$_output .= pack('c', " << type_to_enum(((t_map*)ttype)->get_val_type()) << ");" << endl <<
indent() << "$_output .= strrev(pack('l', count($" << prefix << ")));" << endl;
} else {
- indent(f_service_) <<
- "$this->_oprot->writeMapBegin($this->_otrans, " <<
+ indent(out) <<
+ "$oprot->writeMapBegin($otrans, " <<
type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
"count($" << prefix << "));" << endl;
}
} else if (ttype->is_set()) {
if (binary_inline_) {
- f_service_ <<
+ out <<
indent() << "$_output .= pack('c', " << type_to_enum(((t_set*)ttype)->get_elem_type()) << ");" << endl <<
indent() << "$_output .= strrev(pack('l', count($" << prefix << ")));" << endl;
} else {
- indent(f_service_) <<
- "$this->_oprot->writeSetBegin($this->_otrans, " <<
+ indent(out) <<
+ "$oprot->writeSetBegin($otrans, " <<
type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
"count($" << prefix << "));" << endl;
}
} else if (ttype->is_list()) {
if (binary_inline_) {
- f_service_ <<
+ out <<
indent() << "$_output .= pack('c', " << type_to_enum(((t_list*)ttype)->get_elem_type()) << ");" << endl <<
indent() << "$_output .= strrev(pack('l', count($" << prefix << ")));" << endl;
} else {
- indent(f_service_) <<
- "$this->_oprot->writeListBegin($this->_otrans, " <<
+ indent(out) <<
+ "$oprot->writeListBegin($otrans, " <<
type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
"count($" << prefix << "));" << endl;
}
}
- scope_up(f_service_);
+ scope_up(out);
if (ttype->is_map()) {
string kiter = tmp("_kiter");
string viter = tmp("_viter");
- indent(f_service_) <<
+ indent(out) <<
"foreach ($" << prefix << " as " <<
"$" << kiter << " => $" << viter << ")" << endl;
- scope_up(f_service_);
- generate_serialize_map_element((t_map*)ttype, kiter, viter);
- scope_down(f_service_);
+ scope_up(out);
+ generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
+ scope_down(out);
} else if (ttype->is_set()) {
string iter = tmp("_iter");
- indent(f_service_) <<
+ indent(out) <<
"foreach ($" << prefix << " as $" << iter << ")" << endl;
- scope_up(f_service_);
- generate_serialize_set_element((t_set*)ttype, iter);
- scope_down(f_service_);
+ scope_up(out);
+ generate_serialize_set_element(out, (t_set*)ttype, iter);
+ scope_down(out);
} else if (ttype->is_list()) {
string iter = tmp("_iter");
- indent(f_service_) <<
+ indent(out) <<
"foreach ($" << prefix << " as $" << iter << ")" << endl;
- scope_up(f_service_);
- generate_serialize_list_element((t_list*)ttype, iter);
- scope_down(f_service_);
+ scope_up(out);
+ generate_serialize_list_element(out, (t_list*)ttype, iter);
+ scope_down(out);
}
-
- scope_down(f_service_);
+ scope_down(out);
if (!binary_inline_) {
if (ttype->is_map()) {
- indent(f_service_) <<
- "$this->_oprot->writeMapEnd($this->_otrans);" << endl;
+ indent(out) <<
+ "$oprot->writeMapEnd($otrans);" << endl;
} else if (ttype->is_set()) {
- indent(f_service_) <<
- "$this->_oprot->writeSetEnd($this->_otrans);" << endl;
+ indent(out) <<
+ "$oprot->writeSetEnd($otrans);" << endl;
} else if (ttype->is_list()) {
- indent(f_service_) <<
- "$this->_oprot->writeListEnd($this->_otrans);" << endl;
+ indent(out) <<
+ "$oprot->writeListEnd($otrans);" << endl;
}
}
- scope_down(f_service_);
+ scope_down(out);
}
/**
* Serializes the members of a map.
*
*/
-void t_php_generator::generate_serialize_map_element(t_map* tmap,
- string kiter,
- string viter) {
+void t_php_generator::generate_serialize_map_element(ofstream &out,
+ t_map* tmap,
+ string kiter,
+ string viter) {
t_field kfield(tmap->get_key_type(), kiter);
- generate_serialize_field(&kfield, "");
+ generate_serialize_field(out, &kfield, "");
t_field vfield(tmap->get_val_type(), viter);
- generate_serialize_field(&vfield, "");
+ generate_serialize_field(out, &vfield, "");
}
/**
* Serializes the members of a set.
*/
-void t_php_generator::generate_serialize_set_element(t_set* tset,
- string iter) {
+void t_php_generator::generate_serialize_set_element(ofstream &out,
+ t_set* tset,
+ string iter) {
t_field efield(tset->get_elem_type(), iter);
- generate_serialize_field(&efield, "");
+ generate_serialize_field(out, &efield, "");
}
/**
* Serializes the members of a list.
*/
-void t_php_generator::generate_serialize_list_element(t_list* tlist,
+void t_php_generator::generate_serialize_list_element(ofstream &out,
+ t_list* tlist,
string iter) {
t_field efield(tlist->get_elem_type(), iter);
- generate_serialize_field(&efield, "");
+ generate_serialize_field(out, &efield, "");
}
/**
@@ -1007,16 +1227,14 @@
return "TString";
case t_base_type::TYPE_BYTE:
return "UInt8";
+ case t_base_type::TYPE_I16:
+ return "Int16";
case t_base_type::TYPE_I32:
return "Int32";
- case t_base_type::TYPE_U32:
- return "UInt32";
case t_base_type::TYPE_I64:
return "Int64";
- case t_base_type::TYPE_U64:
- return "UInt64";
default:
- throw "compiler error: no C++ name for base type " + tbase;
+ throw "compiler error: no PHP name for base type " + tbase;
}
}
@@ -1041,10 +1259,9 @@
result += " = ''";
break;
case t_base_type::TYPE_BYTE:
+ case t_base_type::TYPE_I16:
case t_base_type::TYPE_I32:
- case t_base_type::TYPE_U32:
case t_base_type::TYPE_I64:
- case t_base_type::TYPE_U64:
result += " = 0";
break;
default:
@@ -1115,14 +1332,12 @@
return "TType::STRING";
case t_base_type::TYPE_BYTE:
return "TType::BYTE";
+ case t_base_type::TYPE_I16:
+ return "TType::I16";
case t_base_type::TYPE_I32:
return "TType::I32";
- case t_base_type::TYPE_U32:
- return "TType::U32";
case t_base_type::TYPE_I64:
return "TType::I64";
- case t_base_type::TYPE_U64:
- return "TType::U64";
}
} else if (type->is_enum()) {
return "TType::I32";
diff --git a/compiler/cpp/src/generate/t_php_generator.h b/compiler/cpp/src/generate/t_php_generator.h
index e5fb30c..d5bc8e0 100644
--- a/compiler/cpp/src/generate/t_php_generator.h
+++ b/compiler/cpp/src/generate/t_php_generator.h
@@ -8,9 +8,6 @@
#include "t_oop_generator.h"
-// TODO(mcslee: Paramaterize the output dir
-#define T_PHP_DIR "gen-php"
-
/**
* Java code generator.
*
@@ -20,6 +17,11 @@
public:
t_php_generator(bool binary_inline=false) {
binary_inline_ = binary_inline;
+ if (binary_inline_) {
+ T_PHP_DIR = "gen-phpi";
+ } else {
+ T_PHP_DIR = "gen-php";
+ }
}
~t_php_generator() {}
@@ -27,57 +29,80 @@
/** Init and close methods */
void init_generator(t_program *tprogram);
- void close_generator();
+ void close_generator(t_program *tprogram);
/** Program-level generation functions */
- void generate_typedef (t_typedef* ttypedef);
- void generate_enum (t_enum* tenum);
- void generate_struct (t_struct* tstruct);
- void generate_service (t_service* tservice);
+ void generate_typedef (t_typedef* ttypedef);
+ void generate_enum (t_enum* tenum);
+ void generate_struct (t_struct* tstruct);
+ void generate_xception (t_struct* txception);
+ void generate_service (t_service* tservice);
+
+
+ void generate_php_struct(t_struct* tstruct, bool is_exception);
+ void generate_php_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception);
+ void generate_php_struct_reader(std::ofstream& out, t_struct* tstruct);
+ void generate_php_struct_writer(std::ofstream& out, t_struct* tstruct);
+
+ void generate_php_function_helpers (t_function* tfunction);
/** Service-level generation functions */
+ void generate_service_helpers(t_service* tservice);
void generate_service_interface (t_service* tservice);
void generate_service_client (t_service* tservice);
/** Serialization constructs */
- void generate_deserialize_field (t_field* tfield,
+ void generate_deserialize_field (std::ofstream &out,
+ t_field* tfield,
+ std::string prefix="",
+ bool inclass=false);
+
+ void generate_deserialize_struct (std::ofstream &out,
+ t_struct* tstruct,
std::string prefix="");
- void generate_deserialize_struct (t_struct* tstruct,
+ void generate_deserialize_container (std::ofstream &out,
+ t_type* ttype,
std::string prefix="");
- void generate_deserialize_container (t_type* ttype,
- std::string prefix="");
-
- void generate_deserialize_set_element (t_set* tset,
+ void generate_deserialize_set_element (std::ofstream &out,
+ t_set* tset,
std::string prefix="");
- void generate_deserialize_map_element (t_map* tmap,
+ void generate_deserialize_map_element (std::ofstream &out,
+ t_map* tmap,
std::string prefix="");
- void generate_deserialize_list_element (t_list* tlist,
+ void generate_deserialize_list_element (std::ofstream &out,
+ t_list* tlist,
std::string prefix="");
- void generate_serialize_field (t_field* tfield,
+ void generate_serialize_field (std::ofstream &out,
+ t_field* tfield,
std::string prefix="");
- void generate_serialize_struct (t_struct* tstruct,
+ void generate_serialize_struct (std::ofstream &out,
+ t_struct* tstruct,
std::string prefix="");
- void generate_serialize_container (t_type* ttype,
+ void generate_serialize_container (std::ofstream &out,
+ t_type* ttype,
std::string prefix="");
- void generate_serialize_map_element (t_map* tmap,
+ void generate_serialize_map_element (std::ofstream &out,
+ t_map* tmap,
std::string kiter,
std::string viter);
- void generate_serialize_set_element (t_set* tmap,
+ void generate_serialize_set_element (std::ofstream &out,
+ t_set* tmap,
std::string iter);
- void generate_serialize_list_element (t_list* tlist,
+ void generate_serialize_list_element (std::ofstream &out,
+ t_list* tlist,
std::string iter);
/** Helper rendering functions */
@@ -93,8 +118,10 @@
private:
/** File streams */
+ char* T_PHP_DIR;
std::ofstream f_types_;
+ std::ofstream f_helpers_;
std::ofstream f_service_;
/** Generate protocol-independent template? Or Binary inline code? */
diff --git a/compiler/cpp/src/main.cc b/compiler/cpp/src/main.cc
index 6a7faf8..944cd66 100644
--- a/compiler/cpp/src/main.cc
+++ b/compiler/cpp/src/main.cc
@@ -95,12 +95,12 @@
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, " --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, " -python Generate Python output files\n");
- fprintf(stderr, " -d Print parse debugging to standard output\n");
+ fprintf(stderr, " --debug Print parse debugging to standard output\n");
exit(1);
}
@@ -124,16 +124,16 @@
}
for (i = 1; i < argc-1; i++) {
- if (strcmp(argv[i], "-d") == 0) {
+ if (strcmp(argv[i], "--debug") == 0) {
g_debug = 1;
- } else if (strcmp(argv[i], "-cpp") == 0) {
+ } else if (strcmp(argv[i], "--cpp") == 0) {
gen_cpp = true;
- } else if (strcmp(argv[i], "-java") == 0) {
+ } else if (strcmp(argv[i], "--java") == 0) {
gen_java = true;
- } else if (strcmp(argv[i], "-php") == 0) {
+ } else if (strcmp(argv[i], "--php") == 0) {
gen_php = true;
php_inline = false;
- } else if (strcmp(argv[i], "-phpi") == 0) {
+ } else if (strcmp(argv[i], "--phpi") == 0) {
gen_php = true;
php_inline = true;
} else {
diff --git a/compiler/cpp/src/parse/t_base_type.h b/compiler/cpp/src/parse/t_base_type.h
index f6cc197..5aebba7 100644
--- a/compiler/cpp/src/parse/t_base_type.h
+++ b/compiler/cpp/src/parse/t_base_type.h
@@ -15,10 +15,9 @@
TYPE_VOID,
TYPE_STRING,
TYPE_BYTE,
+ TYPE_I16,
TYPE_I32,
- TYPE_U32,
- TYPE_I64,
- TYPE_U64
+ TYPE_I64
};
t_base_type(std::string name, t_base base) :
diff --git a/compiler/cpp/src/parse/t_field.h b/compiler/cpp/src/parse/t_field.h
index fc38456..7f4d0e9 100644
--- a/compiler/cpp/src/parse/t_field.h
+++ b/compiler/cpp/src/parse/t_field.h
@@ -14,19 +14,19 @@
t_field(t_type* type, std::string name) :
type_(type), name_(name), key_(0) {}
- t_field(t_type* type, std::string name, uint32_t key) :
+ t_field(t_type* type, std::string name, int32_t key) :
type_(type), name_(name), key_(key) {}
~t_field() {}
t_type* get_type() const { return type_; }
const std::string& get_name() const { return name_; }
- uint32_t get_key() const { return key_; }
+ int32_t get_key() const { return key_; }
private:
t_type* type_;
std::string name_;
- uint32_t key_;
+ int32_t key_;
};
#endif
diff --git a/compiler/cpp/src/parse/t_function.h b/compiler/cpp/src/parse/t_function.h
index 9e6c56a..58667d8 100644
--- a/compiler/cpp/src/parse/t_function.h
+++ b/compiler/cpp/src/parse/t_function.h
@@ -20,6 +20,20 @@
returntype_(returntype),
name_(name),
arglist_(arglist),
+ async_(async) {
+ xceptions_ = new t_struct;
+ }
+
+
+ t_function(t_type* returntype,
+ std::string name,
+ t_struct* arglist,
+ t_struct* xceptions,
+ bool async=false) :
+ returntype_(returntype),
+ name_(name),
+ arglist_(arglist),
+ xceptions_(xceptions),
async_(async) {}
~t_function() {}
@@ -27,12 +41,14 @@
t_type* get_returntype() const { return returntype_; }
const std::string& get_name() const { return name_; }
t_struct* get_arglist() const { return arglist_; }
+ t_struct* get_xceptions() const { return xceptions_; }
bool is_async() const { return async_; }
private:
t_type* returntype_;
std::string name_;
t_struct* arglist_;
+ t_struct* xceptions_;
bool async_;
};
diff --git a/compiler/cpp/src/parse/t_program.h b/compiler/cpp/src/parse/t_program.h
index cda24c6..98968ff 100644
--- a/compiler/cpp/src/parse/t_program.h
+++ b/compiler/cpp/src/parse/t_program.h
@@ -21,6 +21,7 @@
* Typedefs
* Enumerations
* Structs
+ * Exceptions
* Services
*
* @author Mark Slee <mcslee@facebook.com>
@@ -28,52 +29,54 @@
class t_program {
public:
t_program(std::string name) :
- name_(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_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_u32 = new t_base_type("u32", t_base_type::TYPE_U32);
type_i64 = new t_base_type("i64", t_base_type::TYPE_I64);
- type_u64 = new t_base_type("u64", t_base_type::TYPE_U64);
}
~t_program() {
delete type_string;
delete type_byte;
+ delete type_i16;
delete type_i32;
- delete type_u32;
delete type_i64;
- delete type_u64;
}
// Name accessor
const std::string& get_name() const { return name_; }
+ // Namespace
+ const std::string& get_namespace() const { return namespace_; }
+
// Accessors for program elements
- const std::vector<t_typedef*>& get_typedefs() const { return typedefs_; }
- const std::vector<t_enum*>& get_enums() const { return enums_; }
- const std::vector<t_struct*>& get_structs() const { return structs_; }
- const std::vector<t_service*>& get_services() const { return services_; }
+ const std::vector<t_typedef*>& get_typedefs() const { return typedefs_; }
+ const std::vector<t_enum*>& get_enums() const { return enums_; }
+ const std::vector<t_struct*>& get_structs() const { return structs_; }
+ const std::vector<t_struct*>& get_xceptions() const { return xceptions_; }
+ const std::vector<t_service*>& get_services() const { return services_; }
// Accessors for global types
t_type* get_void_type() const { return type_void; }
t_type* get_string_type() const { return type_string; }
t_type* get_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_u32_type() const { return type_u32; }
t_type* get_i64_type() const { return type_i64; }
- t_type* get_u64_type() const { return type_u64; }
// Custom data type lookup
- void add_custom_type(std::string name, t_type* type) {
- custom_types_[name] = type;
- }
t_type* get_custom_type(std::string name) {
return custom_types_[name];
}
// New program element addition
+ 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);
@@ -86,19 +89,32 @@
structs_.push_back(ts);
add_custom_type(ts->get_name(), ts);
}
+ void add_xception(t_struct* tx) {
+ xceptions_.push_back(tx);
+ add_custom_type(tx->get_name(), tx);
+ }
void add_service(t_service* ts) {
services_.push_back(ts);
}
private:
+ // Add custom type for lookup
+ void add_custom_type(std::string name, t_type* type) {
+ custom_types_[name] = type;
+ }
+
// Name
std::string name_;
+ // Namespace
+ std::string namespace_;
+
// Components
- std::vector<t_typedef*> typedefs_;
- std::vector<t_enum*> enums_;
- std::vector<t_struct*> structs_;
- std::vector<t_service*> services_;
+ std::vector<t_typedef*> typedefs_;
+ std::vector<t_enum*> enums_;
+ std::vector<t_struct*> structs_;
+ std::vector<t_struct*> xceptions_;
+ std::vector<t_service*> services_;
// Type map
std::map<std::string, t_type*> custom_types_;
@@ -107,10 +123,9 @@
t_type* type_void;
t_type* type_string;
t_type* type_byte;
+ t_type* type_i16;
t_type* type_i32;
- t_type* type_u32;
t_type* type_i64;
- t_type* type_u64;
};
#endif
diff --git a/compiler/cpp/src/parse/t_struct.h b/compiler/cpp/src/parse/t_struct.h
index 6e87c8c..a365cd4 100644
--- a/compiler/cpp/src/parse/t_struct.h
+++ b/compiler/cpp/src/parse/t_struct.h
@@ -9,22 +9,41 @@
class t_struct : public t_type {
public:
- t_struct() {}
- t_struct(const std::string& name) : t_type(name) {}
+ t_struct() : is_xception_(false) {}
+ t_struct(const std::string& name) : t_type(name), is_xception_(false) {}
~t_struct() {}
/** Set the struct name */
- void set_name(const std::string& name) { name_ = name; }
+ void set_name(const std::string& name) {
+ name_ = name;
+ }
+
+ /** Mark as an exception */
+ void set_xception(bool is_xception) {
+ is_xception_ = is_xception;
+ }
/** Add a new field to the list */
- void append(t_field* elem) { members_.push_back(elem); }
+ void append(t_field* elem) {
+ members_.push_back(elem);
+ }
- const std::vector<t_field*>& get_members() { return members_; }
- bool is_struct() const { return true; }
+ const std::vector<t_field*>& get_members() {
+ return members_;
+ }
+
+ bool is_struct() const {
+ return !is_xception_;
+ }
+
+ bool is_xception() const {
+ return is_xception_;
+ }
private:
std::vector<t_field*> members_;
+ bool is_xception_;
};
#endif
diff --git a/compiler/cpp/src/parse/t_type.h b/compiler/cpp/src/parse/t_type.h
index 6703bfa..6328961 100644
--- a/compiler/cpp/src/parse/t_type.h
+++ b/compiler/cpp/src/parse/t_type.h
@@ -19,6 +19,7 @@
virtual bool is_typedef() const { return false; }
virtual bool is_enum() const { return false; }
virtual bool is_struct() const { return false; }
+ virtual bool is_xception() const { return false; }
virtual bool is_list() const { return false; }
virtual bool is_set() const { return false; }
virtual bool is_map() const { return false; }
diff --git a/compiler/cpp/src/thrift.l b/compiler/cpp/src/thrift.l
index 9d2944a..1f4d7fe 100644
--- a/compiler/cpp/src/thrift.l
+++ b/compiler/cpp/src/thrift.l
@@ -19,7 +19,7 @@
/** Helper definitions */
intconstant ([0-9]+)
-identifier ([a-zA-Z_][a-zA-Z_0-9]*)
+identifier ([a-zA-Z_][\.a-zA-Z_0-9]*)
whitespace ([ \t\r\n]*)
multicomm ("/*""/"*([^*/]|[^*]"/"|"*"[^/])*"*"*"*/")
comment ("//"[^\n]*)
@@ -31,15 +31,17 @@
{multicomm} { /* do nothing */ }
{comment} { /* do nothing */ }
-{symbol} { return yytext[0]; }
+{symbol} { return yytext[0]; }
+
+"namespace" { return tok_namespace; }
"void" { return tok_void; }
"byte" { return tok_byte; }
-"string" { return tok_string; }
+"i16" { return tok_i16; }
"i32" { return tok_i32; }
-"u32" { return tok_u32; }
"i64" { return tok_i64; }
-"u64" { return tok_u64; }
+"double" { return tok_double; }
+"string" { return tok_string; }
"map" { return tok_map; }
"list" { return tok_list; }
@@ -49,11 +51,13 @@
"typedef" { return tok_typedef; }
"struct" { return tok_struct; }
+"exception" { return tok_xception; }
+"throws" { return tok_throws; }
"service" { return tok_service; }
"enum" { return tok_enum; }
-{intconstant} { yylval.iconst = atoi(yytext) ; return tok_int_constant; }
+{intconstant} { yylval.iconst = atoi(yytext); return tok_int_constant; }
{identifier} { yylval.id = strdup(yytext); return tok_identifier; }
%%
diff --git a/compiler/cpp/src/thrift.y b/compiler/cpp/src/thrift.y
index d0882ff..069d6c8 100644
--- a/compiler/cpp/src/thrift.y
+++ b/compiler/cpp/src/thrift.y
@@ -13,7 +13,7 @@
#include "globals.h"
#include "parse/t_program.h"
-int y_field_val = 0;
+int y_field_val = -1;
%}
@@ -35,13 +35,16 @@
%token<id> tok_identifier
%token<iconst> tok_int_constant
+/** Namespace */
+%token tok_namespace
+
/** Base datatypes */
%token tok_byte
%token tok_string
+%token tok_i16
%token tok_i32
-%token tok_u32
%token tok_i64
-%token tok_u64
+%token tok_double
/** Complex Types */
%token tok_map
@@ -57,6 +60,8 @@
/** Thrift actions */
%token tok_typedef
%token tok_struct
+%token tok_xception
+%token tok_throws
%token tok_service
%token tok_enum
@@ -67,18 +72,22 @@
%type<ttype> SetType
%type<ttype> ListType
+%type<id> Namespace
+
%type<ttypedef> Typedef
%type<ttype> DefinitionType
%type<tfield> Field
%type<ttype> FieldType
%type<tstruct> FieldList
+%type<tstruct> ThrowsOptional
%type<tenum> Enum
%type<tenum> EnumDefList
%type<tconstant> EnumDef
%type<tstruct> Struct
+%type<tstruct> Xception
%type<tservice> Service
@@ -109,7 +118,12 @@
}
Definition:
- Typedef
+ Namespace
+ {
+ pdebug("Definition -> Namespace");
+ g_program->set_namespace($1);
+ }
+| Typedef
{
pdebug("Definition -> Typedef");
g_program->add_typedef($1);
@@ -124,11 +138,23 @@
pdebug("Definition -> Struct");
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;
+ }
Typedef:
tok_typedef DefinitionType tok_identifier
@@ -187,7 +213,17 @@
pdebug("Struct -> tok_struct tok_identifier { FieldList }");
$4->set_name($2);
$$ = $4;
- y_field_val = 0;
+ y_field_val = -1;
+ }
+
+Xception:
+ tok_xception tok_identifier '{' FieldList '}'
+ {
+ pdebug("Xception -> tok_xception tok_identifier { FieldList }");
+ $4->set_name($2);
+ $4->set_xception(true);
+ $$ = $4;
+ y_field_val = -1;
}
Service:
@@ -199,7 +235,7 @@
}
FunctionList:
- FunctionList Function
+ FunctionList Function CommaOptional
{
pdebug("FunctionList -> FunctionList Function");
$$ = $1;
@@ -211,12 +247,18 @@
$$ = new t_service;
}
+CommaOptional:
+ ','
+ {}
+|
+ {}
+
Function:
- FunctionType AsyncOptional tok_identifier '(' FieldList ')'
+ FunctionType AsyncOptional tok_identifier '(' FieldList ')' ThrowsOptional
{
$5->set_name(std::string($3) + "_args");
- $$ = new t_function($1, $3, $5, $2);
- y_field_val = 0;
+ $$ = new t_function($1, $3, $5, $7, $2);
+ y_field_val = -1;
}
AsyncOptional:
@@ -229,6 +271,16 @@
$$ = false;
}
+ThrowsOptional:
+ tok_throws '(' FieldList ')'
+ {
+ $$ = $3;
+ }
+|
+ {
+ $$ = new t_struct;
+ }
+
FieldList:
FieldList ',' Field
{
@@ -252,18 +304,17 @@
FieldType tok_identifier '=' tok_int_constant
{
pdebug("Field -> FieldType tok_identifier = tok_int_constant");
- if ($4 < 0) {
- yyerror("Negative value (%d) not allowed as a field key.", $4);
- exit(1);
+ 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--;
}
- $$ = new t_field($1, $2, (uint32_t)$4);
- y_field_val = $4+1;
+ $$ = new t_field($1, $2, $4);
}
| 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);
- $$ = new t_field($1, $2, y_field_val++);
+ printf("WARNING (%d): No field key specified for '%s', resulting protocol may have conflicts or not be backwards compatible!\n", yylineno, $2);
+ $$ = new t_field($1, $2, y_field_val--);
}
DefinitionType:
@@ -322,26 +373,21 @@
pdebug("BaseType -> tok_byte");
$$ = g_program->get_byte_type();
}
+| tok_i16
+ {
+ pdebug("BaseType -> tok_i16");
+ $$ = g_program->get_i16_type();
+ }
| tok_i32
{
pdebug("BaseType -> tok_i32");
$$ = g_program->get_i32_type();
}
-| tok_u32
- {
- pdebug("BaseType -> tok_u32");
- $$ = g_program->get_u32_type();
- }
| tok_i64
{
pdebug("BaseType -> tok_i64");
$$ = g_program->get_i64_type();
}
-| tok_u64
- {
- pdebug("BaseType -> tok_u64");
- $$ = g_program->get_u64_type();
- }
ContainerType:
MapType
diff --git a/compiler/py/setup.py b/compiler/py/setup.py
index 3901042..7167181 100644
--- a/compiler/py/setup.py
+++ b/compiler/py/setup.py
@@ -1,12 +1,12 @@
from distutils.core import setup
-setup(name='Thrift',
- version='1.0',
- description='Thrift IDL compiler',
- author =['Mark Slee', 'Marc Kwiatkowski'],
- author_email= ['mcslee@facebook.com', 'marc@facebook.com'],
- url='http://code.facebook.com/thrift',
- package_dir={'thrift' : 'src'},
+setup(name = 'Thrift',
+ version = '1.0',
+ description = 'Thrift IDL compiler',
+ author = ['Mark Slee', 'Marc Kwiatkowski'],
+ author_email = ['mcslee@facebook.com', 'marc@facebook.com'],
+ url = 'http://code.facebook.com/thrift',
+ package_dir = {'thrift' : 'src'},
py_modules = ['thrift.parser', 'thrift.cpp_generator', 'thrift.generator', 'thrift.php_generator'],
scripts = ['src/thrift']
)