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
#include <list>
25
 
26
#include <stdlib.h>
27
#include <sys/stat.h>
28
#include <sstream>
29
#include "t_oop_generator.h"
30
#include "platform.h"
31
using namespace std;
32
 
33
 
34
/**
35
 * PERL code generator.
36
 *
37
 */
38
class t_perl_generator : public t_oop_generator {
39
 public:
40
  t_perl_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
    out_dir_base_ = "gen-perl";
47
    escape_['$'] = "\\$";
48
    escape_['@'] = "\\@";
49
  }
50
 
51
  /**
52
   * Init and close methods
53
   */
54
 
55
  void init_generator();
56
  void close_generator();
57
 
58
  /**
59
   * Program-level generation functions
60
   */
61
 
62
  void generate_typedef  (t_typedef*  ttypedef);
63
  void generate_enum     (t_enum*     tenum);
64
  void generate_const    (t_const*    tconst);
65
  void generate_struct   (t_struct*   tstruct);
66
  void generate_xception (t_struct*   txception);
67
  void generate_service  (t_service*  tservice);
68
 
69
  std::string render_const_value(t_type* type, t_const_value* value);
70
 
71
  /**
72
   * Structs!
73
   */
74
 
75
  void generate_perl_struct(t_struct* tstruct, bool is_exception);
76
  void generate_perl_struct_definition(std::ofstream& out, t_struct* tstruct, bool is_xception=false);
77
  void generate_perl_struct_reader(std::ofstream& out, t_struct* tstruct);
78
  void generate_perl_struct_writer(std::ofstream& out, t_struct* tstruct);
79
  void generate_perl_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_service_rest      (t_service* tservice);
88
  void generate_service_client    (t_service* tservice);
89
  void generate_service_processor (t_service* tservice);
90
  void generate_process_function  (t_service* tservice, t_function* tfunction);
91
 
92
  /**
93
   * Serialization constructs
94
   */
95
 
96
  void generate_deserialize_field        (std::ofstream &out,
97
                                          t_field*    tfield,
98
                                          std::string prefix="",
99
                                          bool inclass=false);
100
 
101
  void generate_deserialize_struct       (std::ofstream &out,
102
                                          t_struct*   tstruct,
103
                                          std::string prefix="");
104
 
105
  void generate_deserialize_container    (std::ofstream &out,
106
                                          t_type*     ttype,
107
                                          std::string prefix="");
108
 
109
  void generate_deserialize_set_element  (std::ofstream &out,
110
                                          t_set*      tset,
111
                                          std::string prefix="");
112
 
113
  void generate_deserialize_map_element  (std::ofstream &out,
114
                                          t_map*      tmap,
115
                                          std::string prefix="");
116
 
117
  void generate_deserialize_list_element (std::ofstream &out,
118
                                          t_list*     tlist,
119
                                          std::string prefix="");
120
 
121
  void generate_serialize_field          (std::ofstream &out,
122
                                          t_field*    tfield,
123
                                          std::string prefix="");
124
 
125
  void generate_serialize_struct         (std::ofstream &out,
126
                                          t_struct*   tstruct,
127
                                          std::string prefix="");
128
 
129
  void generate_serialize_container      (std::ofstream &out,
130
                                          t_type*     ttype,
131
                                          std::string prefix="");
132
 
133
  void generate_serialize_map_element    (std::ofstream &out,
134
                                          t_map*      tmap,
135
                                          std::string kiter,
136
                                          std::string viter);
137
 
138
  void generate_serialize_set_element    (std::ofstream &out,
139
                                          t_set*      tmap,
140
                                          std::string iter);
141
 
142
  void generate_serialize_list_element   (std::ofstream &out,
143
                                          t_list*     tlist,
144
                                          std::string iter);
145
 
146
  /**
147
   * Helper rendering functions
148
   */
149
 
150
  std::string perl_includes();
151
  std::string declare_field(t_field* tfield, bool init=false, bool obj=false);
152
  std::string function_signature(t_function* tfunction, std::string prefix="");
153
  std::string argument_list(t_struct* tstruct);
154
  std::string type_to_enum(t_type* ttype);
155
 
156
  std::string autogen_comment() {
157
    return
158
      std::string("#\n") +
159
      "# Autogenerated by Thrift\n" +
160
      "#\n" +
161
      "# DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
162
      "#\n";
163
  }
164
 
165
  void perl_namespace_dirs(t_program* p, std::list<std::string>& dirs) {
166
    std::string ns = p->get_namespace("perl");
167
    std::string::size_type loc;
168
 
169
    if (ns.size() > 0) {
170
      while ((loc = ns.find(".")) != std::string::npos) {
171
        dirs.push_back(ns.substr(0, loc));
172
        ns = ns.substr(loc+1);
173
      }
174
    }
175
 
176
    if (ns.size() > 0) {
177
      dirs.push_back(ns);
178
    }
179
  }
180
 
181
  std::string perl_namespace(t_program* p) {
182
    std::string ns = p->get_namespace("perl");
183
    std::string result = "";
184
    std::string::size_type loc;
185
 
186
    if (ns.size() > 0) {
187
      while ((loc = ns.find(".")) != std::string::npos) {
188
        result += ns.substr(0, loc);
189
        result += "::";
190
        ns = ns.substr(loc+1);
191
      }
192
 
193
      if (ns.size() > 0) {
194
        result += ns + "::";
195
      }
196
    }
197
 
198
    return result;
199
  }
200
 
201
  std::string get_namespace_out_dir() {
202
    std::string outdir = get_out_dir();
203
    std::list<std::string> dirs;
204
    perl_namespace_dirs(program_, dirs);
205
    std::list<std::string>::iterator it;
206
    for (it = dirs.begin(); it != dirs.end(); it++) {
207
      outdir += *it + "/";
208
    }
209
    return outdir;
210
  }
211
 
212
 private:
213
 
214
  /**
215
   * File streams
216
   */
217
  std::ofstream f_types_;
218
  std::ofstream f_consts_;
219
  std::ofstream f_helpers_;
220
  std::ofstream f_service_;
221
 
222
};
223
 
224
 
225
/**
226
 * Prepares for file generation by opening up the necessary file output
227
 * streams.
228
 *
229
 * @param tprogram The program to generate
230
 */
231
void t_perl_generator::init_generator() {
232
  // Make output directory
233
  MKDIR(get_out_dir().c_str());
234
 
235
  string outdir = get_out_dir();
236
  std::list<std::string> dirs;
237
  perl_namespace_dirs(program_, dirs);
238
  std::list<std::string>::iterator it;
239
  for (it = dirs.begin(); it != dirs.end(); it++) {
240
      outdir += *it + "/";
241
      MKDIR(outdir.c_str());
242
  }
243
 
244
  // Make output file
245
  string f_types_name = outdir+"Types.pm";
246
  f_types_.open(f_types_name.c_str());
247
  string f_consts_name = outdir+"Constants.pm";
248
  f_consts_.open(f_consts_name.c_str());
249
 
250
  // Print header
251
  f_types_ <<
252
    autogen_comment() <<
253
    perl_includes();
254
 
255
  // Print header
256
  f_consts_ <<
257
    autogen_comment() <<
258
    "package "<< perl_namespace(program_) <<"Constants;"<<endl<<
259
    perl_includes() <<
260
    endl;
261
}
262
 
263
/**
264
 * Prints standard java imports
265
 */
266
string t_perl_generator::perl_includes() {
267
  string inc;
268
 
269
  inc  = "require 5.6.0;\n";
270
  inc += "use strict;\n";
271
  inc += "use warnings;\n";
272
  inc += "use Thrift;\n\n";
273
 
274
  return inc;
275
}
276
 
277
/**
278
 * Close up (or down) some filez.
279
 */
280
void t_perl_generator::close_generator() {
281
  // Close types file
282
  f_types_ << "1;" << endl;
283
  f_types_.close();
284
 
285
  f_consts_ << "1;" << endl;
286
  f_consts_.close();
287
}
288
 
289
/**
290
 * Generates a typedef. This is not done in PERL, types are all implicit.
291
 *
292
 * @param ttypedef The type definition
293
 */
294
void t_perl_generator::generate_typedef(t_typedef* ttypedef) {}
295
 
296
/**
297
 * Generates code for an enumerated type. Since define is expensive to lookup
298
 * in PERL, we use a global array for this.
299
 *
300
 * @param tenum The enumeration
301
 */
302
void t_perl_generator::generate_enum(t_enum* tenum) {
303
  f_types_ << "package " << perl_namespace(program_) <<tenum->get_name()<<";"<<endl;
304
 
305
  vector<t_enum_value*> constants = tenum->get_constants();
306
  vector<t_enum_value*>::iterator c_iter;
307
  int value = -1;
308
  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
309
    if ((*c_iter)->has_value()) {
310
      value = (*c_iter)->get_value();
311
    } else {
312
      ++value;
313
    }
314
 
315
    f_types_ << "use constant "<<(*c_iter)->get_name() << " => " << value << ";" << endl;
316
  }
317
}
318
 
319
/**
320
 * Generate a constant value
321
 */
322
void t_perl_generator::generate_const(t_const* tconst) {
323
  t_type* type = tconst->get_type();
324
  string name = tconst->get_name();
325
  t_const_value* value = tconst->get_value();
326
 
327
  f_consts_ << "use constant " << name << " => ";
328
  f_consts_ << render_const_value(type, value);
329
  f_consts_ << ";" << endl << endl;
330
}
331
 
332
/**
333
 * Prints the value of a constant with the given type. Note that type checking
334
 * is NOT performed in this function as it is always run beforehand using the
335
 * validate_types method in main.cc
336
 */
337
string t_perl_generator::render_const_value(t_type* type, t_const_value* value) {
338
  std::ostringstream out;
339
 
340
  type = get_true_type(type);
341
 
342
  if (type->is_base_type()) {
343
    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
344
    switch (tbase) {
345
    case t_base_type::TYPE_STRING:
346
      out << '"' << get_escaped_string(value) << '"';
347
      break;
348
    case t_base_type::TYPE_BOOL:
349
      out << (value->get_integer() > 0 ? "1" : "0");
350
      break;
351
    case t_base_type::TYPE_BYTE:
352
    case t_base_type::TYPE_I16:
353
    case t_base_type::TYPE_I32:
354
    case t_base_type::TYPE_I64:
355
      out << value->get_integer();
356
      break;
357
    case t_base_type::TYPE_DOUBLE:
358
      if (value->get_type() == t_const_value::CV_INTEGER) {
359
        out << value->get_integer();
360
      } else {
361
        out << value->get_double();
362
      }
363
      break;
364
    default:
365
      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
366
    }
367
  } else if (type->is_enum()) {
368
    out << value->get_integer();
369
  } else if (type->is_struct() || type->is_xception()) {
370
    out << "new " << perl_namespace(type->get_program()) << type->get_name() << "({" << endl;
371
    indent_up();
372
    const vector<t_field*>& fields = ((t_struct*)type)->get_members();
373
    vector<t_field*>::const_iterator f_iter;
374
    const map<t_const_value*, t_const_value*>& val = value->get_map();
375
    map<t_const_value*, t_const_value*>::const_iterator v_iter;
376
    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
377
      t_type* field_type = NULL;
378
      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
379
        if ((*f_iter)->get_name() == v_iter->first->get_string()) {
380
          field_type = (*f_iter)->get_type();
381
        }
382
      }
383
      if (field_type == NULL) {
384
        throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
385
      }
386
      out << render_const_value(g_type_string, v_iter->first);
387
      out << " => ";
388
      out << render_const_value(field_type, v_iter->second);
389
      out << ",";
390
      out << endl;
391
    }
392
 
393
    out << "})";
394
  } else if (type->is_map()) {
395
    t_type* ktype = ((t_map*)type)->get_key_type();
396
    t_type* vtype = ((t_map*)type)->get_val_type();
397
    out << "{" << endl;
398
 
399
    const map<t_const_value*, t_const_value*>& val = value->get_map();
400
    map<t_const_value*, t_const_value*>::const_iterator v_iter;
401
    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
402
      out << render_const_value(ktype, v_iter->first);
403
      out << " => ";
404
      out << render_const_value(vtype, v_iter->second);
405
      out << "," << endl;
406
    }
407
 
408
    out << "}";
409
  } else if (type->is_list() || type->is_set()) {
410
    t_type* etype;
411
    if (type->is_list()) {
412
      etype = ((t_list*)type)->get_elem_type();
413
    } else {
414
      etype = ((t_set*)type)->get_elem_type();
415
    }
416
    out << "[" << endl;
417
    const vector<t_const_value*>& val = value->get_list();
418
    vector<t_const_value*>::const_iterator v_iter;
419
    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
420
 
421
      out << render_const_value(etype, *v_iter);
422
      if (type->is_set()) {
423
        out << " => 1";
424
      }
425
      out << "," << endl;
426
    }
427
    out << "]";
428
  }
429
  return out.str();
430
}
431
 
432
/**
433
 * Make a struct
434
 */
435
void t_perl_generator::generate_struct(t_struct* tstruct) {
436
  generate_perl_struct(tstruct, false);
437
}
438
 
439
/**
440
 * Generates a struct definition for a thrift exception. Basically the same
441
 * as a struct but extends the Exception class.
442
 *
443
 * @param txception The struct definition
444
 */
445
void t_perl_generator::generate_xception(t_struct* txception) {
446
  generate_perl_struct(txception, true);
447
}
448
 
449
/**
450
 * Structs can be normal or exceptions.
451
 */
452
void t_perl_generator::generate_perl_struct(t_struct* tstruct,
453
                                            bool is_exception) {
454
  generate_perl_struct_definition(f_types_, tstruct, is_exception);
455
}
456
 
457
/**
458
 * Generates a struct definition for a thrift data type. This is nothing in PERL
459
 * where the objects are all just associative arrays (unless of course we
460
 * decide to start using objects for them...)
461
 *
462
 * @param tstruct The struct definition
463
 */
464
void t_perl_generator::generate_perl_struct_definition(ofstream& out,
465
                                                       t_struct* tstruct,
466
                                                       bool is_exception) {
467
  const vector<t_field*>& members = tstruct->get_members();
468
  vector<t_field*>::const_iterator m_iter;
469
 
470
  out <<
471
      "package " << perl_namespace(tstruct->get_program()) << tstruct->get_name() <<";\n";
472
  if (is_exception) {
473
    out << "use base qw(Thrift::TException);\n";
474
  }
475
 
476
  //Create simple acessor methods
477
  out << "use base qw(Class::Accessor);\n";
478
 
479
  if (members.size() > 0) {
480
      out << perl_namespace(tstruct->get_program()) << tstruct->get_name() <<"->mk_accessors( qw( ";
481
      for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
482
          t_type* t = get_true_type((*m_iter)->get_type());
483
          if (!t->is_xception()) {
484
              out << (*m_iter)->get_name() << " ";
485
          }
486
      }
487
 
488
      out << ") );\n";
489
  }
490
 
491
  out << endl;
492
 
493
  // new()
494
  indent_up();
495
  out <<
496
    "sub new {" << endl <<
497
    indent() << "my $classname = shift;" << endl <<
498
    indent() << "my $self      = {};" << endl <<
499
    indent() << "my $vals      = shift || {};" << endl;
500
 
501
  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
502
    string dval = "undef";
503
    t_type* t = get_true_type((*m_iter)->get_type());
504
    if ((*m_iter)->get_value() != NULL && !(t->is_struct() || t->is_xception())) {
505
      dval = render_const_value((*m_iter)->get_type(), (*m_iter)->get_value());
506
    }
507
    out <<
508
      indent() << "$self->{" << (*m_iter)->get_name() << "} = " << dval << ";" << endl;
509
  }
510
 
511
  // Generate constructor from array
512
  if (members.size() > 0) {
513
 
514
    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
515
      t_type* t = get_true_type((*m_iter)->get_type());
516
      if ((*m_iter)->get_value() != NULL && (t->is_struct() || t->is_xception())) {
517
        indent(out) << "$self->{" << (*m_iter)->get_name() << "} = " << render_const_value(t, (*m_iter)->get_value()) << ";" << endl;
518
      }
519
    }
520
 
521
    out << indent() << "if (UNIVERSAL::isa($vals,'HASH')) {" << endl;
522
    indent_up();
523
    for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
524
      out <<
525
        indent() << "if (defined $vals->{" << (*m_iter)->get_name() << "}) {" << endl <<
526
        indent() << "  $self->{" << (*m_iter)->get_name() << "} = $vals->{" << (*m_iter)->get_name() << "};" << endl <<
527
        indent() << "}" << endl;
528
    }
529
    indent_down();
530
    out <<
531
      indent() << "}" << endl;
532
 
533
  }
534
 
535
  out << indent() << "return bless ($self, $classname);" << endl;
536
  indent_down();
537
  out << "}\n\n";
538
 
539
  out <<
540
    "sub getName {" << endl <<
541
    indent() << "  return '" << tstruct->get_name() << "';" << endl <<
542
    indent() << "}" << endl <<
543
    endl;
544
 
545
  generate_perl_struct_reader(out, tstruct);
546
  generate_perl_struct_writer(out, tstruct);
547
 
548
}
549
 
550
/**
551
 * Generates the read() method for a struct
552
 */
553
void t_perl_generator::generate_perl_struct_reader(ofstream& out,
554
                                                   t_struct* tstruct) {
555
  const vector<t_field*>& fields = tstruct->get_members();
556
  vector<t_field*>::const_iterator f_iter;
557
 
558
  out << "sub read {" <<endl;
559
 
560
  indent_up();
561
 
562
  out <<
563
    indent() << "my ($self, $input) = @_;" << endl <<
564
    indent() << "my $xfer  = 0;" << endl <<
565
    indent() << "my $fname;"     << endl <<
566
    indent() << "my $ftype = 0;" << endl <<
567
    indent() << "my $fid   = 0;" << endl;
568
 
569
  indent(out) << "$xfer += $input->readStructBegin(\\$fname);" << endl;
570
 
571
 
572
  // Loop over reading in fields
573
  indent(out) << "while (1) " << endl;
574
 
575
  scope_up(out);
576
 
577
  indent(out) << "$xfer += $input->readFieldBegin(\\$fname, \\$ftype, \\$fid);" << endl;
578
 
579
  // Check for field STOP marker and break
580
  indent(out) << "if ($ftype == TType::STOP) {" << endl;
581
  indent_up();
582
  indent(out) << "last;" << endl;
583
  indent_down();
584
  indent(out) << "}" << endl;
585
 
586
  // Switch statement on the field we are reading
587
  indent(out) << "SWITCH: for($fid)" << endl;
588
 
589
  scope_up(out);
590
 
591
  // Generate deserialization code for known cases
592
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
593
 
594
    indent(out) << "/^" << (*f_iter)->get_key() << "$/ && do{";
595
    indent(out) << "if ($ftype == " << type_to_enum((*f_iter)->get_type()) << ") {" << endl;
596
 
597
    indent_up();
598
    generate_deserialize_field(out, *f_iter, "self->");
599
    indent_down();
600
 
601
    indent(out) << "} else {" << endl;
602
 
603
    indent(out) <<  "  $xfer += $input->skip($ftype);" << endl;
604
 
605
    out <<
606
      indent() << "}" << endl <<
607
      indent() << "last; };" << endl;
608
 
609
  }
610
  // In the default case we skip the field
611
 
612
  indent(out) <<  "  $xfer += $input->skip($ftype);" << endl;
613
 
614
  scope_down(out);
615
 
616
  indent(out) << "$xfer += $input->readFieldEnd();" << endl;
617
 
618
  scope_down(out);
619
 
620
  indent(out) << "$xfer += $input->readStructEnd();" << endl;
621
 
622
  indent(out) << "return $xfer;" << endl;
623
 
624
  indent_down();
625
  out << indent() << "}" << endl << endl;
626
}
627
 
628
/**
629
 * Generates the write() method for a struct
630
 */
631
void t_perl_generator::generate_perl_struct_writer(ofstream& out,
632
                                                   t_struct* tstruct) {
633
  string name = tstruct->get_name();
634
  const vector<t_field*>& fields = tstruct->get_sorted_members();
635
  vector<t_field*>::const_iterator f_iter;
636
 
637
  out << "sub write {" << endl;
638
 
639
  indent_up();
640
  indent(out) << "my ($self, $output) = @_;" << endl;
641
  indent(out) << "my $xfer   = 0;" << endl;
642
 
643
  indent(out) << "$xfer += $output->writeStructBegin('" << name << "');" << endl;
644
 
645
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
646
    out << indent() << "if (defined $self->{" << (*f_iter)->get_name() << "}) {" << endl;
647
    indent_up();
648
 
649
    indent(out) <<
650
      "$xfer += $output->writeFieldBegin(" <<
651
      "'" << (*f_iter)->get_name() << "', " <<
652
      type_to_enum((*f_iter)->get_type()) << ", " <<
653
      (*f_iter)->get_key() << ");" << endl;
654
 
655
 
656
    // Write field contents
657
    generate_serialize_field(out, *f_iter, "self->");
658
 
659
    indent(out) <<
660
        "$xfer += $output->writeFieldEnd();" << endl;
661
 
662
    indent_down();
663
    indent(out) << "}" << endl;
664
  }
665
 
666
 
667
  out <<
668
    indent() << "$xfer += $output->writeFieldStop();" << endl <<
669
    indent() << "$xfer += $output->writeStructEnd();" << endl;
670
 
671
  out <<indent() << "return $xfer;" << endl;
672
 
673
  indent_down();
674
  out <<
675
    indent() << "}" << endl <<
676
    endl;
677
}
678
 
679
/**
680
 * Generates a thrift service.
681
 *
682
 * @param tservice The service definition
683
 */
684
void t_perl_generator::generate_service(t_service* tservice) {
685
  string f_service_name = get_namespace_out_dir()+service_name_+".pm";
686
  f_service_.open(f_service_name.c_str());
687
 
688
  f_service_ <<
689
    ///      "package "<<service_name_<<";"<<endl<<
690
    autogen_comment() <<
691
    perl_includes();
692
 
693
  f_service_ <<
694
    "use " << perl_namespace(tservice->get_program()) << "Types;" << endl;
695
 
696
  t_service* extends_s = tservice->get_extends();
697
  if (extends_s != NULL) {
698
    f_service_ <<
699
      "use " << perl_namespace(extends_s->get_program()) << extends_s->get_name() << ";" << endl;
700
  }
701
 
702
  f_service_ <<
703
    endl;
704
 
705
  // Generate the three main parts of the service (well, two for now in PERL)
706
  generate_service_helpers(tservice);
707
  generate_service_interface(tservice);
708
  generate_service_rest(tservice);
709
  generate_service_client(tservice);
710
  generate_service_processor(tservice);
711
 
712
  // Close service file
713
  f_service_ << "1;" << endl;
714
  f_service_.close();
715
}
716
 
717
/**
718
 * Generates a service server definition.
719
 *
720
 * @param tservice The service to generate a server for.
721
 */
722
void t_perl_generator::generate_service_processor(t_service* tservice) {
723
  // Generate the dispatch methods
724
  vector<t_function*> functions = tservice->get_functions();
725
  vector<t_function*>::iterator f_iter;
726
 
727
  string extends = "";
728
  string extends_processor = "";
729
  t_service* extends_s = tservice->get_extends();
730
  if (extends_s != NULL) {
731
    extends = perl_namespace(extends_s->get_program()) + extends_s->get_name();
732
    extends_processor = "use base qw(" + extends + "Processor);";
733
  }
734
 
735
  indent_up();
736
 
737
  // Generate the header portion
738
  f_service_ <<
739
    "package " << perl_namespace(program_) << service_name_ << "Processor;" << endl << endl <<
740
    "use strict;" << endl <<
741
    extends_processor << endl << endl;
742
 
743
 
744
  if (extends.empty()) {
745
    f_service_ << "sub new {" << endl;
746
 
747
    indent_up();
748
 
749
    f_service_ <<
750
      indent() << "my ($classname, $handler) = @_;"<< endl <<
751
      indent() << "my $self      = {};"   << endl;
752
 
753
    f_service_ <<
754
      indent() << "$self->{handler} = $handler;" << endl;
755
 
756
    f_service_ <<
757
      indent() << "return bless ($self, $classname);"<<endl;
758
 
759
    indent_down();
760
 
761
    f_service_ <<
762
      "}" << endl << endl;
763
  }
764
 
765
  // Generate the server implementation
766
  f_service_ << "sub process {" << endl;
767
  indent_up();
768
 
769
  f_service_ <<
770
    indent() << "my ($self, $input, $output) = @_;" << endl;
771
 
772
  f_service_ <<
773
    indent() << "my $rseqid = 0;" << endl <<
774
    indent() << "my $fname  = undef;" << endl <<
775
    indent() << "my $mtype  = 0;" << endl << endl;
776
 
777
  f_service_ <<
778
    indent() << "$input->readMessageBegin(\\$fname, \\$mtype, \\$rseqid);" << endl;
779
 
780
  // HOT: check for method implementation
781
  f_service_ <<
782
    indent() << "my $methodname = 'process_'.$fname;" << endl <<
783
    indent() << "if (!$self->can($methodname)) {" << endl;
784
  indent_up();
785
 
786
  f_service_ <<
787
    indent() << "$input->skip(TType::STRUCT);" << endl <<
788
    indent() << "$input->readMessageEnd();" << endl <<
789
    indent() << "my $x = new TApplicationException('Function '.$fname.' not implemented.', TApplicationException::UNKNOWN_METHOD);" << endl <<
790
    indent() << "$output->writeMessageBegin($fname, TMessageType::EXCEPTION, $rseqid);" << endl <<
791
    indent() << "$x->write($output);" << endl <<
792
    indent() << "$output->writeMessageEnd();" << endl <<
793
    indent() << "$output->getTransport()->flush();" << endl <<
794
    indent() << "return;" << endl;
795
 
796
  indent_down();
797
  f_service_ <<
798
    indent() << "}" << endl <<
799
    indent() << "$self->$methodname($rseqid, $input, $output);" << endl <<
800
    indent() << "return 1;" << endl;
801
 
802
  indent_down();
803
 
804
  f_service_ <<
805
    "}" << endl <<endl;
806
 
807
  // Generate the process subfunctions
808
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
809
    generate_process_function(tservice, *f_iter);
810
  }
811
}
812
 
813
/**
814
 * Generates a process function definition.
815
 *
816
 * @param tfunction The function to write a dispatcher for
817
 */
818
void t_perl_generator::generate_process_function(t_service* tservice,
819
                                                 t_function* tfunction) {
820
  // Open function
821
  f_service_ <<
822
    "sub process_" << tfunction->get_name() << " {"<<endl;
823
 
824
  indent_up();
825
 
826
  f_service_ <<
827
    indent() << "my ($self, $seqid, $input, $output) = @_;" << endl;
828
 
829
  string argsname = perl_namespace(tservice->get_program()) + service_name_ + "_" + tfunction->get_name() + "_args";
830
  string resultname = perl_namespace(tservice->get_program()) + service_name_ + "_" + tfunction->get_name() + "_result";
831
 
832
  f_service_ <<
833
    indent() << "my $args = new " << argsname << "();" << endl <<
834
    indent() << "$args->read($input);" << endl;
835
 
836
  f_service_ <<
837
    indent() << "$input->readMessageEnd();" << endl;
838
 
839
  t_struct* xs = tfunction->get_xceptions();
840
  const std::vector<t_field*>& xceptions = xs->get_members();
841
  vector<t_field*>::const_iterator x_iter;
842
 
843
  // Declare result for non oneway function
844
  if (!tfunction->is_oneway()) {
845
    f_service_ <<
846
      indent() << "my $result = new " << resultname << "();" << endl;
847
  }
848
 
849
  // Try block for a function with exceptions
850
  if (xceptions.size() > 0) {
851
    f_service_ <<
852
      indent() << "eval {" << endl;
853
    indent_up();
854
  }
855
 
856
  // Generate the function call
857
  t_struct* arg_struct = tfunction->get_arglist();
858
  const std::vector<t_field*>& fields = arg_struct->get_members();
859
  vector<t_field*>::const_iterator f_iter;
860
 
861
  f_service_ << indent();
862
  if (!tfunction->is_oneway() && !tfunction->get_returntype()->is_void()) {
863
    f_service_ << "$result->{success} = ";
864
  }
865
  f_service_ <<
866
    "$self->{handler}->" << tfunction->get_name() << "(";
867
  bool first = true;
868
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
869
    if (first) {
870
      first = false;
871
    } else {
872
      f_service_ << ", ";
873
    }
874
    f_service_ << "$args->" << (*f_iter)->get_name();
875
  }
876
  f_service_ << ");" << endl;
877
 
878
  if (!tfunction->is_oneway() && xceptions.size() > 0) {
879
    indent_down();
880
    for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
881
      f_service_ <<
882
        indent() << "}; if( UNIVERSAL::isa($@,'" <<
883
          perl_namespace((*x_iter)->get_type()->get_program()) <<
884
          (*x_iter)->get_type()->get_name() <<
885
          "') ){ " << endl;
886
 
887
      if (!tfunction->is_oneway()) {
888
        indent_up();
889
        f_service_ <<
890
          indent() << "$result->{" << (*x_iter)->get_name() << "} = $@;" << endl;
891
        indent_down();
892
        f_service_ << indent();
893
      }
894
    }
895
    f_service_ << "}" << endl;
896
  }
897
 
898
  // Shortcut out here for oneway functions
899
  if (tfunction->is_oneway()) {
900
    f_service_ <<
901
      indent() << "return;" << endl;
902
    indent_down();
903
    f_service_ <<
904
      "}" << endl;
905
    return;
906
  }
907
  // Serialize the request header
908
  f_service_ <<
909
    indent() << "$output->writeMessageBegin('" << tfunction->get_name() << "', TMessageType::REPLY, $seqid);" << endl <<
910
    indent() << "$result->write($output);" << endl <<
911
    indent() << "$output->writeMessageEnd();" << endl <<
912
    indent() << "$output->getTransport()->flush();" << endl;
913
 
914
  // Close function
915
  indent_down();
916
  f_service_ <<
917
    "}" << endl << endl;
918
}
919
 
920
/**
921
 * Generates helper functions for a service.
922
 *
923
 * @param tservice The service to generate a header definition for
924
 */
925
void t_perl_generator::generate_service_helpers(t_service* tservice) {
926
  vector<t_function*> functions = tservice->get_functions();
927
  vector<t_function*>::iterator f_iter;
928
 
929
  f_service_ <<
930
    "# HELPER FUNCTIONS AND STRUCTURES" << endl << endl;
931
 
932
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
933
    t_struct* ts = (*f_iter)->get_arglist();
934
    string name = ts->get_name();
935
    ts->set_name(service_name_ + "_" + name);
936
    generate_perl_struct_definition(f_service_, ts, false);
937
    generate_perl_function_helpers(*f_iter);
938
    ts->set_name(name);
939
  }
940
}
941
 
942
/**
943
 * Generates a struct and helpers for a function.
944
 *
945
 * @param tfunction The function
946
 */
947
void t_perl_generator::generate_perl_function_helpers(t_function* tfunction) {
948
  t_struct result(program_, service_name_ + "_" + tfunction->get_name() + "_result");
949
  t_field success(tfunction->get_returntype(), "success", 0);
950
  if (!tfunction->get_returntype()->is_void()) {
951
    result.append(&success);
952
  }
953
 
954
  t_struct* xs = tfunction->get_xceptions();
955
  const vector<t_field*>& fields = xs->get_members();
956
  vector<t_field*>::const_iterator f_iter;
957
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
958
    result.append(*f_iter);
959
  }
960
 
961
  generate_perl_struct_definition(f_service_, &result, false);
962
}
963
 
964
/**
965
 * Generates a service interface definition.
966
 *
967
 * @param tservice The service to generate a header definition for
968
 */
969
void t_perl_generator::generate_service_interface(t_service* tservice) {
970
  string extends_if = "";
971
  t_service* extends_s = tservice->get_extends();
972
  if (extends_s != NULL) {
973
    extends_if = "use base qw(" + perl_namespace(extends_s->get_program()) + extends_s->get_name() + "If);";
974
  }
975
 
976
  f_service_ <<
977
    "package " << perl_namespace(program_) << service_name_ << "If;" << endl << endl <<
978
    "use strict;" << endl <<
979
    extends_if << endl << endl;
980
 
981
 
982
  indent_up();
983
  vector<t_function*> functions = tservice->get_functions();
984
  vector<t_function*>::iterator f_iter;
985
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
986
    f_service_ <<
987
      "sub " << function_signature(*f_iter) <<endl<< "  die 'implement interface';\n}" << endl << endl;
988
  }
989
  indent_down();
990
 
991
}
992
 
993
/**
994
 * Generates a REST interface
995
 */
996
void t_perl_generator::generate_service_rest(t_service* tservice) {
997
  string extends = "";
998
  string extends_if = "";
999
  t_service* extends_s = tservice->get_extends();
1000
  if (extends_s != NULL) {
1001
    extends    =  extends_s->get_name();
1002
    extends_if = "use base qw(" + perl_namespace(extends_s->get_program()) + extends_s->get_name() + "Rest);";
1003
  }
1004
  f_service_ <<
1005
    "package " << perl_namespace(program_) << service_name_ << "Rest;" << endl << endl <<
1006
    "use strict;" << endl <<
1007
    extends_if << endl << endl;
1008
 
1009
 
1010
  if (extends.empty()) {
1011
    f_service_ << "sub new {" << endl;
1012
 
1013
    indent_up();
1014
 
1015
    f_service_ <<
1016
      indent() << "my ($classname, $impl) = @_;" << endl <<
1017
      indent() << "my $self     ={ impl => $impl };" << endl << endl <<
1018
      indent() << "return bless($self,$classname);" << endl;
1019
 
1020
 
1021
    indent_down();
1022
 
1023
    f_service_  <<
1024
      "}" << endl << endl;
1025
  }
1026
 
1027
  vector<t_function*> functions = tservice->get_functions();
1028
  vector<t_function*>::iterator f_iter;
1029
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1030
    f_service_ <<
1031
      "sub " << (*f_iter)->get_name() <<
1032
      "{"    <<endl;
1033
 
1034
    indent_up();
1035
 
1036
    f_service_ <<
1037
      indent() << "my ($self, $request) = @_;" << endl << endl;
1038
 
1039
 
1040
    const vector<t_field*>& args = (*f_iter)->get_arglist()->get_members();
1041
    vector<t_field*>::const_iterator a_iter;
1042
    for (a_iter = args.begin(); a_iter != args.end(); ++a_iter) {
1043
      t_type* atype = get_true_type((*a_iter)->get_type());
1044
      string req = "$request->{'" + (*a_iter)->get_name() + "'}";
1045
      f_service_ <<
1046
        indent() << "my $" << (*a_iter)->get_name() << " = (" << req << ") ? " << req << " : undef;" << endl;
1047
      if (atype->is_string() &&
1048
          ((t_base_type*)atype)->is_string_list()) {
1049
        f_service_ <<
1050
          indent() << "my @" << (*a_iter)->get_name() << " = split(/,/, $" << (*a_iter)->get_name() << ");" << endl <<
1051
          indent()     << "$"<<(*a_iter)->get_name() <<" = \\@"<<(*a_iter)->get_name()<<endl;
1052
      }
1053
    }
1054
    f_service_ <<
1055
      indent() << "return $self->{impl}->" << (*f_iter)->get_name() << "(" << argument_list((*f_iter)->get_arglist()) << ");" << endl;
1056
    indent_down();
1057
    indent(f_service_) << "}" << endl <<endl;
1058
  }
1059
 
1060
}
1061
 
1062
/**
1063
 * Generates a service client definition.
1064
 *
1065
 * @param tservice The service to generate a server for.
1066
 */
1067
void t_perl_generator::generate_service_client(t_service* tservice) {
1068
  string extends = "";
1069
  string extends_client = "";
1070
  t_service* extends_s = tservice->get_extends();
1071
  if (extends_s != NULL) {
1072
    extends = perl_namespace(extends_s->get_program()) + extends_s->get_name();
1073
    extends_client = "use base qw(" + extends + "Client);";
1074
  }
1075
 
1076
  f_service_ <<
1077
      "package " << perl_namespace(program_) << service_name_ << "Client;" << endl << endl <<
1078
      extends_client << endl <<
1079
      "use base qw(" << perl_namespace(program_) << service_name_ << "If);" << endl;
1080
 
1081
  // Constructor function
1082
  f_service_ << "sub new {"<<endl;
1083
 
1084
  indent_up();
1085
 
1086
  f_service_ <<
1087
    indent() << "my ($classname, $input, $output) = @_;" << endl <<
1088
    indent() << "my $self      = {};"   <<endl;
1089
 
1090
  if (!extends.empty()) {
1091
    f_service_ <<
1092
      indent() << "$self = $classname->SUPER::new($input, $output);" << endl;
1093
  } else {
1094
    f_service_ <<
1095
      indent() << "$self->{input}  = $input;" << endl <<
1096
      indent() << "$self->{output} = defined $output ? $output : $input;" << endl <<
1097
      indent() << "$self->{seqid}  = 0;" << endl;
1098
  }
1099
 
1100
  f_service_ <<
1101
    indent() << "return bless($self,$classname);"<<endl;
1102
 
1103
  indent_down();
1104
 
1105
  f_service_ <<
1106
    "}" << endl << endl;
1107
 
1108
  // Generate client method implementations
1109
  vector<t_function*> functions = tservice->get_functions();
1110
  vector<t_function*>::const_iterator f_iter;
1111
  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1112
    t_struct* arg_struct = (*f_iter)->get_arglist();
1113
    const vector<t_field*>& fields = arg_struct->get_members();
1114
    vector<t_field*>::const_iterator fld_iter;
1115
    string funname = (*f_iter)->get_name();
1116
 
1117
    // Open function
1118
    f_service_ << "sub " << function_signature(*f_iter) << endl;
1119
 
1120
    indent_up();
1121
 
1122
    indent(f_service_) << indent() <<
1123
      "$self->send_" << funname << "(";
1124
 
1125
    bool first = true;
1126
    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1127
      if (first) {
1128
        first = false;
1129
      } else {
1130
        f_service_ << ", ";
1131
      }
1132
      f_service_ << "$" << (*fld_iter)->get_name();
1133
    }
1134
    f_service_ << ");" << endl;
1135
 
1136
    if (!(*f_iter)->is_oneway()) {
1137
      f_service_ << indent();
1138
      if (!(*f_iter)->get_returntype()->is_void()) {
1139
        f_service_ << "return ";
1140
      }
1141
      f_service_ <<
1142
        "$self->recv_" << funname << "();" << endl;
1143
    }
1144
 
1145
    indent_down();
1146
 
1147
    f_service_ << "}" << endl << endl;
1148
 
1149
    f_service_ <<
1150
      "sub send_" << function_signature(*f_iter) << endl;
1151
 
1152
    indent_up();
1153
 
1154
    std::string argsname = perl_namespace(tservice->get_program()) + service_name_ + "_" + (*f_iter)->get_name() + "_args";
1155
 
1156
    // Serialize the request header
1157
    f_service_ <<
1158
      indent() << "$self->{output}->writeMessageBegin('" << (*f_iter)->get_name() << "', TMessageType::CALL, $self->{seqid});" << endl;
1159
 
1160
    f_service_ <<
1161
      indent() << "my $args = new " << argsname << "();" << endl;
1162
 
1163
    for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1164
      f_service_ <<
1165
        indent() << "$args->{" << (*fld_iter)->get_name() << "} = $" << (*fld_iter)->get_name() << ";" << endl;
1166
    }
1167
 
1168
    // Write to the stream
1169
    f_service_ <<
1170
      indent() << "$args->write($self->{output});" << endl <<
1171
      indent() << "$self->{output}->writeMessageEnd();" << endl <<
1172
      indent() << "$self->{output}->getTransport()->flush();" << endl;
1173
 
1174
 
1175
    indent_down();
1176
 
1177
    f_service_ << "}" << endl;
1178
 
1179
 
1180
    if (!(*f_iter)->is_oneway()) {
1181
      std::string resultname = perl_namespace(tservice->get_program()) + service_name_ + "_" + (*f_iter)->get_name() + "_result";
1182
      t_struct noargs(program_);
1183
 
1184
      t_function recv_function((*f_iter)->get_returntype(),
1185
                               string("recv_") + (*f_iter)->get_name(),
1186
                               &noargs);
1187
      // Open function
1188
      f_service_ <<
1189
        endl <<
1190
        "sub " << function_signature(&recv_function) << endl;
1191
 
1192
      indent_up();
1193
 
1194
      f_service_ <<
1195
        indent() << "my $rseqid = 0;" << endl <<
1196
        indent() << "my $fname;" << endl <<
1197
        indent() << "my $mtype = 0;" << endl <<
1198
        endl;
1199
 
1200
      f_service_ <<
1201
        indent() << "$self->{input}->readMessageBegin(\\$fname, \\$mtype, \\$rseqid);" << endl <<
1202
        indent() << "if ($mtype == TMessageType::EXCEPTION) {" << endl <<
1203
        indent() << "  my $x = new TApplicationException();" << endl <<
1204
        indent() << "  $x->read($self->{input});" << endl <<
1205
        indent() << "  $self->{input}->readMessageEnd();" << endl <<
1206
        indent() << "  die $x;" << endl <<
1207
        indent() << "}" << endl;
1208
 
1209
 
1210
      f_service_ <<
1211
        indent() << "my $result = new " << resultname << "();" << endl <<
1212
        indent() << "$result->read($self->{input});" << endl;
1213
 
1214
 
1215
      f_service_ <<
1216
        indent() << "$self->{input}->readMessageEnd();" << endl <<
1217
        endl;
1218
 
1219
 
1220
      // Careful, only return result if not a void function
1221
      if (!(*f_iter)->get_returntype()->is_void()) {
1222
        f_service_ <<
1223
          indent() << "if (defined $result->{success} ) {" << endl <<
1224
          indent() << "  return $result->{success};" << endl <<
1225
          indent() << "}" << endl;
1226
      }
1227
 
1228
      t_struct* xs = (*f_iter)->get_xceptions();
1229
      const std::vector<t_field*>& xceptions = xs->get_members();
1230
      vector<t_field*>::const_iterator x_iter;
1231
      for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1232
        f_service_ <<
1233
          indent() << "if (defined $result->{" << (*x_iter)->get_name() << "}) {" << endl <<
1234
          indent() << "  die $result->{" << (*x_iter)->get_name() << "};" << endl <<
1235
          indent() << "}" << endl;
1236
      }
1237
 
1238
      // Careful, only return _result if not a void function
1239
      if ((*f_iter)->get_returntype()->is_void()) {
1240
        indent(f_service_) <<
1241
          "return;" << endl;
1242
      } else {
1243
        f_service_ <<
1244
          indent() << "die \"" << (*f_iter)->get_name() << " failed: unknown result\";" << endl;
1245
      }
1246
 
1247
      // Close function
1248
      indent_down();
1249
      f_service_ << "}"<<endl;
1250
 
1251
    }
1252
  }
1253
 
1254
}
1255
 
1256
/**
1257
 * Deserializes a field of any type.
1258
 */
1259
void t_perl_generator::generate_deserialize_field(ofstream &out,
1260
                                                  t_field* tfield,
1261
                                                  string prefix,
1262
                                                  bool inclass) {
1263
  t_type* type = get_true_type(tfield->get_type());
1264
 
1265
  if (type->is_void()) {
1266
    throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
1267
      prefix + tfield->get_name();
1268
  }
1269
 
1270
  string name = tfield->get_name();
1271
 
1272
  //Hack for when prefix is defined (always a hash ref)
1273
  if (!prefix.empty()) {
1274
    name = prefix + "{" + tfield->get_name() + "}";
1275
  }
1276
 
1277
  if (type->is_struct() || type->is_xception()) {
1278
    generate_deserialize_struct(out,
1279
                                (t_struct*)type,
1280
                                 name);
1281
  } else if (type->is_container()) {
1282
    generate_deserialize_container(out, type, name);
1283
  } else if (type->is_base_type() || type->is_enum()) {
1284
    indent(out) <<
1285
      "$xfer += $input->";
1286
 
1287
    if (type->is_base_type()) {
1288
      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1289
      switch (tbase) {
1290
      case t_base_type::TYPE_VOID:
1291
        throw "compiler error: cannot serialize void field in a struct: " +
1292
          name;
1293
        break;
1294
      case t_base_type::TYPE_STRING:
1295
        out << "readString(\\$" << name << ");";
1296
        break;
1297
      case t_base_type::TYPE_BOOL:
1298
        out << "readBool(\\$" << name << ");";
1299
        break;
1300
      case t_base_type::TYPE_BYTE:
1301
        out << "readByte(\\$" << name << ");";
1302
        break;
1303
      case t_base_type::TYPE_I16:
1304
        out << "readI16(\\$" << name << ");";
1305
        break;
1306
      case t_base_type::TYPE_I32:
1307
        out << "readI32(\\$" << name << ");";
1308
        break;
1309
      case t_base_type::TYPE_I64:
1310
        out << "readI64(\\$" << name << ");";
1311
        break;
1312
      case t_base_type::TYPE_DOUBLE:
1313
        out << "readDouble(\\$" << name << ");";
1314
        break;
1315
      default:
1316
        throw "compiler error: no PERL name for base type " + t_base_type::t_base_name(tbase);
1317
      }
1318
    } else if (type->is_enum()) {
1319
      out << "readI32(\\$" << name << ");";
1320
    }
1321
    out << endl;
1322
 
1323
  } else {
1324
    printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
1325
           tfield->get_name().c_str(), type->get_name().c_str());
1326
  }
1327
}
1328
 
1329
/**
1330
 * Generates an unserializer for a variable. This makes two key assumptions,
1331
 * first that there is a const char* variable named data that points to the
1332
 * buffer for deserialization, and that there is a variable protocol which
1333
 * is a reference to a TProtocol serialization object.
1334
 */
1335
void t_perl_generator::generate_deserialize_struct(ofstream &out,
1336
                                                   t_struct* tstruct,
1337
                                                   string prefix) {
1338
  out <<
1339
    indent() << "$" << prefix << " = new " << perl_namespace(tstruct->get_program()) << tstruct->get_name() << "();" << endl <<
1340
    indent() << "$xfer += $" << prefix << "->read($input);" << endl;
1341
}
1342
 
1343
void t_perl_generator::generate_deserialize_container(ofstream &out,
1344
                                                      t_type* ttype,
1345
                                                      string prefix) {
1346
  scope_up(out);
1347
 
1348
  string size = tmp("_size");
1349
  string ktype = tmp("_ktype");
1350
  string vtype = tmp("_vtype");
1351
  string etype = tmp("_etype");
1352
 
1353
  t_field fsize(g_type_i32, size);
1354
  t_field fktype(g_type_byte, ktype);
1355
  t_field fvtype(g_type_byte, vtype);
1356
  t_field fetype(g_type_byte, etype);
1357
 
1358
  out <<
1359
    indent() << "my $" << size << " = 0;" << endl;
1360
 
1361
  // Declare variables, read header
1362
  if (ttype->is_map()) {
1363
    out <<
1364
      indent() << "$" << prefix << " = {};" << endl <<
1365
      indent() << "my $" << ktype << " = 0;" << endl <<
1366
      indent() << "my $" << vtype << " = 0;" << endl;
1367
 
1368
    out <<
1369
      indent() << "$xfer += $input->readMapBegin(" <<
1370
      "\\$" << ktype << ", \\$" << vtype << ", \\$" << size << ");" << endl;
1371
 
1372
  } else if (ttype->is_set()) {
1373
 
1374
    out <<
1375
      indent() << "$" << prefix << " = {};" << endl <<
1376
      indent() << "my $" << etype << " = 0;" << endl <<
1377
      indent() << "$xfer += $input->readSetBegin(" <<
1378
      "\\$" << etype << ", \\$" << size << ");" << endl;
1379
 
1380
  } else if (ttype->is_list()) {
1381
 
1382
    out <<
1383
      indent() << "$" << prefix << " = [];" << endl <<
1384
      indent() << "my $" << etype << " = 0;" << endl <<
1385
      indent() << "$xfer += $input->readListBegin(" <<
1386
      "\\$" << etype << ", \\$" << size << ");" << endl;
1387
 
1388
  }
1389
 
1390
  // For loop iterates over elements
1391
  string i = tmp("_i");
1392
  indent(out) <<
1393
    "for (my $" <<
1394
    i << " = 0; $" << i << " < $" << size << "; ++$" << i << ")" << endl;
1395
 
1396
  scope_up(out);
1397
 
1398
  if (ttype->is_map()) {
1399
    generate_deserialize_map_element(out, (t_map*)ttype, prefix);
1400
  } else if (ttype->is_set()) {
1401
    generate_deserialize_set_element(out, (t_set*)ttype, prefix);
1402
  } else if (ttype->is_list()) {
1403
    generate_deserialize_list_element(out, (t_list*)ttype, prefix);
1404
  }
1405
 
1406
  scope_down(out);
1407
 
1408
 
1409
  // Read container end
1410
  if (ttype->is_map()) {
1411
    indent(out) << "$xfer += $input->readMapEnd();" << endl;
1412
  } else if (ttype->is_set()) {
1413
    indent(out) << "$xfer += $input->readSetEnd();" << endl;
1414
  } else if (ttype->is_list()) {
1415
    indent(out) << "$xfer += $input->readListEnd();" << endl;
1416
  }
1417
 
1418
  scope_down(out);
1419
}
1420
 
1421
 
1422
/**
1423
 * Generates code to deserialize a map
1424
 */
1425
void t_perl_generator::generate_deserialize_map_element(ofstream &out,
1426
                                                        t_map* tmap,
1427
                                                        string prefix) {
1428
  string key = tmp("key");
1429
  string val = tmp("val");
1430
  t_field fkey(tmap->get_key_type(), key);
1431
  t_field fval(tmap->get_val_type(), val);
1432
 
1433
  indent(out) <<
1434
    declare_field(&fkey, true, true) << endl;
1435
  indent(out) <<
1436
    declare_field(&fval, true, true) << endl;
1437
 
1438
  generate_deserialize_field(out, &fkey);
1439
  generate_deserialize_field(out, &fval);
1440
 
1441
  indent(out) <<
1442
    "$" << prefix << "->{$" << key << "} = $" << val << ";" << endl;
1443
}
1444
 
1445
void t_perl_generator::generate_deserialize_set_element(ofstream &out,
1446
                                                        t_set* tset,
1447
                                                        string prefix) {
1448
  string elem = tmp("elem");
1449
  t_field felem(tset->get_elem_type(), elem);
1450
 
1451
  indent(out) <<
1452
    "my $" << elem << " = undef;" << endl;
1453
 
1454
  generate_deserialize_field(out, &felem);
1455
 
1456
  indent(out) <<
1457
    "$" << prefix << "->{$" << elem << "} = 1;" << endl;
1458
}
1459
 
1460
void t_perl_generator::generate_deserialize_list_element(ofstream &out,
1461
                                                         t_list* tlist,
1462
                                                         string prefix) {
1463
  string elem = tmp("elem");
1464
  t_field felem(tlist->get_elem_type(), elem);
1465
 
1466
  indent(out) <<
1467
    "my $" << elem << " = undef;" << endl;
1468
 
1469
  generate_deserialize_field(out, &felem);
1470
 
1471
  indent(out) <<
1472
    "push(@{$" << prefix << "},$" << elem << ");" << endl;
1473
}
1474
 
1475
 
1476
/**
1477
 * Serializes a field of any type.
1478
 *
1479
 * @param tfield The field to serialize
1480
 * @param prefix Name to prepend to field name
1481
 */
1482
void t_perl_generator::generate_serialize_field(ofstream &out,
1483
                                                t_field* tfield,
1484
                                                string prefix) {
1485
  t_type* type = get_true_type(tfield->get_type());
1486
 
1487
  // Do nothing for void types
1488
  if (type->is_void()) {
1489
    throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
1490
      prefix + tfield->get_name();
1491
  }
1492
 
1493
  if (type->is_struct() || type->is_xception()) {
1494
    generate_serialize_struct(out,
1495
                              (t_struct*)type,
1496
                               prefix + "{"+tfield->get_name()+"}" );
1497
  } else if (type->is_container()) {
1498
    generate_serialize_container(out,
1499
                                 type,
1500
                                 prefix + "{" + tfield->get_name()+"}");
1501
  } else if (type->is_base_type() || type->is_enum()) {
1502
 
1503
    string name = tfield->get_name();
1504
 
1505
    //Hack for when prefix is defined (always a hash ref)
1506
    if(!prefix.empty())
1507
      name = prefix + "{" + tfield->get_name() + "}";
1508
 
1509
    indent(out) <<
1510
      "$xfer += $output->";
1511
 
1512
    if (type->is_base_type()) {
1513
      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1514
      switch (tbase) {
1515
      case t_base_type::TYPE_VOID:
1516
        throw
1517
          "compiler error: cannot serialize void field in a struct: " + name;
1518
        break;
1519
      case t_base_type::TYPE_STRING:
1520
        out << "writeString($" << name << ");";
1521
        break;
1522
      case t_base_type::TYPE_BOOL:
1523
        out << "writeBool($" << name << ");";
1524
        break;
1525
      case t_base_type::TYPE_BYTE:
1526
        out << "writeByte($" << name << ");";
1527
        break;
1528
      case t_base_type::TYPE_I16:
1529
        out << "writeI16($" << name << ");";
1530
        break;
1531
      case t_base_type::TYPE_I32:
1532
        out << "writeI32($" << name << ");";
1533
        break;
1534
      case t_base_type::TYPE_I64:
1535
        out << "writeI64($" << name << ");";
1536
        break;
1537
      case t_base_type::TYPE_DOUBLE:
1538
        out << "writeDouble($" << name << ");";
1539
        break;
1540
      default:
1541
        throw "compiler error: no PERL name for base type " + t_base_type::t_base_name(tbase);
1542
      }
1543
    } else if (type->is_enum()) {
1544
      out << "writeI32($" << name << ");";
1545
    }
1546
    out << endl;
1547
 
1548
  } else {
1549
    printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
1550
           prefix.c_str(),
1551
           tfield->get_name().c_str(),
1552
           type->get_name().c_str());
1553
  }
1554
}
1555
 
1556
/**
1557
 * Serializes all the members of a struct.
1558
 *
1559
 * @param tstruct The struct to serialize
1560
 * @param prefix  String prefix to attach to all fields
1561
 */
1562
void t_perl_generator::generate_serialize_struct(ofstream &out,
1563
                                                 t_struct* tstruct,
1564
                                                 string prefix) {
1565
    indent(out) <<
1566
      "$xfer += $" << prefix << "->write($output);" << endl;
1567
}
1568
 
1569
/**
1570
 * Writes out a container
1571
 */
1572
void t_perl_generator::generate_serialize_container(ofstream &out,
1573
                                                    t_type* ttype,
1574
                                                    string prefix) {
1575
  scope_up(out);
1576
 
1577
  if (ttype->is_map()) {
1578
    indent(out) <<
1579
      "$output->writeMapBegin(" <<
1580
      type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
1581
      type_to_enum(((t_map*)ttype)->get_val_type()) << ", " <<
1582
      "scalar(keys %{$" << prefix << "}));" << endl;
1583
  } else if (ttype->is_set()) {
1584
    indent(out) <<
1585
      "$output->writeSetBegin(" <<
1586
      type_to_enum(((t_set*)ttype)->get_elem_type()) << ", " <<
1587
      "scalar(@{$" << prefix << "}));" << endl;
1588
 
1589
  } else if (ttype->is_list()) {
1590
 
1591
    indent(out) <<
1592
      "$output->writeListBegin(" <<
1593
      type_to_enum(((t_list*)ttype)->get_elem_type()) << ", " <<
1594
      "scalar(@{$" << prefix << "}));" << endl;
1595
 
1596
  }
1597
 
1598
  scope_up(out);
1599
 
1600
  if (ttype->is_map()) {
1601
    string kiter = tmp("kiter");
1602
    string viter = tmp("viter");
1603
    indent(out) <<
1604
      "while( my ($"<<kiter<<",$"<<viter<<") = each %{$" << prefix << "}) " << endl;
1605
 
1606
    scope_up(out);
1607
    generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
1608
    scope_down(out);
1609
 
1610
  } else if (ttype->is_set()) {
1611
    string iter = tmp("iter");
1612
    indent(out) <<
1613
      "foreach my $"<<iter<<" (@{$" << prefix << "})" << endl;
1614
    scope_up(out);
1615
    generate_serialize_set_element(out, (t_set*)ttype, iter);
1616
    scope_down(out);
1617
 
1618
 
1619
  } else if (ttype->is_list()) {
1620
    string iter = tmp("iter");
1621
    indent(out) <<
1622
      "foreach my $"<<iter<<" (@{$" << prefix << "}) " << endl;
1623
    scope_up(out);
1624
    generate_serialize_list_element(out, (t_list*)ttype, iter);
1625
    scope_down(out);
1626
  }
1627
 
1628
  scope_down(out);
1629
 
1630
  if (ttype->is_map()) {
1631
    indent(out) <<
1632
      "$output->writeMapEnd();" << endl;
1633
  } else if (ttype->is_set()) {
1634
    indent(out) <<
1635
      "$output->writeSetEnd();" << endl;
1636
  } else if (ttype->is_list()) {
1637
    indent(out) <<
1638
      "$output->writeListEnd();" << endl;
1639
  }
1640
 
1641
  scope_down(out);
1642
}
1643
 
1644
/**
1645
 * Serializes the members of a map.
1646
 *
1647
 */
1648
void t_perl_generator::generate_serialize_map_element(ofstream &out,
1649
                                                      t_map* tmap,
1650
                                                      string kiter,
1651
                                                      string viter) {
1652
  t_field kfield(tmap->get_key_type(), kiter);
1653
  generate_serialize_field(out, &kfield);
1654
 
1655
  t_field vfield(tmap->get_val_type(), viter);
1656
  generate_serialize_field(out, &vfield);
1657
}
1658
 
1659
/**
1660
 * Serializes the members of a set.
1661
 */
1662
void t_perl_generator::generate_serialize_set_element(ofstream &out,
1663
                                                      t_set* tset,
1664
                                                      string iter) {
1665
  t_field efield(tset->get_elem_type(), iter);
1666
  generate_serialize_field(out, &efield);
1667
}
1668
 
1669
/**
1670
 * Serializes the members of a list.
1671
 */
1672
void t_perl_generator::generate_serialize_list_element(ofstream &out,
1673
                                                       t_list* tlist,
1674
                                                       string iter) {
1675
  t_field efield(tlist->get_elem_type(), iter);
1676
  generate_serialize_field(out, &efield);
1677
}
1678
 
1679
/**
1680
 * Declares a field, which may include initialization as necessary.
1681
 *
1682
 * @param ttype The type
1683
 */
1684
string t_perl_generator::declare_field(t_field* tfield, bool init, bool obj) {
1685
  string result = "my $" + tfield->get_name();
1686
  if (init) {
1687
    t_type* type = get_true_type(tfield->get_type());
1688
    if (type->is_base_type()) {
1689
      t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1690
      switch (tbase) {
1691
      case t_base_type::TYPE_VOID:
1692
        break;
1693
      case t_base_type::TYPE_STRING:
1694
        result += " = ''";
1695
        break;
1696
      case t_base_type::TYPE_BOOL:
1697
        result += " = 0";
1698
        break;
1699
      case t_base_type::TYPE_BYTE:
1700
      case t_base_type::TYPE_I16:
1701
      case t_base_type::TYPE_I32:
1702
      case t_base_type::TYPE_I64:
1703
        result += " = 0";
1704
        break;
1705
      case t_base_type::TYPE_DOUBLE:
1706
        result += " = 0.0";
1707
        break;
1708
      default:
1709
        throw "compiler error: no PERL initializer for base type " + t_base_type::t_base_name(tbase);
1710
      }
1711
    } else if (type->is_enum()) {
1712
      result += " = 0";
1713
    } else if (type->is_container()) {
1714
      result += " = []";
1715
    } else if (type->is_struct() || type->is_xception()) {
1716
      if (obj) {
1717
        result += " = new " + perl_namespace(type->get_program()) + type->get_name() + "()";
1718
      } else {
1719
        result += " = undef";
1720
      }
1721
    }
1722
  }
1723
  return result + ";";
1724
}
1725
 
1726
/**
1727
 * Renders a function signature of the form 'type name(args)'
1728
 *
1729
 * @param tfunction Function definition
1730
 * @return String of rendered function definition
1731
 */
1732
string t_perl_generator::function_signature(t_function* tfunction,
1733
                                            string prefix) {
1734
 
1735
  string str;
1736
 
1737
  str  = prefix + tfunction->get_name() + "{\n";
1738
  str += "  my $self = shift;\n";
1739
 
1740
  //Need to create perl function arg inputs
1741
  const vector<t_field*> &fields = tfunction->get_arglist()->get_members();
1742
  vector<t_field*>::const_iterator f_iter;
1743
 
1744
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1745
    str += "  my $" + (*f_iter)->get_name() + " = shift;\n";
1746
  }
1747
 
1748
  return str;
1749
}
1750
 
1751
/**
1752
 * Renders a field list
1753
 */
1754
string t_perl_generator::argument_list(t_struct* tstruct) {
1755
  string result = "";
1756
 
1757
  const vector<t_field*>& fields = tstruct->get_members();
1758
  vector<t_field*>::const_iterator f_iter;
1759
  bool first = true;
1760
  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1761
    if (first) {
1762
      first = false;
1763
    } else {
1764
      result += ", ";
1765
    }
1766
    result += "$" + (*f_iter)->get_name();
1767
  }
1768
  return result;
1769
}
1770
 
1771
/**
1772
 * Converts the parse type to a C++ enum string for the given type.
1773
 */
1774
string t_perl_generator ::type_to_enum(t_type* type) {
1775
  type = get_true_type(type);
1776
 
1777
  if (type->is_base_type()) {
1778
    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1779
    switch (tbase) {
1780
    case t_base_type::TYPE_VOID:
1781
      throw "NO T_VOID CONSTRUCT";
1782
    case t_base_type::TYPE_STRING:
1783
      return "TType::STRING";
1784
    case t_base_type::TYPE_BOOL:
1785
      return "TType::BOOL";
1786
    case t_base_type::TYPE_BYTE:
1787
      return "TType::BYTE";
1788
    case t_base_type::TYPE_I16:
1789
      return "TType::I16";
1790
    case t_base_type::TYPE_I32:
1791
      return "TType::I32";
1792
    case t_base_type::TYPE_I64:
1793
      return "TType::I64";
1794
    case t_base_type::TYPE_DOUBLE:
1795
      return "TType::DOUBLE";
1796
    }
1797
  } else if (type->is_enum()) {
1798
    return "TType::I32";
1799
  } else if (type->is_struct() || type->is_xception()) {
1800
    return "TType::STRUCT";
1801
  } else if (type->is_map()) {
1802
    return "TType::MAP";
1803
  } else if (type->is_set()) {
1804
    return "TType::SET";
1805
  } else if (type->is_list()) {
1806
    return "TType::LIST";
1807
  }
1808
 
1809
  throw "INVALID TYPE IN type_to_enum: " + type->get_name();
1810
}
1811
 
1812
THRIFT_REGISTER_GENERATOR(perl, "Perl", "");