]>
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 | ||
20 | #include <sstream> | |
21 | #include <string> | |
22 | #include <fstream> | |
23 | #include <iostream> | |
24 | #include <vector> | |
25 | #include <cctype> | |
26 | ||
27 | #include <sys/stat.h> | |
28 | #include <stdexcept> | |
29 | ||
30 | #include "thrift/platform.h" | |
31 | #include "thrift/generate/t_oop_generator.h" | |
32 | ||
33 | using std::map; | |
34 | using std::ostream; | |
35 | using std::ostringstream; | |
36 | using std::string; | |
37 | using std::stringstream; | |
38 | using std::vector; | |
39 | ||
40 | static const string endl = "\n"; // avoid ostream << std::endl flushes | |
41 | ||
42 | /** | |
43 | * Haxe code generator. | |
44 | * | |
45 | */ | |
46 | class t_haxe_generator : public t_oop_generator { | |
47 | public: | |
48 | t_haxe_generator(t_program* program, | |
49 | const std::map<std::string, std::string>& parsed_options, | |
50 | const std::string& option_string) | |
51 | : t_oop_generator(program) { | |
52 | (void)option_string; | |
53 | std::map<std::string, std::string>::const_iterator iter; | |
54 | ||
55 | callbacks_ = false; | |
56 | rtti_ = false; | |
57 | buildmacro_ = ""; | |
58 | for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { | |
59 | if( iter->first.compare("callbacks") == 0) { | |
60 | callbacks_ = true; | |
61 | } else if( iter->first.compare("rtti") == 0) { | |
62 | rtti_ = true; | |
63 | } else if( iter->first.compare("buildmacro") == 0) { | |
64 | buildmacro_ = (iter->second); | |
65 | } else { | |
66 | throw "unknown option haxe:" + iter->first; | |
67 | } | |
68 | } | |
69 | ||
70 | out_dir_base_ = "gen-haxe"; | |
71 | } | |
72 | ||
73 | /** | |
74 | * Init and close methods | |
75 | */ | |
76 | ||
77 | void init_generator() override; | |
78 | void close_generator() override; | |
79 | ||
80 | void generate_consts(std::vector<t_const*> consts) override; | |
81 | ||
82 | /** | |
83 | * Program-level generation functions | |
84 | */ | |
85 | ||
86 | void generate_typedef(t_typedef* ttypedef) override; | |
87 | void generate_enum(t_enum* tenum) override; | |
88 | void generate_struct(t_struct* tstruct) override; | |
89 | void generate_xception(t_struct* txception) override; | |
90 | void generate_service(t_service* tservice) override; | |
91 | ||
92 | void print_const_value(std::ostream& out, | |
93 | std::string name, | |
94 | t_type* type, | |
95 | t_const_value* value, | |
96 | bool in_static, | |
97 | bool defval = false); | |
98 | std::string render_const_value(ostream& out, | |
99 | std::string name, | |
100 | t_type* type, | |
101 | t_const_value* value); | |
102 | ||
103 | /** | |
104 | * Service-level generation functions | |
105 | */ | |
106 | ||
107 | void generate_haxe_struct(t_struct* tstruct, bool is_exception, bool is_result = false); | |
108 | ||
109 | void generate_haxe_struct_definition(std::ostream& out, | |
110 | t_struct* tstruct, | |
111 | bool is_xception = false, | |
112 | bool is_result = false); | |
113 | // removed -- equality,compare_to | |
114 | void generate_haxe_struct_reader(std::ostream& out, t_struct* tstruct); | |
115 | void generate_haxe_validator(std::ostream& out, t_struct* tstruct); | |
116 | void generate_haxe_struct_result_writer(std::ostream& out, t_struct* tstruct); | |
117 | void generate_haxe_struct_writer(std::ostream& out, t_struct* tstruct); | |
118 | void generate_haxe_struct_tostring(std::ostream& out, t_struct* tstruct); | |
119 | void generate_haxe_meta_data_map(std::ostream& out, t_struct* tstruct); | |
120 | void generate_field_value_meta_data(std::ostream& out, t_type* type); | |
121 | std::string get_haxe_type_string(t_type* type); | |
122 | void generate_reflection_setters(std::ostringstream& out, | |
123 | t_type* type, | |
124 | std::string field_name, | |
125 | std::string cap_name); | |
126 | void generate_reflection_getters(std::ostringstream& out, | |
127 | t_type* type, | |
128 | std::string field_name, | |
129 | std::string cap_name); | |
130 | void generate_generic_field_getters_setters(std::ostream& out, t_struct* tstruct); | |
131 | void generate_generic_isset_method(std::ostream& out, t_struct* tstruct); | |
132 | void generate_property_getters_setters(std::ostream& out, t_struct* tstruct); | |
133 | ||
134 | void generate_function_helpers(t_function* tfunction); | |
135 | std::string get_cap_name(std::string name); | |
136 | std::string generate_isset_check(t_field* field); | |
137 | std::string generate_isset_check(std::string field); | |
138 | void generate_isset_set(ostream& out, t_field* field); | |
139 | // removed std::string isset_field_id(t_field* field); | |
140 | ||
141 | void generate_service_interface(t_service* tservice); | |
142 | void generate_service_helpers(t_service* tservice); | |
143 | void generate_service_client(t_service* tservice); | |
144 | void generate_service_server(t_service* tservice); | |
145 | void generate_process_function(t_service* tservice, t_function* tfunction); | |
146 | void generate_service_method_signature(t_function* tfunction, bool is_interface); | |
147 | ||
148 | /** | |
149 | * Serialization constructs | |
150 | */ | |
151 | ||
152 | void generate_deserialize_field(std::ostream& out, t_field* tfield, std::string prefix = ""); | |
153 | void generate_deserialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = ""); | |
154 | void generate_deserialize_container(std::ostream& out, t_type* ttype, std::string prefix = ""); | |
155 | void generate_deserialize_set_element(std::ostream& out, t_set* tset, std::string prefix = ""); | |
156 | void generate_deserialize_map_element(std::ostream& out, t_map* tmap, std::string prefix = ""); | |
157 | void generate_deserialize_list_element(std::ostream& out, | |
158 | t_list* tlist, | |
159 | std::string prefix = ""); | |
160 | ||
161 | void generate_serialize_field(std::ostream& out, t_field* tfield, std::string prefix = ""); | |
162 | void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = ""); | |
163 | void generate_serialize_container(std::ostream& out, t_type* ttype, std::string prefix = ""); | |
164 | void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter); | |
165 | void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter); | |
166 | void generate_serialize_map_element(std::ostream& out, | |
167 | t_map* tmap, | |
168 | std::string iter, | |
169 | std::string map); | |
170 | ||
171 | void generate_haxe_doc(std::ostream& out, t_doc* tdoc); | |
172 | void generate_haxe_doc(std::ostream& out, t_function* tdoc); | |
173 | ||
174 | void generate_rtti_decoration(std::ostream& out); | |
175 | void generate_macro_decoration(std::ostream& out); | |
176 | ||
177 | /** | |
178 | * Helper rendering functions | |
179 | */ | |
180 | ||
181 | std::string haxe_package(); | |
182 | std::string haxe_type_imports(); | |
183 | std::string haxe_thrift_imports(); | |
184 | std::string haxe_thrift_gen_imports(t_struct* tstruct, string& imports); | |
185 | std::string haxe_thrift_gen_imports(t_service* tservice); | |
186 | std::string type_name(t_type* ttype, bool in_container = false, bool in_init = false); | |
187 | std::string base_type_name(t_base_type* tbase, bool in_container = false); | |
188 | std::string declare_field(t_field* tfield, bool init = false); | |
189 | std::string function_signature_callback(t_function* tfunction); | |
190 | std::string function_signature_normal(t_function* tfunction); | |
191 | std::string argument_list(t_struct* tstruct); | |
192 | std::string type_to_enum(t_type* ttype); | |
193 | std::string get_enum_class_name(t_type* type) override; | |
194 | string generate_service_method_onsuccess(t_function* tfunction, bool as_type, bool omit_name); | |
195 | void generate_service_method_signature_callback(t_function* tfunction, bool is_interface); | |
196 | void generate_service_method_signature_normal(t_function* tfunction, bool is_interface); | |
197 | ||
198 | bool type_can_be_null(t_type* ttype) { | |
199 | ttype = get_true_type(ttype); | |
200 | ||
201 | if (ttype->is_container() || ttype->is_struct() || ttype->is_xception() || ttype->is_string()) { | |
202 | return true; | |
203 | } | |
204 | ||
205 | if (ttype->is_base_type()) { | |
206 | t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); | |
207 | switch (tbase) { | |
208 | case t_base_type::TYPE_STRING: | |
209 | // case t_base_type::TYPE_I64: - Int64 is not really nullable, even though it behaved that | |
210 | // way before Haxe 3.2.0 | |
211 | return true; | |
212 | default: | |
213 | return false; | |
214 | } | |
215 | } | |
216 | ||
217 | return false; | |
218 | } | |
219 | ||
220 | std::string constant_name(std::string name); | |
221 | ||
222 | private: | |
223 | bool callbacks_; | |
224 | bool rtti_; | |
225 | string buildmacro_; | |
226 | ||
227 | /** | |
228 | * File streams | |
229 | */ | |
230 | ||
231 | std::string package_name_; | |
232 | ofstream_with_content_based_conditional_update f_service_; | |
233 | std::string package_dir_; | |
234 | }; | |
235 | ||
236 | /** | |
237 | * Prepares for file generation by opening up the necessary file output | |
238 | * streams. | |
239 | * | |
240 | * @param tprogram The program to generate | |
241 | */ | |
242 | void t_haxe_generator::init_generator() { | |
243 | // Make output directory | |
244 | MKDIR(get_out_dir().c_str()); | |
245 | package_name_ = program_->get_namespace("haxe"); | |
246 | ||
247 | // Haxe package names are lowercase | |
248 | if (package_name_.length() > 0) { | |
249 | package_name_[0] = tolower(package_name_[0]); | |
250 | size_t index = package_name_.find('.'); | |
251 | while (index != std::string::npos) { | |
252 | if (++index < package_name_.length()) { | |
253 | package_name_[index] = tolower(package_name_[index]); | |
254 | } | |
255 | index = package_name_.find('.', index); | |
256 | } | |
257 | } | |
258 | ||
259 | string dir = package_name_; | |
260 | string subdir = get_out_dir(); | |
261 | string::size_type loc; | |
262 | while ((loc = dir.find(".")) != string::npos) { | |
263 | subdir = subdir + "/" + dir.substr(0, loc); | |
264 | MKDIR(subdir.c_str()); | |
265 | dir = dir.substr(loc + 1); | |
266 | } | |
267 | if (dir.size() > 0) { | |
268 | subdir = subdir + "/" + dir; | |
269 | MKDIR(subdir.c_str()); | |
270 | } | |
271 | ||
272 | package_dir_ = subdir; | |
273 | } | |
274 | ||
275 | /** | |
276 | * Packages the generated file | |
277 | * | |
278 | * @return String of the package, i.e. "package org.apache.thriftdemo;" | |
279 | */ | |
280 | string t_haxe_generator::haxe_package() { | |
281 | if (!package_name_.empty()) { | |
282 | return string("package ") + package_name_; | |
283 | } | |
284 | return "package"; | |
285 | } | |
286 | ||
287 | /** | |
288 | * Prints standard haxe imports | |
289 | * | |
290 | * @return List of imports for haxe types that are used in here | |
291 | */ | |
292 | string t_haxe_generator::haxe_type_imports() { | |
293 | return string() + "import org.apache.thrift.helper.*;\n" + "import haxe.io.Bytes;\n" | |
294 | + "import haxe.ds.IntMap;\n" + "import haxe.ds.StringMap;\n" | |
295 | + "import haxe.ds.ObjectMap;\n" + "\n" + "#if flash\n" | |
296 | + "import flash.errors.ArgumentError;\n" + "#end\n" + "\n"; | |
297 | } | |
298 | ||
299 | /** | |
300 | * Prints standard haxe imports | |
301 | * | |
302 | * @return List of imports necessary for thrift | |
303 | */ | |
304 | string t_haxe_generator::haxe_thrift_imports() { | |
305 | return string() + "import org.apache.thrift.*;\n" + "import org.apache.thrift.meta_data.*;\n" | |
306 | + "import org.apache.thrift.protocol.*;\n" + "\n"; | |
307 | } | |
308 | ||
309 | /** | |
310 | * Prints imports needed for a given type | |
311 | * | |
312 | * @return List of imports necessary for a given t_struct | |
313 | */ | |
314 | string t_haxe_generator::haxe_thrift_gen_imports(t_struct* tstruct, string& imports) { | |
315 | ||
316 | const vector<t_field*>& members = tstruct->get_members(); | |
317 | vector<t_field*>::const_iterator m_iter; | |
318 | ||
319 | // For each type check if it is from a different namespace | |
320 | for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { | |
321 | t_program* program = (*m_iter)->get_type()->get_program(); | |
322 | if (program != NULL && program != program_) { | |
323 | string package = program->get_namespace("haxe"); | |
324 | if (!package.empty()) { | |
325 | if (imports.find(package + "." + (*m_iter)->get_type()->get_name()) == string::npos) { | |
326 | imports.append("import " + package + "." + (*m_iter)->get_type()->get_name() + ";\n"); | |
327 | } | |
328 | } | |
329 | } | |
330 | } | |
331 | return imports; | |
332 | } | |
333 | ||
334 | /** | |
335 | * Prints imports needed for a given type | |
336 | * | |
337 | * @return List of imports necessary for a given t_service | |
338 | */ | |
339 | string t_haxe_generator::haxe_thrift_gen_imports(t_service* tservice) { | |
340 | string imports; | |
341 | const vector<t_function*>& functions = tservice->get_functions(); | |
342 | vector<t_function*>::const_iterator f_iter; | |
343 | ||
344 | // For each type check if it is from a different namespace | |
345 | for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { | |
346 | t_program* program = (*f_iter)->get_returntype()->get_program(); | |
347 | if (program != NULL && program != program_) { | |
348 | string package = program->get_namespace("haxe"); | |
349 | if (!package.empty()) { | |
350 | if (imports.find(package + "." + (*f_iter)->get_returntype()->get_name()) == string::npos) { | |
351 | imports.append("import " + package + "." + (*f_iter)->get_returntype()->get_name() | |
352 | + ";\n"); | |
353 | } | |
354 | } | |
355 | } | |
356 | ||
357 | haxe_thrift_gen_imports((*f_iter)->get_arglist(), imports); | |
358 | haxe_thrift_gen_imports((*f_iter)->get_xceptions(), imports); | |
359 | } | |
360 | ||
361 | return imports; | |
362 | } | |
363 | ||
364 | /** | |
365 | * Nothing in haxe | |
366 | */ | |
367 | void t_haxe_generator::close_generator() { | |
368 | } | |
369 | ||
370 | /** | |
371 | * Generates a typedef. This is not done in haxe, since it does | |
372 | * not support arbitrary name replacements, and it'd be a wacky waste | |
373 | * of overhead to make wrapper classes. | |
374 | * | |
375 | * @param ttypedef The type definition | |
376 | */ | |
377 | void t_haxe_generator::generate_typedef(t_typedef* ttypedef) { | |
378 | (void)ttypedef; | |
379 | } | |
380 | ||
381 | /** | |
382 | * Enums are a class with a set of static constants. | |
383 | * | |
384 | * @param tenum The enumeration | |
385 | */ | |
386 | void t_haxe_generator::generate_enum(t_enum* tenum) { | |
387 | // Make output file | |
388 | string f_enum_name = package_dir_ + "/" + get_cap_name(tenum->get_name()) + ".hx"; | |
389 | ofstream_with_content_based_conditional_update f_enum; | |
390 | f_enum.open(f_enum_name.c_str()); | |
391 | ||
392 | // Comment and package it | |
393 | f_enum << autogen_comment() << haxe_package() << ";" << endl << endl; | |
394 | ||
395 | // Add haxe imports | |
396 | f_enum << string() + "import org.apache.thrift.helper.*;" << endl << endl; | |
397 | ||
398 | generate_rtti_decoration(f_enum); | |
399 | generate_macro_decoration(f_enum); | |
400 | indent(f_enum) << "class " << get_cap_name(tenum->get_name()) << " "; | |
401 | scope_up(f_enum); | |
402 | ||
403 | vector<t_enum_value*> constants = tenum->get_constants(); | |
404 | vector<t_enum_value*>::iterator c_iter; | |
405 | for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { | |
406 | int value = (*c_iter)->get_value(); | |
407 | indent(f_enum) << "public static inline var " << (*c_iter)->get_name() << " : Int = " << value | |
408 | << ";" << endl; | |
409 | } | |
410 | ||
411 | // Create a static Set with all valid values for this enum | |
412 | f_enum << endl; | |
413 | ||
414 | indent(f_enum) << "public static var VALID_VALUES = { new IntSet( ["; | |
415 | indent_up(); | |
416 | bool firstValue = true; | |
417 | for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { | |
418 | // populate set | |
419 | f_enum << (firstValue ? "" : ", ") << (*c_iter)->get_name(); | |
420 | firstValue = false; | |
421 | } | |
422 | indent_down(); | |
423 | f_enum << "]); };" << endl; | |
424 | ||
425 | indent(f_enum) << "public static var VALUES_TO_NAMES = { ["; | |
426 | indent_up(); | |
427 | firstValue = true; | |
428 | for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { | |
429 | f_enum << (firstValue ? "" : ",") << endl; | |
430 | indent(f_enum) << (*c_iter)->get_name() << " => \"" << (*c_iter)->get_name() << "\""; | |
431 | firstValue = false; | |
432 | } | |
433 | f_enum << endl; | |
434 | indent_down(); | |
435 | indent(f_enum) << "]; };" << endl; | |
436 | ||
437 | scope_down(f_enum); // end class | |
438 | ||
439 | f_enum.close(); | |
440 | } | |
441 | ||
442 | /** | |
443 | * Generates a class that holds all the constants. | |
444 | */ | |
445 | void t_haxe_generator::generate_consts(std::vector<t_const*> consts) { | |
446 | if (consts.empty()) { | |
447 | return; | |
448 | } | |
449 | ||
450 | string f_consts_name = package_dir_ + "/" + get_cap_name(program_name_) + "Constants.hx"; | |
451 | ofstream_with_content_based_conditional_update f_consts; | |
452 | f_consts.open(f_consts_name.c_str()); | |
453 | ||
454 | // Print header | |
455 | f_consts << autogen_comment() << haxe_package() << ";" << endl << endl; | |
456 | ||
457 | f_consts << endl; | |
458 | ||
459 | f_consts << haxe_type_imports(); | |
460 | ||
461 | generate_rtti_decoration(f_consts); | |
462 | generate_macro_decoration(f_consts); | |
463 | indent(f_consts) << "class " << get_cap_name(program_name_) << "Constants {" << endl << endl; | |
464 | indent_up(); | |
465 | vector<t_const*>::iterator c_iter; | |
466 | for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { | |
467 | print_const_value(f_consts, | |
468 | (*c_iter)->get_name(), | |
469 | (*c_iter)->get_type(), | |
470 | (*c_iter)->get_value(), | |
471 | false); | |
472 | } | |
473 | indent_down(); | |
474 | indent(f_consts) << "}" << endl; | |
475 | f_consts.close(); | |
476 | } | |
477 | ||
478 | void t_haxe_generator::print_const_value(std::ostream& out, | |
479 | string name, | |
480 | t_type* type, | |
481 | t_const_value* value, | |
482 | bool in_static, | |
483 | bool defval) { | |
484 | type = get_true_type(type); | |
485 | ||
486 | indent(out); | |
487 | if (!defval) { | |
488 | out << (in_static ? "var " : "public static inline var "); | |
489 | } | |
490 | if (type->is_base_type()) { | |
491 | string v2 = render_const_value(out, name, type, value); | |
492 | out << name; | |
493 | if (!defval) { | |
494 | out << ":" << type_name(type); | |
495 | } | |
496 | out << " = " << v2 << ";" << endl << endl; | |
497 | } else if (type->is_enum()) { | |
498 | out << name; | |
499 | if (!defval) { | |
500 | out << ":" << type_name(type); | |
501 | } | |
502 | out << " = " << value->get_integer() << ";" << endl << endl; | |
503 | } else if (type->is_struct() || type->is_xception()) { | |
504 | const vector<t_field*>& fields = ((t_struct*)type)->get_members(); | |
505 | vector<t_field*>::const_iterator f_iter; | |
506 | const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map(); | |
507 | map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter; | |
508 | out << name << ":" << type_name(type) << " = new " << type_name(type, false, true) << "();" | |
509 | << endl; | |
510 | if (!in_static) { | |
511 | indent(out) << "{" << endl; | |
512 | indent_up(); | |
513 | indent(out) << "new function() : Void {" << endl; | |
514 | indent_up(); | |
515 | } | |
516 | for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { | |
517 | t_type* field_type = NULL; | |
518 | for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { | |
519 | if ((*f_iter)->get_name() == v_iter->first->get_string()) { | |
520 | field_type = (*f_iter)->get_type(); | |
521 | } | |
522 | } | |
523 | if (field_type == NULL) { | |
524 | throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string(); | |
525 | } | |
526 | string val = render_const_value(out, name, field_type, v_iter->second); | |
527 | indent(out) << name << "."; | |
528 | out << v_iter->first->get_string() << " = " << val << ";" << endl; | |
529 | } | |
530 | if (!in_static) { | |
531 | indent_down(); | |
532 | indent(out) << "}();" << endl; | |
533 | indent_down(); | |
534 | indent(out) << "}" << endl; | |
535 | } | |
536 | out << endl; | |
537 | } else if (type->is_map()) { | |
538 | out << name; | |
539 | if (!defval) { | |
540 | out << ":" << type_name(type); | |
541 | } | |
542 | out << " = new " << type_name(type, false, true) << "();" << endl; | |
543 | if (!in_static) { | |
544 | indent(out) << "{" << endl; | |
545 | indent_up(); | |
546 | indent(out) << "new function() : Void {" << endl; | |
547 | indent_up(); | |
548 | } | |
549 | t_type* ktype = ((t_map*)type)->get_key_type(); | |
550 | t_type* vtype = ((t_map*)type)->get_val_type(); | |
551 | const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map(); | |
552 | map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter; | |
553 | for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { | |
554 | string key = render_const_value(out, name, ktype, v_iter->first); | |
555 | string val = render_const_value(out, name, vtype, v_iter->second); | |
556 | indent(out) << name << "[" << key << "] = " << val << ";" << endl; | |
557 | } | |
558 | if (!in_static) { | |
559 | indent_down(); | |
560 | indent(out) << "}();" << endl; | |
561 | indent_down(); | |
562 | indent(out) << "}" << endl; | |
563 | } | |
564 | out << endl; | |
565 | } else if (type->is_list() || type->is_set()) { | |
566 | out << name; | |
567 | if (!defval) { | |
568 | out << ":" << type_name(type); | |
569 | } | |
570 | out << " = new " << type_name(type, false, true) << "();" << endl; | |
571 | if (!in_static) { | |
572 | indent(out) << "{" << endl; | |
573 | indent_up(); | |
574 | indent(out) << "new function() : Void {" << endl; | |
575 | indent_up(); | |
576 | } | |
577 | t_type* etype; | |
578 | if (type->is_list()) { | |
579 | etype = ((t_list*)type)->get_elem_type(); | |
580 | } else { | |
581 | etype = ((t_set*)type)->get_elem_type(); | |
582 | } | |
583 | const vector<t_const_value*>& val = value->get_list(); | |
584 | vector<t_const_value*>::const_iterator v_iter; | |
585 | for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { | |
586 | string val = render_const_value(out, name, etype, *v_iter); | |
587 | indent(out) << name << "." << (type->is_list() ? "push" : "add") << "(" << val << ");" | |
588 | << endl; | |
589 | } | |
590 | if (!in_static) { | |
591 | indent_down(); | |
592 | indent(out) << "}();" << endl; | |
593 | indent_down(); | |
594 | indent(out) << "}" << endl; | |
595 | } | |
596 | out << endl; | |
597 | } else { | |
598 | throw "compiler error: no const of type " + type->get_name(); | |
599 | } | |
600 | } | |
601 | ||
602 | string t_haxe_generator::render_const_value(ostream& out, | |
603 | string name, | |
604 | t_type* type, | |
605 | t_const_value* value) { | |
606 | (void)name; | |
607 | type = get_true_type(type); | |
608 | std::ostringstream render; | |
609 | ||
610 | if (type->is_base_type()) { | |
611 | t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); | |
612 | switch (tbase) { | |
613 | case t_base_type::TYPE_STRING: | |
614 | render << '"' << get_escaped_string(value) << '"'; | |
615 | break; | |
616 | case t_base_type::TYPE_BOOL: | |
617 | render << ((value->get_integer() > 0) ? "true" : "false"); | |
618 | break; | |
619 | case t_base_type::TYPE_I8: | |
620 | render << "(byte)" << value->get_integer(); | |
621 | break; | |
622 | case t_base_type::TYPE_I16: | |
623 | render << "(short)" << value->get_integer(); | |
624 | break; | |
625 | case t_base_type::TYPE_I32: | |
626 | render << value->get_integer(); | |
627 | break; | |
628 | case t_base_type::TYPE_I64: | |
629 | render << value->get_integer() << "L"; | |
630 | break; | |
631 | case t_base_type::TYPE_DOUBLE: | |
632 | if (value->get_type() == t_const_value::CV_INTEGER) { | |
633 | render << "(double)" << value->get_integer(); | |
634 | } else { | |
635 | render << value->get_double(); | |
636 | } | |
637 | break; | |
638 | default: | |
639 | throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); | |
640 | } | |
641 | } else if (type->is_enum()) { | |
642 | render << value->get_integer(); | |
643 | } else { | |
644 | string t = tmp("tmp"); | |
645 | print_const_value(out, t, type, value, true); | |
646 | render << t; | |
647 | } | |
648 | ||
649 | return render.str(); | |
650 | } | |
651 | ||
652 | /** | |
653 | * Generates a struct definition for a thrift data type. This is a class | |
654 | * with data members, read(), write(), and an inner Isset class. | |
655 | * | |
656 | * @param tstruct The struct definition | |
657 | */ | |
658 | void t_haxe_generator::generate_struct(t_struct* tstruct) { | |
659 | generate_haxe_struct(tstruct, false); | |
660 | } | |
661 | ||
662 | /** | |
663 | * Exceptions are structs, but they inherit from Exception | |
664 | * | |
665 | * @param tstruct The struct definition | |
666 | */ | |
667 | void t_haxe_generator::generate_xception(t_struct* txception) { | |
668 | generate_haxe_struct(txception, true); | |
669 | } | |
670 | ||
671 | /** | |
672 | * Haxe struct definition. | |
673 | * | |
674 | * @param tstruct The struct definition | |
675 | */ | |
676 | void t_haxe_generator::generate_haxe_struct(t_struct* tstruct, bool is_exception, bool is_result) { | |
677 | // Make output file | |
678 | string f_struct_name = package_dir_ + "/" + get_cap_name(tstruct->get_name()) + ".hx"; | |
679 | ofstream_with_content_based_conditional_update f_struct; | |
680 | f_struct.open(f_struct_name.c_str()); | |
681 | ||
682 | f_struct << autogen_comment() << haxe_package() << ";" << endl; | |
683 | ||
684 | f_struct << endl; | |
685 | ||
686 | string imports; | |
687 | ||
688 | f_struct << haxe_type_imports() << haxe_thrift_imports() | |
689 | << haxe_thrift_gen_imports(tstruct, imports) << endl; | |
690 | ||
691 | generate_haxe_struct_definition(f_struct, tstruct, is_exception, is_result); | |
692 | ||
693 | f_struct.close(); | |
694 | } | |
695 | ||
696 | /** | |
697 | * haxe struct definition. This has various parameters, as it could be | |
698 | * generated standalone or inside another class as a helper. If it | |
699 | * is a helper than it is a static class. | |
700 | * | |
701 | * @param tstruct The struct definition | |
702 | * @param is_exception Is this an exception? | |
703 | * @param in_class If inside a class, needs to be static class | |
704 | * @param is_result If this is a result it needs a different writer | |
705 | */ | |
706 | void t_haxe_generator::generate_haxe_struct_definition(ostream& out, | |
707 | t_struct* tstruct, | |
708 | bool is_exception, | |
709 | bool is_result) { | |
710 | generate_haxe_doc(out, tstruct); | |
711 | ||
712 | string clsname = get_cap_name(tstruct->get_name()); | |
713 | ||
714 | generate_rtti_decoration(out); | |
715 | generate_macro_decoration(out); | |
716 | indent(out) << "class " << clsname << " "; | |
717 | ||
718 | if (is_exception) { | |
719 | out << "extends TException "; | |
720 | } | |
721 | out << "implements TBase "; | |
722 | ||
723 | scope_up(out); | |
724 | indent(out) << endl; | |
725 | ||
726 | indent(out) << "static var STRUCT_DESC = { new TStruct(\"" << tstruct->get_name() << "\"); };" | |
727 | << endl; | |
728 | ||
729 | const vector<t_field*>& members = tstruct->get_members(); | |
730 | vector<t_field*>::const_iterator m_iter; | |
731 | ||
732 | for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { | |
733 | indent(out) << "static var " << constant_name((*m_iter)->get_name()) | |
734 | << "_FIELD_DESC = { new TField(\"" << (*m_iter)->get_name() << "\", " | |
735 | << type_to_enum((*m_iter)->get_type()) << ", " << (*m_iter)->get_key() << "); };" | |
736 | << endl; | |
737 | } | |
738 | out << endl; | |
739 | ||
740 | for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { | |
741 | generate_haxe_doc(out, *m_iter); | |
742 | // indent(out) << "private var _" << (*m_iter)->get_name() + " : " + | |
743 | // type_name((*m_iter)->get_type()) << ";" << endl; | |
744 | indent(out) << "@:isVar" << endl; | |
745 | indent(out) << "public var " | |
746 | << (*m_iter)->get_name() + "(get,set) : " | |
747 | + get_cap_name(type_name((*m_iter)->get_type())) << ";" << endl; | |
748 | } | |
749 | ||
750 | out << endl; | |
751 | ||
752 | for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { | |
753 | indent(out) << "inline static var " << upcase_string((*m_iter)->get_name()) | |
754 | << "_FIELD_ID : Int = " << (*m_iter)->get_key() << ";" << endl; | |
755 | } | |
756 | ||
757 | out << endl; | |
758 | ||
759 | // Inner Isset class | |
760 | if (members.size() > 0) { | |
761 | for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { | |
762 | if (!type_can_be_null((*m_iter)->get_type())) { | |
763 | indent(out) << "private var __isset_" << (*m_iter)->get_name() << " : Bool = false;" | |
764 | << endl; | |
765 | } | |
766 | } | |
767 | } | |
768 | ||
769 | out << endl; | |
770 | ||
771 | // Static initializer to populate global class to struct metadata map | |
772 | if (false) { | |
773 | // TODO: reactivate when needed | |
774 | generate_haxe_meta_data_map(out, tstruct); | |
775 | indent(out) << "{" << endl; | |
776 | indent_up(); | |
777 | indent(out) << "FieldMetaData.addStructMetaDataMap(" << type_name(tstruct) << ", metaDataMap);" | |
778 | << endl; | |
779 | indent_down(); | |
780 | indent(out) << "}" << endl; | |
781 | indent(out) << "}" << endl; | |
782 | } | |
783 | ||
784 | // Default constructor | |
785 | indent(out) << "public function new() {" << endl; | |
786 | indent_up(); | |
787 | if (is_exception) { | |
788 | indent(out) << "super();" << endl; | |
789 | } | |
790 | for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { | |
791 | if ((*m_iter)->get_value() != NULL) { | |
792 | indent(out) << "this." << (*m_iter)->get_name() << " = " | |
793 | << (*m_iter)->get_value()->get_integer() << ";" << endl; | |
794 | } | |
795 | } | |
796 | indent_down(); | |
797 | indent(out) << "}" << endl << endl; | |
798 | ||
799 | generate_property_getters_setters(out, tstruct); | |
800 | generate_generic_field_getters_setters(out, tstruct); | |
801 | generate_generic_isset_method(out, tstruct); | |
802 | ||
803 | generate_haxe_struct_reader(out, tstruct); | |
804 | if (is_result) { | |
805 | generate_haxe_struct_result_writer(out, tstruct); | |
806 | } else { | |
807 | generate_haxe_struct_writer(out, tstruct); | |
808 | } | |
809 | generate_haxe_struct_tostring(out, tstruct); | |
810 | generate_haxe_validator(out, tstruct); | |
811 | scope_down(out); | |
812 | out << endl; | |
813 | } | |
814 | ||
815 | /** | |
816 | * Generates a function to read all the fields of the struct. | |
817 | * | |
818 | * @param tstruct The struct definition | |
819 | */ | |
820 | void t_haxe_generator::generate_haxe_struct_reader(ostream& out, t_struct* tstruct) { | |
821 | out << indent() << "public function read( iprot : TProtocol) : Void {" << endl; | |
822 | indent_up(); | |
823 | ||
824 | const vector<t_field*>& fields = tstruct->get_members(); | |
825 | vector<t_field*>::const_iterator f_iter; | |
826 | ||
827 | indent(out) << "iprot.IncrementRecursionDepth();" << endl; | |
828 | indent(out) << "try" << endl; | |
829 | scope_up(out); | |
830 | ||
831 | // Declare stack tmp variables and read struct header | |
832 | out << indent() << "var field : TField;" << endl << indent() << "iprot.readStructBegin();" | |
833 | << endl; | |
834 | ||
835 | // Loop over reading in fields | |
836 | indent(out) << "while (true)" << endl; | |
837 | scope_up(out); | |
838 | ||
839 | // Read beginning field marker | |
840 | indent(out) << "field = iprot.readFieldBegin();" << endl; | |
841 | ||
842 | // Check for field STOP marker and break | |
843 | indent(out) << "if (field.type == TType.STOP) { " << endl; | |
844 | indent_up(); | |
845 | indent(out) << "break;" << endl; | |
846 | indent_down(); | |
847 | indent(out) << "}" << endl; | |
848 | ||
849 | // Switch statement on the field we are reading | |
850 | indent(out) << "switch (field.id)" << endl; | |
851 | ||
852 | scope_up(out); | |
853 | ||
854 | // Generate deserialization code for known cases | |
855 | for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { | |
856 | indent(out) << "case " << upcase_string((*f_iter)->get_name()) << "_FIELD_ID:" << endl; | |
857 | indent_up(); | |
858 | indent(out) << "if (field.type == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl; | |
859 | indent_up(); | |
860 | ||
861 | generate_deserialize_field(out, *f_iter, "this."); | |
862 | generate_isset_set(out, *f_iter); | |
863 | indent_down(); | |
864 | out << indent() << "} else { " << endl << indent() << " TProtocolUtil.skip(iprot, field.type);" | |
865 | << endl << indent() << "}" << endl; | |
866 | indent_down(); | |
867 | } | |
868 | ||
869 | // In the default case we skip the field | |
870 | out << indent() << "default:" << endl << indent() << " TProtocolUtil.skip(iprot, field.type);" | |
871 | << endl; | |
872 | ||
873 | scope_down(out); | |
874 | ||
875 | // Read field end marker | |
876 | indent(out) << "iprot.readFieldEnd();" << endl; | |
877 | ||
878 | scope_down(out); | |
879 | ||
880 | out << indent() << "iprot.readStructEnd();" << endl << endl; | |
881 | ||
882 | indent(out) << "iprot.DecrementRecursionDepth();" << endl; | |
883 | scope_down(out); | |
884 | indent(out) << "catch(e:Dynamic)" << endl; | |
885 | scope_up(out); | |
886 | indent(out) << "iprot.DecrementRecursionDepth();" << endl; | |
887 | indent(out) << "throw e;" << endl; | |
888 | scope_down(out); | |
889 | ||
890 | // check for required fields of primitive type | |
891 | // (which can be checked here but not in the general validate method) | |
892 | out << endl << indent() << "// check for required fields of primitive type, which can't be " | |
893 | "checked in the validate method" << endl; | |
894 | for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { | |
895 | if ((*f_iter)->get_req() == t_field::T_REQUIRED && !type_can_be_null((*f_iter)->get_type())) { | |
896 | out << indent() << "if (!__isset_" << (*f_iter)->get_name() << ") {" << endl << indent() | |
897 | << " throw new TProtocolException(TProtocolException.UNKNOWN, \"Required field '" | |
898 | << (*f_iter)->get_name() | |
899 | << "' was not found in serialized data! Struct: \" + toString());" << endl << indent() | |
900 | << "}" << endl; | |
901 | } | |
902 | } | |
903 | ||
904 | // performs various checks (e.g. check that all required fields are set) | |
905 | indent(out) << "validate();" << endl; | |
906 | ||
907 | indent_down(); | |
908 | out << indent() << "}" << endl << endl; | |
909 | } | |
910 | ||
911 | // generates haxe method to perform various checks | |
912 | // (e.g. check that all required fields are set) | |
913 | void t_haxe_generator::generate_haxe_validator(ostream& out, t_struct* tstruct) { | |
914 | indent(out) << "public function validate() : Void {" << endl; | |
915 | indent_up(); | |
916 | ||
917 | const vector<t_field*>& fields = tstruct->get_members(); | |
918 | vector<t_field*>::const_iterator f_iter; | |
919 | ||
920 | out << indent() << "// check for required fields" << endl; | |
921 | for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { | |
922 | if ((*f_iter)->get_req() == t_field::T_REQUIRED) { | |
923 | if (type_can_be_null((*f_iter)->get_type())) { | |
924 | indent(out) << "if (" << (*f_iter)->get_name() << " == null) {" << endl; | |
925 | indent(out) | |
926 | << " throw new TProtocolException(TProtocolException.UNKNOWN, \"Required field '" | |
927 | << (*f_iter)->get_name() << "' was not present! Struct: \" + toString());" << endl; | |
928 | indent(out) << "}" << endl; | |
929 | } else { | |
930 | indent(out) << "// alas, we cannot check '" << (*f_iter)->get_name() | |
931 | << "' because it's a primitive." << endl; | |
932 | } | |
933 | } | |
934 | } | |
935 | ||
936 | // check that fields of type enum have valid values | |
937 | out << indent() << "// check that fields of type enum have valid values" << endl; | |
938 | for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { | |
939 | t_field* field = (*f_iter); | |
940 | t_type* type = field->get_type(); | |
941 | // if field is an enum, check that its value is valid | |
942 | if (type->is_enum()) { | |
943 | indent(out) << "if (" << generate_isset_check(field) << " && !" | |
944 | << get_cap_name(get_enum_class_name(type)) << ".VALID_VALUES.contains(" | |
945 | << field->get_name() << ")){" << endl; | |
946 | indent_up(); | |
947 | indent(out) << "throw new TProtocolException(TProtocolException.UNKNOWN, \"The field '" | |
948 | << field->get_name() << "' has been assigned the invalid value \" + " | |
949 | << field->get_name() << ");" << endl; | |
950 | indent_down(); | |
951 | indent(out) << "}" << endl; | |
952 | } | |
953 | } | |
954 | ||
955 | indent_down(); | |
956 | indent(out) << "}" << endl << endl; | |
957 | } | |
958 | ||
959 | /** | |
960 | * Generates a function to write all the fields of the struct | |
961 | * | |
962 | * @param tstruct The struct definition | |
963 | */ | |
964 | void t_haxe_generator::generate_haxe_struct_writer(ostream& out, t_struct* tstruct) { | |
965 | out << indent() << "public function write(oprot:TProtocol) : Void {" << endl; | |
966 | indent_up(); | |
967 | ||
968 | string name = tstruct->get_name(); | |
969 | const vector<t_field*>& fields = tstruct->get_sorted_members(); | |
970 | vector<t_field*>::const_iterator f_iter; | |
971 | ||
972 | // performs various checks (e.g. check that all required fields are set) | |
973 | indent(out) << "validate();" << endl; | |
974 | indent(out) << "oprot.IncrementRecursionDepth();" << endl; | |
975 | indent(out) << "try" << endl; | |
976 | scope_up(out); | |
977 | ||
978 | indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl; | |
979 | ||
980 | for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { | |
981 | bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL; | |
982 | if (could_be_unset) { | |
983 | indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl; | |
984 | indent_up(); | |
985 | } | |
986 | bool null_allowed = type_can_be_null((*f_iter)->get_type()); | |
987 | if (null_allowed) { | |
988 | out << indent() << "if (this." << (*f_iter)->get_name() << " != null) {" << endl; | |
989 | indent_up(); | |
990 | } | |
991 | ||
992 | indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name()) | |
993 | << "_FIELD_DESC);" << endl; | |
994 | ||
995 | // Write field contents | |
996 | generate_serialize_field(out, *f_iter, "this."); | |
997 | ||
998 | // Write field closer | |
999 | indent(out) << "oprot.writeFieldEnd();" << endl; | |
1000 | ||
1001 | if (null_allowed) { | |
1002 | indent_down(); | |
1003 | indent(out) << "}" << endl; | |
1004 | } | |
1005 | if (could_be_unset) { | |
1006 | indent_down(); | |
1007 | indent(out) << "}" << endl; | |
1008 | } | |
1009 | } | |
1010 | ||
1011 | indent(out) << "oprot.writeFieldStop();" << endl; | |
1012 | indent(out) << "oprot.writeStructEnd();" << endl; | |
1013 | ||
1014 | indent(out) << "oprot.DecrementRecursionDepth();" << endl; | |
1015 | scope_down(out); | |
1016 | indent(out) << "catch(e:Dynamic)" << endl; | |
1017 | scope_up(out); | |
1018 | indent(out) << "oprot.DecrementRecursionDepth();" << endl; | |
1019 | indent(out) << "throw e;" << endl; | |
1020 | scope_down(out); | |
1021 | ||
1022 | indent_down(); | |
1023 | out << indent() << "}" << endl << endl; | |
1024 | } | |
1025 | ||
1026 | /** | |
1027 | * Generates a function to write all the fields of the struct, | |
1028 | * which is a function result. These fields are only written | |
1029 | * if they are set in the Isset array, and only one of them | |
1030 | * can be set at a time. | |
1031 | * | |
1032 | * @param tstruct The struct definition | |
1033 | */ | |
1034 | void t_haxe_generator::generate_haxe_struct_result_writer(ostream& out, t_struct* tstruct) { | |
1035 | out << indent() << "public function write(oprot:TProtocol) : Void {" << endl; | |
1036 | indent_up(); | |
1037 | ||
1038 | string name = tstruct->get_name(); | |
1039 | const vector<t_field*>& fields = tstruct->get_sorted_members(); | |
1040 | vector<t_field*>::const_iterator f_iter; | |
1041 | ||
1042 | indent(out) << "oprot.IncrementRecursionDepth();" << endl; | |
1043 | indent(out) << "try" << endl; | |
1044 | scope_up(out); | |
1045 | ||
1046 | indent(out) << "oprot.writeStructBegin(STRUCT_DESC);" << endl; | |
1047 | ||
1048 | bool first = true; | |
1049 | for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { | |
1050 | if (first) { | |
1051 | first = false; | |
1052 | out << endl << indent() << "if "; | |
1053 | } else { | |
1054 | out << " else if "; | |
1055 | } | |
1056 | ||
1057 | out << "(this." << generate_isset_check(*f_iter) << ") {" << endl; | |
1058 | ||
1059 | indent_up(); | |
1060 | ||
1061 | indent(out) << "oprot.writeFieldBegin(" << constant_name((*f_iter)->get_name()) | |
1062 | << "_FIELD_DESC);" << endl; | |
1063 | ||
1064 | // Write field contents | |
1065 | generate_serialize_field(out, *f_iter, "this."); | |
1066 | ||
1067 | // Write field closer | |
1068 | indent(out) << "oprot.writeFieldEnd();" << endl; | |
1069 | ||
1070 | indent_down(); | |
1071 | indent(out) << "}"; | |
1072 | } | |
1073 | ||
1074 | indent(out) << endl; | |
1075 | indent(out) << "oprot.writeFieldStop();" << endl; | |
1076 | indent(out) << "oprot.writeStructEnd();" << endl; | |
1077 | ||
1078 | indent(out) << "oprot.DecrementRecursionDepth();" << endl; | |
1079 | scope_down(out); | |
1080 | indent(out) << "catch(e:Dynamic)" << endl; | |
1081 | scope_up(out); | |
1082 | indent(out) << "oprot.DecrementRecursionDepth();" << endl; | |
1083 | indent(out) << "throw e;" << endl; | |
1084 | scope_down(out); | |
1085 | ||
1086 | indent_down(); | |
1087 | out << indent() << "}" << endl << endl; | |
1088 | } | |
1089 | ||
1090 | void t_haxe_generator::generate_reflection_getters(ostringstream& out, | |
1091 | t_type* type, | |
1092 | string field_name, | |
1093 | string cap_name) { | |
1094 | (void)type; | |
1095 | (void)cap_name; | |
1096 | indent(out) << "case " << upcase_string(field_name) << "_FIELD_ID:" << endl; | |
1097 | indent_up(); | |
1098 | indent(out) << "return this." << field_name << ";" << endl; | |
1099 | indent_down(); | |
1100 | } | |
1101 | ||
1102 | void t_haxe_generator::generate_reflection_setters(ostringstream& out, | |
1103 | t_type* type, | |
1104 | string field_name, | |
1105 | string cap_name) { | |
1106 | (void)type; | |
1107 | (void)cap_name; | |
1108 | indent(out) << "case " << upcase_string(field_name) << "_FIELD_ID:" << endl; | |
1109 | indent_up(); | |
1110 | indent(out) << "if (value == null) {" << endl; | |
1111 | indent(out) << " unset" << get_cap_name(field_name) << "();" << endl; | |
1112 | indent(out) << "} else {" << endl; | |
1113 | indent(out) << " this." << field_name << " = value;" << endl; | |
1114 | indent(out) << "}" << endl << endl; | |
1115 | ||
1116 | indent_down(); | |
1117 | } | |
1118 | ||
1119 | void t_haxe_generator::generate_generic_field_getters_setters(std::ostream& out, | |
1120 | t_struct* tstruct) { | |
1121 | ||
1122 | std::ostringstream getter_stream; | |
1123 | std::ostringstream setter_stream; | |
1124 | ||
1125 | // build up the bodies of both the getter and setter at once | |
1126 | const vector<t_field*>& fields = tstruct->get_members(); | |
1127 | vector<t_field*>::const_iterator f_iter; | |
1128 | for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { | |
1129 | t_field* field = *f_iter; | |
1130 | t_type* type = get_true_type(field->get_type()); | |
1131 | std::string field_name = field->get_name(); | |
1132 | std::string cap_name = get_cap_name(field_name); | |
1133 | ||
1134 | indent_up(); | |
1135 | generate_reflection_setters(setter_stream, type, field_name, cap_name); | |
1136 | generate_reflection_getters(getter_stream, type, field_name, cap_name); | |
1137 | indent_down(); | |
1138 | } | |
1139 | ||
1140 | // create the setter | |
1141 | indent(out) << "public function setFieldValue(fieldID : Int, value : Dynamic) : Void {" << endl; | |
1142 | indent_up(); | |
1143 | ||
1144 | if (fields.size() > 0) { | |
1145 | indent(out) << "switch (fieldID) {" << endl; | |
1146 | out << setter_stream.str(); | |
1147 | indent(out) << "default:" << endl; | |
1148 | indent(out) << " throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl; | |
1149 | indent(out) << "}" << endl; | |
1150 | } else { | |
1151 | indent(out) << "throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl; | |
1152 | } | |
1153 | ||
1154 | indent_down(); | |
1155 | indent(out) << "}" << endl << endl; | |
1156 | ||
1157 | // create the getter | |
1158 | indent(out) << "public function getFieldValue(fieldID : Int) : Dynamic {" << endl; | |
1159 | indent_up(); | |
1160 | ||
1161 | if (fields.size() > 0) { | |
1162 | indent(out) << "switch (fieldID) {" << endl; | |
1163 | out << getter_stream.str(); | |
1164 | indent(out) << "default:" << endl; | |
1165 | indent(out) << " throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl; | |
1166 | indent(out) << "}" << endl; | |
1167 | } else { | |
1168 | indent(out) << "throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl; | |
1169 | } | |
1170 | ||
1171 | indent_down(); | |
1172 | ||
1173 | indent(out) << "}" << endl << endl; | |
1174 | } | |
1175 | ||
1176 | // Creates a generic isSet method that takes the field number as argument | |
1177 | void t_haxe_generator::generate_generic_isset_method(std::ostream& out, t_struct* tstruct) { | |
1178 | const vector<t_field*>& fields = tstruct->get_members(); | |
1179 | vector<t_field*>::const_iterator f_iter; | |
1180 | ||
1181 | // create the isSet method | |
1182 | indent(out) << "// Returns true if field corresponding to fieldID is set (has been assigned a " | |
1183 | "value) and false otherwise" << endl; | |
1184 | indent(out) << "public function isSet(fieldID : Int) : Bool {" << endl; | |
1185 | indent_up(); | |
1186 | if (fields.size() > 0) { | |
1187 | indent(out) << "switch (fieldID) {" << endl; | |
1188 | ||
1189 | for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { | |
1190 | t_field* field = *f_iter; | |
1191 | indent(out) << "case " << upcase_string(field->get_name()) << "_FIELD_ID:" << endl; | |
1192 | indent_up(); | |
1193 | indent(out) << "return " << generate_isset_check(field) << ";" << endl; | |
1194 | indent_down(); | |
1195 | } | |
1196 | ||
1197 | indent(out) << "default:" << endl; | |
1198 | indent(out) << " throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl; | |
1199 | indent(out) << "}" << endl; | |
1200 | } else { | |
1201 | indent(out) << "throw new ArgumentError(\"Field \" + fieldID + \" doesn't exist!\");" << endl; | |
1202 | } | |
1203 | ||
1204 | indent_down(); | |
1205 | indent(out) << "}" << endl << endl; | |
1206 | } | |
1207 | ||
1208 | /** | |
1209 | * Generates a set of property setters/getters for the given struct. | |
1210 | * | |
1211 | * @param tstruct The struct definition | |
1212 | */ | |
1213 | void t_haxe_generator::generate_property_getters_setters(ostream& out, t_struct* tstruct) { | |
1214 | const vector<t_field*>& fields = tstruct->get_members(); | |
1215 | vector<t_field*>::const_iterator f_iter; | |
1216 | for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { | |
1217 | t_field* field = *f_iter; | |
1218 | t_type* type = get_true_type(field->get_type()); | |
1219 | std::string field_name = field->get_name(); | |
1220 | std::string cap_name = get_cap_name(field_name); | |
1221 | ||
1222 | // Simple getter | |
1223 | generate_haxe_doc(out, field); | |
1224 | indent(out) << "public function get_" << field_name << "() : " << get_cap_name(type_name(type)) | |
1225 | << " {" << endl; | |
1226 | indent_up(); | |
1227 | indent(out) << "return this." << field_name << ";" << endl; | |
1228 | indent_down(); | |
1229 | indent(out) << "}" << endl << endl; | |
1230 | ||
1231 | // Simple setter | |
1232 | generate_haxe_doc(out, field); | |
1233 | indent(out) << "public function set_" << field_name << "(" << field_name << ":" | |
1234 | << get_cap_name(type_name(type)) << ") : " << get_cap_name(type_name(type)) << " {" | |
1235 | << endl; | |
1236 | indent_up(); | |
1237 | indent(out) << "this." << field_name << " = " << field_name << ";" << endl; | |
1238 | generate_isset_set(out, field); | |
1239 | indent(out) << "return this." << field_name << ";" << endl; | |
1240 | ||
1241 | indent_down(); | |
1242 | indent(out) << "}" << endl << endl; | |
1243 | ||
1244 | // Unsetter | |
1245 | indent(out) << "public function unset" << cap_name << "() : Void {" << endl; | |
1246 | indent_up(); | |
1247 | if (type_can_be_null(type)) { | |
1248 | indent(out) << "this." << field_name << " = null;" << endl; | |
1249 | } else { | |
1250 | indent(out) << "this.__isset_" << field_name << " = false;" << endl; | |
1251 | } | |
1252 | indent_down(); | |
1253 | indent(out) << "}" << endl << endl; | |
1254 | ||
1255 | // isSet method | |
1256 | indent(out) << "// Returns true if field " << field_name | |
1257 | << " is set (has been assigned a value) and false otherwise" << endl; | |
1258 | indent(out) << "public function is" << get_cap_name("set") << cap_name << "() : Bool {" << endl; | |
1259 | indent_up(); | |
1260 | if (type_can_be_null(type)) { | |
1261 | indent(out) << "return this." << field_name << " != null;" << endl; | |
1262 | } else { | |
1263 | indent(out) << "return this.__isset_" << field_name << ";" << endl; | |
1264 | } | |
1265 | indent_down(); | |
1266 | indent(out) << "}" << endl << endl; | |
1267 | } | |
1268 | } | |
1269 | ||
1270 | /** | |
1271 | * Generates a toString() method for the given struct | |
1272 | * | |
1273 | * @param tstruct The struct definition | |
1274 | */ | |
1275 | void t_haxe_generator::generate_haxe_struct_tostring(ostream& out, t_struct* tstruct) { | |
1276 | out << indent() << "public " | |
1277 | << "function toString() : String {" << endl; | |
1278 | indent_up(); | |
1279 | ||
1280 | out << indent() << "var ret : String = \"" << tstruct->get_name() << "(\";" << endl; | |
1281 | out << indent() << "var first : Bool = true;" << endl << endl; | |
1282 | ||
1283 | const vector<t_field*>& fields = tstruct->get_members(); | |
1284 | vector<t_field*>::const_iterator f_iter; | |
1285 | bool first = true; | |
1286 | for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { | |
1287 | bool could_be_unset = (*f_iter)->get_req() == t_field::T_OPTIONAL; | |
1288 | if (could_be_unset) { | |
1289 | indent(out) << "if (" << generate_isset_check(*f_iter) << ") {" << endl; | |
1290 | indent_up(); | |
1291 | } | |
1292 | ||
1293 | t_field* field = (*f_iter); | |
1294 | ||
1295 | if (!first) { | |
1296 | indent(out) << "if (!first) ret += \", \";" << endl; | |
1297 | } | |
1298 | indent(out) << "ret += \"" << (*f_iter)->get_name() << ":\";" << endl; | |
1299 | bool can_be_null = type_can_be_null(field->get_type()); | |
1300 | if (can_be_null) { | |
1301 | indent(out) << "if (this." << (*f_iter)->get_name() << " == null) {" << endl; | |
1302 | indent(out) << " ret += \"null\";" << endl; | |
1303 | indent(out) << "} else {" << endl; | |
1304 | indent_up(); | |
1305 | } | |
1306 | ||
1307 | if (field->get_type()->is_binary()) { | |
1308 | indent(out) << " ret += \"BINARY\";" << endl; | |
1309 | } else if (field->get_type()->is_enum()) { | |
1310 | indent(out) << "var " << field->get_name() | |
1311 | << "_name : String = " << get_cap_name(get_enum_class_name(field->get_type())) | |
1312 | << ".VALUES_TO_NAMES[this." << (*f_iter)->get_name() << "];" << endl; | |
1313 | indent(out) << "if (" << field->get_name() << "_name != null) {" << endl; | |
1314 | indent(out) << " ret += " << field->get_name() << "_name;" << endl; | |
1315 | indent(out) << " ret += \" (\";" << endl; | |
1316 | indent(out) << "}" << endl; | |
1317 | indent(out) << "ret += this." << field->get_name() << ";" << endl; | |
1318 | indent(out) << "if (" << field->get_name() << "_name != null) {" << endl; | |
1319 | indent(out) << " ret += \")\";" << endl; | |
1320 | indent(out) << "}" << endl; | |
1321 | } else { | |
1322 | indent(out) << "ret += this." << (*f_iter)->get_name() << ";" << endl; | |
1323 | } | |
1324 | ||
1325 | if (can_be_null) { | |
1326 | indent_down(); | |
1327 | indent(out) << "}" << endl; | |
1328 | } | |
1329 | indent(out) << "first = false;" << endl; | |
1330 | ||
1331 | if (could_be_unset) { | |
1332 | indent_down(); | |
1333 | indent(out) << "}" << endl; | |
1334 | } | |
1335 | first = false; | |
1336 | } | |
1337 | out << indent() << "ret += \")\";" << endl << indent() << "return ret;" << endl; | |
1338 | ||
1339 | indent_down(); | |
1340 | indent(out) << "}" << endl << endl; | |
1341 | } | |
1342 | ||
1343 | /** | |
1344 | * Generates a static map with meta data to store information such as fieldID to | |
1345 | * fieldName mapping | |
1346 | * | |
1347 | * @param tstruct The struct definition | |
1348 | */ | |
1349 | void t_haxe_generator::generate_haxe_meta_data_map(ostream& out, t_struct* tstruct) { | |
1350 | const vector<t_field*>& fields = tstruct->get_members(); | |
1351 | vector<t_field*>::const_iterator f_iter; | |
1352 | ||
1353 | // Static Map with fieldID -> FieldMetaData mappings | |
1354 | indent(out) << "inline static var metaDataMap : IntMap = new IntMap();" << endl; | |
1355 | ||
1356 | if (fields.size() > 0) { | |
1357 | // Populate map | |
1358 | scope_up(out); | |
1359 | for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { | |
1360 | t_field* field = *f_iter; | |
1361 | std::string field_name = field->get_name(); | |
1362 | indent(out) << "metaDataMap[" << upcase_string(field_name) | |
1363 | << "_FIELD_ID] = new FieldMetaData(\"" << field_name << "\", "; | |
1364 | ||
1365 | // Set field requirement type (required, optional, etc.) | |
1366 | if (field->get_req() == t_field::T_REQUIRED) { | |
1367 | out << "TFieldRequirementType.REQUIRED, "; | |
1368 | } else if (field->get_req() == t_field::T_OPTIONAL) { | |
1369 | out << "TFieldRequirementType.OPTIONAL, "; | |
1370 | } else { | |
1371 | out << "TFieldRequirementType.DEFAULT, "; | |
1372 | } | |
1373 | ||
1374 | // Create value meta data | |
1375 | generate_field_value_meta_data(out, field->get_type()); | |
1376 | out << ");" << endl; | |
1377 | } | |
1378 | scope_down(out); | |
1379 | } | |
1380 | } | |
1381 | ||
1382 | /** | |
1383 | * Returns a string with the haxe representation of the given thrift type | |
1384 | * (e.g. for the type struct it returns "TType.STRUCT") | |
1385 | */ | |
1386 | std::string t_haxe_generator::get_haxe_type_string(t_type* type) { | |
1387 | if (type->is_list()) { | |
1388 | return "TType.LIST"; | |
1389 | } else if (type->is_map()) { | |
1390 | return "TType.MAP"; | |
1391 | } else if (type->is_set()) { | |
1392 | return "TType.SET"; | |
1393 | } else if (type->is_struct() || type->is_xception()) { | |
1394 | return "TType.STRUCT"; | |
1395 | } else if (type->is_enum()) { | |
1396 | return "TType.I32"; | |
1397 | } else if (type->is_typedef()) { | |
1398 | return get_haxe_type_string(((t_typedef*)type)->get_type()); | |
1399 | } else if (type->is_base_type()) { | |
1400 | switch (((t_base_type*)type)->get_base()) { | |
1401 | case t_base_type::TYPE_VOID: | |
1402 | return "TType.VOID"; | |
1403 | break; | |
1404 | case t_base_type::TYPE_STRING: | |
1405 | return "TType.STRING"; | |
1406 | break; | |
1407 | case t_base_type::TYPE_BOOL: | |
1408 | return "TType.BOOL"; | |
1409 | break; | |
1410 | case t_base_type::TYPE_I8: | |
1411 | return "TType.BYTE"; | |
1412 | break; | |
1413 | case t_base_type::TYPE_I16: | |
1414 | return "TType.I16"; | |
1415 | break; | |
1416 | case t_base_type::TYPE_I32: | |
1417 | return "TType.I32"; | |
1418 | break; | |
1419 | case t_base_type::TYPE_I64: | |
1420 | return "TType.I64"; | |
1421 | break; | |
1422 | case t_base_type::TYPE_DOUBLE: | |
1423 | return "TType.DOUBLE"; | |
1424 | break; | |
1425 | default: | |
1426 | throw std::runtime_error("Unknown thrift type \"" + type->get_name() | |
1427 | + "\" passed to t_haxe_generator::get_haxe_type_string!"); | |
1428 | break; // This should never happen! | |
1429 | } | |
1430 | } else { | |
1431 | throw std::runtime_error( | |
1432 | "Unknown thrift type \"" + type->get_name() | |
1433 | + "\" passed to t_haxe_generator::get_haxe_type_string!"); // This should never happen! | |
1434 | } | |
1435 | } | |
1436 | ||
1437 | void t_haxe_generator::generate_field_value_meta_data(std::ostream& out, t_type* type) { | |
1438 | out << endl; | |
1439 | indent_up(); | |
1440 | indent_up(); | |
1441 | if (type->is_struct()) { | |
1442 | indent(out) << "new StructMetaData(TType.STRUCT, " << type_name(type); | |
1443 | } else if (type->is_container()) { | |
1444 | if (type->is_list()) { | |
1445 | indent(out) << "new ListMetaData(TType.LIST, "; | |
1446 | t_type* elem_type = ((t_list*)type)->get_elem_type(); | |
1447 | generate_field_value_meta_data(out, elem_type); | |
1448 | } else if (type->is_set()) { | |
1449 | indent(out) << "new SetMetaData(TType.SET, "; | |
1450 | t_type* elem_type = ((t_list*)type)->get_elem_type(); | |
1451 | generate_field_value_meta_data(out, elem_type); | |
1452 | } else { // map | |
1453 | indent(out) << "new MapMetaData(TType.MAP, "; | |
1454 | t_type* key_type = ((t_map*)type)->get_key_type(); | |
1455 | t_type* val_type = ((t_map*)type)->get_val_type(); | |
1456 | generate_field_value_meta_data(out, key_type); | |
1457 | out << ", "; | |
1458 | generate_field_value_meta_data(out, val_type); | |
1459 | } | |
1460 | } else { | |
1461 | indent(out) << "new FieldValueMetaData(" << get_haxe_type_string(type); | |
1462 | } | |
1463 | out << ")"; | |
1464 | indent_down(); | |
1465 | indent_down(); | |
1466 | } | |
1467 | ||
1468 | /** | |
1469 | * Generates a thrift service. In C++, this comprises an entirely separate | |
1470 | * header and source file. The header file defines the methods and includes | |
1471 | * the data types defined in the main header file, and the implementation | |
1472 | * file contains implementations of the basic printer and default interfaces. | |
1473 | * | |
1474 | * @param tservice The service definition | |
1475 | */ | |
1476 | void t_haxe_generator::generate_service(t_service* tservice) { | |
1477 | // Make interface file | |
1478 | string f_service_name = package_dir_ + "/" + get_cap_name(service_name_) + ".hx"; | |
1479 | f_service_.open(f_service_name.c_str()); | |
1480 | ||
1481 | f_service_ << autogen_comment() << haxe_package() << ";" << endl; | |
1482 | ||
1483 | f_service_ << endl << haxe_type_imports() << haxe_thrift_imports() | |
1484 | << haxe_thrift_gen_imports(tservice); | |
1485 | ||
1486 | if (tservice->get_extends() != NULL) { | |
1487 | t_type* parent = tservice->get_extends(); | |
1488 | string parent_namespace = parent->get_program()->get_namespace("haxe"); | |
1489 | if (!parent_namespace.empty() && parent_namespace != package_name_) { | |
1490 | f_service_ << "import " << type_name(parent) << ";" << endl; | |
1491 | } | |
1492 | } | |
1493 | ||
1494 | f_service_ << endl; | |
1495 | ||
1496 | generate_service_interface(tservice); | |
1497 | ||
1498 | f_service_.close(); | |
1499 | ||
1500 | // Now make the implementation/client file | |
1501 | f_service_name = package_dir_ + "/" + get_cap_name(service_name_) + "Impl.hx"; | |
1502 | f_service_.open(f_service_name.c_str()); | |
1503 | ||
1504 | f_service_ << autogen_comment() << haxe_package() << ";" << endl << endl << haxe_type_imports() | |
1505 | << haxe_thrift_imports() << haxe_thrift_gen_imports(tservice) << endl; | |
1506 | ||
1507 | if (tservice->get_extends() != NULL) { | |
1508 | t_type* parent = tservice->get_extends(); | |
1509 | string parent_namespace = parent->get_program()->get_namespace("haxe"); | |
1510 | if (!parent_namespace.empty() && parent_namespace != package_name_) { | |
1511 | f_service_ << "import " << type_name(parent) << "Impl;" << endl; | |
1512 | } | |
1513 | } | |
1514 | ||
1515 | f_service_ << endl; | |
1516 | ||
1517 | generate_service_client(tservice); | |
1518 | ||
1519 | f_service_.close(); | |
1520 | ||
1521 | // Now make the helper class files | |
1522 | generate_service_helpers(tservice); | |
1523 | ||
1524 | // Now make the processor/server file | |
1525 | f_service_name = package_dir_ + "/" + get_cap_name(service_name_) + "Processor.hx"; | |
1526 | f_service_.open(f_service_name.c_str()); | |
1527 | ||
1528 | f_service_ << autogen_comment() << haxe_package() << ";" << endl << endl << haxe_type_imports() | |
1529 | << haxe_thrift_imports() << haxe_thrift_gen_imports(tservice) << endl; | |
1530 | ||
1531 | if (!package_name_.empty()) { | |
1532 | f_service_ << "import " << package_name_ << ".*;" << endl; | |
1533 | f_service_ << "import " << package_name_ << "." << get_cap_name(service_name_).c_str() | |
1534 | << "Impl;" << endl; | |
1535 | f_service_ << endl; | |
1536 | } | |
1537 | ||
1538 | generate_service_server(tservice); | |
1539 | ||
1540 | f_service_.close(); | |
1541 | } | |
1542 | ||
1543 | /** | |
1544 | * Generates the code snippet for the onSuccess callbacks | |
1545 | * | |
1546 | * @param tfunction The service function to generate code for. | |
1547 | */ | |
1548 | string t_haxe_generator::generate_service_method_onsuccess(t_function* tfunction, | |
1549 | bool as_type, | |
1550 | bool omit_name) { | |
1551 | if (tfunction->is_oneway()) { | |
1552 | return ""; | |
1553 | } | |
1554 | ||
1555 | string name = ""; | |
1556 | if (!omit_name) { | |
1557 | name = "onSuccess"; | |
1558 | if (as_type) { | |
1559 | name += " : "; | |
1560 | } | |
1561 | } | |
1562 | ||
1563 | if (tfunction->get_returntype()->is_void()) { | |
1564 | if (as_type) { | |
1565 | return name + "Void->Void = null"; | |
1566 | } else { | |
1567 | return name + "() : Void"; | |
1568 | } | |
1569 | } | |
1570 | ||
1571 | if (as_type) { | |
1572 | return name + type_name(tfunction->get_returntype()) + "->Void = null"; | |
1573 | } else { | |
1574 | return name + "( retval : " + type_name(tfunction->get_returntype()) + ")"; | |
1575 | } | |
1576 | } | |
1577 | ||
1578 | /** | |
1579 | * Generates a service method header | |
1580 | * | |
1581 | * @param tfunction The service function to generate code for. | |
1582 | */ | |
1583 | void t_haxe_generator::generate_service_method_signature(t_function* tfunction, bool is_interface) { | |
1584 | if (callbacks_) { | |
1585 | generate_service_method_signature_callback(tfunction, is_interface); | |
1586 | } else { | |
1587 | generate_service_method_signature_normal(tfunction, is_interface); | |
1588 | } | |
1589 | } | |
1590 | ||
1591 | /** | |
1592 | * Generates a service method header in "normal" style | |
1593 | * | |
1594 | * @param tfunction The service function to generate code for. | |
1595 | */ | |
1596 | void t_haxe_generator::generate_service_method_signature_normal(t_function* tfunction, | |
1597 | bool is_interface) { | |
1598 | if (is_interface) { | |
1599 | indent(f_service_) << function_signature_normal(tfunction) << ";" << endl << endl; | |
1600 | } else { | |
1601 | indent(f_service_) << "public " << function_signature_normal(tfunction) << " {" << endl; | |
1602 | } | |
1603 | } | |
1604 | ||
1605 | /** | |
1606 | * Generates a service method header in "callback" style | |
1607 | * | |
1608 | * @param tfunction The service function to generate code for. | |
1609 | */ | |
1610 | void t_haxe_generator::generate_service_method_signature_callback(t_function* tfunction, | |
1611 | bool is_interface) { | |
1612 | if (!tfunction->is_oneway()) { | |
1613 | std::string on_success_impl = generate_service_method_onsuccess(tfunction, false, false); | |
1614 | indent(f_service_) << "// function onError(Dynamic) : Void;" << endl; | |
1615 | indent(f_service_) << "// function " << on_success_impl.c_str() << ";" << endl; | |
1616 | } | |
1617 | ||
1618 | if (is_interface) { | |
1619 | indent(f_service_) << function_signature_callback(tfunction) << ";" << endl << endl; | |
1620 | } else { | |
1621 | indent(f_service_) << "public " << function_signature_callback(tfunction) << " {" << endl; | |
1622 | } | |
1623 | } | |
1624 | ||
1625 | /** | |
1626 | * Generates a service interface definition. | |
1627 | * | |
1628 | * @param tservice The service to generate a header definition for | |
1629 | */ | |
1630 | void t_haxe_generator::generate_service_interface(t_service* tservice) { | |
1631 | string extends_iface = ""; | |
1632 | if (tservice->get_extends() != NULL) { | |
1633 | extends_iface = " extends " + tservice->get_extends()->get_name(); | |
1634 | } | |
1635 | ||
1636 | generate_haxe_doc(f_service_, tservice); | |
1637 | // generate_rtti_decoration(f_service_); - not yet, because of | |
1638 | // https://github.com/HaxeFoundation/haxe/issues/3626 | |
1639 | generate_macro_decoration(f_service_); | |
1640 | f_service_ << indent() << "interface " << get_cap_name(service_name_) << extends_iface << " {" | |
1641 | << endl << endl; | |
1642 | indent_up(); | |
1643 | vector<t_function*> functions = tservice->get_functions(); | |
1644 | vector<t_function*>::iterator f_iter; | |
1645 | for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { | |
1646 | generate_haxe_doc(f_service_, *f_iter); | |
1647 | generate_service_method_signature(*f_iter, true); | |
1648 | } | |
1649 | indent_down(); | |
1650 | f_service_ << indent() << "}" << endl << endl; | |
1651 | } | |
1652 | ||
1653 | /** | |
1654 | * Generates structs for all the service args and return types | |
1655 | * | |
1656 | * @param tservice The service | |
1657 | */ | |
1658 | void t_haxe_generator::generate_service_helpers(t_service* tservice) { | |
1659 | f_service_ << endl << endl; | |
1660 | vector<t_function*> functions = tservice->get_functions(); | |
1661 | vector<t_function*>::iterator f_iter; | |
1662 | for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { | |
1663 | t_struct* ts = (*f_iter)->get_arglist(); | |
1664 | generate_haxe_struct(ts, false); | |
1665 | generate_function_helpers(*f_iter); | |
1666 | } | |
1667 | } | |
1668 | ||
1669 | /** | |
1670 | * Generates a service client definition. | |
1671 | * | |
1672 | * @param tservice The service to generate a server for. | |
1673 | */ | |
1674 | void t_haxe_generator::generate_service_client(t_service* tservice) { | |
1675 | string extends = ""; | |
1676 | string extends_client = ""; | |
1677 | if (tservice->get_extends() != NULL) { | |
1678 | extends = get_cap_name(tservice->get_extends()->get_name()); | |
1679 | extends_client = " extends " + extends + "Impl"; | |
1680 | } | |
1681 | ||
1682 | generate_rtti_decoration(f_service_); | |
1683 | // build macro is inherited from interface | |
1684 | indent(f_service_) << "class " << get_cap_name(service_name_) << "Impl" << extends_client | |
1685 | << " implements " << get_cap_name(service_name_) << " {" << endl << endl; | |
1686 | indent_up(); | |
1687 | ||
1688 | indent(f_service_) << "public function new( iprot : TProtocol, oprot : TProtocol = null)" << endl; | |
1689 | scope_up(f_service_); | |
1690 | if (extends.empty()) { | |
1691 | f_service_ << indent() << "iprot_ = iprot;" << endl; | |
1692 | f_service_ << indent() << "if (oprot == null) {" << endl; | |
1693 | indent_up(); | |
1694 | f_service_ << indent() << "oprot_ = iprot;" << endl; | |
1695 | indent_down(); | |
1696 | f_service_ << indent() << "} else {" << endl; | |
1697 | indent_up(); | |
1698 | f_service_ << indent() << "oprot_ = oprot;" << endl; | |
1699 | indent_down(); | |
1700 | f_service_ << indent() << "}" << endl; | |
1701 | } else { | |
1702 | f_service_ << indent() << "super(iprot, oprot);" << endl; | |
1703 | } | |
1704 | scope_down(f_service_); | |
1705 | f_service_ << endl; | |
1706 | ||
1707 | if (extends.empty()) { | |
1708 | f_service_ << indent() << "private var iprot_ : TProtocol;" << endl << indent() | |
1709 | << "private var oprot_ : TProtocol;" << endl << indent() | |
1710 | << "private var seqid_ : Int;" << endl << endl; | |
1711 | ||
1712 | indent(f_service_) << "public function getInputProtocol() : TProtocol" << endl; | |
1713 | scope_up(f_service_); | |
1714 | indent(f_service_) << "return this.iprot_;" << endl; | |
1715 | scope_down(f_service_); | |
1716 | f_service_ << endl; | |
1717 | ||
1718 | indent(f_service_) << "public function getOutputProtocol() : TProtocol" << endl; | |
1719 | scope_up(f_service_); | |
1720 | indent(f_service_) << "return this.oprot_;" << endl; | |
1721 | scope_down(f_service_); | |
1722 | f_service_ << endl; | |
1723 | } | |
1724 | ||
1725 | // Generate client method implementations | |
1726 | vector<t_function*> functions = tservice->get_functions(); | |
1727 | vector<t_function*>::const_iterator f_iter; | |
1728 | for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { | |
1729 | string funname = (*f_iter)->get_name(); | |
1730 | ||
1731 | // Open function | |
1732 | generate_service_method_signature(*f_iter, false); | |
1733 | ||
1734 | indent_up(); | |
1735 | ||
1736 | // Get the struct of function call params | |
1737 | t_struct* arg_struct = (*f_iter)->get_arglist(); | |
1738 | ||
1739 | string argsname = get_cap_name((*f_iter)->get_name() + "_args"); | |
1740 | vector<t_field*>::const_iterator fld_iter; | |
1741 | const vector<t_field*>& fields = arg_struct->get_members(); | |
1742 | ||
1743 | // Serialize the request | |
1744 | string calltype = (*f_iter)->is_oneway() ? "ONEWAY" : "CALL"; | |
1745 | f_service_ << indent() << "oprot_.writeMessageBegin(new TMessage(\"" << funname | |
1746 | << "\", TMessageType." << calltype << ", seqid_));" << endl << indent() | |
1747 | << "var args : " << argsname << " = new " << argsname << "();" << endl; | |
1748 | ||
1749 | for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) { | |
1750 | f_service_ << indent() << "args." << (*fld_iter)->get_name() << " = " | |
1751 | << (*fld_iter)->get_name() << ";" << endl; | |
1752 | } | |
1753 | ||
1754 | f_service_ << indent() << "args.write(oprot_);" << endl << indent() | |
1755 | << "oprot_.writeMessageEnd();" << endl; | |
1756 | ||
1757 | if (!((*f_iter)->is_oneway() || (*f_iter)->get_returntype()->is_void())) { | |
1758 | f_service_ << indent() << "var retval : " << type_name((*f_iter)->get_returntype()) << ";" | |
1759 | << endl; | |
1760 | } | |
1761 | ||
1762 | if ((*f_iter)->is_oneway()) { | |
1763 | f_service_ << indent() << "oprot_.getTransport().flush();" << endl; | |
1764 | } else { | |
1765 | indent(f_service_) << "oprot_.getTransport().flush(function(error:Dynamic) : Void {" << endl; | |
1766 | indent_up(); | |
1767 | if (callbacks_) { | |
1768 | indent(f_service_) << "try {" << endl; | |
1769 | indent_up(); | |
1770 | } | |
1771 | string resultname = get_cap_name((*f_iter)->get_name() + "_result"); | |
1772 | indent(f_service_) << "if (error != null) {" << endl; | |
1773 | indent_up(); | |
1774 | if (callbacks_) { | |
1775 | indent(f_service_) << "if (onError != null) onError(error);" << endl; | |
1776 | indent(f_service_) << "return;" << endl; | |
1777 | } else { | |
1778 | indent(f_service_) << "throw error;" << endl; | |
1779 | } | |
1780 | indent_down(); | |
1781 | indent(f_service_) << "}" << endl; | |
1782 | indent(f_service_) << "var msg : TMessage = iprot_.readMessageBegin();" << endl; | |
1783 | indent(f_service_) << "if (msg.type == TMessageType.EXCEPTION) {" << endl; | |
1784 | indent_up(); | |
1785 | indent(f_service_) << "var x = TApplicationException.read(iprot_);" << endl; | |
1786 | indent(f_service_) << "iprot_.readMessageEnd();" << endl; | |
1787 | if (callbacks_) { | |
1788 | indent(f_service_) << "if (onError != null) onError(x);" << endl; | |
1789 | indent(f_service_) << "return;" << endl; | |
1790 | } else { | |
1791 | indent(f_service_) << "throw x;" << endl; | |
1792 | } | |
1793 | indent_down(); | |
1794 | indent(f_service_) << "}" << endl; | |
1795 | indent(f_service_) << "var result : " << resultname << " = new " << resultname << "();" | |
1796 | << endl; | |
1797 | indent(f_service_) << "result.read(iprot_);" << endl; | |
1798 | indent(f_service_) << "iprot_.readMessageEnd();" << endl; | |
1799 | ||
1800 | // Careful, only return _result if not a void function | |
1801 | if (!(*f_iter)->get_returntype()->is_void()) { | |
1802 | indent(f_service_) << "if (result." << generate_isset_check("success") << ") {" << endl; | |
1803 | indent_up(); | |
1804 | if (callbacks_) { | |
1805 | indent(f_service_) << "if (onSuccess != null) onSuccess(result.success);" << endl; | |
1806 | indent(f_service_) << "return;" << endl; | |
1807 | } else { | |
1808 | indent(f_service_) << "retval = result.success;" << endl; | |
1809 | indent(f_service_) << "return;" << endl; | |
1810 | } | |
1811 | indent_down(); | |
1812 | indent(f_service_) << "}" << endl; | |
1813 | } | |
1814 | ||
1815 | t_struct* xs = (*f_iter)->get_xceptions(); | |
1816 | const std::vector<t_field*>& xceptions = xs->get_members(); | |
1817 | vector<t_field*>::const_iterator x_iter; | |
1818 | for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { | |
1819 | indent(f_service_) << "if (result." << (*x_iter)->get_name() << " != null) {" << endl; | |
1820 | indent_up(); | |
1821 | if (callbacks_) { | |
1822 | indent(f_service_) << "if (onError != null) onError(result." << (*x_iter)->get_name() | |
1823 | << ");" << endl; | |
1824 | indent(f_service_) << "return;" << endl; | |
1825 | } else { | |
1826 | indent(f_service_) << "throw result." << (*x_iter)->get_name() << ";" << endl; | |
1827 | } | |
1828 | indent_down(); | |
1829 | indent(f_service_) << "}" << endl; | |
1830 | } | |
1831 | ||
1832 | // If you get here it's an exception, unless a void function | |
1833 | if ((*f_iter)->get_returntype()->is_void()) { | |
1834 | if (callbacks_) { | |
1835 | indent(f_service_) << "if (onSuccess != null) onSuccess();" << endl; | |
1836 | } | |
1837 | indent(f_service_) << "return;" << endl; | |
1838 | } else { | |
1839 | if (callbacks_) { | |
1840 | indent(f_service_) << "if (onError != null)" << endl; | |
1841 | indent_up(); | |
1842 | indent(f_service_) | |
1843 | << "onError( new TApplicationException(TApplicationException.MISSING_RESULT," << endl; | |
1844 | indent(f_service_) << " \"" << (*f_iter)->get_name() | |
1845 | << " failed: unknown result\"));" << endl; | |
1846 | indent_down(); | |
1847 | } else { | |
1848 | indent(f_service_) | |
1849 | << "throw new TApplicationException(TApplicationException.MISSING_RESULT," << endl; | |
1850 | indent(f_service_) << " \"" << (*f_iter)->get_name() | |
1851 | << " failed: unknown result\");" << endl; | |
1852 | } | |
1853 | } | |
1854 | ||
1855 | if (callbacks_) { | |
1856 | indent_down(); | |
1857 | indent(f_service_) << "} catch( e : TException) {" << endl; | |
1858 | indent_up(); | |
1859 | indent(f_service_) << "if (onError != null) onError(e);" << endl; | |
1860 | indent_down(); | |
1861 | indent(f_service_) << "}" << endl; | |
1862 | } | |
1863 | ||
1864 | indent_down(); | |
1865 | indent(f_service_) << "});" << endl; | |
1866 | } | |
1867 | ||
1868 | if (!((*f_iter)->is_oneway() || (*f_iter)->get_returntype()->is_void())) { | |
1869 | f_service_ << indent() << "return retval;" << endl; | |
1870 | } | |
1871 | ||
1872 | // Close function | |
1873 | scope_down(f_service_); | |
1874 | f_service_ << endl; | |
1875 | } | |
1876 | ||
1877 | indent_down(); | |
1878 | indent(f_service_) << "}" << endl; | |
1879 | } | |
1880 | ||
1881 | /** | |
1882 | * Generates a service server definition. | |
1883 | * | |
1884 | * @param tservice The service to generate a server for. | |
1885 | */ | |
1886 | void t_haxe_generator::generate_service_server(t_service* tservice) { | |
1887 | // Generate the dispatch methods | |
1888 | vector<t_function*> functions = tservice->get_functions(); | |
1889 | vector<t_function*>::iterator f_iter; | |
1890 | ||
1891 | // Extends stuff | |
1892 | string extends = ""; | |
1893 | string extends_processor = ""; | |
1894 | if (tservice->get_extends() != NULL) { | |
1895 | extends = get_cap_name(type_name(tservice->get_extends())); | |
1896 | extends_processor = " extends " + extends + "Processor"; | |
1897 | } | |
1898 | ||
1899 | // Generate the header portion | |
1900 | generate_rtti_decoration(f_service_); | |
1901 | generate_macro_decoration(f_service_); | |
1902 | indent(f_service_) << "class " << get_cap_name(service_name_) << "Processor" << extends_processor | |
1903 | << " implements TProcessor {" << endl << endl; | |
1904 | indent_up(); | |
1905 | ||
1906 | f_service_ << indent() << "private var " << get_cap_name(service_name_) | |
1907 | << "_iface_ : " << get_cap_name(service_name_) << ";" << endl; | |
1908 | ||
1909 | if (extends.empty()) { | |
1910 | f_service_ << indent() | |
1911 | << "private var PROCESS_MAP = new StringMap< Int->TProtocol->TProtocol->Void >();" | |
1912 | << endl; | |
1913 | } | |
1914 | ||
1915 | f_service_ << endl; | |
1916 | ||
1917 | indent(f_service_) << "public function new( iface : " << get_cap_name(service_name_) << ")" | |
1918 | << endl; | |
1919 | scope_up(f_service_); | |
1920 | if (!extends.empty()) { | |
1921 | f_service_ << indent() << "super(iface);" << endl; | |
1922 | } | |
1923 | f_service_ << indent() << get_cap_name(service_name_) << "_iface_ = iface;" << endl; | |
1924 | ||
1925 | for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { | |
1926 | f_service_ << indent() << "PROCESS_MAP.set(\"" << (*f_iter)->get_name() << "\", " | |
1927 | << (*f_iter)->get_name() << "());" << endl; | |
1928 | } | |
1929 | ||
1930 | scope_down(f_service_); | |
1931 | f_service_ << endl; | |
1932 | ||
1933 | // Generate the server implementation | |
1934 | string override = ""; | |
1935 | if (tservice->get_extends() != NULL) { | |
1936 | override = "override "; | |
1937 | } | |
1938 | indent(f_service_) << override | |
1939 | << "public function process( iprot : TProtocol, oprot : TProtocol) : Bool" | |
1940 | << endl; | |
1941 | scope_up(f_service_); | |
1942 | ||
1943 | f_service_ << indent() << "var msg : TMessage = iprot.readMessageBegin();" << endl; | |
1944 | ||
1945 | // TODO(mcslee): validate message, was the seqid etc. legit? | |
1946 | // AS- If all method is oneway: | |
1947 | // do you have an oprot? | |
1948 | // do you you need nullcheck? | |
1949 | f_service_ | |
1950 | << indent() << "var fn = PROCESS_MAP.get(msg.name);" << endl << indent() | |
1951 | << "if (fn == null) {" << endl << indent() << " TProtocolUtil.skip(iprot, TType.STRUCT);" | |
1952 | << endl << indent() << " iprot.readMessageEnd();" << endl << indent() | |
1953 | << " var x = new TApplicationException(TApplicationException.UNKNOWN_METHOD, \"Invalid " | |
1954 | "method name: '\"+msg.name+\"'\");" << endl << indent() | |
1955 | << " oprot.writeMessageBegin(new TMessage(msg.name, TMessageType.EXCEPTION, msg.seqid));" | |
1956 | << endl << indent() << " x.write(oprot);" << endl << indent() << " oprot.writeMessageEnd();" | |
1957 | << endl << indent() << " oprot.getTransport().flush();" << endl << indent() | |
1958 | << " return true;" << endl << indent() << "}" << endl << indent() | |
1959 | << "fn( msg.seqid, iprot, oprot);" << endl; | |
1960 | ||
1961 | f_service_ << indent() << "return true;" << endl; | |
1962 | ||
1963 | scope_down(f_service_); | |
1964 | f_service_ << endl; | |
1965 | ||
1966 | // Generate the process subfunctions | |
1967 | for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { | |
1968 | generate_process_function(tservice, *f_iter); | |
1969 | } | |
1970 | ||
1971 | indent_down(); | |
1972 | indent(f_service_) << "}" << endl << endl; | |
1973 | } | |
1974 | ||
1975 | /** | |
1976 | * Generates a struct and helpers for a function. | |
1977 | * | |
1978 | * @param tfunction The function | |
1979 | */ | |
1980 | void t_haxe_generator::generate_function_helpers(t_function* tfunction) { | |
1981 | if (tfunction->is_oneway()) { | |
1982 | return; | |
1983 | } | |
1984 | ||
1985 | string resultname = get_cap_name(tfunction->get_name() + "_result"); | |
1986 | t_struct result(program_, resultname); | |
1987 | t_field success(tfunction->get_returntype(), "success", 0); | |
1988 | if (!tfunction->get_returntype()->is_void()) { | |
1989 | result.append(&success); | |
1990 | } | |
1991 | ||
1992 | t_struct* xs = tfunction->get_xceptions(); | |
1993 | const vector<t_field*>& fields = xs->get_members(); | |
1994 | vector<t_field*>::const_iterator f_iter; | |
1995 | for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { | |
1996 | result.append(*f_iter); | |
1997 | } | |
1998 | ||
1999 | generate_haxe_struct(&result, false, true); | |
2000 | } | |
2001 | ||
2002 | /** | |
2003 | * Generates a process function definition. | |
2004 | * | |
2005 | * @param tfunction The function to write a dispatcher for | |
2006 | */ | |
2007 | void t_haxe_generator::generate_process_function(t_service* tservice, t_function* tfunction) { | |
2008 | (void)tservice; | |
2009 | // Open class | |
2010 | indent(f_service_) << "private function " << tfunction->get_name() | |
2011 | << "() : Int->TProtocol->TProtocol->Void {" << endl; | |
2012 | indent_up(); | |
2013 | ||
2014 | // Open function | |
2015 | indent(f_service_) << "return function( seqid : Int, iprot : TProtocol, oprot : TProtocol) : Void" | |
2016 | << endl; | |
2017 | scope_up(f_service_); | |
2018 | ||
2019 | string argsname = get_cap_name(tfunction->get_name() + "_args"); | |
2020 | string resultname = get_cap_name(tfunction->get_name() + "_result"); | |
2021 | ||
2022 | f_service_ << indent() << "var args : " << argsname << " = new " << argsname << "();" << endl | |
2023 | << indent() << "args.read(iprot);" << endl << indent() << "iprot.readMessageEnd();" | |
2024 | << endl; | |
2025 | ||
2026 | t_struct* xs = tfunction->get_xceptions(); | |
2027 | const std::vector<t_field*>& xceptions = xs->get_members(); | |
2028 | vector<t_field*>::const_iterator x_iter; | |
2029 | ||
2030 | // Declare result for non oneway function | |
2031 | if (!tfunction->is_oneway()) { | |
2032 | f_service_ << indent() << "var result : " << resultname << " = new " << resultname << "();" | |
2033 | << endl; | |
2034 | } | |
2035 | ||
2036 | // Try block for any function to catch (defined or undefined) exceptions | |
2037 | f_service_ << indent() << "try {" << endl; | |
2038 | indent_up(); | |
2039 | ||
2040 | if (callbacks_) { | |
2041 | // callback function style onError/onSuccess | |
2042 | ||
2043 | // Generate the function call | |
2044 | t_struct* arg_struct = tfunction->get_arglist(); | |
2045 | const std::vector<t_field*>& fields = arg_struct->get_members(); | |
2046 | vector<t_field*>::const_iterator f_iter; | |
2047 | ||
2048 | f_service_ << indent(); | |
2049 | f_service_ << get_cap_name(service_name_) << "_iface_." << tfunction->get_name() << "("; | |
2050 | bool first = true; | |
2051 | for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { | |
2052 | if (first) { | |
2053 | first = false; | |
2054 | } else { | |
2055 | f_service_ << ", "; | |
2056 | } | |
2057 | f_service_ << "args." << (*f_iter)->get_name(); | |
2058 | } | |
2059 | ||
2060 | if (tfunction->is_oneway()) { | |
2061 | f_service_ << ");" << endl; | |
2062 | } else { | |
2063 | if (first) { | |
2064 | first = false; | |
2065 | } else { | |
2066 | f_service_ << ", "; | |
2067 | } | |
2068 | string on_success = generate_service_method_onsuccess(tfunction, false, true); | |
2069 | indent_up(); | |
2070 | f_service_ << endl; | |
2071 | indent(f_service_) << "null, // errors are thrown by the handler" << endl; | |
2072 | if (tfunction->get_returntype()->is_void()) { | |
2073 | indent(f_service_) << "null); // no retval" << endl; | |
2074 | } else { | |
2075 | indent(f_service_) << "function" << on_success.c_str() << " {" << endl; | |
2076 | if (!tfunction->get_returntype()->is_void()) { | |
2077 | indent_up(); | |
2078 | indent(f_service_) << "result.success = retval;" << endl; | |
2079 | indent_down(); | |
2080 | } | |
2081 | indent(f_service_) << "});" << endl; | |
2082 | } | |
2083 | indent_down(); | |
2084 | } | |
2085 | ||
2086 | } else { | |
2087 | // normal function():result style | |
2088 | ||
2089 | // Generate the function call | |
2090 | t_struct* arg_struct = tfunction->get_arglist(); | |
2091 | const std::vector<t_field*>& fields = arg_struct->get_members(); | |
2092 | vector<t_field*>::const_iterator f_iter; | |
2093 | ||
2094 | f_service_ << indent(); | |
2095 | if (!(tfunction->is_oneway() || tfunction->get_returntype()->is_void())) { | |
2096 | f_service_ << "result.success = "; | |
2097 | } | |
2098 | f_service_ << get_cap_name(service_name_) << "_iface_." << tfunction->get_name() << "("; | |
2099 | bool first = true; | |
2100 | for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { | |
2101 | if (first) { | |
2102 | first = false; | |
2103 | } else { | |
2104 | f_service_ << ", "; | |
2105 | } | |
2106 | f_service_ << "args." << (*f_iter)->get_name(); | |
2107 | } | |
2108 | f_service_ << ");" << endl; | |
2109 | } | |
2110 | ||
2111 | indent_down(); | |
2112 | f_service_ << indent() << "}"; | |
2113 | if (!tfunction->is_oneway()) { | |
2114 | // catch exceptions defined in the IDL | |
2115 | for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { | |
2116 | f_service_ << " catch (" << (*x_iter)->get_name() << ":" | |
2117 | << get_cap_name(type_name((*x_iter)->get_type(), false, false)) << ") {" << endl; | |
2118 | if (!tfunction->is_oneway()) { | |
2119 | indent_up(); | |
2120 | f_service_ << indent() << "result." << (*x_iter)->get_name() << " = " | |
2121 | << (*x_iter)->get_name() << ";" << endl; | |
2122 | indent_down(); | |
2123 | f_service_ << indent() << "}"; | |
2124 | } else { | |
2125 | f_service_ << "}"; | |
2126 | } | |
2127 | } | |
2128 | } | |
2129 | ||
2130 | // always catch all exceptions to prevent from service denial | |
2131 | f_service_ << " catch (th : Dynamic) {" << endl; | |
2132 | indent_up(); | |
2133 | indent(f_service_) << "trace(\"Internal error processing " << tfunction->get_name() << "\", th);" | |
2134 | << endl; | |
2135 | if (!tfunction->is_oneway()) { | |
2136 | indent(f_service_) << "var x = new TApplicationException(TApplicationException.INTERNAL_ERROR, " | |
2137 | "\"Internal error processing " << tfunction->get_name() << "\");" << endl; | |
2138 | indent(f_service_) << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() | |
2139 | << "\", TMessageType.EXCEPTION, seqid));" << endl; | |
2140 | indent(f_service_) << "x.write(oprot);" << endl; | |
2141 | indent(f_service_) << "oprot.writeMessageEnd();" << endl; | |
2142 | indent(f_service_) << "oprot.getTransport().flush();" << endl; | |
2143 | } | |
2144 | indent(f_service_) << "return;" << endl; | |
2145 | indent_down(); | |
2146 | f_service_ << indent() << "}" << endl; | |
2147 | ||
2148 | // Shortcut out here for oneway functions | |
2149 | if (tfunction->is_oneway()) { | |
2150 | f_service_ << indent() << "return;" << endl; | |
2151 | scope_down(f_service_); | |
2152 | ||
2153 | // Close class | |
2154 | indent_down(); | |
2155 | f_service_ << indent() << "}" << endl << endl; | |
2156 | return; | |
2157 | } | |
2158 | ||
2159 | f_service_ << indent() << "oprot.writeMessageBegin(new TMessage(\"" << tfunction->get_name() | |
2160 | << "\", TMessageType.REPLY, seqid));" << endl << indent() << "result.write(oprot);" | |
2161 | << endl << indent() << "oprot.writeMessageEnd();" << endl << indent() | |
2162 | << "oprot.getTransport().flush();" << endl; | |
2163 | ||
2164 | // Close function | |
2165 | scope_down(f_service_); | |
2166 | f_service_ << endl; | |
2167 | ||
2168 | // Close class | |
2169 | indent_down(); | |
2170 | f_service_ << indent() << "}" << endl << endl; | |
2171 | } | |
2172 | ||
2173 | /** | |
2174 | * Deserializes a field of any type. | |
2175 | * | |
2176 | * @param tfield The field | |
2177 | * @param prefix The variable name or container for this field | |
2178 | */ | |
2179 | void t_haxe_generator::generate_deserialize_field(ostream& out, t_field* tfield, string prefix) { | |
2180 | t_type* type = get_true_type(tfield->get_type()); | |
2181 | ||
2182 | if (type->is_void()) { | |
2183 | throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); | |
2184 | } | |
2185 | ||
2186 | string name = prefix + tfield->get_name(); | |
2187 | ||
2188 | if (type->is_struct() || type->is_xception()) { | |
2189 | generate_deserialize_struct(out, (t_struct*)type, name); | |
2190 | } else if (type->is_container()) { | |
2191 | generate_deserialize_container(out, type, name); | |
2192 | } else if (type->is_base_type() || type->is_enum()) { | |
2193 | ||
2194 | indent(out) << name << " = iprot."; | |
2195 | ||
2196 | if (type->is_base_type()) { | |
2197 | t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); | |
2198 | switch (tbase) { | |
2199 | case t_base_type::TYPE_VOID: | |
2200 | throw "compiler error: cannot serialize void field in a struct: " + name; | |
2201 | break; | |
2202 | case t_base_type::TYPE_STRING: | |
2203 | if (type->is_binary()) { | |
2204 | out << "readBinary();"; | |
2205 | } else { | |
2206 | out << "readString();"; | |
2207 | } | |
2208 | break; | |
2209 | case t_base_type::TYPE_BOOL: | |
2210 | out << "readBool();"; | |
2211 | break; | |
2212 | case t_base_type::TYPE_I8: | |
2213 | out << "readByte();"; | |
2214 | break; | |
2215 | case t_base_type::TYPE_I16: | |
2216 | out << "readI16();"; | |
2217 | break; | |
2218 | case t_base_type::TYPE_I32: | |
2219 | out << "readI32();"; | |
2220 | break; | |
2221 | case t_base_type::TYPE_I64: | |
2222 | out << "readI64();"; | |
2223 | break; | |
2224 | case t_base_type::TYPE_DOUBLE: | |
2225 | out << "readDouble();"; | |
2226 | break; | |
2227 | default: | |
2228 | throw "compiler error: no Haxe name for base type " + t_base_type::t_base_name(tbase); | |
2229 | } | |
2230 | } else if (type->is_enum()) { | |
2231 | out << "readI32();"; | |
2232 | } | |
2233 | out << endl; | |
2234 | } else { | |
2235 | printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n", | |
2236 | tfield->get_name().c_str(), | |
2237 | type_name(type).c_str()); | |
2238 | } | |
2239 | } | |
2240 | ||
2241 | /** | |
2242 | * Generates an unserializer for a struct, invokes read() | |
2243 | */ | |
2244 | void t_haxe_generator::generate_deserialize_struct(ostream& out, | |
2245 | t_struct* tstruct, | |
2246 | string prefix) { | |
2247 | out << indent() << prefix << " = new " << get_cap_name(type_name(tstruct)) << "();" << endl | |
2248 | << indent() << prefix << ".read(iprot);" << endl; | |
2249 | } | |
2250 | ||
2251 | /** | |
2252 | * Deserializes a container by reading its size and then iterating | |
2253 | */ | |
2254 | void t_haxe_generator::generate_deserialize_container(ostream& out, t_type* ttype, string prefix) { | |
2255 | scope_up(out); | |
2256 | ||
2257 | string obj; | |
2258 | ||
2259 | if (ttype->is_map()) { | |
2260 | obj = tmp("_map"); | |
2261 | } else if (ttype->is_set()) { | |
2262 | obj = tmp("_set"); | |
2263 | } else if (ttype->is_list()) { | |
2264 | obj = tmp("_list"); | |
2265 | } | |
2266 | ||
2267 | // Declare variables, read header | |
2268 | if (ttype->is_map()) { | |
2269 | indent(out) << "var " << obj << " = iprot.readMapBegin();" << endl; | |
2270 | } else if (ttype->is_set()) { | |
2271 | indent(out) << "var " << obj << " = iprot.readSetBegin();" << endl; | |
2272 | } else if (ttype->is_list()) { | |
2273 | indent(out) << "var " << obj << " = iprot.readListBegin();" << endl; | |
2274 | } | |
2275 | ||
2276 | indent(out) << prefix << " = new " << type_name(ttype, false, true) | |
2277 | // size the collection correctly | |
2278 | << "(" | |
2279 | << ");" << endl; | |
2280 | ||
2281 | // For loop iterates over elements | |
2282 | string i = tmp("_i"); | |
2283 | indent(out) << "for( " << i << " in 0 ... " << obj << ".size)" << endl; | |
2284 | ||
2285 | scope_up(out); | |
2286 | ||
2287 | if (ttype->is_map()) { | |
2288 | generate_deserialize_map_element(out, (t_map*)ttype, prefix); | |
2289 | } else if (ttype->is_set()) { | |
2290 | generate_deserialize_set_element(out, (t_set*)ttype, prefix); | |
2291 | } else if (ttype->is_list()) { | |
2292 | generate_deserialize_list_element(out, (t_list*)ttype, prefix); | |
2293 | } | |
2294 | ||
2295 | scope_down(out); | |
2296 | ||
2297 | // Read container end | |
2298 | if (ttype->is_map()) { | |
2299 | indent(out) << "iprot.readMapEnd();" << endl; | |
2300 | } else if (ttype->is_set()) { | |
2301 | indent(out) << "iprot.readSetEnd();" << endl; | |
2302 | } else if (ttype->is_list()) { | |
2303 | indent(out) << "iprot.readListEnd();" << endl; | |
2304 | } | |
2305 | ||
2306 | scope_down(out); | |
2307 | } | |
2308 | ||
2309 | /** | |
2310 | * Generates code to deserialize a map | |
2311 | */ | |
2312 | void t_haxe_generator::generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix) { | |
2313 | string key = tmp("_key"); | |
2314 | string val = tmp("_val"); | |
2315 | t_field fkey(tmap->get_key_type(), key); | |
2316 | t_field fval(tmap->get_val_type(), val); | |
2317 | ||
2318 | indent(out) << declare_field(&fkey) << endl; | |
2319 | indent(out) << declare_field(&fval) << endl; | |
2320 | ||
2321 | generate_deserialize_field(out, &fkey); | |
2322 | generate_deserialize_field(out, &fval); | |
2323 | ||
2324 | indent(out) << prefix << ".set( " << key << ", " << val << ");" << endl; | |
2325 | } | |
2326 | ||
2327 | /** | |
2328 | * Deserializes a set element | |
2329 | */ | |
2330 | void t_haxe_generator::generate_deserialize_set_element(ostream& out, t_set* tset, string prefix) { | |
2331 | string elem = tmp("_elem"); | |
2332 | t_field felem(tset->get_elem_type(), elem); | |
2333 | ||
2334 | indent(out) << declare_field(&felem) << endl; | |
2335 | ||
2336 | generate_deserialize_field(out, &felem); | |
2337 | ||
2338 | indent(out) << prefix << ".add(" << elem << ");" << endl; | |
2339 | } | |
2340 | ||
2341 | /** | |
2342 | * Deserializes a list element | |
2343 | */ | |
2344 | void t_haxe_generator::generate_deserialize_list_element(ostream& out, | |
2345 | t_list* tlist, | |
2346 | string prefix) { | |
2347 | string elem = tmp("_elem"); | |
2348 | t_field felem(tlist->get_elem_type(), elem); | |
2349 | ||
2350 | indent(out) << declare_field(&felem) << endl; | |
2351 | ||
2352 | generate_deserialize_field(out, &felem); | |
2353 | ||
2354 | indent(out) << prefix << ".add(" << elem << ");" << endl; | |
2355 | } | |
2356 | ||
2357 | /** | |
2358 | * Serializes a field of any type. | |
2359 | * | |
2360 | * @param tfield The field to serialize | |
2361 | * @param prefix Name to prepend to field name | |
2362 | */ | |
2363 | void t_haxe_generator::generate_serialize_field(ostream& out, t_field* tfield, string prefix) { | |
2364 | t_type* type = get_true_type(tfield->get_type()); | |
2365 | ||
2366 | // Do nothing for void types | |
2367 | if (type->is_void()) { | |
2368 | throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + prefix + tfield->get_name(); | |
2369 | } | |
2370 | ||
2371 | if (type->is_struct() || type->is_xception()) { | |
2372 | generate_serialize_struct(out, (t_struct*)type, prefix + tfield->get_name()); | |
2373 | } else if (type->is_container()) { | |
2374 | generate_serialize_container(out, type, prefix + tfield->get_name()); | |
2375 | } else if (type->is_base_type() || type->is_enum()) { | |
2376 | ||
2377 | string name = prefix + tfield->get_name(); | |
2378 | indent(out) << "oprot."; | |
2379 | ||
2380 | if (type->is_base_type()) { | |
2381 | t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); | |
2382 | switch (tbase) { | |
2383 | case t_base_type::TYPE_VOID: | |
2384 | throw "compiler error: cannot serialize void field in a struct: " + name; | |
2385 | break; | |
2386 | case t_base_type::TYPE_STRING: | |
2387 | if (type->is_binary()) { | |
2388 | out << "writeBinary(" << name << ");"; | |
2389 | } else { | |
2390 | out << "writeString(" << name << ");"; | |
2391 | } | |
2392 | break; | |
2393 | case t_base_type::TYPE_BOOL: | |
2394 | out << "writeBool(" << name << ");"; | |
2395 | break; | |
2396 | case t_base_type::TYPE_I8: | |
2397 | out << "writeByte(" << name << ");"; | |
2398 | break; | |
2399 | case t_base_type::TYPE_I16: | |
2400 | out << "writeI16(" << name << ");"; | |
2401 | break; | |
2402 | case t_base_type::TYPE_I32: | |
2403 | out << "writeI32(" << name << ");"; | |
2404 | break; | |
2405 | case t_base_type::TYPE_I64: | |
2406 | out << "writeI64(" << name << ");"; | |
2407 | break; | |
2408 | case t_base_type::TYPE_DOUBLE: | |
2409 | out << "writeDouble(" << name << ");"; | |
2410 | break; | |
2411 | default: | |
2412 | throw "compiler error: no Haxe name for base type " + t_base_type::t_base_name(tbase); | |
2413 | } | |
2414 | } else if (type->is_enum()) { | |
2415 | out << "writeI32(" << name << ");"; | |
2416 | } | |
2417 | out << endl; | |
2418 | } else { | |
2419 | printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n", | |
2420 | prefix.c_str(), | |
2421 | tfield->get_name().c_str(), | |
2422 | type_name(type).c_str()); | |
2423 | } | |
2424 | } | |
2425 | ||
2426 | /** | |
2427 | * Serializes all the members of a struct. | |
2428 | * | |
2429 | * @param tstruct The struct to serialize | |
2430 | * @param prefix String prefix to attach to all fields | |
2431 | */ | |
2432 | void t_haxe_generator::generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix) { | |
2433 | (void)tstruct; | |
2434 | out << indent() << prefix << ".write(oprot);" << endl; | |
2435 | } | |
2436 | ||
2437 | /** | |
2438 | * Serializes a container by writing its size then the elements. | |
2439 | * | |
2440 | * @param ttype The type of container | |
2441 | * @param prefix String prefix for fields | |
2442 | */ | |
2443 | void t_haxe_generator::generate_serialize_container(ostream& out, t_type* ttype, string prefix) { | |
2444 | scope_up(out); | |
2445 | ||
2446 | if (ttype->is_map()) { | |
2447 | string iter = tmp("_key"); | |
2448 | string counter = tmp("_sizeCounter"); | |
2449 | indent(out) << "var " << counter << " : Int = 0;" << endl; | |
2450 | indent(out) << "for( " << iter << " in " << prefix << ") {" << endl; | |
2451 | indent(out) << " " << counter << +"++;" << endl; | |
2452 | indent(out) << "}" << endl; | |
2453 | ||
2454 | indent(out) << "oprot.writeMapBegin(new TMap(" << type_to_enum(((t_map*)ttype)->get_key_type()) | |
2455 | << ", " << type_to_enum(((t_map*)ttype)->get_val_type()) << ", " << counter << "));" | |
2456 | << endl; | |
2457 | } else if (ttype->is_set()) { | |
2458 | indent(out) << "oprot.writeSetBegin(new TSet(" << type_to_enum(((t_set*)ttype)->get_elem_type()) | |
2459 | << ", " << prefix << ".size));" << endl; | |
2460 | } else if (ttype->is_list()) { | |
2461 | indent(out) << "oprot.writeListBegin(new TList(" | |
2462 | << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " << prefix << ".length));" | |
2463 | << endl; | |
2464 | } | |
2465 | ||
2466 | string iter = tmp("elem"); | |
2467 | if (ttype->is_map()) { | |
2468 | indent(out) << "for( " << iter << " in " << prefix << ".keys())" << endl; | |
2469 | } else if (ttype->is_set()) { | |
2470 | indent(out) << "for( " << iter << " in " << prefix << ".toArray())" << endl; | |
2471 | } else if (ttype->is_list()) { | |
2472 | indent(out) << "for( " << iter << " in " << prefix << ")" << endl; | |
2473 | } | |
2474 | ||
2475 | scope_up(out); | |
2476 | ||
2477 | if (ttype->is_map()) { | |
2478 | generate_serialize_map_element(out, (t_map*)ttype, iter, prefix); | |
2479 | } else if (ttype->is_set()) { | |
2480 | generate_serialize_set_element(out, (t_set*)ttype, iter); | |
2481 | } else if (ttype->is_list()) { | |
2482 | generate_serialize_list_element(out, (t_list*)ttype, iter); | |
2483 | } | |
2484 | ||
2485 | scope_down(out); | |
2486 | ||
2487 | if (ttype->is_map()) { | |
2488 | indent(out) << "oprot.writeMapEnd();" << endl; | |
2489 | } else if (ttype->is_set()) { | |
2490 | indent(out) << "oprot.writeSetEnd();" << endl; | |
2491 | } else if (ttype->is_list()) { | |
2492 | indent(out) << "oprot.writeListEnd();" << endl; | |
2493 | } | |
2494 | ||
2495 | scope_down(out); | |
2496 | } | |
2497 | ||
2498 | /** | |
2499 | * Serializes the members of a map. | |
2500 | */ | |
2501 | void t_haxe_generator::generate_serialize_map_element(ostream& out, | |
2502 | t_map* tmap, | |
2503 | string iter, | |
2504 | string map) { | |
2505 | t_field kfield(tmap->get_key_type(), iter); | |
2506 | generate_serialize_field(out, &kfield, ""); | |
2507 | t_field vfield(tmap->get_val_type(), map + ".get(" + iter + ")"); | |
2508 | generate_serialize_field(out, &vfield, ""); | |
2509 | } | |
2510 | ||
2511 | /** | |
2512 | * Serializes the members of a set. | |
2513 | */ | |
2514 | void t_haxe_generator::generate_serialize_set_element(ostream& out, t_set* tset, string iter) { | |
2515 | t_field efield(tset->get_elem_type(), iter); | |
2516 | generate_serialize_field(out, &efield, ""); | |
2517 | } | |
2518 | ||
2519 | /** | |
2520 | * Serializes the members of a list. | |
2521 | */ | |
2522 | void t_haxe_generator::generate_serialize_list_element(ostream& out, t_list* tlist, string iter) { | |
2523 | t_field efield(tlist->get_elem_type(), iter); | |
2524 | generate_serialize_field(out, &efield, ""); | |
2525 | } | |
2526 | ||
2527 | /** | |
2528 | * Returns a haxe type name | |
2529 | * | |
2530 | * @param ttype The type | |
2531 | * @param container Is the type going inside a container? | |
2532 | * @return haxe type name, i.e. HashMap<Key,Value> | |
2533 | */ | |
2534 | string t_haxe_generator::type_name(t_type* ttype, bool in_container, bool in_init) { | |
2535 | (void)in_init; | |
2536 | ||
2537 | // typedefs are just resolved to their real type | |
2538 | ttype = get_true_type(ttype); | |
2539 | string prefix; | |
2540 | ||
2541 | if (ttype->is_base_type()) { | |
2542 | return base_type_name((t_base_type*)ttype, in_container); | |
2543 | } | |
2544 | ||
2545 | if (ttype->is_enum()) { | |
2546 | return "Int"; | |
2547 | } | |
2548 | ||
2549 | if (ttype->is_map()) { | |
2550 | t_type* tkey = get_true_type(((t_map*)ttype)->get_key_type()); | |
2551 | t_type* tval = get_true_type(((t_map*)ttype)->get_val_type()); | |
2552 | if (tkey->is_base_type()) { | |
2553 | t_base_type::t_base tbase = ((t_base_type*)tkey)->get_base(); | |
2554 | switch (tbase) { | |
2555 | case t_base_type::TYPE_STRING: | |
2556 | if (!(tkey->is_binary())) { | |
2557 | return "StringMap< " + type_name(tval) + ">"; | |
2558 | } | |
2559 | break; // default to ObjectMap<> | |
2560 | case t_base_type::TYPE_I8: | |
2561 | case t_base_type::TYPE_I16: | |
2562 | case t_base_type::TYPE_I32: | |
2563 | return "IntMap< " + type_name(tval) + ">"; | |
2564 | case t_base_type::TYPE_I64: | |
2565 | return "Int64Map< " + type_name(tval) + ">"; | |
2566 | default: | |
2567 | break; // default to ObjectMap<> | |
2568 | } | |
2569 | } | |
2570 | if (tkey->is_enum()) { | |
2571 | return "IntMap< " + type_name(tval) + ">"; | |
2572 | } | |
2573 | return "ObjectMap< " + type_name(tkey) + ", " + type_name(tval) + ">"; | |
2574 | } | |
2575 | ||
2576 | if (ttype->is_set()) { | |
2577 | t_type* tkey = get_true_type(((t_set*)ttype)->get_elem_type()); | |
2578 | if (tkey->is_base_type()) { | |
2579 | t_base_type::t_base tbase = ((t_base_type*)tkey)->get_base(); | |
2580 | switch (tbase) { | |
2581 | case t_base_type::TYPE_STRING: | |
2582 | if (!(tkey->is_binary())) { | |
2583 | return "StringSet"; | |
2584 | } | |
2585 | break; // default to ObjectSet | |
2586 | case t_base_type::TYPE_I8: | |
2587 | case t_base_type::TYPE_I16: | |
2588 | case t_base_type::TYPE_I32: | |
2589 | return "IntSet"; | |
2590 | case t_base_type::TYPE_I64: | |
2591 | return "Int64Set"; | |
2592 | default: | |
2593 | break; // default to ObjectSet | |
2594 | } | |
2595 | } | |
2596 | if (tkey->is_enum()) { | |
2597 | return "IntSet"; | |
2598 | } | |
2599 | return "ObjectSet< " + type_name(tkey) + ">"; | |
2600 | } | |
2601 | ||
2602 | if (ttype->is_list()) { | |
2603 | t_type* telm = ((t_list*)ttype)->get_elem_type(); | |
2604 | return "List< " + type_name(telm) + ">"; | |
2605 | } | |
2606 | ||
2607 | // Check for namespacing | |
2608 | t_program* program = ttype->get_program(); | |
2609 | if (program != NULL && program != program_) { | |
2610 | string package = program->get_namespace("haxe"); | |
2611 | if (!package.empty()) { | |
2612 | return package + "." + ttype->get_name(); | |
2613 | } | |
2614 | } | |
2615 | ||
2616 | return ttype->get_name(); | |
2617 | } | |
2618 | ||
2619 | /** | |
2620 | * Returns the haxe type that corresponds to the thrift type. | |
2621 | * | |
2622 | * @param tbase The base type | |
2623 | * @param container Is it going in a haxe container? | |
2624 | */ | |
2625 | string t_haxe_generator::base_type_name(t_base_type* type, bool in_container) { | |
2626 | (void)in_container; | |
2627 | t_base_type::t_base tbase = type->get_base(); | |
2628 | ||
2629 | switch (tbase) { | |
2630 | case t_base_type::TYPE_VOID: | |
2631 | return "Void"; | |
2632 | case t_base_type::TYPE_STRING: | |
2633 | if (type->is_binary()) { | |
2634 | return "haxe.io.Bytes"; | |
2635 | } else { | |
2636 | return "String"; | |
2637 | } | |
2638 | case t_base_type::TYPE_BOOL: | |
2639 | return "Bool"; | |
2640 | case t_base_type::TYPE_I8: | |
2641 | case t_base_type::TYPE_I16: | |
2642 | case t_base_type::TYPE_I32: | |
2643 | return "haxe.Int32"; | |
2644 | case t_base_type::TYPE_I64: | |
2645 | return "haxe.Int64"; | |
2646 | case t_base_type::TYPE_DOUBLE: | |
2647 | return "Float"; | |
2648 | default: | |
2649 | throw "compiler error: no Haxe name for base type " + t_base_type::t_base_name(tbase); | |
2650 | } | |
2651 | } | |
2652 | ||
2653 | /** | |
2654 | * Declares a field, which may include initialization as necessary. | |
2655 | * | |
2656 | * @param ttype The type | |
2657 | */ | |
2658 | string t_haxe_generator::declare_field(t_field* tfield, bool init) { | |
2659 | // TODO(mcslee): do we ever need to initialize the field? | |
2660 | string result = "var " + tfield->get_name() + " : " + type_name(tfield->get_type()); | |
2661 | if (init) { | |
2662 | t_type* ttype = get_true_type(tfield->get_type()); | |
2663 | if (ttype->is_base_type() && tfield->get_value() != NULL) { | |
2664 | std::ofstream dummy; | |
2665 | result += " = " + render_const_value(dummy, tfield->get_name(), ttype, tfield->get_value()); | |
2666 | } else if (ttype->is_base_type()) { | |
2667 | t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); | |
2668 | switch (tbase) { | |
2669 | case t_base_type::TYPE_VOID: | |
2670 | throw "NO T_VOID CONSTRUCT"; | |
2671 | case t_base_type::TYPE_STRING: | |
2672 | result += " = null"; | |
2673 | break; | |
2674 | case t_base_type::TYPE_BOOL: | |
2675 | result += " = false"; | |
2676 | break; | |
2677 | case t_base_type::TYPE_I8: | |
2678 | case t_base_type::TYPE_I16: | |
2679 | case t_base_type::TYPE_I32: | |
2680 | case t_base_type::TYPE_I64: | |
2681 | result += " = 0"; | |
2682 | break; | |
2683 | case t_base_type::TYPE_DOUBLE: | |
2684 | result += " = (double)0"; | |
2685 | break; | |
2686 | } | |
2687 | ||
2688 | } else if (ttype->is_enum()) { | |
2689 | result += " = 0"; | |
2690 | } else if (ttype->is_container()) { | |
2691 | result += " = new " + type_name(ttype, false, true) + "()"; | |
2692 | } else { | |
2693 | result += " = new " + type_name(ttype, false, true) + "()"; | |
2694 | } | |
2695 | } | |
2696 | return result + ";"; | |
2697 | } | |
2698 | ||
2699 | /** | |
2700 | * Renders a function signature of the form 'type name(args)' | |
2701 | * | |
2702 | * @param tfunction Function definition | |
2703 | * @return String of rendered function definition | |
2704 | */ | |
2705 | string t_haxe_generator::function_signature_callback(t_function* tfunction) { | |
2706 | std::string on_error_success = "onError : Dynamic->Void = null, " | |
2707 | + generate_service_method_onsuccess(tfunction, true, false); | |
2708 | ||
2709 | std::string arguments = argument_list(tfunction->get_arglist()); | |
2710 | if (!tfunction->is_oneway()) { | |
2711 | if (arguments != "") { | |
2712 | arguments += ", "; | |
2713 | } | |
2714 | arguments += on_error_success; //"onError : Function, onSuccess : Function"; | |
2715 | } | |
2716 | ||
2717 | std::string result = "function " + tfunction->get_name() + "(" + arguments + ") : Void"; | |
2718 | return result; | |
2719 | } | |
2720 | ||
2721 | /** | |
2722 | * Renders a function signature of the form 'type name(args)' | |
2723 | * | |
2724 | * @param tfunction Function definition | |
2725 | * @return String of rendered function definition | |
2726 | */ | |
2727 | string t_haxe_generator::function_signature_normal(t_function* tfunction) { | |
2728 | std::string arguments = argument_list(tfunction->get_arglist()); | |
2729 | ||
2730 | std::string resulttype; | |
2731 | if (tfunction->is_oneway() || tfunction->get_returntype()->is_void()) { | |
2732 | resulttype = "Void"; | |
2733 | } else { | |
2734 | resulttype = type_name(tfunction->get_returntype()); | |
2735 | } | |
2736 | ||
2737 | std::string result = "function " + tfunction->get_name() + "(" + arguments + ") : " + resulttype; | |
2738 | return result; | |
2739 | } | |
2740 | ||
2741 | /** | |
2742 | * Renders a comma separated field list, with type names | |
2743 | */ | |
2744 | string t_haxe_generator::argument_list(t_struct* tstruct) { | |
2745 | string result = ""; | |
2746 | ||
2747 | const vector<t_field*>& fields = tstruct->get_members(); | |
2748 | vector<t_field*>::const_iterator f_iter; | |
2749 | bool first = true; | |
2750 | for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { | |
2751 | if (first) { | |
2752 | first = false; | |
2753 | } else { | |
2754 | result += ", "; | |
2755 | } | |
2756 | result += (*f_iter)->get_name() + " : " + type_name((*f_iter)->get_type()); | |
2757 | } | |
2758 | return result; | |
2759 | } | |
2760 | ||
2761 | /** | |
2762 | * Converts the parse type to a C++ enum string for the given type. | |
2763 | */ | |
2764 | string t_haxe_generator::type_to_enum(t_type* type) { | |
2765 | type = get_true_type(type); | |
2766 | ||
2767 | if (type->is_base_type()) { | |
2768 | t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); | |
2769 | switch (tbase) { | |
2770 | case t_base_type::TYPE_VOID: | |
2771 | throw "NO T_VOID CONSTRUCT"; | |
2772 | case t_base_type::TYPE_STRING: | |
2773 | return "TType.STRING"; | |
2774 | case t_base_type::TYPE_BOOL: | |
2775 | return "TType.BOOL"; | |
2776 | case t_base_type::TYPE_I8: | |
2777 | return "TType.BYTE"; | |
2778 | case t_base_type::TYPE_I16: | |
2779 | return "TType.I16"; | |
2780 | case t_base_type::TYPE_I32: | |
2781 | return "TType.I32"; | |
2782 | case t_base_type::TYPE_I64: | |
2783 | return "TType.I64"; | |
2784 | case t_base_type::TYPE_DOUBLE: | |
2785 | return "TType.DOUBLE"; | |
2786 | } | |
2787 | } else if (type->is_enum()) { | |
2788 | return "TType.I32"; | |
2789 | } else if (type->is_struct() || type->is_xception()) { | |
2790 | return "TType.STRUCT"; | |
2791 | } else if (type->is_map()) { | |
2792 | return "TType.MAP"; | |
2793 | } else if (type->is_set()) { | |
2794 | return "TType.SET"; | |
2795 | } else if (type->is_list()) { | |
2796 | return "TType.LIST"; | |
2797 | } | |
2798 | ||
2799 | throw "INVALID TYPE IN type_to_enum: " + type->get_name(); | |
2800 | } | |
2801 | ||
2802 | /** | |
2803 | * Haxe class names must start with uppercase letter, but Haxe namespaces must not. | |
2804 | */ | |
2805 | std::string t_haxe_generator::get_cap_name(std::string name) { | |
2806 | if (name.length() == 0) { | |
2807 | return name; | |
2808 | } | |
2809 | ||
2810 | // test.for.Generic< data.Type, or.the.Like> and handle it recursively | |
2811 | size_t generic_first = name.find('<'); | |
2812 | size_t generic_last = name.rfind('>'); | |
2813 | if ((generic_first != std::string::npos) && (generic_last != std::string::npos)) { | |
2814 | string outer_type = name.substr(0, generic_first); | |
2815 | string inner_types = name.substr(generic_first + 1, generic_last - generic_first - 1); | |
2816 | ||
2817 | string new_inner = ""; | |
2818 | size_t comma_start = 0; | |
2819 | while (comma_start < inner_types.length()) { | |
2820 | size_t comma_pos = comma_start; | |
2821 | int nested = 0; | |
2822 | ||
2823 | while (comma_pos < inner_types.length()) { | |
2824 | bool found = false; | |
2825 | switch (inner_types[comma_pos]) { | |
2826 | case '<': | |
2827 | ++nested; | |
2828 | break; | |
2829 | case '>': | |
2830 | --nested; | |
2831 | break; | |
2832 | case ',': | |
2833 | found = (nested == 0); | |
2834 | break; | |
2835 | } | |
2836 | if (found) { | |
2837 | break; | |
2838 | } | |
2839 | ++comma_pos; | |
2840 | } | |
2841 | ||
2842 | if (new_inner.length() > 0) { | |
2843 | new_inner += ","; | |
2844 | } | |
2845 | ||
2846 | string inner = inner_types.substr(comma_start, comma_pos - comma_start); | |
2847 | new_inner += get_cap_name(inner); | |
2848 | comma_start = ++comma_pos; | |
2849 | } | |
2850 | ||
2851 | return get_cap_name(outer_type) + "<" + new_inner + ">"; | |
2852 | } | |
2853 | ||
2854 | // package name | |
2855 | size_t index = name.find_first_not_of(" \n\r\t"); | |
2856 | if (index < name.length()) { | |
2857 | name[index] = tolower(name[index]); | |
2858 | index = name.find('.'); | |
2859 | while (index != std::string::npos) { | |
2860 | if (++index < name.length()) { | |
2861 | name[index] = tolower(name[index]); | |
2862 | } | |
2863 | index = name.find('.', index); | |
2864 | } | |
2865 | } | |
2866 | ||
2867 | // class name | |
2868 | index = name.rfind('.'); | |
2869 | if (index != std::string::npos) { | |
2870 | ++index; | |
2871 | } else { | |
2872 | index = name.find_first_not_of(" \n\r\t"); | |
2873 | } | |
2874 | ||
2875 | if (index < name.length()) { | |
2876 | name[index] = toupper(name[index]); | |
2877 | } | |
2878 | ||
2879 | return name; | |
2880 | } | |
2881 | ||
2882 | string t_haxe_generator::constant_name(string name) { | |
2883 | string constant_name; | |
2884 | ||
2885 | bool is_first = true; | |
2886 | bool was_previous_char_upper = false; | |
2887 | for (char character : name) { | |
2888 | bool is_upper = isupper(character); | |
2889 | ||
2890 | if (is_upper && !is_first && !was_previous_char_upper) { | |
2891 | constant_name += '_'; | |
2892 | } | |
2893 | constant_name += toupper(character); | |
2894 | ||
2895 | is_first = false; | |
2896 | was_previous_char_upper = is_upper; | |
2897 | } | |
2898 | ||
2899 | return constant_name; | |
2900 | } | |
2901 | ||
2902 | /** | |
2903 | * Enables RTTI for a class or interface | |
2904 | */ | |
2905 | void t_haxe_generator::generate_rtti_decoration(ostream& out) { | |
2906 | if (rtti_) { | |
2907 | out << "@:rtti" << endl; | |
2908 | } | |
2909 | } | |
2910 | ||
2911 | /** | |
2912 | * Adds build macros to a class or interface | |
2913 | */ | |
2914 | void t_haxe_generator::generate_macro_decoration(ostream& out) { | |
2915 | if (!buildmacro_.empty()) { | |
2916 | out << "#if ! macro" << endl; | |
2917 | out << "@:build( " << buildmacro_ << ")" << endl; // current class/interface | |
2918 | out << "@:autoBuild( " << buildmacro_ << ")" << endl; // inherited classes/interfaces | |
2919 | out << "#end" << endl; | |
2920 | } | |
2921 | } | |
2922 | ||
2923 | /** | |
2924 | * Emits a haxeDoc comment if the provided object has a doc in Thrift | |
2925 | */ | |
2926 | void t_haxe_generator::generate_haxe_doc(ostream& out, t_doc* tdoc) { | |
2927 | if (tdoc->has_doc()) { | |
2928 | generate_docstring_comment(out, "/**\n", " * ", tdoc->get_doc(), " */\n"); | |
2929 | } | |
2930 | } | |
2931 | ||
2932 | /** | |
2933 | * Emits a haxeDoc comment if the provided function object has a doc in Thrift | |
2934 | */ | |
2935 | void t_haxe_generator::generate_haxe_doc(ostream& out, t_function* tfunction) { | |
2936 | if (tfunction->has_doc()) { | |
2937 | stringstream ss; | |
2938 | ss << tfunction->get_doc(); | |
2939 | const vector<t_field*>& fields = tfunction->get_arglist()->get_members(); | |
2940 | vector<t_field*>::const_iterator p_iter; | |
2941 | for (p_iter = fields.begin(); p_iter != fields.end(); ++p_iter) { | |
2942 | t_field* p = *p_iter; | |
2943 | ss << "\n@param " << p->get_name(); | |
2944 | if (p->has_doc()) { | |
2945 | ss << " " << p->get_doc(); | |
2946 | } | |
2947 | } | |
2948 | generate_docstring_comment(out, "/**\n", " * ", ss.str(), " */\n"); | |
2949 | } | |
2950 | } | |
2951 | ||
2952 | std::string t_haxe_generator::generate_isset_check(t_field* field) { | |
2953 | return generate_isset_check(field->get_name()); | |
2954 | } | |
2955 | ||
2956 | std::string t_haxe_generator::generate_isset_check(std::string field_name) { | |
2957 | return "is" + get_cap_name("set") + get_cap_name(field_name) + "()"; | |
2958 | } | |
2959 | ||
2960 | void t_haxe_generator::generate_isset_set(ostream& out, t_field* field) { | |
2961 | if (!type_can_be_null(field->get_type())) { | |
2962 | indent(out) << "this.__isset_" << field->get_name() << " = true;" << endl; | |
2963 | } | |
2964 | } | |
2965 | ||
2966 | std::string t_haxe_generator::get_enum_class_name(t_type* type) { | |
2967 | string package = ""; | |
2968 | t_program* program = type->get_program(); | |
2969 | if (program != NULL /*&& program != program_*/) { | |
2970 | package = program->get_namespace("haxe") + "."; | |
2971 | } | |
2972 | return package + type->get_name(); | |
2973 | } | |
2974 | ||
2975 | THRIFT_REGISTER_GENERATOR( | |
2976 | haxe, | |
2977 | "Haxe", | |
2978 | " callbacks Use onError()/onSuccess() callbacks for service methods (like AS3)\n" | |
2979 | " rtti Enable @:rtti for generated classes and interfaces\n" | |
2980 | " buildmacro=my.macros.Class.method(args)\n" | |
2981 | " Add @:build macro calls to generated classes and interfaces\n") |