panda3d/dtool/src/cppparser/cppInstance.cxx
2001-05-25 21:27:38 +00:00

566 lines
18 KiB
C++

// Filename: cppInstance.cxx
// Created by: drose (19Oct99)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, 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://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "cppInstance.h"
#include "cppInstanceIdentifier.h"
#include "cppIdentifier.h"
#include "cppTemplateScope.h"
#include "cppFunctionType.h"
#include "cppSimpleType.h"
#include "cppExpression.h"
#include "cppPreprocessor.h"
#include "indent.h"
#include "cppReferenceType.h"
#include "cppConstType.h"
#include <algorithm>
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPInstance::
CPPInstance(CPPType *type, const string &name, int storage_class) :
CPPDeclaration(CPPFile()),
_type(type),
_ident(new CPPIdentifier(name)),
_storage_class(storage_class)
{
_initializer = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPInstance::
CPPInstance(CPPType *type, CPPIdentifier *ident, int storage_class) :
CPPDeclaration(CPPFile()),
_type(type),
_ident(ident),
_storage_class(storage_class)
{
_initializer = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::Constructor
// Access: Public
// Description: Constructs a new CPPInstance object that defines a
// variable of the indicated type according to the type
// and the InstanceIdentifier. The InstanceIdentifier
// pointer is deallocated.
////////////////////////////////////////////////////////////////////
CPPInstance::
CPPInstance(CPPType *type, CPPInstanceIdentifier *ii, int storage_class,
const CPPFile &file) :
CPPDeclaration(file)
{
_type = ii->unroll_type(type);
_ident = ii->_ident;
ii->_ident = NULL;
_storage_class = storage_class;
delete ii;
_initializer = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::Copy Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPInstance::
CPPInstance(const CPPInstance &copy) :
CPPDeclaration(copy),
_type(copy._type),
_ident(copy._ident),
_initializer(copy._initializer),
_storage_class(copy._storage_class)
{
assert(_type != NULL);
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPInstance::
~CPPInstance() {
// Can't delete the identifier. Don't try.
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::make_typecast_function
// Access: Public, Static
// Description: Constructs and returns a new CPPInstance object that
// corresponds to a function prototype declaration for a
// typecast method, whose return type is implicit in the
// identifier type.
////////////////////////////////////////////////////////////////////
CPPInstance *CPPInstance::
make_typecast_function(CPPInstance *inst, CPPIdentifier *ident,
CPPParameterList *parameters, int function_flags) {
CPPType *type = CPPType::new_type(inst->_type);
delete inst;
function_flags |= (int)CPPFunctionType::F_operator_typecast;
CPPType *ft =
CPPType::new_type(new CPPFunctionType(type, parameters, function_flags));
return new CPPInstance(ft, ident);
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::Equivalence Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
bool CPPInstance::
operator == (const CPPInstance &other) const {
if (_type != other._type) {
return false;
}
if (_storage_class != other._storage_class) {
return false;
}
// We *do* care about the identifier. We need to differentiate
// types of function variables, among possibly other things, based
// on the identifier.
if ((_ident == NULL && other._ident != NULL) ||
(_ident != NULL && other._ident == NULL) ||
(_ident != NULL && other._ident != NULL && *_ident != *other._ident))
{
return false;
}
// We similarly care about the initializer.
if ((_initializer == NULL && other._initializer != NULL) ||
(_initializer != NULL && other._initializer == NULL) ||
(_initializer != NULL && other._initializer != NULL &&
*_initializer != *other._initializer))
{
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::Nonequivalence Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
bool CPPInstance::
operator != (const CPPInstance &other) const {
return !operator == (other);
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::Ordering Operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
bool CPPInstance::
operator < (const CPPInstance &other) const {
if (_type != other._type) {
return _type < other._type;
}
if (_storage_class != other._storage_class) {
return _storage_class < other._storage_class;
}
// We *do* care about the identifier. We need to differentiate
// types of function variables, among possibly other things, based
// on the identifier.
if ((_ident == NULL && other._ident != NULL) ||
(_ident != NULL && other._ident == NULL) ||
(_ident != NULL && other._ident != NULL && *_ident != *other._ident))
{
if (_ident == NULL || other._ident == NULL) {
return _ident < other._ident;
}
return *_ident < *other._ident;
}
// We similarly care about the initializer.
if ((_initializer == NULL && other._initializer != NULL) ||
(_initializer != NULL && other._initializer == NULL) ||
(_initializer != NULL && other._initializer != NULL &&
*_initializer != *other._initializer))
{
if (_initializer == NULL || other._initializer == NULL) {
return _initializer < other._initializer;
}
return *_initializer < *other._initializer;
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::set_initializer
// Access: Public
// Description: Sets the value of the expression that is used to
// initialize the variable, or the default value for a
// parameter. If a non-null expression is set on a
// function declaration, it implies that the function is
// pure virtual.
////////////////////////////////////////////////////////////////////
void CPPInstance::
set_initializer(CPPExpression *initializer) {
if (_type->as_function_type() != (CPPFunctionType *)NULL) {
// This is a function declaration.
if (initializer == (CPPExpression *)NULL) {
_storage_class &= ~SC_pure_virtual;
} else {
_storage_class |= SC_pure_virtual;
}
_initializer = (CPPExpression *)NULL;
} else {
_initializer = initializer;
}
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::is_scoped
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
bool CPPInstance::
is_scoped() const {
if (_ident == NULL) {
return false;
} else {
return _ident->is_scoped();
}
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::get_scope
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPScope *CPPInstance::
get_scope(CPPScope *current_scope, CPPScope *global_scope,
CPPPreprocessor *error_sink) const {
if (_ident == NULL) {
return current_scope;
} else {
return _ident->get_scope(current_scope, global_scope, error_sink);
}
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::get_simple_name
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
string CPPInstance::
get_simple_name() const {
if (_ident == NULL) {
return "";
} else {
return _ident->get_simple_name();
}
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::get_local_name
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
string CPPInstance::
get_local_name(CPPScope *scope) const {
if (_ident == NULL) {
return "";
} else {
return _ident->get_local_name(scope);
}
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::get_fully_scoped_name
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
string CPPInstance::
get_fully_scoped_name() const {
if (_ident == NULL) {
return "";
} else {
return _ident->get_fully_scoped_name();
}
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::check_for_constructor
// Access: Public
// Description: If this is a function type instance, checks whether
// the function name matches the class name (or ~name),
// and if so, flags it as a constructor (or destructor).
////////////////////////////////////////////////////////////////////
void CPPInstance::
check_for_constructor(CPPScope *current_scope, CPPScope *global_scope) {
CPPScope *scope = get_scope(current_scope, global_scope);
if (scope == NULL) {
scope = current_scope;
}
CPPFunctionType *func = _type->as_function_type();
if (func != NULL) {
string method_name = get_local_name(scope);
string class_name = scope->get_local_name();
if (!method_name.empty() && !class_name.empty()) {
if (method_name == class_name) {
CPPType *void_type = CPPType::new_type
(new CPPSimpleType(CPPSimpleType::T_void));
_type = CPPType::new_type
(new CPPFunctionType(void_type, func->_parameters,
func->_flags | CPPFunctionType::F_constructor));
} else if (method_name == "~" + class_name) {
CPPType *void_type = CPPType::new_type
(new CPPSimpleType(CPPSimpleType::T_void));
_type = CPPType::new_type
(new CPPFunctionType(void_type, func->_parameters,
func->_flags | CPPFunctionType::F_destructor));
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::instantiate
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CPPDeclaration *CPPInstance::
instantiate(const CPPTemplateParameterList *actual_params,
CPPScope *current_scope, CPPScope *global_scope,
CPPPreprocessor *error_sink) const {
if (!is_template()) {
if (error_sink != NULL) {
error_sink->warning("Ignoring template parameters for instance " +
_ident->get_local_name());
}
return (CPPInstance *)this;
}
Instantiations::const_iterator ii;
ii = _instantiations.find(actual_params);
if (ii != _instantiations.end()) {
// We've already instantiated this instance with these parameters.
// Return that.
return (*ii).second;
}
CPPTemplateScope *tscope = get_template_scope();
CPPDeclaration::SubstDecl subst;
actual_params->build_subst_decl(tscope->_parameters, subst,
current_scope, global_scope);
CPPInstance *inst =
((CPPInstance *)this)->substitute_decl(subst, current_scope, global_scope)
->as_instance();
if (inst == this) {
// Hmm, nothing to substitute. Make a new instance anyway, so we
// can change the name.
inst = new CPPInstance(*this);
}
assert(inst != NULL);
inst->_ident = inst->_ident->substitute_decl(subst, current_scope, global_scope);
if (inst->_ident == _ident) {
inst->_ident = new CPPIdentifier(*inst->_ident);
}
inst->_ident->_names.back().set_templ
(new CPPTemplateParameterList(*actual_params));
inst->_template_scope = NULL;
((CPPInstance *)this)->_instantiations.insert(Instantiations::value_type(actual_params, inst));
return inst;
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::is_fully_specified
// Access: Public, Virtual
// 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 CPPInstance::
is_fully_specified() const {
if (_ident != NULL && !_ident->is_fully_specified()) {
return false;
}
if (_initializer != NULL && !_initializer->is_fully_specified()) {
return false;
}
return CPPDeclaration::is_fully_specified() &&
_type->is_fully_specified();
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::substitute_decl
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
CPPDeclaration *CPPInstance::
substitute_decl(CPPDeclaration::SubstDecl &subst,
CPPScope *current_scope, CPPScope *global_scope) {
CPPDeclaration *top =
CPPDeclaration::substitute_decl(subst, current_scope, global_scope);
if (top != this) {
return top;
}
CPPInstance *rep = new CPPInstance(*this);
CPPDeclaration *new_type =
_type->substitute_decl(subst, current_scope, global_scope);
rep->_type = new_type->as_type();
if (rep->_type == NULL) {
cerr << "Type " << *_type << " became " << *new_type << " which isn't a type\n";
rep->_type = _type;
}
if (_initializer != NULL) {
rep->_initializer =
_initializer->substitute_decl(subst, current_scope, global_scope)
->as_expression();
}
if (rep->_type == _type &&
rep->_initializer == _initializer) {
delete rep;
rep = this;
}
subst.insert(SubstDecl::value_type(this, rep));
return rep;
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::output
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void CPPInstance::
output(ostream &out, int indent_level, CPPScope *scope, bool complete) const {
output(out, indent_level, scope, complete, -1);
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::output
// Access: Public
// Description: The extra parameter comes into play only when we
// happen to be outputting a function prototype. See
// CPPFunctionType::output().
////////////////////////////////////////////////////////////////////
void CPPInstance::
output(ostream &out, int indent_level, CPPScope *scope, bool complete,
int num_default_parameters) const {
if (is_template()) {
get_template_scope()->_parameters.write_formal(out, scope);
indent(out, indent_level);
}
if (_storage_class & SC_static) {
out << "static ";
}
if (_storage_class & SC_extern) {
out << "extern ";
}
if (_storage_class & SC_c_binding) {
out << "\"C\" ";
}
if (_storage_class & SC_virtual) {
out << "virtual ";
}
if (_storage_class & SC_inline) {
out << "inline ";
}
if (_storage_class & SC_explicit) {
out << "explicit ";
}
if (_storage_class & SC_register) {
out << "register ";
}
if (_storage_class & SC_volatile) {
out << "volatile ";
}
if (_storage_class & SC_mutable) {
out << "mutable ";
}
string name;
if (_ident != NULL) {
name = _ident->get_local_name(scope);
}
assert(_type != NULL);
if (_type->as_function_type()) {
_type->as_function_type()->
output_instance(out, indent_level, scope, complete, "", name,
num_default_parameters);
} else {
_type->output_instance(out, indent_level, scope, complete, "", name);
}
if (_storage_class & SC_pure_virtual) {
out << " = 0";
}
if (_initializer != NULL) {
out << " = (" << *_initializer << ")";
}
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::get_subtype
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
CPPDeclaration::SubType CPPInstance::
get_subtype() const {
return ST_instance;
}
////////////////////////////////////////////////////////////////////
// Function: CPPInstance::as_instance
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
CPPInstance *CPPInstance::
as_instance() {
return this;
}