// Filename: cppType.cxx // Created by: drose (19Oct99) // //////////////////////////////////////////////////////////////////// // // 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 "cppType.h" #include "cppTypedef.h" CPPType::Types CPPType::_types; CPPType::PreferredNames CPPType::_preferred_names; bool CPPTypeCompare:: operator () (CPPType *a, CPPType *b) const { return (*a) < (*b); } //////////////////////////////////////////////////////////////////// // Function: CPPType::Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// CPPType:: CPPType(const CPPFile &file) : CPPDeclaration(file) { _declaration = (CPPTypeDeclaration *)NULL; } //////////////////////////////////////////////////////////////////// // Function: CPPType::resolve_type // Access: Public, Virtual // Description: If this CPPType object is a forward reference or // other nonspecified reference to a type that might now // be known a real type, returns the real type. // Otherwise returns the type itself. //////////////////////////////////////////////////////////////////// CPPType *CPPType:: resolve_type(CPPScope *, CPPScope *) { return this; } //////////////////////////////////////////////////////////////////// // Function: CPPType::is_tbd // Access: Public, Virtual // Description: Returns true if the type, or any nested type within // the type, is a CPPTBDType and thus isn't fully // determined right now. In this case, calling // resolve_type() may or may not resolve the type. //////////////////////////////////////////////////////////////////// bool CPPType:: is_tbd() const { return false; } //////////////////////////////////////////////////////////////////// // Function: CPPType::is_parameter_expr // Access: Public, Virtual // Description: Returns true if the type is a special parameter // expression type. // // This sort of type is created to handle instance // declarations that initially look like function // prototypes. //////////////////////////////////////////////////////////////////// bool CPPType:: is_parameter_expr() const { return false; } //////////////////////////////////////////////////////////////////// // Function: CPPType::has_typedef_name // Access: Public // Description: Returns true if the type has even been typedef'ed and // therefore has a simple name available to stand for // it. Extension types are all implicitly typedef'ed on // declaration. //////////////////////////////////////////////////////////////////// bool CPPType:: has_typedef_name() const { return !_typedefs.empty(); } //////////////////////////////////////////////////////////////////// // Function: CPPType::get_typedef_name // Access: Public // Description: Returns a string that can be used to name the type, // if has_typedef_name() returned true. This will be // the first typedef name applied to the type. //////////////////////////////////////////////////////////////////// string CPPType:: get_typedef_name(CPPScope *scope) const { if (_typedefs.empty()) { return string(); } else { return _typedefs.front()->get_local_name(scope); } } //////////////////////////////////////////////////////////////////// // Function: CPPType::get_simple_name // Access: Public, Virtual // Description: Returns a fundametal one-word name for the type. // This name will not include any scoping operators or // template parameters, so it may not be a compilable // reference to the type. //////////////////////////////////////////////////////////////////// string CPPType:: get_simple_name() const { return get_local_name(); } //////////////////////////////////////////////////////////////////// // Function: CPPType::get_local_name // Access: Public, Virtual // Description: Returns the compilable, correct name for this type // within the indicated scope. If the scope is NULL, // within the scope the type is declared in. //////////////////////////////////////////////////////////////////// string CPPType:: get_local_name(CPPScope *scope) const { ostringstream ostrm; output(ostrm, 0, scope, false); return ostrm.str(); } //////////////////////////////////////////////////////////////////// // Function: CPPType::get_fully_scoped_name // Access: Public, Virtual // Description: Returns the compilable, correct name for the type, // with completely explicit scoping. //////////////////////////////////////////////////////////////////// string CPPType:: get_fully_scoped_name() const { return get_local_name(); } //////////////////////////////////////////////////////////////////// // Function: CPPType::get_preferred_name // Access: Public, Virtual // Description: Returns the best name to use for the type from a // programmer's point of view. This will typically be a // typedef name if one is available, or the full C++ // name if it is not. The typedef may or may not be // visible within the current scope, so this type name // may not be compilable. //////////////////////////////////////////////////////////////////// string CPPType:: get_preferred_name() const { string preferred_name = get_preferred_name_for(this); if (!preferred_name.empty()) { return preferred_name; } return get_local_name(); } //////////////////////////////////////////////////////////////////// // Function: CPPType::is_incomplete // Access: Public, Virtual // Description: Returns true if the type has not yet been fully // specified, false if it has. //////////////////////////////////////////////////////////////////// bool CPPType:: is_incomplete() const { return false; } //////////////////////////////////////////////////////////////////// // Function: CPPType::is_equivalent // Access: Public, Virtual // Description: This is a little more forgiving than is_equal(): it // returns true if the types appear to be referring to // the same thing, even if they may have different // pointers or somewhat different definitions. It's // useful for parameter matching, etc. //////////////////////////////////////////////////////////////////// bool CPPType:: is_equivalent(const CPPType &other) const { if (get_subtype() != other.get_subtype()) { return false; } return is_equal(&other); } //////////////////////////////////////////////////////////////////// // Function: CPPType::output_instance // Access: Public, Virtual // Description: Formats a C++-looking line that defines an instance // of the given type, with the indicated name. In most // cases this will be "type name", but some types have // special exceptions. //////////////////////////////////////////////////////////////////// void CPPType:: output_instance(ostream &out, const string &name, CPPScope *scope) const { output_instance(out, 0, scope, false, "", name); } //////////////////////////////////////////////////////////////////// // Function: CPPType::output_instance // Access: Public, Virtual // Description: Formats a C++-looking line that defines an instance // of the given type, with the indicated name. In most // cases this will be "type name", but some types have // special exceptions. //////////////////////////////////////////////////////////////////// void CPPType:: output_instance(ostream &out, int indent_level, CPPScope *scope, bool complete, const string &prename, const string &name) const { output(out, indent_level, scope, complete); out << " " << prename << name; } //////////////////////////////////////////////////////////////////// // Function: CPPType::as_type // Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// CPPType *CPPType:: as_type() { return this; } //////////////////////////////////////////////////////////////////// // Function: CPPType::new_type // Access: Public, Static // Description: This should be called whenever a new CPPType object // is created. It will uniquify the type pointers by // checking to see if some equivalent CPPType object has // previously been created; if it has, it returns the // old object and deletes the new one. Otherwise, it // stores the new one and returns it. //////////////////////////////////////////////////////////////////// CPPType *CPPType:: new_type(CPPType *type) { pair result = _types.insert(type); if (result.second) { // The insertion has taken place; thus, this is the first time // this type has been declared. assert(*result.first == type); return type; } // The insertion has not taken place; thus, there was previously // another equivalent type declared. if (*result.first != type) { // *** Something wrong here. Deleting this should always be safe; // however, it's not. Thus, someone failed to call new_type() on // a type pointer before saving it somewhere. Fix me soon. **** //delete type; } return *result.first; } //////////////////////////////////////////////////////////////////// // Function: CPPType::record_preferred_name_for // Access: Public, Static // Description: Records a global typedef name associated with the // indicated Type. This will be taken as the // "preferred" name for this class, should anyone ask. //////////////////////////////////////////////////////////////////// void CPPType:: record_preferred_name_for(const CPPType *type, const string &name) { if (!name.empty()) { string tname = type->get_fully_scoped_name(); if (!tname.empty()) { _preferred_names.insert(PreferredNames::value_type(tname, name)); } } } //////////////////////////////////////////////////////////////////// // Function: CPPType::get_preferred_name_for // Access: Public, Static // Description: Returns the previously-stored "preferred" name // associated with the type, if any, or empty string if // no name is associated. //////////////////////////////////////////////////////////////////// string CPPType:: get_preferred_name_for(const CPPType *type) { // We do a lookup based on the type's name, instead of its pointer, // so we can resolve different expansions of the same type. string tname = type->get_fully_scoped_name(); if (!tname.empty()) { PreferredNames::const_iterator pi; pi = _preferred_names.find(tname); if (pi != _preferred_names.end()) { return (*pi).second; } } return string(); }