Bump for 4.0-11
[LibreOffice.git] / basic / source / comp / codegen.cxx
blob77542dd58ae9cfbb3d12a51353baa141270603df
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <basic/sbx.hxx>
22 #include "sbcomp.hxx"
23 #include "image.hxx"
24 #include <limits>
25 #include <algorithm>
26 #include <com/sun/star/script/ModuleType.hpp>
28 // nInc is the increment size of the buffers
30 SbiCodeGen::SbiCodeGen( SbModule& r, SbiParser* p, short nInc )
31 : rMod( r ), aCode( p, nInc )
33 pParser = p;
34 bStmnt = false;
35 nLine = 0;
36 nCol = 0;
37 nForLevel = 0;
40 sal_uInt32 SbiCodeGen::GetPC()
42 return aCode.GetSize();
45 // memorize the statement
47 void SbiCodeGen::Statement()
49 bStmnt = true;
51 nLine = pParser->GetLine();
52 nCol = pParser->GetCol1();
54 // #29955 Store the information of the for-loop-layer
55 // in the uppper Byte of the column
56 nCol = (nCol & 0xff) + 0x100 * nForLevel;
59 // Mark the beginning of a statement
61 void SbiCodeGen::GenStmnt()
63 if( bStmnt )
65 bStmnt = false;
66 Gen( _STMNT, nLine, nCol );
70 // The Gen-Routines return the offset of the 1. operand,
71 // so that jumps can sink their backchain there.
73 sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode )
75 #ifdef DBG_UTIL
76 if( eOpcode < SbOP0_START || eOpcode > SbOP0_END )
77 pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE1" );
78 #endif
79 GenStmnt();
80 aCode += (sal_uInt8) eOpcode;
81 return GetPC();
84 sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode, sal_uInt32 nOpnd )
86 #ifdef DBG_UTIL
87 if( eOpcode < SbOP1_START || eOpcode > SbOP1_END )
88 pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE2" );
89 #endif
90 GenStmnt();
91 aCode += (sal_uInt8) eOpcode;
92 sal_uInt32 n = GetPC();
93 aCode += nOpnd;
94 return n;
97 sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode, sal_uInt32 nOpnd1, sal_uInt32 nOpnd2 )
99 #ifdef DBG_UTIL
100 if( eOpcode < SbOP2_START || eOpcode > SbOP2_END )
101 pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE3" );
102 #endif
103 GenStmnt();
104 aCode += (sal_uInt8) eOpcode;
105 sal_uInt32 n = GetPC();
106 aCode += nOpnd1;
107 aCode += nOpnd2;
108 return n;
111 // Storing of the created image in the module
113 void SbiCodeGen::Save()
115 SbiImage* p = new SbiImage;
116 rMod.StartDefinitions();
117 // OPTION BASE-Value:
118 p->nDimBase = pParser->nBase;
119 // OPTION take over the EXPLICIT-Flag
120 if( pParser->bExplicit )
121 p->SetFlag( SBIMG_EXPLICIT );
123 int nIfaceCount = 0;
124 if( rMod.mnType == com::sun::star::script::ModuleType::CLASS )
126 OSL_TRACE("COdeGen::save() classmodule processing");
127 rMod.bIsProxyModule = true;
128 p->SetFlag( SBIMG_CLASSMODULE );
129 GetSbData()->pClassFac->AddClassModule( &rMod );
131 nIfaceCount = pParser->aIfaceVector.size();
132 if( !rMod.pClassData )
133 rMod.pClassData = new SbClassData;
134 if( nIfaceCount )
136 for( int i = 0 ; i < nIfaceCount ; i++ )
138 const OUString& rIfaceName = pParser->aIfaceVector[i];
139 SbxVariable* pIfaceVar = new SbxVariable( SbxVARIANT );
140 pIfaceVar->SetName( rIfaceName );
141 SbxArray* pIfaces = rMod.pClassData->mxIfaces;
142 pIfaces->Insert( pIfaceVar, pIfaces->Count() );
146 rMod.pClassData->maRequiredTypes = pParser->aRequiredTypes;
148 else
150 GetSbData()->pClassFac->RemoveClassModule( &rMod );
151 // Only a ClassModule can revert to Normal
152 if ( rMod.mnType == com::sun::star::script::ModuleType::CLASS )
154 rMod.mnType = com::sun::star::script::ModuleType::NORMAL;
156 rMod.bIsProxyModule = false;
159 // GlobalCode-Flag
160 if( pParser->HasGlobalCode() )
162 p->SetFlag( SBIMG_INITCODE );
164 // Die Entrypoints:
165 for( SbiSymDef* pDef = pParser->aPublics.First(); pDef;
166 pDef = pParser->aPublics.Next() )
168 SbiProcDef* pProc = pDef->GetProcDef();
169 if( pProc && pProc->IsDefined() )
171 OUString aProcName = pProc->GetName();
172 OUString aIfaceProcName;
173 OUString aIfaceName;
174 sal_uInt16 nPassCount = 1;
175 if( nIfaceCount )
177 int nPropPrefixFound = aProcName.indexOf(OUString("Property "));
178 OUString aPureProcName = aProcName;
179 OUString aPropPrefix;
180 if( nPropPrefixFound == 0 )
182 aPropPrefix = aProcName.copy( 0, 13 ); // 13 == Len( "Property ?et " )
183 aPureProcName = aProcName.copy( 13 );
185 for( int i = 0 ; i < nIfaceCount ; i++ )
187 const OUString& rIfaceName = pParser->aIfaceVector[i];
188 int nFound = aPureProcName.indexOf( rIfaceName );
189 if( nFound == 0 && '_' == aPureProcName[rIfaceName.getLength()] )
191 if( nPropPrefixFound == 0 )
193 aIfaceProcName += aPropPrefix;
195 aIfaceProcName += aPureProcName.copy( rIfaceName.getLength() + 1 );
196 aIfaceName = rIfaceName;
197 nPassCount = 2;
198 break;
202 SbMethod* pMeth = NULL;
203 for( sal_uInt16 nPass = 0 ; nPass < nPassCount ; nPass++ )
205 if( nPass == 1 )
207 aProcName = aIfaceProcName;
209 PropertyMode ePropMode = pProc->getPropertyMode();
210 if( ePropMode != PROPERTY_MODE_NONE )
212 SbxDataType ePropType = SbxEMPTY;
213 switch( ePropMode )
215 case PROPERTY_MODE_GET:
216 ePropType = pProc->GetType();
217 break;
218 case PROPERTY_MODE_LET:
220 // type == type of first parameter
221 ePropType = SbxVARIANT; // Default
222 SbiSymPool* pPool = &pProc->GetParams();
223 if( pPool->GetSize() > 1 )
225 SbiSymDef* pPar = pPool->Get( 1 );
226 if( pPar )
228 ePropType = pPar->GetType();
231 break;
233 case PROPERTY_MODE_SET:
234 ePropType = SbxOBJECT;
235 break;
236 case PROPERTY_MODE_NONE:
237 OSL_FAIL( "Illegal PropertyMode PROPERTY_MODE_NONE" );
238 break;
240 OUString aPropName = pProc->GetPropName();
241 if( nPass == 1 )
243 aPropName = aPropName.copy( aIfaceName.getLength() + 1 );
245 OSL_TRACE("*** getProcedureProperty for thing %s",
246 rtl::OUStringToOString( aPropName,RTL_TEXTENCODING_UTF8 ).getStr() );
247 rMod.GetProcedureProperty( aPropName, ePropType );
249 if( nPass == 1 )
251 rMod.GetIfaceMapperMethod( aProcName, pMeth );
253 else
255 pMeth = rMod.GetMethod( aProcName, pProc->GetType() );
257 if( !pProc->IsPublic() )
259 pMeth->SetFlag( SBX_PRIVATE );
261 // Declare? -> Hidden
262 if( !pProc->GetLib().isEmpty())
264 pMeth->SetFlag( SBX_HIDDEN );
266 pMeth->nStart = pProc->GetAddr();
267 pMeth->nLine1 = pProc->GetLine1();
268 pMeth->nLine2 = pProc->GetLine2();
269 // The parameter:
270 SbxInfo* pInfo = pMeth->GetInfo();
271 OUString aHelpFile, aComment;
272 sal_uIntPtr nHelpId = 0;
273 if( pInfo )
275 // Rescue the additional data
276 aHelpFile = pInfo->GetHelpFile();
277 aComment = pInfo->GetComment();
278 nHelpId = pInfo->GetHelpId();
280 // And reestablish the parameter list
281 pInfo = new SbxInfo( aHelpFile, nHelpId );
282 pInfo->SetComment( aComment );
283 SbiSymPool* pPool = &pProc->GetParams();
284 // The first element is always the value of the function!
285 for( sal_uInt16 i = 1; i < pPool->GetSize(); i++ )
287 SbiSymDef* pPar = pPool->Get( i );
288 SbxDataType t = pPar->GetType();
289 if( !pPar->IsByVal() )
291 t = (SbxDataType) ( t | SbxBYREF );
293 if( pPar->GetDims() )
295 t = (SbxDataType) ( t | SbxARRAY );
297 // #33677 hand-over an Optional-Info
298 sal_uInt16 nFlags = SBX_READ;
299 if( pPar->IsOptional() )
301 nFlags |= SBX_OPTIONAL;
303 pInfo->AddParam( pPar->GetName(), t, nFlags );
305 sal_uInt32 nUserData = 0;
306 sal_uInt16 nDefaultId = pPar->GetDefaultId();
307 if( nDefaultId )
309 nUserData |= nDefaultId;
311 if( pPar->IsParamArray() )
313 nUserData |= PARAM_INFO_PARAMARRAY;
315 if( pPar->IsWithBrackets() )
317 nUserData |= PARAM_INFO_WITHBRACKETS;
319 if( nUserData )
321 SbxParamInfo* pParam = (SbxParamInfo*)pInfo->GetParam( i );
322 pParam->nUserData = nUserData;
325 pMeth->SetInfo( pInfo );
327 } // for( iPass...
330 // The code
331 p->AddCode( aCode.GetBuffer(), aCode.GetSize() );
333 // The global StringPool. 0 is not occupied.
334 SbiStringPool* pPool = &pParser->aGblStrings;
335 sal_uInt16 nSize = pPool->GetSize();
336 p->MakeStrings( nSize );
337 sal_uInt16 i;
338 for( i = 1; i <= nSize; i++ )
340 p->AddString( pPool->Find( i ) );
342 // Insert types
343 sal_uInt16 nCount = pParser->rTypeArray->Count();
344 for (i = 0; i < nCount; i++)
346 p->AddType((SbxObject *)pParser->rTypeArray->Get(i));
348 // Insert enum objects
349 nCount = pParser->rEnumArray->Count();
350 for (i = 0; i < nCount; i++)
352 p->AddEnum((SbxObject *)pParser->rEnumArray->Get(i));
354 if( !p->IsError() )
356 rMod.pImage = p;
358 else
360 delete p;
362 rMod.EndDefinitions();
365 template < class T >
366 class PCodeVisitor
368 public:
369 virtual ~PCodeVisitor();
371 virtual void start( sal_uInt8* pStart ) = 0;
372 virtual void processOpCode0( SbiOpcode eOp ) = 0;
373 virtual void processOpCode1( SbiOpcode eOp, T nOp1 ) = 0;
374 virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 ) = 0;
375 virtual bool processParams() = 0;
376 virtual void end() = 0;
379 template <class T> PCodeVisitor< T >::~PCodeVisitor()
382 template <class T>
383 class PCodeBufferWalker
385 private:
386 T m_nBytes;
387 sal_uInt8* m_pCode;
388 T readParam( sal_uInt8*& pCode )
390 short nBytes = sizeof( T );
391 T nOp1=0;
392 for ( int i=0; i<nBytes; ++i )
393 nOp1 |= *pCode++ << ( i * 8);
394 return nOp1;
396 public:
397 PCodeBufferWalker( sal_uInt8* pCode, T nBytes ): m_nBytes( nBytes ), m_pCode( pCode )
400 void visitBuffer( PCodeVisitor< T >& visitor )
402 sal_uInt8* pCode = m_pCode;
403 if ( !pCode )
404 return;
405 sal_uInt8* pEnd = pCode + m_nBytes;
406 visitor.start( m_pCode );
407 T nOp1 = 0, nOp2 = 0;
408 for( ; pCode < pEnd; )
410 SbiOpcode eOp = (SbiOpcode)(*pCode++);
412 if ( eOp <= SbOP0_END )
413 visitor.processOpCode0( eOp );
414 else if( eOp >= SbOP1_START && eOp <= SbOP1_END )
416 if ( visitor.processParams() )
417 nOp1 = readParam( pCode );
418 else
419 pCode += sizeof( T );
420 visitor.processOpCode1( eOp, nOp1 );
422 else if( eOp >= SbOP2_START && eOp <= SbOP2_END )
424 if ( visitor.processParams() )
426 nOp1 = readParam( pCode );
427 nOp2 = readParam( pCode );
429 else
430 pCode += ( sizeof( T ) * 2 );
431 visitor.processOpCode2( eOp, nOp1, nOp2 );
434 visitor.end();
438 template < class T, class S >
439 class OffSetAccumulator : public PCodeVisitor< T >
441 T m_nNumOp0;
442 T m_nNumSingleParams;
443 T m_nNumDoubleParams;
444 public:
446 OffSetAccumulator() : m_nNumOp0(0), m_nNumSingleParams(0), m_nNumDoubleParams(0){}
447 virtual void start( sal_uInt8* /*pStart*/ ){}
448 virtual void processOpCode0( SbiOpcode /*eOp*/ ){ ++m_nNumOp0; }
449 virtual void processOpCode1( SbiOpcode /*eOp*/, T /*nOp1*/ ){ ++m_nNumSingleParams; }
450 virtual void processOpCode2( SbiOpcode /*eOp*/, T /*nOp1*/, T /*nOp2*/ ) { ++m_nNumDoubleParams; }
451 virtual void end(){}
452 S offset()
454 T result = 0 ;
455 static const S max = std::numeric_limits< S >::max();
456 result = m_nNumOp0 + ( ( sizeof(S) + 1 ) * m_nNumSingleParams ) + ( (( sizeof(S) * 2 )+ 1 ) * m_nNumDoubleParams );
457 return std::min(static_cast<T>(max), result);
459 virtual bool processParams(){ return false; }
464 template < class T, class S >
466 class BufferTransformer : public PCodeVisitor< T >
468 sal_uInt8* m_pStart;
469 SbiBuffer m_ConvertedBuf;
470 public:
471 BufferTransformer():m_pStart(NULL), m_ConvertedBuf( NULL, 1024 ) {}
472 virtual void start( sal_uInt8* pStart ){ m_pStart = pStart; }
473 virtual void processOpCode0( SbiOpcode eOp )
475 m_ConvertedBuf += (sal_uInt8)eOp;
477 virtual void processOpCode1( SbiOpcode eOp, T nOp1 )
479 m_ConvertedBuf += (sal_uInt8)eOp;
480 switch( eOp )
482 case _JUMP:
483 case _JUMPT:
484 case _JUMPF:
485 case _GOSUB:
486 case _CASEIS:
487 case _RETURN:
488 case _ERRHDL:
489 case _TESTFOR:
490 nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
491 break;
492 case _RESUME:
493 if ( nOp1 > 1 )
494 nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
495 break;
496 default:
497 break; //
500 m_ConvertedBuf += (S)nOp1;
502 virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 )
504 m_ConvertedBuf += (sal_uInt8)eOp;
505 if ( eOp == _CASEIS )
506 if ( nOp1 )
507 nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
508 m_ConvertedBuf += (S)nOp1;
509 m_ConvertedBuf += (S)nOp2;
512 virtual bool processParams(){ return true; }
513 virtual void end() {}
514 // yeuch, careful here, you can only call
515 // GetBuffer on the returned SbiBuffer once, also
516 // you (as the caller) get to own the memory
517 SbiBuffer& buffer()
519 return m_ConvertedBuf;
521 static S convertBufferOffSet( sal_uInt8* pStart, T nOp1 )
523 PCodeBufferWalker< T > aBuff( pStart, nOp1);
524 OffSetAccumulator< T, S > aVisitor;
525 aBuff.visitBuffer( aVisitor );
526 return aVisitor.offset();
530 sal_uInt32
531 SbiCodeGen::calcNewOffSet( sal_uInt8* pCode, sal_uInt16 nOffset )
533 return BufferTransformer< sal_uInt16, sal_uInt32 >::convertBufferOffSet( pCode, nOffset );
536 sal_uInt16
537 SbiCodeGen::calcLegacyOffSet( sal_uInt8* pCode, sal_uInt32 nOffset )
539 return BufferTransformer< sal_uInt32, sal_uInt16 >::convertBufferOffSet( pCode, nOffset );
542 template <class T, class S>
543 void
544 PCodeBuffConvertor<T,S>::convert()
546 PCodeBufferWalker< T > aBuf( m_pStart, m_nSize );
547 BufferTransformer< T, S > aTrnsfrmer;
548 aBuf.visitBuffer( aTrnsfrmer );
549 m_pCnvtdBuf = (sal_uInt8*)aTrnsfrmer.buffer().GetBuffer();
550 m_nCnvtdSize = static_cast<S>( aTrnsfrmer.buffer().GetSize() );
553 template class PCodeBuffConvertor< sal_uInt16, sal_uInt32 >;
554 template class PCodeBuffConvertor< sal_uInt32, sal_uInt16 >;
556 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */