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/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>
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
VarDecl(SbiExprListPtr * ppDim,bool bStatic,bool bConst)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
TypeDecl(SbiSymDef & rDef,bool bAsNewAlreadyParsed)79 void SbiParser::TypeDecl( SbiSymDef& rDef, bool bAsNewAlreadyParsed )
80 {
81 SbxDataType eType = rDef.GetType();
82 if( !(bAsNewAlreadyParsed || Peek() == AS) )
83 return;
84
85 short nSize = 0;
86 if( !bAsNewAlreadyParsed )
87 Next();
88 rDef.SetDefinedAs();
89 SbiToken eTok = Next();
90 if( !bAsNewAlreadyParsed && eTok == NEW )
91 {
92 rDef.SetNew();
93 eTok = Next();
94 }
95 switch( eTok )
96 {
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 )
117 {
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 );
128 }
129 }
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
135 {
136 OUString aCompleteName = aSym;
137
138 // #52709 DIM AS NEW for Uno with full-qualified name
139 if( Peek() == DOT )
140 {
141 OUString aDotStr( '.' );
142 while( Peek() == DOT )
143 {
144 aCompleteName += aDotStr;
145 Next();
146 SbiToken ePeekTok = Peek();
147 if( ePeekTok == SYMBOL || IsKwd( ePeekTok ) )
148 {
149 Next();
150 aCompleteName += aSym;
151 }
152 else
153 {
154 Next();
155 Error( ERRCODE_BASIC_UNEXPECTED, SYMBOL );
156 break;
157 }
158 }
159 }
160 else if( rEnumArray->Find( aCompleteName, SbxClassType::Object ) || ( IsVBASupportOn() && VBAConstantHelper::instance().isVBAConstantType( aCompleteName ) ) )
161 {
162 eType = SbxLONG;
163 break;
164 }
165
166 // Take over in the string pool
167 rDef.SetTypeId( aGblStrings.Add( aCompleteName ) );
168
169 if( rDef.IsNew() && pProc == nullptr )
170 aRequiredTypes.push_back( aCompleteName );
171 }
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();
181 }
182 // The variable could have been declared with a suffix
183 if( rDef.GetType() != SbxVARIANT )
184 {
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() );
189 }
190 rDef.SetType( eType );
191 rDef.SetLen( nSize );
192 }
193
194 // Here variables, arrays and structures were defined.
195 // DIM/PRIVATE/PUBLIC/GLOBAL
196
Dim()197 void SbiParser::Dim()
198 {
199 DefVar( SbiOpcode::DIM_, pProc && bVBASupportOn && pProc->IsStatic() );
200 }
201
DefVar(SbiOpcode eOp,bool bStatic)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 )
322 if (auto eOldScope = pOld->GetScope(); eOldScope != SbLOCAL && eOldScope != SbPARAM)
323 pOld = nullptr;
324 }
325 if( pOld )
326 {
327 bDefined = true;
328 // always an error at a RTL-S
329 if( !bRtlSym && (eOp == SbiOpcode::REDIM_ || eOp == SbiOpcode::REDIMP_) )
330 {
331 // compare the attributes at a REDIM
332 SbxDataType eDefType;
333 bool bError_ = false;
334 if( pOld->IsStatic() )
335 {
336 bError_ = true;
337 }
338 else if( pOld->GetType() != ( eDefType = pDef->GetType() ) )
339 {
340 if( eDefType != SbxVARIANT || pDef->IsDefinedAs() )
341 bError_ = true;
342 }
343 if( bError_ )
344 Error( ERRCODE_BASIC_VAR_DEFINED, pDef->GetName() );
345 }
346 else
347 Error( ERRCODE_BASIC_VAR_DEFINED, pDef->GetName() );
348 delete pDef; pDef = pOld;
349 }
350 else
351 pPool->Add( pDef );
352
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 ) )
357 {
358 // Declare variable or global constant
359 SbiOpcode eOp2;
360 switch ( pDef->GetScope() )
361 {
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 )
367 {
368 eOp2 = SbiOpcode::STATIC_;
369 break;
370 }
371 global: aGen.BackChain( nGblChain );
372 nGblChain = 0;
373 bGblDefs = bNewGblDefs = true;
374 break;
375 default: eOp2 = SbiOpcode::LOCAL_;
376 }
377 sal_uInt32 nOpnd2 = sal::static_int_cast< sal_uInt16 >( pDef->GetType() );
378 if( pDef->IsWithEvents() )
379 nOpnd2 |= SBX_TYPE_WITH_EVENTS_FLAG;
380
381 if( bCompatible && pDef->IsNew() )
382 nOpnd2 |= SBX_TYPE_DIM_AS_NEW_FLAG;
383
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
387
388 if( pDim != nullptr && pDim->GetDims() > 0 )
389 nOpnd2 |= SBX_TYPE_VAR_TO_DIM_FLAG;
390
391 aGen.Gen( eOp2, pDef->GetId(), nOpnd2 );
392 }
393
394 // Initialising for self-defined data types
395 // and per NEW created variable
396 if( pDef->GetType() == SbxOBJECT
397 && pDef->GetTypeId() )
398 {
399 if( !bCompatible && !pDef->IsNew() )
400 {
401 OUString aTypeName( aGblStrings.Find( pDef->GetTypeId() ) );
402 if( rTypeArray->Find( aTypeName, SbxClassType::Object ) == nullptr )
403 {
404 if( CodeCompleteOptions::IsExtendedTypeDeclaration() )
405 {
406 if(!IsUnoInterface(aTypeName))
407 Error( ERRCODE_BASIC_UNDEF_TYPE, aTypeName );
408 }
409 else
410 Error( ERRCODE_BASIC_UNDEF_TYPE, aTypeName );
411 }
412 }
413
414 if( bConst )
415 {
416 Error( ERRCODE_BASIC_SYNTAX );
417 }
418
419 if( pDim )
420 {
421 if( eOp == SbiOpcode::REDIMP_ )
422 {
423 SbiExpression aExpr( this, *pDef, nullptr );
424 aExpr.Gen();
425 aGen.Gen( SbiOpcode::REDIMP_ERASE_ );
426
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() );
431 }
432 else
433 {
434 // tdf#145371, tdf#136755 - only delete the variable beforehand REDIM
435 if (eOp == SbiOpcode::REDIM_)
436 {
437 SbiExpression aExpr(this, *pDef, nullptr);
438 aExpr.Gen();
439 aGen.Gen(bVBASupportOn ? SbiOpcode::ERASE_CLEAR_ : SbiOpcode::ERASE_);
440 }
441
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() );
446 }
447 }
448 else
449 {
450 SbiExpression aExpr( this, *pDef );
451 aExpr.Gen();
452
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
463 */
464 sal_uInt32 come_from = 0;
465 if ( pDef->GetScope() == SbGLOBAL )
466 {
467 come_from = aGen.Gen( SbiOpcode::JUMPT_, 0 );
468 aGen.Gen( SbiOpcode::FIND_, pDef->GetId(), pDef->GetTypeId() );
469 }
470
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_ );
477
478 if ( come_from )
479 {
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 );
484 }
485 }
486 }
487 else
488 {
489 if( bConst )
490 {
491 // Definition of the constants
492 if( pDim )
493 {
494 Error( ERRCODE_BASIC_SYNTAX );
495 }
496 SbiExpression aVar( this, *pDef );
497 if( !TestToken( EQ ) )
498 goto MyBreak; // (see below)
499 SbiConstExpression aExpr( this );
500 if( !bDefined && aExpr.IsValid() )
501 {
502 if( pDef->GetScope() == SbGLOBAL )
503 {
504 // Create code only for the global constant!
505 aVar.Gen();
506 aExpr.Gen();
507 aGen.Gen( SbiOpcode::PUTC_ );
508 }
509 SbiConstDef* pConst = pDef->GetConstDef();
510 if( aExpr.GetType() == SbxSTRING )
511 pConst->Set( aExpr.GetString() );
512 else
513 pConst->Set( aExpr.GetValue(), aExpr.GetType() );
514 }
515 }
516 else if( pDim )
517 {
518 // Dimension the variable
519 // Delete the var at REDIM beforehand
520 if( eOp == SbiOpcode::REDIM_ )
521 {
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_ );
532 }
533 else if( eOp == SbiOpcode::REDIMP_ )
534 {
535 SbiExpression aExpr( this, *pDef, nullptr );
536 aExpr.Gen();
537 aGen.Gen( SbiOpcode::REDIMP_ERASE_ );
538 }
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 );
546 }
547 }
548 if( !TestComma() )
549 goto MyBreak;
550
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;
561 }
562
563 // #40689, finalize the jump over statics declarations
564 if( !bVBASupportOn && bStatic )
565 {
566 // maintain the global chain
567 nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
568 bGblDefs = bNewGblDefs = true;
569
570 // Register for Sub a jump to the end of statics
571 aGen.BackChain( nEndOfStaticLbl );
572 }
573
574 }
575
576 // Here were Arrays redimensioned.
577
ReDim()578 void SbiParser::ReDim()
579 {
580 DefVar( SbiOpcode::REDIM_, pProc && bVBASupportOn && pProc->IsStatic() );
581 }
582
583 // ERASE array, ...
584
Erase()585 void SbiParser::Erase()
586 {
587 while( !bAbort )
588 {
589 SbiExpression aExpr( this, SbLVALUE );
590 aExpr.Gen();
591 aGen.Gen( SbiOpcode::ERASE_ );
592 if( !TestComma() ) break;
593 }
594 }
595
596 // Declaration of a data type
597
Type()598 void SbiParser::Type()
599 {
600 DefType();
601 }
602
DefType()603 void SbiParser::DefType()
604 {
605 // Read the new Token lesen. It had to be a symbol
606 if (!TestSymbol())
607 return;
608
609 if (rTypeArray->Find(aSym,SbxClassType::Object))
610 {
611 Error( ERRCODE_BASIC_VAR_DEFINED, aSym );
612 return;
613 }
614
615 SbxObject *pType = new SbxObject(aSym);
616
617 bool bDone = false;
618
619 while( !bDone && !IsEof() )
620 {
621 std::unique_ptr<SbiSymDef> pElem;
622 SbiExprListPtr pDim;
623 switch( Peek() )
624 {
625 case ENDTYPE :
626 bDone = true;
627 Next();
628 break;
629
630 case EOLN :
631 case REM :
632 Next();
633 break;
634
635 default:
636 pElem.reset(VarDecl(&pDim, false, false));
637 if( !pElem )
638 bDone = true; // Error occurred
639 }
640 if( pElem )
641 {
642 SbxArray *pTypeMembers = pType->GetProperties();
643 OUString aElemName = pElem->GetName();
644 if( pTypeMembers->Find( aElemName, SbxClassType::DontCare) )
645 {
646 Error (ERRCODE_BASIC_VAR_DEFINED);
647 }
648 else
649 {
650 SbxDataType eElemType = pElem->GetType();
651 SbxProperty *pTypeElem = new SbxProperty( aElemName, eElemType );
652 if( pDim )
653 {
654 SbxDimArray* pArray = new SbxDimArray( pElem->GetType() );
655 if ( pDim->GetSize() )
656 {
657 // Dimension the target array
658
659 for ( short i=0; i<pDim->GetSize();++i )
660 {
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
665 {
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();
671 }
672 else if ( !bCompatible )
673 ub += nBase;
674 pArray->AddDim(lb, ub);
675 }
676 pArray->setHasFixedSize( true );
677 }
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 );
686 }
687 // Nested user type?
688 if( eElemType == SbxOBJECT )
689 {
690 sal_uInt16 nElemTypeId = pElem->GetTypeId();
691 if( nElemTypeId != 0 )
692 {
693 OUString aTypeName( aGblStrings.Find( nElemTypeId ) );
694 SbxObject* pTypeObj = static_cast< SbxObject* >( rTypeArray->Find( aTypeName, SbxClassType::Object ) );
695 if( pTypeObj != nullptr )
696 {
697 SbxObjectRef pCloneObj = cloneTypeObjectImpl( *pTypeObj );
698 pTypeElem->PutObject( pCloneObj.get() );
699 }
700 }
701 }
702 pTypeMembers->Insert(pTypeElem, pTypeMembers->Count());
703 }
704 }
705 }
706
707 pType->Remove( "Name", SbxClassType::DontCare );
708 pType->Remove( "Parent", SbxClassType::DontCare );
709
710 rTypeArray->Insert(pType, rTypeArray->Count());
711 }
712
713
714 // Declaration of Enum type
715
Enum()716 void SbiParser::Enum()
717 {
718 DefEnum( false );
719 }
720
DefEnum(bool bPrivate)721 void SbiParser::DefEnum( bool bPrivate )
722 {
723 // Read the new Token. It had to be a symbol
724 if (!TestSymbol())
725 return;
726
727 OUString aEnumName = aSym;
728 if( rEnumArray->Find(aEnumName,SbxClassType::Object) )
729 {
730 Error( ERRCODE_BASIC_VAR_DEFINED, aSym );
731 return;
732 }
733
734 SbxObject *pEnum = new SbxObject( aEnumName );
735 if( bPrivate )
736 {
737 pEnum->SetFlag( SbxFlagBits::Private );
738 }
739 SbiSymDef* pElem;
740 bool bDone = false;
741
742 // Starting with -1 to make first default value 0 after ++
743 sal_Int32 nCurrentEnumValue = -1;
744 while( !bDone && !IsEof() )
745 {
746 switch( Peek() )
747 {
748 case ENDENUM :
749 pElem = nullptr;
750 bDone = true;
751 Next();
752 break;
753
754 case EOLN :
755 case REM :
756 pElem = nullptr;
757 Next();
758 break;
759
760 default:
761 {
762 SbiExprListPtr pDim;
763 pElem = VarDecl( &pDim, false, true );
764 if( !pElem )
765 {
766 bDone = true; // Error occurred
767 break;
768 }
769 else if( pDim )
770 {
771 Error( ERRCODE_BASIC_SYNTAX );
772 bDone = true; // Error occurred
773 break;
774 }
775
776 SbiExpression aVar( this, *pElem );
777 if( Peek() == EQ )
778 {
779 Next();
780
781 SbiConstExpression aExpr( this );
782 if( aExpr.IsValid() )
783 {
784 SbxVariableRef xConvertVar = new SbxVariable();
785 if( aExpr.GetType() == SbxSTRING )
786 xConvertVar->PutString( aExpr.GetString() );
787 else
788 xConvertVar->PutDouble( aExpr.GetValue() );
789
790 nCurrentEnumValue = xConvertVar->GetLong();
791 }
792 }
793 else
794 nCurrentEnumValue++;
795
796 SbiSymPool* pPoolToUse = bPrivate ? pPool : &aGlobals;
797
798 SbiSymDef* pOld = pPoolToUse->Find( pElem->GetName() );
799 if( pOld )
800 {
801 Error( ERRCODE_BASIC_VAR_DEFINED, pElem->GetName() );
802 bDone = true; // Error occurred
803 break;
804 }
805
806 pPool->Add( pElem );
807
808 if( !bPrivate )
809 {
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() ) );
816
817 aVar.Gen();
818 sal_uInt16 nStringId = aGen.GetParser()->aGblStrings.Add( nCurrentEnumValue, SbxLONG );
819 aGen.Gen( SbiOpcode::NUMBER_, nStringId );
820 aGen.Gen( SbiOpcode::PUTC_ );
821 }
822
823 SbiConstDef* pConst = pElem->GetConstDef();
824 pConst->Set( nCurrentEnumValue, SbxLONG );
825 }
826 }
827 if( pElem )
828 {
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());
835 }
836 }
837
838 pEnum->Remove( "Name", SbxClassType::DontCare );
839 pEnum->Remove( "Parent", SbxClassType::DontCare );
840
841 rEnumArray->Insert(pEnum, rEnumArray->Count());
842 }
843
844
845 // Procedure-Declaration
846 // the first Token is already read in (SUB/FUNCTION)
847 // xxx Name [LIB "name"[ALIAS "name"]][(Parameter)][AS TYPE]
848
ProcDecl(bool bDecl)849 SbiProcDef* SbiParser::ProcDecl( bool bDecl )
850 {
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_ )
859 {
860 Next(); pDef->SetCdecl(true);
861 }
862 if( Peek() == LIB )
863 {
864 Next();
865 if( Next() == FIXSTRING )
866 {
867 pDef->GetLib() = aSym;
868 }
869 else
870 {
871 Error( ERRCODE_BASIC_SYNTAX );
872 }
873 }
874 if( Peek() == ALIAS )
875 {
876 Next();
877 if( Next() == FIXSTRING )
878 {
879 pDef->GetAlias() = aSym;
880 }
881 else
882 {
883 Error( ERRCODE_BASIC_SYNTAX );
884 }
885 }
886 if( !bDecl )
887 {
888 // CDECL, LIB and ALIAS are invalid
889 if( !pDef->GetLib().isEmpty() )
890 {
891 Error( ERRCODE_BASIC_UNEXPECTED, LIB );
892 }
893 if( !pDef->GetAlias().isEmpty() )
894 {
895 Error( ERRCODE_BASIC_UNEXPECTED, ALIAS );
896 }
897 if( pDef->IsCdecl() )
898 {
899 Error( ERRCODE_BASIC_UNEXPECTED, CDECL_ );
900 }
901 pDef->SetCdecl( false );
902 pDef->GetLib().clear();
903 pDef->GetAlias().clear();
904 }
905 else if( pDef->GetLib().isEmpty() )
906 {
907 // ALIAS and CDECL only together with LIB
908 if( !pDef->GetAlias().isEmpty() )
909 {
910 Error( ERRCODE_BASIC_UNEXPECTED, ALIAS );
911 }
912 if( pDef->IsCdecl() )
913 {
914 Error( ERRCODE_BASIC_UNEXPECTED, CDECL_ );
915 }
916 pDef->SetCdecl( false );
917 pDef->GetAlias().clear();
918 }
919 // Brackets?
920 if( Peek() == LPAREN )
921 {
922 Next();
923 if( Peek() == RPAREN )
924 {
925 Next();
926 }
927 else
928 {
929 for(;;)
930 {
931 bool bByVal = false;
932 bool bOptional = false;
933 bool bParamArray = false;
934 while( Peek() == BYVAL || Peek() == BYREF || Peek() == OPTIONAL_ )
935 {
936 if( Peek() == BYVAL )
937 {
938 bByVal = true;
939 }
940 else if ( Peek() == BYREF )
941 {
942 bByVal = false;
943 }
944 else if ( Peek() == OPTIONAL_ )
945 {
946 bOptional = true;
947 }
948 Next();
949 }
950 if( bCompatible && Peek() == PARAMARRAY )
951 {
952 if( bByVal || bOptional )
953 {
954 Error( ERRCODE_BASIC_UNEXPECTED, PARAMARRAY );
955 }
956 Next();
957 bParamArray = true;
958 }
959 SbiSymDef* pPar = VarDecl( nullptr, false, false );
960 if( !pPar )
961 {
962 break;
963 }
964 if( bByVal )
965 {
966 pPar->SetByVal(true);
967 }
968 if( bOptional )
969 {
970 pPar->SetOptional();
971 }
972 if( bParamArray )
973 {
974 pPar->SetParamArray();
975 }
976 if (SbiSymDef* pOldDef = pDef->GetParams().Find(pPar->GetName(), false))
977 {
978 Error(ERRCODE_BASIC_VAR_DEFINED, pPar->GetName());
979 delete pPar;
980 pPar = pOldDef;
981 }
982 else
983 pDef->GetParams().Add( pPar );
984 SbiToken eTok = Next();
985 if( eTok != COMMA && eTok != RPAREN )
986 {
987 bool bError2 = true;
988 if( bOptional && bCompatible && eTok == EQ )
989 {
990 auto pDefaultExpr = std::make_unique<SbiConstExpression>(this);
991 SbxDataType eType2 = pDefaultExpr->GetType();
992
993 sal_uInt16 nStringId;
994 if( eType2 == SbxSTRING )
995 {
996 nStringId = aGblStrings.Add( pDefaultExpr->GetString() );
997 }
998 else
999 {
1000 nStringId = aGblStrings.Add( pDefaultExpr->GetValue(), eType2 );
1001 }
1002 pPar->SetDefaultId( nStringId );
1003 pDefaultExpr.reset();
1004
1005 eTok = Next();
1006 if( eTok == COMMA || eTok == RPAREN )
1007 {
1008 bError2 = false;
1009 }
1010 }
1011 if( bError2 )
1012 {
1013 Error( ERRCODE_BASIC_EXPECTED, RPAREN );
1014 break;
1015 }
1016 }
1017 if( eTok == RPAREN )
1018 {
1019 break;
1020 }
1021 }
1022 }
1023 }
1024 TypeDecl( *pDef );
1025 if( eType != SbxVARIANT && pDef->GetType() != eType )
1026 {
1027 Error( ERRCODE_BASIC_BAD_DECLARATION, aName );
1028 }
1029 if( pDef->GetType() == SbxVARIANT && !( bFunc || bProp ) )
1030 {
1031 pDef->SetType( SbxEMPTY );
1032 }
1033 return pDef;
1034 }
1035
1036 // DECLARE
1037
Declare()1038 void SbiParser::Declare()
1039 {
1040 DefDeclare( false );
1041 }
1042
DefDeclare(bool bPrivate)1043 void SbiParser::DefDeclare( bool bPrivate )
1044 {
1045 Next();
1046 if( eCurTok == PTRSAFE )
1047 Next();
1048
1049 if( eCurTok != SUB && eCurTok != FUNCTION )
1050 {
1051 Error( ERRCODE_BASIC_UNEXPECTED, eCurTok );
1052 }
1053 else
1054 {
1055 bool bFunction = (eCurTok == FUNCTION);
1056
1057 SbiProcDef* pDef = ProcDecl( true );
1058 if( pDef )
1059 {
1060 if( pDef->GetLib().isEmpty() )
1061 {
1062 Error( ERRCODE_BASIC_EXPECTED, LIB );
1063 }
1064 // Is it already there?
1065 SbiSymDef* pOld = aPublics.Find( pDef->GetName() );
1066 if( pOld )
1067 {
1068 SbiProcDef* p = pOld->GetProcDef();
1069 if( !p )
1070 {
1071 // Declared as a variable
1072 Error( ERRCODE_BASIC_BAD_DECLARATION, pDef->GetName() );
1073 delete pDef;
1074 pDef = nullptr;
1075 }
1076 else
1077 {
1078 pDef->Match( p );
1079 }
1080 }
1081 else
1082 {
1083 aPublics.Add( pDef );
1084 }
1085 if ( pDef )
1086 {
1087 pDef->SetPublic( !bPrivate );
1088
1089 // New declare handling
1090 if( !pDef->GetLib().isEmpty())
1091 {
1092 if( bNewGblDefs && nGblChain == 0 )
1093 {
1094 nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
1095 bNewGblDefs = false;
1096 }
1097
1098 sal_uInt16 nSavLine = nLine;
1099 aGen.Statement();
1100 pDef->Define();
1101 pDef->SetLine1( nSavLine );
1102 pDef->SetLine2( nSavLine );
1103
1104 SbiSymPool& rPool = pDef->GetParams();
1105 sal_uInt16 nParCount = rPool.GetSize();
1106
1107 SbxDataType eType = pDef->GetType();
1108 if( bFunction )
1109 {
1110 aGen.Gen( SbiOpcode::PARAM_, 0, sal::static_int_cast< sal_uInt16 >( eType ) );
1111 }
1112 if( nParCount > 1 )
1113 {
1114 aGen.Gen( SbiOpcode::ARGC_ );
1115
1116 for( sal_uInt16 i = 1 ; i < nParCount ; ++i )
1117 {
1118 SbiSymDef* pParDef = rPool.Get( i );
1119 SbxDataType eParType = pParDef->GetType();
1120
1121 aGen.Gen( SbiOpcode::PARAM_, i, sal::static_int_cast< sal_uInt16 >( eParType ) );
1122 aGen.Gen( SbiOpcode::ARGV_ );
1123
1124 sal_uInt16 nTyp = sal::static_int_cast< sal_uInt16 >( pParDef->GetType() );
1125 if( pParDef->IsByVal() )
1126 {
1127 // Reset to avoid additional byval in call to wrapper function
1128 pParDef->SetByVal( false );
1129 nTyp |= 0x8000;
1130 }
1131 aGen.Gen( SbiOpcode::ARGTYP_, nTyp );
1132 }
1133 }
1134
1135 aGen.Gen( SbiOpcode::LIB_, aGblStrings.Add( pDef->GetLib() ) );
1136
1137 SbiOpcode eOp = pDef->IsCdecl() ? SbiOpcode::CALLC_ : SbiOpcode::CALL_;
1138 sal_uInt16 nId = pDef->GetId();
1139 if( !pDef->GetAlias().isEmpty() )
1140 {
1141 nId = ( nId & 0x8000 ) | aGblStrings.Add( pDef->GetAlias() );
1142 }
1143 if( nParCount > 1 )
1144 {
1145 nId |= 0x8000;
1146 }
1147 aGen.Gen( eOp, nId, sal::static_int_cast< sal_uInt16 >( eType ) );
1148
1149 if( bFunction )
1150 {
1151 aGen.Gen( SbiOpcode::PUT_ );
1152 }
1153 aGen.Gen( SbiOpcode::LEAVE_ );
1154 }
1155 }
1156 }
1157 }
1158 }
1159
Attribute()1160 void SbiParser::Attribute()
1161 {
1162 // TODO: Need to implement the method as an attributed object.
1163 while( Next() != EQ )
1164 {
1165 if( Next() != DOT)
1166 {
1167 break;
1168 }
1169 }
1170
1171 if( eCurTok != EQ )
1172 {
1173 Error( ERRCODE_BASIC_SYNTAX );
1174 }
1175 else
1176 {
1177 SbiExpression aValue( this );
1178 }
1179 // Don't generate any code - just discard it.
1180 }
1181
1182 // Call of a SUB or a FUNCTION
1183
Call()1184 void SbiParser::Call()
1185 {
1186 SbiExpression aVar( this, SbSYMBOL );
1187 aVar.Gen( FORCE_CALL );
1188 aGen.Gen( SbiOpcode::GET_ );
1189 }
1190
1191 // SUB/FUNCTION
1192
SubFunc()1193 void SbiParser::SubFunc()
1194 {
1195 DefProc( false, false );
1196 }
1197
1198 // Read in of a procedure
1199
DefProc(bool bStatic,bool bPrivate)1200 void SbiParser::DefProc( bool bStatic, bool bPrivate )
1201 {
1202 sal_uInt16 l1 = nLine;
1203 bool bSub = ( eCurTok == SUB );
1204 bool bProperty = ( eCurTok == PROPERTY );
1205 PropertyMode ePropertyMode = PropertyMode::NONE;
1206 if( bProperty )
1207 {
1208 Next();
1209 if( eCurTok == GET )
1210 {
1211 ePropertyMode = PropertyMode::Get;
1212 }
1213 else if( eCurTok == LET )
1214 {
1215 ePropertyMode = PropertyMode::Let;
1216 }
1217 else if( eCurTok == SET )
1218 {
1219 ePropertyMode = PropertyMode::Set;
1220 }
1221 else
1222 {
1223 Error( ERRCODE_BASIC_EXPECTED, "Get or Let or Set" );
1224 }
1225 }
1226
1227 SbiToken eExit = eCurTok;
1228 SbiProcDef* pDef = ProcDecl( false );
1229 if( !pDef )
1230 {
1231 return;
1232 }
1233 pDef->setPropertyMode( ePropertyMode );
1234
1235 // Is the Proc already declared?
1236 SbiSymDef* pOld = aPublics.Find( pDef->GetName() );
1237 if( pOld )
1238 {
1239 pProc = pOld->GetProcDef();
1240 if( !pProc )
1241 {
1242 // Declared as a variable
1243 Error( ERRCODE_BASIC_BAD_DECLARATION, pDef->GetName() );
1244 delete pDef;
1245 return;
1246 }
1247 // #100027: Multiple declaration -> Error
1248 // #112787: Not for setup, REMOVE for 8
1249 else if( pProc->IsUsedForProcDecl() )
1250 {
1251 PropertyMode ePropMode = pDef->getPropertyMode();
1252 if( ePropMode == PropertyMode::NONE || ePropMode == pProc->getPropertyMode() )
1253 {
1254 Error( ERRCODE_BASIC_PROC_DEFINED, pDef->GetName() );
1255 delete pDef;
1256 return;
1257 }
1258 }
1259
1260 pDef->Match( pProc );
1261 }
1262 else
1263 {
1264 aPublics.Add( pDef );
1265 }
1266 assert(pDef);
1267 pProc = pDef;
1268 pProc->SetPublic( !bPrivate );
1269
1270 // Now we set the search hierarchy for symbols as well as the
1271 // current procedure.
1272 aPublics.SetProcId( pProc->GetId() );
1273 pProc->GetParams().SetParent( &aPublics );
1274 if( bStatic )
1275 {
1276 if ( bVBASupportOn )
1277 {
1278 pProc->SetStatic();
1279 }
1280 else
1281 {
1282 Error( ERRCODE_BASIC_NOT_IMPLEMENTED ); // STATIC SUB ...
1283 }
1284 }
1285 else
1286 {
1287 pProc->SetStatic( false );
1288 }
1289 // Normal case: Local variable->parameter->global variable
1290 pProc->GetLocals().SetParent( &pProc->GetParams() );
1291 pPool = &pProc->GetLocals();
1292
1293 pProc->Define();
1294 OpenBlock( eExit );
1295 StmntBlock( bSub ? ENDSUB : (bProperty ? ENDPROPERTY : ENDFUNC) );
1296 sal_uInt16 l2 = nLine;
1297 pProc->SetLine1( l1 );
1298 pProc->SetLine2( l2 );
1299 pPool = &aPublics;
1300 aPublics.SetProcId( 0 );
1301 // Open labels?
1302 pProc->GetLabels().CheckRefs();
1303 CloseBlock();
1304 aGen.Gen( SbiOpcode::LEAVE_ );
1305 pProc = nullptr;
1306 }
1307
1308 // STATIC variable|procedure
1309
Static()1310 void SbiParser::Static()
1311 {
1312 DefStatic( false );
1313 }
1314
DefStatic(bool bPrivate)1315 void SbiParser::DefStatic( bool bPrivate )
1316 {
1317 SbiSymPool* p;
1318
1319 switch( Peek() )
1320 {
1321 case SUB:
1322 case FUNCTION:
1323 case PROPERTY:
1324 // End global chain if necessary (not done in
1325 // SbiParser::Parse() under these conditions
1326 if( bNewGblDefs && nGblChain == 0 )
1327 {
1328 nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 );
1329 bNewGblDefs = false;
1330 }
1331 Next();
1332 DefProc( true, bPrivate );
1333 break;
1334 default:
1335 if( !pProc )
1336 {
1337 Error( ERRCODE_BASIC_NOT_IN_SUBR );
1338 }
1339 // Reset the Pool, so that STATIC-Declarations go into the
1340 // global Pool
1341 p = pPool;
1342 pPool = &aPublics;
1343 DefVar( SbiOpcode::STATIC_, true );
1344 pPool = p;
1345 break;
1346 }
1347 }
1348
IsUnoInterface(const OUString & sTypeName)1349 bool SbiParser::IsUnoInterface(const OUString& sTypeName)
1350 {
1351 try
1352 {
1353 return css::reflection::theCoreReflection::get(
1354 comphelper::getProcessComponentContext())->forName(sTypeName).is();
1355 }
1356 catch(const Exception&)
1357 {
1358 OSL_FAIL("Could not create reflection.CoreReflection.");
1359 }
1360 return false;
1361 }
1362
1363 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1364