// Filename: cppIdentifier.cxx // Created by: drose (26Oct99) // //////////////////////////////////////////////////////////////////// // // 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 "cppIdentifier.h" #include "cppScope.h" #include "cppTemplateScope.h" #include "cppPreprocessor.h" #include "cppTemplateParameterList.h" #include "cppTBDType.h" #include "cppStructType.h" //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// CPPIdentifier:: CPPIdentifier(const string &name, const CPPFile &file) : _file(file) { _names.push_back(CPPNameComponent(name)); _native_scope = (CPPScope *)NULL; } //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::Constructor // Access: Public // Description: //////////////////////////////////////////////////////////////////// CPPIdentifier:: CPPIdentifier(const CPPNameComponent &name) { _names.push_back(name); _native_scope = (CPPScope *)NULL; } //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::add_name // Access: Public // Description: //////////////////////////////////////////////////////////////////// void CPPIdentifier:: add_name(const string &name) { _names.push_back(CPPNameComponent(name)); } //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::add_name // Access: Public // Description: //////////////////////////////////////////////////////////////////// void CPPIdentifier:: add_name(const CPPNameComponent &name) { _names.push_back(name); } //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::Equivalence Operator // Access: Public // Description: //////////////////////////////////////////////////////////////////// bool CPPIdentifier:: operator == (const CPPIdentifier &other) const { if (_names.size() != other._names.size()) { return false; } for (int i = 0; i < (int)_names.size(); i++) { if (_names[i] != other._names[i]) { return false; } } return true; } //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::Nonequivalence Operator // Access: Public // Description: //////////////////////////////////////////////////////////////////// bool CPPIdentifier:: operator != (const CPPIdentifier &other) const { return !(*this == other); } //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::Ordering Operator // Access: Public // Description: //////////////////////////////////////////////////////////////////// bool CPPIdentifier:: operator < (const CPPIdentifier &other) const { if (_names.size() != other._names.size()) { return _names.size() < other._names.size(); } for (int i = 0; i < (int)_names.size(); i++) { if (_names[i] != other._names[i]) { return _names[i] < other._names[i]; } } return false; } //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::is_scoped // Access: Public // Description: //////////////////////////////////////////////////////////////////// bool CPPIdentifier:: is_scoped() const { return _names.size() > 1; } //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::get_simple_name // Access: Public // Description: //////////////////////////////////////////////////////////////////// string CPPIdentifier:: get_simple_name() const { return _names.back().get_name(); } //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::get_local_name // Access: Public // Description: //////////////////////////////////////////////////////////////////// string CPPIdentifier:: get_local_name(CPPScope *scope) const { assert(!_names.empty()); string result; if (scope == NULL || (_native_scope == NULL && _names.size() == 1)) { result = _names.back().get_name_with_templ(scope); } else if (_names.front().empty()) { result = get_fully_scoped_name(); } else { // Determine the scope of everything up until but not including the // last name. CPPScope *my_scope = get_scope(scope, NULL); if (my_scope == NULL) { result = get_fully_scoped_name(); } else if (my_scope == scope) { return _names.back().get_name_with_templ(scope); } else { result = my_scope->get_local_name(scope); if (!result.empty()) { result += "::"; } result += _names.back().get_name_with_templ(scope); } } return result; } //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::get_fully_scoped_name // Access: Public // Description: //////////////////////////////////////////////////////////////////// string CPPIdentifier:: get_fully_scoped_name() const { assert(!_names.empty()); Names::const_iterator ni = _names.begin(); string name = (*ni).get_name_with_templ(); ++ni; while (ni != _names.end()) { name += "::" + (*ni).get_name_with_templ(); ++ni; } return name; } //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::is_fully_specified // Access: Public // Description: Returns true if this declaration is an actual, // factual declaration, or false if some part of the // declaration depends on a template parameter which has // not yet been instantiated. //////////////////////////////////////////////////////////////////// bool CPPIdentifier:: is_fully_specified() const { Names::const_iterator ni; for (ni = _names.begin(); ni != _names.end(); ++ni) { if ((*ni).has_templ() && !(*ni).get_templ()->is_fully_specified()) { return false; } } return true; } //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::is_tbd // Access: Public // Description: Returns true if the identifier includes a // template parameter list that includes some // not-yet-defined type. //////////////////////////////////////////////////////////////////// bool CPPIdentifier:: is_tbd() const { Names::const_iterator ni; for (ni = _names.begin(); ni != _names.end(); ++ni) { if ((*ni).is_tbd()) { return true; } } return false; } //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::get_scope // Access: Public // Description: //////////////////////////////////////////////////////////////////// CPPScope *CPPIdentifier:: get_scope(CPPScope *current_scope, CPPScope *global_scope, CPPPreprocessor *error_sink) const { assert(!_names.empty()); CPPScope *scope = _native_scope; if (scope == (CPPScope *)NULL) { scope = current_scope; } int i = 0; if (_names[i].empty()) { // This identifier starts with a ::, thus it begins at the global // scope. scope = global_scope; i++; } while (i + 1 < (int)_names.size() && scope != NULL) { CPPScope *next_scope = scope->find_scope(_names[i].get_name()); if (next_scope == (CPPScope *)NULL) { if (error_sink != NULL) { error_sink->error("Symbol " + _names[i].get_name() + " is not a known scope in " + scope->get_fully_scoped_name()); } return (CPPScope *)NULL; } if (_names[i].has_templ()) { next_scope = next_scope->instantiate(_names[i].get_templ(), current_scope, global_scope); } scope = next_scope; i++; } return scope; } //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::get_scope // Access: Public // Description: //////////////////////////////////////////////////////////////////// CPPScope *CPPIdentifier:: get_scope(CPPScope *current_scope, CPPScope *global_scope, CPPDeclaration::SubstDecl &subst, CPPPreprocessor *error_sink) const { assert(!_names.empty()); CPPScope *scope = _native_scope; if (scope == (CPPScope *)NULL) { scope = current_scope; } int i = 0; if (_names[i].empty()) { // This identifier starts with a ::, thus it begins at the global // scope. scope = global_scope; i++; } while (i + 1 < (int)_names.size() && scope != NULL) { CPPScope *next_scope = scope->find_scope(_names[i].get_name(), subst, global_scope); if (next_scope == (CPPScope *)NULL) { if (error_sink != NULL) { error_sink->error("Symbol " + _names[i].get_name() + " is not a known scope in " + scope->get_fully_scoped_name()); } return (CPPScope *)NULL; } if (_names[i].has_templ()) { next_scope = next_scope->instantiate(_names[i].get_templ(), current_scope, global_scope); } scope = next_scope; i++; } return scope; } //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::find_type // Access: Public // Description: Looks up the identifier in the current and/or global // scopes, and returns a CPPType pointer if it seems to // refer to a type, or NULL if it does not. If // force_instantiate is true, the type will be // instantiated as fully as possible right now, even if // it means instantiating it into an identical template // type. Otherwise, the instantiation may be delayed // for optimization reasons, and a CPPTBDType // placeholder may be returned instead. //////////////////////////////////////////////////////////////////// CPPType *CPPIdentifier:: find_type(CPPScope *current_scope, CPPScope *global_scope, bool force_instantiate, CPPPreprocessor *error_sink) const { CPPScope *scope = get_scope(current_scope, global_scope, error_sink); if (scope == NULL) { return NULL; } CPPType *type = NULL; if (!_names.back().has_templ()) { type = scope->find_type(get_simple_name()); } else { CPPDeclaration *decl = find_symbol(current_scope, global_scope, error_sink); type = decl->as_type(); /* if (type != NULL) { if (!type->is_incomplete() || force_instantiate) { type = type->instantiate(_names.back().get_templ(), current_scope, global_scope, error_sink)->as_type(); // If we ended up with another template, instantiate later. if (type->is_template() && !force_instantiate) { type = CPPType::new_type(new CPPTBDType((CPPIdentifier *)this)); } } else { // Otherwise, we'll have to instantiate the type later. type = CPPType::new_type(new CPPTBDType((CPPIdentifier *)this)); } // type->_file.replace_nearer(_file); } */ } return type; } //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::find_type // Access: Public // Description: This flavor of find_type() will instantiate any scope // names in the identifier. It's useful for fully // defining a type while instantiating a class. //////////////////////////////////////////////////////////////////// CPPType *CPPIdentifier:: find_type(CPPScope *current_scope, CPPScope *global_scope, CPPDeclaration::SubstDecl &subst, CPPPreprocessor *error_sink) const { CPPScope *scope = get_scope(current_scope, global_scope, subst, error_sink); if (scope == NULL) { return NULL; } CPPType *type = scope->find_type(get_simple_name(), subst, global_scope); if (type != NULL && _names.back().has_templ()) { // This is a template type. if (is_fully_specified()) { // If our identifier fully specifies the instantiation, then // apply it. CPPDeclaration *decl = type->instantiate(_names.back().get_templ(), current_scope, global_scope, error_sink); assert(decl != NULL); CPPType *new_type = decl->as_type(); assert(new_type != NULL); if (new_type == type) { type = CPPType::new_type(new CPPTBDType((CPPIdentifier *)this)); // type = new_type; } else { type = new_type; } } else { // Otherwise, we'll have to instantiate the type later. type = CPPType::new_type(new CPPTBDType((CPPIdentifier *)this)); } // type->_file.replace_nearer(_file); } return type; } //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::find_symbol // Access: Public // Description: //////////////////////////////////////////////////////////////////// CPPDeclaration *CPPIdentifier:: find_symbol(CPPScope *current_scope, CPPScope *global_scope, CPPPreprocessor *error_sink) const { CPPScope *scope = get_scope(current_scope, global_scope, error_sink); if (scope == NULL) { return NULL; } CPPDeclaration *sym; if (!_names.back().has_templ()) { sym = scope->find_symbol(get_simple_name()); } else { sym = scope->find_template(get_simple_name()); if (sym != NULL) { CPPType *type = sym->as_type(); if (type != NULL && type->is_incomplete()) { // We can't instantiate an incomplete type. sym = CPPType::new_type(new CPPTBDType((CPPIdentifier *)this)); } else { // Instantiate the symbol. sym = sym->instantiate(_names.back().get_templ(), current_scope, global_scope, error_sink); } } } return sym; } //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::find_template // Access: Public // Description: //////////////////////////////////////////////////////////////////// CPPDeclaration *CPPIdentifier:: find_template(CPPScope *current_scope, CPPScope *global_scope, CPPPreprocessor *error_sink) const { CPPScope *scope = get_scope(current_scope, global_scope, error_sink); if (scope == NULL) { return NULL; } return scope->find_template(get_simple_name()); } //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::find_scope // Access: Public // Description: //////////////////////////////////////////////////////////////////// CPPScope *CPPIdentifier:: find_scope(CPPScope *current_scope, CPPScope *global_scope, CPPPreprocessor *error_sink) const { CPPScope *scope = get_scope(current_scope, global_scope, error_sink); if (scope == NULL) { return NULL; } return scope->find_scope(get_simple_name()); } //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::substitute_decl // Access: Public // Description: //////////////////////////////////////////////////////////////////// CPPIdentifier *CPPIdentifier:: substitute_decl(CPPDeclaration::SubstDecl &subst, CPPScope *current_scope, CPPScope *global_scope) { CPPIdentifier *rep = new CPPIdentifier(*this); bool anything_changed = false; for (int i = 0; i < (int)rep->_names.size(); i++) { if (_names[i].has_templ()) { rep->_names[i].set_templ (_names[i].get_templ()->substitute_decl(subst, current_scope, global_scope)); if (rep->_names[i].get_templ() != _names[i].get_templ()) { anything_changed = true; } } } if (!anything_changed) { delete rep; rep = this; } return rep; } //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::output // Access: Public // Description: //////////////////////////////////////////////////////////////////// void CPPIdentifier:: output(ostream &out, CPPScope *scope) const { if (scope == NULL) { output_fully_scoped_name(out); } else { output_local_name(out, scope); } } //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::output_local_name // Access: Public // Description: //////////////////////////////////////////////////////////////////// void CPPIdentifier:: output_local_name(ostream &out, CPPScope *scope) const { assert(!_names.empty()); if (scope == NULL || (_native_scope == NULL && _names.size() == 1)) { out << _names.back(); } else if (_names.front().empty()) { output_fully_scoped_name(out); } else { // Determine the scope of everything up until but not including the // last name. CPPScope *my_scope = get_scope(scope, NULL); if (my_scope == NULL) { output_fully_scoped_name(out); } else { out << my_scope->get_local_name(scope) << "::" << _names.back(); } } } //////////////////////////////////////////////////////////////////// // Function: CPPIdentifier::output_fully_scoped_name // Access: Public // Description: //////////////////////////////////////////////////////////////////// void CPPIdentifier:: output_fully_scoped_name(ostream &out) const { if (_native_scope != NULL) { _native_scope->output(out, (CPPScope *)NULL); out << "::"; } Names::const_iterator ni = _names.begin(); out << (*ni); ++ni; while (ni != _names.end()) { out << "::" << (*ni); ++ni; } }