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

Quelle  netproduce.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
 * 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/.
 */


#include <iostream>
#include <vector>

#include <codemaker/codemaker.hxx>
#include <o3tl/string_view.hxx>
#include <rtl/strbuf.hxx>
#include <unoidl/unoidl.hxx>

#include "netproduce.hxx"
#include "csharpfile.hxx"

namespace
{
const std::unordered_set<OString> s_reservedKeywords{
    "abstract"_ostr, "as"_ostr,       "base"_ostr,       "bool"_ostr,      "break"_ostr,
    "byte"_ostr,     "case"_ostr,     "catch"_ostr,      "char"_ostr,      "checked"_ostr,
    "class"_ostr,    "const"_ostr,    "continue"_ostr,   "decimal"_ostr,   "default"_ostr,
    "delegate"_ostr, "do"_ostr,       "double"_ostr,     "else"_ostr,      "enum"_ostr,
    "event"_ostr,    "explicit"_ostr, "extern"_ostr,     "false"_ostr,     "finally"_ostr,
    "fixed"_ostr,    "float"_ostr,    "for"_ostr,        "foreach"_ostr,   "goto"_ostr,
    "if"_ostr,       "implicit"_ostr, "in"_ostr,         "int"_ostr,       "interface"_ostr,
    "internal"_ostr, "is"_ostr,       "lock"_ostr,       "long"_ostr,      "namespace"_ostr,
    "new"_ostr,      "null"_ostr,     "object"_ostr,     "operator"_ostr,  "out"_ostr,
    "override"_ostr, "params"_ostr,   "private"_ostr,    "protected"_ostr, "public"_ostr,
    "readonly"_ostr, "ref"_ostr,      "return"_ostr,     "sbyte"_ostr,     "sealed"_ostr,
    "short"_ostr,    "sizeof"_ostr,   "stackalloc"_ostr, "static"_ostr,    "string"_ostr,
    "struct"_ostr,   "switch"_ostr,   "this"_ostr,       "throw"_ostr,     "true"_ostr,
    "try"_ostr,      "typeof"_ostr,   "uint"_ostr,       "ulong"_ostr,     "unchecked"_ostr,
    "unsafe"_ostr,   "ushort"_ostr,   "using"_ostr,      "virtual"_ostr,   "void"_ostr,
    "volatile"_ostr, "while"_ostr,
};

const std::unordered_map<OString, OString> s_baseTypes{
    { "boolean"_ostr, "bool"_ostr },
    { "char"_ostr, "char"_ostr },
    { "byte"_ostr, "sbyte"_ostr },
    { "short"_ostr, "short"_ostr },
    { "unsigned short"_ostr, "ushort"_ostr },
    { "long"_ostr, "int"_ostr },
    { "unsigned long"_ostr, "uint"_ostr },
    { "hyper"_ostr, "long"_ostr },
    { "unsigned hyper"_ostr, "ulong"_ostr },
    { "float"_ostr, "float"_ostr },
    { "double"_ostr, "double"_ostr },
    { "string"_ostr, "string"_ostr },
    { "void"_ostr, "void"_ostr },
    { "type"_ostr, "System.Type"_ostr },
    { "any"_ostr, "com.sun.star.uno.Any"_ostr },
    { "com.sun.star.uno.Exception"_ostr, "com.sun.star.uno.UnoException"_ostr },
    { "com.sun.star.uno.XInterface"_ostr, "com.sun.star.uno.IQueryInterface"_ostr },
};

std::tuple<bool, std::string_view, std::string_view> splitName(std::string_view name)
{
    size_t split = name.find_last_of('.');
    if (split != std::string_view::npos)
        return std::make_tuple(true, name.substr(0, split), name.substr(split + 1));
    else
        return std::make_tuple(false"", name);
}

OString getBaseUnoName(std::string_view name)
{
    size_t start = name.find_first_not_of("[]");
    if (start == std::string_view::npos)
        start = 0;

    size_t end = name.find_first_of('<');
    if (end == std::string_view::npos)
        end = name.size();

    return OString(name.substr(start, end - start));
}
OString getBaseUnoName(std::u16string_view name) { return getBaseUnoName(u2b(name)); }

OString getSafeIdentifier(std::string_view name)
{
    OString temp(name);
    return s_reservedKeywords.contains(temp) ? "@"_ostr + temp : temp;
}
OString getSafeIdentifier(std::u16string_view name) { return getSafeIdentifier(u2b(name)); }

void separatedForeach(const auto& items, auto&& sepFunc, auto&& itemFunc)
{
    for (auto it = items.begin(); it != items.end(); ++it)
    {
        if (it != items.begin())
            sepFunc();
        itemFunc(*it);
    }
}
}

void NetProducer::initProducer(const NetOptions& options)
{
    m_outputDir = options.getOption("--output-dir"_ostr);
    m_dryRun = options.isValid("--dry-run"_ostr);
    m_verbose = options.isValid("--verbose"_ostr);

    if (options.isValid("--types"_ostr))
    {
        const OString& names(options.getOption("--types"_ostr));
        for (size_t i = 0; i != std::string_view::npos;)
        {
            std::string_view name(o3tl::getToken(names, ';', i));
            if (name == "*")
                m_startingTypes.insert(""_ostr);
            else if (name.ends_with(".*"))
                m_startingTypes.emplace(name.substr(0, name.size() - 2));
            else
                m_startingTypes.emplace(name);
        }
    }
    else
    {
        m_startingTypes.insert(""_ostr);
    }

    for (const OString& file : options.getInputFiles())
        m_manager->loadProvider(convertToFileUrl(file), true);
    for (const OString& file : options.getExtraInputFiles())
        m_manager->loadProvider(convertToFileUrl(file), false);
}

void NetProducer::produceAll()
{
    for (const OString& name : m_startingTypes)
        produceType(name);
}

void NetProducer::produceType(const OString& name)
{
    if (m_typesProduced.contains(name))
        return;

    m_typesProduced.insert(name);

    if (s_baseTypes.contains(name))
        return;

    OUString uname(b2u(name));

    rtl::Reference<unoidl::Entity> entity;
    rtl::Reference<unoidl::MapCursor> cursor;

    if (m_manager->foundAtPrimaryProvider(uname))
    {
        switch (m_manager->getSort(uname, &entity, &cursor))
        {
            case codemaker::UnoType::Sort::Module:
                produceModule(name, cursor);
                break;

            case codemaker::UnoType::Sort::Enum:
                produceEnum(name, dynamic_cast<unoidl::EnumTypeEntity*>(entity.get()));
                break;

            case codemaker::UnoType::Sort::PlainStruct:
                producePlainStruct(name,
                                   dynamic_cast<unoidl::PlainStructTypeEntity*>(entity.get()));
                break;

            case codemaker::UnoType::Sort::PolymorphicStructTemplate:
                producePolyStruct(
                    name, dynamic_cast<unoidl::PolymorphicStructTypeTemplateEntity*>(entity.get()));
                break;

            case codemaker::UnoType::Sort::Exception:
                produceException(name, dynamic_cast<unoidl::ExceptionTypeEntity*>(entity.get()));
                break;

            case codemaker::UnoType::Sort::Interface:
                produceInterface(name, dynamic_cast<unoidl::InterfaceTypeEntity*>(entity.get()));
                break;

            case codemaker::UnoType::Sort::Typedef:
                produceTypedef(name, dynamic_cast<unoidl::TypedefEntity*>(entity.get()));
                break;

            case codemaker::UnoType::Sort::ConstantGroup:
                produceConstantGroup(name,
                                     dynamic_cast<unoidl::ConstantGroupEntity*>(entity.get()));
                break;

            case codemaker::UnoType::Sort::SingleInterfaceBasedService:
                produceService(
                    name, dynamic_cast<unoidl::SingleInterfaceBasedServiceEntity*>(entity.get()));
                break;

            case codemaker::UnoType::Sort::InterfaceBasedSingleton:
                produceSingleton(
                    name, dynamic_cast<unoidl::InterfaceBasedSingletonEntity*>(entity.get()));
                break;

            case codemaker::UnoType::Sort::AccumulationBasedService:
            case codemaker::UnoType::Sort::ServiceBasedSingleton:
                // old-style services and singletons not supported
                break;

            default:
                throw CannotDumpException(u"entity '"_ustr + uname + u"' has unexpected type"_ustr);
        }
    }
    else
    {
        // type from --extra-types
        switch (m_manager->getSort(uname, &entity, &cursor))
        {
            case codemaker::UnoType::Sort::Typedef:
                produceTypedef(name, dynamic_cast<unoidl::TypedefEntity*>(entity.get()));
                break;

            default:
                break;
        }
    }
}

void NetProducer::produceModule(std::string_view name,
                                const rtl::Reference<unoidl::MapCursor>& cursor)
{
    OUString moduleName;
    while (cursor->getNext(&moduleName).is())
    {
        OString memberName = name.empty() ? u2b(moduleName) : name + "."_ostr + u2b(moduleName);
        produceType(memberName);
    }
}

void NetProducer::produceEnum(std::string_view name,
                              const rtl::Reference<unoidl::EnumTypeEntity>& entity)
{
    CSharpFile file(m_outputDir, name);

    if (m_verbose)
        std::cout << "[enum] " << name << " -> " << file.getPath() << '\n';
    if (m_dryRun)
        return;

    file.openFile();

    auto[hasNamespace, namespaceName, typeName] = splitName(name);

    if (hasNamespace)
        file.beginLine().append("namespace ").append(namespaceName).endLine().beginBlock();

    file.beginLine()
        .append("[com.sun.star.uno.UnoGenerated]")
        .endLine()
        .beginLine()
        .append("public enum ")
        .append(getSafeIdentifier(typeName))
        .endLine()
        .beginBlock();
    for (const auto& member : entity->getMembers())
    {
        for (const auto& anno : member.annotations)
            if (anno == "deprecated")
                file.beginLine().append("[System.Obsolete]").endLine();
        file.beginLine()
            .append(getSafeIdentifier(member.name))
            .append(" = ")
            .append(OString::number(member.value))
            .append(",")
            .endLine();
    }
    file.endBlock();

    if (hasNamespace)
        file.endBlock();

    file.closeFile();
}

void NetProducer::producePlainStruct(std::string_view name,
                                     const rtl::Reference<unoidl::PlainStructTypeEntity>& entity)
{
    // produce referenced types
    const auto& base = entity->getDirectBase();
    if (!base.isEmpty())
        produceType(getBaseUnoName(base));
    for (const auto& member : entity->getDirectMembers())
        produceType(getBaseUnoName(member.type));

    CSharpFile file(m_outputDir, name);

    // verbose and dry run checks
    if (m_verbose)
        std::cout << "[struct] " << name << " -> " << file.getPath() << '\n';
    if (m_dryRun)
        return;

    file.openFile();

    // output namespace block
    auto[hasNamespace, namespaceName, typeName] = splitName(name);

    if (hasNamespace)
        file.beginLine().append("namespace ").append(namespaceName).endLine().beginBlock();

    // generate struct and base structs list
    file.beginLine()
        .append("[com.sun.star.uno.UnoGenerated]")
        .endLine()
        .beginLine()
        .append("public class ")
        .append(getSafeIdentifier(typeName));
    if (!base.isEmpty())
        file.append(" : ").append(getNetName(base));
    file.endLine().beginBlock();

    // generate default constructor
    file.beginLine()
        .append("public ")
        .append(getSafeIdentifier(typeName))
        .append("()")
        .endLine()
        .beginBlock()
        .endBlock();
    file.endLine(); // extra blank line

    // generate full constructor
    std::vector<unoidl::PlainStructTypeEntity::Member> baseFields;
    {
        OUString baseTypeName = base;
        while (!baseTypeName.isEmpty())
        {
            rtl::Reference<unoidl::Entity> baseEntity;
            if (m_manager->getSort(baseTypeName, &baseEntity)
                != codemaker::UnoType::Sort::PlainStruct)
                throw CannotDumpException("'" + b2u(name) + "' base type '" + baseTypeName
                                          + "' is not a plain struct");

            rtl::Reference<unoidl::PlainStructTypeEntity> ref(
                dynamic_cast<unoidl::PlainStructTypeEntity*>(baseEntity.get()));
            baseFields.insert(baseFields.begin(), ref->getDirectMembers().begin(),
                              ref->getDirectMembers().end());

            baseTypeName = ref->getDirectBase();
        }
    }

    std::vector<unoidl::PlainStructTypeEntity::Member> allFields(entity->getDirectMembers());
    allFields.insert(allFields.begin(), baseFields.begin(), baseFields.end());

    file.beginLine().append("public ").append(getSafeIdentifier(typeName)).append("(");
    separatedForeach(
        allFields, [&file]() { file.append(", "); },
        [this, &file](const auto& member) {
            file.append(getNetName(member.type)).append(" ").append(getSafeIdentifier(member.name));
        });
    file.append(")").endLine();
    file.beginLine().extraIndent().append(": base(");
    separatedForeach(baseFields, [&file]() { file.append(", "); },
                     [&file](const auto& member) { file.append(getSafeIdentifier(member.name)); });
    file.append(")").endLine();
    file.beginBlock();
    for (const auto& member : entity->getDirectMembers())
    {
        file.beginLine()
            .append("this.")
            .append(getSafeIdentifier(member.name))
            .append(" = ")
            .append(getSafeIdentifier(member.name))
            .append(";")
            .endLine();
    }
    file.endBlock();
    file.endLine(); // extra blank line

    // generate deconstructor
    file.beginLine().append("public void Deconstruct(");
    separatedForeach(allFields, [&file]() { file.append(", "); },
                     [this, &file](const auto& member) {
                         file.append("out ")
                             .append(getNetName(member.type))
                             .append(" ")
                             .append(getSafeIdentifier(member.name));
                     });
    file.append(")").endLine();
    file.beginBlock();
    for (const auto& member : allFields)
    {
        file.beginLine()
            .append(getSafeIdentifier(member.name))
            .append(" = ")
            .append("this.")
            .append(getSafeIdentifier(member.name))
            .append(";")
            .endLine();
    }
    file.endBlock();
    file.endLine(); // extra blank line

    // generate struct fields
    for (const auto& member : entity->getDirectMembers())
    {
        for (const auto& anno : member.annotations)
            if (anno == "deprecated")
                file.beginLine().append("[System.Obsolete]").endLine();
        file.beginLine()
            .append("public ")
            .append(getNetName(member.type))
            .append(" ")
            .append(getSafeIdentifier(member.name))
            .append(";")
            .endLine();
    }

    file.endBlock();
    if (hasNamespace)
        file.endBlock();
    file.closeFile();
}

void NetProducer::producePolyStruct(
    std::string_view name,
    const rtl::Reference<unoidl::PolymorphicStructTypeTemplateEntity>& entity)
{
    // produce referenced types
    for (const auto& member : entity->getMembers())
        if (!member.parameterized)
            produceType(getBaseUnoName(member.type));

    CSharpFile file(m_outputDir, name);

    // verbose and dry run checks
    if (m_verbose)
        std::cout << "[polystruct] " << name << " -> " << file.getPath() << '\n';
    if (m_dryRun)
        return;

    file.openFile();

    // output namespace block
    auto[hasNamespace, namespaceName, typeName] = splitName(name);

    if (hasNamespace)
        file.beginLine().append("namespace ").append(namespaceName).endLine().beginBlock();

    // generate struct and type parameters list
    file.beginLine()
        .append("[com.sun.star.uno.UnoGenerated]")
        .endLine()
        .beginLine()
        .append("public class ")
        .append(getSafeIdentifier(typeName))
        .append("<");
    separatedForeach(entity->getTypeParameters(), [&file]() { file.append(", "); },
                     [&file](const auto& param) { file.append(param); });
    file.append(">").endLine().beginBlock();

    // generate default constructor
    file.beginLine()
        .append("public ")
        .append(getSafeIdentifier(typeName))
        .append("()")
        .endLine()
        .beginBlock()
        .endBlock();
    file.endLine(); // extra blank line

    // generate full constructor
    file.beginLine().append("public ").append(getSafeIdentifier(typeName)).append("(");
    separatedForeach(entity->getMembers(), [&file]() { file.append(", "); },
                     [this, &file](const auto& member) {
                         file.append(member.parameterized ? u2b(member.type)
                                                          : getNetName(member.type))
                             .append(" ")
                             .append(getSafeIdentifier(member.name));
                     });
    file.append(")").endLine();
    file.beginBlock();
    for (const auto& member : entity->getMembers())
    {
        file.beginLine()
            .append("this.")
            .append(getSafeIdentifier(member.name))
            .append(" = ")
            .append(getSafeIdentifier(member.name))
            .append(";")
            .endLine();
    }
    file.endBlock();
    file.endLine(); // extra blank line

    // generate struct fields
    for (const auto& member : entity->getMembers())
    {
        for (const auto& anno : member.annotations)
            if (anno == "deprecated")
                file.beginLine().append("[System.Obsolete]").endLine();
        file.beginLine()
            .append("public ")
            .append(member.parameterized ? u2b(member.type) : getNetName(member.type))
            .append(" ")
            .append(getSafeIdentifier(member.name))
            .append(";")
            .endLine();
    }

    file.endBlock();
    if (hasNamespace)
        file.endBlock();
    file.closeFile();
}

void NetProducer::produceException(std::string_view name,
                                   const rtl::Reference<unoidl::ExceptionTypeEntity>& entity)
{
    // produce referenced types
    const auto& base = entity->getDirectBase();
    if (!base.isEmpty())
        produceType(getBaseUnoName(base));
    for (const auto& member : entity->getDirectMembers())
        produceType(getBaseUnoName(member.type));

    CSharpFile file(m_outputDir, name);

    // verbose and dry run checks
    if (m_verbose)
        std::cout << "[exception] " << name << " -> " << file.getPath() << '\n';
    if (m_dryRun)
        return;

    file.openFile();

    // output namespace block
    auto[hasNamespace, namespaceName, typeName] = splitName(name);

    if (hasNamespace)
        file.beginLine().append("namespace ").append(namespaceName).endLine().beginBlock();

    // generate exception and base exceptions list
    file.beginLine()
        .append("[com.sun.star.uno.UnoGenerated]")
        .endLine()
        .beginLine()
        .append("public class ")
        .append(getSafeIdentifier(typeName));
    if (!base.isEmpty())
        file.append(" : ").append(getNetName(base));
    file.endLine().beginBlock();

    // generate default constructor
    file.beginLine()
        .append("public ")
        .append(getSafeIdentifier(typeName))
        .append("()")
        .endLine()
        .beginBlock()
        .endBlock();
    file.endLine(); // extra blank line

    // generate full constructor
    std::vector<unoidl::ExceptionTypeEntity::Member> baseFields;
    {
        OUString baseTypeName = base;
        while (!baseTypeName.isEmpty())
        {
            rtl::Reference<unoidl::Entity> baseEntity;
            if (m_manager->getSort(baseTypeName, &baseEntity)
                != codemaker::UnoType::Sort::Exception)
                throw CannotDumpException("'" + b2u(name) + "' base type '" + baseTypeName
                                          + "' is not an exception");

            rtl::Reference<unoidl::ExceptionTypeEntity> ref(
                dynamic_cast<unoidl::ExceptionTypeEntity*>(baseEntity.get()));
            baseFields.insert(baseFields.begin(), ref->getDirectMembers().begin(),
                              ref->getDirectMembers().end());

            baseTypeName = ref->getDirectBase();
        }
    }

    std::vector<unoidl::ExceptionTypeEntity::Member> allFields(entity->getDirectMembers());
    allFields.insert(allFields.begin(), baseFields.begin(), baseFields.end());

    file.beginLine().append("public ").append(getSafeIdentifier(typeName)).append("(");
    separatedForeach(
        allFields, [&file]() { file.append(", "); },
        [this, &file](const auto& member) {
            file.append(getNetName(member.type)).append(" ").append(getSafeIdentifier(member.name));
        });
    file.append(")").endLine();
    file.beginLine().extraIndent().append(": base(");
    separatedForeach(baseFields, [&file]() { file.append(", "); },
                     [&file](const auto& member) { file.append(getSafeIdentifier(member.name)); });
    file.append(")").endLine();
    file.beginBlock();
    for (const auto& member : entity->getDirectMembers())
    {
        file.beginLine()
            .append("this.")
            .append(getSafeIdentifier(member.name))
            .append(" = ")
            .append(getSafeIdentifier(member.name))
            .append(";")
            .endLine();
    }
    file.endBlock();
    file.endLine(); // extra blank line

    // generate deconstructor
    file.beginLine().append("public void Deconstruct(");
    separatedForeach(allFields, [&file]() { file.append(", "); },
                     [this, &file](const auto& member) {
                         file.append("out ")
                             .append(getNetName(member.type))
                             .append(" ")
                             .append(getSafeIdentifier(member.name));
                     });
    file.append(")").endLine();
    file.beginBlock();
    for (const auto& member : allFields)
    {
        file.beginLine()
            .append(getSafeIdentifier(member.name))
            .append(" = ")
            .append("this.")
            .append(getSafeIdentifier(member.name))
            .append(";")
            .endLine();
    }
    file.endBlock();
    file.endLine(); // extra blank line

    // generate exception fields
    for (const auto& member : entity->getDirectMembers())
    {
        for (const auto& anno : member.annotations)
            if (anno == "deprecated")
                file.beginLine().append("[System.Obsolete]").endLine();
        file.beginLine()
            .append("public ")
            .append(getNetName(member.type))
            .append(" ")
            .append(getSafeIdentifier(member.name))
            .append(";")
            .endLine();
    }

    file.endBlock();
    if (hasNamespace)
        file.endBlock();
    file.closeFile();
}

void NetProducer::produceInterface(std::string_view name,
                                   const rtl::Reference<unoidl::InterfaceTypeEntity>& entity)
{
    // produce referenced types
    for (const auto& base : entity->getDirectMandatoryBases())
        produceType(getBaseUnoName(base.name));
    for (const auto& member : entity->getDirectAttributes())
    {
        produceType(getBaseUnoName(member.type));
        for (const auto& e : member.getExceptions)
            produceType(getBaseUnoName(e));
        for (const auto& e : member.setExceptions)
            produceType(getBaseUnoName(e));
    }
    for (const auto& member : entity->getDirectMethods())
    {
        produceType(getBaseUnoName(member.returnType));
        for (const auto& e : member.exceptions)
            produceType(getBaseUnoName(e));
        for (const auto& p : member.parameters)
            produceType(getBaseUnoName(p.type));
    }

    CSharpFile file(m_outputDir, name);

    // verbose and dry run checks
    if (m_verbose)
        std::cout << "[interface] " << name << " -> " << file.getPath() << '\n';
    if (m_dryRun)
        return;

    file.openFile();

    // output namespace block
    auto[hasNamespace, namespaceName, typeName] = splitName(name);

    if (hasNamespace)
        file.beginLine().append("namespace ").append(namespaceName).endLine().beginBlock();

    // generate interface and base interfaces list
    file.beginLine()
        .append("[com.sun.star.uno.UnoGenerated]")
        .endLine()
        .beginLine()
        .append("public interface ")
        .append(getSafeIdentifier(typeName));
    const auto& bases = entity->getDirectMandatoryBases();
    if (!bases.empty())
    {
        file.append(" : ");
        separatedForeach(bases, [&file]() { file.append(", "); },
                         [this, &file](const auto& b) { file.append(getNetName(b.name)); });
    }
    file.endLine().beginBlock();

    // generate interface properties
    for (const auto& member : entity->getDirectAttributes())
    {
        for (const auto& anno : member.annotations)
            if (anno == "deprecated")
                file.beginLine().append("[System.Obsolete]").endLine();
        if (member.bound)
            file.beginLine().append("[com.sun.star.uno.Bound]").endLine();

        file.beginLine()
            .append(getNetName(member.type))
            .append(" ")
            .append(getSafeIdentifier(member.name))
            .endLine()
            .beginBlock();

        if (!member.getExceptions.empty())
        {
            file.beginLine().append("[com.sun.star.uno.Raises(");
            separatedForeach(member.getExceptions, [&file]() { file.append(", "); },
                             [this, &file](const auto& e) {
                                 file.append("typeof(").append(getNetName(e)).append(")");
                             });
            file.append(")]").endLine();
        }
        file.beginLine().append("get;").endLine();

        if (!member.readOnly)
        {
            if (!member.setExceptions.empty())
            {
                file.beginLine().append("[com.sun.star.uno.Raises(");
                separatedForeach(member.setExceptions, [&file]() { file.append(", "); },
                                 [this, &file](const auto& e) {
                                     file.append("typeof(").append(getNetName(e)).append(")");
                                 });
                file.append(")]").endLine();
            }

            file.beginLine().append("set;").endLine();
        }
        file.endBlock();
    }
    if (!entity->getDirectAttributes().empty())
        file.endLine(); // extra blank line

    // generate interface methods
    for (const auto& member : entity->getDirectMethods())
    {
        for (const auto& anno : member.annotations)
            if (anno == "deprecated")
                file.beginLine().append("[System.Obsolete]").endLine();
        if (!member.exceptions.empty())
        {
            file.beginLine().append("[com.sun.star.uno.Raises(");
            separatedForeach(member.exceptions, [&file]() { file.append(", "); },
                             [this, &file](const auto& e) {
                                 file.append("typeof(").append(getNetName(e)).append(")");
                             });
            file.append(")]").endLine();
        }
        file.beginLine()
            .append(getNetName(member.returnType))
            .append(" ")
            .append(getSafeIdentifier(member.name))
            .append("(");
        separatedForeach(
            member.parameters, [&file]() { file.append(", "); },
            [this, &file](const auto& p) {
                using Dir = unoidl::InterfaceTypeEntity::Method::Parameter::Direction;
                switch (p.direction)
                {
                    case Dir::DIRECTION_IN:
                        break;
                    case Dir::DIRECTION_OUT:
                        file.append("out ");
                        break;
                    case Dir::DIRECTION_IN_OUT:
                        file.append("ref ");
                        break;
                }
                file.append(getNetName(p.type)).append(" ").append(getSafeIdentifier(p.name));
            });
        file.append(");").endLine();
    }

    file.endBlock();
    if (hasNamespace)
        file.endBlock();
    file.closeFile();
}

void NetProducer::produceTypedef(std::string_view name,
                                 const rtl::Reference<unoidl::TypedefEntity>& entity)
{
    OString type = u2b(entity->getType());

    produceType(getBaseUnoName(type));
    m_typedefs.emplace(name, type);

    if (m_verbose)
        std::cout << "[typedef] " << name << " = " << type << '\n';
}

void NetProducer::produceConstantGroup(std::string_view name,
                                       const rtl::Reference<unoidl::ConstantGroupEntity>& entity)
{
    CSharpFile file(m_outputDir, name);

    if (m_verbose)
        std::cout << "[constants] " << name << " -> " << file.getPath() << '\n';
    if (m_dryRun)
        return;

    file.openFile();

    auto[hasNamespace, namespaceName, typeName] = splitName(name);

    if (hasNamespace)
        file.beginLine().append("namespace ").append(namespaceName).endLine().beginBlock();

    file.beginLine()
        .append("[com.sun.star.uno.UnoGenerated]")
        .endLine()
        .beginLine()
        .append("public static class ")
        .append(getSafeIdentifier(typeName))
        .endLine()
        .beginBlock();
    for (const auto& member : entity->getMembers())
    {
        for (const auto& anno : member.annotations)
            if (anno == "deprecated")
                file.beginLine().append("[System.Obsolete]").endLine();
        OString type, value;
        switch (member.value.type)
        {
            case unoidl::ConstantValue::TYPE_BOOLEAN:
                type = "bool"_ostr;
                value = member.value.booleanValue ? "true"_ostr : "false"_ostr;
                break;
            case unoidl::ConstantValue::TYPE_BYTE:
                type = "sbyte"_ostr;
                value = OString::number(member.value.byteValue);
                break;
            case unoidl::ConstantValue::TYPE_SHORT:
                type = "short"_ostr;
                value = OString::number(member.value.shortValue);
                break;
            case unoidl::ConstantValue::TYPE_UNSIGNED_SHORT:
                type = "ushort"_ostr;
                value = OString::number(member.value.unsignedShortValue);
                break;
            case unoidl::ConstantValue::TYPE_LONG:
                type = "int"_ostr;
                value = OString::number(member.value.longValue);
                break;
            case unoidl::ConstantValue::TYPE_UNSIGNED_LONG:
                type = "uint"_ostr;
                value = OString::number(member.value.unsignedLongValue);
                break;
            case unoidl::ConstantValue::TYPE_HYPER:
                type = "long"_ostr;
                value = OString::number(member.value.hyperValue);
                break;
            case unoidl::ConstantValue::TYPE_UNSIGNED_HYPER:
                type = "ulong"_ostr;
                value = OString::number(member.value.unsignedHyperValue);
                break;
            case unoidl::ConstantValue::TYPE_FLOAT:
                type = "float"_ostr;
                value = OString::number(member.value.floatValue) + "f";
                break;
            case unoidl::ConstantValue::TYPE_DOUBLE:
                type = "double"_ostr;
                value = OString::number(member.value.doubleValue);
                break;
        }
        file.beginLine()
            .append("public const ")
            .append(type)
            .append(" ")
            .append(getSafeIdentifier(member.name))
            .append(" = ")
            .append(value)
            .append(";")
            .endLine();
    }
    file.endBlock();
    if (hasNamespace)
        file.endBlock();
    file.closeFile();
}

void NetProducer::produceService(
    std::string_view name, const rtl::Reference<unoidl::SingleInterfaceBasedServiceEntity>& entity)
{
    CSharpFile file(m_outputDir, name);

    if (m_verbose)
        std::cout << "[service] " << name << " -> " << file.getPath() << '\n';
    if (m_dryRun)
        return;

    file.openFile();

    auto[hasNamespace, namespaceName, typeName] = splitName(name);

    if (hasNamespace)
        file.beginLine().append("namespace ").append(namespaceName).endLine().beginBlock();

    file.beginLine()
        .append("[com.sun.star.uno.UnoGenerated]")
        .endLine()
        .beginLine()
        .append("public static class ")
        .append(getSafeIdentifier(typeName))
        .endLine()
        .beginBlock();

    for (const auto& ctor : entity->getConstructors())
    {
        for (const auto& anno : ctor.annotations)
            if (anno == "deprecated")
                file.beginLine().append("[System.Obsolete]").endLine();

        std::vector<OUString> exceptions(ctor.exceptions);
        exceptions.emplace(exceptions.begin(), "com.sun.star.uno.DeploymentException");

        file.beginLine().append("[com.sun.star.uno.Raises(");
        separatedForeach(exceptions, [&file]() { file.append(", "); },
                         [this, &file](const auto& e) {
                             file.append("typeof(").append(getNetName(e)).append(")");
                         });
        file.append(")]").endLine();

        if (ctor.defaultConstructor)
        {
            const auto returnType(getNetName(entity->getBase()));

            file.beginLine()
                .append("public static ")
                .append(returnType)
                .append(" create(com.sun.star.uno.XComponentContext ctx)")
                .endLine()
                .beginBlock();

            file.beginLine()
                .append("try")
                .endLine()
                .beginBlock()
                .beginLine()
                .append("com.sun.star.lang.XMultiComponentFactory mcf = ")
                .append("ctx.getServiceManager();")
                .endLine()
                .beginLine()
                .append("com.sun.star.uno.Any srv = new com.sun.star.uno.Any(")
                .append("mcf.createInstanceWithContext(\"")
                .append(name)
                .append("\", ctx));")
                .endLine()
                .beginLine()
                .append("return srv.cast<")
                .append(returnType)
                .append(">();")
                .beginLine()
                .endLine()
                .endBlock();

            for (const auto& e : ctor.exceptions)
            {
                file.beginLine()
                    .append("catch (")
                    .append(e)
                    .append(")")
                    .endLine()
                    .beginBlock()
                    .beginLine()
                    .append("throw;")
                    .endLine()
                    .endBlock();
            }

            file.beginLine()
                .append("catch")
                .endLine()
                .beginBlock()
                .beginLine()
                .append("throw new com.sun.star.uno.DeploymentException(")
                .append("\"Could not create service ")
                .append(name)
                .append(" from given XComponentContext\", ctx);")
                .endLine()
                .endBlock();

            file.endBlock();
        }
        else
        {
            const auto returnType(getNetName(entity->getBase()));
            const auto* restParam = !ctor.parameters.empty() && ctor.parameters.front().rest
                                        ? &ctor.parameters.front()
                                        : nullptr;

            file.beginLine()
                .append("public static ")
                .append(returnType)
                .append(" ")
                .append(getSafeIdentifier(ctor.name))
                .append("(com.sun.star.uno.XComponentContext ctx");
            if (!ctor.parameters.empty())
                file.append(", ");
            separatedForeach(
                ctor.parameters, [&file]() { file.append(", "); },
                [this, &file](const auto& p) {
                    file.append(getNetName(p.type)).append(" ").append(getSafeIdentifier(p.name));
                });
            file.append(")").endLine().beginBlock();

            file.beginLine()
                .append("try")
                .endLine()
                .beginBlock()
                .beginLine()
                .append("com.sun.star.lang.XMultiComponentFactory mcf = ")
                .append("ctx.getServiceManager();")
                .endLine()
                .beginLine()
                .append("com.sun.star.uno.Any srv = new com.sun.star.uno.Any(")
                .append("mcf.createInstanceWithArgumentsAndContext(\"")
                .append(name)
                .append("\"");
            if (restParam)
            {
                file.append(getSafeIdentifier(ctor.parameters.front().name));
            }
            else if (ctor.parameters.empty())
            {
                file.append("System.Array.Empty()");
            }
            else
            {
                file.append("new com.sun.star.uno.Any[] { ");
                separatedForeach(ctor.parameters, [&file]() { file.append(", "); },
                                 [&file](const auto& p) {
                                     file.append("new com.sun.star.uno.Any(")
                                         .append(getSafeIdentifier(p.name))
                                         .append(")");
                                 });
                file.append(" }");
            }
            file.append(", ctx));")
                .endLine()
                .beginLine()
                .append("return srv.cast<")
                .append(returnType)
                .append(">();")
                .endLine()
                .endBlock();

            for (const auto& e : ctor.exceptions)
            {
                file.beginLine()
                    .append("catch (")
                    .append(getNetName(e))
                    .append(")")
                    .endLine()
                    .beginBlock()
                    .beginLine()
                    .append("throw;")
                    .endLine()
                    .endBlock();
            }

            file.beginLine()
                .append("catch")
                .endLine()
                .beginBlock()
                .beginLine()
                .append("throw new com.sun.star.uno.DeploymentException(")
                .append("\"Could not create service ")
                .append(name)
                .append(" from given XComponentContext\", ctx);")
                .endLine()
                .endBlock();

            file.endBlock();
        }
    }

    file.endBlock();
    if (hasNamespace)
        file.endBlock();
    file.closeFile();
}

void NetProducer::produceSingleton(
    std::string_view name, const rtl::Reference<unoidl::InterfaceBasedSingletonEntity>&&nbsp;entity)
{
    CSharpFile file(m_outputDir, name);

    if (m_verbose)
        std::cout << "[singleton] " << name << " -> " << file.getPath() << '\n';
    if (m_dryRun)
        return;

    file.openFile();

    auto[hasNamespace, namespaceName, typeName] = splitName(name);

    if (hasNamespace)
        file.beginLine().append("namespace ").append(namespaceName).endLine().beginBlock();

    file.beginLine()
        .append("[com.sun.star.uno.UnoGenerated]")
        .endLine()
        .beginLine()
        .append("public static class ")
        .append(getSafeIdentifier(typeName))
        .endLine()
        .beginBlock();

    file.beginLine()
        .append("[com.sun.star.uno.Raises(typeof(com.sun.star.uno.DeploymentException))]")
        .endLine();
    file.beginLine()
        .append("public static ")
        .append(getNetName(entity->getBase()))
        .append(" get(com.sun.star.uno.XComponentContext ctx)")
        .endLine()
        .beginBlock();

    file.beginLine()
        .append("try")
        .endLine()
        .beginBlock()
        .beginLine()
        .append("com.sun.star.uno.Any sgtn = ctx.getValueByName(\"/singletons/")
        .append(name)
        .append("\");")
        .endLine()
        .beginLine()
        .append("return sgtn.cast<")
        .append(getNetName(entity->getBase()))
        .append(">();")
        .endLine()
        .endBlock();

    file.beginLine()
        .append("catch")
        .endLine()
        .beginBlock()
        .beginLine()
        .append("throw new com.sun.star.uno.DeploymentException(\"Could not get singleton ")
        .append(name)
        .append(" from given XComponentContext\", ctx);")
        .endLine()
        .endBlock();

    file.endBlock().endBlock();

    if (hasNamespace)
        file.endBlock();

    file.closeFile();
}

OString NetProducer::getNetName(std::string_view name)
{
    OString fullName(name);
    OStringBuffer buffer;

    while (true)
    {
        OString baseName = getBaseUnoName(fullName);
        if (m_typedefs.contains(baseName))
            fullName = fullName.replaceFirst(baseName, m_typedefs.at(baseName));
        else
            break;
    }

    std::string_view fullNameView(fullName);

    // if sequence, count dimensions
    int dimensions = 0;
    while (fullNameView.starts_with("[]"))
    {
        ++dimensions;
        fullNameView = fullNameView.substr(2);
    }

    // if polymorphic, process parameters too
    if (fullNameView.ends_with('>'))
    {
        const std::string_view::size_type nFirstAngle = fullNameView.find_first_of('<');
        size_t start = (nFirstAngle != std::string_view::npos) ? (nFirstAngle + 1) : 0;
        size_t end = fullNameView.size() - 1;
        buffer.append(fullNameView.substr(0, start));
        OString params(fullNameView.substr(start, end - start));

        bool first = true;
        for (start = 0; start != std::string_view::npos;)
        {
            std::string_view param(o3tl::getToken(params, ',', start));
            if (first)
                first = false;
            else
                buffer.append(", ");
            buffer.append(getNetName(param));
        }
        buffer.append(">");
    }
    else
    {
        // assumes basetypes are not polymorphic for a tiny optimization
        // if this is changed later, move this part out of the else block
        fullName = OString(fullNameView);
        OString baseName = getBaseUnoName(fullName);
        if (s_baseTypes.contains(baseName))
            buffer.append(fullName.replaceFirst(baseName, s_baseTypes.at(baseName)));
        else
            buffer.append(fullName);
    }

    // if sequence, add [] to make array
    while (dimensions--)
        buffer.append("[]");

    return buffer.makeStringAndClear();
}
OString NetProducer::getNetName(std::u16string_view name) { return getNetName(u2b(name)); }

/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */

Messung V0.5
C=97 H=98 G=97

¤ Dauer der Verarbeitung: 0.17 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.