Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/unoidl/source/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 165 kB image not shown  

Quelle  sourceprovider-parser.y   Sprache: unbekannt

 
/* -*- 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/.
 */

/*TODO: check Exception, RuntimeException, XInterface defns */

%locations
%pure-parser

%{

#include <sal/config.h>

#include <o3tl/unreachable.hxx>
#include <o3tl/string_view.hxx>
#include <rtl/ustrbuf.hxx>
#include <unoidl/unoidl.hxx>

#include <algorithm>
#include <cassert>
#include <cerrno>
#include <cstddef>
#include <cstdlib>
#include <limits>
#include <new>
#include <utility>
#include <vector>

#include "sourceprovider-parser-requires.hxx"

%}

%union {
    sal_uInt64 ival;
    double fval;
    OString * sval;

    bool bval;
    std::vector<OUString> * excns;
    unoidl::detail::SourceProviderAccessDecls decls;
    unoidl::InterfaceTypeEntity::Method::Parameter::Direction dir;
    unoidl::detail::SourceProviderFlags flags;
    unoidl::detail::SourceProviderExpr expr;
    unoidl::detail::SourceProviderType * type;
    std::vector<unoidl::detail::SourceProviderType> * types;
}

/* TODO: %destructor { delete $$; } <sval> <excns> <type> <types> */

%lex-param {yyscan_t yyscanner}
%parse-param {yyscan_t yyscanner}

%{

#include <osl/file.h>
#include <osl/thread.h>
#include <sal/log.hxx>

#include "sourceprovider-scanner.hxx"

#define YYLLOC_DEFAULT(Current, Rhs, N) \
    do { (Current) = YYRHSLOC((Rhs), (N) ? 1 : 0); } while (0)

static void yyerror(YYLTYPE * locp, yyscan_t yyscanner, char const * msg) {
    assert(locp != nullptr);
    unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
    data->errorLine = *locp;
    data->parserError = OString(msg);
}

namespace {

void error(YYLTYPE location, yyscan_t yyscanner, OUString const & message) {
    unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
    data->errorLine = location;
    data->errorMessage = message;
}

OUString flagName(unoidl::detail::SourceProviderFlags flag) {
    switch (flag) {
    case unoidl::detail::FLAG_ATTRIBUTE:
        return u"attribute"_ustr;
    case unoidl::detail::FLAG_BOUND:
        return u"bound"_ustr;
    case unoidl::detail::FLAG_CONSTRAINED:
        return u"constrained"_ustr;
    case unoidl::detail::FLAG_MAYBEAMBIGUOUS:
        return u"maybeambiguous"_ustr;
    case unoidl::detail::FLAG_MAYBEDEFAULT:
        return u"maybedefault"_ustr;
    case unoidl::detail::FLAG_MAYBEVOID:
        return u"maybevoid"_ustr;
    case unoidl::detail::FLAG_OPTIONAL:
        return u"optional"_ustr;
    case unoidl::detail::FLAG_PROPERTY:
        return u"property"_ustr;
    case unoidl::detail::FLAG_READONLY:
        return u"readonly"_ustr;
    case unoidl::detail::FLAG_REMOVABLE:
        return u"removable"_ustr;
    case unoidl::detail::FLAG_TRANSIENT:
        return u"transient"_ustr;
    default:
        assert(false && "this cannot happen"); for (;;) { std::abort(); }
    }
}

OUString convertName(OString const * name) {
    assert(name != nullptr);
    OUString s(OStringToOUString(*name, RTL_TEXTENCODING_ASCII_US));
    delete name;
    return s;
}

OUString convertToFullName(
    unoidl::detail::SourceProviderScannerData const * data,
    OString const * identifier)
{
    assert(data != nullptr);
    OUString pref;
    if (!data->modules.empty()) {
        pref = data->modules.back() + ".";
    }
    return pref + convertName(identifier);
}

void convertToCurrentName(
    unoidl::detail::SourceProviderScannerData * data,
    OString const * identifier)
{
    assert(data != nullptr);
    assert(data->currentName.isEmpty());
    data->currentName = convertToFullName(data, identifier);
    assert(!data->currentName.isEmpty());
}

void clearCurrentState(unoidl::detail::SourceProviderScannerData * data) {
    assert(data != nullptr);
    data->currentName.clear();
    data->publishedContext = false;
}

unoidl::detail::SourceProviderEntity * getCurrentEntity(
    unoidl::detail::SourceProviderScannerData * data)
{
    assert(data != nullptr);
    assert(!data->currentName.isEmpty());
    std::map<OUString, unoidl::detail::SourceProviderEntity>::iterator i(
        data->entities.find(data->currentName));
    assert(i != data->entities.end());
    assert(i->second.kind == unoidl::detail::SourceProviderEntity::KIND_LOCAL);
    assert(i->second.pad.is());
    return &i->second;
}

template<typename T> rtl::Reference<T> getCurrentPad(
    unoidl::detail::SourceProviderScannerData * data)
{
    rtl::Reference<T> pad(dynamic_cast<T *>(getCurrentEntity(data)->pad.get()));
    assert(pad.is());
    return pad;
}

bool nameHasSameIdentifierAs(std::u16string_view name, std::u16string_view identifier)
{
    std::u16string_view::size_type pos = name.rfind('.');
    size_t i = (pos != std::u16string_view::npos) ? pos + 1 : 0;
    return identifier.size() == name.size() - i
        && o3tl::starts_with(name.substr(i), identifier);
}

bool coerce(
    YYLTYPE location, yyscan_t yyscanner,
    unoidl::detail::SourceProviderExpr * lhs,
    unoidl::detail::SourceProviderExpr * rhs)
{
    assert(lhs != nullptr);
    assert(rhs != nullptr);
    bool ok = bool(); // avoid warnings
    switch (lhs->type) {
    case unoidl::detail::SourceProviderExpr::TYPE_BOOL:
        ok = rhs->type != unoidl::detail::SourceProviderExpr::TYPE_BOOL;
        break;
    case unoidl::detail::SourceProviderExpr::TYPE_INT:
        switch (rhs->type) {
        case unoidl::detail::SourceProviderExpr::TYPE_BOOL:
            ok = false;
            break;
        case unoidl::detail::SourceProviderExpr::TYPE_INT:
            ok = true;
            break;
        case unoidl::detail::SourceProviderExpr::TYPE_UINT:
            if (lhs->ival >= 0) {
                lhs->type = unoidl::detail::SourceProviderExpr::TYPE_UINT;
                ok = true;
            } else if (rhs->uval <= SAL_MAX_INT64) {
                rhs->type = unoidl::detail::SourceProviderExpr::TYPE_INT;
                ok = true;
            } else {
                ok = false;
            }
            break;
        case unoidl::detail::SourceProviderExpr::TYPE_FLOAT:
            {
                auto tmp = lhs->ival;
                lhs->fval = tmp;
                ok = true;
            }
            break;
        }
        break;
    case unoidl::detail::SourceProviderExpr::TYPE_UINT:
        switch (rhs->type) {
        case unoidl::detail::SourceProviderExpr::TYPE_BOOL:
            ok = false;
            break;
        case unoidl::detail::SourceProviderExpr::TYPE_INT:
            if (rhs->ival >= 0) {
                rhs->type = unoidl::detail::SourceProviderExpr::TYPE_UINT;
                ok = true;
            } else if (lhs->uval <= SAL_MAX_INT64) {
                lhs->type = unoidl::detail::SourceProviderExpr::TYPE_INT;
                ok = true;
            } else {
                ok = false;
            }
            break;
        case unoidl::detail::SourceProviderExpr::TYPE_UINT:
            ok = true;
            break;
        case unoidl::detail::SourceProviderExpr::TYPE_FLOAT:
            {
                auto nTmp = lhs->uval;
                lhs->fval = nTmp;
                ok = true;
            }
            break;
        }
        break;
    case unoidl::detail::SourceProviderExpr::TYPE_FLOAT:
        switch (rhs->type) {
        case unoidl::detail::SourceProviderExpr::TYPE_BOOL:
            ok = false;
            break;
        case unoidl::detail::SourceProviderExpr::TYPE_INT:
            {
                auto tmp = rhs->ival;
                rhs->fval = tmp;
                ok = true;
            }
            break;
        case unoidl::detail::SourceProviderExpr::TYPE_UINT:
            {
                auto tmp = rhs->uval;
                rhs->fval = tmp;
                ok = true;
            }
            break;
        case unoidl::detail::SourceProviderExpr::TYPE_FLOAT:
            ok = true;
            break;
        }
        break;
    }
    if (!ok) {
        error(location, yyscanner, u"cannot coerce binary expression arguments"_ustr);
    }
    return ok;
}

unoidl::detail::SourceProviderEntity * findEntity_(
    unoidl::detail::SourceProviderScannerData * data, OUString * name)
{
    assert(data != nullptr);
    assert(name != nullptr);
    OUString n;
    if (!name->startsWith(".", &n)) {
        for (auto i(data->modules.rbegin()); i != data->modules.rend(); ++i) {
            n = *i + "." + *name;
            std::map<OUString, unoidl::detail::SourceProviderEntity>::iterator j(
                data->entities.find(n));
            if (j != data->entities.end()) {
                *name = n;
                return &j->second;
            }
            rtl::Reference<unoidl::Entity> ent(data->manager->findEntity(n));
            if (ent.is()) {
                std::map<OUString, unoidl::detail::SourceProviderEntity>::iterator
                    k(data->entities.emplace(
                              n,
                              unoidl::detail::SourceProviderEntity(
                                  unoidl::detail::SourceProviderEntity::KIND_EXTERNAL,
                                  ent)).
                      first);
                *name = n;
                return &k->second;
            }
        }
        n = *name;
    }
    std::map<OUString, unoidl::detail::SourceProviderEntity>::iterator i(
        data->entities.find(n));
    if (i != data->entities.end()) {
        *name = n;
        return &i->second;
    }
    rtl::Reference<unoidl::Entity> ent(data->manager->findEntity(n));
    if (ent.is()) {
        std::map<OUString, unoidl::detail::SourceProviderEntity>::iterator
            j(data->entities.emplace(
                      n,
                      unoidl::detail::SourceProviderEntity(
                          unoidl::detail::SourceProviderEntity::KIND_EXTERNAL,
                          ent)).
              first);
        *name = n;
        return &j->second;
    }
    return nullptr;
}

enum Found { FOUND_ERROR, FOUND_TYPE, FOUND_ENTITY };

Found findEntity(
    YYLTYPE location, yyscan_t yyscanner,
    unoidl::detail::SourceProviderScannerData * data,
    bool resolveInterfaceDefinitions, OUString * name,
    unoidl::detail::SourceProviderEntity const ** entity, bool * typedefed,
    unoidl::detail::SourceProviderType * typedefedType)
{
    //TODO: avoid recursion
    assert(data != nullptr);
    assert(name != nullptr);
    assert(entity != nullptr);
    unoidl::detail::SourceProviderEntity * e = findEntity_(data, name);
    OUString n(*name);
    OUString typeNucleus;
    std::size_t rank = 0;
    std::vector<unoidl::detail::SourceProviderType> args;
    for (;;) {
        if (e != nullptr) {
            switch (e->kind) {
            case unoidl::detail::SourceProviderEntity::KIND_LOCAL:
                if (e->pad.is()) {
                    break;
                }
                assert(e->entity.is());
                [[fallthrough]];
            case unoidl::detail::SourceProviderEntity::KIND_EXTERNAL:
                if (e->entity->getSort() == unoidl::Entity::SORT_TYPEDEF) {
                    if (typedefed != nullptr) {
                        *typedefed = true;
                    }
                    if (data->publishedContext
                        && !static_cast<unoidl::TypedefEntity *>(
                            e->entity.get())->isPublished())
                    {
                        error(
                            location, yyscanner,
                            ("type " + *name + " based on unpublished typedef "
                             + n + " used in published context"));
                        return FOUND_ERROR;
                    }
                    OUString t(
                        static_cast<unoidl::TypedefEntity *>(e->entity.get())
                        ->getType());
                    typeNucleus = t;
                    while (typeNucleus.startsWith("[]", &typeNucleus)) {
                        if (!args.empty()) {
                            error(
                                location, yyscanner,
                                ("inconsistent type manager: bad type " + *name
                                 + (" based on instantiated polymorphic struct"
                                    " type based on sequence type named ")
                                 + t));
                            return FOUND_ERROR;
                        }
                        if (rank == std::numeric_limits<std::size_t>::max()) {
                            error(
                                location, yyscanner,
                                ("bad type " + *name
                                 + " based on sequence type of too high rank"));
                            return FOUND_ERROR;
                        }
                        ++rank;
                    }
                    sal_Int32 i = typeNucleus.indexOf('<');
                    if (i != -1) {
                        if (!args.empty()) {
                            error(
                                location, yyscanner,
                                ("inconsistent type manager: bad type " + *name
                                 + (" based on instantiated polymorphic struct"
                                    " type based on instantiated polymorphic"
                                    " struct type named ")
                                 + t));
                            return FOUND_ERROR;
                        }
                        std::u16string_view tmpl(typeNucleus.subView(0, i));
                        do {
                            ++i; // skip '<' or ','
                            sal_Int32 j = i;
                            for (sal_Int32 level = 0;
                                 j != typeNucleus.getLength(); ++j)
                            {
                                sal_Unicode c = typeNucleus[j];
                                if (c == ',') {
                                    if (level == 0) {
                                        break;
                                    }
                                } else if (c == '<') {
                                    ++level;
                                } else if (c == '>') {
                                    if (level == 0) {
                                        break;
                                    }
                                    --level;
                                }
                            }
                            if (j != typeNucleus.getLength()) {
                                OUString argName(typeNucleus.copy(i, j - i));
                                unoidl::detail::SourceProviderEntity const *
                                    argEnt;
                                unoidl::detail::SourceProviderType argType;
                                switch (
                                    findEntity(
                                        location, yyscanner, data, false,
                                        &argName, &argEnt, nullptr, &argType))
                                {
                                case FOUND_ERROR:
                                    return FOUND_ERROR;
                                case FOUND_TYPE:
                                    break;
                                case FOUND_ENTITY:
                                    if (argEnt == nullptr) {
                                        error(
                                            location, yyscanner,
                                            (("inconsistent type manager: bad"
                                              " instantiated polymorphic struct"
                                              " type template type argument ")
                                             + argName));
                                        return FOUND_ERROR;
                                    } else {
                                        unoidl::detail::SourceProviderType::Type
                                            argT
                                            = unoidl::detail::SourceProviderType::Type();
                                            // avoid warnings
                                        switch (argEnt->kind) {
                                        case unoidl::detail::SourceProviderEntity::KIND_LOCAL:
                                            if (e->pad.is()) {
                                                error(
                                                    location, yyscanner,
                                                    (("inconsistent type"
                                                      " manager: bad"
                                                      " instantiated"
                                                      " polymorphic struct type"
                                                      " template type"
                                                      " argument ")
                                                     + argName));
                                                return FOUND_ERROR;
                                            }
                                            assert(e->entity.is());
                                            [[fallthrough]];
                                        case unoidl::detail::SourceProviderEntity::KIND_EXTERNAL:
                                            switch (e->entity->getSort()) {
                                            case unoidl::Entity::SORT_ENUM_TYPE:
                                                argT = unoidl::detail::SourceProviderType::TYPE_ENUM;
                                                break;
                                            case unoidl::Entity::SORT_PLAIN_STRUCT_TYPE:
                                                argT = unoidl::detail::SourceProviderType::TYPE_PLAIN_STRUCT;
                                                break;
                                            case unoidl::Entity::SORT_INTERFACE_TYPE:
                                                argT = unoidl::detail::SourceProviderType::TYPE_INTERFACE;
                                                break;
                                            default:
                                                error(
                                                    location, yyscanner,
                                                    (("inconsistent type"
                                                      "manager: bad"
                                                      " instantiated"
                                                      " polymorphic struct type"
                                                      " template type"
                                                      " argument ")
                                                     + argName));
                                                return FOUND_ERROR;
                                            }
                                            break;
                                        case unoidl::detail::SourceProviderEntity::KIND_INTERFACE_DECL:
                                        case unoidl::detail::SourceProviderEntity::KIND_PUBLISHED_INTERFACE_DECL:
                                            argT = unoidl::detail::SourceProviderType::TYPE_INTERFACE;
                                            break;
                                        case unoidl::detail::SourceProviderEntity::KIND_MODULE:
                                            assert(false && "this cannot happen");
                                        }
                                        argType
                                            = unoidl::detail::SourceProviderType(
                                                argT, argName, argEnt);
                                    }
                                    break;
                                }
                                args.push_back(argType);
                            }
                            i = j;
                        } while (i != typeNucleus.getLength()
                                 && typeNucleus[i] != '>');
                        if (i != typeNucleus.getLength() - 1
                            || typeNucleus[i] != '>')
                        {
                            error(
                                location, yyscanner,
                                ("inconsistent type manager: bad type name \""
                                 + t + "\""));
                            return FOUND_ERROR;
                        }
                        assert(!args.empty());
                        typeNucleus = tmpl;
                    }
                    if (typeNucleus.isEmpty()) {
                        error(
                            location, yyscanner,
                            ("inconsistent type manager: bad type name \"" + t
                             + "\""));
                        return FOUND_ERROR;
                    }
                    if (typeNucleus == "void") {
                        error(
                            location, yyscanner,
                            ("inconsistent type manager: bad type " + *name
                             + " based on void"));
                        return FOUND_ERROR;
                    }
                    if (typeNucleus == "boolean" || typeNucleus == "byte"
                        || typeNucleus == "short"
                        || typeNucleus == "unsigned short"
                        || typeNucleus == "long"
                        || typeNucleus == "unsigned long"
                        || typeNucleus == "hyper"
                        || typeNucleus == "unsigned hyper"
                        || typeNucleus == "float" || typeNucleus == "double"
                        || typeNucleus == "char" || typeNucleus == "string"
                        || typeNucleus == "type" || typeNucleus == "any")
                    {
                        if (!args.empty()) {
                            error(
                                location, yyscanner,
                                ("inconsistent type manager: bad type " + *name
                                 + (" based on instantiated polymorphic struct"
                                    " type based on ")
                                 + typeNucleus));
                            return FOUND_ERROR;
                        }
                        break;
                    }
                    n = "." + typeNucleus;
                    typeNucleus.clear();
                    e = findEntity_(data, &n);
                    continue;
                }
                break;
            case unoidl::detail::SourceProviderEntity::KIND_INTERFACE_DECL:
            case unoidl::detail::SourceProviderEntity::KIND_PUBLISHED_INTERFACE_DECL:
                if (resolveInterfaceDefinitions) {
                    rtl::Reference<unoidl::Entity> ent(
                        data->manager->findEntity(n));
                    // Do not allow ent to be of SORT_TYPEDEF:
                    if (!ent.is()
                        || (ent->getSort()
                            != unoidl::Entity::SORT_INTERFACE_TYPE))
                    {
                        error(
                            location, yyscanner,
                            (*name + " is based on interface declaration " + n
                             + " that is not an interface type entity"));
                        return FOUND_ERROR;
                    }
                    e->kind
                        = unoidl::detail::SourceProviderEntity::KIND_EXTERNAL;
                    e->entity = std::move(ent);
                }
                break;
            case unoidl::detail::SourceProviderEntity::KIND_MODULE:
                error(
                    location, yyscanner,
                    *name + " is based on module entity " + n);
                return FOUND_ERROR;
            }
        }
        if (!typeNucleus.isEmpty() || rank != 0 || !args.empty()) {
            if (typeNucleus.isEmpty() && e == nullptr) {
                // Found a type name based on an unknown entity:
                *entity = nullptr;
                return FOUND_ENTITY;
            }
            unoidl::detail::SourceProviderType t;
            if (args.empty()) {
                if (typeNucleus == "boolean") {
                    t = unoidl::detail::SourceProviderType(
                        unoidl::detail::SourceProviderType::TYPE_BOOLEAN);
                } else if (typeNucleus == "byte") {
                    t = unoidl::detail::SourceProviderType(
                        unoidl::detail::SourceProviderType::TYPE_BYTE);
                } else if (typeNucleus == "short") {
                    t = unoidl::detail::SourceProviderType(
                        unoidl::detail::SourceProviderType::TYPE_SHORT);
                } else if (typeNucleus == "unsigned short") {
                    t = unoidl::detail::SourceProviderType(
                        unoidl::detail::SourceProviderType::TYPE_UNSIGNED_SHORT);
                } else if (typeNucleus == "long") {
                    t = unoidl::detail::SourceProviderType(
                        unoidl::detail::SourceProviderType::TYPE_LONG);
                } else if (typeNucleus == "unsigned long") {
                    t = unoidl::detail::SourceProviderType(
                        unoidl::detail::SourceProviderType::TYPE_UNSIGNED_LONG);
                } else if (typeNucleus == "hyper") {
                    t = unoidl::detail::SourceProviderType(
                        unoidl::detail::SourceProviderType::TYPE_HYPER);
                } else if (typeNucleus == "unsigned hyper") {
                    t = unoidl::detail::SourceProviderType(
                        unoidl::detail::SourceProviderType::TYPE_UNSIGNED_HYPER);
                } else if (typeNucleus == "float") {
                    t = unoidl::detail::SourceProviderType(
                        unoidl::detail::SourceProviderType::TYPE_FLOAT);
                } else if (typeNucleus == "double") {
                    t = unoidl::detail::SourceProviderType(
                        unoidl::detail::SourceProviderType::TYPE_DOUBLE);
                } else if (typeNucleus == "char") {
                    t = unoidl::detail::SourceProviderType(
                        unoidl::detail::SourceProviderType::TYPE_CHAR);
                } else if (typeNucleus == "string") {
                    t = unoidl::detail::SourceProviderType(
                        unoidl::detail::SourceProviderType::TYPE_STRING);
                } else if (typeNucleus == "type") {
                    t = unoidl::detail::SourceProviderType(
                        unoidl::detail::SourceProviderType::TYPE_TYPE);
                } else if (typeNucleus == "any") {
                    t = unoidl::detail::SourceProviderType(
                        unoidl::detail::SourceProviderType::TYPE_ANY);
                } else {
                    assert(typeNucleus.isEmpty());
                    assert(e != nullptr);
                    switch (e->kind) {
                    case unoidl::detail::SourceProviderEntity::KIND_LOCAL:
                        if (e->pad.is()) {
                            if (dynamic_cast<unoidl::detail::SourceProviderEnumTypeEntityPad *>(
                                    e->pad.get())
                                != nullptr)
                            {
                                t = unoidl::detail::SourceProviderType(
                                    unoidl::detail::SourceProviderType::TYPE_ENUM,
                                    n, e);
                            } else if (dynamic_cast<unoidl::detail::SourceProviderPlainStructTypeEntityPad *>(
                                           e->pad.get())
                                       != nullptr)
                            {
                                t = unoidl::detail::SourceProviderType(
                                    unoidl::detail::SourceProviderType::TYPE_PLAIN_STRUCT,
                                    n, e);
                            } else if (dynamic_cast<unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad *>(
                                           e->pad.get())
                                       != nullptr)
                            {
                                error(
                                    location, yyscanner,
                                    ("bad type " + *name
                                     + (" based on recursive reference to"
                                        " polymorphic struct type template ")
                                     + n));
                                return FOUND_ERROR;
                            } else if (dynamic_cast<unoidl::detail::SourceProviderExceptionTypeEntityPad *>(
                                           e->pad.get())
                                       != nullptr)
                            {
                                t = unoidl::detail::SourceProviderType(
                                    unoidl::detail::SourceProviderType::TYPE_EXCEPTION,
                                    n, e);
                            } else if (dynamic_cast<unoidl::detail::SourceProviderInterfaceTypeEntityPad *>(
                                           e->pad.get())
                                       != nullptr)
                            {
                                t = unoidl::detail::SourceProviderType(
                                    unoidl::detail::SourceProviderType::TYPE_INTERFACE,
                                    n, e);
                            } else {
                                error(
                                    location, yyscanner,
                                    ("bad type " + *name
                                     + " based on non-type entity " + n));
                                return FOUND_ERROR;
                            }
                            break;
                        }
                        assert(e->entity.is());
                        [[fallthrough]];
                    case unoidl::detail::SourceProviderEntity::KIND_EXTERNAL:
                        switch (e->entity->getSort()) {
                        case unoidl::Entity::SORT_ENUM_TYPE:
                            t = unoidl::detail::SourceProviderType(
                                unoidl::detail::SourceProviderType::TYPE_ENUM,
                                n, e);
                            break;
                        case unoidl::Entity::SORT_PLAIN_STRUCT_TYPE:
                            t = unoidl::detail::SourceProviderType(
                                unoidl::detail::SourceProviderType::TYPE_PLAIN_STRUCT,
                                n, e);
                            break;
                        case unoidl::Entity::SORT_POLYMORPHIC_STRUCT_TYPE_TEMPLATE:
                            error(
                                location, yyscanner,
                                ("bad type " + *name
                                 + " based on polymorphic struct type template "
                                 + n + " without type arguments"));
                            return FOUND_ERROR;
                        case unoidl::Entity::SORT_EXCEPTION_TYPE:
                            t = unoidl::detail::SourceProviderType(
                                unoidl::detail::SourceProviderType::TYPE_EXCEPTION,
                                n, e);
                            break;
                        case unoidl::Entity::SORT_INTERFACE_TYPE:
                            t = unoidl::detail::SourceProviderType(
                                unoidl::detail::SourceProviderType::TYPE_INTERFACE,
                                n, e);
                            break;
                        default:
                            error(
                                location, yyscanner,
                                ("bad type " + *name
                                 + " based on non-type entity " + n));
                            return FOUND_ERROR;
                        }
                        break;
                    case unoidl::detail::SourceProviderEntity::KIND_INTERFACE_DECL:
                    case unoidl::detail::SourceProviderEntity::KIND_PUBLISHED_INTERFACE_DECL:
                        t = unoidl::detail::SourceProviderType(
                            unoidl::detail::SourceProviderType::TYPE_INTERFACE,
                            n, e);
                        break;
                    case unoidl::detail::SourceProviderEntity::KIND_MODULE:
                        assert(false && "this cannot happen");
                    }
                }
            } else {
                assert(typeNucleus.isEmpty());
                assert(e != nullptr);
                switch (e->kind) {
                case unoidl::detail::SourceProviderEntity::KIND_LOCAL:
                    if (e->pad.is()) {
                        error(
                            location, yyscanner,
                            ("bad type " + *name
                             + (" based on instantiated polymorphic struct type"
                                " based on ")
                             + n
                             + (" that is either not a polymorphic struct type"
                                " template or a recursive reference to a"
                                " polymorphic struct type template")));
                        return FOUND_ERROR;
                    }
                    assert(e->entity.is());
                    [[fallthrough]];
                case unoidl::detail::SourceProviderEntity::KIND_EXTERNAL:
                    if (e->entity->getSort()
                        == unoidl::Entity::SORT_POLYMORPHIC_STRUCT_TYPE_TEMPLATE)
                    {
                        if (args.size()
                            != (static_cast<
                                    unoidl::PolymorphicStructTypeTemplateEntity *>(
                                        e->entity.get())
                                ->getTypeParameters().size()))
                        {
                            error(
                                location, yyscanner,
                                ("bad type " + *name
                                 + (" based on instantiated polymorphic struct"
                                    " type with ")
                                 + OUString::number(args.size())
                                 + (" type arguments based on polymorphic"
                                    " struct type template ")
                                 + n + " with "
                                 + OUString::number(
                                     static_cast<
                                         unoidl::PolymorphicStructTypeTemplateEntity *>(
                                             e->entity.get())
                                     ->getTypeParameters().size())
                                 + " type parameters"));
                            return FOUND_ERROR;
                        }
                        t = unoidl::detail::SourceProviderType(n, e, std::move(args));
                        break;
                    }
                    [[fallthrough]];
                case unoidl::detail::SourceProviderEntity::KIND_INTERFACE_DECL:
                case unoidl::detail::SourceProviderEntity::KIND_PUBLISHED_INTERFACE_DECL:
                    error(
                        location, yyscanner,
                        ("bad type " + *name
                         + (" based on instantiated polymorphic struct type"
                            " based on ")
                         + n
                         + " that is not a polymorphic struct type template"));
                    return FOUND_ERROR;
                case unoidl::detail::SourceProviderEntity::KIND_MODULE:
                    assert(false && "this cannot happen");
                }
            }
            if (typedefedType != nullptr) {
                for (std::size_t i = 0; i != rank; ++i) {
                    t = unoidl::detail::SourceProviderType(&t);
                }
                *typedefedType = std::move(t);
                typedefedType->typedefName = *name;
            }
            *entity = nullptr;
            return FOUND_TYPE;
        }
        *entity = e;
        return FOUND_ENTITY;
    }
}


bool checkTypeArgument(
    YYLTYPE location, yyscan_t yyscanner,
    unoidl::detail::SourceProviderType const & type)
{
    switch (type.type) {
    case unoidl::detail::SourceProviderType::TYPE_VOID:
    case unoidl::detail::SourceProviderType::TYPE_UNSIGNED_SHORT:
    case unoidl::detail::SourceProviderType::TYPE_UNSIGNED_LONG:
    case unoidl::detail::SourceProviderType::TYPE_UNSIGNED_HYPER:
    case unoidl::detail::SourceProviderType::TYPE_EXCEPTION:
    case unoidl::detail::SourceProviderType::TYPE_PARAMETER: //TODO?
        error(
            location, yyscanner,
            u"bad instantiated polymorphic struct type argument"_ustr);
        return false;
    case unoidl::detail::SourceProviderType::TYPE_SEQUENCE:
        return checkTypeArgument(location, yyscanner, type.subtypes.front());
    default:
        return true;
    }
}

bool checkInstantiatedPolymorphicStructTypeArgument(
    unoidl::detail::SourceProviderType const & type, OUString const & name)
{
    if (type.type
        == unoidl::detail::SourceProviderType::TYPE_INSTANTIATED_POLYMORPHIC_STRUCT)
    {
        for (auto & i: type.subtypes) {
            if (checkInstantiatedPolymorphicStructTypeArgument(i, name)
                || i.getName() == name) // no need to worry about typedef
            {
                return true;
            }
        }
    }
    return false;
}

std::vector<OUString> annotations(bool deprecated) {
    std::vector<OUString> ann;
    if (deprecated) {
        ann.push_back(u"deprecated"_ustr);
    }
    return ann;
}

}

%}

%token TOK_ELLIPSIS
%token TOK_COLONS
%token TOK_LEFTSHIFT
%token TOK_RIGHTSHIFT

%token TOK_FALSE
%token TOK_TRUE
%token TOK_ANY
%token TOK_ATTRIBUTE
%token TOK_BOOLEAN
%token TOK_BOUND
%token TOK_BYTE
%token TOK_CHAR
%token TOK_CONST
%token TOK_CONSTANTS
%token TOK_CONSTRAINED
%token TOK_DOUBLE
%token TOK_ENUM
%token TOK_EXCEPTION
%token TOK_FLOAT
%token TOK_GET
%token TOK_HYPER
%token TOK_IN
%token TOK_INOUT
%token TOK_INTERFACE
%token TOK_LONG
%token TOK_MAYBEAMBIGUOUS
%token TOK_MAYBEDEFAULT
%token TOK_MAYBEVOID
%token TOK_MODULE
%token TOK_OPTIONAL
%token TOK_OUT
%token TOK_PROPERTY
%token TOK_PUBLISHED
%token TOK_RAISES
%token TOK_READONLY
%token TOK_REMOVABLE
%token TOK_SEQUENCE
%token TOK_SERVICE
%token TOK_SET
%token TOK_SHORT
%token TOK_SINGLETON
%token TOK_STRING
%token TOK_STRUCT
%token TOK_TRANSIENT
%token TOK_TYPE
%token TOK_TYPEDEF
%token TOK_UNSIGNED
%token TOK_VOID

%token<sval> TOK_IDENTIFIER
%token<ival> TOK_INTEGER
%token<fval> TOK_FLOATING

%token TOK_DEPRECATED

%token TOK_ERROR

%type<sval> identifier name singleInheritance singleInheritance_opt
%type<bval> ctors_opt deprecated_opt ellipsis_opt published_opt
%type<decls> attributeAccessDecl attributeAccessDecls
%type<dir> direction
%type<excns> exceptionSpec exceptionSpec_opt exceptions
%type<flags> flag flagSection flagSection_opt flags
%type<expr> addExpr andExpr expr multExpr orExpr primaryExpr shiftExpr unaryExpr
  xorExpr
%type<type> type
%type<types> typeArguments

%initial-action { yylloc = 1; }

%%

definitions:
  definitions definition
| /* empty */
;

definition:
  moduleDecl
| enumDefn
| plainStructDefn
| polymorphicStructTemplateDefn
| exceptionDefn
| interfaceDefn
| typedefDefn
| constantGroupDefn
| singleInterfaceBasedServiceDefn
| accumulationBasedServiceDefn
| interfaceBasedSingletonDefn
| serviceBasedSingletonDefn
| interfaceDecl
;

moduleDecl:
  TOK_MODULE identifier
  {
      unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
      OUString name(convertToFullName(data, $2));
      data->modules.push_back(name);
      std::pair<std::map<OUString, unoidl::detail::SourceProviderEntity>::iterator, bool> p(
          data->entities.emplace(
                  name,
                  unoidl::detail::SourceProviderEntity(
                      unoidl::detail::SourceProviderEntity::KIND_MODULE)));
      if (!p.second
          && (p.first->second.kind
              != unoidl::detail::SourceProviderEntity::KIND_MODULE))
      {
          error(@2, yyscanner, "multiple entities named " + name);
          YYERROR;
      }
  }
  '{' definitions '}' ';' { yyget_extra(yyscanner)->modules.pop_back(); }
;

enumDefn:
  deprecated_opt published_opt TOK_ENUM identifier
  {
      unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
      data->publishedContext = $2;
      convertToCurrentName(data, $4);
      if (!data->entities.emplace(
                  data->currentName,
                  unoidl::detail::SourceProviderEntity(
                      new unoidl::detail::SourceProviderEnumTypeEntityPad(
                          $2))).
          second)
      {
          error(@4, yyscanner, "multiple entities named " + data->currentName);
          YYERROR;
      }
  }
  '{' enumMembers '}' ';'
  {
      unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
      unoidl::detail::SourceProviderEntity * ent = getCurrentEntity(data);
      unoidl::detail::SourceProviderEnumTypeEntityPad * pad =
          dynamic_cast<unoidl::detail::SourceProviderEnumTypeEntityPad *>(
              ent->pad.get());
      assert(pad != nullptr);
      ent->entity = new unoidl::EnumTypeEntity(
          pad->isPublished(), std::move(pad->members), annotations($1));
      ent->pad.clear();
      clearCurrentState(data);
  }
;

enumMembers:
| enumMembers ',' enumMember
| enumMember
;

enumMember:
  deprecated_opt identifier
  {
      OUString id(convertName($2));
      unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
      rtl::Reference<unoidl::detail::SourceProviderEnumTypeEntityPad> pad(
          getCurrentPad<unoidl::detail::SourceProviderEnumTypeEntityPad>(data));
      sal_Int32 v;
      if (pad->members.empty()) {
          v = 0;
      } else {
          v = pad->members.back().value;
          if (v == SAL_MAX_INT32) {
              error(
                  @2, yyscanner,
                  ("enum " + data->currentName + " member " + id
                   + " would have out-of-range value 2^31"));
              YYERROR;
          }
          ++v;
      }
      pad->members.emplace_back(id, v, annotations($1));
  }
| deprecated_opt identifier '=' expr
  {
      OUString id(convertName($2));
      unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
      rtl::Reference<unoidl::detail::SourceProviderEnumTypeEntityPad> pad(
          getCurrentPad<unoidl::detail::SourceProviderEnumTypeEntityPad>(data));
      sal_Int32 v;
      switch ($4.type) {
      case unoidl::detail::SourceProviderExpr::TYPE_INT:
          if ($4.ival < SAL_MIN_INT32 || $4.ival > SAL_MAX_INT32) {
              error(
                  @4, yyscanner,
                  ("out-of-range enum " + data->currentName + " member " + id
                   + " value " + OUString::number($4.ival)));
              YYERROR;
          }
          v = static_cast<sal_Int32>($4.ival);
          break;
      case unoidl::detail::SourceProviderExpr::TYPE_UINT:
          if ($4.uval > SAL_MAX_INT32) {
              error(
                  @4, yyscanner,
                  ("out-of-range enum " + data->currentName + " member " + id
                   + " value " + OUString::number($4.uval)));
              YYERROR;
          }
          v = static_cast<sal_Int32>($4.uval);
          break;
      default:
          error(
              @4, yyscanner,
              ("non-integer enum " + data->currentName + " member " + id
               + " value"));
          YYERROR;
          break;
      }
      pad->members.emplace_back(id, v, annotations($1));
  }
;

plainStructDefn:
  deprecated_opt published_opt TOK_STRUCT identifier singleInheritance_opt
  {
      unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
      data->publishedContext = $2;
      convertToCurrentName(data, $4);
      OUString baseName;
      rtl::Reference<unoidl::PlainStructTypeEntity> baseEnt;
      if ($5 != nullptr) {
          baseName = convertName($5);
          unoidl::detail::SourceProviderEntity const * p;
          if (findEntity(
                  @5, yyscanner, data, false, &baseName, &p, nullptr, nullptr)
              == FOUND_ERROR)
          {
              YYERROR;
          }
          if (p == nullptr || !p->entity.is()
              || p->entity->getSort() != unoidl::Entity::SORT_PLAIN_STRUCT_TYPE)
          {
              error(
                  @5, yyscanner,
                  ("plain struct type " + data->currentName + " base "
                   + baseName
                   + " does not resolve to an existing plain struct type"));
              YYERROR;
          }
          baseEnt = static_cast<unoidl::PlainStructTypeEntity *>(
              p->entity.get());
          if ($2 && !baseEnt->isPublished()) {
              error(
                  @5, yyscanner,
                  ("published plain struct type " + data->currentName + " base "
                   + baseName + " is unpublished"));
              YYERROR;
          }
      }
      if (!data->entities.emplace(
                  data->currentName,
                  unoidl::detail::SourceProviderEntity(
                      new unoidl::detail::SourceProviderPlainStructTypeEntityPad(
                          $2, baseName, baseEnt))).
          second)
      {
          error(@4, yyscanner, "multiple entities named " + data->currentName);
          YYERROR;
      }
  }
  '{' structMembers '}' ';'
  {
      unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
      unoidl::detail::SourceProviderEntity * ent = getCurrentEntity(data);
      unoidl::detail::SourceProviderPlainStructTypeEntityPad * pad =
          dynamic_cast<
              unoidl::detail::SourceProviderPlainStructTypeEntityPad *>(
                  ent->pad.get());
      assert(pad != nullptr);
      ent->entity = new unoidl::PlainStructTypeEntity(
          pad->isPublished(), pad->baseName, std::move(pad->members), annotations($1));
      ent->pad.clear();
      clearCurrentState(data);
  }
;

polymorphicStructTemplateDefn:
  deprecated_opt published_opt TOK_STRUCT identifier '<'
  {
      unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
      data->publishedContext = $2;
      convertToCurrentName(data, $4);
      if (!data->entities.emplace(
                  data->currentName,
                  unoidl::detail::SourceProviderEntity(
                      new unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad(
                          $2))).
          second)
      {
          error(@4, yyscanner, "multiple entities named " + data->currentName);
          YYERROR;
      }
  }
  typeParameters '>' '{' structMembers '}' ';'
  {
      unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
      unoidl::detail::SourceProviderEntity * ent = getCurrentEntity(data);
      unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad *
          pad = dynamic_cast<
              unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad *>(
                  ent->pad.get());
      assert(pad != nullptr);
      ent->entity = new unoidl::PolymorphicStructTypeTemplateEntity(
          pad->isPublished(), std::move(pad->typeParameters), std::move(pad->members),
          annotations($1));
      ent->pad.clear();
      clearCurrentState(data);
  }
;

typeParameters:
  typeParameters ',' identifier
  {
      unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
      rtl::Reference<unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad>
          pad(getCurrentPad<unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad>(
                  data));
      OUString id(convertName($3));
      if (std::find(pad->typeParameters.begin(), pad->typeParameters.end(), id)
          != pad->typeParameters.end())
      {
          error(
              @3, yyscanner,
              ("polymorphic struct type template " + data->currentName
               + " type parameter " + id
               + " has same identifier as another type parameter"));
          YYERROR;
      }
      pad->typeParameters.push_back(id);
  }
| identifier
  {
      unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
      rtl::Reference<unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad>
          pad(getCurrentPad<unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad>(
                  data));
      OUString id(convertName($1));
      assert(pad->typeParameters.empty());
      pad->typeParameters.push_back(id);
  }
;

exceptionDefn:
  deprecated_opt published_opt TOK_EXCEPTION identifier singleInheritance_opt
  {
      unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
      data->publishedContext = $2;
      convertToCurrentName(data, $4);
      OUString baseName;
      rtl::Reference<unoidl::ExceptionTypeEntity> baseEnt;
      if ($5 != nullptr) {
          baseName = convertName($5);
          unoidl::detail::SourceProviderEntity const * p;
          if (findEntity(
                  @5, yyscanner, data, false, &baseName, &p, nullptr, nullptr)
              == FOUND_ERROR)
          {
              YYERROR;
          }
          if (p == nullptr || !p->entity.is()
              || p->entity->getSort() != unoidl::Entity::SORT_EXCEPTION_TYPE)
          {
              error(
                  @5, yyscanner,
                  ("exception type " + data->currentName + " base " + baseName
                   + " does not resolve to an existing exception type"));
              YYERROR;
          }
          baseEnt = static_cast<unoidl::ExceptionTypeEntity *>(
              p->entity.get());
          if ($2 && !baseEnt->isPublished()) {
              error(
                  @5, yyscanner,
                  ("published exception type " + data->currentName + " base "
                   + baseName + " is unpublished"));
              YYERROR;
          }
      }
      if (!data->entities.emplace(
                  data->currentName,
                  unoidl::detail::SourceProviderEntity(
                      new unoidl::detail::SourceProviderExceptionTypeEntityPad(
                          $2, baseName, baseEnt))).
          second)
      {
          error(@4, yyscanner, "multiple entities named " + data->currentName);
          YYERROR;
      }
  }
 '{' structMembers '}' ';'
  {
      unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
      unoidl::detail::SourceProviderEntity * ent = getCurrentEntity(data);
      unoidl::detail::SourceProviderExceptionTypeEntityPad * pad =
          dynamic_cast<unoidl::detail::SourceProviderExceptionTypeEntityPad *>(
              ent->pad.get());
      assert(pad != nullptr);
      ent->entity = new unoidl::ExceptionTypeEntity(
          pad->isPublished(), pad->baseName, std::move(pad->members), annotations($1));
      ent->pad.clear();
      clearCurrentState(data);
  }
;

structMembers:
  structMembers structMember
| /* empty */
;

structMember:
  deprecated_opt type identifier ';'
  {
      unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
      unoidl::detail::SourceProviderType t(*$2);
      delete $2;
      OUString id(convertName($3));
      switch (t.type) {
      case unoidl::detail::SourceProviderType::TYPE_VOID:
      case unoidl::detail::SourceProviderType::TYPE_EXCEPTION:
          error(
              @2, yyscanner,
              ("illegal struct/exception type " + data->currentName
               + " direct member " + id + " type"));
          YYERROR;
          break;
      default:
          break;
      }
      if (t.type != unoidl::detail::SourceProviderType::TYPE_PARAMETER
          && t.getName() == data->currentName) // no need to worry about typedef
      {
          error(
              @2, yyscanner,
              ("struct/exception type " + data->currentName + " direct member "
               + id + " has same type as the type itself"));
          YYERROR;
      }
      if (checkInstantiatedPolymorphicStructTypeArgument(t, data->currentName))
      {
          error(
              @2, yyscanner,
              ("struct/exception type " + data->currentName + " direct member "
               + id
               + (" has instantiated polymorphic struct type that uses the type"
                  " itself as an argument")));
          YYERROR;
      }
      if (nameHasSameIdentifierAs(data->currentName, id)) {
          error(
              @3, yyscanner,
              ("struct/exception type " + data->currentName + " direct member "
               + id + " has same unqualified identifier as the type itself"));
          YYERROR;
      }
      unoidl::detail::SourceProviderEntity * ent = getCurrentEntity(data);
      unoidl::detail::SourceProviderPlainStructTypeEntityPad * p1 =
          dynamic_cast<unoidl::detail::SourceProviderPlainStructTypeEntityPad *>(
              ent->pad.get());
      if (p1 != nullptr) {
          for (const auto & i: p1->members) {
              if (id == i.name) {
                  error(
                      @3, yyscanner,
                      ("plain struct type " + data->currentName
                       + " direct member " + id
                       + " has same identifier as another direct member"));
                  YYERROR;
              }
          }
          if (p1->baseEntity.is()) {
              OUString baseName(p1->baseName);
              for (auto baseEnt(p1->baseEntity);;) {
                  if (nameHasSameIdentifierAs(baseName, id)) {
                      error(
                          @3, yyscanner,
                          ("plain struct type " + data->currentName
                           + " direct member " + id
                           + " has same unqalified identifier as base "
                           + baseName));
                      YYERROR;
                  }
                  for (auto & i: baseEnt->getDirectMembers()) {
                      if (id == i.name) {
                          error(
                              @3, yyscanner,
                              ("plain struct type " + data->currentName
                               + " direct member " + id
                               + " has same identifier as a member of base "
                               + baseName));
                          YYERROR;
                      }
                  }
                  baseName = baseEnt->getDirectBase();
                  if (baseName.isEmpty()) {
                      break;
                  }
                  unoidl::detail::SourceProviderEntity const * p;
                  if (findEntity(
                          @2, yyscanner, data, false, &baseName, &p, nullptr,
                          nullptr)
                      == FOUND_ERROR)
                  {
                      YYERROR;
                  }
                  if (p == nullptr || !p->entity.is()
                      || (p->entity->getSort()
                          != unoidl::Entity::SORT_PLAIN_STRUCT_TYPE))
                  {
                      error(
                          @2, yyscanner,
                          ("inconsistent type manager: plain struct type "
                           + data->currentName + " base " + baseName
                           + (" does not resolve to an existing plain struct"
                              " type")));
                      YYERROR;
                  }
                  baseEnt = static_cast<unoidl::PlainStructTypeEntity *>(
                      p->entity.get());
              }
          }
          p1->members.emplace_back(id, t.getName(), annotations($1));
      } else {
          unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad *
              p2 = dynamic_cast<unoidl::detail::SourceProviderPolymorphicStructTypeTemplateEntityPad *>(
                  ent->pad.get());
          if (p2 != nullptr) {
              for (const auto & i: p2->members) {
                  if (id == i.name) {
                      error(
                          @3, yyscanner,
                          ("polymorphic struct type template "
                           + data->currentName + " direct member " + id
                           + " has same identifier as another direct member"));
                      YYERROR;
                  }
              }
              p2->members.emplace_back(
                  id, t.getName(),
                  t.type == unoidl::detail::SourceProviderType::TYPE_PARAMETER,
                  annotations($1));
          } else {
              unoidl::detail::SourceProviderExceptionTypeEntityPad * p3
                  = dynamic_cast<unoidl::detail::SourceProviderExceptionTypeEntityPad *>(
                      ent->pad.get());
              assert(p3 != nullptr);
              for (const auto & i: p3->members) {
                  if (id == i.name) {
                      error(
                          @3, yyscanner,
                          ("exception type " + data->currentName
                           + " direct member " + id
                           + " has same identifier as another direct member"));
                      YYERROR;
                  }
              }
              if (p3->baseEntity.is()) {
                  OUString baseName(p3->baseName);
                  for (auto baseEnt(p3->baseEntity);;) {
                      if (nameHasSameIdentifierAs(baseName, id)) {
                          error(
                              @3, yyscanner,
                              ("exception type " + data->currentName
                               + " direct member " + id
                               + " has same unqalified identifier as base "
                               + baseName));
                          YYERROR;
                      }
                      for (auto & i: baseEnt->getDirectMembers()) {
                          if (id == i.name) {
                              error(
                                  @3, yyscanner,
                                  ("exception type " + data->currentName
                                   + " direct member " + id
                                   + " has same identifier as a member of base "
                                   + baseName));
                              YYERROR;
                          }
                      }
                      baseName = baseEnt->getDirectBase();
                      if (baseName.isEmpty()) {
                          break;
                      }
                      unoidl::detail::SourceProviderEntity const * p;
                      if (findEntity(
                              @2, yyscanner, data, false, &baseName, &p,
                              nullptr, nullptr)
                          == FOUND_ERROR)
                      {
                          YYERROR;
                      }
                      if (p == nullptr || !p->entity.is()
                          || (p->entity->getSort()
                              != unoidl::Entity::SORT_EXCEPTION_TYPE))
                      {
                          error(
                              @2, yyscanner,
                              ("inconsistent type manager: exception type "
                               + data->currentName + " base " + baseName
                               + (" does not resolve to an existing exception"
                                  " type")));
                          YYERROR;
                      }
                      baseEnt = static_cast<unoidl::ExceptionTypeEntity *>(
                          p->entity.get());
                  }
              }
              p3->members.emplace_back(id, t.getName(), annotations($1));
          }
      }
  }
;

interfaceDefn:
  deprecated_opt published_opt TOK_INTERFACE identifier singleInheritance_opt
  {
      unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
      data->publishedContext = $2;
      convertToCurrentName(data, $4);
      OUString baseName;
      rtl::Reference<unoidl::InterfaceTypeEntity> baseEnt;
      if ($5 != nullptr) {
          baseName = convertName($5);
          unoidl::detail::SourceProviderEntity const * p;
          if (findEntity(
                  @5, yyscanner, data, true, &baseName, &p, nullptr, nullptr)
              == FOUND_ERROR)
          {
              YYERROR;
          }
          if (p == nullptr || !p->entity.is()
              || p->entity->getSort() != unoidl::Entity::SORT_INTERFACE_TYPE)
          {
              error(
                  @5, yyscanner,
                  ("interface type " + data->currentName + " direct base "
                   + baseName
                   + " does not resolve to an existing interface type"));
              YYERROR;
          }
          baseEnt = static_cast<unoidl::InterfaceTypeEntity *>(p->entity.get());
          if ($2 && !baseEnt->isPublished()) {
              error(
                  @5, yyscanner,
                  ("published interface type " + data->currentName
                   + " direct base " + baseName + " is unpublished"));
              YYERROR;
          }
      }
      std::map<OUString, unoidl::detail::SourceProviderEntity>::iterator i(
          data->entities.find(data->currentName));
      if (i != data->entities.end()) {
          switch (i->second.kind) {
          case unoidl::detail::SourceProviderEntity::KIND_INTERFACE_DECL:
              break;
          case unoidl::detail::SourceProviderEntity::KIND_PUBLISHED_INTERFACE_DECL:
              if (!$2) {
                  error(
                      @4, yyscanner,
                      ("unpublished interface type " + data->currentName
                       + " has been declared published"));
                  YYERROR;
              }
              break;
          default:
              error(
                  @4, yyscanner,
                  "multiple entities named " + data->currentName);
              YYERROR;
              break;
          }
      }
      rtl::Reference<unoidl::detail::SourceProviderInterfaceTypeEntityPad> pad(
          new unoidl::detail::SourceProviderInterfaceTypeEntityPad(
              $2, baseEnt.is()));
      if (baseEnt.is()
          && !pad->addDirectBase(
              @4, yyscanner, data,
              unoidl::detail::SourceProviderInterfaceTypeEntityPad::DirectBase(
                  baseName, baseEnt, std::vector<OUString>()),
              false))
      {
          YYERROR;
      }
      data->entities[data->currentName] = unoidl::detail::SourceProviderEntity(
          pad);
  }
  '{' interfaceMembers '}' ';'
  {
      unoidl::detail::SourceProviderScannerData * data = yyget_extra(yyscanner);
      unoidl::detail::SourceProviderEntity * ent = getCurrentEntity(data);
      unoidl::detail::SourceProviderInterfaceTypeEntityPad * pad =
          dynamic_cast<unoidl::detail::SourceProviderInterfaceTypeEntityPad *>(
              ent->pad.get());
      assert(pad != nullptr);
      if (pad->directMandatoryBases.empty()
          && data->currentName != "com.sun.star.uno.XInterface")
      {
          OUString base(u".com.sun.star.uno.XInterface"_ustr);
          unoidl::detail::SourceProviderEntity const * p;
          if (findEntity(@4, yyscanner, data, true, &base, &p, nullptr, nullptr)
              == FOUND_ERROR)
          {
              YYERROR;
          }
          if (p == nullptr || !p->entity.is()
              || p->entity->getSort() != unoidl::Entity::SORT_INTERFACE_TYPE)
          {
              error(
                  @3, yyscanner,
                  ("interface type " + data->currentName
                   + " implicit direct base " + base
                   + " does not resolve to an existing interface type"));
              YYERROR;
          }
          if (!pad->addDirectBase(
                  @3, yyscanner, data,
                  unoidl::detail::SourceProviderInterfaceTypeEntityPad::DirectBase(
                      base,
                      static_cast<unoidl::InterfaceTypeEntity *>(
                          p->entity.get()),
                      std::vector<OUString>()),
                  false))
          {
              YYERROR;
          }
      }
      std::vector<unoidl::AnnotatedReference> mbases;
      for (auto & i: pad->directMandatoryBases) {
          mbases.emplace_back(i.name, std::move(i.annotations));
      }
      std::vector<unoidl::AnnotatedReference> obases;
--> --------------------

--> maximum size reached

--> --------------------

[ Verzeichnis aufwärts0.28unsichere Verbindung  Übersetzung europäischer Sprachen durch Browser  ]