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