Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

dtool/src/interrogate/interrogateBuilder.cxx

Go to the documentation of this file.
00001 // Filename: interrogateBuilder.cxx
00002 // Created by:  drose (01Aug00)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "interrogateBuilder.h"
00020 #include "interrogate.h"
00021 #include "parameterRemap.h"
00022 #include "typeManager.h"
00023 #include "functionWriters.h"
00024 #include "interfaceMakerC.h"
00025 #include "interfaceMakerPythonObj.h"
00026 #include "interfaceMakerPythonSimple.h"
00027 #include "functionRemap.h"
00028 
00029 #include <interrogateType.h>
00030 #include <interrogateDatabase.h>
00031 #include <indexRemapper.h>
00032 #include <cppParser.h>
00033 #include <cppDeclaration.h>
00034 #include <cppFunctionGroup.h>
00035 #include <cppFunctionType.h>
00036 #include <cppParameterList.h>
00037 #include <cppInstance.h>
00038 #include <cppSimpleType.h>
00039 #include <cppPointerType.h>
00040 #include <cppReferenceType.h>
00041 #include <cppArrayType.h>
00042 #include <cppConstType.h>
00043 #include <cppExtensionType.h>
00044 #include <cppStructType.h>
00045 #include <cppExpression.h>
00046 #include <cppTypedef.h>
00047 #include <cppTypeDeclaration.h>
00048 #include <cppEnumType.h>
00049 #include <cppCommentBlock.h>
00050 #include <notify.h>
00051 
00052 #include <ctype.h>
00053 #include <algorithm>
00054 
00055 InterrogateBuilder builder;
00056 
00057 /*
00058 static string
00059 upcase_string(const string &str) {
00060   string result;
00061   for (string::const_iterator si = str.begin();
00062        si != str.end();
00063        ++si) {
00064     result += toupper(*si);
00065   }
00066   return result;
00067 }
00068 */
00069 
00070 ////////////////////////////////////////////////////////////////////
00071 //     Function: InterrogateBuilder::add_source_file
00072 //       Access: Public
00073 //  Description: Adds the given source filename to the list of files
00074 //               that we are scanning.  Those source files that appear
00075 //               to be header files will be #included in the generated
00076 //               code file.
00077 ////////////////////////////////////////////////////////////////////
00078 void InterrogateBuilder::
00079 add_source_file(const string &filename) {
00080   if (filename.empty()) {
00081     return;
00082   }
00083 
00084   _include_files[filename] = '"';
00085 }
00086 
00087 ////////////////////////////////////////////////////////////////////
00088 //     Function: InterrogateBuilder::read_command_file
00089 //       Access: Public
00090 //  Description: Reads a .N file that might contain control
00091 //               information for the interrogate process.
00092 ////////////////////////////////////////////////////////////////////
00093 void InterrogateBuilder::
00094 read_command_file(istream &in) {
00095   string line;
00096   getline(in, line);
00097   while (!in.fail() && !in.eof()) {
00098     // Strip out the comment.
00099     size_t hash = line.find('#');
00100     if (hash != string::npos) {
00101       line = line.substr(0, hash);
00102     }
00103 
00104     // Skip leading whitespace.
00105     size_t p = 0;
00106     while (p < line.length() && isspace(line[p])) {
00107       p++;
00108     }
00109 
00110     if (p < line.length()) {
00111       // Get the first word.
00112       size_t q = p;
00113       while (q < line.length() && !isspace(line[q])) {
00114         q++;
00115       }
00116       string command = line.substr(p, q - p);
00117 
00118       // Get the rest.
00119       p = q;
00120       while (p < line.length() && isspace(line[p])) {
00121         p++;
00122       }
00123       // Except for the trailing whitespace.
00124       q = line.length();
00125       while (q > p && isspace(line[q - 1])) {
00126         q--;
00127       }
00128       string params = line.substr(p, q - p);
00129 
00130       do_command(command, params);
00131     }
00132     getline(in, line);
00133   }
00134 }
00135 
00136 ////////////////////////////////////////////////////////////////////
00137 //     Function: InterrogateBuilder::do_command
00138 //       Access: Public
00139 //  Description: Executes a single command as read from the .N file.
00140 ////////////////////////////////////////////////////////////////////
00141 void InterrogateBuilder::
00142 do_command(const string &command, const string &params) {
00143   if (command == "forcetype") {
00144     // forcetype explicitly exports the given type.
00145     CPPType *type = parser.parse_type(params);
00146     if (type == (CPPType *)NULL) {
00147       nout << "Unknown type: forcetype " << params << "\n";
00148     } else {
00149       type = type->resolve_type(&parser, &parser);
00150       _forcetype.insert(type->get_local_name(&parser));
00151     }
00152 
00153   } else if (command == "renametype") {
00154     // rename exports the type as the indicated name.  We strip off
00155     // the last word as the new name; the new name may not contain
00156     // spaces (although the original type name may).
00157 
00158     size_t space = params.rfind(' ');
00159     if (space == string::npos) {
00160       nout << "No new name specified for renametype " << params << "\n";
00161     } else {
00162       string orig_name = params.substr(0, space);
00163       string new_name = params.substr(space + 1);
00164 
00165       CPPType *type = parser.parse_type(orig_name);
00166       if (type == (CPPType *)NULL) {
00167         nout << "Unknown type: renametype " << orig_name << "\n";
00168       } else {
00169         type = type->resolve_type(&parser, &parser);
00170         _renametype[type->get_local_name(&parser)] = new_name;
00171       }
00172     }
00173 
00174   } else if (command == "ignoretype") {
00175     // ignoretype explicitly ignores the given type.
00176     CPPType *type = parser.parse_type(params);
00177     if (type == (CPPType *)NULL) {
00178       nout << "Unknown type: ignoretype " << params << "\n";
00179     } else {
00180       type = type->resolve_type(&parser, &parser);
00181       _ignoretype.insert(type->get_local_name(&parser));
00182     }
00183 
00184   } else if (command == "ignoreinvolved") {
00185     _ignoreinvolved.insert(params);
00186 
00187   } else if (command == "ignorefile") {
00188     insert_param_list(_ignorefile, params);
00189 
00190   } else if (command == "ignoremember") {
00191     insert_param_list(_ignoremember, params);
00192 
00193   } else if (command == "noinclude") {
00194     insert_param_list(_noinclude, params);
00195 
00196   } else {
00197     nout << "Ignoring " << command << " " << params << "\n";
00198   }
00199 }
00200 
00201 ////////////////////////////////////////////////////////////////////
00202 //     Function: InterrogateBuilder::build
00203 //       Access: Public
00204 //  Description: Builds all of the interrogate data.
00205 ////////////////////////////////////////////////////////////////////
00206 void InterrogateBuilder::
00207 build() {
00208   _library_hash_name = hash_string(library_name, 5);
00209 
00210   // Make sure we have the complete set of #includes we need.
00211   CPPParser::Includes::const_iterator ii;
00212   for (ii = parser._quote_includes.begin();
00213        ii != parser._quote_includes.end();
00214        ++ii) {
00215     const string &filename = (*ii);
00216     _include_files[filename] = '"';
00217   }
00218   for (ii = parser._angle_includes.begin();
00219        ii != parser._angle_includes.end();
00220        ++ii) {
00221     const string &filename = (*ii);
00222     _include_files[filename] = '<';
00223   }
00224 
00225   // First, get all the types that were explicitly forced.
00226   Commands::const_iterator ci;
00227   for (ci = _forcetype.begin();
00228        ci != _forcetype.end();
00229        ++ci) {
00230     CPPType *type = parser.parse_type(*ci);
00231     assert(type != (CPPType *)NULL);
00232     get_type(type, true);
00233   }
00234 
00235   // Now go through all of the top-level declarations in the file(s).
00236 
00237   CPPScope::Declarations::const_iterator di;
00238   for (di = parser._declarations.begin();
00239        di != parser._declarations.end();
00240        ++di) {
00241     if ((*di)->get_subtype() == CPPDeclaration::ST_instance) {
00242       CPPInstance *inst = (*di)->as_instance();
00243       if (inst->_type->get_subtype() == CPPDeclaration::ST_function) {
00244         // Here's a function declaration.
00245         scan_function(inst);
00246 
00247       } else {
00248         // Here's a data element declaration.
00249         scan_element(inst, (CPPStructType *)NULL, &parser);
00250       }
00251 
00252     } else if ((*di)->get_subtype() == CPPDeclaration::ST_typedef) {
00253       CPPTypedef *tdef = (*di)->as_typedef();
00254       if (tdef->_type->get_subtype() == CPPDeclaration::ST_struct) {
00255         // A typedef counts as a declaration.  This lets us pick up
00256         // most template instantiations.
00257         CPPStructType *struct_type =
00258           tdef->_type->resolve_type(&parser, &parser)->as_struct_type();
00259         scan_struct_type(struct_type);
00260       }
00261 
00262     } else if ((*di)->get_subtype() == CPPDeclaration::ST_type_declaration) {
00263       CPPType *type = (*di)->as_type_declaration()->_type;
00264       type->_vis = (*di)->_vis;
00265 
00266       if (type->get_subtype() == CPPDeclaration::ST_struct) {
00267         CPPStructType *struct_type =
00268           type->as_type()->resolve_type(&parser, &parser)->as_struct_type();
00269         scan_struct_type(struct_type);
00270 
00271       } else if (type->get_subtype() == CPPDeclaration::ST_enum) {
00272         CPPEnumType *enum_type =
00273           type->as_type()->resolve_type(&parser, &parser)->as_enum_type();
00274         scan_enum_type(enum_type);
00275       }
00276     }
00277   }
00278 
00279   CPPPreprocessor::Manifests::const_iterator mi;
00280   for (mi = parser._manifests.begin(); mi != parser._manifests.end(); ++mi) {
00281     CPPManifest *manifest = (*mi).second;
00282     scan_manifest(manifest);
00283   }
00284 
00285   // Now that we've gone through all the code and generated all the
00286   // functions and types, build the function wrappers.
00287   //  make_wrappers();
00288 }
00289 
00290 ////////////////////////////////////////////////////////////////////
00291 //     Function: InterrogateBuilder::write_code
00292 //       Access: Public
00293 //  Description: Generates all the code necessary to the indicated
00294 //               output stream.
00295 ////////////////////////////////////////////////////////////////////
00296 void InterrogateBuilder::
00297 write_code(ostream &out, InterrogateModuleDef *def) {
00298   typedef vector<InterfaceMaker *> InterfaceMakers;
00299   InterfaceMakers makers;
00300 
00301   if (build_c_wrappers) {
00302     InterfaceMaker *maker = new InterfaceMakerC(def);
00303     makers.push_back(maker);
00304   }
00305 
00306   if (build_python_wrappers) {
00307     InterfaceMaker *maker = new InterfaceMakerPythonSimple(def);
00308     makers.push_back(maker);
00309   }
00310 
00311   if (build_python_obj_wrappers) {
00312     InterfaceMaker *maker = new InterfaceMakerPythonObj(def);
00313     makers.push_back(maker);
00314   }
00315 
00316   InterfaceMakers::iterator mi;
00317 
00318   // First, make all the wrappers.
00319   for (mi = makers.begin(); mi != makers.end(); ++mi) {
00320     (*mi)->generate_wrappers();
00321   }
00322 
00323   // Now generate all the function bodies to a temporary buffer.  By
00324   // generating these first, we ensure that we know all of the
00325   // pointers we'll be using ahead of time (and can therefore generate
00326   // correct prototypes).
00327   ostringstream function_bodies;
00328   for (mi = makers.begin(); mi != makers.end(); ++mi) {
00329     (*mi)->write_functions(function_bodies);
00330   }
00331 
00332   // Now, begin the actual output.  Start with the #include lines.
00333   if (!no_database) {
00334     out << "#include \"dtoolbase.h\"\n"
00335         << "#include \"interrogate_request.h\"\n"
00336         << "#include \"dconfig.h\"\n";
00337   }
00338   if (watch_asserts) {
00339     out << "#include \"notify.h\"\n";
00340   }
00341   out << "\n";
00342   
00343   IncludeFiles::const_iterator ifi;
00344   for (ifi = _include_files.begin();
00345        ifi != _include_files.end();
00346        ++ifi) {
00347     const string &filename = (*ifi).first;
00348     char delimiter = (*ifi).second;
00349     if (should_include(filename)) {
00350       if (delimiter == '"') {
00351         out << "#include \"" << filename << "\"\n";
00352       } else {
00353         out << "#include <" << filename << ">\n";
00354       }
00355     }
00356   }
00357   out << "\n";
00358 
00359   for (mi = makers.begin(); mi != makers.end(); ++mi) {
00360     (*mi)->write_includes(out);
00361   }
00362 
00363   if (generate_spam) {
00364     out << "#include \"config_interrogatedb.h\"\n"
00365         << "#include \"notifyCategoryProxy.h\"\n\n"
00366         << "NotifyCategoryDeclNoExport(in_" << library_name << ");\n"
00367         << "NotifyCategoryDef(in_" << library_name << ", interrogatedb_cat);\n\n";
00368   }
00369 
00370   out << "\n";
00371 
00372   // And now the prototypes.
00373   for (mi = makers.begin(); mi != makers.end(); ++mi) {
00374     (*mi)->write_prototypes(out);
00375   }
00376 
00377   out << "\n";
00378   
00379   // Followed by the function bodies.
00380   out << function_bodies.str() << "\n";
00381 
00382   if (output_module_specific) {
00383     // Output whatever stuff we should output if this were a module.
00384     for (mi = makers.begin(); mi != makers.end(); ++mi) {
00385       (*mi)->write_module(out, def);
00386     }
00387   }
00388 
00389   // Now collect all the function wrappers.
00390   vector<FunctionRemap *> remaps;
00391   for (mi = makers.begin(); mi != makers.end(); ++mi) {
00392     (*mi)->get_function_remaps(remaps);
00393   }
00394   
00395   // Make sure all of the function wrappers appear first in the set of
00396   // indices, and that they occupy consecutive index numbers, so we
00397   // can build a simple array of function pointers by index.
00398   remap_indices(remaps);
00399 
00400   // Get the function wrappers in index-number order.
00401   int num_wrappers = 0;
00402   map<int, FunctionRemap *> wrappers_by_index;
00403 
00404   vector<FunctionRemap *>::iterator ri;
00405   for (ri = remaps.begin(); ri != remaps.end(); ++ri) {
00406     FunctionRemap *remap = (*ri);
00407     wrappers_by_index[remap->_wrapper_index] = remap;
00408     num_wrappers++;
00409   }
00410 
00411   if (output_function_pointers) {
00412     // Write out the table of function pointers.
00413     out << "static void *_in_fptrs[" << num_wrappers << "] = {\n";
00414     int next_index = 1;
00415     map<int, FunctionRemap *>::iterator ii;
00416     for (ii = wrappers_by_index.begin();
00417          ii != wrappers_by_index.end();
00418          ++ii) {
00419       int this_index = (*ii).first;
00420       while (next_index < this_index) {
00421         out << "  (void *)0,\n";
00422         next_index++;
00423       }
00424       assert(next_index == this_index);
00425       FunctionRemap *remap = (*ii).second;
00426 
00427       out << "  (void *)&" << remap->_wrapper_name << ",\n";
00428       next_index++;
00429     }
00430     while (next_index < num_wrappers + 1) {
00431       out << "  (void *)0,\n";
00432       next_index++;
00433     }
00434     out << "};\n\n";
00435   }
00436 
00437   if (save_unique_names) {
00438     // Write out the table of unique names, in no particular order.
00439     out << "static InterrogateUniqueNameDef _in_unique_names["
00440         << num_wrappers << "] = {\n";
00441     for (ri = remaps.begin(); ri != remaps.end(); ++ri) {
00442       FunctionRemap *remap = (*ri);
00443       out << "  { \""
00444           << remap->_unique_name << "\", "
00445           << remap->_wrapper_index - 1 << " },\n";
00446     }
00447     out << "};\n\n";
00448   }
00449 
00450   if (!no_database) {
00451     // Now build the module definition structure to add ourselves to
00452     // the global interrogate database.
00453     out << "static InterrogateModuleDef _in_module_def = {\n"
00454         << "  " << def->file_identifier << ",  /* file_identifier */\n"
00455         << "  \"" << def->library_name << "\",  /* library_name */\n"
00456         << "  \"" << def->library_hash_name << "\",  /* library_hash_name */\n"
00457         << "  \"" << def->module_name << "\",  /* module_name */\n";
00458     if (def->database_filename != (const char *)NULL) {
00459       out << "  \"" << def->database_filename
00460           << "\",  /* database_filename */\n";
00461     } else {
00462       out << "  (const char *)0,  /* database_filename */\n";
00463     }
00464 
00465     if (save_unique_names) {
00466       out << "  _in_unique_names,\n"
00467           << "  " << num_wrappers << ",  /* num_unique_names */\n";
00468     } else {
00469       out << "  (InterrogateUniqueNameDef *)0,  /* unique_names */\n"
00470           << "  0,  /* num_unique_names */\n";
00471     }
00472 
00473     if (output_function_pointers) {
00474       out << "  _in_fptrs,\n"
00475           << "  " << num_wrappers << ",  /* num_fptrs */\n";
00476     } else {
00477       out << "  (void **)0,  /* fptrs */\n"
00478           << "  0,  /* num_fptrs */\n";
00479     }
00480 
00481     out << "  1,  /* first_index */\n"
00482         << "  " << InterrogateDatabase::get_ptr()->get_next_index()
00483         << "  /* next_index */\n"
00484         << "};\n\n";
00485 
00486     // And now write the static-init code that tells the interrogate
00487     // database to load up this module.
00488     out << "Configure(_in_configure_" << library_name << ");\n"
00489         << "ConfigureFn(_in_configure_" << library_name << ") {\n"
00490         << "  interrogate_request_module(&_in_module_def);\n"
00491         << "}\n\n";
00492   }
00493 }
00494 
00495 ////////////////////////////////////////////////////////////////////
00496 //     Function: InterrogateBuilder::make_module_def
00497 //       Access: Public
00498 //  Description: Allocates and returns a new InterrogateModuleDef
00499 //               structure that reflects the data we have just build,
00500 //               or at least that subset of the InterrogateModuleDef
00501 //               data that we have available at this time.
00502 //
00503 //               The data in this structure may include pointers that
00504 //               reference directly into the InterrogateBuilder
00505 //               object; thus, this structure is only valid for as
00506 //               long as the builder itself remains in scope.
00507 ////////////////////////////////////////////////////////////////////
00508 InterrogateModuleDef *InterrogateBuilder::
00509 make_module_def(int file_identifier) {
00510   InterrogateModuleDef *def = new InterrogateModuleDef;
00511   memset(def, 0, sizeof(InterrogateModuleDef));
00512 
00513   def->file_identifier = file_identifier;
00514   def->library_name = library_name.c_str();
00515   def->library_hash_name = _library_hash_name.c_str();
00516   def->module_name = module_name.c_str();
00517   if (!output_data_filename.empty()) {
00518     def->database_filename = output_data_basename.c_str();
00519   }
00520 
00521   return def;
00522 }
00523 
00524 ////////////////////////////////////////////////////////////////////
00525 //     Function: InterrogateBuilder::clean_identifier
00526 //       Access: Public, Static
00527 //  Description: Adjusts the given string to remove any characters we
00528 //               don't want to export as part of an identifier name.
00529 //               Returns the cleaned string.
00530 //
00531 //               This replaces any consecutive invalid characters with
00532 //               an underscore.
00533 ////////////////////////////////////////////////////////////////////
00534 string InterrogateBuilder::
00535 clean_identifier(const string &name) {
00536   string result;
00537 
00538   bool last_invalid = false;
00539 
00540   string::const_iterator ni;
00541   for (ni = name.begin(); ni != name.end(); ++ni) {
00542     if (isalnum(*ni)) {
00543       if (last_invalid) {
00544         result += '_';
00545         last_invalid = false;
00546       }
00547       result += (*ni);
00548     } else {
00549       last_invalid = true;
00550     }
00551   }
00552 
00553   return result;
00554 }
00555 
00556 ////////////////////////////////////////////////////////////////////
00557 //     Function: InterrogateBuilder::descope
00558 //       Access: Public, Static
00559 //  Description: Removes the leading "::", if present, from a
00560 //               fully-scoped name.  Sometimes CPPParser throws this
00561 //               on, and sometimes it doesn't.
00562 ////////////////////////////////////////////////////////////////////
00563 string InterrogateBuilder::
00564 descope(const string &name) {
00565   if (name.length() >= 2 && name.substr(0, 2) == "::") {
00566     return name.substr(2);
00567   }
00568   return name;
00569 }
00570 
00571 ////////////////////////////////////////////////////////////////////
00572 //     Function: InterrogateBuilder::get_destructor_for
00573 //       Access: Public
00574 //  Description: Returns the FunctionIndex for the destructor
00575 //               appropriate to destruct an instance of the indicated
00576 //               type, or 0 if no suitable destructor exists.
00577 ////////////////////////////////////////////////////////////////////
00578 FunctionIndex InterrogateBuilder::
00579 get_destructor_for(CPPType *type) {
00580   TypeIndex type_index = get_type(type, false);
00581 
00582   const InterrogateType &itype =
00583     InterrogateDatabase::get_ptr()->get_type(type_index);
00584 
00585   return itype.get_destructor();
00586 }
00587 
00588 ////////////////////////////////////////////////////////////////////
00589 //     Function: InterrogateBuilder::get_preferred_name
00590 //       Access: Public
00591 //  Description: Returns the name of the type as it should be reported
00592 //               to the database.  This is either the name indicated
00593 //               by the user via a renametype command, or the
00594 //               "preferred name" of the type itself (i.e. the typedef
00595 //               name within the C++ code), or failing that, the
00596 //               type's true name.
00597 ////////////////////////////////////////////////////////////////////
00598 string InterrogateBuilder::
00599 get_preferred_name(CPPType *type) {
00600   string true_name = type->get_local_name(&parser);
00601   string name = in_renametype(true_name);
00602   if (!name.empty()) {
00603     return name;
00604   }
00605   return type->get_preferred_name();
00606 }
00607 
00608 ////////////////////////////////////////////////////////////////////
00609 //     Function: InterrogateBuilder::hash_string
00610 //       Access: Public, Static
00611 //  Description: Hashes an arbitrary string into a four-character
00612 //               string using only the characters legal in a C
00613 //               identifier.
00614 ////////////////////////////////////////////////////////////////////
00615 string InterrogateBuilder::
00616 hash_string(const string &name, int shift_offset) {
00617   int hash = 0;
00618 
00619   int shift = 0;
00620   string::const_iterator ni;
00621   for (ni = name.begin(); ni != name.end(); ++ni) {
00622     int c = (int)(unsigned char)(*ni);
00623     int shifted_c = (c << shift) & 0xffffff;
00624     if (shift > 16) {
00625       // We actually want a circular shift, not an arithmetic shift.
00626       shifted_c |= ((c >> (24 - shift)) & 0xff) ;
00627     }
00628     hash = (hash + shifted_c) & 0xffffff;
00629     shift = (shift + shift_offset) % 24;
00630   }
00631 
00632   // Now multiply the hash by a biggish prime number and apply the
00633   // high-order bits back at the bottom, to scramble up the bits a
00634   // bit.  This helps reduce hash conflicts from names that are
00635   // similar to each other, by separating adjacent hash codes.
00636   int prime = 4999;
00637   int low_order = (hash * prime) & 0xffffff;
00638   int high_order = (int)((double)hash * (double)prime / (double)(1 << 24));
00639   hash = low_order ^ high_order;
00640 
00641   // Also add in the additional_number, times some prime factor.
00642   //  hash = (hash + additional_number * 1657) & 0xffffff;
00643 
00644   // Now turn the hash code into a four-character string.  For each
00645   // six bits, we choose a character in the set [A-Za-z0-9_].  Note
00646   // that there are only 63 characters to choose from; we have to
00647   // duplicate '_' for values 62 and 63.  This introduces a small
00648   // additional chance of hash conflicts.  No big deal, since we have
00649   // to resolve hash conflicts anyway.
00650 
00651   string result;
00652   int extract_h = hash;
00653   for (int i = 0; i < 4; i++) {
00654     int value = (extract_h & 0x3f);
00655     extract_h >>= 6;
00656     if (value < 26) {
00657       result += (char)('A' + value);
00658 
00659     } else if (value < 52) {
00660       result += (char)('a' + value - 26);
00661 
00662     } else if (value < 62) {
00663       result += (char)('0' + value - 52);
00664 
00665     } else {
00666       result += '_';
00667     }
00668   }
00669 
00670   return result;
00671 }
00672 
00673 ////////////////////////////////////////////////////////////////////
00674 //     Function: InterrogateBuilder::insert_param_list
00675 //       Access: Public
00676 //  Description: Inserts a list of space-separated parameters into the
00677 //               given command parameter list.
00678 ////////////////////////////////////////////////////////////////////
00679 void InterrogateBuilder::
00680 insert_param_list(InterrogateBuilder::Commands &commands,
00681                   const string &params) {
00682   size_t p = 0;
00683   while (p < params.length()) {
00684     while (p < params.length() && isspace(params[p])) {
00685       p++;
00686     }
00687     size_t q = p;
00688     while (q < params.length() && !isspace(params[q])) {
00689       q++;
00690     }
00691     if (p < q) {
00692       commands.insert(params.substr(p, q - p));
00693     }
00694     p = q;
00695   }
00696 }
00697 
00698 ////////////////////////////////////////////////////////////////////
00699 //     Function: InterrogateBuilder::in_forcetype
00700 //       Access: Private
00701 //  Description: Returns true if the indicated name is one that the
00702 //               user identified with a forcetype command.
00703 ////////////////////////////////////////////////////////////////////
00704 bool InterrogateBuilder::
00705 in_forcetype(const string &name) const {
00706   return (_forcetype.count(name) != 0);
00707 }
00708 
00709 ////////////////////////////////////////////////////////////////////
00710 //     Function: InterrogateBuilder::in_renametype
00711 //       Access: Private
00712 //  Description: If the user requested an explicit name for this type
00713 //               via the renametype command, returns that name;
00714 //               otherwise, returns the empty string.
00715 ////////////////////////////////////////////////////////////////////
00716 string InterrogateBuilder::
00717 in_renametype(const string &name) const {
00718   CommandParams::const_iterator pi;
00719   pi = _renametype.find(name);
00720   if (pi != _renametype.end()) {
00721     return (*pi).second;
00722   }
00723   return string();
00724 }
00725 
00726 ////////////////////////////////////////////////////////////////////
00727 //     Function: InterrogateBuilder::in_ignoretype
00728 //       Access: Private
00729 //  Description: Returns true if the indicated name is one that the
00730 //               user identified with an ignoretype command.
00731 ////////////////////////////////////////////////////////////////////
00732 bool InterrogateBuilder::
00733 in_ignoretype(const string &name) const {
00734   return (_ignoretype.count(name) != 0);
00735 }
00736 
00737 ////////////////////////////////////////////////////////////////////
00738 //     Function: InterrogateBuilder::in_ignoreinvolved
00739 //       Access: Private
00740 //  Description: Returns true if the indicated name is one that the
00741 //               user identified with an ignoreinvolved command.
00742 ////////////////////////////////////////////////////////////////////
00743 bool InterrogateBuilder::
00744 in_ignoreinvolved(const string &name) const {
00745   return (_ignoreinvolved.count(name) != 0);
00746 }
00747 ////////////////////////////////////////////////////////////////////
00748 //     Function: InterrogateBuilder::in_ignoreinvolved
00749 //       Access: Private
00750 //  Description: Returns true if the indicated type involves some type
00751 //               name that the user identified with an ignoreinvolved
00752 //               command.
00753 ////////////////////////////////////////////////////////////////////
00754 bool InterrogateBuilder::
00755 in_ignoreinvolved(CPPType *type) const {
00756   switch (type->get_subtype()) {
00757   case CPPDeclaration::ST_pointer:
00758     {
00759       CPPPointerType *ptr = type->as_pointer_type();
00760       return in_ignoreinvolved(ptr->_pointing_at);
00761     }
00762 
00763   case CPPDeclaration::ST_array:
00764     {
00765       CPPArrayType *ary = type->as_array_type();
00766       return in_ignoreinvolved(ary->_element_type);
00767     }
00768 
00769   case CPPDeclaration::ST_reference:
00770     {
00771       CPPReferenceType *ref = type->as_reference_type();
00772       return in_ignoreinvolved(ref->_pointing_at);
00773     }
00774 
00775   case CPPDeclaration::ST_const:
00776     {
00777       CPPConstType *cnst = type->as_const_type();
00778       return in_ignoreinvolved(cnst->_wrapped_around);
00779     }
00780 
00781   case CPPDeclaration::ST_function:
00782     {
00783       CPPFunctionType *ftype = type->as_function_type();
00784       if (in_ignoreinvolved(ftype->_return_type)) {
00785         return true;
00786       }
00787       const CPPParameterList::Parameters &params =
00788         ftype->_parameters->_parameters;
00789       CPPParameterList::Parameters::const_iterator pi;
00790       for (pi = params.begin(); pi != params.end(); ++pi) {
00791         if (in_ignoreinvolved((*pi)->_type)) {
00792           return true;
00793         }
00794       }
00795       return false;
00796     }
00797 
00798   default:
00799     return in_ignoreinvolved(type->get_simple_name());
00800   }
00801 }
00802 
00803 ////////////////////////////////////////////////////////////////////
00804 //     Function: InterrogateBuilder::in_ignorefile
00805 //       Access: Private
00806 //  Description: Returns true if the indicated name is one that the
00807 //               user identified with an ignorefile command.
00808 ////////////////////////////////////////////////////////////////////
00809 bool InterrogateBuilder::
00810 in_ignorefile(const string &name) const {
00811   return (_ignorefile.count(name) != 0);
00812 }
00813 
00814 ////////////////////////////////////////////////////////////////////
00815 //     Function: InterrogateBuilder::in_ignoremember
00816 //       Access: Private
00817 //  Description: Returns true if the indicated name is one that the
00818 //               user identified with an ignoremember command.
00819 ////////////////////////////////////////////////////////////////////
00820 bool InterrogateBuilder::
00821 in_ignoremember(const string &name) const {
00822   return (_ignoremember.count(name) != 0);
00823 }
00824 
00825 ////////////////////////////////////////////////////////////////////
00826 //     Function: InterrogateBuilder::in_noinclude
00827 //       Access: Private
00828 //  Description: Returns true if the indicated filename is one that
00829 //               the user identified with a noinclude command.
00830 ////////////////////////////////////////////////////////////////////
00831 bool InterrogateBuilder::
00832 in_noinclude(const string &name) const {
00833   return (_noinclude.count(name) != 0);
00834 }
00835 
00836 ////////////////////////////////////////////////////////////////////
00837 //     Function: InterrogateBuilder::should_include
00838 //       Access: Private
00839 //  Description: Returns true if the indicated filename is a valid
00840 //               file to explicitly #include in the generated .cxx
00841 //               file, false otherwise.
00842 ////////////////////////////////////////////////////////////////////
00843 bool InterrogateBuilder::
00844 should_include(const string &filename) const {
00845   // Don't directly include any .cxx or .I files.
00846   if (CPPFile::is_c_or_i_file(filename)) {
00847     return false;
00848   }
00849 
00850   // Also, don't include any files specifically forbidden in a .N
00851   // file.
00852   if (in_noinclude(filename)) {
00853     return false;
00854   }
00855 
00856   // Much as I hate to do it, I'm going to code in a special-case
00857   // for two particularly nasty header files that we probably don't
00858   // want to actually ever include.
00859   if (filename == "winbase.h" || filename == "windows.h") {
00860     return false;
00861   }
00862 
00863   // Finally, don't include *_src.h or *_src.cxx.  These are special
00864   // "template" files that should not generally be included directly.
00865   if (filename.length() > 6 && filename.substr(filename.length() - 6) == "_src.h") {
00866     return false;
00867   }
00868   if (filename.length() > 8 && filename.substr(filename.length() - 8) == "_src.cxx") {
00869     return false;
00870   }
00871 
00872   // Otherwise, no problem.
00873   return true;
00874 }
00875 
00876 ////////////////////////////////////////////////////////////////////
00877 //     Function: InterrogateBuilder::remap_indices
00878 //       Access: Private
00879 //  Description: Resequences all of the index numbers so that
00880 //               function wrappers start at 1 and occupy consecutive
00881 //               positions, and everything else follows.  This allows
00882 //               us to build a table of function wrappers by index
00883 //               number.
00884 //
00885 //               The "remaps" member is a list of FunctionRemap
00886 //               pointers.  The collision in naming is unfortunate;
00887 //               the FunctionRemap objects are so named because they
00888 //               remap synthesized function wrappers to actual C++
00889 //               methods and functions.  It has nothing to do with the
00890 //               remapping of index numbers, which is the purpose of
00891 //               this function.
00892 ////////////////////////////////////////////////////////////////////
00893 void InterrogateBuilder::
00894 remap_indices(vector<FunctionRemap *> &remaps) {
00895   IndexRemapper index_remap;
00896   InterrogateDatabase::get_ptr()->remap_indices(1, index_remap);
00897 
00898   TypesByName::iterator ti;
00899   for (ti = _types_by_name.begin(); ti != _types_by_name.end(); ++ti) {
00900     (*ti).second = index_remap.map_from((*ti).second);
00901   }
00902 
00903   FunctionsByName::iterator fi;
00904   for (fi = _functions_by_name.begin();
00905        fi != _functions_by_name.end();
00906        ++fi) {
00907     (*fi).second = index_remap.map_from((*fi).second);
00908   }
00909 
00910   vector<FunctionRemap *>::iterator ri;
00911   for (ri = remaps.begin(); ri != remaps.end(); ++ri) {
00912     FunctionRemap *remap = (*ri);
00913     remap->_wrapper_index = index_remap.map_from(remap->_wrapper_index);
00914   }
00915 }
00916 
00917 ////////////////////////////////////////////////////////////////////
00918 //     Function: InterrogateBuilder::scan_function
00919 //       Access: Private
00920 //  Description: Adds the indicated global function to the database,
00921 //               if warranted.
00922 ////////////////////////////////////////////////////////////////////
00923 void InterrogateBuilder::
00924 scan_function(CPPFunctionGroup *fgroup) {
00925   CPPFunctionGroup::Instances::const_iterator fi;
00926   for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) {
00927     CPPInstance *function = (*fi);
00928     scan_function(function);
00929   }
00930 }
00931 
00932 ////////////////////////////////////////////////////////////////////
00933 //     Function: InterrogateBuilder::scan_function
00934 //       Access: Private
00935 //  Description: Adds the indicated global function to the database,
00936 //               if warranted.
00937 ////////////////////////////////////////////////////////////////////
00938 void InterrogateBuilder::
00939 scan_function(CPPInstance *function) {
00940   assert(function != (CPPInstance *)NULL);
00941   assert(function->_type != (CPPType *)NULL &&
00942          function->_type->as_function_type() != (CPPFunctionType *)NULL);
00943   CPPFunctionType *ftype =
00944     function->_type->resolve_type(&parser, &parser)->as_function_type();
00945   assert(ftype != (CPPFunctionType *)NULL);
00946 
00947   CPPScope *scope = &parser;
00948   if (function->is_scoped()) {
00949     scope = function->get_scope(&parser, &parser);
00950     if (scope == (CPPScope *)NULL) {
00951       // Invalid scope.
00952       nout << "Invalid scope: " << *function->_ident << "\n";
00953       return;
00954     }
00955 
00956     if (scope->get_struct_type() != (CPPStructType *)NULL) {
00957       // Wait, this is a method, not a function.  This must be the
00958       // declaration for the method (since it's appearing
00959       // out-of-scope).  We don't need to define a new method for it,
00960       // but we'd like to update the comment, if we have a comment.
00961       update_method_comment(function, scope->get_struct_type(), scope);
00962       return;
00963     }
00964   }
00965 
00966   if (function->is_template()) {
00967     // The function is a template function, not a true function.
00968     return;
00969   }
00970 
00971   if (function->_file.is_c_file()) {
00972     // This function declaration appears in a .C file.  We can only
00973     // export functions whose prototypes appear in an .h file.
00974     return;
00975   }
00976 
00977   if (function->_file._source != CPPFile::S_local ||
00978       in_ignorefile(function->_file._filename_as_referenced)) {
00979     // The function is defined in some other package or in an
00980     // ignorable file.
00981     return;
00982   }
00983 
00984   if (function->_vis > min_vis) {
00985     // The function is not marked to be exported.
00986     return;
00987   }
00988 
00989   if ((function->_storage_class & CPPInstance::SC_static) != 0) {
00990     // The function is static, so can't be exported.
00991     return;
00992   }
00993 
00994   if (TypeManager::involves_protected(ftype)) {
00995     // We can't export the function because it involves parameter
00996     // types that are protected or private.
00997     return;
00998   }
00999 
01000   if (in_ignoreinvolved(ftype)) {
01001     // The function or its parameters involves something that the
01002     // user requested we ignore.
01003     return;
01004   }
01005 
01006   get_function(function, "",
01007                (CPPStructType *)NULL, scope, 
01008                InterrogateFunction::F_global);
01009 }
01010 
01011 ////////////////////////////////////////////////////////////////////
01012 //     Function: InterrogateBuilder::scan_struct_type
01013 //       Access: Private
01014 //  Description: Adds the indicated struct type to the database, if
01015 //               warranted.
01016 ////////////////////////////////////////////////////////////////////
01017 void InterrogateBuilder::
01018 scan_struct_type(CPPStructType *type) {
01019   if (type == (CPPStructType *)NULL) {
01020     return;
01021   }
01022 
01023   if (type->is_template()) {
01024     // The type is a template declaration, not a true type.
01025     return;
01026   }
01027 
01028   if (type->_file.is_c_file()) {
01029     // This type declaration appears in a .C file.  We can only export
01030     // types defined in a .h file.
01031     return;
01032   }
01033 
01034   if (type->_file._source != CPPFile::S_local ||
01035       in_ignorefile(type->_file._filename_as_referenced)) {
01036     // The type is defined in some other package or in an
01037     // ignorable file.
01038     return;
01039   }
01040 
01041   // Check if any of the members are exported.  If none of them are,
01042   // and the type itself is not marked for export, then never mind.
01043   if (type->_vis > min_vis) {
01044     CPPScope *scope = type->_scope;
01045 
01046     bool any_exported = false;
01047     CPPScope::Declarations::const_iterator di;
01048     for (di = scope->_declarations.begin();
01049          di != scope->_declarations.end() && !any_exported;
01050          ++di) {
01051       if ((*di)->_vis <= min_vis) {
01052         any_exported = true;
01053       }
01054     }
01055 
01056     if (!any_exported) {
01057       return;
01058     }
01059   }
01060 
01061   get_type(type, true);
01062 }
01063 
01064 ////////////////////////////////////////////////////////////////////
01065 //     Function: InterrogateBuilder::scan_enum_type
01066 //       Access: Private
01067 //  Description: Adds the indicated enum type to the database, if
01068 //               warranted.
01069 ////////////////////////////////////////////////////////////////////
01070 void InterrogateBuilder::
01071 scan_enum_type(CPPEnumType *type) {
01072   if (type == (CPPEnumType *)NULL) {
01073     return;
01074   }
01075 
01076   if (type->is_template()) {
01077     // The type is a template declaration, not a true type.
01078     return;
01079   }
01080 
01081   if (type->_file.is_c_file()) {
01082     // This type declaration appears in a .C file.  We can only export
01083     // types defined in a .h file.
01084     return;
01085   }
01086 
01087   if (type->_file._source != CPPFile::S_local ||
01088       in_ignorefile(type->_file._filename_as_referenced)) {
01089     // The type is defined in some other package or in an
01090     // ignorable file.
01091     return;
01092   }
01093 
01094   if (type->_vis > min_vis) {
01095     // The type is not marked to be exported.
01096     return;
01097   }
01098 
01099   get_type(type, true);
01100 }
01101 
01102 ////////////////////////////////////////////////////////////////////
01103 //     Function: InterrogateBuilder::scan_manifest
01104 //       Access: Private
01105 //  Description: Adds the indicated manifest constant to the database,
01106 //               if warranted.
01107 ////////////////////////////////////////////////////////////////////
01108 void InterrogateBuilder::
01109 scan_manifest(CPPManifest *manifest) {
01110   if (manifest == (CPPManifest *)NULL) {
01111     return;
01112   }
01113 
01114   if (manifest->_file.is_c_file()) {
01115     // This #define appears in a .C file.  We can only export
01116     // manifests defined in a .h file.
01117     return;
01118   }
01119 
01120   if (manifest->_file._source != CPPFile::S_local ||
01121       in_ignorefile(manifest->_file._filename_as_referenced)) {
01122     // The manifest is defined in some other package or in an
01123     // ignorable file.
01124     return;
01125   }
01126 
01127   if (manifest->_vis > min_vis) {
01128     // The manifest is not marked for export.
01129     return;
01130   }
01131 
01132   if (manifest->_has_parameters) {
01133     // We can't export manifest functions.
01134     return;
01135   }
01136 
01137   InterrogateManifest imanifest;
01138   imanifest._name = manifest->_name;
01139   imanifest._definition = manifest->expand();
01140 
01141   CPPType *type = manifest->determine_type();
01142   if (type != (CPPType *)NULL) {
01143     imanifest._flags |= InterrogateManifest::F_has_type;
01144     imanifest._type = get_type(type, false);
01145 
01146     CPPExpression *expr = manifest->_expr;
01147     CPPExpression::Result result = expr->evaluate();
01148     if (result._type == CPPExpression::RT_integer) {
01149       // We have an integer-valued expression.
01150       imanifest._flags |= InterrogateManifest::F_has_int_value;
01151       imanifest._int_value = result.as_integer();
01152 
01153     } else {
01154       // We have a more complex expression.  Generate a getter
01155       // function.
01156       FunctionIndex getter =
01157         get_getter(type, manifest->_name, (CPPStructType *)NULL, &parser,
01158                    (CPPInstance *)NULL);
01159 
01160       if (getter != 0) {
01161         imanifest._flags |= InterrogateManifest::F_has_getter;
01162         imanifest._getter = getter;
01163       }
01164     }
01165   }
01166 
01167   ManifestIndex index =
01168     InterrogateDatabase::get_ptr()->get_next_index();
01169   InterrogateDatabase::get_ptr()->add_manifest(index, imanifest);
01170 }
01171 
01172 ////////////////////////////////////////////////////////////////////
01173 //     Function: InterrogateBuilder::scan_element
01174 //       Access: Private
01175 //  Description: Adds the indicated data element to the database,
01176 //               if warranted.
01177 ////////////////////////////////////////////////////////////////////
01178 ElementIndex InterrogateBuilder::
01179 scan_element(CPPInstance *element, CPPStructType *struct_type,
01180              CPPScope *scope) {
01181   if (element == (CPPInstance *)NULL) {
01182     return 0;
01183   }
01184 
01185   if (element->is_template()) {
01186     // The element is a template element, not a true element.
01187     return 0;
01188   }
01189 
01190   if (element->is_scoped()) {
01191     if (element->get_scope(scope, &parser) != scope) {
01192       // This is an element defined out-of-scope.  It's probably the
01193       // definition for a data member.  Ignore it.
01194       return 0;
01195     }
01196   }
01197 
01198   if (element->_file.is_c_file()) {
01199     // This element declaration appears in a .C file.  We can only
01200     // export elements declared in a .h file.
01201     return 0;
01202   }
01203 
01204   if (element->_file._source != CPPFile::S_local ||
01205       in_ignorefile(element->_file._filename_as_referenced)) {
01206     // The element is defined in some other package or in an
01207     // ignorable file.
01208     return 0;
01209   }
01210 
01211   if (element->_vis > min_vis) {
01212     // The element is not marked for export.
01213     return 0;
01214   }
01215 
01216   if ((element->_storage_class & CPPInstance::SC_static) != 0) {
01217     // The element is static, so can't be exported.
01218     return 0;
01219   }
01220 
01221   // Make sure the element knows what its scope is.
01222   if (element->_ident->_native_scope != scope) {
01223     element = new CPPInstance(*element);
01224     element->_ident = new CPPIdentifier(*element->_ident);
01225     element->_ident->_native_scope = scope;
01226   }
01227 
01228   CPPType *element_type = TypeManager::resolve_type(element->_type, scope);
01229   CPPType *parameter_type = element_type;
01230 
01231   InterrogateElement ielement;
01232   ielement._name = element->get_local_name(scope);
01233   ielement._scoped_name = descope(element->get_local_name(&parser));
01234 
01235   ielement._type = get_type(TypeManager::unwrap_reference(element_type), false);
01236   if (ielement._type == 0) {
01237     // If we can't understand what type it is, forget it.
01238     return 0;
01239   }
01240 
01241   if (!TypeManager::involves_protected(element_type)) {
01242     // We can only generate a getter and a setter if we can talk about
01243     // the type it is.
01244 
01245     if (parameter_type->as_struct_type() != (CPPStructType *)NULL) {
01246       // Wrap the type in a const reference.
01247       parameter_type = TypeManager::wrap_const_reference(parameter_type);
01248     }
01249 
01250     // Generate a getter and setter function for the element.
01251     FunctionIndex getter =
01252       get_getter(parameter_type, element->get_local_name(scope),
01253                  struct_type, scope, element);
01254     if (getter != 0) {
01255       ielement._flags |= InterrogateElement::F_has_getter;
01256       ielement._getter = getter;
01257     }
01258 
01259     if (TypeManager::is_assignable(element_type)) {
01260       FunctionIndex setter =
01261         get_setter(parameter_type, element->get_local_name(scope),
01262                    struct_type, scope, element);
01263       if (setter != 0) {
01264         ielement._flags |= InterrogateElement::F_has_setter;
01265         ielement._setter = setter;
01266       }
01267     }
01268   }
01269 
01270   if (struct_type == (CPPStructType *)NULL) {
01271     // This is a global data element: not a data member.
01272     ielement._flags |= InterrogateElement::F_global;
01273   }
01274 
01275   ElementIndex index =
01276     InterrogateDatabase::get_ptr()->get_next_index();
01277   InterrogateDatabase::get_ptr()->add_element(index, ielement);
01278 
01279   return index;
01280 }
01281 
01282 ////////////////////////////////////////////////////////////////////
01283 //     Function: InterrogateBuilder::get_getter
01284 //       Access: Private
01285 //  Description: Adds a function to return the value for the indicated
01286 //               expression.  Returns the new function index.
01287 ////////////////////////////////////////////////////////////////////
01288 FunctionIndex InterrogateBuilder::
01289 get_getter(CPPType *expr_type, string expression,
01290            CPPStructType *struct_type, CPPScope *scope,
01291            CPPInstance *element) {
01292   // Make up a name for the function.
01293   string fname = clean_identifier("get_" + expression);
01294 
01295   // Unroll the "const" from the expr_type, since that doesn't matter
01296   // for a return type.
01297   while (expr_type->as_const_type() != (CPPConstType *)NULL) {
01298     expr_type = expr_type->as_const_type()->_wrapped_around;
01299     assert(expr_type != (CPPType *)NULL);
01300   }
01301 
01302   // Make up a CPPFunctionType.
01303   CPPParameterList *params = new CPPParameterList;
01304   CPPFunctionType *ftype = new CPPFunctionType(expr_type, params, 0);
01305 
01306   // Now make up an instance for the function.
01307   CPPInstance *function = new CPPInstance(ftype, fname);
01308   function->_ident->_native_scope = scope;
01309 
01310   int getter_flags = InterrogateFunction::F_getter;
01311 
01312   if (struct_type != (CPPStructType *)NULL) {
01313     // This is a data member for some class.
01314     assert(element != (CPPInstance *)NULL);
01315     assert(scope != (CPPScope *)NULL);
01316 
01317     if ((element->_storage_class & CPPInstance::SC_static) != 0) {
01318       // This is a static data member; therefore, the synthesized
01319       // getter is also static.
01320       function->_storage_class |= CPPInstance::SC_static;
01321 
01322       // And the expression is fully scoped.
01323       expression = element->get_local_name(&parser);
01324 
01325     } else {
01326       // This is a non-static data member, so it has a const
01327       // synthesized getter method.
01328       ftype->_flags |= CPPFunctionType::F_const_method;
01329 
01330       // And the expression is locally scoped.
01331       expression = element->get_local_name(scope);
01332       getter_flags |= InterrogateFunction::F_method;
01333     }
01334   }
01335 
01336   // Now check to see if there's already a function matching this
01337   // name.  If there is, we can't define a getter, and we
01338   // shouldn't mistake this other function for a synthesized getter.
01339   string function_name = TypeManager::get_function_name(function);
01340   if (_functions_by_name.count(function_name) != 0) {
01341     return 0;
01342   }
01343 
01344   ostringstream desc;
01345   desc << "getter for ";
01346   if (element != (CPPInstance *)NULL) {
01347     element->_initializer = (CPPExpression *)NULL;
01348     element->output(desc, 0, &parser, false);
01349     desc << ";";
01350   } else {
01351     desc << expression;
01352   }
01353   string description = desc.str();
01354 
01355   // It's clear; make a getter.
01356   FunctionIndex index =
01357     get_function(function, description,
01358                  struct_type, scope,
01359                  getter_flags, expression);
01360 
01361   InterrogateDatabase::get_ptr()->update_function(index)._comment = description;
01362   return index;
01363 }
01364 
01365 ////////////////////////////////////////////////////////////////////
01366 //     Function: InterrogateBuilder::get_setter
01367 //       Access: Private
01368 //  Description: Adds a function to return the value for the indicated
01369 //               expression.  Returns the new function index.
01370 ////////////////////////////////////////////////////////////////////
01371 FunctionIndex InterrogateBuilder::
01372 get_setter(CPPType *expr_type, string expression,
01373            CPPStructType *struct_type, CPPScope *scope,
01374            CPPInstance *element) {
01375   // Make up a name for the function.
01376   string fname = clean_identifier("set_" + expression);
01377 
01378   // Make up a CPPFunctionType.
01379   CPPParameterList *params = new CPPParameterList;
01380   CPPInstance *param0 = new CPPInstance(expr_type, "value");
01381   params->_parameters.push_back(param0);
01382   CPPType *void_type = TypeManager::get_void_type();
01383   CPPFunctionType *ftype = new CPPFunctionType(void_type, params, 0);
01384 
01385   // Now make up an instance for the function.
01386   CPPInstance *function = new CPPInstance(ftype, fname);
01387   function->_ident->_native_scope = scope;
01388 
01389   int setter_flags = InterrogateFunction::F_setter;
01390 
01391   if (struct_type != (CPPStructType *)NULL) {
01392     // This is a data member for some class.
01393     assert(element != (CPPInstance *)NULL);
01394     assert(scope != (CPPScope *)NULL);
01395 
01396     if ((element->_storage_class & CPPInstance::SC_static) != 0) {
01397       // This is a static data member; therefore, the synthesized
01398       // setter is also static.
01399       function->_storage_class |= CPPInstance::SC_static;
01400 
01401       // And the expression is fully scoped.
01402       expression = element->get_local_name(&parser);
01403 
01404     } else {
01405       // This is a non-static data member.  The expression is locally
01406       // scoped.
01407       expression = element->get_local_name(scope);
01408       setter_flags |= InterrogateFunction::F_method;
01409     }
01410   }
01411 
01412   // Now check to see if there's already a function matching this
01413   // name.  If there is, we can't define a setter, and we
01414   // shouldn't mistake this other function for a synthesized setter.
01415   string function_name = TypeManager::get_function_name(function);
01416   if (_functions_by_name.count(function_name) != 0) {
01417     return 0;
01418   }
01419 
01420   ostringstream desc;
01421   desc << "setter for ";
01422   if (element != (CPPInstance *)NULL) {
01423     element->_initializer = (CPPExpression *)NULL;
01424     element->output(desc, 0, &parser, false);
01425     desc << ";";
01426   } else {
01427     desc << expression;
01428   }
01429   string description = desc.str();
01430 
01431   // It's clear; make a setter.
01432   FunctionIndex index =
01433     get_function(function, description,
01434                  struct_type, scope,
01435                  setter_flags, expression);
01436 
01437   InterrogateDatabase::get_ptr()->update_function(index)._comment = description;
01438   return index;
01439 }
01440 
01441 ////////////////////////////////////////////////////////////////////
01442 //     Function: InterrogateBuilder::get_cast_function
01443 //       Access: Private
01444 //  Description: Adds a function to cast from a pointer of the
01445 //               indicated type to a pointer of the indicated type to
01446 //               the database.  Returns the new function index.
01447 ////////////////////////////////////////////////////////////////////
01448 FunctionIndex InterrogateBuilder::
01449 get_cast_function(CPPType *to_type, CPPType *from_type,
01450                   const string &prefix) {
01451   CPPInstance *function;
01452   CPPStructType *struct_type = from_type->as_struct_type();
01453   CPPScope *scope = &parser;
01454 
01455   if (struct_type != (CPPStructType *)NULL) {
01456     // We'll make this a method of the from type.
01457     scope = struct_type->get_scope();
01458 
01459     // Make up a name for the method.
01460     string fname =
01461       clean_identifier(prefix + "_to_" + get_preferred_name(to_type));
01462 
01463     // Make up a CPPFunctionType.
01464     CPPType *to_ptr_type = CPPType::new_type(new CPPPointerType(to_type));
01465 
01466     CPPParameterList *params = new CPPParameterList;
01467     CPPFunctionType *ftype = new CPPFunctionType(to_ptr_type, params, 0);
01468 
01469     // Now make up an instance for the function.
01470     function = new CPPInstance(ftype, fname);
01471 
01472   } else {
01473     // The from type isn't a struct or a class, so this has to be an
01474     // external function.
01475 
01476     // Make up a name for the function.
01477     string fname =
01478       clean_identifier(prefix + "_" + get_preferred_name(from_type) +
01479                        "_to_" + get_preferred_name(to_type));
01480 
01481     // Make up a CPPFunctionType.
01482     CPPType *from_ptr_type = CPPType::new_type(new CPPPointerType(from_type));
01483     CPPType *to_ptr_type = CPPType::new_type(new CPPPointerType(to_type));
01484 
01485     CPPInstance *param0 = new CPPInstance(from_ptr_type, "this");
01486     CPPParameterList *params = new CPPParameterList;
01487     params->_parameters.push_back(param0);
01488     CPPFunctionType *ftype = new CPPFunctionType(to_ptr_type, params, 0);
01489 
01490     // Now make up an instance for the function.
01491     function = new CPPInstance(ftype, fname);
01492   }
01493 
01494   ostringstream desc;
01495   desc << prefix << " from " << *from_type << " to " << *to_type;
01496   string description = desc.str();
01497 
01498   FunctionIndex index =
01499     get_function(function, description,
01500                  struct_type, scope,
01501                  InterrogateFunction::F_typecast);
01502 
01503   InterrogateDatabase::get_ptr()->update_function(index)._comment = description;
01504   return index;
01505 }
01506 
01507 ////////////////////////////////////////////////////////////////////
01508 //     Function: InterrogateBuilder::get_function
01509 //       Access: Private
01510 //  Description: Adds the indicated function to the database, if it is
01511 //               not already present.  In either case, returns the
01512 //               FunctionIndex of the function within the database.
01513 ////////////////////////////////////////////////////////////////////
01514 FunctionIndex InterrogateBuilder::
01515 get_function(CPPInstance *function, string description,
01516              CPPStructType *struct_type,
01517              CPPScope *scope, int flags,
01518              const string &expression) {
01519   // Get a unique function signature.  Make sure we tell the function
01520   // where its native scope is, so we get a fully-scoped signature.
01521 
01522   if (function->_ident->_native_scope != scope) {
01523     function = new CPPInstance(*function);
01524     function->_ident = new CPPIdentifier(*function->_ident);
01525     function->_ident->_native_scope = scope;
01526   }
01527   CPPFunctionType *ftype =
01528     function->_type->resolve_type(scope, &parser)->as_function_type();
01529   function->_type = ftype;
01530 
01531   if ((ftype->_flags & CPPFunctionType::F_constructor) &&
01532       struct_type != (CPPStructType *)NULL &&
01533       struct_type->is_abstract()) {
01534     // This is a constructor for an abstract class; forget it.
01535     return 0;
01536   }
01537 
01538   string function_name = TypeManager::get_function_name(function);
01539   string function_signature = TypeManager::get_function_signature(function);
01540 
01541   // First, check to see if it's already there.
01542   FunctionsByName::const_iterator tni =
01543     _functions_by_name.find(function_name);
01544   if (tni != _functions_by_name.end()) {
01545     FunctionIndex index = (*tni).second;
01546     // It's already here, so update the flags.
01547     InterrogateFunction &ifunction =
01548       InterrogateDatabase::get_ptr()->update_function(index);
01549 
01550     ifunction._flags |= flags;
01551 
01552     // And/or the comment.
01553     if (function->_leading_comment != (CPPCommentBlock *)NULL) {
01554       string comment = trim_blanks(function->_leading_comment->_comment);
01555       if (!ifunction._comment.empty()) {
01556         ifunction._comment += "\n\n";
01557       }
01558       ifunction._comment += comment;
01559     }
01560 
01561     // Also, make sure this particular signature is defined.
01562     ifunction._instances->insert(InterrogateFunction::Instances::value_type(function_signature, function));
01563 
01564     return index;
01565   }
01566 
01567   // It isn't here, so we'll have to define it.
01568   FunctionIndex index =
01569     InterrogateDatabase::get_ptr()->get_next_index();
01570   _functions_by_name[function_name] = index;
01571 
01572   InterrogateFunction *ifunction = new InterrogateFunction;
01573   ifunction->_name = function->get_local_name(scope);
01574   ifunction->_scoped_name = descope(function->get_local_name(&parser));
01575   ifunction->_instances = new InterrogateFunction::Instances;
01576 
01577   if (function->_leading_comment != (CPPCommentBlock *)NULL) {
01578     ifunction->_comment = trim_blanks(function->_leading_comment->_comment);
01579   }
01580 
01581   ostringstream prototype;
01582   function->output(prototype, 0, &parser, false);
01583   prototype << ";";
01584   ifunction->_prototype = prototype.str();
01585 
01586   if (struct_type != (CPPStructType *)NULL) {
01587     // The function is a method.
01588     ifunction->_flags |= InterrogateFunction::F_method;
01589     ifunction->_class = get_type(struct_type, false);
01590   }
01591 
01592   ifunction->_flags |= flags;
01593   ifunction->_instances->insert(InterrogateFunction::Instances::value_type(function_signature, function));
01594   ifunction->_expression = expression;
01595 
01596   InterrogateDatabase::get_ptr()->add_function(index, ifunction);
01597 
01598   return index;
01599 }
01600 
01601 ////////////////////////////////////////////////////////////////////
01602 //     Function: InterrogateBuilder::get_atomic_string_type
01603 //       Access: Private
01604 //  Description: Returns a TypeIndex for the "atomic string" type,
01605 //               which is a bogus type that might be used if -string
01606 //               is passed to interrogate.  It means to translate
01607 //               basic_string<char> and char * to whatever atomic
01608 //               string type is native to the particular the scripting
01609 //               language we happen to be generating wrappers for.
01610 ////////////////////////////////////////////////////////////////////
01611 TypeIndex InterrogateBuilder::
01612 get_atomic_string_type() {
01613   // Make up a true name that can't possibly clash with an actual C++
01614   // type name.
01615   string true_name = "atomic string";
01616 
01617   TypesByName::const_iterator tni = _types_by_name.find(true_name);
01618   if (tni != _types_by_name.end()) {
01619     return (*tni).second;
01620   }
01621 
01622   // This is the first time the atomic string has been requested;
01623   // define it now.
01624 
01625   TypeIndex index = InterrogateDatabase::get_ptr()->get_next_index();
01626   _types_by_name[true_name] = index;
01627 
01628   InterrogateType itype;
01629   itype._flags |= InterrogateType::F_atomic;
01630   itype._atomic_token = AT_string;
01631   itype._true_name = true_name;
01632   itype._scoped_name = true_name;
01633   itype._name = true_name;
01634 
01635   InterrogateDatabase::get_ptr()->add_type(index, itype);
01636 
01637   return index;
01638 }
01639 
01640 ////////////////////////////////////////////////////////////////////
01641 //     Function: InterrogateBuilder::get_type
01642 //       Access: Private
01643 //  Description: Adds the indicated type to the database, if it is not
01644 //               already present.  In either case, returns the
01645 //               TypeIndex of the type within the database.
01646 ////////////////////////////////////////////////////////////////////
01647 TypeIndex InterrogateBuilder::
01648 get_type(CPPType *type, bool global) {
01649   if (type->is_template()) {
01650     // Can't do anything with a template type.
01651     return 0;
01652   }
01653 
01654   TypeIndex index = 0;
01655 
01656   // First, check to see if it's already there.
01657   string true_name = type->get_local_name(&parser);
01658   TypesByName::const_iterator tni = _types_by_name.find(true_name);
01659   if (tni != _types_by_name.end()) {
01660     // It's already here, so update the global flag.
01661     index = (*tni).second;
01662     if (index == 0) {
01663       // This is an invalid type; we don't know anything about it.
01664       return 0;
01665     }
01666 
01667     InterrogateType &itype = InterrogateDatabase::get_ptr()->update_type(index);
01668     if (global) {
01669       itype._flags |= InterrogateType::F_global;
01670     }
01671 
01672     if ((itype._flags & InterrogateType::F_fully_defined) != 0) {
01673       return index;
01674     }
01675 
01676     // But wait--it's not fully defined yet!  We'll go ahead and
01677     // define it now.
01678   }
01679 
01680   bool forced = in_forcetype(true_name);
01681 
01682   if (index == 0) {
01683     // It isn't already there, so we have to define it.
01684     index = InterrogateDatabase::get_ptr()->get_next_index();
01685     _types_by_name[true_name] = index;
01686 
01687     InterrogateType itype;
01688     if (global) {
01689       itype._flags |= InterrogateType::F_global;
01690     }
01691     InterrogateDatabase::get_ptr()->add_type(index, itype);
01692   }
01693 
01694   InterrogateType &itype =
01695     InterrogateDatabase::get_ptr()->update_type(index);
01696 
01697   itype._name = get_preferred_name(type);
01698   itype._scoped_name = true_name;
01699   itype._true_name = true_name;
01700   itype._cpptype = type;
01701 
01702   if (type->_declaration != (CPPTypeDeclaration *)NULL) {
01703     // This type has a declaration; does the declaration have a
01704     // comment?
01705     CPPTypeDeclaration *decl = type->_declaration;
01706     if (decl->_leading_comment != (CPPCommentBlock *)NULL) {
01707       itype._comment = trim_blanks(decl->_leading_comment->_comment);
01708     }
01709   }
01710 
01711   CPPExtensionType *ext_type = type->as_extension_type();
01712   if (ext_type != (CPPExtensionType *)NULL) {
01713     // If it's an extension type of some kind, it might be scoped.
01714     if (ext_type->_ident != (CPPIdentifier *)NULL) {
01715       CPPScope *scope = ext_type->_ident->get_scope(&parser, &parser);
01716       while (scope->as_template_scope() != (CPPTemplateScope *)NULL) {
01717         assert(scope->get_parent_scope() != scope);
01718         scope = scope->get_parent_scope();
01719         assert(scope != (CPPScope *)NULL);
01720       }
01721       itype._cppscope = scope;
01722 
01723       if (scope != &parser) {
01724         // We're scoped!
01725         itype._scoped_name =
01726           descope(scope->get_local_name(&parser) + "::" + itype._name);
01727         CPPStructType *struct_type = scope->get_struct_type();
01728 
01729         if (struct_type != (CPPStructType *)NULL) {
01730           itype._flags |= InterrogateType::F_nested;
01731           itype._outer_class = get_type(struct_type, false);
01732         }
01733       }
01734     }
01735   }
01736 
01737   if (forced || !in_ignoretype(true_name)) {
01738     itype._flags |= InterrogateType::F_fully_defined;
01739 
01740     if (type->as_simple_type() != (CPPSimpleType *)NULL) {
01741       define_atomic_type(itype, type->as_simple_type());
01742 
01743     } else if (type->as_pointer_type() != (CPPPointerType *)NULL) {
01744       define_wrapped_type(itype, type->as_pointer_type());
01745 
01746     } else if (type->as_const_type() != (CPPConstType *)NULL) {
01747       define_wrapped_type(itype, type->as_const_type());
01748 
01749     } else if (type->as_struct_type() != (CPPStructType *)NULL) {
01750       define_struct_type(itype, type->as_struct_type(), index, forced);
01751 
01752     } else if (type->as_enum_type() != (CPPEnumType *)NULL) {
01753       define_enum_type(itype, type->as_enum_type());
01754 
01755     } else if (type->as_extension_type() != (CPPExtensionType *)NULL) {
01756       define_extension_type(itype, type->as_extension_type());
01757 
01758     } else {
01759       //      nout << "Attempt to define invalid type " << true_name << "\n";
01760 
01761       // Remove the type from the database.
01762       InterrogateDatabase::get_ptr()->remove_type(index);
01763       _types_by_name[true_name] = 0;
01764       index = 0;
01765     }
01766   }
01767 
01768   return index;
01769 }
01770 
01771 ////////////////////////////////////////////////////////////////////
01772 //     Function: InterrogateBuilder::define_atomic_type
01773 //       Access: Private
01774 //  Description: Builds up a definition for the indicated atomic type.
01775 ////////////////////////////////////////////////////////////////////
01776 void InterrogateBuilder::
01777 define_atomic_type(InterrogateType &itype, CPPSimpleType *cpptype) {
01778   itype._flags |= InterrogateType::F_atomic;
01779 
01780   switch (cpptype->_type) {
01781   case CPPSimpleType::T_bool:
01782     itype._atomic_token = AT_bool;
01783     break;
01784 
01785   case CPPSimpleType::T_char:
01786     itype._atomic_token = AT_char;
01787     break;
01788 
01789   case CPPSimpleType::T_int:
01790     itype._atomic_token = AT_int;
01791     break;
01792 
01793   case CPPSimpleType::T_float:
01794     itype._atomic_token = AT_float;
01795     break;
01796 
01797   case CPPSimpleType::T_double:
01798     itype._atomic_token = AT_double;
01799     break;
01800 
01801   case CPPSimpleType::T_void:
01802     itype._atomic_token = AT_void;
01803     break;
01804 
01805   default:
01806     nout << "Invalid CPPSimpleType: " << (int)cpptype->_type << "\n";
01807     itype._atomic_token = AT_not_atomic;
01808   }
01809 
01810   if ((cpptype->_flags & CPPSimpleType::F_longlong) != 0) {
01811     itype._flags |= InterrogateType::F_longlong;
01812 
01813   } else if ((cpptype->_flags & CPPSimpleType::F_long) != 0) {
01814     itype._flags |= InterrogateType::F_long;
01815   }
01816 
01817   if ((cpptype->_flags & CPPSimpleType::F_short) != 0) {
01818     itype._flags |= InterrogateType::F_short;
01819   }
01820   if ((cpptype->_flags & CPPSimpleType::F_unsigned) != 0) {
01821     itype._flags |= InterrogateType::F_unsigned;
01822   }
01823   if ((cpptype->_flags & CPPSimpleType::F_signed) != 0) {
01824     itype._flags |= InterrogateType::F_signed;
01825   }
01826 }
01827 
01828 ////////////////////////////////////////////////////////////////////
01829 //     Function: InterrogateBuilder::define_wrapped_type
01830 //       Access: Private
01831 //  Description: Builds up a definition for the indicated wrapped type.
01832 ////////////////////////////////////////////////////////////////////
01833 void InterrogateBuilder::
01834 define_wrapped_type(InterrogateType &itype, CPPPointerType *cpptype) {
01835   itype._flags |= (InterrogateType::F_wrapped | InterrogateType::F_pointer);
01836   itype._wrapped_type = get_type(cpptype->_pointing_at, false);
01837 }
01838 
01839 ////////////////////////////////////////////////////////////////////
01840 //     Function: InterrogateBuilder::define_wrapped_type
01841 //       Access: Private
01842 //  Description: Builds up a definition for the indicated wrapped type.
01843 ////////////////////////////////////////////////////////////////////
01844 void InterrogateBuilder::
01845 define_wrapped_type(InterrogateType &itype, CPPConstType *cpptype) {
01846   itype._flags |= (InterrogateType::F_wrapped | InterrogateType::F_const);
01847   itype._wrapped_type = get_type(cpptype->_wrapped_around, false);
01848 }
01849 
01850 ////////////////////////////////////////////////////////////////////
01851 //     Function: InterrogateBuilder::define_struct_type
01852 //       Access: Private
01853 //  Description: Builds up a definition for the indicated struct type.
01854 ////////////////////////////////////////////////////////////////////
01855 void InterrogateBuilder::
01856 define_struct_type(InterrogateType &itype, CPPStructType *cpptype,
01857                    TypeIndex type_index, bool forced) {
01858   if (cpptype->get_simple_name().empty()) {
01859     // If the type has no name, forget it.  We don't export anonymous
01860     // types.
01861     return;
01862   }
01863 
01864   cpptype = TypeManager::resolve_type(cpptype)->as_struct_type();
01865   assert(cpptype != (CPPStructType *)NULL);
01866   cpptype->check_virtual();
01867 
01868   switch (cpptype->_type) {
01869   case CPPExtensionType::T_class:
01870     itype._flags |= InterrogateType::F_class;
01871     break;
01872 
01873   case CPPExtensionType::T_struct:
01874     itype._flags |= InterrogateType::F_struct;
01875     break;
01876 
01877   case CPPExtensionType::T_union:
01878     itype._flags |= InterrogateType::F_union;
01879     break;
01880 
01881   default:
01882     break;
01883   }
01884 
01885   if (cpptype->_file.is_c_file()) {
01886     // This type declaration appears in a .C file.  We can only export
01887     // types defined in a .h file.
01888     return;
01889   }
01890 
01891   if (!forced &&
01892       (cpptype->_file._source != CPPFile::S_local ||
01893        in_ignorefile(cpptype->_file._filename_as_referenced))) {
01894     // The struct type is defined in some other package or in an
01895     // ignorable file, so don't try to output it.
01896 
01897     // This means we also don't gather any information about its
01898     // derivations or determine if an implicit destructor is
01899     // necessary.  However, this is not important, and it causes
01900     // problems if we do (how many implicit destructors do we need,
01901     // anyway?).
01902     itype._flags &= ~InterrogateType::F_fully_defined;
01903     return;
01904   }
01905 
01906   // Make sure the class declaration within its parent scope isn't
01907   // private or protected.  If it is, we can't export any of its
01908   // members.
01909   if (TypeManager::involves_unpublished(cpptype)) {
01910     itype._flags &= ~InterrogateType::F_fully_defined;
01911     itype._flags |= InterrogateType::F_unpublished;
01912     return;
01913   }
01914   if (TypeManager::involves_protected(cpptype)) {
01915     itype._flags &= ~InterrogateType::F_fully_defined;
01916     return;
01917   }
01918 
01919   // A struct type should always be global.
01920   itype._flags |= InterrogateType::F_global;
01921   
01922   CPPScope *scope = cpptype->_scope;
01923   
01924   CPPStructType::Derivation::const_iterator bi;
01925   for (bi = cpptype->_derivation.begin();
01926        bi != cpptype->_derivation.end();
01927        ++bi) {
01928     const CPPStructType::Base &base = (*bi);
01929     if (base._vis <= V_public) {
01930       CPPType *base_type = TypeManager::resolve_type(base._base, scope);
01931       TypeIndex base_index = get_type(base_type, true);
01932       
01933       if (base_index == 0) {
01934         nout << *cpptype << " reports a derivation from an invalid type.\n";
01935 
01936       } else {
01937         InterrogateType::Derivation d;
01938         d._flags = 0;
01939         d._base = base_index;
01940         d._upcast = 0;
01941         d._downcast = 0;
01942         
01943         // Do we need to synthesize upcast and downcast functions?
01944         bool generate_casts = false;
01945         if (base._is_virtual) {
01946           // We do in the presence of virtual inheritance.
01947           generate_casts = true;
01948           
01949         } else if (bi != cpptype->_derivation.begin()) {
01950           // Or if we're not talking about the leftmost fork of multiple
01951           // inheritance.
01952           generate_casts = true;
01953           
01954         } else if (cpptype->_derivation.size() != 1 &&
01955                    left_inheritance_requires_upcast) {
01956           // Or even if we are the leftmost fork of multiple
01957           // inheritance, if the flag is set indicating that this
01958           // requires a pointer change.  (For many compilers, this does
01959           // not require a pointer change.)
01960           generate_casts = true;
01961         }
01962         
01963         if (generate_casts) {
01964           d._upcast = get_cast_function(base_type, cpptype, "upcast");
01965           d._flags |= InterrogateType::DF_upcast;
01966           
01967           if (base._is_virtual) {
01968             // If this is a virtual inheritance, we can't write a
01969             // downcast.
01970             d._flags |= InterrogateType::DF_downcast_impossible;
01971           } else {
01972             d._downcast = get_cast_function(cpptype, base_type, "downcast");
01973             d._flags |= InterrogateType::DF_downcast;
01974           }
01975         }
01976 
01977         itype._derivations.push_back(d);
01978       }
01979     }
01980   }
01981 
01982   CPPScope::Declarations::const_iterator di;
01983   for (di = scope->_declarations.begin();
01984        di != scope->_declarations.end();
01985        ++di) {
01986     if ((*di)->get_subtype() == CPPDeclaration::ST_instance) {
01987       CPPInstance *inst = (*di)->as_instance();
01988       if (inst->_type->get_subtype() == CPPDeclaration::ST_function) {
01989         // Here's a method declaration.
01990         define_method(inst, itype, cpptype, scope);
01991 
01992       } else {
01993         // Here's a data member declaration.
01994         ElementIndex data_member = scan_element(inst, cpptype, scope);
01995         if (data_member != 0) {
01996           itype._elements.push_back(data_member);
01997         }
01998       }
01999 
02000     } else if ((*di)->get_subtype() == CPPDeclaration::ST_type_declaration) {
02001       CPPType *type = (*di)->as_type_declaration()->_type;
02002 
02003       if ((*di)->_vis <= min_vis) {
02004         if (type->as_struct_type() != (CPPStructType *)NULL ||
02005             type->as_enum_type() != (CPPEnumType *)NULL) {
02006           // Here's a nested class or enum definition.
02007           type->_vis = (*di)->_vis;
02008 
02009           CPPExtensionType *nested_type = type->as_extension_type();
02010           assert(nested_type != (CPPExtensionType *)NULL);
02011 
02012           // Only try to export named types.
02013           if (nested_type->_ident != (CPPIdentifier *)NULL) {
02014             TypeIndex nested_index = get_type(nested_type, false);
02015             itype._nested_types.push_back(nested_index);
02016           }
02017         }
02018       }
02019     }
02020   }
02021 
02022   if ((itype._flags & InterrogateType::F_inherited_destructor) != 0) {
02023     // If we have inherited our virtual destructor from our base
02024     // class, go ahead and assign the same function index.
02025     assert(!itype._derivations.empty());
02026     TypeIndex base_type_index = itype._derivations.front()._base;
02027     InterrogateType &base_type = InterrogateDatabase::get_ptr()->
02028       update_type(base_type_index);
02029 
02030     itype._destructor = base_type._destructor;
02031 
02032   } else if ((itype._flags &
02033               (InterrogateType::F_true_destructor |
02034                InterrogateType::F_private_destructor |
02035                InterrogateType::F_inherited_destructor |
02036                InterrogateType::F_implicit_destructor)) == 0) {
02037     // If we didn't get a destructor at all, we should make a wrapper
02038     // for one anyway.
02039     string function_name = "~" + cpptype->get_simple_name();
02040 
02041     // Make up a CPPFunctionType.
02042     CPPType *void_type = TypeManager::get_void_type();
02043     CPPParameterList *params = new CPPParameterList;
02044     CPPFunctionType *ftype = new CPPFunctionType(void_type, params, 0);
02045     ftype->_flags |= CPPFunctionType::F_destructor;
02046 
02047     // Now make up an instance for the destructor.
02048     CPPInstance *function = new CPPInstance(ftype, function_name);
02049 
02050     itype._destructor = get_function(function, "",
02051                                      cpptype, cpptype->get_scope(),
02052                                      0);
02053     itype._flags |= InterrogateType::F_implicit_destructor;
02054   }
02055 }
02056 
02057 ////////////////////////////////////////////////////////////////////
02058 //     Function: InterrogateBuilder::update_method_comment
02059 //       Access: Private
02060 //  Description: Updates the method definition in the database to
02061 //               include whatever comment is associated with this
02062 //               declaration.  This is called when we encounted a
02063 //               method definition outside of the class; the only new
02064 //               information this might include for us is the method
02065 //               comment.
02066 ////////////////////////////////////////////////////////////////////
02067 void InterrogateBuilder::
02068 update_method_comment(CPPInstance *function, CPPStructType *struct_type,
02069                       CPPScope *scope) {
02070   if (function->_leading_comment == (CPPCommentBlock *)NULL) {
02071     // No comment anyway.  Forget it.
02072     return;
02073   }
02074 
02075   // Get a function name so we can look this method up.
02076   if (function->_ident->_native_scope != scope) {
02077     function = new CPPInstance(*function);
02078     function->_ident = new CPPIdentifier(*function->_ident);
02079     function->_ident->_native_scope = scope;
02080   }
02081   CPPFunctionType *ftype =
02082     function->_type->resolve_type(scope, &parser)->as_function_type();
02083   function->_type = ftype;
02084 
02085   string function_name = TypeManager::get_function_name(function);
02086 
02087   // Now look it up.
02088   FunctionsByName::const_iterator tni =
02089     _functions_by_name.find(function_name);
02090   if (tni != _functions_by_name.end()) {
02091     FunctionIndex index = (*tni).second;
02092 
02093     // Here it is!
02094     InterrogateFunction &ifunction =
02095       InterrogateDatabase::get_ptr()->update_function(index);
02096 
02097     // Update the comment.
02098     string comment = trim_blanks(function->_leading_comment->_comment);
02099     if (!ifunction._comment.empty()) {
02100       ifunction._comment += "\n\n";
02101     }
02102     ifunction._comment += comment;
02103     /*
02104     if (comment.length() > ifunction._comment.length()) {
02105       ifunction._comment = comment;
02106     }
02107     */
02108   }
02109 }
02110 
02111 
02112 ////////////////////////////////////////////////////////////////////
02113 //     Function: InterrogateBuilder::define_method
02114 //       Access: Private
02115 //  Description: Adds the indicated member function to the struct type,
02116 ////////////////////////////////////////////////////////////////////
02117 void InterrogateBuilder::
02118 define_method(CPPFunctionGroup *fgroup, InterrogateType &itype,
02119               CPPStructType *struct_type, CPPScope *scope) {
02120   CPPFunctionGroup::Instances::const_iterator fi;
02121   for (fi = fgroup->_instances.begin(); fi != fgroup->_instances.end(); ++fi) {
02122     CPPInstance *function = (*fi);
02123     define_method(function, itype, struct_type, scope);
02124   }
02125 }
02126 
02127 ////////////////////////////////////////////////////////////////////
02128 //     Function: InterrogateBuilder::define_method
02129 //       Access: Private
02130 //  Description: Adds the indicated member function to the struct type,
02131 ////////////////////////////////////////////////////////////////////
02132 void InterrogateBuilder::
02133 define_method(CPPInstance *function, InterrogateType &itype,
02134               CPPStructType *struct_type, CPPScope *scope) {
02135   assert(function != (CPPInstance *)NULL);
02136   assert(function->_type != (CPPType *)NULL &&
02137          function->_type->as_function_type() != (CPPFunctionType *)NULL);
02138   CPPFunctionType *ftype =
02139     function->_type->resolve_type(scope, &parser)->as_function_type();
02140 
02141   if (function->is_template()) {
02142     // The function is a template function, not a true function.
02143     return;
02144   }
02145 
02146   // As a special kludgey extension, we consider a public static
02147   // method called "get_class_type()" to be marked published, even if
02148   // it is not.  This allows us to export all of the TypeHandle system
02149   // stuff without having to specifically flag get_class_type() as
02150   // published.
02151   bool force_publish = false;
02152   if (function->get_simple_name() == "get_class_type" &&
02153       (function->_storage_class && CPPInstance::SC_static) != 0 &&
02154       function->_vis <= V_public) {
02155     force_publish = true;
02156   }
02157 
02158   if ((ftype->_flags & CPPFunctionType::F_destructor) != 0) {
02159     // A destructor is a special case.  If it's public, we export it
02160     // (even if it's not published), but if it's protected or private,
02161     // we don't exported it, and we flag it so we don't try to
02162     // synthesize one later.
02163     if (function->_vis > V_public) {
02164       itype._flags |= InterrogateType::F_private_destructor;
02165       return;
02166     }
02167     force_publish = true;
02168   }
02169 
02170   if (!force_publish && function->_vis > min_vis) {
02171     // The function is not marked to be exported.
02172     return;
02173   }
02174 
02175   if (TypeManager::involves_protected(ftype)) {
02176     // We can't export the function because it involves parameter
02177     // types that are protected or private.
02178     return;
02179   }
02180 
02181   if (in_ignoreinvolved(ftype)) {
02182     // The function or its parameters involves something that the
02183     // user requested we ignore.
02184     if ((ftype->_flags & CPPFunctionType::F_destructor) != 0) {
02185       itype._flags |= InterrogateType::F_private_destructor;
02186     }
02187     return;
02188   }
02189 
02190   if (in_ignoremember(function->get_simple_name())) {
02191     // The user requested us to ignore members of this name.
02192     if ((ftype->_flags & CPPFunctionType::F_destructor) != 0) {
02193       itype._flags |= InterrogateType::F_private_destructor;
02194     }
02195     return;
02196   }
02197 
02198   if ((function->_storage_class & CPPInstance::SC_inherited_virtual) != 0 &&
02199       struct_type->_derivation.size() == 1 &&
02200       struct_type->_derivation[0]._vis <= V_public &&
02201       !struct_type->_derivation[0]._is_virtual) {
02202     // If this function is a virtual function whose first appearance
02203     // is in some base class, we don't need to repeat its definition
02204     // here, since we're already inheriting it properly.  However, we
02205     // may need to make an exception in the presence of multiple
02206     // inheritance.
02207     if ((ftype->_flags & CPPFunctionType::F_destructor) != 0) {
02208       itype._flags |= InterrogateType::F_inherited_destructor;
02209     }
02210     return;
02211   }
02212 
02213 
02214   FunctionIndex index = get_function(function, "", struct_type, scope, 0);
02215   if (index != 0) {
02216     if ((ftype->_flags & CPPFunctionType::F_constructor) != 0) {
02217       if (find(itype._constructors.begin(), itype._constructors.end(),
02218                index) == itype._constructors.end()) {
02219         itype._constructors.push_back(index);
02220       }
02221 
02222     } else if ((ftype->_flags & CPPFunctionType::F_destructor) != 0) {
02223       itype._flags |= InterrogateType::F_true_destructor;
02224       itype._destructor = index;
02225 
02226     } else if ((ftype->_flags & CPPFunctionType::F_operator_typecast) != 0) {
02227       if (find(itype._casts.begin(), itype._casts.end(),
02228                index) == itype._casts.end()) {
02229         itype._casts.push_back(index);
02230       }
02231 
02232     } else {
02233       if (find(itype._methods.begin(), itype._methods.end(),
02234                index) == itype._methods.end()) {
02235         itype._methods.push_back(index);
02236       }
02237     }
02238   }
02239 }
02240 
02241 ////////////////////////////////////////////////////////////////////
02242 //     Function: InterrogateBuilder::define_enum_type
02243 //       Access: Private
02244 //  Description: Builds up a definition for the indicated enum type.
02245 ////////////////////////////////////////////////////////////////////
02246 void InterrogateBuilder::
02247 define_enum_type(InterrogateType &itype, CPPEnumType *cpptype) {
02248   itype._flags |= InterrogateType::F_enum;
02249 
02250   CPPScope *scope = &parser;
02251   if (cpptype->_ident != (CPPIdentifier *)NULL) {
02252     scope = cpptype->_ident->get_scope(&parser, &parser);
02253   }
02254 
02255   // Make sure the enum declaration within its parent scope isn't
02256   // private or protected.  If it is, we can't export any of its
02257   // members.
02258   if (TypeManager::involves_unpublished(cpptype)) {
02259     itype._flags &= ~InterrogateType::F_fully_defined;
02260     itype._flags |= InterrogateType::F_unpublished;
02261     return;
02262   }
02263 
02264   int next_value = 0;
02265 
02266   CPPEnumType::Elements::const_iterator ei;
02267   for (ei = cpptype->_elements.begin();
02268        ei != cpptype->_elements.end();
02269        ++ei) {
02270     CPPInstance *element = (*ei);
02271 
02272     // Tell the enum element where its native scope is, so we can get
02273     // a properly scoped name.
02274 
02275     if (element->_ident->_native_scope != scope) {
02276       element = new CPPInstance(*element);
02277       element->_ident = new CPPIdentifier(*element->_ident);
02278       element->_ident->_native_scope = scope;
02279     }
02280 
02281     InterrogateType::EnumValue evalue;
02282     evalue._name = element->get_simple_name();
02283     evalue._scoped_name = descope(element->get_local_name(&parser));
02284 
02285     if (element->_initializer != (CPPExpression *)NULL) {
02286       CPPExpression::Result result = element->_initializer->evaluate();
02287       next_value = result.as_integer();
02288     }
02289     evalue._value = next_value;
02290     itype._enum_values.push_back(evalue);
02291 
02292     next_value++;
02293   }
02294 }
02295 
02296 ////////////////////////////////////////////////////////////////////
02297 //     Function: InterrogateBuilder::define_extension_type
02298 //       Access: Private
02299 //  Description: Builds up a definition for the indicated extension type.
02300 ////////////////////////////////////////////////////////////////////
02301 void InterrogateBuilder::
02302 define_extension_type(InterrogateType &itype, CPPExtensionType *cpptype) {
02303   // An "extension type" as returned by CPPParser is really a forward
02304   // reference to an undefined struct or class type.
02305   itype._flags &= ~InterrogateType::F_fully_defined;
02306 
02307   // But we can at least indicate which of the various extension types
02308   // it is.
02309   switch (cpptype->_type) {
02310   case CPPExtensionType::T_enum:
02311     itype._flags |= InterrogateType::F_enum;
02312     break;
02313 
02314   case CPPExtensionType::T_class:
02315     itype._flags |= InterrogateType::F_class;
02316     break;
02317 
02318   case CPPExtensionType::T_struct:
02319     itype._flags |= InterrogateType::F_struct;
02320     break;
02321 
02322   case CPPExtensionType::T_union:
02323     itype._flags |= InterrogateType::F_union;
02324     break;
02325   }
02326 }
02327 
02328 ////////////////////////////////////////////////////////////////////
02329 //     Function: InterrogateBuilder::trim_blanks
02330 //       Access: Private, Static
02331 //  Description:
02332 ////////////////////////////////////////////////////////////////////
02333 string InterrogateBuilder::
02334 trim_blanks(const string &str) {
02335   size_t start = 0;
02336   while (start < str.length() && isspace(str[start])) {
02337     start++;
02338   }
02339 
02340   size_t end = str.length();
02341   while (end > start && isspace(str[end - 1])) {
02342     end--;
02343   }
02344 
02345   return str.substr(start, end - start);
02346 }

Generated on Thu May 1 22:13:03 2003 for DTool by doxygen1.3