r1317@opsdev009 (orig r70384): mcslee | 2007-11-16 16:32:36 -0800
[amiethrift.git] / compiler / cpp / src / generate / t_cocoa_generator.cc
blob6cb86a2d62c9dafd6da91ff1cae4008a0976b619
1 // Copyright (c) 2006- Facebook
2 // Distributed under the Thrift Software License
3 //
4 // See accompanying file LICENSE or visit the Thrift site at:
5 // http://developers.facebook.com/thrift/
7 #include <stdlib.h>
8 #include <sys/stat.h>
9 #include <sstream>
10 #include "t_cocoa_generator.h"
11 using namespace std;
13 /**
14 * Prepares for file generation by opening up the necessary file output
15 * streams.
17 void t_cocoa_generator::init_generator() {
18 // Make output directory
19 mkdir(get_out_dir().c_str(), S_IRWXU | S_IRWXG | S_IRWXO);
20 cocoa_prefix_ = program_->get_cocoa_prefix();
22 // we have a .h header file...
23 string f_header_name = program_name_+".h";
24 string f_header_fullname = get_out_dir()+f_header_name;
25 f_header_.open(f_header_fullname.c_str());
27 f_header_ <<
28 autogen_comment() <<
29 endl;
31 f_header_ <<
32 cocoa_imports() <<
33 cocoa_thrift_imports();
35 // ...and a .m implementation file
36 string f_impl_name = get_out_dir()+program_name_+".m";
37 f_impl_.open(f_impl_name.c_str());
39 f_impl_ <<
40 autogen_comment() <<
41 endl;
43 f_impl_ <<
44 cocoa_imports() <<
45 cocoa_thrift_imports() <<
46 "#import \"" << f_header_name << "\"" << endl <<
47 endl;
51 /**
52 * Prints standard Cocoa imports
54 * @return List of imports for Cocoa libraries
56 string t_cocoa_generator::cocoa_imports() {
57 return
58 string() +
59 "#import <Cocoa/Cocoa.h>\n" +
60 "\n";
63 /**
64 * Prints thrift runtime imports
66 * @return List of imports necessary for thrift runtime
68 string t_cocoa_generator::cocoa_thrift_imports() {
69 string result = string() +
70 "#import <TProtocol.h>\n" +
71 "#import <TApplicationException.h>\n" +
72 "#import <TProtocolUtil.h>\n" +
73 "\n";
75 // Include other Thrift includes
76 const vector<t_program*>& includes = program_->get_includes();
77 for (size_t i = 0; i < includes.size(); ++i) {
78 result += "#import \"" + includes[i]->get_name() + ".h\"" + "\n";
80 result += "\n";
82 return result;
86 /**
87 * Finish up generation.
89 void t_cocoa_generator::close_generator()
91 // stick our constants declarations at the end of the header file
92 // since they refer to things we are defining.
93 f_header_ << constants_declarations_;
96 /**
97 * Generates a typedef. This is just a simple 1-liner in objective-c
99 * @param ttypedef The type definition
101 void t_cocoa_generator::generate_typedef(t_typedef* ttypedef) {
102 f_header_ <<
103 indent() << "typedef " << type_name(ttypedef->get_type()) << " " << cocoa_prefix_ << ttypedef->get_symbolic() << ";" << endl <<
104 endl;
108 * Generates code for an enumerated type. In Objective-C, this is
109 * essentially the same as the thrift definition itself, using the
110 * enum keyword in Objective-C. For namespace purposes, the name of
111 * the enum plus an underscore is prefixed onto each element.
113 * @param tenum The enumeration
115 void t_cocoa_generator::generate_enum(t_enum* tenum) {
116 f_header_ <<
117 indent() << "enum " << cocoa_prefix_ << tenum->get_name() << " {" << endl;
118 indent_up();
120 vector<t_enum_value*> constants = tenum->get_constants();
121 vector<t_enum_value*>::iterator c_iter;
122 bool first = true;
123 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
124 if (first) {
125 first = false;
126 } else {
127 f_header_ <<
128 "," << endl;
130 f_header_ <<
131 indent() << tenum->get_name() << "_" << (*c_iter)->get_name();
132 if ((*c_iter)->has_value()) {
133 f_header_ <<
134 " = " << (*c_iter)->get_value();
138 indent_down();
139 f_header_ <<
140 endl <<
141 "};" << endl <<
142 endl;
146 * Generates a class that holds all the constants. Primitive values
147 * could have been placed outside this class, but I just put
148 * everything in for consistency.
150 void t_cocoa_generator::generate_consts(std::vector<t_const*> consts) {
151 std::ostringstream const_interface;
152 string constants_class_name = cocoa_prefix_ + program_name_ + "Constants";
154 const_interface << "@interface " << constants_class_name << " ";
155 scope_up(const_interface);
156 scope_down(const_interface);
158 // getter method for each constant defined.
159 vector<t_const*>::iterator c_iter;
160 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
161 string name = (*c_iter)->get_name();
162 t_type* type = (*c_iter)->get_type();
163 const_interface <<
164 "+ (" << type_name(type) << ") " << name << ";" << endl;
167 const_interface << "@end";
169 // this gets spit into the header file in ::close_generator
170 constants_declarations_ = const_interface.str();
172 // static variables in the .m hold all constant values
173 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
174 string name = (*c_iter)->get_name();
175 t_type* type = (*c_iter)->get_type();
176 f_impl_ <<
177 "static " << type_name(type) << " " << cocoa_prefix_ << name;
178 if (!type->is_container() && !type->is_struct()) {
179 f_impl_ << " = " << render_const_value(name, type, (*c_iter)->get_value());
181 f_impl_ << ";" << endl;
183 f_impl_ << endl;
185 f_impl_ << "@implementation " << constants_class_name << endl;
187 // initialize complex constants when the class is loaded
188 f_impl_ << "+ (void) initialize ";
189 scope_up(f_impl_);
191 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
192 if ((*c_iter)->get_type()->is_container() ||
193 (*c_iter)->get_type()->is_struct()) {
194 string name = (*c_iter)->get_name();
195 f_impl_ << indent() << name << " = " << render_const_value(name,
196 (*c_iter)->get_type(),
197 (*c_iter)->get_value());
198 f_impl_ << ";" << endl;
201 scope_down(f_impl_);
203 // getter method for each constant
204 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
205 string name = (*c_iter)->get_name();
206 t_type* type = (*c_iter)->get_type();
207 f_impl_ <<
208 "+ (" << type_name(type) << ") " << name;
209 scope_up(f_impl_);
210 indent(f_impl_) << "return " << name << ";" << endl;
211 scope_down(f_impl_);
214 f_impl_ << "@end" << endl << endl;
219 * Generates a struct definition for a thrift data type. This is a class
220 * with protected data members, read(), write(), and getters and setters.
222 * @param tstruct The struct definition
224 void t_cocoa_generator::generate_struct(t_struct* tstruct) {
225 generate_cocoa_struct_interface(f_header_, tstruct, false);
226 generate_cocoa_struct_implementation(f_impl_, tstruct, false);
230 * Exceptions are structs, but they inherit from NSException
232 * @param tstruct The struct definition
234 void t_cocoa_generator::generate_xception(t_struct* txception) {
235 generate_cocoa_struct_interface(f_header_, txception, true);
236 generate_cocoa_struct_implementation(f_impl_, txception, true);
241 * Generate the interface for a struct
243 * @param tstruct The struct definition
245 void t_cocoa_generator::generate_cocoa_struct_interface(ofstream &out,
246 t_struct* tstruct,
247 bool is_exception) {
248 out << "@interface " << cocoa_prefix_ << tstruct->get_name() << " : ";
250 if (is_exception) {
251 out << "NSException ";
252 } else {
253 out << "NSObject ";
256 scope_up(out);
258 // members are protected. this is redundant, but explicit.
259 // f_header_ << endl << "@protected:" << endl;
261 const vector<t_field*>& members = tstruct->get_members();
263 // member varialbes
264 vector<t_field*>::const_iterator m_iter;
265 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
266 out << indent() << declare_field(*m_iter) << endl;
269 if (members.size() > 0) {
270 out << endl;
271 // isset fields
272 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
273 indent(out) <<
274 "BOOL __" << (*m_iter)->get_name() << "_isset;" << endl;
278 scope_down(out);
279 out << endl;
281 // initializer for all fields
282 if (!members.empty()) {
283 generate_cocoa_struct_initializer_signature(out, tstruct);
284 out << ";" << endl;
286 out << endl;
288 // read and write
289 out << "- (void) read: (id <TProtocol>) inProtocol;" << endl;
290 out << "- (void) write: (id <TProtocol>) outProtocol;" << endl;
291 out << endl;
293 // getters and setters
294 generate_cocoa_struct_field_accessor_declarations(out, tstruct, is_exception);
296 out << "@end" << endl << endl;
301 * Generate signature for initializer of struct with a parameter for
302 * each field.
304 void t_cocoa_generator::generate_cocoa_struct_initializer_signature(ofstream &out,
305 t_struct* tstruct) {
306 const vector<t_field*>& members = tstruct->get_members();
307 vector<t_field*>::const_iterator m_iter;
308 indent(out) << "- (id) initWith";
309 for (m_iter = members.begin(); m_iter != members.end(); ) {
310 if (m_iter == members.begin()) {
311 out << capitalize((*m_iter)->get_name());
312 } else {
313 out << (*m_iter)->get_name();
315 out << ": (" << type_name((*m_iter)->get_type()) << ") " <<
316 (*m_iter)->get_name();
317 ++m_iter;
318 if (m_iter != members.end()) {
319 out << " ";
326 * Generate getter and setter declarations for all fields, plus an
327 * IsSet getter.
329 void t_cocoa_generator::generate_cocoa_struct_field_accessor_declarations(ofstream &out,
330 t_struct* tstruct,
331 bool is_exception) {
332 const vector<t_field*>& members = tstruct->get_members();
333 vector<t_field*>::const_iterator m_iter;
334 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
335 out << indent() << "- (" << type_name((*m_iter)->get_type()) << ") " << decapitalize((*m_iter)->get_name()) << ";" << endl;
336 out << indent() << "- (void) set" << capitalize((*m_iter)->get_name()) <<
337 ": (" << type_name((*m_iter)->get_type()) << ") " << (*m_iter)->get_name() << ";" << endl;
338 out << indent() << "- (BOOL) " << (*m_iter)->get_name() << "IsSet;" << endl << endl;
344 * Generate struct implementation.
346 * @param tstruct The struct definition
347 * @param is_exception Is this an exception?
348 * @param is_result If this is a result it needs a different writer
350 void t_cocoa_generator::generate_cocoa_struct_implementation(ofstream &out,
351 t_struct* tstruct,
352 bool is_exception,
353 bool is_result) {
354 indent(out) <<
355 "@implementation " << cocoa_prefix_ << tstruct->get_name() << endl;
357 // exceptions need to call the designated initializer on NSException
358 if (is_exception) {
359 out << indent() << "- (id) init" << endl;
360 scope_up(out);
361 out << indent() << "return [super initWithName: @\"" << tstruct->get_name() <<
362 "\" reason: @\"unknown\" userInfo: nil];" << endl;
363 scope_down(out);
366 // initializer with all fields as params
367 const vector<t_field*>& members = tstruct->get_members();
368 if (!members.empty()) {
369 generate_cocoa_struct_initializer_signature(out, tstruct);
370 out << endl;
371 scope_up(out);
372 if (is_exception) {
373 out << indent() << "self = [self init];" << endl;
374 } else {
375 out << indent() << "self = [super init];" << endl;
378 vector<t_field*>::const_iterator m_iter;
379 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
380 t_type* t = get_true_type((*m_iter)->get_type());
381 out << indent() << "__" << (*m_iter)->get_name() << " = ";
382 if (type_can_be_null(t)) {
383 out << "[" << (*m_iter)->get_name() << " retain];" << endl;
384 } else {
385 out << (*m_iter)->get_name() << ";" << endl;
387 out << indent() << "__" << (*m_iter)->get_name() << "_isset = YES;" << endl;
390 out << indent() << "return self;" << endl;
391 scope_down(out);
392 out << endl;
395 // dealloc
396 if (!members.empty()) {
397 out << "- (void) dealloc" << endl;
398 scope_up(out);
400 vector<t_field*>::const_iterator m_iter;
401 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
402 t_type* t = get_true_type((*m_iter)->get_type());
403 if (type_can_be_null(t)) {
404 indent(out) << "[__" << (*m_iter)->get_name() << " release];" << endl;
408 out << indent() << "[super dealloc];" << endl;
409 scope_down(out);
410 out << endl;
413 // the rest of the methods
414 generate_cocoa_struct_field_accessor_implementations(out, tstruct, is_exception);
415 generate_cocoa_struct_reader(out, tstruct);
416 if (is_result) {
417 generate_cocoa_struct_result_writer(out, tstruct);
418 } else {
419 generate_cocoa_struct_writer(out, tstruct);
421 generate_cocoa_struct_description(out, tstruct);
423 out << "@end" << endl << endl;
428 * Generates a function to read all the fields of the struct.
430 * @param tstruct The struct definition
432 void t_cocoa_generator::generate_cocoa_struct_reader(ofstream& out,
433 t_struct* tstruct) {
434 out <<
435 "- (void) read: (id <TProtocol>) inProtocol" << endl;
436 scope_up(out);
438 const vector<t_field*>& fields = tstruct->get_members();
439 vector<t_field*>::const_iterator f_iter;
441 // Declare stack tmp variables
442 indent(out) << "NSString * fieldName;" << endl;
443 indent(out) << "int fieldType;" << endl;
444 indent(out) << "int fieldID;" << endl;
445 out << endl;
447 indent(out) << "[inProtocol readStructBeginReturningName: NULL];" << endl;
449 // Loop over reading in fields
450 indent(out) <<
451 "while (true)" << endl;
452 scope_up(out);
454 // Read beginning field marker
455 indent(out) <<
456 "[inProtocol readFieldBeginReturningName: &fieldName type: &fieldType fieldID: &fieldID];" << endl;
458 // Check for field STOP marker and break
459 indent(out) <<
460 "if (fieldType == TType_STOP) { " << endl;
461 indent_up();
462 indent(out) <<
463 "break;" << endl;
464 indent_down();
465 indent(out) <<
466 "}" << endl;
468 // Switch statement on the field we are reading
469 indent(out) <<
470 "switch (fieldID)" << endl;
472 scope_up(out);
474 // Generate deserialization code for known cases
475 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
476 indent(out) <<
477 "case " << (*f_iter)->get_key() << ":" << endl;
478 indent_up();
479 indent(out) <<
480 "if (fieldType == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
481 indent_up();
483 generate_deserialize_field(out, *f_iter, "fieldValue");
484 indent(out) << call_field_setter(*f_iter, "fieldValue") << endl;
485 // if this is an allocated field, release it since the struct
486 // is now retaining it
487 if (type_can_be_null((*f_iter)->get_type())) {
488 indent(out) << "[fieldValue release];" << endl;
491 indent_down();
492 out <<
493 indent() << "} else { " << endl <<
494 indent() << " [TProtocolUtil skipType: fieldType onProtocol: inProtocol];" << endl <<
495 indent() << "}" << endl <<
496 indent() << "break;" << endl;
497 indent_down();
500 // In the default case we skip the field
501 out <<
502 indent() << "default:" << endl <<
503 indent() << " [TProtocolUtil skipType: fieldType onProtocol: inProtocol];" << endl <<
504 indent() << " break;" << endl;
506 scope_down(out);
508 // Read field end marker
509 indent(out) <<
510 "[inProtocol readFieldEnd];" << endl;
512 scope_down(out);
514 out <<
515 indent() << "[inProtocol readStructEnd];" << endl;
517 indent_down();
518 out <<
519 indent() << "}" << endl <<
520 endl;
524 * Generates a function to write all the fields of the struct
526 * @param tstruct The struct definition
528 void t_cocoa_generator::generate_cocoa_struct_writer(ofstream& out,
529 t_struct* tstruct) {
530 out <<
531 indent() << "- (void) write: (id <TProtocol>) outProtocol {" << endl;
532 indent_up();
534 string name = tstruct->get_name();
535 const vector<t_field*>& fields = tstruct->get_members();
536 vector<t_field*>::const_iterator f_iter;
538 out <<
539 indent() << "[outProtocol writeStructBeginWithName: @\"" << name << "\"];" << endl;
541 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
542 out <<
543 indent() << "if (__" << (*f_iter)->get_name() << "_isset) {" << endl;
544 indent_up();
545 bool null_allowed = type_can_be_null((*f_iter)->get_type());
546 if (null_allowed) {
547 out <<
548 indent() << "if (__" << (*f_iter)->get_name() << " != nil) {" << endl;
549 indent_up();
552 indent(out) << "[outProtocol writeFieldBeginWithName: @\"" <<
553 (*f_iter)->get_name() << "\" type: " << type_to_enum((*f_iter)->get_type()) <<
554 " fieldID: " << (*f_iter)->get_key() << "];" << endl;
556 // Write field contents
557 generate_serialize_field(out, *f_iter, "__"+(*f_iter)->get_name());
559 // Write field closer
560 indent(out) <<
561 "[outProtocol writeFieldEnd];" << endl;
563 if (null_allowed) {
564 scope_down(out);
566 scope_down(out);
568 // Write the struct map
569 out <<
570 indent() << "[outProtocol writeFieldStop];" << endl <<
571 indent() << "[outProtocol writeStructEnd];" << endl;
573 indent_down();
574 out <<
575 indent() << "}" << endl <<
576 endl;
580 * Generates a function to write all the fields of the struct, which
581 * is a function result. These fields are only written if they are
582 * set, and only one of them can be set at a time.
584 * @param tstruct The struct definition
586 void t_cocoa_generator::generate_cocoa_struct_result_writer(ofstream& out,
587 t_struct* tstruct) {
588 out <<
589 indent() << "- (void) write: (id <TProtocol>) outProtocol {" << endl;
590 indent_up();
592 string name = tstruct->get_name();
593 const vector<t_field*>& fields = tstruct->get_members();
594 vector<t_field*>::const_iterator f_iter;
596 out <<
597 indent() << "[outProtocol writeStructBeginWithName: @\"" << name << "\"];" << endl;
599 bool first = true;
600 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
601 if (first) {
602 first = false;
603 out <<
604 endl <<
605 indent() << "if ";
606 } else {
607 out <<
608 " else if ";
611 out <<
612 "(__" << (*f_iter)->get_name() << "_isset) {" << endl;
613 indent_up();
615 bool null_allowed = type_can_be_null((*f_iter)->get_type());
616 if (null_allowed) {
617 out <<
618 indent() << "if (__" << (*f_iter)->get_name() << " != nil) {" << endl;
619 indent_up();
622 indent(out) << "[outProtocol writeFieldBeginWithName: @\"" <<
623 (*f_iter)->get_name() << "\" type: " << type_to_enum((*f_iter)->get_type()) <<
624 " fieldID: " << (*f_iter)->get_key() << "];" << endl;
626 // Write field contents
627 generate_serialize_field(out, *f_iter, "__"+(*f_iter)->get_name());
629 // Write field closer
630 indent(out) <<
631 "[outProtocol writeFieldEnd];" << endl;
633 if (null_allowed) {
634 indent_down();
635 indent(out) << "}" << endl;
638 indent_down();
639 indent(out) << "}";
641 // Write the struct map
642 out <<
643 endl <<
644 indent() << "[outProtocol writeFieldStop];" << endl <<
645 indent() << "[outProtocol writeStructEnd];" << endl;
647 indent_down();
648 out <<
649 indent() << "}" << endl <<
650 endl;
654 * Generate property accessor methods for all fields in the struct.
655 * getter, setter, isset getter.
657 * @param tstruct The struct definition
659 void t_cocoa_generator::generate_cocoa_struct_field_accessor_implementations(ofstream& out,
660 t_struct* tstruct,
661 bool is_exception) {
662 const vector<t_field*>& fields = tstruct->get_members();
663 vector<t_field*>::const_iterator f_iter;
664 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
665 t_field* field = *f_iter;
666 t_type* type = get_true_type(field->get_type());
667 std::string field_name = field->get_name();
668 std::string cap_name = field_name;
669 cap_name[0] = toupper(cap_name[0]);
671 // Simple getter
672 indent(out) << "- (" << type_name(type) << ") ";
673 out << field_name << " {" << endl;
674 indent_up();
675 if (!type_can_be_null(type)) {
676 indent(out) << "return __" << field_name << ";" << endl;
677 } else {
678 indent(out) << "return [[__" << field_name << " retain] autorelease];" << endl;
680 indent_down();
681 indent(out) << "}" << endl << endl;
683 // Simple setter
684 indent(out) << "- (void) set" << cap_name << ": (" << type_name(type) <<
685 ") " << field_name << " {" << endl;
686 indent_up();
687 if (!type_can_be_null(type)) {
688 indent(out) << "__" << field_name << " = " << field_name << ";" << endl;
689 } else {
690 indent(out) << "[" << field_name << " retain];" << endl;
691 indent(out) << "[__" << field_name << " release];" << endl;
692 indent(out) << "__" << field_name << " = " << field_name << ";" << endl;
694 indent(out) << "__" << field_name << "_isset = YES;" << endl;
695 indent_down();
696 indent(out) << "}" << endl << endl;
698 // IsSet
699 indent(out) << "- (BOOL) " << field_name << "IsSet {" << endl;
700 indent_up();
701 indent(out) << "return __" << field_name << "_isset;" << endl;
702 indent_down();
703 indent(out) << "}" << endl << endl;
705 // Unsetter - do we need this?
706 indent(out) << "- (void) unset" << cap_name << " {" << endl;
707 indent_up();
708 if (type_can_be_null(type)) {
709 indent(out) << "[__" << field_name << " release];" << endl;
710 indent(out) << "__" << field_name << " = nil;" << endl;
712 indent(out) << "__" << field_name << "_isset = NO;" << endl;
713 indent_down();
714 indent(out) << "}" << endl << endl;
719 * Generates a description method for the given struct
721 * @param tstruct The struct definition
723 void t_cocoa_generator::generate_cocoa_struct_description(ofstream& out,
724 t_struct* tstruct) {
725 out <<
726 indent() << "- (NSString *) description {" << endl;
727 indent_up();
729 out <<
730 indent() << "NSMutableString * ms = [NSMutableString stringWithString: @\"" <<
731 tstruct->get_name() << "(\"];" << endl;
733 const vector<t_field*>& fields = tstruct->get_members();
734 vector<t_field*>::const_iterator f_iter;
735 bool first = true;
736 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
737 if (first) {
738 first = false;
739 indent(out) << "[ms appendString: @\"" << (*f_iter)->get_name() << ":\"];" << endl;
740 } else {
741 indent(out) << "[ms appendString: @\"," << (*f_iter)->get_name() << ":\"];" << endl;
743 t_type* ttype = (*f_iter)->get_type();
744 indent(out) << "[ms appendFormat: @\"" << format_string_for_type(ttype) << "\", __" <<
745 (*f_iter)->get_name() << "];" << endl;
747 out <<
748 indent() << "[ms appendString: @\")\"];" << endl <<
749 indent() << "return [ms copy];" << endl;
751 indent_down();
752 indent(out) << "}" << endl <<
753 endl;
758 * Generates a thrift service. In Objective-C this consists of a
759 * protocol definition, a client interface and a client implementation.
761 * @param tservice The service definition
763 void t_cocoa_generator::generate_service(t_service* tservice) {
764 generate_cocoa_service_protocol(f_header_, tservice);
765 generate_cocoa_service_client_interface(f_header_, tservice);
766 generate_cocoa_service_helpers(tservice);
767 generate_cocoa_service_client_implementation(f_impl_, tservice);
772 * Generates structs for all the service return types
774 * @param tservice The service
776 void t_cocoa_generator::generate_cocoa_service_helpers(t_service* tservice) {
777 vector<t_function*> functions = tservice->get_functions();
778 vector<t_function*>::iterator f_iter;
779 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
780 generate_function_helpers(*f_iter);
784 string t_cocoa_generator::function_result_helper_struct_type(t_function* tfunction) {
785 return capitalize(tfunction->get_name()) + "Result_";
790 * Generates a struct and helpers for a function.
792 * @param tfunction The function
794 void t_cocoa_generator::generate_function_helpers(t_function* tfunction) {
795 if (tfunction->is_async()) {
796 return;
799 // create a result struct with a success field of the return type,
800 // and a field for each type of exception thrown
801 t_struct result(program_, function_result_helper_struct_type(tfunction));
802 t_field success(tfunction->get_returntype(), "success", 0);
803 if (!tfunction->get_returntype()->is_void()) {
804 result.append(&success);
807 t_struct* xs = tfunction->get_xceptions();
808 const vector<t_field*>& fields = xs->get_members();
809 vector<t_field*>::const_iterator f_iter;
810 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
811 result.append(*f_iter);
814 // generate the result struct
815 generate_cocoa_struct_interface(f_impl_, &result, false);
816 generate_cocoa_struct_implementation(f_impl_, &result, false, true);
820 * Generates a service protocol definition.
822 * @param tservice The service to generate a protocol definition for
824 void t_cocoa_generator::generate_cocoa_service_protocol(ofstream& out,
825 t_service* tservice) {
826 out << "@protocol " << cocoa_prefix_ << tservice->get_name() << " <NSObject>" << endl;
828 vector<t_function*> functions = tservice->get_functions();
829 vector<t_function*>::iterator f_iter;
830 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
831 out << "- " << function_signature(*f_iter) << ";" <<
832 " // throws ";
833 t_struct* xs = (*f_iter)->get_xceptions();
834 const std::vector<t_field*>& xceptions = xs->get_members();
835 vector<t_field*>::const_iterator x_iter;
836 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
837 out << type_name((*x_iter)->get_type()) + ", ";
839 out << "TException" << endl;
841 out << "@end" << endl << endl;
846 * Generates a service client interface definition.
848 * @param tservice The service to generate a client interface definition for
850 void t_cocoa_generator::generate_cocoa_service_client_interface(ofstream& out,
851 t_service* tservice) {
852 out << "@interface " << cocoa_prefix_ << tservice->get_name() << "Client : NSObject <" <<
853 cocoa_prefix_ << tservice->get_name() << "> ";
855 scope_up(out);
856 out << indent() << "id <TProtocol> inProtocol;" << endl;
857 out << indent() << "id <TProtocol> outProtocol;" << endl;
858 scope_down(out);
860 out << "- (id) initWithProtocol: (id <TProtocol>) protocol;" << endl;
861 out << "- (id) initWithInProtocol: (id <TProtocol>) inProtocol outProtocol: (id <TProtocol>) outProtocol;" << endl;
862 out << "@end" << endl << endl;
867 * Generates a service client implementation.
869 * @param tservice The service to generate an implementation for
871 void t_cocoa_generator::generate_cocoa_service_client_implementation(ofstream& out,
872 t_service* tservice) {
873 out << "@implementation " << cocoa_prefix_ << tservice->get_name() << "Client" << endl;
875 // initializers
876 out << "- (id) initWithProtocol: (id <TProtocol>) protocol" << endl;
877 scope_up(out);
878 out << indent() << "return [self initWithInProtocol: protocol outProtocol: protocol];" << endl;
879 scope_down(out);
880 out << endl;
882 out << "- (id) initWithInProtocol: (id <TProtocol>) anInProtocol outProtocol: (id <TProtocol>) anOutProtocol" << endl;
883 scope_up(out);
884 out << indent() << "[super init];" << endl;
885 out << indent() << "inProtocol = [anInProtocol retain];" << endl;
886 out << indent() << "outProtocol = [anOutProtocol retain];" << endl;
887 out << indent() << "return self;" << endl;
888 scope_down(out);
889 out << endl;
891 // dealloc
892 out << "- (void) dealloc" << endl;
893 scope_up(out);
894 out << indent() << "[inProtocol release];" << endl;
895 out << indent() << "[outProtocol release];" << endl;
896 out << indent() << "[super dealloc];" << endl;
897 scope_down(out);
898 out << endl;
900 // generate client method implementations
901 vector<t_function*> functions = tservice->get_functions();
902 vector<t_function*>::const_iterator f_iter;
903 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
904 string funname = (*f_iter)->get_name();
906 t_function send_function(g_type_void,
907 string("send_") + (*f_iter)->get_name(),
908 (*f_iter)->get_arglist());
910 string argsname = (*f_iter)->get_name() + "_args";
912 // Open function
913 indent(out) <<
914 "- " << function_signature(&send_function) << endl;
915 scope_up(out);
917 // Serialize the request
918 out <<
919 indent() << "[outProtocol writeMessageBeginWithName: @\"" << funname << "\"" <<
920 " type: TMessageType_CALL" <<
921 " sequenceID: 0];" << endl;
923 out <<
924 indent() << "[outProtocol writeStructBeginWithName: @\"" << argsname << "\"];" << endl;
926 // write out function parameters
927 t_struct* arg_struct = (*f_iter)->get_arglist();
928 const vector<t_field*>& fields = arg_struct->get_members();
929 vector<t_field*>::const_iterator fld_iter;
930 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
931 string fieldName = (*fld_iter)->get_name();
932 if (type_can_be_null((*fld_iter)->get_type())) {
933 out << indent() << "if (" << fieldName << " != nil)";
934 scope_up(out);
936 out <<
937 indent() << "[outProtocol writeFieldBeginWithName: @\"" << fieldName << "\""
938 " type: " << type_to_enum((*fld_iter)->get_type()) <<
939 " fieldID: " << (*fld_iter)->get_key() << "];" << endl;
941 generate_serialize_field(out, *fld_iter, fieldName);
943 out <<
944 indent() << "[outProtocol writeFieldEnd];" << endl;
946 if (type_can_be_null((*fld_iter)->get_type())) {
947 scope_down(out);
951 out <<
952 indent() << "[outProtocol writeFieldStop];" << endl;
953 out <<
954 indent() << "[outProtocol writeStructEnd];" << endl;
956 out <<
957 indent() << "[outProtocol writeMessageEnd];" << endl <<
958 indent() << "[[outProtocol transport] flush];" << endl;
960 scope_down(out);
961 out << endl;
963 if (!(*f_iter)->is_async()) {
964 t_struct noargs(program_);
965 t_function recv_function((*f_iter)->get_returntype(),
966 string("recv_") + (*f_iter)->get_name(),
967 &noargs,
968 (*f_iter)->get_xceptions());
969 // Open function
970 indent(out) <<
971 "- " << function_signature(&recv_function) << endl;
972 scope_up(out);
974 // TODO(mcslee): Message validation here, was the seqid etc ok?
976 // check for an exception
977 out <<
978 indent() << "int msgType = 0;" << endl <<
979 indent() << "[inProtocol readMessageBeginReturningName: nil type: &msgType sequenceID: NULL];" << endl <<
980 indent() << "if (msgType == TMessageType_EXCEPTION) {" << endl <<
981 indent() << " TApplicationException * x = [TApplicationException read: inProtocol];" << endl <<
982 indent() << " [inProtocol readMessageEnd];" << endl <<
983 indent() << " @throw x;" << endl <<
984 indent() << "}" << endl;
986 // FIXME - could optimize here to reduce creation of temporary objects.
987 string resultname = function_result_helper_struct_type(*f_iter);
988 out <<
989 indent() << cocoa_prefix_ << resultname << " * result = [[[" << cocoa_prefix_ <<
990 resultname << " alloc] init] autorelease];" << endl;
991 indent(out) << "[result read: inProtocol];" << endl;
992 indent(out) << "[inProtocol readMessageEnd];" << endl;
994 // Careful, only return _result if not a void function
995 if (!(*f_iter)->get_returntype()->is_void()) {
996 out <<
997 indent() << "if ([result successIsSet]) {" << endl <<
998 indent() << " return [result success];" << endl <<
999 indent() << "}" << endl;
1002 t_struct* xs = (*f_iter)->get_xceptions();
1003 const std::vector<t_field*>& xceptions = xs->get_members();
1004 vector<t_field*>::const_iterator x_iter;
1005 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1006 out <<
1007 indent() << "if ([result " << (*x_iter)->get_name() << "IsSet]) {" << endl <<
1008 indent() << " @throw [result " << (*x_iter)->get_name() << "];" << endl <<
1009 indent() << "}" << endl;
1012 // If you get here it's an exception, unless a void function
1013 if ((*f_iter)->get_returntype()->is_void()) {
1014 indent(out) <<
1015 "return;" << endl;
1016 } else {
1017 out <<
1018 indent() << "@throw [TApplicationException exceptionWithType: TApplicationException_MISSING_RESULT" << endl <<
1019 indent() << " reason: @\"" << (*f_iter)->get_name() << " failed: unknown result\"];" << endl;
1022 // Close function
1023 scope_down(out);
1024 out << endl;
1027 // Open function
1028 indent(out) <<
1029 "- " << function_signature(*f_iter) << endl;
1030 scope_up(out);
1031 indent(out) <<
1032 "[self send_" << funname;
1034 // Declare the function arguments
1035 bool first = true;
1036 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1037 if (first) {
1038 first = false;
1039 } else {
1040 out << " ";
1042 out << ": " << (*fld_iter)->get_name();
1044 out << "];" << endl;
1046 if (!(*f_iter)->is_async()) {
1047 out << indent();
1048 if (!(*f_iter)->get_returntype()->is_void()) {
1049 out << "return ";
1051 out <<
1052 "[self recv_" << funname << "];" << endl;
1054 scope_down(out);
1055 out << endl;
1058 indent_down();
1060 out << "@end" << endl << endl;
1065 * Deserializes a field of any type.
1067 * @param tfield The field
1068 * @param fieldName The variable name for this field
1070 void t_cocoa_generator::generate_deserialize_field(ofstream& out,
1071 t_field* tfield,
1072 string fieldName) {
1073 t_type* type = get_true_type(tfield->get_type());
1075 if (type->is_void()) {
1076 throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
1077 tfield->get_name();
1080 if (type->is_struct() || type->is_xception()) {
1081 generate_deserialize_struct(out,
1082 (t_struct*)type,
1083 fieldName);
1084 } else if (type->is_container()) {
1085 generate_deserialize_container(out, type, fieldName);
1086 } else if (type->is_base_type() || type->is_enum()) {
1087 indent(out) <<
1088 type_name(type) << " " << fieldName << " = [inProtocol ";
1090 if (type->is_base_type()) {
1091 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1092 switch (tbase) {
1093 case t_base_type::TYPE_VOID:
1094 throw "compiler error: cannot serialize void field in a struct: " +
1095 tfield->get_name();
1096 break;
1097 case t_base_type::TYPE_STRING:
1098 if (((t_base_type*)type)->is_binary()) {
1099 out << "readBinary];";
1100 } else {
1101 out << "readString];";
1103 break;
1104 case t_base_type::TYPE_BOOL:
1105 out << "readBool];";
1106 break;
1107 case t_base_type::TYPE_BYTE:
1108 out << "readByte];";
1109 break;
1110 case t_base_type::TYPE_I16:
1111 out << "readI16];";
1112 break;
1113 case t_base_type::TYPE_I32:
1114 out << "readI32];";
1115 break;
1116 case t_base_type::TYPE_I64:
1117 out << "readI64];";
1118 break;
1119 case t_base_type::TYPE_DOUBLE:
1120 out << "readDouble];";
1121 break;
1122 default:
1123 throw "compiler error: no Objective-C name for base type " + t_base_type::t_base_name(tbase);
1125 } else if (type->is_enum()) {
1126 out << "readI32];";
1128 out <<
1129 endl;
1130 } else {
1131 printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
1132 tfield->get_name().c_str(), type_name(type).c_str());
1137 * Generates an unserializer for a struct, allocates the struct and invokes read:
1139 void t_cocoa_generator::generate_deserialize_struct(ofstream& out,
1140 t_struct* tstruct,
1141 string fieldName) {
1142 indent(out) << type_name(tstruct) << fieldName << " = [[" <<
1143 type_name(tstruct, true) << " alloc] init];" << endl;
1144 indent(out) << "[" << fieldName << " read: inProtocol];" << endl;
1148 * Deserializes a container by reading its size and then iterating
1150 void t_cocoa_generator::generate_deserialize_container(ofstream& out,
1151 t_type* ttype,
1152 string fieldName) {
1153 string size = tmp("_size");
1154 indent(out) << "int " << size << ";" << endl;
1156 // Declare variables, read header
1157 if (ttype->is_map()) {
1158 indent(out)
1159 << "[inProtocol readMapBeginReturningKeyType: NULL valueType: NULL size: &" <<
1160 size << "];" << endl;
1161 indent(out) << "NSMutableDictionary * " << fieldName <<
1162 " = [[NSMutableDictionary alloc] initWithCapacity: " << size << "];" << endl;
1163 } else if (ttype->is_set()) {
1164 indent(out)
1165 << "[inProtocol readSetBeginReturningElementType: NULL size: &" << size << "];" << endl;
1166 indent(out) << "NSMutableSet * " << fieldName <<
1167 " = [[NSMutableSet alloc] initWithCapacity: " << size << "];" << endl;
1168 } else if (ttype->is_list()) {
1169 indent(out)
1170 << "[inProtocol readListBeginReturningElementType: NULL size: &" << size << "];" << endl;
1171 indent(out) << "NSMutableArray * " << fieldName <<
1172 " = [[NSMutableArray alloc] initWithCapacity: " << size << "];" << endl;
1174 // FIXME - the code above does not verify that the element types of
1175 // the containers being read match the element types of the
1176 // containers we are reading into. Does that matter?
1178 // For loop iterates over elements
1179 string i = tmp("_i");
1180 indent(out) << "int " << i << ";" << endl <<
1181 indent() << "for (" << i << " = 0; " <<
1182 i << " < " << size << "; " <<
1183 "++" << i << ")" << endl;
1185 scope_up(out);
1187 if (ttype->is_map()) {
1188 generate_deserialize_map_element(out, (t_map*)ttype, fieldName);
1189 } else if (ttype->is_set()) {
1190 generate_deserialize_set_element(out, (t_set*)ttype, fieldName);
1191 } else if (ttype->is_list()) {
1192 generate_deserialize_list_element(out, (t_list*)ttype, fieldName);
1195 scope_down(out);
1197 // Read container end
1198 if (ttype->is_map()) {
1199 indent(out) << "[inProtocol readMapEnd];" << endl;
1200 } else if (ttype->is_set()) {
1201 indent(out) << "[inProtocol readSetEnd];" << endl;
1202 } else if (ttype->is_list()) {
1203 indent(out) << "[inProtocol readListEnd];" << endl;
1210 * Take a variable of a given type and wrap it in code to make it
1211 * suitable for putting into a container, if necessary. Basically,
1212 * wrap scaler primitives in NSNumber objects.
1214 string t_cocoa_generator::containerize(t_type * ttype,
1215 string fieldName)
1217 // FIXME - optimize here to avoid autorelease pool?
1218 ttype = get_true_type(ttype);
1219 if (ttype->is_enum()) {
1220 return "[NSNumber numberWithInt: " + fieldName + "]";
1221 } else if (ttype->is_base_type()) {
1222 t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
1223 switch (tbase) {
1224 case t_base_type::TYPE_VOID:
1225 throw "can't containerize void";
1226 case t_base_type::TYPE_BOOL:
1227 return "[NSNumber numberWithBool: " + fieldName + "]";
1228 case t_base_type::TYPE_BYTE:
1229 return "[NSNumber numberWithUnsignedChar: " + fieldName + "]";
1230 case t_base_type::TYPE_I16:
1231 return "[NSNumber numberWithShort: " + fieldName + "]";
1232 case t_base_type::TYPE_I32:
1233 return "[NSNumber numberWithLong: " + fieldName + "]";
1234 case t_base_type::TYPE_I64:
1235 return "[NSNumber numberWithLongLong: " + fieldName + "]";
1236 case t_base_type::TYPE_DOUBLE:
1237 return "[NSNumber numberWithDouble: " + fieldName + "]";
1238 default:
1239 break;
1243 // do nothing
1244 return fieldName;
1249 * Generates code to deserialize a map element
1251 void t_cocoa_generator::generate_deserialize_map_element(ofstream& out,
1252 t_map* tmap,
1253 string fieldName) {
1254 string key = tmp("_key");
1255 string val = tmp("_val");
1256 t_field fkey(tmap->get_key_type(), key);
1257 t_field fval(tmap->get_val_type(), val);
1259 generate_deserialize_field(out, &fkey, key);
1260 generate_deserialize_field(out, &fval, val);
1262 indent(out) <<
1263 "[" << fieldName << " setObject: " << containerize(fval.get_type(), val) <<
1264 " forKey: " << containerize(fkey.get_type(), key) << "];" << endl;
1268 * Deserializes a set element
1270 void t_cocoa_generator::generate_deserialize_set_element(ofstream& out,
1271 t_set* tset,
1272 string fieldName) {
1273 string elem = tmp("_elem");
1274 t_field felem(tset->get_elem_type(), elem);
1276 generate_deserialize_field(out, &felem, elem);
1278 indent(out) <<
1279 "[" << fieldName << " addObject: " << containerize(felem.get_type(), elem) << "];" << endl;
1283 * Deserializes a list element
1285 void t_cocoa_generator::generate_deserialize_list_element(ofstream& out,
1286 t_list* tlist,
1287 string fieldName) {
1288 string elem = tmp("_elem");
1289 t_field felem(tlist->get_elem_type(), elem);
1291 generate_deserialize_field(out, &felem, elem);
1293 indent(out) <<
1294 "[" << fieldName << " addObject: " << containerize(felem.get_type(), elem) << "];" << endl;
1299 * Serializes a field of any type.
1301 * @param tfield The field to serialize
1302 * @param fieldName Name to of the variable holding the field
1304 void t_cocoa_generator::generate_serialize_field(ofstream& out,
1305 t_field* tfield,
1306 string fieldName) {
1307 t_type* type = get_true_type(tfield->get_type());
1309 // Do nothing for void types
1310 if (type->is_void()) {
1311 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
1312 tfield->get_name();
1315 if (type->is_struct() || type->is_xception()) {
1316 generate_serialize_struct(out,
1317 (t_struct*)type,
1318 fieldName);
1319 } else if (type->is_container()) {
1320 generate_serialize_container(out,
1321 type,
1322 fieldName);
1323 } else if (type->is_base_type() || type->is_enum()) {
1324 indent(out) <<
1325 "[outProtocol ";
1327 if (type->is_base_type()) {
1328 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1329 switch (tbase) {
1330 case t_base_type::TYPE_VOID:
1331 throw
1332 "compiler error: cannot serialize void field in a struct: " + fieldName;
1333 break;
1334 case t_base_type::TYPE_STRING:
1335 if (((t_base_type*)type)->is_binary()) {
1336 out << "writeBinary: " << fieldName << "];";
1337 } else {
1338 out << "writeString: " << fieldName << "];";
1340 break;
1341 case t_base_type::TYPE_BOOL:
1342 out << "writeBool: " << fieldName << "];";
1343 break;
1344 case t_base_type::TYPE_BYTE:
1345 out << "writeByte: " << fieldName << "];";
1346 break;
1347 case t_base_type::TYPE_I16:
1348 out << "writeI16: " << fieldName << "];";
1349 break;
1350 case t_base_type::TYPE_I32:
1351 out << "writeI32: " << fieldName << "];";
1352 break;
1353 case t_base_type::TYPE_I64:
1354 out << "writeI64: " << fieldName << "];";
1355 break;
1356 case t_base_type::TYPE_DOUBLE:
1357 out << "writeDouble: " << fieldName << "];";
1358 break;
1359 default:
1360 throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase);
1362 } else if (type->is_enum()) {
1363 out << "writeI32: " << fieldName << "];";
1365 out << endl;
1366 } else {
1367 printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
1368 tfield->get_name().c_str(),
1369 type_name(type).c_str());
1374 * Serialize a struct.
1376 * @param tstruct The struct to serialize
1377 * @param fieldName Name of variable holding struct
1379 void t_cocoa_generator::generate_serialize_struct(ofstream& out,
1380 t_struct* tstruct,
1381 string fieldName) {
1382 out <<
1383 indent() << "[" << fieldName << " write: outProtocol];" << endl;
1387 * Serializes a container by writing its size then the elements.
1389 * @param ttype The type of container
1390 * @param fieldName Name of variable holding container
1392 void t_cocoa_generator::generate_serialize_container(ofstream& out,
1393 t_type* ttype,
1394 string fieldName) {
1395 scope_up(out);
1397 if (ttype->is_map()) {
1398 indent(out) <<
1399 "[outProtocol writeMapBeginWithKeyType: " <<
1400 type_to_enum(((t_map*)ttype)->get_key_type()) << " valueType: " <<
1401 type_to_enum(((t_map*)ttype)->get_val_type()) << " size: [" <<
1402 fieldName << " count]];" << endl;
1403 } else if (ttype->is_set()) {
1404 indent(out) <<
1405 "[outProtocol writeSetBeginWithElementType: " <<
1406 type_to_enum(((t_set*)ttype)->get_elem_type()) << " size: [" <<
1407 fieldName << " count]];" << endl;
1408 } else if (ttype->is_list()) {
1409 indent(out) <<
1410 "[outProtocol writeListBeginWithElementType: " <<
1411 type_to_enum(((t_list*)ttype)->get_elem_type()) << " size: [" <<
1412 fieldName << " count]];" << endl;
1415 string iter = tmp("_iter");
1416 string key;
1417 if (ttype->is_map()) {
1418 key = tmp("key");
1419 indent(out) << "NSEnumerator * " << iter << " = [" << fieldName << " keyEnumerator];" << endl;
1420 indent(out) << "id " << key << ";" << endl;
1421 indent(out) << "while ((" << key << " = [" << iter << " nextObject]))" << endl;
1422 } else if (ttype->is_set()) {
1423 key = tmp("obj");
1424 indent(out) << "NSEnumerator * " << iter << " = [" << fieldName << " objectEnumerator];" << endl;
1425 indent(out) << "id " << key << ";" << endl;
1426 indent(out) << "while ((" << key << " = [" << iter << " nextObject]))" << endl;
1427 } else if (ttype->is_list()) {
1428 key = tmp("i");
1429 indent(out) << "int " << key << ";" << endl;
1430 indent(out) <<
1431 "for (" << key << " = 0; " << key << " < [" << fieldName << " count]; " << key << "++)" << endl;
1434 scope_up(out);
1436 if (ttype->is_map()) {
1437 generate_serialize_map_element(out, (t_map*)ttype, key, fieldName);
1438 } else if (ttype->is_set()) {
1439 generate_serialize_set_element(out, (t_set*)ttype, key);
1440 } else if (ttype->is_list()) {
1441 generate_serialize_list_element(out, (t_list*)ttype, key, fieldName);
1444 scope_down(out);
1446 if (ttype->is_map()) {
1447 indent(out) <<
1448 "[outProtocol writeMapEnd];" << endl;
1449 } else if (ttype->is_set()) {
1450 indent(out) <<
1451 "[outProtocol writeSetEnd];" << endl;
1452 } else if (ttype->is_list()) {
1453 indent(out) <<
1454 "[outProtocol writeListEnd];" << endl;
1457 scope_down(out);
1461 * Given a field variable name, wrap it in code that converts it to a
1462 * primitive type, if necessary.
1464 string t_cocoa_generator::decontainerize(t_field * tfield,
1465 string fieldName)
1467 t_type * ttype = get_true_type(tfield->get_type());
1468 if (ttype->is_enum()) {
1469 return "[" + fieldName + " intValue]";
1470 } else if (ttype->is_base_type()) {
1471 t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
1472 switch (tbase) {
1473 case t_base_type::TYPE_VOID:
1474 throw "can't decontainerize void";
1475 case t_base_type::TYPE_BOOL:
1476 return "[" + fieldName + " boolValue]";
1477 case t_base_type::TYPE_BYTE:
1478 return "[" + fieldName + " unsignedCharValue]";
1479 case t_base_type::TYPE_I16:
1480 return "[" + fieldName + " shortValue]";
1481 case t_base_type::TYPE_I32:
1482 return "[" + fieldName + " longValue]";
1483 case t_base_type::TYPE_I64:
1484 return "[" + fieldName + " longLongValue]";
1485 case t_base_type::TYPE_DOUBLE:
1486 return "[" + fieldName + " doubleValue]";
1487 default:
1488 break;
1492 // do nothing
1493 return fieldName;
1498 * Serializes the members of a map.
1500 void t_cocoa_generator::generate_serialize_map_element(ofstream& out,
1501 t_map* tmap,
1502 string key,
1503 string mapName) {
1504 t_field kfield(tmap->get_key_type(), key);
1505 generate_serialize_field(out, &kfield, decontainerize(&kfield, key));
1506 t_field vfield(tmap->get_val_type(), "[" + mapName + " objectForKey: " + key + "]");
1507 generate_serialize_field(out, &vfield, decontainerize(&vfield, vfield.get_name()));
1511 * Serializes the members of a set.
1513 void t_cocoa_generator::generate_serialize_set_element(ofstream& out,
1514 t_set* tset,
1515 string elementName) {
1516 t_field efield(tset->get_elem_type(), elementName);
1517 generate_serialize_field(out, &efield, decontainerize(&efield, elementName));
1521 * Serializes the members of a list.
1523 void t_cocoa_generator::generate_serialize_list_element(ofstream& out,
1524 t_list* tlist,
1525 string index,
1526 string listName) {
1527 t_field efield(tlist->get_elem_type(), "[" + listName + " objectAtIndex: " + index + "]");
1528 generate_serialize_field(out, &efield, decontainerize(&efield, efield.get_name()));
1533 * Returns an Objective-C name
1535 * @param ttype The type
1536 * @param class_ref Do we want a Class reference istead of a type reference?
1537 * @return Java type name, i.e. HashMap<Key,Value>
1539 string t_cocoa_generator::type_name(t_type* ttype, bool class_ref) {
1540 if (ttype->is_typedef()) {
1541 return cocoa_prefix_ + ttype->get_name();
1544 string result;
1545 if (ttype->is_base_type()) {
1546 return base_type_name((t_base_type*)ttype);
1547 } else if (ttype->is_enum()) {
1548 return "int";
1549 } else if (ttype->is_map()) {
1550 result = "NSDictionary";
1551 } else if (ttype->is_set()) {
1552 result = "NSSet";
1553 } else if (ttype->is_list()) {
1554 result = "NSArray";
1555 } else {
1556 // Check for prefix
1557 t_program* program = ttype->get_program();
1558 if (program != NULL) {
1559 result = program->get_cocoa_prefix() + ttype->get_name();
1560 } else {
1561 result = ttype->get_name();
1565 if (!class_ref) {
1566 result += " *";
1568 return result;
1572 * Returns the Objective-C type that corresponds to the thrift type.
1574 * @param tbase The base type
1576 string t_cocoa_generator::base_type_name(t_base_type* type) {
1577 t_base_type::t_base tbase = type->get_base();
1579 switch (tbase) {
1580 case t_base_type::TYPE_VOID:
1581 return "void";
1582 case t_base_type::TYPE_STRING:
1583 if (type->is_binary()) {
1584 return "NSData *";
1585 } else {
1586 return "NSString *";
1588 case t_base_type::TYPE_BOOL:
1589 return "BOOL";
1590 case t_base_type::TYPE_BYTE:
1591 return "uint8_t";
1592 case t_base_type::TYPE_I16:
1593 return"int16_t";
1594 case t_base_type::TYPE_I32:
1595 return "int32_t";
1596 case t_base_type::TYPE_I64:
1597 return"int64_t";
1598 case t_base_type::TYPE_DOUBLE:
1599 return "double";
1600 default:
1601 throw "compiler error: no objective-c name for base type " + t_base_type::t_base_name(tbase);
1607 * Spit out code that evaluates to the specified constant value.
1609 string t_cocoa_generator::render_const_value(string name,
1610 t_type* type,
1611 t_const_value* value,
1612 bool containerize_it) {
1613 std::ostringstream render;
1615 if (type->is_base_type()) {
1616 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1617 switch (tbase) {
1618 case t_base_type::TYPE_STRING:
1619 render << "@\"" + value->get_string() + "\"";
1620 break;
1621 case t_base_type::TYPE_BOOL:
1622 render << ((value->get_integer() > 0) ? "YES" : "NO");
1623 break;
1624 case t_base_type::TYPE_BYTE:
1625 case t_base_type::TYPE_I16:
1626 case t_base_type::TYPE_I32:
1627 case t_base_type::TYPE_I64:
1628 render << value->get_integer();
1629 break;
1630 case t_base_type::TYPE_DOUBLE:
1631 if (value->get_type() == t_const_value::CV_INTEGER) {
1632 render << value->get_integer();
1633 } else {
1634 render << value->get_double();
1636 break;
1637 default:
1638 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
1640 } else if (type->is_enum()) {
1641 render << value->get_integer();
1642 } else if (type->is_struct() || type->is_xception()) {
1643 render << "[[" << type_name(type, true) << " alloc] initWith";
1644 const vector<t_field*>& fields = ((t_struct*)type)->get_members();
1645 vector<t_field*>::const_iterator f_iter;
1646 const map<t_const_value*, t_const_value*>& val = value->get_map();
1647 map<t_const_value*, t_const_value*>::const_iterator v_iter;
1648 bool first = true;
1649 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
1650 t_type* field_type = NULL;
1651 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1652 if ((*f_iter)->get_name() == v_iter->first->get_string()) {
1653 field_type = (*f_iter)->get_type();
1656 if (field_type == NULL) {
1657 throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
1659 if (first) {
1660 render << capitalize(v_iter->first->get_string());
1661 first = false;
1662 } else {
1663 render << " " << v_iter->first->get_string();
1665 render << ": " << render_const_value(name, field_type, v_iter->second);
1667 render << "]";
1668 } else if (type->is_map()) {
1669 render << "[[NSDictionary alloc] initWithObjectsAndKeys: ";
1670 t_type* ktype = ((t_map*)type)->get_key_type();
1671 t_type* vtype = ((t_map*)type)->get_val_type();
1672 const map<t_const_value*, t_const_value*>& val = value->get_map();
1673 map<t_const_value*, t_const_value*>::const_iterator v_iter;
1674 bool first = true;
1675 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
1676 string key = render_const_value(name, ktype, v_iter->first, true);
1677 string val = render_const_value(name, vtype, v_iter->second, true);
1678 if (first) {
1679 first = false;
1680 } else {
1681 render << ", ";
1683 render << val << ", " << key;
1685 render << ", nil]";
1686 } else if (type->is_list()) {
1687 render << "[[NSArray alloc] initWithObjects: ";
1688 t_type * etype = ((t_list*)type)->get_elem_type();
1689 const vector<t_const_value*>& val = value->get_list();
1690 bool first = true;
1691 vector<t_const_value*>::const_iterator v_iter;
1692 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
1693 if (first) {
1694 first = false;
1695 } else {
1696 render << ", ";
1698 render << render_const_value(name, etype, *v_iter, true);
1700 render << ", nil]";
1701 } else if (type->is_set()) {
1702 render << "[[NSSet alloc] initWithObjects: ";
1703 t_type * etype = ((t_set*)type)->get_elem_type();
1704 const vector<t_const_value*>& val = value->get_list();
1705 bool first = true;
1706 vector<t_const_value*>::const_iterator v_iter;
1707 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
1708 if (first) {
1709 first = false;
1710 } else {
1711 render << ", ";
1713 render << render_const_value(name, etype, *v_iter, true);
1715 render << ", nil]";
1716 } else {
1717 throw "don't know how to render constant for type: " + type->get_name();
1720 if (containerize_it) {
1721 return containerize(type, render.str());
1724 return render.str();
1729 * Declares a field.
1731 * @param ttype The type
1733 string t_cocoa_generator::declare_field(t_field* tfield) {
1734 return type_name(tfield->get_type()) + " __" + tfield->get_name() + ";";
1738 * Renders a function signature
1740 * @param tfunction Function definition
1741 * @return String of rendered function definition
1743 string t_cocoa_generator::function_signature(t_function* tfunction) {
1744 t_type* ttype = tfunction->get_returntype();
1745 std::string result =
1746 "(" + type_name(ttype) + ") " + tfunction->get_name() + argument_list(tfunction->get_arglist());
1747 return result;
1752 * Renders a colon separated list of types and names, suitable for an
1753 * objective-c parameter list
1755 string t_cocoa_generator::argument_list(t_struct* tstruct) {
1756 string result = "";
1758 const vector<t_field*>& fields = tstruct->get_members();
1759 vector<t_field*>::const_iterator f_iter;
1760 bool first = true;
1761 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1762 if (first) {
1763 first = false;
1764 } else {
1765 result += " ";
1767 result += ": (" + type_name((*f_iter)->get_type()) + ") " + (*f_iter)->get_name();
1769 return result;
1774 * Converts the parse type to an Objective-C enum string for the given type.
1776 string t_cocoa_generator::type_to_enum(t_type* type) {
1777 type = get_true_type(type);
1779 if (type->is_base_type()) {
1780 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1781 switch (tbase) {
1782 case t_base_type::TYPE_VOID:
1783 throw "NO T_VOID CONSTRUCT";
1784 case t_base_type::TYPE_STRING:
1785 return "TType_STRING";
1786 case t_base_type::TYPE_BOOL:
1787 return "TType_BOOL";
1788 case t_base_type::TYPE_BYTE:
1789 return "TType_BYTE";
1790 case t_base_type::TYPE_I16:
1791 return "TType_I16";
1792 case t_base_type::TYPE_I32:
1793 return "TType_I32";
1794 case t_base_type::TYPE_I64:
1795 return "TType_I64";
1796 case t_base_type::TYPE_DOUBLE:
1797 return "TType_DOUBLE";
1799 } else if (type->is_enum()) {
1800 return "TType_I32";
1801 } else if (type->is_struct() || type->is_xception()) {
1802 return "TType_STRUCT";
1803 } else if (type->is_map()) {
1804 return "TType_MAP";
1805 } else if (type->is_set()) {
1806 return "TType_SET";
1807 } else if (type->is_list()) {
1808 return "TType_LIST";
1811 throw "INVALID TYPE IN type_to_enum: " + type->get_name();
1816 * Returns a format string specifier for the supplied parse type.
1818 string t_cocoa_generator::format_string_for_type(t_type* type) {
1819 type = get_true_type(type);
1821 if (type->is_base_type()) {
1822 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1823 switch (tbase) {
1824 case t_base_type::TYPE_VOID:
1825 throw "NO T_VOID CONSTRUCT";
1826 case t_base_type::TYPE_STRING:
1827 return "\\\"%@\\\"";
1828 case t_base_type::TYPE_BOOL:
1829 return "%i";
1830 case t_base_type::TYPE_BYTE:
1831 return "%i";
1832 case t_base_type::TYPE_I16:
1833 return "%hi";
1834 case t_base_type::TYPE_I32:
1835 return "%i";
1836 case t_base_type::TYPE_I64:
1837 return "%qi";
1838 case t_base_type::TYPE_DOUBLE:
1839 return "%f";
1841 } else if (type->is_enum()) {
1842 return "%i";
1843 } else if (type->is_struct() || type->is_xception()) {
1844 return "%@";
1845 } else if (type->is_map()) {
1846 return "%@";
1847 } else if (type->is_set()) {
1848 return "%@";
1849 } else if (type->is_list()) {
1850 return "%@";
1853 throw "INVALID TYPE IN format_string_for_type: " + type->get_name();
1857 * Generate a call to a field's setter.
1859 * @param tfield Field the setter is being called on
1860 * @param fieldName Name of variable to pass to setter
1863 string t_cocoa_generator::call_field_setter(t_field* tfield, string fieldName) {
1864 return "[self set" + capitalize(tfield->get_name()) + ": " + fieldName + "];";