blob: e3909bdebdd39a78467f4ca70170b3d2ddd1690c [file] [log] [blame]
Christopher Piro2f5afce2007-06-29 07:17:33 +00001// Copyright (c) 2006- Facebook
2// Distributed under the Thrift Software License
3//
4// See accompanying file LICENSE or visit the Thrift site at:
5// http://developers.facebook.com/thrift/
6
Christopher Piroae1f10f2007-07-24 04:30:15 +00007// still missing: inheritance, containers
8
Christopher Piro2f5afce2007-06-29 07:17:33 +00009#include <stdlib.h>
10#include <sys/stat.h>
11#include <sys/types.h>
12#include <sstream>
13#include "t_erl_generator.h"
Christopher Piro2f5afce2007-06-29 07:17:33 +000014
Christopher Piro094823a2007-07-18 00:26:12 +000015using namespace std;
Christopher Piro2f5afce2007-06-29 07:17:33 +000016
Christopher Piro2f5afce2007-06-29 07:17:33 +000017/**
18 * UI for file generation by opening up the necessary file output
19 * streams.
20 *
21 * @param tprogram The program to generate
22 */
23void t_erl_generator::init_generator() {
24 // Make output directory
25 mkdir(T_ERL_DIR, S_IREAD | S_IWRITE | S_IEXEC);
26
Christopher Piroae1f10f2007-07-24 04:30:15 +000027 // setup export lines
28 export_lines_first_ = true;
29 export_types_lines_first_ = true;
Christopher Piro2f5afce2007-06-29 07:17:33 +000030
Christopher Piroae1f10f2007-07-24 04:30:15 +000031 // types files
Christopher Piro2f5afce2007-06-29 07:17:33 +000032 string f_types_name = string(T_ERL_DIR)+"/"+program_name_+"_types.erl";
33 string f_types_hrl_name = string(T_ERL_DIR)+"/"+program_name_+"_types.hrl";
Christopher Piroae1f10f2007-07-24 04:30:15 +000034
Christopher Piro2f5afce2007-06-29 07:17:33 +000035 f_types_file_.open(f_types_name.c_str());
36 f_types_hrl_file_.open(f_types_hrl_name.c_str());
37
38 hrl_header(f_types_hrl_file_, program_name_ + "_types");
39
Christopher Piro2f5afce2007-06-29 07:17:33 +000040 f_types_file_ <<
41 erl_autogen_comment() << endl <<
Christopher Piroae1f10f2007-07-24 04:30:15 +000042 "-module(" << program_name_ << "_types)." << endl <<
Christopher Piro2f5afce2007-06-29 07:17:33 +000043 erl_imports() << endl;
44
45 f_types_file_ <<
Christopher Piroae1f10f2007-07-24 04:30:15 +000046 "-include(\"" << program_name_ << "_types.hrl\")." << endl <<
Christopher Piro2f5afce2007-06-29 07:17:33 +000047 endl;
48
49 f_types_hrl_file_ << render_includes() << endl;
Christopher Piroae1f10f2007-07-24 04:30:15 +000050
51 // consts file
52 string f_consts_name = string(T_ERL_DIR)+"/"+program_name_+"_constants.hrl";
53 f_consts_.open(f_consts_name.c_str());
54
Christopher Piro2f5afce2007-06-29 07:17:33 +000055 f_consts_ <<
56 erl_autogen_comment() << endl <<
57 erl_imports() << endl <<
Christopher Piroae1f10f2007-07-24 04:30:15 +000058 "-include(\"" << program_name_ << "_types.hrl\")." << endl <<
Christopher Piro2f5afce2007-06-29 07:17:33 +000059 endl;
60}
61
Christopher Piroae1f10f2007-07-24 04:30:15 +000062/**
63 * Boilerplate at beginning and end of header files
64 */
65void t_erl_generator::hrl_header(ostream& out, string name) {
Christopher Piro2f5afce2007-06-29 07:17:33 +000066 out << "-ifndef(_" << name << "_included)." << endl <<
67 "-define(_" << name << "_included, yeah)." << endl;
68}
69
Christopher Piroae1f10f2007-07-24 04:30:15 +000070void t_erl_generator::hrl_footer(ostream& out, string name) {
Christopher Piro2f5afce2007-06-29 07:17:33 +000071 out << "-endif." << endl;
72}
73
74/**
75 * Renders all the imports necessary for including another Thrift program
76 */
77string t_erl_generator::render_includes() {
78 const vector<t_program*>& includes = program_->get_includes();
79 string result = "";
80 for (size_t i = 0; i < includes.size(); ++i) {
Christopher Piroae1f10f2007-07-24 04:30:15 +000081 result += "-include(\"" + includes[i]->get_name() + "_types.hrl\").\n";
Christopher Piro2f5afce2007-06-29 07:17:33 +000082 }
83 if (includes.size() > 0) {
84 result += "\n";
85 }
86 return result;
87}
88
89/**
90 * Autogen'd comment
91 */
92string t_erl_generator::erl_autogen_comment() {
93 return
Christopher Piroae1f10f2007-07-24 04:30:15 +000094 std::string("%%\n") +
95 "%% Autogenerated by Thrift\n" +
96 "%%\n" +
97 "%% DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
98 "%%\n";
Christopher Piro2f5afce2007-06-29 07:17:33 +000099}
100
101/**
102 * Prints standard thrift imports
103 */
104string t_erl_generator::erl_imports() {
105 return
Christopher Piro094823a2007-07-18 00:26:12 +0000106 string("-include(\"thrift.hrl\").\n") +
107 "-include(\"tApplicationException.hrl\").\n" +
108 "-include(\"protocol/tProtocol.hrl\").\n";
Christopher Piro2f5afce2007-06-29 07:17:33 +0000109}
110
111/**
112 * Closes the type files
113 */
114void t_erl_generator::close_generator() {
115 // Close types file
116 f_types_file_ << "-export([" << export_types_lines_.str() << "])." << endl;
117 f_types_file_ << f_types_.str();
118
119 hrl_footer(f_types_hrl_file_, string("BOGUS"));
120
121 f_types_file_.close();
122 f_types_hrl_file_.close();
123 f_consts_.close();
124}
125
126/**
Christopher Piroae1f10f2007-07-24 04:30:15 +0000127 * Generates a typedef. no op
Christopher Piro2f5afce2007-06-29 07:17:33 +0000128 *
129 * @param ttypedef The type definition
130 */
Christopher Piroae1f10f2007-07-24 04:30:15 +0000131void t_erl_generator::generate_typedef(t_typedef* ttypedef) {
132}
Christopher Piro2f5afce2007-06-29 07:17:33 +0000133
134/**
135 * Generates code for an enumerated type. Done using a class to scope
136 * the values.
137 *
138 * @param tenum The enumeration
139 */
140void t_erl_generator::generate_enum(t_enum* tenum) {
Christopher Piro2f5afce2007-06-29 07:17:33 +0000141 vector<t_enum_value*> constants = tenum->get_constants();
142 vector<t_enum_value*>::iterator c_iter;
Christopher Piroae1f10f2007-07-24 04:30:15 +0000143
Christopher Piro2f5afce2007-06-29 07:17:33 +0000144 int value = -1;
Christopher Piroae1f10f2007-07-24 04:30:15 +0000145
Christopher Piro2f5afce2007-06-29 07:17:33 +0000146 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
147 if ((*c_iter)->has_value()) {
148 value = (*c_iter)->get_value();
149 } else {
150 ++value;
151 }
152
Christopher Piro2f5afce2007-06-29 07:17:33 +0000153 string name = capitalize((*c_iter)->get_name());
154
155 f_types_hrl_file_ <<
Christopher Piroae1f10f2007-07-24 04:30:15 +0000156 indent() << "-define(" << program_name_ << "_" << name << ", " << value << ")."<< endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000157 }
158
Christopher Piro2f5afce2007-06-29 07:17:33 +0000159 f_types_hrl_file_ << endl;
160}
161
162/**
163 * Generate a constant value
164 */
165void t_erl_generator::generate_const(t_const* tconst) {
166 t_type* type = tconst->get_type();
Christopher Piroae1f10f2007-07-24 04:30:15 +0000167 string name = capitalize(tconst->get_name());
Christopher Piro2f5afce2007-06-29 07:17:33 +0000168 t_const_value* value = tconst->get_value();
169
Christopher Piroae1f10f2007-07-24 04:30:15 +0000170 f_consts_ << "-define(" << program_name_ << "_" << name << ", " << render_const_value(type, value) << ")." << endl << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000171}
172
173/**
174 * Prints the value of a constant with the given type. Note that type checking
175 * is NOT performed in this function as it is always run beforehand using the
176 * validate_types method in main.cc
177 */
178string t_erl_generator::render_const_value(t_type* type, t_const_value* value) {
179 std::ostringstream out;
Christopher Piroae1f10f2007-07-24 04:30:15 +0000180
Christopher Piro2f5afce2007-06-29 07:17:33 +0000181 if (type->is_base_type()) {
182 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
183 switch (tbase) {
184 case t_base_type::TYPE_STRING:
185 out << "\"" << value->get_string() << "\"";
186 break;
187 case t_base_type::TYPE_BOOL:
188 out << (value->get_integer() > 0 ? "true" : "false");
189 break;
190 case t_base_type::TYPE_BYTE:
191 case t_base_type::TYPE_I16:
192 case t_base_type::TYPE_I32:
193 case t_base_type::TYPE_I64:
194 out << value->get_integer();
195 break;
196 case t_base_type::TYPE_DOUBLE:
197 if (value->get_type() == t_const_value::CV_INTEGER) {
198 out << value->get_integer();
199 } else {
200 out << value->get_double();
201 }
202 break;
203 default:
David Reissdd7796f2007-08-28 21:09:06 +0000204 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
Christopher Piro2f5afce2007-06-29 07:17:33 +0000205 }
206 } else if (type->is_enum()) {
207 indent(out) << value->get_integer();
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000208
209 } else if (type->is_struct() || type->is_xception()) {
210 out << "#" << type->get_name() << "{";
Christopher Piro2f5afce2007-06-29 07:17:33 +0000211 const vector<t_field*>& fields = ((t_struct*)type)->get_members();
212 vector<t_field*>::const_iterator f_iter;
213 const map<t_const_value*, t_const_value*>& val = value->get_map();
214 map<t_const_value*, t_const_value*>::const_iterator v_iter;
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000215
216 bool first = true;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000217 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
218 t_type* field_type = NULL;
219 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
220 if ((*f_iter)->get_name() == v_iter->first->get_string()) {
221 field_type = (*f_iter)->get_type();
222 }
223 }
224 if (field_type == NULL) {
225 throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
226 }
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000227
228 if (first) {
229 first = false;
230 } else {
231 out << ",";
232 }
233 out << v_iter->first->get_string();
234 out << " = ";
Christopher Piro2f5afce2007-06-29 07:17:33 +0000235 out << render_const_value(field_type, v_iter->second);
Christopher Piro2f5afce2007-06-29 07:17:33 +0000236 }
237 indent_down();
238 indent(out) << "}";
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000239
240 } else if (type->is_map()) {
241 t_type* ktype = ((t_map*)type)->get_key_type();
242 t_type* vtype = ((t_map*)type)->get_val_type();
243 const map<t_const_value*, t_const_value*>& val = value->get_map();
244 map<t_const_value*, t_const_value*>::const_iterator v_iter;
245
246 bool first = true;
247 out << "dict:from_list([";
248 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
249 if (first) {
250 first=false;
251 } else {
252 out << ",";
253 }
254 out << "("
255 << render_const_value(ktype, v_iter->first) << ","
256 << render_const_value(vtype, v_iter->second) << ")";
257 }
258 out << "])";
259
260 } else if (type->is_set()) {
Christopher Piro2f5afce2007-06-29 07:17:33 +0000261 t_type* etype;
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000262 etype = ((t_set*)type)->get_elem_type();
263
264 bool first = true;
265 const vector<t_const_value*>& val = value->get_list();
266 vector<t_const_value*>::const_iterator v_iter;
267 out << "sets:from_list([";
268 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
269 if (first) {
270 first=false;
271 } else {
272 out << ",";
273 }
274 out << "(" << render_const_value(etype, *v_iter) << ",true)";
Christopher Piro2f5afce2007-06-29 07:17:33 +0000275 }
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000276 out << "])";
277
278 } else if (type->is_list()) {
279 t_type* etype;
280 etype = ((t_list*)type)->get_elem_type();
281 out << "[";
282
283 bool first = true;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000284 const vector<t_const_value*>& val = value->get_list();
285 vector<t_const_value*>::const_iterator v_iter;
286 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000287 if (first) {
288 first=false;
289 } else {
290 out << ",";
Christopher Piro2f5afce2007-06-29 07:17:33 +0000291 }
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000292 out << render_const_value(etype, *v_iter);
Christopher Piro2f5afce2007-06-29 07:17:33 +0000293 }
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000294 out << "]";
Christopher Piro2f5afce2007-06-29 07:17:33 +0000295 }
296 return out.str();
297}
298
299/**
Christopher Piroae1f10f2007-07-24 04:30:15 +0000300 * Generates a struct
Christopher Piro2f5afce2007-06-29 07:17:33 +0000301 */
302void t_erl_generator::generate_struct(t_struct* tstruct) {
303 generate_erl_struct(tstruct, false);
304}
305
306/**
307 * Generates a struct definition for a thrift exception. Basically the same
308 * as a struct but extends the Exception class.
309 *
310 * @param txception The struct definition
311 */
312void t_erl_generator::generate_xception(t_struct* txception) {
313 generate_erl_struct(txception, true);
314}
315
316/**
Christopher Piroae1f10f2007-07-24 04:30:15 +0000317 * Generates a struct
Christopher Piro2f5afce2007-06-29 07:17:33 +0000318 */
319void t_erl_generator::generate_erl_struct(t_struct* tstruct,
320 bool is_exception) {
321 generate_erl_struct_definition(f_types_, f_types_hrl_file_, tstruct, is_exception);
322}
323
324/**
Christopher Piroae1f10f2007-07-24 04:30:15 +0000325 * Generates a struct definition for a thrift data type.
Christopher Piro2f5afce2007-06-29 07:17:33 +0000326 *
327 * @param tstruct The struct definition
328 */
329void t_erl_generator::generate_erl_struct_definition(ostream& out,
330 ostream& hrl_out,
331 t_struct* tstruct,
332 bool is_exception,
Christopher Piroae1f10f2007-07-24 04:30:15 +0000333 bool is_result)
334{
Christopher Piro2f5afce2007-06-29 07:17:33 +0000335 const vector<t_field*>& members = tstruct->get_members();
336 vector<t_field*>::const_iterator m_iter;
337
Christopher Piro2f5afce2007-06-29 07:17:33 +0000338 indent(out) << "%% struct " << type_name(tstruct) << endl;
339
Christopher Piroae1f10f2007-07-24 04:30:15 +0000340 if (is_exception) {
Christopher Piro2f5afce2007-06-29 07:17:33 +0000341 }
Christopher Piro2f5afce2007-06-29 07:17:33 +0000342
Christopher Piroae1f10f2007-07-24 04:30:15 +0000343 out << endl;
344
Christopher Piro2f5afce2007-06-29 07:17:33 +0000345 if (members.size() > 0) {
Christopher Piroae1f10f2007-07-24 04:30:15 +0000346 indent(out) << "% -record(" << type_name(tstruct) << ", {";
347 indent(hrl_out) << "-record(" << type_name(tstruct) << ", {";
Christopher Piro2f5afce2007-06-29 07:17:33 +0000348
349 bool first = true;
350 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
351 if (first) {
352 first = false;
353 } else {
354 out << ", ";
355 hrl_out << ", ";
356 }
357 out << (*m_iter)->get_name();
358 hrl_out << (*m_iter)->get_name();
359 }
360 out << "})." << endl;
361 hrl_out << "})." << endl;
362 } else { // no members; explicit comment
Christopher Piroae1f10f2007-07-24 04:30:15 +0000363 indent(out) << "% -record(" << type_name(tstruct) << ", {})." << endl;
364 indent(hrl_out) << "-record(" << type_name(tstruct) << ", {})." << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000365 }
366
Christopher Piro2f5afce2007-06-29 07:17:33 +0000367 out << endl;
368 hrl_out << endl;
369
Christopher Piro2f5afce2007-06-29 07:17:33 +0000370 generate_erl_struct_reader(out, tstruct);
371 generate_erl_struct_writer(out, tstruct);
Christopher Piro2f5afce2007-06-29 07:17:33 +0000372}
373
374/**
375 * Generates the read method for a struct
376 */
377void t_erl_generator::generate_erl_struct_reader(ostream& out,
378 t_struct* tstruct) {
379 const vector<t_field*>& fields = tstruct->get_members();
380 vector<t_field*>::const_iterator f_iter;
381
Christopher Piroae1f10f2007-07-24 04:30:15 +0000382 string name = type_name(tstruct) + "_read";
Christopher Piro2f5afce2007-06-29 07:17:33 +0000383
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000384 if (out == f_types_) { // OH HAI MR. HORRIBLE
Christopher Piro2f5afce2007-06-29 07:17:33 +0000385 export_types_string(name, 1);
386 } else {
387 export_string(name, 1);
388 }
389
390 indent(out) << name << "(Iprot) ->" << endl;
391 indent_up();
392
393 out <<
Christopher Piro094823a2007-07-18 00:26:12 +0000394 indent() << "?R0(Iprot, readStructBegin)," << endl <<
Christopher Piroae1f10f2007-07-24 04:30:15 +0000395 indent() << "Str = " << type_name(tstruct) << "_read_loop(Iprot, ";
Christopher Piro2f5afce2007-06-29 07:17:33 +0000396
Christopher Piroae1f10f2007-07-24 04:30:15 +0000397 // empty struct
398 out << "#" << type_name(tstruct) << "{}";
Christopher Piro2f5afce2007-06-29 07:17:33 +0000399 out << ")," << endl <<
Christopher Piro094823a2007-07-18 00:26:12 +0000400 indent() << "?R0(Iprot, readStructEnd)," << endl <<
Christopher Piro2f5afce2007-06-29 07:17:33 +0000401 indent() << "Str." << endl;
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000402
Christopher Piro2f5afce2007-06-29 07:17:33 +0000403 indent_down();
404
405 indent(out) <<
Christopher Piroae1f10f2007-07-24 04:30:15 +0000406 "" << type_name(tstruct) << "_read_loop(Iprot, Str) ->" << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000407 indent_up();
408
Christopher Piroae1f10f2007-07-24 04:30:15 +0000409 // Read beginning field marker
Christopher Piro094823a2007-07-18 00:26:12 +0000410 out <<
411 indent() << "{ _Fname, Ftype, Fid } = ?R0(Iprot, readFieldBegin)," << endl <<
412 indent() << "Fid, % suppress unused warnings" << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000413
Christopher Piroae1f10f2007-07-24 04:30:15 +0000414 // Check for field STOP marker and break
415 indent(out) << "if" << endl;
416 indent_up();
417 indent(out) << "Ftype == ?tType_STOP ->" << endl <<
418 indent() << " Str;" << endl;
419
420 // Generate deserialization code for known cases
421 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
422 out << indent() << "(Fid == " << (*f_iter)->get_key() << ") and (Ftype == "
423 << type_to_enum((*f_iter)->get_type()) << ") ->" << endl;
424
Christopher Piro2f5afce2007-06-29 07:17:33 +0000425 indent_up();
Christopher Piroae1f10f2007-07-24 04:30:15 +0000426 generate_deserialize_field(out, *f_iter, "Val");
427
428 out << indent() << "?R0(Iprot, readFieldEnd)," << endl
429 << indent() << type_name(tstruct) << "_read_loop(Iprot, "
430 << "Str#" << type_name(tstruct)
431 << "{" << (*f_iter)->get_name()
432 << "=Val});" << endl;
433 indent_down();
434 }
Christopher Piro2f5afce2007-06-29 07:17:33 +0000435
Christopher Piroae1f10f2007-07-24 04:30:15 +0000436 // In the default case we skip the field
437 out <<
438 indent() << "true -> " << endl <<
439 indent() << " ?R1(Iprot, skip, Ftype)," << endl <<
440 indent() << " ?R0(Iprot, readFieldEnd)," << endl <<
441 indent() << " " << type_name(tstruct) << "_read_loop(Iprot, Str)" << endl;
442 indent_down();
443
444 indent(out) << "end." << endl;
445
446 indent_down();
Christopher Piro2f5afce2007-06-29 07:17:33 +0000447 out << endl;
448}
449
Christopher Piroae1f10f2007-07-24 04:30:15 +0000450void t_erl_generator::generate_erl_struct_writer(ostream& out,
Christopher Piro2f5afce2007-06-29 07:17:33 +0000451 t_struct* tstruct) {
452 string name = tstruct->get_name();
453 const vector<t_field*>& fields = tstruct->get_members();
454 vector<t_field*>::const_iterator f_iter;
455
Christopher Piroae1f10f2007-07-24 04:30:15 +0000456 string fname = type_name(tstruct) + "_write";
Christopher Piro2f5afce2007-06-29 07:17:33 +0000457
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000458 if (out == f_types_) { // OH HAI MR. HORRIBLE
Christopher Piro2f5afce2007-06-29 07:17:33 +0000459 export_types_string(fname, 2);
460 } else {
461 export_string(fname, 2);
462 }
463
Christopher Piroae1f10f2007-07-24 04:30:15 +0000464 indent(out) << fname << "(Str, Oprot) ->" << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000465 indent_up();
466
Christopher Piro094823a2007-07-18 00:26:12 +0000467 out <<
468 indent() << "Str, % suppress unused warnings" << endl <<
469 indent() << "?R1(Oprot, writeStructBegin, \"" << name << "\")," << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000470
Christopher Piroae1f10f2007-07-24 04:30:15 +0000471 string prefix = string("Str#") + type_name(tstruct) + ".";
Christopher Piro2f5afce2007-06-29 07:17:33 +0000472 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
473 // Write field header
474 indent(out) <<
475 "if " << prefix << (*f_iter)->get_name() << " /= undefined ->" << endl;
476 indent_up();
477 indent(out) <<
Christopher Piro094823a2007-07-18 00:26:12 +0000478 "?R3(Oprot, writeFieldBegin, " <<
Christopher Piro2f5afce2007-06-29 07:17:33 +0000479 "\"" << (*f_iter)->get_name() << "\", " <<
480 type_to_enum((*f_iter)->get_type()) << ", " <<
481 (*f_iter)->get_key() << ")," << endl;
482
483 // Write field contents
484 generate_serialize_field(out, *f_iter, prefix);
485
486 // Write field closer
487 indent(out) <<
Christopher Piro094823a2007-07-18 00:26:12 +0000488 "?R0(Oprot, writeFieldEnd);" << endl <<
Christopher Piro2f5afce2007-06-29 07:17:33 +0000489 indent() << "true -> ok" << endl;
490
491 indent_down();
492 out << " end," << endl;
493 }
494
495 // Write the struct map
496 out <<
Christopher Piro094823a2007-07-18 00:26:12 +0000497 indent() << "?R0(Oprot, writeFieldStop)," << endl <<
498 indent() << "?R0(Oprot, writeStructEnd)," << endl <<
Christopher Piro2f5afce2007-06-29 07:17:33 +0000499 indent() << "ok." << endl;
500
501 indent_down();
502
503 out << endl;
504}
505
506/**
507 * Generates a thrift service.
508 *
509 * @param tservice The service definition
510 */
511void t_erl_generator::generate_service(t_service* tservice) {
Christopher Piro87372602007-07-24 06:20:47 +0000512 // somehow this point is reached before the constructor and it's not downcased yet
513 // ...awesome
514 service_name_[0] = tolower(service_name_[0]);
515
Christopher Piroae1f10f2007-07-24 04:30:15 +0000516 string f_service_hrl_name = string(T_ERL_DIR)+"/"+service_name_+".hrl";
517 string f_service_name = string(T_ERL_DIR)+"/"+service_name_+".erl";
Christopher Piro2f5afce2007-06-29 07:17:33 +0000518 f_service_file_.open(f_service_name.c_str());
519 f_service_hrl_.open(f_service_hrl_name.c_str());
520
Christopher Piroae1f10f2007-07-24 04:30:15 +0000521 hrl_header(f_service_hrl_, service_name_);
Christopher Piro2f5afce2007-06-29 07:17:33 +0000522
523 if (tservice->get_extends() != NULL) {
524 f_service_hrl_ << "-include(\"" <<
525 uncapitalize(tservice->get_extends()->get_name()) << ".hrl\"). % inherit " << endl;
526 }
527
528 f_service_hrl_ <<
Christopher Piroae1f10f2007-07-24 04:30:15 +0000529 "-include(\"" << program_name_ << "_types.hrl\")." << endl <<
Christopher Piro2f5afce2007-06-29 07:17:33 +0000530 endl;
531
532 // Generate the three main parts of the service (well, two for now in PHP)
533 generate_service_helpers(tservice); // cpiro: New Erlang Order
534
535 generate_service_interface(tservice);
536 generate_service_client(tservice);
537 generate_service_server(tservice);
538
539 // indent_down();
540
541 f_service_file_ <<
542 erl_autogen_comment() << endl <<
Christopher Piroae1f10f2007-07-24 04:30:15 +0000543 "-module(" << service_name_ << ")." << endl << endl <<
Christopher Piro2f5afce2007-06-29 07:17:33 +0000544 erl_imports() << endl;
545
546 f_service_file_ << "-include(\"" << uncapitalize(tservice->get_name()) << ".hrl\")." << endl << endl;
547
Christopher Piro094823a2007-07-18 00:26:12 +0000548 f_service_file_ << "-export([" << export_lines_.str() << "])." << endl << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000549
550 f_service_file_ << f_service_.str();
551
552 hrl_footer(f_service_hrl_, f_service_name);
553
554 // Close service file
555 f_service_file_.close();
556 f_service_hrl_.close();
557}
558
559/**
560 * Generates helper functions for a service.
561 *
562 * @param tservice The service to generate a header definition for
563 */
564void t_erl_generator::generate_service_helpers(t_service* tservice) {
565 vector<t_function*> functions = tservice->get_functions();
566 vector<t_function*>::iterator f_iter;
567
Christopher Piroae1f10f2007-07-24 04:30:15 +0000568 // indent(f_service_) <<
569 // "% HELPER FUNCTIONS AND STRUCTURES" << endl << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000570
571 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
572 t_struct* ts = (*f_iter)->get_arglist();
Christopher Piroae1f10f2007-07-24 04:30:15 +0000573
Christopher Piro2f5afce2007-06-29 07:17:33 +0000574 generate_erl_struct_definition(f_service_, f_service_hrl_, ts, false);
575 generate_erl_function_helpers(*f_iter);
576 }
577}
578
579/**
580 * Generates a struct and helpers for a function.
581 *
582 * @param tfunction The function
583 */
584void t_erl_generator::generate_erl_function_helpers(t_function* tfunction) {
585 t_struct result(program_, tfunction->get_name() + "_result");
586 t_field success(tfunction->get_returntype(), "success", 0);
587 if (!tfunction->get_returntype()->is_void()) {
588 result.append(&success);
589 }
590 t_struct* xs = tfunction->get_xceptions();
591 const vector<t_field*>& fields = xs->get_members();
592 vector<t_field*>::const_iterator f_iter;
593 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
594 result.append(*f_iter);
595 }
596 generate_erl_struct_definition(f_service_, f_service_hrl_, &result, false, true);
597}
598
599/**
600 * Generates a service interface definition.
601 *
602 * @param tservice The service to generate a header definition for
603 */
604void t_erl_generator::generate_service_interface(t_service* tservice) {
605 // f_service_ <<
606 // indent() << "module Iface" << endl;
607 // indent_up();
608
609 // if (tservice->get_extends() != NULL) {
610 // string extends = type_name(tservice->get_extends());
611 // indent(f_service_) << "include " << extends << "::Iface" << endl;
612 // }
613
614 vector<t_function*> functions = tservice->get_functions();
615 vector<t_function*>::iterator f_iter;
616 f_service_ << "%%% interface" << endl;
617 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
618 f_service_ <<
619 indent() << "% " << function_signature(*f_iter) << endl;
620 }
621 // indent_down();
Christopher Piroae1f10f2007-07-24 04:30:15 +0000622 indent(f_service_) << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000623}
624
625/**
626 * Generates a service client definition.
627 *
628 * @param tservice The service to generate a server for.
629 */
630void t_erl_generator::generate_service_client(t_service* tservice) {
631 string extends = "";
632 string extends_client = "";
633 // if (tservice->get_extends() != NULL) {
634 // extends = type_name(tservice->get_extends());
635 // extends_client = " < " + extends + "::Client ";
636 // }
637
638 // indent(f_service_) <<
639 // "class Client" << extends_client << endl;
640 // indent_up();
641
642 // indent(f_service_) <<
643 // "include Iface" << endl << endl;
644
645 // Constructor function
646 export_string("new", 2);
647 export_string("new", 1);
648
649 f_service_ <<
Christopher Piroae1f10f2007-07-24 04:30:15 +0000650 indent() << "new(Iprot, Oprot) ->" << endl <<
651 indent() << " #"<<service_name_<<"{iprot=Iprot, oprot=Oprot, seqid=0}." << endl <<
Christopher Piro2f5afce2007-06-29 07:17:33 +0000652 indent() << "new(Iprot) ->" << endl <<
Christopher Piroae1f10f2007-07-24 04:30:15 +0000653 indent() << " #"<<service_name_<<"{iprot=Iprot, oprot=Iprot, seqid=0}." << endl << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000654
655 // indent(f_service_) << "end" << endl << endl;
656
657 f_service_hrl_ <<
Christopher Piroae1f10f2007-07-24 04:30:15 +0000658 indent() << "-record("<< service_name_ <<", {iprot, oprot, seqid})." << endl << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000659
660 // Generate client method implementations
661 vector<t_function*> functions = tservice->get_functions();
662 vector<t_function*>::const_iterator f_iter;
663 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
664 t_struct* arg_struct = (*f_iter)->get_arglist();
665 const vector<t_field*>& fields = arg_struct->get_members();
666 vector<t_field*>::const_iterator fld_iter;
667 string funname = (*f_iter)->get_name();
668
669 export_function(*f_iter);
670
671 // Open function
672 indent(f_service_) <<
Christopher Piroae1f10f2007-07-24 04:30:15 +0000673 function_signature(*f_iter) << " ->" << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000674
675 indent_up();
676
677 indent(f_service_) <<
678 "send_" << funname << "(This";
679
680 //bool first = true;
681 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
682 // if (first) {
683 // first = false;
684 // } else {
685 f_service_ << ", ";
686 // }
687 f_service_ << capitalize((*fld_iter)->get_name());
688 }
689 f_service_ << ")," << endl;
690
691 if (!(*f_iter)->is_async()) {
692 f_service_ << indent();
693 if (!(*f_iter)->get_returntype()->is_void()) {
694 f_service_ << "";
695 }
696 f_service_ <<
697 "recv_" << funname << "(This), " << endl;
698 }
699
700 indent(f_service_) << "ok." << endl;
701 indent_down();
702 f_service_ << endl;
703
704 export_function(*f_iter, "send_");
705
706 indent(f_service_) <<
Christopher Piroae1f10f2007-07-24 04:30:15 +0000707 "send_" << function_signature(*f_iter) << " ->" << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000708 indent_up();
709
710 std::string argsname = capitalize((*f_iter)->get_name() + "_args");
711
712 // Serialize the request header
713 f_service_ <<
Christopher Piro094823a2007-07-18 00:26:12 +0000714 indent() << "Oprot = oop:get(This, oprot)," << endl <<
715 indent() << "Seqid = oop:get(This, seqid)," << endl <<
716 indent() << "?R3(Oprot, writeMessageBegin, \"" << (*f_iter)->get_name() << "\", ?tMessageType_CALL, Seqid)," << endl <<
Christopher Piro2f5afce2007-06-29 07:17:33 +0000717 indent() << "Args = #" << (*f_iter)->get_name() << "_args{";
718
719 bool first = true;
720 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
721 f_service_ << (first ? first = false, "" : ", ")
722 << (*fld_iter)->get_name()
723 << "=" << capitalize((*fld_iter)->get_name());
724 }
725 f_service_ << "}," << endl;
726
727 indent(f_service_) << (*f_iter)->get_name() << "_args_write(Args, Oprot)," << endl;
728
729 // Write to the stream
730 f_service_ <<
Christopher Piro094823a2007-07-18 00:26:12 +0000731 indent() << "?R0(Oprot, writeMessageEnd)," << endl <<
732 indent() << "Trans = ?R1(Oprot, get, trans)," << endl <<
733 indent() << "?R0(Trans, effectful_flush)," << endl <<
Christopher Piro2f5afce2007-06-29 07:17:33 +0000734 indent() << "ok." << endl;
735
736 indent_down();
737
738 if (!(*f_iter)->is_async()) {
739 std::string resultname = uncapitalize((*f_iter)->get_name() + "_result");
740 t_struct noargs(program_);
741
742 t_function recv_function((*f_iter)->get_returntype(),
743 string("recv_") + (*f_iter)->get_name(),
744 &noargs);
745
746 export_function(&recv_function, "");
747
748 // Open function
749 f_service_ <<
750 endl <<
Christopher Piroae1f10f2007-07-24 04:30:15 +0000751 indent() << function_signature(&recv_function) << " ->" << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000752 indent_up();
753
754 // TODO(mcslee): Validate message reply here, seq ids etc.
Christopher Piro2f5afce2007-06-29 07:17:33 +0000755
756 f_service_ <<
Christopher Piro094823a2007-07-18 00:26:12 +0000757 indent() << "Iprot = oop:get(This, iprot)," << endl <<
758 indent() << "{ _Fname, Mtype, _Rseqid } = ?R0(Iprot, readMessageBegin)," << endl <<
Christopher Piro2f5afce2007-06-29 07:17:33 +0000759 indent() << "if" << endl <<
760 indent() << " Mtype == ?tMessageType_EXCEPTION ->" << endl <<
761 indent() << " X = tApplicationException:new()," << endl <<
Christopher Piroae1f10f2007-07-24 04:30:15 +0000762 indent() << " tApplicationException:read(X, Iprot)," << endl <<
Christopher Piro094823a2007-07-18 00:26:12 +0000763 indent() << " ?R0(Iprot, readMessageEnd), " << endl <<
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000764 indent() << " throw(X);" << endl <<
Christopher Piro2f5afce2007-06-29 07:17:33 +0000765 indent() << " true ->" << endl <<
766 indent() << " Result = " << resultname << "_read(Iprot)," << endl <<
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000767 indent() << " Result, % suppress unused warnings" << endl <<
Christopher Piro094823a2007-07-18 00:26:12 +0000768 indent() << " ?R0(Iprot, readMessageEnd)," << endl <<
Christopher Piro2f5afce2007-06-29 07:17:33 +0000769 indent() << " if % time to figure out retval" << endl;
770
Christopher Piro2f5afce2007-06-29 07:17:33 +0000771 // WATCH cpiro
772 // Careful, only return _result if not a void function
773
Christopher Piroae1f10f2007-07-24 04:30:15 +0000774 // TODO(cpiro): exit or {ok, _} and {error, _} ??
775
Christopher Piro2f5afce2007-06-29 07:17:33 +0000776 std::string result = "Result#"+resultname+".";
777 if (!(*f_iter)->get_returntype()->is_void()) {
778 f_service_ <<
779 indent() << " " << result << "success /= nil ->" << endl <<
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000780 indent() << " " << result << "success;" << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000781 }
782
783 t_struct* xs = (*f_iter)->get_xceptions(); // TODO(cpiro)
784 const std::vector<t_field*>& xceptions = xs->get_members();
785 vector<t_field*>::const_iterator x_iter;
786 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
787 f_service_ <<
788 indent() << " " << result << (*x_iter)->get_name() << " /= nil -> " << endl <<
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000789 indent() << " throw(" << result << (*x_iter)->get_name() << ");" << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000790 }
791
792 // Careful, only return _result if not a void function
793 if ((*f_iter)->get_returntype()->is_void()) {
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000794 f_service_ <<
795 indent() << " true -> nil" << endl <<
Christopher Piro2f5afce2007-06-29 07:17:33 +0000796 indent() << " end" << endl;
797 } else {
798 f_service_ <<
799 indent() << " true -> " << endl <<
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000800 indent() << " throw(tApplicationException:new(?tApplicationException_MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\"))" << endl <<
Christopher Piro2f5afce2007-06-29 07:17:33 +0000801 indent() << " end" << endl;
802 }
803
804 // Close function
805 indent(f_service_) << "end." << endl << endl;
806 indent_down();
807 }
808 }
809
810 indent_down();
811 indent(f_service_) << endl;
812}
813
814/**
815 * Generates a service server definition.
816 *
817 * @param tservice The service to generate a server for.
818 */
819void t_erl_generator::generate_service_server(t_service* tservice) {
820 // Generate the dispatch methods
821 vector<t_function*> functions = tservice->get_functions();
822 vector<t_function*>::iterator f_iter;
823
824 string extends = "";
825 string extends_processor = "";
826 if (tservice->get_extends() != NULL) {
827 extends = type_name(tservice->get_extends());
Christopher Piroae1f10f2007-07-24 04:30:15 +0000828 extends_processor = " INHERIT(" + extends + "::Processor) % TODO";
Christopher Piro2f5afce2007-06-29 07:17:33 +0000829 }
830
831 // Generate the header portion
832 indent(f_service_) <<
833 "%% processor" << extends_processor << endl;
834
835 indent_up();
836
Christopher Piroae1f10f2007-07-24 04:30:15 +0000837 // TODO: inheritance runtime code (prolly) goes here:
838
Christopher Piro2f5afce2007-06-29 07:17:33 +0000839 // f_service_ <<
840 // indent() << "include Iface" << endl <<
841 // indent() << "include TProcessor" << endl <<
842 // endl;
843
844 /*
845 indent(f_service_) <<
846 "def initialize(handler)" << endl;
847 indent_up();
848 if (extends.empty()) {
849 f_service_ <<
850 indent() << "@handler = handler" << endl <<
851 indent() << "@processMap = {}" << endl;
852 } else {
853 f_service_ <<
854 indent() << "super(handler)" << endl;
855 }
856 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
857 f_service_ <<
858 indent() << "@processMap['" << (*f_iter)->get_name() << "'] = method(:process_" << (*f_iter)->get_name() << ")" << endl;
859 }
860 indent_down();
861 indent(f_service_) << "end" << endl << endl;
Christopher Piroae1f10f2007-07-24 04:30:15 +0000862 */
863
Christopher Piro2f5afce2007-06-29 07:17:33 +0000864 export_string("process", 3);
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000865 export_string("proc", 6);
Christopher Piro2f5afce2007-06-29 07:17:33 +0000866
867 // Generate the server implementation
868 indent(f_service_) <<
869 "process(HandlerModule, Iprot, Oprot) ->" << endl;
870 indent_up();
871
872 f_service_ <<
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000873 indent() << "{ Name, _Type, Seqid } = ?R0(Iprot, readMessageBegin)," << endl <<
874 indent() << "proc(Name, _Type, Seqid, HandlerModule, Iprot, Oprot)." << endl;
875
876 indent_down();
877 indent(f_service_) <<
878 "proc(Name, _Type, Seqid, HandlerModule, Iprot, Oprot) ->" << endl;
879 indent_up();
Christopher Piro2f5afce2007-06-29 07:17:33 +0000880
881 // TODO(mcslee): validate message
882
883 // HOT: dictionary function lookup
884 f_service_ <<
885 // try to dispatch to one of our process_*
886 indent() << "case Name of" << endl;
Christopher Piroae1f10f2007-07-24 04:30:15 +0000887
888 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
889 f_service_ <<
890 indent() << " \"" << (*f_iter)->get_name() << "\" -> process_" << (*f_iter)->get_name() << "(HandlerModule, Seqid, Iprot, Oprot);" << endl;
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000891 }
Christopher Piroae1f10f2007-07-24 04:30:15 +0000892
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000893 indent(f_service_) << " _ -> % unknown function" << endl;
894 if (tservice->get_extends() != NULL) {
895 indent(f_service_) << " " << extends << ":proc(Name,_Type,Seqid,HandlerModule, Iprot, Oprot)" << endl;
896 } else {
897 f_service_ <<
898 indent() << " ?R1(Iprot, skip, ?tType_STRUCT)," << endl <<
899 indent() << " ?R0(Iprot, readMessageEnd)," << endl <<
900 indent() << " X = tApplicationException:new(?tApplicationException_UNKNOWN_METHOD, \"Unknown function \" ++ Name)," << endl <<
901 indent() << " ?R3(Oprot, writeMessageBegin, Name, ?tMessageType_EXCEPTION, Seqid)," << endl <<
902 indent() << " tApplicationException:write(X, Oprot)," << endl <<
903 indent() << " ?R0(Oprot, writeMessageEnd)," << endl <<
904 indent() << " Trans = ?R1(Oprot, get, trans)," << endl <<
905 indent() << " ?R0(Trans, effectful_flush)," << endl <<
906 indent() << " {error, X} % what's the retval in this case?" << endl;
907 }
908 f_service_ << indent() << "end." << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000909
Christopher Piro2f5afce2007-06-29 07:17:33 +0000910 indent_down();
Christopher Piro2f5afce2007-06-29 07:17:33 +0000911
912 // Generate the process subfunctions
913 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
914 generate_process_function(tservice, *f_iter);
915 }
916
917 indent_down();
918 indent(f_service_) << endl << endl;
919}
920
921/**
922 * Generates a process function definition.
923 *
924 * @param tfunction The function to write a dispatcher for
925 */
926void t_erl_generator::generate_process_function(t_service* tservice,
Christopher Piroae1f10f2007-07-24 04:30:15 +0000927 t_function* tfunction) {
Christopher Piro2f5afce2007-06-29 07:17:33 +0000928
929 string name = "process_" + tfunction->get_name();
930
931 export_string(name, 4);
932
933 // Open function
934 indent(f_service_) <<
935 name <<
936 "(HandlerModule, Seqid, Iprot, Oprot) ->" << endl;
937 indent_up();
938
Christopher Piro094823a2007-07-18 00:26:12 +0000939 f_service_ <<
940 indent() << "Seqid, Oprot, % suppress unused warnings" << endl;
941
Christopher Piro2f5afce2007-06-29 07:17:33 +0000942 string argsname = tfunction->get_name() + "_args";
943 string resultname = tfunction->get_name() + "_result";
944
945 f_service_ <<
Christopher Piro094823a2007-07-18 00:26:12 +0000946 indent() << "_Args = " << argsname << "_read(Iprot)," << endl <<
947 // indent() << "Args, Seqid, Oprot, % suppress unused warnings" << endl <<
948 // indent() << "Args % suppress unused warnings" << endl <<
949 indent() << "?R0(Iprot, readMessageEnd)," << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000950
951 t_struct* xs = tfunction->get_xceptions();
952 const std::vector<t_field*>& xceptions = xs->get_members();
953 vector<t_field*>::const_iterator x_iter;
954
955 // Declare result for non async function
956 if (!tfunction->is_async()) {
957 }
958
Christopher Piro2f5afce2007-06-29 07:17:33 +0000959 // Generate the function call
960 t_struct* arg_struct = tfunction->get_arglist();
961 const std::vector<t_field*>& fields = arg_struct->get_members();
962 vector<t_field*>::const_iterator f_iter;
963
Christopher Piro5b3a8f72007-08-01 22:27:37 +0000964 indent(f_service_) << "try" << endl;
965 indent_up();
966
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000967 indent(f_service_) << "Result = ";
968 if (xceptions.size() > 0) {
969 f_service_ << "try" << endl;
970 } else {
971 f_service_ << "begin" << endl;
972 }
973 indent_up();
974
Christopher Piro2f5afce2007-06-29 07:17:33 +0000975 f_service_ << indent();
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000976 if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) {
977 f_service_<< "Res = ";
978 }
979 f_service_ << "HandlerModule:" << tfunction->get_name() << "(";
Christopher Piro2f5afce2007-06-29 07:17:33 +0000980
981 bool first = true;
982 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
983 if (first) {
984 first = false;
985 } else {
986 f_service_ << ", ";
987 }
Christopher Piro094823a2007-07-18 00:26:12 +0000988 f_service_ << "_Args#" << tfunction->get_name() << "_args." << (*f_iter)->get_name();
Christopher Piro2f5afce2007-06-29 07:17:33 +0000989 }
990 f_service_ << ")," << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000991 if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) {
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000992 indent(f_service_) << "#" << resultname << "{success=Res}" << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000993 } else{
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000994 indent(f_service_) << "#" << resultname << "{}" << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +0000995 }
996 indent_down();
Christopher Piro2f5afce2007-06-29 07:17:33 +0000997 if (!tfunction->is_async() && xceptions.size() > 0) {
Christopher Piro5f5fdf32007-07-25 22:41:00 +0000998 indent(f_service_) << "catch" << endl;
999 indent_up();
Christopher Piro2f5afce2007-06-29 07:17:33 +00001000 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001001 indent(f_service_) << "E when is_record(E," << uncapitalize((*x_iter)->get_type()->get_name()) << ") ->" << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001002 indent_up();
Christopher Piroae1f10f2007-07-24 04:30:15 +00001003 indent(f_service_) << "#" << resultname << "{" << (*x_iter)->get_name() << " = E};" << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001004 indent_down();
1005 }
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001006 indent(f_service_) << "dummy -> dummy % TODO: only for the semicolon's sake" << endl;
1007 indent_down();
Christopher Piro2f5afce2007-06-29 07:17:33 +00001008 }
Christopher Piro2f5afce2007-06-29 07:17:33 +00001009 indent(f_service_) << "end," << endl;
1010
Christopher Piro5b3a8f72007-08-01 22:27:37 +00001011 if (!tfunction->is_async()) {
Christopher Piro2f5afce2007-06-29 07:17:33 +00001012 f_service_ <<
Christopher Piro094823a2007-07-18 00:26:12 +00001013 indent() << "?R3(Oprot, writeMessageBegin, \"" << tfunction->get_name() << "\", ?tMessageType_REPLY, Seqid)," << endl <<
Christopher Piro5b3a8f72007-08-01 22:27:37 +00001014 indent() << tfunction->get_name() << "_result_write(Result, Oprot)," << endl;
1015 }
1016 indent(f_service_) << "Result" << endl;
1017 indent_down();
1018
1019 // catch errors in the handler
1020 indent(f_service_) << "catch" << endl <<
1021 indent() << " _:Kind when Kind == undef; Kind == function_clause ->" << endl <<
1022 indent() << " X = tApplicationException:new(?tApplicationException_HANDLER_ERROR, \"Handler doesn't implement "
1023 << tfunction->get_name() <<"\")," << endl <<
1024
1025 indent() << " ?R3(Oprot, writeMessageBegin, \"" << tfunction->get_name() << "\", ?tMessageType_EXCEPTION, Seqid)," << endl <<
1026 indent() << " tApplicationException:write(X, Oprot)," << endl <<
1027 indent() << " {error, X};" << endl <<
1028 indent() << " _:_Kind ->" << endl <<
1029 indent() << " X = tApplicationException:new(?tApplicationException_HANDLER_ERROR, \"Unknown handler error in "
1030 << tfunction->get_name() << "\")," << endl <<
1031
1032 indent() << " ?R3(Oprot, writeMessageBegin, \"" << tfunction->get_name() << "\", ?tMessageType_EXCEPTION, Seqid)," << endl <<
1033 indent() << " tApplicationException:write(X, Oprot)," << endl <<
1034 indent() << " {error, X}" << endl;
1035
1036 // 'after' block if we're expecting a result written
1037 if (!tfunction->is_async()) {
1038 f_service_ <<
1039 indent() << "after" << endl;
1040
1041 indent_up();
1042
1043 indent(f_service_) << "?R0(Oprot, writeMessageEnd)," << endl <<
Christopher Piro094823a2007-07-18 00:26:12 +00001044 indent() << "Trans = ?R1(Oprot, get, trans)," << endl <<
Christopher Piro5b3a8f72007-08-01 22:27:37 +00001045 indent() << "?R0(Trans, effectful_flush)" << endl;
1046
1047 indent_down();
Christopher Piro2f5afce2007-06-29 07:17:33 +00001048 }
1049
Christopher Piro5b3a8f72007-08-01 22:27:37 +00001050 indent(f_service_) << "end." << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001051
Christopher Piro2f5afce2007-06-29 07:17:33 +00001052 indent_down();
Christopher Piro2f5afce2007-06-29 07:17:33 +00001053}
1054
1055/**
1056 * Deserializes a field of any type.
1057 */
1058void t_erl_generator::generate_deserialize_field(ostream &out,
1059 t_field* tfield,
1060 string prefix,
1061 bool inclass) {
David Reisse087a302007-08-23 21:43:25 +00001062 t_type* type = get_true_type(tfield->get_type());
Christopher Piro2f5afce2007-06-29 07:17:33 +00001063
1064 if (type->is_void()) {
1065 throw "CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " +
1066 prefix + tfield->get_name();
1067 }
1068
1069 string name = prefix; //+ tfield->get_name();
1070
1071 if (type->is_struct() || type->is_xception()) {
1072 generate_deserialize_struct(out,
1073 (t_struct*)type,
1074 name);
1075 } else if (type->is_container()) {
1076 generate_deserialize_container(out, type, name);
1077 } else if (type->is_base_type() || type->is_enum()) {
1078 indent(out) <<
Christopher Piro094823a2007-07-18 00:26:12 +00001079 name << " = ?R0(Iprot, ";
Christopher Piro2f5afce2007-06-29 07:17:33 +00001080
1081 if (type->is_base_type()) {
1082 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1083 switch (tbase) {
1084 case t_base_type::TYPE_VOID:
1085 throw "compiler error: cannot serialize void field in a struct: " +
1086 name;
1087 break;
1088 case t_base_type::TYPE_STRING:
1089 out << "readString";
1090 break;
1091 case t_base_type::TYPE_BOOL:
1092 out << "readBool";
1093 break;
1094 case t_base_type::TYPE_BYTE:
1095 out << "readByte";
1096 break;
1097 case t_base_type::TYPE_I16:
1098 out << "readI16";
1099 break;
1100 case t_base_type::TYPE_I32:
1101 out << "readI32";
1102 break;
1103 case t_base_type::TYPE_I64:
1104 out << "readI64";
1105 break;
1106 case t_base_type::TYPE_DOUBLE:
1107 out << "readDouble";
1108 break;
1109 default:
David Reissdd7796f2007-08-28 21:09:06 +00001110 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase);
Christopher Piro2f5afce2007-06-29 07:17:33 +00001111 }
1112 } else if (type->is_enum()) {
1113 out << "readI32";
1114 }
Christopher Piroae1f10f2007-07-24 04:30:15 +00001115 out << ")," << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001116
1117 } else {
1118 printf("DO NOT KNOW HOW TO DESERIALIZE FIELD '%s' TYPE '%s'\n",
1119 tfield->get_name().c_str(), type->get_name().c_str());
1120 }
1121}
1122
1123/**
1124 * Generates an unserializer for a struct, calling read()
1125 */
Christopher Piroae1f10f2007-07-24 04:30:15 +00001126 void t_erl_generator::generate_deserialize_struct(ostream &out,
Christopher Piro2f5afce2007-06-29 07:17:33 +00001127 t_struct* tstruct,
1128 string prefix) {
1129 out <<
Christopher Piroae1f10f2007-07-24 04:30:15 +00001130 indent() << prefix << " = " << (tstruct->get_program())->get_name() << "_types:" << type_name(tstruct) << "_read(Iprot)," << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001131}
1132
1133/**
1134 * Serialize a container by writing out the header followed by
1135 * data and then a footer.
1136 */
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001137void t_erl_generator::generate_deserialize_container(ostream &out,
Christopher Piro2f5afce2007-06-29 07:17:33 +00001138 t_type* ttype,
1139 string prefix) {
1140 string size = tmp("_size");
1141 string ktype = tmp("_ktype");
1142 string vtype = tmp("_vtype");
1143 string etype = tmp("_etype");
1144
1145 t_field fsize(g_type_i32, size);
1146 t_field fktype(g_type_byte, ktype);
1147 t_field fvtype(g_type_byte, vtype);
1148 t_field fetype(g_type_byte, etype);
1149
1150 // Declare variables, read header
1151 if (ttype->is_map()) {
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001152 t_map* tmap = (t_map*)ttype;
1153 string key = tmp("_key");
1154 string val = tmp("_val");
1155 t_field fkey(tmap->get_key_type(), key);
1156 t_field fval(tmap->get_val_type(), val);
Christopher Piro2f5afce2007-06-29 07:17:33 +00001157
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001158 out <<
1159 indent() << "{" << ktype << ", " << vtype << ", " << size << " } = ?R0(Iprot,readMapBegin)," << endl;
1160 out <<
1161 indent() << prefix << " = dict:from_list(thrift_utils:tabulate(" << size << "," << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001162 indent_up();
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001163 out << indent() << "fun (_) ->" << endl;
1164 indent_up();
1165 generate_deserialize_field(out, &fkey,key);
1166 generate_deserialize_field(out, &fval,val);
1167 out << indent() << "{" << key << "," << val << "}" << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001168 indent_down();
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001169 out << indent() << "end))," << endl;
1170 indent_down();
1171 out << indent() << "?R0(Iprot,readMapEnd)," << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001172
Christopher Piro2f5afce2007-06-29 07:17:33 +00001173 } else if (ttype->is_set()) {
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001174 t_set* tset = (t_set*)ttype;
1175 string elem = tmp("_elem");
1176 t_field felem(tset->get_elem_type(), elem);
1177 out <<
1178 indent() << "{" << etype << ", " << size << "} = ?R0(Iprot,readSetBegin)," << endl;
1179 out <<
1180 indent() << prefix << " = sets:from_list(thrift_utils:tabulate(" << size << "," << endl;
1181 indent_up();
1182 out << indent() << "fun (_) ->" << endl;
1183 indent_up();
1184 generate_deserialize_field(out,&felem,elem);
1185 out << indent() << elem << endl;
1186 indent_down();
1187 out << indent() << "end)),";
1188 indent_down();
1189 out << indent() << "?R0(Iprot,readSetEnd)," << endl;
1190
Christopher Piro2f5afce2007-06-29 07:17:33 +00001191 } else if (ttype->is_list()) {
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001192 t_list* tlist = (t_list*)ttype;
1193 string elem = tmp("_elem");
1194 t_field felem(tlist->get_elem_type(), elem);
1195 out << indent() << "{" << etype << ", " << size << "} = ?R0(Iprot,readListBegin)," << endl;
1196 out << indent() << prefix << " = thrift_utils:tabulate(" << size << "," << endl;
1197 indent_up();
1198 out << indent() << "fun (_) ->" << endl;
1199 indent_up();
1200 generate_deserialize_field(out,&felem,elem);
1201 out << indent() << elem << endl;
1202 indent_down();
1203 out << indent() << "end)," << endl;
1204 indent_down();
1205 out << indent() << "?R0(Iprot,readListEnd)," << endl;
1206 }
Christopher Piro2f5afce2007-06-29 07:17:33 +00001207}
1208
1209
1210/**
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001211 * Generates code to deserialize a map UNUSED
Christopher Piro2f5afce2007-06-29 07:17:33 +00001212 */
1213void t_erl_generator::generate_deserialize_map_element(ostream &out, // TODO
1214 t_map* tmap,
1215 string prefix) {
1216 string key = tmp("_key");
1217 string val = tmp("_val");
1218 t_field fkey(tmap->get_key_type(), key);
1219 t_field fval(tmap->get_val_type(), val);
1220
1221 generate_deserialize_field(out, &fkey);
1222 generate_deserialize_field(out, &fval);
1223
1224 indent(out) <<
1225 prefix << "[" << key << "] = " << val << endl;
1226}
1227
1228/**
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001229 * Read a set element UNUSED
Christopher Piro2f5afce2007-06-29 07:17:33 +00001230 */
1231void t_erl_generator::generate_deserialize_set_element(ostream &out, // TODO
1232 t_set* tset,
1233 string prefix) {
1234 string elem = tmp("_elem");
1235 t_field felem(tset->get_elem_type(), elem);
1236
1237 generate_deserialize_field(out, &felem);
1238
1239 indent(out) <<
1240 prefix << "[" << elem << "] = true" << endl;
1241}
1242
1243/**
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001244 * Read a list element UNUSED
Christopher Piro2f5afce2007-06-29 07:17:33 +00001245 */
Christopher Piroae1f10f2007-07-24 04:30:15 +00001246void t_erl_generator::generate_deserialize_list_element(ostream &out, // TODO
Christopher Piro2f5afce2007-06-29 07:17:33 +00001247 t_list* tlist,
1248 string prefix) {
1249 string elem = tmp("_elem");
1250 t_field felem(tlist->get_elem_type(), elem);
1251
1252 generate_deserialize_field(out, &felem);
1253
1254 indent(out) <<
1255 prefix << ".push(" << elem << ")" << endl;
1256}
1257
1258
1259/**
1260 * Serializes a field of any type.
1261 *
1262 * @param tfield The field to serialize
1263 * @param prefix Name to prepend to field name
1264 */
1265void t_erl_generator::generate_serialize_field(ostream &out,
1266 t_field* tfield,
1267 string prefix) {
David Reisse087a302007-08-23 21:43:25 +00001268 t_type* type = get_true_type(tfield->get_type());
Christopher Piro2f5afce2007-06-29 07:17:33 +00001269
1270 // Do nothing for void types
1271 if (type->is_void()) {
1272 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " +
1273 prefix + tfield->get_name();
1274 }
1275
1276 if (type->is_struct() || type->is_xception()) {
1277 generate_serialize_struct(out,
1278 (t_struct*)type,
1279 prefix + tfield->get_name());
1280 } else if (type->is_container()) {
1281 generate_serialize_container(out,
1282 type,
1283 prefix + tfield->get_name());
1284 } else if (type->is_base_type() || type->is_enum()) {
1285
1286 string name = prefix + tfield->get_name();
1287
1288 indent(out) <<
Christopher Piro094823a2007-07-18 00:26:12 +00001289 "?R1(Oprot, ";
Christopher Piro2f5afce2007-06-29 07:17:33 +00001290
1291 if (type->is_base_type()) {
1292 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1293 switch (tbase) {
1294 case t_base_type::TYPE_VOID:
1295 throw
1296 "compiler error: cannot serialize void field in a struct: " + name;
1297 break;
1298 case t_base_type::TYPE_STRING:
1299 out << "writeString, " << name << "),";
1300 break;
1301 case t_base_type::TYPE_BOOL:
1302 out << "writeBool, " << name << "),";
1303 break;
1304 case t_base_type::TYPE_BYTE:
1305 out << "writeByte, " << name << "),";
1306 break;
1307 case t_base_type::TYPE_I16:
1308 out << "writeI16, " << name << "),";
1309 break;
1310 case t_base_type::TYPE_I32:
1311 out << "writeI32, " << name << "),";
1312 break;
1313 case t_base_type::TYPE_I64:
1314 out << "writeI64, " << name << "),";
1315 break;
1316 case t_base_type::TYPE_DOUBLE:
1317 out << "writeDouble, " << name << "),";
1318 break;
1319 default:
David Reissdd7796f2007-08-28 21:09:06 +00001320 throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase);
Christopher Piro2f5afce2007-06-29 07:17:33 +00001321 }
1322 } else if (type->is_enum()) {
1323 out << "writeI32, " << name << "),";
1324 }
Christopher Piroae1f10f2007-07-24 04:30:15 +00001325 out << "" << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001326 } else {
1327 printf("DO NOT KNOW HOW TO SERIALIZE FIELD '%s%s' TYPE '%s'\n",
1328 prefix.c_str(),
1329 tfield->get_name().c_str(),
1330 type->get_name().c_str());
1331 }
1332}
1333
1334/**
1335 * Serializes all the members of a struct.
1336 *
1337 * @param tstruct The struct to serialize
1338 * @param prefix String prefix to attach to all fields
1339 */
1340void t_erl_generator::generate_serialize_struct(ostream &out,
1341 t_struct* tstruct,
1342 string prefix) {
Christopher Piroae1f10f2007-07-24 04:30:15 +00001343 indent(out) << tstruct->get_program()->get_name() << "_types:" << uncapitalize(tstruct->get_name()) << "_write(" << prefix << ", Oprot)," << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001344}
1345
Christopher Piroae1f10f2007-07-24 04:30:15 +00001346void t_erl_generator::generate_serialize_container(ostream &out, // TODO
Christopher Piro2f5afce2007-06-29 07:17:33 +00001347 t_type* ttype,
1348 string prefix) {
1349 if (ttype->is_map()) {
1350 indent(out) <<
Christopher Piro094823a2007-07-18 00:26:12 +00001351 "?R3(Oprot, writeMapBegin, " <<
Christopher Piro2f5afce2007-06-29 07:17:33 +00001352 type_to_enum(((t_map*)ttype)->get_key_type()) << ", " <<
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001353 type_to_enum(((t_map*)ttype)->get_val_type()) << ", thrift_utils:dict_size(" <<
Christopher Piroae1f10f2007-07-24 04:30:15 +00001354 prefix << "))," << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001355 } else if (ttype->is_set()) {
1356 indent(out) <<
Christopher Piro094823a2007-07-18 00:26:12 +00001357 "?R2(Oprot, writeSetBegin, " <<
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001358 type_to_enum(((t_set*)ttype)->get_elem_type()) << ", sets:size(" <<
Christopher Piroae1f10f2007-07-24 04:30:15 +00001359 prefix << "))," << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001360 } else if (ttype->is_list()) {
1361 indent(out) <<
Christopher Piro094823a2007-07-18 00:26:12 +00001362 "?R2(Oprot, writeListBegin, " <<
Christopher Piro2f5afce2007-06-29 07:17:33 +00001363 type_to_enum(((t_list*)ttype)->get_elem_type()) << ", length(" <<
Christopher Piroae1f10f2007-07-24 04:30:15 +00001364 prefix << "))," << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001365 }
1366
Christopher Piroae1f10f2007-07-24 04:30:15 +00001367 if (ttype->is_map()) {
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001368 string kiter = tmp("_kiter");
1369 string viter = tmp("_viter");
Christopher Piro2f5afce2007-06-29 07:17:33 +00001370 indent(out) <<
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001371 "dict:fold(fun ("<< kiter << ", " << viter << ",_)->" << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001372 indent_up();
1373 generate_serialize_map_element(out, (t_map*)ttype, kiter, viter);
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001374 indent(out) << "nil" << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001375 indent_down();
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001376 indent(out) << "end, nil," << prefix << ")," << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001377 } else if (ttype->is_set()) {
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001378 string iter = tmp("_iter");
Christopher Piro2f5afce2007-06-29 07:17:33 +00001379 indent(out) <<
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001380 "sets:fold(fun ("<< iter << ",_)->" << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001381 indent_up();
1382 generate_serialize_set_element(out, (t_set*)ttype, iter);
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001383 indent(out) << "nil" << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001384 indent_down();
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001385 indent(out) << "end, nil," << prefix << ")," << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001386 } else if (ttype->is_list()) {
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001387 string iter = tmp("_iter");
Christopher Piro2f5afce2007-06-29 07:17:33 +00001388 indent(out) <<
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001389 "lists:foldl(fun (" << iter << ",_)->" << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001390 indent_up();
1391 generate_serialize_list_element(out, (t_list*)ttype, iter);
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001392 indent(out) << "nil" << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001393 indent_down();
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001394 indent(out) << "end,nil," << prefix << ")," << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001395 }
1396
1397 if (ttype->is_map()) {
1398 indent(out) <<
Christopher Piroae1f10f2007-07-24 04:30:15 +00001399 "?R0(Oprot, writeMapEnd)," << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001400 } else if (ttype->is_set()) {
1401 indent(out) <<
Christopher Piroae1f10f2007-07-24 04:30:15 +00001402 "?R0(Oprot, writeSetEnd)," << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001403 } else if (ttype->is_list()) {
1404 indent(out) <<
Christopher Piroae1f10f2007-07-24 04:30:15 +00001405 "?R0(Oprot, writeListEnd)," << endl;
Christopher Piro2f5afce2007-06-29 07:17:33 +00001406 }
1407}
1408
1409/**
1410 * Serializes the members of a map.
1411 *
1412 */
Christopher Piroae1f10f2007-07-24 04:30:15 +00001413void t_erl_generator::generate_serialize_map_element(ostream &out,
Christopher Piro2f5afce2007-06-29 07:17:33 +00001414 t_map* tmap,
1415 string kiter,
1416 string viter) {
1417 t_field kfield(tmap->get_key_type(), kiter);
1418 generate_serialize_field(out, &kfield, "");
1419
1420 t_field vfield(tmap->get_val_type(), viter);
1421 generate_serialize_field(out, &vfield, "");
1422}
1423
1424/**
1425 * Serializes the members of a set.
1426 */
Christopher Piroae1f10f2007-07-24 04:30:15 +00001427void t_erl_generator::generate_serialize_set_element(ostream &out,
Christopher Piro2f5afce2007-06-29 07:17:33 +00001428 t_set* tset,
1429 string iter) {
1430 t_field efield(tset->get_elem_type(), iter);
1431 generate_serialize_field(out, &efield, "");
1432}
1433
1434/**
1435 * Serializes the members of a list.
1436 */
Christopher Piroae1f10f2007-07-24 04:30:15 +00001437void t_erl_generator::generate_serialize_list_element(ostream &out,
Christopher Piro2f5afce2007-06-29 07:17:33 +00001438 t_list* tlist,
1439 string iter) {
1440 t_field efield(tlist->get_elem_type(), iter);
1441 generate_serialize_field(out, &efield, "");
1442}
1443
1444/**
1445 * Declares a field, which may include initialization as necessary.
1446 *
1447 * @param ttype The type
1448 */
1449string t_erl_generator::declare_field(t_field* tfield) { // TODO
1450 string result = "@" + tfield->get_name();
David Reisse087a302007-08-23 21:43:25 +00001451 t_type* type = get_true_type(tfield->get_type());
Christopher Piro2f5afce2007-06-29 07:17:33 +00001452 if (tfield->get_value() != NULL) {
1453 result += " = " + render_const_value(type, tfield->get_value());
1454 } else {
1455 result += " = nil";
1456 }
1457 return result;
1458}
1459
1460/**
1461 * Renders a function signature of the form 'type name(args)'
1462 *
1463 * @param tfunction Function definition
1464 * @return String of rendered function definition
1465 */
1466string t_erl_generator::function_signature(t_function* tfunction,
1467 string prefix) {
Christopher Piro2f5afce2007-06-29 07:17:33 +00001468 return
1469 prefix + tfunction->get_name() +
1470 "(This" + capitalize(argument_list(tfunction->get_arglist())) + ")";
1471}
1472
Christopher Piroae1f10f2007-07-24 04:30:15 +00001473/**
1474 * Add a function to the exports list
1475 */
Christopher Piro2f5afce2007-06-29 07:17:33 +00001476void t_erl_generator::export_string(string name, int num) {
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001477 if (export_lines_first_) {
Christopher Piro2f5afce2007-06-29 07:17:33 +00001478 export_lines_first_ = false;
1479 } else {
1480 export_lines_ << ", ";
1481 }
1482 export_lines_ << name << "/" << num;
1483}
1484
1485void t_erl_generator::export_types_function(t_function* tfunction,
1486 string prefix) {
1487
1488 export_types_string(prefix + tfunction->get_name(),
1489 1 // This
1490 + ((tfunction->get_arglist())->get_members()).size()
1491 );
1492}
Christopher Piroae1f10f2007-07-24 04:30:15 +00001493
Christopher Piro2f5afce2007-06-29 07:17:33 +00001494void t_erl_generator::export_types_string(string name, int num) {
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001495 if (export_types_lines_first_) {
Christopher Piro2f5afce2007-06-29 07:17:33 +00001496 export_types_lines_first_ = false;
1497 } else {
1498 export_types_lines_ << ", ";
1499 }
1500 export_types_lines_ << name << "/" << num;
1501}
1502
1503void t_erl_generator::export_function(t_function* tfunction,
1504 string prefix) {
1505
1506 export_string(prefix + tfunction->get_name(),
1507 1 // This
1508 + ((tfunction->get_arglist())->get_members()).size()
1509 );
1510}
1511
1512
1513/**
1514 * Renders a field list
1515 */
Christopher Piroae1f10f2007-07-24 04:30:15 +00001516string t_erl_generator::argument_list(t_struct* tstruct) {
Christopher Piro2f5afce2007-06-29 07:17:33 +00001517 string result = "";
1518
1519 const vector<t_field*>& fields = tstruct->get_members();
1520 vector<t_field*>::const_iterator f_iter;
1521 bool first = true;
1522 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1523 if (first) {
1524 first = false;
Christopher Piroae1f10f2007-07-24 04:30:15 +00001525 result += ", "; // initial comma to compensate for initial This
Christopher Piro2f5afce2007-06-29 07:17:33 +00001526 } else {
1527 result += ", ";
1528 }
1529 result += capitalize((*f_iter)->get_name());
1530 }
1531 return result;
1532}
1533
Christopher Piroae1f10f2007-07-24 04:30:15 +00001534string t_erl_generator::type_name(t_type* ttype) {
Christopher Piro2f5afce2007-06-29 07:17:33 +00001535 string prefix = "";
1536 t_program* program = ttype->get_program();
1537 if (program != NULL && program != program_) {
1538 if (!ttype->is_service()) {
Christopher Piroae1f10f2007-07-24 04:30:15 +00001539 prefix = program->get_name() + "_types."; // TODO
Christopher Piro2f5afce2007-06-29 07:17:33 +00001540 }
1541 }
1542
1543 string name = ttype->get_name();
Christopher Piroae1f10f2007-07-24 04:30:15 +00001544
Christopher Piro5f5fdf32007-07-25 22:41:00 +00001545 if (ttype->is_struct() || ttype->is_xception() || ttype->is_service()) {
Christopher Piroae1f10f2007-07-24 04:30:15 +00001546 name = uncapitalize(ttype->get_name());
Christopher Piro2f5afce2007-06-29 07:17:33 +00001547 }
1548
1549 return prefix + name;
1550}
1551
1552/**
Christopher Piroae1f10f2007-07-24 04:30:15 +00001553 * Converts the parse type to a Erlang "type" (macro for int constants)
Christopher Piro2f5afce2007-06-29 07:17:33 +00001554 */
1555string t_erl_generator::type_to_enum(t_type* type) {
David Reisse087a302007-08-23 21:43:25 +00001556 type = get_true_type(type);
Christopher Piro2f5afce2007-06-29 07:17:33 +00001557
1558 if (type->is_base_type()) {
1559 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1560 switch (tbase) {
1561 case t_base_type::TYPE_VOID:
1562 throw "NO T_VOID CONSTRUCT";
1563 case t_base_type::TYPE_STRING:
1564 return "?tType_STRING";
1565 case t_base_type::TYPE_BOOL:
1566 return "?tType_BOOL";
1567 case t_base_type::TYPE_BYTE:
1568 return "?tType_BYTE";
1569 case t_base_type::TYPE_I16:
1570 return "?tType_I16";
1571 case t_base_type::TYPE_I32:
1572 return "?tType_I32";
1573 case t_base_type::TYPE_I64:
1574 return "?tType_I64";
1575 case t_base_type::TYPE_DOUBLE:
1576 return "?tType_DOUBLE";
1577 }
1578 } else if (type->is_enum()) {
1579 return "?tType_I32";
1580 } else if (type->is_struct() || type->is_xception()) {
1581 return "?tType_STRUCT";
1582 } else if (type->is_map()) {
1583 return "?tType_MAP";
1584 } else if (type->is_set()) {
1585 return "?tType_SET";
1586 } else if (type->is_list()) {
1587 return "?tType_LIST";
1588 }
1589
1590 throw "INVALID TYPE IN type_to_enum: " + type->get_name();
1591}