You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@thrift.apache.org by je...@apache.org on 2013/06/18 22:29:13 UTC
[09/10] THRIFT-2012 Modernizing Go
http://git-wip-us.apache.org/repos/asf/thrift/blob/0e87c46c/compiler/cpp/src/generate/t_go_generator.cc
----------------------------------------------------------------------
diff --git a/compiler/cpp/src/generate/t_go_generator.cc b/compiler/cpp/src/generate/t_go_generator.cc
index 0b9f16e..82af8a8 100644
--- a/compiler/cpp/src/generate/t_go_generator.cc
+++ b/compiler/cpp/src/generate/t_go_generator.cc
@@ -17,6 +17,14 @@
* under the License.
*/
+/*
+ * This file is programmatically sanitized for style:
+ * astyle --style=1tbs -f -p -H -j -U t_go_generator.cc
+ *
+ * The output of astyle should not be taken unquestioningly, but it is a good
+ * guide for ensuring uniformity and readability.
+ */
+
#include <string>
#include <fstream>
#include <iostream>
@@ -31,325 +39,387 @@
#include "platform.h"
#include "version.h"
-using std::map;
-using std::ofstream;
-using std::ostringstream;
-using std::string;
-using std::stringstream;
-using std::vector;
+using namespace std;
+
+/**
+ * A helper for automatically formatting the emitted Go code from the Thrift
+ * IDL per the Go style guide.
+ *
+ * Returns:
+ * - true, if the formatting process succeeded.
+ * - false, if the formatting process failed, which means the basic output was
+ * still generated.
+ */
+bool format_go_output(const string &file_path);
-static const string endl = "\n"; // avoid ostream << std::endl flushes
+const string default_thrift_import = "git.apache.org/thrift.git/lib/go/thrift";
/**
* Go code generator.
- *
*/
-class t_go_generator : public t_generator {
- public:
- t_go_generator(
- t_program* program,
- const std::map<std::string, std::string>& parsed_options,
- const std::string& option_string)
- : t_generator(program)
- {
- (void) parsed_options;
- (void) option_string;
- std::map<std::string, std::string>::const_iterator iter;
- out_dir_base_ = "gen-go";
- }
-
- /**
- * Init and close methods
- */
-
- void init_generator();
- void close_generator();
-
- /**
- * Program-level generation functions
- */
-
- void generate_typedef (t_typedef* ttypedef);
- void generate_enum (t_enum* tenum);
- void generate_const (t_const* tconst);
- void generate_struct (t_struct* tstruct);
- void generate_xception (t_struct* txception);
- void generate_service (t_service* tservice);
-
- std::string render_const_value(t_type* type, t_const_value* value, const string& name);
-
- /**
- * Struct generation code
- */
-
- void generate_go_struct(t_struct* tstruct, bool is_exception);
- void generate_go_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false, bool is_result=false);
- void generate_go_struct_reader(std::ofstream& out, t_struct* tstruct, const string& tstruct_name, bool is_result=false);
- void generate_go_struct_writer(std::ofstream& out, t_struct* tstruct, const string& tstruct_name, bool is_result=false);
- void generate_go_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);
- void generate_service_remote (t_service* tservice);
- void generate_service_server (t_service* tservice);
- void generate_process_function (t_service* tservice, t_function* tfunction);
-
- /**
- * Serialization constructs
- */
-
- void generate_deserialize_field (std::ofstream &out,
- t_field* tfield,
- bool declare,
- std::string prefix="",
- std::string err="err",
- bool inclass=false,
- bool coerceData=false);
+class t_go_generator : public t_generator
+{
+public:
+ t_go_generator(
+ t_program* program,
+ const std::map<std::string, std::string>& parsed_options,
+ const std::string& option_string)
+ : t_generator(program) {
+ std::map<std::string, std::string>::const_iterator iter;
+ out_dir_base_ = "gen-go";
+ gen_thrift_import_ = default_thrift_import;
+
+ iter = parsed_options.find("package_prefix");
+
+ if (iter != parsed_options.end()) {
+ gen_package_prefix_ = (iter->second);
+ }
- void generate_deserialize_struct (std::ofstream &out,
- t_struct* tstruct,
- bool declare,
- std::string prefix="",
- std::string err="err");
+ iter = parsed_options.find("thrift_import");
- void generate_deserialize_container (std::ofstream &out,
- t_type* ttype,
- bool declare,
- std::string prefix="",
- std::string err="err");
+ if (iter != parsed_options.end()) {
+ gen_thrift_import_ = (iter->second);
+ }
+ }
- void generate_deserialize_set_element (std::ofstream &out,
+ /**
+ * Init and close methods
+ */
+
+ void init_generator();
+ void close_generator();
+
+ /**
+ * Program-level generation functions
+ */
+
+ void generate_typedef(t_typedef* ttypedef);
+ void generate_enum(t_enum* tenum);
+ void generate_const(t_const* tconst);
+ void generate_struct(t_struct* tstruct);
+ void generate_xception(t_struct* txception);
+ void generate_service(t_service* tservice);
+
+ std::string render_const_value(t_type* type, t_const_value* value, const string& name);
+
+ /**
+ * Struct generation code
+ */
+
+ void generate_go_struct(t_struct* tstruct, bool is_exception);
+ void generate_go_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception = false, bool is_result = false);
+ void generate_isset_helpers(std::ofstream& out, t_struct* tstruct, const string& tstruct_name, bool is_result = false);
+ void generate_go_struct_reader(std::ofstream& out, t_struct* tstruct, const string& tstruct_name, bool is_result = false);
+ void generate_go_struct_writer(std::ofstream& out, t_struct* tstruct, const string& tstruct_name, bool is_result = false);
+ void generate_go_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);
+ void generate_service_remote(t_service* tservice);
+ void generate_service_server(t_service* tservice);
+ void generate_process_function(t_service* tservice, t_function* tfunction);
+
+ /**
+ * Serialization constructs
+ */
+
+ void generate_deserialize_field(std::ofstream &out,
+ t_field* tfield,
+ bool declare,
+ std::string prefix = "",
+ bool inclass = false,
+ bool coerceData = false);
+
+ void generate_deserialize_struct(std::ofstream &out,
+ t_struct* tstruct,
+ bool declare,
+ std::string prefix = "");
+
+ void generate_deserialize_container(std::ofstream &out,
+ t_type* ttype,
+ bool declare,
+ std::string prefix = "");
+
+ void generate_deserialize_set_element(std::ofstream &out,
t_set* tset,
bool declare,
- std::string prefix="",
- std::string err="err");
+ std::string prefix = "");
- void generate_deserialize_map_element (std::ofstream &out,
+ void generate_deserialize_map_element(std::ofstream &out,
t_map* tmap,
bool declare,
- std::string prefix="",
- std::string err="err");
+ std::string prefix = "");
+
+ void generate_deserialize_list_element(std::ofstream &out,
+ t_list* tlist,
+ bool declare,
+ std::string prefix = "");
+
+ void generate_serialize_field(std::ofstream &out,
+ t_field* tfield,
+ std::string prefix = "");
+
+ void generate_serialize_struct(std::ofstream &out,
+ t_struct* tstruct,
+ std::string prefix = "");
+
+ void generate_serialize_container(std::ofstream &out,
+ t_type* ttype,
+ std::string prefix = "");
+
+ void generate_serialize_map_element(std::ofstream &out,
+ t_map* tmap,
+ std::string kiter,
+ std::string viter);
+
+ void generate_serialize_set_element(std::ofstream &out,
+ t_set* tmap,
+ std::string iter);
+
+ void generate_serialize_list_element(std::ofstream &out,
+ t_list* tlist,
+ std::string iter);
+
+ void generate_go_docstring(std::ofstream& out,
+ t_struct* tstruct);
+
+ void generate_go_docstring(std::ofstream& out,
+ t_function* tfunction);
+
+ void generate_go_docstring(std::ofstream& out,
+ t_doc* tdoc,
+ t_struct* tstruct,
+ const char* subheader);
+
+ void generate_go_docstring(std::ofstream& out,
+ t_doc* tdoc);
+
+ /**
+ * Helper rendering functions
+ */
+
+ std::string go_autogen_comment();
+ std::string go_package();
+ std::string go_imports_begin();
+ std::string go_imports_end();
+ std::string render_includes();
+ std::string render_fastbinary_includes();
+ std::string declare_argument(t_field* tfield);
+ std::string render_field_default_value(t_field* tfield, const string& name);
+ std::string type_name(t_type* ttype);
+ std::string function_signature(t_function* tfunction, std::string prefix = "");
+ std::string function_signature_if(t_function* tfunction, std::string prefix = "", bool addError = false);
+ std::string argument_list(t_struct* tstruct);
+ std::string type_to_enum(t_type* ttype);
+ std::string type_to_go_type(t_type* ttype);
+ std::string type_to_go_key_type(t_type* ttype);
+ std::string type_to_spec_args(t_type* ttype);
+
+ static std::string get_real_go_module(const t_program* program) {
+ std::string real_module = program->get_namespace("go");
+
+ if (real_module.empty()) {
+ return program->get_name();
+ }
- void generate_deserialize_list_element (std::ofstream &out,
- t_list* tlist,
- bool declare,
- std::string prefix="",
- std::string err="err");
+ return real_module;
+ }
- void generate_serialize_field (std::ofstream &out,
- t_field* tfield,
- std::string prefix="",
- std::string err="err");
+private:
- void generate_serialize_struct (std::ofstream &out,
- t_struct* tstruct,
- std::string prefix="",
- std::string err="err");
+ std::string gen_package_prefix_;
+ std::string gen_thrift_import_;
- void generate_serialize_container (std::ofstream &out,
- t_type* ttype,
- std::string prefix="",
- std::string err="err");
+ /**
+ * File streams
+ */
- void generate_serialize_map_element (std::ofstream &out,
- t_map* tmap,
- std::string kiter,
- std::string viter,
- std::string err="err");
-
- void generate_serialize_set_element (std::ofstream &out,
- t_set* tmap,
- std::string iter,
- std::string err="err");
-
- void generate_serialize_list_element (std::ofstream &out,
- t_list* tlist,
- std::string iter,
- std::string err="err");
-
- void generate_go_docstring (std::ofstream& out,
- t_struct* tstruct);
-
- void generate_go_docstring (std::ofstream& out,
- t_function* tfunction);
-
- void generate_go_docstring (std::ofstream& out,
- t_doc* tdoc,
- t_struct* tstruct,
- const char* subheader);
-
- void generate_go_docstring (std::ofstream& out,
- t_doc* tdoc);
-
- /**
- * Helper rendering functions
- */
-
- std::string go_autogen_comment();
- std::string go_package();
- std::string go_imports();
- std::string render_includes();
- std::string render_fastbinary_includes();
- std::string declare_argument(t_field* tfield);
- std::string render_field_default_value(t_field* tfield, const string& name);
- std::string type_name(t_type* ttype);
- std::string function_signature(t_function* tfunction, std::string prefix="");
- std::string function_signature_if(t_function* tfunction, std::string prefix="", bool addOsError=false);
- std::string argument_list(t_struct* tstruct);
- std::string type_to_enum(t_type* ttype);
- std::string type_to_go_type(t_type* ttype);
- std::string type_to_spec_args(t_type* ttype);
-
- static std::string get_real_go_module(const t_program* program) {
- std::string real_module = program->get_namespace("go");
- if (real_module.empty()) {
- return program->get_name();
- }
- return real_module;
- }
-
- private:
-
- /**
- * File streams
- */
-
- std::ofstream f_types_;
- std::stringstream f_consts_;
- std::ofstream f_service_;
-
- std::string package_name_;
- std::string package_dir_;
-
- static std::string publicize(const std::string& value);
- static std::string privatize(const std::string& value);
- static std::string variable_name_to_go_name(const std::string& value);
- static bool can_be_nil(t_type* value);
+ std::ofstream f_types_;
+ std::string f_types_name_;
+ std::ofstream f_consts_;
+ std::string f_consts_name_;
+ std::stringstream f_const_values_;
+ std::ofstream f_service_;
+
+ std::string package_name_;
+ std::string package_dir_;
+
+ static std::string publicize(const std::string& value);
+ static std::string privatize(const std::string& value);
+ static std::string variable_name_to_go_name(const std::string& value);
+ static bool can_be_nil(t_type* value);
};
-std::string t_go_generator::publicize(const std::string& value) {
- if(value.size() <= 0) return value;
- std::string value2(value);
- if(!isupper(value2[0]))
- value2[0] = toupper(value2[0]);
- // as long as we are changing things, let's change _ followed by lowercase to capital
- for(string::size_type i=1; i<value2.size()-1; ++i) {
- if(value2[i] == '_' && isalpha(value2[i+1])) {
- value2.replace(i, 2, 1, toupper(value2[i+1]));
+std::string t_go_generator::publicize(const std::string& value)
+{
+ if (value.size() <= 0) {
+ return value;
+ }
+
+ std::string value2(value);
+
+ if (!isupper(value2[0])) {
+ value2[0] = toupper(value2[0]);
+ }
+
+ // as long as we are changing things, let's change _ followed by lowercase to capital
+ for (string::size_type i = 1; i < value2.size() - 1; ++i) {
+ if (value2[i] == '_' && islower(value2[i + 1])) {
+ value2.replace(i, 2, 1, toupper(value2[i + 1]));
+ }
}
- }
- return value2;
+
+ return value2;
}
-std::string t_go_generator::privatize(const std::string& value) {
- if(value.size() <= 0) return value;
- std::string value2(value);
- if(!islower(value2[0])) {
- value2[0] = tolower(value2[0]);
- }
- // as long as we are changing things, let's change _ followed by lowercase to capital
- for(string::size_type i=1; i<value2.size()-1; ++i) {
- if(value2[i] == '_' && isalpha(value2[i+1])) {
- value2.replace(i, 2, 1, toupper(value2[i+1]));
- }
- }
- return value2;
+std::string t_go_generator::privatize(const std::string& value)
+{
+ if (value.size() <= 0) {
+ return value;
+ }
+
+ std::string value2(value);
+
+ if (!islower(value2[0])) {
+ value2[0] = tolower(value2[0]);
+ }
+
+ // as long as we are changing things, let's change _ followed by lowercase to capital
+ for (string::size_type i = 1; i < value2.size() - 1; ++i) {
+ if (value2[i] == '_' && isalpha(value2[i + 1])) {
+ value2.replace(i, 2, 1, toupper(value2[i + 1]));
+ }
+ }
+
+ return value2;
}
-std::string t_go_generator::variable_name_to_go_name(const std::string& value) {
- if(value.size() <= 0) return value;
- std::string value2(value);
- std::transform(value2.begin(), value2.end(), value2.begin(), ::tolower);
- switch(value[0]) {
+std::string t_go_generator::variable_name_to_go_name(const std::string& value)
+{
+ if (value.size() <= 0) {
+ return value;
+ }
+
+ std::string value2(value);
+ std::transform(value2.begin(), value2.end(), value2.begin(), ::tolower);
+
+ switch (value[0]) {
case 'b':
case 'B':
- if(value2 != "break") {
- return value;
- }
- break;
+ if (value2 != "break") {
+ return value;
+ }
+
+ break;
+
case 'c':
case 'C':
- if(value2 != "case" && value2 != "chan" && value2 != "const" && value2 != "continue") {
- return value;
- }
- break;
+ if (value2 != "case" && value2 != "chan" && value2 != "const" && value2 != "continue") {
+ return value;
+ }
+
+ break;
+
case 'd':
case 'D':
- if(value2 != "default" && value2 != "defer") {
- return value;
- }
- break;
+ if (value2 != "default" && value2 != "defer") {
+ return value;
+ }
+
+ break;
+
case 'e':
case 'E':
- if(value2 != "else") {
- return value;
- }
- break;
+ if (value2 != "else" && value2 != "error") {
+ return value;
+ }
+
+ break;
+
case 'f':
case 'F':
- if(value2 != "fallthrough" && value2 != "for" && value2 != "func") {
- return value;
- }
- break;
+ if (value2 != "fallthrough" && value2 != "for" && value2 != "func") {
+ return value;
+ }
+
+ break;
+
case 'g':
case 'G':
- if(value2 != "go" && value2 != "goto") {
- return value;
- }
- break;
+ if (value2 != "go" && value2 != "goto") {
+ return value;
+ }
+
+ break;
+
case 'i':
case 'I':
- if(value2 != "if" && value2 != "import" && value2 != "interface") {
- return value;
- }
- break;
+ if (value2 != "if" && value2 != "import" && value2 != "interface") {
+ return value;
+ }
+
+ break;
+
case 'm':
case 'M':
- if(value2 != "map") {
- return value;
- }
- break;
+ if (value2 != "map") {
+ return value;
+ }
+
+ break;
+
case 'p':
case 'P':
- if(value2 != "package") {
- return value;
- }
- break;
+ if (value2 != "package") {
+ return value;
+ }
+
+ break;
+
case 'r':
case 'R':
- if(value2 != "range" && value2 != "return") {
- return value;
- }
- break;
+ if (value2 != "range" && value2 != "return") {
+ return value;
+ }
+
+ break;
+
case 's':
case 'S':
- if(value2 != "select" && value2 != "struct" && value2 != "switch") {
- return value;
- }
- break;
+ if (value2 != "select" && value2 != "struct" && value2 != "switch") {
+ return value;
+ }
+
+ break;
+
case 't':
case 'T':
- if(value2 != "type") {
- return value;
- }
- break;
+ if (value2 != "type") {
+ return value;
+ }
+
+ break;
+
case 'v':
case 'V':
- if(value2 != "var") {
- return value;
- }
- break;
+ if (value2 != "var") {
+ return value;
+ }
+
+ break;
+
default:
- return value;
- }
- return value2 + "_a1";
+ return value;
+ }
+
+ return value2 + "_a1";
}
@@ -359,158 +429,162 @@ std::string t_go_generator::variable_name_to_go_name(const std::string& value) {
*
* @param tprogram The program to generate
*/
-void t_go_generator::init_generator() {
- // Make output directory
- string module = get_real_go_module(program_);
- string target = module;
- package_dir_ = get_out_dir();
- while (true) {
- // TODO: Do better error checking here.
- MKDIR(package_dir_.c_str());
- if (module.empty()) {
- break;
- }
- string::size_type pos = module.find('.');
- if (pos == string::npos) {
- package_dir_ += "/";
- package_dir_ += module;
- package_name_ = module;
- module.clear();
- } else {
- package_dir_ += "/";
- package_dir_ += module.substr(0, pos);
- module.erase(0, pos+1);
- }
- }
- string::size_type loc;
- while((loc = target.find(".")) != string::npos) {
- target.replace(loc, 1, 1, '/');
- }
-
- // Make output file
- string f_types_name = package_dir_+"/"+"ttypes.go";
- f_types_.open(f_types_name.c_str());
- f_consts_ << "func init() {" << endl;
-
- vector<t_service*> services = program_->get_services();
- vector<t_service*>::iterator sv_iter;
- string f_init_name = package_dir_+"/Makefile";
- ofstream f_init;
- f_init.open(f_init_name.c_str());
- f_init <<
- endl <<
- "include $(GOROOT)/src/Make.inc" << endl << endl <<
- "all: install" << endl << endl <<
- "TARG=thriftlib/" << target << endl << endl <<
- "DIRS=\\" << endl;
- for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
- f_init << " " << (*sv_iter)->get_name() << "\\" << endl;
- }
- f_init << endl <<
- "GOFILES=\\" << endl <<
- " ttypes.go\\" << endl;
- // " constants.go\\" << endl;
- for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
- f_init << " " << (*sv_iter)->get_name() << ".go\\" << endl;
- }
- f_init << endl << endl <<
- "include $(GOROOT)/src/Make.pkg" << endl << endl;
- f_init.close();
-
- for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
- string service_dir = package_dir_+"/"+(*sv_iter)->get_name();
+void t_go_generator::init_generator()
+{
+ // Make output directory
+ string module = get_real_go_module(program_);
+ string target = module;
+ package_dir_ = get_out_dir();
+
+ while (true) {
+ // TODO: Do better error checking here.
+ MKDIR(package_dir_.c_str());
+
+ if (module.empty()) {
+ break;
+ }
+
+ string::size_type pos = module.find('.');
+
+ if (pos == string::npos) {
+ package_dir_ += "/";
+ package_dir_ += module;
+ package_name_ = module;
+ module.clear();
+ } else {
+ package_dir_ += "/";
+ package_dir_ += module.substr(0, pos);
+ module.erase(0, pos + 1);
+ }
+ }
+
+ string::size_type loc;
+
+ while ((loc = target.find(".")) != string::npos) {
+ target.replace(loc, 1, 1, '/');
+ }
+
+ // Make output files
+ f_types_name_ = package_dir_ + "/" + "ttypes.go";
+ f_types_.open(f_types_name_.c_str());
+
+ f_consts_name_ = package_dir_ + "/" + "constants.go";
+ f_consts_.open(f_consts_name_.c_str());
+
+ vector<t_service*> services = program_->get_services();
+ vector<t_service*>::iterator sv_iter;
+
+ for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
+ string service_dir = package_dir_ + "/" + underscore((*sv_iter)->get_name()) + "-remote";
#ifdef MINGW
- mkdir(service_dir.c_str());
+ mkdir(service_dir.c_str());
#else
- mkdir(service_dir.c_str(), 0755);
+ mkdir(service_dir.c_str(), 0755);
#endif
- string f_init_name = service_dir+"/Makefile";
- ofstream f_init;
- f_init.open(f_init_name.c_str());
- f_init <<
- endl <<
- "include $(GOROOT)/src/Make.inc" << endl << endl <<
- "all: install" << endl << endl <<
- "TARG=" << publicize((*sv_iter)->get_name()) << "-remote" << endl << endl <<
- "DIRS=\\" << endl << endl <<
- "GOFILES=\\" << endl <<
- " " << (*sv_iter)->get_name() << "-remote.go\\" << endl << endl <<
- "include $(GOROOT)/src/Make.cmd" << endl << endl;
- f_init.close();
- }
-
- // Print header
- f_types_ <<
- go_autogen_comment() <<
- go_package() <<
- go_imports() <<
- render_includes() <<
- render_fastbinary_includes() << endl << endl;
+ }
+
+ // Print header
+ f_types_ <<
+ go_package() <<
+ go_autogen_comment() <<
+ go_imports_begin() <<
+ render_fastbinary_includes() <<
+ go_imports_end();
+
+ f_consts_ <<
+ go_package() <<
+ go_autogen_comment();
+
+ f_const_values_ << endl << "func init() {" << endl;
+
}
/**
* Renders all the imports necessary for including another Thrift program
*/
-string t_go_generator::render_includes() {
- const vector<t_program*>& includes = program_->get_includes();
- string result = "";
- for (size_t i = 0; i < includes.size(); ++i) {
- result += "import \"thriftlib/" + get_real_go_module(includes[i]) + "\"\n";
- }
- if (includes.size() > 0) {
- result += "\n";
- }
- return result;
+string t_go_generator::render_includes()
+{
+ const vector<t_program*>& includes = program_->get_includes();
+ string result = "";
+
+ for (size_t i = 0; i < includes.size(); ++i) {
+ result += "\t\"" + gen_package_prefix_ + get_real_go_module(includes[i]) + "\"\n";
+ }
+
+ if (includes.size() > 0) {
+ result += "\n";
+ }
+
+ return result;
}
/**
* Renders all the imports necessary to use the accelerated TBinaryProtocol
*/
-string t_go_generator::render_fastbinary_includes() {
- return "";
+string t_go_generator::render_fastbinary_includes()
+{
+ return "";
}
/**
* Autogen'd comment
*/
-string t_go_generator::go_autogen_comment() {
- return
- std::string() +
- "/* Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n"
- " *\n"
- " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n"
- " */\n";
+string t_go_generator::go_autogen_comment()
+{
+ return
+ std::string() +
+ "// Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n"
+ "// DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n\n";
}
/**
* Prints standard thrift package
*/
-string t_go_generator::go_package() {
- return
- string("package ") + package_name_ + ";\n\n";
+string t_go_generator::go_package()
+{
+ return string("package ") + package_name_ + "\n\n";
+}
+
+/**
+ * Render the beginning of the import statement
+ */
+string t_go_generator::go_imports_begin()
+{
+ return
+ string("import (\n"
+ "\t\"fmt\"\n"
+ "\t\"math\"\n"
+ "\t\"" + gen_thrift_import_ + "\"\n");
}
/**
- * Prints standard thrift imports
+ * End the import statement, include undscore-assignments
+ *
+ * These "_ =" prevent the go compiler complaining about used imports.
+ * This will have to do in lieu of more intelligent import statement construction
*/
-string t_go_generator::go_imports() {
- return
- string("import (\n"
- " \"thrift\"\n"
-// " \"strings\"\n"
- " \"fmt\"\n"
- ")\n\n");
+string t_go_generator::go_imports_end()
+{
+ return
+ string(
+ ")\n\n"
+ "// (needed to ensure safety because of naive import list constrution.)\n"
+ "var _ = math.MinInt32\n\n");
}
/**
* Closes the type files
*/
-void t_go_generator::close_generator() {
- // Close types file
- f_consts_ << "}" << endl;
- f_types_ << f_consts_.str() << endl;
- f_types_.close();
- f_consts_.clear();
+void t_go_generator::close_generator()
+{
+ f_const_values_ << "}" << endl << endl;
+ f_consts_ << f_const_values_.str();
+
+ // Close types and constants files
+ f_consts_.close();
+ f_types_.close();
+ format_go_output(f_types_name_);
+ format_go_output(f_consts_name_);
}
/**
@@ -518,15 +592,18 @@ void t_go_generator::close_generator() {
*
* @param ttypedef The type definition
*/
-void t_go_generator::generate_typedef(t_typedef* ttypedef) {
-
- generate_go_docstring(f_types_, ttypedef);
- string newTypeDef(publicize(ttypedef->get_symbolic()));
- string baseType(type_to_go_type(ttypedef->get_type()));
- if(baseType == newTypeDef)
- return;
- f_types_ <<
- "type " << newTypeDef << " " << baseType << endl << endl;
+void t_go_generator::generate_typedef(t_typedef* ttypedef)
+{
+ generate_go_docstring(f_types_, ttypedef);
+ string newTypeDef(publicize(ttypedef->get_symbolic()));
+ string baseType(type_to_go_type(ttypedef->get_type()));
+
+ if (baseType == newTypeDef) {
+ return;
+ }
+
+ f_types_ <<
+ "type " << newTypeDef << " " << baseType << endl << endl;
}
/**
@@ -535,83 +612,85 @@ void t_go_generator::generate_typedef(t_typedef* ttypedef) {
*
* @param tenum The enumeration
*/
-void t_go_generator::generate_enum(t_enum* tenum) {
- std::ostringstream to_string_mapping, from_string_mapping;
- std::string tenum_name(publicize(tenum->get_name()));
-
- generate_go_docstring(f_types_, tenum);
- f_types_ <<
- "type " << tenum_name << " int" << endl <<
- "const (" << endl;
-
- to_string_mapping <<
- indent() << "func (p " << tenum_name << ") String() string {" << endl <<
- indent() << " switch p {" << endl;
- from_string_mapping <<
- indent() << "func From" << tenum_name << "String(s string) " << tenum_name << " {" << endl <<
- indent() << " switch s {" << endl;
-
- vector<t_enum_value*> constants = tenum->get_constants();
- vector<t_enum_value*>::iterator c_iter;
- int value = -1;
- for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
- if ((*c_iter)->has_value()) {
- value = (*c_iter)->get_value();
- } else {
- ++value;
- }
- string iter_std_name(escape_string((*c_iter)->get_name()));
- string iter_name((*c_iter)->get_name());
+void t_go_generator::generate_enum(t_enum* tenum)
+{
+ std::ostringstream to_string_mapping, from_string_mapping;
+ std::string tenum_name(publicize(tenum->get_name()));
+ generate_go_docstring(f_types_, tenum);
f_types_ <<
- indent() << " " << iter_name << ' ' << tenum_name << " = " << value << endl;
-
- // Dictionaries to/from string names of enums
+ "type " << tenum_name << " int64" << endl <<
+ "const (" << endl;
to_string_mapping <<
- indent() << " case " << iter_name << ": return \"" << iter_std_name << "\"" << endl;
- if(iter_std_name != escape_string(iter_name)) {
- from_string_mapping <<
- indent() << " case \"" << iter_std_name << "\", \"" << escape_string(iter_name) << "\": return " << iter_name << endl;
- } else {
- from_string_mapping <<
- indent() << " case \"" << iter_std_name << "\": return " << iter_name << endl;
- }
- }
- to_string_mapping <<
- indent() << " }" << endl <<
- indent() << " return \"\"" << endl <<
- indent() << "}" << endl;
- from_string_mapping <<
- indent() << " }" << endl <<
- indent() << " return " << tenum_name << "(-10000)" << endl <<
- indent() << "}" << endl;
-
- f_types_ <<
- indent() << ")" << endl <<
- to_string_mapping.str() << endl << from_string_mapping.str() << endl <<
- indent() << "func (p " << tenum_name << ") Value() int {" << endl <<
- indent() << " return int(p)" << endl <<
- indent() << "}" << endl << endl <<
- indent() << "func (p " << tenum_name << ") IsEnum() bool {" << endl <<
- indent() << " return true" << endl <<
- indent() << "}" << endl << endl;
+ indent() << "func (p " << tenum_name << ") String() string {" << endl <<
+ indent() << " switch p {" << endl;
+ from_string_mapping <<
+ indent() << "func " << tenum_name << "FromString(s string) (" << tenum_name << ", error) {" << endl <<
+ indent() << " switch s {" << endl;
+ vector<t_enum_value*> constants = tenum->get_constants();
+ vector<t_enum_value*>::iterator c_iter;
+ int value = -1;
+
+ for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+ if ((*c_iter)->has_value()) {
+ value = (*c_iter)->get_value();
+ } else {
+ ++value;
+ }
+
+ string iter_std_name(escape_string((*c_iter)->get_name()));
+ string iter_name((*c_iter)->get_name());
+ f_types_ <<
+ indent() << " " << tenum_name << "_" << iter_name << ' ' << tenum_name << " = " << value << endl;
+ // Dictionaries to/from string names of enums
+ to_string_mapping <<
+ indent() << " case " << tenum_name << "_" << iter_name << ": return \"" << tenum_name << "_" << iter_std_name << "\"" << endl;
+
+ if (iter_std_name != escape_string(iter_name)) {
+ from_string_mapping <<
+ indent() << " case \"" << tenum_name << "_" << iter_std_name << "\", \"" << escape_string(iter_name) << "\": return " <<
+ tenum_name << "_" << iter_name << ", nil " << endl;
+ } else {
+ from_string_mapping <<
+ indent() << " case \"" << tenum_name << "_" << iter_std_name << "\": return " <<
+ tenum_name << "_" << iter_name << ", nil " << endl;
+ }
+ }
+
+ to_string_mapping <<
+ indent() << " }" << endl <<
+ indent() << " return \"<UNSET>\"" << endl <<
+ indent() << "}" << endl;
+ from_string_mapping <<
+ indent() << " }" << endl <<
+ indent() << " return " << tenum_name << "(math.MinInt32 - 1)," <<
+ " fmt.Errorf(\"not a valid " << tenum_name << " string\")" << endl <<
+ indent() << "}" << endl;
+
+ f_types_ << ")" << endl << endl
+ << to_string_mapping.str() << endl
+ << from_string_mapping.str() << endl << endl;
+
}
+
/**
* Generate a constant value
*/
-void t_go_generator::generate_const(t_const* tconst) {
- t_type* type = tconst->get_type();
- string name = publicize(tconst->get_name());
- t_const_value* value = tconst->get_value();
-
- if(type->is_base_type() || type->is_enum()) {
- indent(f_types_) << "const " << name << " = " << render_const_value(type, value, name) << endl;
- } else {
- f_types_ <<
- indent() << "var " << name << " " << " " << type_to_go_type(type) << endl;
- f_consts_ <<
- " " << name << " = " << render_const_value(type, value, name) << endl;
- }
+void t_go_generator::generate_const(t_const* tconst)
+{
+ t_type* type = tconst->get_type();
+ string name = publicize(tconst->get_name());
+ t_const_value* value = tconst->get_value();
+
+ if (type->is_base_type() || type->is_enum()) {
+ indent(f_consts_) << "const " << name << " = " << render_const_value(type, value, name) << endl;
+ } else {
+ f_const_values_ <<
+ indent() << name << " = " << render_const_value(type, value, name) << endl << endl;
+
+ f_consts_ <<
+ indent() << "var " << name << " " << type_to_go_type(type) << endl;
+ }
}
/**
@@ -619,136 +698,150 @@ void t_go_generator::generate_const(t_const* tconst) {
* is NOT performed in this function as it is always run beforehand using the
* validate_types method in main.cc
*/
-string t_go_generator::render_const_value(t_type* type, t_const_value* value, const string& name) {
- type = get_true_type(type);
- std::ostringstream out;
-
- if (type->is_base_type()) {
- t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
- switch (tbase) {
- case t_base_type::TYPE_STRING:
- out << '"' << get_escaped_string(value) << '"';
- break;
- case t_base_type::TYPE_BOOL:
- out << (value->get_integer() > 0 ? "true" : "false");
- break;
- case t_base_type::TYPE_BYTE:
- case t_base_type::TYPE_I16:
- case t_base_type::TYPE_I32:
- case t_base_type::TYPE_I64:
- out << value->get_integer();
- break;
- case t_base_type::TYPE_DOUBLE:
- if (value->get_type() == t_const_value::CV_INTEGER) {
- out << value->get_integer();
- } else {
- out << value->get_double();
- }
- break;
- default:
- throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
- }
- } else if (type->is_enum()) {
- indent(out) << value->get_integer();
- } else if (type->is_struct() || type->is_xception()) {
- out <<
- "New" << publicize(type->get_name()) << "()" << endl <<
- indent() << "{" << endl;
- indent_up();
- const vector<t_field*>& fields = ((t_struct*)type)->get_members();
- vector<t_field*>::const_iterator f_iter;
- const map<t_const_value*, t_const_value*>& val = value->get_map();
- map<t_const_value*, t_const_value*>::const_iterator v_iter;
- for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
- t_type* field_type = NULL;
- for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
- if ((*f_iter)->get_name() == v_iter->first->get_string()) {
- field_type = (*f_iter)->get_type();
+string t_go_generator::render_const_value(t_type* type, t_const_value* value, const string& name)
+{
+ type = get_true_type(type);
+ std::ostringstream out;
+
+ if (type->is_base_type()) {
+ t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+
+ switch (tbase) {
+ case t_base_type::TYPE_STRING:
+ if (((t_base_type*)type)->is_binary()) {
+ out << "[]byte(\"" << get_escaped_string(value) << "\")";
+ } else {
+ out << '"' << get_escaped_string(value) << '"';
+ }
+
+ break;
+
+ case t_base_type::TYPE_BOOL:
+ out << (value->get_integer() > 0 ? "true" : "false");
+ break;
+
+ case t_base_type::TYPE_BYTE:
+ case t_base_type::TYPE_I16:
+ case t_base_type::TYPE_I32:
+ case t_base_type::TYPE_I64:
+ out << value->get_integer();
+ break;
+
+ case t_base_type::TYPE_DOUBLE:
+ if (value->get_type() == t_const_value::CV_INTEGER) {
+ out << value->get_integer();
+ } else {
+ out << value->get_double();
+ }
+
+ break;
+
+ default:
+ throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
}
- }
- if (field_type == NULL) {
- throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
- }
- if(field_type->is_base_type() || field_type->is_enum()) {
+ } else if (type->is_enum()) {
+ indent(out) << value->get_integer();
+ } else if (type->is_struct() || type->is_xception()) {
out <<
- indent() << name << "." << publicize(v_iter->first->get_string()) << " = " << render_const_value(field_type, v_iter->second, name) << endl;
- } else {
- string k(tmp("k"));
- string v(tmp("v"));
+ "&" << publicize(type->get_name()) << "{";
+ indent_up();
+ const vector<t_field*>& fields = ((t_struct*)type)->get_members();
+ vector<t_field*>::const_iterator f_iter;
+ const map<t_const_value*, t_const_value*>& val = value->get_map();
+ map<t_const_value*, t_const_value*>::const_iterator v_iter;
+
+ for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+ t_type* field_type = NULL;
+
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ if ((*f_iter)->get_name() == v_iter->first->get_string()) {
+ field_type = (*f_iter)->get_type();
+ }
+ }
+
+ if (field_type == NULL) {
+ throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
+ }
+
+ if (field_type->is_base_type() || field_type->is_enum()) {
+ out << endl <<
+ indent() << publicize(v_iter->first->get_string()) << ": " << render_const_value(field_type, v_iter->second, name) << ",";
+ } else {
+ string k(tmp("k"));
+ string v(tmp("v"));
+ out << endl <<
+ indent() << v << " := " << render_const_value(field_type, v_iter->second, v) << endl <<
+ indent() << name << "." << publicize(v_iter->first->get_string()) << " = " << v;
+ }
+ }
+
+ out << "}";
+
+ indent_down();
+ } else if (type->is_map()) {
+ t_type* ktype = ((t_map*)type)->get_key_type();
+ t_type* vtype = ((t_map*)type)->get_val_type();
+ const map<t_const_value*, t_const_value*>& val = value->get_map();
out <<
- indent() << v << " := " << render_const_value(field_type, v_iter->second, v) << endl <<
- indent() << name << "." << publicize(v_iter->first->get_string()) << " = " << v << endl;
- }
- }
- indent_down();
- out <<
- indent() << "}";
- } else if (type->is_map()) {
- t_type* ktype = ((t_map*)type)->get_key_type();
- t_type* vtype = ((t_map*)type)->get_val_type();
- const map<t_const_value*, t_const_value*>& val = value->get_map();
- out <<
- "thrift.NewTMap(" << type_to_enum(ktype) << ", " << type_to_enum(vtype) << ", " << val.size() << ")" << endl <<
- indent() << "{" << endl;
- indent_up();
- map<t_const_value*, t_const_value*>::const_iterator v_iter;
- for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
- string k(tmp("k"));
- string v(tmp("v"));
- out <<
- indent() << k << " := " << render_const_value(ktype, v_iter->first, k) << endl <<
- indent() << v << " := " << render_const_value(vtype, v_iter->second, v) << endl <<
- indent() << name << ".Set(" << k << ", " << v << ")" << endl;
- }
- indent_down();
- out <<
- indent() << "}" << endl;
- } else if (type->is_list()) {
- t_type* etype = ((t_list*)type)->get_elem_type();
- const vector<t_const_value*>& val = value->get_list();
- out <<
- "thrift.NewTList(" << type_to_enum(etype) << ", " << val.size() << ")" << endl <<
- indent() << "{" << endl;
- indent_up();
- vector<t_const_value*>::const_iterator v_iter;
- for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
- string v(tmp("v"));
- out <<
- indent() << v << " := " << render_const_value(etype, *v_iter, v) << endl <<
- indent() << name << ".Push(" << v << ")" << endl;
- }
- indent_down();
- out <<
- indent() << "}" << endl;
- } else if (type->is_set()) {
- t_type* etype = ((t_set*)type)->get_elem_type();
- const vector<t_const_value*>& val = value->get_list();
- out <<
- "thrift.NewTSet(" << type_to_enum(etype) << ", " << val.size() << ")" << endl <<
- indent() << "{" << endl;
- indent_up();
- vector<t_const_value*>::const_iterator v_iter;
- for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
- string v(tmp("v"));
- out <<
- indent() << v << " := " << render_const_value(etype, *v_iter, v) << endl <<
- indent() << name << ".Add(" << v << ")" << endl;
+ "map[" << type_to_go_type(ktype) << "]" << type_to_go_type(vtype) << "{" << endl;
+ indent_up();
+ map<t_const_value*, t_const_value*>::const_iterator v_iter;
+
+ for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+ out <<
+ indent() << render_const_value(ktype, v_iter->first, name) << ": " <<
+ render_const_value(vtype, v_iter->second, name) << "," << endl;
+ }
+
+ indent_down();
+ out <<
+ indent() << "}";
+ } else if (type->is_list()) {
+ t_type* etype = ((t_list*)type)->get_elem_type();
+ const vector<t_const_value*>& val = value->get_list();
+ out <<
+ "[]" << type_to_go_type(etype) << "{" << endl;
+ indent_up();
+ vector<t_const_value*>::const_iterator v_iter;
+
+ for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+ out <<
+ indent() << render_const_value(etype, *v_iter, name) << ", ";
+ }
+
+ indent_down();
+ out <<
+ indent() << "}";
+ } else if (type->is_set()) {
+ t_type* etype = ((t_set*)type)->get_elem_type();
+ const vector<t_const_value*>& val = value->get_list();
+ out <<
+ "map[" << type_to_go_key_type(etype) << "]bool{" << endl;
+ indent_up();
+ vector<t_const_value*>::const_iterator v_iter;
+
+ for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+ out <<
+ indent() << render_const_value(etype, *v_iter, name) << ": true," << endl;
+
+ }
+
+ indent_down();
+ out <<
+ indent() << "}";
+ } else {
+ throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
}
- indent_down();
- out <<
- indent() << "}" << endl;
- } else {
- throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
- }
- return out.str();
+ return out.str();
}
/**
* Generates a go struct
*/
-void t_go_generator::generate_struct(t_struct* tstruct) {
- generate_go_struct(tstruct, false);
+void t_go_generator::generate_struct(t_struct* tstruct)
+{
+ generate_go_struct(tstruct, false);
}
/**
@@ -757,16 +850,18 @@ void t_go_generator::generate_struct(t_struct* tstruct) {
*
* @param txception The struct definition
*/
-void t_go_generator::generate_xception(t_struct* txception) {
- generate_go_struct(txception, true);
+void t_go_generator::generate_xception(t_struct* txception)
+{
+ generate_go_struct(txception, true);
}
/**
* Generates a go struct
*/
void t_go_generator::generate_go_struct(t_struct* tstruct,
- bool is_exception) {
- generate_go_struct_definition(f_types_, tstruct, is_exception);
+ bool is_exception)
+{
+ generate_go_struct_definition(f_types_, tstruct, is_exception);
}
/**
@@ -775,459 +870,472 @@ void t_go_generator::generate_go_struct(t_struct* tstruct,
* @param tstruct The struct definition
*/
void t_go_generator::generate_go_struct_definition(ofstream& out,
- t_struct* tstruct,
- bool is_exception,
- bool is_result) {
-
- (void) is_exception;
- const vector<t_field*>& members = tstruct->get_members();
- const vector<t_field*>& sorted_members = tstruct->get_sorted_members();
- vector<t_field*>::const_iterator m_iter;
-
- generate_go_docstring(out, tstruct);
- std::string tstruct_name(publicize(tstruct->get_name()));
- out <<
- indent() << "type " << tstruct_name << " struct {" << endl <<
- indent() << " thrift.TStruct" << endl;
-
- /*
- Here we generate the structure specification for the fastbinary codec.
- These specifications have the following structure:
- thrift_spec -> tuple of item_spec
- item_spec -> nil | (tag, type_enum, name, spec_args, default)
- tag -> integer
- type_enum -> TType.I32 | TType.STRING | TType.STRUCT | ...
- name -> string_literal
- default -> nil # Handled by __init__
- spec_args -> nil # For simple types
- | (type_enum, spec_args) # Value type for list/set
- | (type_enum, spec_args, type_enum, spec_args)
- # Key and value for map
- | (class_name, spec_args_ptr) # For struct/exception
- class_name -> identifier # Basically a pointer to the class
- spec_args_ptr -> expression # just class_name.spec_args
-
- TODO(dreiss): Consider making this work for structs with negative tags.
- */
-
- // TODO(dreiss): Look into generating an empty tuple instead of nil
- // for structures with no members.
- // TODO(dreiss): Test encoding of structs where some inner structs
- // don't have thrift_spec.
- indent_up();
- if (sorted_members.empty() || (sorted_members[0]->get_key() >= 0)) {
- int sorted_keys_pos = 0;
- for (m_iter = sorted_members.begin(); m_iter != sorted_members.end(); ++m_iter) {
-
- for (; sorted_keys_pos != (*m_iter)->get_key(); sorted_keys_pos++) {
- if (sorted_keys_pos != 0) {
- indent(out) << "_ interface{} \"" << escape_string((*m_iter)->get_name()) << "\"; // nil # " << sorted_keys_pos << endl;
- }
- }
- t_type* fieldType = (*m_iter)->get_type();
- string goType(type_to_go_type(fieldType));
- indent(out) << publicize(variable_name_to_go_name((*m_iter)->get_name())) << " "
- << goType << " \"" << escape_string((*m_iter)->get_name())
- << "\"; // " << sorted_keys_pos
- << endl;
+ t_struct* tstruct,
+ bool is_exception,
+ bool is_result)
+{
+ const vector<t_field*>& members = tstruct->get_members();
+ const vector<t_field*>& sorted_members = tstruct->get_sorted_members();
+ vector<t_field*>::const_iterator m_iter;
+
+ std::string tstruct_name(publicize(tstruct->get_name()));
+ out <<
+ indent() << "type " << tstruct_name << " struct {" << endl;
+ /*
+ Here we generate the structure specification for the fastbinary codec.
+ These specifications have the following structure:
+ thrift_spec -> tuple of item_spec
+ item_spec -> nil | (tag, type_enum, name, spec_args, default)
+ tag -> integer
+ type_enum -> TType.I32 | TType.STRING | TType.STRUCT | ...
+ name -> string_literal
+ default -> nil # Handled by __init__
+ spec_args -> nil # For simple types
+ | (type_enum, spec_args) # Value type for list/set
+ | (type_enum, spec_args, type_enum, spec_args)
+ # Key and value for map
+ | (class_name, spec_args_ptr) # For struct/exception
+ class_name -> identifier # Basically a pointer to the class
+ spec_args_ptr -> expression # just class_name.spec_args
+
+ TODO(dreiss): Consider making this work for structs with negative tags.
+ */
+ // TODO(dreiss): Look into generating an empty tuple instead of nil
+ // for structures with no members.
+ // TODO(dreiss): Test encoding of structs where some inner structs
+ // don't have thrift_spec.
+ indent_up();
+
+ if (sorted_members.empty() || (sorted_members[0]->get_key() >= 0)) {
+ int sorted_keys_pos = 0;
+
+ for (m_iter = sorted_members.begin(); m_iter != sorted_members.end(); ++m_iter) {
+ for (; sorted_keys_pos != (*m_iter)->get_key(); sorted_keys_pos++) {
+ if (sorted_keys_pos != 0) {
+ indent(out) << "// unused field # " << sorted_keys_pos << endl;
+ }
+ }
- sorted_keys_pos ++;
+ t_type* fieldType = (*m_iter)->get_type();
+ string goType(type_to_go_type(fieldType));
+
+ indent(out) << publicize(variable_name_to_go_name((*m_iter)->get_name())) << " "
+ << goType << " `thrift:\""
+ << escape_string((*m_iter)->get_name())
+ << "," << sorted_keys_pos;
+
+ if ((*m_iter)->get_req() == t_field::T_REQUIRED) {
+ out << ",required";
+ }
+
+ out << "\"`" << endl;
+ sorted_keys_pos ++;
+ }
+ } else {
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ // This fills in default values, as opposed to nulls
+ out <<
+ indent() << publicize((*m_iter)->get_name()) << " " <<
+ type_to_go_type((*m_iter)->get_type()) << endl;
+ }
}
- } else {
- for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
- // This fills in default values, as opposed to nulls
- out <<
- indent() << publicize((*m_iter)->get_name()) << " " <<
- type_to_enum((*m_iter)->get_type()) << endl;
- }
- }
- indent_down();
- out <<
- indent() << "}" << endl << endl <<
- indent() << "func New" << tstruct_name << "() *" << tstruct_name << " {" << endl <<
- indent() << " output := &" << tstruct_name << "{" << endl <<
- indent() << " TStruct:thrift.NewTStruct(\"" << escape_string(tstruct->get_name()) << "\", []thrift.TField{" << endl;
- indent_up();
- indent_up();
- for(m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
- string thrift_name((*m_iter)->get_name());
+ indent_down();
out <<
- indent() << "thrift.NewTField(\"" << escape_string(thrift_name) << "\", " << type_to_enum((*m_iter)->get_type()) << ", "<< (*m_iter)->get_key() << ")," << endl;
- }
- out <<
- indent() << "})," << endl;
- indent_down();
- out <<
- indent() << "}" << endl <<
- indent() << "{" << endl;
- indent_up();
-
- for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
- // Initialize fields
- //t_type* type = (*m_iter)->get_type();
- string fieldName(publicize((*m_iter)->get_name()));
- string fullFieldName = "output." + fieldName;
- if ((*m_iter)->get_value() != NULL) {
- out <<
- indent() << fullFieldName << " = " <<
- render_field_default_value(*m_iter, fullFieldName) << endl;
- }
- }
- indent_down();
- out <<
- indent() << "}" << endl <<
- indent() << "return output" << endl;
- indent_down();
- out <<
- indent() << "}" << endl << endl;
-
- generate_go_struct_reader(out, tstruct, tstruct_name, is_result);
- generate_go_struct_writer(out, tstruct, tstruct_name, is_result);
-
- // Printing utilities so that on the command line thrift
- // structs look pretty like dictionaries
- out <<
- indent() << "func (p *" << tstruct_name << ") TStructName() string {" << endl <<
- indent() << " return \"" << escape_string(tstruct_name) << "\"" << endl <<
- indent() << "}" << endl << endl;
-
- out <<
- indent() << "func (p *" << tstruct_name << ") ThriftName() string {" << endl <<
- indent() << " return \"" << escape_string(tstruct->get_name()) << "\"" << endl <<
- indent() << "}" << endl << endl;
-
- out <<
- indent() << "func (p *" << tstruct_name << ") String() string {" << endl <<
- indent() << " if p == nil {" << endl <<
- indent() << " return \"<nil>\"" << endl <<
- indent() << " }" << endl <<
- indent() << " return fmt.Sprintf(\"" << escape_string(tstruct_name) << "(%+v)\", *p)" << endl <<
- indent() << "}" << endl << endl;
-
- // Equality and inequality methods that compare by value
- if(members.size() <= 0) {
- out <<
- indent() << "func (p *" << tstruct_name << ") CompareTo(other interface{}) (int, bool) {" << endl <<
- indent() << " if other == nil {" << endl <<
- indent() << " return 1, true" << endl <<
- indent() << " }" << endl <<
- indent() << " _, ok := other.(*" << tstruct_name << ")" << endl <<
- indent() << " if !ok {" << endl <<
- indent() << " return 0, false" << endl <<
- indent() << " }" << endl <<
- indent() << " return 0, true" << endl <<
- indent() << "}" << endl << endl;
- } else {
- out <<
- indent() << "func (p *" << tstruct_name << ") CompareTo(other interface{}) (int, bool) {" << endl <<
- indent() << " if other == nil {" << endl <<
- indent() << " return 1, true" << endl <<
- indent() << " }" << endl <<
- indent() << " data, ok := other.(*" << tstruct_name << ")" << endl <<
- indent() << " if !ok {" << endl <<
- indent() << " return 0, false" << endl <<
- indent() << " }" << endl;
- indent_up();
- for(m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
- t_type* orig_type = (*m_iter)->get_type();
- t_type* type = get_true_type(orig_type);
- string field_name(publicize(variable_name_to_go_name((*m_iter)->get_name())));
- if(type->is_base_type() || type->is_enum()) {
- if(type->is_bool()) {
- out <<
- indent() << "if cmp := thrift.CompareBool(p." << field_name << ", data." << field_name << "); cmp != 0 {" << endl <<
- indent() << " return cmp, true" << endl <<
- indent() << "}" << endl;
- } else {
- out <<
- indent() << "if p." << field_name << " != data." << field_name << " {" << endl <<
- indent() << " if p." << field_name << " < data." << field_name << " {" << endl <<
- indent() << " return -1, true" << endl <<
- indent() << " }" << endl <<
- indent() << " return 1, true" << endl <<
- indent() << "}" << endl;
+ indent() << "}" << endl << endl <<
+ indent() << "func New" << tstruct_name << "() *" << tstruct_name << " {" << endl <<
+ indent() << " return &" << tstruct_name << "{";
+
+ for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+ // Initialize fields
+ const string base_field_name = (*m_iter)->get_name();
+ const string escaped_field_name = escape_string(base_field_name);
+ const string go_safe_name = variable_name_to_go_name(escaped_field_name);
+ const string publicized_name = publicize(go_safe_name);
+ const t_type* type = get_true_type((*m_iter)->get_type());
+ const bool has_default_value = (*m_iter)->get_value() != NULL;
+ const bool type_is_enum = type->is_enum();
+
+ if (has_default_value) {
+ out << endl << indent() << publicized_name << ": " << render_field_default_value(*m_iter, base_field_name) << "," << endl;
+ } else if (type_is_enum) {
+ out << endl << indent() << publicized_name << ": math.MinInt32 - 1, // unset sentinal value" << endl;
}
- } else if(type->is_container() || type->is_struct() || type->is_xception()) {
- out <<
- indent() << "if cmp, ok := p." << field_name << ".CompareTo(data." << field_name << "); !ok || cmp != 0 {" << endl <<
- indent() << " return cmp, ok" << endl <<
- indent() << "}" << endl;
- } else {
- throw "INVALID TYPE IN generate_go_struct_definition: " + type->get_name();
- }
}
- indent_down();
- out <<
- indent() << " return 0, true" << endl <<
- indent() << "}" << endl << endl;
- }
-
- // Equality and inequality methods that compare by value
- out <<
- indent() << "func (p *" << tstruct_name << ") AttributeByFieldId(id int) interface{} {" << endl <<
- indent() << " switch id {" << endl <<
- indent() << " default: return nil" << endl;
- indent_up();
- for(m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
- string field_name(publicize(variable_name_to_go_name((*m_iter)->get_name())));
- out <<
- indent() << "case " << (*m_iter)->get_key() << ": return p." << field_name << endl;
- }
- indent_down();
- out <<
- indent() << " }" << endl <<
- indent() << " return nil" << endl <<
- indent() << "}" << endl << endl;
-
- out <<
- indent() << "func (p *" << tstruct_name << ") TStructFields() thrift.TFieldContainer {" << endl <<
- indent() << " return thrift.NewTFieldContainer([]thrift.TField{" << endl;
- indent_up();
- indent_up();
- for(m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
- string thrift_name((*m_iter)->get_name());
+
+ out << "}" << endl;
+ out << "}" << endl << endl;
+ generate_isset_helpers(out, tstruct, tstruct_name, is_result);
+ generate_go_struct_reader(out, tstruct, tstruct_name, is_result);
+ generate_go_struct_writer(out, tstruct, tstruct_name, is_result);
+
out <<
- indent() << "thrift.NewTField(\"" << escape_string(thrift_name) << "\", " << type_to_enum((*m_iter)->get_type()) << ", "<< (*m_iter)->get_key() << ")," << endl;
- }
- out <<
- indent() << "})" << endl;
- indent_down();
- indent_down();
- out <<
- indent() << "}" << endl << endl;
+ indent() << "func (p *" << tstruct_name << ") String() string {" << endl <<
+ indent() << " if p == nil {" << endl <<
+ indent() << " return \"<nil>\"" << endl <<
+ indent() << " }" << endl <<
+ indent() << " return fmt.Sprintf(\"" << escape_string(tstruct_name) << "(%+v)\", *p)" << endl <<
+ indent() << "}" << endl << endl;
+
+}
+
+/**
+ * Generates the IsSet helper methods for a struct
+ */
+void t_go_generator::generate_isset_helpers(ofstream& out,
+ t_struct* tstruct,
+ const string& tstruct_name,
+ bool is_result)
+{
+ const vector<t_field*>& fields = tstruct->get_members();
+ vector<t_field*>::const_iterator f_iter;
+ const string escaped_tstruct_name(escape_string(tstruct->get_name()));
+
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ t_type* type = get_true_type((*f_iter)->get_type());
+
+ if ((*f_iter)->get_req() == t_field::T_OPTIONAL || type->is_enum()) {
+ const string field_name(publicize(variable_name_to_go_name(escape_string((*f_iter)->get_name()))));
+ t_const_value* field_default_value = (*f_iter)->get_value();
+ out <<
+ indent() << "func (p *" << tstruct_name << ") IsSet" << field_name << "() bool {" << endl;
+ indent_up();
+ string s_check_value;
+ int64_t i_check_value;
+ double d_check_value;
+
+ if (type->is_base_type()) {
+ t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+
+ switch (tbase) {
+ case t_base_type::TYPE_STRING:
+ if (((t_base_type*)type)->is_binary()) {
+ // ignore default value for binary
+ out <<
+ indent() << "return p." << field_name << " != nil" << endl;
+ } else {
+ s_check_value = (field_default_value == NULL) ? "\"\"" : render_const_value(type, field_default_value, tstruct_name);
+ out <<
+ indent() << "return p." << field_name << " != " << s_check_value << endl;
+ }
+
+ break;
+
+ case t_base_type::TYPE_BOOL:
+ s_check_value = (field_default_value != NULL && field_default_value->get_integer() > 0) ? "true" : "false";
+ out <<
+ indent() << "return p." << field_name << " != " << s_check_value << endl;
+ break;
+
+ case t_base_type::TYPE_BYTE:
+ case t_base_type::TYPE_I16:
+ case t_base_type::TYPE_I32:
+ case t_base_type::TYPE_I64:
+ i_check_value = (field_default_value == NULL) ? 0 : field_default_value->get_integer();
+ out <<
+ indent() << "return p." << field_name << " != " << i_check_value << endl;
+ break;
+
+ case t_base_type::TYPE_DOUBLE:
+ d_check_value = (field_default_value == NULL) ? 0.0 : field_default_value->get_double();
+ out <<
+ indent() << "return p." << field_name << " != " << d_check_value << endl;
+ break;
+
+ default:
+ throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
+ }
+ } else if (type->is_enum()) {
+ out << indent() << "return int64(p." << field_name << ") != "
+ << "math.MinInt32 - 1" << endl;
+ } else if (type->is_struct() || type->is_xception()) {
+ out <<
+ indent() << "return p." << field_name << " != nil" << endl;
+ } else if (type->is_list() || type->is_set()) {
+ if (field_default_value != NULL && field_default_value->get_list().size() > 0) {
+ out <<
+ indent() << "return p." << field_name << " != nil" << endl;
+ } else {
+ out <<
+ indent() << "return p." << field_name << " != nil && len(p." << field_name << ") > 0" << endl;
+ }
+ } else if (type->is_map()) {
+ if (field_default_value != NULL && field_default_value->get_map().size() > 0) {
+ out <<
+ indent() << "return p." << field_name << " != nil" << endl;
+ } else {
+ out <<
+ indent() << "return p." << field_name << " != nil && len(p." << field_name << ") > 0" << endl;
+ }
+ } else {
+ throw "CANNOT GENERATE ISSET HELPERS FOR TYPE: " + type->get_name();
+ }
+
+ indent_down();
+ out <<
+ indent() << "}" << endl << endl;
+ }
+ }
}
/**
* Generates the read method for a struct
*/
void t_go_generator::generate_go_struct_reader(ofstream& out,
- t_struct* tstruct,
- const string& tstruct_name,
- bool is_result) {
- (void) is_result;
- const vector<t_field*>& fields = tstruct->get_members();
- vector<t_field*>::const_iterator f_iter;
- string escaped_tstruct_name(escape_string(tstruct->get_name()));
-
- out <<
- indent() << "func (p *" << tstruct_name << ") Read(iprot thrift.TProtocol) (err thrift.TProtocolException) {" << endl;
- indent_up();
-
- out <<
- indent() << "_, err = iprot.ReadStructBegin()" << endl <<
- indent() << "if err != nil { return thrift.NewTProtocolExceptionReadStruct(p.ThriftName(), err); }" << endl;
-
- // Loop over reading in fields
- indent(out) << "for {" << endl;
- indent_up();
-
- // Read beginning field marker
- out <<
- indent() << "fieldName, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()" << endl <<
- indent() << "if fieldId < 0 {" << endl <<
- indent() << " fieldId = int16(p.FieldIdFromFieldName(fieldName))" << endl <<
- indent() << "} else if fieldName == \"\" {" << endl <<
- indent() << " fieldName = p.FieldNameFromFieldId(int(fieldId))" << endl <<
- indent() << "}" << endl <<
- indent() << "if fieldTypeId == thrift.GENERIC {" << endl <<
- indent() << " fieldTypeId = p.FieldFromFieldId(int(fieldId)).TypeId()" << endl <<
- indent() << "}" << endl <<
- indent() << "if err != nil {" << endl <<
- indent() << " return thrift.NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err)" << endl <<
- indent() << "}" << endl;
-
- // Check for field STOP marker and break
- out <<
- indent() << "if fieldTypeId == thrift.STOP { break; }" << endl;
-
- // Switch statement on the field we are reading
- bool first = true;
-
- // Generate deserialization code for known cases
- int32_t field_id = -1;
- for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
- field_id = (*f_iter)->get_key();
- if (first) {
- first = false;
- indent(out);
- } else {
- indent(out) << "} else ";
- }
- out << "if fieldId == " << field_id << " || fieldName == \"" << escape_string((*f_iter)->get_name()) << "\" {" << endl;
+ t_struct* tstruct,
+ const string& tstruct_name,
+ bool is_result)
+{
+ const vector<t_field*>& fields = tstruct->get_members();
+ vector<t_field*>::const_iterator f_iter;
+ string escaped_tstruct_name(escape_string(tstruct->get_name()));
+ out <<
+ indent() << "func (p *" << tstruct_name << ") Read(iprot thrift.TProtocol) error {" << endl;
indent_up();
out <<
- indent() << "if fieldTypeId == " << type_to_enum((*f_iter)->get_type()) << " {" << endl <<
- indent() << " err = p.ReadField" << field_id << "(iprot)" << endl <<
- indent() << " if err != nil { return thrift.NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err); }" << endl <<
- indent() << "} else if fieldTypeId == thrift.VOID {" << endl <<
- indent() << " err = iprot.Skip(fieldTypeId)" << endl <<
- indent() << " if err != nil { return thrift.NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err); }" << endl <<
- indent() << "} else {" << endl <<
- indent() << " err = p.ReadField" << field_id << "(iprot)" << endl <<
- indent() << " if err != nil { return thrift.NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err); }" << endl <<
- indent() << "}" << endl;
- indent_down();
- }
-
- // In the default case we skip the field
- if (first) {
+ indent() << "if _, err := iprot.ReadStructBegin(); err != nil {" << endl <<
+ indent() << " return fmt.Errorf(\"%T read error\", p)" << endl <<
+ indent() << "}" << endl;
+ // Loop over reading in fields
+ indent(out) << "for {" << endl;
+ indent_up();
+ // Read beginning field marker
out <<
- indent() << "err = iprot.Skip(fieldTypeId)" << endl <<
- indent() << "if err != nil { return thrift.NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err); }" << endl;
- } else {
+ indent() << "_, fieldTypeId, fieldId, err := iprot.ReadFieldBegin()" << endl <<
+ indent() << "if err != nil {" << endl <<
+ indent() << " return fmt.Errorf(\"%T field %d read error: %s\", p, fieldId, err)" << endl <<
+ indent() << "}" << endl;
+ // Check for field STOP marker and break
out <<
- indent() << "} else {" << endl <<
- indent() << " err = iprot.Skip(fieldTypeId)" << endl <<
- indent() << " if err != nil { return thrift.NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err); }" << endl <<
- indent() << "}" << endl;
- }
- // Read field end marker
- out <<
- indent() << "err = iprot.ReadFieldEnd()" << endl <<
- indent() << "if err != nil { return thrift.NewTProtocolExceptionReadField(int(fieldId), fieldName, p.ThriftName(), err); }" << endl;
-
- indent_down();
- out <<
- indent() << "}" << endl <<
- indent() << "err = iprot.ReadStructEnd()" << endl <<
- indent() << "if err != nil { return thrift.NewTProtocolExceptionReadStruct(p.ThriftName(), err); }" << endl <<
- indent() << "return err" << endl;
-
- indent_down();
- out <<
- indent() << "}" << endl << endl;
- for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
- string field_type_name(publicize((*f_iter)->get_type()->get_name()));
- string field_name(publicize((*f_iter)->get_name()));
- int32_t field_id = (*f_iter)->get_key();
+ indent() << "if fieldTypeId == thrift.STOP { break; }" << endl;
+ // Switch statement on the field we are reading
+ bool first = true;
+ string thriftFieldTypeId;
+ // Generate deserialization code for known cases
+ int32_t field_id = -1;
+
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ field_id = (*f_iter)->get_key();
+
+ if (first) {
+ first = false;
+ indent(out) << "switch fieldId {" << endl;
+ }
+
+ // if negative id, ensure we generate a valid method name
+ string field_method_prefix("readField");
+
+ if (field_id < 0) {
+ field_method_prefix += "_";
+ field_id *= -1;
+ }
+
+ indent_up();
+ out << "case " << field_id << ":" << endl;
+ thriftFieldTypeId = type_to_enum((*f_iter)->get_type());
+
+ if (thriftFieldTypeId == "thrift.BINARY") {
+ thriftFieldTypeId = "thrift.STRING";
+ }
+
+ out <<
+ indent() << "if err := p." << field_method_prefix << field_id << "(iprot); err != nil {" << endl <<
+ indent() << " return err" << endl <<
+ indent() << "}" << endl;
+ indent_down();
+ }
+
+ // In the default case we skip the field
+ if (!first) {
+ out <<
+ indent() << "default:" << endl <<
+ indent() << " if err := iprot.Skip(fieldTypeId); err != nil {" << endl <<
+ indent() << " return err" << endl <<
+ indent() << " }" << endl <<
+ indent() << "}" << endl;
+ }
+
+ // Read field end marker
out <<
- indent() << "func (p *" << tstruct_name << ") ReadField" << field_id << "(iprot thrift.TProtocol) (err thrift.TProtocolException) {" << endl;
- indent_up();
- generate_deserialize_field(out, *f_iter, false, "p.");
+ indent() << "if err := iprot.ReadFieldEnd(); err != nil {" << endl <<
+ indent() << " return err" << endl <<
+ indent() << "}" << endl;
indent_down();
out <<
- indent() << " return err" << endl <<
- indent() << "}" << endl << endl <<
- indent() << "func (p *" << tstruct_name << ") ReadField" << field_name << "(iprot thrift.TProtocol) (thrift.TProtocolException) {" << endl <<
- indent() << " return p.ReadField" << field_id << "(iprot)" << endl <<
- indent() << "}" << endl << endl;
- }
+ indent() << "}" << endl <<
+ indent() << "if err := iprot.ReadStructEnd(); err != nil {" << endl <<
+ indent() << " return fmt.Errorf(\"%T read struct end error: %s\", p, err)" << endl <<
+ indent() << "}" << endl <<
+ indent() << "return nil" << endl;
+ indent_down();
+ out <<
+ indent() << "}" << endl << endl;
+
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ string field_type_name(publicize((*f_iter)->get_type()->get_name()));
+ string field_name(publicize((*f_iter)->get_name()));
+ string field_method_prefix("readField");
+ int32_t field_id = (*f_iter)->get_key();
+
+ if (field_id < 0) {
+ field_method_prefix += "_";
+ field_id *= -1;
+ }
+
+ out <<
+ indent() << "func (p *" << tstruct_name << ") " << field_method_prefix << field_id << "(iprot thrift.TProtocol) error {" << endl;
+ indent_up();
+ generate_deserialize_field(out, *f_iter, false, "p.");
+ indent_down();
+ out <<
+ indent() << " return nil" << endl <<
+ indent() << "}" << endl << endl;
+ }
}
void t_go_generator::generate_go_struct_writer(ofstream& out,
- t_struct* tstruct,
- const string& tstruct_name,
- bool is_result) {
- string name(tstruct->get_name());
- const vector<t_field*>& fields = tstruct->get_sorted_members();
- vector<t_field*>::const_iterator f_iter;
-
- indent(out) <<
- "func (p *" << tstruct_name << ") Write(oprot thrift.TProtocol) (err thrift.TProtocolException) {" << endl;
- indent_up();
-
- out <<
- indent() << "err = oprot.WriteStructBegin(\"" << name << "\")" << endl <<
- indent() << "if err != nil { return thrift.NewTProtocolExceptionWriteStruct(" <<
- "p.ThriftName(), err); }" << endl;
-
- string field_name;
- string escape_field_name;
- int32_t fieldId = -1;
- if (is_result && fields.size()) {
+ t_struct* tstruct,
+ const string& tstruct_name,
+ bool is_result)
+{
+ string name(tstruct->get_name());
+ const vector<t_field*>& fields = tstruct->get_sorted_members();
+ vector<t_field*>::const_iterator f_iter;
+ indent(out) <<
+ "func (p *" << tstruct_name << ") Write(oprot thrift.TProtocol) error {" << endl;
+ indent_up();
out <<
- indent() << "switch {" << endl;
- vector<t_field*>::const_reverse_iterator fr_iter;
- for (fr_iter = fields.rbegin(); fr_iter != fields.rend(); ++fr_iter) {
- field_name = (*fr_iter)->get_name();
- fieldId = (*fr_iter)->get_key();
- if(can_be_nil((*fr_iter)->get_type()) && fieldId != 0) {
+ indent() << "if err := oprot.WriteStructBegin(\"" << name << "\"); err != nil {" << endl <<
+ indent() << " return fmt.Errorf(\"%T write struct begin error: %s\", p, err) }" << endl;
+
+ string field_name;
+ string escape_field_name;
+ t_const_value* field_default_value;
+ t_field::e_req field_required;
+ bool field_can_be_nil = false;
+ int32_t field_id = -1;
+
+ if (is_result && fields.size()) {
out <<
- indent() << "case p." << publicize(variable_name_to_go_name(field_name)) << " != nil:" << endl <<
- indent() << " if err = p.WriteField" << fieldId << "(oprot); err != nil {" << endl <<
- indent() << " return err" << endl <<
- indent() << " }" << endl;
- } else {
+ indent() << "switch {" << endl;
+ vector<t_field*>::const_reverse_iterator fr_iter;
+
+ for (fr_iter = fields.rbegin(); fr_iter != fields.rend(); ++fr_iter) {
+ string field_method_prefix("writeField");
+ field_name = (*fr_iter)->get_name();
+ field_id = (*fr_iter)->get_key();
+
+ if (field_id < 0) {
+ field_method_prefix += "_";
+ field_id *= -1;
+ }
+
+ if (can_be_nil((*fr_iter)->get_type()) && field_id != 0) {
+ out <<
+ indent() << "case p." << publicize(variable_name_to_go_name(field_name)) << " != nil:" << endl <<
+ indent() << " if err := p." << field_method_prefix << field_id << "(oprot); err != nil { return err }" << endl;
+ } else {
+ out <<
+ indent() << "default:" << endl <<
+ indent() << " if err := p." << field_method_prefix << field_id << "(oprot); err != nil { return err }" << endl;
+ }
+ }
+
out <<
- indent() << "default:" << endl <<
- indent() << " if err = p.WriteField" << fieldId << "(oprot); err != nil {" << endl <<
- indent() << " return err" << endl <<
- indent() << " }" << endl;
- }
- }
- out <<
- indent() << "}" << endl;
- } else {
- for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
- field_name = (*f_iter)->get_name();
- escape_field_name = escape_string(field_name);
- fieldId = (*f_iter)->get_key();
- out <<
- indent() << "err = p.WriteField" << fieldId << "(oprot)" << endl <<
- indent() << "if err != nil { return err }" << endl;
- }
- }
-
- // Write the struct map
- out <<
- indent() << "err = oprot.WriteFieldStop()" << endl <<
- indent() << "if err != nil { return thrift.NewTProtocolExceptionWriteField(-1, \"STOP\", p.ThriftName(), err); }" << endl <<
- indent() << "err = oprot.WriteStructEnd()" << endl <<
- indent() << "if err != nil { return thrift.NewTProtocolExceptionWriteStruct(" <<
- "p.ThriftName(), err); }" << endl <<
- indent() << "return err" << endl;
-
- indent_down();
- out <<
- indent() << "}" << endl << endl;
- for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
- fieldId = (*f_iter)->get_key();
- field_name = (*f_iter)->get_name();
- escape_field_name = escape_string(field_name);
- out <<
- indent() << "func (p *" << tstruct_name << ") WriteField" << fieldId << "(oprot thrift.TProtocol) (err thrift.TProtocolException) {" << endl;
- indent_up();
- // Write field header
- if (can_be_nil((*f_iter)->get_type())) {
- out <<
- indent() << "if p." << publicize(variable_name_to_go_name(field_name)) << " != nil {" << endl;
- indent_up();
+ indent() << "}" << endl;
+ } else {
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ string field_method_prefix("writeField");
+ field_name = (*f_iter)->get_name();
+ escape_field_name = escape_string(field_name);
+ field_id = (*f_iter)->get_key();
+
+ if (field_id < 0) {
+ field_method_prefix += "_";
+ field_id *= -1;
+ }
+
+ out <<
+ indent() << "if err := p." << field_method_prefix << field_id << "(oprot); err != nil { return err }" << endl;
+
+ }
}
+
+ // Write the struct map
out <<
- indent() << "err = oprot.WriteFieldBegin(\"" <<
- escape_field_name << "\", " <<
- type_to_enum((*f_iter)->get_type()) << ", " <<
- fieldId << ")" << endl <<
- indent() << "if err != nil { return thrift.NewTProtocolExceptionWriteField(" <<
- fieldId << ", \"" <<
- escape_field_name << "\", " <<
- "p.ThriftName(), err); }" << endl;
-
- // Write field contents
- generate_serialize_field(out, *f_iter, "p.");
-
- // Write field closer
+ indent() << "if err := oprot.WriteFieldStop(); err != nil {" << endl <<
+ indent() << " return fmt.Errorf(\"%T write field stop error: %s\", err) }" << endl <<
+ indent() << "if err := oprot.WriteStructEnd(); err != nil {" << endl <<
+ indent() << " return fmt.Errorf(\"%T write struct stop error: %s\", err) }" << endl <<
+ indent() << "return nil" << endl;
+ indent_down();
out <<
- indent() << "err = oprot.WriteFieldEnd()" << endl <<
- indent() << "if err != nil { return thrift.NewTProtocolExceptionWriteField(" <<
- fieldId << ", \"" <<
- escape_field_name << "\", " <<
- "p.ThriftName(), err); }" << endl;
+ indent() << "}" << endl << endl;
- if (can_be_nil((*f_iter)->get_type())) {
- indent_down();
- out <<
- indent() << "}" << endl;
+ for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+ string field_method_prefix("writeField");
+ field_id = (*f_iter)->get_key();
+ field_name = (*f_iter)->get_name();
+ escape_field_name = escape_string(field_name);
+ field_default_value = (*f_iter)->get_value();
+ field_required = (*f_iter)->get_req();
+ field_can_be_nil = can_be_nil((*f_iter)->get_type());
+
+ if (field_id < 0) {
+ field_method_prefix += "_";
+ field_id *= -1;
+ }
+
+ out <<
+ indent() << "func (p *" << tstruct_name << ") " << field_method_prefix << field_id << "(oprot thrift.TProtocol) (err error) {" << endl;
+ indent_up();
+
+ // Write field header
+ if (field_can_be_nil) {
+ out <<
+ indent() << "if p." << publicize(variable_name_to_go_name(field_name)) << " != nil {" << endl;
+ indent_up();
+ }
+
+ if (field_required == t_field::T_OPTIONAL || (*f_iter)->get_type()->is_enum()) {
+ out <<
+ indent() << "if p.IsSet" << publicize(variable_name_to_go_name(field_name)) << "() {" << endl;
+ indent_up();
+ }
+
+ out <<
+ indent() << "if err := oprot.WriteFieldBegin(\"" <<
+ escape_field_name << "\", " <<
+ type_to_enum((*f_iter)->get_type()) << ", " <<
+ field_id << "); err != nil {" << endl <<
+ indent() << " return fmt.Errorf(\"%T write field begin error " << field_id << ":" << escape_field_name << ": %s\", p, err); }" << endl;
+
+ // Write field contents
+ generate_serialize_field(out, *f_iter, "p.");
+
+
+ // Write field closer
+ out <<
+ indent() << "if err := oprot.WriteFieldEnd(); err != nil {" << endl <<
+ indent() << " return fmt.Errorf(\"%T write field end error " << field_id << ":" << escape_field_name << ": %s\", p, err); }" << endl;
+
+ if (field_required == t_field::T_OPTIONAL || (*f_iter)->get_type()->is_enum()) {
+ indent_down();
+ out <<
+ indent() << "}" << endl;
+ }
+
+ if (field_can_be_nil) {
+ indent_down();
+ out <<
+ indent() << "}" << endl;
+ }
+
+ indent_down();
+ out <<
+ indent() << " return err" << endl <<
+ indent() << "}" << endl << endl;
}
- indent_down();
- out <<
- indent() << " return err" << endl <<
- indent() << "}" << endl << endl <<
- indent() << "func (p *" << tstruct_name << ") WriteField" << publicize(field_name) << "(oprot thrift.TProtocol) (thrift.TProtocolException) {" << endl <<
- indent() << " return p.WriteField" << fieldId << "(oprot)" << endl <<
- indent() << "}" << endl << endl;
- }
}
/**
@@ -1235,38 +1343,31 @@ void t_go_generator::generate_go_struct_writer(ofstream& out,
*
* @param tservice The service definition
*/
-void t_go_generator::generate_service(t_service* tservice) {
- string f_service_name = package_dir_+"/"+service_name_+".go";
- f_service_.open(f_service_name.c_str());
+void t_go_generator::generate_service(t_service* tservice)
+{
+ string f_service_name = package_dir_ + "/" + underscore(service_name_) + ".go";
+ f_service_.open(f_service_name.c_str());
+ f_service_ <<
+ go_autogen_comment() <<
+ go_package() <<
+ go_imports_begin();
- f_service_ <<
- go_autogen_comment() <<
- go_package() <<
- go_imports();
+ if (tservice->get_extends() != NULL) {
+ f_service_ << "\t\"" << gen_package_prefix_ + get_real_go_module(tservice->get_extends()->get_program()) << "\"\n";
+ }
- if (tservice->get_extends() != NULL) {
- f_service_ <<
- "import \"thriftlib/" << get_real_go_module(tservice->get_extends()->get_program()) << "\"" << endl;
- }
-
- f_service_ <<
- "import (" << endl <<
- indent() << " \"os\"" << endl <<
- indent() << ")" << endl << endl <<
- render_fastbinary_includes();
-
- f_service_ << endl;
-
- // Generate the three main parts of the service (well, two for now in PHP)
- generate_service_interface(tservice);
- generate_service_client(tservice);
- generate_service_server(tservice);
- generate_service_helpers(tservice);
- generate_
<TRUNCATED>