Subversion Repositories SmartDukaan

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
30 ashish 1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one
3
 * or more contributor license agreements. See the NOTICE file
4
 * distributed with this work for additional information
5
 * regarding copyright ownership. The ASF licenses this file
6
 * to you under the Apache License, Version 2.0 (the
7
 * "License"); you may not use this file except in compliance
8
 * with the License. You may obtain a copy of the License at
9
 *
10
 *   http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing,
13
 * software distributed under the License is distributed on an
14
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
 * KIND, either express or implied. See the License for the
16
 * specific language governing permissions and limitations
17
 * under the License.
18
 */
19
 
20
#include <string>
21
#include <fstream>
22
#include <iostream>
23
#include <vector>
24
 
25
#include <stdlib.h>
26
#include <sys/stat.h>
27
#include <sstream>
28
#include "t_oop_generator.h"
29
#include "platform.h"
30
using namespace std;
31
 
32
 
33
/**
34
 * Objective-C code generator.
35
 *
36
 * mostly copy/pasting/tweaking from mcslee's work.
37
 */
38
class t_cocoa_generator : public t_oop_generator {
39
 public:
40
  t_cocoa_generator(
41
      t_program* program,
42
      const std::map<std::string, std::string>& parsed_options,
43
      const std::string& option_string)
44
    : t_oop_generator(program)
45
  {
46
    std::map<std::string, std::string>::const_iterator iter;
47
 
48
    iter = parsed_options.find("log_unexpected");
49
    log_unexpected_ = (iter != parsed_options.end());    
50
 
51
    out_dir_base_ = "gen-cocoa";
52
  }
53
 
54
  /**
55
   * Init and close methods
56
   */
57
 
58
  void init_generator();
59
  void close_generator();
60
 
61
  void generate_consts(std::vector<t_const*> consts);
62
 
63
  /**
64
   * Program-level generation functions
65
   */
66
 
67
  void generate_typedef (t_typedef*  ttypedef);
68
  void generate_enum    (t_enum*     tenum);
69
  void generate_struct  (t_struct*   tstruct);
70
  void generate_xception(t_struct*   txception);
71
  void generate_service (t_service*  tservice);
72
 
73
  void print_const_value(std::ofstream& out, std::string name, t_type* type, t_const_value* value);
74
  std::string render_const_value(std::string name, t_type* type, t_const_value* value,
75
                                 bool containerize_it=false);
76
 
77
  void generate_cocoa_struct(t_struct* tstruct, bool is_exception);
78
  void generate_cocoa_struct_interface(std::ofstream& out, t_struct* tstruct, bool is_xception=false);
79
  void generate_cocoa_struct_implementation(std::ofstream& out, t_struct* tstruct, bool is_xception=false, bool is_result=false);
80
  void generate_cocoa_struct_initializer_signature(std::ofstream& out,
81
                                                   t_struct* tstruct);
82
  void generate_cocoa_struct_init_with_coder_method(ofstream &out,
83
                                                    t_struct* tstruct,
84
                                                    bool is_exception);
85
  void generate_cocoa_struct_encode_with_coder_method(ofstream &out,
86
                                                    t_struct* tstruct,
87
                                                    bool is_exception);
88
  void generate_cocoa_struct_field_accessor_declarations(std::ofstream& out,
89
                                                         t_struct* tstruct,
90
                                                         bool is_exception);
91
  void generate_cocoa_struct_field_accessor_implementations(std::ofstream& out,
92
                                                            t_struct* tstruct,
93
                                                            bool is_exception);
94
  void generate_cocoa_struct_reader(std::ofstream& out, t_struct* tstruct);
95
  void generate_cocoa_struct_result_writer(std::ofstream& out, t_struct* tstruct);
96
  void generate_cocoa_struct_writer(std::ofstream& out, t_struct* tstruct);
97
  void generate_cocoa_struct_description(std::ofstream& out, t_struct* tstruct);
98
 
99
  std::string function_result_helper_struct_type(t_function* tfunction);
100
  std::string function_args_helper_struct_type(t_function* tfunction);
101
  void generate_function_helpers(t_function* tfunction);
102
 
103
  /**
104
   * Service-level generation functions
105
   */
106
 
107
  void generate_cocoa_service_protocol (std::ofstream& out, t_service* tservice);
108
  void generate_cocoa_service_client_interface (std::ofstream& out, t_service* tservice);
109
  void generate_cocoa_service_client_implementation (std::ofstream& out, t_service* tservice);
110
  void generate_cocoa_service_server_interface (std::ofstream& out, t_service* tservice);
111
  void generate_cocoa_service_server_implementation (std::ofstream& out, t_service* tservice);
112
  void generate_cocoa_service_helpers   (t_service* tservice);
113
  void generate_service_client    (t_service* tservice);
114
  void generate_service_server    (t_service* tservice);
115
  void generate_process_function  (t_service* tservice, t_function* tfunction);
116
 
117
  /**
118
   * Serialization constructs
119
   */
120
 
121
  void generate_deserialize_field        (std::ofstream& out,
122
                                          t_field*    tfield,
123
                                          std::string fieldName);
124
 
125
  void generate_deserialize_struct       (std::ofstream& out,
126
                                          t_struct*   tstruct,
127
                                          std::string prefix="");
128
 
129
  void generate_deserialize_container    (std::ofstream& out,
130
                                          t_type*     ttype,
131
                                          std::string prefix="");
132
 
133
  void generate_deserialize_set_element  (std::ofstream& out,
134
                                          t_set*      tset,
135
                                          std::string prefix="");
136
 
137
  void generate_deserialize_map_element  (std::ofstream& out,
138
                                          t_map*      tmap,
139
                                          std::string prefix="");
140
 
141
  void generate_deserialize_list_element (std::ofstream& out,
142
                                          t_list*     tlist,
143
                                          std::string prefix="");
144
 
145
  void generate_serialize_field          (std::ofstream& out,
146
                                          t_field*    tfield,
147
                                          std::string prefix="");
148
 
149
  void generate_serialize_struct         (std::ofstream& out,
150
                                          t_struct*   tstruct,
151
                                          std::string fieldName="");
152
 
153
  void generate_serialize_container      (std::ofstream& out,
154
                                          t_type*     ttype,
155
                                          std::string prefix="");
156
 
157
  void generate_serialize_map_element    (std::ofstream& out,
158
                                          t_map*      tmap,
159
                                          std::string iter,
160
                                          std::string map);
161
 
162
  void generate_serialize_set_element    (std::ofstream& out,
163
                                          t_set*      tmap,
164
                                          std::string iter);
165
 
166
  void generate_serialize_list_element   (std::ofstream& out,
167
                                          t_list*     tlist,
168
                                          std::string index,
169
                                          std::string listName);
170
 
171
  /**
172
   * Helper rendering functions
173
   */
174
 
175
  std::string cocoa_prefix();
176
  std::string cocoa_imports();
177
  std::string cocoa_thrift_imports();
178
  std::string type_name(t_type* ttype, bool class_ref=false);
179
  std::string base_type_name(t_base_type* tbase);
180
  std::string declare_field(t_field* tfield);
181
  std::string declare_property(t_field* tfield);
182
  std::string dynamic_property(t_field* tfield);
183
  std::string function_signature(t_function* tfunction);
184
  std::string argument_list(t_struct* tstruct);
185
  std::string type_to_enum(t_type* ttype);
186
  std::string format_string_for_type(t_type* type);
187
  std::string call_field_setter(t_field* tfield, std::string fieldName);
188
  std::string containerize(t_type * ttype, std::string fieldName);
189
  std::string decontainerize(t_field * tfield, std::string fieldName);
190
 
191
  bool type_can_be_null(t_type* ttype) {
192
    ttype = get_true_type(ttype);
193
 
194
    return
195
      ttype->is_container() ||
196
      ttype->is_struct() ||
197
      ttype->is_xception() ||
198
      ttype->is_string();
199
  }
200
 
201
 private:
202
 
203
  std::string cocoa_prefix_;
204
  std::string constants_declarations_;
205
 
206
  /**
207
   * File streams
208
   */
209
 
210
  std::ofstream f_header_;
211
  std::ofstream f_impl_;
212
 
213
  bool log_unexpected_;
214
};
215
 
216
 
217
/**
218
 * Prepares for file generation by opening up the necessary file output
219
 * streams.
220
 */
221
void t_cocoa_generator::init_generator() {
222
  // Make output directory
223
  MKDIR(get_out_dir().c_str());
224
  cocoa_prefix_ = program_->get_namespace("cocoa");
225
 
226
  // we have a .h header file...
227
  string f_header_name = program_name_+".h";
228
  string f_header_fullname = get_out_dir()+f_header_name;
229
  f_header_.open(f_header_fullname.c_str());
230
 
231
  f_header_ <<
232
    autogen_comment() <<
233
    endl;
234
 
235
  f_header_ <<
236
    cocoa_imports() <<
237
    cocoa_thrift_imports();
238
 
239
  // ...and a .m implementation file
240
  string f_impl_name = get_out_dir()+program_name_+".m";
241
  f_impl_.open(f_impl_name.c_str());
242
 
243
  f_impl_ <<
244
    autogen_comment() <<
245
    endl;
246
 
247
  f_impl_ <<
248
    cocoa_imports() <<
249
    cocoa_thrift_imports() <<
250
    "#import \"" << f_header_name << "\"" << endl <<
251
    endl;
252
 
253
}
254
 
255
/**
256
 * Prints standard Cocoa imports
257
 *
258
 * @return List of imports for Cocoa libraries
259
 */
260
string t_cocoa_generator::cocoa_imports() {
261
  return
262
    string() +
263
    "#import <Foundation/Foundation.h>\n" +
264
    "\n";
265
}
266
 
267
/**
268
 * Prints thrift runtime imports
269
 *
270
 * @return List of imports necessary for thrift runtime
271
 */
272
string t_cocoa_generator::cocoa_thrift_imports() {
273
  string result = string() +
274
    "#import <TProtocol.h>\n" +
275
    "#import <TApplicationException.h>\n" +
276
    "#import <TProtocolUtil.h>\n" +
277
    "#import <TProcessor.h>\n" +
278
    "\n";
279
 
280
  // Include other Thrift includes
281
  const vector<t_program*>& includes = program_->get_includes();
282
  for (size_t i = 0; i < includes.size(); ++i) {
283
    result += "#import \"" + includes[i]->get_name() + ".h\"" + "\n";
284
  }
285
  result += "\n";
286
 
287
  return result;
288
}
289
 
290
 
291
/**
292
 * Finish up generation.
293
 */
294
void t_cocoa_generator::close_generator()
295
{
296
  // stick our constants declarations at the end of the header file
297
  // since they refer to things we are defining.
298
  f_header_ << constants_declarations_ << endl;
299
}
300
 
301
/**
302
 * Generates a typedef. This is just a simple 1-liner in objective-c
303
 *
304
 * @param ttypedef The type definition
305
 */
306
void t_cocoa_generator::generate_typedef(t_typedef* ttypedef) {
307
  f_header_ <<
308
    indent() << "typedef " << type_name(ttypedef->get_type()) << " " << cocoa_prefix_ << ttypedef->get_symbolic() << ";" << endl <<
309
    endl;
310
}
311
 
312
/**
313
 * Generates code for an enumerated type. In Objective-C, this is
314
 * essentially the same as the thrift definition itself, using the
315
 * enum keyword in Objective-C.  For namespace purposes, the name of
316
 * the enum plus an underscore is prefixed onto each element.
317
 *
318
 * @param tenum The enumeration
319
 */
320
void t_cocoa_generator::generate_enum(t_enum* tenum) {
321
  f_header_ <<
322
    indent() << "enum " << cocoa_prefix_ << tenum->get_name() << " {" << endl;
323
  indent_up();
324
 
325
  vector<t_enum_value*> constants = tenum->get_constants();
326
  vector<t_enum_value*>::iterator c_iter;
327
  bool first = true;
328
  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
329
    if (first) {
330
      first = false;
331
    } else {
332
      f_header_ <<
333
        "," << endl;
334
    }
335
    f_header_ <<
336
      indent() << tenum->get_name() << "_" << (*c_iter)->get_name();
337
    if ((*c_iter)->has_value()) {
338
      f_header_ <<
339
        " = " << (*c_iter)->get_value();
340
    }
341
  }
342
 
343
  indent_down();
344
  f_header_ <<
345
    endl <<
346
    "};" << endl <<
347
    endl;
348
}
349
 
350
/**
351
 * Generates a class that holds all the constants.  Primitive values
352
 * could have been placed outside this class, but I just put
353
 * everything in for consistency.
354
 */
355
void t_cocoa_generator::generate_consts(std::vector<t_const*> consts) {
356
  std::ostringstream const_interface;
357
  string constants_class_name = cocoa_prefix_ + program_name_ + "Constants";
358
 
359
  const_interface << "@interface " << constants_class_name << " : NSObject ";
360
  scope_up(const_interface);
361
  scope_down(const_interface);
362
 
363
  // getter method for each constant defined.
364
  vector<t_const*>::iterator c_iter;
365
  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
366
    string name = (*c_iter)->get_name();
367
    t_type* type = (*c_iter)->get_type();
368
    const_interface <<
369
      "+ (" << type_name(type) << ") " << name << ";" << endl;
370
  }
371
 
372
  const_interface << "@end";
373
 
374
  // this gets spit into the header file in ::close_generator
375
  constants_declarations_ = const_interface.str();
376
 
377
  // static variables in the .m hold all constant values
378
  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
379
    string name = (*c_iter)->get_name();
380
    t_type* type = (*c_iter)->get_type();
381
    f_impl_ <<
382
      "static " << type_name(type) << " " << cocoa_prefix_ << name;
383
    if (!type->is_container() && !type->is_struct()) {
384
      f_impl_ << " = " << render_const_value(name, type, (*c_iter)->get_value());
385
    }
386
    f_impl_ << ";" << endl;
387
  }
388
  f_impl_ << endl;
389
 
390
  f_impl_ << "@implementation " << constants_class_name << endl;
391
 
392
  // initialize complex constants when the class is loaded
393
  f_impl_ << "+ (void) initialize ";
394
  scope_up(f_impl_);
395
 
396
  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
397
    if ((*c_iter)->get_type()->is_container() ||
398
        (*c_iter)->get_type()->is_struct()) {
399
      string name = (*c_iter)->get_name();
400
      f_impl_ << indent() << cocoa_prefix_ << name << " = " << render_const_value(name,
401
                                                                 (*c_iter)->get_type(),
402
                                                                 (*c_iter)->get_value());
403
      f_impl_ << ";" << endl;
404
    }
405
  }
406
  scope_down(f_impl_);
407
 
408
  // getter method for each constant
409
  for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
410
    string name = (*c_iter)->get_name();
411
    t_type* type = (*c_iter)->get_type();
412
    f_impl_ <<
413
      "+ (" << type_name(type) << ") " << name;
414
    scope_up(f_impl_);
415
    indent(f_impl_) << "return " << cocoa_prefix_ << name << ";" << endl;
416
    scope_down(f_impl_);
417
  }
418
 
419
  f_impl_ << "@end" << endl << endl;
420
}
421
 
422
 
423
/**
424
 * Generates a struct definition for a thrift data type. This is a class
425
 * with protected data members, read(), write(), and getters and setters.
426
 *
427
 * @param tstruct The struct definition
428
 */
429
void t_cocoa_generator::generate_struct(t_struct* tstruct) {
430
  generate_cocoa_struct_interface(f_header_, tstruct, false);
431
  generate_cocoa_struct_implementation(f_impl_, tstruct, false);
432
}
433
 
434
/**
435
 * Exceptions are structs, but they inherit from NSException
436
 *
437
 * @param tstruct The struct definition
438
 */
439
void t_cocoa_generator::generate_xception(t_struct* txception) {
440
  generate_cocoa_struct_interface(f_header_, txception, true);
441
  generate_cocoa_struct_implementation(f_impl_, txception, true);
442
}
443
 
444
 
445
/**
446
 * Generate the interface for a struct
447
 *
448
 * @param tstruct The struct definition
449
 */
450
void t_cocoa_generator::generate_cocoa_struct_interface(ofstream &out,
451
                                                      t_struct* tstruct,
452
                                                      bool is_exception) {
453
  out << "@interface " << cocoa_prefix_ << tstruct->get_name() << " : ";
454
 
455
  if (is_exception) {
456
    out << "NSException ";
457
  } else {
458
    out << "NSObject ";
459
  }
460
  out << "<NSCoding> ";
461
 
462
  scope_up(out);
463
 
464
  // members are protected.  this is redundant, but explicit.
465
  //  f_header_ << endl << "@protected:" << endl;
466
 
467
  const vector<t_field*>& members = tstruct->get_members();
468
 
469
  // member varialbes
470
  vector<t_field*>::const_iterator m_iter;
471
  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
472
    out << indent() << declare_field(*m_iter) << endl;
473
  }
474
 
475
  if (members.size() > 0) {
476
    out << endl;
477
    // isset fields
478
    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
479
      indent(out) <<
480
        "BOOL __" << (*m_iter)->get_name() << "_isset;" <<  endl;
481
    }
482
  }
483
 
484
  scope_down(out);
485
  out << endl;
486
 
487
  // properties
488
  if (members.size() > 0) {
489
    out << "#if TARGET_OS_IPHONE || (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)" << endl;
490
    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
491
      out << indent() << declare_property(*m_iter) << endl;
492
    }
493
    out << "#endif" << endl << endl;
494
  }
495
 
496
  // initializer for all fields
497
  if (!members.empty()) {
498
    generate_cocoa_struct_initializer_signature(out, tstruct);
499
    out << ";" << endl;
500
  }
501
  out << endl;
502
 
503
  // read and write
504
  out << "- (void) read: (id <TProtocol>) inProtocol;" << endl;
505
  out << "- (void) write: (id <TProtocol>) outProtocol;" << endl;
506
  out << endl;
507
 
508
  // getters and setters
509
  generate_cocoa_struct_field_accessor_declarations(out, tstruct, is_exception);
510
 
511
  out << "@end" << endl << endl;
512
}
513
 
514
 
515
/**
516
 * Generate signature for initializer of struct with a parameter for
517
 * each field.
518
 */
519
void t_cocoa_generator::generate_cocoa_struct_initializer_signature(ofstream &out,
520
                                                                  t_struct* tstruct) {
521
  const vector<t_field*>& members = tstruct->get_members();
522
  vector<t_field*>::const_iterator m_iter;
523
  indent(out) << "- (id) initWith";
524
  for (m_iter = members.begin(); m_iter != members.end(); ) {
525
    if (m_iter == members.begin()) {
526
      out << capitalize((*m_iter)->get_name());
527
    } else {
528
      out << (*m_iter)->get_name();
529
    }
530
    out << ": (" << type_name((*m_iter)->get_type()) << ") " <<
531
      (*m_iter)->get_name();
532
    ++m_iter;
533
    if (m_iter != members.end()) {
534
      out << " ";
535
    }
536
  }
537
}
538
 
539
 
540
/**
541
 * Generate getter and setter declarations for all fields, plus an
542
 * IsSet getter.
543
 */
544
void t_cocoa_generator::generate_cocoa_struct_field_accessor_declarations(ofstream &out,
545
                                                                          t_struct* tstruct,
546
                                                                          bool is_exception) {
547
  const vector<t_field*>& members = tstruct->get_members();
548
  vector<t_field*>::const_iterator m_iter;
549
  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
550
    out << indent() << "- (" << type_name((*m_iter)->get_type()) << ") " << decapitalize((*m_iter)->get_name()) << ";" << endl;
551
    out << indent() << "- (void) set" << capitalize((*m_iter)->get_name()) <<
552
      ": (" << type_name((*m_iter)->get_type()) << ") " << (*m_iter)->get_name() << ";" << endl;
553
    out << indent() << "- (BOOL) " << (*m_iter)->get_name() << "IsSet;" << endl << endl;
554
  }
555
}
556
 
557
 
558
/**
559
 * Generate the initWithCoder method for this struct so it's compatible with
560
 * the NSCoding protocol
561
 */
562
void t_cocoa_generator::generate_cocoa_struct_init_with_coder_method(ofstream &out,
563
                                                                     t_struct* tstruct,
564
                                                                     bool is_exception) 
565
{
566
  indent(out) << "- (id) initWithCoder: (NSCoder *) decoder" << endl;
567
  scope_up(out);
568
  if (is_exception) {
569
    // NSExceptions conform to NSCoding, so we can call super
570
    out << indent() << "self = [super initWithCoder: decoder];" << endl;
571
  } else {
572
    out << indent() << "self = [super init];" << endl;
573
  }
574
 
575
  const vector<t_field*>& members = tstruct->get_members();
576
  vector<t_field*>::const_iterator m_iter;
577
 
578
  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
579
    t_type* t = get_true_type((*m_iter)->get_type());
580
    out << indent() << "if ([decoder containsValueForKey: @\""<< (*m_iter)->get_name() <<"\"])" << endl;
581
    scope_up(out);
582
    out << indent() << "__" << (*m_iter)->get_name() << " = ";
583
    if (type_can_be_null(t)) 
584
    {
585
      out << "[[decoder decodeObjectForKey: @\"" << (*m_iter)->get_name() << "\"] retain];" << endl;
586
    }
587
    else if (t->is_enum()) 
588
    {
589
      out << "[decoder decodeIntForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;      
590
    }
591
    else 
592
    {
593
      t_base_type::t_base tbase = ((t_base_type *) t)->get_base();
594
      switch (tbase)
595
      {
596
        case t_base_type::TYPE_BOOL:
597
          out << "[decoder decodeBoolForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;      
598
          break;
599
        case t_base_type::TYPE_BYTE:
600
          out << "[decoder decodeIntForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;      
601
          break;
602
        case t_base_type::TYPE_I16:
603
          out << "[decoder decodeIntForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;      
604
          break;
605
        case t_base_type::TYPE_I32:
606
          out << "[decoder decodeInt32ForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;      
607
          break;
608
        case t_base_type::TYPE_I64:
609
          out << "[decoder decodeInt64ForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;      
610
          break;
611
        case t_base_type::TYPE_DOUBLE:
612
          out << "[decoder decodeDoubleForKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;      
613
          break;
614
        default:    
615
          throw "compiler error: don't know how to decode thrift type: " + t_base_type::t_base_name(tbase);
616
      }
617
    }
618
    out << indent() << "__" << (*m_iter)->get_name() << "_isset = YES;" << endl;
619
    scope_down(out);
620
  }
621
 
622
  out << indent() << "return self;" << endl;
623
  scope_down(out);
624
  out << endl;
625
}
626
 
627
 
628
/**
629
 * Generate the encodeWithCoder method for this struct so it's compatible with
630
 * the NSCoding protocol
631
 */
632
void t_cocoa_generator::generate_cocoa_struct_encode_with_coder_method(ofstream &out,
633
                                                                       t_struct* tstruct,
634
                                                                       bool is_exception) 
635
{
636
  indent(out) << "- (void) encodeWithCoder: (NSCoder *) encoder" << endl;
637
  scope_up(out);
638
  if (is_exception) {
639
    // NSExceptions conform to NSCoding, so we can call super
640
    out << indent() << "[super encodeWithCoder: encoder];" << endl;
641
  }
642
 
643
  const vector<t_field*>& members = tstruct->get_members();
644
  vector<t_field*>::const_iterator m_iter;
645
 
646
  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
647
    t_type* t = get_true_type((*m_iter)->get_type());
648
    out << indent() << "if (__"<< (*m_iter)->get_name() <<"_isset)" << endl;
649
    scope_up(out);
650
    //out << indent() << "__" << (*m_iter)->get_name() << " = ";
651
    if (type_can_be_null(t)) 
652
    {
653
      out << indent() << "[encoder encodeObject: __" << (*m_iter)->get_name() << " forKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;
654
    }
655
    else if (t->is_enum()) 
656
    {
657
      out << indent() << "[encoder encodeInt: __" << (*m_iter)->get_name() << " forKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;
658
    }
659
    else 
660
    {
661
      t_base_type::t_base tbase = ((t_base_type *) t)->get_base();
662
      switch (tbase)
663
      {
664
        case t_base_type::TYPE_BOOL:
665
          out << indent() << "[encoder encodeBool: __" << (*m_iter)->get_name() << " forKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;
666
          break;
667
        case t_base_type::TYPE_BYTE:
668
          out << indent() << "[encoder encodeInt: __" << (*m_iter)->get_name() << " forKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;
669
          break;
670
        case t_base_type::TYPE_I16:
671
          out << indent() << "[encoder encodeInt: __" << (*m_iter)->get_name() << " forKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;
672
          break;
673
        case t_base_type::TYPE_I32:
674
          out << indent() << "[encoder encodeInt32: __" << (*m_iter)->get_name() << " forKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;
675
          break;
676
        case t_base_type::TYPE_I64:
677
          out << indent() << "[encoder encodeInt64: __" << (*m_iter)->get_name() << " forKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;
678
          break;
679
        case t_base_type::TYPE_DOUBLE:
680
          out << indent() << "[encoder encodeDouble: __" << (*m_iter)->get_name() << " forKey: @\"" << (*m_iter)->get_name() << "\"];" << endl;
681
          break;
682
        default:    
683
          throw "compiler error: don't know how to encode thrift type: " + t_base_type::t_base_name(tbase);
684
      }
685
    }
686
    scope_down(out);
687
  }
688
 
689
  scope_down(out);
690
  out << endl;
691
}
692
 
693
 
694
/**
695
 * Generate struct implementation.
696
 *
697
 * @param tstruct      The struct definition
698
 * @param is_exception Is this an exception?
699
 * @param is_result    If this is a result it needs a different writer
700
 */
701
void t_cocoa_generator::generate_cocoa_struct_implementation(ofstream &out,
702
                                                             t_struct* tstruct,
703
                                                             bool is_exception,
704
                                                             bool is_result) {
705
  indent(out) <<
706
    "@implementation " << cocoa_prefix_ << tstruct->get_name() << endl << endl;
707
 
708
  // exceptions need to call the designated initializer on NSException
709
  if (is_exception) {
710
    out << indent() << "- (id) init" << endl;
711
    scope_up(out);
712
    out << indent() << "return [super initWithName: @\"" << tstruct->get_name() <<
713
        "\" reason: @\"unknown\" userInfo: nil];" << endl;
714
    scope_down(out);
715
  }
716
 
717
  const vector<t_field*>& members = tstruct->get_members();
718
  vector<t_field*>::const_iterator m_iter;
719
 
720
  // @dynamic property declarations
721
  if (!members.empty()) {
722
    out << "#if TARGET_OS_IPHONE || (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)" << endl;
723
    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
724
      out << indent() << dynamic_property(*m_iter) << endl;
725
    }
726
    out << "#endif" << endl << endl;
727
  }
728
 
729
  // initializer with all fields as params
730
  if (!members.empty()) {
731
    generate_cocoa_struct_initializer_signature(out, tstruct);
732
    out << endl;
733
    scope_up(out);
734
    if (is_exception) {
735
      out << indent() << "self = [self init];" << endl;
736
    } else {
737
      out << indent() << "self = [super init];" << endl;
738
    }
739
 
740
    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
741
      t_type* t = get_true_type((*m_iter)->get_type());
742
      out << indent() << "__" << (*m_iter)->get_name() << " = ";
743
      if (type_can_be_null(t)) {
744
        out << "[" << (*m_iter)->get_name() << " retain];" << endl;
745
      } else {
746
        out << (*m_iter)->get_name() << ";" << endl;
747
      }
748
      out << indent() << "__" << (*m_iter)->get_name() << "_isset = YES;" << endl;
749
    }
750
 
751
    out << indent() << "return self;" << endl;
752
    scope_down(out);
753
    out << endl;
754
  }
755
 
756
  // initWithCoder for NSCoding
757
  generate_cocoa_struct_init_with_coder_method(out, tstruct, is_exception);
758
  // encodeWithCoder for NSCoding
759
  generate_cocoa_struct_encode_with_coder_method(out, tstruct, is_exception);  
760
 
761
  // dealloc
762
  if (!members.empty()) {
763
    out << "- (void) dealloc" << endl;
764
    scope_up(out);
765
 
766
    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
767
      t_type* t = get_true_type((*m_iter)->get_type());
768
      if (type_can_be_null(t)) {
769
        indent(out) << "[__" << (*m_iter)->get_name() << " release];" << endl;
770
      }
771
    }
772
 
773
    out << indent() << "[super dealloc];" << endl;
774
    scope_down(out);
775
    out << endl;
776
  }
777
 
778
  // the rest of the methods
779
  generate_cocoa_struct_field_accessor_implementations(out, tstruct, is_exception);
780
  generate_cocoa_struct_reader(out, tstruct);
781
  if (is_result) {
782
    generate_cocoa_struct_result_writer(out, tstruct);
783
  } else {
784
    generate_cocoa_struct_writer(out, tstruct);
785
  }
786
  generate_cocoa_struct_description(out, tstruct);
787
 
788
  out << "@end" << endl << endl;
789
}
790
 
791
 
792
/**
793
 * Generates a function to read all the fields of the struct.
794
 *
795
 * @param tstruct The struct definition
796
 */
797
void t_cocoa_generator::generate_cocoa_struct_reader(ofstream& out,
798
                                                     t_struct* tstruct) {
799
  out <<
800
    "- (void) read: (id <TProtocol>) inProtocol" << endl;
801
  scope_up(out);
802
 
803
  const vector<t_field*>& fields = tstruct->get_members();
804
  vector<t_field*>::const_iterator f_iter;
805
 
806
  // Declare stack tmp variables
807
  indent(out) << "NSString * fieldName;" << endl;
808
  indent(out) << "int fieldType;" << endl;
809
  indent(out) << "int fieldID;" << endl;
810
  out << endl;
811
 
812
  indent(out) << "[inProtocol readStructBeginReturningName: NULL];" << endl;
813
 
814
  // Loop over reading in fields
815
  indent(out) <<
816
    "while (true)" << endl;
817
    scope_up(out);
818
 
819
    // Read beginning field marker
820
    indent(out) <<
821
      "[inProtocol readFieldBeginReturningName: &fieldName type: &fieldType fieldID: &fieldID];" << endl;
822
 
823
    // Check for field STOP marker and break
824
    indent(out) <<
825
      "if (fieldType == TType_STOP) { " << endl;
826
    indent_up();
827
    indent(out) <<
828
      "break;" << endl;
829
    indent_down();
830
    indent(out) <<
831
      "}" << endl;
832
 
833
    // Switch statement on the field we are reading
834
    indent(out) <<
835
      "switch (fieldID)" << endl;
836
 
837
      scope_up(out);
838
 
839
      // Generate deserialization code for known cases
840
      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
841
        indent(out) <<
842
          "case " << (*f_iter)->get_key() << ":" << endl;
843
        indent_up();
844
        indent(out) <<
845
          "if (fieldType == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
846
        indent_up();
847
 
848
        generate_deserialize_field(out, *f_iter, "fieldValue");
849
        indent(out) << call_field_setter(*f_iter, "fieldValue") << endl;
850
        // if this is an allocated field, release it since the struct
851
        // is now retaining it
852
        if (type_can_be_null((*f_iter)->get_type())) {
853
          // deserialized strings are autorelease, so don't release them
854
          if (!(get_true_type((*f_iter)->get_type())->is_string())) {
855
            indent(out) << "[fieldValue release];" << endl;
856
          }
857
        }
858
 
859
        indent_down();
860
        out << indent() << "} else { " << endl;
861
        if (log_unexpected_) {
862
          out << indent() << "  NSLog(@\"%s: field ID %i has unexpected type %i.  Skipping.\", __PRETTY_FUNCTION__, fieldID, fieldType);" << endl;
863
        }
864
        out << indent() << "  [TProtocolUtil skipType: fieldType onProtocol: inProtocol];" << endl <<
865
          indent() << "}" << endl <<
866
          indent() << "break;" << endl;
867
        indent_down();
868
      }
869
 
870
      // In the default case we skip the field
871
      out << indent() << "default:" << endl;
872
      if (log_unexpected_) {
873
        out << indent() << "  NSLog(@\"%s: unexpected field ID %i with type %i.  Skipping.\", __PRETTY_FUNCTION__, fieldID, fieldType);" << endl;
874
      }
875
      out << indent() << "  [TProtocolUtil skipType: fieldType onProtocol: inProtocol];" << endl <<
876
        indent() << "  break;" << endl;
877
 
878
      scope_down(out);
879
 
880
    // Read field end marker
881
    indent(out) <<
882
      "[inProtocol readFieldEnd];" << endl;
883
 
884
    scope_down(out);
885
 
886
    out <<
887
      indent() << "[inProtocol readStructEnd];" << endl;
888
 
889
  indent_down();
890
  out <<
891
    indent() << "}" << endl <<
892
    endl;
893
}
894
 
895
/**
896
 * Generates a function to write all the fields of the struct
897
 *
898
 * @param tstruct The struct definition
899
 */
900
void t_cocoa_generator::generate_cocoa_struct_writer(ofstream& out,
901
                                                     t_struct* tstruct) {
902
  out <<
903
    indent() << "- (void) write: (id <TProtocol>) outProtocol {" << endl;
904
  indent_up();
905
 
906
  string name = tstruct->get_name();
907
  const vector<t_field*>& fields = tstruct->get_members();
908
  vector<t_field*>::const_iterator f_iter;
909
 
910
  out <<
911
    indent() << "[outProtocol writeStructBeginWithName: @\"" << name << "\"];" << endl;
912
 
913
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
914
    out <<
915
      indent() << "if (__" << (*f_iter)->get_name() << "_isset) {" << endl;
916
    indent_up();
917
    bool null_allowed = type_can_be_null((*f_iter)->get_type());
918
    if (null_allowed) {
919
      out <<
920
        indent() << "if (__" << (*f_iter)->get_name() << " != nil) {" << endl;
921
      indent_up();
922
    }
923
 
924
    indent(out) << "[outProtocol writeFieldBeginWithName: @\"" <<
925
      (*f_iter)->get_name() << "\" type: " << type_to_enum((*f_iter)->get_type()) <<
926
      " fieldID: " << (*f_iter)->get_key() << "];" << endl;
927
 
928
    // Write field contents
929
    generate_serialize_field(out, *f_iter, "__"+(*f_iter)->get_name());
930
 
931
    // Write field closer
932
    indent(out) <<
933
      "[outProtocol writeFieldEnd];" << endl;
934
 
935
    if (null_allowed) {
936
      scope_down(out);
937
    }
938
    scope_down(out);
939
  }
940
  // Write the struct map
941
  out <<
942
    indent() << "[outProtocol writeFieldStop];" << endl <<
943
    indent() << "[outProtocol writeStructEnd];" << endl;
944
 
945
  indent_down();
946
  out <<
947
    indent() << "}" << endl <<
948
    endl;
949
}
950
 
951
/**
952
 * Generates a function to write all the fields of the struct, which
953
 * is a function result. These fields are only written if they are
954
 * set, and only one of them can be set at a time.
955
 *
956
 * @param tstruct The struct definition
957
 */
958
void t_cocoa_generator::generate_cocoa_struct_result_writer(ofstream& out,
959
                                                            t_struct* tstruct) {
960
  out <<
961
    indent() << "- (void) write: (id <TProtocol>) outProtocol {" << endl;
962
  indent_up();
963
 
964
  string name = tstruct->get_name();
965
  const vector<t_field*>& fields = tstruct->get_members();
966
  vector<t_field*>::const_iterator f_iter;
967
 
968
  out <<
969
    indent() << "[outProtocol writeStructBeginWithName: @\"" << name << "\"];" << endl;
970
 
971
  bool first = true;
972
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
973
    if (first) {
974
      first = false;
975
      out <<
976
        endl <<
977
        indent() << "if ";
978
    } else {
979
      out <<
980
        " else if ";
981
    }
982
 
983
    out <<
984
      "(__" << (*f_iter)->get_name() << "_isset) {" << endl;
985
    indent_up();
986
 
987
    bool null_allowed = type_can_be_null((*f_iter)->get_type());
988
    if (null_allowed) {
989
      out <<
990
        indent() << "if (__" << (*f_iter)->get_name() << " != nil) {" << endl;
991
      indent_up();
992
    }
993
 
994
    indent(out) << "[outProtocol writeFieldBeginWithName: @\"" <<
995
      (*f_iter)->get_name() << "\" type: " << type_to_enum((*f_iter)->get_type()) <<
996
      " fieldID: " << (*f_iter)->get_key() << "];" << endl;
997
 
998
    // Write field contents
999
    generate_serialize_field(out, *f_iter, "__"+(*f_iter)->get_name());
1000
 
1001
    // Write field closer
1002
    indent(out) <<
1003
      "[outProtocol writeFieldEnd];" << endl;
1004
 
1005
    if (null_allowed) {
1006
      indent_down();
1007
      indent(out) << "}" << endl;
1008
    }
1009
 
1010
    indent_down();
1011
    indent(out) << "}";
1012
  }
1013
  // Write the struct map
1014
  out <<
1015
    endl <<
1016
    indent() << "[outProtocol writeFieldStop];" << endl <<
1017
    indent() << "[outProtocol writeStructEnd];" << endl;
1018
 
1019
  indent_down();
1020
  out <<
1021
    indent() << "}" << endl <<
1022
    endl;
1023
}
1024
 
1025
/**
1026
 * Generate property accessor methods for all fields in the struct.
1027
 * getter, setter, isset getter.
1028
 *
1029
 * @param tstruct The struct definition
1030
 */
1031
void t_cocoa_generator::generate_cocoa_struct_field_accessor_implementations(ofstream& out,
1032
                                                                             t_struct* tstruct,
1033
                                                                             bool is_exception) {
1034
  const vector<t_field*>& fields = tstruct->get_members();
1035
  vector<t_field*>::const_iterator f_iter;
1036
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1037
    t_field* field = *f_iter;
1038
    t_type* type = get_true_type(field->get_type());
1039
    std::string field_name = field->get_name();
1040
    std::string cap_name = field_name;
1041
    cap_name[0] = toupper(cap_name[0]);
1042
 
1043
    // Simple getter
1044
    indent(out) << "- (" << type_name(type) << ") ";
1045
    out << field_name << " {" << endl;
1046
    indent_up();
1047
    if (!type_can_be_null(type)) {
1048
      indent(out) << "return __" << field_name << ";" << endl;
1049
    } else {
1050
      indent(out) << "return [[__" << field_name << " retain] autorelease];" << endl;
1051
    }
1052
    indent_down();
1053
    indent(out) << "}" << endl << endl;
1054
 
1055
    // Simple setter
1056
    indent(out) << "- (void) set" << cap_name << ": (" << type_name(type) <<
1057
      ") " << field_name << " {" << endl;
1058
    indent_up();
1059
    if (!type_can_be_null(type)) {
1060
      indent(out) << "__" << field_name << " = " << field_name << ";" << endl;
1061
    } else {
1062
      indent(out) << "[" << field_name << " retain];" << endl;
1063
      indent(out) << "[__" << field_name << " release];" << endl;
1064
      indent(out) << "__" << field_name << " = " << field_name << ";" << endl;
1065
    }
1066
    indent(out) << "__" << field_name << "_isset = YES;" << endl;
1067
    indent_down();
1068
    indent(out) << "}" << endl << endl;
1069
 
1070
    // IsSet
1071
    indent(out) << "- (BOOL) " << field_name << "IsSet {" << endl;
1072
    indent_up();
1073
    indent(out) << "return __" << field_name << "_isset;" << endl;
1074
    indent_down();
1075
    indent(out) << "}" << endl << endl;
1076
 
1077
    // Unsetter - do we need this?
1078
    indent(out) << "- (void) unset" << cap_name << " {" << endl;
1079
    indent_up();
1080
    if (type_can_be_null(type)) {
1081
      indent(out) << "[__" << field_name << " release];" << endl;
1082
      indent(out) << "__" << field_name << " = nil;" << endl;
1083
    }
1084
    indent(out) << "__" << field_name << "_isset = NO;" << endl;
1085
    indent_down();
1086
    indent(out) << "}" << endl << endl;
1087
  }
1088
}
1089
 
1090
/**
1091
 * Generates a description method for the given struct
1092
 *
1093
 * @param tstruct The struct definition
1094
 */
1095
void t_cocoa_generator::generate_cocoa_struct_description(ofstream& out,
1096
                                                          t_struct* tstruct) {
1097
  out <<
1098
    indent() << "- (NSString *) description {" << endl;
1099
  indent_up();
1100
 
1101
  out <<
1102
    indent() << "NSMutableString * ms = [NSMutableString stringWithString: @\"" <<
1103
    tstruct->get_name() << "(\"];" << endl;
1104
 
1105
  const vector<t_field*>& fields = tstruct->get_members();
1106
  vector<t_field*>::const_iterator f_iter;
1107
  bool first = true;
1108
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1109
    if (first) {
1110
      first = false;
1111
      indent(out) << "[ms appendString: @\"" << (*f_iter)->get_name() << ":\"];" << endl;
1112
    } else {
1113
      indent(out) << "[ms appendString: @\"," << (*f_iter)->get_name() << ":\"];" << endl;
1114
    }
1115
    t_type* ttype = (*f_iter)->get_type();
1116
    indent(out) << "[ms appendFormat: @\"" << format_string_for_type(ttype) << "\", __" <<
1117
      (*f_iter)->get_name() << "];" << endl;
1118
  }
1119
  out <<
1120
    indent() << "[ms appendString: @\")\"];" << endl <<
1121
    indent() << "return [NSString stringWithString: ms];" << endl;
1122
 
1123
  indent_down();
1124
  indent(out) << "}" << endl <<
1125
    endl;
1126
}
1127
 
1128
 
1129
/**
1130
 * Generates a thrift service.  In Objective-C this consists of a
1131
 * protocol definition, a client interface and a client implementation.
1132
 *
1133
 * @param tservice The service definition
1134
 */
1135
void t_cocoa_generator::generate_service(t_service* tservice) {
1136
  generate_cocoa_service_protocol(f_header_, tservice);
1137
  generate_cocoa_service_client_interface(f_header_, tservice);
1138
  generate_cocoa_service_server_interface(f_header_, tservice);
1139
  generate_cocoa_service_helpers(tservice);
1140
  generate_cocoa_service_client_implementation(f_impl_, tservice);
1141
  generate_cocoa_service_server_implementation(f_impl_, tservice);
1142
}
1143
 
1144
 
1145
/**
1146
 * Generates structs for all the service return types
1147
 *
1148
 * @param tservice The service
1149
 */
1150
void t_cocoa_generator::generate_cocoa_service_helpers(t_service* tservice) {
1151
  vector<t_function*> functions = tservice->get_functions();
1152
  vector<t_function*>::iterator f_iter;
1153
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1154
    t_struct* ts = (*f_iter)->get_arglist();
1155
    generate_cocoa_struct_interface(f_impl_, ts, false);
1156
    generate_cocoa_struct_implementation(f_impl_, ts, false, false);  
1157
    generate_function_helpers(*f_iter);
1158
  }
1159
}
1160
 
1161
string t_cocoa_generator::function_result_helper_struct_type(t_function* tfunction) {
1162
  return capitalize(tfunction->get_name()) + "_result";
1163
}
1164
 
1165
 
1166
string t_cocoa_generator::function_args_helper_struct_type(t_function* tfunction) {
1167
  return tfunction->get_name() + "_args";
1168
}
1169
 
1170
 
1171
/**
1172
 * Generates a struct and helpers for a function.
1173
 *
1174
 * @param tfunction The function
1175
 */
1176
void t_cocoa_generator::generate_function_helpers(t_function* tfunction) {
1177
  if (tfunction->is_oneway()) {
1178
    return;
1179
  }
1180
 
1181
  // create a result struct with a success field of the return type,
1182
  // and a field for each type of exception thrown
1183
  t_struct result(program_, function_result_helper_struct_type(tfunction));
1184
  t_field success(tfunction->get_returntype(), "success", 0);
1185
  if (!tfunction->get_returntype()->is_void()) {
1186
    result.append(&success);
1187
  }
1188
 
1189
  t_struct* xs = tfunction->get_xceptions();
1190
  const vector<t_field*>& fields = xs->get_members();
1191
  vector<t_field*>::const_iterator f_iter;
1192
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1193
    result.append(*f_iter);
1194
  }
1195
 
1196
  // generate the result struct
1197
  generate_cocoa_struct_interface(f_impl_, &result, false);
1198
  generate_cocoa_struct_implementation(f_impl_, &result, false, true);  
1199
}
1200
 
1201
 
1202
/**
1203
 * Generates a service protocol definition.
1204
 *
1205
 * @param tservice The service to generate a protocol definition for
1206
 */
1207
void t_cocoa_generator::generate_cocoa_service_protocol(ofstream& out,
1208
                                                        t_service* tservice) {
1209
  out << "@protocol " << cocoa_prefix_ << tservice->get_name() << " <NSObject>" << endl;
1210
 
1211
  vector<t_function*> functions = tservice->get_functions();
1212
  vector<t_function*>::iterator f_iter;
1213
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1214
    out << "- " << function_signature(*f_iter) << ";" <<
1215
      "  // throws ";
1216
    t_struct* xs = (*f_iter)->get_xceptions();
1217
    const std::vector<t_field*>& xceptions = xs->get_members();
1218
    vector<t_field*>::const_iterator x_iter;
1219
    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1220
      out << type_name((*x_iter)->get_type()) + ", ";
1221
    }
1222
    out << "TException" << endl;
1223
  }
1224
  out << "@end" << endl << endl;
1225
}
1226
 
1227
 
1228
/**
1229
 * Generates a service client interface definition.
1230
 *
1231
 * @param tservice The service to generate a client interface definition for
1232
 */
1233
void t_cocoa_generator::generate_cocoa_service_client_interface(ofstream& out,
1234
                                                                t_service* tservice) {
1235
  out << "@interface " << cocoa_prefix_ << tservice->get_name() << "Client : NSObject <" <<
1236
    cocoa_prefix_ << tservice->get_name() << "> ";
1237
 
1238
  scope_up(out);
1239
  out << indent() << "id <TProtocol> inProtocol;" << endl;
1240
  out << indent() << "id <TProtocol> outProtocol;" << endl;
1241
  scope_down(out);
1242
 
1243
  out << "- (id) initWithProtocol: (id <TProtocol>) protocol;" << endl;
1244
  out << "- (id) initWithInProtocol: (id <TProtocol>) inProtocol outProtocol: (id <TProtocol>) outProtocol;" << endl;
1245
  out << "@end" << endl << endl;
1246
}
1247
 
1248
 
1249
/**
1250
 * Generates a service server interface definition. In other words, the TProcess implementation for the
1251
 * service definition.
1252
 *
1253
 * @param tservice The service to generate a client interface definition for
1254
 */
1255
void t_cocoa_generator::generate_cocoa_service_server_interface(ofstream& out,
1256
                                                                t_service* tservice) {
1257
  out << "@interface " << cocoa_prefix_ << tservice->get_name() << "Processor : NSObject <TProcessor> ";
1258
 
1259
  scope_up(out);
1260
  out << indent() << "id <" << cocoa_prefix_ << tservice->get_name() <<"> mService;" << endl;
1261
  out << indent() << "NSDictionary * mMethodMap;" << endl;
1262
  scope_down(out);
1263
 
1264
  out << "- (id) initWith" << tservice->get_name() << ": (id <" << cocoa_prefix_ << tservice->get_name() << ">) service;" << endl;
1265
  out << "- (id<"<<cocoa_prefix_ << tservice->get_name() << ">) service;" << endl;
1266
 
1267
  out << "@end" << endl << endl;
1268
}
1269
 
1270
 
1271
/**
1272
 * Generates a service client implementation.
1273
 *
1274
 * @param tservice The service to generate an implementation for
1275
 */
1276
void t_cocoa_generator::generate_cocoa_service_client_implementation(ofstream& out,
1277
                                                                     t_service* tservice) {
1278
  out << "@implementation " << cocoa_prefix_ << tservice->get_name() << "Client" << endl;
1279
 
1280
  // initializers
1281
  out << "- (id) initWithProtocol: (id <TProtocol>) protocol" << endl;
1282
  scope_up(out);
1283
  out << indent() << "return [self initWithInProtocol: protocol outProtocol: protocol];" << endl;
1284
  scope_down(out);
1285
  out << endl;
1286
 
1287
  out << "- (id) initWithInProtocol: (id <TProtocol>) anInProtocol outProtocol: (id <TProtocol>) anOutProtocol" << endl;
1288
  scope_up(out);
1289
  out << indent() << "[super init];" << endl;
1290
  out << indent() << "inProtocol = [anInProtocol retain];" << endl;
1291
  out << indent() << "outProtocol = [anOutProtocol retain];" << endl;
1292
  out << indent() << "return self;" << endl;
1293
  scope_down(out);
1294
  out << endl;
1295
 
1296
  // dealloc
1297
  out << "- (void) dealloc" << endl;
1298
  scope_up(out);
1299
  out << indent() << "[inProtocol release];" << endl;
1300
  out << indent() << "[outProtocol release];" << endl;
1301
  out << indent() << "[super dealloc];" << endl;
1302
  scope_down(out);
1303
  out << endl;
1304
 
1305
  // generate client method implementations
1306
  vector<t_function*> functions = tservice->get_functions();
1307
  vector<t_function*>::const_iterator f_iter;
1308
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1309
    string funname = (*f_iter)->get_name();
1310
 
1311
    t_function send_function(g_type_void,
1312
                             string("send_") + (*f_iter)->get_name(),
1313
                             (*f_iter)->get_arglist());
1314
 
1315
    string argsname = (*f_iter)->get_name() + "_args";
1316
 
1317
    // Open function
1318
    indent(out) <<
1319
      "- " << function_signature(&send_function) << endl;
1320
    scope_up(out);
1321
 
1322
    // Serialize the request
1323
    out <<
1324
      indent() << "[outProtocol writeMessageBeginWithName: @\"" << funname << "\"" <<
1325
      " type: TMessageType_CALL" <<
1326
      " sequenceID: 0];" << endl;
1327
 
1328
    out <<
1329
      indent() << "[outProtocol writeStructBeginWithName: @\"" << argsname << "\"];" << endl;
1330
 
1331
    // write out function parameters
1332
    t_struct* arg_struct = (*f_iter)->get_arglist();
1333
    const vector<t_field*>& fields = arg_struct->get_members();
1334
    vector<t_field*>::const_iterator fld_iter;
1335
    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1336
      string fieldName = (*fld_iter)->get_name();
1337
      if (type_can_be_null((*fld_iter)->get_type())) {
1338
        out << indent() << "if (" << fieldName << " != nil)";
1339
        scope_up(out);
1340
      }
1341
      out <<
1342
        indent() << "[outProtocol writeFieldBeginWithName: @\"" << fieldName << "\""
1343
        " type: " << type_to_enum((*fld_iter)->get_type()) <<
1344
        " fieldID: " << (*fld_iter)->get_key() << "];" << endl;
1345
 
1346
      generate_serialize_field(out, *fld_iter, fieldName);
1347
 
1348
      out <<
1349
        indent() << "[outProtocol writeFieldEnd];" << endl;
1350
 
1351
      if (type_can_be_null((*fld_iter)->get_type())) {
1352
        scope_down(out);
1353
      }
1354
    }
1355
 
1356
    out <<
1357
      indent() << "[outProtocol writeFieldStop];" << endl;
1358
    out <<
1359
      indent() << "[outProtocol writeStructEnd];" << endl;
1360
 
1361
    out <<
1362
      indent() << "[outProtocol writeMessageEnd];" << endl <<
1363
      indent() << "[[outProtocol transport] flush];" << endl;
1364
 
1365
    scope_down(out);
1366
    out << endl;
1367
 
1368
    if (!(*f_iter)->is_oneway()) {
1369
      t_struct noargs(program_);
1370
      t_function recv_function((*f_iter)->get_returntype(),
1371
                               string("recv_") + (*f_iter)->get_name(),
1372
                               &noargs,
1373
                               (*f_iter)->get_xceptions());
1374
      // Open function
1375
      indent(out) <<
1376
        "- " << function_signature(&recv_function) << endl;
1377
      scope_up(out);
1378
 
1379
      // TODO(mcslee): Message validation here, was the seqid etc ok?
1380
 
1381
      // check for an exception
1382
      out <<
1383
        indent() << "int msgType = 0;" << endl <<
1384
        indent() << "[inProtocol readMessageBeginReturningName: nil type: &msgType sequenceID: NULL];" << endl <<
1385
        indent() << "if (msgType == TMessageType_EXCEPTION) {" << endl <<
1386
        indent() << "  TApplicationException * x = [TApplicationException read: inProtocol];" << endl <<
1387
        indent() << "  [inProtocol readMessageEnd];" << endl <<
1388
        indent() << "  @throw x;" << endl <<
1389
        indent() << "}" << endl;
1390
 
1391
      // FIXME - could optimize here to reduce creation of temporary objects.
1392
      string resultname = function_result_helper_struct_type(*f_iter);
1393
      out <<
1394
        indent() << cocoa_prefix_ << resultname << " * result = [[[" << cocoa_prefix_ <<
1395
        resultname << " alloc] init] autorelease];" << endl;
1396
      indent(out) << "[result read: inProtocol];" << endl;
1397
      indent(out) << "[inProtocol readMessageEnd];" << endl;
1398
 
1399
      // Careful, only return _result if not a void function
1400
      if (!(*f_iter)->get_returntype()->is_void()) {
1401
        out <<
1402
          indent() << "if ([result successIsSet]) {" << endl <<
1403
          indent() << "  return [result success];" << endl <<
1404
          indent() << "}" << endl;
1405
      }
1406
 
1407
      t_struct* xs = (*f_iter)->get_xceptions();
1408
      const std::vector<t_field*>& xceptions = xs->get_members();
1409
      vector<t_field*>::const_iterator x_iter;
1410
      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1411
        out <<
1412
          indent() << "if ([result " << (*x_iter)->get_name() << "IsSet]) {" << endl <<
1413
          indent() << "  @throw [result " << (*x_iter)->get_name() << "];" << endl <<
1414
          indent() << "}" << endl;
1415
      }
1416
 
1417
      // If you get here it's an exception, unless a void function
1418
      if ((*f_iter)->get_returntype()->is_void()) {
1419
        indent(out) <<
1420
          "return;" << endl;
1421
      } else {
1422
        out <<
1423
          indent() << "@throw [TApplicationException exceptionWithType: TApplicationException_MISSING_RESULT" << endl <<
1424
          indent() << "                                         reason: @\"" << (*f_iter)->get_name() << " failed: unknown result\"];" << endl;
1425
      }
1426
 
1427
      // Close function
1428
      scope_down(out);
1429
      out << endl;
1430
    }
1431
 
1432
    // Open function
1433
    indent(out) <<
1434
      "- " << function_signature(*f_iter) << endl;
1435
    scope_up(out);
1436
    indent(out) <<
1437
      "[self send_" << funname;
1438
 
1439
    // Declare the function arguments
1440
    bool first = true;
1441
    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1442
      if (first) {
1443
        first = false;
1444
      } else {
1445
        out << " ";
1446
      }
1447
      out << ": " << (*fld_iter)->get_name();
1448
    }
1449
    out << "];" << endl;
1450
 
1451
    if (!(*f_iter)->is_oneway()) {
1452
      out << indent();
1453
      if (!(*f_iter)->get_returntype()->is_void()) {
1454
        out << "return ";
1455
      }
1456
      out <<
1457
        "[self recv_" << funname << "];" << endl;
1458
    }
1459
    scope_down(out);
1460
    out << endl;
1461
  }
1462
 
1463
  indent_down();
1464
 
1465
  out << "@end" << endl << endl;
1466
}
1467
 
1468
 
1469
/**
1470
 * Generates a service server implementation.  In other words the actual TProcessor implementation
1471
 * for the service.
1472
 *
1473
 * @param tservice The service to generate an implementation for
1474
 */
1475
void t_cocoa_generator::generate_cocoa_service_server_implementation(ofstream& out,
1476
                                                                     t_service* tservice) {
1477
  out << "@implementation " << cocoa_prefix_ << tservice->get_name() << "Processor" << endl;
1478
  indent_up();
1479
 
1480
  // initializer
1481
  out << endl;
1482
  out << "- (id) initWith" << tservice->get_name() << ": (id <" << cocoa_prefix_ << tservice->get_name() << ">) service" << endl;
1483
  scope_up(out);
1484
  out << indent() << "self = [super init];" << endl;
1485
  out << indent() << "if (!self) {" << endl;
1486
  out << indent() << "  return nil;" << endl;
1487
  out << indent() << "}" << endl;
1488
  out << indent() << "mService = [service retain];" << endl;
1489
  out << indent() << "mMethodMap = [[NSMutableDictionary dictionary] retain];" << endl;
1490
 
1491
  // generate method map for routing incoming calls
1492
  vector<t_function*> functions = tservice->get_functions();
1493
  vector<t_function*>::const_iterator f_iter;
1494
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1495
    string funname = (*f_iter)->get_name();
1496
    scope_up(out);
1497
    out << indent() << "SEL s = @selector(process_" << funname << "_withSequenceID:inProtocol:outProtocol:);" << endl;
1498
    out << indent() << "NSMethodSignature * sig = [self methodSignatureForSelector: s];" << endl;
1499
    out << indent() << "NSInvocation * invocation = [NSInvocation invocationWithMethodSignature: sig];" << endl;
1500
    out << indent() << "[invocation setSelector: s];" << endl;
1501
    out << indent() << "[invocation retainArguments];" << endl;
1502
    out << indent() << "[mMethodMap setValue: invocation forKey: @\"" << funname << "\"];" << endl;
1503
    scope_down(out);
1504
  }
1505
  out << indent() << "return self;" << endl;
1506
  scope_down(out);
1507
 
1508
  // implementation of the 'service' method which returns the service associated with this
1509
  // processor
1510
  out << endl;
1511
  out << indent() << "- (id<"<<cocoa_prefix_ << tservice->get_name() << ">) service" << endl;
1512
  out << indent() << "{" << endl;
1513
  out << indent() << "  return [[mService retain] autorelease];" << endl;
1514
  out << indent() << "}" << endl;
1515
 
1516
  // implementation of the TProcess method, which dispatches the incoming call using the method map
1517
  out << endl;
1518
  out << indent() << "- (BOOL) processOnInputProtocol: (id <TProtocol>) inProtocol" << endl;
1519
  out << indent() << "                 outputProtocol: (id <TProtocol>) outProtocol" <<endl;
1520
  out << indent() << "{" << endl;
1521
  out << indent() << "  NSString * messageName;" << endl;
1522
  out << indent() << "  int messageType;" << endl;
1523
  out << indent() << "  int seqID;" << endl;
1524
  out << indent() << "  [inProtocol readMessageBeginReturningName: &messageName" << endl;
1525
  out << indent() << "                                       type: &messageType" << endl;
1526
  out << indent() << "                                 sequenceID: &seqID];" << endl;
1527
  out << indent() << "  NSInvocation * invocation = [mMethodMap valueForKey: messageName];" << endl;
1528
  out << indent() << "  if (invocation == nil) {" << endl;
1529
  out << indent() << "    [TProtocolUtil skipType: TType_STRUCT onProtocol: inProtocol];" << endl;
1530
  out << indent() << "    [inProtocol readMessageEnd];" << endl;
1531
  out << indent() << "    TApplicationException * x = [TApplicationException exceptionWithType: TApplicationException_UNKNOWN_METHOD reason: [NSString stringWithFormat: @\"Invalid method name: '%@'\", messageName]];" << endl;
1532
  out << indent() << "    [outProtocol writeMessageBeginWithName: messageName" << endl;
1533
  out << indent() << "                                      type: TMessageType_EXCEPTION" << endl;
1534
  out << indent() << "                                sequenceID: seqID];" << endl;
1535
  out << indent() << "    [x write: outProtocol];" << endl;
1536
  out << indent() << "    [outProtocol writeMessageEnd];" << endl;
1537
  out << indent() << "    [[outProtocol transport] flush];" << endl;
1538
  out << indent() << "    return YES;" << endl;
1539
  out << indent() << "  }" << endl;
1540
  out << indent() << "  // NSInvocation does not conform to NSCopying protocol" << endl;
1541
  out << indent() << "  NSInvocation * i = [NSInvocation invocationWithMethodSignature: [invocation methodSignature]];" << endl;
1542
  out << indent() << "  [i setSelector: [invocation selector]];" << endl;
1543
  out << indent() << "  [i setArgument: &seqID atIndex: 2];" << endl;
1544
  out << indent() << "  [i setArgument: &inProtocol atIndex: 3];" << endl;
1545
  out << indent() << "  [i setArgument: &outProtocol atIndex: 4];" << endl;
1546
  out << indent() << "  [i setTarget: self];" << endl;
1547
  out << indent() << "  [i invoke];" << endl;
1548
  out << indent() << "  return YES;" << endl;
1549
  out << indent() << "}" << endl;
1550
 
1551
  // generate a process_XXXX method for each service function, which reads args, calls the service, and writes results
1552
  functions = tservice->get_functions();
1553
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1554
    out << endl;
1555
    string funname = (*f_iter)->get_name();
1556
    out << indent() << "- (void) process_" << funname << "_withSequenceID: (int32_t) seqID inProtocol: (id<TProtocol>) inProtocol outProtocol: (id<TProtocol>) outProtocol" << endl;
1557
    scope_up(out);
1558
    string argstype = cocoa_prefix_ + function_args_helper_struct_type(*f_iter);
1559
    out << indent() << argstype << " * args = [[" << argstype << " alloc] init];" << endl;
1560
    out << indent() << "[args read: inProtocol];" << endl;
1561
    out << indent() << "[inProtocol readMessageEnd];" << endl;
1562
 
1563
    string resulttype = cocoa_prefix_ + function_result_helper_struct_type(*f_iter);
1564
    out << indent() << resulttype << " * result = [[" << resulttype << " alloc] init];" << endl;
1565
 
1566
    // make the call to the actual service object
1567
    out << indent();
1568
    if (!(*f_iter)->get_returntype()->is_void()) {
1569
      out << "[result setSuccess: ";
1570
    }
1571
    out << "[mService " << funname;
1572
    // supplying arguments
1573
    t_struct* arg_struct = (*f_iter)->get_arglist();
1574
    const vector<t_field*>& fields = arg_struct->get_members();
1575
    vector<t_field*>::const_iterator fld_iter;
1576
    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1577
      string fieldName = (*fld_iter)->get_name();
1578
      out << ": [args " << fieldName << "]";
1579
    }
1580
    out << "]";
1581
    if (!(*f_iter)->get_returntype()->is_void()) {
1582
      out << "]";
1583
    }
1584
    out << ";" << endl;
1585
 
1586
    // write out the result
1587
    out << indent() << "[outProtocol writeMessageBeginWithName: @\"" << funname << "\"" << endl;
1588
    out << indent() << "                                  type: TMessageType_REPLY" << endl;
1589
    out << indent() << "                            sequenceID: seqID];" << endl;
1590
    out << indent() << "[result write: outProtocol];" << endl;
1591
    out << indent() << "[outProtocol writeMessageEnd];" << endl;
1592
    out << indent() << "[[outProtocol transport] flush];" << endl;
1593
    out << indent() << "[result release];" << endl;
1594
    out << indent() << "[args release];" << endl;
1595
 
1596
    scope_down(out);
1597
  }
1598
 
1599
  // dealloc
1600
  out << endl;
1601
  out << "- (void) dealloc" << endl;
1602
  scope_up(out);
1603
  out << indent() << "[mService release];" << endl;
1604
  out << indent() << "[mMethodMap release];" << endl;
1605
  out << indent() << "[super dealloc];" << endl;
1606
  scope_down(out);
1607
  out << endl;
1608
 
1609
  indent_down();
1610
 
1611
  out << "@end" << endl << endl;
1612
}
1613
 
1614
 
1615
/**
1616
 * Deserializes a field of any type.
1617
 *
1618
 * @param tfield The field
1619
 * @param fieldName The variable name for this field
1620
 */
1621
void t_cocoa_generator::generate_deserialize_field(ofstream& out,
1622
                                                   t_field* tfield,
1623
                                                   string fieldName) {
1624
  t_type* type = get_true_type(tfield->get_type());
1625
 
1626
  if (type->is_void()) {
1627
    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
1628
      tfield->get_name();
1629
  }
1630
 
1631
  if (type->is_struct() || type->is_xception()) {
1632
    generate_deserialize_struct(out,
1633
                                (t_struct*)type,
1634
                                fieldName);
1635
  } else if (type->is_container()) {
1636
    generate_deserialize_container(out, type, fieldName);
1637
  } else if (type->is_base_type() || type->is_enum()) {
1638
    indent(out) <<
1639
      type_name(type) << " " << fieldName << " = [inProtocol ";
1640
 
1641
    if (type->is_base_type()) {
1642
      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1643
      switch (tbase) {
1644
      case t_base_type::TYPE_VOID:
1645
        throw "compiler error: cannot serialize void field in a struct: " +
1646
          tfield->get_name();
1647
        break;
1648
      case t_base_type::TYPE_STRING:
1649
        if (((t_base_type*)type)->is_binary()) {
1650
          out << "readBinary];";
1651
        } else {
1652
          out << "readString];";
1653
        }
1654
        break;
1655
      case t_base_type::TYPE_BOOL:
1656
        out << "readBool];";
1657
        break;
1658
      case t_base_type::TYPE_BYTE:
1659
        out << "readByte];";
1660
        break;
1661
      case t_base_type::TYPE_I16:
1662
        out << "readI16];";
1663
        break;
1664
      case t_base_type::TYPE_I32:
1665
        out << "readI32];";
1666
        break;
1667
      case t_base_type::TYPE_I64:
1668
        out << "readI64];";
1669
        break;
1670
      case t_base_type::TYPE_DOUBLE:
1671
        out << "readDouble];";
1672
        break;
1673
      default:
1674
        throw "compiler error: no Objective-C name for base type " + t_base_type::t_base_name(tbase);
1675
      }
1676
    } else if (type->is_enum()) {
1677
      out << "readI32];";
1678
    }
1679
    out <<
1680
      endl;
1681
  } else {
1682
    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
1683
           tfield->get_name().c_str(), type_name(type).c_str());
1684
  }
1685
}
1686
 
1687
/**
1688
 * Generates an unserializer for a struct, allocates the struct and invokes read:
1689
 */
1690
void t_cocoa_generator::generate_deserialize_struct(ofstream& out,
1691
                                                    t_struct* tstruct,
1692
                                                    string fieldName) {
1693
  indent(out) << type_name(tstruct) << fieldName << " = [[" <<
1694
    type_name(tstruct, true) << " alloc] init];" << endl;
1695
  indent(out) << "[" << fieldName << " read: inProtocol];" << endl;
1696
}
1697
 
1698
/**
1699
 * Deserializes a container by reading its size and then iterating
1700
 */
1701
void t_cocoa_generator::generate_deserialize_container(ofstream& out,
1702
                                                       t_type* ttype,
1703
                                                       string fieldName) {
1704
  string size = tmp("_size");
1705
  indent(out) << "int " << size << ";" << endl;
1706
 
1707
  // Declare variables, read header
1708
  if (ttype->is_map()) {
1709
    indent(out)
1710
      << "[inProtocol readMapBeginReturningKeyType: NULL valueType: NULL size: &" <<
1711
      size << "];" << endl;
1712
    indent(out) << "NSMutableDictionary * " << fieldName <<
1713
      " = [[NSMutableDictionary alloc] initWithCapacity: " << size << "];" << endl;
1714
  } else if (ttype->is_set()) {
1715
    indent(out)
1716
      << "[inProtocol readSetBeginReturningElementType: NULL size: &" << size << "];" << endl;
1717
    indent(out) << "NSMutableSet * " << fieldName <<
1718
      " = [[NSMutableSet alloc] initWithCapacity: " << size << "];" << endl;
1719
  } else if (ttype->is_list()) {
1720
    indent(out)
1721
      << "[inProtocol readListBeginReturningElementType: NULL size: &" << size << "];" << endl;
1722
    indent(out) << "NSMutableArray * " << fieldName <<
1723
      " = [[NSMutableArray alloc] initWithCapacity: " << size << "];" << endl;
1724
  }
1725
  // FIXME - the code above does not verify that the element types of
1726
  // the containers being read match the element types of the
1727
  // containers we are reading into.  Does that matter?
1728
 
1729
  // For loop iterates over elements
1730
  string i = tmp("_i");
1731
  indent(out) << "int " << i << ";" << endl <<
1732
    indent() << "for (" << i << " = 0; " <<
1733
    i << " < " << size << "; " <<
1734
    "++" << i << ")" << endl;
1735
 
1736
    scope_up(out);
1737
 
1738
    if (ttype->is_map()) {
1739
      generate_deserialize_map_element(out, (t_map*)ttype, fieldName);
1740
    } else if (ttype->is_set()) {
1741
      generate_deserialize_set_element(out, (t_set*)ttype, fieldName);
1742
    } else if (ttype->is_list()) {
1743
      generate_deserialize_list_element(out, (t_list*)ttype, fieldName);
1744
    }
1745
 
1746
    scope_down(out);
1747
 
1748
  // Read container end
1749
  if (ttype->is_map()) {
1750
    indent(out) << "[inProtocol readMapEnd];" << endl;
1751
  } else if (ttype->is_set()) {
1752
    indent(out) << "[inProtocol readSetEnd];" << endl;
1753
  } else if (ttype->is_list()) {
1754
    indent(out) << "[inProtocol readListEnd];" << endl;
1755
  }
1756
 
1757
}
1758
 
1759
 
1760
/**
1761
 * Take a variable of a given type and wrap it in code to make it
1762
 * suitable for putting into a container, if necessary.  Basically,
1763
 * wrap scaler primitives in NSNumber objects.
1764
 */
1765
string t_cocoa_generator::containerize(t_type * ttype,
1766
                                       string fieldName)
1767
{
1768
  // FIXME - optimize here to avoid autorelease pool?
1769
  ttype = get_true_type(ttype);
1770
  if (ttype->is_enum()) {
1771
    return "[NSNumber numberWithInt: " + fieldName + "]";
1772
  } else if (ttype->is_base_type()) {
1773
    t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
1774
    switch (tbase) {
1775
    case t_base_type::TYPE_VOID:
1776
      throw "can't containerize void";
1777
    case t_base_type::TYPE_BOOL:
1778
      return "[NSNumber numberWithBool: " + fieldName + "]";
1779
    case t_base_type::TYPE_BYTE:
1780
      return "[NSNumber numberWithUnsignedChar: " + fieldName + "]";
1781
    case t_base_type::TYPE_I16:
1782
      return "[NSNumber numberWithShort: " + fieldName + "]";
1783
    case t_base_type::TYPE_I32:
1784
      return "[NSNumber numberWithLong: " + fieldName + "]";
1785
    case t_base_type::TYPE_I64:
1786
      return "[NSNumber numberWithLongLong: " + fieldName + "]";
1787
    case t_base_type::TYPE_DOUBLE:
1788
      return "[NSNumber numberWithDouble: " + fieldName + "]";
1789
    default:
1790
      break;
1791
    }
1792
  }
1793
 
1794
  // do nothing
1795
  return fieldName;
1796
}
1797
 
1798
 
1799
/**
1800
 * Generates code to deserialize a map element
1801
 */
1802
void t_cocoa_generator::generate_deserialize_map_element(ofstream& out,
1803
                                                         t_map* tmap,
1804
                                                         string fieldName) {
1805
  string key = tmp("_key");
1806
  string val = tmp("_val");
1807
  t_type* keyType = tmap->get_key_type();
1808
  t_type* valType = tmap->get_val_type();
1809
  t_field fkey(keyType, key);
1810
  t_field fval(valType, val);
1811
 
1812
  generate_deserialize_field(out, &fkey, key);
1813
  generate_deserialize_field(out, &fval, val);
1814
 
1815
  indent(out) <<
1816
    "[" << fieldName << " setObject: " << containerize(valType, val) <<
1817
    " forKey: " << containerize(keyType, key) << "];" << endl;
1818
 
1819
  if (type_can_be_null(keyType)) {
1820
    if (!(get_true_type(keyType)->is_string())) {
1821
      indent(out) << "[" << containerize(keyType, key) << " release];" << endl;
1822
    }
1823
  }
1824
 
1825
  if (type_can_be_null(valType)) {
1826
    if (!(get_true_type(valType)->is_string())) {
1827
      indent(out) << "[" << containerize(valType, val) << " release];" << endl;
1828
    }
1829
  }
1830
}
1831
 
1832
/**
1833
 * Deserializes a set element
1834
 */
1835
void t_cocoa_generator::generate_deserialize_set_element(ofstream& out,
1836
                                                         t_set* tset,
1837
                                                         string fieldName) {
1838
  string elem = tmp("_elem");
1839
  t_type* type = tset->get_elem_type();
1840
  t_field felem(type, elem);
1841
 
1842
  generate_deserialize_field(out, &felem, elem);
1843
 
1844
  indent(out) <<
1845
    "[" << fieldName << " addObject: " << containerize(type, elem) << "];" << endl;
1846
 
1847
  if (type_can_be_null(type)) {
1848
    // deserialized strings are autorelease, so don't release them
1849
    if (!(get_true_type(type)->is_string())) {
1850
      indent(out) << "[" << containerize(type, elem) << " release];" << endl;
1851
    }
1852
  }
1853
}
1854
 
1855
/**
1856
 * Deserializes a list element
1857
 */
1858
void t_cocoa_generator::generate_deserialize_list_element(ofstream& out,
1859
                                                          t_list* tlist,
1860
                                                          string fieldName) {
1861
  string elem = tmp("_elem");
1862
  t_type* type = tlist->get_elem_type();
1863
  t_field felem(type, elem);
1864
 
1865
  generate_deserialize_field(out, &felem, elem);
1866
 
1867
  indent(out) <<
1868
    "[" << fieldName << " addObject: " << containerize(type, elem) << "];" << endl;
1869
 
1870
  if (type_can_be_null(type)) {
1871
    if (!(get_true_type(type)->is_string())) {
1872
      indent(out) << "[" << containerize(type, elem) << " release];" << endl;
1873
    }
1874
  }
1875
}
1876
 
1877
 
1878
/**
1879
 * Serializes a field of any type.
1880
 *
1881
 * @param tfield The field to serialize
1882
 * @param fieldName Name to of the variable holding the field
1883
 */
1884
void t_cocoa_generator::generate_serialize_field(ofstream& out,
1885
                                                 t_field* tfield,
1886
                                                 string fieldName) {
1887
  t_type* type = get_true_type(tfield->get_type());
1888
 
1889
  // Do nothing for void types
1890
  if (type->is_void()) {
1891
    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
1892
      tfield->get_name();
1893
  }
1894
 
1895
  if (type->is_struct() || type->is_xception()) {
1896
    generate_serialize_struct(out,
1897
                              (t_struct*)type,
1898
                              fieldName);
1899
  } else if (type->is_container()) {
1900
    generate_serialize_container(out,
1901
                                 type,
1902
                                 fieldName);
1903
  } else if (type->is_base_type() || type->is_enum()) {
1904
    indent(out) <<
1905
      "[outProtocol ";
1906
 
1907
    if (type->is_base_type()) {
1908
      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1909
      switch (tbase) {
1910
      case t_base_type::TYPE_VOID:
1911
        throw
1912
          "compiler error: cannot serialize void field in a struct: " + fieldName;
1913
        break;
1914
      case t_base_type::TYPE_STRING:
1915
        if (((t_base_type*)type)->is_binary()) {
1916
          out << "writeBinary: " << fieldName << "];";
1917
        } else {
1918
          out << "writeString: " << fieldName << "];";
1919
        }
1920
        break;
1921
      case t_base_type::TYPE_BOOL:
1922
        out << "writeBool: " << fieldName << "];";
1923
        break;
1924
      case t_base_type::TYPE_BYTE:
1925
        out << "writeByte: " << fieldName << "];";
1926
        break;
1927
      case t_base_type::TYPE_I16:
1928
        out << "writeI16: " << fieldName << "];";
1929
        break;
1930
      case t_base_type::TYPE_I32:
1931
        out << "writeI32: " << fieldName << "];";
1932
        break;
1933
      case t_base_type::TYPE_I64:
1934
        out << "writeI64: " << fieldName << "];";
1935
        break;
1936
      case t_base_type::TYPE_DOUBLE:
1937
        out << "writeDouble: " << fieldName << "];";
1938
        break;
1939
      default:
1940
        throw "compiler error: no Java name for base type " + t_base_type::t_base_name(tbase);
1941
      }
1942
    } else if (type->is_enum()) {
1943
      out << "writeI32: " << fieldName << "];";
1944
    }
1945
    out << endl;
1946
  } else {
1947
    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s' TYPE '%s'\n",
1948
           tfield->get_name().c_str(),
1949
           type_name(type).c_str());
1950
  }
1951
}
1952
 
1953
/**
1954
 * Serialize a struct.
1955
 *
1956
 * @param tstruct The struct to serialize
1957
 * @param fieldName Name of variable holding struct
1958
 */
1959
void t_cocoa_generator::generate_serialize_struct(ofstream& out,
1960
                                                  t_struct* tstruct,
1961
                                                  string fieldName) {
1962
  out <<
1963
    indent() << "[" << fieldName << " write: outProtocol];" << endl;
1964
}
1965
 
1966
/**
1967
 * Serializes a container by writing its size then the elements.
1968
 *
1969
 * @param ttype  The type of container
1970
 * @param fieldName Name of variable holding container
1971
 */
1972
void t_cocoa_generator::generate_serialize_container(ofstream& out,
1973
                                                     t_type* ttype,
1974
                                                     string fieldName) {
1975
  scope_up(out);
1976
 
1977
  if (ttype->is_map()) {
1978
    indent(out) <<
1979
      "[outProtocol writeMapBeginWithKeyType: " <<
1980
      type_to_enum(((t_map*)ttype)->get_key_type()) << " valueType: " <<
1981
      type_to_enum(((t_map*)ttype)->get_val_type()) << " size: [" <<
1982
      fieldName << " count]];" << endl;
1983
  } else if (ttype->is_set()) {
1984
    indent(out) <<
1985
      "[outProtocol writeSetBeginWithElementType: " <<
1986
      type_to_enum(((t_set*)ttype)->get_elem_type()) << " size: [" <<
1987
      fieldName << " count]];" << endl;
1988
  } else if (ttype->is_list()) {
1989
    indent(out) <<
1990
      "[outProtocol writeListBeginWithElementType: " <<
1991
      type_to_enum(((t_list*)ttype)->get_elem_type()) << " size: [" <<
1992
      fieldName << " count]];" << endl;
1993
  }
1994
 
1995
  string iter = tmp("_iter");
1996
  string key;
1997
  if (ttype->is_map()) {
1998
    key = tmp("key");
1999
    indent(out) << "NSEnumerator * " << iter << " = [" << fieldName << " keyEnumerator];" << endl;
2000
    indent(out) << "id " << key << ";" << endl;
2001
    indent(out) << "while ((" << key << " = [" << iter << " nextObject]))" << endl;
2002
  } else if (ttype->is_set()) {
2003
    key = tmp("obj");
2004
    indent(out) << "NSEnumerator * " << iter << " = [" << fieldName << " objectEnumerator];" << endl;
2005
    indent(out) << "id " << key << ";" << endl;
2006
    indent(out) << "while ((" << key << " = [" << iter << " nextObject]))" << endl;
2007
  } else if (ttype->is_list()) {
2008
    key = tmp("i");
2009
    indent(out) << "int " << key << ";" << endl;
2010
    indent(out) <<
2011
      "for (" << key << " = 0; " << key << " < [" << fieldName << " count]; " << key << "++)" << endl;
2012
  }
2013
 
2014
    scope_up(out);
2015
 
2016
    if (ttype->is_map()) {
2017
      generate_serialize_map_element(out, (t_map*)ttype, key, fieldName);
2018
    } else if (ttype->is_set()) {
2019
      generate_serialize_set_element(out, (t_set*)ttype, key);
2020
    } else if (ttype->is_list()) {
2021
      generate_serialize_list_element(out, (t_list*)ttype, key, fieldName);
2022
    }
2023
 
2024
    scope_down(out);
2025
 
2026
    if (ttype->is_map()) {
2027
      indent(out) <<
2028
        "[outProtocol writeMapEnd];" << endl;
2029
    } else if (ttype->is_set()) {
2030
      indent(out) <<
2031
        "[outProtocol writeSetEnd];" << endl;
2032
    } else if (ttype->is_list()) {
2033
      indent(out) <<
2034
        "[outProtocol writeListEnd];" << endl;
2035
    }
2036
 
2037
  scope_down(out);
2038
}
2039
 
2040
/**
2041
 * Given a field variable name, wrap it in code that converts it to a
2042
 * primitive type, if necessary.
2043
 */
2044
string t_cocoa_generator::decontainerize(t_field * tfield,
2045
                                         string fieldName)
2046
{
2047
  t_type * ttype = get_true_type(tfield->get_type());
2048
  if (ttype->is_enum()) {
2049
    return "[" + fieldName + " intValue]";
2050
  } else if (ttype->is_base_type()) {
2051
    t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
2052
    switch (tbase) {
2053
    case t_base_type::TYPE_VOID:
2054
      throw "can't decontainerize void";
2055
    case t_base_type::TYPE_BOOL:
2056
      return "[" + fieldName + " boolValue]";
2057
    case t_base_type::TYPE_BYTE:
2058
      return "[" + fieldName + " unsignedCharValue]";
2059
    case t_base_type::TYPE_I16:
2060
      return "[" + fieldName + " shortValue]";
2061
    case t_base_type::TYPE_I32:
2062
      return "[" + fieldName + " longValue]";
2063
    case t_base_type::TYPE_I64:
2064
      return "[" + fieldName + " longLongValue]";
2065
    case t_base_type::TYPE_DOUBLE:
2066
      return "[" + fieldName + " doubleValue]";
2067
    default:
2068
      break;
2069
    }
2070
  }
2071
 
2072
  // do nothing
2073
  return fieldName;
2074
}
2075
 
2076
 
2077
/**
2078
 * Serializes the members of a map.
2079
 */
2080
void t_cocoa_generator::generate_serialize_map_element(ofstream& out,
2081
                                                       t_map* tmap,
2082
                                                       string key,
2083
                                                       string mapName) {
2084
  t_field kfield(tmap->get_key_type(), key);
2085
  generate_serialize_field(out, &kfield, decontainerize(&kfield, key));
2086
  t_field vfield(tmap->get_val_type(), "[" + mapName + " objectForKey: " + key + "]");
2087
  generate_serialize_field(out, &vfield, decontainerize(&vfield, vfield.get_name()));
2088
}
2089
 
2090
/**
2091
 * Serializes the members of a set.
2092
 */
2093
void t_cocoa_generator::generate_serialize_set_element(ofstream& out,
2094
                                                       t_set* tset,
2095
                                                       string elementName) {
2096
  t_field efield(tset->get_elem_type(), elementName);
2097
  generate_serialize_field(out, &efield, decontainerize(&efield, elementName));
2098
}
2099
 
2100
/**
2101
 * Serializes the members of a list.
2102
 */
2103
void t_cocoa_generator::generate_serialize_list_element(ofstream& out,
2104
                                                        t_list* tlist,
2105
                                                        string index,
2106
                                                        string listName) {
2107
  t_field efield(tlist->get_elem_type(), "[" + listName + " objectAtIndex: " + index + "]");
2108
  generate_serialize_field(out, &efield, decontainerize(&efield, efield.get_name()));
2109
}
2110
 
2111
 
2112
/**
2113
 * Returns an Objective-C name
2114
 *
2115
 * @param ttype The type
2116
 * @param class_ref Do we want a Class reference istead of a type reference?
2117
 * @return Java type name, i.e. HashMap<Key,Value>
2118
 */
2119
string t_cocoa_generator::type_name(t_type* ttype, bool class_ref) {
2120
  if (ttype->is_typedef()) {
2121
    return cocoa_prefix_ + ttype->get_name();
2122
  }
2123
 
2124
  string result;
2125
  if (ttype->is_base_type()) {
2126
    return base_type_name((t_base_type*)ttype);
2127
  } else if (ttype->is_enum()) {
2128
    return "int";
2129
  } else if (ttype->is_map()) {
2130
    result = "NSDictionary";
2131
  } else if (ttype->is_set()) {
2132
    result = "NSSet";
2133
  } else if (ttype->is_list()) {
2134
    result = "NSArray";
2135
  } else {
2136
    // Check for prefix
2137
    t_program* program = ttype->get_program();
2138
    if (program != NULL) {
2139
      result = program->get_namespace("cocoa") + ttype->get_name();
2140
    } else {
2141
      result = ttype->get_name();
2142
    }
2143
  }
2144
 
2145
  if (!class_ref) {
2146
    result += " *";
2147
  }
2148
  return result;
2149
}
2150
 
2151
/**
2152
 * Returns the Objective-C type that corresponds to the thrift type.
2153
 *
2154
 * @param tbase The base type
2155
 */
2156
string t_cocoa_generator::base_type_name(t_base_type* type) {
2157
  t_base_type::t_base tbase = type->get_base();
2158
 
2159
  switch (tbase) {
2160
  case t_base_type::TYPE_VOID:
2161
    return "void";
2162
  case t_base_type::TYPE_STRING:
2163
    if (type->is_binary()) {
2164
      return "NSData *";
2165
    } else {
2166
      return "NSString *";
2167
    }
2168
  case t_base_type::TYPE_BOOL:
2169
    return "BOOL";
2170
  case t_base_type::TYPE_BYTE:
2171
    return "uint8_t";
2172
  case t_base_type::TYPE_I16:
2173
    return"int16_t";
2174
  case t_base_type::TYPE_I32:
2175
    return "int32_t";
2176
  case t_base_type::TYPE_I64:
2177
    return"int64_t";
2178
  case t_base_type::TYPE_DOUBLE:
2179
    return "double";
2180
  default:
2181
    throw "compiler error: no objective-c name for base type " + t_base_type::t_base_name(tbase);
2182
  }
2183
}
2184
 
2185
 
2186
/**
2187
 * Spit out code that evaluates to the specified constant value.
2188
 */
2189
string t_cocoa_generator::render_const_value(string name,
2190
                                             t_type* type,
2191
                                             t_const_value* value,
2192
                                             bool containerize_it) {
2193
  type = get_true_type(type);
2194
  std::ostringstream render;
2195
 
2196
  if (type->is_base_type()) {
2197
    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2198
    switch (tbase) {
2199
    case t_base_type::TYPE_STRING:
2200
      render << "@\"" << get_escaped_string(value) << '"';
2201
      break;
2202
    case t_base_type::TYPE_BOOL:
2203
      render << ((value->get_integer() > 0) ? "YES" : "NO");
2204
      break;
2205
    case t_base_type::TYPE_BYTE:
2206
    case t_base_type::TYPE_I16:
2207
    case t_base_type::TYPE_I32:
2208
    case t_base_type::TYPE_I64:
2209
      render << value->get_integer();
2210
      break;
2211
    case t_base_type::TYPE_DOUBLE:
2212
      if (value->get_type() == t_const_value::CV_INTEGER) {
2213
        render << value->get_integer();
2214
      } else {
2215
        render << value->get_double();
2216
      }
2217
      break;
2218
    default:
2219
      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
2220
    }
2221
  } else if (type->is_enum()) {
2222
    render << value->get_integer();
2223
  } else if (type->is_struct() || type->is_xception()) {
2224
    render << "[[" << type_name(type, true) << " alloc] initWith";
2225
    const vector<t_field*>& fields = ((t_struct*)type)->get_members();
2226
    vector<t_field*>::const_iterator f_iter;
2227
    const map<t_const_value*, t_const_value*>& val = value->get_map();
2228
    map<t_const_value*, t_const_value*>::const_iterator v_iter;
2229
    bool first = true;
2230
    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
2231
      t_type* field_type = NULL;
2232
      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2233
        if ((*f_iter)->get_name() == v_iter->first->get_string()) {
2234
          field_type = (*f_iter)->get_type();
2235
        }
2236
      }
2237
      if (field_type == NULL) {
2238
        throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
2239
      }
2240
      if (first) {
2241
        render << capitalize(v_iter->first->get_string());
2242
        first = false;
2243
      } else {
2244
        render << " " << v_iter->first->get_string();
2245
      }
2246
      render << ": " << render_const_value(name, field_type, v_iter->second);
2247
    }
2248
    render << "]";
2249
  } else if (type->is_map()) {
2250
    render << "[[NSDictionary alloc] initWithObjectsAndKeys: ";
2251
    t_type* ktype = ((t_map*)type)->get_key_type();
2252
    t_type* vtype = ((t_map*)type)->get_val_type();
2253
    const map<t_const_value*, t_const_value*>& val = value->get_map();
2254
    map<t_const_value*, t_const_value*>::const_iterator v_iter;
2255
    bool first = true;
2256
    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
2257
      string key = render_const_value(name, ktype, v_iter->first, true);
2258
      string val = render_const_value(name, vtype, v_iter->second, true);
2259
      if (first) {
2260
        first = false;
2261
      } else {
2262
        render << ", ";
2263
      }
2264
      render << val << ", " << key;
2265
    }
2266
    render << ", nil]";
2267
  } else if (type->is_list()) {
2268
    render << "[[NSArray alloc] initWithObjects: ";
2269
    t_type * etype = ((t_list*)type)->get_elem_type();
2270
    const vector<t_const_value*>& val = value->get_list();
2271
    bool first = true;
2272
    vector<t_const_value*>::const_iterator v_iter;
2273
    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
2274
      if (first) {
2275
        first = false;
2276
      } else {
2277
        render << ", ";
2278
      }
2279
      render << render_const_value(name, etype, *v_iter, true);
2280
    }
2281
    render << ", nil]";
2282
  } else if (type->is_set()) {
2283
    render << "[[NSSet alloc] initWithObjects: ";
2284
    t_type * etype = ((t_set*)type)->get_elem_type();
2285
    const vector<t_const_value*>& val = value->get_list();
2286
    bool first = true;
2287
    vector<t_const_value*>::const_iterator v_iter;
2288
    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
2289
      if (first) {
2290
        first = false;
2291
      } else {
2292
        render << ", ";
2293
      }
2294
      render << render_const_value(name, etype, *v_iter, true);
2295
    }
2296
    render << ", nil]";
2297
  } else {
2298
    throw "don't know how to render constant for type: " + type->get_name();
2299
  }
2300
 
2301
  if (containerize_it) {
2302
    return containerize(type, render.str());
2303
  }
2304
 
2305
  return render.str();
2306
}
2307
 
2308
 
2309
/**
2310
 * Declares a field.
2311
 *
2312
 * @param ttype The type
2313
 */
2314
string t_cocoa_generator::declare_field(t_field* tfield) {
2315
  return type_name(tfield->get_type()) + " __" + tfield->get_name() + ";";
2316
}
2317
 
2318
/**
2319
 * Declares an Objective-C 2.0 property.
2320
 *
2321
 * @param tfield The field to declare a property for
2322
 */
2323
string t_cocoa_generator::declare_property(t_field* tfield) {
2324
  std::ostringstream render;
2325
  render << "@property (nonatomic, ";
2326
 
2327
  if (type_can_be_null(tfield->get_type()))
2328
    render << "retain, ";
2329
 
2330
  render << "getter=" << decapitalize(tfield->get_name()) <<
2331
    ", setter=set" << capitalize(tfield->get_name()) + ":) " <<
2332
    type_name(tfield->get_type()) << " " << tfield->get_name() << ";";
2333
 
2334
  return render.str();
2335
}
2336
 
2337
/**
2338
 * Add @dynamic declaration for an Objective-C 2.0 property.
2339
 *
2340
 * @param tfield The field for which to declare a dynamic property
2341
 */
2342
string t_cocoa_generator::dynamic_property(t_field* tfield) {
2343
  return "@dynamic " + tfield->get_name() + ";";
2344
}
2345
 
2346
/**
2347
 * Renders a function signature
2348
 *
2349
 * @param tfunction Function definition
2350
 * @return String of rendered function definition
2351
 */
2352
string t_cocoa_generator::function_signature(t_function* tfunction) {
2353
  t_type* ttype = tfunction->get_returntype();
2354
  std::string result =
2355
    "(" + type_name(ttype) + ") " + tfunction->get_name() + argument_list(tfunction->get_arglist());
2356
  return result;
2357
}
2358
 
2359
 
2360
/**
2361
 * Renders a colon separated list of types and names, suitable for an
2362
 * objective-c parameter list
2363
 */
2364
string t_cocoa_generator::argument_list(t_struct* tstruct) {
2365
  string result = "";
2366
 
2367
  const vector<t_field*>& fields = tstruct->get_members();
2368
  vector<t_field*>::const_iterator f_iter;
2369
  bool first = true;
2370
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
2371
    if (first) {
2372
      first = false;
2373
    } else {
2374
      result += " ";
2375
    }
2376
    result += ": (" + type_name((*f_iter)->get_type()) + ") " + (*f_iter)->get_name();
2377
  }
2378
  return result;
2379
}
2380
 
2381
 
2382
/**
2383
 * Converts the parse type to an Objective-C enum string for the given type.
2384
 */
2385
string t_cocoa_generator::type_to_enum(t_type* type) {
2386
  type = get_true_type(type);
2387
 
2388
  if (type->is_base_type()) {
2389
    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2390
    switch (tbase) {
2391
    case t_base_type::TYPE_VOID:
2392
      throw "NO T_VOID CONSTRUCT";
2393
    case t_base_type::TYPE_STRING:
2394
      return "TType_STRING";
2395
    case t_base_type::TYPE_BOOL:
2396
      return "TType_BOOL";
2397
    case t_base_type::TYPE_BYTE:
2398
      return "TType_BYTE";
2399
    case t_base_type::TYPE_I16:
2400
      return "TType_I16";
2401
    case t_base_type::TYPE_I32:
2402
      return "TType_I32";
2403
    case t_base_type::TYPE_I64:
2404
      return "TType_I64";
2405
    case t_base_type::TYPE_DOUBLE:
2406
      return "TType_DOUBLE";
2407
    }
2408
  } else if (type->is_enum()) {
2409
    return "TType_I32";
2410
  } else if (type->is_struct() || type->is_xception()) {
2411
    return "TType_STRUCT";
2412
  } else if (type->is_map()) {
2413
    return "TType_MAP";
2414
  } else if (type->is_set()) {
2415
    return "TType_SET";
2416
  } else if (type->is_list()) {
2417
    return "TType_LIST";
2418
  }
2419
 
2420
  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
2421
}
2422
 
2423
 
2424
/**
2425
 * Returns a format string specifier for the supplied parse type.
2426
 */
2427
string t_cocoa_generator::format_string_for_type(t_type* type) {
2428
  type = get_true_type(type);
2429
 
2430
  if (type->is_base_type()) {
2431
    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
2432
    switch (tbase) {
2433
    case t_base_type::TYPE_VOID:
2434
      throw "NO T_VOID CONSTRUCT";
2435
    case t_base_type::TYPE_STRING:
2436
      return "\\\"%@\\\"";
2437
    case t_base_type::TYPE_BOOL:
2438
      return "%i";
2439
    case t_base_type::TYPE_BYTE:
2440
      return "%i";
2441
    case t_base_type::TYPE_I16:
2442
      return "%hi";
2443
    case t_base_type::TYPE_I32:
2444
      return "%i";
2445
    case t_base_type::TYPE_I64:
2446
      return "%qi";
2447
    case t_base_type::TYPE_DOUBLE:
2448
      return "%f";
2449
    }
2450
  } else if (type->is_enum()) {
2451
    return "%i";
2452
  } else if (type->is_struct() || type->is_xception()) {
2453
    return "%@";
2454
  } else if (type->is_map()) {
2455
    return "%@";
2456
  } else if (type->is_set()) {
2457
    return "%@";
2458
  } else if (type->is_list()) {
2459
    return "%@";
2460
  }
2461
 
2462
  throw "INVALID TYPE IN format_string_for_type: " + type->get_name();
2463
}
2464
 
2465
/**
2466
 * Generate a call to a field's setter.
2467
 *
2468
 * @param tfield Field the setter is being called on
2469
 * @param fieldName Name of variable to pass to setter
2470
 */
2471
 
2472
string t_cocoa_generator::call_field_setter(t_field* tfield, string fieldName) {
2473
  return "[self set" + capitalize(tfield->get_name()) + ": " + fieldName + "];";
2474
}
2475
 
2476
 
2477
THRIFT_REGISTER_GENERATOR(cocoa, "Cocoa",
2478
"    log_unexpected:  Log every time an unexpected field ID or type is encountered.\n"
2479
);