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