Subversion Repositories SmartDukaan

Rev

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 <sys/types.h>
28
#include <sstream>
29
#include "t_generator.h"
30
#include "platform.h"
31
 
32
using namespace std;
33
 
34
 
35
/**
36
 * Erlang code generator.
37
 *
38
 */
39
class t_erl_generator : public t_generator {
40
 public:
41
  t_erl_generator(
42
      t_program* program,
43
      const std::map<std::string, std::string>& parsed_options,
44
      const std::string& option_string)
45
    : t_generator(program)
46
  {
47
    program_name_[0] = tolower(program_name_[0]);
48
    service_name_[0] = tolower(service_name_[0]);
49
    out_dir_base_ = "gen-erl";
50
  }
51
 
52
  /**
53
   * Init and close methods
54
   */
55
 
56
  void init_generator();
57
  void close_generator();
58
 
59
  /**
60
   * Program-level generation functions
61
   */
62
 
63
  void generate_typedef  (t_typedef*  ttypedef);
64
  void generate_enum     (t_enum*     tenum);
65
  void generate_const    (t_const*    tconst);
66
  void generate_struct   (t_struct*   tstruct);
67
  void generate_xception (t_struct*   txception);
68
  void generate_service  (t_service*  tservice);
69
 
70
  std::string render_const_value(t_type* type, t_const_value* value);
71
 
72
  /**
73
   * Struct generation code
74
   */
75
 
76
  void generate_erl_struct(t_struct* tstruct, bool is_exception);
77
  void generate_erl_struct_definition(std::ostream& out, std::ostream& hrl_out, t_struct* tstruct, bool is_xception=false, bool is_result=false);
78
  void generate_erl_struct_info(std::ostream& out, t_struct* tstruct);
79
  void generate_erl_function_helpers(t_function* tfunction);
80
 
81
  /**
82
   * Service-level generation functions
83
   */
84
 
85
  void generate_service_helpers   (t_service*  tservice);
86
  void generate_service_interface (t_service* tservice);
87
  void generate_function_info     (t_service* tservice, t_function* tfunction);
88
 
89
  /**
90
   * Helper rendering functions
91
   */
92
 
93
  std::string erl_autogen_comment();
94
  std::string erl_imports();
95
  std::string render_includes();
96
  std::string declare_field(t_field* tfield);
97
  std::string type_name(t_type* ttype);
98
 
99
  std::string function_signature(t_function* tfunction, std::string prefix="");
100
 
101
 
102
  std::string argument_list(t_struct* tstruct);
103
  std::string type_to_enum(t_type* ttype);
104
  std::string generate_type_term(t_type* ttype, bool expand_structs);
105
  std::string type_module(t_type* ttype);
106
 
107
  std::string capitalize(std::string in) {
108
    in[0] = toupper(in[0]);
109
    return in;
110
  }
111
 
112
  std::string uncapitalize(std::string in) {
113
    in[0] = tolower(in[0]);
114
    return in;
115
  }
116
 
117
 private:
118
 
119
  /**
120
   * add function to export list
121
   */
122
 
123
  void export_function(t_function* tfunction, std::string prefix="");
124
  void export_string(std::string name, int num);
125
 
126
  void export_types_function(t_function* tfunction, std::string prefix="");
127
  void export_types_string(std::string name, int num);
128
 
129
  /**
130
   * write out headers and footers for hrl files
131
   */
132
 
133
  void hrl_header(std::ostream& out, std::string name);
134
  void hrl_footer(std::ostream& out, std::string name);
135
 
136
  /**
137
   * stuff to spit out at the top of generated files
138
   */
139
 
140
  bool export_lines_first_;
141
  std::ostringstream export_lines_;
142
 
143
  bool export_types_lines_first_;
144
  std::ostringstream export_types_lines_;
145
 
146
  /**
147
   * File streams
148
   */
149
 
150
  std::ostringstream f_types_;
151
  std::ofstream f_types_file_;
152
  std::ofstream f_types_hrl_file_;
153
 
154
  std::ofstream f_consts_;
155
  std::ostringstream f_service_;
156
  std::ofstream f_service_file_;
157
  std::ofstream f_service_hrl_;
158
 
159
};
160
 
161
 
162
/**
163
 * UI for file generation by opening up the necessary file output
164
 * streams.
165
 *
166
 * @param tprogram The program to generate
167
 */
168
void t_erl_generator::init_generator() {
169
  // Make output directory
170
  MKDIR(get_out_dir().c_str());
171
 
172
  // setup export lines
173
  export_lines_first_ = true;
174
  export_types_lines_first_ = true;
175
 
176
  // types files
177
  string f_types_name = get_out_dir()+program_name_+"_types.erl";
178
  string f_types_hrl_name = get_out_dir()+program_name_+"_types.hrl";
179
 
180
  f_types_file_.open(f_types_name.c_str());
181
  f_types_hrl_file_.open(f_types_hrl_name.c_str());
182
 
183
  hrl_header(f_types_hrl_file_, program_name_ + "_types");
184
 
185
  f_types_file_ <<
186
    erl_autogen_comment() << endl <<
187
    "-module(" << program_name_ << "_types)." << endl <<
188
    erl_imports() << endl;
189
 
190
  f_types_file_ <<
191
    "-include(\"" << program_name_ << "_types.hrl\")." << endl <<
192
    endl;
193
 
194
  f_types_hrl_file_ << render_includes() << endl;
195
 
196
  // consts file
197
  string f_consts_name = get_out_dir()+program_name_+"_constants.hrl";
198
  f_consts_.open(f_consts_name.c_str());
199
 
200
  f_consts_ <<
201
    erl_autogen_comment() << endl <<
202
    erl_imports() << endl <<
203
    "-include(\"" << program_name_ << "_types.hrl\")." << endl <<
204
    endl;
205
}
206
 
207
/**
208
 * Boilerplate at beginning and end of header files
209
 */
210
void t_erl_generator::hrl_header(ostream& out, string name) {
211
  out << "-ifndef(_" << name << "_included)." << endl <<
212
    "-define(_" << name << "_included, yeah)." << endl;
213
}
214
 
215
void t_erl_generator::hrl_footer(ostream& out, string name) {
216
  out << "-endif." << endl;
217
}
218
 
219
/**
220
 * Renders all the imports necessary for including another Thrift program
221
 */
222
string t_erl_generator::render_includes() {
223
  const vector<t_program*>& includes = program_->get_includes();
224
  string result = "";
225
  for (size_t i = 0; i < includes.size(); ++i) {
226
    result += "-include(\"" + uncapitalize(includes[i]->get_name()) + "_types.hrl\").\n";
227
  }
228
  if (includes.size() > 0) {
229
    result += "\n";
230
  }
231
  return result;
232
}
233
 
234
/**
235
 * Autogen'd comment
236
 */
237
string t_erl_generator::erl_autogen_comment() {
238
  return
239
    std::string("%%\n") +
240
    "%% Autogenerated by Thrift\n" +
241
    "%%\n" +
242
    "%% DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
243
    "%%\n";
244
}
245
 
246
/**
247
 * Prints standard thrift imports
248
 */
249
string t_erl_generator::erl_imports() {
250
  return "";
251
}
252
 
253
/**
254
 * Closes the type files
255
 */
256
void t_erl_generator::close_generator() {
257
  // Close types file
258
  export_types_string("struct_info", 1);
259
 
260
  f_types_file_ << "-export([" << export_types_lines_.str() << "])." << endl;
261
  f_types_file_ << f_types_.str();
262
  f_types_file_ << "struct_info('i am a dummy struct') -> undefined." << endl;
263
 
264
  hrl_footer(f_types_hrl_file_, string("BOGUS"));
265
 
266
  f_types_file_.close();
267
  f_types_hrl_file_.close();
268
  f_consts_.close();
269
}
270
 
271
/**
272
 * Generates a typedef. no op
273
 *
274
 * @param ttypedef The type definition
275
 */
276
void t_erl_generator::generate_typedef(t_typedef* ttypedef) {
277
}
278
 
279
/**
280
 * Generates code for an enumerated type. Done using a class to scope
281
 * the values.
282
 *
283
 * @param tenum The enumeration
284
 */
285
void t_erl_generator::generate_enum(t_enum* tenum) {
286
  vector<t_enum_value*> constants = tenum->get_constants();
287
  vector<t_enum_value*>::iterator c_iter;
288
 
289
  int value = -1;
290
 
291
  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
292
    if ((*c_iter)->has_value()) {
293
      value = (*c_iter)->get_value();
294
    } else {
295
      ++value;
296
    }
297
 
298
    string name = capitalize((*c_iter)->get_name());
299
 
300
    f_types_hrl_file_ <<
301
      indent() << "-define(" << program_name_ << "_" << name << ", " << value << ")."<< endl;
302
  }
303
 
304
  f_types_hrl_file_ << endl;
305
}
306
 
307
/**
308
 * Generate a constant value
309
 */
310
void t_erl_generator::generate_const(t_const* tconst) {
311
  t_type* type = tconst->get_type();
312
  string name = capitalize(tconst->get_name());
313
  t_const_value* value = tconst->get_value();
314
 
315
  f_consts_ << "-define(" << program_name_ << "_" << name << ", " << render_const_value(type, value) << ")." << endl << endl;
316
}
317
 
318
/**
319
 * Prints the value of a constant with the given type. Note that type checking
320
 * is NOT performed in this function as it is always run beforehand using the
321
 * validate_types method in main.cc
322
 */
323
string t_erl_generator::render_const_value(t_type* type, t_const_value* value) {
324
  type = get_true_type(type);
325
  std::ostringstream out;
326
 
327
  if (type->is_base_type()) {
328
    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
329
    switch (tbase) {
330
    case t_base_type::TYPE_STRING:
331
      out << '"' << get_escaped_string(value) << '"';
332
      break;
333
    case t_base_type::TYPE_BOOL:
334
      out << (value->get_integer() > 0 ? "true" : "false");
335
      break;
336
    case t_base_type::TYPE_BYTE:
337
    case t_base_type::TYPE_I16:
338
    case t_base_type::TYPE_I32:
339
    case t_base_type::TYPE_I64:
340
      out << value->get_integer();
341
      break;
342
    case t_base_type::TYPE_DOUBLE:
343
      if (value->get_type() == t_const_value::CV_INTEGER) {
344
        out << value->get_integer();
345
      } else {
346
        out << value->get_double();
347
      }
348
      break;
349
    default:
350
      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
351
    }
352
  } else if (type->is_enum()) {
353
    indent(out) << value->get_integer();
354
 
355
  } else if (type->is_struct() || type->is_xception()) {
356
    out << "#" << type->get_name() << "{";
357
    const vector<t_field*>& fields = ((t_struct*)type)->get_members();
358
    vector<t_field*>::const_iterator f_iter;
359
    const map<t_const_value*, t_const_value*>& val = value->get_map();
360
    map<t_const_value*, t_const_value*>::const_iterator v_iter;
361
 
362
    bool first = true;
363
    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
364
      t_type* field_type = NULL;
365
      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
366
        if ((*f_iter)->get_name() == v_iter->first->get_string()) {
367
          field_type = (*f_iter)->get_type();
368
        }
369
      }
370
      if (field_type == NULL) {
371
        throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
372
      }
373
 
374
      if (first) {
375
        first = false;
376
      } else {
377
        out << ",";
378
      }
379
      out << v_iter->first->get_string();
380
      out << " = ";
381
      out << render_const_value(field_type, v_iter->second);
382
    }
383
    indent_down();
384
    indent(out) << "}";
385
 
386
  } else if (type->is_map()) {
387
    t_type* ktype = ((t_map*)type)->get_key_type();
388
    t_type* vtype = ((t_map*)type)->get_val_type();
389
    const map<t_const_value*, t_const_value*>& val = value->get_map();
390
    map<t_const_value*, t_const_value*>::const_iterator v_iter;
391
 
392
    bool first = true;
393
    out << "dict:from_list([";
394
    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
395
      if (first) {
396
        first=false;
397
      } else {
398
        out << ",";
399
      }
400
      out << "("
401
          << render_const_value(ktype, v_iter->first)  << ","
402
          << render_const_value(vtype, v_iter->second) << ")";
403
    }
404
    out << "])";
405
 
406
  } else if (type->is_set()) {
407
    t_type* etype;
408
    etype = ((t_set*)type)->get_elem_type();
409
 
410
    bool first = true;
411
    const vector<t_const_value*>& val = value->get_list();
412
    vector<t_const_value*>::const_iterator v_iter;
413
    out << "sets:from_list([";
414
    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
415
      if (first) {
416
        first=false;
417
      } else {
418
        out << ",";
419
      }
420
      out << "(" << render_const_value(etype, *v_iter) << ",true)";
421
    }
422
    out << "])";
423
 
424
  } else if (type->is_list()) {
425
    t_type* etype;
426
    etype = ((t_list*)type)->get_elem_type();
427
    out << "[";
428
 
429
    bool first = true;
430
    const vector<t_const_value*>& val = value->get_list();
431
    vector<t_const_value*>::const_iterator v_iter;
432
    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
433
      if (first) {
434
        first=false;
435
      } else {
436
        out << ",";
437
      }
438
      out << render_const_value(etype, *v_iter);
439
    }
440
    out << "]";
441
  } else {
442
    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
443
  }
444
  return out.str();
445
}
446
 
447
/**
448
 * Generates a struct
449
 */
450
void t_erl_generator::generate_struct(t_struct* tstruct) {
451
  generate_erl_struct(tstruct, false);
452
}
453
 
454
/**
455
 * Generates a struct definition for a thrift exception. Basically the same
456
 * as a struct but extends the Exception class.
457
 *
458
 * @param txception The struct definition
459
 */
460
void t_erl_generator::generate_xception(t_struct* txception) {
461
  generate_erl_struct(txception, true);
462
}
463
 
464
/**
465
 * Generates a struct
466
 */
467
void t_erl_generator::generate_erl_struct(t_struct* tstruct,
468
                                          bool is_exception) {
469
  generate_erl_struct_definition(f_types_, f_types_hrl_file_, tstruct, is_exception);
470
}
471
 
472
/**
473
 * Generates a struct definition for a thrift data type.
474
 *
475
 * @param tstruct The struct definition
476
 */
477
void t_erl_generator::generate_erl_struct_definition(ostream& out,
478
                                                     ostream& hrl_out,
479
                                                     t_struct* tstruct,
480
                                                     bool is_exception,
481
                                                     bool is_result)
482
{
483
  const vector<t_field*>& members = tstruct->get_members();
484
  vector<t_field*>::const_iterator m_iter;
485
 
486
  indent(out) << "%% struct " << type_name(tstruct) << endl;
487
 
488
  if (is_exception) {
489
  }
490
 
491
  out << endl;
492
 
493
  if (members.size() > 0) {
494
    indent(out)     << "% -record(" << type_name(tstruct) << ", {";
495
    indent(hrl_out) <<   "-record(" << type_name(tstruct) << ", {";
496
 
497
    bool first = true;
498
    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
499
      if (first) {
500
        first = false;
501
      } else {
502
        out     << ", ";
503
        hrl_out << ", ";
504
      }
505
      std::string name = uncapitalize((*m_iter)->get_name());
506
      out     << name;
507
      hrl_out << name;
508
    }
509
    out     << "})." << endl;
510
    hrl_out << "})." << endl;
511
  } else { // no members; explicit comment
512
    indent(out)     << "% -record(" << type_name(tstruct) << ", {})." << endl;
513
    indent(hrl_out) <<   "-record(" << type_name(tstruct) << ", {})." << endl;
514
  }
515
 
516
  out << endl;
517
  hrl_out << endl;
518
 
519
 
520
  generate_erl_struct_info(out, tstruct);
521
}
522
 
523
/**
524
 * Generates the read method for a struct
525
 */
526
void t_erl_generator::generate_erl_struct_info(ostream& out,
527
                                                  t_struct* tstruct) {
528
  string name = type_name(tstruct);
529
 
530
  indent(out) << "struct_info('" << name << "') ->" << endl;
531
  indent_up();
532
 
533
  out << indent() << generate_type_term(tstruct, true) << ";" << endl;
534
 
535
  indent_down();
536
  out << endl;
537
}
538
 
539
 
540
/**
541
 * Generates a thrift service.
542
 *
543
 * @param tservice The service definition
544
 */
545
void t_erl_generator::generate_service(t_service* tservice) {
546
  // somehow this point is reached before the constructor and it's not downcased yet
547
  // ...awesome
548
  service_name_[0] = tolower(service_name_[0]);
549
 
550
  string f_service_hrl_name = get_out_dir()+service_name_+"_thrift.hrl";
551
  string f_service_name = get_out_dir()+service_name_+"_thrift.erl";
552
  f_service_file_.open(f_service_name.c_str());
553
  f_service_hrl_.open(f_service_hrl_name.c_str());
554
 
555
  // Reset service text aggregating stream streams
556
  f_service_.str("");
557
  export_lines_.str("");
558
  export_lines_first_ = true;
559
 
560
  hrl_header(f_service_hrl_, service_name_);
561
 
562
  if (tservice->get_extends() != NULL) {
563
    f_service_hrl_ << "-include(\"" <<
564
      uncapitalize(tservice->get_extends()->get_name()) << "_thrift.hrl\"). % inherit " << endl;
565
  }
566
 
567
  f_service_hrl_ <<
568
    "-include(\"" << program_name_ << "_types.hrl\")." << endl <<
569
    endl;
570
 
571
  // Generate the three main parts of the service (well, two for now in PHP)
572
  generate_service_helpers(tservice); // cpiro: New Erlang Order
573
 
574
  generate_service_interface(tservice);
575
 
576
  // indent_down();
577
 
578
  f_service_file_ <<
579
    erl_autogen_comment() << endl <<
580
    "-module(" << service_name_ << "_thrift)." << endl <<
581
    "-behaviour(thrift_service)." << endl << endl <<
582
    erl_imports() << endl;
583
 
584
  f_service_file_ << "-include(\"" << uncapitalize(tservice->get_name()) << "_thrift.hrl\")." << endl << endl;
585
 
586
  f_service_file_ << "-export([" << export_lines_.str() << "])." << endl << endl;
587
 
588
  f_service_file_ << f_service_.str();
589
 
590
  hrl_footer(f_service_hrl_, f_service_name);
591
 
592
  // Close service file
593
  f_service_file_.close();
594
  f_service_hrl_.close();
595
}
596
 
597
/**
598
 * Generates helper functions for a service.
599
 *
600
 * @param tservice The service to generate a header definition for
601
 */
602
void t_erl_generator::generate_service_helpers(t_service* tservice) {
603
  vector<t_function*> functions = tservice->get_functions();
604
  vector<t_function*>::iterator f_iter;
605
 
606
  //  indent(f_service_) <<
607
  //  "% HELPER FUNCTIONS AND STRUCTURES" << endl << endl;
608
 
609
  export_string("struct_info", 1);
610
 
611
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
612
    generate_erl_function_helpers(*f_iter);
613
  }
614
  f_service_    << "struct_info('i am a dummy struct') -> undefined." << endl;
615
}
616
 
617
/**
618
 * Generates a struct and helpers for a function.
619
 *
620
 * @param tfunction The function
621
 */
622
void t_erl_generator::generate_erl_function_helpers(t_function* tfunction) {
623
}
624
 
625
/**
626
 * Generates a service interface definition.
627
 *
628
 * @param tservice The service to generate a header definition for
629
 */
630
void t_erl_generator::generate_service_interface(t_service* tservice) {
631
 
632
  export_string("function_info", 2);
633
 
634
  vector<t_function*> functions = tservice->get_functions();
635
  vector<t_function*>::iterator f_iter;
636
  f_service_ << "%%% interface" << endl;
637
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
638
    f_service_ <<
639
      indent() << "% " << function_signature(*f_iter) << endl;
640
 
641
    generate_function_info(tservice, *f_iter);
642
  }
643
 
644
  // Inheritance - pass unknown functions to base class
645
  if (tservice->get_extends() != NULL) {
646
      indent(f_service_) << "function_info(Function, InfoType) ->" << endl;
647
      indent_up();
648
      indent(f_service_) << uncapitalize(tservice->get_extends()->get_name())
649
                         << "_thrift:function_info(Function, InfoType)." << endl;
650
      indent_down();
651
  } else {
652
      // Dummy function_info so we don't worry about the ;s
653
      indent(f_service_) << "function_info(xxx, dummy) -> dummy." << endl;
654
  }
655
 
656
  indent(f_service_) << endl;
657
}
658
 
659
 
660
/**
661
 * Generates a function_info(FunctionName, params_type) and
662
 * function_info(FunctionName, reply_type)
663
 */
664
void t_erl_generator::generate_function_info(t_service* tservice,
665
                                                t_function* tfunction) {
666
 
667
  string name_atom = "'" + tfunction->get_name() + "'";
668
 
669
 
670
 
671
  t_struct* xs = tfunction->get_xceptions();
672
  t_struct* arg_struct = tfunction->get_arglist();
673
 
674
  // function_info(Function, params_type):
675
  indent(f_service_) <<
676
    "function_info(" << name_atom << ", params_type) ->" << endl;
677
  indent_up();
678
 
679
  indent(f_service_) << generate_type_term(arg_struct, true) << ";" << endl;
680
 
681
  indent_down();
682
 
683
  // function_info(Function, reply_type):
684
  indent(f_service_) <<
685
    "function_info(" << name_atom << ", reply_type) ->" << endl;
686
  indent_up();
687
 
688
  if (!tfunction->get_returntype()->is_void())
689
    indent(f_service_) <<
690
        generate_type_term(tfunction->get_returntype(), false) << ";" << endl;
691
  else if (tfunction->is_oneway())
692
    indent(f_service_) << "oneway_void;" << endl;
693
  else
694
    indent(f_service_) << "{struct, []}" << ";" << endl;
695
  indent_down();
696
 
697
  // function_info(Function, exceptions):
698
  indent(f_service_) <<
699
    "function_info(" << name_atom << ", exceptions) ->" << endl;
700
  indent_up();
701
  indent(f_service_) << generate_type_term(xs, true) << ";" << endl;
702
  indent_down();
703
}
704
 
705
 
706
/**
707
 * Declares a field, which may include initialization as necessary.
708
 *
709
 * @param ttype The type
710
 */
711
string t_erl_generator::declare_field(t_field* tfield) {  // TODO
712
  string result = "@" + tfield->get_name();
713
  t_type* type = get_true_type(tfield->get_type());
714
  if (tfield->get_value() != NULL) {
715
    result += " = " + render_const_value(type, tfield->get_value());
716
  } else {
717
    result += " = nil";
718
  }
719
  return result;
720
}
721
 
722
/**
723
 * Renders a function signature of the form 'type name(args)'
724
 *
725
 * @param tfunction Function definition
726
 * @return String of rendered function definition
727
 */
728
string t_erl_generator::function_signature(t_function* tfunction,
729
                                           string prefix) {
730
  return
731
    prefix + tfunction->get_name() +
732
    "(This" +  capitalize(argument_list(tfunction->get_arglist())) + ")";
733
}
734
 
735
/**
736
 * Add a function to the exports list
737
 */
738
void t_erl_generator::export_string(string name, int num) {
739
  if (export_lines_first_) {
740
    export_lines_first_ = false;
741
  } else {
742
    export_lines_ << ", ";
743
  }
744
  export_lines_ << name << "/" << num;
745
}
746
 
747
void t_erl_generator::export_types_function(t_function* tfunction,
748
                                               string prefix) {
749
 
750
  export_types_string(prefix + tfunction->get_name(),
751
                      1 // This
752
                      + ((tfunction->get_arglist())->get_members()).size()
753
                      );
754
}
755
 
756
void t_erl_generator::export_types_string(string name, int num) {
757
  if (export_types_lines_first_) {
758
    export_types_lines_first_ = false;
759
  } else {
760
    export_types_lines_ << ", ";
761
  }
762
  export_types_lines_ << name << "/" << num;
763
}
764
 
765
void t_erl_generator::export_function(t_function* tfunction,
766
                                      string prefix) {
767
 
768
  export_string(prefix + tfunction->get_name(),
769
                1 // This
770
                + ((tfunction->get_arglist())->get_members()).size()
771
                );
772
}
773
 
774
 
775
/**
776
 * Renders a field list
777
 */
778
string t_erl_generator::argument_list(t_struct* tstruct) {
779
  string result = "";
780
 
781
  const vector<t_field*>& fields = tstruct->get_members();
782
  vector<t_field*>::const_iterator f_iter;
783
  bool first = true;
784
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
785
    if (first) {
786
      first = false;
787
      result += ", "; // initial comma to compensate for initial This
788
    } else {
789
      result += ", ";
790
    }
791
    result += capitalize((*f_iter)->get_name());
792
  }
793
  return result;
794
}
795
 
796
string t_erl_generator::type_name(t_type* ttype) {
797
  string prefix = "";
798
  string name = ttype->get_name();
799
 
800
  if (ttype->is_struct() || ttype->is_xception() || ttype->is_service()) {
801
    name = uncapitalize(ttype->get_name());
802
  }
803
 
804
  return prefix + name;
805
}
806
 
807
/**
808
 * Converts the parse type to a Erlang "type" (macro for int constants)
809
 */
810
string t_erl_generator::type_to_enum(t_type* type) {
811
  type = get_true_type(type);
812
 
813
  if (type->is_base_type()) {
814
    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
815
    switch (tbase) {
816
    case t_base_type::TYPE_VOID:
817
      throw "NO T_VOID CONSTRUCT";
818
    case t_base_type::TYPE_STRING:
819
      return "?tType_STRING";
820
    case t_base_type::TYPE_BOOL:
821
      return "?tType_BOOL";
822
    case t_base_type::TYPE_BYTE:
823
      return "?tType_BYTE";
824
    case t_base_type::TYPE_I16:
825
      return "?tType_I16";
826
    case t_base_type::TYPE_I32:
827
      return "?tType_I32";
828
    case t_base_type::TYPE_I64:
829
      return "?tType_I64";
830
    case t_base_type::TYPE_DOUBLE:
831
      return "?tType_DOUBLE";
832
    }
833
  } else if (type->is_enum()) {
834
    return "?tType_I32";
835
  } else if (type->is_struct() || type->is_xception()) {
836
    return "?tType_STRUCT";
837
  } else if (type->is_map()) {
838
    return "?tType_MAP";
839
  } else if (type->is_set()) {
840
    return "?tType_SET";
841
  } else if (type->is_list()) {
842
    return "?tType_LIST";
843
  }
844
 
845
  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
846
}
847
 
848
 
849
/**
850
 * Generate an Erlang term which represents a thrift type
851
 */
852
std::string t_erl_generator::generate_type_term(t_type* type,
853
                                                   bool expand_structs) {
854
    type = get_true_type(type);
855
 
856
 
857
  if (type->is_base_type()) {
858
    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
859
    switch (tbase) {
860
    case t_base_type::TYPE_VOID:
861
      throw "NO T_VOID CONSTRUCT";
862
    case t_base_type::TYPE_STRING:
863
      return "string";
864
    case t_base_type::TYPE_BOOL:
865
      return "bool";
866
    case t_base_type::TYPE_BYTE:
867
      return "byte";
868
    case t_base_type::TYPE_I16:
869
      return "i16";
870
    case t_base_type::TYPE_I32:
871
      return "i32";
872
    case t_base_type::TYPE_I64:
873
      return "i64";
874
    case t_base_type::TYPE_DOUBLE:
875
      return "double";
876
    }
877
  } else if (type->is_enum()) {
878
    return "i32";
879
  } else if (type->is_struct() || type->is_xception()) {
880
    if (expand_structs) {
881
      // Convert to format: {struct, [{Fid, TypeTerm}, {Fid, TypeTerm}...]}
882
      std::stringstream ret;
883
 
884
 
885
      ret << "{struct, [";
886
 
887
      int first = true;
888
      const vector<t_field*>& fields = ((t_struct*)type)->get_members();
889
      vector<t_field*>::const_iterator f_iter;
890
 
891
      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
892
        // Comma separate the tuples
893
        if (!first) ret << "," << endl << indent();
894
        first = false;
895
 
896
        ret << "{" << (*f_iter)->get_key() << ", " <<
897
          generate_type_term((*f_iter)->get_type(), false) << "}";
898
      }
899
 
900
      ret << "]}" << endl;
901
 
902
      return ret.str();
903
    } else {
904
      return "{struct, {'" + type_module(type) + "', '" + type_name(type) + "'}}";
905
    }
906
  } else if (type->is_map()) {
907
    // {map, KeyType, ValType}
908
    t_type *key_type = ((t_map*)type)->get_key_type();
909
    t_type *val_type = ((t_map*)type)->get_val_type();
910
 
911
    return "{map, " + generate_type_term(key_type, false) + ", " +
912
      generate_type_term(val_type, false) + "}";
913
 
914
  } else if (type->is_set()) {
915
    t_type *elem_type = ((t_set*)type)->get_elem_type();
916
 
917
    return "{set, " + generate_type_term(elem_type, false) + "}";
918
 
919
  } else if (type->is_list()) {
920
    t_type *elem_type = ((t_list*)type)->get_elem_type();
921
 
922
    return "{list, " + generate_type_term(elem_type, false) + "}";
923
  }
924
 
925
  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
926
}
927
 
928
std::string t_erl_generator::type_module(t_type* ttype) {
929
  return uncapitalize(ttype->get_program()->get_name()) + "_types";
930
}
931
 
932
THRIFT_REGISTER_GENERATOR(erl, "Erlang", "");