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