1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
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 #include <cctype>
18 #include <set>
19 
20 #include <boost/algorithm/string.hpp>
21 #include <boost/algorithm/string/predicate.hpp>
22 #include <boost/algorithm/string/replace.hpp>
23 #include <thrift/compiler/lib/java/util.h>
24 
25 #include <thrift/compiler/generate/t_mstch_generator.h>
26 #include <thrift/compiler/generate/t_mstch_objects.h>
27 
28 using namespace std;
29 
30 namespace apache {
31 namespace thrift {
32 namespace compiler {
33 
34 namespace {
35 /**
36  * Gets the swift namespace, throws a runtime error if not found.
37  */
get_namespace_or_default(const t_program & prog)38 std::string get_namespace_or_default(const t_program& prog) {
39   const auto& prog_namespace = prog.get_namespace("java.swift");
40   if (prog_namespace != "") {
41     return prog_namespace;
42   } else {
43     throw std::runtime_error{"No namespace 'java.swift' in " + prog.name()};
44   }
45 }
46 
get_constants_class_name(const t_program & prog)47 std::string get_constants_class_name(const t_program& prog) {
48   const auto& constant_name = prog.get_namespace("java.swift.constants");
49   if (constant_name == "") {
50     return "Constants";
51   } else {
52     auto java_name_space = get_namespace_or_default(prog);
53     std::string java_class_name;
54     if (constant_name.rfind(java_name_space) == 0) {
55       java_class_name = constant_name.substr(java_name_space.length() + 1);
56     } else {
57       java_class_name = constant_name;
58     }
59 
60     if (java_class_name == "" ||
61         java_class_name.find('.') != std::string::npos) {
62       throw std::runtime_error{
63           "Java Constants Class Name `" + java_class_name +
64           "` is not well formatted."};
65     }
66 
67     return java_class_name;
68   }
69 }
70 
71 template <typename Node>
get_java_swift_name(const Node * node)72 std::string get_java_swift_name(const Node* node) {
73   return node->get_annotation(
74       "java.swift.name", java::mangle_java_name(node->get_name(), false));
75 }
76 
77 } // namespace
78 
79 class t_mstch_swift_generator : public t_mstch_generator {
80  public:
t_mstch_swift_generator(t_program * program,t_generation_context context,const std::map<std::string,std::string> & parsed_options,const std::string &)81   t_mstch_swift_generator(
82       t_program* program,
83       t_generation_context context,
84       const std::map<std::string, std::string>& parsed_options,
85       const std::string& /* option_string */)
86       : t_mstch_generator(
87             program, std::move(context), "java/swift", parsed_options) {
88     out_dir_base_ = "gen-swift";
89   }
90 
91   void generate_program() override;
92 
93  private:
94   void set_mstch_generators();
95 
96   /*
97    * Generate multiple Java items according to the given template. Writes
98    * output to package_dir underneath the global output directory.
99    */
100 
101   template <typename T, typename Generator, typename Cache>
generate_items(Generator const * generator,Cache & c,const t_program * program,const std::vector<T * > & items,const std::string & tpl_path)102   void generate_items(
103       Generator const* generator,
104       Cache& c,
105       const t_program* program,
106       const std::vector<T*>& items,
107       const std::string& tpl_path) {
108     const auto& id = program->path();
109     if (!cache_->programs_.count(id)) {
110       cache_->programs_[id] = generators_->program_generator_->generate(
111           program, generators_, cache_);
112     }
113     auto package_dir = boost::filesystem::path{
114         java::package_to_path(get_namespace_or_default(*program))};
115 
116     for (const T* item : items) {
117       auto filename = java::mangle_java_name(item->get_name(), true) + ".java";
118       const auto& item_id = id + item->get_name();
119       if (!c.count(item_id)) {
120         c[item_id] = generator->generate(item, generators_, cache_);
121       }
122 
123       render_to_file(c[item_id], tpl_path, package_dir / filename);
124     }
125   }
126 
127   /*
128    * Generate Service Client implementation - Sync & Async. Writes
129    * output to package_dir
130    */
131   template <typename T, typename Generator, typename Cache>
generate_client(Generator const * generator,Cache & c,const t_program * program,const std::vector<T * > & services)132   void generate_client(
133       Generator const* generator,
134       Cache& c,
135       const t_program* program,
136       const std::vector<T*>& services) {
137     const auto& id = program->path();
138     if (!cache_->programs_.count(id)) {
139       cache_->programs_[id] = generators_->program_generator_->generate(
140           program, generators_, cache_);
141     }
142     auto package_dir = boost::filesystem::path{
143         java::package_to_path(get_namespace_or_default(*program))};
144 
145     // Iterate through services
146     for (const T* service : services) {
147       auto service_name = java::mangle_java_name(service->get_name(), true);
148       // Generate sync client
149       auto sync_filename = service_name + "ClientImpl.java";
150       const auto& sync_service_id = id + service->get_name() + "Client";
151       if (!c.count(sync_service_id)) {
152         c[sync_service_id] = generator->generate(service, generators_, cache_);
153       }
154 
155       render_to_file(
156           c[sync_service_id], "ServiceClient", package_dir / sync_filename);
157 
158       // Generate async client
159       auto async_filename = service_name + "AsyncClientImpl.java";
160       const auto& async_service_id = id + service->get_name() + "AsyncClient";
161       if (!c.count(async_service_id)) {
162         c[async_service_id] = generator->generate(service, generators_, cache_);
163       }
164 
165       render_to_file(
166           c[async_service_id],
167           "ServiceAsyncClient",
168           package_dir / async_filename);
169 
170       // Generate Async to Reactive Wrapper
171       auto async_reactive_wrapper_filename =
172           service_name + "AsyncReactiveWrapper.java";
173       const auto& async_reactive_wrapper_id =
174           id + service->get_name() + "AsyncReactiveWrapper";
175       if (!c.count(async_reactive_wrapper_id)) {
176         c[async_reactive_wrapper_id] =
177             generator->generate(service, generators_, cache_);
178       }
179 
180       render_to_file(
181           c[async_reactive_wrapper_id],
182           "AsyncReactiveWrapper",
183           package_dir / async_reactive_wrapper_filename);
184 
185       // Generate Blocking to Reactive Wrapper
186       auto blocking_reactive_wrapper_filename =
187           service_name + "BlockingReactiveWrapper.java";
188       const auto& blocking_reactive_wrapper_id =
189           id + service->get_name() + "BlockingReactiveWrapper";
190       if (!c.count(blocking_reactive_wrapper_id)) {
191         c[blocking_reactive_wrapper_id] =
192             generator->generate(service, generators_, cache_);
193       }
194 
195       render_to_file(
196           c[blocking_reactive_wrapper_id],
197           "BlockingReactiveWrapper",
198           package_dir / blocking_reactive_wrapper_filename);
199 
200       // Generate Reactive to Async Wrapper
201       auto reactive_async_wrapper_filename =
202           service_name + "ReactiveAsyncWrapper.java";
203       const auto& reactive_async_wrapper_id =
204           id + service->get_name() + "ReactiveAsyncWrapper";
205       if (!c.count(reactive_async_wrapper_id)) {
206         c[reactive_async_wrapper_id] =
207             generator->generate(service, generators_, cache_);
208       }
209 
210       render_to_file(
211           c[reactive_async_wrapper_id],
212           "ReactiveAsyncWrapper",
213           package_dir / reactive_async_wrapper_filename);
214 
215       // Generate Reactive to Blocking Wrapper
216       auto reactive_blocking_wrapper_filename =
217           service_name + "ReactiveBlockingWrapper.java";
218       const auto& reactive_blocking_wrapper_id =
219           id + service->get_name() + "ReactiveBlockingWrapper";
220       if (!c.count(reactive_blocking_wrapper_id)) {
221         c[reactive_blocking_wrapper_id] =
222             generator->generate(service, generators_, cache_);
223       }
224 
225       render_to_file(
226           c[reactive_blocking_wrapper_id],
227           "ReactiveBlockingWrapper",
228           package_dir / reactive_blocking_wrapper_filename);
229 
230       // Generate Reactive Client
231       auto reactive_client_filename = service_name + "ReactiveClient.java";
232       const auto& reactive_client_wrapper_id =
233           id + service->get_name() + "ReactiveClient";
234       if (!c.count(reactive_client_wrapper_id)) {
235         c[reactive_client_wrapper_id] =
236             generator->generate(service, generators_, cache_);
237       }
238 
239       render_to_file(
240           c[reactive_client_wrapper_id],
241           "ReactiveClient",
242           package_dir / reactive_client_filename);
243 
244       // Generate RpcServerHandler
245       auto rpc_server_handler_filename = service_name + "RpcServerHandler.java";
246       const auto& rpc_server_handler_id =
247           id + service->get_name() + "RpcServerHandler";
248       if (!c.count(rpc_server_handler_id)) {
249         c[rpc_server_handler_id] =
250             generator->generate(service, generators_, cache_);
251       }
252 
253       render_to_file(
254           c[rpc_server_handler_id],
255           "RpcServerHandler",
256           package_dir / rpc_server_handler_filename);
257     }
258   }
259 
generate_constants(const t_program * program)260   void generate_constants(const t_program* program) {
261     if (program->consts().empty()) {
262       // Only generate Constants.java if we actually have constants
263       return;
264     }
265     auto name = program->name();
266     const auto& prog = cached_program(program);
267 
268     auto package_dir = boost::filesystem::path{
269         java::package_to_path(get_namespace_or_default(*program))};
270     auto constant_file_name = get_constants_class_name(*program) + ".java";
271     render_to_file(prog, "Constants", package_dir / constant_file_name);
272   }
273 
generate_placeholder(const t_program * program)274   void generate_placeholder(const t_program* program) {
275     auto package_dir = boost::filesystem::path{
276         java::package_to_path(get_namespace_or_default(*program))};
277     auto placeholder_file_name = ".generated_" + program->name();
278     write_output(package_dir / placeholder_file_name, "");
279   }
280 };
281 
282 class mstch_swift_program : public mstch_program {
283  public:
mstch_swift_program(t_program const * program,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION const pos)284   mstch_swift_program(
285       t_program const* program,
286       std::shared_ptr<mstch_generators const> generators,
287       std::shared_ptr<mstch_cache> cache,
288       ELEMENT_POSITION const pos)
289       : mstch_program(program, generators, cache, pos) {
290     register_methods(
291         this,
292         {
293             {"program:javaPackage", &mstch_swift_program::java_package},
294             {"program:constantClassName",
295              &mstch_swift_program::constant_class_name},
296         });
297   }
java_package()298   mstch::node java_package() { return get_namespace_or_default(*program_); }
constant_class_name()299   mstch::node constant_class_name() {
300     return get_constants_class_name(*program_);
301   }
302 };
303 
304 class mstch_swift_struct : public mstch_struct {
305   // A struct is a "big struct" if it contains > 127 members. The reason for
306   // this limit is that we generate exhaustive constructor for Thrift struct
307   // but Java methods are limited to 255 arguments (and since long/double
308   // types count twice, 127 is a safe threshold).
309   static constexpr uint64_t bigStructThreshold = 127;
310 
311  public:
mstch_swift_struct(t_struct const * strct,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION const pos)312   mstch_swift_struct(
313       t_struct const* strct,
314       std::shared_ptr<mstch_generators const> generators,
315       std::shared_ptr<mstch_cache> cache,
316       ELEMENT_POSITION const pos)
317       : mstch_struct(strct, generators, cache, pos) {
318     register_methods(
319         this,
320         {
321             {"struct:javaPackage", &mstch_swift_struct::java_package},
322             {"struct:unionFieldTypeUnique?",
323              &mstch_swift_struct::is_union_field_type_unique},
324             {"struct:asBean?", &mstch_swift_struct::is_as_bean},
325             {"struct:isBigStruct?", &mstch_swift_struct::is_BigStruct},
326             {"struct:javaCapitalName", &mstch_swift_struct::java_capital_name},
327             {"struct:javaAnnotations?",
328              &mstch_swift_struct::has_java_annotations},
329             {"struct:isUnion?", &mstch_swift_struct::is_struct_union},
330             {"struct:javaAnnotations", &mstch_swift_struct::java_annotations},
331             {"struct:exceptionMessage", &mstch_swift_struct::exception_message},
332             {"struct:needsExceptionMessage?",
333              &mstch_swift_struct::needs_exception_message},
334             {"struct:enableIsSet?", &mstch_swift_struct::enable_is_set},
335         });
336     register_has_option(
337         "struct:extendRuntimeException?", "legacy_extend_runtime_exception");
338   }
java_package()339   mstch::node java_package() {
340     return get_namespace_or_default(*(strct_->program()));
341   }
is_struct_union()342   mstch::node is_struct_union() { return strct_->is_union(); }
is_union_field_type_unique()343   mstch::node is_union_field_type_unique() {
344     std::set<std::string> field_types;
345     for (const auto& field : strct_->fields()) {
346       auto type_name = field.type()->get_full_name();
347       std::string type_with_erasure = type_name.substr(0, type_name.find('<'));
348       if (field_types.find(type_with_erasure) != field_types.end()) {
349         return false;
350       } else {
351         field_types.insert(type_with_erasure);
352       }
353     }
354     return true;
355   }
is_as_bean()356   mstch::node is_as_bean() {
357     if (!strct_->is_xception() && !strct_->is_union()) {
358       return strct_->get_annotation("java.swift.mutable") == "true";
359     } else {
360       return false;
361     }
362   }
363 
is_BigStruct()364   mstch::node is_BigStruct() {
365     return (
366         strct_->is_struct() && strct_->fields().size() > bigStructThreshold);
367   }
368 
java_capital_name()369   mstch::node java_capital_name() {
370     return java::mangle_java_name(strct_->get_name(), true);
371   }
has_java_annotations()372   mstch::node has_java_annotations() {
373     return strct_->has_annotation("java.swift.annotations");
374   }
java_annotations()375   mstch::node java_annotations() {
376     return strct_->get_annotation("java.swift.annotations");
377   }
exception_message()378   mstch::node exception_message() {
379     const auto& field_name_to_use = strct_->get_annotation("message");
380     if (const auto* field = strct_->get_field_by_name(field_name_to_use)) {
381       return get_java_swift_name(field);
382     }
383 
384     throw std::runtime_error{
385         "The exception message field '" + field_name_to_use +
386         "' is not found in " + strct_->get_name() + "!"};
387   }
388   // we can only override Throwable's getMessage() if:
389   //  1 - there is provided 'message' annotation
390   //  2 - there is no struct field named 'message'
391   //      (since it will generate getMessage() as well)
needs_exception_message()392   mstch::node needs_exception_message() {
393     return strct_->is_xception() && strct_->has_annotation("message") &&
394         strct_->get_field_by_name("message") == nullptr;
395   }
enable_is_set()396   mstch::node enable_is_set() {
397     return strct_->has_annotation("java.swift.enable_is_set");
398   }
399 };
400 
401 class mstch_swift_service : public mstch_service {
402  public:
mstch_swift_service(t_service const * service,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION const pos)403   mstch_swift_service(
404       t_service const* service,
405       std::shared_ptr<mstch_generators const> generators,
406       std::shared_ptr<mstch_cache> cache,
407       ELEMENT_POSITION const pos)
408       : mstch_service(service, generators, cache, pos) {
409     register_methods(
410         this,
411         {
412             {"service:javaPackage", &mstch_swift_service::java_package},
413             {"service:javaCapitalName",
414              &mstch_swift_service::java_capital_name},
415             {"service:onewayFunctions",
416              &mstch_swift_service::get_oneway_functions},
417             {"service:requestResponseFunctions",
418              &mstch_swift_service::get_request_response_functions},
419             {"service:supportedFunctions",
420              &mstch_swift_service::get_supported_functions},
421             {"service:streamingFunctions",
422              &mstch_swift_service::get_streaming_functions},
423             {"service:sinkFunctions", &mstch_swift_service::get_sink_functions},
424         });
425   }
java_package()426   mstch::node java_package() {
427     return get_namespace_or_default(*(service_->program()));
428   }
java_capital_name()429   mstch::node java_capital_name() {
430     return java::mangle_java_name(service_->get_name(), true);
431   }
get_oneway_functions()432   mstch::node get_oneway_functions() {
433     std::vector<t_function*> funcs;
434     for (auto func : service_->get_functions()) {
435       if (func->is_oneway()) {
436         funcs.push_back(func);
437       }
438     }
439     return generate_functions(funcs);
440   }
get_request_response_functions()441   mstch::node get_request_response_functions() {
442     std::vector<t_function*> funcs;
443     for (auto func : service_->get_functions()) {
444       if (!func->returns_stream() && !func->returns_sink() &&
445           !func->get_returntype()->is_service() && !func->is_oneway()) {
446         funcs.push_back(func);
447       }
448     }
449     return generate_functions(funcs);
450   }
get_supported_functions()451   mstch::node get_supported_functions() {
452     std::vector<t_function*> funcs;
453     for (auto func : service_->get_functions()) {
454       if (!func->returns_stream() && !func->returns_sink() &&
455           !func->get_returntype()->is_service()) {
456         funcs.push_back(func);
457       }
458     }
459     return generate_functions(funcs);
460   }
461 
get_streaming_functions()462   mstch::node get_streaming_functions() {
463     std::vector<t_function*> funcs;
464     for (auto func : service_->get_functions()) {
465       if (func->returns_stream()) {
466         funcs.push_back(func);
467       }
468     }
469     return generate_functions(funcs);
470   }
471 
get_sink_functions()472   mstch::node get_sink_functions() {
473     std::vector<t_function*> funcs;
474     for (auto func : service_->get_functions()) {
475       if (func->returns_sink()) {
476         funcs.push_back(func);
477       }
478     }
479     return generate_functions(funcs);
480   }
481 };
482 
483 class mstch_swift_function : public mstch_function {
484  public:
mstch_swift_function(t_function const * function,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION const pos)485   mstch_swift_function(
486       t_function const* function,
487       std::shared_ptr<mstch_generators const> generators,
488       std::shared_ptr<mstch_cache> cache,
489       ELEMENT_POSITION const pos)
490       : mstch_function(function, generators, cache, pos) {
491     register_methods(
492         this,
493         {
494             {"function:javaName", &mstch_swift_function::java_name},
495             {"function:voidType", &mstch_swift_function::is_void_type},
496             {"function:nestedDepth", &mstch_swift_function::get_nested_depth},
497             {"function:nestedDepth++",
498              &mstch_swift_function::increment_nested_depth},
499             {"function:nestedDepth--",
500              &mstch_swift_function::decrement_nested_depth},
501             {"function:isFirstDepth?", &mstch_swift_function::is_first_depth},
502             {"function:prevNestedDepth",
503              &mstch_swift_function::preceding_nested_depth},
504             {"function:isNested?",
505              &mstch_swift_function::get_nested_container_flag},
506             {"function:setIsNested",
507              &mstch_swift_function::set_nested_container_flag},
508             {"function:unsetIsNested",
509              &mstch_swift_function::unset_nested_container_flag},
510         });
511   }
512 
513   int32_t nestedDepth = 0;
514   bool isNestedContainerFlag = false;
515 
get_nested_depth()516   mstch::node get_nested_depth() { return nestedDepth; }
preceding_nested_depth()517   mstch::node preceding_nested_depth() { return (nestedDepth - 1); }
is_first_depth()518   mstch::node is_first_depth() { return (nestedDepth == 1); }
get_nested_container_flag()519   mstch::node get_nested_container_flag() { return isNestedContainerFlag; }
set_nested_container_flag()520   mstch::node set_nested_container_flag() {
521     isNestedContainerFlag = true;
522     return mstch::node();
523   }
unset_nested_container_flag()524   mstch::node unset_nested_container_flag() {
525     isNestedContainerFlag = false;
526     return mstch::node();
527   }
increment_nested_depth()528   mstch::node increment_nested_depth() {
529     nestedDepth++;
530     return mstch::node();
531   }
decrement_nested_depth()532   mstch::node decrement_nested_depth() {
533     nestedDepth--;
534     return mstch::node();
535   }
536 
java_name()537   mstch::node java_name() {
538     return java::mangle_java_name(function_->get_name(), false);
539   }
540 
is_void_type()541   mstch::node is_void_type() { return function_->get_returntype()->is_void(); }
542 };
543 
544 class mstch_swift_field : public mstch_field {
545  public:
mstch_swift_field(t_field const * field,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION const pos,int32_t index,field_generator_context const * field_context)546   mstch_swift_field(
547       t_field const* field,
548       std::shared_ptr<mstch_generators const> generators,
549       std::shared_ptr<mstch_cache> cache,
550       ELEMENT_POSITION const pos,
551       int32_t index,
552       field_generator_context const* field_context)
553       : mstch_field(field, generators, cache, pos, index, field_context) {
554     register_methods(
555         this,
556         {
557             {"field:javaName", &mstch_swift_field::java_name},
558             {"field:javaCapitalName", &mstch_swift_field::java_capital_name},
559             {"field:javaDefaultValue", &mstch_swift_field::java_default_value},
560             {"field:javaAllCapsName", &mstch_swift_field::java_all_caps_name},
561             {"field:recursive?", &mstch_swift_field::is_recursive_reference},
562             {"field:negativeId?", &mstch_swift_field::is_negative_id},
563             {"field:javaAnnotations?",
564              &mstch_swift_field::has_java_annotations},
565             {"field:javaAnnotations", &mstch_swift_field::java_annotations},
566             {"field:javaTFieldName", &mstch_swift_field::java_tfield_name},
567             {"field:isNullableOrOptionalNotEnum?",
568              &mstch_swift_field::is_nullable_or_optional_not_enum},
569             {"field:nestedDepth", &mstch_swift_field::get_nested_depth},
570             {"field:nestedDepth++", &mstch_swift_field::increment_nested_depth},
571             {"field:nestedDepth--", &mstch_swift_field::decrement_nested_depth},
572             {"field:isFirstDepth?", &mstch_swift_field::is_first_depth},
573             {"field:prevNestedDepth",
574              &mstch_swift_field::preceding_nested_depth},
575             {"field:isContainer?", &mstch_swift_field::is_container},
576             {"field:isNested?", &mstch_swift_field::get_nested_container_flag},
577             {"field:setIsNested",
578              &mstch_swift_field::set_nested_container_flag},
579             {"field:typeFieldName", &mstch_swift_field::type_field_name},
580             {"field:isSensitive?", &mstch_swift_field::is_sensitive},
581             {"field:hasInitialValue?", &mstch_swift_field::has_initial_value},
582             {"field:isPrimitive?", &mstch_swift_field::is_primitive},
583         });
584   }
585 
586   int32_t nestedDepth = 0;
587   bool isNestedContainerFlag = false;
588 
has_initial_value()589   mstch::node has_initial_value() {
590     if (field_->get_req() == t_field::e_req::optional) {
591       // default values are ignored for optional fields
592       return false;
593     }
594     return field_->get_value();
595   }
get_nested_depth()596   mstch::node get_nested_depth() { return nestedDepth; }
preceding_nested_depth()597   mstch::node preceding_nested_depth() { return (nestedDepth - 1); }
is_first_depth()598   mstch::node is_first_depth() { return (nestedDepth == 1); }
get_nested_container_flag()599   mstch::node get_nested_container_flag() { return isNestedContainerFlag; }
set_nested_container_flag()600   mstch::node set_nested_container_flag() {
601     isNestedContainerFlag = true;
602     return mstch::node();
603   }
increment_nested_depth()604   mstch::node increment_nested_depth() {
605     nestedDepth++;
606     return mstch::node();
607   }
decrement_nested_depth()608   mstch::node decrement_nested_depth() {
609     nestedDepth--;
610     return mstch::node();
611   }
is_primitive()612   mstch::node is_primitive() {
613     auto type = field_->get_type()->get_true_type();
614     return type->is_void() || type->is_bool() || type->is_byte() ||
615         type->is_i16() || type->is_i32() || type->is_i64() ||
616         type->is_double() || type->is_float();
617   }
618 
is_nullable_or_optional_not_enum()619   mstch::node is_nullable_or_optional_not_enum() {
620     if (field_->get_req() == t_field::e_req::optional) {
621       return true;
622     }
623     const t_type* field_type = field_->get_type()->get_true_type();
624     return !(
625         field_type->is_bool() || field_type->is_byte() ||
626         field_type->is_float() || field_type->is_i16() ||
627         field_type->is_i32() || field_type->is_i64() ||
628         field_type->is_double() || field_type->is_enum());
629   }
630 
is_container()631   mstch::node is_container() {
632     return field_->get_type()->get_true_type()->is_container();
633   }
java_name()634   mstch::node java_name() { return get_java_swift_name(field_); }
635 
type_field_name()636   mstch::node type_field_name() {
637     auto type_name = field_->get_type()->get_full_name();
638     return java::mangle_java_name(type_name, true);
639   }
640 
java_tfield_name()641   mstch::node java_tfield_name() {
642     return constant_name(field_->get_name()) + "_FIELD_DESC";
643   }
java_capital_name()644   mstch::node java_capital_name() {
645     return java::mangle_java_name(
646         field_->get_annotation("java.swift.name", &field_->get_name()), true);
647   }
java_all_caps_name()648   mstch::node java_all_caps_name() {
649     auto field_name = field_->get_name();
650     boost::to_upper(field_name);
651     return field_name;
652   }
java_default_value()653   mstch::node java_default_value() { return default_value_for_field(field_); }
is_recursive_reference()654   mstch::node is_recursive_reference() {
655     return field_->get_annotation("swift.recursive_reference") == "true";
656   }
is_negative_id()657   mstch::node is_negative_id() { return field_->get_key() < 0; }
default_value_for_field(const t_field * field)658   std::string default_value_for_field(const t_field* field) {
659     if (field_->get_req() == t_field::e_req::optional) {
660       return "null";
661     }
662     return default_value_for_type(field->get_type());
663   }
default_value_for_type(const t_type * type)664   std::string default_value_for_type(const t_type* type) {
665     if (type->is_typedef()) {
666       auto typedef_type = dynamic_cast<const t_typedef*>(type)->get_type();
667       return default_value_for_type(typedef_type);
668     } else {
669       if (type->is_byte() || type->is_i16() || type->is_i32()) {
670         return "0";
671       } else if (type->is_i64()) {
672         return "0L";
673       } else if (type->is_float()) {
674         return "0.f";
675       } else if (type->is_double()) {
676         return "0.";
677       } else if (type->is_bool()) {
678         return "false";
679       } else if (type->is_enum()) {
680         // we use fromInteger(0) as default value as it may be null or the enum
681         // entry for 0.
682         auto javaNamespace = get_namespace_or_default(*(type->program()));
683         auto enumType = java::mangle_java_name(type->get_name(), true);
684         return javaNamespace + "." + enumType + ".fromInteger(0)";
685       }
686       return "null";
687     }
688   }
has_java_annotations()689   mstch::node has_java_annotations() {
690     return field_->has_annotation("java.swift.annotations");
691   }
is_sensitive()692   mstch::node is_sensitive() {
693     return field_->has_annotation("java.sensitive");
694   }
constant_name(string name)695   std::string constant_name(string name) {
696     string constant_str;
697 
698     bool is_first = true;
699     bool was_previous_char_upper = false;
700     for (string::iterator iter = name.begin(); iter != name.end(); ++iter) {
701       string::value_type character = (*iter);
702       bool is_upper = isupper(character);
703       if (is_upper && !is_first && !was_previous_char_upper) {
704         constant_str += '_';
705       }
706       constant_str += toupper(character);
707       is_first = false;
708       was_previous_char_upper = is_upper;
709     }
710     return constant_str;
711   }
java_annotations()712   mstch::node java_annotations() {
713     return field_->get_annotation("java.swift.annotations");
714   }
715 };
716 
717 class mstch_swift_enum : public mstch_enum {
718  public:
mstch_swift_enum(t_enum const * enm,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION const pos)719   mstch_swift_enum(
720       t_enum const* enm,
721       std::shared_ptr<mstch_generators const> generators,
722       std::shared_ptr<mstch_cache> cache,
723       ELEMENT_POSITION const pos)
724       : mstch_enum(enm, generators, cache, pos) {
725     register_methods(
726         this,
727         {
728             {"enum:javaPackage", &mstch_swift_enum::java_package},
729             {"enum:javaCapitalName", &mstch_swift_enum::java_capital_name},
730             {"enum:skipEnumNameMap?",
731              &mstch_swift_enum::java_skip_enum_name_map},
732         });
733   }
java_package()734   mstch::node java_package() {
735     return get_namespace_or_default(*(enm_->program()));
736   }
java_capital_name()737   mstch::node java_capital_name() {
738     return java::mangle_java_name(enm_->get_name(), true);
739   }
java_skip_enum_name_map()740   mstch::node java_skip_enum_name_map() {
741     return enm_->has_annotation("java.swift.skip_enum_name_map");
742   }
743 };
744 
745 class mstch_swift_enum_value : public mstch_enum_value {
746  public:
mstch_swift_enum_value(t_enum_value const * enm_value,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION const pos)747   mstch_swift_enum_value(
748       t_enum_value const* enm_value,
749       std::shared_ptr<mstch_generators const> generators,
750       std::shared_ptr<mstch_cache> cache,
751       ELEMENT_POSITION const pos)
752       : mstch_enum_value(enm_value, generators, cache, pos) {
753     register_methods(
754         this,
755         {
756             {"enum_value:javaConstantName",
757              &mstch_swift_enum_value::java_constant_name},
758         });
759   }
java_constant_name()760   mstch::node java_constant_name() {
761     return java::mangle_java_constant_name(enm_value_->get_name());
762   }
763 };
764 
765 class mstch_swift_const : public mstch_const {
766  public:
mstch_swift_const(t_const const * cnst,t_const const * current_const,t_type const * expected_type,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION const pos,int32_t index,t_field const * field)767   mstch_swift_const(
768       t_const const* cnst,
769       t_const const* current_const,
770       t_type const* expected_type,
771       std::shared_ptr<mstch_generators const> generators,
772       std::shared_ptr<mstch_cache> cache,
773       ELEMENT_POSITION const pos,
774       int32_t index,
775       t_field const* field)
776       : mstch_const(
777             cnst,
778             current_const,
779             expected_type,
780             generators,
781             cache,
782             pos,
783             index,
784             field) {
785     register_methods(
786         this,
787         {
788             {"constant:javaCapitalName", &mstch_swift_const::java_capital_name},
789             {"constant:javaFieldName", &mstch_swift_const::java_field_name},
790             {"constant:javaIgnoreConstant?",
791              &mstch_swift_const::java_ignore_constant},
792         });
793   }
java_capital_name()794   mstch::node java_capital_name() {
795     return java::mangle_java_constant_name(cnst_->get_name());
796   }
java_field_name()797   mstch::node java_field_name() {
798     return java::mangle_java_name(field_->get_name(), true);
799   }
java_ignore_constant()800   mstch::node java_ignore_constant() {
801     // we have to ignore constants if they are enums that we handled as ints, as
802     // we don't have the constant values to work with.
803     if (cnst_->get_type()->is_map()) {
804       t_map* map = (t_map*)cnst_->get_type();
805       if (map->get_key_type()->is_enum()) {
806         return map->get_key_type()->has_annotation(
807             "java.swift.skip_enum_name_map");
808       }
809     }
810     if (cnst_->get_type()->is_list()) {
811       t_list* list = (t_list*)cnst_->get_type();
812       if (list->get_elem_type()->is_enum()) {
813         return list->get_elem_type()->has_annotation(
814             "java.swift.skip_enum_name_map");
815       }
816     }
817     if (cnst_->get_type()->is_set()) {
818       t_set* set = (t_set*)cnst_->get_type();
819       if (set->get_elem_type()->is_enum()) {
820         return set->get_elem_type()->has_annotation(
821             "java.swift.skip_enum_name_map");
822       }
823     }
824     return mstch::node();
825   }
826 };
827 
828 class mstch_swift_const_value : public mstch_const_value {
829  public:
mstch_swift_const_value(t_const_value const * const_value,t_const const * current_const,t_type const * expected_type,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos,int32_t index)830   mstch_swift_const_value(
831       t_const_value const* const_value,
832       t_const const* current_const,
833       t_type const* expected_type,
834       std::shared_ptr<mstch_generators const> generators,
835       std::shared_ptr<mstch_cache> cache,
836       ELEMENT_POSITION pos,
837       int32_t index)
838       : mstch_const_value(
839             const_value,
840             current_const,
841             expected_type,
842             generators,
843             cache,
844             pos,
845             index) {
846     register_methods(
847         this,
848         {
849             {"value:quotedString", &mstch_swift_const_value::quote_java_string},
850             {"value:javaEnumValueName",
851              &mstch_swift_const_value::java_enum_value_name},
852         });
853   }
quote_java_string()854   mstch::node quote_java_string() {
855     return java::quote_java_string(const_value_->get_string());
856   }
java_enum_value_name()857   mstch::node java_enum_value_name() {
858     if (type_ == cv::CV_INTEGER && const_value_->is_enum()) {
859       const t_enum_value* enum_value = const_value_->get_enum_value();
860       if (enum_value != nullptr) {
861         return java::mangle_java_constant_name(enum_value->get_name());
862       }
863       return "fromInteger(" + std::to_string(const_value_->get_integer()) + ")";
864     }
865     return mstch::node();
866   }
same_type_as_expected() const867   bool same_type_as_expected() const override { return true; }
868 };
869 
870 class mstch_swift_type : public mstch_type {
871  public:
mstch_swift_type(t_type const * type,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION const pos)872   mstch_swift_type(
873       t_type const* type,
874       std::shared_ptr<mstch_generators const> generators,
875       std::shared_ptr<mstch_cache> cache,
876       ELEMENT_POSITION const pos)
877       : mstch_type(type, generators, cache, pos) {
878     register_methods(
879         this,
880         {
881             {"type:primitive?", &mstch_swift_type::is_primitive},
882             {"type:isContainer?", &mstch_swift_type::is_container_type},
883             {"type:javaType", &mstch_swift_type::java_type},
884             {"type:setIsMapKey", &mstch_swift_type::set_is_map_key},
885             {"type:isMapKey?", &mstch_swift_type::get_map_key_flag},
886             {"type:setIsMapValue", &mstch_swift_type::set_is_map_value},
887             {"type:isMapValue?", &mstch_swift_type::get_map_value_flag},
888             {"type:isBinaryString?", &mstch_swift_type::is_binary_string},
889             {"type:setIsNotMap", &mstch_swift_type::set_is_not_map},
890         });
891   }
892   bool isMapValueFlag = false;
893   bool isMapKeyFlag = false;
894 
set_is_not_map()895   mstch::node set_is_not_map() {
896     isMapValueFlag = false;
897     isMapKeyFlag = false;
898     return mstch::node();
899   }
get_map_value_flag()900   mstch::node get_map_value_flag() { return isMapValueFlag; }
get_map_key_flag()901   mstch::node get_map_key_flag() { return isMapKeyFlag; }
set_is_map_value()902   mstch::node set_is_map_value() {
903     isMapValueFlag = true;
904     return mstch::node();
905   }
set_is_map_key()906   mstch::node set_is_map_key() {
907     isMapKeyFlag = true;
908     return mstch::node();
909   }
910 
is_container_type()911   mstch::node is_container_type() {
912     return type_->get_true_type()->is_container();
913   }
914 
is_primitive()915   mstch::node is_primitive() {
916     return type_->is_void() || type_->is_bool() || type_->is_byte() ||
917         type_->is_i16() || type_->is_i32() || type_->is_i64() ||
918         type_->is_double() || type_->is_float();
919   }
java_type()920   mstch::node java_type() {
921     return type_->get_true_type()->get_annotation("java.swift.type");
922   }
is_binary_string()923   mstch::node is_binary_string() {
924     return type_->get_true_type()->get_annotation("java.swift.binary_string");
925   }
926 };
927 
928 class program_swift_generator : public program_generator {
929  public:
930   program_swift_generator() = default;
931   ~program_swift_generator() override = default;
generate(t_program const * program,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos,int32_t) const932   std::shared_ptr<mstch_base> generate(
933       t_program const* program,
934       std::shared_ptr<mstch_generators const> generators,
935       std::shared_ptr<mstch_cache> cache,
936       ELEMENT_POSITION pos,
937       int32_t /*index*/) const override {
938     return std::make_shared<mstch_swift_program>(
939         program, generators, cache, pos);
940   }
941 };
942 
943 class struct_swift_generator : public struct_generator {
944  public:
945   explicit struct_swift_generator() = default;
946   ~struct_swift_generator() override = default;
generate(t_struct const * strct,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos,int32_t) const947   std::shared_ptr<mstch_base> generate(
948       t_struct const* strct,
949       std::shared_ptr<mstch_generators const> generators,
950       std::shared_ptr<mstch_cache> cache,
951       ELEMENT_POSITION pos,
952       int32_t /*index*/) const override {
953     return std::make_shared<mstch_swift_struct>(strct, generators, cache, pos);
954   }
955 };
956 
957 class service_swift_generator : public service_generator {
958  public:
959   explicit service_swift_generator() = default;
960   ~service_swift_generator() override = default;
generate(t_service const * service,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos,int32_t) const961   std::shared_ptr<mstch_base> generate(
962       t_service const* service,
963       std::shared_ptr<mstch_generators const> generators,
964       std::shared_ptr<mstch_cache> cache,
965       ELEMENT_POSITION pos,
966       int32_t /*index*/) const override {
967     return std::make_shared<mstch_swift_service>(
968         service, generators, cache, pos);
969   }
970 };
971 
972 class function_swift_generator : public function_generator {
973  public:
974   function_swift_generator() = default;
975   ~function_swift_generator() override = default;
generate(t_function const * function,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos,int32_t) const976   std::shared_ptr<mstch_base> generate(
977       t_function const* function,
978       std::shared_ptr<mstch_generators const> generators,
979       std::shared_ptr<mstch_cache> cache,
980       ELEMENT_POSITION pos,
981       int32_t /*index*/) const override {
982     return std::make_shared<mstch_swift_function>(
983         function, generators, cache, pos);
984   }
985 };
986 
987 class field_swift_generator : public field_generator {
988  public:
989   field_swift_generator() = default;
990   ~field_swift_generator() override = default;
generate(t_field const * field,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos,int32_t index,field_generator_context const * field_context) const991   std::shared_ptr<mstch_base> generate(
992       t_field const* field,
993       std::shared_ptr<mstch_generators const> generators,
994       std::shared_ptr<mstch_cache> cache,
995       ELEMENT_POSITION pos,
996       int32_t index,
997       field_generator_context const* field_context) const override {
998     return std::make_shared<mstch_swift_field>(
999         field, generators, cache, pos, index, field_context);
1000   }
1001 };
1002 
1003 class enum_swift_generator : public enum_generator {
1004  public:
1005   explicit enum_swift_generator() = default;
1006   ~enum_swift_generator() override = default;
generate(t_enum const * enm,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos,int32_t) const1007   std::shared_ptr<mstch_base> generate(
1008       t_enum const* enm,
1009       std::shared_ptr<mstch_generators const> generators,
1010       std::shared_ptr<mstch_cache> cache,
1011       ELEMENT_POSITION pos,
1012       int32_t /*index*/) const override {
1013     return std::make_shared<mstch_swift_enum>(enm, generators, cache, pos);
1014   }
1015 };
1016 
1017 class enum_value_swift_generator : public enum_value_generator {
1018  public:
1019   enum_value_swift_generator() = default;
1020   ~enum_value_swift_generator() override = default;
generate(t_enum_value const * enm_value,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos,int32_t) const1021   std::shared_ptr<mstch_base> generate(
1022       t_enum_value const* enm_value,
1023       std::shared_ptr<mstch_generators const> generators,
1024       std::shared_ptr<mstch_cache> cache,
1025       ELEMENT_POSITION pos,
1026       int32_t /*index*/) const override {
1027     return std::make_shared<mstch_swift_enum_value>(
1028         enm_value, generators, cache, pos);
1029   }
1030 };
1031 
1032 class type_swift_generator : public type_generator {
1033  public:
1034   type_swift_generator() = default;
1035   ~type_swift_generator() override = default;
generate(t_type const * type,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos,int32_t) const1036   std::shared_ptr<mstch_base> generate(
1037       t_type const* type,
1038       std::shared_ptr<mstch_generators const> generators,
1039       std::shared_ptr<mstch_cache> cache,
1040       ELEMENT_POSITION pos,
1041       int32_t /*index*/) const override {
1042     return std::make_shared<mstch_swift_type>(type, generators, cache, pos);
1043   }
1044 };
1045 
1046 class const_swift_generator : public const_generator {
1047  public:
1048   const_swift_generator() = default;
1049   ~const_swift_generator() override = default;
generate(t_const const * cnst,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos,int32_t index,t_const const * current_const,t_type const * expected_type,t_field const * field) const1050   std::shared_ptr<mstch_base> generate(
1051       t_const const* cnst,
1052       std::shared_ptr<mstch_generators const> generators,
1053       std::shared_ptr<mstch_cache> cache,
1054       ELEMENT_POSITION pos,
1055       int32_t index,
1056       t_const const* current_const,
1057       t_type const* expected_type,
1058       t_field const* field) const override {
1059     return std::make_shared<mstch_swift_const>(
1060         cnst,
1061         current_const,
1062         expected_type,
1063         generators,
1064         cache,
1065         pos,
1066         index,
1067         field);
1068   }
1069 };
1070 
1071 class const_value_swift_generator : public const_value_generator {
1072  public:
1073   const_value_swift_generator() = default;
1074   ~const_value_swift_generator() override = default;
generate(t_const_value const * const_value,std::shared_ptr<mstch_generators const> generators,std::shared_ptr<mstch_cache> cache,ELEMENT_POSITION pos,int32_t index,t_const const * current_const,t_type const * expected_type) const1075   std::shared_ptr<mstch_base> generate(
1076       t_const_value const* const_value,
1077       std::shared_ptr<mstch_generators const> generators,
1078       std::shared_ptr<mstch_cache> cache,
1079       ELEMENT_POSITION pos,
1080       int32_t index,
1081       t_const const* current_const,
1082       t_type const* expected_type) const override {
1083     return std::make_shared<mstch_swift_const_value>(
1084         const_value,
1085         current_const,
1086         expected_type,
1087         generators,
1088         cache,
1089         pos,
1090         index);
1091   }
1092 };
1093 
generate_program()1094 void t_mstch_swift_generator::generate_program() {
1095   set_mstch_generators();
1096 
1097   auto name = get_program()->name();
1098   const auto& id = get_program()->path();
1099   if (!cache_->programs_.count(id)) {
1100     cache_->programs_[id] = generators_->program_generator_->generate(
1101         get_program(), generators_, cache_);
1102   }
1103 
1104   generate_items(
1105       generators_->struct_generator_.get(),
1106       cache_->structs_,
1107       get_program(),
1108       get_program()->objects(),
1109       "Object");
1110   generate_items(
1111       generators_->service_generator_.get(),
1112       cache_->services_,
1113       get_program(),
1114       get_program()->services(),
1115       "Service");
1116   generate_client(
1117       generators_->service_generator_.get(),
1118       cache_->services_,
1119       get_program(),
1120       get_program()->services());
1121   generate_items(
1122       generators_->enum_generator_.get(),
1123       cache_->enums_,
1124       get_program(),
1125       get_program()->enums(),
1126       "Enum");
1127   generate_constants(get_program());
1128   generate_placeholder(get_program());
1129 }
1130 
set_mstch_generators()1131 void t_mstch_swift_generator::set_mstch_generators() {
1132   generators_->set_program_generator(
1133       std::make_unique<program_swift_generator>());
1134   generators_->set_struct_generator(std::make_unique<struct_swift_generator>());
1135   generators_->set_service_generator(
1136       std::make_unique<service_swift_generator>());
1137   generators_->set_function_generator(
1138       std::make_unique<function_swift_generator>());
1139   generators_->set_field_generator(std::make_unique<field_swift_generator>());
1140   generators_->set_enum_generator(std::make_unique<enum_swift_generator>());
1141   generators_->set_enum_value_generator(
1142       std::make_unique<enum_value_swift_generator>());
1143   generators_->set_type_generator(std::make_unique<type_swift_generator>());
1144   generators_->set_const_generator(std::make_unique<const_swift_generator>());
1145   generators_->set_const_value_generator(
1146       std::make_unique<const_value_swift_generator>());
1147 }
1148 
1149 THRIFT_REGISTER_GENERATOR(mstch_swift, "Java Swift", "");
1150 
1151 } // namespace compiler
1152 } // namespace thrift
1153 } // namespace apache
1154