]> git.proxmox.com Git - ceph.git/blob - ceph/src/jaegertracing/thrift/compiler/cpp/src/thrift/generate/t_json_generator.cc
buildsys: switch source download to quincy
[ceph.git] / ceph / src / jaegertracing / thrift / compiler / cpp / src / thrift / generate / t_json_generator.cc
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 <fstream>
25 #include <iostream>
26 #include <sstream>
27 #include <limits>
28
29 #include <stdlib.h>
30 #include <sys/stat.h>
31 #include <sstream>
32
33 #include "thrift/platform.h"
34 #include "thrift/generate/t_generator.h"
35
36 using std::map;
37 using std::ofstream;
38 using std::ostream;
39 using std::ostringstream;
40 using std::string;
41 using std::stringstream;
42 using std::vector;
43 using std::stack;
44
45 static const string endl = "\n";
46 static const string quot = "\"";
47 static const bool NO_INDENT = false;
48 static const bool FORCE_STRING = true;
49
50 class t_json_generator : public t_generator {
51 public:
52 t_json_generator(t_program* program,
53 const std::map<std::string, std::string>& parsed_options,
54 const std::string& option_string)
55 : t_generator(program) {
56 (void)option_string;
57 std::map<std::string, std::string>::const_iterator iter;
58
59 should_merge_includes_ = false;
60 for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
61 if( iter->first.compare("merge") == 0) {
62 should_merge_includes_ = true;
63 } else {
64 throw "unknown option json:" + iter->first;
65 }
66 }
67
68 out_dir_base_ = "gen-json";
69 }
70
71 ~t_json_generator() override = default;
72
73 /**
74 * Init and close methods
75 */
76
77 void init_generator() override;
78 void close_generator() override;
79
80 void generate_typedef(t_typedef* ttypedef) override;
81 void generate_enum(t_enum* tenum) override;
82 void generate_program() override;
83 void generate_function(t_function* tfunc);
84 void generate_field(t_field* field);
85
86 void generate_service(t_service* tservice) override;
87 void generate_struct(t_struct* tstruct) override;
88
89 private:
90 bool should_merge_includes_;
91
92 ofstream_with_content_based_conditional_update f_json_;
93 std::stack<bool> comma_needed_;
94
95 template <typename T>
96 string number_to_string(T t) {
97 std::ostringstream out;
98 out.imbue(std::locale::classic());
99 out.precision(std::numeric_limits<T>::digits10);
100 out << t;
101 return out.str();
102 }
103
104 template <typename T>
105 void write_number(T n) {
106 f_json_ << number_to_string(n);
107 }
108
109 string get_type_name(t_type* ttype);
110 string get_qualified_name(t_type* ttype);
111
112 void start_object(bool should_indent = true);
113 void start_array();
114 void end_object();
115 void end_array();
116 void write_comma_if_needed();
117 void indicate_comma_needed();
118 string escape_json_string(const string& input);
119 string json_str(const string& str);
120 void merge_includes(t_program*);
121
122 void generate_constant(t_const* con);
123
124 void write_type_spec_entry(const char* name, t_type* ttype);
125 void write_type_spec_object(const char* name, t_type* ttype);
126 void write_type_spec(t_type* ttype);
127 void write_string(const string& value);
128 void write_value(t_type* tvalue);
129 void write_const_value(t_const_value* value, bool force_string = false);
130 void write_key_and(string key);
131 void write_key_and_string(string key, string val);
132 void write_key_and_integer(string key, int val);
133 void write_key_and_bool(string key, bool val);
134 };
135
136 void t_json_generator::init_generator() {
137 MKDIR(get_out_dir().c_str());
138
139 string f_json_name = get_out_dir() + program_->get_name() + ".json";
140 f_json_.open(f_json_name.c_str());
141
142 // Merge all included programs into this one so we can output one big file.
143 if (should_merge_includes_) {
144 merge_includes(program_);
145 }
146 }
147
148 string t_json_generator::escape_json_string(const string& input) {
149 std::ostringstream ss;
150 for (char iter : input) {
151 switch (iter) {
152 case '\\':
153 ss << "\\\\";
154 break;
155 case '"':
156 ss << "\\\"";
157 break;
158 case '/':
159 ss << "\\/";
160 break;
161 case '\b':
162 ss << "\\b";
163 break;
164 case '\f':
165 ss << "\\f";
166 break;
167 case '\n':
168 ss << "\\n";
169 break;
170 case '\r':
171 ss << "\\r";
172 break;
173 case '\t':
174 ss << "\\t";
175 break;
176 default:
177 ss << iter;
178 break;
179 }
180 }
181 return ss.str();
182 }
183
184 void t_json_generator::start_object(bool should_indent) {
185 f_json_ << (should_indent ? indent() : "") << "{" << endl;
186 indent_up();
187 comma_needed_.push(false);
188 }
189
190 void t_json_generator::start_array() {
191 f_json_ << "[" << endl;
192 indent_up();
193 comma_needed_.push(false);
194 }
195
196 void t_json_generator::write_comma_if_needed() {
197 if (comma_needed_.top()) {
198 f_json_ << "," << endl;
199 }
200 }
201
202 void t_json_generator::indicate_comma_needed() {
203 comma_needed_.pop();
204 comma_needed_.push(true);
205 }
206
207 void t_json_generator::write_key_and(string key) {
208 write_comma_if_needed();
209 indent(f_json_) << json_str(key) << ": ";
210 indicate_comma_needed();
211 }
212
213 void t_json_generator::write_key_and_integer(string key, int val) {
214 write_comma_if_needed();
215 indent(f_json_) << json_str(key) << ": " << number_to_string(val);
216 indicate_comma_needed();
217 }
218
219 void t_json_generator::write_key_and_string(string key, string val) {
220 write_comma_if_needed();
221 indent(f_json_) << json_str(key) << ": " << json_str(val);
222 indicate_comma_needed();
223 }
224
225 void t_json_generator::write_key_and_bool(string key, bool val) {
226 write_comma_if_needed();
227 indent(f_json_) << json_str(key) << ": " << (val ? "true" : "false");
228 indicate_comma_needed();
229 }
230
231 void t_json_generator::end_object() {
232 indent_down();
233 f_json_ << endl << indent() << "}";
234 comma_needed_.pop();
235 }
236
237 void t_json_generator::end_array() {
238 indent_down();
239 if (comma_needed_.top()) {
240 f_json_ << endl;
241 }
242 indent(f_json_) << "]";
243 comma_needed_.pop();
244 }
245
246 void t_json_generator::write_type_spec_object(const char* name, t_type* ttype) {
247 ttype = ttype->get_true_type();
248 if (ttype->is_struct() || ttype->is_xception() || ttype->is_container()) {
249 write_key_and(name);
250 start_object(NO_INDENT);
251 write_key_and("typeId");
252 write_type_spec(ttype);
253 end_object();
254 }
255 }
256
257 void t_json_generator::write_type_spec_entry(const char* name, t_type* ttype) {
258 write_key_and(name);
259 write_type_spec(ttype);
260 }
261
262 void t_json_generator::write_type_spec(t_type* ttype) {
263 ttype = ttype->get_true_type();
264
265 write_string(get_type_name(ttype));
266
267 if (ttype->annotations_.size() > 0) {
268 write_key_and("annotations");
269 start_object();
270 for (auto & annotation : ttype->annotations_) {
271 write_key_and_string(annotation.first, annotation.second);
272 }
273 end_object();
274 }
275
276 if (ttype->is_struct() || ttype->is_xception()) {
277 write_key_and_string("class", get_qualified_name(ttype));
278 } else if (ttype->is_map()) {
279 t_type* ktype = ((t_map*)ttype)->get_key_type();
280 t_type* vtype = ((t_map*)ttype)->get_val_type();
281 write_key_and_string("keyTypeId", get_type_name(ktype));
282 write_key_and_string("valueTypeId", get_type_name(vtype));
283 write_type_spec_object("keyType", ktype);
284 write_type_spec_object("valueType", vtype);
285 } else if (ttype->is_list()) {
286 t_type* etype = ((t_list*)ttype)->get_elem_type();
287 write_key_and_string("elemTypeId", get_type_name(etype));
288 write_type_spec_object("elemType", etype);
289 } else if (ttype->is_set()) {
290 t_type* etype = ((t_set*)ttype)->get_elem_type();
291 write_key_and_string("elemTypeId", get_type_name(etype));
292 write_type_spec_object("elemType", etype);
293 }
294 }
295
296 void t_json_generator::close_generator() {
297 f_json_ << endl;
298 f_json_.close();
299 }
300
301 void t_json_generator::merge_includes(t_program* program) {
302 vector<t_program*> includes = program->get_includes();
303 vector<t_program*>::iterator inc_iter;
304 for (inc_iter = includes.begin(); inc_iter != includes.end(); ++inc_iter) {
305 t_program* include = *inc_iter;
306 // recurse in case we get crazy
307 merge_includes(include);
308 // merge enums
309 vector<t_enum*> enums = include->get_enums();
310 vector<t_enum*>::iterator en_iter;
311 for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
312 program->add_enum(*en_iter);
313 }
314 // merge typedefs
315 vector<t_typedef*> typedefs = include->get_typedefs();
316 vector<t_typedef*>::iterator td_iter;
317 for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) {
318 program->add_typedef(*td_iter);
319 }
320 // merge structs
321 vector<t_struct*> objects = include->get_objects();
322 vector<t_struct*>::iterator o_iter;
323 for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) {
324 program->add_struct(*o_iter);
325 }
326 // merge constants
327 vector<t_const*> consts = include->get_consts();
328 vector<t_const*>::iterator c_iter;
329 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
330 program->add_const(*c_iter);
331 }
332
333 // merge services
334 vector<t_service*> services = include->get_services();
335 vector<t_service*>::iterator sv_iter;
336 for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
337 program->add_service(*sv_iter);
338 }
339 }
340 }
341
342 void t_json_generator::generate_program() {
343
344 init_generator();
345
346 start_object();
347 write_key_and_string("name", program_->get_name());
348 if (program_->has_doc()) {
349 write_key_and_string("doc", program_->get_doc());
350 }
351
352 // When merging includes, the "namespaces" and "includes" sections
353 // become ambiguous, so just skip them.
354 if (!should_merge_includes_) {
355 // Generate namespaces
356 write_key_and("namespaces");
357 start_object(NO_INDENT);
358 const map<string, string>& namespaces = program_->get_namespaces();
359 map<string, string>::const_iterator ns_it;
360 for (ns_it = namespaces.begin(); ns_it != namespaces.end(); ++ns_it) {
361 write_key_and_string(ns_it->first, ns_it->second);
362 indicate_comma_needed();
363 }
364 end_object();
365
366 // Generate includes
367 write_key_and("includes");
368 start_array();
369 const vector<t_program*> includes = program_->get_includes();
370 vector<t_program*>::const_iterator inc_it;
371 for (inc_it = includes.begin(); inc_it != includes.end(); ++inc_it) {
372 write_comma_if_needed();
373 write_string((*inc_it)->get_name());
374 indicate_comma_needed();
375 }
376 end_array();
377 }
378
379 // Generate enums
380 write_key_and("enums");
381 start_array();
382 vector<t_enum*> enums = program_->get_enums();
383 vector<t_enum*>::iterator en_iter;
384 for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
385 write_comma_if_needed();
386 generate_enum(*en_iter);
387 indicate_comma_needed();
388 }
389 end_array();
390
391 // Generate typedefs
392 write_key_and("typedefs");
393 start_array();
394 vector<t_typedef*> typedefs = program_->get_typedefs();
395 vector<t_typedef*>::iterator td_iter;
396 for (td_iter = typedefs.begin(); td_iter != typedefs.end(); ++td_iter) {
397 write_comma_if_needed();
398 generate_typedef(*td_iter);
399 indicate_comma_needed();
400 }
401 end_array();
402
403 // Generate structs, exceptions, and unions in declared order
404 write_key_and("structs");
405 start_array();
406 vector<t_struct*> objects = program_->get_objects();
407 vector<t_struct*>::iterator o_iter;
408 for (o_iter = objects.begin(); o_iter != objects.end(); ++o_iter) {
409 write_comma_if_needed();
410 if ((*o_iter)->is_xception()) {
411 generate_xception(*o_iter);
412 } else {
413 generate_struct(*o_iter);
414 }
415 indicate_comma_needed();
416 }
417 end_array();
418
419 // Generate constants
420 write_key_and("constants");
421 start_array();
422 vector<t_const*> consts = program_->get_consts();
423 vector<t_const*>::iterator c_iter;
424 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
425 write_comma_if_needed();
426 generate_constant(*c_iter);
427 indicate_comma_needed();
428 }
429 end_array();
430
431 // Generate services
432 write_key_and("services");
433 start_array();
434 vector<t_service*> services = program_->get_services();
435 vector<t_service*>::iterator sv_iter;
436 for (sv_iter = services.begin(); sv_iter != services.end(); ++sv_iter) {
437 write_comma_if_needed();
438 generate_service(*sv_iter);
439 indicate_comma_needed();
440 }
441 end_array();
442
443 end_object();
444
445 // Close the generator
446 close_generator();
447 }
448
449 void t_json_generator::generate_typedef(t_typedef* ttypedef) {
450 start_object();
451 write_key_and_string("name", get_qualified_name(ttypedef));
452 write_key_and_string("typeId", get_type_name(ttypedef->get_true_type()));
453 write_type_spec_object("type", ttypedef->get_true_type());
454 if (ttypedef->has_doc()) {
455 write_key_and_string("doc", ttypedef->get_doc());
456 }
457 if (ttypedef->annotations_.size() > 0) {
458 write_key_and("annotations");
459 start_object();
460 for (auto & annotation : ttypedef->annotations_) {
461 write_key_and_string(annotation.first, annotation.second);
462 }
463 end_object();
464 }
465 end_object();
466 }
467
468 void t_json_generator::write_string(const string& value) {
469 f_json_ << quot << escape_json_string(value) << quot;
470 }
471
472 void t_json_generator::write_const_value(t_const_value* value, bool should_force_string) {
473
474 switch (value->get_type()) {
475
476 case t_const_value::CV_IDENTIFIER:
477 case t_const_value::CV_INTEGER:
478 if (should_force_string) {
479 write_string(number_to_string(value->get_integer()));
480 } else {
481 write_number(value->get_integer());
482 }
483 break;
484
485 case t_const_value::CV_DOUBLE:
486 if (should_force_string) {
487 write_string(number_to_string(value->get_double()));
488 } else {
489 write_number(value->get_double());
490 }
491 break;
492
493 case t_const_value::CV_STRING:
494 write_string(value->get_string());
495 break;
496
497 case t_const_value::CV_LIST: {
498 start_array();
499 std::vector<t_const_value*> list = value->get_list();
500 std::vector<t_const_value*>::iterator lit;
501 for (lit = list.begin(); lit != list.end(); ++lit) {
502 write_comma_if_needed();
503 f_json_ << indent();
504 write_const_value(*lit);
505 indicate_comma_needed();
506 }
507 end_array();
508 break;
509 }
510
511 case t_const_value::CV_MAP: {
512 start_object(NO_INDENT);
513 std::map<t_const_value*, t_const_value*, t_const_value::value_compare> map = value->get_map();
514 std::map<t_const_value*, t_const_value*, t_const_value::value_compare>::iterator mit;
515 for (mit = map.begin(); mit != map.end(); ++mit) {
516 write_comma_if_needed();
517 f_json_ << indent();
518 // JSON objects only allow string keys
519 write_const_value(mit->first, FORCE_STRING);
520 f_json_ << ": ";
521 write_const_value(mit->second);
522 indicate_comma_needed();
523 }
524 end_object();
525 break;
526 }
527
528 default:
529 f_json_ << "null";
530 break;
531 }
532 }
533
534 string t_json_generator::json_str(const string& str) {
535 return quot + escape_json_string(str) + quot;
536 }
537
538 void t_json_generator::generate_constant(t_const* con) {
539 start_object();
540
541 write_key_and_string("name", con->get_name());
542 write_key_and_string("typeId", get_type_name(con->get_type()));
543 write_type_spec_object("type", con->get_type());
544
545 if (con->has_doc()) {
546 write_key_and_string("doc", con->get_doc());
547 }
548
549 write_key_and("value");
550 write_const_value(con->get_value());
551
552 end_object();
553 }
554
555 void t_json_generator::generate_enum(t_enum* tenum) {
556 start_object();
557
558 write_key_and_string("name", tenum->get_name());
559
560 if (tenum->has_doc()) {
561 write_key_and_string("doc", tenum->get_doc());
562 }
563
564 if (tenum->annotations_.size() > 0) {
565 write_key_and("annotations");
566 start_object();
567 for (auto & annotation : tenum->annotations_) {
568 write_key_and_string(annotation.first, annotation.second);
569 }
570 end_object();
571 }
572
573 write_key_and("members");
574 start_array();
575 vector<t_enum_value*> values = tenum->get_constants();
576 vector<t_enum_value*>::iterator val_iter;
577 for (val_iter = values.begin(); val_iter != values.end(); ++val_iter) {
578 write_comma_if_needed();
579 t_enum_value* val = (*val_iter);
580 start_object();
581 write_key_and_string("name", val->get_name());
582 write_key_and_integer("value", val->get_value());
583 if (val->has_doc()) {
584 write_key_and_string("doc", val->get_doc());
585 }
586 end_object();
587 indicate_comma_needed();
588 }
589 end_array();
590
591 end_object();
592 }
593
594 void t_json_generator::generate_struct(t_struct* tstruct) {
595 start_object();
596
597 write_key_and_string("name", tstruct->get_name());
598
599 if (tstruct->has_doc()) {
600 write_key_and_string("doc", tstruct->get_doc());
601 }
602
603 if (tstruct->annotations_.size() > 0) {
604 write_key_and("annotations");
605 start_object();
606 for (auto & annotation : tstruct->annotations_) {
607 write_key_and_string(annotation.first, annotation.second);
608 }
609 end_object();
610 }
611
612 write_key_and_bool("isException", tstruct->is_xception());
613
614 write_key_and_bool("isUnion", tstruct->is_union());
615
616 write_key_and("fields");
617 start_array();
618 vector<t_field*> members = tstruct->get_members();
619 vector<t_field*>::iterator mem_iter;
620 for (mem_iter = members.begin(); mem_iter != members.end(); mem_iter++) {
621 write_comma_if_needed();
622 generate_field(*mem_iter);
623 indicate_comma_needed();
624 }
625 end_array();
626
627 end_object();
628 }
629
630 void t_json_generator::generate_service(t_service* tservice) {
631 start_object();
632
633 write_key_and_string("name", get_qualified_name(tservice));
634
635 if (tservice->get_extends()) {
636 write_key_and_string("extends", get_qualified_name(tservice->get_extends()));
637 }
638
639 if (tservice->has_doc()) {
640 write_key_and_string("doc", tservice->get_doc());
641 }
642
643 if (tservice->annotations_.size() > 0) {
644 write_key_and("annotations");
645 start_object();
646 for (auto & annotation : tservice->annotations_) {
647 write_key_and_string(annotation.first, annotation.second);
648 }
649 end_object();
650 }
651
652 write_key_and("functions");
653 start_array();
654 vector<t_function*> functions = tservice->get_functions();
655 vector<t_function*>::iterator fn_iter = functions.begin();
656 for (; fn_iter != functions.end(); fn_iter++) {
657 write_comma_if_needed();
658 generate_function(*fn_iter);
659 indicate_comma_needed();
660 }
661 end_array();
662
663 end_object();
664 }
665
666 void t_json_generator::generate_function(t_function* tfunc) {
667 start_object();
668
669 write_key_and_string("name", tfunc->get_name());
670
671 write_key_and_string("returnTypeId", get_type_name(tfunc->get_returntype()));
672 write_type_spec_object("returnType", tfunc->get_returntype());
673
674 write_key_and_bool("oneway", tfunc->is_oneway());
675
676 if (tfunc->has_doc()) {
677 write_key_and_string("doc", tfunc->get_doc());
678 }
679
680 if (tfunc->annotations_.size() > 0) {
681 write_key_and("annotations");
682 start_object();
683 for (auto & annotation : tfunc->annotations_) {
684 write_key_and_string(annotation.first, annotation.second);
685 }
686 end_object();
687 }
688
689 write_key_and("arguments");
690 start_array();
691 vector<t_field*> members = tfunc->get_arglist()->get_members();
692 vector<t_field*>::iterator mem_iter = members.begin();
693 for (; mem_iter != members.end(); mem_iter++) {
694 write_comma_if_needed();
695 generate_field(*mem_iter);
696 indicate_comma_needed();
697 }
698 end_array();
699
700 write_key_and("exceptions");
701 start_array();
702 vector<t_field*> excepts = tfunc->get_xceptions()->get_members();
703 vector<t_field*>::iterator ex_iter = excepts.begin();
704 for (; ex_iter != excepts.end(); ex_iter++) {
705 write_comma_if_needed();
706 generate_field(*ex_iter);
707 indicate_comma_needed();
708 }
709 end_array();
710
711 end_object();
712 }
713
714 void t_json_generator::generate_field(t_field* field) {
715 start_object();
716
717 write_key_and_integer("key", field->get_key());
718 write_key_and_string("name", field->get_name());
719 write_key_and_string("typeId", get_type_name(field->get_type()));
720 write_type_spec_object("type", field->get_type());
721
722 if (field->has_doc()) {
723 write_key_and_string("doc", field->get_doc());
724 }
725
726 if (field->annotations_.size() > 0) {
727 write_key_and("annotations");
728 start_object();
729 for (auto & annotation : field->annotations_) {
730 write_key_and_string(annotation.first, annotation.second);
731 }
732 end_object();
733 }
734
735 write_key_and("required");
736 switch (field->get_req()) {
737 case t_field::T_REQUIRED:
738 write_string("required");
739 break;
740 case t_field::T_OPT_IN_REQ_OUT:
741 write_string("req_out");
742 break;
743 default:
744 write_string("optional");
745 break;
746 }
747
748 if (field->get_value()) {
749 write_key_and("default");
750 write_const_value(field->get_value());
751 }
752
753 end_object();
754 }
755
756 string t_json_generator::get_type_name(t_type* ttype) {
757 ttype = ttype->get_true_type();
758 if (ttype->is_list()) {
759 return "list";
760 }
761 if (ttype->is_set()) {
762 return "set";
763 }
764 if (ttype->is_map()) {
765 return "map";
766 }
767 if (ttype->is_enum()) {
768 return "i32";
769 }
770 if (ttype->is_struct()) {
771 return ((t_struct*)ttype)->is_union() ? "union" : "struct";
772 }
773 if (ttype->is_xception()) {
774 return "exception";
775 }
776 if (ttype->is_base_type()) {
777 t_base_type* tbasetype = (t_base_type*)ttype;
778 return tbasetype->is_binary() ? "binary" : t_base_type::t_base_name(tbasetype->get_base());
779 }
780
781 return "(unknown)";
782 }
783
784 string t_json_generator::get_qualified_name(t_type* ttype) {
785 if (should_merge_includes_ || ttype->get_program() == program_) {
786 return ttype->get_name();
787 }
788 return ttype->get_program()->get_name() + "." + ttype->get_name();
789 }
790
791 THRIFT_REGISTER_GENERATOR(json,
792 "JSON",
793 " merge: Generate output with included files merged\n")