Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / basic / source / comp / dim.cxx
blob3b3a0e75bd5c801513a4b3126f277f6ec34892dc
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/sbx.hxx>
21 #include "sbunoobj.hxx"
22 #include "parser.hxx"
23 #include <svtools/miscopt.hxx>
24 #include <osl/diagnose.h>
25 #include <com/sun/star/reflection/theCoreReflection.hpp>
26 #include <comphelper/namedvaluecollection.hxx>
27 #include <comphelper/processfactory.hxx>
28 #include <com/sun/star/reflection/XInterfaceMemberTypeDescription.hpp>
29 #include <com/sun/star/reflection/XIdlMethod.hpp>
30 #include <com/sun/star/uno/Exception.hpp>
31 #include <basic/codecompletecache.hxx>
32 #include <memory>
34 using namespace ::com::sun::star;
35 using namespace ::com::sun::star::uno;
37 // Declaration of a variable
38 // If there are errors it will be parsed up to the comma or the newline.
39 // Return-value: a new instance, which were inserted and then deleted.
40 // Array-Index were returned as SbiExprList
42 SbiSymDef* SbiParser::VarDecl( SbiExprListPtr* ppDim, bool bStatic, bool bConst )
44 bool bWithEvents = false;
45 if( Peek() == WITHEVENTS )
47 Next();
48 bWithEvents = true;
50 if( !TestSymbol() ) return nullptr;
51 SbxDataType t = eScanType;
52 SbiSymDef* pDef = bConst ? new SbiConstDef( aSym ) : new SbiSymDef( aSym );
53 SbiExprListPtr pDim;
54 // Brackets?
55 if( Peek() == LPAREN )
57 pDim = SbiExprList::ParseDimList( this );
58 if( !pDim->GetDims() )
59 pDef->SetWithBrackets();
61 pDef->SetType( t );
62 if( bStatic )
63 pDef->SetStatic();
64 if( bWithEvents )
65 pDef->SetWithEvents();
66 TypeDecl( *pDef );
67 if( !ppDim && pDim )
69 if(pDim->GetDims() )
70 Error( ERRCODE_BASIC_EXPECTED, "()" );
72 else if( ppDim )
73 *ppDim = std::move(pDim);
74 return pDef;
77 // Resolving of a AS-Type-Declaration
78 // The data type were inserted into the handed over variable
80 void SbiParser::TypeDecl( SbiSymDef& rDef, bool bAsNewAlreadyParsed )
82 SbxDataType eType = rDef.GetType();
83 if( bAsNewAlreadyParsed || Peek() == AS )
85 short nSize = 0;
86 if( !bAsNewAlreadyParsed )
87 Next();
88 rDef.SetDefinedAs();
89 SbiToken eTok = Next();
90 if( !bAsNewAlreadyParsed && eTok == NEW )
92 rDef.SetNew();
93 eTok = Next();
95 switch( eTok )
97 case ANY:
98 if( rDef.IsNew() )
99 Error( ERRCODE_BASIC_SYNTAX );
100 eType = SbxVARIANT; break;
101 case TINTEGER:
102 case TLONG:
103 case TSINGLE:
104 case TDOUBLE:
105 case TCURRENCY:
106 case TDATE:
107 case TSTRING:
108 case TOBJECT:
109 case ERROR_:
110 case TBOOLEAN:
111 case TVARIANT:
112 case TBYTE:
113 if( rDef.IsNew() )
114 Error( ERRCODE_BASIC_SYNTAX );
115 eType = (eTok==TBYTE) ? SbxBYTE : SbxDataType( eTok - TINTEGER + SbxINTEGER );
116 if( eType == SbxSTRING )
118 // STRING*n ?
119 if( Peek() == MUL )
120 { // fixed size!
121 Next();
122 SbiConstExpression aSize( this );
123 nSize = aSize.GetShortValue();
124 if( nSize < 0 || (bVBASupportOn && nSize <= 0) )
125 Error( ERRCODE_BASIC_OUT_OF_RANGE );
126 else
127 rDef.SetFixedStringLength( nSize );
130 break;
131 case SYMBOL: // can only be a TYPE or a object class!
132 if( eScanType != SbxVARIANT )
133 Error( ERRCODE_BASIC_SYNTAX );
134 else
136 OUString aCompleteName = aSym;
138 // #52709 DIM AS NEW for Uno with full-qualified name
139 if( Peek() == DOT )
141 OUString aDotStr( '.' );
142 while( Peek() == DOT )
144 aCompleteName += aDotStr;
145 Next();
146 SbiToken ePeekTok = Peek();
147 if( ePeekTok == SYMBOL || IsKwd( ePeekTok ) )
149 Next();
150 aCompleteName += aSym;
152 else
154 Next();
155 Error( ERRCODE_BASIC_UNEXPECTED, SYMBOL );
156 break;
160 else if( rEnumArray->Find( aCompleteName, SbxClassType::Object ) || ( IsVBASupportOn() && VBAConstantHelper::instance().isVBAConstantType( aCompleteName ) ) )
162 eType = SbxLONG;
163 break;
166 // Take over in the string pool
167 rDef.SetTypeId( aGblStrings.Add( aCompleteName ) );
169 if( rDef.IsNew() && pProc == nullptr )
170 aRequiredTypes.push_back( aCompleteName );
172 eType = SbxOBJECT;
173 break;
174 case FIXSTRING: // new syntax for complex UNO types
175 rDef.SetTypeId( aGblStrings.Add( aSym ) );
176 eType = SbxOBJECT;
177 break;
178 default:
179 Error( ERRCODE_BASIC_UNEXPECTED, eTok );
180 Next();
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 );
195 // Here variables, arrays and structures were definied.
196 // DIM/PRIVATE/PUBLIC/GLOBAL
198 void SbiParser::Dim()
200 DefVar( SbiOpcode::DIM_, pProc && bVBASupportOn && pProc->IsStatic() );
203 void SbiParser::DefVar( SbiOpcode eOp, bool bStatic )
205 SbiSymPool* pOldPool = pPool;
206 bool bSwitchPool = false;
207 bool bPersistentGlobal = false;
208 SbiToken eFirstTok = eCurTok;
210 if( pProc && ( eCurTok == GLOBAL || eCurTok == PUBLIC || eCurTok == PRIVATE ) )
211 Error( ERRCODE_BASIC_NOT_IN_SUBR, eCurTok );
212 if( eCurTok == PUBLIC || eCurTok == GLOBAL )
214 bSwitchPool = true; // at the right moment switch to the global pool
215 if( eCurTok == GLOBAL )
216 bPersistentGlobal = true;
218 // behavior in VBA is that a module scope variable's lifetime is
219 // tied to the document. e.g. a module scope variable is global
220 if( GetBasic()->IsDocBasic() && bVBASupportOn && !pProc )
221 bPersistentGlobal = true;
222 // PRIVATE is a synonymous for DIM
223 // _CONST_?
224 bool bConst = false;
225 if( eCurTok == CONST_ )
226 bConst = true;
227 else if( Peek() == CONST_ )
229 Next();
230 bConst = true;
233 // #110004 It can also be a sub/function
234 if( !bConst && (eCurTok == SUB || eCurTok == FUNCTION || eCurTok == PROPERTY ||
235 eCurTok == STATIC || eCurTok == ENUM || eCurTok == DECLARE || eCurTok == TYPE) )
237 // Next token is read here, because !bConst
238 bool bPrivate = ( eFirstTok == PRIVATE );
240 if( eCurTok == STATIC )
242 Next();
243 DefStatic( bPrivate );
245 else if( eCurTok == SUB || eCurTok == FUNCTION || eCurTok == PROPERTY )
247 // End global chain if necessary (not done in
248 // SbiParser::Parse() under these conditions
249 if( bNewGblDefs && nGblChain == 0 )
251 nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
252 bNewGblDefs = false;
254 Next();
255 DefProc( false, bPrivate );
256 return;
258 else if( eCurTok == ENUM )
260 Next();
261 DefEnum( bPrivate );
262 return;
264 else if( eCurTok == DECLARE )
266 Next();
267 DefDeclare( bPrivate );
268 return;
270 // #i109049
271 else if( eCurTok == TYPE )
273 Next();
274 DefType( bPrivate );
275 return;
279 // SHARED were ignored
280 if( Peek() == SHARED ) Next();
282 // PRESERVE only at REDIM
283 if( Peek() == PRESERVE )
285 Next();
286 if( eOp == SbiOpcode::REDIM_ )
287 eOp = SbiOpcode::REDIMP_;
288 else
289 Error( ERRCODE_BASIC_UNEXPECTED, eCurTok );
291 SbiSymDef* pDef;
292 SbiExprListPtr pDim;
294 // #40689, Statics -> Module-Initialising, skip in Sub
295 sal_uInt32 nEndOfStaticLbl = 0;
296 if( !bVBASupportOn && bStatic )
298 nEndOfStaticLbl = aGen.Gen( SbiOpcode::JUMP_, 0 );
299 aGen.Statement(); // catch up on static here
302 bool bDefined = false;
303 while( ( pDef = VarDecl( &pDim, bStatic, bConst ) ) != nullptr )
305 /*fprintf(stderr, "Actual sub: \n");
306 fprintf(stderr, "Symbol name: %s\n",OUStringToOString(pDef->GetName(),RTL_TEXTENCODING_UTF8).getStr());*/
307 EnableErrors();
308 // search variable:
309 if( bSwitchPool )
310 pPool = &aGlobals;
311 SbiSymDef* pOld = pPool->Find( pDef->GetName() );
312 // search also in the Runtime-Library
313 bool bRtlSym = false;
314 if( !pOld )
316 pOld = CheckRTLForSym( pDef->GetName(), SbxVARIANT );
317 if( pOld )
318 bRtlSym = true;
320 if( pOld && !(eOp == SbiOpcode::REDIM_ || eOp == SbiOpcode::REDIMP_) )
322 if( pDef->GetScope() == SbLOCAL && pOld->GetScope() != SbLOCAL )
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( false );
568 void SbiParser::DefType( bool bPrivate )
570 // TODO: Use bPrivate
571 (void)bPrivate;
573 // Read the new Token lesen. It had to be a symbol
574 if (!TestSymbol())
575 return;
577 if (rTypeArray->Find(aSym,SbxClassType::Object))
579 Error( ERRCODE_BASIC_VAR_DEFINED, aSym );
580 return;
583 SbxObject *pType = new SbxObject(aSym);
585 bool bDone = false;
587 while( !bDone && !IsEof() )
589 std::unique_ptr<SbiSymDef> pElem;
590 SbiExprListPtr pDim;
591 switch( Peek() )
593 case ENDTYPE :
594 bDone = true;
595 Next();
596 break;
598 case EOLN :
599 case REM :
600 Next();
601 break;
603 default:
604 pElem.reset(VarDecl(&pDim, false, false));
605 if( !pElem )
606 bDone = true; // Error occurred
608 if( pElem )
610 SbxArray *pTypeMembers = pType->GetProperties();
611 OUString aElemName = pElem->GetName();
612 if( pTypeMembers->Find( aElemName, SbxClassType::DontCare) )
614 Error (ERRCODE_BASIC_VAR_DEFINED);
616 else
618 SbxDataType eElemType = pElem->GetType();
619 SbxProperty *pTypeElem = new SbxProperty( aElemName, eElemType );
620 if( pDim )
622 SbxDimArray* pArray = new SbxDimArray( pElem->GetType() );
623 if ( pDim->GetSize() )
625 // Dimension the target array
627 for ( short i=0; i<pDim->GetSize();++i )
629 sal_Int32 lb = nBase;
630 SbiExprNode* pNode = pDim->Get(i)->GetExprNode();
631 sal_Int32 ub = pNode->GetNumber();
632 if ( !pDim->Get( i )->IsBased() ) // each dim is low/up
634 if ( ++i >= pDim->GetSize() ) // trouble
635 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR );
636 pNode = pDim->Get(i)->GetExprNode();
637 lb = ub;
638 ub = pNode->GetNumber();
640 else if ( !bCompatible )
641 ub += nBase;
642 pArray->AddDim32( lb, ub );
644 pArray->setHasFixedSize( true );
646 else
647 pArray->unoAddDim( 0, -1 ); // variant array
648 SbxFlagBits nSavFlags = pTypeElem->GetFlags();
649 // need to reset the FIXED flag
650 // when calling PutObject ( because the type will not match Object )
651 pTypeElem->ResetFlag( SbxFlagBits::Fixed );
652 pTypeElem->PutObject( pArray );
653 pTypeElem->SetFlags( nSavFlags );
655 // Nested user type?
656 if( eElemType == SbxOBJECT )
658 sal_uInt16 nElemTypeId = pElem->GetTypeId();
659 if( nElemTypeId != 0 )
661 OUString aTypeName( aGblStrings.Find( nElemTypeId ) );
662 SbxObject* pTypeObj = static_cast< SbxObject* >( rTypeArray->Find( aTypeName, SbxClassType::Object ) );
663 if( pTypeObj != nullptr )
665 SbxObject* pCloneObj = cloneTypeObjectImpl( *pTypeObj );
666 pTypeElem->PutObject( pCloneObj );
670 pTypeMembers->Insert( pTypeElem, pTypeMembers->Count() );
675 pType->Remove( "Name", SbxClassType::DontCare );
676 pType->Remove( "Parent", SbxClassType::DontCare );
678 rTypeArray->Insert (pType,rTypeArray->Count());
682 // Declaration of Enum type
684 void SbiParser::Enum()
686 DefEnum( false );
689 void SbiParser::DefEnum( bool bPrivate )
691 // Read a the new Token. It had to be a symbol
692 if (!TestSymbol())
693 return;
695 OUString aEnumName = aSym;
696 if( rEnumArray->Find(aEnumName,SbxClassType::Object) )
698 Error( ERRCODE_BASIC_VAR_DEFINED, aSym );
699 return;
702 SbxObject *pEnum = new SbxObject( aEnumName );
703 if( bPrivate )
705 pEnum->SetFlag( SbxFlagBits::Private );
707 SbiSymDef* pElem;
708 bool bDone = false;
710 // Starting with -1 to make first default value 0 after ++
711 sal_Int32 nCurrentEnumValue = -1;
712 while( !bDone && !IsEof() )
714 switch( Peek() )
716 case ENDENUM :
717 pElem = nullptr;
718 bDone = true;
719 Next();
720 break;
722 case EOLN :
723 case REM :
724 pElem = nullptr;
725 Next();
726 break;
728 default:
730 SbiExprListPtr pDim;
731 pElem = VarDecl( &pDim, false, true );
732 if( !pElem )
734 bDone = true; // Error occurred
735 break;
737 else if( pDim )
739 Error( ERRCODE_BASIC_SYNTAX );
740 bDone = true; // Error occurred
741 break;
744 SbiExpression aVar( this, *pElem );
745 if( Peek() == EQ )
747 Next();
749 SbiConstExpression aExpr( this );
750 if( aExpr.IsValid() )
752 SbxVariableRef xConvertVar = new SbxVariable();
753 if( aExpr.GetType() == SbxSTRING )
754 xConvertVar->PutString( aExpr.GetString() );
755 else
756 xConvertVar->PutDouble( aExpr.GetValue() );
758 nCurrentEnumValue = xConvertVar->GetLong();
761 else
762 nCurrentEnumValue++;
764 SbiSymPool* pPoolToUse = bPrivate ? pPool : &aGlobals;
766 SbiSymDef* pOld = pPoolToUse->Find( pElem->GetName() );
767 if( pOld )
769 Error( ERRCODE_BASIC_VAR_DEFINED, pElem->GetName() );
770 bDone = true; // Error occurred
771 break;
774 pPool->Add( pElem );
776 if( !bPrivate )
778 SbiOpcode eOp = SbiOpcode::GLOBAL_;
779 aGen.BackChain( nGblChain );
780 nGblChain = 0;
781 bGblDefs = bNewGblDefs = true;
782 aGen.Gen(
783 eOp, pElem->GetId(),
784 sal::static_int_cast< sal_uInt16 >( pElem->GetType() ) );
786 aVar.Gen();
787 sal_uInt16 nStringId = aGen.GetParser()->aGblStrings.Add( nCurrentEnumValue, SbxLONG );
788 aGen.Gen( SbiOpcode::NUMBER_, nStringId );
789 aGen.Gen( SbiOpcode::PUTC_ );
792 SbiConstDef* pConst = pElem->GetConstDef();
793 pConst->Set( nCurrentEnumValue, SbxLONG );
796 if( pElem )
798 SbxArray *pEnumMembers = pEnum->GetProperties();
799 SbxProperty *pEnumElem = new SbxProperty( pElem->GetName(), SbxLONG );
800 pEnumElem->PutLong( nCurrentEnumValue );
801 pEnumElem->ResetFlag( SbxFlagBits::Write );
802 pEnumElem->SetFlag( SbxFlagBits::Const );
803 pEnumMembers->Insert( pEnumElem, pEnumMembers->Count() );
807 pEnum->Remove( "Name", SbxClassType::DontCare );
808 pEnum->Remove( "Parent", SbxClassType::DontCare );
810 rEnumArray->Insert( pEnum, rEnumArray->Count() );
814 // Procedure-Declaration
815 // the first Token is already read in (SUB/FUNCTION)
816 // xxx Name [LIB "name"[ALIAS "name"]][(Parameter)][AS TYPE]
818 SbiProcDef* SbiParser::ProcDecl( bool bDecl )
820 bool bFunc = ( eCurTok == FUNCTION );
821 bool bProp = ( eCurTok == GET || eCurTok == SET || eCurTok == LET );
822 if( !TestSymbol() ) return nullptr;
823 OUString aName( aSym );
824 SbxDataType eType = eScanType;
825 SbiProcDef* pDef = new SbiProcDef( this, aName, true );
826 pDef->SetType( eType );
827 if( Peek() == CDECL_ )
829 Next(); pDef->SetCdecl(true);
831 if( Peek() == LIB )
833 Next();
834 if( Next() == FIXSTRING )
836 pDef->GetLib() = aSym;
838 else
840 Error( ERRCODE_BASIC_SYNTAX );
843 if( Peek() == ALIAS )
845 Next();
846 if( Next() == FIXSTRING )
848 pDef->GetAlias() = aSym;
850 else
852 Error( ERRCODE_BASIC_SYNTAX );
855 if( !bDecl )
857 // CDECL, LIB and ALIAS are invalid
858 if( !pDef->GetLib().isEmpty() )
860 Error( ERRCODE_BASIC_UNEXPECTED, LIB );
862 if( !pDef->GetAlias().isEmpty() )
864 Error( ERRCODE_BASIC_UNEXPECTED, ALIAS );
866 if( pDef->IsCdecl() )
868 Error( ERRCODE_BASIC_UNEXPECTED, CDECL_ );
870 pDef->SetCdecl( false );
871 pDef->GetLib().clear();
872 pDef->GetAlias().clear();
874 else if( pDef->GetLib().isEmpty() )
876 // ALIAS and CDECL only together with LIB
877 if( !pDef->GetAlias().isEmpty() )
879 Error( ERRCODE_BASIC_UNEXPECTED, ALIAS );
881 if( pDef->IsCdecl() )
883 Error( ERRCODE_BASIC_UNEXPECTED, CDECL_ );
885 pDef->SetCdecl( false );
886 pDef->GetAlias().clear();
888 // Brackets?
889 if( Peek() == LPAREN )
891 Next();
892 if( Peek() == RPAREN )
894 Next();
896 else
898 for(;;)
900 bool bByVal = false;
901 bool bOptional = false;
902 bool bParamArray = false;
903 while( Peek() == BYVAL || Peek() == BYREF || Peek() == OPTIONAL_ )
905 if( Peek() == BYVAL )
907 bByVal = true;
909 else if ( Peek() == BYREF )
911 bByVal = false;
913 else if ( Peek() == OPTIONAL_ )
915 bOptional = true;
917 Next();
919 if( bCompatible && Peek() == PARAMARRAY )
921 if( bByVal || bOptional )
923 Error( ERRCODE_BASIC_UNEXPECTED, PARAMARRAY );
925 Next();
926 bParamArray = true;
928 SbiSymDef* pPar = VarDecl( nullptr, false, false );
929 if( !pPar )
931 break;
933 if( bByVal )
935 pPar->SetByVal(true);
937 if( bOptional )
939 pPar->SetOptional();
941 if( bParamArray )
943 pPar->SetParamArray();
945 pDef->GetParams().Add( pPar );
946 SbiToken eTok = Next();
947 if( eTok != COMMA && eTok != RPAREN )
949 bool bError2 = true;
950 if( bOptional && bCompatible && eTok == EQ )
952 std::unique_ptr<SbiConstExpression> pDefaultExpr(new SbiConstExpression( this ));
953 SbxDataType eType2 = pDefaultExpr->GetType();
955 sal_uInt16 nStringId;
956 if( eType2 == SbxSTRING )
958 nStringId = aGblStrings.Add( pDefaultExpr->GetString() );
960 else
962 nStringId = aGblStrings.Add( pDefaultExpr->GetValue(), eType2 );
964 pPar->SetDefaultId( nStringId );
965 pDefaultExpr.reset();
967 eTok = Next();
968 if( eTok == COMMA || eTok == RPAREN )
970 bError2 = false;
973 if( bError2 )
975 Error( ERRCODE_BASIC_EXPECTED, RPAREN );
976 break;
979 if( eTok == RPAREN )
981 break;
986 TypeDecl( *pDef );
987 if( eType != SbxVARIANT && pDef->GetType() != eType )
989 Error( ERRCODE_BASIC_BAD_DECLARATION, aName );
991 if( pDef->GetType() == SbxVARIANT && !( bFunc || bProp ) )
993 pDef->SetType( SbxEMPTY );
995 return pDef;
998 // DECLARE
1000 void SbiParser::Declare()
1002 DefDeclare( false );
1005 void SbiParser::DefDeclare( bool bPrivate )
1007 Next();
1008 if( eCurTok == PTRSAFE )
1009 Next();
1011 if( eCurTok != SUB && eCurTok != FUNCTION )
1013 Error( ERRCODE_BASIC_UNEXPECTED, eCurTok );
1015 else
1017 bool bFunction = (eCurTok == FUNCTION);
1019 SbiProcDef* pDef = ProcDecl( true );
1020 if( pDef )
1022 if( pDef->GetLib().isEmpty() )
1024 Error( ERRCODE_BASIC_EXPECTED, LIB );
1026 // Is it already there?
1027 SbiSymDef* pOld = aPublics.Find( pDef->GetName() );
1028 if( pOld )
1030 SbiProcDef* p = pOld->GetProcDef();
1031 if( !p )
1033 // Declared as a variable
1034 Error( ERRCODE_BASIC_BAD_DECLARATION, pDef->GetName() );
1035 delete pDef;
1036 pDef = nullptr;
1038 else
1040 pDef->Match( p );
1043 else
1045 aPublics.Add( pDef );
1047 if ( pDef )
1049 pDef->SetPublic( !bPrivate );
1051 // New declare handling
1052 if( !pDef->GetLib().isEmpty())
1054 if( bNewGblDefs && nGblChain == 0 )
1056 nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
1057 bNewGblDefs = false;
1060 sal_uInt16 nSavLine = nLine;
1061 aGen.Statement();
1062 pDef->Define();
1063 pDef->SetLine1( nSavLine );
1064 pDef->SetLine2( nSavLine );
1066 SbiSymPool& rPool = pDef->GetParams();
1067 sal_uInt16 nParCount = rPool.GetSize();
1069 SbxDataType eType = pDef->GetType();
1070 if( bFunction )
1072 aGen.Gen( SbiOpcode::PARAM_, 0, sal::static_int_cast< sal_uInt16 >( eType ) );
1074 if( nParCount > 1 )
1076 aGen.Gen( SbiOpcode::ARGC_ );
1078 for( sal_uInt16 i = 1 ; i < nParCount ; ++i )
1080 SbiSymDef* pParDef = rPool.Get( i );
1081 SbxDataType eParType = pParDef->GetType();
1083 aGen.Gen( SbiOpcode::PARAM_, i, sal::static_int_cast< sal_uInt16 >( eParType ) );
1084 aGen.Gen( SbiOpcode::ARGV_ );
1086 sal_uInt16 nTyp = sal::static_int_cast< sal_uInt16 >( pParDef->GetType() );
1087 if( pParDef->IsByVal() )
1089 // Reset to avoid additional byval in call to wrapper function
1090 pParDef->SetByVal( false );
1091 nTyp |= 0x8000;
1093 aGen.Gen( SbiOpcode::ARGTYP_, nTyp );
1097 aGen.Gen( SbiOpcode::LIB_, aGblStrings.Add( pDef->GetLib() ) );
1099 SbiOpcode eOp = pDef->IsCdecl() ? SbiOpcode::CALLC_ : SbiOpcode::CALL_;
1100 sal_uInt16 nId = pDef->GetId();
1101 if( !pDef->GetAlias().isEmpty() )
1103 nId = ( nId & 0x8000 ) | aGblStrings.Add( pDef->GetAlias() );
1105 if( nParCount > 1 )
1107 nId |= 0x8000;
1109 aGen.Gen( eOp, nId, sal::static_int_cast< sal_uInt16 >( eType ) );
1111 if( bFunction )
1113 aGen.Gen( SbiOpcode::PUT_ );
1115 aGen.Gen( SbiOpcode::LEAVE_ );
1122 void SbiParser::Attribute()
1124 // TODO: Need to implement the method as an attributed object.
1125 while( Next() != EQ )
1127 if( Next() != DOT)
1129 break;
1133 if( eCurTok != EQ )
1135 Error( ERRCODE_BASIC_SYNTAX );
1137 else
1139 SbiExpression aValue( this );
1141 // Don't generate any code - just discard it.
1144 // Call of a SUB or a FUNCTION
1146 void SbiParser::Call()
1148 SbiExpression aVar( this, SbSYMBOL );
1149 aVar.Gen( FORCE_CALL );
1150 aGen.Gen( SbiOpcode::GET_ );
1153 // SUB/FUNCTION
1155 void SbiParser::SubFunc()
1157 DefProc( false, false );
1160 // Read in of a procedure
1162 void SbiParser::DefProc( bool bStatic, bool bPrivate )
1164 sal_uInt16 l1 = nLine;
1165 bool bSub = ( eCurTok == SUB );
1166 bool bProperty = ( eCurTok == PROPERTY );
1167 PropertyMode ePropertyMode = PropertyMode::NONE;
1168 if( bProperty )
1170 Next();
1171 if( eCurTok == GET )
1173 ePropertyMode = PropertyMode::Get;
1175 else if( eCurTok == LET )
1177 ePropertyMode = PropertyMode::Let;
1179 else if( eCurTok == SET )
1181 ePropertyMode = PropertyMode::Set;
1183 else
1185 Error( ERRCODE_BASIC_EXPECTED, "Get or Let or Set" );
1189 SbiToken eExit = eCurTok;
1190 SbiProcDef* pDef = ProcDecl( false );
1191 if( !pDef )
1193 return;
1195 pDef->setPropertyMode( ePropertyMode );
1197 // Is the Proc already declared?
1198 SbiSymDef* pOld = aPublics.Find( pDef->GetName() );
1199 if( pOld )
1201 pProc = pOld->GetProcDef();
1202 if( !pProc )
1204 // Declared as a variable
1205 Error( ERRCODE_BASIC_BAD_DECLARATION, pDef->GetName() );
1206 delete pDef;
1207 return;
1209 // #100027: Multiple declaration -> Error
1210 // #112787: Not for setup, REMOVE for 8
1211 else if( pProc->IsUsedForProcDecl() )
1213 PropertyMode ePropMode = pDef->getPropertyMode();
1214 if( ePropMode == PropertyMode::NONE || ePropMode == pProc->getPropertyMode() )
1216 Error( ERRCODE_BASIC_PROC_DEFINED, pDef->GetName() );
1217 delete pDef;
1218 return;
1222 pDef->Match( pProc );
1223 pProc = pDef;
1225 else
1227 aPublics.Add( pDef );
1228 pProc = pDef;
1230 if( !pProc )
1232 return;
1234 pProc->SetPublic( !bPrivate );
1236 // Now we set the search hierarchy for symbols as well as the
1237 // current procedure.
1238 aPublics.SetProcId( pProc->GetId() );
1239 pProc->GetParams().SetParent( &aPublics );
1240 if( bStatic )
1242 if ( bVBASupportOn )
1244 pProc->SetStatic();
1246 else
1248 Error( ERRCODE_BASIC_NOT_IMPLEMENTED ); // STATIC SUB ...
1251 else
1253 pProc->SetStatic( false );
1255 // Normal case: Local variable->parameter->global variable
1256 pProc->GetLocals().SetParent( &pProc->GetParams() );
1257 pPool = &pProc->GetLocals();
1259 pProc->Define();
1260 OpenBlock( eExit );
1261 StmntBlock( bSub ? ENDSUB : (bProperty ? ENDPROPERTY : ENDFUNC) );
1262 sal_uInt16 l2 = nLine;
1263 pProc->SetLine1( l1 );
1264 pProc->SetLine2( l2 );
1265 pPool = &aPublics;
1266 aPublics.SetProcId( 0 );
1267 // Open labels?
1268 pProc->GetLabels().CheckRefs();
1269 CloseBlock();
1270 aGen.Gen( SbiOpcode::LEAVE_ );
1271 pProc = nullptr;
1274 // STATIC variable|procedure
1276 void SbiParser::Static()
1278 DefStatic( false );
1281 void SbiParser::DefStatic( bool bPrivate )
1283 SbiSymPool* p;
1285 switch( Peek() )
1287 case SUB:
1288 case FUNCTION:
1289 case PROPERTY:
1290 // End global chain if necessary (not done in
1291 // SbiParser::Parse() under these conditions
1292 if( bNewGblDefs && nGblChain == 0 )
1294 nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
1295 bNewGblDefs = false;
1297 Next();
1298 DefProc( true, bPrivate );
1299 break;
1300 default:
1301 if( !pProc )
1303 Error( ERRCODE_BASIC_NOT_IN_SUBR );
1305 // Reset the Pool, so that STATIC-Declarations go into the
1306 // global Pool
1307 p = pPool;
1308 pPool = &aPublics;
1309 DefVar( SbiOpcode::STATIC_, true );
1310 pPool = p;
1311 break;
1315 bool SbiParser::IsUnoInterface(const OUString& sTypeName)
1319 return css::reflection::theCoreReflection::get(
1320 comphelper::getProcessComponentContext())->forName(sTypeName).is();
1322 catch(const Exception&)
1324 OSL_FAIL("Could not create reflection.CoreReflection.");
1326 return false;
1329 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */