]> git.proxmox.com Git - ceph.git/blame - ceph/src/jaegertracing/thrift/compiler/cpp/src/thrift/generate/t_haxe_generator.cc
buildsys: switch source download to quincy
[ceph.git] / ceph / src / jaegertracing / thrift / compiler / cpp / src / thrift / generate / t_haxe_generator.cc
CommitLineData
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
33using std::map;
34using std::ostream;
35using std::ostringstream;
36using std::string;
37using std::stringstream;
38using std::vector;
39
40static const string endl = "\n"; // avoid ostream << std::endl flushes
41
42/**
43 * Haxe code generator.
44 *
45 */
46class t_haxe_generator : public t_oop_generator {
47public:
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
222private:
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 */
242void 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 */
280string 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 */
292string 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 */
304string 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 */
314string 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 */
339string 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 */
367void 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 */
377void 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 */
386void 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 */
445void 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
478void 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
602string 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 */
658void 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 */
667void 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 */
676void 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 */
706void 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 */
820void 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)
913void 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 */
964void 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 */
1034void 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
1090void 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
1102void 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
1119void 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
1177void 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 */
1213void 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 */
1275void 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 */
1349void 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 */
1386std::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
1437void 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 */
1476void 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 */
1548string 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 */
1583void 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 */
1596void 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 */
1610void 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 */
1630void 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 */
1658void 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 */
1674void 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 */
1886void 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 */
1980void 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 */
2007void 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 */
2179void 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 */
2244void 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 */
2254void 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 */
2312void 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 */
2330void 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 */
2344void 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 */
2363void 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 */
2432void 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 */
2443void 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 */
2501void 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 */
2514void 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 */
2522void 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 */
2534string 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 */
2625string 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 */
2658string 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 */
2705string 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 */
2727string 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 */
2744string 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 */
2764string 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 */
2805std::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
2882string 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 */
2905void 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 */
2914void 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 */
2926void 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 */
2935void 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
2952std::string t_haxe_generator::generate_isset_check(t_field* field) {
2953 return generate_isset_check(field->get_name());
2954}
2955
2956std::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
2960void 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
2966std::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
2975THRIFT_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")