Fawkes API Fawkes Development Version
tolua_generator.cpp
1
2/***************************************************************************
3 * tolua_generator.cpp - ToLua++ Interface generator
4 *
5 * Created: Tue Mar 11 15:33:26 2006
6 * Copyright 2006-2008 Tim Niemueller [www.niemueller.de]
7 *
8 ****************************************************************************/
9
10/* This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Library General Public License for more details.
19 *
20 * Read the full text in the LICENSE.GPL file in the doc directory.
21 */
22
23#include "tolua_generator.h"
24
25#include "exceptions.h"
26
27#include <utils/misc/string_conversions.h>
28
29#include <algorithm>
30#include <fstream>
31#include <iostream>
32#include <time.h>
33#include <vector>
34
35using namespace std;
36
37/** @class ToLuaInterfaceGenerator <interfaces/generator/tolua_generator.h>
38 * Generator that transforms input from the InterfaceParser into valid
39 * ToLua++ package file.
40 * @author Tim Niemueller
41 */
42
43/** Constructor.
44 * @param directory Directory where to create the files
45 * @param interface_name name of the interface, should end with Interface
46 * @param config_basename basename of the config without suffix
47 * @param author author of interface
48 * @param year year of copyright
49 * @param creation_date user-supplied creation date of interface
50 * @param data_comment comment in data block.
51 * @param hash MD5 hash of the config file that was used to generate the interface
52 * @param hash_size size in bytes of hash
53 * @param constants constants
54 * @param enum_constants constants defined as an enum
55 * @param data_fields data fields of the interface
56 * @param pseudo_maps pseudo maps of the interface
57 * @param messages messages defined in the interface
58 */
60 std::string directory,
61 std::string interface_name,
62 std::string config_basename,
63 std::string author,
64 std::string year,
65 std::string creation_date,
66 std::string data_comment,
67 const unsigned char * hash,
68 size_t hash_size,
69 const std::vector<InterfaceConstant> & constants,
70 const std::vector<InterfaceEnumConstant> &enum_constants,
71 const std::vector<InterfaceField> & data_fields,
72 const std::vector<InterfacePseudoMap> & pseudo_maps,
73 const std::vector<InterfaceMessage> & messages)
74{
75 this->dir = directory;
76 if (dir.find_last_of("/") != (dir.length() - 1)) {
77 dir += "/";
78 }
79 this->author = author;
80 this->year = year;
81 this->creation_date = creation_date;
82 this->data_comment = data_comment;
83 this->hash = hash;
84 this->hash_size = hash_size;
85 this->constants = constants;
86 this->enum_constants = enum_constants;
87 this->data_fields = data_fields;
88 this->pseudo_maps = pseudo_maps;
89 this->messages = messages;
90
91 filename_tolua = config_basename + ".tolua";
92 filename_h = config_basename + ".h";
93
94 if (interface_name.find("Interface", 0) == string::npos) {
95 // append Interface
96 class_name = interface_name + "Interface";
97 } else {
98 class_name = interface_name;
99 }
100}
101
102/** Destructor */
104{
105}
106
107/** Convert C type to Lua type.
108 * tolua++ does not deal well with stdint types, therefore we convert them
109 * to "traditional" types.
110 * @param c_type C type to convert
111 * @return constant string of the Lua compatible type
112 */
113const char *
115{
116 if (c_type == "uint8_t") {
117 return "unsigned char";
118 } else if (c_type == "uint16_t") {
119 return "unsigned short";
120 } else if (c_type == "uint32_t") {
121 return "unsigned int";
122 } else if (c_type == "uint64_t") {
123#if __WORDSIZE == 64 || defined(__x86_64__)
124 return "unsigned long";
125#else
126 return "unsigned long long";
127#endif
128 } else if (c_type == "int8_t") {
129 return "char";
130 } else if (c_type == "int16_t") {
131 return "short";
132 } else if (c_type == "int32_t") {
133 return "int";
134 } else if (c_type == "int64_t") {
135#if __WORDSIZE == 64 || defined(__x86_64__)
136 return "long";
137#else
138 return "long long";
139#endif
140 } else if (c_type == "uint8_t *") {
141 return "unsigned char *";
142 } else if (c_type == "uint16_t *") {
143 return "unsigned short *";
144 } else if (c_type == "uint32_t *") {
145 return "unsigned int *";
146 } else if (c_type == "uint64_t *") {
147#if __WORDSIZE == 64 || defined(__x86_64__)
148 return "unsigned long *";
149#else
150 return "unsigned long long *";
151#endif
152 } else if (c_type == "int8_t *") {
153 return "char *";
154 } else if (c_type == "int16_t *") {
155 return "short *";
156 } else if (c_type == "int32_t *") {
157 return "int *";
158 } else if (c_type == "int64_t *") {
159#if __WORDSIZE == 64 || defined(__x86_64__)
160 return "long *";
161#else
162 return "long long *";
163#endif
164 } else {
165 return c_type.c_str();
166 }
167}
168
169/** Write header to file.
170 * @param f file to write to
171 * @param filename name of file
172 */
173void
174ToLuaInterfaceGenerator::write_header(FILE *f, std::string filename)
175{
176 fprintf(f, "\n/***************************************************************************\n");
177 fprintf(f,
178 " * %s - Fawkes BlackBoard Interface - %s - tolua++ wrapper\n",
179 filename.c_str(),
180 class_name.c_str());
181 fprintf(f, " *\n");
182 if (creation_date.length() > 0) {
183 fprintf(f, " * Interface created: %s\n", creation_date.c_str());
184 }
185 fprintf(f, " * Templated created: Thu Oct 12 10:49:19 2006\n");
186 fprintf(f,
187 " * Copyright %s %s\n",
188 year.c_str(),
189 ((author.length() > 0) ? author.c_str() : "AllemaniACs RoboCup Team"));
190 fprintf(f, " *\n");
191 fprintf(f, " ****************************************************************************/\n\n");
192 fprintf(f, "/*\n");
193 fprintf(f, " * This program is free software; you can redistribute it and/or modify\n");
194 fprintf(f, " * it under the terms of the GNU General Public License as published by\n");
195 fprintf(f, " * the Free Software Foundation; either version 2 of the License, or\n");
196 fprintf(f, " * (at your option) any later version.\n");
197 fprintf(f, " *\n");
198 fprintf(f, " * This program is distributed in the hope that it will be useful,\n");
199 fprintf(f, " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
200 fprintf(f, " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
201 fprintf(f, " * GNU Library General Public License for more details.\n");
202 fprintf(f, " *\n");
203 fprintf(f, " * You should have received a copy of the GNU General Public License\n");
204 fprintf(f, " * along with this program; if not, write to the Free Software Foundation,\n");
205 fprintf(f, " * Inc., 51 Franklin Street, Fifth floor, Boston, MA 02111-1307, USA.\n");
206 fprintf(f, " */\n\n");
207}
208
209/** Write constants to h file
210 * @param f file to write to
211 */
212void
214{
215 for (vector<InterfaceConstant>::iterator i = constants.begin(); i != constants.end(); ++i) {
216 fprintf(f, " static const %s %s;\n", convert_type(i->getType()), i->getName().c_str());
217 }
218 fprintf(f, "\n");
219
220 for (vector<InterfaceEnumConstant>::iterator i = enum_constants.begin();
221 i != enum_constants.end();
222 ++i) {
223 fprintf(f, " typedef enum {\n");
224 vector<InterfaceEnumConstant::EnumItem> items = (*i).get_items();
225 vector<InterfaceEnumConstant::EnumItem>::iterator j = items.begin();
226 while (j != items.end()) {
227 if (j->has_custom_value) {
228 fprintf(f, " %s = %i", j->name.c_str(), j->custom_value);
229 } else {
230 fprintf(f, " %s", j->name.c_str());
231 }
232 ++j;
233 if (j != items.end()) {
234 fprintf(f, ",\n");
235 } else {
236 fprintf(f, "\n");
237 }
238 }
239 fprintf(f, " } %s;\n\n", (*i).get_name().c_str());
240 }
241}
242
243/** Write messages to h file.
244 * @param f file to write to
245 */
246void
248{
249 for (vector<InterfaceMessage>::iterator i = messages.begin(); i != messages.end(); ++i) {
250 fprintf(f,
251 " class %s : public Message\n"
252 " {\n",
253 (*i).getName().c_str());
254 write_message_ctor_dtor_h(f, " ", (*i).getName(), (*i).getFields());
256 write_methods_h(f, " ", (*i).getFields());
257
258 fprintf(f, " };\n\n");
259 }
260}
261
262/** Write constructor and destructor to h file.
263 * @param f file to write to
264 * @param is indentation space
265 * @param classname name of class
266 */
267void
269 std::string /* indent space */ is,
270 std::string classname)
271{
272 fprintf(f,
273 "%s%s();\n"
274 "%s~%s();\n\n",
275 is.c_str(),
276 classname.c_str(),
277 is.c_str(),
278 classname.c_str());
279}
280
281/** Write constructor and destructor for message to h file.
282 * @param f file to write to
283 * @param is indentation space
284 * @param classname name of class
285 * @param fields vector of data fields of message
286 */
287void
289 std::string /* indent space */ is,
290 std::string classname,
291 std::vector<InterfaceField> fields)
292{
293 vector<InterfaceField>::iterator i;
294
295 if (fields.size() > 0) {
296 fprintf(f, "%s%s(", is.c_str(), classname.c_str());
297
298 i = fields.begin();
299 while (i != fields.end()) {
300 fprintf(f, "%s ini_%s", convert_type(i->getAccessType()), i->getName().c_str());
301 ++i;
302 if (i != fields.end()) {
303 fprintf(f, ", ");
304 }
305 }
306
307 fprintf(f, ");\n");
308 }
309
310 write_ctor_dtor_h(f, is, classname);
311}
312
313/** Write superclass methods.
314 * @param f file to write to
315 */
316void
318{
319 fprintf(f,
320 " bool oftype(const char *interface_type) const;\n"
321 " const void * datachunk() const;\n"
322 " unsigned int datasize() const;\n"
323 " const char * type() const;\n"
324 " const char * id() const;\n"
325 " const char * uid() const;\n"
326 " fawkes::Uuid serial() const;\n"
327 " unsigned int mem_serial() const;\n"
328 " bool operator== (Interface &comp) const;\n"
329 " const unsigned char * hash() const;\n"
330 " int hash_size() const;\n"
331 " const char * hash_printable() const;\n"
332 " bool is_writer() const;\n"
333
334 " void set_from_chunk(void *chunk);\n"
335
336 " virtual fawkes::Message * create_message @ create_message_generic(const char *type) "
337 "const;\n"
338
339 " void read();\n"
340 " void write();\n"
341
342 " bool has_writer() const;\n"
343 " unsigned int num_readers() const;\n"
344
345 " bool changed() const;\n"
346 " const fawkes::Time * timestamp() const;\n"
347 " void set_auto_timestamping(bool enabled);\n"
348 " void set_timestamp(const fawkes::Time *t);\n"
349 " void set_clock(fawkes::Clock *clock);\n"
350
351 " unsigned int msgq_enqueue_copy(Message *message);\n"
352 " void msgq_remove(Message *message);\n"
353 " void msgq_remove(unsigned int message_id);\n"
354 " unsigned int msgq_size();\n"
355 " void msgq_flush();\n"
356 " void msgq_lock();\n"
357 " bool msgq_try_lock();\n"
358 " void msgq_unlock();\n"
359 " void msgq_pop();\n"
360 " fawkes::Message * msgq_first @ msgq_first_generic();\n"
361 " bool msgq_empty();\n"
362 "\n");
363}
364
365/** Write superclass methods.
366 * @param f file to write to
367 */
368void
370{
371 fprintf(f,
372 " unsigned int id() const;\n"
373 "\n"
374 " fawkes::Uuid sender_id() const;\n"
375 " fawkes::Uuid source_id() const;\n"
376 " const char * sender_thread_name() const;\n"
377 " Interface * interface() const;\n"
378 " const char * type() const;\n"
379 "\n"
380 " const void * datachunk() const;\n"
381 " unsigned int datasize() const;\n"
382 "\n"
383 " void set_from_chunk(const void *chunk);\n"
384 "\n"
385 " /* from RefCount */\n"
386 " void ref();\n"
387 " void unref();\n"
388 " unsigned int refcount();\n"
389 "\n");
390}
391
392/** Write additional Lua code to file.
393 * The code is required for correctly type message access.
394 * @param f file to write to
395 * @param classname name of the interface class
396 */
397void
398ToLuaInterfaceGenerator::write_lua_code(FILE *f, std::string classname)
399{
400 fprintf(f,
401 "\n$[\n\n"
402 "assert(fawkes.Interface.msgq_first)\n"
403 "assert(fawkes.Interface.msgq_enqueue)\n"
404 "assert(fawkes.Interface.create_message)\n\n"
405 "fawkes.%s.msgq_first = fawkes.Interface.msgq_first\n"
406 "fawkes.%s.msgq_enqueue = fawkes.Interface.msgq_enqueue\n"
407 "fawkes.%s.create_message = fawkes.Interface.create_message\n"
408 "\n$]\n\n",
409 classname.c_str(),
410 classname.c_str(),
411 classname.c_str());
412}
413
414/** Write methods to h file.
415 * @param f file to write to
416 * @param is indentation space.
417 * @param fields fields to write accessor methods for.
418 */
419void
421 std::string /* indent space */ is,
422 std::vector<InterfaceField> fields)
423{
424 for (vector<InterfaceField>::iterator i = fields.begin(); i != fields.end(); ++i) {
425 if ((i->getLengthValue() > 0) && (i->getType() != "string")) {
426 fprintf(f,
427 "%s%s %s%s(int index);\n",
428 is.c_str(),
429 (i->getType() == "byte") ? "unsigned int" : convert_type(i->getPlainAccessType()),
430 (((*i).getType() == "bool") ? "is_" : ""),
431 (*i).getName().c_str());
432
433 fprintf(f,
434 "%svoid set_%s(unsigned int index, const %s new_%s);\n",
435 is.c_str(),
436 (*i).getName().c_str(),
437 convert_type(i->getPlainAccessType()),
438 i->getName().c_str());
439 } else {
440 fprintf(f,
441 "%s%s %s%s();\n",
442 is.c_str(),
443 convert_type(i->getAccessType()),
444 (((*i).getType() == "bool") ? "is_" : ""),
445 (*i).getName().c_str());
446
447 fprintf(f,
448 "%svoid set_%s(const %s new_%s);\n",
449 is.c_str(),
450 (*i).getName().c_str(),
451 convert_type(i->getAccessType()),
452 i->getName().c_str());
453 }
454 fprintf(f, "%sint maxlenof_%s() const;\n", is.c_str(), (*i).getName().c_str());
455 }
456}
457
458/** Write methods to h file.
459 * @param f file to write to
460 * @param is indentation space.
461 * @param fields fields to write accessor methods for.
462 * @param pseudo_maps pseudo maps
463 */
464void
466 std::string /* indent space */ is,
467 std::vector<InterfaceField> fields,
468 std::vector<InterfacePseudoMap> pseudo_maps)
469{
470 write_methods_h(f, is, fields);
471
472 for (vector<InterfacePseudoMap>::iterator i = pseudo_maps.begin(); i != pseudo_maps.end(); ++i) {
473 fprintf(f,
474 "%s%s %s(%s key) const;\n"
475 "%svoid set_%s(const %s key, const %s new_value);\n",
476 is.c_str(),
477 convert_type(i->getType()),
478 (*i).getName().c_str(),
479 convert_type(i->getKeyType()),
480 is.c_str(),
481 (*i).getName().c_str(),
482 convert_type(i->getKeyType()),
483 convert_type(i->getType()));
484 }
485}
486
487/** Write h file.
488 * @param f file to write to
489 */
490void
492{
493 fprintf(f,
494 "$#include <interfaces/%s>\n"
495 "$#include <utils/time/time.h>\n"
496 "$#include <utils/time/clock.h>\n"
497 "$using namespace fawkes;\n"
498 "namespace fawkes {\n"
499 "class %s : public Interface\n"
500 "{\n",
501 filename_h.c_str(),
502 class_name.c_str());
503
506 //write_ctor_dtor_h(f, " ", class_name);
507 write_methods_h(f, " ", data_fields, pseudo_maps);
509 fprintf(f, "\n};\n\n");
510 write_lua_code(f, class_name);
511 fprintf(f, "}\n");
512}
513
514/** Generator cpp and h files.
515 */
516void
518{
519 char timestring[26]; // 26 is mentioned in man asctime_r
520 struct tm timestruct;
521 time_t t = time(NULL);
522 localtime_r(&t, &timestruct);
523 asctime_r(&timestruct, timestring);
524 gendate = timestring;
525
526 FILE *toluaf;
527
528 toluaf = fopen(string(dir + filename_tolua).c_str(), "w");
529
530 if (toluaf == NULL) {
531 printf("Cannot open tolua file %s%s\n", dir.c_str(), filename_tolua.c_str());
532 }
533
534 write_toluaf(toluaf);
535
536 fclose(toluaf);
537}
void write_methods_h(FILE *f, std::string is, std::vector< InterfaceField > fields)
Write methods to h file.
void write_lua_code(FILE *f, std::string classname)
Write additional Lua code to file.
void write_superclass_h(FILE *f)
Write superclass methods.
void write_messages_h(FILE *f)
Write messages to h file.
ToLuaInterfaceGenerator(std::string directory, std::string interface_name, std::string config_basename, std::string author, std::string year, std::string creation_date, std::string data_comment, const unsigned char *hash, size_t hash_size, const std::vector< InterfaceConstant > &constants, const std::vector< InterfaceEnumConstant > &enum_constants, const std::vector< InterfaceField > &data_fields, const std::vector< InterfacePseudoMap > &pseudo_maps, const std::vector< InterfaceMessage > &messages)
Constructor.
void write_header(FILE *f, std::string filename)
Write header to file.
~ToLuaInterfaceGenerator()
Destructor.
void write_message_superclass_h(FILE *f)
Write superclass methods.
void write_ctor_dtor_h(FILE *f, std::string is, std::string classname)
Write constructor and destructor to h file.
const char * convert_type(std::string c_type)
Convert C type to Lua type.
void write_message_ctor_dtor_h(FILE *f, std::string is, std::string classname, std::vector< InterfaceField > fields)
Write constructor and destructor for message to h file.
void write_constants_h(FILE *f)
Write constants to h file.
void write_toluaf(FILE *f)
Write h file.
void generate()
Generator cpp and h files.