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