tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / basic / source / comp / dim.cxx
blob1e1d443069181acf2c7c5e8475a4ac340159422d
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, u"()"_ustr );
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) )
83 return;
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 an 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 );
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 // tdf#145371, tdf#136755 - only delete the variable beforehand REDIM
435 if (eOp == SbiOpcode::REDIM_)
437 SbiExpression aExpr(this, *pDef, nullptr);
438 aExpr.Gen();
439 aGen.Gen(bVBASupportOn ? SbiOpcode::ERASE_CLEAR_ : SbiOpcode::ERASE_);
442 pDef->SetDims( pDim->GetDims() );
443 SbiExpression aExpr2( this, *pDef, std::move(pDim) );
444 aExpr2.Gen();
445 aGen.Gen( SbiOpcode::DCREATE_, pDef->GetId(), pDef->GetTypeId() );
448 else
450 SbiExpression aExpr( this, *pDef );
451 aExpr.Gen();
453 /* tdf#88442
454 * Don't initialize a
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() );
473 if ( bVBASupportOn )
474 aGen.Gen( SbiOpcode::VBASET_ );
475 else
476 aGen.Gen( SbiOpcode::SET_ );
478 if ( come_from )
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 );
487 else
489 if( bConst )
491 // Definition of the constants
492 if( pDim )
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!
505 aVar.Gen();
506 aExpr.Gen();
507 aGen.Gen( SbiOpcode::PUTC_ );
509 SbiConstDef* pConst = pDef->GetConstDef();
510 if( aExpr.GetType() == SbxSTRING )
511 pConst->Set( aExpr.GetString() );
512 else
513 pConst->Set( aExpr.GetValue(), aExpr.GetType() );
516 else if( pDim )
518 // Dimension the variable
519 // Delete the var at REDIM beforehand
520 if( eOp == SbiOpcode::REDIM_ )
522 SbiExpression aExpr( this, *pDef, nullptr );
523 aExpr.Gen();
524 if ( bVBASupportOn )
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_ );
530 else
531 aGen.Gen( SbiOpcode::ERASE_ );
533 else if( eOp == SbiOpcode::REDIMP_ )
535 SbiExpression aExpr( this, *pDef, nullptr );
536 aExpr.Gen();
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) );
543 aExpr.Gen();
544 pDef->SetGlobal( false );
545 aGen.Gen( (eOp == SbiOpcode::STATIC_) ? SbiOpcode::DIM_ : eOp );
548 if( !TestComma() )
549 goto MyBreak;
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.
555 // also at a break
556 pPool = pOldPool;
557 continue; // Skip MyBreak
558 MyBreak:
559 pPool = pOldPool;
560 break;
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() );
583 // ERASE array, ...
585 void SbiParser::Erase()
587 while( !bAbort )
589 SbiExpression aExpr( this, SbLVALUE );
590 aExpr.Gen();
591 aGen.Gen( SbiOpcode::ERASE_ );
592 if( !TestComma() ) break;
596 // Declaration of a data type
598 void SbiParser::Type()
600 DefType();
603 void SbiParser::DefType()
605 // Read the new Token lesen. It had to be a symbol
606 if (!TestSymbol())
607 return;
609 if (rTypeArray->Find(aSym,SbxClassType::Object))
611 Error( ERRCODE_BASIC_VAR_DEFINED, aSym );
612 return;
615 SbxObject *pType = new SbxObject(aSym);
617 bool bDone = false;
619 while( !bDone && !IsEof() )
621 std::unique_ptr<SbiSymDef> pElem;
622 SbiExprListPtr pDim;
623 switch( Peek() )
625 case ENDTYPE :
626 bDone = true;
627 Next();
628 break;
630 case EOLN :
631 case REM :
632 Next();
633 break;
635 default:
636 pElem.reset(VarDecl(&pDim, false, false));
637 if( !pElem )
638 bDone = true; // Error occurred
640 if( pElem )
642 SbxArray *pTypeMembers = pType->GetProperties();
643 OUString aElemName = pElem->GetName();
644 if( pTypeMembers->Find( aElemName, SbxClassType::DontCare) )
646 Error (ERRCODE_BASIC_VAR_DEFINED);
648 else
650 SbxDataType eElemType = pElem->GetType();
651 SbxProperty *pTypeElem = new SbxProperty( aElemName, eElemType );
652 if( pDim )
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();
669 lb = ub;
670 ub = pNode->GetNumber();
672 else if ( !bCompatible )
673 ub += nBase;
674 pArray->AddDim(lb, ub);
676 pArray->setHasFixedSize( true );
678 else
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 );
687 // Nested user type?
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()
718 DefEnum( false );
721 void SbiParser::DefEnum( bool bPrivate )
723 // Read the new Token. It had to be a symbol
724 if (!TestSymbol())
725 return;
727 OUString aEnumName = aSym;
728 if( rEnumArray->Find(aEnumName,SbxClassType::Object) )
730 Error( ERRCODE_BASIC_VAR_DEFINED, aSym );
731 return;
734 SbxObject *pEnum = new SbxObject( aEnumName );
735 if( bPrivate )
737 pEnum->SetFlag( SbxFlagBits::Private );
739 SbiSymDef* pElem;
740 bool bDone = false;
742 // Starting with -1 to make first default value 0 after ++
743 sal_Int32 nCurrentEnumValue = -1;
744 while( !bDone && !IsEof() )
746 switch( Peek() )
748 case ENDENUM :
749 pElem = nullptr;
750 bDone = true;
751 Next();
752 break;
754 case EOLN :
755 case REM :
756 pElem = nullptr;
757 Next();
758 break;
760 default:
762 SbiExprListPtr pDim;
763 pElem = VarDecl( &pDim, false, true );
764 if( !pElem )
766 bDone = true; // Error occurred
767 break;
769 else if( pDim )
771 Error( ERRCODE_BASIC_SYNTAX );
772 bDone = true; // Error occurred
773 break;
776 SbiExpression aVar( this, *pElem );
777 if( Peek() == EQ )
779 Next();
781 SbiConstExpression aExpr( this );
782 if( aExpr.IsValid() )
784 SbxVariableRef xConvertVar = new SbxVariable();
785 if( aExpr.GetType() == SbxSTRING )
786 xConvertVar->PutString( aExpr.GetString() );
787 else
788 xConvertVar->PutDouble( aExpr.GetValue() );
790 nCurrentEnumValue = xConvertVar->GetLong();
793 else
794 nCurrentEnumValue++;
796 SbiSymPool* pPoolToUse = bPrivate ? pPool : &aGlobals;
798 SbiSymDef* pOld = pPoolToUse->Find( pElem->GetName() );
799 if( pOld )
801 Error( ERRCODE_BASIC_VAR_DEFINED, pElem->GetName() );
802 bDone = true; // Error occurred
803 break;
806 pPool->Add( pElem );
808 if( !bPrivate )
810 aGen.BackChain( nGblChain );
811 nGblChain = 0;
812 bGblDefs = bNewGblDefs = true;
813 aGen.Gen(
814 SbiOpcode::GLOBAL_, pElem->GetId(),
815 sal::static_int_cast< sal_uInt16 >( pElem->GetType() ) );
817 aVar.Gen();
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 );
827 if( pElem )
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);
862 if( Peek() == LIB )
864 Next();
865 if( Next() == FIXSTRING )
867 pDef->GetLib() = aSym;
869 else
871 Error( ERRCODE_BASIC_SYNTAX );
874 if( Peek() == ALIAS )
876 Next();
877 if( Next() == FIXSTRING )
879 pDef->GetAlias() = aSym;
881 else
883 Error( ERRCODE_BASIC_SYNTAX );
886 if( !bDecl )
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();
919 // Brackets?
920 if( Peek() == LPAREN )
922 Next();
923 if( Peek() == RPAREN )
925 Next();
927 else
929 for(;;)
931 bool bByVal = false;
932 bool bOptional = false;
933 bool bParamArray = false;
934 while( Peek() == BYVAL || Peek() == BYREF || Peek() == OPTIONAL_ )
936 if( Peek() == BYVAL )
938 bByVal = true;
940 else if ( Peek() == BYREF )
942 bByVal = false;
944 else if ( Peek() == OPTIONAL_ )
946 bOptional = true;
948 Next();
950 if( bCompatible && Peek() == PARAMARRAY )
952 if( bByVal || bOptional )
954 Error( ERRCODE_BASIC_UNEXPECTED, PARAMARRAY );
956 Next();
957 bParamArray = true;
959 SbiSymDef* pPar = VarDecl( nullptr, false, false );
960 if( !pPar )
962 break;
964 if( bByVal )
966 pPar->SetByVal(true);
968 if( bOptional )
970 pPar->SetOptional();
972 if( bParamArray )
974 pPar->SetParamArray();
976 if (SbiSymDef* pOldDef = pDef->GetParams().Find(pPar->GetName(), false))
978 Error(ERRCODE_BASIC_VAR_DEFINED, pPar->GetName());
979 delete pPar;
980 pPar = pOldDef;
982 else
983 pDef->GetParams().Add( pPar );
984 SbiToken eTok = Next();
985 if( eTok != COMMA && eTok != RPAREN )
987 bool bError2 = true;
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());
999 else
1001 nStringId = aGblStrings.Add(aDefaultExpr.GetValue(), eType2);
1003 pPar->SetDefaultId(nStringId);
1006 eTok = Next();
1007 if( eTok == COMMA || eTok == RPAREN )
1009 bError2 = false;
1012 if( bError2 )
1014 Error( ERRCODE_BASIC_EXPECTED, RPAREN );
1015 break;
1018 if( eTok == RPAREN )
1020 break;
1025 TypeDecl( *pDef );
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 );
1034 return pDef;
1037 // DECLARE
1039 void SbiParser::Declare()
1041 DefDeclare( false );
1044 void SbiParser::DefDeclare( bool bPrivate )
1046 Next();
1047 if( eCurTok == PTRSAFE )
1048 Next();
1050 if( eCurTok != SUB && eCurTok != FUNCTION )
1052 Error( ERRCODE_BASIC_UNEXPECTED, eCurTok );
1054 else
1056 bool bFunction = (eCurTok == FUNCTION);
1058 SbiProcDef* pDef = ProcDecl( true );
1059 if( pDef )
1061 if( pDef->GetLib().isEmpty() )
1063 Error( ERRCODE_BASIC_EXPECTED, LIB );
1065 // Is it already there?
1066 SbiSymDef* pOld = aPublics.Find( pDef->GetName() );
1067 if( pOld )
1069 SbiProcDef* p = pOld->GetProcDef();
1070 if( !p )
1072 // Declared as a variable
1073 Error( ERRCODE_BASIC_BAD_DECLARATION, pDef->GetName() );
1074 delete pDef;
1075 pDef = nullptr;
1077 else
1079 pDef->Match( p );
1082 else
1084 aPublics.Add( pDef );
1086 if ( 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;
1100 aGen.Statement();
1101 pDef->Define();
1102 pDef->SetLine1( nSavLine );
1103 pDef->SetLine2( nSavLine );
1105 SbiSymPool& rPool = pDef->GetParams();
1106 sal_uInt16 nParCount = rPool.GetSize();
1108 SbxDataType eType = pDef->GetType();
1109 if( bFunction )
1111 aGen.Gen( SbiOpcode::PARAM_, 0, sal::static_int_cast< sal_uInt16 >( eType ) );
1113 if( nParCount > 1 )
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 );
1130 nTyp |= 0x8000;
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() );
1144 if( nParCount > 1 )
1146 nId |= 0x8000;
1148 aGen.Gen( eOp, nId, sal::static_int_cast< sal_uInt16 >( eType ) );
1150 if( bFunction )
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 )
1166 if( Next() != DOT)
1168 break;
1172 if( eCurTok != EQ )
1174 Error( ERRCODE_BASIC_SYNTAX );
1176 else
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_ );
1192 // SUB/FUNCTION
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;
1207 if( bProperty )
1209 Next();
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;
1222 else
1224 Error( ERRCODE_BASIC_EXPECTED, u"Get or Let or Set"_ustr );
1228 SbiToken eExit = eCurTok;
1229 SbiProcDef* pDef = ProcDecl( false );
1230 if( !pDef )
1232 return;
1234 pDef->setPropertyMode( ePropertyMode );
1236 // Is the Proc already declared?
1237 SbiSymDef* pOld = aPublics.Find( pDef->GetName() );
1238 if( pOld )
1240 pProc = pOld->GetProcDef();
1241 if( !pProc )
1243 // Declared as a variable
1244 Error( ERRCODE_BASIC_BAD_DECLARATION, pDef->GetName() );
1245 delete pDef;
1246 return;
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() );
1256 delete pDef;
1257 return;
1261 pDef->Match( pProc );
1263 else
1265 aPublics.Add( pDef );
1267 assert(pDef);
1268 pProc = 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 );
1275 if( bStatic )
1277 if ( bVBASupportOn )
1279 pProc->SetStatic();
1281 else
1283 Error( ERRCODE_BASIC_NOT_IMPLEMENTED ); // STATIC SUB ...
1286 else
1288 pProc->SetStatic( false );
1290 // Normal case: Local variable->parameter->global variable
1291 pProc->GetLocals().SetParent( &pProc->GetParams() );
1292 pPool = &pProc->GetLocals();
1294 pProc->Define();
1295 OpenBlock( eExit );
1296 StmntBlock( bSub ? ENDSUB : (bProperty ? ENDPROPERTY : ENDFUNC) );
1297 sal_uInt16 l2 = nLine;
1298 pProc->SetLine1( l1 );
1299 pProc->SetLine2( l2 );
1300 pPool = &aPublics;
1301 aPublics.SetProcId( 0 );
1302 // Open labels?
1303 pProc->GetLabels().CheckRefs();
1304 CloseBlock();
1305 aGen.Gen( SbiOpcode::LEAVE_ );
1306 pProc = nullptr;
1309 // STATIC variable|procedure
1311 void SbiParser::Static()
1313 DefStatic( false );
1316 void SbiParser::DefStatic( bool bPrivate )
1318 SbiSymPool* p;
1320 switch( Peek() )
1322 case SUB:
1323 case FUNCTION:
1324 case PROPERTY:
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;
1332 Next();
1333 DefProc( true, bPrivate );
1334 break;
1335 default:
1336 if( !pProc )
1338 Error( ERRCODE_BASIC_NOT_IN_SUBR );
1340 // Reset the Pool, so that STATIC-Declarations go into the
1341 // global Pool
1342 p = pPool;
1343 pPool = &aPublics;
1344 DefVar( SbiOpcode::STATIC_, true );
1345 pPool = p;
1346 break;
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.");
1361 return false;
1364 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */