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 
35 using 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  */
113 const 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  */
173 void
174 ToLuaInterfaceGenerator::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  */
212 void
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  */
246 void
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());
255  write_message_superclass_h(f);
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  */
267 void
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  */
287 void
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  */
316 void
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  " unsigned int 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  */
368 void
370 {
371  fprintf(f,
372  " unsigned int id() const;\n"
373  "\n"
374  " unsigned int sender_id() const;\n"
375  " const char * sender_thread_name() const;\n"
376  " Interface * interface() const;\n"
377  " const char * type() const;\n"
378  "\n"
379  " const void * datachunk() const;\n"
380  " unsigned int datasize() const;\n"
381  "\n"
382  " void set_from_chunk(const void *chunk);\n"
383  "\n"
384  " /* from RefCount */\n"
385  " void ref();\n"
386  " void unref();\n"
387  " unsigned int refcount();\n"
388  "\n");
389 }
390 
391 /** Write additional Lua code to file.
392  * The code is required for correctly type message access.
393  * @param f file to write to
394  * @param classname name of the interface class
395  */
396 void
397 ToLuaInterfaceGenerator::write_lua_code(FILE *f, std::string classname)
398 {
399  fprintf(f,
400  "\n$[\n\n"
401  "assert(fawkes.Interface.msgq_first)\n"
402  "assert(fawkes.Interface.msgq_enqueue)\n"
403  "assert(fawkes.Interface.create_message)\n\n"
404  "fawkes.%s.msgq_first = fawkes.Interface.msgq_first\n"
405  "fawkes.%s.msgq_enqueue = fawkes.Interface.msgq_enqueue\n"
406  "fawkes.%s.create_message = fawkes.Interface.create_message\n"
407  "\n$]\n\n",
408  classname.c_str(),
409  classname.c_str(),
410  classname.c_str());
411 }
412 
413 /** Write methods to h file.
414  * @param f file to write to
415  * @param is indentation space.
416  * @param fields fields to write accessor methods for.
417  */
418 void
420  std::string /* indent space */ is,
421  std::vector<InterfaceField> fields)
422 {
423  for (vector<InterfaceField>::iterator i = fields.begin(); i != fields.end(); ++i) {
424  if ((i->getLengthValue() > 0) && (i->getType() != "string")) {
425  fprintf(f,
426  "%s%s %s%s(int index);\n",
427  is.c_str(),
428  (i->getType() == "byte") ? "unsigned int" : convert_type(i->getPlainAccessType()),
429  (((*i).getType() == "bool") ? "is_" : ""),
430  (*i).getName().c_str());
431 
432  fprintf(f,
433  "%svoid set_%s(unsigned int index, const %s new_%s);\n",
434  is.c_str(),
435  (*i).getName().c_str(),
436  convert_type(i->getPlainAccessType()),
437  i->getName().c_str());
438  } else {
439  fprintf(f,
440  "%s%s %s%s();\n",
441  is.c_str(),
442  convert_type(i->getAccessType()),
443  (((*i).getType() == "bool") ? "is_" : ""),
444  (*i).getName().c_str());
445 
446  fprintf(f,
447  "%svoid set_%s(const %s new_%s);\n",
448  is.c_str(),
449  (*i).getName().c_str(),
450  convert_type(i->getAccessType()),
451  i->getName().c_str());
452  }
453  fprintf(f, "%sint maxlenof_%s() const;\n", is.c_str(), (*i).getName().c_str());
454  }
455 }
456 
457 /** Write methods to h file.
458  * @param f file to write to
459  * @param is indentation space.
460  * @param fields fields to write accessor methods for.
461  * @param pseudo_maps pseudo maps
462  */
463 void
465  std::string /* indent space */ is,
466  std::vector<InterfaceField> fields,
467  std::vector<InterfacePseudoMap> pseudo_maps)
468 {
469  write_methods_h(f, is, fields);
470 
471  for (vector<InterfacePseudoMap>::iterator i = pseudo_maps.begin(); i != pseudo_maps.end(); ++i) {
472  fprintf(f,
473  "%s%s %s(%s key) const;\n"
474  "%svoid set_%s(const %s key, const %s new_value);\n",
475  is.c_str(),
476  convert_type(i->getType()),
477  (*i).getName().c_str(),
478  convert_type(i->getKeyType()),
479  is.c_str(),
480  (*i).getName().c_str(),
481  convert_type(i->getKeyType()),
482  convert_type(i->getType()));
483  }
484 }
485 
486 /** Write h file.
487  * @param f file to write to
488  */
489 void
491 {
492  fprintf(f,
493  "$#include <interfaces/%s>\n"
494  "$#include <utils/time/time.h>\n"
495  "$#include <utils/time/clock.h>\n"
496  "$using namespace fawkes;\n"
497  "namespace fawkes {\n"
498  "class %s : public Interface\n"
499  "{\n",
500  filename_h.c_str(),
501  class_name.c_str());
502 
503  write_constants_h(f);
504  write_messages_h(f);
505  //write_ctor_dtor_h(f, " ", class_name);
506  write_methods_h(f, " ", data_fields, pseudo_maps);
507  write_superclass_h(f);
508  fprintf(f, "\n};\n\n");
509  write_lua_code(f, class_name);
510  fprintf(f, "}\n");
511 }
512 
513 /** Generator cpp and h files.
514  */
515 void
517 {
518  char timestring[26]; // 26 is mentioned in man asctime_r
519  struct tm timestruct;
520  time_t t = time(NULL);
521  localtime_r(&t, &timestruct);
522  asctime_r(&timestruct, timestring);
523  gendate = timestring;
524 
525  FILE *toluaf;
526 
527  toluaf = fopen(string(dir + filename_tolua).c_str(), "w");
528 
529  if (toluaf == NULL) {
530  printf("Cannot open tolua file %s%s\n", dir.c_str(), filename_tolua.c_str());
531  }
532 
533  write_toluaf(toluaf);
534 
535  fclose(toluaf);
536 }
ToLuaInterfaceGenerator::~ToLuaInterfaceGenerator
~ToLuaInterfaceGenerator()
Destructor.
Definition: tolua_generator.cpp:103
ToLuaInterfaceGenerator::write_superclass_h
void write_superclass_h(FILE *f)
Write superclass methods.
Definition: tolua_generator.cpp:317
ToLuaInterfaceGenerator::write_methods_h
void write_methods_h(FILE *f, std::string is, std::vector< InterfaceField > fields)
Write methods to h file.
Definition: tolua_generator.cpp:419
ToLuaInterfaceGenerator::write_constants_h
void write_constants_h(FILE *f)
Write constants to h file.
Definition: tolua_generator.cpp:213
ToLuaInterfaceGenerator::write_ctor_dtor_h
void write_ctor_dtor_h(FILE *f, std::string is, std::string classname)
Write constructor and destructor to h file.
Definition: tolua_generator.cpp:268
ToLuaInterfaceGenerator::generate
void generate()
Generator cpp and h files.
Definition: tolua_generator.cpp:516
ToLuaInterfaceGenerator::convert_type
const char * convert_type(std::string c_type)
Convert C type to Lua type.
Definition: tolua_generator.cpp:114
ToLuaInterfaceGenerator::write_lua_code
void write_lua_code(FILE *f, std::string classname)
Write additional Lua code to file.
Definition: tolua_generator.cpp:397
ToLuaInterfaceGenerator::write_header
void write_header(FILE *f, std::string filename)
Write header to file.
Definition: tolua_generator.cpp:174
ToLuaInterfaceGenerator::write_messages_h
void write_messages_h(FILE *f)
Write messages to h file.
Definition: tolua_generator.cpp:247
ToLuaInterfaceGenerator::write_message_superclass_h
void write_message_superclass_h(FILE *f)
Write superclass methods.
Definition: tolua_generator.cpp:369
ToLuaInterfaceGenerator::write_toluaf
void write_toluaf(FILE *f)
Write h file.
Definition: tolua_generator.cpp:490
ToLuaInterfaceGenerator::ToLuaInterfaceGenerator
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.
Definition: tolua_generator.cpp:59
ToLuaInterfaceGenerator::write_message_ctor_dtor_h
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.
Definition: tolua_generator.cpp:288