Rev 2 of Thrift, the Pillar successor
Summary: End-to-end communications and serialization in C++ is working
Reviewed By: aditya
Test Plan: See the new top-level test/ folder. It vaguely resembles a unit test, though it could be more automated.
Revert Plan: Revertible
Notes: Still a LOT of optimization work to be done on the generated C++ code, which should be using dynamic memory in a number of places. Next major task is writing the PHP/Java/Python generators.
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@664712 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/compiler/src/generate/t_cpp_generator.cc b/compiler/src/generate/t_cpp_generator.cc
index b328a1a..e47c13b 100644
--- a/compiler/src/generate/t_cpp_generator.cc
+++ b/compiler/src/generate/t_cpp_generator.cc
@@ -1,4 +1,6 @@
+#include <stdlib.h>
#include <sys/stat.h>
+#include <sstream>
#include "t_cpp_generator.h"
#include "globals.h"
using namespace std;
@@ -14,7 +16,7 @@
mkdir(T_CPP_DIR, S_IREAD | S_IWRITE | S_IEXEC);
// Make output file
- string f_types_name = string(T_CPP_DIR)+"/"+tprogram->get_name()+"_types.h";
+ string f_types_name = string(T_CPP_DIR)+"/"+program_name_+"Types.h";
f_types_.open(f_types_name.c_str());
// Print header
@@ -23,13 +25,13 @@
// Start ifndef
f_types_ <<
- "#ifndef thrift_" << tprogram->get_name() << "_types_h" << endl <<
- "#define thrift_" << tprogram->get_name() << "_types_h" << endl <<
+ "#ifndef " << program_name_ << "_TYPES_H" << endl <<
+ "#define " << program_name_ << "_TYPES_H" << endl <<
endl;
// Include base types
f_types_ <<
- "#include <sys/types.h>" << endl <<
+ "#include \"Thrift.h\"" << endl <<
endl;
}
@@ -109,13 +111,11 @@
indent_up();
- const t_list* memberlist = tstruct->get_members();
- vector<t_field*> members = memberlist->elems();
- vector<t_field*>::iterator m_iter;
+ const vector<t_field*>& members = tstruct->get_members();
+ vector<t_field*>::const_iterator m_iter;
for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
- f_types_ <<
- indent() << (*m_iter)->get_type()->get_name() << " " <<
- (*m_iter)->get_name() << ";" << endl;
+ indent(f_types_) <<
+ declare_field(*m_iter) << endl;
}
indent_down();
@@ -135,24 +135,24 @@
*/
void t_cpp_generator::generate_service(t_service* tservice) {
// Make output files
- string f_header_name = string(T_CPP_DIR)+"/"+tservice->get_name()+".h";
+ 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)+"/"+tservice->get_name()+".cc";
+ 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 " << tservice->get_name() << "_h" << endl <<
- "#define " << tservice->get_name() << "_h" << endl <<
+ "#ifndef " << service_name_ << "_H" << endl <<
+ "#define " << service_name_ << "_H" << endl <<
endl <<
- "#include \"TInterface.h\"" << endl <<
"#include \"TDispatcher.h\"" << endl <<
- "#include \"TProtocol.h\"" << endl <<
+ "#include \"protocol/TProtocol.h\"" << endl <<
+ "#include \"" << program_name_ << "Types.h\"" << endl <<
endl;
f_service_ << autogen_comment();
f_service_ <<
- "#include \"" << tservice->get_name() << "_h\"" << endl << endl;
+ "#include \"" << service_name_ << ".h\"" << endl << endl;
// Generate the three main parts of the service
generate_service_interface(tservice);
@@ -174,7 +174,7 @@
*/
void t_cpp_generator::generate_service_interface(t_service* tservice) {
f_header_ <<
- "class " << tservice->get_name() << " : public TInterface {" << endl <<
+ "class " << service_name_ << "If {" << endl <<
" public: " << endl;
indent_up();
vector<t_function*> functions = tservice->get_functions();
@@ -184,13 +184,85 @@
indent() << "virtual " << function_signature(*f_iter) << " = 0;" << endl;
}
f_header_ <<
- indent() << "virtual ~" << tservice->get_name() << "() = 0;" << endl;
+ indent() << "virtual ~" << service_name_ << "If() {}" << endl;
indent_down();
f_header_ <<
"}; " << endl << endl;
}
/**
+ * Generates a service client definition.
+ *
+ * @param tservice The service to generate a server for.
+ */
+void t_cpp_generator::generate_service_client(t_service* tservice) {
+ // Generate the header portion
+ f_header_ <<
+ "class " << service_name_ << "Client : " <<
+ "public " << service_name_ << "If {" << endl <<
+ " public:" << endl;
+ indent_up();
+ f_header_ <<
+ indent() << service_name_ << "Client" <<
+ "(TDispatcher* dispatcher, TProtocol* protocol) : " <<
+ "_dispatcher(dispatcher), _protocol(protocol) {}" << endl;
+ vector<t_function*> functions = tservice->get_functions();
+ vector<t_function*>::iterator f_iter;
+ for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+ f_header_ <<
+ indent() << function_signature(*f_iter) << ";" << endl;
+ }
+ indent_down();
+
+ f_header_ <<
+ " protected:" << endl;
+ indent_up();
+ f_header_ <<
+ indent() << "TDispatcher* _dispatcher;" << endl <<
+ indent() << "TProtocol* _protocol;" << endl;
+ indent_down();
+ f_header_ <<
+ "};" << endl <<
+ endl;
+
+ // Generate client method implementations
+ for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+ string prefix = service_name_ + "Client::";
+ f_service_ <<
+ function_signature(*f_iter, prefix) << " {" << endl;
+ indent_up();
+
+ indent(f_service_) <<
+ "std::string _argbuf = \"\";" << endl;
+ generate_serialize_struct("_argbuf", (*f_iter)->get_arglist());
+ indent(f_service_) <<
+ "std::string _sbuf = _protocol->writeFunction(\"" <<
+ (*f_iter)->get_name() << "\", _argbuf);" << endl;
+ indent(f_service_) <<
+ "std::string _rbuf = _dispatcher->dispatch(_sbuf);" << endl;
+
+ if (!(*f_iter)->get_returntype()->is_void()) {
+ indent(f_service_) <<
+ "TBuf _tbuf((uint8_t*)_rbuf.data(), _rbuf.size());" << endl;
+ indent(f_service_) <<
+ type_name((*f_iter)->get_returntype()) << " _result;" << endl;
+ t_field result_field((*f_iter)->get_returntype(), "_result", 0);
+ generate_deserialize_field("_tbuf", &result_field);
+ indent(f_service_) <<
+ "return _result;" << endl;
+ } else {
+ indent(f_service_) <<
+ "return;" << endl;
+ }
+
+ indent_down();
+ f_service_ <<
+ "}" << endl <<
+ endl;
+ }
+}
+
+/**
* Generates a service server definition.
*
* @param tservice The service to generate a server for.
@@ -198,16 +270,24 @@
void t_cpp_generator::generate_service_server(t_service* tservice) {
// Generate the header portion
f_header_ <<
- "class " << tservice->get_name() << "Server : " <<
- "public " << tservice->get_name() << ", " <<
+ "class " << service_name_ << "ServerIf : " <<
+ "public " << service_name_ << "If, " <<
"public TDispatcher {" << endl <<
" public: " << endl;
indent_up();
f_header_ <<
- indent() << "std::string dispatch(const std::string& buff);" << endl <<
- indent() << "virtual ~" << tservice->get_name() << "Server();" << endl;
+ indent() << service_name_ << "ServerIf(TProtocol* protocol) : " <<
+ "_protocol(protocol) {}" << endl <<
+ indent() << "std::string dispatch(const std::string& _in);" << endl <<
+ indent() << "virtual ~" << service_name_ << "ServerIf() {}" << endl;
indent_down();
f_header_ <<
+ " protected:" << endl;
+ indent_up();
+ f_header_ <<
+ indent() << "TProtocol* _protocol;" << endl;
+ indent_down();
+ f_header_ <<
"};" << endl << endl;
// Generate the dispatch methods
@@ -216,6 +296,54 @@
for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
generate_dispatch_function(tservice, *f_iter);
}
+
+ // Generate the server implementation
+ f_service_ <<
+ "std::string " << service_name_ << "ServerIf::" <<
+ "dispatch(const std::string& _in) {" << endl;
+ indent_up();
+
+ f_service_ <<
+ indent() << "TBuf _tbuf((uint8_t*)_in.data(), _in.size());" << endl <<
+ indent() << "std::string _fname = " <<
+ "_protocol->readFunction(_tbuf);" << endl <<
+ indent() << "std::string _result;" << endl;
+
+ bool first = true;
+ for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+ if (!first) {
+ f_service_ << " else ";
+ } else {
+ f_service_ << indent();
+ first = false;
+ }
+ f_service_ <<
+ "if (_fname.compare(\"" << (*f_iter)->get_name() <<"\") == 0) {" << endl;
+ indent_up();
+ indent(f_service_) <<
+ "_result = dispatch_" << (*f_iter)->get_name() <<
+ "(_tbuf, this, _protocol);" << endl;
+ indent_down();
+ indent(f_service_) << "}";
+ }
+ indent(f_service_) <<
+ " else {" << endl;
+ indent_up();
+ f_service_ <<
+ indent() << "fprintf(stderr, \"Unknown function: '%s'\\n\", " <<
+ "_fname.c_str());" << endl <<
+ indent() << "_result = \"\";" << endl;
+ indent_down();
+ indent(f_service_) <<
+ "}" << endl;
+
+ indent(f_service_) <<
+ "return _result;" << endl;
+
+ indent_down();
+ f_service_ <<
+ "}" << endl <<
+ endl;
}
/**
@@ -227,22 +355,32 @@
t_function* tfunction) {
f_service_ <<
"std::string dispatch_" << tfunction->get_name() <<
- "(const char *_tbuf, " <<
- tservice->get_name() << " *dispatcher, " <<
- "TProtocol *protocol) {" << endl;
+ "(TBuf _tbuf, " <<
+ service_name_ << "If *_dispatcher, " <<
+ "const TProtocol *_protocol) {" << endl;
indent_up();
- // Create a field to represent this function's arguments
- t_field arg_field(tfunction->get_arglist(), "_targs", 0);
+ // Get the struct of function call params
+ t_struct* arg_struct = tfunction->get_arglist();
- generate_deserialize_struct(&arg_field);
+ // 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;
+ }
+ // Deserialize the function arguments as a struct
+ generate_deserialize_struct("_tbuf", arg_struct);
+
// Generate the function call
- indent(f_service_) <<
- type_name(tfunction->get_returntype()) << " _tresult = dispatcher." <<
- tfunction->get_name() << "(";
- vector<t_field*> fields = tfunction->get_arglist()->get_members()->elems();
- vector<t_field*>::iterator f_iter;
+ f_service_ << indent();
+ if (!tfunction->get_returntype()->is_void()) {
+ f_service_ << type_name(tfunction->get_returntype()) << " _result = ";
+ }
+ f_service_ <<
+ "_dispatcher->" << tfunction->get_name() << "(";
bool first = true;
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
if (first) {
@@ -250,16 +388,21 @@
} else {
f_service_ << ", ";
}
- f_service_ << "_targs." << (*f_iter)->get_name();
+ f_service_ << (*f_iter)->get_name();
}
f_service_ << ");" << endl;
- // Serialize the result
+ // Serialize the result into _sbuf
indent(f_service_) <<
- "std::string _tout = "";" << endl;
- t_field out_field(tfunction->get_returntype(), "_tout", 0);
- generate_serialize_field(&out_field);
-
+ "std::string _sbuf = \"\";" << endl;
+
+ t_field result_field(tfunction->get_returntype(), "_result", 0);
+ generate_serialize_field("_sbuf", &result_field);
+
+ // Return the serialized buffer
+ indent(f_service_) <<
+ "return _sbuf;" << endl;
+
indent_down();
f_service_ <<
"}" << endl <<
@@ -267,149 +410,390 @@
}
/**
+ * Deserializes a field of any type.
+ */
+void t_cpp_generator::generate_deserialize_field(string src,
+ t_field* tfield,
+ string prefix) {
+ t_type* type = tfield->get_type();
+ while (type->is_typedef()) {
+ type = ((t_typedef*)type)->get_type();
+ }
+
+ if (type->is_void()) {
+ return;
+ }
+
+ if (type->is_struct()) {
+ generate_deserialize_struct(src,
+ (t_struct*)(tfield->get_type()),
+ prefix + tfield->get_name() + ".");
+ } else if (type->is_container()) {
+ generate_deserialize_container(src,
+ tfield->get_type(),
+ prefix + tfield->get_name());
+ } else if (type->is_base_type() || type->is_enum()) {
+
+ indent(f_service_) <<
+ prefix << tfield->get_name() << " = ";
+ if (type->is_enum()) {
+ f_service_ << "(" << type_name(type) << ")";
+ }
+ f_service_ <<
+ "_protocol->";
+
+ if (type->is_base_type()) {
+ t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+ switch (tbase) {
+ case t_base_type::TYPE_VOID:
+ throw "compiler error: cannot serialize void field in a struct: " +
+ src + ":" + tfield->get_name() + ":" + prefix;
+ break;
+ case t_base_type::TYPE_STRING:
+ f_service_ << "readString(" << src << ");";
+ break;
+ case t_base_type::TYPE_BYTE:
+ f_service_ << "readByte(" << src << ");";
+ break;
+ case t_base_type::TYPE_I32:
+ f_service_ << "readI32(" << src << ");";
+ break;
+ case t_base_type::TYPE_U32:
+ f_service_ << "readU32(" << src << ");";
+ break;
+ case t_base_type::TYPE_I64:
+ f_service_ << "readI64(" << src << ");";
+ break;
+ case t_base_type::TYPE_U64:
+ f_service_ << "readU64(" << src << ");";
+ break;
+ default:
+ throw "compiler error: no C++ name for base type " + tbase;
+ }
+ } else if (type->is_enum()) {
+ f_service_ << "readI32(" << src << ");";
+ }
+
+ f_service_ <<
+ endl;
+ } else {
+ printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
+ tfield->get_name().c_str(), type_name(type).c_str());
+ }
+}
+
+/**
* Generates an unserializer for a variable. This makes two key assumptions,
* first that there is a const char* variable named data that points to the
* buffer for deserialization, and that there is a variable protocol which
* is a reference to a TProtocol serialization object.
*/
-void t_cpp_generator::generate_deserialize_struct(t_field* tfield) {
- t_struct* tstruct = (t_struct*)(tfield->get_type());
- vector<t_field*> fields = tstruct->get_members()->elems();
- vector<t_field*>::iterator f_iter;
+void t_cpp_generator::generate_deserialize_struct(string src,
+ t_struct* tstruct,
+ string prefix) {
+ const vector<t_field*>& fields = tstruct->get_members();
+ vector<t_field*>::const_iterator f_iter;
- indent(f_service_) <<
- declare_field(tfield) << endl;
- indent(f_service_) <<
- "map<uint32_t,const char*> fmap = protocol.readFieldMap(_tbuf);" << endl;
+ // Ensure that there are some fields
+ if (fields.size() == 0) {
+ return;
+ }
- // Declare the fields up front
+ scope_up(f_service_);
+
+ // Read the struct fields from the protocol
+ string _struct = tmp("_struct");
+ indent(f_service_) <<
+ "std::map<uint32_t,TBuf> " << _struct <<
+ " = _protocol->readStruct(" << src << ");" << endl;
+ indent(f_service_) <<
+ "std::map<uint32_t,TBuf>::iterator _field;" << endl;
+
+ // Decleare a temp buffer for working with fields
+ string fbuf = tmp("_fbuf");
+
+ // Iterate over the fields and extract them
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ // Check for existence of the field
indent(f_service_) <<
- declare_field(*f_iter) << endl;
- indent(f_service_) <<
- "if (fmap.find(" << tfield->get_key() << ") != fmap.end()) {" << endl;
+ "if ((_field = " << _struct << ".find(" << (*f_iter)->get_key() <<
+ ")) != " << _struct << ".end()) {" <<
+ endl;
indent_up();
+
+ // Copy the field buffer into temp buffer
indent(f_service_) <<
- "_tbuf = fmap[" << tfield->get_key() << "];" << endl;
- generate_deserialize_field(*f_iter);
+ "TBuf& " << fbuf << " = _field->second;" << endl;
+
+ // Deserialize from the field's buffer
+ generate_deserialize_field(fbuf, *f_iter, prefix);
+
indent_down();
indent(f_service_) <<
"}" << endl;
}
+
+ scope_down(f_service_);
}
-/**
- * Deserializes a field of any type.
- */
-void t_cpp_generator::generate_deserialize_field(t_field* tfield) {
- t_type* type = tfield->get_type();
- while (type->is_typedef()) {
- type = ((t_typedef*)type)->get_type();
- }
-
- if (type->is_struct()) {
- generate_deserialize_struct(tfield);
- }
-
- if (type->is_base_type()) {
- t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
- switch (tbase) {
- case t_base_type::TYPE_VOID:
- return;
- case t_base_type::TYPE_STRING:
- return;
- case t_base_type::TYPE_BYTE:
- return;
- case t_base_type::TYPE_I32:
- return;
- case t_base_type::TYPE_U32:
- return;
- case t_base_type::TYPE_I64:
- return;
- case t_base_type::TYPE_U64:
- return;
- default:
- throw "compiler error: no C++ name for base type " + tbase;
- }
- } else if (type->is_enum()) {
-
- }
-}
-
-/**
- * Generates a service client definition.
- *
- * @param tservice The service to generate a server for.
- */
-void t_cpp_generator::generate_service_client(t_service* tservice) {
- // Generate the header portion
- f_header_ <<
- "class " << tservice->get_name() << "Client : " <<
- "public " << tservice->get_name() << " {" << endl <<
- " public:" << endl;
+void t_cpp_generator::generate_deserialize_container(string src,
+ t_type* ttype,
+ string prefix) {
+ scope_up(f_service_);
+ string size = tmp("_size");
+ indent(f_service_) <<
+ "uint32_t " << size << " = _protocol->readU32(" << src << ");" << endl;
+
+ string i = tmp("_i");
+ indent(f_service_) <<
+ "uint32_t " << i << ";" << endl;
+ indent(f_service_) <<
+ "for (" <<
+ i << " = 0; " << i << " < " << size << "; ++" << i << ") {" << endl;
indent_up();
- f_header_ <<
- indent() << tservice->get_name() <<
- "(TDispatcher& dispatcher, TProtocol& protocol);" << endl;
- vector<t_function*> functions = tservice->get_functions();
- vector<t_function*>::iterator f_iter;
- for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
- f_header_ <<
- indent() << function_signature(*f_iter) << ";" << endl;
+
+ if (ttype->is_map()) {
+ generate_deserialize_map_element(src, (t_map*)ttype, prefix);
+ } else if (ttype->is_set()) {
+ generate_deserialize_set_element(src, (t_set*)ttype, prefix);
+ } else if (ttype->is_list()) {
+ generate_deserialize_list_element(src, (t_list*)ttype, prefix);
}
+
indent_down();
-
- f_header_ <<
- " private:" << endl;
- indent_up();
- f_header_ <<
- indent() << "TDispatcher& dispatcher;" << endl <<
- indent() << "TProtocol& protocol;" << endl;
- indent_down();
- f_header_ <<
- "};" << endl <<
- endl;
+ indent(f_service_) <<
+ "}" << endl;
+
+ scope_down(f_service_);
}
+
/**
- * Deserializes a field of any type.
+ * Generates code to deserialize a map
*/
-void t_cpp_generator::generate_serialize_field(t_field* tfield) {
+void t_cpp_generator::generate_deserialize_map_element(string src,
+ t_map* tmap,
+ string prefix) {
+ string key = tmp("_key");
+ string val = tmp("_val");
+ t_field fkey(tmap->get_key_type(), key, 0);
+ t_field fval(tmap->get_val_type(), val, 0);
+
+ indent(f_service_) <<
+ declare_field(&fkey) << endl;
+ indent(f_service_) <<
+ declare_field(&fval) << endl;
+
+ generate_deserialize_field(src, &fkey, "");
+ generate_deserialize_field(src, &fval, "");
+
+ indent(f_service_) <<
+ prefix << ".insert(std::make_pair(" << key << ", " << val << "));" << endl;
+}
+
+void t_cpp_generator::generate_deserialize_set_element(string src,
+ t_set* tset,
+ string prefix) {
+ string elem = tmp("_elem");
+ t_field felem(tset->get_elem_type(), elem, 0);
+
+ indent(f_service_) <<
+ declare_field(&felem) << endl;
+
+ generate_deserialize_field(src, &felem, "");
+
+ indent(f_service_) <<
+ prefix << ".insert(" << elem << ");" << endl;
+}
+
+void t_cpp_generator::generate_deserialize_list_element(string src,
+ t_list* tlist,
+ string prefix) {
+ string elem = tmp("_elem");
+ t_field felem(tlist->get_elem_type(), elem, 0);
+
+ indent(f_service_) <<
+ declare_field(&felem) << endl;
+
+ generate_deserialize_field(src, &felem, "");
+
+ indent(f_service_) <<
+ prefix << ".push_back(" << elem << ");" << endl;
+}
+
+
+/**
+ * Serializes a field of any type.
+ *
+ * @param tfield The field to serialize
+ * @param prefix Name to prepend to field name
+ */
+void t_cpp_generator::generate_serialize_field(string dest,
+ t_field* tfield,
+ string prefix) {
t_type* type = tfield->get_type();
while (type->is_typedef()) {
type = ((t_typedef*)type)->get_type();
}
-
- if (type->is_struct()) {
-
+
+ // Do nothing for void types
+ if (type->is_void()) {
+ return;
}
- if (type->is_base_type()) {
- t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
- switch (tbase) {
- case t_base_type::TYPE_VOID:
- return;
- case t_base_type::TYPE_STRING:
- return;
- case t_base_type::TYPE_BYTE:
- return;
- case t_base_type::TYPE_I32:
- return;
- case t_base_type::TYPE_U32:
- return;
- case t_base_type::TYPE_I64:
- return;
- case t_base_type::TYPE_U64:
- return;
- default:
- throw "compiler error: no C++ name for base type " + tbase;
- }
- } else if (type->is_enum()) {
+ if (type->is_struct()) {
+ generate_serialize_struct(dest,
+ (t_struct*)(tfield->get_type()),
+ prefix + tfield->get_name() + ".");
+ } else if (type->is_container()) {
+ generate_serialize_container(dest,
+ tfield->get_type(),
+ prefix + tfield->get_name());
+ } else if (type->is_base_type() || type->is_enum()) {
+ indent(f_service_) <<
+ dest << " += _protocol->";
+ if (type->is_base_type()) {
+ t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+ switch (tbase) {
+ case t_base_type::TYPE_VOID:
+ throw "compiler error: cannot serialize void field in a struct: " +
+ dest + ":" + tfield->get_name() + ":" + prefix;
+ break;
+ case t_base_type::TYPE_STRING:
+ f_service_ << "writeString(" << prefix << tfield->get_name() << ");";
+ break;
+ case t_base_type::TYPE_BYTE:
+ f_service_ << "writeByte(" << prefix << tfield->get_name() << ");";
+ break;
+ case t_base_type::TYPE_I32:
+ f_service_ << "writeI32(" << prefix << tfield->get_name() << ");";
+ break;
+ case t_base_type::TYPE_U32:
+ f_service_ << "writeU32(" << prefix << tfield->get_name() << ");";
+ break;
+ case t_base_type::TYPE_I64:
+ f_service_ << "writeI64(" << prefix << tfield->get_name() << ");";
+ break;
+ case t_base_type::TYPE_U64:
+ f_service_ << "writeU64(" << prefix << tfield->get_name() << ");";
+ break;
+ default:
+ throw "compiler error: no C++ name for base type " + tbase;
+ }
+ } else if (type->is_enum()) {
+ f_service_ << "writeI32(" << prefix << tfield->get_name() << ");";
+ }
+ f_service_ << endl;
+ } else {
+ printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
+ tfield->get_name().c_str(), type_name(type).c_str());
}
}
+/**
+ * Serializes all the members of a struct.
+ *
+ * @param tstruct The struct to serialize
+ * @param prefix String prefix to attach to all fields
+ */
+void t_cpp_generator::generate_serialize_struct(string dest,
+ t_struct* tstruct,
+ string prefix) {
+ const vector<t_field*>& fields = tstruct->get_members();
+ vector<t_field*>::const_iterator f_iter;
+
+ // Ensure that there are some fields
+ if (fields.size() == 0) {
+ return;
+ }
+
+ scope_up(f_service_);
+ string _struct = tmp("_struct");
+
+ indent(f_service_) <<
+ "std::map<uint32_t,std::string> " << _struct << ";" << endl;
+
+ // Serialize each of the fields into the map
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ ostringstream fdest;
+ fdest << _struct << "[" << (*f_iter)->get_key() << "]";
+ generate_serialize_field(fdest.str(), *f_iter, prefix);
+ }
+
+ // Write the struct map
+ indent(f_service_) <<
+ dest << " += _protocol->writeStruct(" << _struct << ");" << endl;
+
+ scope_down(f_service_);
+}
+
+void t_cpp_generator::generate_serialize_container(string dest,
+ t_type* ttype,
+ string prefix) {
+ scope_up(f_service_);
+
+ indent(f_service_) <<
+ dest << " += _protocol->writeU32(" << prefix << ".size());" << endl;
+
+ string iter = tmp("_iter");
+ indent(f_service_) <<
+ type_name(ttype) << "::const_iterator " << iter << ";" << endl;
+ indent(f_service_) <<
+ "for (" << iter << " = " << prefix << ".begin(); " <<
+ iter << " != " << prefix << ".end(); " <<
+ "++" << iter << ") {" << endl;
+ indent_up();
+
+ if (ttype->is_map()) {
+ generate_serialize_map_element(dest, (t_map*)ttype, iter);
+ } else if (ttype->is_set()) {
+ generate_serialize_set_element(dest, (t_set*)ttype, iter);
+ } else if (ttype->is_list()) {
+ generate_serialize_list_element(dest, (t_list*)ttype, iter);
+ }
+
+ indent_down();
+ indent(f_service_) <<
+ "}" << endl;
+
+ scope_down(f_service_);
+}
+
+/**
+ * Serializes the members of a map.
+ *
+ */
+void t_cpp_generator::generate_serialize_map_element(string dest,
+ t_map* tmap,
+ string iter) {
+ t_field kfield(tmap->get_key_type(), iter + "->first", 0);
+ generate_serialize_field(dest, &kfield, "");
+
+ t_field vfield(tmap->get_val_type(), iter + "->second", 0);
+ generate_serialize_field(dest, &vfield, "");
+}
+
+/**
+ * Serializes the members of a set.
+ */
+void t_cpp_generator::generate_serialize_set_element(string dest,
+ t_set* tset,
+ string iter) {
+ t_field efield(tset->get_elem_type(), "(*" + iter + ")", 0);
+ generate_serialize_field(dest, &efield, "");
+}
+
+/**
+ * Serializes the members of a list.
+ */
+void t_cpp_generator::generate_serialize_list_element(string dest,
+ t_list* tlist,
+ string iter) {
+ t_field efield(tlist->get_elem_type(), "(*" + iter + ")", 0);
+ generate_serialize_field(dest, &efield, "");
+}
/**
* Generates a comment about this code being autogenerated.
@@ -436,6 +820,17 @@
string t_cpp_generator::type_name(t_type* ttype) {
if (ttype->is_base_type()) {
return base_type_name(((t_base_type*)ttype)->get_base());
+ } else if (ttype->is_map()) {
+ t_map* tmap = (t_map*) ttype;
+ return "std::map<" +
+ type_name(tmap->get_key_type()) + ", " +
+ type_name(tmap->get_val_type()) + "> ";
+ } else if (ttype->is_set()) {
+ t_set* tset = (t_set*) ttype;
+ return "std::set<" + type_name(tset->get_elem_type()) + "> ";
+ } else if (ttype->is_list()) {
+ t_list* tlist = (t_list*) ttype;
+ return "std::list<" + type_name(tlist->get_elem_type()) + "> ";
} else {
return ttype->get_name();
}
@@ -472,9 +867,38 @@
*
* @param ttype The type
*/
-string t_cpp_generator::declare_field(t_field* tfield) {
+string t_cpp_generator::declare_field(t_field* tfield, bool init) {
// TODO(mcslee): do we ever need to initialize the field?
- return type_name(tfield->get_type()) + " " + tfield->get_name() + ";";
+ string result = type_name(tfield->get_type()) + " " + tfield->get_name();
+ if (init) {
+ t_type* type = tfield->get_type();
+ while (type->is_typedef()) {
+ type = ((t_typedef*)type)->get_type();
+ }
+
+ if (type->is_base_type()) {
+ t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+ switch (tbase) {
+ case t_base_type::TYPE_VOID:
+ break;
+ case t_base_type::TYPE_STRING:
+ result += " = \"\"";
+ 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;
+ default:
+ throw "compiler error: no C++ initializer for base type " + tbase;
+ }
+ } else if (type->is_enum()) {
+ result += " = (" + type_name(type) + ")0";
+ }
+ }
+ return result + ";";
}
/**
@@ -483,20 +907,22 @@
* @param tfunction Function definition
* @return String of rendered function definition
*/
-string t_cpp_generator::function_signature(t_function* tfunction) {
+string t_cpp_generator::function_signature(t_function* tfunction,
+ string prefix) {
+ t_type* ttype = tfunction->get_returntype();
return
- type_name(tfunction->get_returntype()) + " " + tfunction->get_name() +
- "(" + field_list(tfunction->get_arglist()->get_members()) + ")";
+ type_name(ttype) + " " + prefix + tfunction->get_name() +
+ "(" + argument_list(tfunction->get_arglist()) + ")";
}
/**
* Renders a field list
*/
-string t_cpp_generator::field_list(t_list* tlist) {
+string t_cpp_generator::argument_list(t_struct* tstruct) {
string result = "";
- vector<t_field*> fields = tlist->elems();
- vector<t_field*>::iterator f_iter;
+ const vector<t_field*>& fields = tstruct->get_members();
+ vector<t_field*>::const_iterator f_iter;
bool first = true;
for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
if (first) {
diff --git a/compiler/src/generate/t_cpp_generator.h b/compiler/src/generate/t_cpp_generator.h
index 87eb72a..079a26d 100644
--- a/compiler/src/generate/t_cpp_generator.h
+++ b/compiler/src/generate/t_cpp_generator.h
@@ -3,13 +3,15 @@
#include <string>
#include <fstream>
+#include <iostream>
+#include <vector>
#include "t_generator.h"
#define T_CPP_DIR "gen-cpp"
/**
- * C++ code generator
+ * C++ code generator.
*
* @author Mark Slee <mcslee@facebook.com>
*/
@@ -19,35 +21,98 @@
~t_cpp_generator() {}
/** Init and close methods */
+
void init_generator(t_program *tprogram);
void close_generator();
/** Program-level generation functions */
+
void generate_typedef (t_typedef* ttypedef);
void generate_enum (t_enum* tenum);
void generate_struct (t_struct* tstruct);
void generate_service (t_service* tservice);
/** Service-level generation functions */
+
void generate_service_interface (t_service* tservice);
- void generate_service_server (t_service* tservice);
void generate_service_client (t_service* tservice);
+ void generate_service_server (t_service* tservice);
+ void generate_dispatch_function (t_service* tservice, t_function* tfunction);
/** Serialization constructs */
- void generate_dispatch_function (t_service* tservice, t_function* tfunction);
- void generate_deserialize_struct(t_field* tfield);
- void generate_deserialize_field(t_field* tfield);
+
+ void generate_deserialize_field (std::string src,
+ t_field* tfield,
+ std::string prefix="");
+
+ void generate_deserialize_struct (std::string src,
+ t_struct* tstruct,
+ std::string prefix="");
+
+ void generate_deserialize_container (std::string src,
+ t_type* ttype,
+ std::string prefix="");
+
+ void generate_deserialize_set_element (std::string src,
+ t_set* tset,
+ std::string prefix="");
+
+ void generate_deserialize_map_element (std::string src,
+ t_map* tmap,
+ std::string prefix="");
+
+ void generate_deserialize_list_element (std::string src,
+ t_list* tlist,
+ std::string prefix="");
+
+ void generate_serialize_field (std::string dest,
+ t_field* tfield,
+ std::string prefix="");
+
+ void generate_serialize_struct (std::string dest,
+ t_struct* tstruct,
+ std::string prefix="");
+
+ void generate_serialize_container (std::string dest,
+ t_type* ttype,
+ std::string prefix="");
+
+ void generate_serialize_map_element (std::string dest,
+ t_map* tmap,
+ std::string iter);
+
+ void generate_serialize_set_element (std::string dest,
+ t_set* tmap,
+ std::string iter);
+
+ void generate_serialize_list_element (std::string dest,
+ t_list* tlist,
+ std::string iter);
+
+ /** Scoping */
+
+ void scope_up(std::ostream& out) {
+ indent(out) << "{" << std::endl;
+ indent_up();
+ }
+
+ void scope_down(std::ostream& out) {
+ indent_down();
+ indent(out) << "}" << std::endl;
+ }
/** Helper rendering functions */
+
std::string autogen_comment();
std::string type_name(t_type* ttype);
std::string base_type_name(t_base_type::t_base tbase);
- std::string declare_field(t_field* tfield);
- std::string function_signature(t_function* tfunction);
- std::string field_list(t_list* tlist);
+ std::string declare_field(t_field* tfield, bool init=false);
+ std::string function_signature(t_function* tfunction, std::string prefix="");
+ std::string argument_list(t_struct* tstruct);
private:
/** File streams */
+
std::ofstream f_types_;
std::ofstream f_header_;
std::ofstream f_service_;
diff --git a/compiler/src/generate/t_generator.cc b/compiler/src/generate/t_generator.cc
index 0ba44ac..d68e66d 100644
--- a/compiler/src/generate/t_generator.cc
+++ b/compiler/src/generate/t_generator.cc
@@ -9,6 +9,9 @@
* @param program The thrift program to compile into C++ source
*/
void t_generator::generate_program(t_program *tprogram) {
+ // Set program name
+ program_name_ = get_program_name(tprogram);
+
// Initialize the generator
init_generator(tprogram);
@@ -37,6 +40,7 @@
vector<t_service*> services = tprogram->get_services();
vector<t_service*>::iterator sv_iter;
for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
+ service_name_ = get_service_name(*sv_iter);
generate_service(*sv_iter);
}
diff --git a/compiler/src/generate/t_generator.h b/compiler/src/generate/t_generator.h
index 71d0318..be0b83e 100644
--- a/compiler/src/generate/t_generator.h
+++ b/compiler/src/generate/t_generator.h
@@ -3,6 +3,7 @@
#include <string>
#include <iostream>
+#include <sstream>
#include "parse/t_program.h"
/**
@@ -14,7 +15,7 @@
*/
class t_generator {
public:
- t_generator() {}
+ t_generator() { tmp_ = 0; }
virtual ~t_generator() {}
/**
@@ -26,16 +27,37 @@
protected:
/** Optional methods that may be imlemented by subclasses. */
+
virtual void init_generator (t_program* tprogram) {}
virtual void close_generator () {}
/** Pure virtual methods implemented by the generator subclasses. */
+
virtual void generate_typedef (t_typedef* ttypedef) = 0;
virtual void generate_enum (t_enum* tenum) = 0;
virtual void generate_struct (t_struct* tstruct) = 0;
virtual void generate_service (t_service* tservice) = 0;
+ /** Method to get the program name, may be overridden */
+
+ virtual std::string get_program_name(t_program* tprogram) {
+ return tprogram->get_name();
+ }
+
+ /** Method to get the service name, may be overridden */
+ virtual std::string get_service_name(t_service* tservice) {
+ return tservice->get_name();
+ }
+
+ /** Creates a unique temporary variable name. */
+ std::string tmp(std::string name) {
+ std::ostringstream out;
+ out << name << tmp_++;
+ return out.str();
+ }
+
/** Indentation level modifiers */
+
void indent_up() { ++indent_; }
void indent_down() { --indent_; }
@@ -49,15 +71,24 @@
return ind;
}
- /** Indentation wrapper */
+ /** Indentation utility wrapper */
std::ostream& indent(std::ostream &os) {
return os << indent();
}
+ protected:
+ /** Quick accessor for formatted program name */
+ std::string program_name_;
+
+ /** Quick accessor for formatted service name */
+ std::string service_name_;
+
private:
/** Indentation level */
int indent_;
+ /** Temporary variable counter */
+ int tmp_;
};
#endif
diff --git a/compiler/src/main.cc b/compiler/src/main.cc
index cc126f8..8d8263c 100644
--- a/compiler/src/main.cc
+++ b/compiler/src/main.cc
@@ -137,6 +137,7 @@
// Parse it
g_program = new t_program(name);
+
if (yyparse() != 0) {
failure("Parser error.");
}
@@ -146,6 +147,8 @@
t_cpp_generator* cpp = new t_cpp_generator();
cpp->generate_program(g_program);
delete cpp;
+ } catch (string s) {
+ printf("Error: %s\n", s.c_str());
} catch (const char* exc) {
printf("Error: %s\n", exc);
}
diff --git a/compiler/src/parse/t_base_type.h b/compiler/src/parse/t_base_type.h
index bc96122..f6cc197 100644
--- a/compiler/src/parse/t_base_type.h
+++ b/compiler/src/parse/t_base_type.h
@@ -25,6 +25,7 @@
t_type(name), base_(base) {}
t_base get_base() const { return base_; }
+ bool is_void() const { return base_ == TYPE_VOID; }
bool is_base_type() const { return true; }
private:
diff --git a/compiler/src/parse/t_list.h b/compiler/src/parse/t_list.h
index 736ac48..65874cc 100644
--- a/compiler/src/parse/t_list.h
+++ b/compiler/src/parse/t_list.h
@@ -1,27 +1,19 @@
#ifndef T_LIST_H
#define T_LIST_H
-#include "t_field.h"
-#include <vector>
+#include "t_type.h"
-/**
- * List of elements.
- *
- * @author Mark Slee <mcslee@facebook.com>
- */
-class t_list {
+class t_list : public t_type {
public:
- t_list() {}
+ t_list(t_type* elem_type) : elem_type_(elem_type) {}
~t_list() {}
- /** Add a new field to the list */
- void append(t_field* elem) { list_.push_back(elem); }
-
- /** Retrieve the list contents */
- const std::vector<t_field*>& elems() const { return list_; }
+ t_type* get_elem_type() const { return elem_type_; }
+ bool is_list() const { return true; }
private:
- std::vector<t_field*> list_;
+ t_type* elem_type_;
};
#endif
+
diff --git a/compiler/src/parse/t_map.h b/compiler/src/parse/t_map.h
new file mode 100644
index 0000000..1f61843
--- /dev/null
+++ b/compiler/src/parse/t_map.h
@@ -0,0 +1,19 @@
+#ifndef T_MAP_H
+#define T_MAP_H
+
+class t_map : public t_type {
+ public:
+ t_map(t_type* key_type, t_type* val_type) :
+ key_type_(key_type), val_type_(val_type) {}
+ ~t_map() {}
+
+ t_type* get_key_type() const { return key_type_; }
+ t_type* get_val_type() const { return val_type_; }
+ bool is_map() const { return true; }
+
+ private:
+ t_type* key_type_;
+ t_type* val_type_;
+};
+
+#endif
diff --git a/compiler/src/parse/t_program.h b/compiler/src/parse/t_program.h
index fd35799..cda24c6 100644
--- a/compiler/src/parse/t_program.h
+++ b/compiler/src/parse/t_program.h
@@ -1,6 +1,7 @@
#ifndef T_PROGRAM_H
#define T_PROGRAM_H
+#include <map>
#include <string>
#include <vector>
@@ -9,6 +10,9 @@
#include "t_enum.h"
#include "t_struct.h"
#include "t_service.h"
+#include "t_list.h"
+#include "t_map.h"
+#include "t_set.h"
/**
* Top level class representing an entire thrift program. A program consists
@@ -52,12 +56,6 @@
const std::vector<t_struct*>& get_structs() const { return structs_; }
const std::vector<t_service*>& get_services() const { return services_; }
- // New program element addition
- void add_typedef(t_typedef *td) { typedefs_.push_back(td); }
- void add_enum (t_enum *te) { enums_.push_back(te); }
- void add_struct (t_struct *ts) { structs_.push_back(ts); }
- void add_service(t_service *ts) { services_.push_back(ts); }
-
// Accessors for global types
t_type* get_void_type() const { return type_void; }
t_type* get_string_type() const { return type_string; }
@@ -67,6 +65,31 @@
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 add_typedef(t_typedef* td) {
+ typedefs_.push_back(td);
+ add_custom_type(td->get_symbolic(), td);
+ }
+ void add_enum(t_enum* te) {
+ enums_.push_back(te);
+ add_custom_type(te->get_name(), te);
+ }
+ void add_struct(t_struct* ts) {
+ structs_.push_back(ts);
+ add_custom_type(ts->get_name(), ts);
+ }
+ void add_service(t_service* ts) {
+ services_.push_back(ts);
+ }
+
private:
// Name
std::string name_;
@@ -76,7 +99,10 @@
std::vector<t_enum*> enums_;
std::vector<t_struct*> structs_;
std::vector<t_service*> services_;
-
+
+ // Type map
+ std::map<std::string, t_type*> custom_types_;
+
// Global base types
t_type* type_void;
t_type* type_string;
diff --git a/compiler/src/parse/t_set.h b/compiler/src/parse/t_set.h
new file mode 100644
index 0000000..3d34ace
--- /dev/null
+++ b/compiler/src/parse/t_set.h
@@ -0,0 +1,18 @@
+#ifndef T_SET_H
+#define T_SET_H
+
+#include "t_type.h"
+
+class t_set : public t_type {
+ public:
+ t_set(t_type* elem_type) : elem_type_(elem_type) {}
+ ~t_set() {}
+
+ t_type* get_elem_type() const { return elem_type_; }
+ bool is_set() const { return true; }
+
+ private:
+ t_type* elem_type_;
+};
+
+#endif
diff --git a/compiler/src/parse/t_struct.h b/compiler/src/parse/t_struct.h
index fcc00e7..38eb750 100644
--- a/compiler/src/parse/t_struct.h
+++ b/compiler/src/parse/t_struct.h
@@ -5,19 +5,24 @@
#include <string>
#include "t_type.h"
-#include "t_list.h"
+#include "t_field.h"
class t_struct : public t_type {
public:
- t_struct(std::string name, t_list* members) :
- t_type(name), members_(members) {}
+ t_struct() {}
~t_struct() {}
- t_list* get_members() { return members_; }
- bool is_struct() { return true; }
+ /** Set the struct name */
+ void set_name(const std::string& name) { name_ = name; }
+
+ /** Add a new field to the list */
+ void append(t_field* elem) { members_.push_back(elem); }
+
+ const std::vector<t_field*>& get_members() { return members_; }
+ bool is_struct() const { return true; }
private:
- t_list* members_;
+ std::vector<t_field*> members_;
};
#endif
diff --git a/compiler/src/parse/t_type.h b/compiler/src/parse/t_type.h
index 436c59e..6703bfa 100644
--- a/compiler/src/parse/t_type.h
+++ b/compiler/src/parse/t_type.h
@@ -14,10 +14,16 @@
virtual const std::string& get_name() const { return name_; }
+ virtual bool is_void() const { return false; }
virtual bool is_base_type() const { return false; }
virtual bool is_typedef() const { return false; }
virtual bool is_enum() const { return false; }
virtual bool is_struct() const { return false; }
+ virtual bool is_list() const { return false; }
+ virtual bool is_set() const { return false; }
+ virtual bool is_map() const { return false; }
+
+ bool is_container() const { return is_map() || is_set() || is_list(); }
protected:
t_type() {}
diff --git a/compiler/src/thrift.l b/compiler/src/thrift.l
index 5164c89..61a0ce3 100644
--- a/compiler/src/thrift.l
+++ b/compiler/src/thrift.l
@@ -23,7 +23,7 @@
whitespace ([ \t\r\n]*)
multicomm ("/*""/"*([^*/]|[^*]"/"|"*"[^/])*"*"*"*/")
comment ("//"[^\n]*)
-symbol ([\,\{\}\(\)\=])
+symbol ([\,\{\}\(\)\=<>])
%%
diff --git a/compiler/src/thrift.y b/compiler/src/thrift.y
index f0fa3c4..a406c8e 100644
--- a/compiler/src/thrift.y
+++ b/compiler/src/thrift.y
@@ -27,7 +27,6 @@
t_service* tservice;
t_function* tfunction;
t_field* tfield;
- t_list* tlist;
t_constant* tconstant;
}
@@ -63,13 +62,17 @@
/** Types */
%type<ttype> BaseType
+%type<ttype> ContainerType
+%type<ttype> MapType
+%type<ttype> SetType
+%type<ttype> ListType
%type<ttypedef> Typedef
%type<ttype> DefinitionType
%type<tfield> Field
%type<ttype> FieldType
-%type<tlist> FieldList
+%type<tstruct> FieldList
%type<tenum> Enum
%type<tenum> EnumDefList
@@ -130,7 +133,6 @@
tok_typedef DefinitionType tok_identifier
{
pdebug("TypeDef -> tok_typedef DefinitionType tok_identifier");
-
t_typedef *td = new t_typedef($2, $3);
$$ = td;
}
@@ -165,10 +167,10 @@
EnumDef:
tok_identifier '=' tok_int_constant
{
+ pdebug("EnumDef => tok_identifier = tok_int_constant");
if ($3 < 0) {
printf("WARNING (%d): Negative value supplied for enum %s.\n", yylineno, $1);
}
- pdebug("EnumDef => tok_identifier = tok_int_constant");
$$ = new t_constant($1, $3);
}
|
@@ -182,7 +184,8 @@
tok_struct tok_identifier '{' FieldList '}'
{
pdebug("Struct -> tok_struct tok_identifier { FieldList }");
- $$ = new t_struct($2, $4);
+ $4->set_name($2);
+ $$ = $4;
y_field_val = 0;
}
@@ -210,8 +213,7 @@
Function:
FunctionType FunctionModifiers tok_identifier '(' FieldList ')'
{
- t_struct* fun_args = new t_struct("__targs", $5);
- $$ = new t_function($1, $3, fun_args);
+ $$ = new t_function($1, $3, $5);
y_field_val = 0;
}
@@ -231,26 +233,29 @@
| Field
{
pdebug("FieldList -> Field");
- $$ = new t_list;
+ $$ = new t_struct;
$$->append($1);
}
|
{
pdebug("FieldList -> ");
- $$ = new t_list;
+ $$ = new t_struct;
}
Field:
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);
}
$$ = new t_field($1, $2, (uint32_t)$4);
y_field_val = $4+1;
}
| FieldType tok_identifier
{
+ pdebug("Field -> FieldType tok_identifier");
printf("WARNING (%d): No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", yylineno, $2);
$$ = new t_field($1, $2, y_field_val++);
}
@@ -261,25 +266,42 @@
pdebug("DefinitionType -> BaseType");
$$ = $1;
}
+| ContainerType
+ {
+ pdebug("DefinitionType -> ContainerType");
+ $$ = $1;
+ }
FunctionType:
FieldType
{
+ pdebug("FunctionType -> FieldType");
$$ = $1;
}
| tok_void
{
+ pdebug("FunctionType -> tok_void");
$$ = g_program->get_void_type();
}
FieldType:
tok_identifier
{
- /** TODO(mcslee): Dynamic type lookup */
- yyerror("No dynamic type lookup yet.");
+ pdebug("FieldType -> tok_identifier");
+ $$ = g_program->get_custom_type($1);
+ if ($$ == NULL) {
+ yyerror("Type \"%s\" has not been defined.", $1);
+ exit(1);
+ }
}
| BaseType
{
+ pdebug("FieldType -> BaseType");
+ $$ = $1;
+ }
+| ContainerType
+ {
+ pdebug("FieldType -> ContainerType");
$$ = $1;
}
@@ -315,4 +337,42 @@
$$ = g_program->get_u64_type();
}
+ContainerType:
+ MapType
+ {
+ pdebug("ContainerType -> MapType");
+ $$ = $1;
+ }
+| SetType
+ {
+ pdebug("ContainerType -> SetType");
+ $$ = $1;
+ }
+| ListType
+ {
+ pdebug("ContainerType -> ListType");
+ $$ = $1;
+ }
+
+MapType:
+ tok_map '<' FieldType ',' FieldType '>'
+ {
+ pdebug("MapType -> tok_map <FieldType, FieldType>");
+ $$ = new t_map($3, $5);
+ }
+
+SetType:
+ tok_set '<' FieldType '>'
+ {
+ pdebug("SetType -> tok_set<FieldType>");
+ $$ = new t_set($3);
+ }
+
+ListType:
+ tok_list '<' FieldType '>'
+ {
+ pdebug("ListType -> tok_list<FieldType>");
+ $$ = new t_list($3);
+ }
+
%%