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 
00106 /** Write header to file.
00107  * @param f file to write to
00108  * @param filename name of file
00109  */
00110 void
00111 ToLuaInterfaceGenerator::write_header(FILE *f, std::string filename)
00112 {
00113   fprintf(f, "\n/***************************************************************************\n");
00114   fprintf(f, " *  %s - Fawkes BlackBoard Interface - %s - tolua++ wrapper\n", filename.c_str(), class_name.c_str());
00115   fprintf(f, " *\n");
00116   if ( creation_date.length() > 0 ) {
00117     fprintf(f, " *  Interface created: %s\n", creation_date.c_str());
00118   }
00119   fprintf(f, " *  Templated created:   Thu Oct 12 10:49:19 2006\n");
00120   fprintf(f, " *  Copyright  %s  %s\n", year.c_str(),
00121           ((author.length() > 0) ? author.c_str() : "AllemaniACs RoboCup Team") );
00122   fprintf(f, " *\n");
00123   fprintf(f, " ****************************************************************************/\n\n");
00124   fprintf(f, "/*\n");
00125   fprintf(f, " *  This program is free software; you can redistribute it and/or modify\n");
00126   fprintf(f, " *  it under the terms of the GNU General Public License as published by\n");
00127   fprintf(f, " *  the Free Software Foundation; either version 2 of the License, or\n");
00128   fprintf(f, " *  (at your option) any later version.\n");
00129   fprintf(f, " *\n");
00130   fprintf(f, " *  This program is distributed in the hope that it will be useful,\n");
00131   fprintf(f, " *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
00132   fprintf(f, " *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n");
00133   fprintf(f, " *  GNU Library General Public License for more details.\n");
00134   fprintf(f, " *\n");
00135   fprintf(f, " *  You should have received a copy of the GNU General Public License\n");
00136   fprintf(f, " *  along with this program; if not, write to the Free Software Foundation,\n");
00137   fprintf(f, " *  Inc., 51 Franklin Street, Fifth floor, Boston, MA 02111-1307, USA.\n");
00138   fprintf(f, " */\n\n");
00139 }
00140
00141 
00142 /** Write constants to h file
00143  * @param f file to write to
00144  */
00145 void
00146 ToLuaInterfaceGenerator::write_constants_h(FILE *f)
00147 {
00148   for ( vector<InterfaceConstant>::iterator i = constants.begin(); i != constants.end(); ++i) {
00149     fprintf(f, "  static const %s %s;\n", (*i).getType().c_str(), (*i).getName().c_str());
00150   }
00151   fprintf(f, "\n");
00152
00153   for ( vector<InterfaceEnumConstant>::iterator i = enum_constants.begin(); i != enum_constants.end(); ++i) {
00154     fprintf(f, "  typedef enum {\n");
00155     vector< pair<string,string> > items = (*i).getItems();
00156     vector< pair<string,string> >::iterator j = items.begin();
00157     while (j != items.end()) {
00158       fprintf(f, "    %s", (*j).first.c_str());
00159       ++j;
00160       if ( j != items.end() ) {
00161         fprintf(f, ",\n");
00162       } else {
00163         fprintf(f, "\n");
00164       }
00165     }
00166     fprintf(f, "  } %s;\n\n", (*i).getName().c_str());
00167   }
00168 }
00169
00170 
00171 /** Write messages to h file.
00172  * @param f file to write to
00173  */
00174 void
00175 ToLuaInterfaceGenerator::write_messages_h(FILE *f)
00176 {
00177   for (vector<InterfaceMessage>::iterator i = messages.begin(); i != messages.end(); ++i) {
00178     fprintf(f, "  class %s : public Message\n"
00179             "  {\n", (*i).getName().c_str());
00180     write_message_ctor_dtor_h(f, "    ", (*i).getName(), (*i).getFields());
00181     write_methods_h(f, "    ", (*i).getFields());
00182
00183     fprintf(f, "  };\n\n");
00184   }
00185
00186 }
00187
00188 
00189 /** Write constructor and destructor to h file.
00190  * @param f file to write to
00191  * @param is indentation space
00192  * @param classname name of class
00193  */
00194 void
00195 ToLuaInterfaceGenerator::write_ctor_dtor_h(FILE *f, std::string /* indent space */ is,
00196                                          std::string classname)
00197 {
00198   fprintf(f,
00199           "%s%s();\n"
00200           "%s~%s();\n\n",
00201           is.c_str(), classname.c_str(),
00202           is.c_str(), classname.c_str());
00203 }
00204
00205 
00206 /** Write constructor and destructor for message to h file.
00207  * @param f file to write to
00208  * @param is indentation space
00209  * @param classname name of class
00210  * @param fields vector of data fields of message
00211  */
00212 void
00213 ToLuaInterfaceGenerator::write_message_ctor_dtor_h(FILE *f, std::string /* indent space */ is,
00214                                                  std::string classname,
00215                                                  std::vector<InterfaceField> fields)
00216 {
00217   vector<InterfaceField>::iterator i;
00218
00219   if ( fields.size() > 0 ) {
00220
00221     fprintf(f, "%s%s(", is.c_str(), classname.c_str());
00222
00223     i = fields.begin();
00224     while (i != fields.end()) {
00225       fprintf(f, "%s ini_%s",
00226               (*i).getAccessType().c_str(), (*i).getName().c_str());
00227       ++i;
00228       if ( i != fields.end() ) {
00229         fprintf(f, ", ");
00230       }
00231     }
00232
00233     fprintf(f, ");\n");
00234   }
00235
00236
00237   write_ctor_dtor_h(f, is, classname);
00238 }
00239 
00240 /** Write superclass methods.
00241  * @param f file to write to
00242  */
00243 void
00244 ToLuaInterfaceGenerator::write_superclass_h(FILE *f)
00245 {
00246   fprintf(f,
00247           "  bool                    oftype(const char *interface_type) const;\n"
00248           "  const void *            datachunk() const;\n"
00249           "  unsigned int            datasize() const;\n"
00250           "  const char *            type() const;\n"
00251           "  const char *            id() const;\n"
00252           "  const char *            uid() const;\n"
00253           "  unsigned int            serial() const;\n"
00254           "  unsigned int            mem_serial() const;\n"
00255           "  bool                    operator== (Interface &comp) const;\n"
00256           "  const unsigned char *   hash() const;\n"
00257           "  int                     hash_size() const;\n"
00258           "  const char *            hash_printable() const;\n"
00259           "  bool                    is_writer() const;\n"
00260
00261           "  void                    set_from_chunk(void *chunk);\n"
00262
00263           "  virtual Message *   create_message(const char *type) const = 0;\n"
00264
00265           "  void          read();\n"
00266           "  void          write();\n"
00267
00268           "  bool          has_writer() const;\n"
00269           "  unsigned int  num_readers() const;\n"
00270
00271
00272           "  unsigned int  msgq_enqueue_copy(Message *message);\n"
00273           "  void          msgq_remove(Message *message);\n"
00274           "  void          msgq_remove(unsigned int message_id);\n"
00275           "  unsigned int  msgq_size();\n"
00276           "  void          msgq_flush();\n"
00277           "  void          msgq_lock();\n"
00278           "  bool          msgq_try_lock();\n"
00279           "  void          msgq_unlock();\n"
00280           "  void          msgq_pop();\n"
00281           "  Message *     msgq_first();\n"
00282           "  bool          msgq_empty();\n"
00283           "\n");
00284 }
00285 
00286 /** Write methods to h file.
00287  * @param f file to write to
00288  * @param is indentation space.
00289  * @param fields fields to write accessor methods for.
00290  */
00291 void
00292 ToLuaInterfaceGenerator::write_methods_h(FILE *f, std::string /* indent space */ is,
00293                                          std::vector<InterfaceField> fields)
00294 {
00295   for (vector<InterfaceField>::iterator i = fields.begin(); i != fields.end(); ++i) {
00296
00297     if ( (i->getLengthValue() > 0) && (i->getType() != "string" ) ) {
00298       fprintf(f,
00299               "%s%s %s%s(int index);\n",
00300               is.c_str(),
00301               (i->getType() == "byte") ? "unsigned int" : i->getPlainAccessType().c_str(),
00302               ( ((*i).getType() == "bool" ) ? "is_" : ""),
00303               (*i).getName().c_str());
00304
00305       fprintf(f,
00306               "%svoid set_%s(unsigned int index, const %s new_%s);\n",
00307               is.c_str(), (*i).getName().c_str(),
00308               (*i).getPlainAccessType().c_str(), (*i).getName().c_str());
00309     } else {
00310       fprintf(f,
00311               "%s%s %s%s();\n",
00312               is.c_str(), (*i).getAccessType().c_str(),
00313               ( ((*i).getType() == "bool" ) ? "is_" : ""),
00314               (*i).getName().c_str());
00315
00316       fprintf(f,
00317               "%svoid set_%s(const %s new_%s);\n",
00318               is.c_str(), (*i).getName().c_str(),
00319               (*i).getAccessType().c_str(), (*i).getName().c_str());
00320     }
00321     fprintf(f,
00322             "%sint maxlenof_%s() const;\n",
00323             is.c_str(), (*i).getName().c_str()
00324             );
00325   }
00326 }
00327
00328 
00329 /** Write methods to h file.
00330  * @param f file to write to
00331  * @param is indentation space.
00332  * @param fields fields to write accessor methods for.
00333  * @param pseudo_maps pseudo maps
00334  */
00335 void
00336 ToLuaInterfaceGenerator::write_methods_h(FILE *f, std::string /* indent space */ is,
00337                                          std::vector<InterfaceField> fields,
00338                                          std::vector<InterfacePseudoMap> pseudo_maps)
00339 {
00340   write_methods_h(f, is, fields);
00341
00342   for (vector<InterfacePseudoMap>::iterator i = pseudo_maps.begin(); i != pseudo_maps.end(); ++i) {
00343     fprintf(f,
00344             "%s%s %s(%s key) const;\n"
00345             "%svoid set_%s(const %s key, const %s new_value);\n",
00346             is.c_str(), (*i).getType().c_str(),
00347             (*i).getName().c_str(), (*i).getKeyType().c_str(),
00348             is.c_str(), (*i).getName().c_str(),
00349             i->getKeyType().c_str(), i->getType().c_str());
00350   }
00351 }
00352
00353 
00354 /** Write h file.
00355           " * @param f file to write to
00356           " */
00357 void
00358 ToLuaInterfaceGenerator::write_toluaf(FILE *f)
00359 {
00360   fprintf(f,
00361           "$#include <interfaces/%s>\n"
00362           "$using namespace fawkes;\n"
00363           "namespace fawkes {\n"
00364           "class %s : public Interface\n"
00365           "{\n",
00366           filename_h.c_str(),
00367           class_name.c_str());
00368
00369   write_constants_h(f);
00370   write_messages_h(f);
00371   //write_ctor_dtor_h(f, "  ", class_name);
00372   write_methods_h(f, "  ", data_fields, pseudo_maps);
00373   write_superclass_h(f);
00374   fprintf(f, "\n};\n\n}\n");
00375 }
00376
00377 
00378 /** Generator cpp and h files.
00379  */
00380 void
00381 ToLuaInterfaceGenerator::generate()
00382 {
00383   char timestring[26]; // 26 is mentioned in man asctime_r
00384   struct tm timestruct;
00385   time_t t = time(NULL);
00386   localtime_r(&t, &timestruct);
00387   asctime_r(&timestruct, timestring);
00388   gendate = timestring;
00389
00390   FILE *toluaf;
00391
00392   toluaf = fopen(string(dir + filename_tolua).c_str(), "w");
00393
00394   if ( toluaf == NULL ) {
00395     printf("Cannot open tolua file %s%s\n", dir.c_str(), filename_tolua.c_str());
00396   }
00397
00398   write_toluaf(toluaf);
00399
00400   fclose(toluaf);
00401 }