blob: 394ebe32fbdb304a7acf9b14d1709a989e4c8b12 [file] [log] [blame]
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001/*
2 * Copyright 2014 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17// independent from idl_parser, since this code is not needed for most clients
18
19#include "flatbuffers/code_generators.h"
20#include "flatbuffers/flatbuffers.h"
21#include "flatbuffers/idl.h"
22#include "flatbuffers/util.h"
Austin Schuhe89fa2d2019-08-14 20:24:23 -070023#include "src/compiler/cpp_generator.h"
24#include "src/compiler/go_generator.h"
25#include "src/compiler/java_generator.h"
Austin Schuh272c6132020-11-14 16:37:52 -080026#include "src/compiler/python_generator.h"
27#include "src/compiler/python_private_generator.h"
28#include "src/compiler/swift_generator.h"
29#include "src/compiler/ts_generator.h"
Austin Schuhe89fa2d2019-08-14 20:24:23 -070030
31#if defined(_MSC_VER)
32# pragma warning(push)
33# pragma warning(disable : 4512) // C4512: 'class' : assignment operator could
34// not be generated
35#endif
36
37namespace flatbuffers {
38
39class FlatBufMethod : public grpc_generator::Method {
40 public:
Austin Schuh272c6132020-11-14 16:37:52 -080041 enum Streaming { kNone, kClient, kServer, kBiDi };
Austin Schuhe89fa2d2019-08-14 20:24:23 -070042
43 FlatBufMethod(const RPCCall *method) : method_(method) {
44 streaming_ = kNone;
45 auto val = method_->attributes.Lookup("streaming");
46 if (val) {
47 if (val->constant == "client") streaming_ = kClient;
48 if (val->constant == "server") streaming_ = kServer;
49 if (val->constant == "bidi") streaming_ = kBiDi;
50 }
51 }
52
53 grpc::string GetLeadingComments(const grpc::string) const { return ""; }
54
55 grpc::string GetTrailingComments(const grpc::string) const { return ""; }
56
57 std::vector<grpc::string> GetAllComments() const {
58 return method_->doc_comment;
59 }
60
61 std::string name() const { return method_->name; }
62
Austin Schuh272c6132020-11-14 16:37:52 -080063 // TODO: This method need to incorporate namespace for C++ side. Other
64 // language bindings simply don't use this method.
Austin Schuhe89fa2d2019-08-14 20:24:23 -070065 std::string GRPCType(const StructDef &sd) const {
66 return "flatbuffers::grpc::Message<" + sd.name + ">";
67 }
68
Austin Schuh272c6132020-11-14 16:37:52 -080069 std::vector<std::string> get_input_namespace_parts() const {
70 return (*method_->request).defined_namespace->components;
71 }
72
Austin Schuhe89fa2d2019-08-14 20:24:23 -070073 std::string get_input_type_name() const { return (*method_->request).name; }
74
Austin Schuh272c6132020-11-14 16:37:52 -080075 std::vector<std::string> get_output_namespace_parts() const {
76 return (*method_->response).defined_namespace->components;
77 }
78
Austin Schuhe89fa2d2019-08-14 20:24:23 -070079 std::string get_output_type_name() const { return (*method_->response).name; }
80
81 bool get_module_and_message_path_input(grpc::string * /*str*/,
82 grpc::string /*generator_file_name*/,
83 bool /*generate_in_pb2_grpc*/,
84 grpc::string /*import_prefix*/) const {
85 return true;
86 }
87
88 bool get_module_and_message_path_output(
89 grpc::string * /*str*/, grpc::string /*generator_file_name*/,
90 bool /*generate_in_pb2_grpc*/, grpc::string /*import_prefix*/) const {
91 return true;
92 }
93
Austin Schuh272c6132020-11-14 16:37:52 -080094 std::string get_fb_builder() const { return "builder"; }
95
Austin Schuhe89fa2d2019-08-14 20:24:23 -070096 std::string input_type_name() const { return GRPCType(*method_->request); }
97
98 std::string output_type_name() const { return GRPCType(*method_->response); }
99
100 bool NoStreaming() const { return streaming_ == kNone; }
101
102 bool ClientStreaming() const { return streaming_ == kClient; }
103
104 bool ServerStreaming() const { return streaming_ == kServer; }
105
106 bool BidiStreaming() const { return streaming_ == kBiDi; }
107
108 private:
109 const RPCCall *method_;
110 Streaming streaming_;
111};
112
113class FlatBufService : public grpc_generator::Service {
114 public:
115 FlatBufService(const ServiceDef *service) : service_(service) {}
116
117 grpc::string GetLeadingComments(const grpc::string) const { return ""; }
118
119 grpc::string GetTrailingComments(const grpc::string) const { return ""; }
120
121 std::vector<grpc::string> GetAllComments() const {
122 return service_->doc_comment;
123 }
124
Austin Schuh272c6132020-11-14 16:37:52 -0800125 std::vector<grpc::string> namespace_parts() const {
126 return service_->defined_namespace->components;
127 }
128
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700129 std::string name() const { return service_->name; }
Austin Schuh272c6132020-11-14 16:37:52 -0800130 bool is_internal() const {
131 return service_->Definition::attributes.Lookup("private") ? true : false;
132 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700133
134 int method_count() const {
135 return static_cast<int>(service_->calls.vec.size());
136 }
137
138 std::unique_ptr<const grpc_generator::Method> method(int i) const {
139 return std::unique_ptr<const grpc_generator::Method>(
140 new FlatBufMethod(service_->calls.vec[i]));
141 }
142
143 private:
144 const ServiceDef *service_;
145};
146
147class FlatBufPrinter : public grpc_generator::Printer {
148 public:
149 FlatBufPrinter(std::string *str) : str_(str), escape_char_('$'), indent_(0) {}
150
151 void Print(const std::map<std::string, std::string> &vars,
152 const char *string_template) {
153 std::string s = string_template;
154 // Replace any occurrences of strings in "vars" that are surrounded
155 // by the escape character by what they're mapped to.
156 size_t pos;
157 while ((pos = s.find(escape_char_)) != std::string::npos) {
158 // Found an escape char, must also find the closing one.
159 size_t pos2 = s.find(escape_char_, pos + 1);
160 // If placeholder not closed, ignore.
161 if (pos2 == std::string::npos) break;
162 auto it = vars.find(s.substr(pos + 1, pos2 - pos - 1));
163 // If unknown placeholder, ignore.
164 if (it == vars.end()) break;
165 // Subtitute placeholder.
166 s.replace(pos, pos2 - pos + 1, it->second);
167 }
168 Print(s.c_str());
169 }
170
171 void Print(const char *s) {
172 if (s == nullptr || *s == '\0') { return; }
173 // Add this string, but for each part separated by \n, add indentation.
174 for (;;) {
175 // Current indentation.
176 str_->insert(str_->end(), indent_ * 2, ' ');
177 // See if this contains more than one line.
178 const char *lf = strchr(s, '\n');
179 if (lf) {
180 (*str_) += std::string(s, lf + 1);
181 s = lf + 1;
182 if (!*s) break; // Only continue if there's more lines.
183 } else {
184 (*str_) += s;
185 break;
186 }
187 }
188 }
189
190 void Indent() { indent_++; }
191
192 void Outdent() {
193 indent_--;
Austin Schuh272c6132020-11-14 16:37:52 -0800194 FLATBUFFERS_ASSERT(indent_ >= 0);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700195 }
196
197 private:
198 std::string *str_;
199 char escape_char_;
200 int indent_;
201};
202
203class FlatBufFile : public grpc_generator::File {
204 public:
205 enum Language {
Austin Schuh272c6132020-11-14 16:37:52 -0800206 kLanguageGo,
207 kLanguageCpp,
208 kLanguageJava,
209 kLanguagePython,
210 kLanguageSwift,
211 kLanguageTS
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700212 };
213
214 FlatBufFile(const Parser &parser, const std::string &file_name,
215 Language language)
216 : parser_(parser), file_name_(file_name), language_(language) {}
217
218 FlatBufFile &operator=(const FlatBufFile &);
219
220 grpc::string GetLeadingComments(const grpc::string) const { return ""; }
221
222 grpc::string GetTrailingComments(const grpc::string) const { return ""; }
223
224 std::vector<grpc::string> GetAllComments() const {
225 return std::vector<grpc::string>();
226 }
227
228 std::string filename() const { return file_name_; }
229
230 std::string filename_without_ext() const {
231 return StripExtension(file_name_);
232 }
233
234 std::string message_header_ext() const { return "_generated.h"; }
235
236 std::string service_header_ext() const { return ".grpc.fb.h"; }
237
238 std::string package() const {
239 return parser_.current_namespace_->GetFullyQualifiedName("");
240 }
241
242 std::vector<std::string> package_parts() const {
243 return parser_.current_namespace_->components;
244 }
245
246 std::string additional_headers() const {
247 switch (language_) {
248 case kLanguageCpp: {
249 return "#include \"flatbuffers/grpc.h\"\n";
250 }
251 case kLanguageGo: {
252 return "import \"github.com/google/flatbuffers/go\"";
253 }
254 case kLanguageJava: {
255 return "import com.google.flatbuffers.grpc.FlatbuffersUtils;";
256 }
Austin Schuh272c6132020-11-14 16:37:52 -0800257 case kLanguagePython: {
258 return "";
259 }
260 case kLanguageSwift: {
261 return "";
262 }
263 case kLanguageTS: {
264 return "";
265 }
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700266 }
267 return "";
268 }
269
270 int service_count() const {
271 return static_cast<int>(parser_.services_.vec.size());
272 }
273
274 std::unique_ptr<const grpc_generator::Service> service(int i) const {
275 return std::unique_ptr<const grpc_generator::Service>(
276 new FlatBufService(parser_.services_.vec[i]));
277 }
278
279 std::unique_ptr<grpc_generator::Printer> CreatePrinter(
280 std::string *str) const {
281 return std::unique_ptr<grpc_generator::Printer>(new FlatBufPrinter(str));
282 }
283
284 private:
285 const Parser &parser_;
286 const std::string &file_name_;
287 const Language language_;
288};
289
290class GoGRPCGenerator : public flatbuffers::BaseGenerator {
291 public:
292 GoGRPCGenerator(const Parser &parser, const std::string &path,
293 const std::string &file_name)
Austin Schuh272c6132020-11-14 16:37:52 -0800294 : BaseGenerator(parser, path, file_name, "", "" /*Unused*/, "go"),
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700295 parser_(parser),
296 path_(path),
297 file_name_(file_name) {}
298
299 bool generate() {
300 FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageGo);
301 grpc_go_generator::Parameters p;
302 p.custom_method_io_type = "flatbuffers.Builder";
303 for (int i = 0; i < file.service_count(); i++) {
304 auto service = file.service(i);
305 const Definition *def = parser_.services_.vec[i];
306 p.package_name = LastNamespacePart(*(def->defined_namespace));
Austin Schuh272c6132020-11-14 16:37:52 -0800307 p.service_prefix =
308 def->defined_namespace->GetFullyQualifiedName(""); // file.package();
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700309 std::string output =
310 grpc_go_generator::GenerateServiceSource(&file, service.get(), &p);
311 std::string filename =
312 NamespaceDir(*def->defined_namespace) + def->name + "_grpc.go";
313 if (!flatbuffers::SaveFile(filename.c_str(), output, false)) return false;
314 }
315 return true;
316 }
317
318 protected:
319 const Parser &parser_;
320 const std::string &path_, &file_name_;
321};
322
323bool GenerateGoGRPC(const Parser &parser, const std::string &path,
324 const std::string &file_name) {
325 int nservices = 0;
326 for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
327 ++it) {
328 if (!(*it)->generated) nservices++;
329 }
330 if (!nservices) return true;
331 return GoGRPCGenerator(parser, path, file_name).generate();
332}
333
334bool GenerateCppGRPC(const Parser &parser, const std::string &path,
335 const std::string &file_name) {
336 int nservices = 0;
337 for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
338 ++it) {
339 if (!(*it)->generated) nservices++;
340 }
341 if (!nservices) return true;
342
343 grpc_cpp_generator::Parameters generator_parameters;
344 // TODO(wvo): make the other parameters in this struct configurable.
345 generator_parameters.use_system_headers = true;
346
347 FlatBufFile fbfile(parser, file_name, FlatBufFile::kLanguageCpp);
348
349 std::string header_code =
350 grpc_cpp_generator::GetHeaderPrologue(&fbfile, generator_parameters) +
Austin Schuh272c6132020-11-14 16:37:52 -0800351 grpc_cpp_generator::GetHeaderIncludes(&fbfile, generator_parameters) +
352 grpc_cpp_generator::GetHeaderServices(&fbfile, generator_parameters) +
353 grpc_cpp_generator::GetHeaderEpilogue(&fbfile, generator_parameters);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700354
355 std::string source_code =
356 grpc_cpp_generator::GetSourcePrologue(&fbfile, generator_parameters) +
Austin Schuh272c6132020-11-14 16:37:52 -0800357 grpc_cpp_generator::GetSourceIncludes(&fbfile, generator_parameters) +
358 grpc_cpp_generator::GetSourceServices(&fbfile, generator_parameters) +
359 grpc_cpp_generator::GetSourceEpilogue(&fbfile, generator_parameters);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700360
361 return flatbuffers::SaveFile((path + file_name + ".grpc.fb.h").c_str(),
362 header_code, false) &&
Austin Schuh272c6132020-11-14 16:37:52 -0800363 flatbuffers::SaveFile((path + file_name + ".grpc.fb.cc").c_str(),
364 source_code, false);
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700365}
366
367class JavaGRPCGenerator : public flatbuffers::BaseGenerator {
368 public:
369 JavaGRPCGenerator(const Parser &parser, const std::string &path,
370 const std::string &file_name)
Austin Schuh272c6132020-11-14 16:37:52 -0800371 : BaseGenerator(parser, path, file_name, "", "." /*separator*/, "java") {}
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700372
373 bool generate() {
374 FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageJava);
375 grpc_java_generator::Parameters p;
376 for (int i = 0; i < file.service_count(); i++) {
377 auto service = file.service(i);
378 const Definition *def = parser_.services_.vec[i];
379 p.package_name =
380 def->defined_namespace->GetFullyQualifiedName(""); // file.package();
381 std::string output =
382 grpc_java_generator::GenerateServiceSource(&file, service.get(), &p);
383 std::string filename =
384 NamespaceDir(*def->defined_namespace) + def->name + "Grpc.java";
385 if (!flatbuffers::SaveFile(filename.c_str(), output, false)) return false;
386 }
387 return true;
388 }
389};
390
391bool GenerateJavaGRPC(const Parser &parser, const std::string &path,
392 const std::string &file_name) {
393 int nservices = 0;
394 for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
395 ++it) {
396 if (!(*it)->generated) nservices++;
397 }
398 if (!nservices) return true;
399 return JavaGRPCGenerator(parser, path, file_name).generate();
400}
401
Austin Schuh272c6132020-11-14 16:37:52 -0800402bool GeneratePythonGRPC(const Parser &parser, const std::string & /*path*/,
403 const std::string &file_name) {
404 int nservices = 0;
405 for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
406 ++it) {
407 if (!(*it)->generated) nservices++;
408 }
409 if (!nservices) return true;
410
411 grpc_python_generator::GeneratorConfiguration config;
412 config.grpc_package_root = "grpc";
413 config.beta_package_root = "grpc.beta";
414 config.import_prefix = "";
415
416 FlatBufFile fbfile(parser, file_name, FlatBufFile::kLanguagePython);
417
418 grpc_python_generator::PrivateGenerator generator(config, &fbfile);
419
420 std::string code = generator.GetGrpcServices();
421 std::string namespace_dir;
422 auto &namespaces = parser.namespaces_.back()->components;
423 for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
424 if (it != namespaces.begin()) namespace_dir += kPathSeparator;
425 namespace_dir += *it;
426 }
427
428 std::string grpc_py_filename = namespace_dir;
429 if (!namespace_dir.empty()) grpc_py_filename += kPathSeparator;
430 grpc_py_filename += file_name + "_grpc_fb.py";
431
432 return flatbuffers::SaveFile(grpc_py_filename.c_str(), code, false);
433}
434
435class SwiftGRPCGenerator : public flatbuffers::BaseGenerator {
436 private:
437 CodeWriter code_;
438
439 public:
440 SwiftGRPCGenerator(const Parser &parser, const std::string &path,
441 const std::string &filename)
442 : BaseGenerator(parser, path, filename, "", "" /*Unused*/, "swift") {}
443
444 bool generate() {
445 code_.Clear();
446 code_ += "// Generated GRPC code for FlatBuffers swift!";
447 code_ += grpc_swift_generator::GenerateHeader();
448 FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageSwift);
449 for (int i = 0; i < file.service_count(); i++) {
450 auto service = file.service(i);
451 code_ += grpc_swift_generator::Generate(&file, service.get());
452 }
453 const auto final_code = code_.ToString();
454 const auto filename = GeneratedFileName(path_, file_name_);
455 return SaveFile(filename.c_str(), final_code, false);
456 }
457
458 static std::string GeneratedFileName(const std::string &path,
459 const std::string &file_name) {
460 return path + file_name + ".grpc.swift";
461 }
462};
463
464bool GenerateSwiftGRPC(const Parser &parser, const std::string &path,
465 const std::string &file_name) {
466 int nservices = 0;
467 for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
468 ++it) {
469 if (!(*it)->generated) nservices++;
470 }
471 if (!nservices) return true;
472 return SwiftGRPCGenerator(parser, path, file_name).generate();
473}
474
475class TSGRPCGenerator : public flatbuffers::BaseGenerator {
476 private:
477 CodeWriter code_;
478
479 public:
480 TSGRPCGenerator(const Parser &parser, const std::string &path,
481 const std::string &filename)
482 : BaseGenerator(parser, path, filename, "", "" /*Unused*/, "ts") {}
483
484 bool generate() {
485 code_.Clear();
486 FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageTS);
487
488 for (int i = 0; i < file.service_count(); i++) {
489 auto service = file.service(i);
490 code_ += grpc_ts_generator::Generate(&file, service.get(), file_name_);
491 const auto ts_name = GeneratedFileName(path_, file_name_);
492 if (!SaveFile(ts_name.c_str(), code_.ToString(), false)) return false;
493
494 code_.Clear();
495 code_ += grpc_ts_generator::GenerateInterface(&file, service.get(),
496 file_name_);
497 const auto ts_interface_name = GeneratedFileName(path_, file_name_, true);
498 if (!SaveFile(ts_interface_name.c_str(), code_.ToString(), false))
499 return false;
500 }
501 return true;
502 }
503
504 static std::string GeneratedFileName(const std::string &path,
505 const std::string &file_name,
506 const bool is_interface = false) {
507 if (is_interface) return path + file_name + "_grpc.d.ts";
508 return path + file_name + "_grpc.js";
509 }
510};
511
512bool GenerateTSGRPC(const Parser &parser, const std::string &path,
513 const std::string &file_name) {
514 int nservices = 0;
515 for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end();
516 ++it) {
517 if (!(*it)->generated) nservices++;
518 }
519 if (!nservices) return true;
520 return TSGRPCGenerator(parser, path, file_name).generate();
521}
522
Austin Schuhe89fa2d2019-08-14 20:24:23 -0700523} // namespace flatbuffers
524
525#if defined(_MSC_VER)
526# pragma warning(pop)
527#endif