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 .
20 #include <basic/sberrors.hxx>
21 #include <basic/sbstar.hxx>
22 #include <basic/sbx.hxx>
23 #include <sbunoobj.hxx>
26 #include <osl/diagnose.h>
27 #include <com/sun/star/reflection/theCoreReflection.hpp>
28 #include <comphelper/processfactory.hxx>
29 #include <com/sun/star/uno/Exception.hpp>
30 #include <basic/codecompletecache.hxx>
33 using namespace ::com::sun::star
;
34 using namespace ::com::sun::star::uno
;
36 // Declaration of a variable
37 // If there are errors it will be parsed up to the comma or the newline.
38 // Return-value: a new instance, which were inserted and then deleted.
39 // Array-Index were returned as SbiExprList
41 SbiSymDef
* SbiParser::VarDecl( SbiExprListPtr
* ppDim
, bool bStatic
, bool bConst
)
43 bool bWithEvents
= false;
44 if( Peek() == WITHEVENTS
)
49 if( !TestSymbol() ) return nullptr;
50 SbxDataType t
= eScanType
;
51 SbiSymDef
* pDef
= bConst
? new SbiConstDef( aSym
) : new SbiSymDef( aSym
);
54 if( Peek() == LPAREN
)
56 pDim
= SbiExprList::ParseDimList( this );
57 if( !pDim
->GetDims() )
58 pDef
->SetWithBrackets();
64 pDef
->SetWithEvents();
69 Error( ERRCODE_BASIC_EXPECTED
, u
"()"_ustr
);
72 *ppDim
= std::move(pDim
);
76 // Resolving of an AS-Type-Declaration
77 // The data type were inserted into the handed over variable
79 void SbiParser::TypeDecl( SbiSymDef
& rDef
, bool bAsNewAlreadyParsed
)
81 SbxDataType eType
= rDef
.GetType();
82 if( !(bAsNewAlreadyParsed
|| Peek() == AS
) )
86 if( !bAsNewAlreadyParsed
)
89 SbiToken eTok
= Next();
90 if( !bAsNewAlreadyParsed
&& eTok
== NEW
)
99 Error( ERRCODE_BASIC_SYNTAX
);
100 eType
= SbxVARIANT
; break;
114 Error( ERRCODE_BASIC_SYNTAX
);
115 eType
= (eTok
==TBYTE
) ? SbxBYTE
: SbxDataType( eTok
- TINTEGER
+ SbxINTEGER
);
116 if( eType
== SbxSTRING
)
122 SbiConstExpression
aSize( this );
123 nSize
= aSize
.GetShortValue();
124 if( nSize
< 0 || (bVBASupportOn
&& nSize
<= 0) )
125 Error( ERRCODE_BASIC_OUT_OF_RANGE
);
127 rDef
.SetFixedStringLength( nSize
);
131 case SYMBOL
: // can only be a TYPE or an object class!
132 if( eScanType
!= SbxVARIANT
)
133 Error( ERRCODE_BASIC_SYNTAX
);
136 OUString aCompleteName
= aSym
;
138 // #52709 DIM AS NEW for Uno with full-qualified name
141 OUString
aDotStr( '.' );
142 while( Peek() == DOT
)
144 aCompleteName
+= aDotStr
;
146 SbiToken ePeekTok
= Peek();
147 if( ePeekTok
== SYMBOL
|| IsKwd( ePeekTok
) )
150 aCompleteName
+= aSym
;
155 Error( ERRCODE_BASIC_UNEXPECTED
, SYMBOL
);
160 else if( rEnumArray
->Find( aCompleteName
, SbxClassType::Object
) || ( IsVBASupportOn() && VBAConstantHelper::instance().isVBAConstantType( aCompleteName
) ) )
166 // Take over in the string pool
167 rDef
.SetTypeId( aGblStrings
.Add( aCompleteName
) );
169 if( rDef
.IsNew() && pProc
== nullptr )
170 aRequiredTypes
.push_back( aCompleteName
);
174 case FIXSTRING
: // new syntax for complex UNO types
175 rDef
.SetTypeId( aGblStrings
.Add( aSym
) );
179 Error( ERRCODE_BASIC_UNEXPECTED
, eTok
);
182 // The variable could have been declared with a suffix
183 if( rDef
.GetType() != SbxVARIANT
)
185 if( rDef
.GetType() != eType
)
186 Error( ERRCODE_BASIC_VAR_DEFINED
, rDef
.GetName() );
187 else if( eType
== SbxSTRING
&& rDef
.GetLen() != nSize
)
188 Error( ERRCODE_BASIC_VAR_DEFINED
, rDef
.GetName() );
190 rDef
.SetType( eType
);
191 rDef
.SetLen( nSize
);
194 // Here variables, arrays and structures were defined.
195 // DIM/PRIVATE/PUBLIC/GLOBAL
197 void SbiParser::Dim()
199 DefVar( SbiOpcode::DIM_
, pProc
&& bVBASupportOn
&& pProc
->IsStatic() );
202 void SbiParser::DefVar( SbiOpcode eOp
, bool bStatic
)
204 SbiSymPool
* pOldPool
= pPool
;
205 bool bSwitchPool
= false;
206 bool bPersistentGlobal
= false;
207 SbiToken eFirstTok
= eCurTok
;
209 if( pProc
&& ( eCurTok
== GLOBAL
|| eCurTok
== PUBLIC
|| eCurTok
== PRIVATE
) )
210 Error( ERRCODE_BASIC_NOT_IN_SUBR
, eCurTok
);
211 if( eCurTok
== PUBLIC
|| eCurTok
== GLOBAL
)
213 bSwitchPool
= true; // at the right moment switch to the global pool
214 if( eCurTok
== GLOBAL
)
215 bPersistentGlobal
= true;
217 // behavior in VBA is that a module scope variable's lifetime is
218 // tied to the document. e.g. a module scope variable is global
219 if( GetBasic()->IsDocBasic() && bVBASupportOn
&& !pProc
)
220 bPersistentGlobal
= true;
221 // PRIVATE is a synonymous for DIM
224 if( eCurTok
== CONST_
)
226 else if( Peek() == CONST_
)
232 // #110004 It can also be a sub/function
233 if( !bConst
&& (eCurTok
== SUB
|| eCurTok
== FUNCTION
|| eCurTok
== PROPERTY
||
234 eCurTok
== STATIC
|| eCurTok
== ENUM
|| eCurTok
== DECLARE
|| eCurTok
== TYPE
) )
236 // Next token is read here, because !bConst
237 bool bPrivate
= ( eFirstTok
== PRIVATE
);
239 if( eCurTok
== STATIC
)
242 DefStatic( bPrivate
);
244 else if( eCurTok
== SUB
|| eCurTok
== FUNCTION
|| eCurTok
== PROPERTY
)
246 // End global chain if necessary (not done in
247 // SbiParser::Parse() under these conditions
248 if( bNewGblDefs
&& nGblChain
== 0 )
250 nGblChain
= aGen
.Gen( SbiOpcode::JUMP_
, 0 );
254 DefProc( false, bPrivate
);
257 else if( eCurTok
== ENUM
)
263 else if( eCurTok
== DECLARE
)
266 DefDeclare( bPrivate
);
270 else if( eCurTok
== TYPE
)
273 DefType(); // TODO: Use bPrivate in DefType()
278 // SHARED were ignored
279 if( Peek() == SHARED
) Next();
281 // PRESERVE only at REDIM
282 if( Peek() == PRESERVE
)
285 if( eOp
== SbiOpcode::REDIM_
)
286 eOp
= SbiOpcode::REDIMP_
;
288 Error( ERRCODE_BASIC_UNEXPECTED
, eCurTok
);
293 // #40689, Statics -> Module-Initialising, skip in Sub
294 sal_uInt32 nEndOfStaticLbl
= 0;
295 if( !bVBASupportOn
&& bStatic
)
297 nEndOfStaticLbl
= aGen
.Gen( SbiOpcode::JUMP_
, 0 );
298 aGen
.Statement(); // catch up on static here
301 bool bDefined
= false;
302 while( ( pDef
= VarDecl( &pDim
, bStatic
, bConst
) ) != nullptr )
304 /*fprintf(stderr, "Actual sub: \n");
305 fprintf(stderr, "Symbol name: %s\n",OUStringToOString(pDef->GetName(),RTL_TEXTENCODING_UTF8).getStr());*/
310 SbiSymDef
* pOld
= pPool
->Find( pDef
->GetName() );
311 // search also in the Runtime-Library
312 bool bRtlSym
= false;
315 pOld
= CheckRTLForSym( pDef
->GetName(), SbxVARIANT
);
319 if( pOld
&& eOp
!= SbiOpcode::REDIM_
&& eOp
!= SbiOpcode::REDIMP_
)
321 if( pDef
->GetScope() == SbLOCAL
)
322 if (auto eOldScope
= pOld
->GetScope(); eOldScope
!= SbLOCAL
&& eOldScope
!= SbPARAM
)
328 // always an error at a RTL-S
329 if( !bRtlSym
&& (eOp
== SbiOpcode::REDIM_
|| eOp
== SbiOpcode::REDIMP_
) )
331 // compare the attributes at a REDIM
332 SbxDataType eDefType
;
333 bool bError_
= false;
334 if( pOld
->IsStatic() )
338 else if( pOld
->GetType() != ( eDefType
= pDef
->GetType() ) )
340 if( eDefType
!= SbxVARIANT
|| pDef
->IsDefinedAs() )
344 Error( ERRCODE_BASIC_VAR_DEFINED
, pDef
->GetName() );
347 Error( ERRCODE_BASIC_VAR_DEFINED
, pDef
->GetName() );
348 delete pDef
; pDef
= pOld
;
353 // #36374: Create the variable in front of the distinction IsNew()
354 // Otherwise error at Dim Identifier As New Type and option explicit
355 if( !bDefined
&& eOp
!= SbiOpcode::REDIM_
&& eOp
!= SbiOpcode::REDIMP_
356 && ( !bConst
|| pDef
->GetScope() == SbGLOBAL
) )
358 // Declare variable or global constant
360 switch ( pDef
->GetScope() )
362 case SbGLOBAL
: eOp2
= bPersistentGlobal
? SbiOpcode::GLOBAL_P_
: SbiOpcode::GLOBAL_
;
364 case SbPUBLIC
: eOp2
= bPersistentGlobal
? SbiOpcode::PUBLIC_P_
: SbiOpcode::PUBLIC_
;
365 // #40689, no own Opcode anymore
366 if( bVBASupportOn
&& bStatic
)
368 eOp2
= SbiOpcode::STATIC_
;
371 global
: aGen
.BackChain( nGblChain
);
373 bGblDefs
= bNewGblDefs
= true;
375 default: eOp2
= SbiOpcode::LOCAL_
;
377 sal_uInt32 nOpnd2
= sal::static_int_cast
< sal_uInt16
>( pDef
->GetType() );
378 if( pDef
->IsWithEvents() )
379 nOpnd2
|= SBX_TYPE_WITH_EVENTS_FLAG
;
381 if( bCompatible
&& pDef
->IsNew() )
382 nOpnd2
|= SBX_TYPE_DIM_AS_NEW_FLAG
;
384 short nFixedStringLength
= pDef
->GetFixedStringLength();
385 if( nFixedStringLength
>= 0 )
386 nOpnd2
|= (SBX_FIXED_LEN_STRING_FLAG
+ (sal_uInt32(nFixedStringLength
) << 17)); // len = all bits above 0x10000
388 if( pDim
!= nullptr && pDim
->GetDims() > 0 )
389 nOpnd2
|= SBX_TYPE_VAR_TO_DIM_FLAG
;
391 aGen
.Gen( eOp2
, pDef
->GetId(), nOpnd2
);
394 // Initialising for self-defined data types
395 // and per NEW created variable
396 if( pDef
->GetType() == SbxOBJECT
397 && pDef
->GetTypeId() )
399 if( !bCompatible
&& !pDef
->IsNew() )
401 OUString
aTypeName( aGblStrings
.Find( pDef
->GetTypeId() ) );
402 if( rTypeArray
->Find( aTypeName
, SbxClassType::Object
) == nullptr )
404 if( CodeCompleteOptions::IsExtendedTypeDeclaration() )
406 if(!IsUnoInterface(aTypeName
))
407 Error( ERRCODE_BASIC_UNDEF_TYPE
, aTypeName
);
410 Error( ERRCODE_BASIC_UNDEF_TYPE
, aTypeName
);
416 Error( ERRCODE_BASIC_SYNTAX
);
421 if( eOp
== SbiOpcode::REDIMP_
)
423 SbiExpression
aExpr( this, *pDef
, nullptr );
425 aGen
.Gen( SbiOpcode::REDIMP_ERASE_
);
427 pDef
->SetDims( pDim
->GetDims() );
428 SbiExpression
aExpr2( this, *pDef
, std::move(pDim
) );
430 aGen
.Gen( SbiOpcode::DCREATE_REDIMP_
, pDef
->GetId(), pDef
->GetTypeId() );
434 // tdf#145371, tdf#136755 - only delete the variable beforehand REDIM
435 if (eOp
== SbiOpcode::REDIM_
)
437 SbiExpression
aExpr(this, *pDef
, nullptr);
439 aGen
.Gen(bVBASupportOn
? SbiOpcode::ERASE_CLEAR_
: SbiOpcode::ERASE_
);
442 pDef
->SetDims( pDim
->GetDims() );
443 SbiExpression
aExpr2( this, *pDef
, std::move(pDim
) );
445 aGen
.Gen( SbiOpcode::DCREATE_
, pDef
->GetId(), pDef
->GetTypeId() );
450 SbiExpression
aExpr( this, *pDef
);
455 * Global X as New SomeObjectType
456 * if it has already been initialized.
457 * This approach relies on JUMPT evaluating Object->NULL as being 'false'
458 * But the effect of this code is similar to inserting
459 * If IsNull(YourGlobal)
460 * Set YourGlobal = ' new obj
461 * End If ' If IsNull(YourGlobal)
462 * Only for globals. For locals that check is skipped as it's unnecessary
464 sal_uInt32 come_from
= 0;
465 if ( pDef
->GetScope() == SbGLOBAL
)
467 come_from
= aGen
.Gen( SbiOpcode::JUMPT_
, 0 );
468 aGen
.Gen( SbiOpcode::FIND_
, pDef
->GetId(), pDef
->GetTypeId() );
471 SbiOpcode eOp_
= pDef
->IsNew() ? SbiOpcode::CREATE_
: SbiOpcode::TCREATE_
;
472 aGen
.Gen( eOp_
, pDef
->GetId(), pDef
->GetTypeId() );
474 aGen
.Gen( SbiOpcode::VBASET_
);
476 aGen
.Gen( SbiOpcode::SET_
);
480 // See other tdf#88442 comment above where come_from is
481 // initialized. This is effectively 'inserting' the
482 // End If ' If IsNull(YourGlobal)
483 aGen
.BackChain( come_from
);
491 // Definition of the constants
494 Error( ERRCODE_BASIC_SYNTAX
);
496 SbiExpression
aVar( this, *pDef
);
497 if( !TestToken( EQ
) )
498 goto MyBreak
; // (see below)
499 SbiConstExpression
aExpr( this );
500 if( !bDefined
&& aExpr
.IsValid() )
502 if( pDef
->GetScope() == SbGLOBAL
)
504 // Create code only for the global constant!
507 aGen
.Gen( SbiOpcode::PUTC_
);
509 SbiConstDef
* pConst
= pDef
->GetConstDef();
510 if( aExpr
.GetType() == SbxSTRING
)
511 pConst
->Set( aExpr
.GetString() );
513 pConst
->Set( aExpr
.GetValue(), aExpr
.GetType() );
518 // Dimension the variable
519 // Delete the var at REDIM beforehand
520 if( eOp
== SbiOpcode::REDIM_
)
522 SbiExpression
aExpr( this, *pDef
, nullptr );
525 // delete the array but
526 // clear the variable ( this
527 // allows the processing of
528 // the param to happen as normal without errors ( ordinary ERASE just clears the array )
529 aGen
.Gen( SbiOpcode::ERASE_CLEAR_
);
531 aGen
.Gen( SbiOpcode::ERASE_
);
533 else if( eOp
== SbiOpcode::REDIMP_
)
535 SbiExpression
aExpr( this, *pDef
, nullptr );
537 aGen
.Gen( SbiOpcode::REDIMP_ERASE_
);
539 pDef
->SetDims( pDim
->GetDims() );
540 if( bPersistentGlobal
)
541 pDef
->SetGlobal( true );
542 SbiExpression
aExpr( this, *pDef
, std::move(pDim
) );
544 pDef
->SetGlobal( false );
545 aGen
.Gen( (eOp
== SbiOpcode::STATIC_
) ? SbiOpcode::DIM_
: eOp
);
551 // Implementation of bSwitchPool (see above): pPool must not be set to &aGlobals
552 // at the VarDecl-Call.
553 // Apart from that the behavior should be absolutely identical,
554 // i.e., pPool had to be reset always at the end of the loop.
557 continue; // Skip MyBreak
563 // #40689, finalize the jump over statics declarations
564 if( !bVBASupportOn
&& bStatic
)
566 // maintain the global chain
567 nGblChain
= aGen
.Gen( SbiOpcode::JUMP_
, 0 );
568 bGblDefs
= bNewGblDefs
= true;
570 // Register for Sub a jump to the end of statics
571 aGen
.BackChain( nEndOfStaticLbl
);
576 // Here were Arrays redimensioned.
578 void SbiParser::ReDim()
580 DefVar( SbiOpcode::REDIM_
, pProc
&& bVBASupportOn
&& pProc
->IsStatic() );
585 void SbiParser::Erase()
589 SbiExpression
aExpr( this, SbLVALUE
);
591 aGen
.Gen( SbiOpcode::ERASE_
);
592 if( !TestComma() ) break;
596 // Declaration of a data type
598 void SbiParser::Type()
603 void SbiParser::DefType()
605 // Read the new Token lesen. It had to be a symbol
609 if (rTypeArray
->Find(aSym
,SbxClassType::Object
))
611 Error( ERRCODE_BASIC_VAR_DEFINED
, aSym
);
615 SbxObject
*pType
= new SbxObject(aSym
);
619 while( !bDone
&& !IsEof() )
621 std::unique_ptr
<SbiSymDef
> pElem
;
636 pElem
.reset(VarDecl(&pDim
, false, false));
638 bDone
= true; // Error occurred
642 SbxArray
*pTypeMembers
= pType
->GetProperties();
643 OUString aElemName
= pElem
->GetName();
644 if( pTypeMembers
->Find( aElemName
, SbxClassType::DontCare
) )
646 Error (ERRCODE_BASIC_VAR_DEFINED
);
650 SbxDataType eElemType
= pElem
->GetType();
651 SbxProperty
*pTypeElem
= new SbxProperty( aElemName
, eElemType
);
654 SbxDimArray
* pArray
= new SbxDimArray( pElem
->GetType() );
655 if ( pDim
->GetSize() )
657 // Dimension the target array
659 for ( short i
=0; i
<pDim
->GetSize();++i
)
661 sal_Int32 lb
= nBase
;
662 SbiExprNode
* pNode
= pDim
->Get(i
)->GetExprNode();
663 sal_Int32 ub
= pNode
->GetNumber();
664 if ( !pDim
->Get( i
)->IsBased() ) // each dim is low/up
666 if ( ++i
>= pDim
->GetSize() ) // trouble
667 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR
);
668 pNode
= pDim
->Get(i
)->GetExprNode();
670 ub
= pNode
->GetNumber();
672 else if ( !bCompatible
)
674 pArray
->AddDim(lb
, ub
);
676 pArray
->setHasFixedSize( true );
679 pArray
->unoAddDim(0, -1); // variant array
680 SbxFlagBits nSavFlags
= pTypeElem
->GetFlags();
681 // need to reset the FIXED flag
682 // when calling PutObject ( because the type will not match Object )
683 pTypeElem
->ResetFlag( SbxFlagBits::Fixed
);
684 pTypeElem
->PutObject( pArray
);
685 pTypeElem
->SetFlags( nSavFlags
);
688 if( eElemType
== SbxOBJECT
)
690 sal_uInt16 nElemTypeId
= pElem
->GetTypeId();
691 if( nElemTypeId
!= 0 )
693 OUString
aTypeName( aGblStrings
.Find( nElemTypeId
) );
694 SbxObject
* pTypeObj
= static_cast< SbxObject
* >( rTypeArray
->Find( aTypeName
, SbxClassType::Object
) );
695 if( pTypeObj
!= nullptr )
697 SbxObjectRef pCloneObj
= cloneTypeObjectImpl( *pTypeObj
);
698 pTypeElem
->PutObject( pCloneObj
.get() );
702 pTypeMembers
->Insert(pTypeElem
, pTypeMembers
->Count());
707 pType
->Remove( u
"Name"_ustr
, SbxClassType::DontCare
);
708 pType
->Remove( u
"Parent"_ustr
, SbxClassType::DontCare
);
710 rTypeArray
->Insert(pType
, rTypeArray
->Count());
714 // Declaration of Enum type
716 void SbiParser::Enum()
721 void SbiParser::DefEnum( bool bPrivate
)
723 // Read the new Token. It had to be a symbol
727 OUString aEnumName
= aSym
;
728 if( rEnumArray
->Find(aEnumName
,SbxClassType::Object
) )
730 Error( ERRCODE_BASIC_VAR_DEFINED
, aSym
);
734 SbxObject
*pEnum
= new SbxObject( aEnumName
);
737 pEnum
->SetFlag( SbxFlagBits::Private
);
742 // Starting with -1 to make first default value 0 after ++
743 sal_Int32 nCurrentEnumValue
= -1;
744 while( !bDone
&& !IsEof() )
763 pElem
= VarDecl( &pDim
, false, true );
766 bDone
= true; // Error occurred
771 Error( ERRCODE_BASIC_SYNTAX
);
772 bDone
= true; // Error occurred
776 SbiExpression
aVar( this, *pElem
);
781 SbiConstExpression
aExpr( this );
782 if( aExpr
.IsValid() )
784 SbxVariableRef xConvertVar
= new SbxVariable();
785 if( aExpr
.GetType() == SbxSTRING
)
786 xConvertVar
->PutString( aExpr
.GetString() );
788 xConvertVar
->PutDouble( aExpr
.GetValue() );
790 nCurrentEnumValue
= xConvertVar
->GetLong();
796 SbiSymPool
* pPoolToUse
= bPrivate
? pPool
: &aGlobals
;
798 SbiSymDef
* pOld
= pPoolToUse
->Find( pElem
->GetName() );
801 Error( ERRCODE_BASIC_VAR_DEFINED
, pElem
->GetName() );
802 bDone
= true; // Error occurred
810 aGen
.BackChain( nGblChain
);
812 bGblDefs
= bNewGblDefs
= true;
814 SbiOpcode::GLOBAL_
, pElem
->GetId(),
815 sal::static_int_cast
< sal_uInt16
>( pElem
->GetType() ) );
818 sal_uInt16 nStringId
= aGen
.GetParser()->aGblStrings
.Add( nCurrentEnumValue
, SbxLONG
);
819 aGen
.Gen( SbiOpcode::NUMBER_
, nStringId
);
820 aGen
.Gen( SbiOpcode::PUTC_
);
823 SbiConstDef
* pConst
= pElem
->GetConstDef();
824 pConst
->Set( nCurrentEnumValue
, SbxLONG
);
829 SbxArray
*pEnumMembers
= pEnum
->GetProperties();
830 SbxProperty
*pEnumElem
= new SbxProperty( pElem
->GetName(), SbxLONG
);
831 pEnumElem
->PutLong( nCurrentEnumValue
);
832 pEnumElem
->ResetFlag( SbxFlagBits::Write
);
833 pEnumElem
->SetFlag( SbxFlagBits::Const
);
834 pEnumMembers
->Insert(pEnumElem
, pEnumMembers
->Count());
838 pEnum
->Remove( u
"Name"_ustr
, SbxClassType::DontCare
);
839 pEnum
->Remove( u
"Parent"_ustr
, SbxClassType::DontCare
);
841 rEnumArray
->Insert(pEnum
, rEnumArray
->Count());
845 // Procedure-Declaration
846 // the first Token is already read in (SUB/FUNCTION)
847 // xxx Name [LIB "name"[ALIAS "name"]][(Parameter)][AS TYPE]
849 SbiProcDef
* SbiParser::ProcDecl( bool bDecl
)
851 bool bFunc
= ( eCurTok
== FUNCTION
);
852 bool bProp
= ( eCurTok
== GET
|| eCurTok
== SET
|| eCurTok
== LET
);
853 if( !TestSymbol() ) return nullptr;
854 OUString
aName( aSym
);
855 SbxDataType eType
= eScanType
;
856 SbiProcDef
* pDef
= new SbiProcDef( this, aName
, true );
857 pDef
->SetType( eType
);
858 if( Peek() == CDECL_
)
860 Next(); pDef
->SetCdecl(true);
865 if( Next() == FIXSTRING
)
867 pDef
->GetLib() = aSym
;
871 Error( ERRCODE_BASIC_SYNTAX
);
874 if( Peek() == ALIAS
)
877 if( Next() == FIXSTRING
)
879 pDef
->GetAlias() = aSym
;
883 Error( ERRCODE_BASIC_SYNTAX
);
888 // CDECL, LIB and ALIAS are invalid
889 if( !pDef
->GetLib().isEmpty() )
891 Error( ERRCODE_BASIC_UNEXPECTED
, LIB
);
893 if( !pDef
->GetAlias().isEmpty() )
895 Error( ERRCODE_BASIC_UNEXPECTED
, ALIAS
);
897 if( pDef
->IsCdecl() )
899 Error( ERRCODE_BASIC_UNEXPECTED
, CDECL_
);
901 pDef
->SetCdecl( false );
902 pDef
->GetLib().clear();
903 pDef
->GetAlias().clear();
905 else if( pDef
->GetLib().isEmpty() )
907 // ALIAS and CDECL only together with LIB
908 if( !pDef
->GetAlias().isEmpty() )
910 Error( ERRCODE_BASIC_UNEXPECTED
, ALIAS
);
912 if( pDef
->IsCdecl() )
914 Error( ERRCODE_BASIC_UNEXPECTED
, CDECL_
);
916 pDef
->SetCdecl( false );
917 pDef
->GetAlias().clear();
920 if( Peek() == LPAREN
)
923 if( Peek() == RPAREN
)
932 bool bOptional
= false;
933 bool bParamArray
= false;
934 while( Peek() == BYVAL
|| Peek() == BYREF
|| Peek() == OPTIONAL_
)
936 if( Peek() == BYVAL
)
940 else if ( Peek() == BYREF
)
944 else if ( Peek() == OPTIONAL_
)
950 if( bCompatible
&& Peek() == PARAMARRAY
)
952 if( bByVal
|| bOptional
)
954 Error( ERRCODE_BASIC_UNEXPECTED
, PARAMARRAY
);
959 SbiSymDef
* pPar
= VarDecl( nullptr, false, false );
966 pPar
->SetByVal(true);
974 pPar
->SetParamArray();
976 if (SbiSymDef
* pOldDef
= pDef
->GetParams().Find(pPar
->GetName(), false))
978 Error(ERRCODE_BASIC_VAR_DEFINED
, pPar
->GetName());
983 pDef
->GetParams().Add( pPar
);
984 SbiToken eTok
= Next();
985 if( eTok
!= COMMA
&& eTok
!= RPAREN
)
988 if( bOptional
&& bCompatible
&& eTok
== EQ
)
991 SbiConstExpression
aDefaultExpr(this);
992 SbxDataType eType2
= aDefaultExpr
.GetType();
994 sal_uInt16 nStringId
;
995 if (eType2
== SbxSTRING
)
997 nStringId
= aGblStrings
.Add(aDefaultExpr
.GetString());
1001 nStringId
= aGblStrings
.Add(aDefaultExpr
.GetValue(), eType2
);
1003 pPar
->SetDefaultId(nStringId
);
1007 if( eTok
== COMMA
|| eTok
== RPAREN
)
1014 Error( ERRCODE_BASIC_EXPECTED
, RPAREN
);
1018 if( eTok
== RPAREN
)
1026 if( eType
!= SbxVARIANT
&& pDef
->GetType() != eType
)
1028 Error( ERRCODE_BASIC_BAD_DECLARATION
, aName
);
1030 if( pDef
->GetType() == SbxVARIANT
&& !( bFunc
|| bProp
) )
1032 pDef
->SetType( SbxEMPTY
);
1039 void SbiParser::Declare()
1041 DefDeclare( false );
1044 void SbiParser::DefDeclare( bool bPrivate
)
1047 if( eCurTok
== PTRSAFE
)
1050 if( eCurTok
!= SUB
&& eCurTok
!= FUNCTION
)
1052 Error( ERRCODE_BASIC_UNEXPECTED
, eCurTok
);
1056 bool bFunction
= (eCurTok
== FUNCTION
);
1058 SbiProcDef
* pDef
= ProcDecl( true );
1061 if( pDef
->GetLib().isEmpty() )
1063 Error( ERRCODE_BASIC_EXPECTED
, LIB
);
1065 // Is it already there?
1066 SbiSymDef
* pOld
= aPublics
.Find( pDef
->GetName() );
1069 SbiProcDef
* p
= pOld
->GetProcDef();
1072 // Declared as a variable
1073 Error( ERRCODE_BASIC_BAD_DECLARATION
, pDef
->GetName() );
1084 aPublics
.Add( pDef
);
1088 pDef
->SetPublic( !bPrivate
);
1090 // New declare handling
1091 if( !pDef
->GetLib().isEmpty())
1093 if( bNewGblDefs
&& nGblChain
== 0 )
1095 nGblChain
= aGen
.Gen( SbiOpcode::JUMP_
, 0 );
1096 bNewGblDefs
= false;
1099 sal_uInt16 nSavLine
= nLine
;
1102 pDef
->SetLine1( nSavLine
);
1103 pDef
->SetLine2( nSavLine
);
1105 SbiSymPool
& rPool
= pDef
->GetParams();
1106 sal_uInt16 nParCount
= rPool
.GetSize();
1108 SbxDataType eType
= pDef
->GetType();
1111 aGen
.Gen( SbiOpcode::PARAM_
, 0, sal::static_int_cast
< sal_uInt16
>( eType
) );
1115 aGen
.Gen( SbiOpcode::ARGC_
);
1117 for( sal_uInt16 i
= 1 ; i
< nParCount
; ++i
)
1119 SbiSymDef
* pParDef
= rPool
.Get( i
);
1120 SbxDataType eParType
= pParDef
->GetType();
1122 aGen
.Gen( SbiOpcode::PARAM_
, i
, sal::static_int_cast
< sal_uInt16
>( eParType
) );
1123 aGen
.Gen( SbiOpcode::ARGV_
);
1125 sal_uInt16 nTyp
= sal::static_int_cast
< sal_uInt16
>( pParDef
->GetType() );
1126 if( pParDef
->IsByVal() )
1128 // Reset to avoid additional byval in call to wrapper function
1129 pParDef
->SetByVal( false );
1132 aGen
.Gen( SbiOpcode::ARGTYP_
, nTyp
);
1136 aGen
.Gen( SbiOpcode::LIB_
, aGblStrings
.Add( pDef
->GetLib() ) );
1138 SbiOpcode eOp
= pDef
->IsCdecl() ? SbiOpcode::CALLC_
: SbiOpcode::CALL_
;
1139 sal_uInt16 nId
= pDef
->GetId();
1140 if( !pDef
->GetAlias().isEmpty() )
1142 nId
= ( nId
& 0x8000 ) | aGblStrings
.Add( pDef
->GetAlias() );
1148 aGen
.Gen( eOp
, nId
, sal::static_int_cast
< sal_uInt16
>( eType
) );
1152 aGen
.Gen( SbiOpcode::PUT_
);
1154 aGen
.Gen( SbiOpcode::LEAVE_
);
1161 void SbiParser::Attribute()
1163 // TODO: Need to implement the method as an attributed object.
1164 while( Next() != EQ
)
1174 Error( ERRCODE_BASIC_SYNTAX
);
1178 SbiExpression
aValue( this );
1180 // Don't generate any code - just discard it.
1183 // Call of a SUB or a FUNCTION
1185 void SbiParser::Call()
1187 SbiExpression
aVar( this, SbSYMBOL
);
1188 aVar
.Gen( FORCE_CALL
);
1189 aGen
.Gen( SbiOpcode::GET_
);
1194 void SbiParser::SubFunc()
1196 DefProc( false, false );
1199 // Read in of a procedure
1201 void SbiParser::DefProc( bool bStatic
, bool bPrivate
)
1203 sal_uInt16 l1
= nLine
;
1204 bool bSub
= ( eCurTok
== SUB
);
1205 bool bProperty
= ( eCurTok
== PROPERTY
);
1206 PropertyMode ePropertyMode
= PropertyMode::NONE
;
1210 if( eCurTok
== GET
)
1212 ePropertyMode
= PropertyMode::Get
;
1214 else if( eCurTok
== LET
)
1216 ePropertyMode
= PropertyMode::Let
;
1218 else if( eCurTok
== SET
)
1220 ePropertyMode
= PropertyMode::Set
;
1224 Error( ERRCODE_BASIC_EXPECTED
, u
"Get or Let or Set"_ustr
);
1228 SbiToken eExit
= eCurTok
;
1229 SbiProcDef
* pDef
= ProcDecl( false );
1234 pDef
->setPropertyMode( ePropertyMode
);
1236 // Is the Proc already declared?
1237 SbiSymDef
* pOld
= aPublics
.Find( pDef
->GetName() );
1240 pProc
= pOld
->GetProcDef();
1243 // Declared as a variable
1244 Error( ERRCODE_BASIC_BAD_DECLARATION
, pDef
->GetName() );
1248 // #100027: Multiple declaration -> Error
1249 // #112787: Not for setup, REMOVE for 8
1250 else if( pProc
->IsUsedForProcDecl() )
1252 PropertyMode ePropMode
= pDef
->getPropertyMode();
1253 if( ePropMode
== PropertyMode::NONE
|| ePropMode
== pProc
->getPropertyMode() )
1255 Error( ERRCODE_BASIC_PROC_DEFINED
, pDef
->GetName() );
1261 pDef
->Match( pProc
);
1265 aPublics
.Add( pDef
);
1269 pProc
->SetPublic( !bPrivate
);
1271 // Now we set the search hierarchy for symbols as well as the
1272 // current procedure.
1273 aPublics
.SetProcId( pProc
->GetId() );
1274 pProc
->GetParams().SetParent( &aPublics
);
1277 if ( bVBASupportOn
)
1283 Error( ERRCODE_BASIC_NOT_IMPLEMENTED
); // STATIC SUB ...
1288 pProc
->SetStatic( false );
1290 // Normal case: Local variable->parameter->global variable
1291 pProc
->GetLocals().SetParent( &pProc
->GetParams() );
1292 pPool
= &pProc
->GetLocals();
1296 StmntBlock( bSub
? ENDSUB
: (bProperty
? ENDPROPERTY
: ENDFUNC
) );
1297 sal_uInt16 l2
= nLine
;
1298 pProc
->SetLine1( l1
);
1299 pProc
->SetLine2( l2
);
1301 aPublics
.SetProcId( 0 );
1303 pProc
->GetLabels().CheckRefs();
1305 aGen
.Gen( SbiOpcode::LEAVE_
);
1309 // STATIC variable|procedure
1311 void SbiParser::Static()
1316 void SbiParser::DefStatic( bool bPrivate
)
1325 // End global chain if necessary (not done in
1326 // SbiParser::Parse() under these conditions
1327 if( bNewGblDefs
&& nGblChain
== 0 )
1329 nGblChain
= aGen
.Gen( SbiOpcode::JUMP_
, 0 );
1330 bNewGblDefs
= false;
1333 DefProc( true, bPrivate
);
1338 Error( ERRCODE_BASIC_NOT_IN_SUBR
);
1340 // Reset the Pool, so that STATIC-Declarations go into the
1344 DefVar( SbiOpcode::STATIC_
, true );
1350 bool SbiParser::IsUnoInterface(const OUString
& sTypeName
)
1354 return css::reflection::theCoreReflection::get(
1355 comphelper::getProcessComponentContext())->forName(sTypeName
).is();
1357 catch(const Exception
&)
1359 OSL_FAIL("Could not create reflection.CoreReflection.");
1364 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */