Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / basic / source / comp / dim.cxx
blob6e6c3e024d67e965b0e1309199ffb9b012f6da0e
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 .
20 #include <basic/sberrors.hxx>
21 #include <basic/sbstar.hxx>
22 #include <basic/sbx.hxx>
23 #include <sbunoobj.hxx>
24 #include <parser.hxx>
25 #include <sb.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>
31 #include <memory>
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 )
46 Next();
47 bWithEvents = true;
49 if( !TestSymbol() ) return nullptr;
50 SbxDataType t = eScanType;
51 SbiSymDef* pDef = bConst ? new SbiConstDef( aSym ) : new SbiSymDef( aSym );
52 SbiExprListPtr pDim;
53 // Brackets?
54 if( Peek() == LPAREN )
56 pDim = SbiExprList::ParseDimList( this );
57 if( !pDim->GetDims() )
58 pDef->SetWithBrackets();
60 pDef->SetType( t );
61 if( bStatic )
62 pDef->SetStatic();
63 if( bWithEvents )
64 pDef->SetWithEvents();
65 TypeDecl( *pDef );
66 if( !ppDim && pDim )
68 if(pDim->GetDims() )
69 Error( ERRCODE_BASIC_EXPECTED, "()" );
71 else if( ppDim )
72 *ppDim = std::move(pDim);
73 return pDef;
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 )
84 short nSize = 0;
85 if( !bAsNewAlreadyParsed )
86 Next();
87 rDef.SetDefinedAs();
88 SbiToken eTok = Next();
89 if( !bAsNewAlreadyParsed && eTok == NEW )
91 rDef.SetNew();
92 eTok = Next();
94 switch( eTok )
96 case ANY:
97 if( rDef.IsNew() )
98 Error( ERRCODE_BASIC_SYNTAX );
99 eType = SbxVARIANT; break;
100 case TINTEGER:
101 case TLONG:
102 case TSINGLE:
103 case TDOUBLE:
104 case TCURRENCY:
105 case TDATE:
106 case TSTRING:
107 case TOBJECT:
108 case ERROR_:
109 case TBOOLEAN:
110 case TVARIANT:
111 case TBYTE:
112 if( rDef.IsNew() )
113 Error( ERRCODE_BASIC_SYNTAX );
114 eType = (eTok==TBYTE) ? SbxBYTE : SbxDataType( eTok - TINTEGER + SbxINTEGER );
115 if( eType == SbxSTRING )
117 // STRING*n ?
118 if( Peek() == MUL )
119 { // fixed size!
120 Next();
121 SbiConstExpression aSize( this );
122 nSize = aSize.GetShortValue();
123 if( nSize < 0 || (bVBASupportOn && nSize <= 0) )
124 Error( ERRCODE_BASIC_OUT_OF_RANGE );
125 else
126 rDef.SetFixedStringLength( nSize );
129 break;
130 case SYMBOL: // can only be a TYPE or an object class!
131 if( eScanType != SbxVARIANT )
132 Error( ERRCODE_BASIC_SYNTAX );
133 else
135 OUString aCompleteName = aSym;
137 // #52709 DIM AS NEW for Uno with full-qualified name
138 if( Peek() == DOT )
140 OUString aDotStr( '.' );
141 while( Peek() == DOT )
143 aCompleteName += aDotStr;
144 Next();
145 SbiToken ePeekTok = Peek();
146 if( ePeekTok == SYMBOL || IsKwd( ePeekTok ) )
148 Next();
149 aCompleteName += aSym;
151 else
153 Next();
154 Error( ERRCODE_BASIC_UNEXPECTED, SYMBOL );
155 break;
159 else if( rEnumArray->Find( aCompleteName, SbxClassType::Object ) || ( IsVBASupportOn() && VBAConstantHelper::instance().isVBAConstantType( aCompleteName ) ) )
161 eType = SbxLONG;
162 break;
165 // Take over in the string pool
166 rDef.SetTypeId( aGblStrings.Add( aCompleteName ) );
168 if( rDef.IsNew() && pProc == nullptr )
169 aRequiredTypes.push_back( aCompleteName );
171 eType = SbxOBJECT;
172 break;
173 case FIXSTRING: // new syntax for complex UNO types
174 rDef.SetTypeId( aGblStrings.Add( aSym ) );
175 eType = SbxOBJECT;
176 break;
177 default:
178 Error( ERRCODE_BASIC_UNEXPECTED, eTok );
179 Next();
181 // The variable could have been declared with a suffix
182 if( rDef.GetType() != SbxVARIANT )
184 if( rDef.GetType() != eType )
185 Error( ERRCODE_BASIC_VAR_DEFINED, rDef.GetName() );
186 else if( eType == SbxSTRING && rDef.GetLen() != nSize )
187 Error( ERRCODE_BASIC_VAR_DEFINED, rDef.GetName() );
189 rDef.SetType( eType );
190 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
222 // _CONST_?
223 bool bConst = false;
224 if( eCurTok == CONST_ )
225 bConst = true;
226 else if( Peek() == CONST_ )
228 Next();
229 bConst = true;
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 )
241 Next();
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 );
251 bNewGblDefs = false;
253 Next();
254 DefProc( false, bPrivate );
255 return;
257 else if( eCurTok == ENUM )
259 Next();
260 DefEnum( bPrivate );
261 return;
263 else if( eCurTok == DECLARE )
265 Next();
266 DefDeclare( bPrivate );
267 return;
269 // #i109049
270 else if( eCurTok == TYPE )
272 Next();
273 DefType(); // TODO: Use bPrivate in DefType()
274 return;
278 // SHARED were ignored
279 if( Peek() == SHARED ) Next();
281 // PRESERVE only at REDIM
282 if( Peek() == PRESERVE )
284 Next();
285 if( eOp == SbiOpcode::REDIM_ )
286 eOp = SbiOpcode::REDIMP_;
287 else
288 Error( ERRCODE_BASIC_UNEXPECTED, eCurTok );
290 SbiSymDef* pDef;
291 SbiExprListPtr pDim;
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());*/
306 EnableErrors();
307 // search variable:
308 if( bSwitchPool )
309 pPool = &aGlobals;
310 SbiSymDef* pOld = pPool->Find( pDef->GetName() );
311 // search also in the Runtime-Library
312 bool bRtlSym = false;
313 if( !pOld )
315 pOld = CheckRTLForSym( pDef->GetName(), SbxVARIANT );
316 if( pOld )
317 bRtlSym = true;
319 if( pOld && !(eOp == SbiOpcode::REDIM_ || eOp == SbiOpcode::REDIMP_) )
321 if( pDef->GetScope() == SbLOCAL )
322 if (auto eOldScope = pOld->GetScope(); eOldScope != SbLOCAL && eOldScope != SbPARAM)
323 pOld = nullptr;
325 if( pOld )
327 bDefined = true;
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() )
336 bError_ = true;
338 else if( pOld->GetType() != ( eDefType = pDef->GetType() ) )
340 if( !( eDefType == SbxVARIANT && !pDef->IsDefinedAs() ) )
341 bError_ = true;
343 if( bError_ )
344 Error( ERRCODE_BASIC_VAR_DEFINED, pDef->GetName() );
346 else
347 Error( ERRCODE_BASIC_VAR_DEFINED, pDef->GetName() );
348 delete pDef; pDef = pOld;
350 else
351 pPool->Add( pDef );
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
359 SbiOpcode eOp2;
360 switch ( pDef->GetScope() )
362 case SbGLOBAL: eOp2 = bPersistentGlobal ? SbiOpcode::GLOBAL_P_ : SbiOpcode::GLOBAL_;
363 goto 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_;
369 break;
371 global: aGen.BackChain( nGblChain );
372 nGblChain = 0;
373 bGblDefs = bNewGblDefs = true;
374 break;
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 );
409 else
410 Error( ERRCODE_BASIC_UNDEF_TYPE, aTypeName );
414 if( bConst )
416 Error( ERRCODE_BASIC_SYNTAX );
419 if( pDim )
421 if( eOp == SbiOpcode::REDIMP_ )
423 SbiExpression aExpr( this, *pDef, nullptr );
424 aExpr.Gen();
425 aGen.Gen( SbiOpcode::REDIMP_ERASE_ );
427 pDef->SetDims( pDim->GetDims() );
428 SbiExpression aExpr2( this, *pDef, std::move(pDim) );
429 aExpr2.Gen();
430 aGen.Gen( SbiOpcode::DCREATE_REDIMP_, pDef->GetId(), pDef->GetTypeId() );
432 else
434 pDef->SetDims( pDim->GetDims() );
435 SbiExpression aExpr( this, *pDef, std::move(pDim) );
436 aExpr.Gen();
437 aGen.Gen( SbiOpcode::DCREATE_, pDef->GetId(), pDef->GetTypeId() );
440 else
442 SbiExpression aExpr( this, *pDef );
443 aExpr.Gen();
444 SbiOpcode eOp_ = pDef->IsNew() ? SbiOpcode::CREATE_ : SbiOpcode::TCREATE_;
445 aGen.Gen( eOp_, pDef->GetId(), pDef->GetTypeId() );
446 if ( bVBASupportOn )
447 aGen.Gen( SbiOpcode::VBASET_ );
448 else
449 aGen.Gen( SbiOpcode::SET_ );
452 else
454 if( bConst )
456 // Definition of the constants
457 if( pDim )
459 Error( ERRCODE_BASIC_SYNTAX );
461 SbiExpression aVar( this, *pDef );
462 if( !TestToken( EQ ) )
463 goto MyBreak; // (see below)
464 SbiConstExpression aExpr( this );
465 if( !bDefined && aExpr.IsValid() )
467 if( pDef->GetScope() == SbGLOBAL )
469 // Create code only for the global constant!
470 aVar.Gen();
471 aExpr.Gen();
472 aGen.Gen( SbiOpcode::PUTC_ );
474 SbiConstDef* pConst = pDef->GetConstDef();
475 if( aExpr.GetType() == SbxSTRING )
476 pConst->Set( aExpr.GetString() );
477 else
478 pConst->Set( aExpr.GetValue(), aExpr.GetType() );
481 else if( pDim )
483 // Dimension the variable
484 // Delete the var at REDIM beforehand
485 if( eOp == SbiOpcode::REDIM_ )
487 SbiExpression aExpr( this, *pDef, nullptr );
488 aExpr.Gen();
489 if ( bVBASupportOn )
490 // delete the array but
491 // clear the variable ( this
492 // allows the processing of
493 // the param to happen as normal without errors ( ordinary ERASE just clears the array )
494 aGen.Gen( SbiOpcode::ERASE_CLEAR_ );
495 else
496 aGen.Gen( SbiOpcode::ERASE_ );
498 else if( eOp == SbiOpcode::REDIMP_ )
500 SbiExpression aExpr( this, *pDef, nullptr );
501 aExpr.Gen();
502 aGen.Gen( SbiOpcode::REDIMP_ERASE_ );
504 pDef->SetDims( pDim->GetDims() );
505 if( bPersistentGlobal )
506 pDef->SetGlobal( true );
507 SbiExpression aExpr( this, *pDef, std::move(pDim) );
508 aExpr.Gen();
509 pDef->SetGlobal( false );
510 aGen.Gen( (eOp == SbiOpcode::STATIC_) ? SbiOpcode::DIM_ : eOp );
513 if( !TestComma() )
514 goto MyBreak;
516 // Implementation of bSwitchPool (see above): pPool must not be set to &aGlobals
517 // at the VarDecl-Call.
518 // Apart from that the behavior should be absolutely identical,
519 // i.e., pPool had to be reset always at the end of the loop.
520 // also at a break
521 pPool = pOldPool;
522 continue; // Skip MyBreak
523 MyBreak:
524 pPool = pOldPool;
525 break;
528 // #40689, finalize the jump over statics declarations
529 if( !bVBASupportOn && bStatic )
531 // maintain the global chain
532 nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
533 bGblDefs = bNewGblDefs = true;
535 // Register for Sub a jump to the end of statics
536 aGen.BackChain( nEndOfStaticLbl );
541 // Here were Arrays redimensioned.
543 void SbiParser::ReDim()
545 DefVar( SbiOpcode::REDIM_, pProc && bVBASupportOn && pProc->IsStatic() );
548 // ERASE array, ...
550 void SbiParser::Erase()
552 while( !bAbort )
554 SbiExpression aExpr( this, SbLVALUE );
555 aExpr.Gen();
556 aGen.Gen( SbiOpcode::ERASE_ );
557 if( !TestComma() ) break;
561 // Declaration of a data type
563 void SbiParser::Type()
565 DefType();
568 void SbiParser::DefType()
570 // Read the new Token lesen. It had to be a symbol
571 if (!TestSymbol())
572 return;
574 if (rTypeArray->Find(aSym,SbxClassType::Object))
576 Error( ERRCODE_BASIC_VAR_DEFINED, aSym );
577 return;
580 SbxObject *pType = new SbxObject(aSym);
582 bool bDone = false;
584 while( !bDone && !IsEof() )
586 std::unique_ptr<SbiSymDef> pElem;
587 SbiExprListPtr pDim;
588 switch( Peek() )
590 case ENDTYPE :
591 bDone = true;
592 Next();
593 break;
595 case EOLN :
596 case REM :
597 Next();
598 break;
600 default:
601 pElem.reset(VarDecl(&pDim, false, false));
602 if( !pElem )
603 bDone = true; // Error occurred
605 if( pElem )
607 SbxArray *pTypeMembers = pType->GetProperties();
608 OUString aElemName = pElem->GetName();
609 if( pTypeMembers->Find( aElemName, SbxClassType::DontCare) )
611 Error (ERRCODE_BASIC_VAR_DEFINED);
613 else
615 SbxDataType eElemType = pElem->GetType();
616 SbxProperty *pTypeElem = new SbxProperty( aElemName, eElemType );
617 if( pDim )
619 SbxDimArray* pArray = new SbxDimArray( pElem->GetType() );
620 if ( pDim->GetSize() )
622 // Dimension the target array
624 for ( short i=0; i<pDim->GetSize();++i )
626 sal_Int32 lb = nBase;
627 SbiExprNode* pNode = pDim->Get(i)->GetExprNode();
628 sal_Int32 ub = pNode->GetNumber();
629 if ( !pDim->Get( i )->IsBased() ) // each dim is low/up
631 if ( ++i >= pDim->GetSize() ) // trouble
632 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR );
633 pNode = pDim->Get(i)->GetExprNode();
634 lb = ub;
635 ub = pNode->GetNumber();
637 else if ( !bCompatible )
638 ub += nBase;
639 pArray->AddDim32( lb, ub );
641 pArray->setHasFixedSize( true );
643 else
644 pArray->unoAddDim( 0, -1 ); // variant array
645 SbxFlagBits nSavFlags = pTypeElem->GetFlags();
646 // need to reset the FIXED flag
647 // when calling PutObject ( because the type will not match Object )
648 pTypeElem->ResetFlag( SbxFlagBits::Fixed );
649 pTypeElem->PutObject( pArray );
650 pTypeElem->SetFlags( nSavFlags );
652 // Nested user type?
653 if( eElemType == SbxOBJECT )
655 sal_uInt16 nElemTypeId = pElem->GetTypeId();
656 if( nElemTypeId != 0 )
658 OUString aTypeName( aGblStrings.Find( nElemTypeId ) );
659 SbxObject* pTypeObj = static_cast< SbxObject* >( rTypeArray->Find( aTypeName, SbxClassType::Object ) );
660 if( pTypeObj != nullptr )
662 SbxObject* pCloneObj = cloneTypeObjectImpl( *pTypeObj );
663 pTypeElem->PutObject( pCloneObj );
667 pTypeMembers->Insert( pTypeElem, pTypeMembers->Count() );
672 pType->Remove( "Name", SbxClassType::DontCare );
673 pType->Remove( "Parent", SbxClassType::DontCare );
675 rTypeArray->Insert (pType,rTypeArray->Count());
679 // Declaration of Enum type
681 void SbiParser::Enum()
683 DefEnum( false );
686 void SbiParser::DefEnum( bool bPrivate )
688 // Read the new Token. It had to be a symbol
689 if (!TestSymbol())
690 return;
692 OUString aEnumName = aSym;
693 if( rEnumArray->Find(aEnumName,SbxClassType::Object) )
695 Error( ERRCODE_BASIC_VAR_DEFINED, aSym );
696 return;
699 SbxObject *pEnum = new SbxObject( aEnumName );
700 if( bPrivate )
702 pEnum->SetFlag( SbxFlagBits::Private );
704 SbiSymDef* pElem;
705 bool bDone = false;
707 // Starting with -1 to make first default value 0 after ++
708 sal_Int32 nCurrentEnumValue = -1;
709 while( !bDone && !IsEof() )
711 switch( Peek() )
713 case ENDENUM :
714 pElem = nullptr;
715 bDone = true;
716 Next();
717 break;
719 case EOLN :
720 case REM :
721 pElem = nullptr;
722 Next();
723 break;
725 default:
727 SbiExprListPtr pDim;
728 pElem = VarDecl( &pDim, false, true );
729 if( !pElem )
731 bDone = true; // Error occurred
732 break;
734 else if( pDim )
736 Error( ERRCODE_BASIC_SYNTAX );
737 bDone = true; // Error occurred
738 break;
741 SbiExpression aVar( this, *pElem );
742 if( Peek() == EQ )
744 Next();
746 SbiConstExpression aExpr( this );
747 if( aExpr.IsValid() )
749 SbxVariableRef xConvertVar = new SbxVariable();
750 if( aExpr.GetType() == SbxSTRING )
751 xConvertVar->PutString( aExpr.GetString() );
752 else
753 xConvertVar->PutDouble( aExpr.GetValue() );
755 nCurrentEnumValue = xConvertVar->GetLong();
758 else
759 nCurrentEnumValue++;
761 SbiSymPool* pPoolToUse = bPrivate ? pPool : &aGlobals;
763 SbiSymDef* pOld = pPoolToUse->Find( pElem->GetName() );
764 if( pOld )
766 Error( ERRCODE_BASIC_VAR_DEFINED, pElem->GetName() );
767 bDone = true; // Error occurred
768 break;
771 pPool->Add( pElem );
773 if( !bPrivate )
775 aGen.BackChain( nGblChain );
776 nGblChain = 0;
777 bGblDefs = bNewGblDefs = true;
778 aGen.Gen(
779 SbiOpcode::GLOBAL_, pElem->GetId(),
780 sal::static_int_cast< sal_uInt16 >( pElem->GetType() ) );
782 aVar.Gen();
783 sal_uInt16 nStringId = aGen.GetParser()->aGblStrings.Add( nCurrentEnumValue, SbxLONG );
784 aGen.Gen( SbiOpcode::NUMBER_, nStringId );
785 aGen.Gen( SbiOpcode::PUTC_ );
788 SbiConstDef* pConst = pElem->GetConstDef();
789 pConst->Set( nCurrentEnumValue, SbxLONG );
792 if( pElem )
794 SbxArray *pEnumMembers = pEnum->GetProperties();
795 SbxProperty *pEnumElem = new SbxProperty( pElem->GetName(), SbxLONG );
796 pEnumElem->PutLong( nCurrentEnumValue );
797 pEnumElem->ResetFlag( SbxFlagBits::Write );
798 pEnumElem->SetFlag( SbxFlagBits::Const );
799 pEnumMembers->Insert( pEnumElem, pEnumMembers->Count() );
803 pEnum->Remove( "Name", SbxClassType::DontCare );
804 pEnum->Remove( "Parent", SbxClassType::DontCare );
806 rEnumArray->Insert( pEnum, rEnumArray->Count() );
810 // Procedure-Declaration
811 // the first Token is already read in (SUB/FUNCTION)
812 // xxx Name [LIB "name"[ALIAS "name"]][(Parameter)][AS TYPE]
814 SbiProcDef* SbiParser::ProcDecl( bool bDecl )
816 bool bFunc = ( eCurTok == FUNCTION );
817 bool bProp = ( eCurTok == GET || eCurTok == SET || eCurTok == LET );
818 if( !TestSymbol() ) return nullptr;
819 OUString aName( aSym );
820 SbxDataType eType = eScanType;
821 SbiProcDef* pDef = new SbiProcDef( this, aName, true );
822 pDef->SetType( eType );
823 if( Peek() == CDECL_ )
825 Next(); pDef->SetCdecl(true);
827 if( Peek() == LIB )
829 Next();
830 if( Next() == FIXSTRING )
832 pDef->GetLib() = aSym;
834 else
836 Error( ERRCODE_BASIC_SYNTAX );
839 if( Peek() == ALIAS )
841 Next();
842 if( Next() == FIXSTRING )
844 pDef->GetAlias() = aSym;
846 else
848 Error( ERRCODE_BASIC_SYNTAX );
851 if( !bDecl )
853 // CDECL, LIB and ALIAS are invalid
854 if( !pDef->GetLib().isEmpty() )
856 Error( ERRCODE_BASIC_UNEXPECTED, LIB );
858 if( !pDef->GetAlias().isEmpty() )
860 Error( ERRCODE_BASIC_UNEXPECTED, ALIAS );
862 if( pDef->IsCdecl() )
864 Error( ERRCODE_BASIC_UNEXPECTED, CDECL_ );
866 pDef->SetCdecl( false );
867 pDef->GetLib().clear();
868 pDef->GetAlias().clear();
870 else if( pDef->GetLib().isEmpty() )
872 // ALIAS and CDECL only together with LIB
873 if( !pDef->GetAlias().isEmpty() )
875 Error( ERRCODE_BASIC_UNEXPECTED, ALIAS );
877 if( pDef->IsCdecl() )
879 Error( ERRCODE_BASIC_UNEXPECTED, CDECL_ );
881 pDef->SetCdecl( false );
882 pDef->GetAlias().clear();
884 // Brackets?
885 if( Peek() == LPAREN )
887 Next();
888 if( Peek() == RPAREN )
890 Next();
892 else
894 for(;;)
896 bool bByVal = false;
897 bool bOptional = false;
898 bool bParamArray = false;
899 while( Peek() == BYVAL || Peek() == BYREF || Peek() == OPTIONAL_ )
901 if( Peek() == BYVAL )
903 bByVal = true;
905 else if ( Peek() == BYREF )
907 bByVal = false;
909 else if ( Peek() == OPTIONAL_ )
911 bOptional = true;
913 Next();
915 if( bCompatible && Peek() == PARAMARRAY )
917 if( bByVal || bOptional )
919 Error( ERRCODE_BASIC_UNEXPECTED, PARAMARRAY );
921 Next();
922 bParamArray = true;
924 SbiSymDef* pPar = VarDecl( nullptr, false, false );
925 if( !pPar )
927 break;
929 if( bByVal )
931 pPar->SetByVal(true);
933 if( bOptional )
935 pPar->SetOptional();
937 if( bParamArray )
939 pPar->SetParamArray();
941 if (SbiSymDef* pOldDef = pDef->GetParams().Find(pPar->GetName(), false))
943 Error(ERRCODE_BASIC_VAR_DEFINED, pPar->GetName());
944 delete pPar;
945 pPar = pOldDef;
947 else
948 pDef->GetParams().Add( pPar );
949 SbiToken eTok = Next();
950 if( eTok != COMMA && eTok != RPAREN )
952 bool bError2 = true;
953 if( bOptional && bCompatible && eTok == EQ )
955 std::unique_ptr<SbiConstExpression> pDefaultExpr(new SbiConstExpression( this ));
956 SbxDataType eType2 = pDefaultExpr->GetType();
958 sal_uInt16 nStringId;
959 if( eType2 == SbxSTRING )
961 nStringId = aGblStrings.Add( pDefaultExpr->GetString() );
963 else
965 nStringId = aGblStrings.Add( pDefaultExpr->GetValue(), eType2 );
967 pPar->SetDefaultId( nStringId );
968 pDefaultExpr.reset();
970 eTok = Next();
971 if( eTok == COMMA || eTok == RPAREN )
973 bError2 = false;
976 if( bError2 )
978 Error( ERRCODE_BASIC_EXPECTED, RPAREN );
979 break;
982 if( eTok == RPAREN )
984 break;
989 TypeDecl( *pDef );
990 if( eType != SbxVARIANT && pDef->GetType() != eType )
992 Error( ERRCODE_BASIC_BAD_DECLARATION, aName );
994 if( pDef->GetType() == SbxVARIANT && !( bFunc || bProp ) )
996 pDef->SetType( SbxEMPTY );
998 return pDef;
1001 // DECLARE
1003 void SbiParser::Declare()
1005 DefDeclare( false );
1008 void SbiParser::DefDeclare( bool bPrivate )
1010 Next();
1011 if( eCurTok == PTRSAFE )
1012 Next();
1014 if( eCurTok != SUB && eCurTok != FUNCTION )
1016 Error( ERRCODE_BASIC_UNEXPECTED, eCurTok );
1018 else
1020 bool bFunction = (eCurTok == FUNCTION);
1022 SbiProcDef* pDef = ProcDecl( true );
1023 if( pDef )
1025 if( pDef->GetLib().isEmpty() )
1027 Error( ERRCODE_BASIC_EXPECTED, LIB );
1029 // Is it already there?
1030 SbiSymDef* pOld = aPublics.Find( pDef->GetName() );
1031 if( pOld )
1033 SbiProcDef* p = pOld->GetProcDef();
1034 if( !p )
1036 // Declared as a variable
1037 Error( ERRCODE_BASIC_BAD_DECLARATION, pDef->GetName() );
1038 delete pDef;
1039 pDef = nullptr;
1041 else
1043 pDef->Match( p );
1046 else
1048 aPublics.Add( pDef );
1050 if ( pDef )
1052 pDef->SetPublic( !bPrivate );
1054 // New declare handling
1055 if( !pDef->GetLib().isEmpty())
1057 if( bNewGblDefs && nGblChain == 0 )
1059 nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
1060 bNewGblDefs = false;
1063 sal_uInt16 nSavLine = nLine;
1064 aGen.Statement();
1065 pDef->Define();
1066 pDef->SetLine1( nSavLine );
1067 pDef->SetLine2( nSavLine );
1069 SbiSymPool& rPool = pDef->GetParams();
1070 sal_uInt16 nParCount = rPool.GetSize();
1072 SbxDataType eType = pDef->GetType();
1073 if( bFunction )
1075 aGen.Gen( SbiOpcode::PARAM_, 0, sal::static_int_cast< sal_uInt16 >( eType ) );
1077 if( nParCount > 1 )
1079 aGen.Gen( SbiOpcode::ARGC_ );
1081 for( sal_uInt16 i = 1 ; i < nParCount ; ++i )
1083 SbiSymDef* pParDef = rPool.Get( i );
1084 SbxDataType eParType = pParDef->GetType();
1086 aGen.Gen( SbiOpcode::PARAM_, i, sal::static_int_cast< sal_uInt16 >( eParType ) );
1087 aGen.Gen( SbiOpcode::ARGV_ );
1089 sal_uInt16 nTyp = sal::static_int_cast< sal_uInt16 >( pParDef->GetType() );
1090 if( pParDef->IsByVal() )
1092 // Reset to avoid additional byval in call to wrapper function
1093 pParDef->SetByVal( false );
1094 nTyp |= 0x8000;
1096 aGen.Gen( SbiOpcode::ARGTYP_, nTyp );
1100 aGen.Gen( SbiOpcode::LIB_, aGblStrings.Add( pDef->GetLib() ) );
1102 SbiOpcode eOp = pDef->IsCdecl() ? SbiOpcode::CALLC_ : SbiOpcode::CALL_;
1103 sal_uInt16 nId = pDef->GetId();
1104 if( !pDef->GetAlias().isEmpty() )
1106 nId = ( nId & 0x8000 ) | aGblStrings.Add( pDef->GetAlias() );
1108 if( nParCount > 1 )
1110 nId |= 0x8000;
1112 aGen.Gen( eOp, nId, sal::static_int_cast< sal_uInt16 >( eType ) );
1114 if( bFunction )
1116 aGen.Gen( SbiOpcode::PUT_ );
1118 aGen.Gen( SbiOpcode::LEAVE_ );
1125 void SbiParser::Attribute()
1127 // TODO: Need to implement the method as an attributed object.
1128 while( Next() != EQ )
1130 if( Next() != DOT)
1132 break;
1136 if( eCurTok != EQ )
1138 Error( ERRCODE_BASIC_SYNTAX );
1140 else
1142 SbiExpression aValue( this );
1144 // Don't generate any code - just discard it.
1147 // Call of a SUB or a FUNCTION
1149 void SbiParser::Call()
1151 SbiExpression aVar( this, SbSYMBOL );
1152 aVar.Gen( FORCE_CALL );
1153 aGen.Gen( SbiOpcode::GET_ );
1156 // SUB/FUNCTION
1158 void SbiParser::SubFunc()
1160 DefProc( false, false );
1163 // Read in of a procedure
1165 void SbiParser::DefProc( bool bStatic, bool bPrivate )
1167 sal_uInt16 l1 = nLine;
1168 bool bSub = ( eCurTok == SUB );
1169 bool bProperty = ( eCurTok == PROPERTY );
1170 PropertyMode ePropertyMode = PropertyMode::NONE;
1171 if( bProperty )
1173 Next();
1174 if( eCurTok == GET )
1176 ePropertyMode = PropertyMode::Get;
1178 else if( eCurTok == LET )
1180 ePropertyMode = PropertyMode::Let;
1182 else if( eCurTok == SET )
1184 ePropertyMode = PropertyMode::Set;
1186 else
1188 Error( ERRCODE_BASIC_EXPECTED, "Get or Let or Set" );
1192 SbiToken eExit = eCurTok;
1193 SbiProcDef* pDef = ProcDecl( false );
1194 if( !pDef )
1196 return;
1198 pDef->setPropertyMode( ePropertyMode );
1200 // Is the Proc already declared?
1201 SbiSymDef* pOld = aPublics.Find( pDef->GetName() );
1202 if( pOld )
1204 pProc = pOld->GetProcDef();
1205 if( !pProc )
1207 // Declared as a variable
1208 Error( ERRCODE_BASIC_BAD_DECLARATION, pDef->GetName() );
1209 delete pDef;
1210 return;
1212 // #100027: Multiple declaration -> Error
1213 // #112787: Not for setup, REMOVE for 8
1214 else if( pProc->IsUsedForProcDecl() )
1216 PropertyMode ePropMode = pDef->getPropertyMode();
1217 if( ePropMode == PropertyMode::NONE || ePropMode == pProc->getPropertyMode() )
1219 Error( ERRCODE_BASIC_PROC_DEFINED, pDef->GetName() );
1220 delete pDef;
1221 return;
1225 pDef->Match( pProc );
1227 else
1229 aPublics.Add( pDef );
1231 assert(pDef);
1232 pProc = pDef;
1233 pProc->SetPublic( !bPrivate );
1235 // Now we set the search hierarchy for symbols as well as the
1236 // current procedure.
1237 aPublics.SetProcId( pProc->GetId() );
1238 pProc->GetParams().SetParent( &aPublics );
1239 if( bStatic )
1241 if ( bVBASupportOn )
1243 pProc->SetStatic();
1245 else
1247 Error( ERRCODE_BASIC_NOT_IMPLEMENTED ); // STATIC SUB ...
1250 else
1252 pProc->SetStatic( false );
1254 // Normal case: Local variable->parameter->global variable
1255 pProc->GetLocals().SetParent( &pProc->GetParams() );
1256 pPool = &pProc->GetLocals();
1258 pProc->Define();
1259 OpenBlock( eExit );
1260 StmntBlock( bSub ? ENDSUB : (bProperty ? ENDPROPERTY : ENDFUNC) );
1261 sal_uInt16 l2 = nLine;
1262 pProc->SetLine1( l1 );
1263 pProc->SetLine2( l2 );
1264 pPool = &aPublics;
1265 aPublics.SetProcId( 0 );
1266 // Open labels?
1267 pProc->GetLabels().CheckRefs();
1268 CloseBlock();
1269 aGen.Gen( SbiOpcode::LEAVE_ );
1270 pProc = nullptr;
1273 // STATIC variable|procedure
1275 void SbiParser::Static()
1277 DefStatic( false );
1280 void SbiParser::DefStatic( bool bPrivate )
1282 SbiSymPool* p;
1284 switch( Peek() )
1286 case SUB:
1287 case FUNCTION:
1288 case PROPERTY:
1289 // End global chain if necessary (not done in
1290 // SbiParser::Parse() under these conditions
1291 if( bNewGblDefs && nGblChain == 0 )
1293 nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
1294 bNewGblDefs = false;
1296 Next();
1297 DefProc( true, bPrivate );
1298 break;
1299 default:
1300 if( !pProc )
1302 Error( ERRCODE_BASIC_NOT_IN_SUBR );
1304 // Reset the Pool, so that STATIC-Declarations go into the
1305 // global Pool
1306 p = pPool;
1307 pPool = &aPublics;
1308 DefVar( SbiOpcode::STATIC_, true );
1309 pPool = p;
1310 break;
1314 bool SbiParser::IsUnoInterface(const OUString& sTypeName)
1318 return css::reflection::theCoreReflection::get(
1319 comphelper::getProcessComponentContext())->forName(sTypeName).is();
1321 catch(const Exception&)
1323 OSL_FAIL("Could not create reflection.CoreReflection.");
1325 return false;
1328 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */