]> git.proxmox.com Git - ceph.git/blob - ceph/src/jaegertracing/thrift/compiler/cpp/src/thrift/generate/t_st_generator.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / jaegertracing / thrift / compiler / cpp / src / thrift / generate / t_st_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 <string>
25 #include <fstream>
26 #include <iostream>
27 #include <vector>
28
29 #include <stdlib.h>
30 #include <time.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
33 #include <sstream>
34
35 #include "thrift/platform.h"
36 #include "thrift/version.h"
37 #include "thrift/generate/t_oop_generator.h"
38
39 using std::map;
40 using std::ofstream;
41 using std::ostringstream;
42 using std::string;
43 using std::stringstream;
44 using std::vector;
45
46 static const string endl = "\n"; // avoid ostream << std::endl flushes
47
48 /**
49 * Smalltalk code generator.
50 *
51 */
52 class t_st_generator : public t_oop_generator {
53 public:
54 t_st_generator(t_program* program,
55 const std::map<std::string, std::string>& parsed_options,
56 const std::string& option_string)
57 : t_oop_generator(program) {
58 (void)option_string;
59 temporary_var = 0;
60 std::map<std::string, std::string>::const_iterator iter;
61
62 /* no options yet */
63 for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
64 throw "unknown option st:" + iter->first;
65 }
66
67 out_dir_base_ = "gen-st";
68 }
69
70 /**
71 * Init and close methods
72 */
73
74 void init_generator() override;
75 void close_generator() override;
76
77 /**
78 * Program-level generation functions
79 */
80
81 void generate_typedef(t_typedef* ttypedef) override;
82 void generate_enum(t_enum* tenum) override;
83 void generate_const(t_const* tconst) override;
84 void generate_struct(t_struct* tstruct) override;
85 void generate_xception(t_struct* txception) override;
86 void generate_service(t_service* tservice) override;
87 void generate_class_side_definition();
88 void generate_force_consts();
89
90 std::string render_const_value(t_type* type, t_const_value* value);
91
92 /**
93 * Struct generation code
94 */
95
96 void generate_st_struct(std::ostream& out, t_struct* tstruct, bool is_exception);
97 void generate_accessors(std::ostream& out, t_struct* tstruct);
98
99 /**
100 * Service-level generation functions
101 */
102
103 void generate_service_client(t_service* tservice);
104
105 void generate_send_method(t_function* tfunction);
106 void generate_recv_method(t_function* tfunction);
107
108 std::string map_reader(t_map* tmap);
109 std::string list_reader(t_list* tlist);
110 std::string set_reader(t_set* tset);
111 std::string struct_reader(t_struct* tstruct, std::string clsName);
112
113 std::string map_writer(t_map* tmap, std::string name);
114 std::string list_writer(t_list* tlist, std::string name);
115 std::string set_writer(t_set* tset, std::string name);
116 std::string struct_writer(t_struct* tstruct, std::string fname);
117
118 std::string write_val(t_type* t, std::string fname);
119 std::string read_val(t_type* t);
120
121 /**
122 * Helper rendering functions
123 */
124
125 std::string st_autogen_comment();
126
127 void st_class_def(std::ostream& out, std::string name);
128 void st_method(std::ostream& out, std::string cls, std::string name);
129 void st_method(std::ostream& out, std::string cls, std::string name, std::string category);
130 void st_close_method(std::ostream& out);
131 void st_class_method(std::ostream& out, std::string cls, std::string name);
132 void st_class_method(std::ostream& out, std::string cls, std::string name, std::string category);
133 void st_setter(std::ostream& out, std::string cls, std::string name, std::string type);
134 void st_getter(std::ostream& out, std::string cls, std::string name);
135 void st_accessors(std::ostream& out, std::string cls, std::string name, std::string type);
136
137 std::string class_name();
138 static bool is_valid_namespace(const std::string& sub_namespace);
139 std::string client_class_name();
140 std::string prefix(std::string name);
141 std::string declare_field(t_field* tfield);
142 std::string type_name(t_type* ttype);
143
144 std::string function_signature(t_function* tfunction);
145 std::string argument_list(t_struct* tstruct);
146 std::string function_types_comment(t_function* fn);
147
148 std::string type_to_enum(t_type* ttype);
149 std::string a_type(t_type* type);
150 bool is_vowel(char c);
151 std::string temp_name();
152 std::string generated_category();
153
154 private:
155 /**
156 * File streams
157 */
158 int temporary_var;
159 ofstream_with_content_based_conditional_update f_;
160 };
161
162 /**
163 * Prepares for file generation by opening up the necessary file output
164 * streams.
165 *
166 * @param tprogram The program to generate
167 */
168 void t_st_generator::init_generator() {
169 // Make output directory
170 MKDIR(get_out_dir().c_str());
171
172 temporary_var = 0;
173
174 // Make output file
175 string f_name = get_out_dir() + "/" + program_name_ + ".st";
176 f_.open(f_name.c_str());
177
178 // Print header
179 f_ << st_autogen_comment() << endl;
180
181 st_class_def(f_, program_name_);
182 generate_class_side_definition();
183
184 // Generate enums
185 vector<t_enum*> enums = program_->get_enums();
186 vector<t_enum*>::iterator en_iter;
187 for (en_iter = enums.begin(); en_iter != enums.end(); ++en_iter) {
188 generate_enum(*en_iter);
189 }
190 }
191
192 string t_st_generator::class_name() {
193 return capitalize(program_name_);
194 }
195
196 bool t_st_generator::is_valid_namespace(const std::string& sub_namespace) {
197 return sub_namespace == "prefix" || sub_namespace == "category";
198 }
199
200 string t_st_generator::prefix(string class_name) {
201 string prefix = program_->get_namespace("smalltalk.prefix");
202 string name = capitalize(class_name);
203 name = prefix.empty() ? name : (prefix + name);
204 return name;
205 }
206
207 string t_st_generator::client_class_name() {
208 return capitalize(service_name_) + "Client";
209 }
210
211 /**
212 * Autogen'd comment
213 */
214 string t_st_generator::st_autogen_comment() {
215 return std::string("'") + "Autogenerated by Thrift Compiler (" + THRIFT_VERSION + ")\n" + "\n"
216 + "DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" + "'!\n";
217 }
218
219 void t_st_generator::generate_force_consts() {
220 f_ << prefix(class_name()) << " enums keysAndValuesDo: [:k :v | " << prefix(class_name())
221 << " enums at: k put: v value].!" << endl;
222
223 f_ << prefix(class_name()) << " constants keysAndValuesDo: [:k :v | " << prefix(class_name())
224 << " constants at: k put: v value].!" << endl;
225 }
226
227 void t_st_generator::close_generator() {
228 generate_force_consts();
229 f_.close();
230 }
231
232 string t_st_generator::generated_category() {
233 string cat = program_->get_namespace("smalltalk.category");
234 // For compatibility with the Thrift grammar, the category must
235 // be punctuated by dots. Replaces them with dashes here.
236 for (char & iter : cat) {
237 if (iter == '.') {
238 iter = '-';
239 }
240 }
241 return cat.size() ? cat : "Generated-" + class_name();
242 }
243
244 /**
245 * Generates a typedef. This is not done in Smalltalk, types are all implicit.
246 *
247 * @param ttypedef The type definition
248 */
249 void t_st_generator::generate_typedef(t_typedef* ttypedef) {
250 (void)ttypedef;
251 }
252
253 void t_st_generator::st_class_def(std::ostream& out, string name) {
254 out << "Object subclass: #" << prefix(name) << endl;
255 indent_up();
256 out << indent() << "instanceVariableNames: ''" << endl << indent() << "classVariableNames: ''"
257 << endl << indent() << "poolDictionaries: ''" << endl << indent() << "category: '"
258 << generated_category() << "'!" << endl << endl;
259 }
260
261 void t_st_generator::st_method(std::ostream& out, string cls, string name) {
262 st_method(out, cls, name, "as yet uncategorized");
263 }
264
265 void t_st_generator::st_class_method(std::ostream& out, string cls, string name) {
266 st_method(out, cls + " class", name);
267 }
268
269 void t_st_generator::st_class_method(std::ostream& out, string cls, string name, string category) {
270 st_method(out, cls, name, category);
271 }
272
273 void t_st_generator::st_method(std::ostream& out, string cls, string name, string category) {
274 char timestr[50];
275 time_t rawtime;
276 struct tm* tinfo;
277
278 time(&rawtime);
279 tinfo = localtime(&rawtime);
280 strftime(timestr, 50, "%m/%d/%Y %H:%M", tinfo);
281
282 out << "!" << prefix(cls) << " methodsFor: '" + category + "' stamp: 'thrift " << timestr
283 << "'!\n" << name << endl;
284
285 indent_up();
286 out << indent();
287 }
288
289 void t_st_generator::st_close_method(std::ostream& out) {
290 out << "! !" << endl << endl;
291 indent_down();
292 }
293
294 void t_st_generator::st_setter(std::ostream& out,
295 string cls,
296 string name,
297 string type = "anObject") {
298 st_method(out, cls, name + ": " + type);
299 out << name << " := " + type;
300 st_close_method(out);
301 }
302
303 void t_st_generator::st_getter(std::ostream& out, string cls, string name) {
304 st_method(out, cls, name + "");
305 out << "^ " << name;
306 st_close_method(out);
307 }
308
309 void t_st_generator::st_accessors(std::ostream& out,
310 string cls,
311 string name,
312 string type = "anObject") {
313 st_setter(out, cls, name, type);
314 st_getter(out, cls, name);
315 }
316
317 void t_st_generator::generate_class_side_definition() {
318 f_ << prefix(class_name()) << " class" << endl << "\tinstanceVariableNames: 'constants enums'!"
319 << endl << endl;
320
321 st_accessors(f_, class_name() + " class", "enums");
322 st_accessors(f_, class_name() + " class", "constants");
323
324 f_ << prefix(class_name()) << " enums: Dictionary new!" << endl;
325 f_ << prefix(class_name()) << " constants: Dictionary new!" << endl;
326
327 f_ << endl;
328 }
329
330 /**
331 * Generates code for an enumerated type. Done using a class to scope
332 * the values.
333 *
334 * @param tenum The enumeration
335 */
336 void t_st_generator::generate_enum(t_enum* tenum) {
337 string cls_name = program_name_ + capitalize(tenum->get_name());
338
339 f_ << prefix(class_name()) << " enums at: '" << tenum->get_name() << "' put: ["
340 << "(Dictionary new " << endl;
341
342 vector<t_enum_value*> constants = tenum->get_constants();
343 vector<t_enum_value*>::iterator c_iter;
344 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
345 int value = (*c_iter)->get_value();
346 f_ << "\tat: '" << (*c_iter)->get_name() << "' put: " << value << ";" << endl;
347 }
348
349 f_ << "\tyourself)]!" << endl << endl;
350 }
351
352 /**
353 * Generate a constant value
354 */
355 void t_st_generator::generate_const(t_const* tconst) {
356 t_type* type = tconst->get_type();
357 string name = tconst->get_name();
358 t_const_value* value = tconst->get_value();
359
360 f_ << prefix(class_name()) << " constants at: '" << name << "' put: ["
361 << render_const_value(type, value) << "]!" << endl << endl;
362 }
363
364 /**
365 * Prints the value of a constant with the given type. Note that type checking
366 * is NOT performed in this function as it is always run beforehand using the
367 * validate_types method in main.cc
368 */
369 string t_st_generator::render_const_value(t_type* type, t_const_value* value) {
370 type = get_true_type(type);
371 std::ostringstream out;
372 if (type->is_base_type()) {
373 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
374 switch (tbase) {
375 case t_base_type::TYPE_STRING:
376 out << '"' << get_escaped_string(value) << '"';
377 break;
378 case t_base_type::TYPE_BOOL:
379 out << (value->get_integer() > 0 ? "true" : "false");
380 break;
381 case t_base_type::TYPE_I8:
382 case t_base_type::TYPE_I16:
383 case t_base_type::TYPE_I32:
384 case t_base_type::TYPE_I64:
385 out << value->get_integer();
386 break;
387 case t_base_type::TYPE_DOUBLE:
388 if (value->get_type() == t_const_value::CV_INTEGER) {
389 out << value->get_integer();
390 } else {
391 out << value->get_double();
392 }
393 break;
394 default:
395 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
396 }
397 } else if (type->is_enum()) {
398 indent(out) << value->get_integer();
399 } else if (type->is_struct() || type->is_xception()) {
400 out << "(" << capitalize(type->get_name()) << " new " << endl;
401 indent_up();
402
403 const vector<t_field*>& fields = ((t_struct*)type)->get_members();
404 vector<t_field*>::const_iterator f_iter;
405 const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
406 map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
407
408 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
409 t_type* field_type = NULL;
410 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
411 if ((*f_iter)->get_name() == v_iter->first->get_string()) {
412 field_type = (*f_iter)->get_type();
413 }
414 }
415 if (field_type == NULL) {
416 throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
417 }
418
419 out << indent() << v_iter->first->get_string() << ": "
420 << render_const_value(field_type, v_iter->second) << ";" << endl;
421 }
422 out << indent() << "yourself)";
423
424 indent_down();
425 } else if (type->is_map()) {
426 t_type* ktype = ((t_map*)type)->get_key_type();
427 t_type* vtype = ((t_map*)type)->get_val_type();
428 out << "(Dictionary new" << endl;
429 indent_up();
430 indent_up();
431 const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
432 map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
433 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
434 out << indent() << indent();
435 out << "at: " << render_const_value(ktype, v_iter->first);
436 out << " put: ";
437 out << render_const_value(vtype, v_iter->second);
438 out << ";" << endl;
439 }
440 out << indent() << indent() << "yourself)";
441 indent_down();
442 indent_down();
443 } else if (type->is_list() || type->is_set()) {
444 t_type* etype;
445 if (type->is_list()) {
446 etype = ((t_list*)type)->get_elem_type();
447 } else {
448 etype = ((t_set*)type)->get_elem_type();
449 }
450 if (type->is_set()) {
451 out << "(Set new" << endl;
452 } else {
453 out << "(OrderedCollection new" << endl;
454 }
455 indent_up();
456 indent_up();
457 const vector<t_const_value*>& val = value->get_list();
458 vector<t_const_value*>::const_iterator v_iter;
459 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
460 out << indent() << indent();
461 out << "add: " << render_const_value(etype, *v_iter);
462 out << ";" << endl;
463 }
464 out << indent() << indent() << "yourself)";
465 indent_down();
466 indent_down();
467 } else {
468 throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
469 }
470 return out.str();
471 }
472
473 /**
474 * Generates a Smalltalk struct
475 */
476 void t_st_generator::generate_struct(t_struct* tstruct) {
477 generate_st_struct(f_, tstruct, false);
478 }
479
480 /**
481 * Generates a struct definition for a thrift exception. Basically the same
482 * as a struct but extends the Exception class.
483 *
484 * @param txception The struct definition
485 */
486 void t_st_generator::generate_xception(t_struct* txception) {
487 generate_st_struct(f_, txception, true);
488 }
489
490 /**
491 * Generates a smalltalk class to represent a struct
492 */
493 void t_st_generator::generate_st_struct(std::ostream& out,
494 t_struct* tstruct,
495 bool is_exception = false) {
496 const vector<t_field*>& members = tstruct->get_members();
497 vector<t_field*>::const_iterator m_iter;
498
499 if (is_exception)
500 out << "Error";
501 else
502 out << "Object";
503
504 out << " subclass: #" << prefix(type_name(tstruct)) << endl << "\tinstanceVariableNames: '";
505
506 if (members.size() > 0) {
507 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
508 if (m_iter != members.begin())
509 out << " ";
510 out << camelcase((*m_iter)->get_name());
511 }
512 }
513
514 out << "'\n"
515 << "\tclassVariableNames: ''\n"
516 << "\tpoolDictionaries: ''\n"
517 << "\tcategory: '" << generated_category() << "'!\n\n";
518
519 generate_accessors(out, tstruct);
520 }
521
522 bool t_st_generator::is_vowel(char c) {
523 switch (tolower(c)) {
524 case 'a':
525 case 'e':
526 case 'i':
527 case 'o':
528 case 'u':
529 return true;
530 }
531 return false;
532 }
533
534 string t_st_generator::a_type(t_type* type) {
535 string prefix;
536
537 if (is_vowel(type_name(type)[0]))
538 prefix = "an";
539 else
540 prefix = "a";
541
542 return prefix + capitalize(type_name(type));
543 }
544
545 void t_st_generator::generate_accessors(std::ostream& out, t_struct* tstruct) {
546 const vector<t_field*>& members = tstruct->get_members();
547 vector<t_field*>::const_iterator m_iter;
548 string type;
549 string prefix;
550
551 if (members.size() > 0) {
552 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
553 st_accessors(out,
554 capitalize(type_name(tstruct)),
555 camelcase((*m_iter)->get_name()),
556 a_type((*m_iter)->get_type()));
557 }
558 out << endl;
559 }
560 }
561
562 /**
563 * Generates a thrift service.
564 *
565 * @param tservice The service definition
566 */
567 void t_st_generator::generate_service(t_service* tservice) {
568 generate_service_client(tservice);
569 // generate_service_server(tservice);
570 }
571
572 string t_st_generator::temp_name() {
573 std::ostringstream out;
574 out << "temp" << temporary_var++;
575 return out.str();
576 }
577
578 string t_st_generator::map_writer(t_map* tmap, string fname) {
579 std::ostringstream out;
580 string key = temp_name();
581 string val = temp_name();
582
583 out << "[oprot writeMapBegin: (TMap new keyType: " << type_to_enum(tmap->get_key_type())
584 << "; valueType: " << type_to_enum(tmap->get_val_type()) << "; size: " << fname << " size)."
585 << endl;
586 indent_up();
587
588 out << indent() << fname << " keysAndValuesDo: [:" << key << " :" << val << " |" << endl;
589 indent_up();
590
591 out << indent() << write_val(tmap->get_key_type(), key) << "." << endl << indent()
592 << write_val(tmap->get_val_type(), val);
593 indent_down();
594
595 out << "]." << endl << indent() << "oprot writeMapEnd] value";
596 indent_down();
597
598 return out.str();
599 }
600
601 string t_st_generator::map_reader(t_map* tmap) {
602 std::ostringstream out;
603 string desc = temp_name();
604 string val = temp_name();
605
606 out << "[|" << desc << " " << val << "| " << endl;
607 indent_up();
608
609 out << indent() << desc << " := iprot readMapBegin." << endl << indent() << val
610 << " := Dictionary new." << endl << indent() << desc << " size timesRepeat: [" << endl;
611
612 indent_up();
613 out << indent() << val << " at: " << read_val(tmap->get_key_type())
614 << " put: " << read_val(tmap->get_val_type());
615 indent_down();
616
617 out << "]." << endl << indent() << "iprot readMapEnd." << endl << indent() << val << "] value";
618 indent_down();
619
620 return out.str();
621 }
622
623 string t_st_generator::list_writer(t_list* tlist, string fname) {
624 std::ostringstream out;
625 string val = temp_name();
626
627 out << "[oprot writeListBegin: (TList new elemType: " << type_to_enum(tlist->get_elem_type())
628 << "; size: " << fname << " size)." << endl;
629 indent_up();
630
631 out << indent() << fname << " do: [:" << val << "|" << endl;
632 indent_up();
633
634 out << indent() << write_val(tlist->get_elem_type(), val) << endl;
635 indent_down();
636
637 out << "]." << endl << indent() << "oprot writeListEnd] value";
638 indent_down();
639
640 return out.str();
641 }
642
643 string t_st_generator::list_reader(t_list* tlist) {
644 std::ostringstream out;
645 string desc = temp_name();
646 string val = temp_name();
647
648 out << "[|" << desc << " " << val << "| " << desc << " := iprot readListBegin." << endl;
649 indent_up();
650
651 out << indent() << val << " := OrderedCollection new." << endl << indent() << desc
652 << " size timesRepeat: [" << endl;
653
654 indent_up();
655 out << indent() << val << " add: " << read_val(tlist->get_elem_type());
656 indent_down();
657
658 out << "]." << endl << indent() << "iprot readListEnd." << endl << indent() << val << "] value";
659 indent_down();
660
661 return out.str();
662 }
663
664 string t_st_generator::set_writer(t_set* tset, string fname) {
665 std::ostringstream out;
666 string val = temp_name();
667
668 out << "[oprot writeSetBegin: (TSet new elemType: " << type_to_enum(tset->get_elem_type())
669 << "; size: " << fname << " size)." << endl;
670 indent_up();
671
672 out << indent() << fname << " do: [:" << val << "|" << endl;
673 indent_up();
674
675 out << indent() << write_val(tset->get_elem_type(), val) << endl;
676 indent_down();
677
678 out << "]." << endl << indent() << "oprot writeSetEnd] value";
679 indent_down();
680
681 return out.str();
682 }
683
684 string t_st_generator::set_reader(t_set* tset) {
685 std::ostringstream out;
686 string desc = temp_name();
687 string val = temp_name();
688
689 out << "[|" << desc << " " << val << "| " << desc << " := iprot readSetBegin." << endl;
690 indent_up();
691
692 out << indent() << val << " := Set new." << endl << indent() << desc << " size timesRepeat: ["
693 << endl;
694
695 indent_up();
696 out << indent() << val << " add: " << read_val(tset->get_elem_type());
697 indent_down();
698
699 out << "]." << endl << indent() << "iprot readSetEnd." << endl << indent() << val << "] value";
700 indent_down();
701
702 return out.str();
703 }
704
705 string t_st_generator::struct_writer(t_struct* tstruct, string sname) {
706 std::ostringstream out;
707 const vector<t_field*>& fields = tstruct->get_sorted_members();
708 vector<t_field*>::const_iterator fld_iter;
709
710 out << "[oprot writeStructBegin: "
711 << "(TStruct new name: '" + tstruct->get_name() + "')." << endl;
712 indent_up();
713
714 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
715 bool optional = (*fld_iter)->get_req() == t_field::T_OPTIONAL;
716 string fname = camelcase((*fld_iter)->get_name());
717 string accessor = sname + " " + camelcase(fname);
718
719 if (optional) {
720 out << indent() << accessor << " ifNotNil: [" << endl;
721 indent_up();
722 }
723
724 out << indent() << "oprot writeFieldBegin: (TField new name: '" << fname
725 << "'; type: " << type_to_enum((*fld_iter)->get_type())
726 << "; id: " << (*fld_iter)->get_key() << ")." << endl;
727
728 out << indent() << write_val((*fld_iter)->get_type(), accessor) << "." << endl << indent()
729 << "oprot writeFieldEnd";
730
731 if (optional) {
732 out << "]";
733 indent_down();
734 }
735
736 out << "." << endl;
737 }
738
739 out << indent() << "oprot writeFieldStop; writeStructEnd] value";
740 indent_down();
741
742 return out.str();
743 }
744
745 string t_st_generator::struct_reader(t_struct* tstruct, string clsName = "") {
746 std::ostringstream out;
747 const vector<t_field*>& fields = tstruct->get_members();
748 vector<t_field*>::const_iterator fld_iter;
749 string val = temp_name();
750 string desc = temp_name();
751 string found = temp_name();
752
753 if (clsName.size() == 0) {
754 clsName = tstruct->get_name();
755 }
756
757 out << "[|" << desc << " " << val << "|" << endl;
758 indent_up();
759
760 // This is nasty, but without it we'll break things by prefixing TResult.
761 string name = ((capitalize(clsName) == "TResult") ? capitalize(clsName) : prefix(clsName));
762 out << indent() << val << " := " << name << " new." << endl;
763
764 out << indent() << "iprot readStructBegin." << endl << indent() << "[" << desc
765 << " := iprot readFieldBegin." << endl << indent() << desc
766 << " type = TType stop] whileFalse: [|" << found << "|" << endl;
767 indent_up();
768
769 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
770 out << indent() << desc << " id = " << (*fld_iter)->get_key() << " ifTrue: [" << endl;
771 indent_up();
772
773 out << indent() << found << " := true." << endl << indent() << val << " "
774 << camelcase((*fld_iter)->get_name()) << ": " << read_val((*fld_iter)->get_type());
775 indent_down();
776
777 out << "]." << endl;
778 }
779
780 out << indent() << found << " ifNil: [iprot skip: " << desc << " type]]." << endl;
781 indent_down();
782
783 out << indent() << "oprot readStructEnd." << endl << indent() << val << "] value";
784 indent_down();
785
786 return out.str();
787 }
788
789 string t_st_generator::write_val(t_type* t, string fname) {
790 t = get_true_type(t);
791
792 if (t->is_base_type()) {
793 t_base_type::t_base tbase = ((t_base_type*)t)->get_base();
794 switch (tbase) {
795 case t_base_type::TYPE_DOUBLE:
796 return "iprot writeDouble: " + fname + " asFloat";
797 break;
798 case t_base_type::TYPE_I8:
799 case t_base_type::TYPE_I16:
800 case t_base_type::TYPE_I32:
801 case t_base_type::TYPE_I64:
802 return "iprot write" + capitalize(type_name(t)) + ": " + fname + " asInteger";
803 default:
804 return "iprot write" + capitalize(type_name(t)) + ": " + fname;
805 }
806 } else if (t->is_map()) {
807 return map_writer((t_map*)t, fname);
808 } else if (t->is_struct() || t->is_xception()) {
809 return struct_writer((t_struct*)t, fname);
810 } else if (t->is_list()) {
811 return list_writer((t_list*)t, fname);
812 } else if (t->is_set()) {
813 return set_writer((t_set*)t, fname);
814 } else if (t->is_enum()) {
815 return "iprot writeI32: " + fname;
816 } else {
817 throw "Sorry, I don't know how to write this: " + type_name(t);
818 }
819 }
820
821 string t_st_generator::read_val(t_type* t) {
822 t = get_true_type(t);
823
824 if (t->is_base_type()) {
825 return "iprot read" + capitalize(type_name(t));
826 } else if (t->is_map()) {
827 return map_reader((t_map*)t);
828 } else if (t->is_struct() || t->is_xception()) {
829 return struct_reader((t_struct*)t);
830 } else if (t->is_list()) {
831 return list_reader((t_list*)t);
832 } else if (t->is_set()) {
833 return set_reader((t_set*)t);
834 } else if (t->is_enum()) {
835 return "iprot readI32";
836 } else {
837 throw "Sorry, I don't know how to read this: " + type_name(t);
838 }
839 }
840
841 void t_st_generator::generate_send_method(t_function* function) {
842 string funname = function->get_name();
843 string signature = function_signature(function);
844 t_struct* arg_struct = function->get_arglist();
845 const vector<t_field*>& fields = arg_struct->get_members();
846 vector<t_field*>::const_iterator fld_iter;
847
848 st_method(f_, client_class_name(), "send" + capitalize(signature));
849 f_ << "oprot writeMessageBegin:" << endl;
850 indent_up();
851
852 f_ << indent() << "(TCallMessage new" << endl;
853 indent_up();
854
855 f_ << indent() << "name: '" << funname << "'; " << endl << indent() << "seqid: self nextSeqid)."
856 << endl;
857 indent_down();
858 indent_down();
859
860 f_ << indent() << "oprot writeStructBegin: "
861 << "(TStruct new name: '" + capitalize(camelcase(funname)) + "_args')." << endl;
862
863 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
864 string fname = camelcase((*fld_iter)->get_name());
865
866 f_ << indent() << "oprot writeFieldBegin: (TField new name: '" << fname
867 << "'; type: " << type_to_enum((*fld_iter)->get_type()) << "; id: " << (*fld_iter)->get_key()
868 << ")." << endl;
869
870 f_ << indent() << write_val((*fld_iter)->get_type(), fname) << "." << endl << indent()
871 << "oprot writeFieldEnd." << endl;
872 }
873
874 f_ << indent() << "oprot writeFieldStop; writeStructEnd; writeMessageEnd." << endl;
875 f_ << indent() << "oprot transport flush";
876
877 st_close_method(f_);
878 }
879
880 // We only support receiving TResult structures (so this won't work on the server side)
881 void t_st_generator::generate_recv_method(t_function* function) {
882 string funname = camelcase(function->get_name());
883 string signature = function_signature(function);
884
885 t_struct result(program_, "TResult");
886 t_field success(function->get_returntype(), "success", 0);
887 result.append(&success);
888
889 t_struct* xs = function->get_xceptions();
890 const vector<t_field*>& fields = xs->get_members();
891 vector<t_field*>::const_iterator f_iter;
892 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
893 // duplicate the field, but call it "exception"... we don't need a dynamic name
894 t_field* exception = new t_field((*f_iter)->get_type(), "exception", (*f_iter)->get_key());
895 result.append(exception);
896 }
897
898 st_method(f_, client_class_name(), "recv" + capitalize(funname));
899 f_ << "| f msg res | " << endl << indent() << "msg := oprot readMessageBegin." << endl << indent()
900 << "self validateRemoteMessage: msg." << endl << indent()
901 << "res := " << struct_reader(&result) << "." << endl << indent() << "oprot readMessageEnd."
902 << endl << indent() << "oprot transport flush." << endl << indent()
903 << "res exception ifNotNil: [res exception signal]." << endl << indent() << "^ res";
904 st_close_method(f_);
905 }
906
907 string t_st_generator::function_types_comment(t_function* fn) {
908 std::ostringstream out;
909 const vector<t_field*>& fields = fn->get_arglist()->get_members();
910 vector<t_field*>::const_iterator f_iter;
911
912 out << "\"";
913
914 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
915 out << camelcase((*f_iter)->get_name()) << ": " << type_name((*f_iter)->get_type());
916 if ((f_iter + 1) != fields.end()) {
917 out << ", ";
918 }
919 }
920
921 out << "\"";
922
923 return out.str();
924 }
925
926 /**
927 * Generates a service client definition.
928 *
929 * @param tservice The service to generate a server for.
930 */
931 void t_st_generator::generate_service_client(t_service* tservice) {
932 string extends = "";
933 string extends_client = "TClient";
934 vector<t_function*> functions = tservice->get_functions();
935 vector<t_function*>::iterator f_iter;
936
937 if (tservice->get_extends() != NULL) {
938 extends = type_name(tservice->get_extends());
939 extends_client = extends + "Client";
940 }
941
942 f_ << extends_client << " subclass: #" << prefix(client_class_name()) << endl
943 << "\tinstanceVariableNames: ''\n"
944 << "\tclassVariableNames: ''\n"
945 << "\tpoolDictionaries: ''\n"
946 << "\tcategory: '" << generated_category() << "'!\n\n";
947
948 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
949 string funname = camelcase((*f_iter)->get_name());
950 string signature = function_signature(*f_iter);
951
952 st_method(f_, client_class_name(), signature);
953 f_ << function_types_comment(*f_iter) << endl << indent() << "self send"
954 << capitalize(signature) << "." << endl;
955
956 if (!(*f_iter)->is_oneway()) {
957 f_ << indent() << "^ self recv" << capitalize(funname) << " success " << endl;
958 }
959
960 st_close_method(f_);
961
962 generate_send_method(*f_iter);
963 if (!(*f_iter)->is_oneway()) {
964 generate_recv_method(*f_iter);
965 }
966 }
967 }
968
969 /**
970 * Renders a function signature of the form 'type name(args)'
971 *
972 * @param tfunction Function definition
973 * @return String of rendered function definition
974 */
975 string t_st_generator::function_signature(t_function* tfunction) {
976 return camelcase(tfunction->get_name()) + capitalize(argument_list(tfunction->get_arglist()));
977 }
978
979 /**
980 * Renders a field list
981 */
982 string t_st_generator::argument_list(t_struct* tstruct) {
983 string result = "";
984
985 const vector<t_field*>& fields = tstruct->get_members();
986 vector<t_field*>::const_iterator f_iter;
987 bool first = true;
988 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
989 if (first) {
990 first = false;
991 } else {
992 result += " ";
993 }
994 string name = camelcase((*f_iter)->get_name());
995 result += name + ": " + name;
996 }
997 return result;
998 }
999
1000 string t_st_generator::type_name(t_type* ttype) {
1001 string prefix = "";
1002 t_program* program = ttype->get_program();
1003 if (program != NULL && program != program_) {
1004 if (!ttype->is_service()) {
1005 prefix = program->get_name() + "_types.";
1006 }
1007 }
1008
1009 string name = ttype->get_name();
1010 if (ttype->is_struct() || ttype->is_xception()) {
1011 name = capitalize(ttype->get_name());
1012 }
1013
1014 return prefix + name;
1015 }
1016
1017 /* Convert t_type to Smalltalk type code */
1018 string t_st_generator::type_to_enum(t_type* type) {
1019 type = get_true_type(type);
1020
1021 if (type->is_base_type()) {
1022 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
1023 switch (tbase) {
1024 case t_base_type::TYPE_VOID:
1025 throw "NO T_VOID CONSTRUCT";
1026 case t_base_type::TYPE_STRING:
1027 return "TType string";
1028 case t_base_type::TYPE_BOOL:
1029 return "TType bool";
1030 case t_base_type::TYPE_I8:
1031 return "TType byte";
1032 case t_base_type::TYPE_I16:
1033 return "TType i16";
1034 case t_base_type::TYPE_I32:
1035 return "TType i32";
1036 case t_base_type::TYPE_I64:
1037 return "TType i64";
1038 case t_base_type::TYPE_DOUBLE:
1039 return "TType double";
1040 }
1041 } else if (type->is_enum()) {
1042 return "TType i32";
1043 } else if (type->is_struct() || type->is_xception()) {
1044 return "TType struct";
1045 } else if (type->is_map()) {
1046 return "TType map";
1047 } else if (type->is_set()) {
1048 return "TType set";
1049 } else if (type->is_list()) {
1050 return "TType list";
1051 }
1052
1053 throw "INVALID TYPE IN type_to_enum: " + type->get_name();
1054 }
1055
1056 THRIFT_REGISTER_GENERATOR(st, "Smalltalk", "")