blob: 4e1b2b901d3100cb557a3afd9dca81500f884ead [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.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_basic.hxx"
#include <basic/sbx.hxx>
#include "sbcomp.hxx"
#include "image.hxx"
#include <limits>
#include <com/sun/star/script/ModuleType.hpp>
// nInc ist die Inkrementgroesse der Puffer
SbiCodeGen::SbiCodeGen( SbModule& r, SbiParser* p, short nInc )
: rMod( r ), aCode( p, nInc )
{
pParser = p;
bStmnt = sal_False;
nLine = 0;
nCol = 0;
nForLevel = 0;
}
sal_uInt32 SbiCodeGen::GetPC()
{
return aCode.GetSize();
}
// Statement merken
void SbiCodeGen::Statement()
{
bStmnt = sal_True;
nLine = pParser->GetLine();
nCol = pParser->GetCol1();
// #29955 Information der for-Schleifen-Ebene
// in oberen Byte der Spalte speichern
nCol = (nCol & 0xff) + 0x100 * nForLevel;
}
// Anfang eines Statements markieren
void SbiCodeGen::GenStmnt()
{
if( bStmnt )
{
bStmnt = sal_False;
Gen( _STMNT, nLine, nCol );
}
}
// Die Gen-Routinen returnen den Offset des 1. Operanden,
// damit Jumps dort ihr Backchain versenken koennen
sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode )
{
#ifdef DBG_UTIL
if( eOpcode < SbOP0_START || eOpcode > SbOP0_END )
pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE1" );
#endif
GenStmnt();
aCode += (sal_uInt8) eOpcode;
return GetPC();
}
sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode, sal_uInt32 nOpnd )
{
#ifdef DBG_UTIL
if( eOpcode < SbOP1_START || eOpcode > SbOP1_END )
pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE2" );
#endif
GenStmnt();
aCode += (sal_uInt8) eOpcode;
sal_uInt32 n = GetPC();
aCode += nOpnd;
return n;
}
sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode, sal_uInt32 nOpnd1, sal_uInt32 nOpnd2 )
{
#ifdef DBG_UTIL
if( eOpcode < SbOP2_START || eOpcode > SbOP2_END )
pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE3" );
#endif
GenStmnt();
aCode += (sal_uInt8) eOpcode;
sal_uInt32 n = GetPC();
aCode += nOpnd1;
aCode += nOpnd2;
return n;
}
// Abspeichern des erzeugten Images im Modul
void SbiCodeGen::Save()
{
SbiImage* p = new SbiImage;
rMod.StartDefinitions();
// OPTION BASE-Wert:
p->nDimBase = pParser->nBase;
// OPTION EXPLICIT-Flag uebernehmen
if( pParser->bExplicit )
p->SetFlag( SBIMG_EXPLICIT );
int nIfaceCount = 0;
if( rMod.mnType == com::sun::star::script::ModuleType::CLASS )
{
OSL_TRACE("COdeGen::save() classmodule processing");
rMod.bIsProxyModule = true;
p->SetFlag( SBIMG_CLASSMODULE );
pCLASSFAC->AddClassModule( &rMod );
nIfaceCount = pParser->aIfaceVector.size();
if( !rMod.pClassData )
rMod.pClassData = new SbClassData;
if( nIfaceCount )
{
for( int i = 0 ; i < nIfaceCount ; i++ )
{
const String& rIfaceName = pParser->aIfaceVector[i];
SbxVariable* pIfaceVar = new SbxVariable( SbxVARIANT );
pIfaceVar->SetName( rIfaceName );
SbxArray* pIfaces = rMod.pClassData->mxIfaces;
pIfaces->Insert( pIfaceVar, pIfaces->Count() );
}
}
rMod.pClassData->maRequiredTypes = pParser->aRequiredTypes;
}
else
{
pCLASSFAC->RemoveClassModule( &rMod );
// Only a ClassModule can revert to Normal
if ( rMod.mnType == com::sun::star::script::ModuleType::CLASS )
rMod.mnType = com::sun::star::script::ModuleType::NORMAL;
rMod.bIsProxyModule = false;
}
if( pParser->bText )
p->SetFlag( SBIMG_COMPARETEXT );
// GlobalCode-Flag
if( pParser->HasGlobalCode() )
p->SetFlag( SBIMG_INITCODE );
// Die Entrypoints:
for( SbiSymDef* pDef = pParser->aPublics.First(); pDef;
pDef = pParser->aPublics.Next() )
{
SbiProcDef* pProc = pDef->GetProcDef();
if( pProc && pProc->IsDefined() )
{
String aProcName = pProc->GetName();
String aIfaceProcName;
String aIfaceName;
sal_uInt16 nPassCount = 1;
if( nIfaceCount )
{
int nPropPrefixFound =
aProcName.Search( String( RTL_CONSTASCII_USTRINGPARAM("Property ") ) );
String aPureProcName = aProcName;
String aPropPrefix;
if( nPropPrefixFound == 0 )
{
aPropPrefix = aProcName.Copy( 0, 13 ); // 13 == Len( "Property ?et " )
aPureProcName = aProcName.Copy( 13 );
}
for( int i = 0 ; i < nIfaceCount ; i++ )
{
const String& rIfaceName = pParser->aIfaceVector[i];
int nFound = aPureProcName.Search( rIfaceName );
if( nFound == 0 && '_' == aPureProcName.GetChar( rIfaceName.Len() ) )
{
if( nPropPrefixFound == 0 )
aIfaceProcName += aPropPrefix;
aIfaceProcName += aPureProcName.Copy( rIfaceName.Len() + 1 );
aIfaceName = rIfaceName;
nPassCount = 2;
break;
}
}
}
SbMethod* pMeth = NULL;
for( sal_uInt16 nPass = 0 ; nPass < nPassCount ; nPass++ )
{
if( nPass == 1 )
aProcName = aIfaceProcName;
PropertyMode ePropMode = pProc->getPropertyMode();
if( ePropMode != PROPERTY_MODE_NONE )
{
SbxDataType ePropType = SbxEMPTY;
switch( ePropMode )
{
case PROPERTY_MODE_GET:
ePropType = pProc->GetType();
break;
case PROPERTY_MODE_LET:
{
// type == type of first parameter
ePropType = SbxVARIANT; // Default
SbiSymPool* pPool = &pProc->GetParams();
if( pPool->GetSize() > 1 )
{
SbiSymDef* pPar = pPool->Get( 1 );
if( pPar )
ePropType = pPar->GetType();
}
break;
}
case PROPERTY_MODE_SET:
ePropType = SbxOBJECT;
break;
case PROPERTY_MODE_NONE:
DBG_ERROR( "Illegal PropertyMode PROPERTY_MODE_NONE" );
break;
}
String aPropName = pProc->GetPropName();
if( nPass == 1 )
aPropName = aPropName.Copy( aIfaceName.Len() + 1 );
SbProcedureProperty* pProcedureProperty = NULL;
pProcedureProperty = rMod.GetProcedureProperty( aPropName, ePropType );
}
if( nPass == 1 )
{
SbIfaceMapperMethod* pMapperMeth = NULL;
pMapperMeth = rMod.GetIfaceMapperMethod( aProcName, pMeth );
}
else
{
pMeth = rMod.GetMethod( aProcName, pProc->GetType() );
// #110004
if( !pProc->IsPublic() )
pMeth->SetFlag( SBX_PRIVATE );
// Declare? -> Hidden
if( pProc->GetLib().Len() > 0 )
pMeth->SetFlag( SBX_HIDDEN );
pMeth->nStart = pProc->GetAddr();
pMeth->nLine1 = pProc->GetLine1();
pMeth->nLine2 = pProc->GetLine2();
// Die Parameter:
SbxInfo* pInfo = pMeth->GetInfo();
String aHelpFile, aComment;
sal_uIntPtr nHelpId = 0;
if( pInfo )
{
// Die Zusatzdaten retten
aHelpFile = pInfo->GetHelpFile();
aComment = pInfo->GetComment();
nHelpId = pInfo->GetHelpId();
}
// Und die Parameterliste neu aufbauen
pInfo = new SbxInfo( aHelpFile, nHelpId );
pInfo->SetComment( aComment );
SbiSymPool* pPool = &pProc->GetParams();
// Das erste Element ist immer der Funktionswert!
for( sal_uInt16 i = 1; i < pPool->GetSize(); i++ )
{
SbiSymDef* pPar = pPool->Get( i );
SbxDataType t = pPar->GetType();
if( !pPar->IsByVal() )
t = (SbxDataType) ( t | SbxBYREF );
if( pPar->GetDims() )
t = (SbxDataType) ( t | SbxARRAY );
// #33677 Optional-Info durchreichen
sal_uInt16 nFlags = SBX_READ;
if( pPar->IsOptional() )
nFlags |= SBX_OPTIONAL;
pInfo->AddParam( pPar->GetName(), t, nFlags );
sal_uInt32 nUserData = 0;
sal_uInt16 nDefaultId = pPar->GetDefaultId();
if( nDefaultId )
nUserData |= nDefaultId;
if( pPar->IsParamArray() )
nUserData |= PARAM_INFO_PARAMARRAY;
if( pPar->IsWithBrackets() )
nUserData |= PARAM_INFO_WITHBRACKETS;
if( nUserData )
{
SbxParamInfo* pParam = (SbxParamInfo*)pInfo->GetParam( i );
pParam->nUserData = nUserData;
}
}
pMeth->SetInfo( pInfo );
}
} // for( iPass...
}
}
// Der Code
p->AddCode( aCode.GetBuffer(), aCode.GetSize() );
// Der globale StringPool. 0 ist nicht belegt.
SbiStringPool* pPool = &pParser->aGblStrings;
sal_uInt16 nSize = pPool->GetSize();
p->MakeStrings( nSize );
sal_uInt16 i;
for( i = 1; i <= nSize; i++ )
p->AddString( pPool->Find( i ) );
// Typen einfuegen
sal_uInt16 nCount = pParser->rTypeArray->Count();
for (i = 0; i < nCount; i++)
p->AddType((SbxObject *)pParser->rTypeArray->Get(i));
// Insert enum objects
nCount = pParser->rEnumArray->Count();
for (i = 0; i < nCount; i++)
p->AddEnum((SbxObject *)pParser->rEnumArray->Get(i));
if( !p->IsError() )
rMod.pImage = p;
else
delete p;
rMod.EndDefinitions();
}
template < class T >
class PCodeVisitor
{
public:
virtual ~PCodeVisitor();
virtual void start( sal_uInt8* pStart ) = 0;
virtual void processOpCode0( SbiOpcode eOp ) = 0;
virtual void processOpCode1( SbiOpcode eOp, T nOp1 ) = 0;
virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 ) = 0;
virtual bool processParams() = 0;
virtual void end() = 0;
};
template <class T> PCodeVisitor< T >::~PCodeVisitor()
{}
template <class T>
class PCodeBufferWalker
{
private:
T m_nBytes;
sal_uInt8* m_pCode;
T readParam( sal_uInt8*& pCode )
{
short nBytes = sizeof( T );
T nOp1=0;
for ( int i=0; i<nBytes; ++i )
nOp1 |= *pCode++ << ( i * 8);
return nOp1;
}
public:
PCodeBufferWalker( sal_uInt8* pCode, T nBytes ): m_nBytes( nBytes ), m_pCode( pCode )
{
}
void visitBuffer( PCodeVisitor< T >& visitor )
{
sal_uInt8* pCode = m_pCode;
if ( !pCode )
return;
sal_uInt8* pEnd = pCode + m_nBytes;
visitor.start( m_pCode );
T nOp1 = 0, nOp2 = 0;
for( ; pCode < pEnd; )
{
SbiOpcode eOp = (SbiOpcode)(*pCode++);
if ( eOp <= SbOP0_END )
visitor.processOpCode0( eOp );
else if( eOp >= SbOP1_START && eOp <= SbOP1_END )
{
if ( visitor.processParams() )
nOp1 = readParam( pCode );
else
pCode += sizeof( T );
visitor.processOpCode1( eOp, nOp1 );
}
else if( eOp >= SbOP2_START && eOp <= SbOP2_END )
{
if ( visitor.processParams() )
{
nOp1 = readParam( pCode );
nOp2 = readParam( pCode );
}
else
pCode += ( sizeof( T ) * 2 );
visitor.processOpCode2( eOp, nOp1, nOp2 );
}
}
visitor.end();
}
};
template < class T, class S >
class OffSetAccumulator : public PCodeVisitor< T >
{
T m_nNumOp0;
T m_nNumSingleParams;
T m_nNumDoubleParams;
public:
OffSetAccumulator() : m_nNumOp0(0), m_nNumSingleParams(0), m_nNumDoubleParams(0){}
virtual void start( sal_uInt8* /*pStart*/ ){}
virtual void processOpCode0( SbiOpcode /*eOp*/ ){ ++m_nNumOp0; }
virtual void processOpCode1( SbiOpcode /*eOp*/, T /*nOp1*/ ){ ++m_nNumSingleParams; }
virtual void processOpCode2( SbiOpcode /*eOp*/, T /*nOp1*/, T /*nOp2*/ ) { ++m_nNumDoubleParams; }
virtual void end(){}
S offset()
{
T result = 0 ;
static const S max = std::numeric_limits< S >::max();
result = m_nNumOp0 + ( ( sizeof(S) + 1 ) * m_nNumSingleParams ) + ( (( sizeof(S) * 2 )+ 1 ) * m_nNumDoubleParams );
if ( result > max )
return max;
return static_cast<S>(result);
}
virtual bool processParams(){ return false; }
};
template < class T, class S >
class BufferTransformer : public PCodeVisitor< T >
{
sal_uInt8* m_pStart;
SbiBuffer m_ConvertedBuf;
public:
BufferTransformer():m_pStart(NULL), m_ConvertedBuf( NULL, 1024 ) {}
virtual void start( sal_uInt8* pStart ){ m_pStart = pStart; }
virtual void processOpCode0( SbiOpcode eOp )
{
m_ConvertedBuf += (sal_uInt8)eOp;
}
virtual void processOpCode1( SbiOpcode eOp, T nOp1 )
{
m_ConvertedBuf += (sal_uInt8)eOp;
switch( eOp )
{
case _JUMP:
case _JUMPT:
case _JUMPF:
case _GOSUB:
case _CASEIS:
case _RETURN:
case _ERRHDL:
case _TESTFOR:
nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
break;
case _RESUME:
if ( nOp1 > 1 )
nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
break;
default:
break; //
}
m_ConvertedBuf += (S)nOp1;
}
virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 )
{
m_ConvertedBuf += (sal_uInt8)eOp;
if ( eOp == _CASEIS )
if ( nOp1 )
nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
m_ConvertedBuf += (S)nOp1;
m_ConvertedBuf += (S)nOp2;
}
virtual bool processParams(){ return true; }
virtual void end() {}
// yeuch, careful here, you can only call
// GetBuffer on the returned SbiBuffer once, also
// you (as the caller) get to own the memory
SbiBuffer& buffer()
{
return m_ConvertedBuf;
}
static S convertBufferOffSet( sal_uInt8* pStart, T nOp1 )
{
PCodeBufferWalker< T > aBuff( pStart, nOp1);
OffSetAccumulator< T, S > aVisitor;
aBuff.visitBuffer( aVisitor );
return aVisitor.offset();
}
};
sal_uInt32
SbiCodeGen::calcNewOffSet( sal_uInt8* pCode, sal_uInt16 nOffset )
{
return BufferTransformer< sal_uInt16, sal_uInt32 >::convertBufferOffSet( pCode, nOffset );
}
sal_uInt16
SbiCodeGen::calcLegacyOffSet( sal_uInt8* pCode, sal_uInt32 nOffset )
{
return BufferTransformer< sal_uInt32, sal_uInt16 >::convertBufferOffSet( pCode, nOffset );
}
template <class T, class S>
void
PCodeBuffConvertor<T,S>::convert()
{
PCodeBufferWalker< T > aBuf( m_pStart, m_nSize );
BufferTransformer< T, S > aTrnsfrmer;
aBuf.visitBuffer( aTrnsfrmer );
m_pCnvtdBuf = (sal_uInt8*)aTrnsfrmer.buffer().GetBuffer();
m_nCnvtdSize = static_cast<S>( aTrnsfrmer.buffer().GetSize() );
}
template class PCodeBuffConvertor< sal_uInt16, sal_uInt32 >;
template class PCodeBuffConvertor< sal_uInt32, sal_uInt16 >;