]> git.proxmox.com Git - ceph.git/blame - ceph/src/jaegertracing/thrift/compiler/cpp/src/thrift/generate/t_d_generator.cc
buildsys: switch source download to quincy
[ceph.git] / ceph / src / jaegertracing / thrift / compiler / cpp / src / thrift / generate / t_d_generator.cc
CommitLineData
f67539c2
TL
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
38using std::map;
39using std::ofstream;
40using std::ostream;
41using std::ostringstream;
42using std::set;
43using std::string;
44using std::vector;
45
46static 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 */
56class t_d_generator : public t_oop_generator {
57public:
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
73protected:
74
75 // D reserved words are suffixed with an underscore
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
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
121 void close_generator() override {
122 // Close output file
123 f_types_.close();
124 }
125
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
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
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
199 void generate_struct(t_struct* tstruct) override {
200 print_struct_definition(f_types_, tstruct, false);
201 }
202
203 void generate_xception(t_struct* txception) override {
204 print_struct_definition(f_types_, txception, true);
205 }
206
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
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
370private:
371 /**
372 * Writes a server skeleton for the passed service to out.
373 */
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 */
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 */
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 */
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 */
630 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 */
643 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 */
705 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 */
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 */
735 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
754vector<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
774THRIFT_REGISTER_GENERATOR(d, "D", "")