blob: 54c7d9bfbceeb89cbcdd1055057c467626ca4e4e [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
#include <precomp.h>
#include "ca_ce.hxx"
// NOT FULLY DEFINED SERVICES
#include <ary/qualiname.hxx>
#include <ary/cpp/inpcontx.hxx>
#include <ary/cpp/c_namesp.hxx>
#include <ary/cpp/c_class.hxx>
#include <ary/cpp/c_enum.hxx>
#include <ary/cpp/c_enuval.hxx>
#include <ary/cpp/c_funct.hxx>
#include <ary/cpp/c_tydef.hxx>
#include <ary/cpp/c_type.hxx>
#include <ary/cpp/c_vari.hxx>
#include <ary/cpp/cp_type.hxx>
#include <ary/loc/loc_file.hxx>
#include <ary/getncast.hxx>
namespace
{
String Get_NewAnonymousNamespaceName();
String Get_NewAnonymousName(
char i_start );
} // anonymous namespace
namespace ary
{
namespace cpp
{
// KORR_FUTURE
// What about namespace visibility ?
// Perhaps handle all/some visibility transfer only after parse is complete.
void
transfer_visibility( const Class * i_owner,
CodeEntity & o_child )
{
if ( i_owner != 0 ? NOT i_owner->IsVisible() : false )
o_child.Set_InVisible();
}
inline const TypePilot &
CeAdmin::Types() const
{
csv_assert(pTypes != 0);
return *pTypes;
}
CeAdmin::CeAdmin(RepositoryPartition & io_myReposyPartition)
: aStorage(),
pTypes(0),
pCppRepositoryPartition(&io_myReposyPartition)
{
}
void
CeAdmin::Set_Related(const TypePilot & i_types)
{
pTypes = &i_types;
}
CeAdmin::~CeAdmin()
{
}
Namespace &
CeAdmin::CheckIn_Namespace( const InputContext & i_context,
const String & i_localName )
{
const String
local_name = NOT i_localName.empty()
? i_localName
: Get_NewAnonymousNamespaceName();
Namespace &
rParent = i_context.CurNamespace();
Namespace *
ret = rParent.Search_LocalNamespace(local_name);
if ( ret == 0 )
{
ret = &Create_Namespace(rParent, local_name);
}
return *ret;
}
Class &
CeAdmin::Store_Class( const InputContext & i_context,
const String & i_localName,
E_ClassKey i_eClassKey )
{
const String
local_name = i_localName.empty()
? Get_NewAnonymousName( i_eClassKey == CK_class
? 'c'
: i_eClassKey == CK_struct
? 's'
: 'u' )
: i_localName;
Class &
ret = * new Class( local_name,
i_context.CurOwner().CeId(),
i_context.CurProtection(),
i_context.CurFile().LeId(),
i_eClassKey );
aStorage.Store_Type(ret);
i_context.CurOwner().Add_Class(local_name, ret.CeId());
transfer_visibility(i_context.CurClass(), ret);
return ret;
}
Enum &
CeAdmin::Store_Enum( const InputContext & i_context,
const String & i_localName )
{
const String
local_name = i_localName.empty()
? Get_NewAnonymousName('e')
: i_localName;
Enum &
ret = * new Enum( local_name,
i_context.CurOwner().CeId(),
i_context.CurProtection(),
i_context.CurFile().LeId() );
aStorage.Store_Type(ret);
i_context.CurOwner().Add_Enum(local_name, ret.CeId());
transfer_visibility(i_context.CurClass(), ret);
return ret;
}
Typedef &
CeAdmin::Store_Typedef( const InputContext& i_context,
const String & i_localName,
Type_id i_referredType )
{
Typedef &
ret = * new Typedef( i_localName,
i_context.CurOwner().CeId(),
i_context.CurProtection(),
i_context.CurFile().LeId(),
i_referredType );
aStorage.Store_Type(ret);
i_context.CurOwner().Add_Typedef(i_localName, ret.CeId());
transfer_visibility(i_context.CurClass(), ret);
return ret;
}
Function *
CeAdmin::Store_Operation( const InputContext & i_context,
const String & i_localName,
Type_id i_returnType,
const std::vector<S_Parameter> & i_parameters,
E_Virtuality i_virtuality,
E_ConVol i_conVol,
FunctionFlags i_flags,
bool i_throwExists,
const std::vector<Type_id> & i_exceptions )
{
Function &
ret = * new Function( i_localName,
i_context.CurOwner().CeId(),
i_context.CurProtection(),
i_context.CurFile().LeId(),
i_returnType,
i_parameters,
i_conVol,
i_virtuality,
i_flags,
i_throwExists,
i_exceptions );
// Check for double declaration:
Ce_id
nAlreadyExistingFunction(0);
switch ( lhf_CheckAndHandle_DuplicateOperation(
nAlreadyExistingFunction,
i_context,
ret) )
{
case df_discard_new:
delete &ret;
return 0;
case df_replace:
csv_assert(nAlreadyExistingFunction.IsValid());
aStorage.Replace_Entity(
nAlreadyExistingFunction,
ret );
break;
case df_no:
aStorage.Store_Operation(ret); // Now it has a valid id.
i_context.CurOwner().Add_Operation( i_localName, ret.CeId(), i_flags.IsStaticMember() );
break;
default:
csv_assert(false);
}
transfer_visibility(i_context.CurClass(), ret);
if ( i_context.CurProtection() != PROTECT_global )
{
Class *
pClass = i_context.CurClass();
if ( pClass != 0 AND i_virtuality != VIRTUAL_none)
{
pClass->UpdateVirtuality(i_virtuality);
}
}
return &ret;
}
Variable &
CeAdmin::Store_Variable( const InputContext& i_context,
const String & i_localName,
Type_id i_type,
VariableFlags i_flags,
const String & i_arraySize,
const String & i_initValue )
{
Variable &
ret = * new Variable( i_localName,
i_context.CurOwner().CeId(),
i_context.CurProtection(),
i_context.CurFile().LeId(),
i_type,
i_flags,
i_arraySize,
i_initValue );
bool
is_const = Types().Find_Type(i_type).IsConst();
aStorage.Store_Datum(ret);
i_context.CurOwner().Add_Variable(
i_localName,
ret.CeId(),
is_const,
i_flags.IsStaticMember() );
transfer_visibility(i_context.CurClass(), ret);
return ret;
}
EnumValue &
CeAdmin::Store_EnumValue( const InputContext & i_context,
const String & i_localName,
const String & i_initValue )
{
Enum *
parent = i_context.CurEnum();
csv_assert( parent != 0 );
EnumValue &
ret = * new EnumValue( i_localName,
parent->CeId(),
i_initValue );
aStorage.Store_Datum(ret);
parent->Add_Value(ret.CeId());
// KORR also for current enum:
transfer_visibility(i_context.CurClass(), ret);
return ret;
}
const Namespace &
CeAdmin::GlobalNamespace() const
{
return ary_cast<Namespace>( aStorage[predefined::ce_GlobalNamespace] );
}
const CodeEntity &
CeAdmin::Find_Ce(Ce_id i_id) const
{
return aStorage[i_id];
}
const CodeEntity *
CeAdmin::Search_Ce(Ce_id i_id) const
{
return aStorage.Exists(i_id)
? & aStorage[i_id]
: (const CodeEntity*)(0);
}
const CodeEntity *
CeAdmin::Search_CeAbsolute( const CodeEntity & i_curScope,
const QualifiedName & i_rSearchedName ) const
{
const symtree::Node<CeNode_Traits> *
cur_node = CeNode_Traits::NodeOf_(i_curScope);
csv_assert(cur_node != 0);
Ce_id
ret(0);
cur_node->SearchUp( ret,
i_rSearchedName.first_namespace(),
i_rSearchedName.end_namespace(),
i_rSearchedName.LocalName() );
return Search_Ce(ret);
}
const CodeEntity *
CeAdmin::Search_CeLocal( const String & i_localName,
bool i_bIsFunction,
const Namespace & i_rCurNamespace,
const Class * i_pCurClass ) const
{
// KORR_FUTURE
// See if this is correct.
Ce_id
ret(0);
if ( NOT i_bIsFunction )
{
CesResultList
type_instances = aStorage.TypeIndex().SearchAll(i_localName);
CesResultList
data_instances = aStorage.DataIndex().SearchAll(i_localName);
Ce_id
ret1 = Search_MatchingInstance(
type_instances,
(i_pCurClass
? i_pCurClass->CeId()
: i_rCurNamespace.CeId())
);
Ce_id
ret2 = Search_MatchingInstance(
data_instances,
(i_pCurClass
? i_pCurClass->CeId()
: i_rCurNamespace.CeId())
);
if (NOT ret2.IsValid())
ret = ret1;
else if (NOT ret1.IsValid())
ret = ret2;
}
else
{
CesResultList
function_instances = aStorage.OperationIndex().SearchAll(i_localName);
if ( function_instances.size() == 1 )
ret = *function_instances.begin();
else
{
ret = Search_MatchingInstance(
function_instances,
(i_pCurClass
? i_pCurClass->CeId()
: i_rCurNamespace.CeId())
);
}
}
if ( ret.IsValid() )
return & Find_Ce(ret);
return 0;
}
void
CeAdmin::Get_QualifiedName( StreamStr & o_rOut,
const String & i_localName,
Ce_id i_nOwner,
const char * i_sDelimiter ) const
{
if ( i_localName.empty() OR NOT i_nOwner.IsValid() )
return;
const CodeEntity *
pOwner = & Find_Ce( i_nOwner );
if ( is_type<Enum>(*pOwner) )
pOwner = &Find_Ce( Ce_id(pOwner->Owner()) );
Get_QualifiedName( o_rOut,
pOwner->LocalName(),
Ce_id(pOwner->Owner()),
i_sDelimiter );
o_rOut
<< i_sDelimiter
<< i_localName;
}
void
CeAdmin::Get_SignatureText( StreamStr & o_rOut,
const OperationSignature & i_signature,
const StringVector * i_sParameterNames ) const
{
OperationSignature::ParameterTypeList::const_iterator
it = i_signature.Parameters().begin();
OperationSignature::ParameterTypeList::const_iterator
it_end = i_signature.Parameters().end();
const StringVector aDummy;
StringVector::const_iterator
itName = i_sParameterNames != 0
? i_sParameterNames->begin()
: aDummy.begin();
StringVector::const_iterator
itName_end = i_sParameterNames != 0
? i_sParameterNames->end()
: aDummy.end();
bool
bEmpty = (it == it_end);
if (NOT bEmpty)
{
o_rOut << "( ";
Types().Get_TypeText(o_rOut, *it);
if (itName != itName_end)
o_rOut << " " << (*itName);
for ( ++it; it != it_end; ++it )
{
o_rOut << ", ";
Types().Get_TypeText(o_rOut, *it);
if (itName != itName_end)
{
++itName;
if (itName != itName_end)
o_rOut << " " << (*itName);
}
}
o_rOut << " )";
}
else
{
o_rOut << "( )";
}
if ( intt(i_signature.ConVol()) & intt(ary::cpp::CONVOL_const) )
o_rOut << " const";
if ( intt(i_signature.ConVol()) & intt(ary::cpp::CONVOL_volatile) )
o_rOut << " volatile";
}
CesResultList
CeAdmin::Search_TypeName(const String & i_sName) const
{
return aStorage.TypeIndex().SearchAll(i_sName);
}
Namespace &
CeAdmin::GlobalNamespace()
{
return ary_cast<Namespace>( aStorage[predefined::ce_GlobalNamespace] );
}
CeAdmin::E_DuplicateFunction
CeAdmin::lhf_CheckAndHandle_DuplicateOperation(
Ce_id & o_existentFunction,
const InputContext & i_context,
const Function & i_newFunction )
{
if (i_context.CurProtection() != PROTECT_global)
{
// Assume, there will be no duplicates within the same class.
// KORR_FUTURE
// Assumption may be wrong in case of #defines providing different
// versions for different compilers.
return df_no;
}
std::vector<Ce_id>
aOperationsWithSameName;
i_context.CurNamespace().Search_LocalOperations(
aOperationsWithSameName,
i_newFunction.LocalName() );
for ( std::vector<Ce_id>::const_iterator
it = aOperationsWithSameName.begin();
it != aOperationsWithSameName.end();
++it )
{
const Function &
rFunction = ary_cast<Function>(aStorage[*it]);
if ( rFunction.LocalName() == i_newFunction.LocalName()
AND rFunction.Signature() == i_newFunction.Signature() )
{
if (NOT rFunction.IsIdentical(i_newFunction))
{
// KORR_FUTURE Make this more detailed.
Cerr() << "Non identical function with same signature "
<< "found: "
<< i_context.CurNamespace().LocalName()
<< "::"
<< i_newFunction.LocalName()
<< "(..)"
<< Endl();
}
o_existentFunction = rFunction.CeId();
if (rFunction.Docu().Data() == 0)
return df_replace;
else
return df_discard_new;
}
} // end for
return df_no;
}
Namespace &
CeAdmin::Create_Namespace( Namespace & o_parent,
const String & i_localName )
{
DYN Namespace &
ret = *new Namespace(i_localName, o_parent);
aStorage.Store_Entity(ret);
o_parent.Add_LocalNamespace(ret);
return ret;
}
Ce_id
CeAdmin::Search_MatchingInstance( CesResultList i_list,
Ce_id i_owner ) const
{
// KORR
// Multiple results?
for ( CesList::const_iterator it = i_list.begin();
it != i_list.end();
++it )
{
const CodeEntity &
ce = aStorage[*it];
if ( ce.Owner() == i_owner)
{
return *it;
}
}
return Ce_id(0);
}
} // namespace cpp
} // namespace ary
namespace
{
uintt G_nLastFreeAnonymousNamespaceNr = 0;
uintt G_nLastFreeAnonymousEntityNr = 0;
String
Get_NewAnonymousNamespaceName()
{
StreamLock
sl(100);
return String( sl()
<< "namespace_anonymous_"
<< ++G_nLastFreeAnonymousNamespaceNr
<< csv::c_str );
}
String
Get_NewAnonymousName(char i_cStart)
{
StreamLock
sl(100);
return String( sl()
<< i_cStart
<< "_Anonymous__"
<< ++G_nLastFreeAnonymousEntityNr
<< c_str );
}
} // namespace anonymous