1 // Copyright (c) 2006- Facebook
2 // Distributed under the Thrift Software License
4 // See accompanying file LICENSE or visit the Thrift site at:
5 // http://developers.facebook.com/thrift/
10 #include "t_cocoa_generator.h"
14 * Prepares for file generation by opening up the necessary file output
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());
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());
45 cocoa_thrift_imports() <<
46 "#import \"" << f_header_name
<< "\"" << endl
<<
52 * Prints standard Cocoa imports
54 * @return List of imports for Cocoa libraries
56 string
t_cocoa_generator::cocoa_imports() {
59 "#import <Cocoa/Cocoa.h>\n" +
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" +
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";
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_
;
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
) {
103 indent() << "typedef " << type_name(ttypedef
->get_type()) << " " << cocoa_prefix_
<< ttypedef
->get_symbolic() << ";" << 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
) {
117 indent() << "enum " << cocoa_prefix_
<< tenum
->get_name() << " {" << endl
;
120 vector
<t_enum_value
*> constants
= tenum
->get_constants();
121 vector
<t_enum_value
*>::iterator c_iter
;
123 for (c_iter
= constants
.begin(); c_iter
!= constants
.end(); ++c_iter
) {
131 indent() << tenum
->get_name() << "_" << (*c_iter
)->get_name();
132 if ((*c_iter
)->has_value()) {
134 " = " << (*c_iter
)->get_value();
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();
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();
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
;
185 f_impl_
<< "@implementation " << constants_class_name
<< endl
;
187 // initialize complex constants when the class is loaded
188 f_impl_
<< "+ (void) initialize ";
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
;
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();
208 "+ (" << type_name(type
) << ") " << name
;
210 indent(f_impl_
) << "return " << name
<< ";" << endl
;
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
,
248 out
<< "@interface " << cocoa_prefix_
<< tstruct
->get_name() << " : ";
251 out
<< "NSException ";
258 // members are protected. this is redundant, but explicit.
259 // f_header_ << endl << "@protected:" << endl;
261 const vector
<t_field
*>& members
= tstruct
->get_members();
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) {
272 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
) {
274 "BOOL __" << (*m_iter
)->get_name() << "_isset;" << endl
;
281 // initializer for all fields
282 if (!members
.empty()) {
283 generate_cocoa_struct_initializer_signature(out
, tstruct
);
289 out
<< "- (void) read: (id <TProtocol>) inProtocol;" << endl
;
290 out
<< "- (void) write: (id <TProtocol>) outProtocol;" << 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
304 void t_cocoa_generator::generate_cocoa_struct_initializer_signature(ofstream
&out
,
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());
313 out
<< (*m_iter
)->get_name();
315 out
<< ": (" << type_name((*m_iter
)->get_type()) << ") " <<
316 (*m_iter
)->get_name();
318 if (m_iter
!= members
.end()) {
326 * Generate getter and setter declarations for all fields, plus an
329 void t_cocoa_generator::generate_cocoa_struct_field_accessor_declarations(ofstream
&out
,
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
,
355 "@implementation " << cocoa_prefix_
<< tstruct
->get_name() << endl
;
357 // exceptions need to call the designated initializer on NSException
359 out
<< indent() << "- (id) init" << endl
;
361 out
<< indent() << "return [super initWithName: @\"" << tstruct
->get_name() <<
362 "\" reason: @\"unknown\" userInfo: nil];" << endl
;
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
);
373 out
<< indent() << "self = [self init];" << endl
;
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
;
385 out
<< (*m_iter
)->get_name() << ";" << endl
;
387 out
<< indent() << "__" << (*m_iter
)->get_name() << "_isset = YES;" << endl
;
390 out
<< indent() << "return self;" << endl
;
396 if (!members
.empty()) {
397 out
<< "- (void) dealloc" << endl
;
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
;
413 // the rest of the methods
414 generate_cocoa_struct_field_accessor_implementations(out
, tstruct
, is_exception
);
415 generate_cocoa_struct_reader(out
, tstruct
);
417 generate_cocoa_struct_result_writer(out
, tstruct
);
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
,
435 "- (void) read: (id <TProtocol>) inProtocol" << endl
;
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
;
447 indent(out
) << "[inProtocol readStructBeginReturningName: NULL];" << endl
;
449 // Loop over reading in fields
451 "while (true)" << endl
;
454 // Read beginning field marker
456 "[inProtocol readFieldBeginReturningName: &fieldName type: &fieldType fieldID: &fieldID];" << endl
;
458 // Check for field STOP marker and break
460 "if (fieldType == TType_STOP) { " << endl
;
468 // Switch statement on the field we are reading
470 "switch (fieldID)" << endl
;
474 // Generate deserialization code for known cases
475 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
477 "case " << (*f_iter
)->get_key() << ":" << endl
;
480 "if (fieldType == " << type_to_enum((*f_iter
)->get_type()) << ") {" << endl
;
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
;
493 indent() << "} else { " << endl
<<
494 indent() << " [TProtocolUtil skipType: fieldType onProtocol: inProtocol];" << endl
<<
495 indent() << "}" << endl
<<
496 indent() << "break;" << endl
;
500 // In the default case we skip the field
502 indent() << "default:" << endl
<<
503 indent() << " [TProtocolUtil skipType: fieldType onProtocol: inProtocol];" << endl
<<
504 indent() << " break;" << endl
;
508 // Read field end marker
510 "[inProtocol readFieldEnd];" << endl
;
515 indent() << "[inProtocol readStructEnd];" << endl
;
519 indent() << "}" << 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
,
531 indent() << "- (void) write: (id <TProtocol>) outProtocol {" << endl
;
534 string name
= tstruct
->get_name();
535 const vector
<t_field
*>& fields
= tstruct
->get_members();
536 vector
<t_field
*>::const_iterator f_iter
;
539 indent() << "[outProtocol writeStructBeginWithName: @\"" << name
<< "\"];" << endl
;
541 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
543 indent() << "if (__" << (*f_iter
)->get_name() << "_isset) {" << endl
;
545 bool null_allowed
= type_can_be_null((*f_iter
)->get_type());
548 indent() << "if (__" << (*f_iter
)->get_name() << " != nil) {" << endl
;
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
561 "[outProtocol writeFieldEnd];" << endl
;
568 // Write the struct map
570 indent() << "[outProtocol writeFieldStop];" << endl
<<
571 indent() << "[outProtocol writeStructEnd];" << endl
;
575 indent() << "}" << 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
,
589 indent() << "- (void) write: (id <TProtocol>) outProtocol {" << endl
;
592 string name
= tstruct
->get_name();
593 const vector
<t_field
*>& fields
= tstruct
->get_members();
594 vector
<t_field
*>::const_iterator f_iter
;
597 indent() << "[outProtocol writeStructBeginWithName: @\"" << name
<< "\"];" << endl
;
600 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
612 "(__" << (*f_iter
)->get_name() << "_isset) {" << endl
;
615 bool null_allowed
= type_can_be_null((*f_iter
)->get_type());
618 indent() << "if (__" << (*f_iter
)->get_name() << " != nil) {" << endl
;
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
631 "[outProtocol writeFieldEnd];" << endl
;
635 indent(out
) << "}" << endl
;
641 // Write the struct map
644 indent() << "[outProtocol writeFieldStop];" << endl
<<
645 indent() << "[outProtocol writeStructEnd];" << endl
;
649 indent() << "}" << 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
,
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]);
672 indent(out
) << "- (" << type_name(type
) << ") ";
673 out
<< field_name
<< " {" << endl
;
675 if (!type_can_be_null(type
)) {
676 indent(out
) << "return __" << field_name
<< ";" << endl
;
678 indent(out
) << "return [[__" << field_name
<< " retain] autorelease];" << endl
;
681 indent(out
) << "}" << endl
<< endl
;
684 indent(out
) << "- (void) set" << cap_name
<< ": (" << type_name(type
) <<
685 ") " << field_name
<< " {" << endl
;
687 if (!type_can_be_null(type
)) {
688 indent(out
) << "__" << field_name
<< " = " << field_name
<< ";" << endl
;
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
;
696 indent(out
) << "}" << endl
<< endl
;
699 indent(out
) << "- (BOOL) " << field_name
<< "IsSet {" << endl
;
701 indent(out
) << "return __" << field_name
<< "_isset;" << endl
;
703 indent(out
) << "}" << endl
<< endl
;
705 // Unsetter - do we need this?
706 indent(out
) << "- (void) unset" << cap_name
<< " {" << endl
;
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
;
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
,
726 indent() << "- (NSString *) description {" << endl
;
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
;
736 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
739 indent(out
) << "[ms appendString: @\"" << (*f_iter
)->get_name() << ":\"];" << endl
;
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
;
748 indent() << "[ms appendString: @\")\"];" << endl
<<
749 indent() << "return [ms copy];" << endl
;
752 indent(out
) << "}" << 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()) {
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
) << ";" <<
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() << "> ";
856 out
<< indent() << "id <TProtocol> inProtocol;" << endl
;
857 out
<< indent() << "id <TProtocol> outProtocol;" << endl
;
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
;
876 out
<< "- (id) initWithProtocol: (id <TProtocol>) protocol" << endl
;
878 out
<< indent() << "return [self initWithInProtocol: protocol outProtocol: protocol];" << endl
;
882 out
<< "- (id) initWithInProtocol: (id <TProtocol>) anInProtocol outProtocol: (id <TProtocol>) anOutProtocol" << endl
;
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
;
892 out
<< "- (void) dealloc" << endl
;
894 out
<< indent() << "[inProtocol release];" << endl
;
895 out
<< indent() << "[outProtocol release];" << endl
;
896 out
<< indent() << "[super dealloc];" << 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";
914 "- " << function_signature(&send_function
) << endl
;
917 // Serialize the request
919 indent() << "[outProtocol writeMessageBeginWithName: @\"" << funname
<< "\"" <<
920 " type: TMessageType_CALL" <<
921 " sequenceID: 0];" << endl
;
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)";
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
);
944 indent() << "[outProtocol writeFieldEnd];" << endl
;
946 if (type_can_be_null((*fld_iter
)->get_type())) {
952 indent() << "[outProtocol writeFieldStop];" << endl
;
954 indent() << "[outProtocol writeStructEnd];" << endl
;
957 indent() << "[outProtocol writeMessageEnd];" << endl
<<
958 indent() << "[[outProtocol transport] flush];" << 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(),
968 (*f_iter
)->get_xceptions());
971 "- " << function_signature(&recv_function
) << endl
;
974 // TODO(mcslee): Message validation here, was the seqid etc ok?
976 // check for an exception
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
);
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()) {
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
) {
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()) {
1018 indent() << "@throw [TApplicationException exceptionWithType: TApplicationException_MISSING_RESULT" << endl
<<
1019 indent() << " reason: @\"" << (*f_iter
)->get_name() << " failed: unknown result\"];" << endl
;
1029 "- " << function_signature(*f_iter
) << endl
;
1032 "[self send_" << funname
;
1034 // Declare the function arguments
1036 for (fld_iter
= fields
.begin(); fld_iter
!= fields
.end(); ++fld_iter
) {
1042 out
<< ": " << (*fld_iter
)->get_name();
1044 out
<< "];" << endl
;
1046 if (!(*f_iter
)->is_async()) {
1048 if (!(*f_iter
)->get_returntype()->is_void()) {
1052 "[self recv_" << funname
<< "];" << endl
;
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
,
1073 t_type
* type
= get_true_type(tfield
->get_type());
1075 if (type
->is_void()) {
1076 throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
1080 if (type
->is_struct() || type
->is_xception()) {
1081 generate_deserialize_struct(out
,
1084 } else if (type
->is_container()) {
1085 generate_deserialize_container(out
, type
, fieldName
);
1086 } else if (type
->is_base_type() || type
->is_enum()) {
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();
1093 case t_base_type::TYPE_VOID
:
1094 throw "compiler error: cannot serialize void field in a struct: " +
1097 case t_base_type::TYPE_STRING
:
1098 if (((t_base_type
*)type
)->is_binary()) {
1099 out
<< "readBinary];";
1101 out
<< "readString];";
1104 case t_base_type::TYPE_BOOL
:
1105 out
<< "readBool];";
1107 case t_base_type::TYPE_BYTE
:
1108 out
<< "readByte];";
1110 case t_base_type::TYPE_I16
:
1113 case t_base_type::TYPE_I32
:
1116 case t_base_type::TYPE_I64
:
1119 case t_base_type::TYPE_DOUBLE
:
1120 out
<< "readDouble];";
1123 throw "compiler error: no Objective-C name for base type " + t_base_type::t_base_name(tbase
);
1125 } else if (type
->is_enum()) {
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
,
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
,
1153 string size
= tmp("_size");
1154 indent(out
) << "int " << size
<< ";" << endl
;
1156 // Declare variables, read header
1157 if (ttype
->is_map()) {
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()) {
1165 << "[inProtocol readSetBeginReturningElementType: NULL size: &" << size
<< "];" << endl
;
1166 indent(out
) << "NSMutableSet * " << fieldName
<<
1167 " = [[NSMutableSet alloc] initWithCapacity: " << size
<< "];" << endl
;
1168 } else if (ttype
->is_list()) {
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
;
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
);
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
,
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();
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
+ "]";
1249 * Generates code to deserialize a map element
1251 void t_cocoa_generator::generate_deserialize_map_element(ofstream
& out
,
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
);
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
,
1273 string elem
= tmp("_elem");
1274 t_field
felem(tset
->get_elem_type(), elem
);
1276 generate_deserialize_field(out
, &felem
, elem
);
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
,
1288 string elem
= tmp("_elem");
1289 t_field
felem(tlist
->get_elem_type(), elem
);
1291 generate_deserialize_field(out
, &felem
, elem
);
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
,
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: " +
1315 if (type
->is_struct() || type
->is_xception()) {
1316 generate_serialize_struct(out
,
1319 } else if (type
->is_container()) {
1320 generate_serialize_container(out
,
1323 } else if (type
->is_base_type() || type
->is_enum()) {
1327 if (type
->is_base_type()) {
1328 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
1330 case t_base_type::TYPE_VOID
:
1332 "compiler error: cannot serialize void field in a struct: " + fieldName
;
1334 case t_base_type::TYPE_STRING
:
1335 if (((t_base_type
*)type
)->is_binary()) {
1336 out
<< "writeBinary: " << fieldName
<< "];";
1338 out
<< "writeString: " << fieldName
<< "];";
1341 case t_base_type::TYPE_BOOL
:
1342 out
<< "writeBool: " << fieldName
<< "];";
1344 case t_base_type::TYPE_BYTE
:
1345 out
<< "writeByte: " << fieldName
<< "];";
1347 case t_base_type::TYPE_I16
:
1348 out
<< "writeI16: " << fieldName
<< "];";
1350 case t_base_type::TYPE_I32
:
1351 out
<< "writeI32: " << fieldName
<< "];";
1353 case t_base_type::TYPE_I64
:
1354 out
<< "writeI64: " << fieldName
<< "];";
1356 case t_base_type::TYPE_DOUBLE
:
1357 out
<< "writeDouble: " << fieldName
<< "];";
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
<< "];";
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
,
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
,
1397 if (ttype
->is_map()) {
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()) {
1405 "[outProtocol writeSetBeginWithElementType: " <<
1406 type_to_enum(((t_set
*)ttype
)->get_elem_type()) << " size: [" <<
1407 fieldName
<< " count]];" << endl
;
1408 } else if (ttype
->is_list()) {
1410 "[outProtocol writeListBeginWithElementType: " <<
1411 type_to_enum(((t_list
*)ttype
)->get_elem_type()) << " size: [" <<
1412 fieldName
<< " count]];" << endl
;
1415 string iter
= tmp("_iter");
1417 if (ttype
->is_map()) {
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()) {
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()) {
1429 indent(out
) << "int " << key
<< ";" << endl
;
1431 "for (" << key
<< " = 0; " << key
<< " < [" << fieldName
<< " count]; " << key
<< "++)" << endl
;
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
);
1446 if (ttype
->is_map()) {
1448 "[outProtocol writeMapEnd];" << endl
;
1449 } else if (ttype
->is_set()) {
1451 "[outProtocol writeSetEnd];" << endl
;
1452 } else if (ttype
->is_list()) {
1454 "[outProtocol writeListEnd];" << endl
;
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
,
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();
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]";
1498 * Serializes the members of a map.
1500 void t_cocoa_generator::generate_serialize_map_element(ofstream
& out
,
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
,
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
,
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();
1545 if (ttype
->is_base_type()) {
1546 return base_type_name((t_base_type
*)ttype
);
1547 } else if (ttype
->is_enum()) {
1549 } else if (ttype
->is_map()) {
1550 result
= "NSDictionary";
1551 } else if (ttype
->is_set()) {
1553 } else if (ttype
->is_list()) {
1557 t_program
* program
= ttype
->get_program();
1558 if (program
!= NULL
) {
1559 result
= program
->get_cocoa_prefix() + ttype
->get_name();
1561 result
= ttype
->get_name();
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();
1580 case t_base_type::TYPE_VOID
:
1582 case t_base_type::TYPE_STRING
:
1583 if (type
->is_binary()) {
1586 return "NSString *";
1588 case t_base_type::TYPE_BOOL
:
1590 case t_base_type::TYPE_BYTE
:
1592 case t_base_type::TYPE_I16
:
1594 case t_base_type::TYPE_I32
:
1596 case t_base_type::TYPE_I64
:
1598 case t_base_type::TYPE_DOUBLE
:
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
,
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();
1618 case t_base_type::TYPE_STRING
:
1619 render
<< "@\"" + value
->get_string() + "\"";
1621 case t_base_type::TYPE_BOOL
:
1622 render
<< ((value
->get_integer() > 0) ? "YES" : "NO");
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();
1630 case t_base_type::TYPE_DOUBLE
:
1631 if (value
->get_type() == t_const_value::CV_INTEGER
) {
1632 render
<< value
->get_integer();
1634 render
<< value
->get_double();
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
;
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();
1660 render
<< capitalize(v_iter
->first
->get_string());
1663 render
<< " " << v_iter
->first
->get_string();
1665 render
<< ": " << render_const_value(name
, field_type
, v_iter
->second
);
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
;
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);
1683 render
<< val
<< ", " << key
;
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();
1691 vector
<t_const_value
*>::const_iterator v_iter
;
1692 for (v_iter
= val
.begin(); v_iter
!= val
.end(); ++v_iter
) {
1698 render
<< render_const_value(name
, etype
, *v_iter
, true);
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();
1706 vector
<t_const_value
*>::const_iterator v_iter
;
1707 for (v_iter
= val
.begin(); v_iter
!= val
.end(); ++v_iter
) {
1713 render
<< render_const_value(name
, etype
, *v_iter
, true);
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();
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());
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
) {
1758 const vector
<t_field
*>& fields
= tstruct
->get_members();
1759 vector
<t_field
*>::const_iterator f_iter
;
1761 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
1767 result
+= ": (" + type_name((*f_iter
)->get_type()) + ") " + (*f_iter
)->get_name();
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();
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
:
1792 case t_base_type::TYPE_I32
:
1794 case t_base_type::TYPE_I64
:
1796 case t_base_type::TYPE_DOUBLE
:
1797 return "TType_DOUBLE";
1799 } else if (type
->is_enum()) {
1801 } else if (type
->is_struct() || type
->is_xception()) {
1802 return "TType_STRUCT";
1803 } else if (type
->is_map()) {
1805 } else if (type
->is_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();
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
:
1830 case t_base_type::TYPE_BYTE
:
1832 case t_base_type::TYPE_I16
:
1834 case t_base_type::TYPE_I32
:
1836 case t_base_type::TYPE_I64
:
1838 case t_base_type::TYPE_DOUBLE
:
1841 } else if (type
->is_enum()) {
1843 } else if (type
->is_struct() || type
->is_xception()) {
1845 } else if (type
->is_map()) {
1847 } else if (type
->is_set()) {
1849 } else if (type
->is_list()) {
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
+ "];";