1364 lines
42 KiB
C++
1364 lines
42 KiB
C++
/* -*- 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, u"()"_ustr );
|
|
}
|
|
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( u"Name"_ustr, SbxClassType::DontCare );
|
|
pType->Remove( u"Parent"_ustr, 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( u"Name"_ustr, SbxClassType::DontCare );
|
|
pEnum->Remove( u"Parent"_ustr, 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 )
|
|
{
|
|
{
|
|
SbiConstExpression aDefaultExpr(this);
|
|
SbxDataType eType2 = aDefaultExpr.GetType();
|
|
|
|
sal_uInt16 nStringId;
|
|
if (eType2 == SbxSTRING)
|
|
{
|
|
nStringId = aGblStrings.Add(aDefaultExpr.GetString());
|
|
}
|
|
else
|
|
{
|
|
nStringId = aGblStrings.Add(aDefaultExpr.GetValue(), eType2);
|
|
}
|
|
pPar->SetDefaultId(nStringId);
|
|
}
|
|
|
|
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, u"Get or Let or Set"_ustr );
|
|
}
|
|
}
|
|
|
|
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: */
|