1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 * 19 * Contains some contributions under the Thrift Software License. 20 * Please see doc/old-thrift-license.txt in the Thrift distribution for 21 * details. 22 */ 23 24 #include <cassert> 25 26 #include <fstream> 27 #include <iostream> 28 #include <set> 29 #include <sstream> 30 #include <string> 31 #include <vector> 32 33 #include <sys/stat.h> 34 35 #include "thrift/platform.h" 36 #include "thrift/generate/t_oop_generator.h" 37 38 using std::map; 39 using std::ofstream; 40 using std::ostream; 41 using std::ostringstream; 42 using std::set; 43 using std::string; 44 using std::vector; 45 46 static const string endl = "\n"; // avoid ostream << std::endl flushes 47 48 /** 49 * D code generator. 50 * 51 * generate_*() functions are called by the base class to emit code for the 52 * given entity, print_*() functions write a piece of code to the passed 53 * stream, and render_*() return a string containing the D representation of 54 * the passed entity. 55 */ 56 class t_d_generator : public t_oop_generator { 57 public: t_d_generator(t_program * program,const std::map<string,string> & parsed_options,const string & option_string)58 t_d_generator(t_program* program, 59 const std::map<string, string>& parsed_options, 60 const string& option_string) 61 : t_oop_generator(program) { 62 (void)option_string; 63 std::map<std::string, std::string>::const_iterator iter; 64 65 /* no options yet */ 66 for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) { 67 throw "unknown option d:" + iter->first; 68 } 69 70 out_dir_base_ = "gen-d"; 71 } 72 73 protected: 74 75 // D reserved words are suffixed with an underscore suffix_if_reserved(const string & name)76 static string suffix_if_reserved(const string& name) { 77 const bool isIn = std::binary_search(std::begin(d_reserved_words), std::end(d_reserved_words), name); 78 string ret = isIn ? name + "_" : name; 79 return ret; 80 } 81 init_generator()82 void init_generator() override { 83 // Make output directory 84 MKDIR(get_out_dir().c_str()); 85 86 string dir = program_->get_namespace("d"); 87 string subdir = get_out_dir(); 88 string::size_type loc; 89 while ((loc = dir.find(".")) != string::npos) { 90 subdir = subdir + "/" + dir.substr(0, loc); 91 MKDIR(subdir.c_str()); 92 dir = dir.substr(loc + 1); 93 } 94 if (!dir.empty()) { 95 subdir = subdir + "/" + dir; 96 MKDIR(subdir.c_str()); 97 } 98 99 package_dir_ = subdir + "/"; 100 101 // Make output file 102 string f_types_name = package_dir_ + program_name_ + "_types.d"; 103 f_types_.open(f_types_name.c_str()); 104 105 // Print header 106 f_types_ << autogen_comment() << "module " << render_package(*program_) << program_name_ 107 << "_types;" << endl << endl; 108 109 print_default_imports(f_types_); 110 111 // Include type modules from other imported programs. 112 const vector<t_program*>& includes = program_->get_includes(); 113 for (auto include : includes) { 114 f_types_ << "public import " << render_package(*include) << include->get_name() 115 << "_types;" << endl; 116 } 117 if (!includes.empty()) 118 f_types_ << endl; 119 } 120 close_generator()121 void close_generator() override { 122 // Close output file 123 f_types_.close(); 124 } 125 generate_consts(std::vector<t_const * > consts)126 void generate_consts(std::vector<t_const*> consts) override { 127 if (!consts.empty()) { 128 string f_consts_name = package_dir_ + program_name_ + "_constants.d"; 129 ofstream_with_content_based_conditional_update f_consts; 130 f_consts.open(f_consts_name.c_str()); 131 132 f_consts << autogen_comment() << "module " << render_package(*program_) << program_name_ 133 << "_constants;" << endl << endl; 134 135 print_default_imports(f_consts); 136 137 f_consts << "import " << render_package(*get_program()) << program_name_ << "_types;" << endl 138 << endl; 139 140 vector<t_const*>::iterator c_iter; 141 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { 142 this->emit_doc(*c_iter, f_consts); 143 string name = suffix_if_reserved((*c_iter)->get_name()); 144 t_type* type = (*c_iter)->get_type(); 145 indent(f_consts) << "immutable(" << render_type_name(type) << ") " << name << ";" << endl; 146 } 147 148 f_consts << endl << "shared static this() {" << endl; 149 indent_up(); 150 151 bool first = true; 152 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) { 153 if (first) { 154 first = false; 155 } else { 156 f_consts << endl; 157 } 158 t_type* type = (*c_iter)->get_type(); 159 indent(f_consts) << suffix_if_reserved((*c_iter)->get_name()) << " = "; 160 if (!is_immutable_type(type)) { 161 f_consts << "cast(immutable(" << render_type_name(type) << ")) "; 162 } 163 f_consts << render_const_value(type, (*c_iter)->get_value()) << ";" << endl; 164 } 165 indent_down(); 166 indent(f_consts) << "}" << endl; 167 } 168 } 169 generate_typedef(t_typedef * ttypedef)170 void generate_typedef(t_typedef* ttypedef) override { 171 this->emit_doc(ttypedef, f_types_); 172 f_types_ << indent() << "alias " << render_type_name(ttypedef->get_type()) << " " 173 << ttypedef->get_symbolic() << ";" << endl << endl; 174 } 175 generate_enum(t_enum * tenum)176 void generate_enum(t_enum* tenum) override { 177 vector<t_enum_value*> constants = tenum->get_constants(); 178 179 this->emit_doc(tenum, f_types_); 180 string enum_name = suffix_if_reserved(tenum->get_name()); 181 f_types_ << indent() << "enum " << enum_name << " {" << endl; 182 183 indent_up(); 184 185 vector<t_enum_value*>::const_iterator c_iter; 186 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) { 187 this->emit_doc(*c_iter, f_types_); 188 indent(f_types_) << suffix_if_reserved((*c_iter)->get_name()); 189 f_types_ << " = " << (*c_iter)->get_value() << ","; 190 } 191 192 f_types_ << endl; 193 indent_down(); 194 indent(f_types_) << "}" << endl; 195 196 f_types_ << endl; 197 } 198 generate_struct(t_struct * tstruct)199 void generate_struct(t_struct* tstruct) override { 200 print_struct_definition(f_types_, tstruct, false); 201 } 202 generate_xception(t_struct * txception)203 void generate_xception(t_struct* txception) override { 204 print_struct_definition(f_types_, txception, true); 205 } 206 generate_service(t_service * tservice)207 void generate_service(t_service* tservice) override { 208 string svc_name = suffix_if_reserved(tservice->get_name()); 209 210 // Service implementation file includes 211 string f_servicename = package_dir_ + svc_name + ".d"; 212 ofstream_with_content_based_conditional_update f_service; 213 f_service.open(f_servicename.c_str()); 214 f_service << autogen_comment() << "module " << suffix_if_reserved(render_package(*program_)) << svc_name << ";" 215 << endl << endl; 216 217 print_default_imports(f_service); 218 219 f_service << "import " << suffix_if_reserved(render_package(*get_program())) << program_name_ << "_types;" << endl; 220 221 t_service* extends_service = tservice->get_extends(); 222 if (extends_service != NULL) { 223 f_service << "import " << suffix_if_reserved(render_package(*(extends_service->get_program()))) 224 << suffix_if_reserved(extends_service->get_name()) << ";" << endl; 225 } 226 227 f_service << endl; 228 229 string extends = ""; 230 if (tservice->get_extends() != NULL) { 231 extends = " : " + suffix_if_reserved(render_type_name(tservice->get_extends())); 232 } 233 234 this->emit_doc(tservice, f_service); 235 f_service << indent() << "interface " << svc_name << extends << " {" << endl; 236 indent_up(); 237 238 // Collect all the exception types service methods can throw so we can 239 // emit the necessary aliases later. 240 set<t_type*> exception_types; 241 242 // Print the method signatures. 243 vector<t_function*> functions = tservice->get_functions(); 244 vector<t_function*>::iterator fn_iter; 245 for (fn_iter = functions.begin(); fn_iter != functions.end(); ++fn_iter) { 246 this->emit_doc(*fn_iter, f_service); 247 f_service << indent(); 248 print_function_signature(f_service, *fn_iter); 249 f_service << ";" << endl; 250 251 const vector<t_field*>& exceptions = (*fn_iter)->get_xceptions()->get_members(); 252 vector<t_field*>::const_iterator ex_iter; 253 for (ex_iter = exceptions.begin(); ex_iter != exceptions.end(); ++ex_iter) { 254 exception_types.insert((*ex_iter)->get_type()); 255 } 256 } 257 258 // Alias the exception types into the current scope. 259 if (!exception_types.empty()) 260 f_service << endl; 261 set<t_type*>::const_iterator et_iter; 262 for (et_iter = exception_types.begin(); et_iter != exception_types.end(); ++et_iter) { 263 indent(f_service) << "alias " << render_package(*(*et_iter)->get_program()) 264 << (*et_iter)->get_program()->get_name() << "_types" 265 << "." << (*et_iter)->get_name() << " " << (*et_iter)->get_name() << ";" 266 << endl; 267 } 268 269 // Write the method metadata. 270 ostringstream meta; 271 indent_up(); 272 bool first = true; 273 for (fn_iter = functions.begin(); fn_iter != functions.end(); ++fn_iter) { 274 if ((*fn_iter)->get_arglist()->get_members().empty() 275 && (*fn_iter)->get_xceptions()->get_members().empty() && !(*fn_iter)->is_oneway()) { 276 continue; 277 } 278 279 if (first) { 280 first = false; 281 } else { 282 meta << ","; 283 } 284 285 meta << endl << indent() << "TMethodMeta(`" << suffix_if_reserved((*fn_iter)->get_name()) << "`, " << endl; 286 indent_up(); 287 indent(meta) << "["; 288 289 bool first = true; 290 const vector<t_field*>& params = (*fn_iter)->get_arglist()->get_members(); 291 vector<t_field*>::const_iterator p_iter; 292 for (p_iter = params.begin(); p_iter != params.end(); ++p_iter) { 293 if (first) { 294 first = false; 295 } else { 296 meta << ", "; 297 } 298 299 meta << "TParamMeta(`" << suffix_if_reserved((*p_iter)->get_name()) << "`, " << (*p_iter)->get_key(); 300 301 t_const_value* cv = (*p_iter)->get_value(); 302 if (cv != NULL) { 303 meta << ", q{" << render_const_value((*p_iter)->get_type(), cv) << "}"; 304 } 305 meta << ")"; 306 } 307 308 meta << "]"; 309 310 if (!(*fn_iter)->get_xceptions()->get_members().empty() || (*fn_iter)->is_oneway()) { 311 meta << "," << endl << indent() << "["; 312 313 bool first = true; 314 const vector<t_field*>& exceptions = (*fn_iter)->get_xceptions()->get_members(); 315 vector<t_field*>::const_iterator ex_iter; 316 for (ex_iter = exceptions.begin(); ex_iter != exceptions.end(); ++ex_iter) { 317 if (first) { 318 first = false; 319 } else { 320 meta << ", "; 321 } 322 323 meta << "TExceptionMeta(`" << suffix_if_reserved((*ex_iter)->get_name()) << "`, " 324 << (*ex_iter)->get_key() << ", `" << (*ex_iter)->get_type()->get_name() << "`)"; 325 } 326 327 meta << "]"; 328 } 329 330 if ((*fn_iter)->is_oneway()) { 331 meta << "," << endl << indent() << "TMethodType.ONEWAY"; 332 } 333 334 indent_down(); 335 meta << endl << indent() << ")"; 336 } 337 indent_down(); 338 339 string meta_str(meta.str()); 340 if (!meta_str.empty()) { 341 f_service << endl << indent() << "enum methodMeta = [" << meta_str << endl << indent() << "];" 342 << endl; 343 } 344 345 indent_down(); 346 indent(f_service) << "}" << endl; 347 348 // Server skeleton generation. 349 string f_skeletonname = package_dir_ + svc_name + "_server.skeleton.d"; 350 ofstream_with_content_based_conditional_update f_skeleton; 351 f_skeleton.open(f_skeletonname.c_str()); 352 print_server_skeleton(f_skeleton, tservice); 353 f_skeleton.close(); 354 } 355 emit_doc(t_doc * doc,std::ostream & out)356 void emit_doc(t_doc *doc, std::ostream& out) { 357 if (!doc->has_doc()) { 358 return; 359 } 360 indent(out) << "/**" << std::endl; 361 indent_up(); 362 // No endl -- comments reliably have a newline at the end. 363 // This is true even for stuff like: 364 // /** method infos */ void foo(/** huh?*/ 1: i64 stuff) 365 indent(out) << doc->get_doc(); 366 indent_down(); 367 indent(out) << "*/" << std::endl; 368 } 369 370 private: 371 /** 372 * Writes a server skeleton for the passed service to out. 373 */ print_server_skeleton(ostream & out,t_service * tservice)374 void print_server_skeleton(ostream& out, t_service* tservice) { 375 string svc_name = suffix_if_reserved(tservice->get_name()); 376 377 out << "/*" << endl 378 << " * This auto-generated skeleton file illustrates how to build a server. If you" << endl 379 << " * intend to customize it, you should edit a copy with another file name to " << endl 380 << " * avoid overwriting it when running the generator again." << endl << " */" << endl 381 << "module " << render_package(*tservice->get_program()) << svc_name << "_server;" << endl 382 << endl << "import std.stdio;" << endl << "import thrift.codegen.processor;" << endl 383 << "import thrift.protocol.binary;" << endl << "import thrift.server.simple;" << endl 384 << "import thrift.server.transport.socket;" << endl << "import thrift.transport.buffered;" 385 << endl << "import thrift.util.hashset;" << endl << endl << "import " 386 << render_package(*tservice->get_program()) << svc_name << ";" << endl << "import " 387 << render_package(*get_program()) << program_name_ << "_types;" << endl << endl << endl 388 << "class " << svc_name << "Handler : " << svc_name << " {" << endl; 389 390 indent_up(); 391 out << indent() << "this() {" << endl << indent() << " // Your initialization goes here." 392 << endl << indent() << "}" << endl << endl; 393 394 vector<t_function*> functions = tservice->get_functions(); 395 vector<t_function*>::iterator f_iter; 396 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) { 397 out << indent(); 398 print_function_signature(out, *f_iter); 399 out << " {" << endl; 400 401 indent_up(); 402 403 out << indent() << "// Your implementation goes here." << endl << indent() << "writeln(\"" 404 << suffix_if_reserved((*f_iter)->get_name()) << " called\");" << endl; 405 406 t_type* rt = (*f_iter)->get_returntype(); 407 if (!rt->is_void()) { 408 indent(out) << "return typeof(return).init;" << endl; 409 } 410 411 indent_down(); 412 413 out << indent() << "}" << endl << endl; 414 } 415 416 indent_down(); 417 out << "}" << endl << endl; 418 419 out << indent() << "void main() {" << endl; 420 indent_up(); 421 out << indent() << "auto protocolFactory = new TBinaryProtocolFactory!();" << endl << indent() 422 << "auto processor = new TServiceProcessor!" << svc_name << "(new " << svc_name 423 << "Handler);" << endl << indent() << "auto serverTransport = new TServerSocket(9090);" 424 << endl << indent() << "auto transportFactory = new TBufferedTransportFactory;" << endl 425 << indent() << "auto server = new TSimpleServer(" << endl << indent() 426 << " processor, serverTransport, transportFactory, protocolFactory);" << endl << indent() 427 << "server.serve();" << endl; 428 indent_down(); 429 out << "}" << endl; 430 } 431 432 /** 433 * Writes the definition of a struct or an exception type to out. 434 */ print_struct_definition(ostream & out,t_struct * tstruct,bool is_exception)435 void print_struct_definition(ostream& out, t_struct* tstruct, bool is_exception) { 436 const vector<t_field*>& members = tstruct->get_members(); 437 438 if (is_exception) { 439 indent(out) << "class " << suffix_if_reserved(tstruct->get_name()) << " : TException {" << endl; 440 } else { 441 indent(out) << "struct " << suffix_if_reserved(tstruct->get_name()) << " {" << endl; 442 } 443 indent_up(); 444 445 // Declare all fields. 446 vector<t_field*>::const_iterator m_iter; 447 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { 448 indent(out) << render_type_name((*m_iter)->get_type()) << " " << suffix_if_reserved((*m_iter)->get_name()) << ";" 449 << endl; 450 } 451 452 if (!members.empty()) 453 indent(out) << endl; 454 indent(out) << "mixin TStructHelpers!("; 455 456 if (!members.empty()) { 457 // If there are any fields, construct the TFieldMeta array to pass to 458 // TStructHelpers. We can't just pass an empty array if not because [] 459 // doesn't pass the TFieldMeta[] constraint. 460 out << "["; 461 indent_up(); 462 463 bool first = true; 464 vector<t_field*>::const_iterator m_iter; 465 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) { 466 if (first) { 467 first = false; 468 } else { 469 out << ","; 470 } 471 out << endl; 472 473 indent(out) << "TFieldMeta(`" << suffix_if_reserved((*m_iter)->get_name()) << "`, " << (*m_iter)->get_key(); 474 475 t_const_value* cv = (*m_iter)->get_value(); 476 t_field::e_req req = (*m_iter)->get_req(); 477 out << ", " << render_req(req); 478 if (cv != NULL) { 479 out << ", q{" << render_const_value((*m_iter)->get_type(), cv) << "}"; 480 } 481 out << ")"; 482 } 483 484 indent_down(); 485 out << endl << indent() << "]"; 486 } 487 488 out << ");" << endl; 489 490 indent_down(); 491 indent(out) << "}" << endl << endl; 492 } 493 494 /** 495 * Prints the D function signature (including return type) for the given 496 * method. 497 */ print_function_signature(ostream & out,t_function * fn)498 void print_function_signature(ostream& out, t_function* fn) { 499 out << render_type_name(fn->get_returntype()) << " " << suffix_if_reserved(fn->get_name()) << "("; 500 501 const vector<t_field*>& fields = fn->get_arglist()->get_members(); 502 vector<t_field*>::const_iterator f_iter; 503 bool first = true; 504 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { 505 if (first) { 506 first = false; 507 } else { 508 out << ", "; 509 } 510 out << render_type_name((*f_iter)->get_type(), true) << " " << suffix_if_reserved((*f_iter)->get_name()); 511 } 512 513 out << ")"; 514 } 515 516 /** 517 * Returns the D representation of value. The result is guaranteed to be a 518 * single expression; for complex types, immediately called delegate 519 * literals are used to achieve this. 520 */ render_const_value(t_type * type,t_const_value * value)521 string render_const_value(t_type* type, t_const_value* value) { 522 // Resolve any typedefs. 523 type = get_true_type(type); 524 525 ostringstream out; 526 if (type->is_base_type()) { 527 t_base_type::t_base tbase = ((t_base_type*)type)->get_base(); 528 switch (tbase) { 529 case t_base_type::TYPE_STRING: 530 out << '"' << get_escaped_string(value) << '"'; 531 break; 532 case t_base_type::TYPE_BOOL: 533 out << ((value->get_integer() > 0) ? "true" : "false"); 534 break; 535 case t_base_type::TYPE_I8: 536 case t_base_type::TYPE_I16: 537 out << "cast(" << render_type_name(type) << ")" << value->get_integer(); 538 break; 539 case t_base_type::TYPE_I32: 540 out << value->get_integer(); 541 break; 542 case t_base_type::TYPE_I64: 543 out << value->get_integer() << "L"; 544 break; 545 case t_base_type::TYPE_DOUBLE: 546 if (value->get_type() == t_const_value::CV_INTEGER) { 547 out << value->get_integer(); 548 } else { 549 out << value->get_double(); 550 } 551 break; 552 default: 553 throw "Compiler error: No const of base type " + t_base_type::t_base_name(tbase); 554 } 555 } else if (type->is_enum()) { 556 out << "cast(" << render_type_name(type) << ")" << value->get_integer(); 557 } else { 558 out << "{" << endl; 559 indent_up(); 560 561 indent(out) << render_type_name(type) << " v;" << endl; 562 if (type->is_struct() || type->is_xception()) { 563 indent(out) << "v = " << (type->is_xception() ? "new " : "") << render_type_name(type) 564 << "();" << endl; 565 566 const vector<t_field*>& fields = ((t_struct*)type)->get_members(); 567 vector<t_field*>::const_iterator f_iter; 568 const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map(); 569 map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter; 570 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { 571 t_type* field_type = NULL; 572 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) { 573 if ((*f_iter)->get_name() == v_iter->first->get_string()) { 574 field_type = (*f_iter)->get_type(); 575 } 576 } 577 if (field_type == NULL) { 578 throw "Type error: " + type->get_name() + " has no field " 579 + v_iter->first->get_string(); 580 } 581 string val = render_const_value(field_type, v_iter->second); 582 indent(out) << "v.set!`" << v_iter->first->get_string() << "`(" << val << ");" << endl; 583 } 584 } else if (type->is_map()) { 585 t_type* ktype = ((t_map*)type)->get_key_type(); 586 t_type* vtype = ((t_map*)type)->get_val_type(); 587 const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map(); 588 map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter; 589 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { 590 string key = render_const_value(ktype, v_iter->first); 591 string val = render_const_value(vtype, v_iter->second); 592 indent(out) << "v["; 593 if (!is_immutable_type(ktype)) { 594 out << "cast(immutable(" << render_type_name(ktype) << "))"; 595 } 596 out << key << "] = " << val << ";" << endl; 597 } 598 } else if (type->is_list()) { 599 t_type* etype = ((t_list*)type)->get_elem_type(); 600 const vector<t_const_value*>& val = value->get_list(); 601 vector<t_const_value*>::const_iterator v_iter; 602 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { 603 string val = render_const_value(etype, *v_iter); 604 indent(out) << "v ~= " << val << ";" << endl; 605 } 606 } else if (type->is_set()) { 607 t_type* etype = ((t_set*)type)->get_elem_type(); 608 const vector<t_const_value*>& val = value->get_list(); 609 vector<t_const_value*>::const_iterator v_iter; 610 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) { 611 string val = render_const_value(etype, *v_iter); 612 indent(out) << "v ~= " << val << ";" << endl; 613 } 614 } else { 615 throw "Compiler error: Invalid type in render_const_value: " + type->get_name(); 616 } 617 indent(out) << "return v;" << endl; 618 619 indent_down(); 620 indent(out) << "}()"; 621 } 622 623 return out.str(); 624 } 625 626 /** 627 * Returns the D package to which modules for program are written (with a 628 * trailing dot, if not empty). 629 */ render_package(const t_program & program) const630 string render_package(const t_program& program) const { 631 string package = program.get_namespace("d"); 632 if (package.size() == 0) 633 return ""; 634 return package + "."; 635 } 636 637 /** 638 * Returns the name of the D repesentation of ttype. 639 * 640 * If isArg is true, a const reference to the type will be returned for 641 * structs. 642 */ render_type_name(const t_type * ttype,bool isArg=false) const643 string render_type_name(const t_type* ttype, bool isArg = false) const { 644 if (ttype->is_base_type()) { 645 t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base(); 646 switch (tbase) { 647 case t_base_type::TYPE_VOID: 648 return "void"; 649 case t_base_type::TYPE_STRING: 650 return "string"; 651 case t_base_type::TYPE_BOOL: 652 return "bool"; 653 case t_base_type::TYPE_I8: 654 return "byte"; 655 case t_base_type::TYPE_I16: 656 return "short"; 657 case t_base_type::TYPE_I32: 658 return "int"; 659 case t_base_type::TYPE_I64: 660 return "long"; 661 case t_base_type::TYPE_DOUBLE: 662 return "double"; 663 default: 664 throw "Compiler error: No D type name for base type " + t_base_type::t_base_name(tbase); 665 } 666 } 667 668 if (ttype->is_container()) { 669 t_container* tcontainer = (t_container*)ttype; 670 if (tcontainer->has_cpp_name()) { 671 return tcontainer->get_cpp_name(); 672 } else if (ttype->is_map()) { 673 t_map* tmap = (t_map*)ttype; 674 t_type* ktype = tmap->get_key_type(); 675 676 string name = render_type_name(tmap->get_val_type()) + "["; 677 if (!is_immutable_type(ktype)) { 678 name += "immutable("; 679 } 680 name += render_type_name(ktype); 681 if (!is_immutable_type(ktype)) { 682 name += ")"; 683 } 684 name += "]"; 685 return name; 686 } else if (ttype->is_set()) { 687 t_set* tset = (t_set*)ttype; 688 return "HashSet!(" + render_type_name(tset->get_elem_type()) + ")"; 689 } else if (ttype->is_list()) { 690 t_list* tlist = (t_list*)ttype; 691 return render_type_name(tlist->get_elem_type()) + "[]"; 692 } 693 } 694 695 if (ttype->is_struct() && isArg) { 696 return "ref const(" + ttype->get_name() + ")"; 697 } else { 698 return ttype->get_name(); 699 } 700 } 701 702 /** 703 * Returns the D TReq enum member corresponding to req. 704 */ render_req(t_field::e_req req) const705 string render_req(t_field::e_req req) const { 706 switch (req) { 707 case t_field::T_OPT_IN_REQ_OUT: 708 return "TReq.OPT_IN_REQ_OUT"; 709 case t_field::T_OPTIONAL: 710 return "TReq.OPTIONAL"; 711 case t_field::T_REQUIRED: 712 return "TReq.REQUIRED"; 713 default: { 714 std::stringstream ss; 715 ss << "Compiler error: Invalid requirement level " << req; 716 throw ss.str(); 717 } 718 } 719 } 720 721 /** 722 * Writes the default list of imports (which are written to every generated 723 * module) to f. 724 */ print_default_imports(ostream & out)725 void print_default_imports(ostream& out) { 726 indent(out) << "import thrift.base;" << endl << "import thrift.codegen.base;" << endl 727 << "import thrift.util.hashset;" << endl << endl; 728 } 729 730 /** 731 * Returns whether type is »intrinsically immutable«, in the sense that 732 * a value of that type is implicitly castable to immutable(type), and it is 733 * allowed for AA keys without an immutable() qualifier. 734 */ is_immutable_type(t_type * type) const735 bool is_immutable_type(t_type* type) const { 736 t_type* ttype = get_true_type(type); 737 return ttype->is_base_type() || ttype->is_enum(); 738 } 739 740 /* 741 * File streams, stored here to avoid passing them as parameters to every 742 * function. 743 */ 744 ofstream_with_content_based_conditional_update f_types_; 745 ofstream_with_content_based_conditional_update f_header_; 746 747 string package_dir_; 748 749 protected: 750 static vector<string> d_reserved_words; 751 752 }; 753 754 vector<string> t_d_generator::d_reserved_words = { 755 // The keywords are extracted from https://dlang.org/spec/lex.html 756 // and sorted for use with std::binary_search 757 "__FILE_FULL_PATH__", "__FILE__", "__FUNCTION__", "__LINE__", "__MODULE__", 758 "__PRETTY_FUNCTION__", "__gshared", "__parameters", "__traits", "__vector", 759 "abstract", "alias", "align", "asm", "assert", "auto", "body", "bool", 760 "break", "byte", "case", "cast", "catch", "cdouble", "cent", "cfloat", 761 "char", "class", "const", "continue", "creal", "dchar", "debug", "default", 762 "delegate", "delete", "deprecated", "do", "double", "else", "enum", 763 "export", "extern", "false", "final", "finally", "float", "for", "foreach", 764 "foreach_reverse", "function", "goto", "idouble", "if", "ifloat", "immutable", 765 "import", "in", "inout", "int", "interface", "invariant", "ireal", "is", 766 "lazy", "long", "macro ", "mixin", "module", "new", "nothrow", "null", "out", 767 "override", "package", "pragma", "private", "protected", "public", "pure", 768 "real", "ref", "return", "scope", "shared", "short", "static", "struct", 769 "super", "switch", "synchronized", "template", "this", "throw", "true", "try", 770 "typeid", "typeof", "ubyte", "ucent", "uint", "ulong", "union", "unittest", 771 "ushort", "version", "void", "wchar", "while", "with" 772 }; 773 774 THRIFT_REGISTER_GENERATOR(d, "D", "") 775