Fawkes API  Fawkes Development Version
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
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 #include "exceptions.h"
25 
26 #include <utils/misc/string_conversions.h>
27 
28 #include <algorithm>
29 #include <iostream>
30 #include <vector>
31 #include <time.h>
32 #include <fstream>
33 
34 using namespace std;
35 
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  */
59 ToLuaInterfaceGenerator::ToLuaInterfaceGenerator(std::string directory, std::string interface_name,
60  std::string config_basename, std::string author,
61  std::string year, std::string creation_date,
62  std::string data_comment,
63  const unsigned char *hash, size_t hash_size,
64  const std::vector<InterfaceConstant> &constants,
65  const std::vector<InterfaceEnumConstant> &enum_constants,
66  const std::vector<InterfaceField> &data_fields,
67  const std::vector<InterfacePseudoMap> &pseudo_maps,
68  const std::vector<InterfaceMessage> &messages
69  )
70 {
71  this->dir = directory;
72  if ( dir.find_last_of("/") != (dir.length() - 1) ) {
73  dir += "/";
74  }
75  this->author = author;
76  this->year = year;
77  this->creation_date = creation_date;
78  this->data_comment = data_comment;
79  this->hash = hash;
80  this->hash_size = hash_size;
81  this->constants = constants;
82  this->enum_constants = enum_constants;
83  this->data_fields = data_fields;
84  this->pseudo_maps = pseudo_maps;
85  this->messages = messages;
86 
87  filename_tolua = config_basename + ".tolua";
88  filename_h = config_basename + ".h";
89 
90  if ( interface_name.find("Interface", 0) == string::npos ) {
91  // append Interface
92  class_name = interface_name + "Interface";
93  } else {
94  class_name = interface_name;
95  }
96 }
97 
98 
99 /** Destructor */
101 {
102 }
103 
104 
105 /** Convert C type to Lua type.
106  * tolua++ does not deal well with stdint types, therefore we convert them
107  * to "traditional" types.
108  * @param c_type C type to convert
109  * @return constant string of the Lua compatible type
110  */
111 const char *
113 {
114  if (c_type == "uint8_t") {
115  return "unsigned char";
116  } else if (c_type == "uint16_t") {
117  return "unsigned short";
118  } else if (c_type == "uint32_t") {
119  return "unsigned int";
120  } else if (c_type == "uint64_t") {
121 #if __WORDSIZE == 64
122  return "unsigned long";
123 #else
124  return "unsigned long long";
125 #endif
126  } else if (c_type == "int8_t") {
127  return "char";
128  } else if (c_type == "int16_t") {
129  return "short";
130  } else if (c_type == "int32_t") {
131  return "int";
132  } else if (c_type == "int64_t") {
133 #if __WORDSIZE == 64
134  return "long";
135 #else
136  return "long long";
137 #endif
138  } else if (c_type == "uint8_t *") {
139  return "unsigned char *";
140  } else if (c_type == "uint16_t *") {
141  return "unsigned short *";
142  } else if (c_type == "uint32_t *") {
143  return "unsigned int *";
144  } else if (c_type == "uint64_t *") {
145 #if __WORDSIZE == 64
146  return "unsigned long *";
147 #else
148  return "unsigned long long *";
149 #endif
150  } else if (c_type == "int8_t *") {
151  return "char *";
152  } else if (c_type == "int16_t *") {
153  return "short *";
154  } else if (c_type == "int32_t *") {
155  return "int *";
156  } else if (c_type == "int64_t *") {
157 #if __WORDSIZE == 64
158  return "long *";
159 #else
160  return "long long *";
161 #endif
162  } else {
163  return c_type.c_str();
164  }
165 }
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, " * %s - Fawkes BlackBoard Interface - %s - tolua++ wrapper\n", filename.c_str(), class_name.c_str());
178  fprintf(f, " *\n");
179  if ( creation_date.length() > 0 ) {
180  fprintf(f, " * Interface created: %s\n", creation_date.c_str());
181  }
182  fprintf(f, " * Templated created: Thu Oct 12 10:49:19 2006\n");
183  fprintf(f, " * Copyright %s %s\n", year.c_str(),
184  ((author.length() > 0) ? author.c_str() : "AllemaniACs RoboCup Team") );
185  fprintf(f, " *\n");
186  fprintf(f, " ****************************************************************************/\n\n");
187  fprintf(f, "/*\n");
188  fprintf(f, " * This program is free software; you can redistribute it and/or modify\n");
189  fprintf(f, " * it under the terms of the GNU General Public License as published by\n");
190  fprintf(f, " * the Free Software Foundation; either version 2 of the License, or\n");
191  fprintf(f, " * (at your option) any later version.\n");
192  fprintf(f, " *\n");
193  fprintf(f, " * This program is distributed in the hope that it will be useful,\n");
194  fprintf(f, " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
195  fprintf(f, " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
196  fprintf(f, " * GNU Library General Public License for more details.\n");
197  fprintf(f, " *\n");
198  fprintf(f, " * You should have received a copy of the GNU General Public License\n");
199  fprintf(f, " * along with this program; if not, write to the Free Software Foundation,\n");
200  fprintf(f, " * Inc., 51 Franklin Street, Fifth floor, Boston, MA 02111-1307, USA.\n");
201  fprintf(f, " */\n\n");
202 }
203 
204 
205 /** Write constants to h file
206  * @param f file to write to
207  */
208 void
210 {
211  for ( vector<InterfaceConstant>::iterator i = constants.begin(); i != constants.end(); ++i) {
212  fprintf(f, " static const %s %s;\n", convert_type(i->getType()),
213  i->getName().c_str());
214  }
215  fprintf(f, "\n");
216 
217  for ( vector<InterfaceEnumConstant>::iterator i = enum_constants.begin(); i != enum_constants.end(); ++i) {
218  fprintf(f, " typedef enum {\n");
219  vector<InterfaceEnumConstant::EnumItem> items = (*i).get_items();
220  vector<InterfaceEnumConstant::EnumItem>::iterator j = items.begin();
221  while (j != items.end()) {
222  if (j->has_custom_value) {
223  fprintf(f, " %s = %i", j->name.c_str(), j->custom_value);
224  } else {
225  fprintf(f, " %s", j->name.c_str());
226  }
227  ++j;
228  if ( j != items.end() ) {
229  fprintf(f, ",\n");
230  } else {
231  fprintf(f, "\n");
232  }
233  }
234  fprintf(f, " } %s;\n\n", (*i).get_name().c_str());
235  }
236 }
237 
238 
239 /** Write messages to h file.
240  * @param f file to write to
241  */
242 void
244 {
245  for (vector<InterfaceMessage>::iterator i = messages.begin(); i != messages.end(); ++i) {
246  fprintf(f, " class %s : public Message\n"
247  " {\n", (*i).getName().c_str());
248  write_message_ctor_dtor_h(f, " ", (*i).getName(), (*i).getFields());
249  write_methods_h(f, " ", (*i).getFields());
250 
251  fprintf(f, " };\n\n");
252  }
253 
254 }
255 
256 
257 /** Write constructor and destructor to h file.
258  * @param f file to write to
259  * @param is indentation space
260  * @param classname name of class
261  */
262 void
263 ToLuaInterfaceGenerator::write_ctor_dtor_h(FILE *f, std::string /* indent space */ is,
264  std::string classname)
265 {
266  fprintf(f,
267  "%s%s();\n"
268  "%s~%s();\n\n",
269  is.c_str(), classname.c_str(),
270  is.c_str(), classname.c_str());
271 }
272 
273 
274 /** Write constructor and destructor for message to h file.
275  * @param f file to write to
276  * @param is indentation space
277  * @param classname name of class
278  * @param fields vector of data fields of message
279  */
280 void
281 ToLuaInterfaceGenerator::write_message_ctor_dtor_h(FILE *f, std::string /* indent space */ is,
282  std::string classname,
283  std::vector<InterfaceField> fields)
284 {
285  vector<InterfaceField>::iterator i;
286 
287  if ( fields.size() > 0 ) {
288 
289  fprintf(f, "%s%s(", is.c_str(), classname.c_str());
290 
291  i = fields.begin();
292  while (i != fields.end()) {
293  fprintf(f, "%s ini_%s",
294  convert_type(i->getAccessType()), i->getName().c_str());
295  ++i;
296  if ( i != fields.end() ) {
297  fprintf(f, ", ");
298  }
299  }
300 
301  fprintf(f, ");\n");
302  }
303 
304 
305  write_ctor_dtor_h(f, is, classname);
306 }
307 
308 /** Write superclass methods.
309  * @param f file to write to
310  */
311 void
313 {
314  fprintf(f,
315  " bool oftype(const char *interface_type) const;\n"
316  " const void * datachunk() const;\n"
317  " unsigned int datasize() const;\n"
318  " const char * type() const;\n"
319  " const char * id() const;\n"
320  " const char * uid() const;\n"
321  " unsigned int serial() const;\n"
322  " unsigned int mem_serial() const;\n"
323  " bool operator== (Interface &comp) const;\n"
324  " const unsigned char * hash() const;\n"
325  " int hash_size() const;\n"
326  " const char * hash_printable() const;\n"
327  " bool is_writer() const;\n"
328 
329  " void set_from_chunk(void *chunk);\n"
330 
331  " virtual Message * create_message(const char *type) const = 0;\n"
332 
333  " void read();\n"
334  " void write();\n"
335 
336  " bool has_writer() const;\n"
337  " unsigned int num_readers() const;\n"
338 
339 
340  " unsigned int msgq_enqueue_copy(Message *message);\n"
341  " void msgq_remove(Message *message);\n"
342  " void msgq_remove(unsigned int message_id);\n"
343  " unsigned int msgq_size();\n"
344  " void msgq_flush();\n"
345  " void msgq_lock();\n"
346  " bool msgq_try_lock();\n"
347  " void msgq_unlock();\n"
348  " void msgq_pop();\n"
349  " Message * msgq_first();\n"
350  " bool msgq_empty();\n"
351  "\n");
352 }
353 
354 /** Write methods to h file.
355  * @param f file to write to
356  * @param is indentation space.
357  * @param fields fields to write accessor methods for.
358  */
359 void
360 ToLuaInterfaceGenerator::write_methods_h(FILE *f, std::string /* indent space */ is,
361  std::vector<InterfaceField> fields)
362 {
363  for (vector<InterfaceField>::iterator i = fields.begin(); i != fields.end(); ++i) {
364 
365  if ( (i->getLengthValue() > 0) && (i->getType() != "string" ) ) {
366  fprintf(f,
367  "%s%s %s%s(int index);\n",
368  is.c_str(),
369  (i->getType() == "byte") ? "unsigned int" : convert_type(i->getPlainAccessType()),
370  ( ((*i).getType() == "bool" ) ? "is_" : ""),
371  (*i).getName().c_str());
372 
373  fprintf(f,
374  "%svoid set_%s(unsigned int index, const %s new_%s);\n",
375  is.c_str(), (*i).getName().c_str(),
376  convert_type(i->getPlainAccessType()), i->getName().c_str());
377  } else {
378  fprintf(f,
379  "%s%s %s%s();\n",
380  is.c_str(), convert_type(i->getAccessType()),
381  ( ((*i).getType() == "bool" ) ? "is_" : ""),
382  (*i).getName().c_str());
383 
384  fprintf(f,
385  "%svoid set_%s(const %s new_%s);\n",
386  is.c_str(), (*i).getName().c_str(),
387  convert_type(i->getAccessType()), i->getName().c_str());
388  }
389  fprintf(f,
390  "%sint maxlenof_%s() const;\n",
391  is.c_str(), (*i).getName().c_str()
392  );
393  }
394 }
395 
396 
397 /** Write methods to h file.
398  * @param f file to write to
399  * @param is indentation space.
400  * @param fields fields to write accessor methods for.
401  * @param pseudo_maps pseudo maps
402  */
403 void
404 ToLuaInterfaceGenerator::write_methods_h(FILE *f, std::string /* indent space */ is,
405  std::vector<InterfaceField> fields,
406  std::vector<InterfacePseudoMap> pseudo_maps)
407 {
408  write_methods_h(f, is, fields);
409 
410  for (vector<InterfacePseudoMap>::iterator i = pseudo_maps.begin(); i != pseudo_maps.end(); ++i) {
411  fprintf(f,
412  "%s%s %s(%s key) const;\n"
413  "%svoid set_%s(const %s key, const %s new_value);\n",
414  is.c_str(), convert_type(i->getType()),
415  (*i).getName().c_str(), convert_type(i->getKeyType()),
416  is.c_str(), (*i).getName().c_str(),
417  convert_type(i->getKeyType()), convert_type(i->getType()));
418  }
419 }
420 
421 
422 /** Write h file.
423  * @param f file to write to
424  */
425 void
427 {
428  fprintf(f,
429  "$#include <interfaces/%s>\n"
430  "$using namespace fawkes;\n"
431  "namespace fawkes {\n"
432  "class %s : public Interface\n"
433  "{\n",
434  filename_h.c_str(),
435  class_name.c_str());
436 
437  write_constants_h(f);
438  write_messages_h(f);
439  //write_ctor_dtor_h(f, " ", class_name);
440  write_methods_h(f, " ", data_fields, pseudo_maps);
441  write_superclass_h(f);
442  fprintf(f, "\n};\n\n}\n");
443 }
444 
445 
446 /** Generator cpp and h files.
447  */
448 void
450 {
451  char timestring[26]; // 26 is mentioned in man asctime_r
452  struct tm timestruct;
453  time_t t = time(NULL);
454  localtime_r(&t, &timestruct);
455  asctime_r(&timestruct, timestring);
456  gendate = timestring;
457 
458  FILE *toluaf;
459 
460  toluaf = fopen(string(dir + filename_tolua).c_str(), "w");
461 
462  if ( toluaf == NULL ) {
463  printf("Cannot open tolua file %s%s\n", dir.c_str(), filename_tolua.c_str());
464  }
465 
466  write_toluaf(toluaf);
467 
468  fclose(toluaf);
469 }