700 lines
25 KiB
C++
700 lines
25 KiB
C++
|
|
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
Copyright (c) 1989-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
CopyTo.cxx
|
|
|
|
Abstract:
|
|
|
|
cloning routines
|
|
|
|
Notes:
|
|
|
|
|
|
Author:
|
|
|
|
NishadM Sep-29-1997 Created.
|
|
|
|
Notes:
|
|
|
|
|
|
----------------------------------------------------------------------------*/
|
|
|
|
// unreferenced inline/local function has been removed
|
|
#pragma warning ( disable : 4514 )
|
|
|
|
// includes
|
|
#include "nodeskl.hxx"
|
|
#include "attrnode.hxx"
|
|
#include "acfattr.hxx"
|
|
#include "idict.hxx"
|
|
|
|
// externs
|
|
extern SymTable* pBaseSymTbl;
|
|
|
|
// constants
|
|
const char* const szAsyncIntfPrefix = "Async";
|
|
const unsigned int uAsyncIntfPrefixLen = 5;
|
|
const char* const szFinishProcPrefix = "Finish_";
|
|
const unsigned int uFinishProcPrefixLen = 7;
|
|
const char* const szBeginProcPrefix = "Begin_";
|
|
const unsigned int uBeginProcPrefixLen = 6;
|
|
|
|
// forwards
|
|
extern IDICT* pInterfaceDict;
|
|
|
|
void
|
|
FixupCallAs (
|
|
node_call_as*,
|
|
ITERATOR&
|
|
);
|
|
node_interface*
|
|
DuplicateNodeInterface (
|
|
node_interface* pIntfSrc,
|
|
const char* const szPrefix,
|
|
unsigned short uPrefixLen
|
|
);
|
|
node_proc*
|
|
DuplicateNodeProc (
|
|
node_proc* pProcSrc,
|
|
const char* const szPrefix,
|
|
unsigned uPrefixLen,
|
|
unsigned long uInterfaceKey,
|
|
ITERATOR& Itr
|
|
);
|
|
node_param*
|
|
DuplicateNodeParam (
|
|
node_param* pParamSrc,
|
|
node_proc* pProc
|
|
);
|
|
node_skl*
|
|
FindInOnlyParamInExpr (
|
|
expr_node* pExpr
|
|
);
|
|
node_skl*
|
|
GetInOnlyParamPairedWithOut (
|
|
MEM_ITER& MemParamList
|
|
);
|
|
void
|
|
FixupBeginProcExpr (
|
|
expr_node* pExpr
|
|
);
|
|
|
|
void
|
|
FixupFinishProcExpr (
|
|
expr_node* pExpr
|
|
);
|
|
void
|
|
TraverseParamsAndExprs (
|
|
MEM_ITER& MemParamList,
|
|
void (*CallFunc)( expr_node* )
|
|
);
|
|
|
|
// routines
|
|
|
|
/****************************************************************************
|
|
CloneIFAndSplitMethods:
|
|
Given an interface, copy it and split the methods for async. e.g.
|
|
method IFoo::Foo becomes AsyncIFoo::Begin_Bar and AsyncIFoo::Finish_Bar.
|
|
****************************************************************************/
|
|
node_interface*
|
|
CloneIFAndSplitMethods (
|
|
node_interface* pSrc
|
|
)
|
|
{
|
|
node_interface* pAsyncIntf = DuplicateNodeInterface (
|
|
pSrc,
|
|
szAsyncIntfPrefix,
|
|
uAsyncIntfPrefixLen
|
|
) ;
|
|
|
|
if ( pAsyncIntf )
|
|
{
|
|
// for [call_as] fixups
|
|
ITERATOR BeginProcList;
|
|
ITERATOR FinishProcList;
|
|
|
|
// each IFoo::Bar() becomes,
|
|
named_node* pNodeProcItr = 0;
|
|
named_node* pPrevSibling = 0;
|
|
MEM_ITER MemList( pSrc );
|
|
while ( ( pNodeProcItr = MemList.GetNext() ) != 0 )
|
|
{
|
|
if ( pNodeProcItr->NodeKind() == NODE_PROC )
|
|
{
|
|
// AsyncIFoo::Begin_Bar()
|
|
node_proc* pProcBegin = DuplicateNodeProc (
|
|
(node_proc*)pNodeProcItr,
|
|
szBeginProcPrefix,
|
|
uBeginProcPrefixLen,
|
|
CurrentIntfKey,
|
|
BeginProcList
|
|
);
|
|
pProcBegin->SetIsBeginProc();
|
|
if ( pPrevSibling )
|
|
{
|
|
pPrevSibling->SetSibling( pProcBegin );
|
|
}
|
|
else
|
|
{
|
|
pAsyncIntf->SetFirstMember( pProcBegin );
|
|
}
|
|
|
|
// AsyncIFoo::Finish_Bar()
|
|
node_proc* pProcFinish = DuplicateNodeProc (
|
|
(node_proc*)pNodeProcItr,
|
|
szFinishProcPrefix,
|
|
uFinishProcPrefixLen,
|
|
CurrentIntfKey,
|
|
FinishProcList
|
|
);
|
|
pProcFinish->SetIsFinishProc();
|
|
pProcFinish->SetBeginProc( pProcBegin );
|
|
pProcBegin->SetSibling( pProcFinish );
|
|
pPrevSibling = pProcFinish;
|
|
|
|
// AsyncIFoo::Begin_Bar() gets all [in] params of IFoo::Bar() &
|
|
// AsyncIFoo::Finish_Bar() gets all [out] params IFoo::Bar().
|
|
MEM_ITER MemParamList( (node_proc*)pNodeProcItr );
|
|
named_node* pNodeParamItr = 0;
|
|
MemParamList.Init();
|
|
while ( ( pNodeParamItr = (node_param *) MemParamList.GetNext() ) != 0 )
|
|
{
|
|
// if parameter has [in] or, does not have either [in] or [out] attributes
|
|
// assume [in] by default
|
|
if ( pNodeParamItr->FInSummary( ATTR_IN ) ||
|
|
!( pNodeParamItr->FInSummary( ATTR_IN ) || pNodeParamItr->FInSummary( ATTR_OUT ) ) )
|
|
{
|
|
( (node_param*) pNodeParamItr )->SetAsyncBeginSibling (
|
|
DuplicateNodeParam( (node_param*)pNodeParamItr, pProcBegin )
|
|
);
|
|
}
|
|
if ( pNodeParamItr->FInSummary( ATTR_OUT )
|
|
// || ( (node_param *) pNodeParamItr )->IsTaggedForAsyncFinishParamList()
|
|
)
|
|
{
|
|
( (node_param*) pNodeParamItr )->SetAsyncFinishSibling (
|
|
DuplicateNodeParam( (node_param*)pNodeParamItr, pProcFinish )
|
|
);
|
|
}
|
|
}
|
|
// fix up expr in Begin_* and Finish_*
|
|
MEM_ITER BeginProcParamList( pProcBegin );
|
|
TraverseParamsAndExprs( BeginProcParamList, FixupBeginProcExpr );
|
|
|
|
MEM_ITER FinishProcParamList( pProcFinish );
|
|
TraverseParamsAndExprs( FinishProcParamList, FixupFinishProcExpr );
|
|
}
|
|
}
|
|
// [call_as] fixups
|
|
// [call_as(Baz)] IFoo::Bar() becomes,
|
|
// [call_as(Begin_Baz)] AsyncIFoo::Begin_Bar()
|
|
// [call_as(Finish_Baz)] AsyncIFoo::Finish_Bar()
|
|
MEM_ITER AsyncMemList( pAsyncIntf );
|
|
AsyncMemList.Init();
|
|
while ( ( pNodeProcItr = AsyncMemList.GetNext() ) != 0 )
|
|
{
|
|
node_call_as* pCallAs = ( node_call_as* )pNodeProcItr->GetAttribute( ATTR_CALL_AS );
|
|
|
|
if ( pCallAs )
|
|
{
|
|
FixupCallAs( pCallAs, BeginProcList );
|
|
pNodeProcItr = AsyncMemList.GetNext();
|
|
// if Begin_* has [call_as] Finish_* has it too.
|
|
pCallAs = ( node_call_as* )pNodeProcItr->GetAttribute( ATTR_CALL_AS );
|
|
FixupCallAs( pCallAs, FinishProcList );
|
|
}
|
|
}
|
|
}
|
|
return pAsyncIntf;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
DuplicateNodeInterface:
|
|
Duplicate an interface changing it's name from IFoo to AsyncIFoo and
|
|
changing the [async_uuid] attribute to [uuid]
|
|
****************************************************************************/
|
|
node_interface*
|
|
DuplicateNodeInterface (
|
|
node_interface* pIntfSrc,
|
|
const char* const szPrefix,
|
|
unsigned short uPrefixLen
|
|
)
|
|
{
|
|
node_interface* pIntfDup = new node_interface;
|
|
if ( pIntfDup )
|
|
{
|
|
*pIntfDup = *pIntfSrc;
|
|
// new named_node get a new copy of the attributes
|
|
pIntfDup->CopyAttributes( pIntfSrc );
|
|
// members will be added later
|
|
pIntfDup->SetFirstMember( 0 );
|
|
|
|
// async interface inherits from base interface's async clone
|
|
node_interface* pSrcBase = pIntfSrc->GetMyBaseInterface();
|
|
if ( pSrcBase && pSrcBase->GetAsyncInterface() )
|
|
{
|
|
pIntfDup->SetMyBaseInterfaceReference (
|
|
new node_interface_reference(
|
|
pSrcBase->GetAsyncInterface()
|
|
)
|
|
);
|
|
}
|
|
|
|
// [async_uuid] becomes [uuid]
|
|
node_guid* pAsyncGuid = (node_guid*) pIntfSrc->GetAttribute( ATTR_ASYNCUUID );
|
|
char* szGuid = new char[strlen(pAsyncGuid->GetGuidString())+1];
|
|
strcpy( szGuid, pAsyncGuid->GetGuidString() );
|
|
pIntfDup->RemoveAttribute( ATTR_GUID );
|
|
pIntfDup->RemoveAttribute( ATTR_ASYNCUUID );
|
|
pIntfDup->SetAttribute( new node_guid( szGuid, ATTR_GUID ) );
|
|
|
|
// IFoo becomes AsyncIFoo
|
|
char* szName = new char[strlen(pIntfSrc->GetSymName())+uPrefixLen+1];
|
|
strcpy( szName, szPrefix );
|
|
strcat( szName, pIntfSrc->GetSymName() );
|
|
pIntfDup->SetSymName( szName );
|
|
|
|
// AsyncIFoo added to the list of interfaces
|
|
pIntfDup->SetSibling( pIntfSrc->GetSibling() );
|
|
pIntfSrc->SetSibling( pIntfDup );
|
|
|
|
CurrentIntfKey = (unsigned short) pInterfaceDict->AddElement( pIntfDup );
|
|
|
|
SymKey SKey( pIntfDup->GetSymName(), NAME_DEF );
|
|
named_node* pFound = pBaseSymTbl->SymSearch( SKey );
|
|
if ( pFound )
|
|
{
|
|
pFound->SetChild( pIntfDup );
|
|
}
|
|
}
|
|
return pIntfDup;
|
|
}
|
|
|
|
/****************************************************************************
|
|
DuplicateNodeProc
|
|
Duplicate a node_proc and prefix it's name with the given string.
|
|
Only the procedure node is duplicated, parameters are not set.
|
|
****************************************************************************/
|
|
node_proc*
|
|
DuplicateNodeProc (
|
|
node_proc* pProcSrc,
|
|
const char* const szPrefix,
|
|
unsigned uPrefixLen,
|
|
unsigned long uInterfaceKey,
|
|
ITERATOR& Itr
|
|
)
|
|
{
|
|
node_proc* pProcDup = new node_proc( short( 0 ), true );
|
|
// pProcSrc->CopyTo( pProcDup );
|
|
*pProcDup = *pProcSrc;
|
|
pProcDup->SetSibling( 0 );
|
|
pProcDup->SetClientCorrelationCount();
|
|
pProcDup->SetServerCorrelationCount();
|
|
// new named_node get a new copy of the attributes
|
|
pProcDup->CopyAttributes( pProcSrc );
|
|
// members will be added later
|
|
pProcDup->SetFirstMember( 0 );
|
|
pProcDup->SetInterfaceKey( uInterfaceKey );
|
|
char* szName = new char[strlen(pProcSrc->GetSymName())+uPrefixLen+1];
|
|
strcpy( szName, szPrefix );
|
|
strcat( szName, pProcSrc->GetSymName() );
|
|
pProcDup->SetSymName( szName );
|
|
ITERATOR_INSERT( Itr, pProcDup );
|
|
return pProcDup;
|
|
}
|
|
|
|
/****************************************************************************
|
|
DuplicateNodeParam:
|
|
Duplicate the given parameter and attach it to the given procedure.
|
|
****************************************************************************/
|
|
node_param*
|
|
DuplicateNodeParam (
|
|
node_param* pParamSrc,
|
|
node_proc* pProc
|
|
)
|
|
{
|
|
node_param* pParamDup = new node_param;
|
|
// pParamSrc->CopyTo( pParamDup );
|
|
*pParamDup = *pParamSrc;
|
|
pParamDup->SetSibling( 0 );
|
|
// new named_node get a new copy of the attributes
|
|
pParamDup->CopyAttributes( pParamSrc );
|
|
pProc->AddLastMember( pParamDup );
|
|
return pParamDup;
|
|
}
|
|
|
|
/****************************************************************************
|
|
FixupCallAs:
|
|
When an async interface is created from a sync one the duplicated
|
|
interface still points to stuff in the original interface. Fix up [call_as]
|
|
procs to point to the split procedures instead.
|
|
****************************************************************************/
|
|
void
|
|
FixupCallAs( node_call_as* pCallAs, ITERATOR& ProcList )
|
|
{
|
|
char* szProcName = pCallAs->GetCallAsName();
|
|
node_proc* pProcItr = 0;
|
|
|
|
ITERATOR_INIT( ProcList );
|
|
while ( ITERATOR_GETNEXT( ProcList, pProcItr ) )
|
|
{
|
|
// advance past Begin_ or Finish_
|
|
char* szProcItrName = pProcItr->GetSymName();
|
|
szProcItrName = strchr( szProcItrName, '_' );
|
|
szProcItrName++;
|
|
// semantic errors will be caught in node_proc::SemanticAnalysis()
|
|
if ( !strcmp( szProcItrName, szProcName ) )
|
|
{
|
|
pCallAs->SetCallAsName( pProcItr->GetSymName() );
|
|
pCallAs->SetCallAsType( pProcItr );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
FindInOnlyParamInExpr:
|
|
Search an expression for an in-only parameter.
|
|
****************************************************************************/
|
|
node_skl*
|
|
FindInOnlyParamInExpr (
|
|
expr_node* pExpr
|
|
)
|
|
{
|
|
node_skl* pRet = 0;
|
|
if ( pExpr )
|
|
{
|
|
if ( pExpr->IsAVariable() )
|
|
{
|
|
if ( !pExpr->GetType()->FInSummary( ATTR_OUT ) )
|
|
pRet = pExpr->GetType();
|
|
}
|
|
else
|
|
{
|
|
pRet = FindInOnlyParamInExpr( pExpr->GetLeft() );
|
|
if ( !pRet )
|
|
{
|
|
pRet = FindInOnlyParamInExpr( pExpr->GetRight() );
|
|
}
|
|
}
|
|
}
|
|
return pRet;
|
|
}
|
|
|
|
/****************************************************************************
|
|
GetUnknownExpression:
|
|
Determine if a given expression is a non-simple with in parameters.
|
|
An expression is simple if it is NULL, a constant, or a single variable.
|
|
An expression is also simple if it is of the form "var+1", "var-1",
|
|
"var*2", "var/2", or "*var" (these are simple because they can be
|
|
expressed by directly in the correlation descriptor).
|
|
|
|
If the expression is non-simple with in parameters, non-0 is returned,
|
|
else 0 is returned.
|
|
****************************************************************************/
|
|
bool
|
|
IsSimpleExpression(
|
|
expr_node* pExpr
|
|
)
|
|
{
|
|
if ( ! pExpr || pExpr->IsAVariable() || pExpr->IsConstant() )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
expr_node* pExprLHS = pExpr->GetLeft();
|
|
expr_node* pExprRHS = pExpr->GetRight();
|
|
|
|
switch ( pExpr->GetOperator() )
|
|
{
|
|
case OP_SLASH:
|
|
case OP_STAR:
|
|
if ( pExprLHS->IsAVariable() &&
|
|
pExprRHS->IsConstant() &&
|
|
((expr_constant *)pExprRHS)->GetValue() == 2 )
|
|
{
|
|
return true;
|
|
}
|
|
break;
|
|
|
|
case OP_PLUS :
|
|
case OP_MINUS :
|
|
if ( pExprLHS->IsAVariable() &&
|
|
pExprRHS->IsConstant() &&
|
|
((expr_constant *)pExprRHS)->GetValue() == 1 )
|
|
{
|
|
return true;
|
|
}
|
|
break;
|
|
|
|
case OP_UNARY_INDIRECTION :
|
|
if ( pExprLHS->IsAVariable() )
|
|
{
|
|
return true;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/****************************************************************************
|
|
GetInOnlyParamPairedWithOut:
|
|
Determine if any of the expression in the given parameter list mixes
|
|
in and out parameters in non-simple ways. Return non-0 if the do and 0
|
|
if they don't.
|
|
****************************************************************************/
|
|
node_skl*
|
|
GetInOnlyParamPairedWithOut (
|
|
MEM_ITER& MemParamList
|
|
)
|
|
{
|
|
named_node* pNodeParamItr = 0;
|
|
node_skl* pNode = 0;
|
|
MemParamList.Init();
|
|
while ( ( pNodeParamItr = (node_param *) MemParamList.GetNext() ) != 0 )
|
|
{
|
|
if ( !pNodeParamItr->GetAttribute( ATTR_OUT ) )
|
|
{
|
|
continue;
|
|
}
|
|
node_base_attr* pAttr;
|
|
ATTRLIST AList = pNodeParamItr->GetAttributeList(AList);
|
|
ATTR_T lastAttrID = ATTR_NONE;
|
|
int nAttrInstance = 0;
|
|
bool bFirstInstanceWasNull = false;
|
|
bool bHasInParam = false;
|
|
|
|
for ( pAttr = AList.GetFirst(); NULL != pAttr && 0 == pNode; pAttr = pAttr->GetNext() )
|
|
{
|
|
ATTR_T thisAttrID = pAttr->GetAttrID();
|
|
|
|
if ( thisAttrID == lastAttrID )
|
|
++nAttrInstance;
|
|
else
|
|
nAttrInstance = 1;
|
|
|
|
lastAttrID = thisAttrID;
|
|
|
|
switch ( thisAttrID )
|
|
{
|
|
case ATTR_SIZE:
|
|
case ATTR_LENGTH:
|
|
case ATTR_SWITCH_IS:
|
|
case ATTR_IID_IS:
|
|
case ATTR_FIRST:
|
|
case ATTR_LAST:
|
|
case ATTR_MAX:
|
|
case ATTR_MIN:
|
|
{
|
|
if ( 1 == nAttrInstance )
|
|
{
|
|
bFirstInstanceWasNull = ( NULL == pAttr->GetExpr() );
|
|
bHasInParam = false;
|
|
}
|
|
|
|
// Don't allow any dimensions after one with an in param
|
|
if ( bHasInParam )
|
|
{
|
|
pNode = (node_skl *) -1;
|
|
break;
|
|
}
|
|
|
|
if ( FindInOnlyParamInExpr( pAttr->GetExpr() ) )
|
|
{
|
|
if ( ! IsSimpleExpression( pAttr->GetExpr() )
|
|
|| ( nAttrInstance > 2 )
|
|
|| ( nAttrInstance == 2 && ! bFirstInstanceWasNull ) )
|
|
{
|
|
pNode = (node_skl *) -1;
|
|
break;
|
|
}
|
|
|
|
bHasInParam = true;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ATTR_BYTE_COUNT:
|
|
{
|
|
pNode = ( ( node_byte_count* ) pAttr )->GetByteCountParam();
|
|
if ( pNode->FInSummary( ATTR_OUT ) )
|
|
{
|
|
pNode = 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
default:
|
|
// Only need to worry about attributes with parameter
|
|
// expressions
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( pNode )
|
|
{
|
|
// Do this to have an error message context.
|
|
pNode = pNodeParamItr;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return pNode;
|
|
}
|
|
|
|
/****************************************************************************
|
|
FixupFinishProcExpr:
|
|
When an async interface is created from a sync one the duplicated
|
|
interface still points to stuff in the original interface. Fix up
|
|
parameters in a Finish method to point to the duplicated parameters
|
|
in the async interface instead of the original sync interface.
|
|
****************************************************************************/
|
|
void
|
|
FixupFinishProcExpr (
|
|
expr_node* pExpr
|
|
)
|
|
{
|
|
if ( pExpr )
|
|
{
|
|
// If we don't have a type then that means we have a reference to a
|
|
// variable that doesn't exist. The dangling reference will be caught
|
|
// and reported in FIELD_ATTR_INFO::Validate
|
|
|
|
if ( NULL == pExpr->GetType() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( pExpr->GetType()->NodeKind() == NODE_PARAM )
|
|
{
|
|
node_param* pParam = (node_param*)pExpr->GetType();
|
|
if ( pParam->GetAsyncFinishSibling() )
|
|
{
|
|
pExpr->SetType( pParam->GetAsyncFinishSibling() );
|
|
}
|
|
else
|
|
{
|
|
pExpr->SetType( pParam->GetAsyncBeginSibling() );
|
|
pParam->GetAsyncBeginSibling()->SaveForAsyncFinish();
|
|
}
|
|
}
|
|
FixupFinishProcExpr( pExpr->GetLeft() );
|
|
FixupFinishProcExpr( pExpr->GetRight() );
|
|
// FixupFinishProcExpr( pExpr->GetRelational() );
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
FixupFinishProcExpr:
|
|
When an async interface is created from a sync one the duplicated
|
|
interface still points to stuff in the original interface. Fix up
|
|
parameters in a Begin method to point to the duplicated parameters
|
|
in the async interface instead of the original sync interface.
|
|
****************************************************************************/
|
|
void
|
|
FixupBeginProcExpr (
|
|
expr_node* pExpr
|
|
)
|
|
{
|
|
if ( pExpr )
|
|
{
|
|
// If we don't have a type then that means we have a reference to a
|
|
// variable that doesn't exist. The dangling reference will be caught
|
|
// and reported in FIELD_ATTR_INFO::Validate
|
|
|
|
if ( NULL == pExpr->GetType() )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( pExpr->GetType()->NodeKind() == NODE_PARAM )
|
|
{
|
|
node_param* pParam = (node_param*)pExpr->GetType();
|
|
pExpr->SetType( pParam->GetAsyncBeginSibling() );
|
|
}
|
|
FixupBeginProcExpr( pExpr->GetLeft() );
|
|
FixupBeginProcExpr( pExpr->GetRight() );
|
|
// FixupExpr( pExpr->GetRelational() );
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
FixupFinishProcExpr:
|
|
When an async interface is created from a sync one the duplicated
|
|
interface still points to stuff in the original interface. This routine
|
|
traverses the parameters and fixes up the pointers to point to the
|
|
proper stuff in the duplicated interface instead.
|
|
|
|
This routine is quite specific to the needs of async and is not meant as
|
|
a general purpose parameter traversing function.
|
|
****************************************************************************/
|
|
void
|
|
TraverseParamsAndExprs (
|
|
MEM_ITER& MemParamList,
|
|
void (*CallFunc)( expr_node* )
|
|
)
|
|
{
|
|
node_param* pNodeParamItr = 0;
|
|
|
|
MemParamList.Init();
|
|
while ( ( pNodeParamItr = ( node_param *) MemParamList.GetNext() ) != 0 )
|
|
{
|
|
node_base_attr* pAttr;
|
|
ATTRLIST AList = pNodeParamItr->GetAttributeList(AList);
|
|
|
|
for ( pAttr = AList.GetFirst(); NULL != pAttr; pAttr = pAttr->GetNext() )
|
|
{
|
|
switch ( pAttr->GetAttrID() )
|
|
{
|
|
case ATTR_SIZE:
|
|
case ATTR_LENGTH:
|
|
case ATTR_SWITCH_IS:
|
|
case ATTR_IID_IS:
|
|
case ATTR_FIRST:
|
|
case ATTR_LAST:
|
|
case ATTR_MAX:
|
|
case ATTR_MIN:
|
|
{
|
|
CallFunc( pAttr->GetExpr() );
|
|
break;
|
|
}
|
|
|
|
case ATTR_BYTE_COUNT:
|
|
{
|
|
node_param* pParam = ( ( node_byte_count* ) pAttr )->GetByteCountParam();
|
|
if ( FixupBeginProcExpr == CallFunc )
|
|
{
|
|
( ( node_byte_count* ) pAttr )->SetByteCountParam( pParam->GetAsyncBeginSibling() );
|
|
}
|
|
else
|
|
{
|
|
if ( pParam->GetAsyncFinishSibling() )
|
|
{
|
|
( ( node_byte_count* ) pAttr )->SetByteCountParam( pParam->GetAsyncFinishSibling() );
|
|
}
|
|
else
|
|
{
|
|
( ( node_byte_count* ) pAttr )->SetByteCountParam( pParam->GetAsyncBeginSibling() );
|
|
pParam->GetAsyncBeginSibling()->SaveForAsyncFinish();
|
|
}
|
|
}
|
|
}
|
|
|
|
default:
|
|
// Only need to worry about attributes with parameter
|
|
// expressions
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|