// Filename: interfaceMaker.cxx // Created by: drose (19Sep01) // //////////////////////////////////////////////////////////////////// // // PANDA 3D SOFTWARE // Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved // // All use of this software is subject to the terms of the Panda 3d // Software license. You should have received a copy of this license // along with this source code; you will also find a current copy of // the license at http://etc.cmu.edu/panda3d/docs/license/ . // // To contact the maintainers of this program write to // panda3d-general@lists.sourceforge.net . // //////////////////////////////////////////////////////////////////// #include "interfaceMaker.h" #include "interrogateBuilder.h" #include "typeManager.h" #include "interrogate.h" #include "functionRemap.h" #include "parameterRemap.h" #include "parameterRemapThis.h" #include "parameterRemapUnchanged.h" #include "parameterRemapReferenceToPointer.h" #include "parameterRemapConcreteToPointer.h" #include "parameterRemapEnumToInt.h" #include "parameterRemapConstToNonConst.h" #include "parameterRemapReferenceToConcrete.h" #include "parameterRemapCharStarToString.h" #include "parameterRemapBasicStringToString.h" #include "parameterRemapBasicStringRefToString.h" #include "parameterRemapPTToPointer.h" #include "interrogateDatabase.h" #include "interrogateManifest.h" #include "interrogateElement.h" #include "cppFunctionType.h" #include "cppParameterList.h" #include "notify.h" InterrogateType dummy_type; //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::Function::Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// InterfaceMaker::Function:: Function(const string &name, const InterrogateType &itype, const InterrogateFunction &ifunc) : _name(name), _itype(itype), _ifunc(ifunc) { _has_this = false; } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::Function::Destructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// InterfaceMaker::Function:: ~Function() { Remaps::iterator ri; for (ri = _remaps.begin(); ri != _remaps.end(); ++ri) { delete (*ri); } } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::Object::Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// InterfaceMaker::Object:: Object(const InterrogateType &itype) : _itype(itype) { } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::Object::Destructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// InterfaceMaker::Object:: ~Object() { } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// InterfaceMaker:: InterfaceMaker(InterrogateModuleDef *def) : _def(def) { } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::Destructor // Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// InterfaceMaker:: ~InterfaceMaker() { Objects::iterator oi; for (oi = _objects.begin(); oi != _objects.end(); ++oi) { Object *object = (*oi).second; delete object; } Functions::iterator fi; for (fi = _functions.begin(); fi != _functions.end(); ++fi) { delete (*fi); } } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::generate_wrappers // Access: Public, Virtual // Description: Walks through the set of functions in the database // and generates wrappers for each function, storing // these in the database. No actual code should be // output yet; this just updates the database with the // wrapper information. //////////////////////////////////////////////////////////////////// void InterfaceMaker:: generate_wrappers() { InterrogateDatabase *idb = InterrogateDatabase::get_ptr(); // We use a while loop rather than a simple for loop, because we // might increase the number of types recursively during the // traversal. int ti = 0; while (ti < idb->get_num_all_types()) { TypeIndex type_index = idb->get_all_type(ti); record_object(type_index); if(interrogate_type_is_enum(ti)) { int enum_count = interrogate_type_number_of_enum_values(ti); for(int xx = 0; xx< enum_count; xx++) { // printf(" PyModule_AddIntConstant(module,\"%s\",%d)\n",interrogate_type_enum_value_name(ti,xx),interrogate_type_enum_value(ti,xx)); } } ++ti; // printf(" New Type %d\n",ti); } int num_global_elements = idb->get_num_global_elements(); for (int gi = 0; gi < num_global_elements; ++gi) { printf(" Global Type = %d",gi); TypeIndex type_index = idb->get_global_element(gi); record_object(type_index); } int num_functions = idb->get_num_global_functions(); for (int fi = 0; fi < num_functions; fi++) { FunctionIndex func_index = idb->get_global_function(fi); record_function(dummy_type, func_index); } int num_manifests = idb->get_num_global_manifests(); for (int mi = 0; mi < num_manifests; mi++) { ManifestIndex manifest_index = idb->get_global_manifest(mi); const InterrogateManifest &iman = idb->get_manifest(manifest_index); if (iman.has_getter()) { FunctionIndex func_index = iman.get_getter(); record_function(dummy_type, func_index); } printf(" Manafests %d\n",mi); } int num_elements = idb->get_num_global_elements(); for (int ei = 0; ei < num_elements; ei++) { printf(" Element %d\n",ei); ElementIndex element_index = idb->get_global_element(ei); const InterrogateElement &ielement = idb->get_element(element_index); if (ielement.has_getter()) { FunctionIndex func_index = ielement.get_getter(); record_function(dummy_type, func_index); } if (ielement.has_setter()) { FunctionIndex func_index = ielement.get_setter(); record_function(dummy_type, func_index); } } } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::write_includes // Access: Public, Virtual // Description: Generates the list of #include ... whatever that's // required by this particular interface to the // indicated output stream. //////////////////////////////////////////////////////////////////// void InterfaceMaker:: write_includes(ostream &) { } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::write_prototypes // Access: Public, Virtual // Description: Generates the list of function prototypes // corresponding to the functions that will be output in // write_functions(). //////////////////////////////////////////////////////////////////// void InterfaceMaker:: write_prototypes(ostream &out,ostream *out_h) { _function_writers.write_prototypes(out); } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::write_functions // Access: Public, Virtual // Description: Generates the list of functions that are appropriate // for this interface. //////////////////////////////////////////////////////////////////// void InterfaceMaker:: write_functions(ostream &out) { _function_writers.write_code(out); } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::write_module // Access: Public, Virtual // Description: Generates whatever additional code is required to // support a module file. //////////////////////////////////////////////////////////////////// void InterfaceMaker:: write_module(ostream &, ostream *out_h,InterrogateModuleDef *) { } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::remap_parameter // Access: Public, Virtual // Description: Allocates a new ParameterRemap object suitable to the // indicated parameter type. If struct_type is // non-NULL, it is the type of the enclosing class for // the function (method) in question. // // The return value is a newly-allocated ParameterRemap // object, if the parameter type is acceptable, or NULL // if the parameter type cannot be handled. //////////////////////////////////////////////////////////////////// ParameterRemap *InterfaceMaker:: remap_parameter(CPPType *struct_type, CPPType *param_type) { if (convert_strings) { if (TypeManager::is_char_pointer(param_type)) { return new ParameterRemapCharStarToString(param_type); } // If we're exporting a method of basic_string itself, don't // convert basic_string's to atomic strings. if (struct_type == (CPPType *)NULL || !(TypeManager::is_basic_string_char(struct_type) || TypeManager::is_basic_string_wchar(struct_type))) { if (TypeManager::is_basic_string_char(param_type)) { return new ParameterRemapBasicStringToString(param_type); } else if (TypeManager::is_const_ref_to_basic_string_char(param_type)) { return new ParameterRemapBasicStringRefToString(param_type); } else if (TypeManager::is_basic_string_wchar(param_type)) { return new ParameterRemapBasicWStringToWString(param_type); } else if (TypeManager::is_const_ref_to_basic_string_wchar(param_type)) { return new ParameterRemapBasicWStringRefToWString(param_type); } } } if (manage_reference_counts) { if (TypeManager::is_pointer_to_base(param_type) || TypeManager::is_const_ref_to_pointer_to_base(param_type)) { CPPType *pt_type = TypeManager::unwrap_reference(param_type); // Don't convert PointerTo<>'s to pointers for methods of the // PointerTo itself! if (struct_type == (CPPType *)NULL || !(pt_type->get_local_name(&parser) == struct_type->get_local_name(&parser))) { return new ParameterRemapPTToPointer(param_type); } } } if (TypeManager::is_reference(param_type)) { return new ParameterRemapReferenceToPointer(param_type); } else if (TypeManager::is_struct(param_type)) { return new ParameterRemapConcreteToPointer(param_type); /* } else if (TypeManager::is_enum(param_type) || TypeManager::is_const_ref_to_enum(param_type)) { return new ParameterRemapEnumToInt(param_type); */ } else if (TypeManager::is_const_simple(param_type)) { return new ParameterRemapConstToNonConst(param_type); } else if (TypeManager::is_const_ref_to_simple(param_type)) { return new ParameterRemapReferenceToConcrete(param_type); } else if (TypeManager::is_pointer(param_type) || TypeManager::is_simple(param_type)) { return new ParameterRemapUnchanged(param_type); } else { // Here's something we have a problem with. return (ParameterRemap *)NULL; } } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::synthesize_this_parameter // Access: Public, Virtual // Description: This method should be overridden and redefined to // return true for interfaces that require the implicit // "this" parameter, if present, to be passed as the // first parameter to any wrapper functions. //////////////////////////////////////////////////////////////////// bool InterfaceMaker:: synthesize_this_parameter() { return false; } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::separate_overloading // Access: Public, Virtual // Description: This method should be overridden and redefined to // return true for interfaces that require overloaded // instances of a function to be defined as separate // functions (each with its own hashed name), or false // for interfaces that can support overloading natively, // and thus only require one wrapper function per each // overloaded input function. //////////////////////////////////////////////////////////////////// bool InterfaceMaker:: separate_overloading() { return true; } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::get_function_remaps // Access: Public // Description: Fills up the indicated vector with all of the // FunctionRemap pointers created by this // InterfaceMaker. It is the user's responsibility to // empty the vector before calling this function; the // new pointers will simply be added to the end. //////////////////////////////////////////////////////////////////// void InterfaceMaker:: get_function_remaps(vector &remaps) { Functions::iterator fi; for (fi = _functions.begin(); fi != _functions.end(); ++fi) { Function *func = (*fi); Function::Remaps::const_iterator ri; for (ri = func->_remaps.begin(); ri != func->_remaps.end(); ++ri) { FunctionRemap *remap = (*ri); remaps.push_back(remap); } } } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::indent // Access: Public, Static // Description: //////////////////////////////////////////////////////////////////// ostream &InterfaceMaker:: indent(ostream &out, int indent_level) { for (int i = 0; i < indent_level; i++) { out << ' '; } return out; } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::make_function_remap // Access: Protected, Virtual // Description: Creates a FunctionRemap object corresponding to the // particular function wrapper. //////////////////////////////////////////////////////////////////// FunctionRemap *InterfaceMaker:: make_function_remap(const InterrogateType &itype, const InterrogateFunction &ifunc, CPPInstance *cppfunc, int num_default_parameters) { FunctionRemap *remap = new FunctionRemap(itype, ifunc, cppfunc, num_default_parameters, this); if (remap->_is_valid) { if (separate_overloading()) { hash_function_signature(remap); remap->_unique_name = get_unique_prefix() + _def->library_hash_name + remap->_hash; remap->_wrapper_name = get_wrapper_prefix() + _def->library_hash_name + remap->_hash; remap->_reported_name = remap->_wrapper_name; if (true_wrapper_names) { remap->_reported_name = InterrogateBuilder::clean_identifier(remap->_cppfunc->get_local_name(&parser)); } } return remap; } // No such FunctionRemap is valid. Return NULL. delete remap; return (FunctionRemap *)NULL; } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::get_wrapper_name // Access: Protected, Virtual // Description: Returns the function name that will be used to wrap // the indicated function. // // This is the name for the overall wrapper function, // including all of the overloaded instances. // Interfaces that must define a different wrapper for // each FunctionRemap object (i.e. for each instance of // an overloaded function) need not define a name here. //////////////////////////////////////////////////////////////////// string InterfaceMaker:: get_wrapper_name(const InterrogateType &itype, const InterrogateFunction &ifunc, FunctionIndex func_index) { string func_name = ifunc.get_scoped_name(); string clean_name = InterrogateBuilder::clean_identifier(func_name); ostringstream new_name; new_name << get_wrapper_prefix() << clean_name << "_" << func_index; return new_name.str(); } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::get_wrapper_prefix // Access: Protected, Virtual // Description: Returns the prefix string used to generate wrapper // function names. //////////////////////////////////////////////////////////////////// string InterfaceMaker:: get_wrapper_prefix() { return "xx_"; } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::get_unique_prefix // Access: Protected, Virtual // Description: Returns the prefix string used to generate unique // symbolic names, which are not necessarily C-callable // function names. //////////////////////////////////////////////////////////////////// string InterfaceMaker:: get_unique_prefix() { return "x"; } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::record_function // Access: Protected // Description: Records the indicated function, along with all of its // FunctionRemap flavors and FunctionWriter helpers, for // future output. Returns the new Function pointer. //////////////////////////////////////////////////////////////////// InterfaceMaker::Function *InterfaceMaker:: record_function(const InterrogateType &itype, FunctionIndex func_index) { InterrogateDatabase *idb = InterrogateDatabase::get_ptr(); const InterrogateFunction &ifunc = idb->get_function(func_index); string wrapper_name = get_wrapper_name(itype, ifunc, func_index); Function *func = new Function(wrapper_name, itype, ifunc); _functions.push_back(func); // printf(" Function Name = %s\n",ifunc.get_name().c_str()); // Now get all the valid FunctionRemaps for the function. if (ifunc._instances != (InterrogateFunction::Instances *)NULL) { InterrogateFunction::Instances::const_iterator ii; for (ii = ifunc._instances->begin();ii != ifunc._instances->end();++ii) { CPPInstance *cppfunc = (*ii).second; CPPFunctionType *ftype = cppfunc->_type->as_function_type(); int max_default_parameters = 0; if (separate_overloading()) { // Count up the number of default parameters this function might // take. CPPParameterList *parameters = ftype->_parameters; CPPParameterList::Parameters::reverse_iterator pi; for (pi = parameters->_parameters.rbegin(); pi != parameters->_parameters.rend(); ++pi) { CPPInstance *param = (*pi); if (param->_initializer != (CPPExpression *)NULL) { // This parameter has a default value. max_default_parameters++; } else { // The first parameter without a default value ends the search. break; } } } // Now make a different wrapper for each combination of default // parameters. This will happen only if separate_overloading(), // tested above, returned true; otherwise, max_default_parameters // will be 0 and the loop will only be traversed once. for (int num_default_parameters = 0; num_default_parameters <= max_default_parameters; num_default_parameters++) { FunctionRemap *remap = make_function_remap(itype, ifunc, cppfunc, num_default_parameters); if (remap != (FunctionRemap *)NULL) { func->_remaps.push_back(remap); // If *any* of the variants of this function has a "this" // pointer, the entire set of functions is deemed to have a // "this" pointer. if (remap->_has_this) { func->_has_this = true; } // Make a wrapper for the function. FunctionWrapperIndex wrapper_index = remap->make_wrapper_entry(func_index); if (wrapper_index != 0) { InterrogateFunction &mod_ifunc = idb->update_function(func_index); record_function_wrapper(mod_ifunc, wrapper_index); } } } } } return func; } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::record_function_wrapper // Access: Protected, Virtual // Description: Associates the function wrapper with its function in // the appropriate structures in the database. //////////////////////////////////////////////////////////////////// void InterfaceMaker:: record_function_wrapper(InterrogateFunction &, FunctionWrapperIndex) { } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::record_object // Access: Protected // Description: Records the indicated type, which may be a struct // type, along with all of its associated methods, if // any. //////////////////////////////////////////////////////////////////// InterfaceMaker::Object *InterfaceMaker:: record_object(TypeIndex type_index) { if (type_index == 0) { // An invalid type. return (Object *)NULL; } Objects::iterator oi = _objects.find(type_index); if (oi != _objects.end()) { // The object has previously been recorded. return (*oi).second; } InterrogateDatabase *idb = InterrogateDatabase::get_ptr(); const InterrogateType &itype = idb->get_type(type_index); Object *object = new Object(itype); bool inserted = _objects.insert(Objects::value_type(type_index, object)).second; assert(inserted); Function *function; int num_constructors = itype.number_of_constructors(); for (int ci = 0; ci < num_constructors; ci++) { function = record_function(itype, itype.get_constructor(ci)); object->_constructors.push_back(function); } int num_methods = itype.number_of_methods(); int mi; for (mi = 0; mi < num_methods; mi++) { function = record_function(itype, itype.get_method(mi)); object->_methods.push_back(function); } int num_casts = itype.number_of_casts(); for (mi = 0; mi < num_casts; mi++) { function = record_function(itype, itype.get_cast(mi)); object->_methods.push_back(function); } int num_derivations = itype.number_of_derivations(); for (int di = 0; di < num_derivations; di++) { if (itype.derivation_has_upcast(di)) { record_function(itype, itype.derivation_get_upcast(di)); } if (itype.derivation_has_downcast(di)) { // Downcasts are methods of the base class, not the child class. TypeIndex base_type_index = itype.get_derivation(di); const InterrogateType &base_type = idb->get_type(base_type_index); record_function(base_type, itype.derivation_get_downcast(di)); } } int num_elements = itype.number_of_elements(); for (int ei = 0; ei < num_elements; ei++) { ElementIndex element_index = itype.get_element(ei); const InterrogateElement &ielement = idb->get_element(element_index); if (ielement.has_getter()) { FunctionIndex func_index = ielement.get_getter(); record_function(itype, func_index); } if (ielement.has_setter()) { FunctionIndex func_index = ielement.get_setter(); record_function(itype, func_index); } } int num_nested = itype.number_of_nested_types(); for (int ni = 0; ni < num_nested; ni++) { TypeIndex nested_index = itype.get_nested_type(ni); record_object(nested_index); } return object; } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::manage_return_value // Access: Protected // Description: Does any additional processing that we might want to // do on the return value for the function, just before // we return it. Returns the string representing the // new return value after processing. //////////////////////////////////////////////////////////////////// string InterfaceMaker:: manage_return_value(ostream &out, int indent_level, FunctionRemap *remap, const string &return_expr) const { if (remap->_manage_reference_count) { // If we're managing reference counts, and we're about to return a // reference countable object, then increment its count. if (return_expr == "return_value") { // If the expression is just a variable name, we can just ref it // directly. output_ref(out, indent_level, remap, return_expr); return return_expr; } else { // Otherwise, we should probably assign it to a temporary first, // so we don't invoke the function twice or something. CPPType *type = remap->_return_type->get_temporary_type(); indent(out, indent_level); type->output_instance(out, "refcount", &parser); out << " = " << return_expr << ";\n"; indent(out, indent_level) << "if (" << return_expr << " != (" << remap->_return_type->get_new_type()->get_local_name(&parser) << ")0) {\n"; indent(out, indent_level + 2) << return_expr << "->ref();\n"; indent(out, indent_level) << "}\n"; output_ref(out, indent_level, remap, "refcount"); return remap->_return_type->temporary_to_return("refcount"); } } // Otherwise, just return the expression unchanged. return return_expr; } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::output_ref // Access: Protected // Description: Outputs the code to increment the reference count for // the indicated variable name. //////////////////////////////////////////////////////////////////// void InterfaceMaker:: output_ref(ostream &out, int indent_level, FunctionRemap *remap, const string &varname) const { if (remap->_type == FunctionRemap::T_constructor || remap->_type == FunctionRemap::T_typecast) { // In either of these cases, we can safely assume the pointer will // never be NULL. indent(out, indent_level) << varname << "->ref();\n"; } else { // However, in the general case, we have to check for that before // we attempt to ref it. indent(out, indent_level) << "if (" << varname << " != (" << remap->_return_type->get_new_type()->get_local_name(&parser) << ")0) {\n"; indent(out, indent_level + 2) << varname << "->ref();\n"; indent(out, indent_level) << "}\n"; } } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::hash_function_signature // Access: Protected // Description: Generates a unique string that corresponds to the // function signature for the indicated FunctionRemap // object, and stores the generated string in the _hash // member of the FunctionRemap. //////////////////////////////////////////////////////////////////// void InterfaceMaker:: hash_function_signature(FunctionRemap *remap) { string hash = InterrogateBuilder::hash_string(remap->_function_signature, 5); // Now make sure we don't have another function with the same hash. WrappersByHash::iterator hi; hi = _wrappers_by_hash.find(hash); if (hi == _wrappers_by_hash.end()) { // No other name; we're in the clear. _wrappers_by_hash[hash] = remap; remap->_hash = hash; return; } if ((*hi).second != (FunctionRemap *)NULL && (*hi).second->_function_signature == remap->_function_signature) { // The same function signature has already appeared. This // shouldn't happen. nout << "Internal error! Function signature " << remap->_function_signature << " repeated!\n"; remap->_hash = hash; abort(); return; } // We have a conflict. Extend both strings to resolve the // ambiguity. if ((*hi).second != (FunctionRemap *)NULL) { FunctionRemap *other_remap = (*hi).second; (*hi).second = (FunctionRemap *)NULL; other_remap->_hash += InterrogateBuilder::hash_string(other_remap->_function_signature, 11); bool inserted = _wrappers_by_hash.insert (WrappersByHash::value_type(other_remap->_hash, other_remap)).second; if (!inserted) { nout << "Internal error! Hash " << other_remap->_hash << " already appears!\n"; } } hash += InterrogateBuilder::hash_string(remap->_function_signature, 11); bool inserted = _wrappers_by_hash.insert (WrappersByHash::value_type(hash, remap)).second; if (!inserted) { // Huh. We still have a conflict. This should be extremely rare. // Well, just tack on a letter until it's resolved. string old_hash = hash; for (char ch = 'a'; ch <= 'z' && !inserted; ch++) { hash = old_hash + ch; inserted = _wrappers_by_hash.insert (WrappersByHash::value_type(hash, remap)).second; } if (!inserted) { nout << "Internal error! Too many conflicts with hash " << hash << "\n"; } } remap->_hash = hash; } //////////////////////////////////////////////////////////////////// // Function: InterfaceMaker::write_spam_message // Access: Protected // Description: Generates a string to output a spammy message to // notify indicating we have just called this function. //////////////////////////////////////////////////////////////////// void InterfaceMaker:: write_spam_message(ostream &out, FunctionRemap *remap) const { ostringstream strm; remap->write_orig_prototype(strm, 0); string prototype = strm.str(); out << " if (interrogatedb_cat.is_spam()) {\n" " interrogatedb_cat.spam() << \""; for (string::const_iterator si = prototype.begin(); si != prototype.end(); ++si) { switch (*si) { case '"': out << "\\\""; break; case '\\': out << "\\\\"; break; default: out << *si; } } out << "\\n\";\n" " }\n"; }