diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /basic/source/comp/dim.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'basic/source/comp/dim.cxx')
-rw-r--r-- | basic/source/comp/dim.cxx | 1363 |
1 files changed, 1363 insertions, 0 deletions
diff --git a/basic/source/comp/dim.cxx b/basic/source/comp/dim.cxx new file mode 100644 index 000000000..cbc25b015 --- /dev/null +++ b/basic/source/comp/dim.cxx @@ -0,0 +1,1363 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <basic/sberrors.hxx> +#include <basic/sbstar.hxx> +#include <basic/sbx.hxx> +#include <sbunoobj.hxx> +#include <parser.hxx> +#include <sb.hxx> +#include <osl/diagnose.h> +#include <com/sun/star/reflection/theCoreReflection.hpp> +#include <comphelper/processfactory.hxx> +#include <com/sun/star/uno/Exception.hpp> +#include <basic/codecompletecache.hxx> +#include <memory> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +// Declaration of a variable +// If there are errors it will be parsed up to the comma or the newline. +// Return-value: a new instance, which were inserted and then deleted. +// Array-Index were returned as SbiExprList + +SbiSymDef* SbiParser::VarDecl( SbiExprListPtr* ppDim, bool bStatic, bool bConst ) +{ + bool bWithEvents = false; + if( Peek() == WITHEVENTS ) + { + Next(); + bWithEvents = true; + } + if( !TestSymbol() ) return nullptr; + SbxDataType t = eScanType; + SbiSymDef* pDef = bConst ? new SbiConstDef( aSym ) : new SbiSymDef( aSym ); + SbiExprListPtr pDim; + // Brackets? + if( Peek() == LPAREN ) + { + pDim = SbiExprList::ParseDimList( this ); + if( !pDim->GetDims() ) + pDef->SetWithBrackets(); + } + pDef->SetType( t ); + if( bStatic ) + pDef->SetStatic(); + if( bWithEvents ) + pDef->SetWithEvents(); + TypeDecl( *pDef ); + if( !ppDim && pDim ) + { + if(pDim->GetDims() ) + Error( ERRCODE_BASIC_EXPECTED, "()" ); + } + else if( ppDim ) + *ppDim = std::move(pDim); + return pDef; +} + +// Resolving of an AS-Type-Declaration +// The data type were inserted into the handed over variable + +void SbiParser::TypeDecl( SbiSymDef& rDef, bool bAsNewAlreadyParsed ) +{ + SbxDataType eType = rDef.GetType(); + if( !(bAsNewAlreadyParsed || Peek() == AS) ) + return; + + short nSize = 0; + if( !bAsNewAlreadyParsed ) + Next(); + rDef.SetDefinedAs(); + SbiToken eTok = Next(); + if( !bAsNewAlreadyParsed && eTok == NEW ) + { + rDef.SetNew(); + eTok = Next(); + } + switch( eTok ) + { + case ANY: + if( rDef.IsNew() ) + Error( ERRCODE_BASIC_SYNTAX ); + eType = SbxVARIANT; break; + case TINTEGER: + case TLONG: + case TSINGLE: + case TDOUBLE: + case TCURRENCY: + case TDATE: + case TSTRING: + case TOBJECT: + case ERROR_: + case TBOOLEAN: + case TVARIANT: + case TBYTE: + if( rDef.IsNew() ) + Error( ERRCODE_BASIC_SYNTAX ); + eType = (eTok==TBYTE) ? SbxBYTE : SbxDataType( eTok - TINTEGER + SbxINTEGER ); + if( eType == SbxSTRING ) + { + // STRING*n ? + if( Peek() == MUL ) + { // fixed size! + Next(); + SbiConstExpression aSize( this ); + nSize = aSize.GetShortValue(); + if( nSize < 0 || (bVBASupportOn && nSize <= 0) ) + Error( ERRCODE_BASIC_OUT_OF_RANGE ); + else + rDef.SetFixedStringLength( nSize ); + } + } + break; + case SYMBOL: // can only be a TYPE or an object class! + if( eScanType != SbxVARIANT ) + Error( ERRCODE_BASIC_SYNTAX ); + else + { + OUString aCompleteName = aSym; + + // #52709 DIM AS NEW for Uno with full-qualified name + if( Peek() == DOT ) + { + OUString aDotStr( '.' ); + while( Peek() == DOT ) + { + aCompleteName += aDotStr; + Next(); + SbiToken ePeekTok = Peek(); + if( ePeekTok == SYMBOL || IsKwd( ePeekTok ) ) + { + Next(); + aCompleteName += aSym; + } + else + { + Next(); + Error( ERRCODE_BASIC_UNEXPECTED, SYMBOL ); + break; + } + } + } + else if( rEnumArray->Find( aCompleteName, SbxClassType::Object ) || ( IsVBASupportOn() && VBAConstantHelper::instance().isVBAConstantType( aCompleteName ) ) ) + { + eType = SbxLONG; + break; + } + + // Take over in the string pool + rDef.SetTypeId( aGblStrings.Add( aCompleteName ) ); + + if( rDef.IsNew() && pProc == nullptr ) + aRequiredTypes.push_back( aCompleteName ); + } + eType = SbxOBJECT; + break; + case FIXSTRING: // new syntax for complex UNO types + rDef.SetTypeId( aGblStrings.Add( aSym ) ); + eType = SbxOBJECT; + break; + default: + Error( ERRCODE_BASIC_UNEXPECTED, eTok ); + Next(); + } + // The variable could have been declared with a suffix + if( rDef.GetType() != SbxVARIANT ) + { + if( rDef.GetType() != eType ) + Error( ERRCODE_BASIC_VAR_DEFINED, rDef.GetName() ); + else if( eType == SbxSTRING && rDef.GetLen() != nSize ) + Error( ERRCODE_BASIC_VAR_DEFINED, rDef.GetName() ); + } + rDef.SetType( eType ); + rDef.SetLen( nSize ); +} + +// Here variables, arrays and structures were defined. +// DIM/PRIVATE/PUBLIC/GLOBAL + +void SbiParser::Dim() +{ + DefVar( SbiOpcode::DIM_, pProc && bVBASupportOn && pProc->IsStatic() ); +} + +void SbiParser::DefVar( SbiOpcode eOp, bool bStatic ) +{ + SbiSymPool* pOldPool = pPool; + bool bSwitchPool = false; + bool bPersistentGlobal = false; + SbiToken eFirstTok = eCurTok; + + if( pProc && ( eCurTok == GLOBAL || eCurTok == PUBLIC || eCurTok == PRIVATE ) ) + Error( ERRCODE_BASIC_NOT_IN_SUBR, eCurTok ); + if( eCurTok == PUBLIC || eCurTok == GLOBAL ) + { + bSwitchPool = true; // at the right moment switch to the global pool + if( eCurTok == GLOBAL ) + bPersistentGlobal = true; + } + // behavior in VBA is that a module scope variable's lifetime is + // tied to the document. e.g. a module scope variable is global + if( GetBasic()->IsDocBasic() && bVBASupportOn && !pProc ) + bPersistentGlobal = true; + // PRIVATE is a synonymous for DIM + // _CONST_? + bool bConst = false; + if( eCurTok == CONST_ ) + bConst = true; + else if( Peek() == CONST_ ) + { + Next(); + bConst = true; + } + + // #110004 It can also be a sub/function + if( !bConst && (eCurTok == SUB || eCurTok == FUNCTION || eCurTok == PROPERTY || + eCurTok == STATIC || eCurTok == ENUM || eCurTok == DECLARE || eCurTok == TYPE) ) + { + // Next token is read here, because !bConst + bool bPrivate = ( eFirstTok == PRIVATE ); + + if( eCurTok == STATIC ) + { + Next(); + DefStatic( bPrivate ); + } + else if( eCurTok == SUB || eCurTok == FUNCTION || eCurTok == PROPERTY ) + { + // End global chain if necessary (not done in + // SbiParser::Parse() under these conditions + if( bNewGblDefs && nGblChain == 0 ) + { + nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 ); + bNewGblDefs = false; + } + Next(); + DefProc( false, bPrivate ); + return; + } + else if( eCurTok == ENUM ) + { + Next(); + DefEnum( bPrivate ); + return; + } + else if( eCurTok == DECLARE ) + { + Next(); + DefDeclare( bPrivate ); + return; + } + // #i109049 + else if( eCurTok == TYPE ) + { + Next(); + DefType(); // TODO: Use bPrivate in DefType() + return; + } + } + + // SHARED were ignored + if( Peek() == SHARED ) Next(); + + // PRESERVE only at REDIM + if( Peek() == PRESERVE ) + { + Next(); + if( eOp == SbiOpcode::REDIM_ ) + eOp = SbiOpcode::REDIMP_; + else + Error( ERRCODE_BASIC_UNEXPECTED, eCurTok ); + } + SbiSymDef* pDef; + SbiExprListPtr pDim; + + // #40689, Statics -> Module-Initialising, skip in Sub + sal_uInt32 nEndOfStaticLbl = 0; + if( !bVBASupportOn && bStatic ) + { + nEndOfStaticLbl = aGen.Gen( SbiOpcode::JUMP_, 0 ); + aGen.Statement(); // catch up on static here + } + + bool bDefined = false; + while( ( pDef = VarDecl( &pDim, bStatic, bConst ) ) != nullptr ) + { + /*fprintf(stderr, "Actual sub: \n"); + fprintf(stderr, "Symbol name: %s\n",OUStringToOString(pDef->GetName(),RTL_TEXTENCODING_UTF8).getStr());*/ + EnableErrors(); + // search variable: + if( bSwitchPool ) + pPool = &aGlobals; + SbiSymDef* pOld = pPool->Find( pDef->GetName() ); + // search also in the Runtime-Library + bool bRtlSym = false; + if( !pOld ) + { + pOld = CheckRTLForSym( pDef->GetName(), SbxVARIANT ); + if( pOld ) + bRtlSym = true; + } + if( pOld && eOp != SbiOpcode::REDIM_ && eOp != SbiOpcode::REDIMP_ ) + { + if( pDef->GetScope() == SbLOCAL ) + if (auto eOldScope = pOld->GetScope(); eOldScope != SbLOCAL && eOldScope != SbPARAM) + pOld = nullptr; + } + if( pOld ) + { + bDefined = true; + // always an error at a RTL-S + if( !bRtlSym && (eOp == SbiOpcode::REDIM_ || eOp == SbiOpcode::REDIMP_) ) + { + // compare the attributes at a REDIM + SbxDataType eDefType; + bool bError_ = false; + if( pOld->IsStatic() ) + { + bError_ = true; + } + else if( pOld->GetType() != ( eDefType = pDef->GetType() ) ) + { + if( eDefType != SbxVARIANT || pDef->IsDefinedAs() ) + bError_ = true; + } + if( bError_ ) + Error( ERRCODE_BASIC_VAR_DEFINED, pDef->GetName() ); + } + else + Error( ERRCODE_BASIC_VAR_DEFINED, pDef->GetName() ); + delete pDef; pDef = pOld; + } + else + pPool->Add( pDef ); + + // #36374: Create the variable in front of the distinction IsNew() + // Otherwise error at Dim Identifier As New Type and option explicit + if( !bDefined && eOp != SbiOpcode::REDIM_ && eOp != SbiOpcode::REDIMP_ + && ( !bConst || pDef->GetScope() == SbGLOBAL ) ) + { + // Declare variable or global constant + SbiOpcode eOp2; + switch ( pDef->GetScope() ) + { + case SbGLOBAL: eOp2 = bPersistentGlobal ? SbiOpcode::GLOBAL_P_ : SbiOpcode::GLOBAL_; + goto global; + case SbPUBLIC: eOp2 = bPersistentGlobal ? SbiOpcode::PUBLIC_P_ : SbiOpcode::PUBLIC_; + // #40689, no own Opcode anymore + if( bVBASupportOn && bStatic ) + { + eOp2 = SbiOpcode::STATIC_; + break; + } + global: aGen.BackChain( nGblChain ); + nGblChain = 0; + bGblDefs = bNewGblDefs = true; + break; + default: eOp2 = SbiOpcode::LOCAL_; + } + sal_uInt32 nOpnd2 = sal::static_int_cast< sal_uInt16 >( pDef->GetType() ); + if( pDef->IsWithEvents() ) + nOpnd2 |= SBX_TYPE_WITH_EVENTS_FLAG; + + if( bCompatible && pDef->IsNew() ) + nOpnd2 |= SBX_TYPE_DIM_AS_NEW_FLAG; + + short nFixedStringLength = pDef->GetFixedStringLength(); + if( nFixedStringLength >= 0 ) + nOpnd2 |= (SBX_FIXED_LEN_STRING_FLAG + (sal_uInt32(nFixedStringLength) << 17)); // len = all bits above 0x10000 + + if( pDim != nullptr && pDim->GetDims() > 0 ) + nOpnd2 |= SBX_TYPE_VAR_TO_DIM_FLAG; + + aGen.Gen( eOp2, pDef->GetId(), nOpnd2 ); + } + + // Initialising for self-defined data types + // and per NEW created variable + if( pDef->GetType() == SbxOBJECT + && pDef->GetTypeId() ) + { + if( !bCompatible && !pDef->IsNew() ) + { + OUString aTypeName( aGblStrings.Find( pDef->GetTypeId() ) ); + if( rTypeArray->Find( aTypeName, SbxClassType::Object ) == nullptr ) + { + if( CodeCompleteOptions::IsExtendedTypeDeclaration() ) + { + if(!IsUnoInterface(aTypeName)) + Error( ERRCODE_BASIC_UNDEF_TYPE, aTypeName ); + } + else + Error( ERRCODE_BASIC_UNDEF_TYPE, aTypeName ); + } + } + + if( bConst ) + { + Error( ERRCODE_BASIC_SYNTAX ); + } + + if( pDim ) + { + if( eOp == SbiOpcode::REDIMP_ ) + { + SbiExpression aExpr( this, *pDef, nullptr ); + aExpr.Gen(); + aGen.Gen( SbiOpcode::REDIMP_ERASE_ ); + + pDef->SetDims( pDim->GetDims() ); + SbiExpression aExpr2( this, *pDef, std::move(pDim) ); + aExpr2.Gen(); + aGen.Gen( SbiOpcode::DCREATE_REDIMP_, pDef->GetId(), pDef->GetTypeId() ); + } + else + { + // tdf#145371, tdf#136755 - only delete the variable beforehand REDIM + if (eOp == SbiOpcode::REDIM_) + { + SbiExpression aExpr(this, *pDef, nullptr); + aExpr.Gen(); + aGen.Gen(bVBASupportOn ? SbiOpcode::ERASE_CLEAR_ : SbiOpcode::ERASE_); + } + + pDef->SetDims( pDim->GetDims() ); + SbiExpression aExpr2( this, *pDef, std::move(pDim) ); + aExpr2.Gen(); + aGen.Gen( SbiOpcode::DCREATE_, pDef->GetId(), pDef->GetTypeId() ); + } + } + else + { + SbiExpression aExpr( this, *pDef ); + aExpr.Gen(); + + /* tdf#88442 + * Don't initialize a + * Global X as New SomeObjectType + * if it has already been initialized. + * This approach relies on JUMPT evaluating Object->NULL as being 'false' + * But the effect of this code is similar to inserting + * If IsNull(YourGlobal) + * Set YourGlobal = ' new obj + * End If ' If IsNull(YourGlobal) + * Only for globals. For locals that check is skipped as it's unnecessary + */ + sal_uInt32 come_from = 0; + if ( pDef->GetScope() == SbGLOBAL ) + { + come_from = aGen.Gen( SbiOpcode::JUMPT_, 0 ); + aGen.Gen( SbiOpcode::FIND_, pDef->GetId(), pDef->GetTypeId() ); + } + + SbiOpcode eOp_ = pDef->IsNew() ? SbiOpcode::CREATE_ : SbiOpcode::TCREATE_; + aGen.Gen( eOp_, pDef->GetId(), pDef->GetTypeId() ); + if ( bVBASupportOn ) + aGen.Gen( SbiOpcode::VBASET_ ); + else + aGen.Gen( SbiOpcode::SET_ ); + + if ( come_from ) + { + // See other tdf#88442 comment above where come_from is + // initialized. This is effectively 'inserting' the + // End If ' If IsNull(YourGlobal) + aGen.BackChain( come_from ); + } + } + } + else + { + if( bConst ) + { + // Definition of the constants + if( pDim ) + { + Error( ERRCODE_BASIC_SYNTAX ); + } + SbiExpression aVar( this, *pDef ); + if( !TestToken( EQ ) ) + goto MyBreak; // (see below) + SbiConstExpression aExpr( this ); + if( !bDefined && aExpr.IsValid() ) + { + if( pDef->GetScope() == SbGLOBAL ) + { + // Create code only for the global constant! + aVar.Gen(); + aExpr.Gen(); + aGen.Gen( SbiOpcode::PUTC_ ); + } + SbiConstDef* pConst = pDef->GetConstDef(); + if( aExpr.GetType() == SbxSTRING ) + pConst->Set( aExpr.GetString() ); + else + pConst->Set( aExpr.GetValue(), aExpr.GetType() ); + } + } + else if( pDim ) + { + // Dimension the variable + // Delete the var at REDIM beforehand + if( eOp == SbiOpcode::REDIM_ ) + { + SbiExpression aExpr( this, *pDef, nullptr ); + aExpr.Gen(); + if ( bVBASupportOn ) + // delete the array but + // clear the variable ( this + // allows the processing of + // the param to happen as normal without errors ( ordinary ERASE just clears the array ) + aGen.Gen( SbiOpcode::ERASE_CLEAR_ ); + else + aGen.Gen( SbiOpcode::ERASE_ ); + } + else if( eOp == SbiOpcode::REDIMP_ ) + { + SbiExpression aExpr( this, *pDef, nullptr ); + aExpr.Gen(); + aGen.Gen( SbiOpcode::REDIMP_ERASE_ ); + } + pDef->SetDims( pDim->GetDims() ); + if( bPersistentGlobal ) + pDef->SetGlobal( true ); + SbiExpression aExpr( this, *pDef, std::move(pDim) ); + aExpr.Gen(); + pDef->SetGlobal( false ); + aGen.Gen( (eOp == SbiOpcode::STATIC_) ? SbiOpcode::DIM_ : eOp ); + } + } + if( !TestComma() ) + goto MyBreak; + + // Implementation of bSwitchPool (see above): pPool must not be set to &aGlobals + // at the VarDecl-Call. + // Apart from that the behavior should be absolutely identical, + // i.e., pPool had to be reset always at the end of the loop. + // also at a break + pPool = pOldPool; + continue; // Skip MyBreak + MyBreak: + pPool = pOldPool; + break; + } + + // #40689, finalize the jump over statics declarations + if( !bVBASupportOn && bStatic ) + { + // maintain the global chain + nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 ); + bGblDefs = bNewGblDefs = true; + + // Register for Sub a jump to the end of statics + aGen.BackChain( nEndOfStaticLbl ); + } + +} + +// Here were Arrays redimensioned. + +void SbiParser::ReDim() +{ + DefVar( SbiOpcode::REDIM_, pProc && bVBASupportOn && pProc->IsStatic() ); +} + +// ERASE array, ... + +void SbiParser::Erase() +{ + while( !bAbort ) + { + SbiExpression aExpr( this, SbLVALUE ); + aExpr.Gen(); + aGen.Gen( SbiOpcode::ERASE_ ); + if( !TestComma() ) break; + } +} + +// Declaration of a data type + +void SbiParser::Type() +{ + DefType(); +} + +void SbiParser::DefType() +{ + // Read the new Token lesen. It had to be a symbol + if (!TestSymbol()) + return; + + if (rTypeArray->Find(aSym,SbxClassType::Object)) + { + Error( ERRCODE_BASIC_VAR_DEFINED, aSym ); + return; + } + + SbxObject *pType = new SbxObject(aSym); + + bool bDone = false; + + while( !bDone && !IsEof() ) + { + std::unique_ptr<SbiSymDef> pElem; + SbiExprListPtr pDim; + switch( Peek() ) + { + case ENDTYPE : + bDone = true; + Next(); + break; + + case EOLN : + case REM : + Next(); + break; + + default: + pElem.reset(VarDecl(&pDim, false, false)); + if( !pElem ) + bDone = true; // Error occurred + } + if( pElem ) + { + SbxArray *pTypeMembers = pType->GetProperties(); + OUString aElemName = pElem->GetName(); + if( pTypeMembers->Find( aElemName, SbxClassType::DontCare) ) + { + Error (ERRCODE_BASIC_VAR_DEFINED); + } + else + { + SbxDataType eElemType = pElem->GetType(); + SbxProperty *pTypeElem = new SbxProperty( aElemName, eElemType ); + if( pDim ) + { + SbxDimArray* pArray = new SbxDimArray( pElem->GetType() ); + if ( pDim->GetSize() ) + { + // Dimension the target array + + for ( short i=0; i<pDim->GetSize();++i ) + { + sal_Int32 lb = nBase; + SbiExprNode* pNode = pDim->Get(i)->GetExprNode(); + sal_Int32 ub = pNode->GetNumber(); + if ( !pDim->Get( i )->IsBased() ) // each dim is low/up + { + if ( ++i >= pDim->GetSize() ) // trouble + StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); + pNode = pDim->Get(i)->GetExprNode(); + lb = ub; + ub = pNode->GetNumber(); + } + else if ( !bCompatible ) + ub += nBase; + pArray->AddDim(lb, ub); + } + pArray->setHasFixedSize( true ); + } + else + pArray->unoAddDim(0, -1); // variant array + SbxFlagBits nSavFlags = pTypeElem->GetFlags(); + // need to reset the FIXED flag + // when calling PutObject ( because the type will not match Object ) + pTypeElem->ResetFlag( SbxFlagBits::Fixed ); + pTypeElem->PutObject( pArray ); + pTypeElem->SetFlags( nSavFlags ); + } + // Nested user type? + if( eElemType == SbxOBJECT ) + { + sal_uInt16 nElemTypeId = pElem->GetTypeId(); + if( nElemTypeId != 0 ) + { + OUString aTypeName( aGblStrings.Find( nElemTypeId ) ); + SbxObject* pTypeObj = static_cast< SbxObject* >( rTypeArray->Find( aTypeName, SbxClassType::Object ) ); + if( pTypeObj != nullptr ) + { + SbxObjectRef pCloneObj = cloneTypeObjectImpl( *pTypeObj ); + pTypeElem->PutObject( pCloneObj.get() ); + } + } + } + pTypeMembers->Insert(pTypeElem, pTypeMembers->Count()); + } + } + } + + pType->Remove( "Name", SbxClassType::DontCare ); + pType->Remove( "Parent", SbxClassType::DontCare ); + + rTypeArray->Insert(pType, rTypeArray->Count()); +} + + +// Declaration of Enum type + +void SbiParser::Enum() +{ + DefEnum( false ); +} + +void SbiParser::DefEnum( bool bPrivate ) +{ + // Read the new Token. It had to be a symbol + if (!TestSymbol()) + return; + + OUString aEnumName = aSym; + if( rEnumArray->Find(aEnumName,SbxClassType::Object) ) + { + Error( ERRCODE_BASIC_VAR_DEFINED, aSym ); + return; + } + + SbxObject *pEnum = new SbxObject( aEnumName ); + if( bPrivate ) + { + pEnum->SetFlag( SbxFlagBits::Private ); + } + SbiSymDef* pElem; + bool bDone = false; + + // Starting with -1 to make first default value 0 after ++ + sal_Int32 nCurrentEnumValue = -1; + while( !bDone && !IsEof() ) + { + switch( Peek() ) + { + case ENDENUM : + pElem = nullptr; + bDone = true; + Next(); + break; + + case EOLN : + case REM : + pElem = nullptr; + Next(); + break; + + default: + { + SbiExprListPtr pDim; + pElem = VarDecl( &pDim, false, true ); + if( !pElem ) + { + bDone = true; // Error occurred + break; + } + else if( pDim ) + { + Error( ERRCODE_BASIC_SYNTAX ); + bDone = true; // Error occurred + break; + } + + SbiExpression aVar( this, *pElem ); + if( Peek() == EQ ) + { + Next(); + + SbiConstExpression aExpr( this ); + if( aExpr.IsValid() ) + { + SbxVariableRef xConvertVar = new SbxVariable(); + if( aExpr.GetType() == SbxSTRING ) + xConvertVar->PutString( aExpr.GetString() ); + else + xConvertVar->PutDouble( aExpr.GetValue() ); + + nCurrentEnumValue = xConvertVar->GetLong(); + } + } + else + nCurrentEnumValue++; + + SbiSymPool* pPoolToUse = bPrivate ? pPool : &aGlobals; + + SbiSymDef* pOld = pPoolToUse->Find( pElem->GetName() ); + if( pOld ) + { + Error( ERRCODE_BASIC_VAR_DEFINED, pElem->GetName() ); + bDone = true; // Error occurred + break; + } + + pPool->Add( pElem ); + + if( !bPrivate ) + { + aGen.BackChain( nGblChain ); + nGblChain = 0; + bGblDefs = bNewGblDefs = true; + aGen.Gen( + SbiOpcode::GLOBAL_, pElem->GetId(), + sal::static_int_cast< sal_uInt16 >( pElem->GetType() ) ); + + aVar.Gen(); + sal_uInt16 nStringId = aGen.GetParser()->aGblStrings.Add( nCurrentEnumValue, SbxLONG ); + aGen.Gen( SbiOpcode::NUMBER_, nStringId ); + aGen.Gen( SbiOpcode::PUTC_ ); + } + + SbiConstDef* pConst = pElem->GetConstDef(); + pConst->Set( nCurrentEnumValue, SbxLONG ); + } + } + if( pElem ) + { + SbxArray *pEnumMembers = pEnum->GetProperties(); + SbxProperty *pEnumElem = new SbxProperty( pElem->GetName(), SbxLONG ); + pEnumElem->PutLong( nCurrentEnumValue ); + pEnumElem->ResetFlag( SbxFlagBits::Write ); + pEnumElem->SetFlag( SbxFlagBits::Const ); + pEnumMembers->Insert(pEnumElem, pEnumMembers->Count()); + } + } + + pEnum->Remove( "Name", SbxClassType::DontCare ); + pEnum->Remove( "Parent", SbxClassType::DontCare ); + + rEnumArray->Insert(pEnum, rEnumArray->Count()); +} + + +// Procedure-Declaration +// the first Token is already read in (SUB/FUNCTION) +// xxx Name [LIB "name"[ALIAS "name"]][(Parameter)][AS TYPE] + +SbiProcDef* SbiParser::ProcDecl( bool bDecl ) +{ + bool bFunc = ( eCurTok == FUNCTION ); + bool bProp = ( eCurTok == GET || eCurTok == SET || eCurTok == LET ); + if( !TestSymbol() ) return nullptr; + OUString aName( aSym ); + SbxDataType eType = eScanType; + SbiProcDef* pDef = new SbiProcDef( this, aName, true ); + pDef->SetType( eType ); + if( Peek() == CDECL_ ) + { + Next(); pDef->SetCdecl(true); + } + if( Peek() == LIB ) + { + Next(); + if( Next() == FIXSTRING ) + { + pDef->GetLib() = aSym; + } + else + { + Error( ERRCODE_BASIC_SYNTAX ); + } + } + if( Peek() == ALIAS ) + { + Next(); + if( Next() == FIXSTRING ) + { + pDef->GetAlias() = aSym; + } + else + { + Error( ERRCODE_BASIC_SYNTAX ); + } + } + if( !bDecl ) + { + // CDECL, LIB and ALIAS are invalid + if( !pDef->GetLib().isEmpty() ) + { + Error( ERRCODE_BASIC_UNEXPECTED, LIB ); + } + if( !pDef->GetAlias().isEmpty() ) + { + Error( ERRCODE_BASIC_UNEXPECTED, ALIAS ); + } + if( pDef->IsCdecl() ) + { + Error( ERRCODE_BASIC_UNEXPECTED, CDECL_ ); + } + pDef->SetCdecl( false ); + pDef->GetLib().clear(); + pDef->GetAlias().clear(); + } + else if( pDef->GetLib().isEmpty() ) + { + // ALIAS and CDECL only together with LIB + if( !pDef->GetAlias().isEmpty() ) + { + Error( ERRCODE_BASIC_UNEXPECTED, ALIAS ); + } + if( pDef->IsCdecl() ) + { + Error( ERRCODE_BASIC_UNEXPECTED, CDECL_ ); + } + pDef->SetCdecl( false ); + pDef->GetAlias().clear(); + } + // Brackets? + if( Peek() == LPAREN ) + { + Next(); + if( Peek() == RPAREN ) + { + Next(); + } + else + { + for(;;) + { + bool bByVal = false; + bool bOptional = false; + bool bParamArray = false; + while( Peek() == BYVAL || Peek() == BYREF || Peek() == OPTIONAL_ ) + { + if( Peek() == BYVAL ) + { + bByVal = true; + } + else if ( Peek() == BYREF ) + { + bByVal = false; + } + else if ( Peek() == OPTIONAL_ ) + { + bOptional = true; + } + Next(); + } + if( bCompatible && Peek() == PARAMARRAY ) + { + if( bByVal || bOptional ) + { + Error( ERRCODE_BASIC_UNEXPECTED, PARAMARRAY ); + } + Next(); + bParamArray = true; + } + SbiSymDef* pPar = VarDecl( nullptr, false, false ); + if( !pPar ) + { + break; + } + if( bByVal ) + { + pPar->SetByVal(true); + } + if( bOptional ) + { + pPar->SetOptional(); + } + if( bParamArray ) + { + pPar->SetParamArray(); + } + if (SbiSymDef* pOldDef = pDef->GetParams().Find(pPar->GetName(), false)) + { + Error(ERRCODE_BASIC_VAR_DEFINED, pPar->GetName()); + delete pPar; + pPar = pOldDef; + } + else + pDef->GetParams().Add( pPar ); + SbiToken eTok = Next(); + if( eTok != COMMA && eTok != RPAREN ) + { + bool bError2 = true; + if( bOptional && bCompatible && eTok == EQ ) + { + auto pDefaultExpr = std::make_unique<SbiConstExpression>(this); + SbxDataType eType2 = pDefaultExpr->GetType(); + + sal_uInt16 nStringId; + if( eType2 == SbxSTRING ) + { + nStringId = aGblStrings.Add( pDefaultExpr->GetString() ); + } + else + { + nStringId = aGblStrings.Add( pDefaultExpr->GetValue(), eType2 ); + } + pPar->SetDefaultId( nStringId ); + pDefaultExpr.reset(); + + eTok = Next(); + if( eTok == COMMA || eTok == RPAREN ) + { + bError2 = false; + } + } + if( bError2 ) + { + Error( ERRCODE_BASIC_EXPECTED, RPAREN ); + break; + } + } + if( eTok == RPAREN ) + { + break; + } + } + } + } + TypeDecl( *pDef ); + if( eType != SbxVARIANT && pDef->GetType() != eType ) + { + Error( ERRCODE_BASIC_BAD_DECLARATION, aName ); + } + if( pDef->GetType() == SbxVARIANT && !( bFunc || bProp ) ) + { + pDef->SetType( SbxEMPTY ); + } + return pDef; +} + +// DECLARE + +void SbiParser::Declare() +{ + DefDeclare( false ); +} + +void SbiParser::DefDeclare( bool bPrivate ) +{ + Next(); + if( eCurTok == PTRSAFE ) + Next(); + + if( eCurTok != SUB && eCurTok != FUNCTION ) + { + Error( ERRCODE_BASIC_UNEXPECTED, eCurTok ); + } + else + { + bool bFunction = (eCurTok == FUNCTION); + + SbiProcDef* pDef = ProcDecl( true ); + if( pDef ) + { + if( pDef->GetLib().isEmpty() ) + { + Error( ERRCODE_BASIC_EXPECTED, LIB ); + } + // Is it already there? + SbiSymDef* pOld = aPublics.Find( pDef->GetName() ); + if( pOld ) + { + SbiProcDef* p = pOld->GetProcDef(); + if( !p ) + { + // Declared as a variable + Error( ERRCODE_BASIC_BAD_DECLARATION, pDef->GetName() ); + delete pDef; + pDef = nullptr; + } + else + { + pDef->Match( p ); + } + } + else + { + aPublics.Add( pDef ); + } + if ( pDef ) + { + pDef->SetPublic( !bPrivate ); + + // New declare handling + if( !pDef->GetLib().isEmpty()) + { + if( bNewGblDefs && nGblChain == 0 ) + { + nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 ); + bNewGblDefs = false; + } + + sal_uInt16 nSavLine = nLine; + aGen.Statement(); + pDef->Define(); + pDef->SetLine1( nSavLine ); + pDef->SetLine2( nSavLine ); + + SbiSymPool& rPool = pDef->GetParams(); + sal_uInt16 nParCount = rPool.GetSize(); + + SbxDataType eType = pDef->GetType(); + if( bFunction ) + { + aGen.Gen( SbiOpcode::PARAM_, 0, sal::static_int_cast< sal_uInt16 >( eType ) ); + } + if( nParCount > 1 ) + { + aGen.Gen( SbiOpcode::ARGC_ ); + + for( sal_uInt16 i = 1 ; i < nParCount ; ++i ) + { + SbiSymDef* pParDef = rPool.Get( i ); + SbxDataType eParType = pParDef->GetType(); + + aGen.Gen( SbiOpcode::PARAM_, i, sal::static_int_cast< sal_uInt16 >( eParType ) ); + aGen.Gen( SbiOpcode::ARGV_ ); + + sal_uInt16 nTyp = sal::static_int_cast< sal_uInt16 >( pParDef->GetType() ); + if( pParDef->IsByVal() ) + { + // Reset to avoid additional byval in call to wrapper function + pParDef->SetByVal( false ); + nTyp |= 0x8000; + } + aGen.Gen( SbiOpcode::ARGTYP_, nTyp ); + } + } + + aGen.Gen( SbiOpcode::LIB_, aGblStrings.Add( pDef->GetLib() ) ); + + SbiOpcode eOp = pDef->IsCdecl() ? SbiOpcode::CALLC_ : SbiOpcode::CALL_; + sal_uInt16 nId = pDef->GetId(); + if( !pDef->GetAlias().isEmpty() ) + { + nId = ( nId & 0x8000 ) | aGblStrings.Add( pDef->GetAlias() ); + } + if( nParCount > 1 ) + { + nId |= 0x8000; + } + aGen.Gen( eOp, nId, sal::static_int_cast< sal_uInt16 >( eType ) ); + + if( bFunction ) + { + aGen.Gen( SbiOpcode::PUT_ ); + } + aGen.Gen( SbiOpcode::LEAVE_ ); + } + } + } + } +} + +void SbiParser::Attribute() +{ + // TODO: Need to implement the method as an attributed object. + while( Next() != EQ ) + { + if( Next() != DOT) + { + break; + } + } + + if( eCurTok != EQ ) + { + Error( ERRCODE_BASIC_SYNTAX ); + } + else + { + SbiExpression aValue( this ); + } + // Don't generate any code - just discard it. +} + +// Call of a SUB or a FUNCTION + +void SbiParser::Call() +{ + SbiExpression aVar( this, SbSYMBOL ); + aVar.Gen( FORCE_CALL ); + aGen.Gen( SbiOpcode::GET_ ); +} + +// SUB/FUNCTION + +void SbiParser::SubFunc() +{ + DefProc( false, false ); +} + +// Read in of a procedure + +void SbiParser::DefProc( bool bStatic, bool bPrivate ) +{ + sal_uInt16 l1 = nLine; + bool bSub = ( eCurTok == SUB ); + bool bProperty = ( eCurTok == PROPERTY ); + PropertyMode ePropertyMode = PropertyMode::NONE; + if( bProperty ) + { + Next(); + if( eCurTok == GET ) + { + ePropertyMode = PropertyMode::Get; + } + else if( eCurTok == LET ) + { + ePropertyMode = PropertyMode::Let; + } + else if( eCurTok == SET ) + { + ePropertyMode = PropertyMode::Set; + } + else + { + Error( ERRCODE_BASIC_EXPECTED, "Get or Let or Set" ); + } + } + + SbiToken eExit = eCurTok; + SbiProcDef* pDef = ProcDecl( false ); + if( !pDef ) + { + return; + } + pDef->setPropertyMode( ePropertyMode ); + + // Is the Proc already declared? + SbiSymDef* pOld = aPublics.Find( pDef->GetName() ); + if( pOld ) + { + pProc = pOld->GetProcDef(); + if( !pProc ) + { + // Declared as a variable + Error( ERRCODE_BASIC_BAD_DECLARATION, pDef->GetName() ); + delete pDef; + return; + } + // #100027: Multiple declaration -> Error + // #112787: Not for setup, REMOVE for 8 + else if( pProc->IsUsedForProcDecl() ) + { + PropertyMode ePropMode = pDef->getPropertyMode(); + if( ePropMode == PropertyMode::NONE || ePropMode == pProc->getPropertyMode() ) + { + Error( ERRCODE_BASIC_PROC_DEFINED, pDef->GetName() ); + delete pDef; + return; + } + } + + pDef->Match( pProc ); + } + else + { + aPublics.Add( pDef ); + } + assert(pDef); + pProc = pDef; + pProc->SetPublic( !bPrivate ); + + // Now we set the search hierarchy for symbols as well as the + // current procedure. + aPublics.SetProcId( pProc->GetId() ); + pProc->GetParams().SetParent( &aPublics ); + if( bStatic ) + { + if ( bVBASupportOn ) + { + pProc->SetStatic(); + } + else + { + Error( ERRCODE_BASIC_NOT_IMPLEMENTED ); // STATIC SUB ... + } + } + else + { + pProc->SetStatic( false ); + } + // Normal case: Local variable->parameter->global variable + pProc->GetLocals().SetParent( &pProc->GetParams() ); + pPool = &pProc->GetLocals(); + + pProc->Define(); + OpenBlock( eExit ); + StmntBlock( bSub ? ENDSUB : (bProperty ? ENDPROPERTY : ENDFUNC) ); + sal_uInt16 l2 = nLine; + pProc->SetLine1( l1 ); + pProc->SetLine2( l2 ); + pPool = &aPublics; + aPublics.SetProcId( 0 ); + // Open labels? + pProc->GetLabels().CheckRefs(); + CloseBlock(); + aGen.Gen( SbiOpcode::LEAVE_ ); + pProc = nullptr; +} + +// STATIC variable|procedure + +void SbiParser::Static() +{ + DefStatic( false ); +} + +void SbiParser::DefStatic( bool bPrivate ) +{ + SbiSymPool* p; + + switch( Peek() ) + { + case SUB: + case FUNCTION: + case PROPERTY: + // End global chain if necessary (not done in + // SbiParser::Parse() under these conditions + if( bNewGblDefs && nGblChain == 0 ) + { + nGblChain = aGen.Gen( SbiOpcode::JUMP_, 0 ); + bNewGblDefs = false; + } + Next(); + DefProc( true, bPrivate ); + break; + default: + if( !pProc ) + { + Error( ERRCODE_BASIC_NOT_IN_SUBR ); + } + // Reset the Pool, so that STATIC-Declarations go into the + // global Pool + p = pPool; + pPool = &aPublics; + DefVar( SbiOpcode::STATIC_, true ); + pPool = p; + break; + } +} + +bool SbiParser::IsUnoInterface(const OUString& sTypeName) +{ + try + { + return css::reflection::theCoreReflection::get( + comphelper::getProcessComponentContext())->forName(sTypeName).is(); + } + catch(const Exception&) + { + OSL_FAIL("Could not create reflection.CoreReflection."); + } + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |