summaryrefslogtreecommitdiff
path: root/compiler/cpp/src/thrift/generate/t_go_generator.h
blob: ad6cee636d2ecd965ff6cab90121a5307cfad3ea (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#ifndef T_GO_GENERATOR_H
#define T_GO_GENERATOR_H

#include <fstream>
#include <iostream>
#include <limits>
#include <string>
#include <unordered_map>
#include <vector>

#include "thrift/generate/t_generator.h"
#include "thrift/platform.h"
#include "thrift/version.h"
#include <algorithm>
#include <clocale>
#include <sstream>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>

using std::map;
using std::ostream;
using std::ostringstream;
using std::string;
using std::stringstream;
using std::vector;

static const string endl = "\n"; // avoid ostream << std::endl flushes

const string DEFAULT_THRIFT_IMPORT = "github.com/apache/thrift/lib/go/thrift";
static std::string package_flag;

/**
 * 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)option_string;
    std::map<std::string, std::string>::const_iterator iter;

    gen_thrift_import_ = DEFAULT_THRIFT_IMPORT;
    gen_package_prefix_ = "";
    package_flag = "";
    read_write_private_ = false;
    ignore_initialisms_ = false;
    skip_remote_ = false;
    for (iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
      if (iter->first.compare("package_prefix") == 0) {
        gen_package_prefix_ = (iter->second);
      } else if (iter->first.compare("thrift_import") == 0) {
        gen_thrift_import_ = (iter->second);
      } else if (iter->first.compare("package") == 0) {
        package_flag = (iter->second);
      } else if (iter->first.compare("read_write_private") == 0) {
        read_write_private_ = true;
      } else if (iter->first.compare("ignore_initialisms") == 0) {
        ignore_initialisms_ = true;
      } else if( iter->first.compare("skip_remote") == 0) {
        skip_remote_ =  true;
      } else {
        throw "unknown option go:" + iter->first;
      }
    }

    out_dir_base_ = "gen-go";
  }

  /**
   * Init and close methods
   */

  void init_generator() override;
  void close_generator() override;
  std::string display_name() const override;

  /**
   * Program-level generation functions
   */

  void generate_typedef(t_typedef* ttypedef) override;
  void generate_enum(t_enum* tenum) override;
  void generate_const(t_const* tconst) override;
  void generate_struct(t_struct* tstruct) override;
  void generate_xception(t_struct* txception) override;
  void generate_service(t_service* tservice) override;

  std::string render_const_value(t_type* type,
                                 t_const_value* value,
                                 const string& name,
                                 bool opt = false);

  /**
   * Struct generation code
   */

  void generate_go_struct(t_struct* tstruct, bool is_exception);
  void generate_go_struct_definition(std::ostream& out,
                                     t_struct* tstruct,
                                     bool is_xception = false,
                                     bool is_result = false,
                                     bool is_args = false);
  void generate_go_struct_initializer(std::ostream& out,
                                      t_struct* tstruct,
                                      bool is_args_or_result = false);
  void generate_isset_helpers(std::ostream& out,
                              t_struct* tstruct,
                              const string& tstruct_name,
                              bool is_result = false);
  void generate_countsetfields_helper(std::ostream& out,
                                      t_struct* tstruct,
                                      const string& tstruct_name,
                                      bool is_result = false);
  void generate_go_struct_reader(std::ostream& out,
                                 t_struct* tstruct,
                                 const string& tstruct_name,
                                 bool is_result = false);
  void generate_go_struct_writer(std::ostream& out,
                                 t_struct* tstruct,
                                 const string& tstruct_name,
                                 bool is_result = false,
                                 bool uses_countsetfields = false);
  void generate_go_struct_equals(std::ostream& out, t_struct* tstruct, const string& tstruct_name);
  void generate_go_function_helpers(t_function* tfunction);
  void get_publicized_name_and_def_value(t_field* tfield,
                                         string* OUT_pub_name,
                                         t_const_value** OUT_def_value) const;

  /**
   * 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::ostream& out,
                                  t_field* tfield,
                                  bool declare,
                                  std::string prefix = "",
                                  bool inclass = false,
                                  bool coerceData = false,
                                  bool inkey = false,
                                  bool in_container = false);

  void generate_deserialize_struct(std::ostream& out,
                                   t_struct* tstruct,
                                   bool is_pointer_field,
                                   bool declare,
                                   std::string prefix = "");

  void generate_deserialize_container(std::ostream& out,
                                      t_type* ttype,
                                      bool pointer_field,
                                      bool declare,
                                      std::string prefix = "");

  void generate_deserialize_set_element(std::ostream& out,
                                        t_set* tset,
                                        bool declare,
                                        std::string prefix = "");

  void generate_deserialize_map_element(std::ostream& out,
                                        t_map* tmap,
                                        bool declare,
                                        std::string prefix = "");

  void generate_deserialize_list_element(std::ostream& out,
                                         t_list* tlist,
                                         bool declare,
                                         std::string prefix = "");

  void generate_serialize_field(std::ostream& out,
                                t_field* tfield,
                                std::string prefix = "",
                                bool inkey = false);

  void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");

  void generate_serialize_container(std::ostream& out,
                                    t_type* ttype,
                                    bool pointer_field,
                                    std::string prefix = "");

  void generate_serialize_map_element(std::ostream& out,
                                      t_map* tmap,
                                      std::string kiter,
                                      std::string viter);

  void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);

  void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter);

  void generate_go_equals(std::ostream& out, t_type* ttype, string tgt, string src);

  void generate_go_equals_struct(std::ostream& out, t_type* ttype, string tgt, string src);

  void generate_go_equals_container(std::ostream& out, t_type* ttype, string tgt, string src);

  void generate_go_docstring(std::ostream& out, t_struct* tstruct);

  void generate_go_docstring(std::ostream& out, t_function* tfunction);

  void generate_go_docstring(std::ostream& out,
                             t_doc* tdoc,
                             t_struct* tstruct,
                             const char* subheader);

  void generate_go_docstring(std::ostream& out, t_doc* tdoc);

  void parse_go_tags(map<string, string>* tags, const string in);

  /**
   * Helper rendering functions
   */

  std::string go_autogen_comment();
  std::string go_package();
  std::string go_imports_begin(bool consts);
  std::string go_imports_end();
  std::string render_includes(bool consts);
  std::string render_included_programs(string& unused_protection);
  std::string render_program_import(const t_program* program, string& unused_protection);
  std::string render_system_packages(std::vector<string>& system_packages);
  std::string render_import_protection();
  std::string render_fastbinary_includes();
  std::string declare_argument(t_field* tfield);
  std::string render_field_initial_value(t_field* tfield, const string& name, bool optional_field);
  std::string type_name(t_type* ttype);
  std::string module_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_type_with_opt(t_type* ttype, bool optional_field, bool is_container_value);
  std::string type_to_go_key_type(t_type* ttype);
  std::string type_to_go_container_value_type(t_type* ttype);
  std::string type_to_spec_args(t_type* ttype);

  void indent_up() { t_generator::indent_up(); }
  void indent_down() { t_generator::indent_down(); }
  std::string indent() { return t_generator::indent(); }
  std::ostream& indent(std::ostream& os) { return t_generator::indent(os); }

  static std::string get_real_go_module(const t_program* program) {

    if (!package_flag.empty()) {
      return package_flag;
    }
    std::string real_module = program->get_namespace("go");
    if (!real_module.empty()) {
      return real_module;
    }

    return lowercase(program->get_name());
  }

  static bool is_pointer_field(t_field* tfield, bool in_container = false);

private:
  std::string gen_package_prefix_;
  std::string gen_thrift_import_;
  bool read_write_private_;
  bool ignore_initialisms_;
  bool skip_remote_;

  /**
   * File streams
   */

  ofstream_with_content_based_conditional_update f_types_;
  std::string f_types_name_;
  ofstream_with_content_based_conditional_update f_consts_;
  std::string f_consts_name_;
  std::stringstream f_const_values_;

  std::string package_name_;
  std::string package_dir_;
  std::unordered_map<std::string, std::string> package_identifiers_;
  std::set<std::string> package_identifiers_set_;
  std::string read_method_name_;
  std::string write_method_name_;
  std::string equals_method_name_;

  std::set<std::string> commonInitialisms;

  std::string camelcase(const std::string& value) const;
  void fix_common_initialism(std::string& value, int i) const;
  std::string publicize(const std::string& value, bool is_args_or_result = false) const;
  std::string publicize(const std::string& value,
                        bool is_args_or_result,
                        const std::string& service_name) const;
  std::string privatize(const std::string& value) const;
  std::string new_prefix(const std::string& value) const;
  static std::string variable_name_to_go_name(const std::string& value);
  static bool omit_initialization(t_field* tfield);
};

#endif