1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  *
19  * Contains some contributions under the Thrift Software License.
20  * Please see doc/old-thrift-license.txt in the Thrift distribution for
21  * details.
22  */
23 
24 #include <cassert>
25 
26 #include <string>
27 #include <fstream>
28 #include <iostream>
29 #include <vector>
30 #include <list>
31 
32 #include <stdlib.h>
33 #include <sys/stat.h>
34 #include <sstream>
35 #include <cctype>
36 
37 #include "thrift/platform.h"
38 #include "thrift/generate/t_oop_generator.h"
39 
40 #ifdef _WIN32
41 #include <locale>
42 #include <codecvt>
43 #include <combaseapi.h>
44 #include <guiddef.h>
45 #endif
46 
47 using std::map;
48 using std::ofstream;
49 using std::ostream;
50 using std::ostringstream;
51 using std::string;
52 using std::stringstream;
53 using std::vector;
54 
55 static const string endl = "\n"; // avoid ostream << std::endl flushes
56 
57 class t_delphi_generator : public t_oop_generator {
58 public:
t_delphi_generator(t_program * program,const std::map<std::string,std::string> & parsed_options,const std::string & option_string)59   t_delphi_generator(t_program* program,
60                      const std::map<std::string, std::string>& parsed_options,
61                      const std::string& option_string)
62     : t_oop_generator(program) {
63     (void)option_string;
64     indent_impl_ = 0;
65     has_forward = false;
66     has_enum = false;
67     has_const = false;
68     std::map<std::string, std::string>::const_iterator iter;
69 
70     ansistr_binary_ = false;
71     register_types_ = false;
72     constprefix_ = false;
73     events_ = false;
74     xmldoc_ = false;
75     async_ = false;
76     for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
77       if( iter->first.compare("ansistr_binary") == 0) {
78         ansistr_binary_ = true;
79       } else if( iter->first.compare("register_types") == 0) {
80         register_types_ = true;
81       } else if( iter->first.compare("constprefix") == 0) {
82         constprefix_ = true;
83       } else if( iter->first.compare("events") == 0) {
84         events_ = true;
85       } else if( iter->first.compare("xmldoc") == 0) {
86         xmldoc_ = true;
87       } else if( iter->first.compare("async") == 0) {
88         async_ = true;
89       } else {
90         throw "unknown option delphi:" + iter->first;
91       }
92     }
93 
94     out_dir_base_ = "gen-delphi";
95     escape_.clear();
96     escape_['\''] = "''";
97   }
98 
99   void init_generator() override;
100   void close_generator() override;
101 
102   void generate_consts(std::vector<t_const*> consts) override;
103 
104   void generate_typedef(t_typedef* ttypedef) override;
105   void generate_enum(t_enum* tenum) override;
106   void generate_forward_declaration(t_struct* tstruct) override;
107   void generate_struct(t_struct* tstruct) override;
108   void generate_xception(t_struct* txception) override;
109   void generate_service(t_service* tservice) override;
110   void generate_property(ostream& out, t_field* tfield, bool isPublic, bool is_xception);
111   void generate_property_writer_(ostream& out, t_field* tfield, bool isPublic);
112 
113   void generate_delphi_property(ostream& out,
114                                 bool struct_is_exception,
115                                 t_field* tfield,
116                                 bool isPublic,
117                                 std::string fieldPrefix = "");
118   void generate_delphi_isset_reader_writer_definition(ostream& out, t_field* tfield, bool is_xception);
119   void generate_delphi_property_reader_definition(ostream& out,
120                                                   t_field* tfield,
121                                                   bool is_xception_class);
122   void generate_delphi_property_writer_definition(ostream& out,
123                                                   t_field* tfield,
124                                                   bool is_xception_class);
125   void generate_delphi_property_reader_impl(ostream& out,
126                                             std::string cls_prefix,
127                                             std::string name,
128                                             t_type* type,
129                                             t_field* tfield,
130                                             std::string fieldPrefix,
131                                             bool is_xception_class);
132   void generate_delphi_property_writer_impl(ostream& out,
133                                             std::string cls_prefix,
134                                             std::string name,
135                                             t_type* type,
136                                             t_field* tfield,
137                                             std::string fieldPrefix,
138                                             bool is_xception_class,
139                                             bool is_union,
140                                             bool is_xception_factory,
141                                             std::string xception_factory_name);
142   void generate_delphi_clear_union_value(ostream& out,
143                                          std::string cls_prefix,
144                                          std::string name,
145                                          t_type* type,
146                                          t_field* tfield,
147                                          std::string fieldPrefix,
148                                          bool is_xception_class,
149                                          bool is_union,
150                                          bool is_xception_factory,
151                                          std::string xception_factory_name);
152   void generate_delphi_isset_reader_writer_impl(ostream& out,
153                                          std::string cls_prefix,
154                                          std::string name,
155                                          t_type* type,
156                                          t_field* tfield,
157                                          std::string fieldPrefix,
158                                          bool is_xception);
159   void generate_delphi_struct_writer_impl(ostream& out,
160                                           std::string cls_prefix,
161                                           t_struct* tstruct,
162                                           bool is_exception,
163                                           bool is_x_factory);
164   void generate_delphi_struct_result_writer_impl(ostream& out,
165                                                  std::string cls_prefix,
166                                                  t_struct* tstruct,
167                                                  bool is_exception,
168                                                  bool is_x_factory);
169 
170   void generate_delphi_struct_tostring_impl(ostream& out,
171                                             std::string cls_prefix,
172                                             t_struct* tstruct,
173                                             bool is_exception,
174                                             bool is_x_factory);
175 
176   void add_delphi_uses_list(string unitname);
177 
178   void generate_delphi_struct_reader_impl(ostream& out,
179                                           std::string cls_prefix,
180                                           t_struct* tstruct,
181                                           bool is_exception,
182                                           bool is_x_factory);
183   void generate_delphi_create_exception_impl(ostream& out,
184                                              string cls_prefix,
185                                              t_struct* tstruct,
186                                              bool is_exception);
187 
188   bool const_needs_var(t_type* type);
189   void print_const_prop(std::ostream& out, string name, t_type* type, t_const_value* value);
190   void print_private_field(std::ostream& out, string name, t_type* type, t_const_value* value);
191   void print_const_value(std::ostream& vars,
192                          std::ostream& out,
193                          std::string name,
194                          t_type* type,
195                          t_const_value* value);
196   void initialize_field(std::ostream& vars,
197                         std::ostream& out,
198                         std::string name,
199                         t_type* type,
200                         t_const_value* value);
201   void finalize_field(std::ostream& out,
202                       std::string name,
203                       t_type* type,
204                       t_const_value* value,
205                       std::string cls_nm = "");
206   std::string render_const_value(std::ostream& local_vars,
207                                  std::ostream& out,
208                                  std::string name,
209                                  t_type* type,
210                                  t_const_value* value);
211   void print_const_def_value(std::ostream& vars,
212                              std::ostream& out,
213                              std::string name,
214                              t_type* type,
215                              t_const_value* value,
216                              std::string cls_nm = "");
217   std::string make_constants_classname();
218 
219   void generate_delphi_struct(t_struct* tstruct, bool is_exception);
220   void generate_delphi_struct_impl(ostream& out,
221                                    std::string cls_prefix,
222                                    t_struct* tstruct,
223                                    bool is_exception,
224                                    bool is_result = false,
225                                    bool is_x_factory = false);
226   void print_delphi_struct_type_factory_func(ostream& out, t_struct* tstruct);
227   void generate_delphi_struct_type_factory(ostream& out,
228                                            std::string cls_prefix,
229                                            t_struct* tstruct,
230                                            bool is_exception,
231                                            bool is_result = false,
232                                            bool is_x_factory = false);
233   void generate_delphi_struct_type_factory_registration(ostream& out,
234                                                         std::string cls_prefix,
235                                                         t_struct* tstruct,
236                                                         bool is_exception,
237                                                         bool is_result = false,
238                                                         bool is_x_factory = false);
239   void generate_delphi_struct_definition(std::ostream& out,
240                                          t_struct* tstruct,
241                                          bool is_xception = false,
242                                          bool in_class = false,
243                                          bool is_result = false,
244                                          bool is_x_factory = false);
245   void generate_delphi_struct_reader(std::ostream& out, t_struct* tstruct);
246   void generate_delphi_struct_result_writer(std::ostream& out, t_struct* tstruct);
247   void generate_delphi_struct_writer(std::ostream& out, t_struct* tstruct);
248   void generate_delphi_struct_tostring(std::ostream& out, t_struct* tstruct);
249 
250   void generate_function_helpers(t_function* tfunction);
251   void generate_service_interface(t_service* tservice);
252   void generate_service_interface(t_service* tservice, bool for_async);
253   void generate_guid(std::ostream& out);
254   void generate_service_helpers(t_service* tservice);
255   void generate_service_client(t_service* tservice);
256   void generate_service_server(t_service* tservice);
257   void generate_process_function(t_service* tservice, t_function* function);
258 
259   void generate_deserialize_field(std::ostream& out,
260                                   bool is_xception,
261                                   t_field* tfield,
262                                   std::string prefix,
263                                   std::ostream& local_vars);
264   void generate_deserialize_struct(std::ostream& out,
265                                    t_struct* tstruct,
266                                    std::string name,
267                                    std::string prefix);
268   void generate_deserialize_container(ostream& out,
269                                       bool is_xception,
270                                       t_type* ttype,
271                                       string name,
272                                       std::ostream& local_vars);
273 
274   void generate_deserialize_set_element(std::ostream& out,
275                                         bool is_xception,
276                                         t_set* tset,
277                                         std::string prefix,
278                                         std::ostream& local_vars);
279   void generate_deserialize_map_element(std::ostream& out,
280                                         bool is_xception,
281                                         t_map* tmap,
282                                         std::string prefix,
283                                         std::ostream& local_vars);
284   void generate_deserialize_list_element(std::ostream& out,
285                                          bool is_xception,
286                                          t_list* list,
287                                          std::string prefix,
288                                          std::ostream& local_vars);
289 
290   void generate_serialize_field(std::ostream& out,
291                                 bool is_xception,
292                                 t_field* tfield,
293                                 std::string prefix,
294                                 std::ostream& local_vars);
295   void generate_serialize_struct(std::ostream& out,
296                                  t_struct* tstruct,
297                                  std::string prefix,
298                                  std::ostream& local_vars);
299   void generate_serialize_container(std::ostream& out,
300                                     bool is_xception,
301                                     t_type* ttype,
302                                     std::string prefix,
303                                     std::ostream& local_vars);
304   void generate_serialize_map_element(std::ostream& out,
305                                       bool is_xception,
306                                       t_map* tmap,
307                                       std::string iter,
308                                       std::string map,
309                                       std::ostream& local_vars);
310   void generate_serialize_set_element(std::ostream& out,
311                                       bool is_xception,
312                                       t_set* tmap,
313                                       std::string iter,
314                                       std::ostream& local_vars);
315   void generate_serialize_list_element(std::ostream& out,
316                                        bool is_xception,
317                                        t_list* tlist,
318                                        std::string iter,
319                                        std::ostream& local_vars);
320 
321   void delphi_type_usings(std::ostream& out);
322   std::string delphi_thrift_usings();
323 
324   std::string type_name(t_type* ttype,
325                         bool b_cls = false,
326                         bool b_no_postfix = false,
327                         bool b_exception_factory = false,
328                         bool b_full_exception_factory = false);
329   std::string normalize_clsnm(std::string name,
330                               std::string prefix,
331                               bool b_no_check_keyword = false);
332   std::string make_valid_delphi_identifier(std::string const& fromName);
333   std::string make_pascal_string_literal( std::string value);
334   std::string input_arg_prefix(t_type* ttype);
335 
336   std::string base_type_name(t_base_type* tbase);
337   std::string declare_field(t_field* tfield,
338                             bool init = false,
339                             std::string prefix = "",
340                             bool is_xception_class = false);
341   std::string function_signature(t_function* tfunction,
342                                  bool for_async,
343                                  std::string full_cls = "",
344                                  bool is_xception = false);
345   std::string argument_list(t_struct* tstruct);
346   std::string constructor_argument_list(t_struct* tstruct, std::string current_indent);
347   std::string type_to_enum(t_type* ttype);
348   std::string prop_name(t_field* tfield, bool is_xception = false);
349   std::string prop_name(std::string name, bool is_xception = false);
350   std::string constructor_param_name(string name);
351 
352   void write_enum(std::string line);
353   void write_forward_decr(std::string line);
354   void write_const(std::string line);
355   void write_struct(std::string line);
356   void write_service(std::string line);
357 
autogen_comment()358   std::string autogen_comment() override {
359     return std::string("(**\n") + " * Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n"
360            + " *\n" + " * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n"
361            + " *)\n";
362   }
363 
364   string replace_all(string contents, string search, string replace);
365   string xml_encode(string contents);
366   string xmldoc_encode(string contents);
367   string xmlattrib_encode(string contents);
368   void generate_delphi_doc(std::ostream& out, t_field* field);
369   void generate_delphi_doc(std::ostream& out, t_doc* tdoc);
370   void generate_delphi_doc(std::ostream& out, t_function* tdoc);
371   void generate_delphi_docstring_comment(std::ostream& out, string contents);
372 
type_can_be_null(t_type * ttype)373   bool type_can_be_null(t_type* ttype) {
374     while (ttype->is_typedef()) {
375       ttype = ((t_typedef*)ttype)->get_type();
376     }
377 
378     return ttype->is_container() || ttype->is_struct() || ttype->is_xception();
379   }
380 
381 private:
382   std::string namespace_name_;
383   std::ostringstream s_forward_decr;
384   std::ostringstream s_enum;
385   std::ostringstream s_const;
386   std::ostringstream s_struct;
387   std::ostringstream s_service;
388   std::ostringstream s_const_impl;
389   std::ostringstream s_struct_impl;
390   std::ostringstream s_service_impl;
391   std::ostringstream s_type_factory_registration;
392   std::ostringstream s_type_factory_funcs;
393   bool has_forward;
394   bool has_enum;
395   bool has_const;
396   std::string namespace_dir_;
397   std::map<std::string, int> delphi_keywords;
398   std::map<std::string, int> delphi_reserved_method;
399   std::map<std::string, int> delphi_reserved_method_exception;
400   std::map<std::string, int> types_known;
401   std::list<t_typedef*> typedefs_pending;
402   std::vector<std::string> uses_list;
403   void create_keywords();
404   bool find_keyword(std::map<std::string, int>& keyword_map, std::string name);
405   std::string normalize_name(std::string name,
406                              bool b_method = false,
407                              bool b_exception_method = false);
408   std::string empty_value(t_type* type);
409   bool is_fully_defined_type(t_type* ttype);
410   void add_defined_type(t_type* ttype);
411   void init_known_types_list();
412   bool is_void(t_type* type);
413   int indent_impl_;
414   bool ansistr_binary_;
415   bool register_types_;
416   bool constprefix_;
417   bool events_;
418   bool xmldoc_;
419   bool async_;
indent_up_impl()420   void indent_up_impl() { ++indent_impl_; };
indent_down_impl()421   void indent_down_impl() { --indent_impl_; };
indent_impl()422   std::string indent_impl() {
423     std::string ind = "";
424     int i;
425     for (i = 0; i < indent_impl_; ++i) {
426       ind += "  ";
427     }
428     return ind;
429   };
indent_impl(std::ostream & os)430   std::ostream& indent_impl(std::ostream& os) { return os << indent_impl(); };
431 };
432 
replace_all(string contents,string search,string repl)433 string t_delphi_generator::replace_all(string contents, string search, string repl) {
434   string str(contents);
435 
436   size_t slen = search.length();
437   size_t rlen = repl.length();
438   size_t incr = (rlen > 0) ? rlen : 1;
439 
440   if (slen > 0) {
441     size_t found = str.find(search);
442     while ((found != string::npos) && (found < str.length())) {
443       str.replace(found, slen, repl);
444       found = str.find(search, found + incr);
445     }
446   }
447 
448   return str;
449 }
450 
451 // XML encoding
xml_encode(string contents)452 string t_delphi_generator::xml_encode(string contents) {
453   string str(contents);
454 
455   // escape the escape
456   str = replace_all(str, "&", "&amp;");
457 
458   // other standard XML entities
459   str = replace_all(str, "<", "&lt;");
460   str = replace_all(str, ">", "&gt;");
461 
462   return str;
463 }
464 
465 // XML attribute encoding
xmlattrib_encode(string contents)466 string t_delphi_generator::xmlattrib_encode(string contents) {
467   string str(xml_encode(contents));
468 
469   // our attribs are enclosed in "
470   str = replace_all(str, "\"", "\\\"");
471 
472   return str;
473 }
474 
475 // XML encoding for doc comments
xmldoc_encode(string contents)476 string t_delphi_generator::xmldoc_encode(string contents) {
477   string str(xml_encode(contents));
478 
479   // XMLDoc specific: convert linebreaks into <para>graphs</para>
480   str = replace_all(str, "\r\n", "\r");
481   str = replace_all(str, "\n", "\r");
482   str = replace_all(str, "\r", "</para>\n<para>");
483 
484   return str;
485 }
486 
generate_delphi_docstring_comment(ostream & out,string contents)487 void t_delphi_generator::generate_delphi_docstring_comment(ostream& out, string contents) {
488   if (xmldoc_) {
489     generate_docstring_comment(out,
490                                "{$REGION 'XMLDoc'}/// <summary>\n",
491                                "/// ",
492                                "<para>" + contents + "</para>",
493                                "/// </summary>\n{$ENDREGION}\n");
494   }
495 }
496 
generate_delphi_doc(ostream & out,t_field * field)497 void t_delphi_generator::generate_delphi_doc(ostream& out, t_field* field) {
498   if (xmldoc_) {
499     if (field->get_type()->is_enum()) {
500       string combined_message = xmldoc_encode(field->get_doc()) + "\n<seealso cref=\""
501                                 + xmldoc_encode(type_name(field->get_type())) + "\"/>";
502       generate_delphi_docstring_comment(out, combined_message);
503     } else {
504       generate_delphi_doc(out, (t_doc*)field);
505     }
506   }
507 }
508 
generate_delphi_doc(ostream & out,t_doc * tdoc)509 void t_delphi_generator::generate_delphi_doc(ostream& out, t_doc* tdoc) {
510   if (tdoc->has_doc() && xmldoc_) {
511     generate_delphi_docstring_comment(out, xmldoc_encode(tdoc->get_doc()));
512   }
513 }
514 
generate_delphi_doc(ostream & out,t_function * tfunction)515 void t_delphi_generator::generate_delphi_doc(ostream& out, t_function* tfunction) {
516   if (tfunction->has_doc() && xmldoc_) {
517     stringstream ps;
518     const vector<t_field*>& fields = tfunction->get_arglist()->get_members();
519     vector<t_field*>::const_iterator p_iter;
520     for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) {
521       t_field* p = *p_iter;
522       ps << "\n<param name=\"" << xmlattrib_encode(p->get_name()) << "\">";
523       if (p->has_doc()) {
524         std::string str = p->get_doc();
525         str.erase(std::remove(str.begin(), str.end(), '\n'),
526                   str.end()); // remove the newlines that appear from the parser
527         ps << xmldoc_encode(str);
528       }
529       ps << "</param>";
530     }
531     generate_docstring_comment(out,
532                                "{$REGION 'XMLDoc'}",
533                                "/// ",
534                                "<summary><para>" + xmldoc_encode(tfunction->get_doc())
535                                + "</para></summary>" + ps.str(),
536                                "{$ENDREGION}\n");
537   }
538 }
539 
find_keyword(std::map<std::string,int> & keyword_map,std::string name)540 bool t_delphi_generator::find_keyword(std::map<std::string, int>& keyword_map, std::string name) {
541   std::string::size_type len = name.length();
542 
543   if (len <= 0) {
544     return false;
545   }
546 
547   std::string::size_type nlast = name.find_last_of('_');
548 
549   if (nlast >= 1) {
550     if (nlast == (len - 1)) {
551       string new_name(name, 0, nlast);
552       return find_keyword(keyword_map, new_name);
553     }
554   }
555   return (keyword_map[name] == 1);
556 }
557 
normalize_name(std::string name,bool b_method,bool b_exception_method)558 std::string t_delphi_generator::normalize_name(std::string name,
559                                                bool b_method,
560                                                bool b_exception_method) {
561   string tmp(name);
562   std::transform(tmp.begin(), tmp.end(), tmp.begin(), static_cast<int (*)(int)>(std::tolower));
563 
564   bool b_found = false;
565 
566   if (find_keyword(delphi_keywords, tmp)) {
567     b_found = true;
568   } else if (b_method && find_keyword(delphi_reserved_method, tmp)) {
569     b_found = true;
570   } else if (b_exception_method && find_keyword(delphi_reserved_method_exception, tmp)) {
571     b_found = true;
572   }
573 
574   if (b_found) {
575     return name + "_";
576   } else {
577     return name;
578   }
579 }
580 
create_keywords()581 void t_delphi_generator::create_keywords() {
582   delphi_keywords["and"] = 1;
583   delphi_keywords["end"] = 1;
584   delphi_keywords["interface"] = 1;
585   delphi_keywords["raise"] = 1;
586   delphi_keywords["uses"] = 1;
587   delphi_keywords["array"] = 1;
588   delphi_keywords["except"] = 1;
589   delphi_keywords["is"] = 1;
590   delphi_keywords["record"] = 1;
591   delphi_keywords["var"] = 1;
592   delphi_keywords["as"] = 1;
593   delphi_keywords["exports"] = 1;
594   delphi_keywords["label"] = 1;
595   delphi_keywords["repeat"] = 1;
596   delphi_keywords["while"] = 1;
597   delphi_keywords["asm"] = 1;
598   delphi_keywords["file"] = 1;
599   delphi_keywords["library"] = 1;
600   delphi_keywords["resourcestring"] = 1;
601   delphi_keywords["with"] = 1;
602   delphi_keywords["begin"] = 1;
603   delphi_keywords["finalization"] = 1;
604   delphi_keywords["mod"] = 1;
605   delphi_keywords["set"] = 1;
606   delphi_keywords["xor"] = 1;
607   delphi_keywords["case"] = 1;
608   delphi_keywords["finally"] = 1;
609   delphi_keywords["nil"] = 1;
610   delphi_keywords["shl"] = 1;
611   delphi_keywords["class"] = 1;
612   delphi_keywords["for"] = 1;
613   delphi_keywords["not"] = 1;
614   delphi_keywords["shr"] = 1;
615   delphi_keywords["const"] = 1;
616   delphi_keywords["function"] = 1;
617   delphi_keywords["object"] = 1;
618   delphi_keywords["string"] = 1;
619   delphi_keywords["constructor"] = 1;
620   delphi_keywords["goto"] = 1;
621   delphi_keywords["of"] = 1;
622   delphi_keywords["then"] = 1;
623   delphi_keywords["destructor"] = 1;
624   delphi_keywords["if"] = 1;
625   delphi_keywords["or"] = 1;
626   delphi_keywords["threadvar"] = 1;
627   delphi_keywords["dispinterface"] = 1;
628   delphi_keywords["implementation"] = 1;
629   delphi_keywords["out"] = 1;
630   delphi_keywords["to"] = 1;
631   delphi_keywords["div"] = 1;
632   delphi_keywords["in"] = 1;
633   delphi_keywords["packed"] = 1;
634   delphi_keywords["try"] = 1;
635   delphi_keywords["do"] = 1;
636   delphi_keywords["inherited"] = 1;
637   delphi_keywords["procedure"] = 1;
638   delphi_keywords["type"] = 1;
639   delphi_keywords["downto"] = 1;
640   delphi_keywords["initialization"] = 1;
641   delphi_keywords["program"] = 1;
642   delphi_keywords["unit"] = 1;
643   delphi_keywords["else"] = 1;
644   delphi_keywords["inline"] = 1;
645   delphi_keywords["property"] = 1;
646   delphi_keywords["until"] = 1;
647   delphi_keywords["private"] = 1;
648   delphi_keywords["protected"] = 1;
649   delphi_keywords["public"] = 1;
650   delphi_keywords["published"] = 1;
651   delphi_keywords["automated"] = 1;
652   delphi_keywords["at"] = 1;
653   delphi_keywords["on"] = 1;
654 
655   // reserved/predefined variables and types (lowercase!)
656   delphi_keywords["result"] = 1;
657   delphi_keywords["system"] = 1;
658   delphi_keywords["sysutils"] = 1;
659   delphi_keywords["thrift"] = 1;
660   delphi_keywords["tbytes"] = 1;
661   delphi_keywords["tobject"] = 1;
662   delphi_keywords["tclass"] = 1;
663   delphi_keywords["tinterfacedobject"] = 1;
664   delphi_keywords["ansistring"] = 1;
665   delphi_keywords["string"] = 1;
666   delphi_keywords["boolean"] = 1;
667   delphi_keywords["shortint"] = 1;
668   delphi_keywords["smallint"] = 1;
669   delphi_keywords["integer"] = 1;
670   delphi_keywords["int64"] = 1;
671   delphi_keywords["double"] = 1;
672 
673   delphi_reserved_method["create"] = 1;
674   delphi_reserved_method["free"] = 1;
675   delphi_reserved_method["initinstance"] = 1;
676   delphi_reserved_method["cleanupinstance"] = 1;
677   delphi_reserved_method["classtype"] = 1;
678   delphi_reserved_method["classname"] = 1;
679   delphi_reserved_method["classnameis"] = 1;
680   delphi_reserved_method["classparent"] = 1;
681   delphi_reserved_method["classinfo"] = 1;
682   delphi_reserved_method["instancesize"] = 1;
683   delphi_reserved_method["inheritsfrom"] = 1;
684   delphi_reserved_method["methodaddress"] = 1;
685   delphi_reserved_method["methodname"] = 1;
686   delphi_reserved_method["fieldaddress"] = 1;
687   delphi_reserved_method["getinterface"] = 1;
688   delphi_reserved_method["getinterfaceentry"] = 1;
689   delphi_reserved_method["getinterfacetable"] = 1;
690   delphi_reserved_method["unitname"] = 1;
691   delphi_reserved_method["equals"] = 1;
692   delphi_reserved_method["gethashcode"] = 1;
693   delphi_reserved_method["tostring"] = 1;
694   delphi_reserved_method["safecallexception"] = 1;
695   delphi_reserved_method["afterconstruction"] = 1;
696   delphi_reserved_method["beforedestruction"] = 1;
697   delphi_reserved_method["dispatch"] = 1;
698   delphi_reserved_method["defaulthandler"] = 1;
699   delphi_reserved_method["newinstance"] = 1;
700   delphi_reserved_method["freeinstance"] = 1;
701   delphi_reserved_method["destroy"] = 1;
702   delphi_reserved_method["read"] = 1;
703   delphi_reserved_method["write"] = 1;
704 
705   delphi_reserved_method_exception["setinnerexception"] = 1;
706   delphi_reserved_method_exception["setstackinfo"] = 1;
707   delphi_reserved_method_exception["getstacktrace"] = 1;
708   delphi_reserved_method_exception["raisingexception"] = 1;
709   delphi_reserved_method_exception["createfmt"] = 1;
710   delphi_reserved_method_exception["createres"] = 1;
711   delphi_reserved_method_exception["createresfmt"] = 1;
712   delphi_reserved_method_exception["createhelp"] = 1;
713   delphi_reserved_method_exception["createfmthelp"] = 1;
714   delphi_reserved_method_exception["createreshelp"] = 1;
715   delphi_reserved_method_exception["createresfmthelp"] = 1;
716   delphi_reserved_method_exception["getbaseexception"] = 1;
717   delphi_reserved_method_exception["baseexception"] = 1;
718   delphi_reserved_method_exception["helpcontext"] = 1;
719   delphi_reserved_method_exception["innerexception"] = 1;
720   delphi_reserved_method_exception["message"] = 1;
721   delphi_reserved_method_exception["stacktrace"] = 1;
722   delphi_reserved_method_exception["stackinfo"] = 1;
723   delphi_reserved_method_exception["getexceptionstackinfoproc"] = 1;
724   delphi_reserved_method_exception["getstackinfostringproc"] = 1;
725   delphi_reserved_method_exception["cleanupstackinfoproc"] = 1;
726   delphi_reserved_method_exception["raiseouterexception"] = 1;
727   delphi_reserved_method_exception["throwouterexception"] = 1;
728 }
729 
add_delphi_uses_list(string unitname)730 void t_delphi_generator::add_delphi_uses_list(string unitname) {
731   vector<std::string>::const_iterator s_iter;
732   bool found = false;
733   for (s_iter = uses_list.begin(); s_iter != uses_list.end(); ++s_iter) {
734     if ((*s_iter) == unitname) {
735       found = true;
736       break;
737     }
738   }
739   if (!found) {
740     uses_list.push_back(unitname);
741   }
742 }
743 
init_generator()744 void t_delphi_generator::init_generator() {
745   indent_impl_ = 0;
746   namespace_name_ = program_->get_namespace("delphi");
747   has_forward = false;
748   has_enum = false;
749   has_const = false;
750   create_keywords();
751 
752   add_delphi_uses_list("Classes");
753   add_delphi_uses_list("SysUtils");
754   add_delphi_uses_list("Generics.Collections");
755   if(async_) {
756     add_delphi_uses_list("System.Threading");
757   }
758 
759   add_delphi_uses_list("Thrift");
760   add_delphi_uses_list("Thrift.Utils");
761   add_delphi_uses_list("Thrift.Collections");
762   add_delphi_uses_list("Thrift.Protocol");
763   add_delphi_uses_list("Thrift.Transport");
764   if (register_types_) {
765     add_delphi_uses_list("Thrift.TypeRegistry");
766   }
767 
768   init_known_types_list();
769 
770   string unitname, nsname;
771   const vector<t_program*>& includes = program_->get_includes();
772   for (auto include : includes) {
773     unitname = include->get_name();
774     nsname = include->get_namespace("delphi");
775     if ("" != nsname) {
776       unitname = normalize_name(nsname);
777     }
778     add_delphi_uses_list(unitname);
779   }
780 
781   MKDIR(get_out_dir().c_str());
782 }
783 
close_generator()784 void t_delphi_generator::close_generator() {
785   std::string unitname = program_name_;
786   if ("" != namespace_name_) {
787     unitname = namespace_name_;
788   }
789 
790   for (int i = 0; i < (int)unitname.size(); i++) {
791     if (unitname[i] == ' ') {
792       unitname.replace(i, 1, "_");
793     }
794   }
795 
796   unitname = normalize_name(unitname);
797 
798   std::string f_name = get_out_dir() + "/" + unitname + ".pas";
799   ofstream_with_content_based_conditional_update f_all;
800 
801   f_all.open(f_name);
802 
803   f_all << autogen_comment() << endl;
804   generate_delphi_doc(f_all, program_);
805   f_all << "unit " << unitname << ";" << endl << endl;
806   f_all << "{$WARN SYMBOL_DEPRECATED OFF}" << endl << endl;
807   f_all << "interface" << endl << endl;
808   f_all << "uses" << endl;
809 
810   indent_up();
811 
812   vector<std::string>::const_iterator s_iter;
813   for (s_iter = uses_list.begin(); s_iter != uses_list.end(); ++s_iter) {
814     if (s_iter != uses_list.begin()) {
815       f_all << ",";
816       f_all << endl;
817     }
818     indent(f_all) << *s_iter;
819   }
820 
821   f_all << ";" << endl << endl;
822 
823   indent_down();
824 
825   string tmp_unit(unitname);
826   for (int i = 0; i < (int)tmp_unit.size(); i++) {
827     if (tmp_unit[i] == '.') {
828       tmp_unit.replace(i, 1, "_");
829     }
830   }
831 
832   f_all << "const" << endl;
833   indent_up();
834   indent(f_all) << "c" << tmp_unit
835                 << "_Option_AnsiStr_Binary = " << (ansistr_binary_ ? "True" : "False") << ";"
836                 << endl;
837   indent(f_all) << "c" << tmp_unit
838                 << "_Option_Register_Types = " << (register_types_ ? "True" : "False") << ";"
839                 << endl;
840   indent(f_all) << "c" << tmp_unit
841                 << "_Option_ConstPrefix    = " << (constprefix_ ? "True" : "False") << ";" << endl;
842   indent(f_all) << "c" << tmp_unit << "_Option_Events         = " << (events_ ? "True" : "False")
843                 << ";" << endl;
844   indent(f_all) << "c" << tmp_unit << "_Option_XmlDoc         = " << (xmldoc_ ? "True" : "False")
845                 << ";" << endl;
846   indent_down();
847 
848   f_all << endl;
849   f_all << "type" << endl;
850   if (has_forward) {
851     f_all << s_forward_decr.str() << endl;
852   }
853   if (has_enum) {
854     indent(f_all) << endl;
855     indent(f_all) << "{$SCOPEDENUMS ON}" << endl << endl;
856     f_all << s_enum.str();
857     indent(f_all) << "{$SCOPEDENUMS OFF}" << endl << endl;
858   }
859   f_all << s_struct.str();
860   f_all << s_service.str();
861   f_all << s_const.str();
862   f_all << "implementation" << endl << endl;
863   f_all << s_struct_impl.str();
864   f_all << s_service_impl.str();
865   f_all << s_const_impl.str();
866 
867   if (register_types_) {
868     f_all << endl;
869     f_all << "// Type factory methods and registration" << endl;
870     f_all << s_type_factory_funcs.str();
871     f_all << "procedure RegisterTypeFactories;" << endl;
872     f_all << "begin" << endl;
873     f_all << s_type_factory_registration.str();
874     f_all << "end;" << endl;
875   }
876   f_all << endl;
877 
878   string constants_class = make_constants_classname();
879 
880   f_all << "initialization" << endl;
881   if (has_const) {
882     f_all << "{$IF CompilerVersion < 21.0}  // D2010" << endl;
883     f_all << "  " << constants_class.c_str() << "_Initialize;" << endl;
884     f_all << "{$IFEND}" << endl;
885   }
886   if (register_types_) {
887     f_all << "  RegisterTypeFactories;" << endl;
888   }
889   f_all << endl;
890 
891   f_all << "finalization" << endl;
892   if (has_const) {
893     f_all << "{$IF CompilerVersion < 21.0}  // D2010" << endl;
894     f_all << "  " << constants_class.c_str() << "_Finalize;" << endl;
895     f_all << "{$IFEND}" << endl;
896   }
897   f_all << endl << endl;
898 
899   f_all << "end." << endl;
900   f_all.close();
901 
902   if (!typedefs_pending.empty()) {
903     pwarning(0, "%d typedefs with unresolved type references left:\n", typedefs_pending.size());
904     for (std::list<t_typedef*>::iterator iter = typedefs_pending.begin();
905          typedefs_pending.end() != iter;
906          ++iter) {
907       pwarning(0, "- %s\n", (*iter)->get_symbolic().c_str());
908     }
909   }
910 }
911 
delphi_type_usings(ostream & out)912 void t_delphi_generator::delphi_type_usings(ostream& out) {
913   indent_up();
914   indent(out) << "Classes, SysUtils, Generics.Collections, Thrift.Collections, Thrift.Protocol,"
915               << endl;
916   indent(out) << "Thrift.Transport;" << endl << endl;
917   indent_down();
918 }
919 
generate_forward_declaration(t_struct * tstruct)920 void t_delphi_generator::generate_forward_declaration(t_struct* tstruct) {
921   // Forward declare struct def
922   has_forward = true;
923   pverbose("forward declaration of %s\n", type_name(tstruct).c_str());
924 
925   string what = tstruct->is_xception() ? "class" : "interface";
926 
927   indent_up();
928   indent(s_forward_decr) << type_name(tstruct, tstruct->is_xception(), true) << " = " << what << ";"
929                          << endl;
930   indent_down();
931 
932   add_defined_type(tstruct);
933 }
934 
generate_typedef(t_typedef * ttypedef)935 void t_delphi_generator::generate_typedef(t_typedef* ttypedef) {
936   t_type* type = ttypedef->get_type();
937 
938   // write now or save for later?
939   if (!is_fully_defined_type(type)) {
940     pverbose("typedef %s: unresolved dependencies found\n", type_name(ttypedef).c_str());
941     typedefs_pending.push_back(ttypedef);
942     return;
943   }
944 
945   indent_up();
946   generate_delphi_doc(s_struct, ttypedef);
947   indent(s_struct) << type_name(ttypedef) << " = ";
948 
949   // commented out: the benefit is not big enough to risk breaking existing code
950   // bool container = type->is_list() || type->is_map() || type->is_set();
951   // if( ! container)
952   //  s_struct << "type ";  //the "type A = type B" syntax leads to E2574 with generics
953 
954   s_struct << type_name(ttypedef->get_type()) << ";" << endl << endl;
955   indent_down();
956 
957   add_defined_type(ttypedef);
958 }
959 
is_fully_defined_type(t_type * ttype)960 bool t_delphi_generator::is_fully_defined_type(t_type* ttype) {
961   if ((nullptr != ttype->get_program()) && (ttype->get_program() != program_)) {
962     t_scope* scope = ttype->get_program()->scope();
963     if (nullptr != scope->get_type(ttype->get_name())) {
964       // printf("type %s found in included scope %s\n", ttype->get_name().c_str(),
965       // ttype->get_program()->get_name().c_str());
966       return true;
967     }
968   }
969 
970   if (ttype->is_typedef()) {
971     return (1 == types_known[type_name(ttype)]);
972   }
973 
974   if (ttype->is_base_type()) {
975     return (1 == types_known[base_type_name((t_base_type*)ttype)]);
976   } else if (ttype->is_enum()) {
977     return true; // enums are written first, before all other types
978   } else if (ttype->is_map()) {
979     t_map* tmap = (t_map*)ttype;
980     return is_fully_defined_type(tmap->get_key_type())
981            && is_fully_defined_type(tmap->get_val_type());
982   } else if (ttype->is_set()) {
983     t_set* tset = (t_set*)ttype;
984     return is_fully_defined_type(tset->get_elem_type());
985   } else if (ttype->is_list()) {
986     t_list* tlist = (t_list*)ttype;
987     return is_fully_defined_type(tlist->get_elem_type());
988   }
989 
990   return (1 == types_known[type_name(ttype)]);
991 }
992 
add_defined_type(t_type * ttype)993 void t_delphi_generator::add_defined_type(t_type* ttype) {
994   // mark as known type
995   types_known[type_name(ttype)] = 1;
996 
997   // check all pending typedefs
998   std::list<t_typedef*>::iterator iter;
999   bool more = true;
1000   while (more && (!typedefs_pending.empty())) {
1001     more = false;
1002 
1003     for (iter = typedefs_pending.begin(); typedefs_pending.end() != iter; ++iter) {
1004       t_typedef* ttypedef = (*iter);
1005       if (is_fully_defined_type(ttypedef->get_type())) {
1006         pverbose("typedef %s: all pending references are now resolved\n",
1007                  type_name(ttypedef).c_str());
1008         typedefs_pending.erase(iter);
1009         generate_typedef(ttypedef);
1010         more = true;
1011         break;
1012       }
1013     }
1014   }
1015 }
1016 
init_known_types_list()1017 void t_delphi_generator::init_known_types_list() {
1018   // known base types
1019   types_known[type_name(g_type_string)] = 1;
1020   types_known[type_name(g_type_binary)] = 1;
1021   types_known[type_name(g_type_bool)] = 1;
1022   types_known[type_name(g_type_i8)] = 1;
1023   types_known[type_name(g_type_i16)] = 1;
1024   types_known[type_name(g_type_i32)] = 1;
1025   types_known[type_name(g_type_i64)] = 1;
1026   types_known[type_name(g_type_double)] = 1;
1027 }
1028 
generate_enum(t_enum * tenum)1029 void t_delphi_generator::generate_enum(t_enum* tenum) {
1030   has_enum = true;
1031   indent_up();
1032   generate_delphi_doc(s_enum, tenum);
1033   indent(s_enum) << type_name(tenum, true, true) << " = "
1034                  << "(" << endl;
1035   indent_up();
1036   vector<t_enum_value*> constants = tenum->get_constants();
1037   if (constants.empty()) {
1038     indent(s_enum) << "dummy = 0  // empty enums are not allowed";
1039   } else {
1040     vector<t_enum_value*>::iterator c_iter;
1041     for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
1042       int value = (*c_iter)->get_value();
1043       if (c_iter != constants.begin()) {
1044         s_enum << ",";
1045         s_enum << endl;
1046       }
1047       generate_delphi_doc(s_enum, *c_iter);
1048       indent(s_enum) << normalize_name((*c_iter)->get_name()) << " = " << value;
1049     }
1050   }
1051   s_enum << endl;
1052   indent_down();
1053   indent(s_enum) << ");" << endl << endl;
1054   indent_down();
1055 }
1056 
make_pascal_string_literal(std::string value)1057 std::string t_delphi_generator::make_pascal_string_literal(std::string value) {
1058   std::stringstream result;
1059 
1060   if (value.length() == 0) {
1061     return "";
1062   }
1063 
1064   result << "'";
1065   for (char const &c: value) {
1066     if( (c >= 0) && (c < 32)) {  // convert ctrl chars, but leave UTF-8 alone
1067       result << "#" << (int)c;
1068     } else if (c == '\'') {
1069       result << "''";   // duplicate any single quotes we find
1070     } else {
1071       result << c;   // anything else "as is"
1072     }
1073   }
1074   result << "'";
1075 
1076   return result.str();
1077 }
1078 
make_valid_delphi_identifier(std::string const & fromName)1079 std::string t_delphi_generator::make_valid_delphi_identifier(std::string const& fromName) {
1080   std::string str = fromName;
1081   if (str.empty()) {
1082     return str;
1083   }
1084 
1085   // tests rely on this
1086   assert(('A' < 'Z') && ('a' < 'z') && ('0' < '9'));
1087 
1088   // if the first letter is a number, we add an additional underscore in front of it
1089   char c = str.at(0);
1090   if (('0' <= c) && (c <= '9')) {
1091     str = "_" + str;
1092   }
1093 
1094   // following chars: letter, number or underscore
1095   for (size_t i = 0; i < str.size(); ++i) {
1096     c = str.at(i);
1097     if ((('A' > c) || (c > 'Z')) && (('a' > c) || (c > 'z')) && (('0' > c) || (c > '9'))
1098         && ('_' != c)) {
1099       str.replace(i, 1, "_");
1100     }
1101   }
1102 
1103   return str;
1104 }
1105 
make_constants_classname()1106 std::string t_delphi_generator::make_constants_classname() {
1107   if (constprefix_) {
1108     return make_valid_delphi_identifier("T" + program_name_ + "Constants");
1109   } else {
1110     return "TConstants"; // compatibility
1111   }
1112 }
1113 
generate_consts(std::vector<t_const * > consts)1114 void t_delphi_generator::generate_consts(std::vector<t_const*> consts) {
1115   if (consts.empty()) {
1116     return;
1117   }
1118 
1119   has_const = true;
1120   string constants_class = make_constants_classname();
1121 
1122   indent_up();
1123   indent(s_const) << constants_class.c_str() << " = class" << endl;
1124   indent(s_const) << "private" << endl;
1125   indent_up();
1126   vector<t_const*>::iterator c_iter;
1127   for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
1128     if (const_needs_var((*c_iter)->get_type())) {
1129       print_private_field(s_const,
1130                           normalize_name((*c_iter)->get_name()),
1131                           (*c_iter)->get_type(),
1132                           (*c_iter)->get_value());
1133     }
1134   }
1135   indent_down();
1136   indent(s_const) << "public" << endl;
1137   indent_up();
1138   for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
1139     generate_delphi_doc(s_const, *c_iter);
1140     print_const_prop(s_const,
1141                      normalize_name((*c_iter)->get_name()),
1142                      (*c_iter)->get_type(),
1143                      (*c_iter)->get_value());
1144   }
1145   indent(s_const) << "{$IF CompilerVersion >= 21.0}" << endl;
1146   indent(s_const) << "class constructor Create;" << endl;
1147   indent(s_const) << "class destructor Destroy;" << endl;
1148   indent(s_const) << "{$IFEND}" << endl;
1149   indent_down();
1150   indent(s_const) << "end;" << endl << endl;
1151   indent_down();
1152 
1153   std::ostringstream vars, code;
1154 
1155   indent_up_impl();
1156   for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
1157     initialize_field(vars,
1158                      code,
1159                      "F" + prop_name((*c_iter)->get_name()),
1160                      (*c_iter)->get_type(),
1161                      (*c_iter)->get_value());
1162   }
1163   indent_down_impl();
1164 
1165   indent_impl(s_const_impl) << "{$IF CompilerVersion >= 21.0}" << endl;
1166   indent_impl(s_const_impl) << "class constructor " << constants_class.c_str() << ".Create;"
1167                             << endl;
1168 
1169   if (!vars.str().empty()) {
1170     indent_impl(s_const_impl) << "var" << endl;
1171     s_const_impl << vars.str();
1172   }
1173   indent_impl(s_const_impl) << "begin" << endl;
1174   if (!code.str().empty()) {
1175     s_const_impl << code.str();
1176   }
1177   indent_impl(s_const_impl) << "end;" << endl << endl;
1178   indent_impl(s_const_impl) << "class destructor " << constants_class.c_str() << ".Destroy;"
1179                             << endl;
1180   indent_impl(s_const_impl) << "begin" << endl;
1181   indent_up_impl();
1182   for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
1183     if (const_needs_var((*c_iter)->get_type())) {
1184       finalize_field(s_const_impl,
1185                      normalize_name((*c_iter)->get_name()),
1186                      (*c_iter)->get_type(),
1187                      (*c_iter)->get_value());
1188     }
1189   }
1190   indent_impl(s_const_impl) << "inherited;" << endl;
1191   indent_down_impl();
1192   indent_impl(s_const_impl) << "end;" << endl;
1193   indent_impl(s_const_impl) << "{$ELSE}" << endl;
1194 
1195   vars.str("");
1196   code.str("");
1197 
1198   indent_up_impl();
1199   for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
1200     if (const_needs_var((*c_iter)->get_type())) {
1201       initialize_field(vars,
1202                        code,
1203                        constants_class + ".F" + prop_name((*c_iter)->get_name()),
1204                        (*c_iter)->get_type(),
1205                        (*c_iter)->get_value());
1206     }
1207   }
1208   indent_down_impl();
1209 
1210   indent_impl(s_const_impl) << "procedure " << constants_class.c_str() << "_Initialize;" << endl;
1211   if (!vars.str().empty()) {
1212     indent_impl(s_const_impl) << "var" << endl;
1213     s_const_impl << vars.str();
1214   }
1215   indent_impl(s_const_impl) << "begin" << endl;
1216   if (!code.str().empty()) {
1217     s_const_impl << code.str();
1218   }
1219   indent_impl(s_const_impl) << "end;" << endl << endl;
1220 
1221   indent_impl(s_const_impl) << "procedure " << constants_class.c_str() << "_Finalize;" << endl;
1222   indent_impl(s_const_impl) << "begin" << endl;
1223   indent_up_impl();
1224   for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
1225     finalize_field(s_const_impl,
1226                    normalize_name((*c_iter)->get_name()),
1227                    (*c_iter)->get_type(),
1228                    (*c_iter)->get_value(),
1229                    constants_class);
1230   }
1231   indent_down_impl();
1232   indent_impl(s_const_impl) << "end;" << endl;
1233   indent_impl(s_const_impl) << "{$IFEND}" << endl << endl;
1234 }
1235 
print_const_def_value(std::ostream & vars,std::ostream & out,string name,t_type * type,t_const_value * value,string cls_nm)1236 void t_delphi_generator::print_const_def_value(std::ostream& vars,
1237                                                std::ostream& out,
1238                                                string name,
1239                                                t_type* type,
1240                                                t_const_value* value,
1241                                                string cls_nm) {
1242 
1243   string cls_prefix;
1244 
1245   if (cls_nm == "") {
1246     cls_prefix = "";
1247   } else {
1248     cls_prefix = cls_nm + ".";
1249   }
1250 
1251   if (type->is_struct() || type->is_xception()) {
1252     const vector<t_field*>& fields = ((t_struct*)type)->get_members();
1253     vector<t_field*>::const_iterator f_iter;
1254     const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
1255     map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
1256     for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
1257       t_type* field_type = nullptr;
1258       for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1259         if ((*f_iter)->get_name() == v_iter->first->get_string()) {
1260           field_type = (*f_iter)->get_type();
1261         }
1262       }
1263       if (field_type == nullptr) {
1264         throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
1265       }
1266       string val = render_const_value(vars, out, name, field_type, v_iter->second);
1267       indent_impl(out) << cls_prefix << normalize_name(name) << "."
1268                        << prop_name(v_iter->first->get_string(), type->is_xception())
1269                        << " := " << val << ";" << endl;
1270     }
1271   } else if (type->is_map()) {
1272     t_type* ktype = ((t_map*)type)->get_key_type();
1273     t_type* vtype = ((t_map*)type)->get_val_type();
1274     const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
1275     map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
1276     for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
1277       string key = render_const_value(vars, out, name, ktype, v_iter->first);
1278       string val = render_const_value(vars, out, name, vtype, v_iter->second);
1279       indent_impl(out) << cls_prefix << normalize_name(name) << "[" << key << "]"
1280                        << " := " << val << ";" << endl;
1281     }
1282   } else if (type->is_list() || type->is_set()) {
1283     t_type* etype;
1284     if (type->is_list()) {
1285       etype = ((t_list*)type)->get_elem_type();
1286     } else {
1287       etype = ((t_set*)type)->get_elem_type();
1288     }
1289 
1290     const vector<t_const_value*>& val = value->get_list();
1291     vector<t_const_value*>::const_iterator v_iter;
1292     for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
1293       string val = render_const_value(vars, out, name, etype, *v_iter);
1294       indent_impl(out) << cls_prefix << normalize_name(name) << ".Add(" << val << ");" << endl;
1295     }
1296   }
1297 }
1298 
print_private_field(std::ostream & out,string name,t_type * type,t_const_value * value)1299 void t_delphi_generator::print_private_field(std::ostream& out,
1300                                              string name,
1301                                              t_type* type,
1302                                              t_const_value* value) {
1303   (void)value;
1304   indent(out) << "class var F" << name << ": " << type_name(type) << ";" << endl;
1305 }
1306 
const_needs_var(t_type * type)1307 bool t_delphi_generator::const_needs_var(t_type* type) {
1308   t_type* truetype = type;
1309   while (truetype->is_typedef()) {
1310     truetype = ((t_typedef*)truetype)->get_type();
1311   }
1312   return (!truetype->is_base_type());
1313 }
1314 
print_const_prop(std::ostream & out,string name,t_type * type,t_const_value * value)1315 void t_delphi_generator::print_const_prop(std::ostream& out,
1316                                           string name,
1317                                           t_type* type,
1318                                           t_const_value* value) {
1319   (void)value;
1320   if (const_needs_var(type)) {
1321     indent(out) << "class property " << name << ": " << type_name(type) << " read F" << name << ";"
1322                 << endl;
1323   } else {
1324     std::ostringstream vars; // dummy
1325     string v2 = render_const_value(vars, out, name, type, value);
1326     indent(out) << "const " << name << " = " << v2 << ";" << endl;
1327   }
1328 }
1329 
print_const_value(std::ostream & vars,std::ostream & out,string name,t_type * type,t_const_value * value)1330 void t_delphi_generator::print_const_value(std::ostream& vars,
1331                                            std::ostream& out,
1332                                            string name,
1333                                            t_type* type,
1334                                            t_const_value* value) {
1335   t_type* truetype = type;
1336   while (truetype->is_typedef()) {
1337     truetype = ((t_typedef*)truetype)->get_type();
1338   }
1339 
1340   if (truetype->is_base_type()) {
1341     // already done
1342     // string v2 = render_const_value( vars, out, name, type, value);
1343     // indent_impl(out) << name << " := " << v2 << ";" << endl;
1344   } else if (truetype->is_enum()) {
1345     indent_impl(out) << name << " := " << type_name(type) << "." << value->get_identifier_name()
1346                      << ";" << endl;
1347   } else {
1348     string typname;
1349     typname = type_name(truetype, true, false, type->is_xception(), type->is_xception());
1350     indent_impl(out) << name << " := " << typname << ".Create;" << endl;
1351     print_const_def_value(vars, out, name, truetype, value);
1352   }
1353 }
1354 
initialize_field(std::ostream & vars,std::ostream & out,string name,t_type * type,t_const_value * value)1355 void t_delphi_generator::initialize_field(std::ostream& vars,
1356                                           std::ostream& out,
1357                                           string name,
1358                                           t_type* type,
1359                                           t_const_value* value) {
1360   print_const_value(vars, out, name, type, value);
1361 }
1362 
finalize_field(std::ostream & out,string name,t_type * type,t_const_value * value,string cls_nm)1363 void t_delphi_generator::finalize_field(std::ostream& out,
1364                                         string name,
1365                                         t_type* type,
1366                                         t_const_value* value,
1367                                         string cls_nm) {
1368   (void)out;
1369   (void)name;
1370   (void)type;
1371   (void)value;
1372   (void)cls_nm;
1373 }
1374 
render_const_value(ostream & vars,ostream & out,string name,t_type * type,t_const_value * value)1375 string t_delphi_generator::render_const_value(ostream& vars,
1376                                               ostream& out,
1377                                               string name,
1378                                               t_type* type,
1379                                               t_const_value* value) {
1380   (void)name;
1381 
1382   t_type* truetype = type;
1383   while (truetype->is_typedef()) {
1384     truetype = ((t_typedef*)truetype)->get_type();
1385   }
1386 
1387   std::ostringstream render;
1388 
1389   if (truetype->is_base_type()) {
1390     t_base_type::t_base tbase = ((t_base_type*)truetype)->get_base();
1391     switch (tbase) {
1392     case t_base_type::TYPE_STRING:
1393       render << "'" << get_escaped_string(value) << "'";
1394       break;
1395     case t_base_type::TYPE_BOOL:
1396       render << ((value->get_integer() > 0) ? "True" : "False");
1397       break;
1398     case t_base_type::TYPE_I8:
1399       render << "ShortInt( " << value->get_integer() << ")";
1400       break;
1401     case t_base_type::TYPE_I16:
1402       render << "SmallInt( " << value->get_integer() << ")";
1403       break;
1404     case t_base_type::TYPE_I32:
1405       render << "LongInt( " << value->get_integer() << ")";
1406       break;
1407     case t_base_type::TYPE_I64:
1408       render << "Int64( " << value->get_integer() << ")";
1409       break;
1410     case t_base_type::TYPE_DOUBLE:
1411       if (value->get_type() == t_const_value::CV_INTEGER) {
1412         render << value->get_integer() << ".0"; // make it a double constant by adding ".0"
1413       } else {
1414         render << value->get_double();
1415       }
1416       break;
1417     default:
1418       throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
1419     }
1420   } else if (truetype->is_enum()) {
1421     render << type_name(type, false) << "." << value->get_identifier_name();
1422   } else {
1423     string t = tmp("tmp");
1424     vars << "  " << t << " : " << type_name(type) << ";" << endl;
1425     print_const_value(vars, out, t, type, value);
1426     render << t;
1427   }
1428 
1429   return render.str();
1430 }
1431 
generate_struct(t_struct * tstruct)1432 void t_delphi_generator::generate_struct(t_struct* tstruct) {
1433   generate_delphi_struct(tstruct, false);
1434 }
1435 
generate_xception(t_struct * txception)1436 void t_delphi_generator::generate_xception(t_struct* txception) {
1437   generate_delphi_struct(txception, true);
1438 }
1439 
generate_delphi_struct(t_struct * tstruct,bool is_exception)1440 void t_delphi_generator::generate_delphi_struct(t_struct* tstruct, bool is_exception) {
1441   indent_up();
1442   generate_delphi_struct_definition(s_struct, tstruct, is_exception);
1443   indent_down();
1444 
1445   add_defined_type(tstruct);
1446 
1447   generate_delphi_struct_impl(s_struct_impl, "", tstruct, is_exception);
1448   if (register_types_) {
1449     generate_delphi_struct_type_factory(s_type_factory_funcs, "", tstruct, is_exception);
1450     generate_delphi_struct_type_factory_registration(s_type_factory_registration,
1451                                                      "",
1452                                                      tstruct,
1453                                                      is_exception);
1454   }
1455 }
1456 
generate_delphi_struct_impl(ostream & out,string cls_prefix,t_struct * tstruct,bool is_exception,bool is_result,bool is_x_factory)1457 void t_delphi_generator::generate_delphi_struct_impl(ostream& out,
1458                                                      string cls_prefix,
1459                                                      t_struct* tstruct,
1460                                                      bool is_exception,
1461                                                      bool is_result,
1462                                                      bool is_x_factory) {
1463 
1464   if (is_exception && (!is_x_factory)) {
1465     generate_delphi_struct_impl(out, cls_prefix, tstruct, is_exception, is_result, true);
1466   }
1467 
1468   string cls_nm;
1469 
1470   string exception_factory_name;
1471 
1472   if (is_exception) {
1473     exception_factory_name = normalize_clsnm(tstruct->get_name(), "", true) + "Factory";
1474   }
1475 
1476   if (is_exception) {
1477     cls_nm = type_name(tstruct, true, (!is_x_factory), is_x_factory, true);
1478   } else {
1479     cls_nm = type_name(tstruct, true, false);
1480   }
1481 
1482   std::ostringstream vars, code;
1483 
1484   const vector<t_field*>& members = tstruct->get_members();
1485   vector<t_field*>::const_iterator m_iter;
1486 
1487   indent_up_impl();
1488   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1489     t_type* t = (*m_iter)->get_type();
1490     while (t->is_typedef()) {
1491       t = ((t_typedef*)t)->get_type();
1492     }
1493     if ((*m_iter)->get_value() != nullptr) {
1494       initialize_field(vars,
1495                        code,
1496                        "F" + prop_name((*m_iter)->get_name(), is_exception),
1497                        t,
1498                        (*m_iter)->get_value());
1499       if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
1500         indent_impl(code) << "F__isset_" << prop_name((*m_iter), is_exception) << " := True;"
1501                           << endl;
1502       }
1503     }
1504   }
1505   indent_down_impl();
1506 
1507   indent_impl(out) << "constructor " << cls_prefix << cls_nm << "."
1508                    << "Create;" << endl;
1509 
1510   if (!vars.str().empty()) {
1511     out << "var" << endl;
1512     out << vars.str();
1513   }
1514 
1515   indent_impl(out) << "begin" << endl;
1516   indent_up_impl();
1517   if (is_exception && (!is_x_factory)) {
1518     indent_impl(out) << "inherited Create('');" << endl;
1519   } else {
1520     indent_impl(out) << "inherited;" << endl;
1521   }
1522 
1523   if (!code.str().empty()) {
1524     out << code.str();
1525   }
1526 
1527   indent_down_impl();
1528   indent_impl(out) << "end;" << endl << endl;
1529 
1530   if ((members.size() > 0) && is_exception && (!is_x_factory)) {
1531     indent_impl(out) << "constructor " << cls_prefix << cls_nm << "."
1532                      << "Create(" << constructor_argument_list(tstruct, indent_impl()) << ");"
1533                      << endl;
1534     indent_impl(out) << "begin" << endl;
1535     indent_up_impl();
1536     indent_impl(out) << "Create;" << endl;
1537     for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1538       string propname = prop_name((*m_iter)->get_name(), is_exception);
1539       string param_name = constructor_param_name((*m_iter)->get_name());
1540       indent_impl(out) << propname << " := " << param_name << ";" << endl;
1541     }
1542     indent_impl(out) << "UpdateMessageProperty;" << endl;
1543     indent_down_impl();
1544     indent_impl(out) << "end;" << endl << endl;
1545   }
1546 
1547   indent_impl(out) << "destructor " << cls_prefix << cls_nm << "."
1548                    << "Destroy;" << endl;
1549   indent_impl(out) << "begin" << endl;
1550   indent_up_impl();
1551 
1552   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1553     t_type* t = (*m_iter)->get_type();
1554     while (t->is_typedef()) {
1555       t = ((t_typedef*)t)->get_type();
1556     }
1557     finalize_field(out, prop_name(*m_iter, is_exception), t, (*m_iter)->get_value());
1558   }
1559 
1560   indent_impl(out) << "inherited;" << endl;
1561   indent_down_impl();
1562   indent_impl(out) << "end;" << endl << endl;
1563 
1564   if (is_exception && (!is_x_factory)) {
1565     indent_impl(out) << "function " << cls_prefix << cls_nm << "." << exception_factory_name
1566                      << ": I" << exception_factory_name << ";" << endl;
1567     indent_impl(out) << "begin" << endl;
1568     indent_up_impl();
1569     indent_impl(out) << "if F" << exception_factory_name << " = nil" << endl;
1570     indent_impl(out) << "then F" << exception_factory_name << " := T" << exception_factory_name << "Impl.Create;" << endl << endl;
1571     indent_impl(out) << "result := F" << exception_factory_name << ";" << endl;
1572     indent_down_impl();
1573     indent_impl(out) << "end;" << endl << endl;
1574     indent_impl(out) << "function " << cls_prefix << cls_nm << ".QueryInterface(const IID: TGUID; out Obj): HRESULT;" << endl;
1575     indent_impl(out) << "begin" << endl;
1576     indent_up_impl();
1577     indent_impl(out) << "if GetInterface(IID, Obj)" << endl;
1578     indent_impl(out) << "then result := S_OK" << endl;
1579     indent_impl(out) << "else result := E_NOINTERFACE;" << endl;
1580     indent_down_impl();
1581     indent_impl(out) << "end;" << endl << endl;
1582     indent_impl(out) << "function " << cls_prefix << cls_nm << "._AddRef: Integer;" << endl;
1583     indent_impl(out) << "begin" << endl;
1584     indent_up_impl();
1585     indent_impl(out) << "result := -1;    // not refcounted" << endl;
1586     indent_down_impl();
1587     indent_impl(out) << "end;" << endl << endl;
1588     indent_impl(out) << "function " << cls_prefix << cls_nm << "._Release: Integer;" << endl;
1589     indent_impl(out) << "begin" << endl;
1590     indent_up_impl();
1591     indent_impl(out) << "result := -1;    // not refcounted" << endl;
1592     indent_down_impl();
1593     indent_impl(out) << "end;" << endl << endl;
1594   }
1595 
1596   if (tstruct->is_union()) {
1597     indent_impl(out) << "procedure " << cls_prefix << cls_nm << "."
1598                      << "ClearUnionValues;" << endl;
1599     indent_impl(out) << "begin" << endl;
1600     indent_up_impl();
1601     for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1602       t_type* t = (*m_iter)->get_type();
1603       while (t->is_typedef()) {
1604         t = ((t_typedef*)t)->get_type();
1605       }
1606 
1607       generate_delphi_clear_union_value(out,
1608                                         cls_prefix,
1609                                         cls_nm,
1610                                         t,
1611                                         *m_iter,
1612                                         "F",
1613                                         is_exception,
1614                                         tstruct->is_union(),
1615                                         is_x_factory,
1616                                         exception_factory_name);
1617     }
1618     indent_down_impl();
1619     indent_impl(out) << "end;" << endl << endl;
1620   }
1621 
1622   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1623     t_type* t = (*m_iter)->get_type();
1624     while (t->is_typedef()) {
1625       t = ((t_typedef*)t)->get_type();
1626     }
1627     generate_delphi_property_reader_impl(out, cls_prefix, cls_nm, t, *m_iter, "F", is_exception);
1628     generate_delphi_property_writer_impl(out,
1629                                          cls_prefix,
1630                                          cls_nm,
1631                                          t,
1632                                          *m_iter,
1633                                          "F",
1634                                          is_exception,
1635                                          tstruct->is_union(),
1636                                          is_x_factory,
1637                                          exception_factory_name);
1638     if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
1639       generate_delphi_isset_reader_writer_impl(out, cls_prefix, cls_nm, t, *m_iter, "F", is_exception);
1640     }
1641   }
1642 
1643   generate_delphi_struct_reader_impl(out, cls_prefix, tstruct, is_exception, is_x_factory);
1644   if (is_result) {
1645     generate_delphi_struct_result_writer_impl(out, cls_prefix, tstruct, is_exception, is_x_factory);
1646   } else {
1647     generate_delphi_struct_writer_impl(out, cls_prefix, tstruct, is_exception, is_x_factory);
1648   }
1649   generate_delphi_struct_tostring_impl(out, cls_prefix, tstruct, is_exception, is_x_factory);
1650 
1651   if (is_exception && is_x_factory) {
1652     generate_delphi_create_exception_impl(out, cls_prefix, tstruct, is_exception);
1653   }
1654 }
1655 
print_delphi_struct_type_factory_func(ostream & out,t_struct * tstruct)1656 void t_delphi_generator::print_delphi_struct_type_factory_func(ostream& out, t_struct* tstruct) {
1657   string struct_intf_name = type_name(tstruct);
1658   out << "Create_";
1659   out << struct_intf_name;
1660   out << "_Impl";
1661 }
1662 
generate_delphi_struct_type_factory(ostream & out,string cls_prefix,t_struct * tstruct,bool is_exception,bool is_result,bool is_x_factory)1663 void t_delphi_generator::generate_delphi_struct_type_factory(ostream& out,
1664                                                              string cls_prefix,
1665                                                              t_struct* tstruct,
1666                                                              bool is_exception,
1667                                                              bool is_result,
1668                                                              bool is_x_factory) {
1669   (void)cls_prefix;
1670   if (is_exception)
1671     return;
1672   if (is_result)
1673     return;
1674   if (is_x_factory)
1675     return;
1676 
1677   string struct_intf_name = type_name(tstruct);
1678   string cls_nm = type_name(tstruct, true, false);
1679 
1680   out << "function ";
1681   print_delphi_struct_type_factory_func(out, tstruct);
1682   out << ": ";
1683   out << struct_intf_name;
1684   out << ";" << endl;
1685   out << "begin" << endl;
1686   indent_up();
1687   indent(out) << "Result := " << cls_nm << ".Create;" << endl;
1688   indent_down();
1689   out << "end;" << endl << endl;
1690 }
1691 
generate_delphi_struct_type_factory_registration(ostream & out,string cls_prefix,t_struct * tstruct,bool is_exception,bool is_result,bool is_x_factory)1692 void t_delphi_generator::generate_delphi_struct_type_factory_registration(ostream& out,
1693                                                                           string cls_prefix,
1694                                                                           t_struct* tstruct,
1695                                                                           bool is_exception,
1696                                                                           bool is_result,
1697                                                                           bool is_x_factory) {
1698   (void)cls_prefix;
1699   if (is_exception)
1700     return;
1701   if (is_result)
1702     return;
1703   if (is_x_factory)
1704     return;
1705 
1706   string struct_intf_name = type_name(tstruct);
1707 
1708   indent(out) << "  TypeRegistry.RegisterTypeFactory<" << struct_intf_name << ">(";
1709   print_delphi_struct_type_factory_func(out, tstruct);
1710   out << ");";
1711   out << endl;
1712 }
1713 
generate_delphi_struct_definition(ostream & out,t_struct * tstruct,bool is_exception,bool in_class,bool is_result,bool is_x_factory)1714 void t_delphi_generator::generate_delphi_struct_definition(ostream& out,
1715                                                            t_struct* tstruct,
1716                                                            bool is_exception,
1717                                                            bool in_class,
1718                                                            bool is_result,
1719                                                            bool is_x_factory) {
1720   bool is_final = (tstruct->annotations_.find("final") != tstruct->annotations_.end());
1721   string struct_intf_name;
1722   string struct_name;
1723   string isset_name;
1724   const vector<t_field*>& members = tstruct->get_members();
1725   vector<t_field*>::const_iterator m_iter;
1726 
1727   string exception_factory_name = normalize_clsnm(tstruct->get_name(), "", true) + "Factory";
1728 
1729   if (is_exception) {
1730     struct_intf_name = type_name(tstruct, false, false, true);
1731   } else {
1732     struct_intf_name = type_name(tstruct);
1733   }
1734 
1735   if (is_exception) {
1736     struct_name = type_name(tstruct, true, (!is_x_factory), is_x_factory);
1737   } else {
1738     struct_name = type_name(tstruct, true);
1739   }
1740 
1741   if ((!is_exception) || is_x_factory) {
1742 
1743     generate_delphi_doc(out, tstruct);
1744     indent(out) << struct_intf_name << " = interface(IBase)" << endl;
1745     indent_up();
1746 
1747     generate_guid(out);
1748 
1749     for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1750       generate_delphi_property_reader_definition(out, *m_iter, is_exception);
1751       generate_delphi_property_writer_definition(out, *m_iter, is_exception);
1752     }
1753 
1754     if (is_x_factory) {
1755       out << endl;
1756       indent(out) << "// Create Exception Object" << endl;
1757       indent(out) << "function CreateException: " << type_name(tstruct, true, true) << ";" << endl;
1758     }
1759 
1760     if (members.size() > 0) {
1761       out << endl;
1762       for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1763         generate_property(out, *m_iter, true, is_exception);
1764       }
1765     }
1766 
1767     if (members.size() > 0) {
1768       out << endl;
1769       for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1770         if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
1771           generate_delphi_isset_reader_writer_definition(out, *m_iter, is_exception);
1772         }
1773       }
1774     }
1775 
1776     if (members.size() > 0) {
1777       out << endl;
1778       for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1779         if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
1780           isset_name = "__isset_" + prop_name(*m_iter, is_exception);
1781           indent(out) << "property " << isset_name << ": System.Boolean read Get" << isset_name << " write Set" << isset_name << ";"
1782                       << endl;
1783         }
1784       }
1785     }
1786 
1787     indent_down();
1788     indent(out) << "end;" << endl << endl;
1789   }
1790 
1791   generate_delphi_doc(out, tstruct);
1792   indent(out) << struct_name << " = ";
1793   if (is_final) {
1794     out << "sealed ";
1795   }
1796   out << "class(";
1797   if (is_exception && (!is_x_factory)) {
1798     out << "TException, IInterface, IBase, ISupportsToString";
1799   } else {
1800     out << "TInterfacedObject, IBase, ISupportsToString, " << struct_intf_name;
1801   }
1802   out << ")" << endl;
1803 
1804   if (is_exception && (!is_x_factory)) {
1805     indent(out) << "public" << endl;
1806     indent_up();
1807     indent(out) << "type" << endl;
1808     indent_up();
1809     generate_delphi_struct_definition(out, tstruct, is_exception, in_class, is_result, true);
1810     indent_down();
1811     indent_down();
1812   }
1813 
1814   indent(out) << "private" << endl;
1815   indent_up();
1816 
1817   if (is_exception && (!is_x_factory)) {
1818     indent(out) << "F" << exception_factory_name << " :" << struct_intf_name << ";" << endl << endl;
1819   }
1820 
1821   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1822     indent(out) << declare_field(*m_iter, false, "F", is_exception) << endl;
1823   }
1824 
1825   if (members.size() > 0) {
1826     indent(out) << endl;
1827     for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1828       if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
1829         isset_name = "F__isset_" + prop_name(*m_iter, is_exception);
1830         indent(out) << isset_name << ": System.Boolean;" << endl;
1831       }
1832     }
1833   }
1834 
1835   indent(out) << endl;
1836 
1837   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1838     generate_delphi_property_reader_definition(out, *m_iter, is_exception);
1839     generate_delphi_property_writer_definition(out, *m_iter, is_exception);
1840   }
1841 
1842   if (tstruct->is_union()) {
1843     out << endl;
1844     indent(out) << "// Clear values(for union's property setter)" << endl;
1845     indent(out) << "procedure ClearUnionValues;" << endl;
1846   }
1847 
1848   if (members.size() > 0) {
1849     out << endl;
1850     for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1851       if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
1852         isset_name = "__isset_" + prop_name(*m_iter, is_exception);
1853         indent(out) << "function Get" << isset_name << ": System.Boolean;" << endl;
1854         indent(out) << "procedure Set" << isset_name << "( const value : System.Boolean);" << endl;
1855       }
1856     }
1857   }
1858 
1859   if (is_exception && (!is_x_factory)) {
1860     out << endl;
1861     indent_down();
1862     indent(out) << "strict protected" << endl;
1863     indent_up();
1864     indent(out) << "function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall;" << endl;
1865     indent(out) << "function _AddRef: Integer; stdcall;" << endl;
1866     indent(out) << "function _Release: Integer; stdcall;" << endl;
1867     out << endl;
1868   }
1869 
1870   indent_down();
1871   indent(out) << "public" << endl;
1872   indent_up();
1873 
1874   if ((members.size() > 0) && is_exception && (!is_x_factory)) {
1875     indent(out) << "constructor Create; overload;" << endl;
1876     indent(out) << "constructor Create(" << constructor_argument_list(tstruct, indent())
1877                 << "); overload;" << endl;
1878   } else {
1879     indent(out) << "constructor Create;" << endl;
1880   }
1881 
1882   indent(out) << "destructor Destroy; override;" << endl;
1883 
1884   out << endl;
1885   indent(out) << "function ToString: string; override;" << endl;
1886 
1887   if (is_exception && (!is_x_factory)) {
1888     out << endl;
1889     indent(out) << "// Exception Factory" << endl;
1890     indent(out) << "function " << exception_factory_name << ": " << struct_intf_name << ";" << endl;
1891   }
1892 
1893   out << endl;
1894   indent(out) << "// IBase" << endl;
1895   indent(out) << "procedure Read( const iprot: IProtocol);" << endl;
1896   indent(out) << "procedure Write( const oprot: IProtocol);" << endl;
1897 
1898   if (is_exception && is_x_factory) {
1899     out << endl;
1900     indent(out) << "// Create Exception Object" << endl;
1901     indent(out) << "function CreateException: " << type_name(tstruct, true, true) << ";" << endl;
1902   }
1903 
1904   if (members.size() > 0) {
1905     out << endl;
1906     indent(out) << "// Properties" << endl;
1907     for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1908       generate_property(out, *m_iter, true, is_exception);
1909     }
1910   }
1911 
1912   if (members.size() > 0) {
1913     out << endl;
1914     indent(out) << "// isset" << endl;
1915     for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
1916       if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
1917         isset_name = "__isset_" + prop_name(*m_iter, is_exception);
1918         indent(out) << "property " << isset_name << ": System.Boolean read Get" << isset_name << " write Set" << isset_name << ";"
1919                     << endl;
1920       }
1921     }
1922   }
1923 
1924   indent_down();
1925   indent(out) << "end;" << endl << endl;
1926 }
1927 
generate_service(t_service * tservice)1928 void t_delphi_generator::generate_service(t_service* tservice) {
1929   indent_up();
1930   generate_delphi_doc(s_service, tservice);
1931   indent(s_service) << normalize_clsnm(service_name_, "T") << " = class" << endl;
1932   indent(s_service) << "public" << endl;
1933   indent_up();
1934   indent(s_service) << "type" << endl;
1935   generate_service_interface(tservice);
1936   generate_service_client(tservice);
1937   generate_service_server(tservice);
1938   generate_service_helpers(tservice);
1939   indent_down();
1940   indent_down();
1941   indent(s_service) << "end;" << endl;
1942   indent(s_service) << endl;
1943   indent_down();
1944 }
1945 
generate_service_interface(t_service * tservice)1946 void t_delphi_generator::generate_service_interface(t_service* tservice) {
1947   generate_service_interface(tservice,false);
1948   if(async_) {
1949     generate_service_interface(tservice,true);
1950   }
1951 }
1952 
1953 
generate_service_interface(t_service * tservice,bool for_async)1954 void t_delphi_generator::generate_service_interface(t_service* tservice, bool for_async) {
1955   string extends = "";
1956   string extends_iface = "";
1957   string iface_name = for_async ? "IAsync" : "Iface";
1958 
1959   indent_up();
1960 
1961   generate_delphi_doc(s_service, tservice);
1962   if (tservice->get_extends() != nullptr) {
1963     extends = type_name(tservice->get_extends(), true, true);
1964     extends_iface = extends + "." + iface_name;
1965     generate_delphi_doc(s_service, tservice);
1966     indent(s_service) << iface_name << " = interface(" << extends_iface << ")" << endl;
1967   } else {
1968     indent(s_service) << iface_name << " = interface" << endl;
1969   }
1970 
1971   indent_up();
1972   generate_guid(s_service);
1973   vector<t_function*> functions = tservice->get_functions();
1974   vector<t_function*>::iterator f_iter;
1975   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1976     generate_delphi_doc(s_service, *f_iter);
1977     indent(s_service) << function_signature(*f_iter, for_async) << endl;
1978   }
1979   indent_down();
1980   indent(s_service) << "end;" << endl << endl;
1981 
1982   indent_down();
1983 }
1984 
generate_guid(std::ostream & out)1985 void t_delphi_generator::generate_guid(std::ostream& out) {
1986 #ifdef _WIN32   // TODO: add support for non-windows platforms if needed
1987   GUID guid;
1988   if (SUCCEEDED(CoCreateGuid(&guid))) {
1989     OLECHAR guid_chars[40];
1990     if (StringFromGUID2(guid, &guid_chars[0], sizeof(guid_chars) / sizeof(guid_chars[0])) > 0) {
1991       std::wstring guid_wstr(guid_chars);
1992       std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> convert;
1993       std::string guid_str = convert.to_bytes(guid_wstr);
1994       indent(out) << "['" << guid_str << "']" << endl;
1995     }
1996   }
1997 #else
1998   (void)out;  // prevent unused warning on other platforms
1999 #endif
2000 }
2001 
generate_service_helpers(t_service * tservice)2002 void t_delphi_generator::generate_service_helpers(t_service* tservice) {
2003   vector<t_function*> functions = tservice->get_functions();
2004   vector<t_function*>::iterator f_iter;
2005 
2006   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
2007     t_struct* ts = (*f_iter)->get_arglist();
2008     generate_delphi_struct_definition(s_service, ts, false, true);
2009     generate_delphi_struct_impl(s_service_impl,
2010                                 normalize_clsnm(service_name_, "T") + ".",
2011                                 ts,
2012                                 false);
2013     generate_function_helpers(*f_iter);
2014   }
2015 }
2016 
generate_service_client(t_service * tservice)2017 void t_delphi_generator::generate_service_client(t_service* tservice) {
2018   indent_up();
2019   string extends = "";
2020   string extends_client = "TInterfacedObject";
2021   string implements = async_ ? "Iface, IAsync" : "Iface";
2022 
2023   generate_delphi_doc(s_service, tservice);
2024   if (tservice->get_extends() != nullptr) {
2025     extends = type_name(tservice->get_extends(), true, true);
2026     extends_client = extends + ".TClient";
2027   }
2028   indent(s_service) << "TClient = class( " << extends_client << ", " << implements << ")" << endl;
2029 
2030   indent(s_service) << "public" << endl;
2031   indent_up();
2032 
2033   indent(s_service) << "constructor Create( prot: IProtocol); overload;" << endl;
2034 
2035   indent_impl(s_service_impl) << "constructor " << normalize_clsnm(service_name_, "T")
2036                               << ".TClient.Create( prot: IProtocol);" << endl;
2037   indent_impl(s_service_impl) << "begin" << endl;
2038   indent_up_impl();
2039   indent_impl(s_service_impl) << "Create( prot, prot );" << endl;
2040   indent_down_impl();
2041   indent_impl(s_service_impl) << "end;" << endl << endl;
2042 
2043   indent(s_service)
2044       << "constructor Create( const iprot: IProtocol; const oprot: IProtocol); overload;" << endl;
2045 
2046   indent_impl(s_service_impl) << "constructor " << normalize_clsnm(service_name_, "T")
2047                               << ".TClient.Create( const iprot: IProtocol; const oprot: IProtocol);"
2048                               << endl;
2049   indent_impl(s_service_impl) << "begin" << endl;
2050   indent_up_impl();
2051   indent_impl(s_service_impl) << "inherited Create;" << endl;
2052   indent_impl(s_service_impl) << "iprot_ := iprot;" << endl;
2053   indent_impl(s_service_impl) << "oprot_ := oprot;" << endl;
2054   indent_down_impl();
2055   indent_impl(s_service_impl) << "end;" << endl << endl;
2056 
2057   indent_down();
2058 
2059   if (extends.empty()) {
2060     indent(s_service) << "protected" << endl;
2061     indent_up();
2062     indent(s_service) << "iprot_: IProtocol;" << endl;
2063     indent(s_service) << "oprot_: IProtocol;" << endl;
2064     indent(s_service) << "seqid_: System.Integer;" << endl;
2065     indent_down();
2066 
2067     indent(s_service) << "public" << endl;
2068     indent_up();
2069     indent(s_service) << "property InputProtocol: IProtocol read iprot_;" << endl;
2070     indent(s_service) << "property OutputProtocol: IProtocol read oprot_;" << endl;
2071     indent_down();
2072   }
2073 
2074   vector<t_function*> functions = tservice->get_functions();
2075   vector<t_function*>::const_iterator f_iter;
2076 
2077   indent(s_service) << "protected" << endl;
2078   indent_up();
2079 
2080   indent(s_service) << "// Iface" << endl;
2081   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
2082     string funname = (*f_iter)->get_name();
2083     generate_delphi_doc(s_service, *f_iter);
2084     indent(s_service) << function_signature(*f_iter, false) << endl;
2085   }
2086 
2087   if( async_) {
2088     indent(s_service) << endl;
2089     indent(s_service) << "// IAsync" << endl;
2090     for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
2091       string funname = (*f_iter)->get_name();
2092       generate_delphi_doc(s_service, *f_iter);
2093       indent(s_service) << function_signature(*f_iter, true) << endl;
2094     }
2095   }
2096 
2097   indent_down();
2098 
2099   indent(s_service) << "public" << endl;
2100   indent_up();
2101 
2102   string full_cls = normalize_clsnm(service_name_, "T") + ".TClient";
2103 
2104   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
2105     string funname = (*f_iter)->get_name();
2106 
2107     vector<t_field*>::const_iterator fld_iter;
2108     t_struct* arg_struct = (*f_iter)->get_arglist();
2109     const vector<t_field*>& fields = arg_struct->get_members();
2110 
2111     // one for sync only, two for async+sync
2112     int mode = async_ ? 1 : 0;
2113     while( mode >= 0) {
2114       bool for_async = (mode != 0);
2115       mode--;
2116 
2117       indent_impl(s_service_impl) << function_signature(*f_iter, for_async, full_cls) << endl;
2118       indent_impl(s_service_impl) << "begin" << endl;
2119       indent_up_impl();
2120 
2121       t_type* ttype = (*f_iter)->get_returntype();
2122       if( for_async) {
2123         if (is_void(ttype)) {
2124            // Delphi forces us to specify a type with IFuture<T>, so we use Integer=0 for void methods
2125           indent_impl(s_service_impl) << "result := TTask.Future<System.Integer>(function: System.Integer" << endl;
2126         } else {
2127           string rettype = type_name(ttype, false, true, false, true);
2128           indent_impl(s_service_impl) << "result := TTask.Future<" << rettype << ">(function: " << rettype << endl;
2129         }
2130         indent_impl(s_service_impl) << "begin" << endl;
2131         indent_up_impl();
2132       }
2133 
2134       indent_impl(s_service_impl) << "send_" << funname << "(";
2135 
2136       bool first = true;
2137       for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
2138         if (first) {
2139           first = false;
2140         } else {
2141           s_service_impl << ", ";
2142         }
2143         s_service_impl << normalize_name((*fld_iter)->get_name());
2144       }
2145       s_service_impl << ");" << endl;
2146 
2147       if (!(*f_iter)->is_oneway()) {
2148         s_service_impl << indent_impl();
2149         if (!(*f_iter)->get_returntype()->is_void()) {
2150           s_service_impl << "Result := ";
2151         }
2152         s_service_impl << "recv_" << funname << "();" << endl;
2153       }
2154 
2155       if( for_async) {
2156         if (is_void(ttype)) {
2157           indent_impl(s_service_impl) << "Result := 0;" << endl;  // no IFuture<void> in Delphi
2158         }
2159         indent_down_impl();
2160         indent_impl(s_service_impl) << "end);" << endl;
2161       }
2162 
2163       indent_down_impl();
2164       indent_impl(s_service_impl) << "end;" << endl << endl;
2165     }
2166 
2167     t_function send_function(g_type_void,
2168                              string("send_") + (*f_iter)->get_name(),
2169                              (*f_iter)->get_arglist());
2170 
2171     string argsname = (*f_iter)->get_name() + "_args";
2172     string args_clsnm = normalize_clsnm(argsname, "T");
2173     string args_intfnm = normalize_clsnm(argsname, "I");
2174 
2175     string argsvar = tmp("_args");
2176     string msgvar = tmp("_msg");
2177 
2178     indent(s_service) << function_signature(&send_function, false) << endl;
2179     indent_impl(s_service_impl) << function_signature(&send_function, false, full_cls) << endl;
2180     indent_impl(s_service_impl) << "var" << endl;
2181     indent_up_impl();
2182     indent_impl(s_service_impl) << argsvar << " : " << args_intfnm << ";" << endl;
2183     indent_impl(s_service_impl) << msgvar << " : Thrift.Protocol.TThriftMessage;" << endl;
2184     indent_down_impl();
2185     indent_impl(s_service_impl) << "begin" << endl;
2186     indent_up_impl();
2187 
2188     indent_impl(s_service_impl) << "seqid_ := seqid_ + 1;" << endl;
2189     indent_impl(s_service_impl) << "Thrift.Protocol.Init( " << msgvar << ", '" << funname
2190                                 << "', " << ((*f_iter)->is_oneway() ? "TMessageType.Oneway"
2191                                                                     : "TMessageType.Call")
2192                                 << ", seqid_);" << endl;
2193 
2194     indent_impl(s_service_impl) << "oprot_.WriteMessageBegin( " << msgvar << " );" << endl;
2195     indent_impl(s_service_impl) << argsvar << " := " << args_clsnm << "Impl.Create();" << endl;
2196 
2197     for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
2198       indent_impl(s_service_impl) << argsvar << "." << prop_name(*fld_iter)
2199                                   << " := " << normalize_name((*fld_iter)->get_name()) << ";"
2200                                   << endl;
2201     }
2202     indent_impl(s_service_impl) << argsvar << ".Write(oprot_);" << endl;
2203     for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
2204       indent_impl(s_service_impl) << argsvar << "." << prop_name(*fld_iter)
2205                                   << " := " << empty_value((*fld_iter)->get_type()) << ";" << endl;
2206     }
2207 
2208     indent_impl(s_service_impl) << "oprot_.WriteMessageEnd();" << endl;
2209     indent_impl(s_service_impl) << "oprot_.Transport.Flush();" << endl;
2210 
2211     indent_down_impl();
2212     indent_impl(s_service_impl) << "end;" << endl << endl;
2213 
2214     if (!(*f_iter)->is_oneway()) {
2215       string org_resultname = (*f_iter)->get_name() + "_result";
2216       string result_clsnm = normalize_clsnm(org_resultname, "T");
2217       string result_intfnm = normalize_clsnm(org_resultname, "I");
2218 
2219       t_struct noargs(program_);
2220       t_function recv_function((*f_iter)->get_returntype(),
2221                                string("recv_") + (*f_iter)->get_name(),
2222                                &noargs,
2223                                (*f_iter)->get_xceptions());
2224 
2225       t_struct* xs = (*f_iter)->get_xceptions();
2226       const std::vector<t_field*>& xceptions = xs->get_members();
2227 
2228       string exceptvar = tmp("_ex");
2229       string appexvar = tmp("_ax");
2230       string retvar = tmp("_ret");
2231 
2232       indent(s_service) << function_signature(&recv_function, false) << endl;
2233       indent_impl(s_service_impl) << function_signature(&recv_function, false, full_cls) << endl;
2234       indent_impl(s_service_impl) << "var" << endl;
2235       indent_up_impl();
2236       indent_impl(s_service_impl) << msgvar << " : Thrift.Protocol.TThriftMessage;" << endl;
2237       if (xceptions.size() > 0) {
2238         indent_impl(s_service_impl) << exceptvar << " : Exception;" << endl;
2239       }
2240       indent_impl(s_service_impl) << appexvar << " : TApplicationException;" << endl;
2241       indent_impl(s_service_impl) << retvar << " : " << result_intfnm << ";" << endl;
2242 
2243       indent_down_impl();
2244       indent_impl(s_service_impl) << "begin" << endl;
2245       indent_up_impl();
2246       indent_impl(s_service_impl) << msgvar << " := iprot_.ReadMessageBegin();" << endl;
2247       indent_impl(s_service_impl) << "if (" << msgvar << ".Type_ = TMessageType.Exception) then begin" << endl;
2248       indent_up_impl();
2249       indent_impl(s_service_impl) << appexvar << " := TApplicationException.Read(iprot_);" << endl;
2250       indent_impl(s_service_impl) << "iprot_.ReadMessageEnd();" << endl;
2251       indent_impl(s_service_impl) << "raise " << appexvar << ";" << endl;
2252       indent_down_impl();
2253       indent_impl(s_service_impl) << "end;" << endl;
2254 
2255       indent_impl(s_service_impl) << retvar << " := " << result_clsnm << "Impl.Create();" << endl;
2256       indent_impl(s_service_impl) << retvar << ".Read(iprot_);" << endl;
2257       indent_impl(s_service_impl) << "iprot_.ReadMessageEnd();" << endl;
2258 
2259       if (!(*f_iter)->get_returntype()->is_void()) {
2260         indent_impl(s_service_impl) << "if (" << retvar << ".__isset_success) then begin" << endl;
2261         indent_up_impl();
2262         indent_impl(s_service_impl) << "Result := " << retvar << ".Success;" << endl;
2263         t_type* type = (*f_iter)->get_returntype();
2264         if (type->is_struct() || type->is_xception() || type->is_map() || type->is_list()
2265             || type->is_set()) {
2266           indent_impl(s_service_impl) << retvar << ".Success := nil;" << endl;
2267         }
2268         indent_impl(s_service_impl) << "Exit;" << endl;
2269         indent_down_impl();
2270         indent_impl(s_service_impl) << "end;" << endl;
2271       }
2272 
2273       vector<t_field*>::const_iterator x_iter;
2274       for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
2275         indent_impl(s_service_impl) << "if (" << retvar << ".__isset_" << prop_name(*x_iter)
2276                                     << ") then begin" << endl;
2277         indent_up_impl();
2278         indent_impl(s_service_impl) << exceptvar << " := " << retvar << "." << prop_name(*x_iter)
2279                                     << ".CreateException;" << endl;
2280         indent_impl(s_service_impl) << "raise " << exceptvar << ";" << endl;
2281         indent_down_impl();
2282         indent_impl(s_service_impl) << "end;" << endl;
2283       }
2284 
2285       if (!(*f_iter)->get_returntype()->is_void()) {
2286         indent_impl(s_service_impl)
2287             << "raise TApplicationExceptionMissingResult.Create('"
2288             << (*f_iter)->get_name() << " failed: unknown result');" << endl;
2289       }
2290 
2291       indent_down_impl();
2292       indent_impl(s_service_impl) << "end;" << endl << endl;
2293     }
2294   }
2295 
2296   indent_down();
2297   indent(s_service) << "end;" << endl << endl;
2298 }
2299 
generate_service_server(t_service * tservice)2300 void t_delphi_generator::generate_service_server(t_service* tservice) {
2301   vector<t_function*> functions = tservice->get_functions();
2302   vector<t_function*>::iterator f_iter;
2303 
2304   string extends = "";
2305   string extends_processor = "";
2306 
2307   string full_cls = normalize_clsnm(service_name_, "T") + ".TProcessorImpl";
2308 
2309   if (tservice->get_extends() != nullptr) {
2310     extends = type_name(tservice->get_extends(), true, true);
2311     extends_processor = extends + ".TProcessorImpl";
2312     indent(s_service) << "TProcessorImpl = class(" << extends_processor << ", IProcessor)" << endl;
2313   } else {
2314     indent(s_service) << "TProcessorImpl = class( TInterfacedObject, IProcessor)" << endl;
2315   }
2316 
2317   indent(s_service) << "public" << endl;
2318   indent_up();
2319   indent(s_service) << "constructor Create( iface_: Iface );" << endl;
2320   indent(s_service) << "destructor Destroy; override;" << endl;
2321   indent_down();
2322 
2323   indent_impl(s_service_impl) << "constructor " << full_cls << ".Create( iface_: Iface );" << endl;
2324   indent_impl(s_service_impl) << "begin" << endl;
2325   indent_up_impl();
2326   if (tservice->get_extends() != nullptr) {
2327     indent_impl(s_service_impl) << "inherited Create( iface_);" << endl;
2328   } else {
2329     indent_impl(s_service_impl) << "inherited Create;" << endl;
2330   }
2331   indent_impl(s_service_impl) << "Self.iface_ := iface_;" << endl;
2332   if (tservice->get_extends() != nullptr) {
2333     indent_impl(s_service_impl) << "ASSERT( processMap_ <> nil);  // inherited" << endl;
2334   } else {
2335     indent_impl(s_service_impl)
2336         << "processMap_ := TThriftDictionaryImpl<string, TProcessFunction>.Create;" << endl;
2337   }
2338 
2339   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
2340     indent_impl(s_service_impl) << "processMap_.AddOrSetValue( '" << (*f_iter)->get_name() << "', "
2341                                 << (*f_iter)->get_name() << "_Process);" << endl;
2342   }
2343   indent_down_impl();
2344   indent_impl(s_service_impl) << "end;" << endl << endl;
2345 
2346   indent_impl(s_service_impl) << "destructor " << full_cls << ".Destroy;" << endl;
2347   indent_impl(s_service_impl) << "begin" << endl;
2348   indent_up_impl();
2349   indent_impl(s_service_impl) << "inherited;" << endl;
2350   indent_down_impl();
2351   indent_impl(s_service_impl) << "end;" << endl << endl;
2352 
2353   indent(s_service) << "private" << endl;
2354   indent_up();
2355   indent(s_service) << "iface_: Iface;" << endl;
2356   indent_down();
2357 
2358   if (tservice->get_extends() == nullptr) {
2359     indent(s_service) << "protected" << endl;
2360     indent_up();
2361     indent(s_service) << "type" << endl;
2362     indent_up();
2363     indent(s_service) << "TProcessFunction = reference to procedure( seqid: System.Integer; const iprot: "
2364                          "IProtocol; const oprot: IProtocol"
2365                       << (events_ ? "; const events : IRequestEvents" : "") << ");" << endl;
2366     indent_down();
2367     indent_down();
2368     indent(s_service) << "protected" << endl;
2369     indent_up();
2370     indent(s_service) << "processMap_: IThriftDictionary<string, TProcessFunction>;" << endl;
2371     indent_down();
2372   }
2373 
2374   indent(s_service) << "public" << endl;
2375   indent_up();
2376   if (extends.empty()) {
2377     indent(s_service) << "function Process( const iprot: IProtocol; const oprot: IProtocol; const "
2378                          "events : IProcessorEvents): System.Boolean;" << endl;
2379   } else {
2380     indent(s_service) << "function Process( const iprot: IProtocol; const oprot: IProtocol; const "
2381                          "events : IProcessorEvents): System.Boolean; reintroduce;" << endl;
2382   }
2383 
2384   indent_impl(s_service_impl) << "function " << full_cls << ".Process( const iprot: IProtocol; "
2385                                                             "const oprot: IProtocol; const events "
2386                                                             ": IProcessorEvents): System.Boolean;" << endl;
2387   ;
2388   indent_impl(s_service_impl) << "var" << endl;
2389   indent_up_impl();
2390   indent_impl(s_service_impl) << "msg : Thrift.Protocol.TThriftMessage;" << endl;
2391   indent_impl(s_service_impl) << "fn : TProcessFunction;" << endl;
2392   indent_impl(s_service_impl) << "x : TApplicationException;" << endl;
2393   if (events_) {
2394     indent_impl(s_service_impl) << "context : IRequestEvents;" << endl;
2395   }
2396   indent_down_impl();
2397   indent_impl(s_service_impl) << "begin" << endl;
2398   indent_up_impl();
2399   indent_impl(s_service_impl) << "try" << endl;
2400   indent_up_impl();
2401   indent_impl(s_service_impl) << "msg := iprot.ReadMessageBegin();" << endl;
2402   indent_impl(s_service_impl) << "fn := nil;" << endl;
2403   indent_impl(s_service_impl) << "if not processMap_.TryGetValue(msg.Name, fn)" << endl;
2404   indent_impl(s_service_impl) << "or not Assigned(fn) then begin" << endl;
2405   indent_up_impl();
2406   indent_impl(s_service_impl) << "TProtocolUtil.Skip(iprot, TType.Struct);" << endl;
2407   indent_impl(s_service_impl) << "iprot.ReadMessageEnd();" << endl;
2408   indent_impl(s_service_impl) << "x := "
2409                                  "TApplicationExceptionUnknownMethod.Create("
2410                                  "'Invalid method name: ''' + msg.Name + '''');" << endl;
2411   indent_impl(s_service_impl)
2412       << "Thrift.Protocol.Init( msg, msg.Name, TMessageType.Exception, msg.SeqID);"
2413       << endl;
2414   indent_impl(s_service_impl) << "oprot.WriteMessageBegin( msg);" << endl;
2415   indent_impl(s_service_impl) << "x.Write(oprot);" << endl;
2416   indent_impl(s_service_impl) << "oprot.WriteMessageEnd();" << endl;
2417   indent_impl(s_service_impl) << "oprot.Transport.Flush();" << endl;
2418   indent_impl(s_service_impl) << "Result := True;" << endl;
2419   indent_impl(s_service_impl) << "Exit;" << endl;
2420   indent_down_impl();
2421   indent_impl(s_service_impl) << "end;" << endl;
2422   if (events_) {
2423     indent_impl(s_service_impl) << "if events <> nil" << endl;
2424     indent_impl(s_service_impl) << "then context := events.CreateRequestContext(msg.Name)" << endl;
2425     indent_impl(s_service_impl) << "else context := nil;" << endl;
2426     indent_impl(s_service_impl) << "try" << endl;
2427     indent_up_impl();
2428     indent_impl(s_service_impl) << "fn(msg.SeqID, iprot, oprot, context);" << endl;
2429     indent_down_impl();
2430     indent_impl(s_service_impl) << "finally" << endl;
2431     indent_up_impl();
2432     indent_impl(s_service_impl) << "if context <> nil then begin" << endl;
2433     indent_up_impl();
2434     indent_impl(s_service_impl) << "context.CleanupContext;" << endl;
2435     indent_impl(s_service_impl) << "context := nil;" << endl;
2436     indent_down_impl();
2437     indent_impl(s_service_impl) << "end;" << endl;
2438     indent_down_impl();
2439     indent_impl(s_service_impl) << "end;" << endl;
2440   } else {
2441     indent_impl(s_service_impl) << "fn(msg.SeqID, iprot, oprot);" << endl;
2442   }
2443   indent_down_impl();
2444   indent_impl(s_service_impl) << "except" << endl;
2445   indent_up_impl();
2446   indent_impl(s_service_impl) << "on TTransportExceptionTimedOut do begin" << endl;
2447   indent_up_impl();
2448   indent_impl(s_service_impl) << "Result := True;" << endl;
2449   indent_impl(s_service_impl) << "Exit;" << endl;
2450   indent_down_impl();
2451   indent_impl(s_service_impl) << "end;" << endl;
2452   indent_impl(s_service_impl) << "else begin" << endl;
2453   indent_up_impl();
2454   indent_impl(s_service_impl) << "Result := False;" << endl;
2455   indent_impl(s_service_impl) << "Exit;" << endl;
2456   indent_down_impl();
2457   indent_impl(s_service_impl) << "end;" << endl;
2458   indent_down_impl();
2459   indent_impl(s_service_impl) << "end;" << endl;
2460   indent_impl(s_service_impl) << "Result := True;" << endl;
2461   indent_down_impl();
2462   indent_impl(s_service_impl) << "end;" << endl << endl;
2463 
2464   for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
2465     generate_process_function(tservice, *f_iter);
2466   }
2467 
2468   indent_down();
2469   indent(s_service) << "end;" << endl << endl;
2470 }
2471 
generate_function_helpers(t_function * tfunction)2472 void t_delphi_generator::generate_function_helpers(t_function* tfunction) {
2473   if (tfunction->is_oneway()) {
2474     return;
2475   }
2476 
2477   t_struct result(program_, tfunction->get_name() + "_result");
2478   t_field success(tfunction->get_returntype(), "Success", 0);
2479   if (!tfunction->get_returntype()->is_void()) {
2480     result.append(&success);
2481   }
2482 
2483   t_struct* xs = tfunction->get_xceptions();
2484   const vector<t_field*>& fields = xs->get_members();
2485   vector<t_field*>::const_iterator f_iter;
2486   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2487     result.append(*f_iter);
2488   }
2489 
2490   generate_delphi_struct_definition(s_service, &result, false, true, true);
2491   generate_delphi_struct_impl(s_service_impl,
2492                               normalize_clsnm(service_name_, "T") + ".",
2493                               &result,
2494                               false);
2495 }
2496 
generate_process_function(t_service * tservice,t_function * tfunction)2497 void t_delphi_generator::generate_process_function(t_service* tservice, t_function* tfunction) {
2498   (void)tservice;
2499   string funcname = tfunction->get_name();
2500   string full_cls = normalize_clsnm(service_name_, "T") + ".TProcessorImpl";
2501 
2502   string org_argsname = funcname + "_args";
2503   string args_clsnm = normalize_clsnm(org_argsname, "T");
2504   string args_intfnm = normalize_clsnm(org_argsname, "I");
2505 
2506   string org_resultname = funcname + "_result";
2507   string result_clsnm = normalize_clsnm(org_resultname, "T");
2508   string result_intfnm = normalize_clsnm(org_resultname, "I");
2509 
2510   indent(s_service) << "procedure " << funcname
2511                     << "_Process( seqid: System.Integer; const iprot: IProtocol; const oprot: IProtocol"
2512                     << (events_ ? "; const events : IRequestEvents" : "") << ");" << endl;
2513 
2514   if (tfunction->is_oneway()) {
2515     indent_impl(s_service_impl) << "// one way processor" << endl;
2516   } else {
2517     indent_impl(s_service_impl) << "// both way processor" << endl;
2518   }
2519 
2520   indent_impl(s_service_impl)
2521       << "procedure " << full_cls << "." << funcname
2522       << "_Process( seqid: System.Integer; const iprot: IProtocol; const oprot: IProtocol"
2523       << (events_ ? "; const events : IRequestEvents" : "") << ");" << endl;
2524   indent_impl(s_service_impl) << "var" << endl;
2525   indent_up_impl();
2526   indent_impl(s_service_impl) << "args: " << args_intfnm << ";" << endl;
2527   if (!tfunction->is_oneway()) {
2528     indent_impl(s_service_impl) << "msg: Thrift.Protocol.TThriftMessage;" << endl;
2529     indent_impl(s_service_impl) << "ret: " << result_intfnm << ";" << endl;
2530     indent_impl(s_service_impl) << "appx : TApplicationException;" << endl;
2531   }
2532 
2533   indent_down_impl();
2534   indent_impl(s_service_impl) << "begin" << endl;
2535   indent_up_impl();
2536 
2537   if (events_) {
2538     indent_impl(s_service_impl) << "if events <> nil then events.PreRead;" << endl;
2539   }
2540   indent_impl(s_service_impl) << "args := " << args_clsnm << "Impl.Create;" << endl;
2541   indent_impl(s_service_impl) << "args.Read(iprot);" << endl;
2542   indent_impl(s_service_impl) << "iprot.ReadMessageEnd();" << endl;
2543   if (events_) {
2544     indent_impl(s_service_impl) << "if events <> nil then events.PostRead;" << endl;
2545   }
2546 
2547   t_struct* xs = tfunction->get_xceptions();
2548   const std::vector<t_field*>& xceptions = xs->get_members();
2549   vector<t_field*>::const_iterator x_iter;
2550 
2551   if (!tfunction->is_oneway()) {
2552     indent_impl(s_service_impl) << "ret := " << result_clsnm << "Impl.Create;" << endl;
2553   }
2554 
2555   indent_impl(s_service_impl) << "try" << endl;
2556   indent_up_impl();
2557 
2558   t_struct* arg_struct = tfunction->get_arglist();
2559   const std::vector<t_field*>& fields = arg_struct->get_members();
2560   vector<t_field*>::const_iterator f_iter;
2561 
2562   s_service_impl << indent_impl();
2563   if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
2564     s_service_impl << "ret.Success := ";
2565   }
2566   s_service_impl << "iface_." << normalize_name(tfunction->get_name(), true) << "(";
2567   bool first = true;
2568   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2569     if (first) {
2570       first = false;
2571     } else {
2572       s_service_impl << ", ";
2573     }
2574     s_service_impl << "args." << prop_name(*f_iter);
2575   }
2576   s_service_impl << ");" << endl;
2577 
2578   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2579     indent_impl(s_service_impl) << "args." << prop_name(*f_iter)
2580                                 << " := " << empty_value((*f_iter)->get_type()) << ";" << endl;
2581   }
2582 
2583   indent_down_impl();
2584   indent_impl(s_service_impl) << "except" << endl;
2585   indent_up_impl();
2586 
2587   for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
2588     indent_impl(s_service_impl) << "on E: " << type_name((*x_iter)->get_type(), true, true)
2589                                 << " do begin" << endl;
2590     indent_up_impl();
2591     if (!tfunction->is_oneway()) {
2592       string factory_name = normalize_clsnm((*x_iter)->get_type()->get_name(), "", true)
2593                             + "Factory";
2594       indent_impl(s_service_impl) << "ret." << prop_name(*x_iter) << " := E." << factory_name << ";"
2595                                   << endl;
2596     }
2597     indent_down_impl();
2598     indent_impl(s_service_impl) << "end;" << endl;
2599   }
2600 
2601   indent_impl(s_service_impl) << "on E: Exception do begin" << endl;
2602   indent_up_impl();
2603   if(events_) {
2604     indent_impl(s_service_impl) << "if events <> nil then events.UnhandledError(E);" << endl;
2605   }
2606   if (!tfunction->is_oneway()) {
2607     indent_impl(s_service_impl) << "appx := TApplicationExceptionInternalError.Create(E.Message);"
2608                                 << endl;
2609     indent_impl(s_service_impl) << "try" << endl;
2610     indent_up_impl();
2611     if(events_) {
2612       indent_impl(s_service_impl) << "if events <> nil then events.PreWrite;" << endl;
2613     }
2614     indent_impl(s_service_impl) << "Thrift.Protocol.Init( msg, '"
2615                                 << tfunction->get_name() << "', TMessageType.Exception, seqid);"
2616                                 << endl;
2617     indent_impl(s_service_impl) << "oprot.WriteMessageBegin( msg);" << endl;
2618     indent_impl(s_service_impl) << "appx.Write(oprot);" << endl;
2619     indent_impl(s_service_impl) << "oprot.WriteMessageEnd();" << endl;
2620     indent_impl(s_service_impl) << "oprot.Transport.Flush();" << endl;
2621     if(events_) {
2622       indent_impl(s_service_impl) << "if events <> nil then events.PostWrite;" << endl;
2623     }
2624     indent_impl(s_service_impl) << "Exit;" << endl;
2625     indent_down_impl();
2626     indent_impl(s_service_impl) << "finally" << endl;
2627     indent_up_impl();
2628     indent_impl(s_service_impl) << "appx.Free;" << endl;
2629     indent_down_impl();
2630     indent_impl(s_service_impl) << "end;" << endl;
2631   }
2632   indent_down_impl();
2633   indent_impl(s_service_impl) << "end;" << endl;
2634 
2635   indent_down_impl();
2636   indent_impl(s_service_impl) << "end;" << endl;
2637 
2638   if (!tfunction->is_oneway()) {
2639     if (events_) {
2640       indent_impl(s_service_impl) << "if events <> nil then events.PreWrite;" << endl;
2641     }
2642     indent_impl(s_service_impl) << "Thrift.Protocol.Init( msg, '"
2643                                 << tfunction->get_name() << "', TMessageType.Reply, seqid); "
2644                                 << endl;
2645     indent_impl(s_service_impl) << "oprot.WriteMessageBegin( msg); " << endl;
2646     indent_impl(s_service_impl) << "ret.Write(oprot);" << endl;
2647     indent_impl(s_service_impl) << "oprot.WriteMessageEnd();" << endl;
2648     indent_impl(s_service_impl) << "oprot.Transport.Flush();" << endl;
2649     if (events_) {
2650       indent_impl(s_service_impl) << "if events <> nil then events.PostWrite;" << endl;
2651     }
2652   } else if (events_) {
2653     indent_impl(s_service_impl) << "if events <> nil then events.OnewayComplete;" << endl;
2654   }
2655 
2656   indent_down_impl();
2657   indent_impl(s_service_impl) << "end;" << endl << endl;
2658 }
2659 
generate_deserialize_field(ostream & out,bool is_xception,t_field * tfield,string prefix,ostream & local_vars)2660 void t_delphi_generator::generate_deserialize_field(ostream& out,
2661                                                     bool is_xception,
2662                                                     t_field* tfield,
2663                                                     string prefix,
2664                                                     ostream& local_vars) {
2665   t_type* type = tfield->get_type();
2666   while (type->is_typedef()) {
2667     type = ((t_typedef*)type)->get_type();
2668   }
2669 
2670   if (type->is_void()) {
2671     throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name();
2672   }
2673 
2674   string name = prefix + prop_name(tfield, is_xception);
2675 
2676   if (type->is_struct() || type->is_xception()) {
2677     generate_deserialize_struct(out, (t_struct*)type, name, "");
2678   } else if (type->is_container()) {
2679     generate_deserialize_container(out, is_xception, type, name, local_vars);
2680   } else if (type->is_base_type() || type->is_enum()) {
2681     indent_impl(out) << name << " := ";
2682 
2683     if (type->is_enum()) {
2684       out << type_name(type, false) << "(";
2685     }
2686 
2687     out << "iprot.";
2688 
2689     if (type->is_base_type()) {
2690       t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2691       switch (tbase) {
2692       case t_base_type::TYPE_VOID:
2693         throw "compiler error: cannot serialize void field in a struct: " + name;
2694         break;
2695       case t_base_type::TYPE_STRING:
2696         if (type->is_binary()) {
2697           if (ansistr_binary_) {
2698             out << "ReadAnsiString();";
2699           } else {
2700             out << "ReadBinary();";
2701           }
2702         } else {
2703           out << "ReadString();";
2704         }
2705         break;
2706       case t_base_type::TYPE_BOOL:
2707         out << "ReadBool();";
2708         break;
2709       case t_base_type::TYPE_I8:
2710         out << "ReadByte();";
2711         break;
2712       case t_base_type::TYPE_I16:
2713         out << "ReadI16();";
2714         break;
2715       case t_base_type::TYPE_I32:
2716         out << "ReadI32();";
2717         break;
2718       case t_base_type::TYPE_I64:
2719         out << "ReadI64();";
2720         break;
2721       case t_base_type::TYPE_DOUBLE:
2722         out << "ReadDouble();";
2723         break;
2724       default:
2725         throw "compiler error: no Delphi name for base type " + t_base_type::t_base_name(tbase);
2726       }
2727     } else if (type->is_enum()) {
2728       out << "ReadI32()";
2729       out << ");";
2730     }
2731     out << endl;
2732   } else {
2733     printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
2734            tfield->get_name().c_str(),
2735            type_name(type).c_str());
2736   }
2737 }
2738 
generate_deserialize_struct(ostream & out,t_struct * tstruct,string name,string prefix)2739 void t_delphi_generator::generate_deserialize_struct(ostream& out,
2740                                                      t_struct* tstruct,
2741                                                      string name,
2742                                                      string prefix) {
2743   string typ_name;
2744 
2745   if (tstruct->is_xception()) {
2746     typ_name = type_name(tstruct, true, false, true, true);
2747   } else {
2748     typ_name = type_name(tstruct, true, false);
2749   }
2750 
2751   indent_impl(out) << prefix << name << " := " << typ_name << ".Create;" << endl;
2752   indent_impl(out) << prefix << name << ".Read(iprot);" << endl;
2753 }
2754 
generate_deserialize_container(ostream & out,bool is_xception,t_type * ttype,string name,std::ostream & local_vars)2755 void t_delphi_generator::generate_deserialize_container(ostream& out,
2756                                                         bool is_xception,
2757                                                         t_type* ttype,
2758                                                         string name,
2759                                                         std::ostream& local_vars) {
2760 
2761   string obj;
2762   string counter;
2763   string local_var;
2764 
2765   if (ttype->is_map()) {
2766     obj = tmp("_map");
2767   } else if (ttype->is_set()) {
2768     obj = tmp("_set");
2769   } else if (ttype->is_list()) {
2770     obj = tmp("_list");
2771   }
2772 
2773   if (ttype->is_map()) {
2774     local_var = obj + ": TThriftMap;";
2775   } else if (ttype->is_set()) {
2776     local_var = obj + ": TThriftSet;";
2777   } else if (ttype->is_list()) {
2778     local_var = obj + ": TThriftList;";
2779   }
2780   local_vars << "  " << local_var << endl;
2781   counter = tmp("_i");
2782   local_var = counter + ": System.Integer;";
2783   local_vars << "  " << local_var << endl;
2784 
2785   indent_impl(out) << name << " := " << type_name(ttype, true) << ".Create;" << endl;
2786 
2787   if (ttype->is_map()) {
2788     indent_impl(out) << obj << " := iprot.ReadMapBegin();" << endl;
2789   } else if (ttype->is_set()) {
2790     indent_impl(out) << obj << " := iprot.ReadSetBegin();" << endl;
2791   } else if (ttype->is_list()) {
2792     indent_impl(out) << obj << " := iprot.ReadListBegin();" << endl;
2793   }
2794 
2795   indent_impl(out) << "for " << counter << " := 0 to " << obj << ".Count - 1 do begin" << endl;
2796   indent_up_impl();
2797   if (ttype->is_map()) {
2798     generate_deserialize_map_element(out, is_xception, (t_map*)ttype, name, local_vars);
2799   } else if (ttype->is_set()) {
2800     generate_deserialize_set_element(out, is_xception, (t_set*)ttype, name, local_vars);
2801   } else if (ttype->is_list()) {
2802     generate_deserialize_list_element(out, is_xception, (t_list*)ttype, name, local_vars);
2803   }
2804   indent_down_impl();
2805   indent_impl(out) << "end;" << endl;
2806 
2807   if (ttype->is_map()) {
2808     indent_impl(out) << "iprot.ReadMapEnd();" << endl;
2809   } else if (ttype->is_set()) {
2810     indent_impl(out) << "iprot.ReadSetEnd();" << endl;
2811   } else if (ttype->is_list()) {
2812     indent_impl(out) << "iprot.ReadListEnd();" << endl;
2813   }
2814 }
2815 
generate_deserialize_map_element(ostream & out,bool is_xception,t_map * tmap,string prefix,ostream & local_vars)2816 void t_delphi_generator::generate_deserialize_map_element(ostream& out,
2817                                                           bool is_xception,
2818                                                           t_map* tmap,
2819                                                           string prefix,
2820                                                           ostream& local_vars) {
2821 
2822   string key = tmp("_key");
2823   string val = tmp("_val");
2824   string local_var;
2825 
2826   t_field fkey(tmap->get_key_type(), key);
2827   t_field fval(tmap->get_val_type(), val);
2828 
2829   local_vars << "  " << declare_field(&fkey) << endl;
2830   local_vars << "  " << declare_field(&fval) << endl;
2831 
2832   generate_deserialize_field(out, is_xception, &fkey, "", local_vars);
2833   generate_deserialize_field(out, is_xception, &fval, "", local_vars);
2834 
2835   indent_impl(out) << prefix << ".AddOrSetValue( " << key << ", " << val << ");" << endl;
2836 }
2837 
generate_deserialize_set_element(ostream & out,bool is_xception,t_set * tset,string prefix,ostream & local_vars)2838 void t_delphi_generator::generate_deserialize_set_element(ostream& out,
2839                                                           bool is_xception,
2840                                                           t_set* tset,
2841                                                           string prefix,
2842                                                           ostream& local_vars) {
2843   string elem = tmp("_elem");
2844   t_field felem(tset->get_elem_type(), elem);
2845   local_vars << "  " << declare_field(&felem) << endl;
2846   generate_deserialize_field(out, is_xception, &felem, "", local_vars);
2847   indent_impl(out) << prefix << ".Add(" << elem << ");" << endl;
2848 }
2849 
generate_deserialize_list_element(ostream & out,bool is_xception,t_list * tlist,string prefix,ostream & local_vars)2850 void t_delphi_generator::generate_deserialize_list_element(ostream& out,
2851                                                            bool is_xception,
2852                                                            t_list* tlist,
2853                                                            string prefix,
2854                                                            ostream& local_vars) {
2855   string elem = tmp("_elem");
2856   t_field felem(tlist->get_elem_type(), elem);
2857   local_vars << "  " << declare_field(&felem) << endl;
2858   generate_deserialize_field(out, is_xception, &felem, "", local_vars);
2859   indent_impl(out) << prefix << ".Add(" << elem << ");" << endl;
2860 }
2861 
generate_serialize_field(ostream & out,bool is_xception,t_field * tfield,string prefix,ostream & local_vars)2862 void t_delphi_generator::generate_serialize_field(ostream& out,
2863                                                   bool is_xception,
2864                                                   t_field* tfield,
2865                                                   string prefix,
2866                                                   ostream& local_vars) {
2867   (void)local_vars;
2868 
2869   t_type* type = tfield->get_type();
2870   while (type->is_typedef()) {
2871     type = ((t_typedef*)type)->get_type();
2872   }
2873 
2874   string name = prefix + prop_name(tfield, is_xception);
2875 
2876   if (type->is_void()) {
2877     throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name;
2878   }
2879 
2880   if (type->is_struct() || type->is_xception()) {
2881     generate_serialize_struct(out, (t_struct*)type, name, local_vars);
2882   } else if (type->is_container()) {
2883     generate_serialize_container(out, is_xception, type, name, local_vars);
2884   } else if (type->is_base_type() || type->is_enum()) {
2885 
2886     indent_impl(out) << "oprot.";
2887 
2888     if (type->is_base_type()) {
2889       t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2890 
2891       switch (tbase) {
2892       case t_base_type::TYPE_VOID:
2893         throw "compiler error: cannot serialize void field in a struct: " + name;
2894         break;
2895       case t_base_type::TYPE_STRING:
2896         if (type->is_binary()) {
2897           if (ansistr_binary_) {
2898             out << "WriteAnsiString(";
2899           } else {
2900             out << "WriteBinary(";
2901           }
2902         } else {
2903           out << "WriteString(";
2904         }
2905         out << name << ");";
2906         break;
2907       case t_base_type::TYPE_BOOL:
2908         out << "WriteBool(" << name << ");";
2909         break;
2910       case t_base_type::TYPE_I8:
2911         out << "WriteByte(" << name << ");";
2912         break;
2913       case t_base_type::TYPE_I16:
2914         out << "WriteI16(" << name << ");";
2915         break;
2916       case t_base_type::TYPE_I32:
2917         out << "WriteI32(" << name << ");";
2918         break;
2919       case t_base_type::TYPE_I64:
2920         out << "WriteI64(" << name << ");";
2921         break;
2922       case t_base_type::TYPE_DOUBLE:
2923         out << "WriteDouble(" << name << ");";
2924         break;
2925       default:
2926         throw "compiler error: no Delphi name for base type " + t_base_type::t_base_name(tbase);
2927       }
2928     } else if (type->is_enum()) {
2929       out << "WriteI32(System.Integer(" << name << "));";
2930     }
2931     out << endl;
2932   } else {
2933     printf("DO NOT KNOW HOW TO SERIALIZE '%s%s' TYPE '%s'\n",
2934            prefix.c_str(),
2935            tfield->get_name().c_str(),
2936            type_name(type).c_str());
2937   }
2938 }
2939 
generate_serialize_struct(ostream & out,t_struct * tstruct,string prefix,ostream & local_vars)2940 void t_delphi_generator::generate_serialize_struct(ostream& out,
2941                                                    t_struct* tstruct,
2942                                                    string prefix,
2943                                                    ostream& local_vars) {
2944   (void)local_vars;
2945   (void)tstruct;
2946   out << indent_impl() << prefix << ".Write(oprot);" << endl;
2947 }
2948 
generate_serialize_container(ostream & out,bool is_xception,t_type * ttype,string prefix,ostream & local_vars)2949 void t_delphi_generator::generate_serialize_container(ostream& out,
2950                                                       bool is_xception,
2951                                                       t_type* ttype,
2952                                                       string prefix,
2953                                                       ostream& local_vars) {
2954   string obj;
2955   if (ttype->is_map()) {
2956     obj = tmp("map");
2957     local_vars << "  " << obj << " : TThriftMap;" << endl;
2958     indent_impl(out) << "Thrift.Protocol.Init( " << obj << ", "
2959                      << type_to_enum(((t_map*)ttype)->get_key_type()) << ", "
2960                      << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << prefix
2961                      << ".Count);" << endl;
2962     indent_impl(out) << "oprot.WriteMapBegin( " << obj << ");" << endl;
2963   } else if (ttype->is_set()) {
2964     obj = tmp("set_");
2965     local_vars << "  " << obj << " : TThriftSet;" << endl;
2966     indent_impl(out) << "Thrift.Protocol.Init( " << obj << ", "
2967                      << type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " << prefix
2968                      << ".Count);" << endl;
2969     indent_impl(out) << "oprot.WriteSetBegin( " << obj << ");" << endl;
2970   } else if (ttype->is_list()) {
2971     obj = tmp("list_");
2972     local_vars << "  " << obj << " : TThriftList;" << endl;
2973     indent_impl(out) << "Thrift.Protocol.Init( " << obj << ", "
2974                      << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix
2975                      << ".Count);" << endl;
2976     indent_impl(out) << "oprot.WriteListBegin( " << obj << ");" << endl;
2977   }
2978 
2979   string iter = tmp("_iter");
2980   if (ttype->is_map()) {
2981     local_vars << "  " << iter << ": " << type_name(((t_map*)ttype)->get_key_type()) << ";" << endl;
2982     indent_impl(out) << "for " << iter << " in " << prefix << ".Keys do begin" << endl;
2983     indent_up_impl();
2984   } else if (ttype->is_set()) {
2985     local_vars << "  " << iter << ": " << type_name(((t_set*)ttype)->get_elem_type()) << ";"
2986                << endl;
2987     indent_impl(out) << "for " << iter << " in " << prefix << " do begin" << endl;
2988     indent_up_impl();
2989   } else if (ttype->is_list()) {
2990     local_vars << "  " << iter << ": " << type_name(((t_list*)ttype)->get_elem_type()) << ";"
2991                << endl;
2992     indent_impl(out) << "for " << iter << " in " << prefix << " do begin" << endl;
2993     indent_up_impl();
2994   }
2995 
2996   if (ttype->is_map()) {
2997     generate_serialize_map_element(out, is_xception, (t_map*)ttype, iter, prefix, local_vars);
2998   } else if (ttype->is_set()) {
2999     generate_serialize_set_element(out, is_xception, (t_set*)ttype, iter, local_vars);
3000   } else if (ttype->is_list()) {
3001     generate_serialize_list_element(out, is_xception, (t_list*)ttype, iter, local_vars);
3002   }
3003 
3004   indent_down_impl();
3005   indent_impl(out) << "end;" << endl;
3006 
3007   if (ttype->is_map()) {
3008     indent_impl(out) << "oprot.WriteMapEnd();" << endl;
3009   } else if (ttype->is_set()) {
3010     indent_impl(out) << "oprot.WriteSetEnd();" << endl;
3011   } else if (ttype->is_list()) {
3012     indent_impl(out) << "oprot.WriteListEnd();" << endl;
3013   }
3014 }
3015 
generate_serialize_map_element(ostream & out,bool is_xception,t_map * tmap,string iter,string map,ostream & local_vars)3016 void t_delphi_generator::generate_serialize_map_element(ostream& out,
3017                                                         bool is_xception,
3018                                                         t_map* tmap,
3019                                                         string iter,
3020                                                         string map,
3021                                                         ostream& local_vars) {
3022   t_field kfield(tmap->get_key_type(), iter);
3023   generate_serialize_field(out, is_xception, &kfield, "", local_vars);
3024   t_field vfield(tmap->get_val_type(), map + "[" + iter + "]");
3025   generate_serialize_field(out, is_xception, &vfield, "", local_vars);
3026 }
3027 
generate_serialize_set_element(ostream & out,bool is_xception,t_set * tset,string iter,ostream & local_vars)3028 void t_delphi_generator::generate_serialize_set_element(ostream& out,
3029                                                         bool is_xception,
3030                                                         t_set* tset,
3031                                                         string iter,
3032                                                         ostream& local_vars) {
3033   t_field efield(tset->get_elem_type(), iter);
3034   generate_serialize_field(out, is_xception, &efield, "", local_vars);
3035 }
3036 
generate_serialize_list_element(ostream & out,bool is_xception,t_list * tlist,string iter,ostream & local_vars)3037 void t_delphi_generator::generate_serialize_list_element(ostream& out,
3038                                                          bool is_xception,
3039                                                          t_list* tlist,
3040                                                          string iter,
3041                                                          ostream& local_vars) {
3042   t_field efield(tlist->get_elem_type(), iter);
3043   generate_serialize_field(out, is_xception, &efield, "", local_vars);
3044 }
3045 
generate_property(ostream & out,t_field * tfield,bool isPublic,bool is_xception)3046 void t_delphi_generator::generate_property(ostream& out,
3047                                            t_field* tfield,
3048                                            bool isPublic,
3049                                            bool is_xception) {
3050   generate_delphi_property(out, is_xception, tfield, isPublic, "Get");
3051 }
3052 
generate_delphi_property(ostream & out,bool struct_is_xception,t_field * tfield,bool isPublic,std::string fieldPrefix)3053 void t_delphi_generator::generate_delphi_property(ostream& out,
3054                                                   bool struct_is_xception,
3055                                                   t_field* tfield,
3056                                                   bool isPublic,
3057                                                   std::string fieldPrefix) {
3058   (void)isPublic;
3059 
3060   t_type* ftype = tfield->get_type();
3061   bool is_xception = ftype->is_xception();
3062   generate_delphi_doc(out, tfield);
3063   indent(out) << "property " << prop_name(tfield, struct_is_xception) << ": "
3064               << type_name(ftype, false, true, is_xception, true) << " read "
3065               << fieldPrefix + prop_name(tfield, struct_is_xception) << " write Set"
3066               << prop_name(tfield, struct_is_xception) << ";" << endl;
3067 }
3068 
prop_name(t_field * tfield,bool is_xception)3069 std::string t_delphi_generator::prop_name(t_field* tfield, bool is_xception) {
3070   return prop_name(tfield->get_name(), is_xception);
3071 }
3072 
prop_name(string name,bool is_xception)3073 std::string t_delphi_generator::prop_name(string name, bool is_xception) {
3074   string ret = name;
3075   ret[0] = toupper(ret[0]);
3076   return normalize_name(ret, true, is_xception);
3077 }
3078 
constructor_param_name(string name)3079 std::string t_delphi_generator::constructor_param_name(string name) {
3080   string ret = name;
3081   ret[0] = toupper(ret[0]);
3082   ret = "A" + ret;
3083   return normalize_name(ret, false, false);
3084 }
3085 
normalize_clsnm(string clsnm,string prefix,bool b_no_check_keyword)3086 string t_delphi_generator::normalize_clsnm(string clsnm, string prefix, bool b_no_check_keyword) {
3087   if (clsnm.size() > 0) {
3088     clsnm[0] = toupper(clsnm[0]);
3089   }
3090   if (b_no_check_keyword) {
3091     return prefix + clsnm;
3092   } else {
3093     return normalize_name(prefix + clsnm);
3094   }
3095 }
3096 
type_name(t_type * ttype,bool b_cls,bool b_no_postfix,bool b_exception_factory,bool b_full_exception_factory)3097 string t_delphi_generator::type_name(t_type* ttype,
3098                                      bool b_cls,
3099                                      bool b_no_postfix,
3100                                      bool b_exception_factory,
3101                                      bool b_full_exception_factory) {
3102 
3103   if (ttype->is_typedef()) {
3104     t_typedef* tdef = (t_typedef*)ttype;
3105     if (tdef->is_forward_typedef()) { // forward types according to THRIFT-2421
3106       if (tdef->get_type() != nullptr) {
3107         return type_name(tdef->get_type(),
3108                          b_cls,
3109                          b_no_postfix,
3110                          b_exception_factory,
3111                          b_full_exception_factory);
3112       } else {
3113         throw "unresolved forward declaration: " + tdef->get_symbolic();
3114       }
3115     } else {
3116       return normalize_name("T" + tdef->get_symbolic());
3117     }
3118   }
3119 
3120   string typ_nm;
3121 
3122   string s_factory;
3123 
3124   if (ttype->is_base_type()) {
3125     return base_type_name((t_base_type*)ttype);
3126   } else if (ttype->is_enum()) {
3127     b_cls = true;
3128     b_no_postfix = true;
3129   } else if (ttype->is_map()) {
3130     t_map* tmap = (t_map*)ttype;
3131     if (b_cls) {
3132       typ_nm = "TThriftDictionaryImpl";
3133     } else {
3134       typ_nm = "IThriftDictionary";
3135     }
3136     return typ_nm + "<" + type_name(tmap->get_key_type()) + ", " + type_name(tmap->get_val_type())
3137            + ">";
3138   } else if (ttype->is_set()) {
3139     t_set* tset = (t_set*)ttype;
3140     if (b_cls) {
3141       typ_nm = "THashSetImpl";
3142     } else {
3143       typ_nm = "IHashSet";
3144     }
3145     return typ_nm + "<" + type_name(tset->get_elem_type()) + ">";
3146   } else if (ttype->is_list()) {
3147     t_list* tlist = (t_list*)ttype;
3148     if (b_cls) {
3149       typ_nm = "TThriftListImpl";
3150     } else {
3151       typ_nm = "IThriftList";
3152     }
3153     return typ_nm + "<" + type_name(tlist->get_elem_type()) + ">";
3154   }
3155 
3156   string type_prefix;
3157 
3158   if (b_cls) {
3159     type_prefix = "T";
3160   } else {
3161     type_prefix = "I";
3162   }
3163 
3164   string nm = normalize_clsnm(ttype->get_name(), type_prefix);
3165 
3166   if (b_exception_factory) {
3167     nm = nm + "Factory";
3168   }
3169 
3170   if (b_cls) {
3171     if (!b_no_postfix) {
3172       nm = nm + "Impl";
3173     }
3174   }
3175 
3176   if (b_exception_factory && b_full_exception_factory) {
3177     return type_name(ttype, true, true, false, false) + "." + nm;
3178   }
3179 
3180   return nm;
3181 }
3182 
3183 // returns "const " for some argument types
input_arg_prefix(t_type * ttype)3184 string t_delphi_generator::input_arg_prefix(t_type* ttype) {
3185 
3186   // base types
3187   if (ttype->is_base_type()) {
3188     switch (((t_base_type*)ttype)->get_base()) {
3189 
3190     // these should be const'ed for optimal performamce
3191     case t_base_type::TYPE_STRING: // refcounted pointer
3192     case t_base_type::TYPE_I64:    // larger than 32 bit
3193     case t_base_type::TYPE_DOUBLE: // larger than 32 bit
3194       return "const ";
3195 
3196     // all others don't need to be
3197     case t_base_type::TYPE_I8:
3198     case t_base_type::TYPE_I16:
3199     case t_base_type::TYPE_I32:
3200     case t_base_type::TYPE_BOOL:
3201     case t_base_type::TYPE_VOID:
3202       return "";
3203 
3204     // we better always report any unknown types
3205     default:
3206       throw "compiler error: no input_arg_prefix() for base type "
3207           + t_base_type::t_base_name(((t_base_type*)ttype)->get_base());
3208     }
3209 
3210     // enums
3211   } else if (ttype->is_enum()) {
3212     return ""; // usually <= 32 bit
3213 
3214     // containers
3215   } else if (ttype->is_map()) {
3216     return "const "; // refcounted pointer
3217 
3218   } else if (ttype->is_set()) {
3219     return "const "; // refcounted pointer
3220 
3221   } else if (ttype->is_list()) {
3222     return "const "; // refcounted pointer
3223   }
3224 
3225   // any other type, either TSomething or ISomething
3226   return "const "; // possibly refcounted pointer
3227 }
3228 
base_type_name(t_base_type * tbase)3229 string t_delphi_generator::base_type_name(t_base_type* tbase) {
3230   switch (tbase->get_base()) {
3231   case t_base_type::TYPE_VOID:
3232     // no "void" in Delphi language
3233     return "";
3234   case t_base_type::TYPE_STRING:
3235     if (tbase->is_binary()) {
3236       if (ansistr_binary_) {
3237         return "System.AnsiString";
3238       } else {
3239         return "SysUtils.TBytes";
3240       }
3241     } else {
3242       return "System.string";
3243     }
3244   case t_base_type::TYPE_BOOL:
3245     return "System.Boolean";
3246   case t_base_type::TYPE_I8:
3247     return "System.ShortInt";
3248   case t_base_type::TYPE_I16:
3249     return "System.SmallInt";
3250   case t_base_type::TYPE_I32:
3251     return "System.Integer";
3252   case t_base_type::TYPE_I64:
3253     return "System.Int64";
3254   case t_base_type::TYPE_DOUBLE:
3255     return "System.Double";
3256   default:
3257     throw "compiler error: no Delphi name for base type "
3258         + t_base_type::t_base_name(tbase->get_base());
3259   }
3260 }
3261 
declare_field(t_field * tfield,bool init,std::string prefix,bool is_xception_class)3262 string t_delphi_generator::declare_field(t_field* tfield,
3263                                          bool init,
3264                                          std::string prefix,
3265                                          bool is_xception_class) {
3266   (void)init;
3267 
3268   t_type* ftype = tfield->get_type();
3269   bool is_xception = ftype->is_xception();
3270 
3271   string result = prefix + prop_name(tfield, is_xception_class) + ": "
3272                   + type_name(ftype, false, true, is_xception, true) + ";";
3273   return result;
3274 }
3275 
function_signature(t_function * tfunction,bool for_async,std::string full_cls,bool is_xception)3276 string t_delphi_generator::function_signature(t_function* tfunction,
3277                                               bool for_async,
3278                                               std::string full_cls,
3279                                               bool is_xception) {
3280   t_type* ttype = tfunction->get_returntype();
3281   string prefix;
3282   if (full_cls == "") {
3283     prefix = "";
3284   } else {
3285     prefix = full_cls + ".";
3286   }
3287 
3288   string signature = "";
3289 
3290   if( for_async) {
3291     if (is_void(ttype)) {
3292       signature = "function " + prefix + normalize_name(tfunction->get_name(), true, is_xception) + "Async("
3293                 + argument_list(tfunction->get_arglist()) + "): IFuture<Integer>;";  // no IFuture<void> in Delphi
3294     } else {
3295       signature = "function " + prefix + normalize_name(tfunction->get_name(), true, is_xception) + "Async("
3296                 + argument_list(tfunction->get_arglist()) + "): IFuture<"
3297                 + type_name(ttype, false, true, is_xception, true) + ">;";
3298     }
3299   } else {
3300     if (is_void(ttype)) {
3301       signature = "procedure " + prefix + normalize_name(tfunction->get_name(), true, is_xception) + "("
3302                 + argument_list(tfunction->get_arglist()) + ");";
3303     } else {
3304       signature = "function " + prefix + normalize_name(tfunction->get_name(), true, is_xception) + "("
3305                 + argument_list(tfunction->get_arglist()) + "): "
3306                 + type_name(ttype, false, true, is_xception, true) + ";";
3307     }
3308   }
3309 
3310   // deprecated method? only at intf decl!
3311   if( full_cls == "") {
3312     auto iter = tfunction->annotations_.find("deprecated");
3313     if( tfunction->annotations_.end() != iter) {
3314       signature += " deprecated";
3315       // empty annotation values end up with "1" somewhere, ignore these as well
3316       if ((iter->second.length() > 0) && (iter->second != "1")) {
3317         signature += " " + make_pascal_string_literal(iter->second);
3318       }
3319       signature += ";";
3320     }
3321   }
3322 
3323   return signature;
3324 }
3325 
argument_list(t_struct * tstruct)3326 string t_delphi_generator::argument_list(t_struct* tstruct) {
3327   string result = "";
3328   const vector<t_field*>& fields = tstruct->get_members();
3329   vector<t_field*>::const_iterator f_iter;
3330   bool first = true;
3331   t_type* tt;
3332 
3333   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
3334     if (first) {
3335       first = false;
3336     } else {
3337       result += "; ";
3338     }
3339 
3340     tt = (*f_iter)->get_type();
3341     result += input_arg_prefix(tt); // const?
3342     result += normalize_name((*f_iter)->get_name()) + ": "
3343               + type_name(tt, false, true, tt->is_xception(), true);
3344   }
3345   return result;
3346 }
3347 
constructor_argument_list(t_struct * tstruct,string current_indent)3348 string t_delphi_generator::constructor_argument_list(t_struct* tstruct, string current_indent) {
3349   ostringstream result;
3350   const vector<t_field*>& fields = tstruct->get_members();
3351   vector<t_field*>::const_iterator f_iter;
3352   bool first = true;
3353   t_type* tt;
3354   string line = "";
3355   string newline_indent = current_indent + "  ";
3356 
3357   bool firstline = true;
3358 
3359   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
3360     if (first) {
3361       first = false;
3362     } else {
3363       line += ";";
3364     }
3365 
3366     if (line.size() > 80) {
3367       if (firstline) {
3368         result << endl << newline_indent;
3369         firstline = false;
3370       }
3371       result << line << endl;
3372       line = newline_indent;
3373     } else if (line.size() > 0) {
3374       line += " ";
3375     }
3376 
3377     tt = (*f_iter)->get_type();
3378     line += input_arg_prefix(tt); // const?
3379     line += constructor_param_name((*f_iter)->get_name()) + ": "
3380             + type_name(tt, false, true, tt->is_xception(), true);
3381   }
3382 
3383   if (line.size() > 0) {
3384     result << line;
3385   }
3386 
3387   string result_str;
3388 
3389   if (firstline) {
3390     result_str = " " + result.str();
3391   } else {
3392     result_str = result.str();
3393   }
3394 
3395   return result_str;
3396 }
3397 
type_to_enum(t_type * type)3398 string t_delphi_generator::type_to_enum(t_type* type) {
3399   while (type->is_typedef()) {
3400     type = ((t_typedef*)type)->get_type();
3401   }
3402 
3403   if (type->is_base_type()) {
3404     t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
3405     switch (tbase) {
3406     case t_base_type::TYPE_VOID:
3407       throw "NO T_VOID CONSTRUCT";
3408     case t_base_type::TYPE_STRING:
3409       return "TType.String_";
3410     case t_base_type::TYPE_BOOL:
3411       return "TType.Bool_";
3412     case t_base_type::TYPE_I8:
3413       return "TType.Byte_";
3414     case t_base_type::TYPE_I16:
3415       return "TType.I16";
3416     case t_base_type::TYPE_I32:
3417       return "TType.I32";
3418     case t_base_type::TYPE_I64:
3419       return "TType.I64";
3420     case t_base_type::TYPE_DOUBLE:
3421       return "TType.Double_";
3422     }
3423   } else if (type->is_enum()) {
3424     return "TType.I32";
3425   } else if (type->is_struct() || type->is_xception()) {
3426     return "TType.Struct";
3427   } else if (type->is_map()) {
3428     return "TType.Map";
3429   } else if (type->is_set()) {
3430     return "TType.Set_";
3431   } else if (type->is_list()) {
3432     return "TType.List";
3433   }
3434 
3435   throw "INVALID TYPE IN type_to_enum: " + type->get_name();
3436 }
3437 
empty_value(t_type * type)3438 string t_delphi_generator::empty_value(t_type* type) {
3439   while (type->is_typedef()) {
3440     type = ((t_typedef*)type)->get_type();
3441   }
3442 
3443   if (type->is_base_type()) {
3444     t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
3445     switch (tbase) {
3446     case t_base_type::TYPE_VOID:
3447       return "0";
3448     case t_base_type::TYPE_STRING:
3449       if (type->is_binary()) {
3450         if (ansistr_binary_) {
3451           return "''";
3452         } else {
3453           return "nil";
3454         }
3455       } else {
3456         return "''";
3457       }
3458     case t_base_type::TYPE_BOOL:
3459       return "False";
3460     case t_base_type::TYPE_I8:
3461     case t_base_type::TYPE_I16:
3462     case t_base_type::TYPE_I32:
3463     case t_base_type::TYPE_I64:
3464       return "0";
3465     case t_base_type::TYPE_DOUBLE:
3466       return "0.0";
3467     }
3468   } else if (type->is_enum()) {
3469     return "T" + type->get_name() + "(0)";
3470   } else if (type->is_struct() || type->is_xception()) {
3471     return "nil";
3472   } else if (type->is_map()) {
3473     return "nil";
3474   } else if (type->is_set()) {
3475     return "nil";
3476   } else if (type->is_list()) {
3477     return "nil";
3478   }
3479 
3480   throw "INVALID TYPE IN type_to_enum: " + type->get_name();
3481 }
3482 
generate_delphi_property_writer_definition(ostream & out,t_field * tfield,bool is_xception_class)3483 void t_delphi_generator::generate_delphi_property_writer_definition(ostream& out,
3484                                                                     t_field* tfield,
3485                                                                     bool is_xception_class) {
3486   t_type* ftype = tfield->get_type();
3487   bool is_xception = ftype->is_xception();
3488 
3489   indent(out) << "procedure Set" << prop_name(tfield, is_xception_class)
3490               << "( const Value: " << type_name(ftype, false, true, is_xception, true) << ");"
3491               << endl;
3492 }
3493 
generate_delphi_property_reader_definition(ostream & out,t_field * tfield,bool is_xception_class)3494 void t_delphi_generator::generate_delphi_property_reader_definition(ostream& out,
3495                                                                     t_field* tfield,
3496                                                                     bool is_xception_class) {
3497   t_type* ftype = tfield->get_type();
3498   bool is_xception = ftype->is_xception();
3499 
3500   indent(out) << "function Get" << prop_name(tfield, is_xception_class) << ": "
3501               << type_name(ftype, false, true, is_xception, true) << ";" << endl;
3502 }
3503 
generate_delphi_isset_reader_writer_definition(ostream & out,t_field * tfield,bool is_xception)3504 void t_delphi_generator::generate_delphi_isset_reader_writer_definition(ostream& out,
3505                                                                  t_field* tfield,
3506                                                                  bool is_xception) {
3507   indent(out) << "function Get__isset_" << prop_name(tfield, is_xception) << ": System.Boolean;" << endl;
3508   indent(out) << "procedure Set__isset_" << prop_name(tfield, is_xception) << "( const value : System.Boolean);" << endl;
3509 }
3510 
generate_delphi_clear_union_value(ostream & out,std::string cls_prefix,std::string name,t_type * type,t_field * tfield,std::string fieldPrefix,bool is_xception_class,bool is_union,bool is_xception_factory,std::string xception_factory_name)3511 void t_delphi_generator::generate_delphi_clear_union_value(ostream& out,
3512                                                            std::string cls_prefix,
3513                                                            std::string name,
3514                                                            t_type* type,
3515                                                            t_field* tfield,
3516                                                            std::string fieldPrefix,
3517                                                            bool is_xception_class,
3518                                                            bool is_union,
3519                                                            bool is_xception_factory,
3520                                                            std::string xception_factory_name) {
3521   (void)cls_prefix;
3522   (void)name;
3523   (void)type;
3524   (void)is_union;
3525   (void)is_xception_factory;
3526   (void)xception_factory_name;
3527 
3528   t_type* ftype = tfield->get_type();
3529   bool is_xception = ftype->is_xception();
3530 
3531   indent_impl(out) << "if F__isset_" << prop_name(tfield, is_xception_class) << " then begin"
3532                    << endl;
3533   indent_up_impl();
3534   indent_impl(out) << "F__isset_" << prop_name(tfield, is_xception_class) << " := False;" << endl;
3535   indent_impl(out) << fieldPrefix << prop_name(tfield, is_xception_class) << " := "
3536                    << "Default( " << type_name(ftype, false, true, is_xception, true) << ");"
3537                    << endl;
3538   indent_down_impl();
3539   indent_impl(out) << "end;" << endl;
3540 }
3541 
generate_delphi_property_writer_impl(ostream & out,std::string cls_prefix,std::string name,t_type * type,t_field * tfield,std::string fieldPrefix,bool is_xception_class,bool is_union,bool is_xception_factory,std::string xception_factory_name)3542 void t_delphi_generator::generate_delphi_property_writer_impl(ostream& out,
3543                                                               std::string cls_prefix,
3544                                                               std::string name,
3545                                                               t_type* type,
3546                                                               t_field* tfield,
3547                                                               std::string fieldPrefix,
3548                                                               bool is_xception_class,
3549                                                               bool is_union,
3550                                                               bool is_xception_factory,
3551                                                               std::string xception_factory_name) {
3552   (void)type;
3553 
3554   t_type* ftype = tfield->get_type();
3555   bool is_xception = ftype->is_xception();
3556 
3557   indent_impl(out) << "procedure " << cls_prefix << name << "."
3558                    << "Set" << prop_name(tfield, is_xception_class)
3559                    << "( const Value: " << type_name(ftype, false, true, is_xception, true) << ");"
3560                    << endl;
3561   indent_impl(out) << "begin" << endl;
3562   indent_up_impl();
3563   if (is_union) {
3564     indent_impl(out) << "ClearUnionValues;" << endl;
3565   }
3566   if (tfield->get_req() != t_field::T_REQUIRED) {
3567     indent_impl(out) << "F__isset_" << prop_name(tfield, is_xception_class) << " := True;" << endl;
3568   }
3569   indent_impl(out) << fieldPrefix << prop_name(tfield, is_xception_class) << " := Value;" << endl;
3570 
3571   if (is_xception_class && (!is_xception_factory)) {
3572     indent_impl(out) << xception_factory_name << "." << prop_name(tfield, is_xception_class)
3573                      << " := Value;" << endl;
3574   }
3575 
3576   indent_down_impl();
3577   indent_impl(out) << "end;" << endl << endl;
3578 }
3579 
generate_delphi_property_reader_impl(ostream & out,std::string cls_prefix,std::string name,t_type * type,t_field * tfield,std::string fieldPrefix,bool is_xception_class)3580 void t_delphi_generator::generate_delphi_property_reader_impl(ostream& out,
3581                                                               std::string cls_prefix,
3582                                                               std::string name,
3583                                                               t_type* type,
3584                                                               t_field* tfield,
3585                                                               std::string fieldPrefix,
3586                                                               bool is_xception_class) {
3587   (void)type;
3588 
3589   t_type* ftype = tfield->get_type();
3590   bool is_xception = ftype->is_xception();
3591 
3592   indent_impl(out) << "function " << cls_prefix << name << "."
3593                    << "Get" << prop_name(tfield, is_xception_class) << ": "
3594                    << type_name(ftype, false, true, is_xception, true) << ";" << endl;
3595   indent_impl(out) << "begin" << endl;
3596   indent_up_impl();
3597   indent_impl(out) << "Result := " << fieldPrefix << prop_name(tfield, is_xception_class) << ";"
3598                    << endl;
3599   indent_down_impl();
3600   indent_impl(out) << "end;" << endl << endl;
3601 }
3602 
generate_delphi_isset_reader_writer_impl(ostream & out,std::string cls_prefix,std::string name,t_type * type,t_field * tfield,std::string fieldPrefix,bool is_xception)3603 void t_delphi_generator::generate_delphi_isset_reader_writer_impl(ostream& out,
3604                                                            std::string cls_prefix,
3605                                                            std::string name,
3606                                                            t_type* type,
3607                                                            t_field* tfield,
3608                                                            std::string fieldPrefix,
3609                                                            bool is_xception) {
3610   (void)type;
3611 
3612   string isset_name = "__isset_" + prop_name(tfield, is_xception);
3613 
3614   indent_impl(out) << "function " << cls_prefix << name << "."
3615                    << "Get" << isset_name << ": System.Boolean;" << endl;
3616   indent_impl(out) << "begin" << endl;
3617   indent_up_impl();
3618   indent_impl(out) << "Result := " << fieldPrefix << isset_name << ";" << endl;
3619   indent_down_impl();
3620   indent_impl(out) << "end;" << endl << endl;
3621 
3622   indent_impl(out) << "procedure " << cls_prefix << name << "."
3623                    << "Set" << isset_name << "( const value: System.Boolean);" << endl;
3624   indent_impl(out) << "begin" << endl;
3625   indent_up_impl();
3626   indent_impl(out) << fieldPrefix << isset_name << " := value;" << endl;
3627   indent_down_impl();
3628   indent_impl(out) << "end;" << endl << endl;
3629 }
3630 
generate_delphi_create_exception_impl(ostream & out,string cls_prefix,t_struct * tstruct,bool is_exception)3631 void t_delphi_generator::generate_delphi_create_exception_impl(ostream& out,
3632                                                                string cls_prefix,
3633                                                                t_struct* tstruct,
3634                                                                bool is_exception) {
3635   (void)cls_prefix;
3636 
3637   string exception_cls_nm = type_name(tstruct, true, true);
3638   string cls_nm = type_name(tstruct, true, false, is_exception, is_exception);
3639 
3640   indent_impl(out) << "function " << cls_nm << ".CreateException: " << exception_cls_nm << ";"
3641                    << endl;
3642 
3643   indent_impl(out) << "begin" << endl;
3644   indent_up_impl();
3645 
3646   indent_impl(out) << "Result := " << exception_cls_nm << ".Create;" << endl;
3647   string factory_name = normalize_clsnm(tstruct->get_name(), "", true) + "Factory";
3648   indent_impl(out) << "Result.F" << factory_name << " := Self;" << endl;
3649 
3650   const vector<t_field*>& fields = tstruct->get_members();
3651   vector<t_field*>::const_iterator f_iter;
3652 
3653   string propname;
3654 
3655   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
3656     propname = prop_name(*f_iter, is_exception);
3657     if ((*f_iter)->get_req() != t_field::T_REQUIRED) {
3658       indent_impl(out) << "if __isset_" << propname << " then begin" << endl;
3659       indent_up_impl();
3660     }
3661     indent_impl(out) << "Result." << propname << " := " << propname << ";" << endl;
3662     if ((*f_iter)->get_req() != t_field::T_REQUIRED) {
3663       indent_down_impl();
3664       indent_impl(out) << "end;" << endl;
3665     }
3666   }
3667 
3668   indent_impl(out) << "Result.UpdateMessageProperty;" << endl;
3669 
3670   indent_down_impl();
3671   indent_impl(out) << "end;" << endl << endl;
3672 }
3673 
generate_delphi_struct_reader_impl(ostream & out,string cls_prefix,t_struct * tstruct,bool is_exception,bool is_x_factory)3674 void t_delphi_generator::generate_delphi_struct_reader_impl(ostream& out,
3675                                                             string cls_prefix,
3676                                                             t_struct* tstruct,
3677                                                             bool is_exception,
3678                                                             bool is_x_factory) {
3679 
3680   ostringstream local_vars;
3681   ostringstream code_block;
3682 
3683   const vector<t_field*>& fields = tstruct->get_members();
3684   vector<t_field*>::const_iterator f_iter;
3685 
3686   indent_impl(code_block) << "begin" << endl;
3687   indent_up_impl();
3688 
3689   indent_impl(local_vars) << "tracker : IProtocolRecursionTracker;" << endl;
3690   indent_impl(code_block) << "tracker := iprot.NextRecursionLevel;" << endl;
3691 
3692   // local bools for required fields
3693   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
3694     if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
3695       indent_impl(local_vars) << "_req_isset_" << prop_name(*f_iter, is_exception) << " : System.Boolean;"
3696                               << endl;
3697       indent_impl(code_block) << "_req_isset_" << prop_name(*f_iter, is_exception) << " := FALSE;"
3698                               << endl;
3699     }
3700   }
3701 
3702   indent_impl(code_block) << "struc := iprot.ReadStructBegin;" << endl;
3703 
3704   indent_impl(code_block) << "try" << endl;
3705   indent_up_impl();
3706 
3707   indent_impl(code_block) << "while (true) do begin" << endl;
3708   indent_up_impl();
3709 
3710   indent_impl(code_block) << "field_ := iprot.ReadFieldBegin();" << endl;
3711 
3712   indent_impl(code_block) << "if (field_.Type_ = TType.Stop) then Break;" << endl;
3713 
3714   bool first = true;
3715 
3716   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
3717 
3718     if (first) {
3719       code_block << endl;
3720       indent_impl(code_block) << "case field_.ID of" << endl;
3721       indent_up_impl();
3722     }
3723 
3724     first = false;
3725     if (f_iter != fields.begin()) {
3726       code_block << endl;
3727     }
3728 
3729     indent_impl(code_block) << (*f_iter)->get_key() << ": begin" << endl;
3730     indent_up_impl();
3731     indent_impl(code_block) << "if (field_.Type_ = " << type_to_enum((*f_iter)->get_type())
3732                             << ") then begin" << endl;
3733     indent_up_impl();
3734 
3735     generate_deserialize_field(code_block, is_exception, *f_iter, "Self.", local_vars);
3736 
3737     // required field?
3738     if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
3739       indent_impl(code_block) << "_req_isset_" << prop_name(*f_iter, is_exception) << " := TRUE;"
3740                               << endl;
3741     }
3742 
3743     indent_down_impl();
3744 
3745     indent_impl(code_block) << "end else begin" << endl;
3746     indent_up_impl();
3747     indent_impl(code_block) << "TProtocolUtil.Skip(iprot, field_.Type_);" << endl;
3748     indent_down_impl();
3749     indent_impl(code_block) << "end;" << endl;
3750     indent_down_impl();
3751     indent_impl(code_block) << "end;";
3752   }
3753 
3754   if (!first) {
3755     code_block << endl;
3756     indent_down_impl();
3757     indent_impl(code_block) << "else" << endl;
3758     indent_up_impl();
3759   }
3760 
3761   indent_impl(code_block) << "TProtocolUtil.Skip(iprot, field_.Type_);" << endl;
3762 
3763   if (!first) {
3764     indent_down_impl();
3765     indent_impl(code_block) << "end;" << endl;
3766   }
3767 
3768   indent_impl(code_block) << "iprot.ReadFieldEnd;" << endl;
3769 
3770   indent_down_impl();
3771 
3772   indent_impl(code_block) << "end;" << endl;
3773   indent_down_impl();
3774 
3775   indent_impl(code_block) << "finally" << endl;
3776   indent_up_impl();
3777   indent_impl(code_block) << "iprot.ReadStructEnd;" << endl;
3778   indent_down_impl();
3779   indent_impl(code_block) << "end;" << endl;
3780 
3781   // all required fields have been read?
3782   first = true;
3783   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
3784     if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
3785       if(first) {
3786         code_block << endl;
3787         first = false;
3788       }
3789       indent_impl(code_block) << "if not _req_isset_" << prop_name(*f_iter, is_exception) << endl;
3790       indent_impl(code_block)
3791           << "then raise TProtocolExceptionInvalidData.Create("
3792           << "'required field " << prop_name(*f_iter, is_exception) << " not set');"
3793           << endl;
3794     }
3795   }
3796 
3797   if( is_exception && (!is_x_factory)) {
3798     code_block << endl;
3799     indent_impl(code_block) << "UpdateMessageProperty;" << endl;
3800   }
3801   indent_down_impl();
3802   indent_impl(code_block) << "end;" << endl << endl;
3803 
3804   string cls_nm;
3805 
3806   cls_nm = type_name(tstruct, true, is_exception && (!is_x_factory), is_x_factory, is_x_factory);
3807 
3808   indent_impl(out) << "procedure " << cls_prefix << cls_nm << ".Read( const iprot: IProtocol);"
3809                    << endl;
3810   indent_impl(out) << "var" << endl;
3811   indent_up_impl();
3812   indent_impl(out) << "field_ : TThriftField;" << endl;
3813   indent_impl(out) << "struc : TThriftStruct;" << endl;
3814   indent_down_impl();
3815   out << local_vars.str() << endl;
3816   out << code_block.str();
3817 }
3818 
generate_delphi_struct_result_writer_impl(ostream & out,string cls_prefix,t_struct * tstruct,bool is_exception,bool is_x_factory)3819 void t_delphi_generator::generate_delphi_struct_result_writer_impl(ostream& out,
3820                                                                    string cls_prefix,
3821                                                                    t_struct* tstruct,
3822                                                                    bool is_exception,
3823                                                                    bool is_x_factory) {
3824 
3825   ostringstream local_vars;
3826   ostringstream code_block;
3827 
3828   string name = tstruct->get_name();
3829   const vector<t_field*>& fields = tstruct->get_sorted_members();
3830   vector<t_field*>::const_iterator f_iter;
3831 
3832   indent_impl(code_block) << "begin" << endl;
3833   indent_up_impl();
3834 
3835   indent_impl(local_vars) << "tracker : IProtocolRecursionTracker;" << endl;
3836   indent_impl(code_block) << "tracker := oprot.NextRecursionLevel;" << endl;
3837 
3838   indent_impl(code_block) << "Thrift.Protocol.Init( struc, '" << name << "');" << endl;
3839   indent_impl(code_block) << "oprot.WriteStructBegin(struc);" << endl;
3840 
3841   if (fields.size() > 0) {
3842     indent_impl(code_block) << "Thrift.Protocol.Init( field_);" << endl;
3843     for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
3844       indent_impl(code_block) << "if (__isset_" << prop_name(*f_iter, is_exception) << ") then"
3845                               << endl;
3846       indent_impl(code_block) << "begin" << endl;
3847       indent_up_impl();
3848       indent_impl(code_block) << "field_.Name := '" << (*f_iter)->get_name() << "';" << endl;
3849       indent_impl(code_block) << "field_.Type_  := " << type_to_enum((*f_iter)->get_type()) << ";"
3850                               << endl;
3851       indent_impl(code_block) << "field_.ID := " << (*f_iter)->get_key() << ";" << endl;
3852       indent_impl(code_block) << "oprot.WriteFieldBegin(field_);" << endl;
3853       generate_serialize_field(code_block, is_exception, *f_iter, "Self.", local_vars);
3854       indent_impl(code_block) << "oprot.WriteFieldEnd();" << endl;
3855       indent_down_impl();
3856     }
3857   }
3858 
3859   indent_impl(code_block) << "oprot.WriteFieldStop();" << endl;
3860   indent_impl(code_block) << "oprot.WriteStructEnd();" << endl;
3861 
3862   indent_down_impl();
3863   indent_impl(code_block) << "end;" << endl << endl;
3864 
3865   string cls_nm;
3866 
3867   cls_nm = type_name(tstruct, true, is_exception && (!is_x_factory), is_x_factory, is_x_factory);
3868 
3869   indent_impl(out) << "procedure " << cls_prefix << cls_nm << ".Write( const oprot: IProtocol);"
3870                    << endl;
3871   indent_impl(out) << "var" << endl;
3872   indent_up_impl();
3873   indent_impl(out) << "struc : TThriftStruct;" << endl;
3874 
3875   if (fields.size() > 0) {
3876     indent_impl(out) << "field_ : TThriftField;" << endl;
3877   }
3878 
3879   out << local_vars.str();
3880   indent_down_impl();
3881   out << code_block.str();
3882 }
3883 
generate_delphi_struct_writer_impl(ostream & out,string cls_prefix,t_struct * tstruct,bool is_exception,bool is_x_factory)3884 void t_delphi_generator::generate_delphi_struct_writer_impl(ostream& out,
3885                                                             string cls_prefix,
3886                                                             t_struct* tstruct,
3887                                                             bool is_exception,
3888                                                             bool is_x_factory) {
3889 
3890   ostringstream local_vars;
3891   ostringstream code_block;
3892 
3893   string name = tstruct->get_name();
3894   const vector<t_field*>& fields = tstruct->get_sorted_members();
3895   vector<t_field*>::const_iterator f_iter;
3896 
3897   indent_impl(code_block) << "begin" << endl;
3898   indent_up_impl();
3899 
3900   indent_impl(local_vars) << "tracker : IProtocolRecursionTracker;" << endl;
3901   indent_impl(code_block) << "tracker := oprot.NextRecursionLevel;" << endl;
3902 
3903   indent_impl(code_block) << "Thrift.Protocol.Init( struc, '" << name << "');" << endl;
3904   indent_impl(code_block) << "oprot.WriteStructBegin(struc);" << endl;
3905 
3906   if (fields.size() > 0) {
3907     indent_impl(code_block) << "Thrift.Protocol.Init( field_);" << endl;
3908   }
3909 
3910   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
3911     string fieldname = prop_name((*f_iter), is_exception);
3912     bool null_allowed = type_can_be_null((*f_iter)->get_type());
3913     bool is_required = ((*f_iter)->get_req() == t_field::T_REQUIRED);
3914     bool has_isset = (!is_required);
3915     if (is_required && null_allowed) {
3916       null_allowed = false;
3917       indent_impl(code_block) << "if (Self." << fieldname << " = nil)" << endl;
3918       indent_impl(code_block) << "then raise TProtocolExceptionInvalidData.Create("
3919                               << "'required field " << fieldname << " not set');"
3920                               << endl;
3921     }
3922     if (null_allowed) {
3923       indent_impl(code_block) << "if (Self." << fieldname << " <> nil)";
3924       if (has_isset) {
3925         code_block << " and __isset_" << fieldname;
3926       }
3927       code_block << " then begin" << endl;
3928       indent_up_impl();
3929     } else {
3930       if (has_isset) {
3931         indent_impl(code_block) << "if (__isset_" << fieldname << ") then begin" << endl;
3932         indent_up_impl();
3933       }
3934     }
3935     indent_impl(code_block) << "field_.Name := '" << (*f_iter)->get_name() << "';" << endl;
3936     indent_impl(code_block) << "field_.Type_  := " << type_to_enum((*f_iter)->get_type()) << ";"
3937                             << endl;
3938     indent_impl(code_block) << "field_.ID := " << (*f_iter)->get_key() << ";" << endl;
3939     indent_impl(code_block) << "oprot.WriteFieldBegin(field_);" << endl;
3940     generate_serialize_field(code_block, is_exception, *f_iter, "Self.", local_vars);
3941     indent_impl(code_block) << "oprot.WriteFieldEnd();" << endl;
3942     if (null_allowed || has_isset) {
3943       indent_down_impl();
3944       indent_impl(code_block) << "end;" << endl;
3945     }
3946   }
3947 
3948   indent_impl(code_block) << "oprot.WriteFieldStop();" << endl;
3949   indent_impl(code_block) << "oprot.WriteStructEnd();" << endl;
3950 
3951   indent_down_impl();
3952   indent_impl(code_block) << "end;" << endl << endl;
3953 
3954   string cls_nm;
3955 
3956   cls_nm = type_name(tstruct, true, is_exception && (!is_x_factory), is_x_factory, is_x_factory);
3957 
3958   indent_impl(out) << "procedure " << cls_prefix << cls_nm << ".Write( const oprot: IProtocol);"
3959                    << endl;
3960   indent_impl(out) << "var" << endl;
3961   indent_up_impl();
3962   indent_impl(out) << "struc : TThriftStruct;" << endl;
3963   if (fields.size() > 0) {
3964     indent_impl(out) << "field_ : TThriftField;" << endl;
3965   }
3966   out << local_vars.str();
3967   indent_down_impl();
3968   out << code_block.str();
3969 }
3970 
generate_delphi_struct_tostring_impl(ostream & out,string cls_prefix,t_struct * tstruct,bool is_exception,bool is_x_factory)3971 void t_delphi_generator::generate_delphi_struct_tostring_impl(ostream& out,
3972                                                               string cls_prefix,
3973                                                               t_struct* tstruct,
3974                                                               bool is_exception,
3975                                                               bool is_x_factory) {
3976 
3977   const vector<t_field*>& fields = tstruct->get_members();
3978   vector<t_field*>::const_iterator f_iter;
3979 
3980   string cls_nm;
3981 
3982   if (is_exception) {
3983     cls_nm = type_name(tstruct, true, (!is_x_factory), is_x_factory, true);
3984   } else {
3985     cls_nm = type_name(tstruct, true, false);
3986   }
3987 
3988   string tmp_sb = tmp("_sb");
3989   string tmp_first = tmp("_first");
3990   bool useFirstFlag = false;
3991 
3992   indent_impl(out) << "function " << cls_prefix << cls_nm << ".ToString: string;" << endl;
3993   indent_impl(out) << "var" << endl;
3994   indent_up_impl();
3995   indent_impl(out) << tmp_sb << " : TThriftStringBuilder;" << endl;
3996   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
3997     bool is_optional = ((*f_iter)->get_req() != t_field::T_REQUIRED);
3998     if (is_optional) {
3999       indent_impl(out) << tmp_first << " : System.Boolean;" << endl;
4000       useFirstFlag = true;
4001     }
4002     break;
4003   }
4004   indent_down_impl();
4005   indent_impl(out) << "begin" << endl;
4006   indent_up_impl();
4007 
4008   indent_impl(out) << tmp_sb << " := TThriftStringBuilder.Create('(');" << endl;
4009   indent_impl(out) << "try" << endl;
4010   indent_up_impl();
4011 
4012   if (useFirstFlag) {
4013     indent_impl(out) << tmp_first << " := TRUE;" << endl;
4014   }
4015 
4016   bool had_required = false; // set to true after first required field has been processed
4017 
4018   for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
4019     bool null_allowed = type_can_be_null((*f_iter)->get_type());
4020     bool is_optional = ((*f_iter)->get_req() != t_field::T_REQUIRED);
4021     if (null_allowed) {
4022       indent_impl(out) << "if (Self." << prop_name((*f_iter), is_exception) << " <> nil)";
4023       if (is_optional) {
4024         out << " and __isset_" << prop_name(*f_iter, is_exception);
4025       }
4026       out << " then begin" << endl;
4027       indent_up_impl();
4028     } else {
4029       if (is_optional) {
4030         indent_impl(out) << "if (__isset_" << prop_name(*f_iter, is_exception) << ") then begin"
4031                          << endl;
4032         indent_up_impl();
4033       }
4034     }
4035 
4036     if (useFirstFlag && (!had_required)) {
4037       indent_impl(out) << "if not " << tmp_first << " then " << tmp_sb << ".Append(',');" << endl;
4038       if (is_optional) {
4039         indent_impl(out) << tmp_first << " := FALSE;" << endl;
4040       }
4041       indent_impl(out) << tmp_sb << ".Append('" << prop_name((*f_iter), is_exception) << ": ');"
4042                        << endl;
4043     } else {
4044       indent_impl(out) << tmp_sb << ".Append(', " << prop_name((*f_iter), is_exception) << ": ');"
4045                        << endl;
4046     }
4047 
4048     t_type* ttype = (*f_iter)->get_type();
4049     while (ttype->is_typedef()) {
4050       ttype = ((t_typedef*)ttype)->get_type();
4051     }
4052 
4053     if (ttype->is_xception() || ttype->is_struct()) {
4054       indent_impl(out) << "if (Self." << prop_name((*f_iter), is_exception) << " = nil) then " << tmp_sb
4055                        << ".Append('<null>') else " << tmp_sb << ".Append( Self."
4056                        << prop_name((*f_iter), is_exception) << ".ToString());" << endl;
4057     } else if (ttype->is_enum()) {
4058       indent_impl(out) << tmp_sb << ".Append(EnumUtils<"
4059                        << type_name(ttype, false, true, false, false)
4060                        << ">.ToString( System.Ord( Self."
4061                        << prop_name((*f_iter), is_exception) << ")));" << endl;
4062     } else {
4063       indent_impl(out) << tmp_sb << ".Append( Self." << prop_name((*f_iter), is_exception) << ");"
4064                        << endl;
4065     }
4066 
4067     if (null_allowed || is_optional) {
4068       indent_down_impl();
4069       indent_impl(out) << "end;" << endl;
4070     }
4071 
4072     if (!is_optional) {
4073       had_required = true; // now __first must be false, so we don't need to check it anymore
4074     }
4075   }
4076 
4077   indent_impl(out) << tmp_sb << ".Append(')');" << endl;
4078   indent_impl(out) << "Result := " << tmp_sb << ".ToString;" << endl;
4079   if (useFirstFlag) {
4080     indent_impl(out) << "if " << tmp_first << " then {prevent warning};" << endl;
4081   }
4082 
4083   indent_down_impl();
4084   indent_impl(out) << "finally" << endl;
4085   indent_up_impl();
4086   indent_impl(out) << tmp_sb << ".Free;" << endl;
4087   indent_down_impl();
4088   indent_impl(out) << "end;" << endl;
4089 
4090   indent_down_impl();
4091   indent_impl(out) << "end;" << endl << endl;
4092 }
4093 
is_void(t_type * type)4094 bool t_delphi_generator::is_void(t_type* type) {
4095   while (type->is_typedef()) {
4096     type = ((t_typedef*)type)->get_type();
4097   }
4098 
4099   if (type->is_base_type()) {
4100     t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
4101     if (tbase == t_base_type::TYPE_VOID) {
4102       return true;
4103     }
4104   }
4105   return false;
4106 }
4107 
4108 THRIFT_REGISTER_GENERATOR(
4109     delphi,
4110     "delphi",
4111     "    ansistr_binary:  Use AnsiString for binary datatype (default is TBytes).\n"
4112     "    register_types:  Enable TypeRegistry, allows for creation of struct, union\n"
4113     "                     and container instances by interface or TypeInfo()\n"
4114     "    constprefix:     Name TConstants classes after IDL to reduce ambiguities\n"
4115     "    events:          Enable and use processing events in the generated code.\n"
4116     "    xmldoc:          Enable XMLDoc comments for Help Insight etc.\n"
4117     "    async:           Generate IAsync interface to use Parallel Programming Library (XE7+ only).\n")
4118