bump product version to 5.0.4.1
[LibreOffice.git] / basic / source / comp / codegen.cxx
blob332bb7b91517ef2c7fd0e3b4f1195e855e0d6ea0
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 "image.hxx"
23 #include "codegen.hxx"
24 #include "parser.hxx"
25 #include <limits>
26 #include <algorithm>
27 #include <osl/diagnose.h>
28 #include <com/sun/star/script/ModuleType.hpp>
30 // nInc is the increment size of the buffers
32 SbiCodeGen::SbiCodeGen( SbModule& r, SbiParser* p, short nInc )
33 : rMod( r ), aCode( p, nInc )
35 pParser = p;
36 bStmnt = false;
37 nLine = 0;
38 nCol = 0;
39 nForLevel = 0;
42 sal_uInt32 SbiCodeGen::GetPC()
44 return aCode.GetSize();
47 // memorize the statement
49 void SbiCodeGen::Statement()
51 if( pParser->IsCodeCompleting() )
52 return;
54 bStmnt = true;
56 nLine = pParser->GetLine();
57 nCol = pParser->GetCol1();
59 // #29955 Store the information of the for-loop-layer
60 // in the uppper Byte of the column
61 nCol = (nCol & 0xff) + 0x100 * nForLevel;
64 // Mark the beginning of a statement
66 void SbiCodeGen::GenStmnt()
68 if( pParser->IsCodeCompleting() )
69 return;
71 if( bStmnt )
73 bStmnt = false;
74 Gen( _STMNT, nLine, nCol );
78 // The Gen-Routines return the offset of the 1. operand,
79 // so that jumps can sink their backchain there.
81 sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode )
83 if( pParser->IsCodeCompleting() )
84 return 0;
86 #ifdef DBG_UTIL
87 if( eOpcode < SbOP0_START || eOpcode > SbOP0_END )
88 pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE1" );
89 #endif
90 GenStmnt();
91 aCode += (sal_uInt8) eOpcode;
92 return GetPC();
95 sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode, sal_uInt32 nOpnd )
97 if( pParser->IsCodeCompleting() )
98 return 0;
100 #ifdef DBG_UTIL
101 if( eOpcode < SbOP1_START || eOpcode > SbOP1_END )
102 pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE2" );
103 #endif
104 GenStmnt();
105 aCode += (sal_uInt8) eOpcode;
106 sal_uInt32 n = GetPC();
107 aCode += nOpnd;
108 return n;
111 sal_uInt32 SbiCodeGen::Gen( SbiOpcode eOpcode, sal_uInt32 nOpnd1, sal_uInt32 nOpnd2 )
113 if( pParser->IsCodeCompleting() )
114 return 0;
116 #ifdef DBG_UTIL
117 if( eOpcode < SbOP2_START || eOpcode > SbOP2_END )
118 pParser->Error( SbERR_INTERNAL_ERROR, "OPCODE3" );
119 #endif
120 GenStmnt();
121 aCode += (sal_uInt8) eOpcode;
122 sal_uInt32 n = GetPC();
123 aCode += nOpnd1;
124 aCode += nOpnd2;
125 return n;
128 // Storing of the created image in the module
130 void SbiCodeGen::Save()
132 if( pParser->IsCodeCompleting() )
133 return;
135 SbiImage* p = new SbiImage;
136 rMod.StartDefinitions();
137 // OPTION BASE-Value:
138 p->nDimBase = pParser->nBase;
139 // OPTION take over the EXPLICIT-Flag
140 if( pParser->bExplicit )
141 p->SetFlag( SbiImageFlags::EXPLICIT );
143 int nIfaceCount = 0;
144 if( rMod.mnType == com::sun::star::script::ModuleType::CLASS )
146 OSL_TRACE("COdeGen::save() classmodule processing");
147 rMod.bIsProxyModule = true;
148 p->SetFlag( SbiImageFlags::CLASSMODULE );
149 GetSbData()->pClassFac->AddClassModule( &rMod );
151 nIfaceCount = pParser->aIfaceVector.size();
152 if( !rMod.pClassData )
153 rMod.pClassData = new SbClassData;
154 if( nIfaceCount )
156 for( int i = 0 ; i < nIfaceCount ; i++ )
158 const OUString& rIfaceName = pParser->aIfaceVector[i];
159 SbxVariable* pIfaceVar = new SbxVariable( SbxVARIANT );
160 pIfaceVar->SetName( rIfaceName );
161 SbxArray* pIfaces = rMod.pClassData->mxIfaces;
162 pIfaces->Insert( pIfaceVar, pIfaces->Count() );
166 rMod.pClassData->maRequiredTypes = pParser->aRequiredTypes;
168 else
170 GetSbData()->pClassFac->RemoveClassModule( &rMod );
171 // Only a ClassModule can revert to Normal
172 if ( rMod.mnType == com::sun::star::script::ModuleType::CLASS )
174 rMod.mnType = com::sun::star::script::ModuleType::NORMAL;
176 rMod.bIsProxyModule = false;
179 // GlobalCode-Flag
180 if( pParser->HasGlobalCode() )
182 p->SetFlag( SbiImageFlags::INITCODE );
184 // Die Entrypoints:
185 for( SbiSymDef* pDef = pParser->aPublics.First(); pDef;
186 pDef = pParser->aPublics.Next() )
188 SbiProcDef* pProc = pDef->GetProcDef();
189 if( pProc && pProc->IsDefined() )
191 OUString aProcName = pProc->GetName();
192 OUString aIfaceProcName;
193 OUString aIfaceName;
194 sal_uInt16 nPassCount = 1;
195 if( nIfaceCount )
197 int nPropPrefixFound = aProcName.indexOf(OUString("Property "));
198 OUString aPureProcName = aProcName;
199 OUString aPropPrefix;
200 if( nPropPrefixFound == 0 )
202 aPropPrefix = aProcName.copy( 0, 13 ); // 13 == Len( "Property ?et " )
203 aPureProcName = aProcName.copy( 13 );
205 for( int i = 0 ; i < nIfaceCount ; i++ )
207 const OUString& rIfaceName = pParser->aIfaceVector[i];
208 int nFound = aPureProcName.indexOf( rIfaceName );
209 if( nFound == 0 && '_' == aPureProcName[rIfaceName.getLength()] )
211 if( nPropPrefixFound == 0 )
213 aIfaceProcName += aPropPrefix;
215 aIfaceProcName += aPureProcName.copy( rIfaceName.getLength() + 1 );
216 aIfaceName = rIfaceName;
217 nPassCount = 2;
218 break;
222 SbMethod* pMeth = NULL;
223 for( sal_uInt16 nPass = 0 ; nPass < nPassCount ; nPass++ )
225 if( nPass == 1 )
227 aProcName = aIfaceProcName;
229 PropertyMode ePropMode = pProc->getPropertyMode();
230 if( ePropMode != PROPERTY_MODE_NONE )
232 SbxDataType ePropType = SbxEMPTY;
233 switch( ePropMode )
235 case PROPERTY_MODE_GET:
236 ePropType = pProc->GetType();
237 break;
238 case PROPERTY_MODE_LET:
240 // type == type of first parameter
241 ePropType = SbxVARIANT; // Default
242 SbiSymPool* pPool = &pProc->GetParams();
243 if( pPool->GetSize() > 1 )
245 SbiSymDef* pPar = pPool->Get( 1 );
246 if( pPar )
248 ePropType = pPar->GetType();
251 break;
253 case PROPERTY_MODE_SET:
254 ePropType = SbxOBJECT;
255 break;
256 default:
257 OSL_FAIL("Illegal PropertyMode");
258 break;
260 OUString aPropName = pProc->GetPropName();
261 if( nPass == 1 )
263 aPropName = aPropName.copy( aIfaceName.getLength() + 1 );
265 OSL_TRACE("*** getProcedureProperty for thing %s",
266 OUStringToOString( aPropName,RTL_TEXTENCODING_UTF8 ).getStr() );
267 rMod.GetProcedureProperty( aPropName, ePropType );
269 if( nPass == 1 )
271 rMod.GetIfaceMapperMethod( aProcName, pMeth );
273 else
275 pMeth = rMod.GetMethod( aProcName, pProc->GetType() );
277 if( !pProc->IsPublic() )
279 pMeth->SetFlag( SBX_PRIVATE );
281 // Declare? -> Hidden
282 if( !pProc->GetLib().isEmpty())
284 pMeth->SetFlag( SBX_HIDDEN );
286 pMeth->nStart = pProc->GetAddr();
287 pMeth->nLine1 = pProc->GetLine1();
288 pMeth->nLine2 = pProc->GetLine2();
289 // The parameter:
290 SbxInfo* pInfo = pMeth->GetInfo();
291 OUString aHelpFile, aComment;
292 sal_uInt32 nHelpId = 0;
293 if( pInfo )
295 // Rescue the additional data
296 aHelpFile = pInfo->GetHelpFile();
297 aComment = pInfo->GetComment();
298 nHelpId = pInfo->GetHelpId();
300 // And reestablish the parameter list
301 pInfo = new SbxInfo( aHelpFile, nHelpId );
302 pInfo->SetComment( aComment );
303 SbiSymPool* pPool = &pProc->GetParams();
304 // The first element is always the value of the function!
305 for( sal_uInt16 i = 1; i < pPool->GetSize(); i++ )
307 SbiSymDef* pPar = pPool->Get( i );
308 SbxDataType t = pPar->GetType();
309 if( !pPar->IsByVal() )
311 t = (SbxDataType) ( t | SbxBYREF );
313 if( pPar->GetDims() )
315 t = (SbxDataType) ( t | SbxARRAY );
317 // #33677 hand-over an Optional-Info
318 SbxFlagBits nFlags = SBX_READ;
319 if( pPar->IsOptional() )
321 nFlags |= SBX_OPTIONAL;
323 pInfo->AddParam( pPar->GetName(), t, nFlags );
325 sal_uInt32 nUserData = 0;
326 sal_uInt16 nDefaultId = pPar->GetDefaultId();
327 if( nDefaultId )
329 nUserData |= nDefaultId;
331 if( pPar->IsParamArray() )
333 nUserData |= PARAM_INFO_PARAMARRAY;
335 if( pPar->IsWithBrackets() )
337 nUserData |= PARAM_INFO_WITHBRACKETS;
339 SbxParamInfo* pParam = NULL;
340 if( nUserData )
342 pParam = const_cast<SbxParamInfo*>(pInfo->GetParam( i ));
344 if( pParam )
346 pParam->nUserData = nUserData;
349 pMeth->SetInfo( pInfo );
351 } // for( iPass...
354 // The code
355 p->AddCode( aCode.GetBuffer(), aCode.GetSize() );
357 // The global StringPool. 0 is not occupied.
358 SbiStringPool* pPool = &pParser->aGblStrings;
359 sal_uInt16 nSize = pPool->GetSize();
360 p->MakeStrings( nSize );
361 sal_uInt16 i;
362 for( i = 1; i <= nSize; i++ )
364 p->AddString( pPool->Find( i ) );
366 // Insert types
367 sal_uInt16 nCount = pParser->rTypeArray->Count();
368 for (i = 0; i < nCount; i++)
370 p->AddType(static_cast<SbxObject *>(pParser->rTypeArray->Get(i)));
372 // Insert enum objects
373 nCount = pParser->rEnumArray->Count();
374 for (i = 0; i < nCount; i++)
376 p->AddEnum(static_cast<SbxObject *>(pParser->rEnumArray->Get(i)));
378 if( !p->IsError() )
380 rMod.pImage = p;
382 else
384 delete p;
386 rMod.EndDefinitions();
389 template < class T >
390 class PCodeVisitor
392 public:
393 virtual ~PCodeVisitor();
395 virtual void start( sal_uInt8* pStart ) = 0;
396 virtual void processOpCode0( SbiOpcode eOp ) = 0;
397 virtual void processOpCode1( SbiOpcode eOp, T nOp1 ) = 0;
398 virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 ) = 0;
399 virtual bool processParams() = 0;
400 virtual void end() = 0;
403 template <class T> PCodeVisitor< T >::~PCodeVisitor()
406 template <class T>
407 class PCodeBufferWalker
409 private:
410 T m_nBytes;
411 sal_uInt8* m_pCode;
412 static T readParam( sal_uInt8*& pCode )
414 short nBytes = sizeof( T );
415 T nOp1=0;
416 for ( int i=0; i<nBytes; ++i )
417 nOp1 |= *pCode++ << ( i * 8);
418 return nOp1;
420 public:
421 PCodeBufferWalker( sal_uInt8* pCode, T nBytes ): m_nBytes( nBytes ), m_pCode( pCode )
424 void visitBuffer( PCodeVisitor< T >& visitor )
426 sal_uInt8* pCode = m_pCode;
427 if ( !pCode )
428 return;
429 sal_uInt8* pEnd = pCode + m_nBytes;
430 visitor.start( m_pCode );
431 T nOp1 = 0, nOp2 = 0;
432 for( ; pCode < pEnd; )
434 SbiOpcode eOp = (SbiOpcode)(*pCode++);
436 if ( eOp <= SbOP0_END )
437 visitor.processOpCode0( eOp );
438 else if( eOp >= SbOP1_START && eOp <= SbOP1_END )
440 if ( visitor.processParams() )
441 nOp1 = readParam( pCode );
442 else
443 pCode += sizeof( T );
444 visitor.processOpCode1( eOp, nOp1 );
446 else if( eOp >= SbOP2_START && eOp <= SbOP2_END )
448 if ( visitor.processParams() )
450 nOp1 = readParam( pCode );
451 nOp2 = readParam( pCode );
453 else
454 pCode += ( sizeof( T ) * 2 );
455 visitor.processOpCode2( eOp, nOp1, nOp2 );
458 visitor.end();
462 template < class T, class S >
463 class OffSetAccumulator : public PCodeVisitor< T >
465 T m_nNumOp0;
466 T m_nNumSingleParams;
467 T m_nNumDoubleParams;
468 public:
470 OffSetAccumulator() : m_nNumOp0(0), m_nNumSingleParams(0), m_nNumDoubleParams(0){}
471 virtual void start( sal_uInt8* /*pStart*/ ){}
472 virtual void processOpCode0( SbiOpcode /*eOp*/ ){ ++m_nNumOp0; }
473 virtual void processOpCode1( SbiOpcode /*eOp*/, T /*nOp1*/ ){ ++m_nNumSingleParams; }
474 virtual void processOpCode2( SbiOpcode /*eOp*/, T /*nOp1*/, T /*nOp2*/ ) { ++m_nNumDoubleParams; }
475 virtual void end(){}
476 S offset()
478 T result = 0 ;
479 static const S max = std::numeric_limits< S >::max();
480 result = m_nNumOp0 + ( ( sizeof(S) + 1 ) * m_nNumSingleParams ) + ( (( sizeof(S) * 2 )+ 1 ) * m_nNumDoubleParams );
481 return std::min(static_cast<T>(max), result);
483 virtual bool processParams(){ return false; }
488 template < class T, class S >
490 class BufferTransformer : public PCodeVisitor< T >
492 sal_uInt8* m_pStart;
493 SbiBuffer m_ConvertedBuf;
494 public:
495 BufferTransformer():m_pStart(NULL), m_ConvertedBuf( NULL, 1024 ) {}
496 virtual void start( sal_uInt8* pStart ){ m_pStart = pStart; }
497 virtual void processOpCode0( SbiOpcode eOp )
499 m_ConvertedBuf += (sal_uInt8)eOp;
501 virtual void processOpCode1( SbiOpcode eOp, T nOp1 )
503 m_ConvertedBuf += (sal_uInt8)eOp;
504 switch( eOp )
506 case _JUMP:
507 case _JUMPT:
508 case _JUMPF:
509 case _GOSUB:
510 case _CASEIS:
511 case _RETURN:
512 case _ERRHDL:
513 case _TESTFOR:
514 nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
515 break;
516 case _RESUME:
517 if ( nOp1 > 1 )
518 nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
519 break;
520 default:
521 break;
524 m_ConvertedBuf += static_cast<S>(nOp1);
526 virtual void processOpCode2( SbiOpcode eOp, T nOp1, T nOp2 )
528 m_ConvertedBuf += (sal_uInt8)eOp;
529 if ( eOp == _CASEIS )
530 if ( nOp1 )
531 nOp1 = static_cast<T>( convertBufferOffSet(m_pStart, nOp1) );
532 m_ConvertedBuf += static_cast<S>(nOp1);
533 m_ConvertedBuf += static_cast<S>(nOp2);
536 virtual bool processParams(){ return true; }
537 virtual void end() {}
538 // yeuch, careful here, you can only call
539 // GetBuffer on the returned SbiBuffer once, also
540 // you (as the caller) get to own the memory
541 SbiBuffer& buffer()
543 return m_ConvertedBuf;
545 static S convertBufferOffSet( sal_uInt8* pStart, T nOp1 )
547 PCodeBufferWalker< T > aBuff( pStart, nOp1);
548 OffSetAccumulator< T, S > aVisitor;
549 aBuff.visitBuffer( aVisitor );
550 return aVisitor.offset();
554 sal_uInt32
555 SbiCodeGen::calcNewOffSet( sal_uInt8* pCode, sal_uInt16 nOffset )
557 return BufferTransformer< sal_uInt16, sal_uInt32 >::convertBufferOffSet( pCode, nOffset );
560 sal_uInt16
561 SbiCodeGen::calcLegacyOffSet( sal_uInt8* pCode, sal_uInt32 nOffset )
563 return BufferTransformer< sal_uInt32, sal_uInt16 >::convertBufferOffSet( pCode, nOffset );
566 template <class T, class S>
567 void
568 PCodeBuffConvertor<T,S>::convert()
570 PCodeBufferWalker< T > aBuf( m_pStart, m_nSize );
571 BufferTransformer< T, S > aTrnsfrmer;
572 aBuf.visitBuffer( aTrnsfrmer );
573 m_pCnvtdBuf = reinterpret_cast<sal_uInt8*>(aTrnsfrmer.buffer().GetBuffer());
574 m_nCnvtdSize = static_cast<S>( aTrnsfrmer.buffer().GetSize() );
577 template class PCodeBuffConvertor< sal_uInt16, sal_uInt32 >;
578 template class PCodeBuffConvertor< sal_uInt32, sal_uInt16 >;
580 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */