xref: /core/basic/source/comp/dim.cxx (revision 9e6ca513)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
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/processfactory.hxx>
27 #include <com/sun/star/reflection/XInterfaceMemberTypeDescription.hpp>
28 #include <com/sun/star/reflection/XIdlMethod.hpp>
29 #include <com/sun/star/uno/Exception.hpp>
30 #include <basic/codecompletecache.hxx>
31 #include <memory>
32 
33 using namespace ::com::sun::star;
34 using namespace ::com::sun::star::uno;
35 
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
40 
41 SbiSymDef* SbiParser::VarDecl( SbiExprListPtr* ppDim, bool bStatic, bool bConst )
42 {
43     bool bWithEvents = false;
44     if( Peek() == WITHEVENTS )
45     {
46         Next();
47         bWithEvents = true;
48     }
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 )
55     {
56         pDim = SbiExprList::ParseDimList( this );
57         if( !pDim->GetDims() )
58             pDef->SetWithBrackets();
59     }
60     pDef->SetType( t );
61     if( bStatic )
62         pDef->SetStatic();
63     if( bWithEvents )
64         pDef->SetWithEvents();
65     TypeDecl( *pDef );
66     if( !ppDim && pDim )
67     {
68         if(pDim->GetDims() )
69             Error( ERRCODE_BASIC_EXPECTED, "()" );
70     }
71     else if( ppDim )
72         *ppDim = std::move(pDim);
73     return pDef;
74 }
75 
76 // Resolving of an AS-Type-Declaration
77 // The data type were inserted into the handed over variable
78 
79 void SbiParser::TypeDecl( SbiSymDef& rDef, bool bAsNewAlreadyParsed )
80 {
81     SbxDataType eType = rDef.GetType();
82     if( bAsNewAlreadyParsed || Peek() == AS )
83     {
84         short nSize = 0;
85         if( !bAsNewAlreadyParsed )
86             Next();
87         rDef.SetDefinedAs();
88         SbiToken eTok = Next();
89         if( !bAsNewAlreadyParsed && eTok == NEW )
90         {
91             rDef.SetNew();
92             eTok = Next();
93         }
94         switch( eTok )
95         {
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 )
116                 {
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 );
127                     }
128                 }
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
134                 {
135                     OUString aCompleteName = aSym;
136 
137                     // #52709 DIM AS NEW for Uno with full-qualified name
138                     if( Peek() == DOT )
139                     {
140                         OUString aDotStr( '.' );
141                         while( Peek() == DOT )
142                         {
143                             aCompleteName += aDotStr;
144                             Next();
145                             SbiToken ePeekTok = Peek();
146                             if( ePeekTok == SYMBOL || IsKwd( ePeekTok ) )
147                             {
148                                 Next();
149                                 aCompleteName += aSym;
150                             }
151                             else
152                             {
153                                 Next();
154                                 Error( ERRCODE_BASIC_UNEXPECTED, SYMBOL );
155                                 break;
156                             }
157                         }
158                     }
159                     else if( rEnumArray->Find( aCompleteName, SbxClassType::Object ) || ( IsVBASupportOn() && VBAConstantHelper::instance().isVBAConstantType( aCompleteName ) ) )
160                     {
161                         eType = SbxLONG;
162                         break;
163                     }
164 
165                     // Take over in the string pool
166                     rDef.SetTypeId( aGblStrings.Add( aCompleteName ) );
167 
168                     if( rDef.IsNew() && pProc == nullptr )
169                         aRequiredTypes.push_back( aCompleteName );
170                 }
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();
180         }
181         // The variable could have been declared with a suffix
182         if( rDef.GetType() != SbxVARIANT )
183         {
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() );
188         }
189         rDef.SetType( eType );
190         rDef.SetLen( nSize );
191     }
192 }
193 
194 // Here variables, arrays and structures were defined.
195 // DIM/PRIVATE/PUBLIC/GLOBAL
196 
197 void SbiParser::Dim()
198 {
199     DefVar( SbiOpcode::DIM_, pProc && bVBASupportOn && pProc->IsStatic() );
200 }
201 
202 void SbiParser::DefVar( SbiOpcode eOp, bool bStatic )
203 {
204     SbiSymPool* pOldPool = pPool;
205     bool bSwitchPool = false;
206     bool bPersistentGlobal = false;
207     SbiToken eFirstTok = eCurTok;
208 
209     if( pProc && ( eCurTok == GLOBAL || eCurTok == PUBLIC || eCurTok == PRIVATE ) )
210         Error( ERRCODE_BASIC_NOT_IN_SUBR, eCurTok );
211     if( eCurTok == PUBLIC || eCurTok == GLOBAL )
212     {
213         bSwitchPool = true;     // at the right moment switch to the global pool
214         if( eCurTok == GLOBAL )
215             bPersistentGlobal = true;
216     }
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_ )
227     {
228         Next();
229         bConst = true;
230     }
231 
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) )
235     {
236         // Next token is read here, because !bConst
237         bool bPrivate = ( eFirstTok == PRIVATE );
238 
239         if( eCurTok == STATIC )
240         {
241             Next();
242             DefStatic( bPrivate );
243         }
244         else if( eCurTok == SUB || eCurTok == FUNCTION || eCurTok == PROPERTY )
245         {
246             // End global chain if necessary (not done in
247             // SbiParser::Parse() under these conditions
248             if( bNewGblDefs && nGblChain == 0 )
249             {
250                 nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
251                 bNewGblDefs = false;
252             }
253             Next();
254             DefProc( false, bPrivate );
255             return;
256         }
257         else if( eCurTok == ENUM )
258         {
259             Next();
260             DefEnum( bPrivate );
261             return;
262         }
263         else if( eCurTok == DECLARE )
264         {
265             Next();
266             DefDeclare( bPrivate );
267             return;
268         }
269         // #i109049
270         else if( eCurTok == TYPE )
271         {
272             Next();
273             DefType(); // TODO: Use bPrivate in DefType()
274             return;
275         }
276     }
277 
278     // SHARED were ignored
279     if( Peek() == SHARED ) Next();
280 
281     // PRESERVE only at REDIM
282     if( Peek() == PRESERVE )
283     {
284         Next();
285         if( eOp == SbiOpcode::REDIM_ )
286             eOp = SbiOpcode::REDIMP_;
287         else
288             Error( ERRCODE_BASIC_UNEXPECTED, eCurTok );
289     }
290     SbiSymDef* pDef;
291     SbiExprListPtr pDim;
292 
293     // #40689, Statics -> Module-Initialising, skip in Sub
294     sal_uInt32 nEndOfStaticLbl = 0;
295     if( !bVBASupportOn && bStatic )
296     {
297         nEndOfStaticLbl = aGen.Gen( SbiOpcode::JUMP_, 0 );
298         aGen.Statement();   // catch up on static here
299     }
300 
301     bool bDefined = false;
302     while( ( pDef = VarDecl( &pDim, bStatic, bConst ) ) != nullptr )
303     {
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 )
314         {
315             pOld = CheckRTLForSym( pDef->GetName(), SbxVARIANT );
316             if( pOld )
317                 bRtlSym = true;
318         }
319         if( pOld && !(eOp == SbiOpcode::REDIM_ || eOp == SbiOpcode::REDIMP_) )
320         {
321             if( pDef->GetScope() == SbLOCAL && pOld->GetScope() != SbLOCAL )
322                 pOld = nullptr;
323         }
324         if( pOld )
325         {
326             bDefined = true;
327             // always an error at a RTL-S
328             if( !bRtlSym && (eOp == SbiOpcode::REDIM_ || eOp == SbiOpcode::REDIMP_) )
329             {
330                 // compare the attributes at a REDIM
331                 SbxDataType eDefType;
332                 bool bError_ = false;
333                 if( pOld->IsStatic() )
334                 {
335                     bError_ = true;
336                 }
337                 else if( pOld->GetType() != ( eDefType = pDef->GetType() ) )
338                 {
339                     if( !( eDefType == SbxVARIANT && !pDef->IsDefinedAs() ) )
340                         bError_ = true;
341                 }
342                 if( bError_ )
343                     Error( ERRCODE_BASIC_VAR_DEFINED, pDef->GetName() );
344             }
345             else
346                 Error( ERRCODE_BASIC_VAR_DEFINED, pDef->GetName() );
347             delete pDef; pDef = pOld;
348         }
349         else
350             pPool->Add( pDef );
351 
352         // #36374: Create the variable in front of the distinction IsNew()
353         // Otherwise error at Dim Identifier As New Type and option explicit
354         if( !bDefined && !(eOp == SbiOpcode::REDIM_ || eOp == SbiOpcode::REDIMP_)
355                       && ( !bConst || pDef->GetScope() == SbGLOBAL ) )
356         {
357             // Declare variable or global constant
358             SbiOpcode eOp2;
359             switch ( pDef->GetScope() )
360             {
361                 case SbGLOBAL:  eOp2 = bPersistentGlobal ? SbiOpcode::GLOBAL_P_ : SbiOpcode::GLOBAL_;
362                                 goto global;
363                 case SbPUBLIC:  eOp2 = bPersistentGlobal ? SbiOpcode::PUBLIC_P_ : SbiOpcode::PUBLIC_;
364                                 // #40689, no own Opcode anymore
365                                 if( bVBASupportOn && bStatic )
366                                 {
367                                     eOp2 = SbiOpcode::STATIC_;
368                                     break;
369                                 }
370                 global:         aGen.BackChain( nGblChain );
371                                 nGblChain = 0;
372                                 bGblDefs = bNewGblDefs = true;
373                                 break;
374                 default:        eOp2 = SbiOpcode::LOCAL_;
375             }
376             sal_uInt32 nOpnd2 = sal::static_int_cast< sal_uInt16 >( pDef->GetType() );
377             if( pDef->IsWithEvents() )
378                 nOpnd2 |= SBX_TYPE_WITH_EVENTS_FLAG;
379 
380             if( bCompatible && pDef->IsNew() )
381                 nOpnd2 |= SBX_TYPE_DIM_AS_NEW_FLAG;
382 
383             short nFixedStringLength = pDef->GetFixedStringLength();
384             if( nFixedStringLength >= 0 )
385                 nOpnd2 |= (SBX_FIXED_LEN_STRING_FLAG + (sal_uInt32(nFixedStringLength) << 17));     // len = all bits above 0x10000
386 
387             if( pDim != nullptr && pDim->GetDims() > 0 )
388                 nOpnd2 |= SBX_TYPE_VAR_TO_DIM_FLAG;
389 
390             aGen.Gen( eOp2, pDef->GetId(), nOpnd2 );
391         }
392 
393         // Initialising for self-defined data types
394         // and per NEW created variable
395         if( pDef->GetType() == SbxOBJECT
396          && pDef->GetTypeId() )
397         {
398             if( !bCompatible && !pDef->IsNew() )
399             {
400                 OUString aTypeName( aGblStrings.Find( pDef->GetTypeId() ) );
401                 if( rTypeArray->Find( aTypeName, SbxClassType::Object ) == nullptr )
402                 {
403                     if( CodeCompleteOptions::IsExtendedTypeDeclaration() )
404                     {
405                         if(!IsUnoInterface(aTypeName))
406                             Error( ERRCODE_BASIC_UNDEF_TYPE, aTypeName );
407                     }
408                     else
409                         Error( ERRCODE_BASIC_UNDEF_TYPE, aTypeName );
410                 }
411             }
412 
413             if( bConst )
414             {
415                 Error( ERRCODE_BASIC_SYNTAX );
416             }
417 
418             if( pDim )
419             {
420                 if( eOp == SbiOpcode::REDIMP_ )
421                 {
422                     SbiExpression aExpr( this, *pDef, nullptr );
423                     aExpr.Gen();
424                     aGen.Gen( SbiOpcode::REDIMP_ERASE_ );
425 
426                     pDef->SetDims( pDim->GetDims() );
427                     SbiExpression aExpr2( this, *pDef, std::move(pDim) );
428                     aExpr2.Gen();
429                     aGen.Gen( SbiOpcode::DCREATE_REDIMP_, pDef->GetId(), pDef->GetTypeId() );
430                 }
431                 else
432                 {
433                     pDef->SetDims( pDim->GetDims() );
434                     SbiExpression aExpr( this, *pDef, std::move(pDim) );
435                     aExpr.Gen();
436                     aGen.Gen( SbiOpcode::DCREATE_, pDef->GetId(), pDef->GetTypeId() );
437                 }
438             }
439             else
440             {
441                 SbiExpression aExpr( this, *pDef );
442                 aExpr.Gen();
443                 SbiOpcode eOp_ = pDef->IsNew() ? SbiOpcode::CREATE_ : SbiOpcode::TCREATE_;
444                 aGen.Gen( eOp_, pDef->GetId(), pDef->GetTypeId() );
445                 if ( bVBASupportOn )
446                     aGen.Gen( SbiOpcode::VBASET_ );
447                 else
448                     aGen.Gen( SbiOpcode::SET_ );
449             }
450         }
451         else
452         {
453             if( bConst )
454             {
455                 // Definition of the constants
456                 if( pDim )
457                 {
458                     Error( ERRCODE_BASIC_SYNTAX );
459                 }
460                 SbiExpression aVar( this, *pDef );
461                 if( !TestToken( EQ ) )
462                     goto MyBreak;   // (see below)
463                 SbiConstExpression aExpr( this );
464                 if( !bDefined && aExpr.IsValid() )
465                 {
466                     if( pDef->GetScope() == SbGLOBAL )
467                     {
468                         // Create code only for the global constant!
469                         aVar.Gen();
470                         aExpr.Gen();
471                         aGen.Gen( SbiOpcode::PUTC_ );
472                     }
473                     SbiConstDef* pConst = pDef->GetConstDef();
474                     if( aExpr.GetType() == SbxSTRING )
475                         pConst->Set( aExpr.GetString() );
476                     else
477                         pConst->Set( aExpr.GetValue(), aExpr.GetType() );
478                 }
479             }
480             else if( pDim )
481             {
482                 // Dimension the variable
483                 // Delete the var at REDIM beforehand
484                 if( eOp == SbiOpcode::REDIM_ )
485                 {
486                     SbiExpression aExpr( this, *pDef, nullptr );
487                     aExpr.Gen();
488                     if ( bVBASupportOn )
489                         // delete the array but
490                         // clear the variable ( this
491                         // allows the processing of
492                         // the param to happen as normal without errors ( ordinary ERASE just clears the array )
493                         aGen.Gen( SbiOpcode::ERASE_CLEAR_ );
494                     else
495                         aGen.Gen( SbiOpcode::ERASE_ );
496                 }
497                 else if( eOp == SbiOpcode::REDIMP_ )
498                 {
499                     SbiExpression aExpr( this, *pDef, nullptr );
500                     aExpr.Gen();
501                     aGen.Gen( SbiOpcode::REDIMP_ERASE_ );
502                 }
503                 pDef->SetDims( pDim->GetDims() );
504                 if( bPersistentGlobal )
505                     pDef->SetGlobal( true );
506                 SbiExpression aExpr( this, *pDef, std::move(pDim) );
507                 aExpr.Gen();
508                 pDef->SetGlobal( false );
509                 aGen.Gen( (eOp == SbiOpcode::STATIC_) ? SbiOpcode::DIM_ : eOp );
510             }
511         }
512         if( !TestComma() )
513             goto MyBreak;
514 
515         // Implementation of bSwitchPool (see above): pPool must not be set to &aGlobals
516         // at the VarDecl-Call.
517         // Apart from that the behavior should be absolutely identical,
518         // i.e., pPool had to be reset always at the end of the loop.
519         // also at a break
520         pPool = pOldPool;
521         continue;       // Skip MyBreak
522     MyBreak:
523         pPool = pOldPool;
524         break;
525     }
526 
527     // #40689, finalize the jump over statics declarations
528     if( !bVBASupportOn && bStatic )
529     {
530         // maintain the global chain
531         nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
532         bGblDefs = bNewGblDefs = true;
533 
534         // Register for Sub a jump to the end of statics
535         aGen.BackChain( nEndOfStaticLbl );
536     }
537 
538 }
539 
540 // Here were Arrays redimensioned.
541 
542 void SbiParser::ReDim()
543 {
544     DefVar( SbiOpcode::REDIM_, pProc && bVBASupportOn && pProc->IsStatic() );
545 }
546 
547 // ERASE array, ...
548 
549 void SbiParser::Erase()
550 {
551     while( !bAbort )
552     {
553         SbiExpression aExpr( this, SbLVALUE );
554         aExpr.Gen();
555         aGen.Gen( SbiOpcode::ERASE_ );
556         if( !TestComma() ) break;
557     }
558 }
559 
560 // Declaration of a data type
561 
562 void SbiParser::Type()
563 {
564     DefType();
565 }
566 
567 void SbiParser::DefType()
568 {
569     // Read the new Token lesen. It had to be a symbol
570     if (!TestSymbol())
571         return;
572 
573     if (rTypeArray->Find(aSym,SbxClassType::Object))
574     {
575         Error( ERRCODE_BASIC_VAR_DEFINED, aSym );
576         return;
577     }
578 
579     SbxObject *pType = new SbxObject(aSym);
580 
581     bool bDone = false;
582 
583     while( !bDone && !IsEof() )
584     {
585         std::unique_ptr<SbiSymDef> pElem;
586         SbiExprListPtr pDim;
587         switch( Peek() )
588         {
589             case ENDTYPE :
590                 bDone = true;
591                 Next();
592             break;
593 
594             case EOLN :
595             case REM :
596                 Next();
597             break;
598 
599             default:
600                 pElem.reset(VarDecl(&pDim, false, false));
601                 if( !pElem )
602                     bDone = true;   // Error occurred
603         }
604         if( pElem )
605         {
606             SbxArray *pTypeMembers = pType->GetProperties();
607             OUString aElemName = pElem->GetName();
608             if( pTypeMembers->Find( aElemName, SbxClassType::DontCare) )
609             {
610                 Error (ERRCODE_BASIC_VAR_DEFINED);
611             }
612             else
613             {
614                 SbxDataType eElemType = pElem->GetType();
615                 SbxProperty *pTypeElem = new SbxProperty( aElemName, eElemType );
616                 if( pDim )
617                 {
618                     SbxDimArray* pArray = new SbxDimArray( pElem->GetType() );
619                     if ( pDim->GetSize() )
620                     {
621                         // Dimension the target array
622 
623                         for ( short i=0; i<pDim->GetSize();++i )
624                         {
625                             sal_Int32 lb = nBase;
626                             SbiExprNode* pNode =  pDim->Get(i)->GetExprNode();
627                             sal_Int32 ub = pNode->GetNumber();
628                             if ( !pDim->Get( i )->IsBased() ) // each dim is low/up
629                             {
630                                 if (  ++i >= pDim->GetSize() ) // trouble
631                                     StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR );
632                                 pNode =  pDim->Get(i)->GetExprNode();
633                                 lb = ub;
634                                 ub = pNode->GetNumber();
635                             }
636                             else if ( !bCompatible )
637                                 ub += nBase;
638                             pArray->AddDim32( lb, ub );
639                         }
640                         pArray->setHasFixedSize( true );
641                     }
642                     else
643                         pArray->unoAddDim( 0, -1 ); // variant array
644                     SbxFlagBits nSavFlags = pTypeElem->GetFlags();
645                     // need to reset the FIXED flag
646                     // when calling PutObject ( because the type will not match Object )
647                     pTypeElem->ResetFlag( SbxFlagBits::Fixed );
648                     pTypeElem->PutObject( pArray );
649                     pTypeElem->SetFlags( nSavFlags );
650                 }
651                 // Nested user type?
652                 if( eElemType == SbxOBJECT )
653                 {
654                     sal_uInt16 nElemTypeId = pElem->GetTypeId();
655                     if( nElemTypeId != 0 )
656                     {
657                         OUString aTypeName( aGblStrings.Find( nElemTypeId ) );
658                         SbxObject* pTypeObj = static_cast< SbxObject* >( rTypeArray->Find( aTypeName, SbxClassType::Object ) );
659                         if( pTypeObj != nullptr )
660                         {
661                             SbxObject* pCloneObj = cloneTypeObjectImpl( *pTypeObj );
662                             pTypeElem->PutObject( pCloneObj );
663                         }
664                     }
665                 }
666                 pTypeMembers->Insert( pTypeElem, pTypeMembers->Count() );
667             }
668         }
669     }
670 
671     pType->Remove( "Name", SbxClassType::DontCare );
672     pType->Remove( "Parent", SbxClassType::DontCare );
673 
674     rTypeArray->Insert (pType,rTypeArray->Count());
675 }
676 
677 
678 // Declaration of Enum type
679 
680 void SbiParser::Enum()
681 {
682     DefEnum( false );
683 }
684 
685 void SbiParser::DefEnum( bool bPrivate )
686 {
687     // Read the new Token. It had to be a symbol
688     if (!TestSymbol())
689         return;
690 
691     OUString aEnumName = aSym;
692     if( rEnumArray->Find(aEnumName,SbxClassType::Object) )
693     {
694         Error( ERRCODE_BASIC_VAR_DEFINED, aSym );
695         return;
696     }
697 
698     SbxObject *pEnum = new SbxObject( aEnumName );
699     if( bPrivate )
700     {
701         pEnum->SetFlag( SbxFlagBits::Private );
702     }
703     SbiSymDef* pElem;
704     bool bDone = false;
705 
706     // Starting with -1 to make first default value 0 after ++
707     sal_Int32 nCurrentEnumValue = -1;
708     while( !bDone && !IsEof() )
709     {
710         switch( Peek() )
711         {
712             case ENDENUM :
713                 pElem = nullptr;
714                 bDone = true;
715                 Next();
716             break;
717 
718             case EOLN :
719             case REM :
720                 pElem = nullptr;
721                 Next();
722             break;
723 
724             default:
725             {
726                 SbiExprListPtr pDim;
727                 pElem = VarDecl( &pDim, false, true );
728                 if( !pElem )
729                 {
730                     bDone = true;   // Error occurred
731                     break;
732                 }
733                 else if( pDim )
734                 {
735                     Error( ERRCODE_BASIC_SYNTAX );
736                     bDone = true;   // Error occurred
737                     break;
738                 }
739 
740                 SbiExpression aVar( this, *pElem );
741                 if( Peek() == EQ )
742                 {
743                     Next();
744 
745                     SbiConstExpression aExpr( this );
746                     if( aExpr.IsValid() )
747                     {
748                         SbxVariableRef xConvertVar = new SbxVariable();
749                         if( aExpr.GetType() == SbxSTRING )
750                             xConvertVar->PutString( aExpr.GetString() );
751                         else
752                             xConvertVar->PutDouble( aExpr.GetValue() );
753 
754                         nCurrentEnumValue = xConvertVar->GetLong();
755                     }
756                 }
757                 else
758                     nCurrentEnumValue++;
759 
760                 SbiSymPool* pPoolToUse = bPrivate ? pPool : &aGlobals;
761 
762                 SbiSymDef* pOld = pPoolToUse->Find( pElem->GetName() );
763                 if( pOld )
764                 {
765                     Error( ERRCODE_BASIC_VAR_DEFINED, pElem->GetName() );
766                     bDone = true;   // Error occurred
767                     break;
768                 }
769 
770                 pPool->Add( pElem );
771 
772                 if( !bPrivate )
773                 {
774                     aGen.BackChain( nGblChain );
775                     nGblChain = 0;
776                     bGblDefs = bNewGblDefs = true;
777                     aGen.Gen(
778                         SbiOpcode::GLOBAL_, pElem->GetId(),
779                         sal::static_int_cast< sal_uInt16 >( pElem->GetType() ) );
780 
781                     aVar.Gen();
782                     sal_uInt16 nStringId = aGen.GetParser()->aGblStrings.Add( nCurrentEnumValue, SbxLONG );
783                     aGen.Gen( SbiOpcode::NUMBER_, nStringId );
784                     aGen.Gen( SbiOpcode::PUTC_ );
785                 }
786 
787                 SbiConstDef* pConst = pElem->GetConstDef();
788                 pConst->Set( nCurrentEnumValue, SbxLONG );
789             }
790         }
791         if( pElem )
792         {
793             SbxArray *pEnumMembers = pEnum->GetProperties();
794             SbxProperty *pEnumElem = new SbxProperty( pElem->GetName(), SbxLONG );
795             pEnumElem->PutLong( nCurrentEnumValue );
796             pEnumElem->ResetFlag( SbxFlagBits::Write );
797             pEnumElem->SetFlag( SbxFlagBits::Const );
798             pEnumMembers->Insert( pEnumElem, pEnumMembers->Count() );
799         }
800     }
801 
802     pEnum->Remove( "Name", SbxClassType::DontCare );
803     pEnum->Remove( "Parent", SbxClassType::DontCare );
804 
805     rEnumArray->Insert( pEnum, rEnumArray->Count() );
806 }
807 
808 
809 // Procedure-Declaration
810 // the first Token is already read in (SUB/FUNCTION)
811 // xxx Name [LIB "name"[ALIAS "name"]][(Parameter)][AS TYPE]
812 
813 SbiProcDef* SbiParser::ProcDecl( bool bDecl )
814 {
815     bool bFunc = ( eCurTok == FUNCTION );
816     bool bProp = ( eCurTok == GET || eCurTok == SET || eCurTok == LET );
817     if( !TestSymbol() ) return nullptr;
818     OUString aName( aSym );
819     SbxDataType eType = eScanType;
820     SbiProcDef* pDef = new SbiProcDef( this, aName, true );
821     pDef->SetType( eType );
822     if( Peek() == CDECL_ )
823     {
824         Next(); pDef->SetCdecl(true);
825     }
826     if( Peek() == LIB )
827     {
828         Next();
829         if( Next() == FIXSTRING )
830         {
831             pDef->GetLib() = aSym;
832         }
833         else
834         {
835             Error( ERRCODE_BASIC_SYNTAX );
836         }
837     }
838     if( Peek() == ALIAS )
839     {
840         Next();
841         if( Next() == FIXSTRING )
842         {
843             pDef->GetAlias() = aSym;
844         }
845         else
846         {
847             Error( ERRCODE_BASIC_SYNTAX );
848         }
849     }
850     if( !bDecl )
851     {
852         // CDECL, LIB and ALIAS are invalid
853         if( !pDef->GetLib().isEmpty() )
854         {
855             Error( ERRCODE_BASIC_UNEXPECTED, LIB );
856         }
857         if( !pDef->GetAlias().isEmpty() )
858         {
859             Error( ERRCODE_BASIC_UNEXPECTED, ALIAS );
860         }
861         if( pDef->IsCdecl() )
862         {
863             Error( ERRCODE_BASIC_UNEXPECTED, CDECL_ );
864         }
865         pDef->SetCdecl( false );
866         pDef->GetLib().clear();
867         pDef->GetAlias().clear();
868     }
869     else if( pDef->GetLib().isEmpty() )
870     {
871         // ALIAS and CDECL only together with LIB
872         if( !pDef->GetAlias().isEmpty() )
873         {
874             Error( ERRCODE_BASIC_UNEXPECTED, ALIAS );
875         }
876         if( pDef->IsCdecl() )
877         {
878             Error( ERRCODE_BASIC_UNEXPECTED, CDECL_ );
879         }
880         pDef->SetCdecl( false );
881         pDef->GetAlias().clear();
882     }
883     // Brackets?
884     if( Peek() == LPAREN )
885     {
886         Next();
887         if( Peek() == RPAREN )
888         {
889             Next();
890         }
891         else
892         {
893             for(;;)
894             {
895                 bool bByVal = false;
896                 bool bOptional = false;
897                 bool bParamArray = false;
898                 while( Peek() == BYVAL || Peek() == BYREF || Peek() == OPTIONAL_ )
899                 {
900                     if( Peek() == BYVAL )
901                     {
902                         bByVal = true;
903                     }
904                     else if ( Peek() == BYREF )
905                     {
906                         bByVal = false;
907                     }
908                     else if ( Peek() == OPTIONAL_ )
909                     {
910                         bOptional = true;
911                     }
912                     Next();
913                 }
914                 if( bCompatible && Peek() == PARAMARRAY )
915                 {
916                     if( bByVal || bOptional )
917                     {
918                         Error( ERRCODE_BASIC_UNEXPECTED, PARAMARRAY );
919                     }
920                     Next();
921                     bParamArray = true;
922                 }
923                 SbiSymDef* pPar = VarDecl( nullptr, false, false );
924                 if( !pPar )
925                 {
926                     break;
927                 }
928                 if( bByVal )
929                 {
930                     pPar->SetByVal(true);
931                 }
932                 if( bOptional )
933                 {
934                     pPar->SetOptional();
935                 }
936                 if( bParamArray )
937                 {
938                     pPar->SetParamArray();
939                 }
940                 pDef->GetParams().Add( pPar );
941                 SbiToken eTok = Next();
942                 if( eTok != COMMA && eTok != RPAREN )
943                 {
944                     bool bError2 = true;
945                     if( bOptional && bCompatible && eTok == EQ )
946                     {
947                         std::unique_ptr<SbiConstExpression> pDefaultExpr(new SbiConstExpression( this ));
948                         SbxDataType eType2 = pDefaultExpr->GetType();
949 
950                         sal_uInt16 nStringId;
951                         if( eType2 == SbxSTRING )
952                         {
953                             nStringId = aGblStrings.Add( pDefaultExpr->GetString() );
954                         }
955                         else
956                         {
957                             nStringId = aGblStrings.Add( pDefaultExpr->GetValue(), eType2 );
958                         }
959                         pPar->SetDefaultId( nStringId );
960                         pDefaultExpr.reset();
961 
962                         eTok = Next();
963                         if( eTok == COMMA || eTok == RPAREN )
964                         {
965                             bError2 = false;
966                         }
967                     }
968                     if( bError2 )
969                     {
970                         Error( ERRCODE_BASIC_EXPECTED, RPAREN );
971                         break;
972                     }
973                 }
974                 if( eTok == RPAREN )
975                 {
976                     break;
977                 }
978             }
979         }
980     }
981     TypeDecl( *pDef );
982     if( eType != SbxVARIANT && pDef->GetType() != eType )
983     {
984         Error( ERRCODE_BASIC_BAD_DECLARATION, aName );
985     }
986     if( pDef->GetType() == SbxVARIANT && !( bFunc || bProp ) )
987     {
988         pDef->SetType( SbxEMPTY );
989     }
990     return pDef;
991 }
992 
993 // DECLARE
994 
995 void SbiParser::Declare()
996 {
997     DefDeclare( false );
998 }
999 
1000 void SbiParser::DefDeclare( bool bPrivate )
1001 {
1002     Next();
1003     if( eCurTok == PTRSAFE )
1004         Next();
1005 
1006     if( eCurTok != SUB && eCurTok != FUNCTION )
1007     {
1008       Error( ERRCODE_BASIC_UNEXPECTED, eCurTok );
1009     }
1010     else
1011     {
1012         bool bFunction = (eCurTok == FUNCTION);
1013 
1014         SbiProcDef* pDef = ProcDecl( true );
1015         if( pDef )
1016         {
1017             if( pDef->GetLib().isEmpty() )
1018             {
1019                 Error( ERRCODE_BASIC_EXPECTED, LIB );
1020             }
1021             // Is it already there?
1022             SbiSymDef* pOld = aPublics.Find( pDef->GetName() );
1023             if( pOld )
1024             {
1025                 SbiProcDef* p = pOld->GetProcDef();
1026                 if( !p )
1027                 {
1028                     // Declared as a variable
1029                     Error( ERRCODE_BASIC_BAD_DECLARATION, pDef->GetName() );
1030                     delete pDef;
1031                     pDef = nullptr;
1032                 }
1033                 else
1034                 {
1035                     pDef->Match( p );
1036                 }
1037             }
1038             else
1039             {
1040                 aPublics.Add( pDef );
1041             }
1042             if ( pDef )
1043             {
1044                 pDef->SetPublic( !bPrivate );
1045 
1046                 // New declare handling
1047                 if( !pDef->GetLib().isEmpty())
1048                 {
1049                     if( bNewGblDefs && nGblChain == 0 )
1050                     {
1051                         nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
1052                         bNewGblDefs = false;
1053                     }
1054 
1055                     sal_uInt16 nSavLine = nLine;
1056                     aGen.Statement();
1057                     pDef->Define();
1058                     pDef->SetLine1( nSavLine );
1059                     pDef->SetLine2( nSavLine );
1060 
1061                     SbiSymPool& rPool = pDef->GetParams();
1062                     sal_uInt16 nParCount = rPool.GetSize();
1063 
1064                     SbxDataType eType = pDef->GetType();
1065                     if( bFunction )
1066                     {
1067                         aGen.Gen( SbiOpcode::PARAM_, 0, sal::static_int_cast< sal_uInt16 >( eType ) );
1068                     }
1069                     if( nParCount > 1 )
1070                     {
1071                         aGen.Gen( SbiOpcode::ARGC_ );
1072 
1073                         for( sal_uInt16 i = 1 ; i < nParCount ; ++i )
1074                         {
1075                             SbiSymDef* pParDef = rPool.Get( i );
1076                             SbxDataType eParType = pParDef->GetType();
1077 
1078                             aGen.Gen( SbiOpcode::PARAM_, i, sal::static_int_cast< sal_uInt16 >( eParType ) );
1079                             aGen.Gen( SbiOpcode::ARGV_ );
1080 
1081                             sal_uInt16 nTyp = sal::static_int_cast< sal_uInt16 >( pParDef->GetType() );
1082                             if( pParDef->IsByVal() )
1083                             {
1084                                 // Reset to avoid additional byval in call to wrapper function
1085                                 pParDef->SetByVal( false );
1086                                 nTyp |= 0x8000;
1087                             }
1088                             aGen.Gen( SbiOpcode::ARGTYP_, nTyp );
1089                         }
1090                     }
1091 
1092                     aGen.Gen( SbiOpcode::LIB_, aGblStrings.Add( pDef->GetLib() ) );
1093 
1094                     SbiOpcode eOp = pDef->IsCdecl() ? SbiOpcode::CALLC_ : SbiOpcode::CALL_;
1095                     sal_uInt16 nId = pDef->GetId();
1096                     if( !pDef->GetAlias().isEmpty() )
1097                     {
1098                         nId = ( nId & 0x8000 ) | aGblStrings.Add( pDef->GetAlias() );
1099                     }
1100                     if( nParCount > 1 )
1101                     {
1102                         nId |= 0x8000;
1103                     }
1104                     aGen.Gen( eOp, nId, sal::static_int_cast< sal_uInt16 >( eType ) );
1105 
1106                     if( bFunction )
1107                     {
1108                         aGen.Gen( SbiOpcode::PUT_ );
1109                     }
1110                     aGen.Gen( SbiOpcode::LEAVE_ );
1111                 }
1112             }
1113         }
1114     }
1115 }
1116 
1117 void SbiParser::Attribute()
1118 {
1119     // TODO: Need to implement the method as an attributed object.
1120     while( Next() != EQ )
1121     {
1122         if( Next() != DOT)
1123         {
1124             break;
1125         }
1126     }
1127 
1128     if( eCurTok != EQ )
1129     {
1130         Error( ERRCODE_BASIC_SYNTAX );
1131     }
1132     else
1133     {
1134         SbiExpression aValue( this );
1135     }
1136     // Don't generate any code - just discard it.
1137 }
1138 
1139 // Call of a SUB or a FUNCTION
1140 
1141 void SbiParser::Call()
1142 {
1143     SbiExpression aVar( this, SbSYMBOL );
1144     aVar.Gen( FORCE_CALL );
1145     aGen.Gen( SbiOpcode::GET_ );
1146 }
1147 
1148 // SUB/FUNCTION
1149 
1150 void SbiParser::SubFunc()
1151 {
1152     DefProc( false, false );
1153 }
1154 
1155 // Read in of a procedure
1156 
1157 void SbiParser::DefProc( bool bStatic, bool bPrivate )
1158 {
1159     sal_uInt16 l1 = nLine;
1160     bool bSub = ( eCurTok == SUB );
1161     bool bProperty = ( eCurTok == PROPERTY );
1162     PropertyMode ePropertyMode = PropertyMode::NONE;
1163     if( bProperty )
1164     {
1165         Next();
1166         if( eCurTok == GET )
1167         {
1168             ePropertyMode = PropertyMode::Get;
1169         }
1170         else if( eCurTok == LET )
1171         {
1172             ePropertyMode = PropertyMode::Let;
1173         }
1174         else if( eCurTok == SET )
1175         {
1176             ePropertyMode = PropertyMode::Set;
1177         }
1178         else
1179         {
1180             Error( ERRCODE_BASIC_EXPECTED, "Get or Let or Set" );
1181         }
1182     }
1183 
1184     SbiToken eExit = eCurTok;
1185     SbiProcDef* pDef = ProcDecl( false );
1186     if( !pDef )
1187     {
1188         return;
1189     }
1190     pDef->setPropertyMode( ePropertyMode );
1191 
1192     // Is the Proc already declared?
1193     SbiSymDef* pOld = aPublics.Find( pDef->GetName() );
1194     if( pOld )
1195     {
1196         pProc = pOld->GetProcDef();
1197         if( !pProc )
1198         {
1199             // Declared as a variable
1200             Error( ERRCODE_BASIC_BAD_DECLARATION, pDef->GetName() );
1201             delete pDef;
1202             return;
1203         }
1204         // #100027: Multiple declaration -> Error
1205         // #112787: Not for setup, REMOVE for 8
1206         else if( pProc->IsUsedForProcDecl() )
1207         {
1208             PropertyMode ePropMode = pDef->getPropertyMode();
1209             if( ePropMode == PropertyMode::NONE || ePropMode == pProc->getPropertyMode() )
1210             {
1211                 Error( ERRCODE_BASIC_PROC_DEFINED, pDef->GetName() );
1212                 delete pDef;
1213                 return;
1214             }
1215         }
1216 
1217         pDef->Match( pProc );
1218     }
1219     else
1220     {
1221         aPublics.Add( pDef );
1222     }
1223     assert(pDef);
1224     pProc = pDef;
1225     pProc->SetPublic( !bPrivate );
1226 
1227     // Now we set the search hierarchy for symbols as well as the
1228     // current procedure.
1229     aPublics.SetProcId( pProc->GetId() );
1230     pProc->GetParams().SetParent( &aPublics );
1231     if( bStatic )
1232     {
1233         if ( bVBASupportOn )
1234         {
1235             pProc->SetStatic();
1236         }
1237         else
1238         {
1239             Error( ERRCODE_BASIC_NOT_IMPLEMENTED ); // STATIC SUB ...
1240         }
1241     }
1242     else
1243     {
1244         pProc->SetStatic( false );
1245     }
1246     // Normal case: Local variable->parameter->global variable
1247     pProc->GetLocals().SetParent( &pProc->GetParams() );
1248     pPool = &pProc->GetLocals();
1249 
1250     pProc->Define();
1251     OpenBlock( eExit );
1252     StmntBlock( bSub ? ENDSUB : (bProperty ? ENDPROPERTY : ENDFUNC) );
1253     sal_uInt16 l2 = nLine;
1254     pProc->SetLine1( l1 );
1255     pProc->SetLine2( l2 );
1256     pPool = &aPublics;
1257     aPublics.SetProcId( 0 );
1258     // Open labels?
1259     pProc->GetLabels().CheckRefs();
1260     CloseBlock();
1261     aGen.Gen( SbiOpcode::LEAVE_ );
1262     pProc = nullptr;
1263 }
1264 
1265 // STATIC variable|procedure
1266 
1267 void SbiParser::Static()
1268 {
1269     DefStatic( false );
1270 }
1271 
1272 void SbiParser::DefStatic( bool bPrivate )
1273 {
1274     SbiSymPool* p;
1275 
1276     switch( Peek() )
1277     {
1278     case SUB:
1279     case FUNCTION:
1280     case PROPERTY:
1281         // End global chain if necessary (not done in
1282         // SbiParser::Parse() under these conditions
1283         if( bNewGblDefs && nGblChain == 0 )
1284         {
1285             nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
1286             bNewGblDefs = false;
1287         }
1288         Next();
1289         DefProc( true, bPrivate );
1290         break;
1291     default:
1292         if( !pProc )
1293         {
1294             Error( ERRCODE_BASIC_NOT_IN_SUBR );
1295         }
1296         // Reset the Pool, so that STATIC-Declarations go into the
1297         // global Pool
1298         p = pPool;
1299         pPool = &aPublics;
1300         DefVar( SbiOpcode::STATIC_, true );
1301         pPool = p;
1302         break;
1303     }
1304 }
1305 
1306 bool SbiParser::IsUnoInterface(const OUString& sTypeName)
1307 {
1308     try
1309     {
1310         return css::reflection::theCoreReflection::get(
1311             comphelper::getProcessComponentContext())->forName(sTypeName).is();
1312     }
1313     catch(const Exception&)
1314     {
1315         OSL_FAIL("Could not create reflection.CoreReflection.");
1316     }
1317     return false;
1318 }
1319 
1320 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1321