// CPPSymTableScope.cpp: Scope-manipulation for CPPSymTable.
#include "CPPSymTable.h"
#include "CPPScopeNormal.h"
#include "CPPTypeClass.h"
#include "CPPTypeTemplated.h"
#include "CPPDecl.h"
#include "JLCast.h"
#include "CPPScopeState.h"
#include "CPPScopeContainers.h"
#include "CPPTypeClassBaseClass.h"
#include "CPPExpr.h"
/////////////////////////////////////////////////////////////////////
// SaveScope: Return a struct signifying the position of the scope
// stack. This is used before an arbitrary series of scope
// pushes, so that the scope stack can be restored to a given state.
//
// Inputs: none
// Outputs: none
// Return:
// CPPScopeState The state of the stack (i.e., its size)
/////////////////////////////////////////////////////////////////////
// virtual
CPPScopeState
CPPSymTable::SaveScope() const
{
return CPPScopeState((int)scopeStack->size());
}
/////////////////////////////////////////////////////////////////////
// RestoreScope: Pop the scope stack to the indicated position.
//
// Inputs:
// CPPScopeState state The scope stack state to which
// it should be restored.
// Outputs: none
// Return: none
/////////////////////////////////////////////////////////////////////
// virtual
void
CPPSymTable::RestoreScope(
CPPScopeState state
)
{
// Make sure this isn't a bogus state
assert(state.position > 0);
assert(state.position <= (int)scopeStack->size());
while ( (int)scopeStack->size() > state.position)
{
// The top of the stack is the front of the list
scopeStack->pop_front();
}
}
///////////////////////////////////////////////////////////////////////
CPPScopeLevel
CPPSymTable::PopScope()
{
assert((int)scopeStack->size() > 1);
CPPScopeLevel topScope = scopeStack->front();
scopeStack->pop_front();
return topScope;
}
///////////////////////////////////////////////////////////////////////
void
CPPSymTable::PushScope(
CPPScopeLevel scopeLevel
)
{
scopeStack->push_front(scopeLevel);
}
/////////////////////////////////////////////////////////////////////
// EnterNamedScope: Push the scope for a class or namespace on the
// stack. Drags in the scopes of the base classes (and parent classes
// if "resolved" is false).
//
// Inputs:
// const JLStr& name The name of the class or namespace
// bool resolved If true, then put the scopes on the
// stack in "resolved" mode so that only
// the scopes of the class/namespace and
// any base classes are searchable.
//
// Outputs: none
// Return:
// bool true on success, false if the scope could not be found.
//
// Note: Used with resolved==false when a class member
// function is entered, like:
// class A { int f(); };
// int A::f() { ... }
//
// Note: Used with resolved=false during class definitions to enter
// the scope of defined base classes:
// class A : public B { ... };
//
// Note: Used with resolved=true when the scope resolution operator
// is encountered with a class or namespace name:
// A::B::x
//
// Note: Use SaveScope/Restore scope to pop this scope when finished.
/////////////////////////////////////////////////////////////////////
// virtual
bool
CPPSymTable::EnterNamedScope(
const JLStr& name,
bool resolved
)
{
// Find the scope
CPPScopeRefI theScope;
if (LookupScope(name, theScope, true))
{
// Push the scope for the namespace on the stack.
EnterScopeContext(theScope, resolved);
return true;
} else {
// non-existent class/namespace.
return false;
}
}
/////////////////////////////////////////////////////////////////////
// EnterClassScope: Enter the given class scope. Drags in the
// scopes of the base classes.
//
// Inputs:
// const CPPTypeRefI theClass The class for the scope being entered.
// bool resolved If true, then the scope is entered in
// "resolved" mode.
//
// Outputs: none
// Return: none
/////////////////////////////////////////////////////////////////////
void
CPPSymTable::EnterClassScope(
CPPTypeRefI theClass,
bool resolved
)
{
if (resolved)
{
// Push a "resolved" empty scope
EnterScope(emptyScope, true);
}
theClass = theClass->StripTemplateModifiers();
// Get the list of base classes for the class
assert(theClass->GetFlavor() == CPPType::Class);
CPPTypeClass::BaseClassListCRefI baseClasses =
STATIC_CAST(CPPTypeClass*, theClass.get())->GetBaseClasses();
// Recursively push the scopes for the base classes on the stack
for (
CPPTypeClass::BaseClassList::const_iterator iter = baseClasses->begin();
iter != baseClasses->end();
iter++
)
{
EnterClassScope((*iter).GetBaseClass(), false);
}
// Push the scope for the class itself on the stack.
EnterScope(
STATIC_CAST(CPPTypeClass*,theClass.get())->GetMemberScope(),
false
);
}
/////////////////////////////////////////////////////////////////////
// EnterScopeContext: Enter a scope context, which is the scope, its
// parents, and base classes
//
// Inputs:
// CPPScopeRefI scope The scope whose context is to be entered
// bool resolved If true, then the scope is entered in
// "resolved" mode, and no parent scopes are
// entered.
// Outputs: none
// Return: none
//
// Note: Used to enter the context of a class member function, or to
// enter the scope of a scope-override prefix.
/////////////////////////////////////////////////////////////////////
void
CPPSymTable::EnterScopeContext(
CPPScopeRefI scope,
bool resolved
)
{
if (!resolved)
{
// Push the parent scopes first
if (scope->GetParentScope().get() != 0)
{
switch (scope->GetParentScope()->GetFlavor())
{
case CPPScope::ScopeClass:
case CPPScope::ScopeNamespace:
// Only class/namespace should be pushed
EnterScopeContext(scope->GetParentScope(), false);
break;
}
}
} else {
// Push a "resolved" empty scope
EnterScope(emptyScope, true);
}
// Look for a class or class template by that name
CPPTypeRefI classType;
if (scope->GetParentScope().get() != 0)
{
CPPDeclRefI theDecl;
theDecl = scope->GetParentScope()->FindClassDeclByName(scope->GetName());
if (theDecl.get() != 0)
{
classType = theDecl->GetType();
} else {
// try for a templated class
theDecl = scope->GetParentScope()->FindTemplatedDeclByName(scope->GetName());
if (theDecl->IsType())
{
classType = theDecl->GetType()->StripTemplateModifiers();
if (classType->GetFlavor() != CPPType::Class)
{
classType = (CPPType*)0;
}
}
}
}
if (classType.get() != 0)
{
// Recursively push the base classes for the class on the stack.
EnterClassScope(classType, false);
} else {
EnterScope(scope, false);
}
}
/////////////////////////////////////////////////////////////////////
// EnterResolvedGlobalScope: Start a new global scope for qualifying names.
//
// Inputs: none
// Outputs: none
// Return: none
//
// Note: Used when a qualified name is being parsed, like:
// int x;
// class A { A(); int x; };
// A::A() { x = ::x; }
// To make sure that "::x" only searches the global scope.
//
// Note: Use SaveScope/Restore scope to pop this scope when finished.
/////////////////////////////////////////////////////////////////////
// virtual
void
CPPSymTable::EnterResolvedGlobalScope()
{
EnterScope(globalScope, true);
}
/////////////////////////////////////////////////////////////////////
// EnterLocalScope: Start a new scope for code blocks, including
// function definitions
//
// Inputs: none
// Outputs: none
// Return: none
//
// Note: Use SaveScope/Restore scope to pop this scope when finished.
/////////////////////////////////////////////////////////////////////
// virtual
void
CPPSymTable::EnterLocalScope()
{
EnterScope(
new CPPScopeNormal(CPPScope::ScopeLocal, ""),
false
);
}
/////////////////////////////////////////////////////////////////////
// EnterLocalScope: Start a new scope to hold template declarations.
//
// Inputs: none
// Outputs: none
// Return: none
//
// Note: Use SaveScope/Restore scope to pop this scope when finished.
/////////////////////////////////////////////////////////////////////
// virtual
void
CPPSymTable::EnterWorkScope()
{
EnterScope(
new CPPScopeNormal(CPPScope::ScopeWork, ""),
false
);
}
/////////////////////////////////////////////////////////////////////
// EnterScope: Push the given scope on the scope stack.
//
// Inputs:
// CPPScopeRefI scope The scope to enter
// bool resolved true to enter scope in resolved mode
//
// Outputs: none
// Return: none
//
// Note: Use SaveScope/Restore scope to pop this scope when finished.
/////////////////////////////////////////////////////////////////////
void
CPPSymTable::EnterScope(
const CPPScopeRefI& scope,
bool resolved
)
{
// The top of the stack is the front of the list
scopeStack->push_front(
CPPScopeLevel(
scope,
resolved
)
);
}
/////////////////////////////////////////////////////////////////////
// EnterExprScope: Given an expression, find the type of the
// expression; if the type is a class, then enter it's member scope
//
// Inputs:
// CPPExprRefI expr The expression
// bool resolved true to enter scope in resolved mode
//
// Outputs: none
// Return: none
//
// Note: Use SaveScope/Restore scope to pop this scope when finished.
/////////////////////////////////////////////////////////////////////
void
CPPSymTable::EnterExprScope(
CPPExprRefI expr,
bool resolved
)
{
// TODO: Get the expression type and do this for real.
// For now: fake it for id expressions only
CPPTypeRefI exprType = expr->GetType();
if (exprType.get() != 0)
{
// Strip off template, const, volatile and indirection modifiers.
// Only strip one template/indirection
// TODO: this sort of type processing should be centralized
bool strippedTemplate = false;
bool strippedIndirection = false;
bool strippedModifier;
do {
strippedModifier = false;
if (!strippedTemplate && exprType->GetFlavor() == CPPType::Templated)
{
exprType = exprType->GetBaseType();
strippedTemplate = true;
strippedModifier = true;
}
if (!strippedIndirection && exprType->GetFlavor() == CPPType::Indirection)
{
exprType = exprType->GetBaseType();
strippedIndirection = true;
strippedModifier = true;
}
if (exprType->GetFlavor() == CPPType::CVQualified)
{
exprType = exprType->GetBaseType();
strippedModifier = true;
}
} while (strippedModifier);
// After stripping the modifiers, if what's left is a class, then
// enter the class scope;
if (exprType->GetFlavor() == CPPType::Class)
{
EnterClassScope(exprType, resolved);
}
}
}
/////////////////////////////////////////////////////////////////////
// GetEnclosingClassName: Get the name of the enclosing class scope
// if any exists.
//
// Inputs: none
// Outputs: none
// Return:
// const JLStr& The name of the enclosing class scope, or
// the empty string if none exists;
/////////////////////////////////////////////////////////////////////
// virtual
const JLStr&
CPPSymTable::GetEnclosingClassName() const
{
static const JLStr dummy;
// The top of the stack is the front of the list
for (
CPPScopeStack::iterator iter = scopeStack->begin();
iter != scopeStack->end();
iter++
)
{
if ((*iter).GetScope()->GetFlavor() == CPPScope::ScopeClass)
{
return (*iter).GetScope()->GetName();
}
if ((*iter).GetResolved())
{
// Don't search beyond a resolved scope
break;
}
}
return dummy;
}
/////////////////////////////////////////////////////////////////////
// GetCurrentScope: Get the current scope.
//
// Inputs: none
// Outputs: none
// Return:
// CPPScopeRefI The current scope
/////////////////////////////////////////////////////////////////////
// virtual
CPPScopeRefI
CPPSymTable::GetCurrentScope() const
{
return scopeStack->front().GetScope().get();
}
/////////////////////////////////////////////////////////////////////
// GetCurrentScopeName: Get the current scope name
//
// Inputs: none
// Outputs: none
// Return:
// JLStr The current scope name
/////////////////////////////////////////////////////////////////////
// virtual
JLStr
CPPSymTable::GetCurrentScopeName() const
{
return scopeStack->front().GetScope()->GetName();
}
/////////////////////////////////////////////////////////////////////
// SetCurrentScopeAccess: Set the current access for succeeding
// declarations in the scope.
//
// Inputs:
// AccessSpecifier as The next default access.
// Outputs: none
// Return: none
/////////////////////////////////////////////////////////////////////
// virtual
void
CPPSymTable::SetCurrentScopeAccess(
CPPConst::AccessSpecifier as
)
{
scopeStack->front().GetScope()->SetCurrentAccess(as);
}
/////////////////////////////////////////////////////////////////////
// GetCurrentScopeAccess: Get the current access for succeeding
// declarations in the scope.
//
// Inputs: none
// Outputs: none
// Return:
// AccessSpecifier The default access.
/////////////////////////////////////////////////////////////////////
// virtual
CPPConst::AccessSpecifier
CPPSymTable::GetCurrentScopeAccess() const
{
return scopeStack->front().GetScope()->GetCurrentAccess();
}
//////////////////////////////////////////////////////////////////////
// CPPSymTable::GetEnclosingPermanentScope: Get the nearest enclosing
// permanent scope from the scope stack. Note that work scopes are
// considered to be permanent scopes.
//
// Inputs: none
// Outputs: none
// Return:
// CPPScopeRefI The enclosing permanent scope
//////////////////////////////////////////////////////////////////////
CPPScopeRefI
CPPSymTable::GetEnclosingPermanentScope() const
{
// Search the scope stack to find the closest local or global scope
for (
CPPScopeStack::iterator stackIter = scopeStack->begin();
stackIter != scopeStack->end();
stackIter++
)
{
switch ((*stackIter).GetScope()->GetFlavor())
{
case CPPScope::ScopeGlobal:
case CPPScope::ScopeClass:
case CPPScope::ScopeNamespace:
case CPPScope::ScopeWork:
return (*stackIter).GetScope();
default:
break;
}
}
// We should always hit a global scope before we finish
assert(0);
return CPPScopeRefI();
}