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

dtool/src/interrogate/functionRemap.cxx

Go to the documentation of this file.
00001 // Filename: functionRemap.cxx
00002 // Created by:  drose (19Sep01)
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 "functionRemap.h"
00020 #include "typeManager.h"
00021 #include "interrogate.h"
00022 #include "parameterRemap.h"
00023 #include "parameterRemapThis.h"
00024 #include "interfaceMaker.h"
00025 #include "interrogateBuilder.h"
00026 
00027 #include "interrogateDatabase.h"
00028 #include "cppInstance.h"
00029 #include "cppFunctionType.h"
00030 #include "cppParameterList.h"
00031 #include "cppReferenceType.h"
00032 #include "interrogateType.h"
00033 #include "notify.h"
00034 
00035 ////////////////////////////////////////////////////////////////////
00036 //     Function: FunctionRemap::Constructor
00037 //       Access: Public
00038 //  Description:
00039 ////////////////////////////////////////////////////////////////////
00040 FunctionRemap::
00041 FunctionRemap(const InterrogateType &itype, const InterrogateFunction &ifunc,
00042               CPPInstance *cppfunc, int num_default_parameters,
00043               InterfaceMaker *interface) {
00044   _return_type = (ParameterRemap *)NULL;
00045   _void_return = true;
00046   _has_this = false;
00047   _first_true_parameter = 0;
00048   _num_default_parameters = num_default_parameters;
00049   _type = T_normal;
00050   _wrapper_index = 0;
00051 
00052   _return_value_needs_management = false;
00053   _return_value_destructor = 0;
00054   _manage_reference_count = false;
00055 
00056   _cppfunc = cppfunc;
00057   _ftype = _cppfunc->_type->as_function_type();
00058   _cpptype = itype._cpptype;
00059   _cppscope = itype._cppscope;
00060 
00061   _is_valid = setup_properties(ifunc, interface);
00062 }
00063 
00064 ////////////////////////////////////////////////////////////////////
00065 //     Function: FunctionRemap::Destructor
00066 //       Access: Public
00067 //  Description:
00068 ////////////////////////////////////////////////////////////////////
00069 FunctionRemap::
00070 ~FunctionRemap() {
00071 }
00072 
00073 ////////////////////////////////////////////////////////////////////
00074 //     Function: FunctionRemap::get_parameter_name
00075 //       Access: Public
00076 //  Description: Returns a string that will be a suitable name for the
00077 //               nth parameter in the generated code.  This may not
00078 //               correspond to the name of the parameter in the
00079 //               original code.
00080 ////////////////////////////////////////////////////////////////////
00081 string FunctionRemap::
00082 get_parameter_name(int n) const {
00083   ostringstream str;
00084   str << "param" << n;
00085   return str.str();
00086 }
00087 
00088 ////////////////////////////////////////////////////////////////////
00089 //     Function: FunctionRemap::call_function
00090 //       Access: Public
00091 //  Description: Writes a sequence of commands to the given output
00092 //               stream to call the wrapped function.  The parameter
00093 //               values are taken from pexprs, if it is nonempty, or
00094 //               are assumed to be simply the names of the parameters,
00095 //               if it is empty.
00096 //
00097 //               The return value is the expression to return, if we
00098 //               are returning a value, or the empty string if we
00099 //               return nothing.
00100 ////////////////////////////////////////////////////////////////////
00101 string FunctionRemap::
00102 call_function(ostream &out, int indent_level, bool convert_result,
00103               const string &container, const vector_string &pexprs) const {
00104   string return_expr;
00105 
00106   if (_type == T_destructor) {
00107     // A destructor wrapper is just a wrapper around the delete operator.
00108     assert(!container.empty());
00109     assert(_cpptype != (CPPType *)NULL);
00110 
00111     if (TypeManager::is_reference_count(_cpptype)) {
00112       // Except for a reference-count type object, in which case the
00113       // destructor is a wrapper around unref_delete().
00114       InterfaceMaker::indent(out, indent_level)
00115         << "unref_delete(" << container << ");\n";
00116     } else {
00117       InterfaceMaker::indent(out, indent_level)
00118         << "delete " << container << ";\n";
00119     }
00120 
00121   } else if (_type == T_typecast_method) {
00122     // A typecast method can be invoked implicitly.
00123     string cast_expr =
00124       "(" + _return_type->get_orig_type()->get_local_name(&parser) +
00125       ")(*" + container + ")";
00126 
00127     if (!convert_result) {
00128       return_expr = cast_expr;
00129     } else {
00130       string new_str =
00131         _return_type->prepare_return_expr(out, indent_level, cast_expr);
00132       return_expr = _return_type->get_return_expr(new_str);
00133     }
00134 
00135   } else if (_type == T_typecast) {
00136     // A regular typecast converts from a pointer type to another
00137     // pointer type.  (This is different from the typecast method,
00138     // above, which converts from the concrete type to some other
00139     // type.)
00140     assert(!container.empty());
00141     string cast_expr =
00142       "(" + _return_type->get_orig_type()->get_local_name(&parser) +
00143       ")" + container;
00144 
00145     if (!convert_result) {
00146       return_expr = cast_expr;
00147     } else {
00148       string new_str =
00149         _return_type->prepare_return_expr(out, indent_level, cast_expr);
00150       return_expr = _return_type->get_return_expr(new_str);
00151     }
00152 
00153   } else if (_type == T_constructor) {
00154     // A special case for constructors.
00155     return_expr = "new " + get_call_str(container, pexprs);
00156     if (_void_return) {
00157       nout << "Error, constructor for " << *_cpptype << " returning void.\n";
00158       return_expr = "";
00159     }
00160 
00161   } else if (_type == T_assignment_method) {
00162     // Another special case for assignment operators.
00163     assert(!container.empty());
00164     InterfaceMaker::indent(out, indent_level)
00165       << get_call_str(container, pexprs) << ";\n";
00166 
00167     string this_expr = container;
00168     string ref_expr = "*" + this_expr;
00169 
00170     if (!convert_result) {
00171       return_expr = ref_expr;
00172     } else {
00173       string new_str =
00174         _return_type->prepare_return_expr(out, indent_level, ref_expr);
00175       return_expr = _return_type->get_return_expr(new_str);
00176 
00177       // Now a simple special-case test.  Often, we will have converted
00178       // the reference-returning assignment operator to a pointer.  In
00179       // this case, we might inadventent generate code like "return
00180       // &(*this)", when "return this" would do.  We check for this here
00181       // and undo it as a special case.
00182 
00183       // There's no real good reason to do this, other than that it
00184       // feels more satisfying to a casual perusal of the generated
00185       // code.  It *is* conceivable that some broken compilers wouldn't
00186       // like "&(*this)", though.
00187 
00188       if (return_expr == "&(" + ref_expr + ")" ||
00189           return_expr == "&" + ref_expr) {
00190         return_expr = this_expr;
00191       }
00192     }
00193 
00194   } else if (_void_return) {
00195     InterfaceMaker::indent(out, indent_level)
00196       << get_call_str(container, pexprs) << ";\n";
00197 
00198   } else {
00199     string call = get_call_str(container, pexprs);
00200 
00201     if (!convert_result) {
00202       return_expr = get_call_str(container, pexprs);
00203 
00204     } else {
00205       if (_return_type->return_value_should_be_simple()) {
00206         // We have to assign the result to a temporary first; this makes
00207         // it a bit easier on poor old VC++.
00208         InterfaceMaker::indent(out, indent_level);
00209         _return_type->get_orig_type()->output_instance(out, "result",
00210                                                            &parser);
00211         out << " = " << call << ";\n";
00212 
00213         string new_str =
00214           _return_type->prepare_return_expr(out, indent_level, "result");
00215         return_expr = _return_type->get_return_expr(new_str);
00216 
00217       } else {
00218         // This should be simple enough that we can return it directly.
00219         string new_str =
00220           _return_type->prepare_return_expr(out, indent_level, call);
00221         return_expr = _return_type->get_return_expr(new_str);
00222       }
00223     }
00224   }
00225 
00226   return return_expr;
00227 }
00228 
00229 ////////////////////////////////////////////////////////////////////
00230 //     Function: FunctionRemap::write_orig_prototype
00231 //       Access: Public
00232 //  Description: Writes a line describing the original C++ method or
00233 //               function.  This is generally useful only within a
00234 //               comment.
00235 ////////////////////////////////////////////////////////////////////
00236 void FunctionRemap::
00237 write_orig_prototype(ostream &out, int indent_level) const {
00238   _cppfunc->output(out, indent_level, &parser, false, _num_default_parameters);
00239 }
00240 
00241 ////////////////////////////////////////////////////////////////////
00242 //     Function: FunctionRemap::make_wrapper_entry
00243 //       Access: Public
00244 //  Description: Creates an InterrogateFunctionWrapper object
00245 //               corresponding to this callable instance and stores it
00246 //               in the database.
00247 ////////////////////////////////////////////////////////////////////
00248 FunctionWrapperIndex FunctionRemap::
00249 make_wrapper_entry(FunctionIndex function_index) {
00250   _wrapper_index =
00251     InterrogateDatabase::get_ptr()->get_next_index();
00252 
00253   InterrogateFunctionWrapper iwrapper;
00254   iwrapper._function = function_index;
00255   iwrapper._name = _wrapper_name;
00256   iwrapper._unique_name = _unique_name;
00257 
00258   if (true_wrapper_names) {
00259     // If we're reporting "true" names, it means we set the
00260     // wrapper's name to the name of the function it wraps.
00261     iwrapper._name = 
00262       InterrogateBuilder::clean_identifier(_cppfunc->get_local_name(&parser));
00263   }
00264   if (output_function_names) {
00265     // If we're keeping the function names, record that the wrapper is
00266     // callable.
00267     iwrapper._flags |= InterrogateFunctionWrapper::F_callable_by_name;
00268   }
00269 
00270   Parameters::const_iterator pi;
00271   for (pi = _parameters.begin();
00272        pi != _parameters.end();
00273        ++pi) {
00274     InterrogateFunctionWrapper::Parameter param;
00275     param._parameter_flags = 0;
00276     if ((*pi)._remap->new_type_is_atomic_string()) {
00277       param._type = builder.get_atomic_string_type();
00278     } else {
00279       param._type = builder.get_type((*pi)._remap->get_new_type(), false);
00280     }
00281     param._name = (*pi)._name;
00282     if ((*pi)._has_name) {
00283       param._parameter_flags |= InterrogateFunctionWrapper::PF_has_name;
00284     }
00285     iwrapper._parameters.push_back(param);
00286   }
00287 
00288   if (_has_this) {
00289     // If one of the parameters is "this", it must be the first one.
00290     assert(!iwrapper._parameters.empty());
00291     iwrapper._parameters.front()._parameter_flags |=
00292       InterrogateFunctionWrapper::PF_is_this;
00293   }
00294 
00295   if (!_void_return) {
00296     iwrapper._flags |= InterrogateFunctionWrapper::F_has_return;
00297   }
00298 
00299   if (_return_type->new_type_is_atomic_string()) {
00300     iwrapper._return_type = builder.get_atomic_string_type();
00301   } else {
00302     iwrapper._return_type =
00303       builder.get_type(_return_type->get_new_type(), false);
00304   }
00305 
00306   if (_return_value_needs_management) {
00307     iwrapper._flags |= InterrogateFunctionWrapper::F_caller_manages;
00308     FunctionIndex destructor = _return_value_destructor;
00309     
00310     if (destructor != 0) {
00311       iwrapper._return_value_destructor = destructor;
00312       
00313     } else {
00314       // We don't need to report this warning, since the FFI code
00315       // understands that if the destructor function is zero, it
00316       // should use the regular class destructor.
00317       
00318       //          nout << "Warning!  Destructor for " 
00319       //               << *_return_type->get_orig_type()
00320       //               << " is unavailable.\n"
00321       //               << "  Cannot manage return value for:\n  "
00322       //               << description << "\n";
00323     }
00324   }
00325 
00326   InterrogateDatabase::get_ptr()->add_wrapper(_wrapper_index, iwrapper);
00327   return _wrapper_index;
00328 }
00329 
00330 ////////////////////////////////////////////////////////////////////
00331 //     Function: FunctionRemap::get_call_str
00332 //       Access: Private
00333 //  Description: Returns a string suitable for calling the wrapped
00334 //               function.  If pexprs is nonempty, it represents
00335 //               the list of expressions that will evaluate to each
00336 //               parameter value.
00337 ////////////////////////////////////////////////////////////////////
00338 string FunctionRemap::
00339 get_call_str(const string &container, const vector_string &pexprs) const {
00340   // Build up the call to the actual function.
00341   ostringstream call;
00342 
00343   // Getters and setters are a special case.
00344   if (_type == T_getter) {
00345     if (!container.empty()) {
00346       call << "(" << container << ")->" << _expression;
00347     } else {
00348       call << _expression;
00349     }
00350 
00351   } else if (_type == T_setter) {
00352     if (!container.empty()) {
00353       call << "(" << container << ")->" << _expression;
00354     } else {
00355       call << _expression;
00356     }
00357 
00358     call << " = ";
00359     _parameters[0]._remap->pass_parameter(call, get_parameter_expr(_first_true_parameter, pexprs));
00360 
00361   } else {
00362     if (_type == T_constructor) {
00363       // Constructors are called differently.
00364       call << _cpptype->get_local_name(&parser);
00365 
00366     } else if (_has_this && !container.empty()) {
00367       // If we have a "this" parameter, the calling convention is also
00368       // a bit different.
00369       call << "(" << container << ")->" << _cppfunc->get_local_name();
00370       
00371     } else {
00372       call << _cppfunc->get_local_name(&parser);
00373     }
00374 
00375     call << "(";
00376     int pn = _first_true_parameter;
00377     if (pn < (int)_parameters.size()) {
00378       _parameters[pn]._remap->pass_parameter(call, get_parameter_expr(pn, pexprs));
00379       pn++;
00380       while (pn < (int)_parameters.size()) {
00381         call << ", ";
00382         _parameters[pn]._remap->pass_parameter(call, get_parameter_expr(pn, pexprs));
00383         pn++;
00384       }
00385     }
00386     call << ")";
00387   }
00388 
00389   return call.str();
00390 }
00391 
00392 ////////////////////////////////////////////////////////////////////
00393 //     Function: FunctionRemap::get_parameter_expr
00394 //       Access: Private
00395 //  Description: Returns a string that represents the expression
00396 //               associated with the nth parameter.  This is just the
00397 //               nth element of pexprs if it is nonempty, or the name
00398 //               of the nth parameter is it is empty.
00399 ////////////////////////////////////////////////////////////////////
00400 string FunctionRemap::
00401 get_parameter_expr(int n, const vector_string &pexprs) const {
00402   if (n < (int)pexprs.size()) {
00403     return pexprs[n];
00404   }
00405   return get_parameter_name(n);
00406 }
00407 
00408 ////////////////////////////////////////////////////////////////////
00409 //     Function: FunctionRemap::setup_properties
00410 //       Access: Private
00411 //  Description: Sets up the properties of the function appropriately.
00412 //               Returns true if successful, or false if there is
00413 //               something unacceptable about the function.
00414 ////////////////////////////////////////////////////////////////////
00415 bool FunctionRemap::
00416 setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface) {
00417   _function_signature = 
00418     TypeManager::get_function_signature(_cppfunc, _num_default_parameters);
00419   _expression = ifunc._expression;
00420 
00421   if ((_ftype->_flags & CPPFunctionType::F_constructor) != 0) {
00422     _type = T_constructor;
00423 
00424   } else if ((_ftype->_flags & CPPFunctionType::F_destructor) != 0) {
00425     _type = T_destructor;
00426 
00427   } else if ((_ftype->_flags & CPPFunctionType::F_operator_typecast) != 0) {
00428     _type = T_typecast_method;
00429 
00430   } else if ((ifunc._flags & InterrogateFunction::F_typecast) != 0) {
00431     _type = T_typecast;
00432 
00433   } else if ((ifunc._flags & InterrogateFunction::F_getter) != 0) {
00434     _type = T_getter;
00435 
00436   } else if ((ifunc._flags & InterrogateFunction::F_setter) != 0) {
00437     _type = T_setter;
00438   }
00439 
00440   if (_cpptype != (CPPType *)NULL &&
00441       ((_cppfunc->_storage_class & CPPInstance::SC_static) == 0) &&
00442       _type != T_constructor) {
00443 
00444     // If this is a method, but not a static method, and not a
00445     // constructor, then we need a "this" parameter.
00446     _has_this = true;
00447 
00448     if (interface->synthesize_this_parameter()) {
00449       // If the interface demands it, the "this" parameter is treated
00450       // as any other parameter, and inserted at the beginning of the
00451       // parameter list.
00452       Parameter param;
00453       param._name = "this";
00454       param._has_name = true;
00455       bool is_const = (_ftype->_flags & CPPFunctionType::F_const_method) != 0;
00456       param._remap = new ParameterRemapThis(_cpptype, is_const);
00457       _parameters.push_back(param);
00458       _first_true_parameter = 1;
00459     }
00460       
00461     // Also check the name of the function.  If it's one of the
00462     // assignment-style operators, flag it as such.
00463     string fname = _cppfunc->get_simple_name();
00464     if (fname == "operator =" ||
00465         fname == "operator *=" ||
00466         fname == "operator /=" ||
00467         fname == "operator %=" ||
00468         fname == "operator +=" ||
00469         fname == "operator -=" ||
00470         fname == "operator |=" ||
00471         fname == "operator &=" ||
00472         fname == "operator ^=" ||
00473         fname == "operator <<=" ||
00474         fname == "operator >>=") {
00475       _type = T_assignment_method;
00476     }
00477   }
00478 
00479   const CPPParameterList::Parameters &params =
00480     _ftype->_parameters->_parameters;
00481   for (int i = 0; i < (int)params.size() - _num_default_parameters; i++) {
00482     CPPType *type = params[i]->_type->resolve_type(&parser, _cppscope);
00483     Parameter param;
00484     param._has_name = true;
00485     param._name = params[i]->get_simple_name();
00486 
00487     if (param._name.empty()) {
00488       // If the parameter has no name, record it as being nameless,
00489       // but also synthesize one in case someone asks anyway.
00490       param._has_name = false;
00491       ostringstream param_name;
00492       param_name << "param" << i;
00493       param._name = param_name.str();
00494     }
00495 
00496     param._remap = interface->remap_parameter(_cpptype, type);
00497     if (param._remap == (ParameterRemap *)NULL) {
00498       // If we can't handle one of the parameter types, we can't call
00499       // the function.
00500       return false;
00501     }
00502     param._remap->set_default_value(params[i]->_initializer);
00503 
00504     if (!param._remap->is_valid()) {
00505       return false;
00506     }
00507 
00508     _parameters.push_back(param);
00509   }
00510 
00511   if (_type == T_constructor) {
00512     // Constructors are a special case.  These appear to return void
00513     // as seen by the parser, but we know they actually return a new
00514     // concrete instance.
00515 
00516     if (_cpptype == (CPPType *)NULL) {
00517       nout << "Method " << *_cppfunc << " has no struct type\n";
00518       return false;
00519     }
00520 
00521     _return_type = interface->remap_parameter(_cpptype, _cpptype);
00522     if (_return_type != (ParameterRemap *)NULL) {
00523       _void_return = false;
00524     }
00525 
00526   } else if (_type == T_assignment_method) {
00527     // Assignment-type methods are also a special case.  We munge
00528     // these to return *this, which is a semi-standard C++ convention
00529     // anyway.  We just enforce it.
00530 
00531     if (_cpptype == (CPPType *)NULL) {
00532       nout << "Method " << *_cppfunc << " has no struct type\n";
00533       return false;
00534     } else {
00535       CPPType *ref_type = CPPType::new_type(new CPPReferenceType(_cpptype));
00536       _return_type = interface->remap_parameter(_cpptype, ref_type);
00537       if (_return_type != (ParameterRemap *)NULL) {
00538         _void_return = false;
00539       }
00540     }
00541 
00542   } else {
00543     // The normal case.
00544     CPPType *rtype = _ftype->_return_type->resolve_type(&parser, _cppscope);
00545     _return_type = interface->remap_parameter(_cpptype, rtype);
00546     if (_return_type != (ParameterRemap *)NULL) {
00547       _void_return = TypeManager::is_void(rtype);
00548     }
00549   }
00550 
00551   if (_return_type == (ParameterRemap *)NULL || 
00552       !_return_type->is_valid()) {
00553     // If our return type isn't something we can deal with, treat the
00554     // function as if it returns NULL.
00555     _void_return = true;
00556     CPPType *void_type = TypeManager::get_void_type();
00557     _return_type = interface->remap_parameter(_cpptype, void_type);
00558     assert(_return_type != (ParameterRemap *)NULL);
00559   }
00560   
00561   // Do we need to manage the return value?
00562   _return_value_needs_management = 
00563     _return_type->return_value_needs_management();
00564   _return_value_destructor = 
00565     _return_type->get_return_value_destructor();
00566   
00567   // Should we manage a reference count?
00568   CPPType *return_type = _return_type->get_new_type();
00569   CPPType *return_meat_type = TypeManager::unwrap_pointer(return_type);
00570   
00571   if (manage_reference_counts &&
00572       TypeManager::is_reference_count_pointer(return_type) &&
00573       !TypeManager::has_protected_destructor(return_meat_type)) {
00574     // Yes!
00575     _manage_reference_count = true;
00576     _return_value_needs_management = true;
00577     
00578     // This is problematic, because we might not have the class in
00579     // question fully defined here, particularly if the class is
00580     // defined in some other library.
00581     _return_value_destructor = builder.get_destructor_for(return_meat_type);
00582   }
00583 
00584   return true;
00585 }

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