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
10 * http://www.apache.org/licenses/LICENSE-2.0
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
19 * Contains some contributions under the Thrift Software License.
20 * Please see doc/old-thrift-license.txt in the Thrift distribution for
32 #include <sys/types.h>
35 #include "thrift/platform.h"
36 #include "thrift/version.h"
37 #include "thrift/generate/t_oop_generator.h"
41 using std::ostringstream
;
43 using std::stringstream
;
46 static const string endl
= "\n"; // avoid ostream << std::endl flushes
49 * Smalltalk code generator.
52 class t_st_generator
: public t_oop_generator
{
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
) {
60 std::map
<std::string
, std::string
>::const_iterator iter
;
63 for( iter
= parsed_options
.begin(); iter
!= parsed_options
.end(); ++iter
) {
64 throw "unknown option st:" + iter
->first
;
67 out_dir_base_
= "gen-st";
71 * Init and close methods
74 void init_generator() override
;
75 void close_generator() override
;
78 * Program-level generation functions
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();
90 std::string
render_const_value(t_type
* type
, t_const_value
* value
);
93 * Struct generation code
96 void generate_st_struct(std::ostream
& out
, t_struct
* tstruct
, bool is_exception
);
97 void generate_accessors(std::ostream
& out
, t_struct
* tstruct
);
100 * Service-level generation functions
103 void generate_service_client(t_service
* tservice
);
105 void generate_send_method(t_function
* tfunction
);
106 void generate_recv_method(t_function
* tfunction
);
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
);
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
);
118 std::string
write_val(t_type
* t
, std::string fname
);
119 std::string
read_val(t_type
* t
);
122 * Helper rendering functions
125 std::string
st_autogen_comment();
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
);
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
);
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
);
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();
159 ofstream_with_content_based_conditional_update f_
;
163 * Prepares for file generation by opening up the necessary file output
166 * @param tprogram The program to generate
168 void t_st_generator::init_generator() {
169 // Make output directory
170 MKDIR(get_out_dir().c_str());
175 string f_name
= get_out_dir() + "/" + program_name_
+ ".st";
176 f_
.open(f_name
.c_str());
179 f_
<< st_autogen_comment() << endl
;
181 st_class_def(f_
, program_name_
);
182 generate_class_side_definition();
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
);
192 string
t_st_generator::class_name() {
193 return capitalize(program_name_
);
196 bool t_st_generator::is_valid_namespace(const std::string
& sub_namespace
) {
197 return sub_namespace
== "prefix" || sub_namespace
== "category";
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
);
207 string
t_st_generator::client_class_name() {
208 return capitalize(service_name_
) + "Client";
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";
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
;
223 f_
<< prefix(class_name()) << " constants keysAndValuesDo: [:k :v | " << prefix(class_name())
224 << " constants at: k put: v value].!" << endl
;
227 void t_st_generator::close_generator() {
228 generate_force_consts();
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
) {
241 return cat
.size() ? cat
: "Generated-" + class_name();
245 * Generates a typedef. This is not done in Smalltalk, types are all implicit.
247 * @param ttypedef The type definition
249 void t_st_generator::generate_typedef(t_typedef
* ttypedef
) {
253 void t_st_generator::st_class_def(std::ostream
& out
, string name
) {
254 out
<< "Object subclass: #" << prefix(name
) << endl
;
256 out
<< indent() << "instanceVariableNames: ''" << endl
<< indent() << "classVariableNames: ''"
257 << endl
<< indent() << "poolDictionaries: ''" << endl
<< indent() << "category: '"
258 << generated_category() << "'!" << endl
<< endl
;
261 void t_st_generator::st_method(std::ostream
& out
, string cls
, string name
) {
262 st_method(out
, cls
, name
, "as yet uncategorized");
265 void t_st_generator::st_class_method(std::ostream
& out
, string cls
, string name
) {
266 st_method(out
, cls
+ " class", name
);
269 void t_st_generator::st_class_method(std::ostream
& out
, string cls
, string name
, string category
) {
270 st_method(out
, cls
, name
, category
);
273 void t_st_generator::st_method(std::ostream
& out
, string cls
, string name
, string category
) {
279 tinfo
= localtime(&rawtime
);
280 strftime(timestr
, 50, "%m/%d/%Y %H:%M", tinfo
);
282 out
<< "!" << prefix(cls
) << " methodsFor: '" + category
+ "' stamp: 'thrift " << timestr
283 << "'!\n" << name
<< endl
;
289 void t_st_generator::st_close_method(std::ostream
& out
) {
290 out
<< "! !" << endl
<< endl
;
294 void t_st_generator::st_setter(std::ostream
& out
,
297 string type
= "anObject") {
298 st_method(out
, cls
, name
+ ": " + type
);
299 out
<< name
<< " := " + type
;
300 st_close_method(out
);
303 void t_st_generator::st_getter(std::ostream
& out
, string cls
, string name
) {
304 st_method(out
, cls
, name
+ "");
306 st_close_method(out
);
309 void t_st_generator::st_accessors(std::ostream
& out
,
312 string type
= "anObject") {
313 st_setter(out
, cls
, name
, type
);
314 st_getter(out
, cls
, name
);
317 void t_st_generator::generate_class_side_definition() {
318 f_
<< prefix(class_name()) << " class" << endl
<< "\tinstanceVariableNames: 'constants enums'!"
321 st_accessors(f_
, class_name() + " class", "enums");
322 st_accessors(f_
, class_name() + " class", "constants");
324 f_
<< prefix(class_name()) << " enums: Dictionary new!" << endl
;
325 f_
<< prefix(class_name()) << " constants: Dictionary new!" << endl
;
331 * Generates code for an enumerated type. Done using a class to scope
334 * @param tenum The enumeration
336 void t_st_generator::generate_enum(t_enum
* tenum
) {
337 string cls_name
= program_name_
+ capitalize(tenum
->get_name());
339 f_
<< prefix(class_name()) << " enums at: '" << tenum
->get_name() << "' put: ["
340 << "(Dictionary new " << endl
;
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
;
349 f_
<< "\tyourself)]!" << endl
<< endl
;
353 * Generate a constant value
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();
360 f_
<< prefix(class_name()) << " constants at: '" << name
<< "' put: ["
361 << render_const_value(type
, value
) << "]!" << endl
<< endl
;
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
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();
375 case t_base_type::TYPE_STRING
:
376 out
<< '"' << get_escaped_string(value
) << '"';
378 case t_base_type::TYPE_BOOL
:
379 out
<< (value
->get_integer() > 0 ? "true" : "false");
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();
387 case t_base_type::TYPE_DOUBLE
:
388 if (value
->get_type() == t_const_value::CV_INTEGER
) {
389 out
<< value
->get_integer();
391 out
<< value
->get_double();
395 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase
);
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
;
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
;
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();
415 if (field_type
== NULL
) {
416 throw "type error: " + type
->get_name() + " has no field " + v_iter
->first
->get_string();
419 out
<< indent() << v_iter
->first
->get_string() << ": "
420 << render_const_value(field_type
, v_iter
->second
) << ";" << endl
;
422 out
<< indent() << "yourself)";
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
;
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
);
437 out
<< render_const_value(vtype
, v_iter
->second
);
440 out
<< indent() << indent() << "yourself)";
443 } else if (type
->is_list() || type
->is_set()) {
445 if (type
->is_list()) {
446 etype
= ((t_list
*)type
)->get_elem_type();
448 etype
= ((t_set
*)type
)->get_elem_type();
450 if (type
->is_set()) {
451 out
<< "(Set new" << endl
;
453 out
<< "(OrderedCollection new" << endl
;
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
);
464 out
<< indent() << indent() << "yourself)";
468 throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type
->get_name();
474 * Generates a Smalltalk struct
476 void t_st_generator::generate_struct(t_struct
* tstruct
) {
477 generate_st_struct(f_
, tstruct
, false);
481 * Generates a struct definition for a thrift exception. Basically the same
482 * as a struct but extends the Exception class.
484 * @param txception The struct definition
486 void t_st_generator::generate_xception(t_struct
* txception
) {
487 generate_st_struct(f_
, txception
, true);
491 * Generates a smalltalk class to represent a struct
493 void t_st_generator::generate_st_struct(std::ostream
& out
,
495 bool is_exception
= false) {
496 const vector
<t_field
*>& members
= tstruct
->get_members();
497 vector
<t_field
*>::const_iterator m_iter
;
504 out
<< " subclass: #" << prefix(type_name(tstruct
)) << endl
<< "\tinstanceVariableNames: '";
506 if (members
.size() > 0) {
507 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
) {
508 if (m_iter
!= members
.begin())
510 out
<< camelcase((*m_iter
)->get_name());
515 << "\tclassVariableNames: ''\n"
516 << "\tpoolDictionaries: ''\n"
517 << "\tcategory: '" << generated_category() << "'!\n\n";
519 generate_accessors(out
, tstruct
);
522 bool t_st_generator::is_vowel(char c
) {
523 switch (tolower(c
)) {
534 string
t_st_generator::a_type(t_type
* type
) {
537 if (is_vowel(type_name(type
)[0]))
542 return prefix
+ capitalize(type_name(type
));
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
;
551 if (members
.size() > 0) {
552 for (m_iter
= members
.begin(); m_iter
!= members
.end(); ++m_iter
) {
554 capitalize(type_name(tstruct
)),
555 camelcase((*m_iter
)->get_name()),
556 a_type((*m_iter
)->get_type()));
563 * Generates a thrift service.
565 * @param tservice The service definition
567 void t_st_generator::generate_service(t_service
* tservice
) {
568 generate_service_client(tservice
);
569 // generate_service_server(tservice);
572 string
t_st_generator::temp_name() {
573 std::ostringstream out
;
574 out
<< "temp" << temporary_var
++;
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();
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)."
588 out
<< indent() << fname
<< " keysAndValuesDo: [:" << key
<< " :" << val
<< " |" << endl
;
591 out
<< indent() << write_val(tmap
->get_key_type(), key
) << "." << endl
<< indent()
592 << write_val(tmap
->get_val_type(), val
);
595 out
<< "]." << endl
<< indent() << "oprot writeMapEnd] value";
601 string
t_st_generator::map_reader(t_map
* tmap
) {
602 std::ostringstream out
;
603 string desc
= temp_name();
604 string val
= temp_name();
606 out
<< "[|" << desc
<< " " << val
<< "| " << endl
;
609 out
<< indent() << desc
<< " := iprot readMapBegin." << endl
<< indent() << val
610 << " := Dictionary new." << endl
<< indent() << desc
<< " size timesRepeat: [" << endl
;
613 out
<< indent() << val
<< " at: " << read_val(tmap
->get_key_type())
614 << " put: " << read_val(tmap
->get_val_type());
617 out
<< "]." << endl
<< indent() << "iprot readMapEnd." << endl
<< indent() << val
<< "] value";
623 string
t_st_generator::list_writer(t_list
* tlist
, string fname
) {
624 std::ostringstream out
;
625 string val
= temp_name();
627 out
<< "[oprot writeListBegin: (TList new elemType: " << type_to_enum(tlist
->get_elem_type())
628 << "; size: " << fname
<< " size)." << endl
;
631 out
<< indent() << fname
<< " do: [:" << val
<< "|" << endl
;
634 out
<< indent() << write_val(tlist
->get_elem_type(), val
) << endl
;
637 out
<< "]." << endl
<< indent() << "oprot writeListEnd] value";
643 string
t_st_generator::list_reader(t_list
* tlist
) {
644 std::ostringstream out
;
645 string desc
= temp_name();
646 string val
= temp_name();
648 out
<< "[|" << desc
<< " " << val
<< "| " << desc
<< " := iprot readListBegin." << endl
;
651 out
<< indent() << val
<< " := OrderedCollection new." << endl
<< indent() << desc
652 << " size timesRepeat: [" << endl
;
655 out
<< indent() << val
<< " add: " << read_val(tlist
->get_elem_type());
658 out
<< "]." << endl
<< indent() << "iprot readListEnd." << endl
<< indent() << val
<< "] value";
664 string
t_st_generator::set_writer(t_set
* tset
, string fname
) {
665 std::ostringstream out
;
666 string val
= temp_name();
668 out
<< "[oprot writeSetBegin: (TSet new elemType: " << type_to_enum(tset
->get_elem_type())
669 << "; size: " << fname
<< " size)." << endl
;
672 out
<< indent() << fname
<< " do: [:" << val
<< "|" << endl
;
675 out
<< indent() << write_val(tset
->get_elem_type(), val
) << endl
;
678 out
<< "]." << endl
<< indent() << "oprot writeSetEnd] value";
684 string
t_st_generator::set_reader(t_set
* tset
) {
685 std::ostringstream out
;
686 string desc
= temp_name();
687 string val
= temp_name();
689 out
<< "[|" << desc
<< " " << val
<< "| " << desc
<< " := iprot readSetBegin." << endl
;
692 out
<< indent() << val
<< " := Set new." << endl
<< indent() << desc
<< " size timesRepeat: ["
696 out
<< indent() << val
<< " add: " << read_val(tset
->get_elem_type());
699 out
<< "]." << endl
<< indent() << "iprot readSetEnd." << endl
<< indent() << val
<< "] value";
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
;
710 out
<< "[oprot writeStructBegin: "
711 << "(TStruct new name: '" + tstruct
->get_name() + "')." << endl
;
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
);
720 out
<< indent() << accessor
<< " ifNotNil: [" << endl
;
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
;
728 out
<< indent() << write_val((*fld_iter
)->get_type(), accessor
) << "." << endl
<< indent()
729 << "oprot writeFieldEnd";
739 out
<< indent() << "oprot writeFieldStop; writeStructEnd] value";
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();
753 if (clsName
.size() == 0) {
754 clsName
= tstruct
->get_name();
757 out
<< "[|" << desc
<< " " << val
<< "|" << endl
;
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
;
764 out
<< indent() << "iprot readStructBegin." << endl
<< indent() << "[" << desc
765 << " := iprot readFieldBegin." << endl
<< indent() << desc
766 << " type = TType stop] whileFalse: [|" << found
<< "|" << endl
;
769 for (fld_iter
= fields
.begin(); fld_iter
!= fields
.end(); ++fld_iter
) {
770 out
<< indent() << desc
<< " id = " << (*fld_iter
)->get_key() << " ifTrue: [" << endl
;
773 out
<< indent() << found
<< " := true." << endl
<< indent() << val
<< " "
774 << camelcase((*fld_iter
)->get_name()) << ": " << read_val((*fld_iter
)->get_type());
780 out
<< indent() << found
<< " ifNil: [iprot skip: " << desc
<< " type]]." << endl
;
783 out
<< indent() << "oprot readStructEnd." << endl
<< indent() << val
<< "] value";
789 string
t_st_generator::write_val(t_type
* t
, string fname
) {
790 t
= get_true_type(t
);
792 if (t
->is_base_type()) {
793 t_base_type::t_base tbase
= ((t_base_type
*)t
)->get_base();
795 case t_base_type::TYPE_DOUBLE
:
796 return "iprot writeDouble: " + fname
+ " asFloat";
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";
804 return "iprot write" + capitalize(type_name(t
)) + ": " + fname
;
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
;
817 throw "Sorry, I don't know how to write this: " + type_name(t
);
821 string
t_st_generator::read_val(t_type
* t
) {
822 t
= get_true_type(t
);
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";
837 throw "Sorry, I don't know how to read this: " + type_name(t
);
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
;
848 st_method(f_
, client_class_name(), "send" + capitalize(signature
));
849 f_
<< "oprot writeMessageBegin:" << endl
;
852 f_
<< indent() << "(TCallMessage new" << endl
;
855 f_
<< indent() << "name: '" << funname
<< "'; " << endl
<< indent() << "seqid: self nextSeqid)."
860 f_
<< indent() << "oprot writeStructBegin: "
861 << "(TStruct new name: '" + capitalize(camelcase(funname
)) + "_args')." << endl
;
863 for (fld_iter
= fields
.begin(); fld_iter
!= fields
.end(); ++fld_iter
) {
864 string fname
= camelcase((*fld_iter
)->get_name());
866 f_
<< indent() << "oprot writeFieldBegin: (TField new name: '" << fname
867 << "'; type: " << type_to_enum((*fld_iter
)->get_type()) << "; id: " << (*fld_iter
)->get_key()
870 f_
<< indent() << write_val((*fld_iter
)->get_type(), fname
) << "." << endl
<< indent()
871 << "oprot writeFieldEnd." << endl
;
874 f_
<< indent() << "oprot writeFieldStop; writeStructEnd; writeMessageEnd." << endl
;
875 f_
<< indent() << "oprot transport flush";
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
);
885 t_struct
result(program_
, "TResult");
886 t_field
success(function
->get_returntype(), "success", 0);
887 result
.append(&success
);
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
);
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";
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
;
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()) {
927 * Generates a service client definition.
929 * @param tservice The service to generate a server for.
931 void t_st_generator::generate_service_client(t_service
* tservice
) {
933 string extends_client
= "TClient";
934 vector
<t_function
*> functions
= tservice
->get_functions();
935 vector
<t_function
*>::iterator f_iter
;
937 if (tservice
->get_extends() != NULL
) {
938 extends
= type_name(tservice
->get_extends());
939 extends_client
= extends
+ "Client";
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";
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
);
952 st_method(f_
, client_class_name(), signature
);
953 f_
<< function_types_comment(*f_iter
) << endl
<< indent() << "self send"
954 << capitalize(signature
) << "." << endl
;
956 if (!(*f_iter
)->is_oneway()) {
957 f_
<< indent() << "^ self recv" << capitalize(funname
) << " success " << endl
;
962 generate_send_method(*f_iter
);
963 if (!(*f_iter
)->is_oneway()) {
964 generate_recv_method(*f_iter
);
970 * Renders a function signature of the form 'type name(args)'
972 * @param tfunction Function definition
973 * @return String of rendered function definition
975 string
t_st_generator::function_signature(t_function
* tfunction
) {
976 return camelcase(tfunction
->get_name()) + capitalize(argument_list(tfunction
->get_arglist()));
980 * Renders a field list
982 string
t_st_generator::argument_list(t_struct
* tstruct
) {
985 const vector
<t_field
*>& fields
= tstruct
->get_members();
986 vector
<t_field
*>::const_iterator f_iter
;
988 for (f_iter
= fields
.begin(); f_iter
!= fields
.end(); ++f_iter
) {
994 string name
= camelcase((*f_iter
)->get_name());
995 result
+= name
+ ": " + name
;
1000 string
t_st_generator::type_name(t_type
* ttype
) {
1002 t_program
* program
= ttype
->get_program();
1003 if (program
!= NULL
&& program
!= program_
) {
1004 if (!ttype
->is_service()) {
1005 prefix
= program
->get_name() + "_types.";
1009 string name
= ttype
->get_name();
1010 if (ttype
->is_struct() || ttype
->is_xception()) {
1011 name
= capitalize(ttype
->get_name());
1014 return prefix
+ name
;
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
);
1021 if (type
->is_base_type()) {
1022 t_base_type::t_base tbase
= ((t_base_type
*)type
)->get_base();
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
:
1034 case t_base_type::TYPE_I32
:
1036 case t_base_type::TYPE_I64
:
1038 case t_base_type::TYPE_DOUBLE
:
1039 return "TType double";
1041 } else if (type
->is_enum()) {
1043 } else if (type
->is_struct() || type
->is_xception()) {
1044 return "TType struct";
1045 } else if (type
->is_map()) {
1047 } else if (type
->is_set()) {
1049 } else if (type
->is_list()) {
1050 return "TType list";
1053 throw "INVALID TYPE IN type_to_enum: " + type
->get_name();
1056 THRIFT_REGISTER_GENERATOR(st
, "Smalltalk", "")