Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1 | // 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 7 | // still missing: inheritance, containers |
| 8 | |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 9 | #include <stdlib.h> |
| 10 | #include <sys/stat.h> |
| 11 | #include <sys/types.h> |
| 12 | #include <sstream> |
| 13 | #include "t_erl_generator.h" |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 14 | |
Christopher Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 15 | using namespace std; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 16 | |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 17 | /** |
| 18 | * UI for file generation by opening up the necessary file output |
| 19 | * streams. |
| 20 | * |
| 21 | * @param tprogram The program to generate |
| 22 | */ |
| 23 | void t_erl_generator::init_generator() { |
| 24 | // Make output directory |
| 25 | mkdir(T_ERL_DIR, S_IREAD | S_IWRITE | S_IEXEC); |
| 26 | |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 27 | // setup export lines |
| 28 | export_lines_first_ = true; |
| 29 | export_types_lines_first_ = true; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 30 | |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 31 | // types files |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 32 | 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 34 | |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 35 | 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 Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 40 | f_types_file_ << |
| 41 | erl_autogen_comment() << endl << |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 42 | "-module(" << program_name_ << "_types)." << endl << |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 43 | erl_imports() << endl; |
| 44 | |
| 45 | f_types_file_ << |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 46 | "-include(\"" << program_name_ << "_types.hrl\")." << endl << |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 47 | endl; |
| 48 | |
| 49 | f_types_hrl_file_ << render_includes() << endl; |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 50 | |
| 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 Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 55 | f_consts_ << |
| 56 | erl_autogen_comment() << endl << |
| 57 | erl_imports() << endl << |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 58 | "-include(\"" << program_name_ << "_types.hrl\")." << endl << |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 59 | endl; |
| 60 | } |
| 61 | |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 62 | /** |
| 63 | * Boilerplate at beginning and end of header files |
| 64 | */ |
| 65 | void t_erl_generator::hrl_header(ostream& out, string name) { |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 66 | out << "-ifndef(_" << name << "_included)." << endl << |
| 67 | "-define(_" << name << "_included, yeah)." << endl; |
| 68 | } |
| 69 | |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 70 | void t_erl_generator::hrl_footer(ostream& out, string name) { |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 71 | out << "-endif." << endl; |
| 72 | } |
| 73 | |
| 74 | /** |
| 75 | * Renders all the imports necessary for including another Thrift program |
| 76 | */ |
| 77 | string 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 81 | result += "-include(\"" + includes[i]->get_name() + "_types.hrl\").\n"; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 82 | } |
| 83 | if (includes.size() > 0) { |
| 84 | result += "\n"; |
| 85 | } |
| 86 | return result; |
| 87 | } |
| 88 | |
| 89 | /** |
| 90 | * Autogen'd comment |
| 91 | */ |
| 92 | string t_erl_generator::erl_autogen_comment() { |
| 93 | return |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 94 | 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 Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 99 | } |
| 100 | |
| 101 | /** |
| 102 | * Prints standard thrift imports |
| 103 | */ |
| 104 | string t_erl_generator::erl_imports() { |
| 105 | return |
Christopher Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 106 | string("-include(\"thrift.hrl\").\n") + |
| 107 | "-include(\"tApplicationException.hrl\").\n" + |
| 108 | "-include(\"protocol/tProtocol.hrl\").\n"; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 109 | } |
| 110 | |
| 111 | /** |
| 112 | * Closes the type files |
| 113 | */ |
| 114 | void 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 127 | * Generates a typedef. no op |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 128 | * |
| 129 | * @param ttypedef The type definition |
| 130 | */ |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 131 | void t_erl_generator::generate_typedef(t_typedef* ttypedef) { |
| 132 | } |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 133 | |
| 134 | /** |
| 135 | * Generates code for an enumerated type. Done using a class to scope |
| 136 | * the values. |
| 137 | * |
| 138 | * @param tenum The enumeration |
| 139 | */ |
| 140 | void t_erl_generator::generate_enum(t_enum* tenum) { |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 141 | vector<t_enum_value*> constants = tenum->get_constants(); |
| 142 | vector<t_enum_value*>::iterator c_iter; |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 143 | |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 144 | int value = -1; |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 145 | |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 146 | 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 Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 153 | string name = capitalize((*c_iter)->get_name()); |
| 154 | |
| 155 | f_types_hrl_file_ << |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 156 | indent() << "-define(" << program_name_ << "_" << name << ", " << value << ")."<< endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 157 | } |
| 158 | |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 159 | f_types_hrl_file_ << endl; |
| 160 | } |
| 161 | |
| 162 | /** |
| 163 | * Generate a constant value |
| 164 | */ |
| 165 | void t_erl_generator::generate_const(t_const* tconst) { |
| 166 | t_type* type = tconst->get_type(); |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 167 | string name = capitalize(tconst->get_name()); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 168 | t_const_value* value = tconst->get_value(); |
| 169 | |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 170 | f_consts_ << "-define(" << program_name_ << "_" << name << ", " << render_const_value(type, value) << ")." << endl << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 171 | } |
| 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 | */ |
| 178 | string t_erl_generator::render_const_value(t_type* type, t_const_value* value) { |
| 179 | std::ostringstream out; |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 180 | |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 181 | 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 Reiss | dd7796f | 2007-08-28 21:09:06 +0000 | [diff] [blame] | 204 | throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 205 | } |
| 206 | } else if (type->is_enum()) { |
| 207 | indent(out) << value->get_integer(); |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 208 | |
| 209 | } else if (type->is_struct() || type->is_xception()) { |
| 210 | out << "#" << type->get_name() << "{"; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 211 | 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 Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 215 | |
| 216 | bool first = true; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 217 | 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 Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 227 | |
| 228 | if (first) { |
| 229 | first = false; |
| 230 | } else { |
| 231 | out << ","; |
| 232 | } |
| 233 | out << v_iter->first->get_string(); |
| 234 | out << " = "; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 235 | out << render_const_value(field_type, v_iter->second); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 236 | } |
| 237 | indent_down(); |
| 238 | indent(out) << "}"; |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 239 | |
| 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 Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 261 | t_type* etype; |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 262 | 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 Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 275 | } |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 276 | 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 Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 284 | 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 Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 287 | if (first) { |
| 288 | first=false; |
| 289 | } else { |
| 290 | out << ","; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 291 | } |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 292 | out << render_const_value(etype, *v_iter); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 293 | } |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 294 | out << "]"; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 295 | } |
| 296 | return out.str(); |
| 297 | } |
| 298 | |
| 299 | /** |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 300 | * Generates a struct |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 301 | */ |
| 302 | void 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 | */ |
| 312 | void t_erl_generator::generate_xception(t_struct* txception) { |
| 313 | generate_erl_struct(txception, true); |
| 314 | } |
| 315 | |
| 316 | /** |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 317 | * Generates a struct |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 318 | */ |
| 319 | void 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 325 | * Generates a struct definition for a thrift data type. |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 326 | * |
| 327 | * @param tstruct The struct definition |
| 328 | */ |
| 329 | void t_erl_generator::generate_erl_struct_definition(ostream& out, |
| 330 | ostream& hrl_out, |
| 331 | t_struct* tstruct, |
| 332 | bool is_exception, |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 333 | bool is_result) |
| 334 | { |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 335 | const vector<t_field*>& members = tstruct->get_members(); |
| 336 | vector<t_field*>::const_iterator m_iter; |
| 337 | |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 338 | indent(out) << "%% struct " << type_name(tstruct) << endl; |
| 339 | |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 340 | if (is_exception) { |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 341 | } |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 342 | |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 343 | out << endl; |
| 344 | |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 345 | if (members.size() > 0) { |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 346 | indent(out) << "% -record(" << type_name(tstruct) << ", {"; |
| 347 | indent(hrl_out) << "-record(" << type_name(tstruct) << ", {"; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 348 | |
| 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 363 | indent(out) << "% -record(" << type_name(tstruct) << ", {})." << endl; |
| 364 | indent(hrl_out) << "-record(" << type_name(tstruct) << ", {})." << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 365 | } |
| 366 | |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 367 | out << endl; |
| 368 | hrl_out << endl; |
| 369 | |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 370 | generate_erl_struct_reader(out, tstruct); |
| 371 | generate_erl_struct_writer(out, tstruct); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 372 | } |
| 373 | |
| 374 | /** |
| 375 | * Generates the read method for a struct |
| 376 | */ |
| 377 | void 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 382 | string name = type_name(tstruct) + "_read"; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 383 | |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 384 | if (out == f_types_) { // OH HAI MR. HORRIBLE |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 385 | 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 Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 394 | indent() << "?R0(Iprot, readStructBegin)," << endl << |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 395 | indent() << "Str = " << type_name(tstruct) << "_read_loop(Iprot, "; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 396 | |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 397 | // empty struct |
| 398 | out << "#" << type_name(tstruct) << "{}"; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 399 | out << ")," << endl << |
Christopher Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 400 | indent() << "?R0(Iprot, readStructEnd)," << endl << |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 401 | indent() << "Str." << endl; |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 402 | |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 403 | indent_down(); |
| 404 | |
| 405 | indent(out) << |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 406 | "" << type_name(tstruct) << "_read_loop(Iprot, Str) ->" << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 407 | indent_up(); |
| 408 | |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 409 | // Read beginning field marker |
Christopher Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 410 | out << |
| 411 | indent() << "{ _Fname, Ftype, Fid } = ?R0(Iprot, readFieldBegin)," << endl << |
| 412 | indent() << "Fid, % suppress unused warnings" << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 413 | |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 414 | // 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 Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 425 | indent_up(); |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 426 | 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 Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 435 | |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 436 | // 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 Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 447 | out << endl; |
| 448 | } |
| 449 | |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 450 | void t_erl_generator::generate_erl_struct_writer(ostream& out, |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 451 | 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 456 | string fname = type_name(tstruct) + "_write"; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 457 | |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 458 | if (out == f_types_) { // OH HAI MR. HORRIBLE |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 459 | export_types_string(fname, 2); |
| 460 | } else { |
| 461 | export_string(fname, 2); |
| 462 | } |
| 463 | |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 464 | indent(out) << fname << "(Str, Oprot) ->" << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 465 | indent_up(); |
| 466 | |
Christopher Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 467 | out << |
| 468 | indent() << "Str, % suppress unused warnings" << endl << |
| 469 | indent() << "?R1(Oprot, writeStructBegin, \"" << name << "\")," << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 470 | |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 471 | string prefix = string("Str#") + type_name(tstruct) + "."; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 472 | 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 Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 478 | "?R3(Oprot, writeFieldBegin, " << |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 479 | "\"" << (*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 Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 488 | "?R0(Oprot, writeFieldEnd);" << endl << |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 489 | indent() << "true -> ok" << endl; |
| 490 | |
| 491 | indent_down(); |
| 492 | out << " end," << endl; |
| 493 | } |
| 494 | |
| 495 | // Write the struct map |
| 496 | out << |
Christopher Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 497 | indent() << "?R0(Oprot, writeFieldStop)," << endl << |
| 498 | indent() << "?R0(Oprot, writeStructEnd)," << endl << |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 499 | 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 | */ |
| 511 | void t_erl_generator::generate_service(t_service* tservice) { |
Christopher Piro | 8737260 | 2007-07-24 06:20:47 +0000 | [diff] [blame] | 512 | // 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 516 | 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 Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 518 | f_service_file_.open(f_service_name.c_str()); |
| 519 | f_service_hrl_.open(f_service_hrl_name.c_str()); |
| 520 | |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 521 | hrl_header(f_service_hrl_, service_name_); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 522 | |
| 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 529 | "-include(\"" << program_name_ << "_types.hrl\")." << endl << |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 530 | 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 543 | "-module(" << service_name_ << ")." << endl << endl << |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 544 | erl_imports() << endl; |
| 545 | |
| 546 | f_service_file_ << "-include(\"" << uncapitalize(tservice->get_name()) << ".hrl\")." << endl << endl; |
| 547 | |
Christopher Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 548 | f_service_file_ << "-export([" << export_lines_.str() << "])." << endl << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 549 | |
| 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 | */ |
| 564 | void 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 568 | // indent(f_service_) << |
| 569 | // "% HELPER FUNCTIONS AND STRUCTURES" << endl << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 570 | |
| 571 | for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { |
| 572 | t_struct* ts = (*f_iter)->get_arglist(); |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 573 | |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 574 | 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 | */ |
| 584 | void 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 | */ |
| 604 | void 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 622 | indent(f_service_) << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 623 | } |
| 624 | |
| 625 | /** |
| 626 | * Generates a service client definition. |
| 627 | * |
| 628 | * @param tservice The service to generate a server for. |
| 629 | */ |
| 630 | void 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 650 | indent() << "new(Iprot, Oprot) ->" << endl << |
| 651 | indent() << " #"<<service_name_<<"{iprot=Iprot, oprot=Oprot, seqid=0}." << endl << |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 652 | indent() << "new(Iprot) ->" << endl << |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 653 | indent() << " #"<<service_name_<<"{iprot=Iprot, oprot=Iprot, seqid=0}." << endl << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 654 | |
| 655 | // indent(f_service_) << "end" << endl << endl; |
| 656 | |
| 657 | f_service_hrl_ << |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 658 | indent() << "-record("<< service_name_ <<", {iprot, oprot, seqid})." << endl << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 659 | |
| 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 673 | function_signature(*f_iter) << " ->" << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 674 | |
| 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 707 | "send_" << function_signature(*f_iter) << " ->" << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 708 | indent_up(); |
| 709 | |
| 710 | std::string argsname = capitalize((*f_iter)->get_name() + "_args"); |
| 711 | |
| 712 | // Serialize the request header |
| 713 | f_service_ << |
Christopher Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 714 | 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 Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 717 | 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 Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 731 | indent() << "?R0(Oprot, writeMessageEnd)," << endl << |
| 732 | indent() << "Trans = ?R1(Oprot, get, trans)," << endl << |
| 733 | indent() << "?R0(Trans, effectful_flush)," << endl << |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 734 | 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 751 | indent() << function_signature(&recv_function) << " ->" << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 752 | indent_up(); |
| 753 | |
| 754 | // TODO(mcslee): Validate message reply here, seq ids etc. |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 755 | |
| 756 | f_service_ << |
Christopher Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 757 | indent() << "Iprot = oop:get(This, iprot)," << endl << |
| 758 | indent() << "{ _Fname, Mtype, _Rseqid } = ?R0(Iprot, readMessageBegin)," << endl << |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 759 | indent() << "if" << endl << |
| 760 | indent() << " Mtype == ?tMessageType_EXCEPTION ->" << endl << |
| 761 | indent() << " X = tApplicationException:new()," << endl << |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 762 | indent() << " tApplicationException:read(X, Iprot)," << endl << |
Christopher Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 763 | indent() << " ?R0(Iprot, readMessageEnd), " << endl << |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 764 | indent() << " throw(X);" << endl << |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 765 | indent() << " true ->" << endl << |
| 766 | indent() << " Result = " << resultname << "_read(Iprot)," << endl << |
Christopher Piro | 5b3a8f7 | 2007-08-01 22:27:37 +0000 | [diff] [blame] | 767 | indent() << " Result, % suppress unused warnings" << endl << |
Christopher Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 768 | indent() << " ?R0(Iprot, readMessageEnd)," << endl << |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 769 | indent() << " if % time to figure out retval" << endl; |
| 770 | |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 771 | // WATCH cpiro |
| 772 | // Careful, only return _result if not a void function |
| 773 | |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 774 | // TODO(cpiro): exit or {ok, _} and {error, _} ?? |
| 775 | |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 776 | std::string result = "Result#"+resultname+"."; |
| 777 | if (!(*f_iter)->get_returntype()->is_void()) { |
| 778 | f_service_ << |
| 779 | indent() << " " << result << "success /= nil ->" << endl << |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 780 | indent() << " " << result << "success;" << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 781 | } |
| 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 Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 789 | indent() << " throw(" << result << (*x_iter)->get_name() << ");" << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 790 | } |
| 791 | |
| 792 | // Careful, only return _result if not a void function |
| 793 | if ((*f_iter)->get_returntype()->is_void()) { |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 794 | f_service_ << |
| 795 | indent() << " true -> nil" << endl << |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 796 | indent() << " end" << endl; |
| 797 | } else { |
| 798 | f_service_ << |
| 799 | indent() << " true -> " << endl << |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 800 | indent() << " throw(tApplicationException:new(?tApplicationException_MISSING_RESULT, \"" << (*f_iter)->get_name() << " failed: unknown result\"))" << endl << |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 801 | 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 | */ |
| 819 | void 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 828 | extends_processor = " INHERIT(" + extends + "::Processor) % TODO"; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 829 | } |
| 830 | |
| 831 | // Generate the header portion |
| 832 | indent(f_service_) << |
| 833 | "%% processor" << extends_processor << endl; |
| 834 | |
| 835 | indent_up(); |
| 836 | |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 837 | // TODO: inheritance runtime code (prolly) goes here: |
| 838 | |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 839 | // 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 862 | */ |
| 863 | |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 864 | export_string("process", 3); |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 865 | export_string("proc", 6); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 866 | |
| 867 | // Generate the server implementation |
| 868 | indent(f_service_) << |
| 869 | "process(HandlerModule, Iprot, Oprot) ->" << endl; |
| 870 | indent_up(); |
| 871 | |
| 872 | f_service_ << |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 873 | 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 Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 880 | |
| 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 887 | |
| 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 Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 891 | } |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 892 | |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 893 | 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 Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 909 | |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 910 | indent_down(); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 911 | |
| 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 | */ |
| 926 | void t_erl_generator::generate_process_function(t_service* tservice, |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 927 | t_function* tfunction) { |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 928 | |
| 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 Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 939 | f_service_ << |
| 940 | indent() << "Seqid, Oprot, % suppress unused warnings" << endl; |
| 941 | |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 942 | string argsname = tfunction->get_name() + "_args"; |
| 943 | string resultname = tfunction->get_name() + "_result"; |
| 944 | |
| 945 | f_service_ << |
Christopher Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 946 | 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 Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 950 | |
| 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 Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 959 | // 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 Piro | 5b3a8f7 | 2007-08-01 22:27:37 +0000 | [diff] [blame] | 964 | indent(f_service_) << "try" << endl; |
| 965 | indent_up(); |
| 966 | |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 967 | 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 Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 975 | f_service_ << indent(); |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 976 | if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) { |
| 977 | f_service_<< "Res = "; |
| 978 | } |
| 979 | f_service_ << "HandlerModule:" << tfunction->get_name() << "("; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 980 | |
| 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 Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 988 | f_service_ << "_Args#" << tfunction->get_name() << "_args." << (*f_iter)->get_name(); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 989 | } |
| 990 | f_service_ << ")," << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 991 | if (!tfunction->is_async() && !tfunction->get_returntype()->is_void()) { |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 992 | indent(f_service_) << "#" << resultname << "{success=Res}" << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 993 | } else{ |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 994 | indent(f_service_) << "#" << resultname << "{}" << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 995 | } |
| 996 | indent_down(); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 997 | if (!tfunction->is_async() && xceptions.size() > 0) { |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 998 | indent(f_service_) << "catch" << endl; |
| 999 | indent_up(); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1000 | for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) { |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1001 | indent(f_service_) << "E when is_record(E," << uncapitalize((*x_iter)->get_type()->get_name()) << ") ->" << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1002 | indent_up(); |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1003 | indent(f_service_) << "#" << resultname << "{" << (*x_iter)->get_name() << " = E};" << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1004 | indent_down(); |
| 1005 | } |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1006 | indent(f_service_) << "dummy -> dummy % TODO: only for the semicolon's sake" << endl; |
| 1007 | indent_down(); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1008 | } |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1009 | indent(f_service_) << "end," << endl; |
| 1010 | |
Christopher Piro | 5b3a8f7 | 2007-08-01 22:27:37 +0000 | [diff] [blame] | 1011 | if (!tfunction->is_async()) { |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1012 | f_service_ << |
Christopher Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 1013 | indent() << "?R3(Oprot, writeMessageBegin, \"" << tfunction->get_name() << "\", ?tMessageType_REPLY, Seqid)," << endl << |
Christopher Piro | 5b3a8f7 | 2007-08-01 22:27:37 +0000 | [diff] [blame] | 1014 | 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 Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 1044 | indent() << "Trans = ?R1(Oprot, get, trans)," << endl << |
Christopher Piro | 5b3a8f7 | 2007-08-01 22:27:37 +0000 | [diff] [blame] | 1045 | indent() << "?R0(Trans, effectful_flush)" << endl; |
| 1046 | |
| 1047 | indent_down(); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1048 | } |
| 1049 | |
Christopher Piro | 5b3a8f7 | 2007-08-01 22:27:37 +0000 | [diff] [blame] | 1050 | indent(f_service_) << "end." << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1051 | |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1052 | indent_down(); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1053 | } |
| 1054 | |
| 1055 | /** |
| 1056 | * Deserializes a field of any type. |
| 1057 | */ |
| 1058 | void t_erl_generator::generate_deserialize_field(ostream &out, |
| 1059 | t_field* tfield, |
| 1060 | string prefix, |
| 1061 | bool inclass) { |
David Reiss | e087a30 | 2007-08-23 21:43:25 +0000 | [diff] [blame] | 1062 | t_type* type = get_true_type(tfield->get_type()); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1063 | |
| 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 Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 1079 | name << " = ?R0(Iprot, "; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1080 | |
| 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 Reiss | dd7796f | 2007-08-28 21:09:06 +0000 | [diff] [blame] | 1110 | throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1111 | } |
| 1112 | } else if (type->is_enum()) { |
| 1113 | out << "readI32"; |
| 1114 | } |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1115 | out << ")," << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1116 | |
| 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1126 | void t_erl_generator::generate_deserialize_struct(ostream &out, |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1127 | t_struct* tstruct, |
| 1128 | string prefix) { |
| 1129 | out << |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1130 | indent() << prefix << " = " << (tstruct->get_program())->get_name() << "_types:" << type_name(tstruct) << "_read(Iprot)," << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1131 | } |
| 1132 | |
| 1133 | /** |
| 1134 | * Serialize a container by writing out the header followed by |
| 1135 | * data and then a footer. |
| 1136 | */ |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1137 | void t_erl_generator::generate_deserialize_container(ostream &out, |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1138 | 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 Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1152 | 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 Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1157 | |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1158 | out << |
| 1159 | indent() << "{" << ktype << ", " << vtype << ", " << size << " } = ?R0(Iprot,readMapBegin)," << endl; |
| 1160 | out << |
| 1161 | indent() << prefix << " = dict:from_list(thrift_utils:tabulate(" << size << "," << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1162 | indent_up(); |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1163 | 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 Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1168 | indent_down(); |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1169 | out << indent() << "end))," << endl; |
| 1170 | indent_down(); |
| 1171 | out << indent() << "?R0(Iprot,readMapEnd)," << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1172 | |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1173 | } else if (ttype->is_set()) { |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1174 | 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 Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1191 | } else if (ttype->is_list()) { |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1192 | 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 Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1207 | } |
| 1208 | |
| 1209 | |
| 1210 | /** |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1211 | * Generates code to deserialize a map UNUSED |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1212 | */ |
| 1213 | void 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 Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1229 | * Read a set element UNUSED |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1230 | */ |
| 1231 | void 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 Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1244 | * Read a list element UNUSED |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1245 | */ |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1246 | void t_erl_generator::generate_deserialize_list_element(ostream &out, // TODO |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1247 | 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 | */ |
| 1265 | void t_erl_generator::generate_serialize_field(ostream &out, |
| 1266 | t_field* tfield, |
| 1267 | string prefix) { |
David Reiss | e087a30 | 2007-08-23 21:43:25 +0000 | [diff] [blame] | 1268 | t_type* type = get_true_type(tfield->get_type()); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1269 | |
| 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 Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 1289 | "?R1(Oprot, "; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1290 | |
| 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 Reiss | dd7796f | 2007-08-28 21:09:06 +0000 | [diff] [blame] | 1320 | throw "compiler error: no PHP name for base type " + t_base_type::t_base_name(tbase); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1321 | } |
| 1322 | } else if (type->is_enum()) { |
| 1323 | out << "writeI32, " << name << "),"; |
| 1324 | } |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1325 | out << "" << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1326 | } 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 | */ |
| 1340 | void t_erl_generator::generate_serialize_struct(ostream &out, |
| 1341 | t_struct* tstruct, |
| 1342 | string prefix) { |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1343 | indent(out) << tstruct->get_program()->get_name() << "_types:" << uncapitalize(tstruct->get_name()) << "_write(" << prefix << ", Oprot)," << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1344 | } |
| 1345 | |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1346 | void t_erl_generator::generate_serialize_container(ostream &out, // TODO |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1347 | t_type* ttype, |
| 1348 | string prefix) { |
| 1349 | if (ttype->is_map()) { |
| 1350 | indent(out) << |
Christopher Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 1351 | "?R3(Oprot, writeMapBegin, " << |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1352 | type_to_enum(((t_map*)ttype)->get_key_type()) << ", " << |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1353 | type_to_enum(((t_map*)ttype)->get_val_type()) << ", thrift_utils:dict_size(" << |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1354 | prefix << "))," << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1355 | } else if (ttype->is_set()) { |
| 1356 | indent(out) << |
Christopher Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 1357 | "?R2(Oprot, writeSetBegin, " << |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1358 | type_to_enum(((t_set*)ttype)->get_elem_type()) << ", sets:size(" << |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1359 | prefix << "))," << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1360 | } else if (ttype->is_list()) { |
| 1361 | indent(out) << |
Christopher Piro | 094823a | 2007-07-18 00:26:12 +0000 | [diff] [blame] | 1362 | "?R2(Oprot, writeListBegin, " << |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1363 | type_to_enum(((t_list*)ttype)->get_elem_type()) << ", length(" << |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1364 | prefix << "))," << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1365 | } |
| 1366 | |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1367 | if (ttype->is_map()) { |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1368 | string kiter = tmp("_kiter"); |
| 1369 | string viter = tmp("_viter"); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1370 | indent(out) << |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1371 | "dict:fold(fun ("<< kiter << ", " << viter << ",_)->" << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1372 | indent_up(); |
| 1373 | generate_serialize_map_element(out, (t_map*)ttype, kiter, viter); |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1374 | indent(out) << "nil" << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1375 | indent_down(); |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1376 | indent(out) << "end, nil," << prefix << ")," << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1377 | } else if (ttype->is_set()) { |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1378 | string iter = tmp("_iter"); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1379 | indent(out) << |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1380 | "sets:fold(fun ("<< iter << ",_)->" << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1381 | indent_up(); |
| 1382 | generate_serialize_set_element(out, (t_set*)ttype, iter); |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1383 | indent(out) << "nil" << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1384 | indent_down(); |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1385 | indent(out) << "end, nil," << prefix << ")," << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1386 | } else if (ttype->is_list()) { |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1387 | string iter = tmp("_iter"); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1388 | indent(out) << |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1389 | "lists:foldl(fun (" << iter << ",_)->" << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1390 | indent_up(); |
| 1391 | generate_serialize_list_element(out, (t_list*)ttype, iter); |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1392 | indent(out) << "nil" << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1393 | indent_down(); |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1394 | indent(out) << "end,nil," << prefix << ")," << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1395 | } |
| 1396 | |
| 1397 | if (ttype->is_map()) { |
| 1398 | indent(out) << |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1399 | "?R0(Oprot, writeMapEnd)," << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1400 | } else if (ttype->is_set()) { |
| 1401 | indent(out) << |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1402 | "?R0(Oprot, writeSetEnd)," << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1403 | } else if (ttype->is_list()) { |
| 1404 | indent(out) << |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1405 | "?R0(Oprot, writeListEnd)," << endl; |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1406 | } |
| 1407 | } |
| 1408 | |
| 1409 | /** |
| 1410 | * Serializes the members of a map. |
| 1411 | * |
| 1412 | */ |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1413 | void t_erl_generator::generate_serialize_map_element(ostream &out, |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1414 | 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1427 | void t_erl_generator::generate_serialize_set_element(ostream &out, |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1428 | 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1437 | void t_erl_generator::generate_serialize_list_element(ostream &out, |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1438 | 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 | */ |
| 1449 | string t_erl_generator::declare_field(t_field* tfield) { // TODO |
| 1450 | string result = "@" + tfield->get_name(); |
David Reiss | e087a30 | 2007-08-23 21:43:25 +0000 | [diff] [blame] | 1451 | t_type* type = get_true_type(tfield->get_type()); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1452 | 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 | */ |
| 1466 | string t_erl_generator::function_signature(t_function* tfunction, |
| 1467 | string prefix) { |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1468 | return |
| 1469 | prefix + tfunction->get_name() + |
| 1470 | "(This" + capitalize(argument_list(tfunction->get_arglist())) + ")"; |
| 1471 | } |
| 1472 | |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1473 | /** |
| 1474 | * Add a function to the exports list |
| 1475 | */ |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1476 | void t_erl_generator::export_string(string name, int num) { |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1477 | if (export_lines_first_) { |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1478 | export_lines_first_ = false; |
| 1479 | } else { |
| 1480 | export_lines_ << ", "; |
| 1481 | } |
| 1482 | export_lines_ << name << "/" << num; |
| 1483 | } |
| 1484 | |
| 1485 | void 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1493 | |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1494 | void t_erl_generator::export_types_string(string name, int num) { |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1495 | if (export_types_lines_first_) { |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1496 | export_types_lines_first_ = false; |
| 1497 | } else { |
| 1498 | export_types_lines_ << ", "; |
| 1499 | } |
| 1500 | export_types_lines_ << name << "/" << num; |
| 1501 | } |
| 1502 | |
| 1503 | void 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1516 | string t_erl_generator::argument_list(t_struct* tstruct) { |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1517 | 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 Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1525 | result += ", "; // initial comma to compensate for initial This |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1526 | } else { |
| 1527 | result += ", "; |
| 1528 | } |
| 1529 | result += capitalize((*f_iter)->get_name()); |
| 1530 | } |
| 1531 | return result; |
| 1532 | } |
| 1533 | |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1534 | string t_erl_generator::type_name(t_type* ttype) { |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1535 | string prefix = ""; |
| 1536 | t_program* program = ttype->get_program(); |
| 1537 | if (program != NULL && program != program_) { |
| 1538 | if (!ttype->is_service()) { |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1539 | prefix = program->get_name() + "_types."; // TODO |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1540 | } |
| 1541 | } |
| 1542 | |
| 1543 | string name = ttype->get_name(); |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1544 | |
Christopher Piro | 5f5fdf3 | 2007-07-25 22:41:00 +0000 | [diff] [blame] | 1545 | if (ttype->is_struct() || ttype->is_xception() || ttype->is_service()) { |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1546 | name = uncapitalize(ttype->get_name()); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1547 | } |
| 1548 | |
| 1549 | return prefix + name; |
| 1550 | } |
| 1551 | |
| 1552 | /** |
Christopher Piro | ae1f10f | 2007-07-24 04:30:15 +0000 | [diff] [blame] | 1553 | * Converts the parse type to a Erlang "type" (macro for int constants) |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1554 | */ |
| 1555 | string t_erl_generator::type_to_enum(t_type* type) { |
David Reiss | e087a30 | 2007-08-23 21:43:25 +0000 | [diff] [blame] | 1556 | type = get_true_type(type); |
Christopher Piro | 2f5afce | 2007-06-29 07:17:33 +0000 | [diff] [blame] | 1557 | |
| 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 | } |