1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/sberrors.hxx>
22 #include <basic/sbx.hxx>
23 #include <basic/sbmeth.hxx>
24 #include <basic/sbmod.hxx>
26 #include <codegen.hxx>
28 #include <sbintern.hxx>
32 #include <osl/diagnose.h>
33 #include <rtl/ustrbuf.hxx>
34 #include <o3tl/string_view.hxx>
35 #include <com/sun/star/script/ModuleType.hpp>
37 // nInc is the increment size of the buffers
39 SbiCodeGen::SbiCodeGen(SbModule
& r
, SbiParser
* p
)
49 sal_uInt32
SbiCodeGen::GetPC() const
51 return aCode
.GetSize();
54 // memorize the statement
56 void SbiCodeGen::Statement()
58 if( pParser
->IsCodeCompleting() )
63 nLine
= pParser
->GetLine();
64 nCol
= pParser
->GetCol1();
66 // #29955 Store the information of the for-loop-layer
67 // in the upper Byte of the column
68 nCol
= (nCol
& 0xff) + 0x100 * nForLevel
;
71 // Mark the beginning of a statement
73 void SbiCodeGen::GenStmnt()
75 if( pParser
->IsCodeCompleting() )
81 Gen( SbiOpcode::STMNT_
, nLine
, nCol
);
85 // The Gen-Routines return the offset of the 1. operand,
86 // so that jumps can sink their backchain there.
88 sal_uInt32
SbiCodeGen::Gen( SbiOpcode eOpcode
)
90 if( pParser
->IsCodeCompleting() )
94 if( eOpcode
< SbiOpcode::SbOP0_START
|| eOpcode
> SbiOpcode::SbOP0_END
)
95 pParser
->Error( ERRCODE_BASIC_INTERNAL_ERROR
, u
"OPCODE1"_ustr
);
98 aCode
+= static_cast<sal_uInt8
>(eOpcode
);
102 sal_uInt32
SbiCodeGen::Gen( SbiOpcode eOpcode
, sal_uInt32 nOpnd
)
104 if( pParser
->IsCodeCompleting() )
108 if( eOpcode
< SbiOpcode::SbOP1_START
|| eOpcode
> SbiOpcode::SbOP1_END
)
109 pParser
->Error( ERRCODE_BASIC_INTERNAL_ERROR
, u
"OPCODE2"_ustr
);
112 aCode
+= static_cast<sal_uInt8
>(eOpcode
);
113 sal_uInt32 n
= GetPC();
118 sal_uInt32
SbiCodeGen::Gen( SbiOpcode eOpcode
, sal_uInt32 nOpnd1
, sal_uInt32 nOpnd2
)
120 if( pParser
->IsCodeCompleting() )
124 if( eOpcode
< SbiOpcode::SbOP2_START
|| eOpcode
> SbiOpcode::SbOP2_END
)
125 pParser
->Error( ERRCODE_BASIC_INTERNAL_ERROR
, u
"OPCODE3"_ustr
);
128 aCode
+= static_cast<sal_uInt8
>(eOpcode
);
129 sal_uInt32 n
= GetPC();
135 // Storing of the created image in the module
137 void SbiCodeGen::Save()
139 if( pParser
->IsCodeCompleting() )
142 std::unique_ptr
<SbiImage
> p(new SbiImage
);
143 rMod
.StartDefinitions();
144 // OPTION BASE-Value:
145 p
->nDimBase
= pParser
->nBase
;
146 // OPTION take over the EXPLICIT-Flag
147 if( pParser
->bExplicit
)
148 p
->SetFlag( SbiImageFlags::EXPLICIT
);
151 if( rMod
.mnType
== css::script::ModuleType::CLASS
)
153 rMod
.bIsProxyModule
= true;
154 p
->SetFlag( SbiImageFlags::CLASSMODULE
);
155 GetSbData()->pClassFac
->AddClassModule( &rMod
);
157 nIfaceCount
= pParser
->aIfaceVector
.size();
158 if( !rMod
.pClassData
)
159 rMod
.pClassData
.reset(new SbClassData
);
162 for( int i
= 0 ; i
< nIfaceCount
; i
++ )
164 const OUString
& rIfaceName
= pParser
->aIfaceVector
[i
];
165 SbxVariable
* pIfaceVar
= new SbxVariable( SbxVARIANT
);
166 pIfaceVar
->SetName( rIfaceName
);
167 SbxArray
* pIfaces
= rMod
.pClassData
->mxIfaces
.get();
168 pIfaces
->Insert( pIfaceVar
, pIfaces
->Count() );
172 rMod
.pClassData
->maRequiredTypes
= pParser
->aRequiredTypes
;
176 GetSbData()->pClassFac
->RemoveClassModule( &rMod
);
177 // Only a ClassModule can revert to Normal
178 if ( rMod
.mnType
== css::script::ModuleType::CLASS
)
180 rMod
.mnType
= css::script::ModuleType::NORMAL
;
182 rMod
.bIsProxyModule
= false;
186 if( pParser
->HasGlobalCode() )
188 p
->SetFlag( SbiImageFlags::INITCODE
);
191 for( SbiSymDef
* pDef
= pParser
->aPublics
.First(); pDef
;
192 pDef
= pParser
->aPublics
.Next() )
194 SbiProcDef
* pProc
= pDef
->GetProcDef();
195 if( pProc
&& pProc
->IsDefined() )
197 OUString aProcName
= pProc
->GetName();
198 OUStringBuffer aIfaceProcName
;
200 sal_uInt16 nPassCount
= 1;
203 int nPropPrefixFound
= aProcName
.indexOf("Property ");
204 std::u16string_view aPureProcName
= aProcName
;
205 std::u16string_view aPropPrefix
;
206 if( nPropPrefixFound
== 0 )
208 aPropPrefix
= aProcName
.subView( 0, 13 ); // 13 == Len( "Property ?et " )
209 aPureProcName
= aProcName
.subView( 13 );
211 for( int i
= 0 ; i
< nIfaceCount
; i
++ )
213 const OUString
& rIfaceName
= pParser
->aIfaceVector
[i
];
214 bool bFound
= o3tl::starts_with(aPureProcName
, rIfaceName
);
215 if( bFound
&& aPureProcName
[rIfaceName
.getLength()] == '_' )
217 if( nPropPrefixFound
== 0 )
219 aIfaceProcName
.append(aPropPrefix
);
221 aIfaceProcName
.append(aPureProcName
.substr(rIfaceName
.getLength() + 1) );
222 aIfaceName
= rIfaceName
;
228 SbMethod
* pMeth
= nullptr;
229 for( sal_uInt16 nPass
= 0 ; nPass
< nPassCount
; nPass
++ )
233 aProcName
= aIfaceProcName
.toString();
235 PropertyMode ePropMode
= pProc
->getPropertyMode();
236 if( ePropMode
!= PropertyMode::NONE
)
238 SbxDataType ePropType
= SbxEMPTY
;
241 case PropertyMode::Get
:
242 ePropType
= pProc
->GetType();
244 case PropertyMode::Let
:
246 // type == type of first parameter
247 ePropType
= SbxVARIANT
; // Default
248 SbiSymPool
* pPool
= &pProc
->GetParams();
249 if( pPool
->GetSize() > 1 )
251 SbiSymDef
* pPar
= pPool
->Get( 1 );
254 ePropType
= pPar
->GetType();
259 case PropertyMode::Set
:
260 ePropType
= SbxOBJECT
;
263 OSL_FAIL("Illegal PropertyMode");
266 OUString aPropName
= pProc
->GetPropName();
269 aPropName
= aPropName
.copy( aIfaceName
.getLength() + 1 );
271 rMod
.GetProcedureProperty( aPropName
, ePropType
);
275 rMod
.GetIfaceMapperMethod( aProcName
, pMeth
);
279 pMeth
= rMod
.GetMethod( aProcName
, pProc
->GetType() );
281 if( !pProc
->IsPublic() )
283 pMeth
->SetFlag( SbxFlagBits::Private
);
285 // Declare? -> Hidden
286 if( !pProc
->GetLib().isEmpty())
288 pMeth
->SetFlag( SbxFlagBits::Hidden
);
290 pMeth
->nStart
= pProc
->GetAddr();
291 pMeth
->nLine1
= pProc
->GetLine1();
292 pMeth
->nLine2
= pProc
->GetLine2();
294 SbxInfo
* pInfo
= pMeth
->GetInfo();
295 OUString aHelpFile
, aComment
;
296 sal_uInt32 nHelpId
= 0;
299 // Rescue the additional data
300 aHelpFile
= pInfo
->GetHelpFile();
301 aComment
= pInfo
->GetComment();
302 nHelpId
= pInfo
->GetHelpId();
304 // And reestablish the parameter list
305 pInfo
= new SbxInfo( aHelpFile
, nHelpId
);
306 pInfo
->SetComment( aComment
);
307 SbiSymPool
* pPool
= &pProc
->GetParams();
308 // The first element is always the value of the function!
309 for( sal_uInt16 i
= 1; i
< pPool
->GetSize(); i
++ )
311 SbiSymDef
* pPar
= pPool
->Get( i
);
312 SbxDataType t
= pPar
->GetType();
313 if( !pPar
->IsByVal() )
315 t
= static_cast<SbxDataType
>( t
| SbxBYREF
);
317 if( pPar
->GetDims() )
319 t
= static_cast<SbxDataType
>( t
| SbxARRAY
);
321 // #33677 hand-over an Optional-Info
322 SbxFlagBits nFlags
= SbxFlagBits::Read
;
323 if( pPar
->IsOptional() )
325 nFlags
|= SbxFlagBits::Optional
;
327 pInfo
->AddParam( pPar
->GetName(), t
, nFlags
);
329 sal_uInt32 nUserData
= 0;
330 sal_uInt16 nDefaultId
= pPar
->GetDefaultId();
333 nUserData
|= nDefaultId
;
335 if( pPar
->IsParamArray() )
337 nUserData
|= PARAM_INFO_PARAMARRAY
;
339 if( pPar
->IsWithBrackets() )
341 nUserData
|= PARAM_INFO_WITHBRACKETS
;
343 SbxParamInfo
* pParam
= nullptr;
346 pParam
= const_cast<SbxParamInfo
*>(pInfo
->GetParam( i
));
350 pParam
->nUserData
= nUserData
;
353 pMeth
->SetInfo( pInfo
);
358 if (aCode
.GetErrCode())
360 pParser
->Error(aCode
.GetErrCode(), aCode
.GetErrMessage());
363 p
->AddCode(aCode
.GetBuffer());
365 // The global StringPool. 0 is not occupied.
366 SbiStringPool
* pPool
= &pParser
->aGblStrings
;
367 sal_uInt16 nSize
= pPool
->GetSize();
368 p
->MakeStrings( nSize
);
370 for( i
= 1; i
<= nSize
; i
++ )
372 p
->AddString( pPool
->Find( i
) );
375 sal_uInt32 nCount
= pParser
->rTypeArray
->Count();
376 for (i
= 0; i
< nCount
; i
++)
378 p
->AddType(static_cast<SbxObject
*>(pParser
->rTypeArray
->Get(i
)));
380 // Insert enum objects
381 nCount
= pParser
->rEnumArray
->Count();
382 for (i
= 0; i
< nCount
; i
++)
384 p
->AddEnum(static_cast<SbxObject
*>(pParser
->rEnumArray
->Get(i
)));
388 rMod
.pImage
= std::move(p
);
390 rMod
.EndDefinitions();
399 virtual ~PCodeVisitor();
401 virtual void start( const sal_uInt8
* pStart
) = 0;
402 virtual void processOpCode0( SbiOpcode eOp
) = 0;
403 virtual void processOpCode1( SbiOpcode eOp
, T nOp1
) = 0;
404 virtual void processOpCode2( SbiOpcode eOp
, T nOp1
, T nOp2
) = 0;
405 virtual bool processParams() = 0;
410 template <class T
> PCodeVisitor
< T
>::~PCodeVisitor()
416 class PCodeBufferWalker
420 const sal_uInt8
* m_pCode
;
421 static T
readParam( sal_uInt8
const *& pCode
)
424 for ( std::size_t i
=0; i
<sizeof( T
); ++i
)
425 nOp1
|= *pCode
++ << ( i
* 8);
429 PCodeBufferWalker( const sal_uInt8
* pCode
, T nBytes
): m_nBytes( nBytes
), m_pCode( pCode
)
432 void visitBuffer( PCodeVisitor
< T
>& visitor
)
434 const sal_uInt8
* pCode
= m_pCode
;
437 const sal_uInt8
* pEnd
= pCode
+ m_nBytes
;
438 visitor
.start( m_pCode
);
439 T nOp1
= 0, nOp2
= 0;
440 for( ; pCode
< pEnd
; )
442 SbiOpcode eOp
= static_cast<SbiOpcode
>(*pCode
++);
444 if ( eOp
<= SbiOpcode::SbOP0_END
)
445 visitor
.processOpCode0( eOp
);
446 else if( eOp
>= SbiOpcode::SbOP1_START
&& eOp
<= SbiOpcode::SbOP1_END
)
448 if ( visitor
.processParams() )
449 nOp1
= readParam( pCode
);
451 pCode
+= sizeof( T
);
452 visitor
.processOpCode1( eOp
, nOp1
);
454 else if( eOp
>= SbiOpcode::SbOP2_START
&& eOp
<= SbiOpcode::SbOP2_END
)
456 if ( visitor
.processParams() )
458 nOp1
= readParam( pCode
);
459 nOp2
= readParam( pCode
);
462 pCode
+= ( sizeof( T
) * 2 );
463 visitor
.processOpCode2( eOp
, nOp1
, nOp2
);
469 template < class T
, class S
>
470 class OffSetAccumulator
: public PCodeVisitor
< T
>
473 T m_nNumSingleParams
;
474 T m_nNumDoubleParams
;
477 OffSetAccumulator() : m_nNumOp0(0), m_nNumSingleParams(0), m_nNumDoubleParams(0){}
478 virtual void start( const sal_uInt8
* /*pStart*/ ) override
{}
479 virtual void processOpCode0( SbiOpcode
/*eOp*/ ) override
{ ++m_nNumOp0
; }
480 virtual void processOpCode1( SbiOpcode
/*eOp*/, T
/*nOp1*/ ) override
{ ++m_nNumSingleParams
; }
481 virtual void processOpCode2( SbiOpcode
/*eOp*/, T
/*nOp1*/, T
/*nOp2*/ ) override
{ ++m_nNumDoubleParams
; }
484 typedef decltype(T(1) + S(1)) larger_t
; // type capable to hold both value ranges of T and S
486 static const S max
= std::numeric_limits
< S
>::max();
487 result
= m_nNumOp0
+ ( ( sizeof(S
) + 1 ) * m_nNumSingleParams
) + ( (( sizeof(S
) * 2 )+ 1 ) * m_nNumDoubleParams
);
488 return std::min
<larger_t
>(max
, result
);
490 virtual bool processParams() override
{ return false; }
494 template < class T
, class S
>
495 class BufferTransformer
: public PCodeVisitor
< T
>
497 const sal_uInt8
* m_pStart
;
498 SbiBuffer m_ConvertedBuf
;
500 BufferTransformer():m_pStart(nullptr) {}
501 virtual void start( const sal_uInt8
* pStart
) override
{ m_pStart
= pStart
; }
502 virtual void processOpCode0( SbiOpcode eOp
) override
504 m_ConvertedBuf
+= static_cast<sal_uInt8
>(eOp
);
506 virtual void processOpCode1( SbiOpcode eOp
, T nOp1
) override
508 m_ConvertedBuf
+= static_cast<sal_uInt8
>(eOp
);
511 case SbiOpcode::JUMP_
:
512 case SbiOpcode::JUMPT_
:
513 case SbiOpcode::JUMPF_
:
514 case SbiOpcode::GOSUB_
:
515 case SbiOpcode::CASEIS_
:
516 case SbiOpcode::RETURN_
:
517 case SbiOpcode::ERRHDL_
:
518 case SbiOpcode::TESTFOR_
:
519 nOp1
= static_cast<T
>( convertBufferOffSet(m_pStart
, nOp1
) );
521 case SbiOpcode::RESUME_
:
523 nOp1
= static_cast<T
>( convertBufferOffSet(m_pStart
, nOp1
) );
529 m_ConvertedBuf
+= static_cast<S
>(nOp1
);
531 virtual void processOpCode2( SbiOpcode eOp
, T nOp1
, T nOp2
) override
533 m_ConvertedBuf
+= static_cast<sal_uInt8
>(eOp
);
534 if ( eOp
== SbiOpcode::CASEIS_
&& nOp1
)
535 nOp1
= static_cast<T
>( convertBufferOffSet(m_pStart
, nOp1
) );
536 m_ConvertedBuf
+= static_cast<S
>(nOp1
);
537 m_ConvertedBuf
+= static_cast<S
>(nOp2
);
540 virtual bool processParams() override
{ return true; }
541 // yeuch, careful here, you can only call
542 // GetBuffer on the returned SbiBuffer once, also
543 // you (as the caller) get to own the memory
546 return m_ConvertedBuf
;
548 static S
convertBufferOffSet( const sal_uInt8
* pStart
, T nOp1
)
550 PCodeBufferWalker
< T
> aBuff( pStart
, nOp1
);
551 OffSetAccumulator
< T
, S
> aVisitor
;
552 aBuff
.visitBuffer( aVisitor
);
553 return aVisitor
.offset();
560 SbiCodeGen::calcNewOffSet( sal_uInt8
const * pCode
, sal_uInt16 nOffset
)
562 return BufferTransformer
< sal_uInt16
, sal_uInt32
>::convertBufferOffSet( pCode
, nOffset
);
566 SbiCodeGen::calcLegacyOffSet( sal_uInt8
const * pCode
, sal_uInt32 nOffset
)
568 return BufferTransformer
< sal_uInt32
, sal_uInt16
>::convertBufferOffSet( pCode
, nOffset
);
571 template <class T
, class S
>
573 PCodeBuffConvertor
<T
,S
>::convert()
575 PCodeBufferWalker
< T
> aBuf( m_pStart
, m_nSize
);
576 BufferTransformer
< T
, S
> aTrnsfrmer
;
577 aBuf
.visitBuffer( aTrnsfrmer
);
578 // TODO: handle buffer errors
579 m_aCnvtdBuf
= aTrnsfrmer
.buffer().GetBuffer();
582 template class PCodeBuffConvertor
< sal_uInt16
, sal_uInt32
>;
583 template class PCodeBuffConvertor
< sal_uInt32
, sal_uInt16
>;
585 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */