tolua_generator.cpp

00001  
00002 /***************************************************************************
00003  *  tolua_generator.cpp - ToLua++ Interface generator
00004  *
00005  *  Created: Tue Mar 11 15:33:26 2006
00006  *  Copyright  2006-2008  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009 
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU Library General Public License for more details.
00019  *
00020  *  Read the full text in the LICENSE.GPL file in the doc directory.
00021  */
00022 
00023 #include "tolua_generator.h"
00024 #include "exceptions.h"
00025 
00026 #include <utils/misc/string_conversions.h>
00027 
00028 #include <algorithm>
00029 #include <iostream>
00030 #include <vector>
00031 #include <time.h>
00032 #include <fstream>
00033 
00034 using namespace std;
00035 
00036 
00037 /** @class ToLuaInterfaceGenerator <interfaces/generator/tolua_generator.h>
00038  * Generator that transforms input from the InterfaceParser into valid
00039  * ToLua++ package file.
00040  * @author Tim Niemueller
00041  */
00042 
00043 /** Constructor.
00044  * @param directory Directory where to create the files
00045  * @param interface_name name of the interface, should end with Interface
00046  * @param config_basename basename of the config without suffix
00047  * @param author author of interface
00048  * @param year year of copyright
00049  * @param creation_date user-supplied creation date of interface
00050  * @param data_comment comment in data block.
00051  * @param hash MD5 hash of the config file that was used to generate the interface
00052  * @param hash_size size in bytes of hash
00053  * @param constants constants
00054  * @param enum_constants constants defined as an enum
00055  * @param data_fields data fields of the interface
00056  * @param pseudo_maps pseudo maps of the interface
00057  * @param messages messages defined in the interface
00058  */
00059 ToLuaInterfaceGenerator::ToLuaInterfaceGenerator(std::string directory, std::string interface_name,
00060                                                  std::string config_basename, std::string author,
00061                                                  std::string year, std::string creation_date,
00062                                                  std::string data_comment,
00063                                                  const unsigned char *hash, size_t hash_size,
00064                                                  const std::vector<InterfaceConstant> &constants,
00065                                                  const std::vector<InterfaceEnumConstant> &enum_constants,
00066                                                  const std::vector<InterfaceField> &data_fields,
00067                                                  const std::vector<InterfacePseudoMap> &pseudo_maps,
00068                                                  const std::vector<InterfaceMessage> &messages
00069                                                  )
00070 {
00071   this->dir    = directory;
00072   if ( dir.find_last_of("/") != (dir.length() - 1) ) {
00073     dir += "/";
00074   }
00075   this->author = author;
00076   this->year   = year;
00077   this->creation_date = creation_date;
00078   this->data_comment  = data_comment;
00079   this->hash = hash;
00080   this->hash_size = hash_size;
00081   this->constants = constants;
00082   this->enum_constants = enum_constants;
00083   this->data_fields = data_fields;
00084   this->pseudo_maps = pseudo_maps;
00085   this->messages = messages;
00086 
00087   filename_tolua = config_basename + ".tolua";
00088   filename_h     = config_basename + ".h";
00089 
00090   if ( interface_name.find("Interface", 0) == string::npos ) {
00091     // append Interface
00092     class_name = interface_name + "Interface";
00093   } else {
00094     class_name = interface_name;
00095   }
00096 }
00097 
00098 
00099 /** Destructor */
00100 ToLuaInterfaceGenerator::~ToLuaInterfaceGenerator()
00101 {
00102 }
00103 
00104 
00105 /** Convert C type to Lua type.
00106  * tolua++ does not deal well with stdint types, therefore we convert them
00107  * to "traditional" types.
00108  * @param c_type C type to convert
00109  * @return constant string of the Lua compatible type
00110  */
00111 const char *
00112 ToLuaInterfaceGenerator::convert_type(std::string c_type)
00113 {
00114   if (c_type == "uint8_t") {
00115     return "unsigned char";
00116   } else if (c_type == "uint16_t") {
00117     return "unsigned short";
00118   } else if (c_type == "uint32_t") {
00119     return "unsigned int";
00120   } else if (c_type == "uint64_t") {
00121 #if __WORDSIZE == 64
00122     return "unsigned long";
00123 #else
00124     return "unsigned long long";
00125 #endif
00126   } else if (c_type == "int8_t") {
00127     return "char";
00128   } else if (c_type == "int16_t") {
00129     return "short";
00130   } else if (c_type == "int32_t") {
00131     return "int";
00132   } else if (c_type == "int64_t") {
00133 #if __WORDSIZE == 64
00134     return "long";
00135 #else
00136     return "long long";
00137 #endif
00138   } else if (c_type == "uint8_t *") {
00139     return "unsigned char *";
00140   } else if (c_type == "uint16_t *") {
00141     return "unsigned short *";
00142   } else if (c_type == "uint32_t *") {
00143     return "unsigned int *";
00144   } else if (c_type == "uint64_t *") {
00145 #if __WORDSIZE == 64
00146     return "unsigned long *";
00147 #else
00148     return "unsigned long long *";
00149 #endif
00150   } else if (c_type == "int8_t *") {
00151     return "char *";
00152   } else if (c_type == "int16_t *") {
00153     return "short *";
00154   } else if (c_type == "int32_t *") {
00155     return "int *";
00156   } else if (c_type == "int64_t *") {
00157 #if __WORDSIZE == 64
00158     return "long *";
00159 #else
00160     return "long long *";
00161 #endif
00162   } else {
00163     return c_type.c_str();
00164   }
00165 }
00166 
00167 
00168 
00169 /** Write header to file.
00170  * @param f file to write to
00171  * @param filename name of file
00172  */
00173 void
00174 ToLuaInterfaceGenerator::write_header(FILE *f, std::string filename)
00175 {
00176   fprintf(f, "\n/***************************************************************************\n");
00177   fprintf(f, " *  %s - Fawkes BlackBoard Interface - %s - tolua++ wrapper\n", filename.c_str(), class_name.c_str());
00178   fprintf(f, " *\n");
00179   if ( creation_date.length() > 0 ) {
00180     fprintf(f, " *  Interface created: %s\n", creation_date.c_str());
00181   }
00182   fprintf(f, " *  Templated created:   Thu Oct 12 10:49:19 2006\n");
00183   fprintf(f, " *  Copyright  %s  %s\n", year.c_str(),
00184           ((author.length() > 0) ? author.c_str() : "AllemaniACs RoboCup Team") );
00185   fprintf(f, " *\n");
00186   fprintf(f, " ****************************************************************************/\n\n");
00187   fprintf(f, "/*\n");
00188   fprintf(f, " *  This program is free software; you can redistribute it and/or modify\n");
00189   fprintf(f, " *  it under the terms of the GNU General Public License as published by\n");
00190   fprintf(f, " *  the Free Software Foundation; either version 2 of the License, or\n");
00191   fprintf(f, " *  (at your option) any later version.\n");
00192   fprintf(f, " *\n");
00193   fprintf(f, " *  This program is distributed in the hope that it will be useful,\n");
00194   fprintf(f, " *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
00195   fprintf(f, " *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
00196   fprintf(f, " *  GNU Library General Public License for more details.\n");
00197   fprintf(f, " *\n");
00198   fprintf(f, " *  You should have received a copy of the GNU General Public License\n");
00199   fprintf(f, " *  along with this program; if not, write to the Free Software Foundation,\n");
00200   fprintf(f, " *  Inc., 51 Franklin Street, Fifth floor, Boston, MA 02111-1307, USA.\n");
00201   fprintf(f, " */\n\n");
00202 }
00203 
00204 
00205 /** Write constants to h file
00206  * @param f file to write to
00207  */
00208 void
00209 ToLuaInterfaceGenerator::write_constants_h(FILE *f)
00210 {
00211   for ( vector<InterfaceConstant>::iterator i = constants.begin(); i != constants.end(); ++i) {
00212     fprintf(f, "  static const %s %s;\n", convert_type(i->getType()),
00213             i->getName().c_str());
00214   }
00215   fprintf(f, "\n");
00216 
00217   for ( vector<InterfaceEnumConstant>::iterator i = enum_constants.begin(); i != enum_constants.end(); ++i) {
00218     fprintf(f, "  typedef enum {\n");
00219     vector< pair<string,string> > items = (*i).getItems();
00220     vector< pair<string,string> >::iterator j = items.begin();
00221     while (j != items.end()) {
00222       fprintf(f, "    %s", (*j).first.c_str());
00223       ++j;
00224       if ( j != items.end() ) {
00225         fprintf(f, ",\n");
00226       } else {
00227         fprintf(f, "\n");
00228       }
00229     }
00230     fprintf(f, "  } %s;\n\n", (*i).getName().c_str());
00231   }
00232 }
00233 
00234 
00235 /** Write messages to h file.
00236  * @param f file to write to
00237  */
00238 void
00239 ToLuaInterfaceGenerator::write_messages_h(FILE *f)
00240 {
00241   for (vector<InterfaceMessage>::iterator i = messages.begin(); i != messages.end(); ++i) {
00242     fprintf(f, "  class %s : public Message\n"
00243             "  {\n", (*i).getName().c_str());
00244     write_message_ctor_dtor_h(f, "    ", (*i).getName(), (*i).getFields());
00245     write_methods_h(f, "    ", (*i).getFields());
00246 
00247     fprintf(f, "  };\n\n");
00248   }
00249 
00250 }
00251 
00252 
00253 /** Write constructor and destructor to h file.
00254  * @param f file to write to
00255  * @param is indentation space
00256  * @param classname name of class
00257  */
00258 void
00259 ToLuaInterfaceGenerator::write_ctor_dtor_h(FILE *f, std::string /* indent space */ is,
00260                                          std::string classname)
00261 {
00262   fprintf(f,
00263           "%s%s();\n"
00264           "%s~%s();\n\n",
00265           is.c_str(), classname.c_str(),
00266           is.c_str(), classname.c_str());
00267 }
00268 
00269 
00270 /** Write constructor and destructor for message to h file.
00271  * @param f file to write to
00272  * @param is indentation space
00273  * @param classname name of class
00274  * @param fields vector of data fields of message
00275  */
00276 void
00277 ToLuaInterfaceGenerator::write_message_ctor_dtor_h(FILE *f, std::string /* indent space */ is,
00278                                                  std::string classname,
00279                                                  std::vector<InterfaceField> fields)
00280 {
00281   vector<InterfaceField>::iterator i;
00282 
00283   if ( fields.size() > 0 ) {
00284 
00285     fprintf(f, "%s%s(", is.c_str(), classname.c_str());
00286 
00287     i = fields.begin();
00288     while (i != fields.end()) {
00289       fprintf(f, "%s ini_%s",
00290               convert_type(i->getAccessType()), i->getName().c_str());
00291       ++i;
00292       if ( i != fields.end() ) {
00293         fprintf(f, ", ");
00294       }
00295     }
00296 
00297     fprintf(f, ");\n");
00298   }
00299 
00300 
00301   write_ctor_dtor_h(f, is, classname);
00302 }
00303 
00304 /** Write superclass methods.
00305  * @param f file to write to
00306  */
00307 void
00308 ToLuaInterfaceGenerator::write_superclass_h(FILE *f)
00309 {
00310   fprintf(f,
00311           "  bool                    oftype(const char *interface_type) const;\n"
00312           "  const void *            datachunk() const;\n"
00313           "  unsigned int            datasize() const;\n"
00314           "  const char *            type() const;\n"
00315           "  const char *            id() const;\n"
00316           "  const char *            uid() const;\n"
00317           "  unsigned int            serial() const;\n"
00318           "  unsigned int            mem_serial() const;\n"
00319           "  bool                    operator== (Interface &comp) const;\n"
00320           "  const unsigned char *   hash() const;\n"
00321           "  int                     hash_size() const;\n"
00322           "  const char *            hash_printable() const;\n"
00323           "  bool                    is_writer() const;\n"
00324 
00325           "  void                    set_from_chunk(void *chunk);\n"
00326 
00327           "  virtual Message *   create_message(const char *type) const = 0;\n"
00328 
00329           "  void          read();\n"
00330           "  void          write();\n"
00331 
00332           "  bool          has_writer() const;\n"
00333           "  unsigned int  num_readers() const;\n"
00334 
00335 
00336           "  unsigned int  msgq_enqueue_copy(Message *message);\n"
00337           "  void          msgq_remove(Message *message);\n"
00338           "  void          msgq_remove(unsigned int message_id);\n"
00339           "  unsigned int  msgq_size();\n"
00340           "  void          msgq_flush();\n"
00341           "  void          msgq_lock();\n"
00342           "  bool          msgq_try_lock();\n"
00343           "  void          msgq_unlock();\n"
00344           "  void          msgq_pop();\n"
00345           "  Message *     msgq_first();\n"
00346           "  bool          msgq_empty();\n"
00347           "\n");
00348 }
00349 
00350 /** Write methods to h file.
00351  * @param f file to write to
00352  * @param is indentation space.
00353  * @param fields fields to write accessor methods for.
00354  */
00355 void
00356 ToLuaInterfaceGenerator::write_methods_h(FILE *f, std::string /* indent space */ is,
00357                                          std::vector<InterfaceField> fields)
00358 {
00359   for (vector<InterfaceField>::iterator i = fields.begin(); i != fields.end(); ++i) {
00360 
00361     if ( (i->getLengthValue() > 0) && (i->getType() != "string" ) ) {
00362       fprintf(f,
00363               "%s%s %s%s(int index);\n",
00364               is.c_str(),
00365               (i->getType() == "byte") ? "unsigned int" : convert_type(i->getPlainAccessType()),
00366               ( ((*i).getType() == "bool" ) ? "is_" : ""),
00367               (*i).getName().c_str());
00368 
00369       fprintf(f,
00370               "%svoid set_%s(unsigned int index, const %s new_%s);\n",
00371               is.c_str(), (*i).getName().c_str(),
00372               convert_type(i->getPlainAccessType()), i->getName().c_str());
00373     } else {
00374       fprintf(f,
00375               "%s%s %s%s();\n",
00376               is.c_str(), convert_type(i->getAccessType()),
00377               ( ((*i).getType() == "bool" ) ? "is_" : ""),
00378               (*i).getName().c_str());
00379 
00380       fprintf(f,
00381               "%svoid set_%s(const %s new_%s);\n",
00382               is.c_str(), (*i).getName().c_str(),
00383               convert_type(i->getAccessType()), i->getName().c_str());
00384     }
00385     fprintf(f,
00386             "%sint maxlenof_%s() const;\n",
00387             is.c_str(), (*i).getName().c_str()
00388             );
00389   }
00390 }
00391 
00392 
00393 /** Write methods to h file.
00394  * @param f file to write to
00395  * @param is indentation space.
00396  * @param fields fields to write accessor methods for.
00397  * @param pseudo_maps pseudo maps
00398  */
00399 void
00400 ToLuaInterfaceGenerator::write_methods_h(FILE *f, std::string /* indent space */ is,
00401                                          std::vector<InterfaceField> fields,
00402                                          std::vector<InterfacePseudoMap> pseudo_maps)
00403 {
00404   write_methods_h(f, is, fields);
00405 
00406   for (vector<InterfacePseudoMap>::iterator i = pseudo_maps.begin(); i != pseudo_maps.end(); ++i) {
00407     fprintf(f,
00408             "%s%s %s(%s key) const;\n"
00409             "%svoid set_%s(const %s key, const %s new_value);\n",
00410             is.c_str(), convert_type(i->getType()),
00411             (*i).getName().c_str(), convert_type(i->getKeyType()),
00412             is.c_str(), (*i).getName().c_str(),
00413             convert_type(i->getKeyType()), convert_type(i->getType()));
00414   }
00415 }
00416 
00417 
00418 /** Write h file.
00419  * @param f file to write to
00420  */
00421 void
00422 ToLuaInterfaceGenerator::write_toluaf(FILE *f)
00423 {
00424   fprintf(f,
00425           "$#include <interfaces/%s>\n"
00426           "$using namespace fawkes;\n"
00427           "namespace fawkes {\n"
00428           "class %s : public Interface\n"
00429           "{\n",
00430           filename_h.c_str(),
00431           class_name.c_str());
00432 
00433   write_constants_h(f);
00434   write_messages_h(f);
00435   //write_ctor_dtor_h(f, "  ", class_name);
00436   write_methods_h(f, "  ", data_fields, pseudo_maps);
00437   write_superclass_h(f);
00438   fprintf(f, "\n};\n\n}\n");
00439 }
00440 
00441 
00442 /** Generator cpp and h files.
00443  */
00444 void
00445 ToLuaInterfaceGenerator::generate()
00446 {
00447   char timestring[26]; // 26 is mentioned in man asctime_r
00448   struct tm timestruct;
00449   time_t t = time(NULL);
00450   localtime_r(&t, &timestruct);
00451   asctime_r(&timestruct, timestring);
00452   gendate = timestring;
00453 
00454   FILE *toluaf;
00455 
00456   toluaf = fopen(string(dir + filename_tolua).c_str(), "w");
00457 
00458   if ( toluaf == NULL ) {
00459     printf("Cannot open tolua file %s%s\n", dir.c_str(), filename_tolua.c_str());
00460   }
00461 
00462   write_toluaf(toluaf);
00463 
00464   fclose(toluaf);
00465 }

Generated on Tue Feb 22 13:32:24 2011 for Fawkes API by  doxygen 1.4.7