diff options
Diffstat (limited to 'idl/source/prj/parser.cxx')
-rw-r--r-- | idl/source/prj/parser.cxx | 590 |
1 files changed, 590 insertions, 0 deletions
diff --git a/idl/source/prj/parser.cxx b/idl/source/prj/parser.cxx new file mode 100644 index 000000000..31bbee9a9 --- /dev/null +++ b/idl/source/prj/parser.cxx @@ -0,0 +1,590 @@ +/* -*- 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 <sal/config.h> + +#include <algorithm> + +#include <parser.hxx> +#include <database.hxx> +#include <globals.hxx> +#include <slot.hxx> +#include <osl/file.hxx> + +void SvIdlParser::ReadSvIdl( const OUString & rPath ) +{ + rBase.SetPath(rPath); // only valid for this iteration + SvToken& rTok = rInStm.GetToken(); + + while( true ) + { + rTok = rInStm.GetToken(); + if( rTok.IsEof() ) + return; + + Read( SvHash_module() ); + tools::SvRef<SvMetaModule> aModule = new SvMetaModule; + ReadModuleHeader(*aModule); + rBase.GetModuleList().push_back( aModule.get() ); + } +} + +void SvIdlParser::ReadModuleHeader(SvMetaModule& rModule) +{ + OString aName = ReadIdentifier(); + rModule.SetName( aName ); + rBase.Push( &rModule ); // onto the context stack + ReadModuleBody(rModule); + rBase.GetStack().pop_back(); // remove from stack +} + +void SvIdlParser::ReadModuleBody(SvMetaModule& rModule) +{ + if( ReadIf( '[' ) ) + { + while( true ) + { + OString aSlotIdFile; + if( !ReadStringSvIdl( SvHash_SlotIdFile(), rInStm, aSlotIdFile ) ) + break; + if( !rBase.ReadIdFile( aSlotIdFile ) ) + { + throw SvParseException( rInStm, "cannot read file: " + aSlotIdFile ); + } + ReadIfDelimiter(); + } + Read( ']' ); + } + + if( !ReadIf( '{' ) ) + return; + + sal_uInt32 nBeginPos = 0; + while( nBeginPos != rInStm.Tell() ) + { + nBeginPos = rInStm.Tell(); + ReadModuleElement( rModule ); + ReadIfDelimiter(); + } + Read( '}' ); +} + +void SvIdlParser::ReadModuleElement( SvMetaModule& rModule ) +{ + if( ReadIf( SvHash_interface() ) ) + { + ReadInterfaceOrShell(rModule, MetaTypeType::Interface); + } + else if( ReadIf( SvHash_shell() ) ) + { + ReadInterfaceOrShell(rModule, MetaTypeType::Shell); + } + else if( ReadIf( SvHash_enum() ) ) + { + ReadEnum(); + } + else if( ReadIf( SvHash_item() ) ) + { + ReadItem(); + } + else if( ReadIf( SvHash_struct() ) ) + { + ReadStruct(); + } + else if( ReadIf( SvHash_include() ) ) + { + ReadInclude(rModule); + } + else + { + tools::SvRef<SvMetaSlot> xSlot( new SvMetaSlot() ); + + if (ReadSlot(*xSlot)) + { + if( xSlot->Test( rInStm ) ) + { + // announce globally + rBase.AppendSlot( xSlot.get() ); + } + } + } +} + +void SvIdlParser::ReadInclude( SvMetaModule& rModule ) +{ + sal_uInt32 nTokPos = rInStm.Tell(); + bool bOk = false; + OUString aFullName(OStringToOUString(ReadString(), RTL_TEXTENCODING_ASCII_US)); + rBase.StartNewFile( aFullName ); + osl::FileBase::RC searchError = osl::File::searchFileURL(aFullName, rBase.GetPath(), aFullName); + if( osl::FileBase::E_None != searchError ) + { + OString aStr = "cannot find file:" + + OUStringToOString(aFullName, RTL_TEXTENCODING_UTF8); + throw SvParseException(aStr, rInStm.GetToken()); + } + osl::FileBase::getSystemPathFromFileURL( aFullName, aFullName ); + rBase.AddDepFile( aFullName ); + SvTokenStream aTokStm( aFullName ); + if( ERRCODE_NONE != aTokStm.GetStream().GetError() ) + { + OString aStr = "cannot open file: " + + OUStringToOString(aFullName, RTL_TEXTENCODING_UTF8); + throw SvParseException(aStr, rInStm.GetToken()); + } + // rescue error from old file + SvIdlError aOldErr = rBase.GetError(); + // reset error + rBase.SetError( SvIdlError() ); + + try { + SvIdlParser aIncludeParser( rBase, aTokStm ); + sal_uInt32 nBeginPos = 0xFFFFFFFF; // can not happen with Tell + while( nBeginPos != aTokStm.Tell() ) + { + nBeginPos = aTokStm.Tell(); + aIncludeParser.ReadModuleElement(rModule); + aTokStm.ReadIfDelimiter(); + } + } catch (const SvParseException& ex) { + rBase.SetError(ex.aError); + rBase.WriteError(aTokStm); + } + bOk = aTokStm.GetToken().IsEof(); + if( !bOk ) + { + rBase.WriteError( aTokStm ); + } + // recover error from old file + rBase.SetError( aOldErr ); + if( !bOk ) + rInStm.Seek( nTokPos ); +} + +void SvIdlParser::ReadStruct() +{ + tools::SvRef<SvMetaType> xStruct(new SvMetaType() ); + xStruct->SetType( MetaTypeType::Struct ); + xStruct->SetName( ReadIdentifier() ); + Read( '{' ); + while( true ) + { + tools::SvRef<SvMetaAttribute> xAttr( new SvMetaAttribute() ); + xAttr->aType = ReadKnownType(); + xAttr->SetName(ReadIdentifier()); + xAttr->aSlotId.setString(ReadIdentifier()); + sal_uInt32 n; + if( !rBase.FindId( xAttr->aSlotId.getString(), &n ) ) + throw SvParseException( rInStm, "no value for identifier <" + xAttr->aSlotId.getString() + "> " ); + xAttr->aSlotId.SetValue(n); + xStruct->GetAttrList().push_back( xAttr.get() ); + if( !ReadIfDelimiter() ) + break; + if( rInStm.GetToken().IsChar() && rInStm.GetToken().GetChar() == '}') + break; + } + Read( '}' ); + ReadDelimiter(); + // announce globally + rBase.GetTypeList().push_back( xStruct.get() ); +} + +void SvIdlParser::ReadItem() +{ + tools::SvRef<SvMetaType> xItem(new SvMetaType() ); + xItem->SetItem(true); + xItem->SetRef( ReadKnownType() ); + xItem->SetName( ReadIdentifier() ); + // announce globally + rBase.GetTypeList().push_back( xItem.get() ); +} + +void SvIdlParser::ReadEnum() +{ + tools::SvRef<SvMetaTypeEnum> xEnum( new SvMetaTypeEnum() ); + xEnum->SetType( MetaTypeType::Enum ); + xEnum->SetName( ReadIdentifier() ); + + Read('{'); + while( true ) + { + ReadEnumValue( *xEnum ); + if( !ReadIfDelimiter() ) + break; + } + Read( '}' ); + // announce globally + rBase.GetTypeList().push_back( xEnum.get() ); +} + +static std::string_view getCommonSubPrefix(std::string_view rA, std::string_view rB) +{ + sal_Int32 nMax = std::min(rA.size(), rB.size()); + sal_Int32 nI = 0; + while (nI < nMax) + { + if (rA[nI] != rB[nI]) + break; + ++nI; + } + return rA.substr(0, nI); +} + +void SvIdlParser::ReadEnumValue( SvMetaTypeEnum& rEnum ) +{ + tools::SvRef<SvMetaEnumValue> aEnumVal = new SvMetaEnumValue(); + aEnumVal->SetName( ReadIdentifier() ); + if( rEnum.aEnumValueList.empty() ) + { + // the first + rEnum.aPrefix = aEnumVal->GetName(); + } + else + { + rEnum.aPrefix = OString(getCommonSubPrefix(rEnum.aPrefix, aEnumVal->GetName())); + } + rEnum.aEnumValueList.push_back( aEnumVal.get() ); +} + +void SvIdlParser::ReadInterfaceOrShell( SvMetaModule& rModule, MetaTypeType aMetaTypeType ) +{ + tools::SvRef<SvMetaClass> aClass( new SvMetaClass() ); + + aClass->SetType( aMetaTypeType ); + + aClass->SetName( ReadIdentifier() ); + + if( ReadIf( ':' ) ) + { + aClass->aSuperClass = ReadKnownClass(); + } + if( ReadIf( '{' ) ) + { + sal_uInt32 nBeginPos = 0; // can not happen with Tell + while( nBeginPos != rInStm.Tell() ) + { + nBeginPos = rInStm.Tell(); + ReadInterfaceOrShellEntry(*aClass); + ReadIfDelimiter(); + } + Read( '}' ); + } + rModule.aClassList.push_back( aClass.get() ); + // announce globally + rBase.GetClassList().push_back( aClass.get() ); +} + +void SvIdlParser::ReadInterfaceOrShellEntry(SvMetaClass& rClass) +{ + if( ReadIf( SvHash_import() ) ) + { + SvMetaClass * pClass = ReadKnownClass(); + SvClassElement aEle(pClass); + SvToken& rTok = rInStm.GetToken(); + if( rTok.IsString() ) + { + aEle.SetPrefix( rTok.GetString() ); + rInStm.GetToken_Next(); + } + rClass.aClassElementList.push_back( aEle ); + } + else + { + SvMetaType * pType = rBase.ReadKnownType( rInStm ); + tools::SvRef<SvMetaAttribute> xAttr; + bool bOk = false; + if( !pType || pType->IsItem() ) + { + xAttr = new SvMetaSlot( pType ); + bOk = ReadSlot(static_cast<SvMetaSlot&>(*xAttr)); + } + else + { + xAttr = new SvMetaAttribute( pType ); + ReadInterfaceOrShellMethod(*xAttr); + bOk = true; + } + if( bOk ) + bOk = xAttr->Test( rInStm ); + if( bOk ) + bOk = rClass.TestAttribute( rBase, rInStm, *xAttr ); + if( bOk ) + { + if( !xAttr->GetSlotId().IsSet() ) + xAttr->SetSlotId( SvIdentifier(rBase.GetUniqueId()) ); + rClass.aAttrList.push_back( xAttr.get() ); + } + } +} + +bool SvIdlParser::ReadSlot(SvMetaSlot& rSlot) +{ + sal_uInt32 nTokPos = rInStm.Tell(); + bool bOk = true; + + SvMetaAttribute * pAttr = rBase.ReadKnownAttr( rInStm, rSlot.GetType() ); + if( pAttr ) + { + SvMetaSlot * pKnownSlot = dynamic_cast<SvMetaSlot*>( pAttr ); + if( !pKnownSlot ) + throw SvParseException( rInStm, "attribute " + pAttr->GetName() + " is method or variable but not a slot" ); + rSlot.SetRef( pKnownSlot ); + rSlot.SetName( pKnownSlot->GetName() ); + if( ReadIf( '[' ) ) + { + sal_uInt32 nBeginPos = 0; // can not happen with Tell + while( nBeginPos != rInStm.Tell() ) + { + nBeginPos = rInStm.Tell(); + ReadSlotAttribute(rSlot); + ReadIfDelimiter(); + } + Read( ']' ); + } + } + else + { + bOk = rSlot.SvMetaAttribute::ReadSvIdl( rBase, rInStm ); + SvMetaAttribute *pAttr2 = rBase.FindKnownAttr( rSlot.GetSlotId() ); + if( pAttr2 ) + { + SvMetaSlot * pKnownSlot = dynamic_cast<SvMetaSlot*>( pAttr2 ); + if( !pKnownSlot ) + throw SvParseException( rInStm, "attribute " + pAttr2->GetName() + " is method or variable but not a slot" ); + rSlot.SetRef( pKnownSlot ); + // names may differ, because explicitly given + if ( pKnownSlot->GetName() != rSlot.GetName() ) + throw SvParseException( rInStm, "Illegal definition!" ); + } + } + + if( !bOk ) + rInStm.Seek( nTokPos ); + + return bOk; +} + +void SvIdlParser::ReadSlotAttribute( SvMetaSlot& rSlot ) +{ + ReadIfIdAttribute(rSlot.aGroupId, SvHash_GroupId() ); + ReadIfIdAttribute(rSlot.aExecMethod, SvHash_ExecMethod() ); + ReadIfIdAttribute(rSlot.aStateMethod, SvHash_StateMethod() ); + ReadStringSvIdl( SvHash_DisableFlags(), rInStm, rSlot.aDisableFlags ); + ReadIfBoolAttribute(rSlot.aReadOnlyDoc, SvHash_ReadOnlyDoc() ); + + ReadIfBoolAttribute(rSlot.aToggle, SvHash_Toggle() ); + ReadIfBoolAttribute(rSlot.aAutoUpdate, SvHash_AutoUpdate() ); + ReadIfBoolAttribute(rSlot.aAsynchron, SvHash_Asynchron() ); + ReadIfBoolAttribute(rSlot.aRecordAbsolute, SvHash_RecordAbsolute() ); + + if( ReadIfBoolAttribute(rSlot.aRecordPerItem, SvHash_RecordPerItem()) ) + { + if (rSlot.aRecordPerSet.IsSet() || rSlot.aNoRecord.IsSet()) + throw SvParseException(rInStm, "conflicting attributes"); + rSlot.SetRecordPerItem( rSlot.aRecordPerItem ); + } + if( ReadIfBoolAttribute(rSlot.aRecordPerSet, SvHash_RecordPerSet() ) ) + { + if (rSlot.aRecordPerItem.IsSet() || rSlot.aNoRecord.IsSet()) + throw SvParseException(rInStm, "conflicting attributes"); + rSlot.SetRecordPerSet( rSlot.aRecordPerSet ); + } + if( ReadIfBoolAttribute(rSlot.aNoRecord, SvHash_NoRecord() ) ) + { + if (rSlot.aRecordPerItem.IsSet() || rSlot.aRecordPerSet.IsSet()) + throw SvParseException(rInStm, "conflicting attributes"); + rSlot.SetNoRecord( rSlot.aNoRecord ); + } + + ReadIfBoolAttribute(rSlot.aMenuConfig, SvHash_MenuConfig() ); + ReadIfBoolAttribute(rSlot.aToolBoxConfig, SvHash_ToolBoxConfig() ); + ReadIfBoolAttribute(rSlot.aAccelConfig, SvHash_AccelConfig() ); + + ReadIfBoolAttribute(rSlot.aFastCall, SvHash_FastCall() ); + ReadIfBoolAttribute(rSlot.aContainer, SvHash_Container() ); +} + +void SvIdlParser::ReadInterfaceOrShellMethod( SvMetaAttribute& rAttr ) +{ + rAttr.SetName( ReadIdentifier() ); + ReadSlotId( rAttr.aSlotId ); + + // read method arguments + Read( '(' ); + tools::SvRef<SvMetaType> xT(new SvMetaType() ); + xT->SetRef(rAttr.GetType() ); + rAttr.aType = xT; + rAttr.aType->SetType( MetaTypeType::Method ); + if (ReadIf(')')) + return; + + while (true) + { + tools::SvRef<SvMetaAttribute> xParamAttr( new SvMetaAttribute() ); + xParamAttr->aType = ReadKnownType(); + xParamAttr->SetName( ReadIdentifier() ); + ReadSlotId(xParamAttr->aSlotId); + rAttr.aType->GetAttrList().push_back( xParamAttr.get() ); + if (!ReadIfDelimiter()) + break; + } + Read(')'); +} + +void SvIdlParser::ReadSlotId(SvIdentifier& rSlotId) +{ + rSlotId.setString( ReadIdentifier() ); + sal_uInt32 n; + if( !rBase.FindId( rSlotId.getString(), &n ) ) + throw SvParseException( rInStm, "no value for identifier <" + rSlotId.getString() + "> " ); + rSlotId.SetValue(n); +} + +SvMetaClass * SvIdlParser::ReadKnownClass() +{ + OString aName(ReadIdentifier()); + SvMetaClass* pClass = rBase.FindKnownClass( aName ); + if( !pClass ) + throw SvParseException( rInStm, "unknown class" ); + return pClass; +} + +SvMetaType * SvIdlParser::ReadKnownType() +{ + OString aName = ReadIdentifier(); + for( const auto& aType : rBase.GetTypeList() ) + { + if( aType->GetName() == aName ) + return aType; + } + throw SvParseException( rInStm, "wrong typedef: "); +} + +bool SvIdlParser::ReadIfBoolAttribute( SvBOOL& rBool, SvStringHashEntry const * pName ) +{ + sal_uInt32 nTokPos = rInStm.Tell(); + SvToken& rTok = rInStm.GetToken_Next(); + + if( rTok.Is( pName ) ) + { + if( rInStm.ReadIf( '=' ) ) + { + rTok = rInStm.GetToken(); + if( !rTok.IsBool() ) + throw SvParseException(rInStm, "xxx"); + rBool = rTok.GetBool(); + rInStm.GetToken_Next(); + } + else + rBool = true; //default action set to TRUE + return true; + } + rInStm.Seek( nTokPos ); + return false; +} + +void SvIdlParser::ReadIfIdAttribute( SvIdentifier& rIdentifier, SvStringHashEntry const * pName ) +{ + sal_uInt32 nTokPos = rInStm.Tell(); + SvToken& rTok = rInStm.GetToken_Next(); + + if( rTok.Is( pName ) ) + { + if( rInStm.ReadIf( '=' ) ) + { + rTok = rInStm.GetToken(); + if( !rTok.IsIdentifier() ) + throw SvParseException(rInStm, "expected identifier"); + rIdentifier.setString(rTok.GetString()); + rInStm.GetToken_Next(); + } + } + else + rInStm.Seek( nTokPos ); +} + +void SvIdlParser::ReadDelimiter() +{ + if( !ReadIfDelimiter() ) + throw SvParseException(rInStm, "expected delimiter"); +} + +bool SvIdlParser::ReadIfDelimiter() +{ + if( rInStm.GetToken().IsChar() + && (';' == rInStm.GetToken().GetChar() + || ',' == rInStm.GetToken().GetChar()) ) + { + rInStm.GetToken_Next(); + return true; + } + return false; +} + +OString SvIdlParser::ReadIdentifier() +{ + SvToken& rTok = rInStm.GetToken(); + if( !rTok.IsIdentifier() ) + throw SvParseException("expected identifier", rTok); + rInStm.GetToken_Next(); + return rTok.GetString(); +} + +OString SvIdlParser::ReadString() +{ + SvToken& rTok = rInStm.GetToken(); + if( !rTok.IsString() ) + throw SvParseException("expected string", rTok); + rInStm.GetToken_Next(); + return rTok.GetString(); +} + +void SvIdlParser::Read(char cChar) +{ + if( !ReadIf(cChar) ) + throw SvParseException(rInStm, "expected char '" + OStringChar(cChar) + "'"); +} + +bool SvIdlParser::ReadIf(char cChar) +{ + if( rInStm.GetToken().IsChar() && rInStm.GetToken().GetChar() == cChar ) + { + rInStm.GetToken_Next(); + return true; + } + return false; +} + +void SvIdlParser::Read(SvStringHashEntry const * entry) +{ + if( !rInStm.GetToken().Is(entry) ) + throw SvParseException("expected " + entry->GetName(), rInStm.GetToken()); + rInStm.GetToken_Next(); +} + +bool SvIdlParser::ReadIf(SvStringHashEntry const * entry) +{ + if( rInStm.GetToken().Is(entry) ) + { + rInStm.GetToken_Next(); + return true; + } + return false; +} +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |