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, "&", "&");
457
458 // other standard XML entities
459 str = replace_all(str, "<", "<");
460 str = replace_all(str, ">", ">");
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