From 940b4d1848e8c70ab7642901a68594e8016caffc Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 18:51:28 +0200 Subject: Adding upstream version 1:7.0.4. Signed-off-by: Daniel Baumann --- idlc/source/astconstant.cxx | 123 ++ idlc/source/astdeclaration.cxx | 164 +++ idlc/source/astdump.cxx | 420 ++++++ idlc/source/astenum.cxx | 105 ++ idlc/source/astexpression.cxx | 1321 +++++++++++++++++ idlc/source/astinterface.cxx | 399 +++++ idlc/source/astoperation.cxx | 115 ++ idlc/source/astscope.cxx | 313 ++++ idlc/source/astservice.cxx | 54 + idlc/source/aststack.cxx | 85 ++ idlc/source/aststruct.cxx | 167 +++ idlc/source/aststructinstance.cxx | 63 + idlc/source/attributeexceptions.hxx | 36 + idlc/source/errorhandler.cxx | 583 ++++++++ idlc/source/fehelper.cxx | 102 ++ idlc/source/idlc.cxx | 400 +++++ idlc/source/idlccompile.cxx | 390 +++++ idlc/source/idlcmain.cxx | 165 +++ idlc/source/idlcproduce.cxx | 245 ++++ idlc/source/options.cxx | 421 ++++++ idlc/source/parser.y | 2737 +++++++++++++++++++++++++++++++++++ idlc/source/scanner.l | 524 +++++++ 22 files changed, 8932 insertions(+) create mode 100644 idlc/source/astconstant.cxx create mode 100644 idlc/source/astdeclaration.cxx create mode 100644 idlc/source/astdump.cxx create mode 100644 idlc/source/astenum.cxx create mode 100644 idlc/source/astexpression.cxx create mode 100644 idlc/source/astinterface.cxx create mode 100644 idlc/source/astoperation.cxx create mode 100644 idlc/source/astscope.cxx create mode 100644 idlc/source/astservice.cxx create mode 100644 idlc/source/aststack.cxx create mode 100644 idlc/source/aststruct.cxx create mode 100644 idlc/source/aststructinstance.cxx create mode 100644 idlc/source/attributeexceptions.hxx create mode 100644 idlc/source/errorhandler.cxx create mode 100644 idlc/source/fehelper.cxx create mode 100644 idlc/source/idlc.cxx create mode 100644 idlc/source/idlccompile.cxx create mode 100644 idlc/source/idlcmain.cxx create mode 100644 idlc/source/idlcproduce.cxx create mode 100644 idlc/source/options.cxx create mode 100644 idlc/source/parser.y create mode 100644 idlc/source/scanner.l (limited to 'idlc/source') diff --git a/idlc/source/astconstant.cxx b/idlc/source/astconstant.cxx new file mode 100644 index 000000000..54d235fa3 --- /dev/null +++ b/idlc/source/astconstant.cxx @@ -0,0 +1,123 @@ +/* -*- 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 +#include + +#include + +AstConstant::AstConstant(const ExprType type, + const NodeType nodeType, + AstExpression* pExpr, + const OString& name, + AstScope* pScope) + : AstDeclaration(nodeType, name, pScope) + , m_pConstValue(pExpr) + , m_constValueType(type) +{ +} + +AstConstant::AstConstant(const ExprType type, + AstExpression* pExpr, + const OString& name, + AstScope* pScope) + : AstDeclaration(NT_const, name, pScope) + , m_pConstValue(pExpr) + , m_constValueType(type) +{ +} + +AstConstant::~AstConstant() +{ + +} + +bool AstConstant::dumpBlob( + typereg::Writer & rBlob, sal_uInt16 index, bool published) +{ + RTConstValue aConst; + + AstExprValue *exprVal = getConstValue()->getExprValue(); + switch (getConstValueType()) + { + case ET_short: + aConst.m_type = RT_TYPE_INT16; + aConst.m_value.aShort = exprVal->u.sval; + break; + case ET_ushort: + aConst.m_type = RT_TYPE_UINT16; + aConst.m_value.aUShort = exprVal->u.usval; + break; + case ET_long: + aConst.m_type = RT_TYPE_INT32; + aConst.m_value.aLong = exprVal->u.lval; + break; + case ET_ulong: + aConst.m_type = RT_TYPE_UINT32; + aConst.m_value.aULong = exprVal->u.ulval; + break; + case ET_hyper: + aConst.m_type = RT_TYPE_INT64; + aConst.m_value.aHyper = exprVal->u.hval; + break; + case ET_uhyper: + aConst.m_type = RT_TYPE_UINT64; + aConst.m_value.aUHyper = exprVal->u.uhval; + break; + case ET_float: + aConst.m_type = RT_TYPE_FLOAT; + aConst.m_value.aFloat = exprVal->u.fval; + break; + case ET_double: + aConst.m_type = RT_TYPE_DOUBLE; + aConst.m_value.aDouble = exprVal->u.dval; + break; + case ET_byte: + aConst.m_type = RT_TYPE_BYTE; + aConst.m_value.aByte = exprVal->u.byval; + break; + case ET_boolean: + aConst.m_type = RT_TYPE_BOOL; + aConst.m_value.aBool = exprVal->u.bval; + break; + default: + { + fprintf(stderr, "%s: exprtype to const type: cannot convert ExprType\n", + idlc()->getOptions()->getProgramName().getStr()); + return false; + } + } + + OString name = getLocalName(); + + OUString type; + if ( getNodeType() != NT_enum_val ) + { + type = OStringToOUString(exprTypeToString(getConstValueType()), RTL_TEXTENCODING_UTF8); + } + + rBlob.setFieldData( + index, getDocumentation(), OUString(), + RTFieldAccess::CONST | (published ? RTFieldAccess::PUBLISHED : RTFieldAccess::NONE), + OStringToOUString(name, RTL_TEXTENCODING_UTF8), type, aConst); + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/idlc/source/astdeclaration.cxx b/idlc/source/astdeclaration.cxx new file mode 100644 index 000000000..f44febc8a --- /dev/null +++ b/idlc/source/astdeclaration.cxx @@ -0,0 +1,164 @@ +/* -*- 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 +#include +#include +#include + +static const OString sGlobal("::"); + +static OString convertName(const OString& name) +{ + OStringBuffer nameBuffer(name.getLength()+1); + sal_Int32 nIndex = 0; + do + { + OString token( name.getToken( 0, ':', nIndex ) ); + if( !token.isEmpty() ) + { + nameBuffer.append('/'); + nameBuffer.append( token ); + } + } while( nIndex != -1 ); + return nameBuffer.makeStringAndClear(); +} + +AstDeclaration::AstDeclaration(NodeType type, const OString& name, AstScope* pScope) + : m_localName(name) + , m_pScope(pScope) + , m_nodeType(type) + , m_bImported(false) + , m_bInMainFile(false) + , m_bPredefined(false) + , m_lineNumber(0) +{ + if ( m_pScope ) + { + AstDeclaration* pDecl = scopeAsDecl(m_pScope); + if (pDecl) + { + m_scopedName = pDecl->getScopedName(); + if (!m_scopedName.isEmpty()) + m_scopedName += sGlobal; + m_scopedName += m_localName; + } + } else + { + m_scopedName = m_localName; + } + m_fullName = convertName(m_scopedName); + + if ( idlc()->getFileName() == idlc()->getRealFileName() ) + { + m_fileName = idlc()->getMainFileName(); + m_bInMainFile = true; + } else + { + m_fileName = idlc()->getFileName(); + m_bImported = true; + } + + m_documentation = idlc()->processDocumentation(); + + m_bPublished = idlc()->isPublished(); +} + + +AstDeclaration::~AstDeclaration() +{ + +} + +void AstDeclaration::setPredefined(bool bPredefined) +{ + m_bPredefined = bPredefined; + if ( m_bPredefined ) + { + m_fileName.clear(); + m_bInMainFile = false; + } +} + +bool AstDeclaration::isType() const { + switch (m_nodeType) { + case NT_interface: + case NT_instantiated_struct: + case NT_enum: + case NT_sequence: + case NT_typedef: + case NT_predefined: + case NT_type_parameter: + return true; + + default: + OSL_ASSERT(m_nodeType != NT_struct); // see AstStruct::isType + return false; + } +} + +bool AstDeclaration::hasAncestor(AstDeclaration* pDecl) +{ + if (this == pDecl) + return true; + if ( !m_pScope ) + return false; + return scopeAsDecl(m_pScope)->hasAncestor(pDecl); +} + +bool AstDeclaration::dump(RegistryKey& rKey) +{ + AstScope* pScope = declAsScope(this); + bool bRet = true; + + if ( pScope ) + { + DeclList::const_iterator iter = pScope->getIteratorBegin(); + DeclList::const_iterator end = pScope->getIteratorEnd(); + AstDeclaration* pDecl = nullptr; + while ( iter != end && bRet) + { + pDecl = *iter; + if ( pDecl->isInMainfile() ) + { + switch ( pDecl->getNodeType() ) + { + case NT_module: + case NT_constants: + case NT_interface: + case NT_struct: + case NT_exception: + case NT_enum: + case NT_typedef: + case NT_service: + case NT_singleton: + bRet = pDecl->dump(rKey); + break; + default: + break; + } + } + + ++iter; + } + } + return bRet; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/idlc/source/astdump.cxx b/idlc/source/astdump.cxx new file mode 100644 index 000000000..79613e137 --- /dev/null +++ b/idlc/source/astdump.cxx @@ -0,0 +1,420 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +bool AstModule::dump(RegistryKey& rKey) +{ + RegistryKey localKey; + if ( getNodeType() == NT_root ) + { + localKey = rKey; + }else + { + if (rKey.createKey( OStringToOUString(getFullName(), RTL_TEXTENCODING_UTF8 ), localKey) != RegError::NO_ERROR) + { + fprintf(stderr, "%s: warning, could not create key '%s' in '%s'\n", + idlc()->getOptions()->getProgramName().getStr(), + getFullName().getStr(), OUStringToOString(rKey.getRegistryName(), RTL_TEXTENCODING_UTF8).getStr()); + return false; + } + } + + sal_uInt16 nConst = getNodeCount(NT_const); + + if ( nConst > 0 ) + { + RTTypeClass typeClass = RT_TYPE_MODULE; + if ( getNodeType() == NT_constants ) + typeClass = RT_TYPE_CONSTANTS; + + typereg::Writer aBlob( + m_bPublished ? TYPEREG_VERSION_1 : TYPEREG_VERSION_0, + getDocumentation(), "", typeClass, + m_bPublished, + OStringToOUString(getRelativName(), RTL_TEXTENCODING_UTF8), 0, + nConst, 0, 0); + + DeclList::const_iterator iter = getIteratorBegin(); + DeclList::const_iterator end = getIteratorEnd(); + sal_uInt16 index = 0; + while ( iter != end ) + { + AstDeclaration* pDecl = *iter; + if ( pDecl->getNodeType() == NT_const && + pDecl->isInMainfile() ) + { + static_cast(pDecl)->dumpBlob( + aBlob, index++, + getNodeType() == NT_module && pDecl->isPublished()); + } + ++iter; + } + + sal_uInt32 aBlobSize; + void const * pBlob = aBlob.getBlob(&aBlobSize); + + if (localKey.setValue("", RegValueType::BINARY, + const_cast(pBlob), aBlobSize) != RegError::NO_ERROR) + { + fprintf(stderr, "%s: warning, could not set value of key \"%s\" in %s\n", + idlc()->getOptions()->getProgramName().getStr(), + getFullName().getStr(), OUStringToOString(localKey.getRegistryName(), RTL_TEXTENCODING_UTF8).getStr()); + return false; + } + } else + { + RTTypeClass typeClass = RT_TYPE_MODULE; + if ( getNodeType() == NT_constants ) + typeClass = RT_TYPE_CONSTANTS; + + typereg::Writer aBlob( + m_bPublished ? TYPEREG_VERSION_1 : TYPEREG_VERSION_0, + getDocumentation(), "", typeClass, m_bPublished, + OStringToOUString(getRelativName(), RTL_TEXTENCODING_UTF8), 0, 0, 0, + 0); + + sal_uInt32 aBlobSize; + void const * pBlob = aBlob.getBlob(&aBlobSize); + + if ( getNodeType() != NT_root ) + { + if (localKey.setValue("", RegValueType::BINARY, + const_cast(pBlob), aBlobSize) != RegError::NO_ERROR) + { + fprintf(stderr, "%s: warning, could not set value of key \"%s\" in %s\n", + idlc()->getOptions()->getProgramName().getStr(), + getFullName().getStr(), OUStringToOString(localKey.getRegistryName(), RTL_TEXTENCODING_UTF8).getStr()); + return false; + } + } + } + if ( getNodeType() == NT_root ) + { + localKey.releaseKey(); + } + return AstDeclaration::dump(rKey); +} + +bool AstTypeDef::dump(RegistryKey& rKey) +{ + RegistryKey localKey; + if (rKey.createKey( OStringToOUString(getFullName(), RTL_TEXTENCODING_UTF8 ), localKey) != RegError::NO_ERROR) + { + fprintf(stderr, "%s: warning, could not create key '%s' in '%s'\n", + idlc()->getOptions()->getProgramName().getStr(), + getFullName().getStr(), OUStringToOString(rKey.getRegistryName(), RTL_TEXTENCODING_UTF8).getStr()); + return false; + } + + typereg::Writer aBlob( + m_bPublished ? TYPEREG_VERSION_1 : TYPEREG_VERSION_0, + getDocumentation(), "", RT_TYPE_TYPEDEF, m_bPublished, + OStringToOUString(getRelativName(), RTL_TEXTENCODING_UTF8), 1, 0, 0, 0); + aBlob.setSuperTypeName( + 0, + OStringToOUString( + getBaseType()->getRelativName(), RTL_TEXTENCODING_UTF8)); + + sal_uInt32 aBlobSize; + void const * pBlob = aBlob.getBlob(&aBlobSize); + + if (localKey.setValue("", RegValueType::BINARY, const_cast(pBlob), aBlobSize) != RegError::NO_ERROR) + { + fprintf(stderr, "%s: warning, could not set value of key \"%s\" in %s\n", + idlc()->getOptions()->getProgramName().getStr(), + getFullName().getStr(), OUStringToOString(localKey.getRegistryName(), RTL_TEXTENCODING_UTF8).getStr()); + return false; + } + + return true; +} + +bool AstService::dump(RegistryKey& rKey) +{ + typereg_Version version = m_bPublished + ? TYPEREG_VERSION_1 : TYPEREG_VERSION_0; + OString superName; + sal_uInt16 constructors = 0; + sal_uInt16 properties = 0; + sal_uInt16 references = 0; + for (DeclList::const_iterator i(getIteratorBegin()); i != getIteratorEnd(); + ++i) + { + switch ((*i)->getNodeType()) { + case NT_interface: + case NT_typedef: + version = TYPEREG_VERSION_1; + OSL_ASSERT(superName.isEmpty()); + superName = (*i)->getRelativName(); + break; + + case NT_operation: + OSL_ASSERT(getNodeType() == NT_service); + ++constructors; + break; + + case NT_property: + OSL_ASSERT(getNodeType() == NT_service); + ++properties; + break; + + case NT_service_member: + if (getNodeType() == NT_singleton) { + OSL_ASSERT(superName.isEmpty()); + superName = static_cast(*i)-> + getRealService()->getRelativName(); + break; + } + [[fallthrough]]; + case NT_interface_member: + case NT_observes: + case NT_needs: + OSL_ASSERT(getNodeType() == NT_service); + ++references; + break; + + default: + OSL_ASSERT(false); + break; + } + } + OSL_ASSERT(constructors == 0 || !m_defaultConstructor); + if (m_defaultConstructor) { + constructors = 1; + } + RegistryKey localKey; + if (rKey.createKey( + OStringToOUString(getFullName(), RTL_TEXTENCODING_UTF8), + localKey) != RegError::NO_ERROR) { + fprintf( + stderr, "%s: warning, could not create key '%s' in '%s'\n", + idlc()->getOptions()->getProgramName().getStr(), + getFullName().getStr(), + OUStringToOString( + rKey.getRegistryName(), RTL_TEXTENCODING_UTF8).getStr()); + return false; + } + typereg::Writer writer( + version, getDocumentation(), "", + getNodeType() == NT_singleton ? RT_TYPE_SINGLETON : RT_TYPE_SERVICE, + m_bPublished, + OStringToOUString(getRelativName(), RTL_TEXTENCODING_UTF8), + superName.isEmpty() ? 0 : 1, properties, constructors, + references); + if (!superName.isEmpty()) { + writer.setSuperTypeName( + 0, OStringToOUString(superName, RTL_TEXTENCODING_UTF8)); + } + sal_uInt16 constructorIndex = 0; + sal_uInt16 propertyIndex = 0; + sal_uInt16 referenceIndex = 0; + for (DeclList::const_iterator i(getIteratorBegin()); i != getIteratorEnd(); ++i) + { + switch ((*i)->getNodeType()) { + case NT_operation: + static_cast(*i)->dumpBlob(writer, constructorIndex++); + break; + + case NT_property: + static_cast(*i)->dumpBlob(writer, propertyIndex++, nullptr); + break; + + case NT_interface_member: + { + AstInterfaceMember * decl = static_cast(*i); + writer.setReferenceData( + referenceIndex++, decl->getDocumentation(), RTReferenceType::SUPPORTS, + (decl->isOptional() ? RTFieldAccess::OPTIONAL : RTFieldAccess::INVALID), + OStringToOUString( decl->getRealInterface()->getRelativName(), + RTL_TEXTENCODING_UTF8)); + break; + } + + case NT_service_member: + if (getNodeType() == NT_service) + { + AstServiceMember * decl = static_cast(*i); + writer.setReferenceData(referenceIndex++, decl->getDocumentation(), RTReferenceType::EXPORTS, + (decl->isOptional() ? RTFieldAccess::OPTIONAL : RTFieldAccess::INVALID), + OStringToOUString(decl->getRealService()->getRelativName(), + RTL_TEXTENCODING_UTF8)); + } + break; + + case NT_observes: + { + AstObserves * decl = static_cast(*i); + writer.setReferenceData(referenceIndex++, decl->getDocumentation(), RTReferenceType::OBSERVES, + RTFieldAccess::INVALID, + OStringToOUString( decl->getRealInterface()->getRelativName(), + RTL_TEXTENCODING_UTF8)); + break; + } + + case NT_needs: + { + AstNeeds * decl = static_cast(*i); + writer.setReferenceData( referenceIndex++, decl->getDocumentation(), RTReferenceType::NEEDS, + RTFieldAccess::INVALID, + OStringToOUString( decl->getRealService()->getRelativName(), + RTL_TEXTENCODING_UTF8)); + break; + } + + default: + OSL_ASSERT( (*i)->getNodeType() == NT_interface || (*i)->getNodeType() == NT_typedef); + break; + } + } + if (m_defaultConstructor) { + writer.setMethodData( + constructorIndex++, "", RTMethodMode::TWOWAY, + "", "void", + 0, 0); + } + sal_uInt32 size; + void const * blob = writer.getBlob(&size); + if (localKey.setValue( + "", RegValueType::BINARY, const_cast< void * >(blob), + size) != RegError::NO_ERROR) + { + fprintf( + stderr, "%s: warning, could not set value of key \"%s\" in %s\n", + idlc()->getOptions()->getProgramName().getStr(), + getFullName().getStr(), + OUStringToOString( + localKey.getRegistryName(), RTL_TEXTENCODING_UTF8).getStr()); + return false; + } + return true; +} + +void AstAttribute::dumpBlob( + typereg::Writer & rBlob, sal_uInt16 index, sal_uInt16 * methodIndex) const +{ + RTFieldAccess accessMode = RTFieldAccess::INVALID; + + if (isReadonly()) + { + accessMode |= RTFieldAccess::READONLY; + } else + { + accessMode |= RTFieldAccess::READWRITE; + } + if (isOptional()) + { + accessMode |= RTFieldAccess::OPTIONAL; + } + if (isBound()) + { + accessMode |= RTFieldAccess::BOUND; + } + if (isMayBeVoid()) + { + accessMode |= RTFieldAccess::MAYBEVOID; + } + if (isConstrained()) + { + accessMode |= RTFieldAccess::CONSTRAINED; + } + if (isTransient()) + { + accessMode |= RTFieldAccess::TRANSIENT; + } + if (isMayBeAmbiguous()) + { + accessMode |= RTFieldAccess::MAYBEAMBIGUOUS; + } + if (isMayBeDefault()) + { + accessMode |= RTFieldAccess::MAYBEDEFAULT; + } + if (isRemoveable()) + { + accessMode |= RTFieldAccess::REMOVABLE; + } + + OUString name(OStringToOUString(getLocalName(), RTL_TEXTENCODING_UTF8)); + rBlob.setFieldData( + index, getDocumentation(), OUString(), accessMode, name, + OStringToOUString(m_pType->getRelativName(), RTL_TEXTENCODING_UTF8), + RTConstValue()); + dumpExceptions( + rBlob, m_getDocumentation, m_getExceptions, RTMethodMode::ATTRIBUTE_GET, + methodIndex); + dumpExceptions( + rBlob, m_setDocumentation, m_setExceptions, RTMethodMode::ATTRIBUTE_SET, + methodIndex); +} + +void AstAttribute::dumpExceptions( + typereg::Writer & writer, OUString const & documentation, + DeclList const & exceptions, RTMethodMode flags, sal_uInt16 * methodIndex) const +{ + if (exceptions.empty()) + return; + + OSL_ASSERT(methodIndex != nullptr); + sal_uInt16 idx = (*methodIndex)++; + // exceptions.size() <= SAL_MAX_UINT16 already checked in + // AstInterface::dump: + writer.setMethodData( + idx, documentation, flags, + OStringToOUString(getLocalName(), RTL_TEXTENCODING_UTF8), + "void", 0, + static_cast< sal_uInt16 >(exceptions.size())); + sal_uInt16 exceptionIndex = 0; + for (auto const& elem : exceptions) + { + writer.setMethodExceptionTypeName( + idx, exceptionIndex++, + OStringToOUString( + elem->getRelativName(), RTL_TEXTENCODING_UTF8)); + } +} + +const char* AstSequence::getRelativName() const +{ + if ( !m_xRelativName ) + { + m_xRelativName = OString("[]"); + AstDeclaration const * pType = resolveTypedefs( m_pMemberType ); + *m_xRelativName += pType->getRelativName(); + } + + return m_xRelativName->getStr(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/idlc/source/astenum.cxx b/idlc/source/astenum.cxx new file mode 100644 index 000000000..54324337d --- /dev/null +++ b/idlc/source/astenum.cxx @@ -0,0 +1,105 @@ +/* -*- 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 + +#include + +#include + +#include +#include + +AstEnum::AstEnum(const OString& name, AstScope* pScope) + : AstType(NT_enum, name, pScope) + , AstScope(NT_enum) + , m_enumValueCount(0) +{ +} + +AstEnum::~AstEnum() +{ +} + +AstConstant* AstEnum::checkValue(AstExpression* pExpr) +{ + DeclList::const_iterator iter = getIteratorBegin(); + DeclList::const_iterator end = getIteratorEnd(); + + iter = std::find_if(iter, end, [&pExpr](AstDeclaration* pDecl) { + return static_cast(pDecl)->getConstValue()->compareLong(pExpr); }); + + if (iter != end) + return static_cast(*iter); + + if ( pExpr->getExprValue()->u.lval > m_enumValueCount ) + m_enumValueCount = pExpr->getExprValue()->u.lval + 1; + + return nullptr; +} + +bool AstEnum::dump(RegistryKey& rKey) +{ + RegistryKey localKey; + if (rKey.createKey( OStringToOUString(getFullName(), RTL_TEXTENCODING_UTF8 ), localKey) != RegError::NO_ERROR) + { + fprintf(stderr, "%s: warning, could not create key '%s' in '%s'\n", + idlc()->getOptions()->getProgramName().getStr(), + getFullName().getStr(), OUStringToOString(rKey.getRegistryName(), RTL_TEXTENCODING_UTF8).getStr()); + return false; + } + + sal_uInt16 nConst = getNodeCount(NT_enum_val); + if ( nConst > 0 ) + { + typereg::Writer aBlob( + m_bPublished ? TYPEREG_VERSION_1 : TYPEREG_VERSION_0, + getDocumentation(), "", RT_TYPE_ENUM, m_bPublished, + OStringToOUString(getRelativName(), RTL_TEXTENCODING_UTF8), 0, + nConst, 0, 0); + + DeclList::const_iterator iter = getIteratorBegin(); + DeclList::const_iterator end = getIteratorEnd(); + sal_uInt16 index = 0; + while ( iter != end ) + { + AstDeclaration* pDecl = *iter; + if ( pDecl->getNodeType() == NT_enum_val ) + static_cast(pDecl)->dumpBlob(aBlob, index++, false); + + ++iter; + } + + sal_uInt32 aBlobSize; + void const * pBlob = aBlob.getBlob(&aBlobSize); + + if (localKey.setValue("", RegValueType::BINARY, + const_cast(pBlob), aBlobSize) != RegError::NO_ERROR) + { + fprintf(stderr, "%s: warning, could not set value of key \"%s\" in %s\n", + idlc()->getOptions()->getProgramName().getStr(), + getFullName().getStr(), OUStringToOString(localKey.getRegistryName(), RTL_TEXTENCODING_UTF8).getStr()); + return false; + } + } + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/idlc/source/astexpression.cxx b/idlc/source/astexpression.cxx new file mode 100644 index 000000000..cd5a21656 --- /dev/null +++ b/idlc/source/astexpression.cxx @@ -0,0 +1,1321 @@ +/* -*- 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 +#include +#include +#include + +#include +#include + +#include +#include +#include + +AstExpression::AstExpression(ExprComb c, AstExpression *pExpr1, AstExpression *pExpr2) + : m_combOperator(c) + , m_subExpr1(pExpr1) + , m_subExpr2(pExpr2) +{ +} + +AstExpression::AstExpression(sal_Int32 l) + : m_combOperator(ExprComb::NONE) +{ + m_exprValue.reset( new AstExprValue ); + m_exprValue->et = ET_long; + m_exprValue->u.lval = l; +} + +AstExpression::AstExpression(sal_Int32 l, ExprType et) + : m_combOperator(ExprComb::NONE) +{ + m_exprValue.reset( new AstExprValue ); + m_exprValue->et = et; + m_exprValue->u.lval = l; +} + +AstExpression::AstExpression(sal_Int64 h) + : m_combOperator(ExprComb::NONE) +{ + m_exprValue.reset( new AstExprValue ); + m_exprValue->et = ET_hyper; + m_exprValue->u.hval = h; +} + +AstExpression::AstExpression(sal_uInt64 uh) + : m_combOperator(ExprComb::NONE) +{ + m_exprValue.reset( new AstExprValue ); + m_exprValue->et = ET_uhyper; + m_exprValue->u.uhval = uh; +} + +AstExpression::AstExpression(double d) + : m_combOperator(ExprComb::NONE) +{ + m_exprValue.reset( new AstExprValue ); + m_exprValue->et = ET_double; + m_exprValue->u.dval = d; +} + +AstExpression::AstExpression(OString* scopedName) + : m_combOperator(ExprComb::Symbol) +{ + if (scopedName) + m_xSymbolicName = *scopedName; +} + +AstExpression::~AstExpression() +{ +} + +/* + * Perform the coercion from the given AstExprValue to the requested + * ExprType. Return an AstExprValue if successful, NULL if failed. + * must be done for hyper, uhyper + */ +static bool +coerce_value(AstExprValue *ev, ExprType t) +{ + if (ev == nullptr) + return false; + + switch (t) + { + case ET_short: + switch (ev->et) + { + case ET_short: + return true; + case ET_ushort: + { + if (ev->u.usval > SAL_MAX_INT16) + return false; + auto tmp = static_cast(ev->u.usval); + ev->u.sval = tmp; + ev->et = ET_short; + return true; + } + case ET_long: + { + if (ev->u.lval < SAL_MIN_INT16 || ev->u.lval > SAL_MAX_INT16) + return false; + auto tmp = static_cast(ev->u.lval); + ev->u.sval = tmp; + ev->et = ET_short; + return true; + } + case ET_ulong: + { + if (ev->u.ulval > SAL_MAX_INT16) + return false; + auto tmp = static_cast(ev->u.ulval); + ev->u.sval = tmp; + ev->et = ET_short; + return true; + } + case ET_hyper: + { + if (ev->u.hval < SAL_MIN_INT16 || ev->u.hval > SAL_MAX_INT16) + return false; + auto tmp = static_cast(ev->u.hval); + ev->u.sval = tmp; + ev->et = ET_short; + return true; + } + case ET_uhyper: + { + if (ev->u.uhval > SAL_MAX_INT16) + return false; + auto tmp = static_cast(ev->u.uhval); + ev->u.sval = tmp; + ev->et = ET_short; + return true; + } + case ET_boolean: + { + auto tmp = static_cast(ev->u.bval); + ev->u.sval = tmp; + ev->et = ET_short; + return true; + } + case ET_float: + { + if (!(o3tl::convertsToAtLeast(o3tl::roundAway(ev->u.fval), SAL_MIN_INT16) + && o3tl::convertsToAtMost(o3tl::roundAway(ev->u.fval), SAL_MAX_INT16))) + { + return false; + } + auto tmp = static_cast(ev->u.fval); + ev->u.sval = tmp; + ev->et = ET_short; + return true; + } + case ET_double: + { + if (!(o3tl::convertsToAtLeast(o3tl::roundAway(ev->u.dval), SAL_MIN_INT16) + && o3tl::convertsToAtMost(o3tl::roundAway(ev->u.dval), SAL_MAX_INT16))) + { + return false; + } + auto tmp = static_cast(ev->u.dval); + ev->u.sval = tmp; + ev->et = ET_short; + return true; + } + case ET_byte: + { + auto tmp = static_cast(ev->u.byval); + ev->u.sval = tmp; + ev->et = ET_short; + return true; + } + default: + OSL_ASSERT(false); + return false; + } + case ET_ushort: + switch (ev->et) + { + case ET_short: + { + if (ev->u.sval < 0) + return false; + auto tmp = static_cast(ev->u.sval); + ev->u.usval = tmp; + ev->et = ET_ushort; + return true; + } + case ET_ushort: + return true; + case ET_long: + { + if (ev->u.lval < 0 || ev->u.lval > SAL_MAX_UINT16) + return false; + auto tmp = static_cast(ev->u.lval); + ev->u.usval = tmp; + ev->et = ET_ushort; + return true; + } + case ET_ulong: + { + if (ev->u.ulval > SAL_MAX_UINT16) + return false; + auto tmp = static_cast(ev->u.ulval); + ev->u.usval = tmp; + ev->et = ET_ushort; + return true; + } + case ET_hyper: + { + if (ev->u.hval < 0 || ev->u.hval > SAL_MAX_UINT16) + return false; + auto tmp = static_cast(ev->u.hval); + ev->u.usval = tmp; + ev->et = ET_ushort; + return true; + } + case ET_uhyper: + { + if (ev->u.uhval > SAL_MAX_UINT16) + return false; + auto tmp = static_cast(ev->u.uhval); + ev->u.usval = tmp; + ev->et = ET_ushort; + return true; + } + case ET_boolean: + { + auto tmp = static_cast(ev->u.bval); + ev->u.usval = tmp; + ev->et = ET_short; + return true; + } + case ET_float: + { + if (ev->u.fval < 0.0 + || !o3tl::convertsToAtMost(o3tl::roundAway(ev->u.fval), SAL_MAX_UINT16)) + { + return false; + } + auto tmp = static_cast(ev->u.fval); + ev->u.usval = tmp; + ev->et = ET_short; + return true; + } + case ET_double: + { + if (ev->u.dval < 0.0 + || !o3tl::convertsToAtMost(o3tl::roundAway(ev->u.dval), SAL_MAX_UINT16)) + { + return false; + } + auto tmp = static_cast(ev->u.dval); + ev->u.usval = tmp; + ev->et = ET_short; + return true; + } + case ET_byte: + { + auto tmp = static_cast(ev->u.byval); + ev->u.usval = tmp; + ev->et = ET_ushort; + return true; + } + default: + OSL_ASSERT(false); + return false; + } + case ET_long: + switch (ev->et) + { + case ET_short: + { + auto tmp = static_cast(ev->u.sval); + ev->u.lval = tmp; + ev->et = ET_long; + return true; + } + case ET_ushort: + { + auto tmp = static_cast(ev->u.usval); + ev->u.lval = tmp; + ev->et = ET_long; + return true; + } + case ET_long: + return true; + case ET_ulong: + { + if (ev->u.ulval > SAL_MAX_INT32) + return false; + auto tmp = static_cast(ev->u.ulval); + ev->u.lval = tmp; + ev->et = ET_long; + return true; + } + case ET_hyper: + { + if (ev->u.hval < SAL_MIN_INT32 || ev->u.hval > SAL_MAX_INT32) + return false; + auto tmp = static_cast(ev->u.hval); + ev->u.lval = tmp; + ev->et = ET_long; + return true; + } + case ET_uhyper: + { + if (ev->u.uhval > SAL_MAX_INT32) + return false; + auto tmp = static_cast(ev->u.uhval); + ev->u.lval = tmp; + ev->et = ET_long; + return true; + } + case ET_boolean: + { + auto tmp = static_cast(ev->u.bval); + ev->u.lval = tmp; + ev->et = ET_long; + return true; + } + case ET_float: + { + if (!(o3tl::convertsToAtLeast(o3tl::roundAway(ev->u.fval), SAL_MIN_INT32) + && o3tl::convertsToAtMost(o3tl::roundAway(ev->u.fval), SAL_MAX_INT32))) + { + return false; + } + auto tmp = static_cast(ev->u.fval); + ev->u.lval = tmp; + ev->et = ET_long; + return true; + } + case ET_double: + { + if (!(o3tl::convertsToAtLeast(o3tl::roundAway(ev->u.dval), SAL_MIN_INT32) + && o3tl::convertsToAtMost(o3tl::roundAway(ev->u.dval), SAL_MAX_INT32))) + { + return false; + } + auto tmp = static_cast(ev->u.dval); + ev->u.lval = tmp; + ev->et = ET_long; + return true; + } + case ET_byte: + { + auto tmp = static_cast(ev->u.byval); + ev->u.lval = tmp; + ev->et = ET_long; + return true; + } + default: + OSL_ASSERT(false); + return false; + } + case ET_ulong: + switch (ev->et) + { + case ET_short: + { + if (ev->u.sval < 0) + return false; + auto tmp = static_cast(ev->u.sval); + ev->u.ulval = tmp; + ev->et = ET_ulong; + return true; + } + case ET_ushort: + { + auto tmp = static_cast(ev->u.usval); + ev->u.ulval = tmp; + ev->et = ET_ulong; + return true; + } + case ET_long: + { + if (ev->u.lval < 0) + return false; + auto tmp = static_cast(ev->u.lval); + ev->u.ulval = tmp; + ev->et = ET_ulong; + return true; + } + case ET_ulong: + return true; + case ET_hyper: + { + if (ev->u.hval < 0 || ev->u.hval > SAL_MAX_UINT32) + return false; + auto tmp = static_cast(ev->u.hval); + ev->u.lval = tmp; + ev->et = ET_ulong; + return true; + } + case ET_uhyper: + { + if (ev->u.uhval > SAL_MAX_UINT32) + return false; + auto tmp = static_cast(ev->u.uhval); + ev->u.ulval = tmp; + ev->et = ET_ulong; + return true; + } + case ET_boolean: + { + auto tmp = static_cast(ev->u.bval); + ev->u.ulval = tmp; + ev->et = ET_ulong; + return true; + } + case ET_float: + { + if (ev->u.fval < 0.0 + || !o3tl::convertsToAtMost(o3tl::roundAway(ev->u.fval), SAL_MAX_UINT32)) + { + return false; + } + auto tmp = static_cast(ev->u.fval); + ev->u.ulval = tmp; + ev->et = ET_ulong; + return true; + } + case ET_double: + { + if (ev->u.dval < 0.0 + || !o3tl::convertsToAtMost(o3tl::roundAway(ev->u.dval), SAL_MAX_UINT32)) + { + return false; + } + auto tmp = static_cast(ev->u.dval); + ev->u.ulval = tmp; + ev->et = ET_ulong; + return true; + } + case ET_byte: + { + auto tmp = static_cast(ev->u.byval); + ev->u.ulval = tmp; + ev->et = ET_ulong; + return true; + } + default: + OSL_ASSERT(false); + return false; + } + case ET_hyper: + switch (ev->et) + { + case ET_short: + { + auto tmp = static_cast(ev->u.sval); + ev->u.hval = tmp; + ev->et = ET_hyper; + return true; + } + case ET_ushort: + { + auto tmp = static_cast(ev->u.usval); + ev->u.hval = tmp; + ev->et = ET_hyper; + return true; + } + case ET_long: + { + auto tmp = static_cast(ev->u.lval); + ev->u.hval = tmp; + ev->et = ET_hyper; + return true; + } + case ET_ulong: + { + auto tmp = static_cast(ev->u.ulval); + ev->u.hval = tmp; + ev->et = ET_hyper; + return true; + } + case ET_hyper: + return true; + case ET_uhyper: + { + if (ev->u.uhval > SAL_MAX_INT64) + return false; + auto tmp = static_cast(ev->u.uhval); + ev->u.hval = tmp; + ev->et = ET_long; + return true; + } + case ET_boolean: + { + auto tmp = static_cast(ev->u.bval); + ev->u.hval = tmp; + ev->et = ET_hyper; + return true; + } + case ET_float: + { + if (!(o3tl::convertsToAtLeast(o3tl::roundAway(ev->u.fval), SAL_MIN_INT64) + && o3tl::convertsToAtMost(o3tl::roundAway(ev->u.fval), SAL_MAX_INT64))) + { + return false; + } + auto tmp = static_cast(ev->u.fval); + ev->u.hval = tmp; + ev->et = ET_hyper; + return true; + } + case ET_double: + { + if (!(o3tl::convertsToAtLeast(o3tl::roundAway(ev->u.dval), SAL_MIN_INT64) + && o3tl::convertsToAtMost(o3tl::roundAway(ev->u.dval), SAL_MAX_INT64))) + { + return false; + } + auto tmp = static_cast(ev->u.dval); + ev->u.hval = tmp; + ev->et = ET_hyper; + return true; + } + case ET_byte: + { + auto tmp = static_cast(ev->u.byval); + ev->u.hval = tmp; + ev->et = ET_hyper; + return true; + } + default: + OSL_ASSERT(false); + return false; + } + case ET_uhyper: + switch (ev->et) + { + case ET_short: + { + if (ev->u.sval < 0) + return false; + auto tmp = static_cast(ev->u.sval); + ev->u.uhval = tmp; + ev->et = ET_uhyper; + return true; + } + case ET_ushort: + { + auto tmp = static_cast(ev->u.usval); + ev->u.uhval = tmp; + ev->et = ET_uhyper; + return true; + } + case ET_long: + { + if (ev->u.lval < 0) + return false; + auto tmp = static_cast(ev->u.lval); + ev->u.uhval = tmp; + ev->et = ET_uhyper; + return true; + } + case ET_ulong: + { + auto tmp = static_cast(ev->u.ulval); + ev->u.uhval = tmp; + ev->et = ET_uhyper; + return true; + } + case ET_hyper: + { + if (ev->u.hval < 0) + return false; + auto tmp = static_cast(ev->u.hval); + ev->u.uhval = tmp; + ev->et = ET_uhyper; + return true; + } + case ET_uhyper: + return true; + case ET_boolean: + { + auto tmp = static_cast(ev->u.bval); + ev->u.uhval = tmp; + ev->et = ET_uhyper; + return true; + } + case ET_float: + { + if (ev->u.fval < 0.0 + || !o3tl::convertsToAtMost(o3tl::roundAway(ev->u.fval), SAL_MAX_UINT64)) + { + return false; + } + auto tmp = static_cast(ev->u.fval); + ev->u.uhval = tmp; + ev->et = ET_uhyper; + return true; + } + case ET_double: + { + if (ev->u.dval < 0.0 + || !o3tl::convertsToAtMost(o3tl::roundAway(ev->u.dval), SAL_MAX_UINT64)) + { + return false; + } + auto tmp = static_cast(ev->u.dval); + ev->u.uhval = tmp; + ev->et = ET_uhyper; + return true; + } + case ET_byte: + { + auto tmp = static_cast(ev->u.byval); + ev->u.uhval = tmp; + ev->et = ET_uhyper; + return true; + } + default: + OSL_ASSERT(false); + return false; + } + case ET_boolean: + switch (ev->et) + { + case ET_short: + ev->u.bval = ev->u.sval != 0; + ev->et = ET_boolean; + return true; + case ET_ushort: + ev->u.bval = ev->u.usval != 0; + ev->et = ET_boolean; + return true; + case ET_long: + ev->u.bval = ev->u.lval != 0; + ev->et = ET_boolean; + return true; + case ET_ulong: + ev->u.bval = ev->u.ulval != 0; + ev->et = ET_boolean; + return true; + case ET_hyper: + ev->u.bval = ev->u.hval != 0; + ev->et = ET_boolean; + return true; + case ET_uhyper: + ev->u.bval = ev->u.uhval != 0; + ev->et = ET_boolean; + return true; + case ET_boolean: + return true; + case ET_float: + ev->u.bval = ev->u.fval != 0.0; + ev->et = ET_boolean; + return true; + case ET_double: + ev->u.bval = ev->u.dval != 0.0; + ev->et = ET_boolean; + return true; + case ET_byte: + ev->u.bval = ev->u.byval != 0; + ev->et = ET_boolean; + return true; + default: + OSL_ASSERT(false); + return false; + } + case ET_float: + switch (ev->et) + { + case ET_short: + { + auto tmp = static_cast(ev->u.sval); + ev->u.fval = tmp; + ev->et = ET_float; + return true; + } + case ET_ushort: + { + auto tmp = static_cast(ev->u.usval); + ev->u.fval = tmp; + ev->et = ET_float; + return true; + } + case ET_long: + { + auto tmp = static_cast(ev->u.lval); + ev->u.fval = tmp; + ev->et = ET_float; + return true; + } + case ET_ulong: + { + auto tmp = static_cast(ev->u.ulval); + ev->u.fval = tmp; + ev->et = ET_float; + return true; + } + case ET_hyper: + { + auto tmp = static_cast(ev->u.hval); + ev->u.fval = tmp; + ev->et = ET_float; + return true; + } + case ET_uhyper: + { + if (static_cast(ev->u.ulval) > FLT_MAX) + return false; + auto tmp = static_cast(ev->u.ulval); + ev->u.fval = tmp; + ev->et = ET_float; + return true; + } + case ET_boolean: + ev->u.fval = ev->u.bval ? 1.0f : 0.0f; + ev->et = ET_float; + return true; + case ET_float: + return true; + case ET_double: + { + if (static_cast(ev->u.dval) > FLT_MAX || static_cast(ev->u.dval) < -FLT_MAX) + return false; + auto tmp = static_cast(ev->u.dval); + ev->u.fval = tmp; + ev->et = ET_float; + return true; + } + case ET_byte: + { + auto tmp = static_cast(ev->u.byval); + ev->u.fval = tmp; + ev->et = ET_float; + return true; + } + default: + OSL_ASSERT(false); + return false; + } + case ET_double: + switch (ev->et) + { + case ET_short: + { + auto tmp = static_cast(ev->u.sval); + ev->u.dval = tmp; + ev->et = ET_double; + return true; + } + case ET_ushort: + { + auto tmp = static_cast(ev->u.usval); + ev->u.dval = tmp; + ev->et = ET_double; + return true; + } + case ET_long: + { + auto tmp = static_cast(ev->u.lval); + ev->u.dval = tmp; + ev->et = ET_double; + return true; + } + case ET_ulong: + { + auto tmp = static_cast(ev->u.ulval); + ev->u.dval = tmp; + ev->et = ET_double; + return true; + } + case ET_hyper: + { + auto tmp = static_cast(ev->u.hval); + ev->u.dval = tmp; + ev->et = ET_double; + return true; + } + case ET_uhyper: + { + if (ev->u.dval > FLT_MAX || ev->u.dval < -FLT_MAX) + return false; + auto tmp = static_cast(ev->u.ulval); + ev->u.dval = tmp; + ev->et = ET_double; + return true; + } + case ET_boolean: + ev->u.dval = ev->u.bval ? 1.0 : 0.0; + ev->et = ET_double; + return true; + case ET_float: + { + auto tmp = static_cast(ev->u.fval); + ev->u.dval = tmp; + ev->et = ET_double; + return true; + } + case ET_double: + return true; + case ET_byte: + { + auto tmp = static_cast(ev->u.byval); + ev->u.dval = tmp; + ev->et = ET_double; + return true; + } + default: + OSL_ASSERT(false); + return false; + } + case ET_byte: + switch (ev->et) + { + case ET_short: + { + if (ev->u.sval < SAL_MIN_INT8 || ev->u.sval > SAL_MAX_UINT8) + return false; + auto tmp = static_cast(ev->u.sval); + ev->u.byval = tmp; + ev->et = ET_byte; + return true; + } + case ET_ushort: + { + if (ev->u.usval > SAL_MAX_UINT8) + return false; + auto tmp = static_cast(ev->u.usval); + ev->u.byval = tmp; + ev->et = ET_byte; + return true; + } + case ET_long: + { + if (ev->u.lval < SAL_MIN_INT8 || ev->u.lval > SAL_MAX_UINT8) + return false; + auto tmp = static_cast(ev->u.lval); + ev->u.byval = tmp; + ev->et = ET_byte; + return true; + } + case ET_ulong: + { + if (ev->u.ulval > SAL_MAX_UINT8) + return false; + auto tmp = static_cast(ev->u.ulval); + ev->u.byval = tmp; + ev->et = ET_byte; + return true; + } + case ET_hyper: + { + if (ev->u.hval < SAL_MIN_INT8 || ev->u.hval > SAL_MAX_UINT8) + return false; + auto tmp = static_cast(ev->u.hval); + ev->u.byval = tmp; + ev->et = ET_byte; + return true; + } + case ET_uhyper: + { + if (ev->u.uhval > SAL_MAX_UINT8) + return false; + auto tmp = static_cast(ev->u.uhval); + ev->u.byval = tmp; + ev->et = ET_byte; + return true; + } + case ET_boolean: + ev->u.byval = ev->u.bval ? 1 : 0; + ev->et = ET_byte; + return true; + case ET_float: + { + if (!(o3tl::convertsToAtLeast(o3tl::roundAway(ev->u.fval), SAL_MIN_INT8) + && o3tl::convertsToAtMost(o3tl::roundAway(ev->u.fval), SAL_MAX_UINT8))) + { + return false; + } + auto tmp = static_cast(static_cast(ev->u.fval)); + ev->u.byval = tmp; + ev->et = ET_byte; + return true; + } + case ET_double: + { + if (!(o3tl::convertsToAtLeast(o3tl::roundAway(ev->u.dval), SAL_MIN_INT8) + && o3tl::convertsToAtMost(o3tl::roundAway(ev->u.dval), SAL_MAX_UINT8))) + { + return false; + } + auto tmp = static_cast(static_cast(ev->u.dval)); + ev->u.byval = tmp; + ev->et = ET_byte; + return true; + } + case ET_byte: + return true; + default: + OSL_ASSERT(false); + return false; + } + default: + OSL_ASSERT(false); + return false; + } +} + +bool AstExpression::coerce(ExprType t) +{ + /* + * Is it already of the right type? + */ + if (m_exprValue != nullptr && m_exprValue->et == t) + return true; + /* + * OK, must coerce + * + * First, evaluate it, then try to coerce result type + * If already evaluated, return the result + */ + evaluate(); + if (m_exprValue == nullptr) + return false; + + if (!coerce_value(m_exprValue.get(), t)) + m_exprValue.reset(); + + return m_exprValue != nullptr; +} + +bool AstExpression::compareLong(AstExpression *pExpr) +{ + bool bRet = false; + if (m_combOperator != pExpr->m_combOperator) + return bRet; + evaluate(); + pExpr->evaluate(); + if (m_exprValue == nullptr || pExpr->getExprValue() == nullptr) + return bRet; + if (m_exprValue->et != pExpr->getExprValue()->et) + return bRet; + switch (m_exprValue->et) + { + case ET_long: + bRet = m_exprValue->u.lval == pExpr->getExprValue()->u.lval; + break; + default: + OSL_ASSERT(false); + bRet = false; + break; + } + return bRet; +} + +void AstExpression::evaluate() +{ + /* + * Already evaluated? + */ + if ( m_exprValue != nullptr ) + return; + /* + * OK, must evaluate operator + */ + switch (m_combOperator) + { + case ExprComb::Add: + case ExprComb::Minus: + case ExprComb::Mul: + case ExprComb::Div: + case ExprComb::Mod: + m_exprValue = eval_bin_op(); + break; + case ExprComb::Or: + case ExprComb::Xor: + case ExprComb::And: + case ExprComb::Left: + case ExprComb::Right: + m_exprValue = eval_bit_op(); + break; + case ExprComb::UPlus: + case ExprComb::UMinus: + m_exprValue = eval_un_op(); + break; + case ExprComb::Symbol: + m_exprValue = eval_symbol(); + break; + case ExprComb::NONE: + break; + } +} + +std::unique_ptr AstExpression::eval_bin_op() +{ + ExprType eType = ET_double; + + if ( m_combOperator == ExprComb::Mod ) + eType = ET_hyper; + + if (m_subExpr1 == nullptr || m_subExpr2 == nullptr) + return nullptr; + m_subExpr1->evaluate(); + if (m_subExpr1->getExprValue() == nullptr) + return nullptr; + if (!m_subExpr1->coerce(eType)) + return nullptr; + m_subExpr2->evaluate(); + if (m_subExpr2->getExprValue() == nullptr) + return nullptr; + if (!m_subExpr2->coerce(eType)) + return nullptr; + + std::unique_ptr< AstExprValue > retval(new AstExprValue); + retval->et = eType; + + switch (m_combOperator) + { + case ExprComb::Mod: + if (m_subExpr2->getExprValue()->u.hval == 0) + return nullptr; + retval->u.hval = m_subExpr1->getExprValue()->u.hval % m_subExpr2->getExprValue()->u.hval; + break; + case ExprComb::Add: + retval->u.dval = m_subExpr1->getExprValue()->u.dval + m_subExpr2->getExprValue()->u.dval; + break; + case ExprComb::Minus: + retval->u.dval = m_subExpr1->getExprValue()->u.dval - m_subExpr2->getExprValue()->u.dval; + break; + case ExprComb::Mul: + retval->u.dval = m_subExpr1->getExprValue()->u.dval * m_subExpr2->getExprValue()->u.dval; + break; + case ExprComb::Div: + if (m_subExpr2->getExprValue()->u.dval == 0.0) + return nullptr; + retval->u.dval = m_subExpr1->getExprValue()->u.dval / m_subExpr2->getExprValue()->u.dval; + break; + default: + return nullptr; + } + + return retval; +} + +std::unique_ptr AstExpression::eval_bit_op() +{ + if (m_subExpr1 == nullptr || m_subExpr2 == nullptr) + return nullptr; + m_subExpr1->evaluate(); + if (m_subExpr1->getExprValue() == nullptr) + return nullptr; + if (!m_subExpr1->coerce(ET_long)) + return nullptr; + m_subExpr2->evaluate(); + if (m_subExpr2->getExprValue() == nullptr) + return nullptr; + if (!m_subExpr2->coerce(ET_long)) + return nullptr; + + std::unique_ptr< AstExprValue > retval(new AstExprValue); + retval->et = ET_long; + + switch (m_combOperator) + { + case ExprComb::Or: + retval->u.lval = m_subExpr1->getExprValue()->u.lval | m_subExpr2->getExprValue()->u.lval; + break; + case ExprComb::Xor: + retval->u.lval = m_subExpr1->getExprValue()->u.lval ^ m_subExpr2->getExprValue()->u.lval; + break; + case ExprComb::And: + retval->u.lval = m_subExpr1->getExprValue()->u.lval & m_subExpr2->getExprValue()->u.lval; + break; + case ExprComb::Left: + retval->u.lval = m_subExpr1->getExprValue()->u.lval << m_subExpr2->getExprValue()->u.lval; + break; + case ExprComb::Right: + retval->u.lval = m_subExpr1->getExprValue()->u.lval >> m_subExpr2->getExprValue()->u.lval; + break; + default: + return nullptr; + } + + return retval; +} + +std::unique_ptr AstExpression::eval_un_op() +{ + if (m_subExpr1 == nullptr) + return nullptr; + m_subExpr1->evaluate(); + if (m_subExpr1->getExprValue() == nullptr) + return nullptr; + if (!m_subExpr1->coerce(ET_double)) + return nullptr; + + std::unique_ptr< AstExprValue > retval(new AstExprValue); + retval->et = ET_double; + + switch (m_combOperator) + { + case ExprComb::UPlus: + retval->u.lval = m_subExpr1->getExprValue()->u.lval; + break; + case ExprComb::UMinus: + retval->u.lval = -(m_subExpr1->getExprValue()->u.lval); + break; + default: + return nullptr; + } + + return retval; +} + +std::unique_ptr AstExpression::eval_symbol() +{ + AstScope *pScope = nullptr; + AstDeclaration *pDecl; + AstConstant *pConst; + + /* + * Is there a symbol stored? + */ + if (!m_xSymbolicName) + { + ErrorHandler::evalError(this); + return nullptr; + } + /* + * Get current scope for lookup + */ + if (idlc()->scopes()->depth() > 0) + pScope = idlc()->scopes()->topNonNull(); + if ( !pScope ) + { + ErrorHandler::lookupError(*m_xSymbolicName); + return nullptr; + } + /* + * Do lookup + */ + pDecl = pScope->lookupByName(*m_xSymbolicName); + if (pDecl == nullptr) + { + ErrorHandler::lookupError(*m_xSymbolicName); + return nullptr; + } + /* + * Is it a constant? + */ + if (pDecl->getNodeType() != NT_const && + pDecl->getNodeType() != NT_enum_val) + { + ErrorHandler::constantExpected(pDecl, *m_xSymbolicName); + return nullptr; + } + if (!ErrorHandler::checkPublished(pDecl)) + { + return nullptr; + } + /* + * OK, now evaluate the constant we just got, to produce its value + */ + pConst = static_cast< AstConstant* >(pDecl); + pConst->getConstValue()->evaluate(); + auto const val = pConst->getConstValue()->getExprValue(); + return val == nullptr ? nullptr : std::make_unique(*val); +} + +OString AstExpression::toString() +{ + OString exprStr; + if ( m_combOperator == ExprComb::Symbol ) + return m_xSymbolicName ? *m_xSymbolicName : OString(""); + + if ( m_exprValue ) + { + switch (m_exprValue->et) + { + case ET_short: + return OString::number(m_exprValue->u.sval); + case ET_ushort: + return OString::number(m_exprValue->u.usval); + case ET_long: + return OString::number(m_exprValue->u.lval); + case ET_ulong: + return OString::number(m_exprValue->u.ulval); + case ET_hyper: + return OString::number(m_exprValue->u.hval); + case ET_uhyper: + return OString::number(m_exprValue->u.uhval); + case ET_float: + return OString::number(m_exprValue->u.fval); + case ET_double: + return OString::number(m_exprValue->u.dval); + case ET_byte: + return OString::number(m_exprValue->u.byval); + case ET_boolean: + if ( m_exprValue->u.lval == 0) + return "FALSE"; + else + return "TRUE"; + default: + OSL_ASSERT(false); + return OString(); + } + } + + switch (m_combOperator) + { + case ExprComb::UPlus: + exprStr += "+"; + break; + case ExprComb::UMinus: + exprStr += "-"; + break; + default: + break; + } + if ( m_subExpr1 ) + exprStr += m_subExpr1->toString(); + switch (m_combOperator) + { + case ExprComb::Add: + exprStr += " + "; + break; + case ExprComb::Minus: + exprStr += " - "; + break; + case ExprComb::Mul: + exprStr += " * "; + break; + case ExprComb::Div: + exprStr += " / "; + break; + case ExprComb::Mod: + exprStr += " % "; + break; + case ExprComb::Or: + exprStr += " | "; + break; + case ExprComb::Xor: + exprStr += " ^ "; + break; + case ExprComb::And: + exprStr += " & "; + break; + case ExprComb::Left: + exprStr += " << "; + break; + case ExprComb::Right: + exprStr += " >> "; + break; + default: + break; + } + + if ( m_subExpr2 ) + exprStr += m_subExpr2->toString(); + + return exprStr; +} + +// Convert the type of an AST_Expression to a char * +const char* exprTypeToString(ExprType t) +{ + switch (t) + { + case ET_short: + return "short"; + case ET_ushort: + return "unsigned short"; + case ET_long: + return "long"; + case ET_ulong: + return "unsigned long"; + case ET_hyper: + return "hyper"; + case ET_uhyper: + return "unsigned hyper"; + case ET_float: + return "float"; + case ET_double: + return "double"; + case ET_char: + return "char"; + case ET_byte: + return "byte"; + case ET_boolean: + return "boolean"; + case ET_string: + return "string"; + case ET_any: + return "any"; + case ET_type: + return "type"; + case ET_void: + return "void"; + case ET_none: + return "none"; + } + + return "unknown"; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/idlc/source/astinterface.cxx b/idlc/source/astinterface.cxx new file mode 100644 index 000000000..a5f2ed21b --- /dev/null +++ b/idlc/source/astinterface.cxx @@ -0,0 +1,399 @@ +/* -*- 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 +#include +#include +#include + +#include +#include + +#include + +AstInterface::AstInterface(const OString& name, + AstInterface const * pInherits, + AstScope* pScope) + : AstType(NT_interface, name, pScope) + , AstScope(NT_interface) + , m_mandatoryInterfaces(0) + , m_bIsDefined(false) + , m_bSingleInheritance(pInherits != nullptr) +{ + if (pInherits != nullptr) { + addInheritedInterface(pInherits, false, OUString()); + } +} + +AstInterface::~AstInterface() +{ +} + +AstInterface::DoubleDeclarations AstInterface::checkInheritedInterfaceClashes( + AstInterface const * ifc, bool optional) const +{ + DoubleDeclarations doubleDecls; + std::set< OString > seen; + checkInheritedInterfaceClashes( + doubleDecls, seen, ifc, true, optional, optional); + return doubleDecls; +} + +void AstInterface::addInheritedInterface( + AstType const * ifc, bool optional, OUString const & documentation) +{ + m_inheritedInterfaces.emplace_back(ifc, optional, documentation); + if (!optional) { + ++m_mandatoryInterfaces; + } + AstInterface const * resolved = resolveInterfaceTypedefs(ifc); + addVisibleInterface(resolved, true, optional); + if (optional) { + addOptionalVisibleMembers(resolved); + } +} + +AstInterface::DoubleMemberDeclarations AstInterface::checkMemberClashes( + AstDeclaration const * member) const +{ + DoubleMemberDeclarations doubleMembers; + checkMemberClashes(doubleMembers, member, true); + return doubleMembers; +} + +void AstInterface::addMember(AstDeclaration /*TODO: const*/ * member) { + addDeclaration(member); + m_visibleMembers.emplace(member->getLocalName(), VisibleMember(member)); +} + +void AstInterface::forwardDefined(AstInterface const & def) +{ + setImported(def.isImported()); + setInMainfile(def.isInMainfile()); + setLineNumber(def.getLineNumber()); + setFileName(def.getFileName()); + setDocumentation(def.getDocumentation()); + m_inheritedInterfaces = def.m_inheritedInterfaces; + m_mandatoryInterfaces = def.m_mandatoryInterfaces; + m_bIsDefined = true; +} + +bool AstInterface::dump(RegistryKey& rKey) +{ + if ( !isDefined() ) + return true; + + RegistryKey localKey; + if (rKey.createKey( OStringToOUString(getFullName(), RTL_TEXTENCODING_UTF8 ), localKey) != RegError::NO_ERROR) + { + fprintf(stderr, "%s: warning, could not create key '%s' in '%s'\n", + idlc()->getOptions()->getProgramName().getStr(), + getFullName().getStr(), OUStringToOString(rKey.getRegistryName(), RTL_TEXTENCODING_UTF8).getStr()); + return false; + } + + if (m_mandatoryInterfaces > SAL_MAX_UINT16 + || m_inheritedInterfaces.size() - m_mandatoryInterfaces + > SAL_MAX_UINT16) + { + fprintf( + stderr, "%s: interface %s has too many direct base interfaces\n", + idlc()->getOptions()->getProgramName().getStr(), + getScopedName().getStr()); + return false; + } + sal_uInt16 nBaseTypes = static_cast< sal_uInt16 >(m_mandatoryInterfaces); + sal_uInt16 nAttributes = 0; + sal_uInt16 nMethods = 0; + sal_uInt16 nReferences = static_cast< sal_uInt16 >( + m_inheritedInterfaces.size() - m_mandatoryInterfaces); + typereg_Version version + = (nBaseTypes <= 1 && nReferences == 0 && !m_bPublished + ? TYPEREG_VERSION_0 : TYPEREG_VERSION_1); + for (DeclList::const_iterator i(getIteratorBegin()); i != getIteratorEnd(); + ++i) + { + switch ((*i)->getNodeType()) { + case NT_attribute: + { + if (!increment(&nAttributes, "attributes")) { + return false; + } + AstAttribute * attr = static_cast(*i); + if (attr->isBound()) { + version = TYPEREG_VERSION_1; + } + DeclList::size_type getCount = attr->getGetExceptionCount(); + if (getCount > SAL_MAX_UINT16) { + fprintf( + stderr, + ("%s: raises clause of getter for attribute %s of" + " interface %s is too long\n"), + idlc()->getOptions()->getProgramName().getStr(), + (*i)->getLocalName().getStr(), + getScopedName().getStr()); + return false; + } + if (getCount > 0) { + version = TYPEREG_VERSION_1; + if (!increment(&nMethods, "attributes")) { + return false; + } + } + DeclList::size_type setCount = attr->getSetExceptionCount(); + if (setCount > SAL_MAX_UINT16) { + fprintf( + stderr, + ("%s: raises clause of setter for attribute %s of" + " interface %s is too long\n"), + idlc()->getOptions()->getProgramName().getStr(), + (*i)->getLocalName().getStr(), + getScopedName().getStr()); + return false; + } + if (setCount > 0) { + version = TYPEREG_VERSION_1; + if (!increment(&nMethods, "attributes")) { + return false; + } + } + break; + } + + case NT_operation: + if (!increment(&nMethods, "methods")) { + return false; + } + break; + + default: + OSL_ASSERT(false); + break; + } + } + + typereg::Writer aBlob( + version, getDocumentation(), "", RT_TYPE_INTERFACE, m_bPublished, + OStringToOUString(getRelativName(), RTL_TEXTENCODING_UTF8), nBaseTypes, + nAttributes, nMethods, nReferences); + + sal_uInt16 superTypeIndex = 0; + sal_uInt16 referenceIndex = 0; + for (auto const& elem : m_inheritedInterfaces) + { + if (elem.isOptional()) { + aBlob.setReferenceData( + referenceIndex++, elem.getDocumentation(), RTReferenceType::SUPPORTS, + RTFieldAccess::OPTIONAL, + OStringToOUString( + elem.getInterface()->getRelativName(), + RTL_TEXTENCODING_UTF8)); + } else { + aBlob.setSuperTypeName( + superTypeIndex++, + OStringToOUString( + elem.getInterface()->getRelativName(), + RTL_TEXTENCODING_UTF8)); + } + } + + sal_uInt16 attributeIndex = 0; + sal_uInt16 methodIndex = 0; + for (DeclList::const_iterator i(getIteratorBegin()); i != getIteratorEnd(); + ++i) + { + switch ((*i)->getNodeType()) { + case NT_attribute: + static_cast(*i)->dumpBlob( + aBlob, attributeIndex++, &methodIndex); + break; + + case NT_operation: + static_cast(*i)->dumpBlob(aBlob, methodIndex++); + break; + + default: + OSL_ASSERT(false); + break; + } + } + + sal_uInt32 aBlobSize; + void const * pBlob = aBlob.getBlob(&aBlobSize); + + if (localKey.setValue("", RegValueType::BINARY, const_cast(pBlob), aBlobSize) != RegError::NO_ERROR) + { + fprintf(stderr, "%s: warning, could not set value of key \"%s\" in %s\n", + idlc()->getOptions()->getProgramName().getStr(), + getFullName().getStr(), OUStringToOString(localKey.getRegistryName(), RTL_TEXTENCODING_UTF8).getStr()); + return false; + } + + return true; +} + +void AstInterface::checkInheritedInterfaceClashes( + DoubleDeclarations & doubleDeclarations, + std::set< OString > & seenInterfaces, AstInterface const * ifc, + bool direct, bool optional, bool mainOptional) const +{ + if (!(direct || optional + || seenInterfaces.insert(ifc->getScopedName()).second)) + return; + + VisibleInterfaces::const_iterator visible( + m_visibleInterfaces.find(ifc->getScopedName())); + if (visible != m_visibleInterfaces.end()) { + switch (visible->second) { + case INTERFACE_INDIRECT_OPTIONAL: + if (direct && optional) { + doubleDeclarations.interfaces.push_back(ifc); + return; + } + break; + + case INTERFACE_DIRECT_OPTIONAL: + if (direct || !mainOptional) { + doubleDeclarations.interfaces.push_back(ifc); + } + return; + + case INTERFACE_INDIRECT_MANDATORY: + if (direct) { + doubleDeclarations.interfaces.push_back(ifc); + } + return; + + case INTERFACE_DIRECT_MANDATORY: + if (direct || (!optional && !mainOptional)) { + doubleDeclarations.interfaces.push_back(ifc); + } + return; + } + } + if (!(direct || !optional)) + return; + + for (DeclList::const_iterator i(ifc->getIteratorBegin()); + i != ifc->getIteratorEnd(); ++i) + { + checkMemberClashes( + doubleDeclarations.members, *i, !mainOptional); + } + for (auto const& elem : ifc->m_inheritedInterfaces) + { + checkInheritedInterfaceClashes( + doubleDeclarations, seenInterfaces, elem.getResolved(), + false, elem.isOptional(), mainOptional); + } +} + +void AstInterface::checkMemberClashes( + DoubleMemberDeclarations & doubleMembers, AstDeclaration const * member, + bool checkOptional) const +{ + VisibleMembers::const_iterator i( + m_visibleMembers.find(member->getLocalName())); + if (i == m_visibleMembers.end()) + return; + + if (i->second.mandatory != nullptr) { + if (i->second.mandatory->getScopedName() != member->getScopedName()) + { + DoubleMemberDeclaration d; + d.first = i->second.mandatory; + d.second = member; + doubleMembers.push_back(d); + } + } else if (checkOptional) { + for (auto const& elem : i->second.optionals) + { + if (elem.second->getScopedName() != member->getScopedName()) { + DoubleMemberDeclaration d; + d.first = elem.second; + d.second = member; + doubleMembers.push_back(d); + } + } + } +} + +void AstInterface::addVisibleInterface( + AstInterface const * ifc, bool direct, bool optional) +{ + InterfaceKind kind = optional + ? direct ? INTERFACE_DIRECT_OPTIONAL : INTERFACE_INDIRECT_OPTIONAL + : direct ? INTERFACE_DIRECT_MANDATORY : INTERFACE_INDIRECT_MANDATORY; + std::pair< VisibleInterfaces::iterator, bool > result( + m_visibleInterfaces.emplace(ifc->getScopedName(), kind)); + bool seen = !result.second + && result.first->second >= INTERFACE_INDIRECT_MANDATORY; + if (!result.second && kind > result.first->second) { + result.first->second = kind; + } + if (optional || seen) + return; + + for (DeclList::const_iterator i(ifc->getIteratorBegin()); + i != ifc->getIteratorEnd(); ++i) + { + m_visibleMembers.emplace( + (*i)->getLocalName(), VisibleMember(*i)); + } + for (auto const& elem : ifc->m_inheritedInterfaces) + { + addVisibleInterface(elem.getResolved(), false, elem.isOptional()); + } +} + +void AstInterface::addOptionalVisibleMembers(AstInterface const * ifc) { + for (DeclList::const_iterator i(ifc->getIteratorBegin()); + i != ifc->getIteratorEnd(); ++i) + { + VisibleMembers::iterator visible( + m_visibleMembers.find((*i)->getLocalName())); + if (visible == m_visibleMembers.end()) { + visible = m_visibleMembers.emplace( + (*i)->getLocalName(), VisibleMember()).first; + } + if (visible->second.mandatory == nullptr) { + visible->second.optionals.emplace(ifc->getScopedName(), *i); + } + } + for (auto const& elem : ifc->m_inheritedInterfaces) + { + if (!elem.isOptional()) { + addOptionalVisibleMembers(elem.getResolved()); + } + } +} + +bool AstInterface::increment(sal_uInt16 * counter, char const * sort) const { + if (*counter == SAL_MAX_UINT16) { + fprintf( + stderr, "%s: interface %s has too many direct %s\n", + idlc()->getOptions()->getProgramName().getStr(), + getScopedName().getStr(), sort); + return false; + } + ++*counter; + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/idlc/source/astoperation.cxx b/idlc/source/astoperation.cxx new file mode 100644 index 000000000..4dea37576 --- /dev/null +++ b/idlc/source/astoperation.cxx @@ -0,0 +1,115 @@ +/* -*- 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 +#include +#include +#include +#include + +#include + +void AstOperation::setExceptions(DeclList const * pExceptions) +{ + if (pExceptions != nullptr) { + m_exceptions = *pExceptions; + } +} + +bool AstOperation::isVariadic() const { + DeclList::const_iterator i(getIteratorEnd()); + return i != getIteratorBegin() + && static_cast< AstParameter const * >(*(--i))->isRest(); +} + +void AstOperation::dumpBlob(typereg::Writer & rBlob, sal_uInt16 index) +{ + sal_uInt16 nParam = getNodeCount(NT_parameter); + sal_uInt16 nExcep = static_cast(m_exceptions.size()); + + OUString returnTypeName; + if (m_pReturnType == nullptr) { + returnTypeName = "void"; + } else { + returnTypeName = OStringToOUString( + m_pReturnType->getRelativName(), RTL_TEXTENCODING_UTF8); + } + rBlob.setMethodData( + index, getDocumentation(), RTMethodMode::TWOWAY, + OStringToOUString(getLocalName(), RTL_TEXTENCODING_UTF8), + returnTypeName, nParam, nExcep); + + if ( nParam ) + { + DeclList::const_iterator iter = getIteratorBegin(); + DeclList::const_iterator end = getIteratorEnd(); + RTParamMode paramMode; + sal_uInt16 paramIndex = 0; + while ( iter != end ) + { + AstDeclaration* pDecl = *iter; + if ( pDecl->getNodeType() == NT_parameter ) + { + AstParameter* pParam = static_cast(pDecl); + switch (pParam->getDirection()) + { + case DIR_IN : + paramMode = RT_PARAM_IN; + break; + case DIR_OUT : + paramMode = RT_PARAM_OUT; + break; + case DIR_INOUT : + paramMode = RT_PARAM_INOUT; + break; + default: + paramMode = RT_PARAM_INVALID; + break; + } + if (pParam->isRest()) { + paramMode = static_cast< RTParamMode >( + paramMode | RT_PARAM_REST); + } + + rBlob.setMethodParameterData( + index, paramIndex++, paramMode, + OStringToOUString( + pDecl->getLocalName(), RTL_TEXTENCODING_UTF8), + OStringToOUString( + pParam->getType()->getRelativName(), + RTL_TEXTENCODING_UTF8)); + } + ++iter; + } + } + + if ( nExcep ) + { + sal_uInt16 exceptIndex = 0; + for (auto const& exception : m_exceptions) + { + rBlob.setMethodExceptionTypeName( + index, exceptIndex++, + OStringToOUString( + exception->getRelativName(), RTL_TEXTENCODING_UTF8)); + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/idlc/source/astscope.cxx b/idlc/source/astscope.cxx new file mode 100644 index 000000000..26ebcdb40 --- /dev/null +++ b/idlc/source/astscope.cxx @@ -0,0 +1,313 @@ +/* -*- 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 + +#include + +#include +#include +#include +#include +#include + + +static bool isGlobal(const OString& scopedName) +{ + return scopedName.isEmpty() || scopedName.startsWith(":"); +} + +AstScope::AstScope(NodeType nodeType) + : m_nodeType(nodeType) +{ + +} + +AstScope::~AstScope() +{ + +} + +AstDeclaration* AstScope::addDeclaration(AstDeclaration* pDecl) +{ + AstDeclaration* pDeclaration = nullptr; + + if ((pDeclaration = lookupForAdd(pDecl)) != nullptr) + { + if ( pDecl->hasAncestor(pDeclaration) ) + { + ErrorHandler::error2(ErrorCode::RedefScope, pDecl, pDeclaration); + return nullptr; + } + if ( (pDecl->getNodeType() == pDeclaration->getNodeType()) && + (pDecl->getNodeType() == NT_sequence + || pDecl->getNodeType() == NT_instantiated_struct) ) + { + return pDeclaration; + } + if ( (pDeclaration->getNodeType() == NT_interface) + && (pDecl->getNodeType() == NT_interface) + && !(static_cast(pDeclaration)->isDefined()) ) + { + m_declarations.push_back(pDecl); + return pDecl; + } + if ( (NT_service == m_nodeType) && + ( ((pDecl->getNodeType() == NT_interface_member) + && (pDeclaration->getNodeType() == NT_interface)) || + ((pDecl->getNodeType() == NT_service_member) + && (pDeclaration->getNodeType() == NT_service)) ) + ) + { + m_declarations.push_back(pDecl); + return pDecl; + } + + ErrorHandler::error2(ErrorCode::RedefScope, scopeAsDecl(this), pDecl); + return nullptr; + } + + m_declarations.push_back(pDecl); + return pDecl; +} + +sal_uInt16 AstScope::getNodeCount(NodeType nodeType) const +{ + return static_cast(std::count_if(getIteratorBegin(), getIteratorEnd(), + [&nodeType](const AstDeclaration* pDecl) { return pDecl->getNodeType() == nodeType; })); +} + +AstDeclaration* AstScope::lookupByName(const OString& scopedName) +{ + AstDeclaration* pDecl = nullptr; + AstScope* pScope = nullptr; + if (scopedName.isEmpty()) + return nullptr; + + // If name starts with "::" start look up in global scope + if ( isGlobal(scopedName) ) + { + pDecl = scopeAsDecl(this); + if ( !pDecl ) + return nullptr; + + pScope = pDecl->getScope(); + // If this is the global scope ... + if ( !pScope ) + { + // look up the scopedName part after "::" + OString subName = scopedName.copy(2); + pDecl = lookupByName(subName); + return pDecl; + //return pScope->lookupByName(); + } + // OK, not global scope yet, so simply iterate with parent scope + pDecl = pScope->lookupByName(scopedName); + return pDecl; + } + + // The name does not start with "::" + // Look up in the local scope and start with the first scope + sal_Int32 nIndex = scopedName.indexOf(':'); + OString firstScope = nIndex > 0 ? scopedName.copy(0, nIndex) : scopedName; + bool bFindFirstScope = true; + pDecl = lookupByNameLocal(firstScope); + if ( !pDecl ) + { + bFindFirstScope = false; + + // OK, not found. Go down parent scope chain + pDecl = scopeAsDecl(this); + if ( pDecl ) + { + pScope = pDecl->getScope(); + if ( pScope ) + pDecl = pScope->lookupByName(scopedName); + else + pDecl = nullptr; + + // Special case for scope which is an interface. We + // have to look in the inherited interfaces as well. + if ( !pDecl && m_nodeType == NT_interface ) + pDecl = lookupInInherited(scopedName); + } + } + + if ( bFindFirstScope && (firstScope != scopedName) ) + { + sal_Int32 i = 0; + sal_Int32 nOffset = 2; + do + { + pScope = declAsScope(pDecl); + if( pScope ) + { + pDecl = pScope->lookupByNameLocal(scopedName.getToken(nOffset, ':', i )); + nOffset = 1; + } + if( !pDecl ) + break; + } while( i != -1 ); + + if ( !pDecl ) + { + // last try if is not the global scope and the scopeName isn't specify global too + pDecl = scopeAsDecl(this); + if ( pDecl && !pDecl->getLocalName().isEmpty() ) + { + pScope = pDecl->getScope(); + if ( pScope ) + pDecl = pScope->lookupByName(scopedName); + } else + { + pDecl = nullptr; + } + } + + } + + return pDecl; +} + +AstDeclaration* AstScope::lookupByNameLocal(const OString& name) const +{ + for (auto const& declaration : m_declarations) + { + if ( declaration->getLocalName() == name ) + return declaration; + } + return nullptr; +} + +AstDeclaration* AstScope::lookupInInherited(const OString& scopedName) const +{ + const AstInterface* pInterface = dynamic_cast(this); + + if ( !pInterface ) + return nullptr; + + // Can't look in an interface which was not yet defined + if ( !pInterface->getScope() ) + { + ErrorHandler::forwardLookupError(pInterface, scopedName); + } + + // OK, loop through inherited interfaces. Stop when you find it + for (auto const& elem : pInterface->getAllInheritedInterfaces()) + { + AstInterface const * resolved = elem.getResolved(); + AstDeclaration* pDecl = resolved->lookupByNameLocal(scopedName); + if ( pDecl ) + return pDecl; + pDecl = resolved->lookupInInherited(scopedName); + if ( pDecl ) + return pDecl; + } + // Not found + return nullptr; +} + +AstDeclaration* AstScope::lookupPrimitiveType(ExprType type) +{ + AstDeclaration* pDecl = nullptr; + AstScope* pScope = nullptr; + OString typeName; + pDecl = scopeAsDecl(this); + if ( !pDecl ) + return nullptr; + pScope = pDecl->getScope(); + if ( pScope) + return pScope->lookupPrimitiveType(type); + + switch (type) + { + case ET_none: + OSL_ASSERT(false); + break; + case ET_short: + typeName = OString("short"); + break; + case ET_ushort: + typeName = OString("unsigned short"); + break; + case ET_long: + typeName = OString("long"); + break; + case ET_ulong: + typeName = OString("unsigned long"); + break; + case ET_hyper: + typeName = OString("hyper"); + break; + case ET_uhyper: + typeName = OString("unsigned hyper"); + break; + case ET_float: + typeName = OString("float"); + break; + case ET_double: + typeName = OString("double"); + break; + case ET_char: + typeName = OString("char"); + break; + case ET_byte: + typeName = OString("byte"); + break; + case ET_boolean: + typeName = OString("boolean"); + break; + case ET_any: + typeName = OString("any"); + break; + case ET_void: + typeName = OString("void"); + break; + case ET_type: + typeName = OString("type"); + break; + case ET_string: + typeName = OString("string"); + break; + } + + pDecl = lookupByNameLocal(typeName); + + if ( pDecl && (pDecl->getNodeType() == NT_predefined) ) + { + AstBaseType* pBaseType = static_cast(pDecl); + + if ( pBaseType->getExprType() == type ) + return pDecl; + } + + return nullptr; +} + +AstDeclaration* AstScope::lookupForAdd(AstDeclaration const * pDecl) const +{ + if ( !pDecl ) + return nullptr; + + AstDeclaration* pRetDecl = lookupByNameLocal(pDecl->getLocalName()); + + return pRetDecl; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/idlc/source/astservice.cxx b/idlc/source/astservice.cxx new file mode 100644 index 000000000..c90ded6b4 --- /dev/null +++ b/idlc/source/astservice.cxx @@ -0,0 +1,54 @@ +/* -*- 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 + +#include +#include +#include +#include + +bool AstService::checkLastConstructor() const { + AstOperation const * last = static_cast< AstOperation const * >(getLast()); + for (DeclList::const_iterator i(getIteratorBegin()); i != getIteratorEnd(); + ++i) + { + if (*i != last && (*i)->getNodeType() == NT_operation) { + AstOperation const * ctor = static_cast< AstOperation * >(*i); + if (ctor->isVariadic() && last->isVariadic()) { + return true; + } + sal_uInt32 n = ctor->nMembers(); + if (n == last->nMembers()) { + return std::equal(ctor->getIteratorBegin(), ctor->getIteratorEnd(), last->getIteratorBegin(), + [](AstDeclaration* a, AstDeclaration* b) { + sal_Int32 r1; + AstDeclaration const * t1 = deconstructAndResolveTypedefs(static_cast< AstMember * >(a)->getType(), &r1); + sal_Int32 r2; + AstDeclaration const * t2 = deconstructAndResolveTypedefs(static_cast< AstMember * >(b)->getType(), &r2); + return r1 == r2 && t1->getScopedName() == t2->getScopedName(); + }); + } + } + } + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/idlc/source/aststack.cxx b/idlc/source/aststack.cxx new file mode 100644 index 000000000..6e01cdabf --- /dev/null +++ b/idlc/source/aststack.cxx @@ -0,0 +1,85 @@ +/* -*- 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 +#include +#include + +AstStack::AstStack() +{ +} + +AstStack::~AstStack() +{ + for (AstScope* p : m_stack) + delete p; +} + + +AstScope* AstStack::top() +{ + if (m_stack.empty()) + return nullptr; + return m_stack.back(); +} + +AstScope* AstStack::bottom() +{ + if (m_stack.empty()) + return nullptr; + return m_stack.front(); +} + +AstScope* AstStack::nextToTop() +{ + if (m_stack.size() < 2) + return nullptr; + + return m_stack[m_stack.size() - 2]; +} + +AstScope* AstStack::topNonNull() +{ + for (sal_uInt32 i = m_stack.size(); i > 0; i--) + { + if ( m_stack[i - 1] ) + return m_stack[i - 1]; + } + return nullptr; +} + +AstStack* AstStack::push(AstScope* pScope) +{ + m_stack.push_back(pScope); + return this; +} + +void AstStack::pop() +{ + if (m_stack.empty()) + return; + m_stack.pop_back(); +} + +void AstStack::clear() +{ + m_stack.clear(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/idlc/source/aststruct.cxx b/idlc/source/aststruct.cxx new file mode 100644 index 000000000..e06adc2b2 --- /dev/null +++ b/idlc/source/aststruct.cxx @@ -0,0 +1,167 @@ +/* -*- 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 +#include + +#include +#include + +AstStruct::AstStruct( + const OString& name, std::vector< OString > const & typeParameters, + AstStruct const* pBaseType, AstScope* pScope) + : AstType(NT_struct, name, pScope) + , AstScope(NT_struct) + , m_pBaseType(pBaseType) +{ + for (auto const& elem : typeParameters) + { + m_typeParameters.emplace_back( + new AstType(NT_type_parameter, elem, nullptr)); + } +} + +AstStruct::AstStruct(const NodeType type, + const OString& name, + AstStruct const* pBaseType, + AstScope* pScope) + : AstType(type, name, pScope) + , AstScope(type) + , m_pBaseType(pBaseType) +{ +} + +AstStruct::~AstStruct() +{ +} + +AstDeclaration const * AstStruct::findTypeParameter(OString const & name) + const +{ + for (auto const& elem : m_typeParameters) + { + if (elem->getLocalName() == name) { + return elem.get(); + } + } + return nullptr; +} + +bool AstStruct::isType() const { + return getNodeType() == NT_struct + ? getTypeParameterCount() == 0 : AstDeclaration::isType(); +} + +bool AstStruct::dump(RegistryKey& rKey) +{ + RegistryKey localKey; + if (rKey.createKey( OStringToOUString(getFullName(), RTL_TEXTENCODING_UTF8 ), localKey) != RegError::NO_ERROR) + { + fprintf(stderr, "%s: warning, could not create key '%s' in '%s'\n", + idlc()->getOptions()->getProgramName().getStr(), + getFullName().getStr(), OUStringToOString(rKey.getRegistryName(), RTL_TEXTENCODING_UTF8).getStr()); + return false; + } + + if (m_typeParameters.size() > SAL_MAX_UINT16) { + fprintf( + stderr, + ("%s: polymorphic struct type template %s has too many type" + " parameters\n"), + idlc()->getOptions()->getProgramName().getStr(), + getScopedName().getStr()); + return false; + } + + sal_uInt16 nMember = getNodeCount(NT_member); + + RTTypeClass typeClass = RT_TYPE_STRUCT; + if ( getNodeType() == NT_exception ) + typeClass = RT_TYPE_EXCEPTION; + + typereg::Writer aBlob( + (m_typeParameters.empty() && !m_bPublished + ? TYPEREG_VERSION_0 : TYPEREG_VERSION_1), + getDocumentation(), "", typeClass, m_bPublished, + OStringToOUString(getRelativName(), RTL_TEXTENCODING_UTF8), + m_pBaseType == nullptr ? 0 : 1, nMember, 0, + static_cast< sal_uInt16 >(m_typeParameters.size())); + if (m_pBaseType != nullptr) { + aBlob.setSuperTypeName( + 0, + OStringToOUString( + m_pBaseType->getRelativName(), RTL_TEXTENCODING_UTF8)); + } + + if ( nMember > 0 ) + { + DeclList::const_iterator iter = getIteratorBegin(); + DeclList::const_iterator end = getIteratorEnd(); + AstMember* pMember = nullptr; + sal_uInt16 index = 0; + while ( iter != end ) + { + AstDeclaration* pDecl = *iter; + if ( pDecl->getNodeType() == NT_member ) + { + pMember = static_cast(pDecl); + RTFieldAccess flags = RTFieldAccess::READWRITE; + OString typeName; + if (pMember->getType()->getNodeType() == NT_type_parameter) { + flags |= RTFieldAccess::PARAMETERIZED_TYPE; + typeName = pMember->getType()->getLocalName(); + } else { + typeName = pMember->getType()->getRelativName(); + } + aBlob.setFieldData( + index++, pMember->getDocumentation(), "", flags, + OStringToOUString( + pMember->getLocalName(), RTL_TEXTENCODING_UTF8), + OStringToOUString(typeName, RTL_TEXTENCODING_UTF8), + RTConstValue()); + } + ++iter; + } + } + + sal_uInt16 index = 0; + for (auto const& elem : m_typeParameters) + { + aBlob.setReferenceData( + index++, "", RTReferenceType::TYPE_PARAMETER, RTFieldAccess::INVALID, + OStringToOUString( + elem->getLocalName(), RTL_TEXTENCODING_UTF8)); + } + + sal_uInt32 aBlobSize; + void const * pBlob = aBlob.getBlob(&aBlobSize); + + if (localKey.setValue("", RegValueType::BINARY, + const_cast(pBlob), aBlobSize) != RegError::NO_ERROR) + { + fprintf(stderr, "%s: warning, could not set value of key \"%s\" in %s\n", + idlc()->getOptions()->getProgramName().getStr(), + getFullName().getStr(), OUStringToOString(localKey.getRegistryName(), RTL_TEXTENCODING_UTF8).getStr()); + return false; + } + + return true; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/idlc/source/aststructinstance.cxx b/idlc/source/aststructinstance.cxx new file mode 100644 index 000000000..878745793 --- /dev/null +++ b/idlc/source/aststructinstance.cxx @@ -0,0 +1,63 @@ +/* -*- 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 + +#include +#include + +#include +#include + +namespace { + +OString createName( + AstType const * typeTemplate, DeclList const * typeArguments) +{ + OStringBuffer buf(64); + buf.append(typeTemplate->getScopedName()); + if (typeArguments != nullptr) { + buf.append('<'); + for (DeclList::const_iterator i(typeArguments->begin()); + i != typeArguments->end(); ++i) + { + if (i != typeArguments->begin()) { + buf.append(','); + } + if (*i != nullptr) { + buf.append((*i)->getScopedName()); + } + } + buf.append('>'); + } + return buf.makeStringAndClear(); +} + +} + +AstStructInstance::AstStructInstance( + AstType const * typeTemplate, DeclList const * typeArguments, + AstScope * scope): + AstType( + NT_instantiated_struct, createName(typeTemplate, typeArguments), scope), + m_typeTemplate(typeTemplate), m_typeArguments(*typeArguments) +{} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/idlc/source/attributeexceptions.hxx b/idlc/source/attributeexceptions.hxx new file mode 100644 index 000000000..e1a3033a9 --- /dev/null +++ b/idlc/source/attributeexceptions.hxx @@ -0,0 +1,36 @@ +/* -*- 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 . + */ + +#ifndef INCLUDED_IDLC_SOURCE_ATTRIBUTEEXCEPTIONS_HXX +#define INCLUDED_IDLC_SOURCE_ATTRIBUTEEXCEPTIONS_HXX + +#include + +struct AttributeExceptions { + struct Part { + OUString const * documentation; + DeclList const * exceptions; + }; + Part get; + Part set; +}; + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/idlc/source/errorhandler.cxx b/idlc/source/errorhandler.cxx new file mode 100644 index 000000000..6d2d92ea3 --- /dev/null +++ b/idlc/source/errorhandler.cxx @@ -0,0 +1,583 @@ +/* -*- 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 +#include + +static const char* errorCodeToMessage(ErrorCode eCode) +{ + switch (eCode) + { + case ErrorCode::SyntaxError: + return ""; + case ErrorCode::RedefScope: + return "illegal redefinition in scope "; + case ErrorCode::CoercionFailure: + return "coercion failure "; + case ErrorCode::ScopeConflict: + return "definition scope is different than fwd declare scope, "; + case ErrorCode::IllegalAdd: + return "illegal add operation, "; + case ErrorCode::IllegalRaises: + return "non-exception type in raises(..) clause, "; + case ErrorCode::CantInherit: + return "cannot inherit "; + case ErrorCode::IdentNotFound: + return "error in lookup of symbol: "; + case ErrorCode::CannotInheritFromForward: + return ""; + case ErrorCode::ExpectedConstant: + return "constant expected: "; + case ErrorCode::Eval: + return "expression evaluation error: "; + case ErrorCode::ForwardDeclLookup: + return ""; + case ErrorCode::RecursiveType: + return "illegal recursive use of type: "; + case ErrorCode::NotAType: + return "specified symbol is not a type: "; + case ErrorCode::InterfaceMemberLookup: + return "error in lookup of symbol, expected interface is not defined and no forward exists: "; + case ErrorCode::ServiceMemberLookup: + return "error in lookup of symbol, expected service is not defined: "; + case ErrorCode::DefinedAttributeFlag: + return "flag is already set: "; + case ErrorCode::WrongAttributeKeyword: + return "keyword not allowed: "; + case ErrorCode::MissingAttributeKeyword: + return "missing keyword: "; + case ErrorCode::BadAttributeFlags: + return + "the 'attribute' flag is mandatory, and only the 'bound' and" + " 'readonly' optional flags are accepted: "; + case ErrorCode::ExpectedOptional: + return "only the 'optional' flag is accepted: "; + case ErrorCode::MixedInheritance: + return "interface inheritance declarations cannot appear in both an" + " interface's header and its body"; + case ErrorCode::DoubleInheritance: + return + "interface is (directly or indirectly) inherited more than once: "; + case ErrorCode::DoubleMember: + return + "member is (directly or indirectly) declared more than once: "; + case ErrorCode::ConstructorParameterNotIn: + return + "a service constructor parameter may not be an out or inout" + " parameter"; + case ErrorCode::ConstructorRestParameterNotFirst: + return + "no parameters may precede a rest parameter in a service" + " constructor"; + case ErrorCode::RestParameterNotLast: + return "no parameters may follow a rest parameter"; + case ErrorCode::RestParameterNotAny: + return "a rest parameter must be of type any"; + case ErrorCode::MethodHasRestParameter: + return "a rest parameter may not be used on an interface method"; + case ErrorCode::ReadOnlyAttributeSetExceptions: + return "a readonly attribute may not have a setter raises clause"; + case ErrorCode::UnsignedTypeArgument: + return "an unsigned type cannot be used as a type argument"; + case ErrorCode::WrongNumberOfTypeArguments: + return + "the number of given type arguments does not match the expected" + " number of type parameters"; + case ErrorCode::InstantiatedStructTypeTypedef: + return + "an instantiated polymorphic struct type cannot be used in a" + " typedef"; + case ErrorCode::IdenticalTypeParameters: + return "two type parameters have the same name"; + case ErrorCode::StructTypeTemplateWithBase: + return "a polymorphic struct type template may not have a base type"; + case ErrorCode::PublishedForward: + return + "a published forward declaration of an interface type cannot be" + " followed by an unpublished declaration of that type"; + case ErrorCode::PublishedusesUnpublished: + return + "an unpublished entity cannot be used in the declaration of a" + " published entity: "; + case ErrorCode::SimilarConstructors: + return "two constructors have identical lists of parameter types"; + } + return "unknown error"; +} + +static const char* warningCodeToMessage(WarningCode wCode) +{ + switch (wCode) + { + case WarningCode::WrongNamingConvention: + return "type or identifier doesn't fulfill the UNO naming convention: "; + } + return "unknown warning"; +} + +static const char* parseStateToMessage(ParseState state) +{ + switch (state) + { + case PS_NoState: + return "Statement can not be parsed"; + case PS_TypeDeclSeen: + return "Malformed type declaration"; + case PS_ConstantDeclSeen: + return "Malformed const declaration"; + case PS_ExceptionDeclSeen: + return "Malformed exception declaration"; + case PS_InterfaceDeclSeen: + return "Malformed interface declaration"; + case PS_ServiceDeclSeen: + return "Malformed service declaration"; + case PS_ModuleDeclSeen: + return "Malformed module declaration"; + case PS_AttributeDeclSeen: + return "Malformed attribute declaration"; + case PS_PropertyDeclSeen: + return "Malformed property declaration"; + case PS_OperationDeclSeen: + return "Malformed operation declaration"; + case PS_InterfaceInheritanceDeclSeen: + return "Malformed interface inheritance declaration"; + case PS_ConstantsDeclSeen: + return "Malformed constants declaration"; + case PS_ServiceSeen: + return "Missing service identifier following SERVICE keyword"; + case PS_ServiceIDSeen: + return "Missing '{' or illegal syntax following service identifier"; + case PS_ServiceSqSeen: + return "Illegal syntax following service '{' opener"; + case PS_ServiceBodySeen: + return "Illegal syntax following service '}' closer"; + case PS_ServiceMemberSeen: + return "Illegal syntax following service member declaration"; + case PS_ServiceIFHeadSeen: + return "Illegal syntax following header of an interface member"; + case PS_ServiceSHeadSeen: + return "Illegal syntax following header of a service member"; + case PS_ModuleSeen: + return "Missing module identifier following MODULE keyword"; + case PS_ModuleIDSeen: + return "Missing '{' or illegal syntax following module identifier"; + case PS_ModuleSqSeen: + return "Illegal syntax following module '{' opener"; + case PS_ModuleQsSeen: + return "Illegal syntax following module '}' closer"; + case PS_ModuleBodySeen: + return "Illegal syntax following module export(s)"; + case PS_ConstantsSeen: + return "Missing constants identifier following CONSTANTS keyword"; + case PS_ConstantsIDSeen: + return "Missing '{' or illegal syntax following constants identifier"; + case PS_ConstantsSqSeen: + return "Illegal syntax following module '{' opener"; + case PS_ConstantsQsSeen: + return "Illegal syntax following module '}' closer"; + case PS_ConstantsBodySeen: + return "Illegal syntax following constants export(s)"; + case PS_InterfaceSeen: + return "Missing interface identifier following INTERFACE keyword"; + case PS_InterfaceIDSeen: + return "Illegal syntax following interface identifier"; + case PS_InterfaceHeadSeen: + return "Illegal syntax following interface head"; + case PS_InheritSpecSeen: + return "Missing '{' or illegal syntax following inheritance spec"; + case PS_ForwardDeclSeen: + return "Missing ';' following forward interface declaration"; + case PS_InterfaceSqSeen: + return "Illegal syntax following interface '{' opener"; + case PS_InterfaceQsSeen: + return "Illegal syntax following interface '}' closer"; + case PS_InterfaceBodySeen: + return "Illegal syntax following interface export(s)"; + case PS_InheritColonSeen: + return "Illegal syntax following ':' starting inheritance list"; + case PS_SNListCommaSeen: + return "Found illegal scoped name in scoped name list"; + case PS_ScopedNameSeen: + return "Missing ',' following scoped name in scoped name list"; + case PS_SN_IDSeen: + return "Illegal component in scoped name"; + case PS_ScopeDelimSeen: + return "Illegal component in scoped name following '::'"; + case PS_ConstSeen: + return "Missing type or illegal syntax following CONST keyword"; + case PS_ConstTypeSeen: + return "Missing identifier or illegal syntax following const type"; + case PS_ConstIDSeen: + return "Missing '=' or illegal syntax after const identifier"; + case PS_ConstAssignSeen: + return "Missing value expr or illegal syntax following '='"; + case PS_ConstExprSeen: + return "Missing ';' or illegal syntax following value expr in const"; + case PS_TypedefSeen: + return "Missing type or illegal syntax following TYPEDEF keyword"; + case PS_TypeSpecSeen: + return "Missing declarators or illegal syntax following type spec"; + case PS_DeclaratorsSeen: + return "Illegal syntax following declarators in TYPEDEF declaration"; + case PS_StructSeen: + return "Missing struct identifier following STRUCT keyword"; + case PS_StructHeaderSeen: + return "Missing '{' or illegal syntax following struct inheritance spec"; + case PS_StructIDSeen: + return "Missing '{' or illegal syntax following struct identifier"; + case PS_StructSqSeen: + return "Illegal syntax following struct '{' opener"; + case PS_StructQsSeen: + return "Illegal syntax following struct '}' closer"; + case PS_StructBodySeen: + return "Illegal syntax following struct member(s)"; + case PS_MemberTypeSeen: + return "Illegal syntax or missing identifier following member type"; + case PS_MemberDeclsSeen: + return "Illegal syntax following member declarator(s)"; + case PS_MemberDeclsCompleted: + return "Missing ',' between member decls of same type(?)"; + case PS_EnumSeen: + return "Illegal syntax or missing identifier following ENUM keyword"; + case PS_EnumIDSeen: + return "Illegal syntax or missing '{' following enum identifier"; + case PS_EnumSqSeen: + return "Illegal syntax following enum '{' opener"; + case PS_EnumQsSeen: + return "Illegal syntax following enum '}' closer"; + case PS_EnumBodySeen: + return "Illegal syntax following enum enumerator(s)"; + case PS_EnumCommaSeen: + return "Illegal syntax or missing identifier following ',' in enum"; + case PS_SequenceSeen: + return "Illegal syntax or missing '<' following SEQUENCE keyword"; + case PS_SequenceSqSeen: + return "Illegal syntax or missing type following '<' in sequence"; + case PS_SequenceQsSeen: + return "Illegal syntax following '>' in sequence"; + case PS_SequenceTypeSeen: + return "Illegal syntax following sequence type declaration"; + case PS_FlagHeaderSeen: + return "Illegal syntax after flags"; + case PS_AttrSeen: + return "Illegal syntax after ATTRIBUTE keyword"; + case PS_AttrTypeSeen: + return "Illegal syntax after type in attribute declaration"; + case PS_AttrCompleted: + return "Illegal syntax after attribute declaration"; + case PS_ReadOnlySeen: + return "Illegal syntax after READONLY keyword"; + case PS_OptionalSeen: + return "Illegal syntax after OPTIONAL keyword"; + case PS_MayBeVoidSeen: + return "Illegal syntax after MAYBEVOID keyword"; + case PS_BoundSeen: + return "Illegal syntax after BOUND keyword"; + case PS_ConstrainedSeen: + return "Illegal syntax after CONSTRAINED keyword"; + case PS_TransientSeen: + return "Illegal syntax after TRANSIENT keyword"; + case PS_MayBeAmbigiousSeen: + return "Illegal syntax after MAYBEAMBIGIOUS keyword"; + case PS_MayBeDefaultSeen: + return "Illegal syntax after MAYBEDEFAULT keyword"; + case PS_RemoveableSeen: + return "Illegal syntax after REMOVABLE keyword"; + case PS_PropertySeen: + return "Illegal syntax after PROPERTY keyword"; + case PS_PropertyTypeSeen: + return "Illegal syntax after type in property declaration"; + case PS_PropertyCompleted: + return "Illegal syntax after property declaration"; + case PS_ExceptSeen: + return "Illegal syntax or missing identifier after EXCEPTION keyword"; + case PS_ExceptHeaderSeen: + return "Missing '{' or illegal syntax following exception inheritance spec"; + case PS_ExceptIDSeen: + return "Illegal syntax or missing '{' after exception identifier"; + case PS_ExceptSqSeen: + return "Illegal syntax after exception '{' opener"; + case PS_ExceptQsSeen: + return "Illegal syntax after exception '}' closer"; + case PS_ExceptBodySeen: + return "Illegal syntax after exception member(s)"; + case PS_OpTypeSeen: + return "Illegal syntax or missing identifier after operation type"; + case PS_OpIDSeen: + return "Illegal syntax or missing '(' after operation identifier"; + case PS_OpParsCompleted: + return "Illegal syntax after operation parameter list"; + case PS_OpSqSeen: + return "Illegal syntax after operation parameter list '(' opener"; + case PS_OpQsSeen: + return "Illegal syntax after operation parameter list ')' closer"; + case PS_OpParCommaSeen: + return "Illegal syntax or missing direction in parameter declaration"; + case PS_OpParDirSeen: + return "Illegal syntax or missing type in parameter declaration"; + case PS_OpParTypeSeen: + return "Illegal syntax or missing declarator in parameter declaration"; + case PS_OpParDeclSeen: + return "Illegal syntax following parameter declarator"; + case PS_RaiseSeen: + return "Illegal syntax or missing '(' after RAISES keyword"; + case PS_RaiseSqSeen: + return "Illegal syntax after RAISES '(' opener"; + case PS_RaiseQsSeen: + return "Illegal syntax after RAISES ')' closer"; + case PS_DeclsCommaSeen: + return "Illegal syntax after ',' in declarators list"; + case PS_DeclsDeclSeen: + return "Illegal syntax after declarator in declarators list"; + default: + return "no wider described syntax error"; + } +} + +static OString flagToString(sal_uInt32 flag) +{ + OString flagStr; + if ( (flag & AF_READONLY) == AF_READONLY ) + flagStr += "'readonly'"; + if ( (flag & AF_OPTIONAL) == AF_OPTIONAL ) + flagStr += "'optional'"; + if ( (flag & AF_MAYBEVOID) == AF_MAYBEVOID ) + flagStr += "'maybevoid'"; + if ( (flag & AF_BOUND) == AF_BOUND ) + flagStr += "'bound'"; + if ( (flag & AF_CONSTRAINED) == AF_CONSTRAINED ) + flagStr += "'constrained'"; + if ( (flag & AF_TRANSIENT) == AF_TRANSIENT ) + flagStr += "'transient'"; + if ( (flag & AF_MAYBEAMBIGUOUS) == AF_MAYBEAMBIGUOUS ) + flagStr += "'maybeambiguous'"; + if ( (flag & AF_MAYBEDEFAULT) == AF_MAYBEDEFAULT ) + flagStr += "'maybedefault'"; + if ( (flag & AF_REMOVABLE) == AF_REMOVABLE ) + flagStr += "'removable'"; + if ( (flag & AF_ATTRIBUTE) == AF_ATTRIBUTE ) + flagStr += "'attribute'"; + if ( (flag & AF_PROPERTY) == AF_PROPERTY ) + flagStr += "'property'"; + if ( flagStr.isEmpty() ) + flagStr += "'unknown'"; + + return flagStr; +} + +static void errorHeader(ErrorCode eCode, sal_Int32 lineNumber, sal_uInt32 start, sal_uInt32 end) +{ + OString file; + if ( idlc()->getFileName() == idlc()->getRealFileName() ) + file = idlc()->getMainFileName(); + else + file = idlc()->getFileName(); + + fprintf(stderr, "%s:%lu [%lu:%lu] : %s", file.getStr(), + sal::static_int_cast< unsigned long >(lineNumber), + sal::static_int_cast< unsigned long >(start), + sal::static_int_cast< unsigned long >(end), + errorCodeToMessage(eCode)); +} + +static void errorHeader(ErrorCode eCode, sal_uInt32 lineNumber) +{ + errorHeader(eCode, lineNumber, + idlc()->getOffsetStart(), idlc()->getOffsetEnd()); +} + +static void errorHeader(ErrorCode eCode) +{ + errorHeader(eCode, idlc()->getLineNumber(), + idlc()->getOffsetStart(), idlc()->getOffsetEnd()); +} + +static void warningHeader(WarningCode wCode) +{ + OString file; + if ( idlc()->getFileName() == idlc()->getRealFileName() ) + file = idlc()->getMainFileName(); + else + file = idlc()->getFileName(); + + fprintf(stderr, "%s(%lu) : WARNING, %s", file.getStr(), + sal::static_int_cast< unsigned long >(idlc()->getLineNumber()), + warningCodeToMessage(wCode)); +} + +void ErrorHandler::error0(ErrorCode e) +{ + errorHeader(e); + fprintf(stderr, "\n"); + idlc()->incErrorCount(); +} + +void ErrorHandler::error1(ErrorCode e, AstDeclaration const * d) +{ + errorHeader(e); + fprintf(stderr, "'%s'\n", d->getScopedName().getStr()); + idlc()->incErrorCount(); +} + +void ErrorHandler::error2( + ErrorCode e, AstDeclaration const * d1, AstDeclaration const * d2) +{ + errorHeader(e); + fprintf(stderr, "'%s', '%s'\n", d1->getScopedName().getStr(), + d2->getScopedName().getStr()); + idlc()->incErrorCount(); +} + +void ErrorHandler::error3(ErrorCode e, AstDeclaration const * d1, AstDeclaration const * d2, AstDeclaration const * d3) +{ + errorHeader(e); + fprintf(stderr, "'%s', '%s', '%s'\n", d1->getScopedName().getStr(), + d2->getScopedName().getStr(), d3->getScopedName().getStr()); + idlc()->incErrorCount(); +} + +void ErrorHandler::warning0(WarningCode w, const char* warningmsg) +{ + if ( idlc()->getOptions()->isValid("-w") || idlc()->getOptions()->isValid("-we") ) { + warningHeader(w); + fprintf(stderr, "%s\n", warningmsg); + } + + if ( idlc()->getOptions()->isValid("-we") ) + idlc()->incErrorCount(); + else + idlc()->incWarningCount(); +} + +void ErrorHandler::syntaxError(ParseState ps, sal_Int32 lineNumber, const char* errmsg) +{ + errorHeader(ErrorCode::SyntaxError, lineNumber); + fprintf(stderr, "%s: %s\n", parseStateToMessage(ps), errmsg); + idlc()->incErrorCount(); +} + +void ErrorHandler::coercionError(AstExpression *pExpr, ExprType et) +{ + errorHeader(ErrorCode::CoercionFailure); + fprintf(stderr, "'%s' to '%s'\n", pExpr->toString().getStr(), + exprTypeToString(et)); + idlc()->incErrorCount(); +} + +void ErrorHandler::lookupError(const OString& n) +{ + errorHeader(ErrorCode::IdentNotFound); + fprintf(stderr, "'%s'\n", n.getStr()); + idlc()->incErrorCount(); +} + +void ErrorHandler::lookupError(ErrorCode e, const OString& n, AstDeclaration const * pScope) +{ + errorHeader(e); + fprintf(stderr, "'%s' in '%s'\n", n.getStr(), pScope->getFullName().getStr()); + idlc()->incErrorCount(); +} + +void ErrorHandler::flagError(ErrorCode e, sal_uInt32 flag) +{ + errorHeader(e); + fprintf(stderr, "'%s'\n", flagToString(flag).getStr()); + idlc()->incErrorCount(); +} + +void ErrorHandler::noTypeError(AstDeclaration const * pDecl) +{ + errorHeader(ErrorCode::NotAType); + fprintf(stderr, "'%s'\n", pDecl->getScopedName().getStr()); + idlc()->incErrorCount(); +} + +namespace { + +char const * nodeTypeName(NodeType nodeType) { + switch (nodeType) { + case NT_interface: + return "interface"; + + case NT_exception: + return "exception"; + + case NT_struct: + return "struct"; + + default: + return ""; + } +} + +} + +void ErrorHandler::inheritanceError(NodeType nodeType, const OString* name, AstDeclaration const * pDecl) +{ + if ( nodeType == NT_interface && + (pDecl->getNodeType() == NT_interface) && + !(static_cast(pDecl)->isDefined()) ) + { + errorHeader(ErrorCode::CannotInheritFromForward); + fprintf(stderr, "interface '%s' cannot inherit from forward declared interface '%s'\n", + name->getStr(), pDecl->getScopedName().getStr()); + } else + { + errorHeader(ErrorCode::CantInherit); + fprintf(stderr, "%s '%s' from '%s'\n", + nodeTypeName(nodeType), name->getStr(), + pDecl->getScopedName().getStr()); + } + idlc()->incErrorCount(); +} + +void ErrorHandler::forwardLookupError(const AstDeclaration* pForward, + const OString& name) +{ + errorHeader(ErrorCode::ForwardDeclLookup); + fprintf(stderr, "trying to look up '%s' in undefined forward declared interface '%s'\n", + pForward->getScopedName().getStr(), name.getStr()); + idlc()->incErrorCount(); +} + +void ErrorHandler::constantExpected(AstDeclaration const * pDecl, + const OString& name) +{ + errorHeader(ErrorCode::ExpectedConstant); + fprintf(stderr, "'%s' is bound to '%s'\n", name.getStr(), pDecl->getScopedName().getStr()); + idlc()->incErrorCount(); +} + +void ErrorHandler::evalError(AstExpression* pExpr) +{ + errorHeader(ErrorCode::Eval); + fprintf(stderr, "'%s'\n", pExpr->toString().getStr()); + idlc()->incErrorCount(); +} + +bool ErrorHandler::checkPublished(AstDeclaration const * decl, bool bOptional) { + if (idlc()->isPublished() && !decl->isPublished() && !bOptional) { + error1(ErrorCode::PublishedusesUnpublished, decl); + return false; + } else { + return true; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/idlc/source/fehelper.cxx b/idlc/source/fehelper.cxx new file mode 100644 index 000000000..607f5a145 --- /dev/null +++ b/idlc/source/fehelper.cxx @@ -0,0 +1,102 @@ +/* -*- 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 +#include +#include + +FeDeclarator::FeDeclarator(const OString& name) + : m_name(name) +{ +} + +FeDeclarator::~FeDeclarator() +{ +} + +bool FeDeclarator::checkType(AstDeclaration const * type) const +{ + OString tmp(m_name); + sal_Int32 count = m_name.lastIndexOf( ':' ); + if( count != -1 ) + tmp = m_name.copy( count+1 ); + + return tmp != type->getLocalName(); +} + +AstType const * FeDeclarator::compose(AstDeclaration const * pDecl) +{ + if ( pDecl == nullptr ) + { + return nullptr; + } + if ( !pDecl->isType() ) + { + ErrorHandler::noTypeError(pDecl); + return nullptr; + } + return static_cast(pDecl); +} + +FeInheritanceHeader::FeInheritanceHeader( + NodeType nodeType, OString* pName, OString const * pInherits, + std::vector< OString > const * typeParameters) + : m_nodeType(nodeType) + , m_pName(pName) + , m_pInherits(nullptr) +{ + if (typeParameters != nullptr) { + m_typeParameters = *typeParameters; + } + initializeInherits(pInherits); +} + +void FeInheritanceHeader::initializeInherits(OString const * pInherits) +{ + if ( !pInherits ) + return; + + AstScope* pScope = idlc()->scopes()->topNonNull(); + AstDeclaration* pDecl = pScope->lookupByName(*pInherits); + if ( pDecl ) + { + AstDeclaration const * resolved = resolveTypedefs(pDecl); + if ( resolved->getNodeType() == getNodeType() + && (resolved->getNodeType() != NT_interface + || static_cast< AstInterface const * >( + resolved)->isDefined()) ) + { + if ( ErrorHandler::checkPublished( pDecl ) ) + { + m_pInherits = pDecl; + } + } + else + { + ErrorHandler::inheritanceError( + getNodeType(), getName(), pDecl); + } + } + else + { + ErrorHandler::lookupError(*pInherits); + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/idlc/source/idlc.cxx b/idlc/source/idlc.cxx new file mode 100644 index 000000000..5984ca759 --- /dev/null +++ b/idlc/source/idlc.cxx @@ -0,0 +1,400 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +AstDeclaration* scopeAsDecl(AstScope* pScope) +{ + if (pScope == nullptr) return nullptr; + + switch( pScope->getScopeNodeType() ) + { + case NT_service: + case NT_singleton: + return static_cast(pScope); + case NT_module: + case NT_root: + return static_cast(pScope); + case NT_constants: + return static_cast(pScope); + case NT_interface: + return static_cast(pScope); + case NT_operation: + return static_cast(pScope); + case NT_exception: + return static_cast(pScope); + case NT_struct: + return static_cast(pScope); + case NT_enum: + return static_cast(pScope); + default: + return nullptr; + } +} + +AstScope* declAsScope(AstDeclaration* pDecl) +{ + if (pDecl == nullptr) return nullptr; + + switch(pDecl->getNodeType()) + { + case NT_interface: + return static_cast(pDecl); + case NT_service: + case NT_singleton: + return static_cast(pDecl); + case NT_module: + case NT_root: + return static_cast(pDecl); + case NT_constants: + return static_cast(pDecl); + case NT_exception: + return static_cast(pDecl); + case NT_struct: + return static_cast(pDecl); + case NT_enum: + return static_cast(pDecl); + case NT_operation: + return static_cast(pDecl); + default: + return nullptr; + } +} + +static void predefineXInterface(AstModule* pRoot) +{ + // define the modules com::sun::star::uno + AstModule* pParentScope = pRoot; + AstModule* pModule = new AstModule("com", pParentScope); + pModule->setPredefined(true); + pParentScope->addDeclaration(pModule); + pParentScope = pModule; + pModule = new AstModule("sun", pParentScope); + pModule->setPredefined(true); + pParentScope->addDeclaration(pModule); + pParentScope = pModule; + pModule = new AstModule("star", pParentScope); + pModule->setPredefined(true); + pParentScope->addDeclaration(pModule); + pParentScope = pModule; + pModule = new AstModule("uno", pParentScope); + pModule->setPredefined(true); + pParentScope->addDeclaration(pModule); + pParentScope = pModule; + + // define XInterface + AstInterface* pInterface = new AstInterface("XInterface", nullptr, pParentScope); + pInterface->setDefined(); + pInterface->setPredefined(true); + pInterface->setPublished(); + pParentScope->addDeclaration(pInterface); + + // define XInterface::queryInterface + AstOperation* pOp = new AstOperation(static_cast(pRoot->lookupPrimitiveType(ET_any)), + "queryInterface", pInterface); + AstParameter* pParam = new AstParameter(DIR_IN, false, + static_cast(pRoot->lookupPrimitiveType(ET_type)), + "aType", pOp); + pOp->addDeclaration(pParam); + pInterface->addMember(pOp); + + // define XInterface::acquire + pOp = new AstOperation(static_cast(pRoot->lookupPrimitiveType(ET_void)), + "acquire", pInterface); + pInterface->addMember(pOp); + + // define XInterface::release + pOp = new AstOperation(static_cast(pRoot->lookupPrimitiveType(ET_void)), + "release", pInterface); + pInterface->addMember(pOp); +} + +static void initializePredefinedTypes(AstModule* pRoot) +{ + if ( !pRoot ) + return; + + AstBaseType* pPredefined = new AstBaseType(ET_long, "long", pRoot); + pRoot->addDeclaration(pPredefined); + + pPredefined = new AstBaseType(ET_ulong, "unsigned long", pRoot); + pRoot->addDeclaration(pPredefined); + + pPredefined = new AstBaseType(ET_hyper, "hyper", pRoot); + pRoot->addDeclaration(pPredefined); + + pPredefined = new AstBaseType(ET_uhyper, "unsigned hyper", pRoot); + pRoot->addDeclaration(pPredefined); + + pPredefined = new AstBaseType(ET_short, "short", pRoot); + pRoot->addDeclaration(pPredefined); + + pPredefined = new AstBaseType(ET_ushort, "unsigned short", pRoot); + pRoot->addDeclaration(pPredefined); + + pPredefined = new AstBaseType(ET_float, "float", pRoot); + pRoot->addDeclaration(pPredefined); + + pPredefined = new AstBaseType(ET_double, "double", pRoot); + pRoot->addDeclaration(pPredefined); + + pPredefined = new AstBaseType(ET_char, "char", pRoot); + pRoot->addDeclaration(pPredefined); + + pPredefined = new AstBaseType(ET_byte, "byte", pRoot); + pRoot->addDeclaration(pPredefined); + + pPredefined = new AstBaseType(ET_any, "any", pRoot); + pRoot->addDeclaration(pPredefined); + + pPredefined = new AstBaseType(ET_string, "string", pRoot); + pRoot->addDeclaration(pPredefined); + + pPredefined = new AstBaseType(ET_type, "type", pRoot); + pRoot->addDeclaration(pPredefined); + + pPredefined = new AstBaseType(ET_boolean, "boolean", pRoot); + pRoot->addDeclaration(pPredefined); + + pPredefined = new AstBaseType(ET_void, "void", pRoot); + pRoot->addDeclaration(pPredefined); +} + +Idlc::Idlc(Options* pOptions) + : m_pOptions(pOptions) + , m_bIsDocValid(false) + , m_bIsInMainfile(true) + , m_published(false) + , m_errorCount(0) + , m_warningCount(0) + , m_lineNumber(0) + , m_offsetStart(0) + , m_offsetEnd(0) + , m_parseState(PS_NoState) +{ + m_pScopes.reset( new AstStack() ); + // init root object after construction + m_pRoot = nullptr; + m_bGenerateDoc = m_pOptions->isValid("-C"); +} + +Idlc::~Idlc() +{ +} + +void Idlc::init() +{ + m_pRoot.reset(new AstModule(NT_root, OString(), nullptr)); + + // push the root node on the stack + m_pScopes->push(m_pRoot.get()); + initializePredefinedTypes(m_pRoot.get()); + predefineXInterface(m_pRoot.get()); +} + +void Idlc::reset() +{ + m_bIsDocValid = false; + m_bIsInMainfile = true; + m_published = false; + + m_errorCount = 0; + m_warningCount = 0; + m_lineNumber = 0; + m_parseState = PS_NoState; + + m_fileName.clear(); + m_mainFileName.clear(); + m_realFileName.clear(); + m_documentation.clear(); + + m_pScopes->clear(); + m_pRoot.reset( new AstModule(NT_root, OString(), nullptr) ); + + // push the root node on the stack + m_pScopes->push(m_pRoot.get()); + initializePredefinedTypes(m_pRoot.get()); + + m_includes.clear(); +} + +OUString Idlc::processDocumentation() +{ + OUString doc; + if (m_bIsDocValid) { + OString raw(getDocumentation()); + if (m_bGenerateDoc) { + doc = OStringToOUString(raw, RTL_TEXTENCODING_UTF8); + } else if (raw.indexOf("@deprecated") != -1) { + //TODO: this check is somewhat crude + doc = "@deprecated"; + } + } + return doc; +} + +static void lcl_writeString(::osl::File & rFile, ::osl::FileBase::RC & o_rRC, + OString const& rString) +{ + sal_uInt64 nWritten(0); + if (::osl::FileBase::E_None == o_rRC) { + o_rRC = rFile.write(rString.getStr(), rString.getLength(), nWritten); + if (static_cast(rString.getLength()) != nWritten) { + o_rRC = ::osl::FileBase::E_INVAL; //? + } + } +} + +namespace { + +struct WriteDep +{ + ::osl::File& m_rFile; + ::osl::FileBase::RC & m_rRC; + explicit WriteDep(::osl::File & rFile, ::osl::FileBase::RC & rRC) + : m_rFile(rFile), m_rRC(rRC) { } + void operator() (OString const& rEntry) + { + lcl_writeString(m_rFile, m_rRC, " \\\n "); + lcl_writeString(m_rFile, m_rRC, rEntry); + } +}; + +// write a dummy target for one included file, so the incremental build does +// not break with "No rule to make target" if the included file is removed +struct WriteDummy +{ + ::osl::File& m_rFile; + ::osl::FileBase::RC & m_rRC; + explicit WriteDummy(::osl::File & rFile, ::osl::FileBase::RC & rRC) + : m_rFile(rFile), m_rRC(rRC) { } + void operator() (OString const& rEntry) + { + lcl_writeString(m_rFile, m_rRC, rEntry); + lcl_writeString(m_rFile, m_rRC, ":\n\n"); + } +}; + +} + +bool +Idlc::dumpDeps(OString const& rDepFile, OString const& rTarget) +{ + ::osl::File depFile( + OStringToOUString(rDepFile, osl_getThreadTextEncoding())); + ::osl::FileBase::RC rc = + depFile.open(osl_File_OpenFlag_Write | osl_File_OpenFlag_Create); + if (::osl::FileBase::E_None != rc) { + return false; + } + lcl_writeString(depFile, rc, rTarget); + if (::osl::FileBase::E_None != rc) { + return false; + } + lcl_writeString(depFile, rc, " :"); + if (::osl::FileBase::E_None != rc) { + return false; + } + m_includes.erase(getRealFileName()); // eeek, that is a temp file... + ::std::for_each(m_includes.begin(), m_includes.end(), + WriteDep(depFile, rc)); + lcl_writeString(depFile, rc, "\n\n"); + ::std::for_each(m_includes.begin(), m_includes.end(), + WriteDummy(depFile, rc)); + if (::osl::FileBase::E_None != rc) { + return false; + } + rc = depFile.close(); + return ::osl::FileBase::E_None == rc; +} + +static Idlc* pStaticIdlc = nullptr; + +Idlc* idlc() +{ + return pStaticIdlc; +} + +Idlc* setIdlc(Options* pOptions) +{ + delete pStaticIdlc; + pStaticIdlc = new Idlc(pOptions); + pStaticIdlc->init(); + return pStaticIdlc; +} + +AstDeclaration const * resolveTypedefs(AstDeclaration const * type) { + if (type != nullptr) { + while (type->getNodeType() == NT_typedef) { + type = static_cast< AstTypeDef const * >(type)->getBaseType(); + } + } + return type; +} + +AstDeclaration const * deconstructAndResolveTypedefs( + AstDeclaration const * type, sal_Int32 * rank) +{ + *rank = 0; + for (;;) { + if (type == nullptr) { + return nullptr; + } + switch (type->getNodeType()) { + case NT_typedef: + type = static_cast< AstTypeDef const * >(type)->getBaseType(); + break; + case NT_sequence: + ++(*rank); + type = static_cast< AstSequence const * >(type)->getMemberType(); + break; + default: + return type; + } + } +} + +AstInterface const * resolveInterfaceTypedefs(AstType const * type) { + AstDeclaration const * decl = resolveTypedefs(type); + OSL_ASSERT(decl->getNodeType() == NT_interface); + return static_cast< AstInterface const * >(decl); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/idlc/source/idlccompile.cxx b/idlc/source/idlccompile.cxx new file mode 100644 index 000000000..8db6d82a0 --- /dev/null +++ b/idlc/source/idlccompile.cxx @@ -0,0 +1,390 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(_WIN32) +#include +#endif + +#ifdef SAL_UNX +#include +#include +#if defined(MACOSX) || defined(FREEBSD) || defined(NETBSD) || \ + defined(AIX) || defined(OPENBSD) || defined(DRAGONFLY) || defined(HAIKU) +#include +#else +#include +#endif +#endif + +#include + +using namespace ::osl; + +extern int yyparse(); +extern FILE* yyin; +extern int yydebug; + +static char tmpFilePattern[512]; + +bool isFileUrl(const OString& fileName) +{ + return fileName.startsWith("file://"); +} + +OString convertToAbsoluteSystemPath(const OString& fileName) +{ + OUString uSysFileName; + OUString uFileName(fileName.getStr(), fileName.getLength(), osl_getThreadTextEncoding()); + if ( isFileUrl(fileName) ) + { + if (FileBase::getSystemPathFromFileURL(uFileName, uSysFileName) + != FileBase::E_None) + { + OSL_ASSERT(false); + } + } else + { + OUString uWorkingDir, uUrlFileName, uTmp; + if (osl_getProcessWorkingDir(&uWorkingDir.pData) != osl_Process_E_None) + { + OSL_ASSERT(false); + } + if (FileBase::getFileURLFromSystemPath(uFileName, uTmp) + != FileBase::E_None) + { + OSL_ASSERT(false); + } + if (FileBase::getAbsoluteFileURL(uWorkingDir, uTmp, uUrlFileName) + != FileBase::E_None) + { + OSL_ASSERT(false); + } + if (FileBase::getSystemPathFromFileURL(uUrlFileName, uSysFileName) + != FileBase::E_None) + { + OSL_ASSERT(false); + } + } + + return OUStringToOString(uSysFileName, osl_getThreadTextEncoding()); +} + +OString convertToFileUrl(const OString& fileName) +{ + if ( !isFileUrl(fileName) ) + { + OString tmp = convertToAbsoluteSystemPath(fileName); + OUString uFileName(tmp.getStr(), tmp.getLength(), osl_getThreadTextEncoding()); + OUString uUrlFileName; + if (FileBase::getFileURLFromSystemPath(uFileName, uUrlFileName) + != FileBase::E_None) + { + OSL_ASSERT(false); + } + return OUStringToOString(uUrlFileName, osl_getThreadTextEncoding()); + } + + return fileName; +} + +static OString makeTempName(const OString& prefix) +{ + OUString uTmpPath; + OString tmpPath; + + if ( osl_getEnvironment(OUString("TMP").pData, &uTmpPath.pData) != osl_Process_E_None ) + { + if ( osl_getEnvironment(OUString("TEMP").pData, &uTmpPath.pData) != osl_Process_E_None ) + { +#if defined(_WIN32) + tmpPath = OString("c:\\temp"); +#else + tmpPath = OString("/tmp"); +#endif + } + } + + if ( !uTmpPath.isEmpty() ) + tmpPath = OUStringToOString(uTmpPath, RTL_TEXTENCODING_UTF8); + +#if defined(_WIN32) || defined(SAL_UNX) + + OSL_ASSERT( sizeof(tmpFilePattern) > + o3tl::make_unsigned( tmpPath.getLength() + + RTL_CONSTASCII_LENGTH( PATH_SEPARATOR ) + + prefix.getLength() + + RTL_CONSTASCII_LENGTH( "XXXXXX") ) ); + + tmpFilePattern[ sizeof(tmpFilePattern)-1 ] = '\0'; + strncpy(tmpFilePattern, tmpPath.getStr(), sizeof(tmpFilePattern)-1); + strncat(tmpFilePattern, PATH_SEPARATOR, sizeof(tmpFilePattern)-1-strlen(tmpFilePattern)); + strncat(tmpFilePattern, prefix.getStr(), sizeof(tmpFilePattern)-1-strlen(tmpFilePattern)); + strncat(tmpFilePattern, "XXXXXX", sizeof(tmpFilePattern)-1-strlen(tmpFilePattern)); + +#ifdef SAL_UNX + // coverity[secure_temp] - https://communities.coverity.com/thread/3179 + int nDescriptor = mkstemp(tmpFilePattern); + if( -1 == nDescriptor ) + { + fprintf(stderr, "idlc: mkstemp(\"%s\") failed: %s\n", tmpFilePattern, strerror(errno)); + exit( 1 ); + } + // the file shall later be reopened by stdio functions + close( nDescriptor ); +#else + (void) mktemp(tmpFilePattern); +#endif +#endif + + return tmpFilePattern; +} + +bool copyFile(const OString* source, const OString& target) +{ + bool bRet = true; + + FILE* pSource = source == nullptr ? stdin : fopen(source->getStr(), "rb"); + if ( !pSource ) + return false; + + FILE* pTarget = fopen(target.getStr(), "wb"); + if ( !pTarget ) + { + fclose(pSource); + return false; + } + + size_t const totalSize = 512; + char pBuffer[totalSize + 1]; + + while ( !feof(pSource) ) + { + size_t readSize = fread(pBuffer, 1, totalSize, pSource); + if ( readSize > 0 && !ferror(pSource) ) + { + if ( (fwrite(pBuffer, 1, readSize, pTarget)) != readSize || ferror(pTarget) ) + { + if (source != nullptr) { + fclose(pSource); + } + fclose(pTarget); + return false; + } + } + } + + if (source != nullptr) { + fclose(pSource); + } + if ( fclose(pTarget) ) + bRet = false; + + return bRet; +} + +sal_Int32 compileFile(const OString * pathname) +{ + // preprocess input file + OString tmpFile = makeTempName("idli_"); + OString preprocFile = makeTempName("idlf_"); + + OString fileName; + if (pathname == nullptr) { + fileName = "stdin"; + } else { + fileName = *pathname; + } + + if ( !copyFile(pathname, tmpFile) ) + { + fprintf(stderr, "%s: could not copy %s%s to %s\n", + idlc()->getOptions()->getProgramName().getStr(), + pathname == nullptr ? "" : "file ", fileName.getStr(), + tmpFile.getStr()); + exit(99); + } + + idlc()->setFileName(fileName); + idlc()->setMainFileName(fileName); + idlc()->setRealFileName(tmpFile); + + ::std::vector< OUString> lCppArgs; + lCppArgs.emplace_back("-DIDL"); + lCppArgs.emplace_back("-C"); + lCppArgs.emplace_back("-zI"); + + Options* pOptions = idlc()->getOptions(); + + OString filePath; + sal_Int32 index = fileName.lastIndexOf(SEPARATOR); + + if ( index > 0) + { + filePath = fileName.copy(0, index); + + if ( !filePath.isEmpty() ) + { + OString cppArgs = "-I" + filePath; + lCppArgs.push_back(OStringToOUString( + cppArgs.replace('\\', '/'), + RTL_TEXTENCODING_UTF8)); + } + } + + if ( pOptions->isValid("-D") ) + { + OString token, dOpt = pOptions->getOption("-D"); + sal_Int32 nIndex = 0; + do + { + token = dOpt.getToken( 0, ' ', nIndex ); + if (token.getLength()) + lCppArgs.push_back(OStringToOUString("-D" + token, RTL_TEXTENCODING_UTF8)); + } while( nIndex != -1 ); + } + + if ( pOptions->isValid("-I") ) + { + OString token, incOpt = pOptions->getOption("-I"); + sal_Int32 nIndex = 0; + do + { + token = incOpt.getToken( 0, ' ', nIndex ); + if (token.getLength()) + lCppArgs.push_back(OStringToOUString("-I" + token, RTL_TEXTENCODING_UTF8)); + } while( nIndex != -1 ); + } + + lCppArgs.emplace_back("-o"); + + lCppArgs.push_back(OStringToOUString(preprocFile, RTL_TEXTENCODING_UTF8)); + + lCppArgs.push_back(OStringToOUString(tmpFile, RTL_TEXTENCODING_UTF8)); + + OUString cpp; + OUString startDir; +#ifndef SYSTEM_UCPP + if (osl_getExecutableFile(&cpp.pData) != osl_Process_E_None) { + OSL_ASSERT(false); + } + + sal_Int32 idx= cpp.lastIndexOf("idlc"); + cpp = cpp.copy(0, idx); + +#if defined(_WIN32) + cpp += "ucpp.exe"; +#else + cpp += "ucpp"; +#endif +#else // SYSTEM_UCPP + cpp = OUString(UCPP); +#endif + oslProcess hProcess = nullptr; + oslProcessError procError = osl_Process_E_None; + + const int nCmdArgs = lCppArgs.size(); + std::unique_ptr pCmdArgs(new rtl_uString*[nCmdArgs]); + + int i = 0; + for (auto const& elem : lCppArgs) + { + pCmdArgs[i++] = elem.pData; + } + + procError = osl_executeProcess( cpp.pData, pCmdArgs.get(), nCmdArgs, osl_Process_WAIT, + nullptr, startDir.pData, nullptr, 0, &hProcess ); + + oslProcessInfo hInfo; + hInfo.Size = sal_uInt32(sizeof(oslProcessInfo)); + if (osl_getProcessInfo(hProcess, osl_Process_EXITCODE, &hInfo) + != osl_Process_E_None) + { + OSL_ASSERT(false); + } + + if ( procError || (hInfo.Code != 0) ) + { + if ( procError != osl_Process_E_None ) + fprintf(stderr, "%s: starting preprocessor failed\n", pOptions->getProgramName().getStr()); + else + fprintf(stderr, "%s: preprocessing %s%s failed\n", + pOptions->getProgramName().getStr(), + pathname == nullptr ? "" : "file ", fileName.getStr()); + + osl_freeProcessHandle(hProcess); + exit(hInfo.Code ? hInfo.Code : 99); + } + osl_freeProcessHandle(hProcess); + + if (unlink(tmpFile.getStr()) != 0) + { + fprintf(stderr, "%s: Could not remove cpp input file %s\n", + pOptions->getProgramName().getStr(), tmpFile.getStr()); + exit(99); + } + + if ( pOptions->isValid("-E") ) + { + if (unlink(preprocFile.getStr()) != 0) + { + fprintf(stderr, "%s: Could not remove parser input file %s\n", + pOptions->getProgramName().getStr(), preprocFile.getStr()); + exit(99); + } + exit(0); + } + + // parse file + yyin = fopen(preprocFile.getStr(), "r"); + if (yyin == nullptr) + { + fprintf(stderr, "%s: Could not open cpp output file %s\n", + pOptions->getProgramName().getStr(), preprocFile.getStr()); + exit(99); + } + + //yydebug = 0 no trace information + //yydebug = 1 parser produce trace information + yydebug = 0; + + yyparse(); + sal_Int32 nErrors = idlc()->getErrorCount(); + + fclose(yyin); + if (unlink(preprocFile.getStr()) != 0) + { + fprintf(stderr, "%s: Could not remove parser input file %s\n", + pOptions->getProgramName().getStr(), preprocFile.getStr()); + exit(99); + } + + return nErrors; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/idlc/source/idlcmain.cxx b/idlc/source/idlcmain.cxx new file mode 100644 index 000000000..0c4ded92b --- /dev/null +++ b/idlc/source/idlcmain.cxx @@ -0,0 +1,165 @@ +/* -*- 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 +#include + +#include + +SAL_IMPLEMENT_MAIN_WITH_ARGS(argc, argv) +{ + std::vector< std::string > args; + for (int i = 1; i < argc; i++) + { + if (!Options::checkArgument (args, argv[i], strlen(argv[i]))) + return 1; + } + + Options options(argv[0]); + sal_Int32 nErrors = 0; + + try + { + if (!options.initOptions(args)) + return 0; + + setIdlc(&options); + + if (options.readStdin()) { + if ( !options.quiet() ) + fprintf( + stdout, "%s: Compiling stdin\n", + options.getProgramName().getStr()); + nErrors = compileFile(nullptr); + if ( ( idlc()->getWarningCount() > 0 ) && !options.quiet() ) { + fprintf( + stdout, "%s: detected %lu warnings compiling stdin\n", + options.getProgramName().getStr(), + sal::static_int_cast< unsigned long >( + idlc()->getWarningCount())); + } + OString outputUrl; + if (options.isValid("-O")) { + outputUrl = convertToFileUrl(options.getOption("-O")); + if (!outputUrl.endsWith("/")) { + outputUrl += "/"; + } + outputUrl += "stdin.urd"; + } else { + outputUrl = convertToFileUrl("stdin.urd"); + } + if (nErrors > 0) { + removeIfExists(outputUrl); + } else { + nErrors = produceFile(outputUrl, nullptr); + } + idlc()->reset(); + } + std::vector< OString > const & files = options.getInputFiles(); + if ( options.verbose() ) + { + fprintf( stdout, "%s: compiling %i source files ... \n", + options.getProgramName().getStr(), static_cast(files.size()) ); + fflush( stdout ); + } + for (auto const& elem : files) + { + if (nErrors) + break; + OString sysFileName( convertToAbsoluteSystemPath(elem) ); + + if ( !options.quiet() ) + fprintf(stdout, "Compiling: %s\n", elem.getStr()); + nErrors = compileFile(&sysFileName); + + if ( idlc()->getWarningCount() && !options.quiet() ) + fprintf(stdout, "%s: detected %lu warnings compiling file '%s'\n", + options.getProgramName().getStr(), + sal::static_int_cast< unsigned long >( + idlc()->getWarningCount()), + elem.getStr()); + + // prepare output file name + OString const strippedFileName( + sysFileName.copy(sysFileName.lastIndexOf(SEPARATOR) + 1)); + OString outputFile; + if ( options.isValid("-O") ) + { + outputFile = options.getOption("-O"); + if (!outputFile.endsWith("/")) { + outputFile += OString('/'); + } + outputFile += strippedFileName.replaceAt( + strippedFileName.getLength() -3 , 3, "urd"); + } else { + outputFile = + sysFileName.replaceAt(sysFileName.getLength() -3 , 3, "urd"); + } + OString const outputFileUrl = convertToFileUrl(outputFile); + + OString depFileUrl; + if (options.isValid("-M")) { + depFileUrl = convertToFileUrl(options.getOption("-M")); + if (!depFileUrl.endsWith("/")) { + depFileUrl += "/"; + } + depFileUrl += strippedFileName.replaceAt( + strippedFileName.getLength() -3 , 3, "d"); + } + + if ( nErrors ) { + if (options.isValid("-M")) { + removeIfExists(depFileUrl); + } + removeIfExists(outputFileUrl); + } else { + sPair_t const pair(depFileUrl, outputFile); + nErrors = produceFile(outputFileUrl, + (options.isValid("-M")) ? &pair : nullptr); + } + + idlc()->reset(); + } + + if ( nErrors > 0 ) + { + fprintf(stderr, "%s: detected %ld errors%s", + options.getProgramName().getStr(), + sal::static_int_cast< long >(nErrors), + options.prepareVersion().getStr()); + } else + { + if ( options.verbose() ) + fprintf(stdout, "%s: returned successful%s", + options.getProgramName().getStr(), + options.prepareVersion().getStr()); + } + } catch(const IllegalArgument& e) + { + fprintf(stderr, "Illegal argument: %s\n%s", + e.m_message.getStr(), + options.prepareVersion().getStr()); + return 99; + } + + return nErrors; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/idlc/source/idlcproduce.cxx b/idlc/source/idlcproduce.cxx new file mode 100644 index 000000000..ff9ca2f2d --- /dev/null +++ b/idlc/source/idlcproduce.cxx @@ -0,0 +1,245 @@ +/* -*- 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 +#include +#include +#include +#include + +#if defined(_WIN32) +#include +#include +#include +#endif + +#ifdef SAL_UNX +#include +#include +#include +#endif + +#include + +using namespace ::osl; + +static std::list< OString >* pCreatedDirectories = nullptr; + +static bool checkOutputPath(const OString& completeName) +{ + OString sysPathName = convertToAbsoluteSystemPath(completeName); + OStringBuffer buffer(sysPathName.getLength()+16); + + if ( sysPathName.indexOf( SEPARATOR ) == -1 ) + return true; + + sal_Int32 nIndex = 0; + OString token(sysPathName.getToken(0, SEPARATOR, nIndex)); + if (token.startsWith("..") + || (token.getLength() >= 2 && token[1] == ':') + || token.startsWith(".")) + { + buffer.append(token); + buffer.append(SEPARATOR); + } + else + nIndex = 0; + + do + { + buffer.append(sysPathName.getToken(0, SEPARATOR, nIndex)); + + if ( !buffer.isEmpty() && nIndex != -1 ) + { +#if defined(SAL_UNX) + if (mkdir(buffer.getStr(), 0777) == -1) +#else + if (mkdir(buffer.getStr()) == -1) +#endif + { + if (errno == ENOENT) + { + fprintf(stderr, "%s: cannot create directory '%s'\n", + idlc()->getOptions()->getProgramName().getStr(), buffer.getStr()); + return false; + } + } else + { + if ( !pCreatedDirectories ) + pCreatedDirectories = new std::list< OString >; + pCreatedDirectories->push_front(buffer.getStr()); + } + } + buffer.append(SEPARATOR); + } while( nIndex != -1 ); + return true; +} + +static bool cleanPath() +{ + if ( pCreatedDirectories ) + { + for (auto const& createdDirectory : *pCreatedDirectories) + { +//#ifdef SAL_UNX +// if (rmdir((char*)createdDirectory.getStr(), 0777) == -1) +//#else + if (rmdir(createdDirectory.getStr()) == -1) +//#endif + { + fprintf(stderr, "%s: cannot remove directory '%s'\n", + idlc()->getOptions()->getProgramName().getStr(), createdDirectory.getStr()); + return false; + } + } + delete pCreatedDirectories; + } + return true; +} + +void removeIfExists(const OString& pathname) +{ + osl::File::remove(OStringToOUString(pathname, RTL_TEXTENCODING_UTF8)); +} + +sal_Int32 +produceFile(const OString& regFileName, sPair_t const*const pDepFile) +{ + Options* pOptions = idlc()->getOptions(); + + OString regTmpName = regFileName.replaceAt(regFileName.getLength() -3, 3, "_idlc_"); + + if ( !checkOutputPath(regFileName) ) + { + fprintf(stderr, "%s: could not create path of registry file '%s'.\n", + pOptions->getProgramName().getStr(), regFileName.getStr()); + return 1; + } + + OString depTmpName; + if (pDepFile) + { + depTmpName = pDepFile->first.replaceAt( + regFileName.getLength() -3, 3, "_idlc_"); + if ( !checkOutputPath(depTmpName) ) + { + fprintf(stderr, "%s: could not create path of dep file '%s'.\n", + pOptions->getProgramName().getStr(), pDepFile->first.getStr()); + return 1; + } + removeIfExists(depTmpName); + } + + removeIfExists(regTmpName); + OString urlRegTmpName = convertToFileUrl(regTmpName); + + Registry regFile; + if ( regFile.create(OStringToOUString(urlRegTmpName, RTL_TEXTENCODING_UTF8)) != RegError::NO_ERROR ) + { + fprintf(stderr, "%s: could not create registry file '%s'\n", + pOptions->getProgramName().getStr(), regTmpName.getStr()); + removeIfExists(regTmpName); + removeIfExists(regFileName); + cleanPath(); + return 1; + } + + RegistryKey rootKey; + if ( regFile.openRootKey(rootKey) != RegError::NO_ERROR ) + { + fprintf(stderr, "%s: could not open root of registry file '%s'\n", + pOptions->getProgramName().getStr(), regFileName.getStr()); + removeIfExists(regTmpName); + removeIfExists(regFileName); + cleanPath(); + return 1; + } + + // produce registry file + if ( !idlc()->getRoot()->dump(rootKey) ) + { + rootKey.releaseKey(); + if (regFile.close() != RegError::NO_ERROR) + { + fprintf(stderr, "%s: could not close registry file '%s'\n", + pOptions->getProgramName().getStr(), regFileName.getStr()); + } + regFile.destroy(OStringToOUString(regFileName, RTL_TEXTENCODING_UTF8)); + removeIfExists(regFileName); + cleanPath(); + return 1; + } + + rootKey.releaseKey(); + if ( regFile.close() != RegError::NO_ERROR ) + { + fprintf(stderr, "%s: could not close registry file '%s'\n", + pOptions->getProgramName().getStr(), regFileName.getStr()); + removeIfExists(regTmpName); + removeIfExists(regFileName); + cleanPath(); + return 1; + } + + if (pDepFile && !idlc()->dumpDeps(depTmpName, pDepFile->second)) + { + fprintf(stderr, "%s: could not write dep file '%s'\n", + pOptions->getProgramName().getStr(), pDepFile->first.getStr()); + removeIfExists(depTmpName); + removeIfExists(pDepFile->first); + removeIfExists(regTmpName); + removeIfExists(regFileName); + cleanPath(); + return 1; + } + + removeIfExists(regFileName); + + if ( File::move(OStringToOUString(regTmpName, osl_getThreadTextEncoding()), + OStringToOUString(regFileName, osl_getThreadTextEncoding())) != FileBase::E_None ) { + fprintf(stderr, "%s: cannot rename temporary registry '%s' to '%s'\n", + idlc()->getOptions()->getProgramName().getStr(), + regTmpName.getStr(), regFileName.getStr()); + removeIfExists(regTmpName); + cleanPath(); + return 1; + } + removeIfExists(regTmpName); + + if (pDepFile) + { + removeIfExists(pDepFile->first); + if ( File::move(OStringToOUString(depTmpName, osl_getThreadTextEncoding()), + OStringToOUString(pDepFile->first, osl_getThreadTextEncoding())) != FileBase::E_None ) { + fprintf(stderr, "%s: cannot rename dep file '%s' to '%s'\n", + idlc()->getOptions()->getProgramName().getStr(), + depTmpName.getStr(), pDepFile->first.getStr()); + removeIfExists(depTmpName); + removeIfExists(pDepFile->first); + removeIfExists(regFileName); + cleanPath(); + return 1; + } + removeIfExists(depTmpName); + } + + return 0; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/idlc/source/options.cxx b/idlc/source/options.cxx new file mode 100644 index 000000000..2f2e3bb1e --- /dev/null +++ b/idlc/source/options.cxx @@ -0,0 +1,421 @@ +/* -*- 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 + +#include +#include +#include + +#include +#include +#include + +#ifdef _WIN32 +# if !defined WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +#endif + +#include +#include + + +Options::Options(char const * progname) + : m_program(progname), m_stdin(false), m_verbose(false), m_quiet(false) +{ +} + +Options::~Options() +{ +} + +// static +bool Options::checkArgument (std::vector< std::string > & rArgs, char const * arg, size_t len) +{ + bool result = ((arg != nullptr) && (len > 0)); + OSL_PRECOND(result, "idlc::Options::checkArgument(): invalid arguments"); + if (result) + { + switch(arg[0]) + { + case '@': + result = len > 1; + if (result) + { + // "@" + result = Options::checkCommandFile (rArgs, &(arg[1])); + } + break; + case '-': + result = len > 1; + if (result) + { + // "-