#include "c_plugin_generator.h" #include // Convert a snake_case name to PascalCase static QString toPascal(const QString& snake) { QStringList parts = snake.split('_', Qt::SkipEmptyParts); QString result; for (const QString& p : parts) { if (p.isEmpty()) continue; result += p.at(0).toUpper() + p.mid(1); } return result; } // Map LIDL type to Qt/C++ type string for the plugin interface static QString lidlToQt(const TypeExpr& t) { if (t.kind == TypeExpr::Primitive) { if (t.name == "tstr") return "QString"; if (t.name == "bstr") return "QByteArray"; if (t.name == "int") return "int"; if (t.name == "uint") return "int"; if (t.name == "float64") return "double"; if (t.name == "bool") return "bool"; if (t.name == "void") return "void"; if (t.name == "result") return "LogosResult"; if (t.name == "any") return "QVariant"; } if (t.kind == TypeExpr::Array) { if (!t.elements.empty() && t.elements[0].name == "tstr") return "QStringList"; return "QVariantList"; } if (t.kind == TypeExpr::Map) return "QVariantMap"; return "QVariant"; } // Map LIDL type to C type string for the function call static QString lidlToC(const TypeExpr& t) { if (t.kind == TypeExpr::Primitive) { if (t.name == "tstr") return "const char*"; if (t.name == "int") return "int64_t"; if (t.name == "uint") return "uint64_t"; if (t.name == "float64") return "double"; if (t.name == "bool") return "bool"; if (t.name == "void") return "void"; } return "void*"; // fallback } // Generate expression to convert a Qt-typed parameter to C type for the call static QString qtToCallExpr(const TypeExpr& t, const QString& paramName) { if (t.name == "tstr") return paramName + ".toUtf8().constData()"; if (t.name == "int") return "static_cast(" + paramName + ")"; if (t.name == "uint") return "static_cast(" + paramName + ")"; return paramName; // double, bool pass through } // Generate expression to convert a C return value to Qt type static QString cRetToQt(const TypeExpr& t, const QString& expr) { if (t.name == "tstr") return "QString::fromUtf8(" + expr + ")"; if (t.name == "int") return "static_cast(" + expr + ")"; if (t.name == "uint") return "static_cast(" + expr + ")"; return expr; // double, bool, void pass through } QString cPluginMakeHeader(const ModuleDecl& module, const QString& cHeaderInclude, const QString& prefix) { Q_UNUSED(prefix); QString pascal = toPascal(module.name); QString out; out += "// AUTO-GENERATED by logos-cpp-generator --from-c-header -- do not edit\n"; out += "#pragma once\n\n"; out += "#include \n"; out += "#include \n"; out += "#include \n"; out += "#include \n"; out += "#include \"interface.h\"\n"; out += "#include \"logos_api.h\"\n\n"; out += "extern \"C\" {\n"; out += "#include \"" + cHeaderInclude + "\"\n"; out += "}\n\n"; // Interface class QString ifaceName = pascal + "Interface"; QString ifaceIid = "\"org.logos." + ifaceName + "\""; out += "class " + ifaceName + " : public PluginInterface {\n"; out += "public:\n"; out += " virtual ~" + ifaceName + "() = default;\n"; for (const MethodDecl& m : module.methods) { out += " Q_INVOKABLE virtual " + lidlToQt(m.returnType) + " " + m.name + "("; for (size_t i = 0; i < m.params.size(); ++i) { if (i > 0) out += ", "; out += lidlToQt(m.params[i].type) + " " + m.params[i].name; } out += ") = 0;\n"; } out += "};\n\n"; out += "#define " + ifaceName + "_iid " + ifaceIid + "\n"; out += "Q_DECLARE_INTERFACE(" + ifaceName + ", " + ifaceName + "_iid)\n\n"; // Plugin class QString pluginName = pascal + "Plugin"; out += "class " + pluginName + " : public QObject, public " + ifaceName + " {\n"; out += " Q_OBJECT\n"; out += " Q_PLUGIN_METADATA(IID " + ifaceName + "_iid FILE \"metadata.json\")\n"; out += " Q_INTERFACES(" + ifaceName + " PluginInterface)\n\n"; out += "public:\n"; out += " explicit " + pluginName + "(QObject* parent = nullptr);\n"; out += " ~" + pluginName + "() override;\n\n"; out += " QString name() const override { return QStringLiteral(\"" + module.name + "\"); }\n"; out += " QString version() const override { return QStringLiteral(\"" + module.version + "\"); }\n\n"; out += " Q_INVOKABLE void initLogos(LogosAPI* logosAPIInstance);\n\n"; for (const MethodDecl& m : module.methods) { out += " Q_INVOKABLE " + lidlToQt(m.returnType) + " " + m.name + "("; for (size_t i = 0; i < m.params.size(); ++i) { if (i > 0) out += ", "; out += lidlToQt(m.params[i].type) + " " + m.params[i].name; } out += ") override;\n"; } out += "\nsignals:\n"; out += " void eventResponse(const QString& eventName, const QVariantList& args);\n"; out += "};\n"; return out; } QString cPluginMakeSource(const ModuleDecl& module, const QString& prefix) { QString pascal = toPascal(module.name); QString pluginName = pascal + "Plugin"; QString out; out += "// AUTO-GENERATED by logos-cpp-generator --from-c-header -- do not edit\n"; out += "#include \"" + module.name + "_plugin.h\"\n"; out += "#include \n\n"; // Constructor out += pluginName + "::" + pluginName + "(QObject* parent)\n"; out += " : QObject(parent)\n"; out += "{\n"; out += " qDebug() << \"" + pluginName + ": created\";\n"; out += "}\n\n"; // Destructor out += pluginName + "::~" + pluginName + "()\n"; out += "{\n"; out += " qDebug() << \"" + pluginName + ": destroyed\";\n"; out += "}\n\n"; // initLogos — store the API pointer (required by QtProviderObject::callMethod) out += "void " + pluginName + "::initLogos(LogosAPI* logosAPIInstance)\n"; out += "{\n"; out += " logosAPI = logosAPIInstance;\n"; out += " qDebug() << \"" + pluginName + "::initLogos called, api=\" << (void*)logosAPIInstance << \"stored=\" << (void*)logosAPI;\n"; out += "}\n\n"; // Method implementations for (const MethodDecl& m : module.methods) { QString retQt = lidlToQt(m.returnType); out += retQt + " " + pluginName + "::" + m.name + "("; for (size_t i = 0; i < m.params.size(); ++i) { if (i > 0) out += ", "; out += lidlToQt(m.params[i].type) + " " + m.params[i].name; } out += ")\n{\n"; // Build C function call QString cFunc = prefix + m.name; // Handle the reserved-name rename: if method is "libVersion", original C func is prefix + "version" if (m.name.startsWith("lib") && m.name.length() > 3 && m.name[3].isUpper()) { QString original = m.name.mid(3); original[0] = original[0].toLower(); cFunc = prefix + original; } QString callArgs; for (size_t i = 0; i < m.params.size(); ++i) { if (i > 0) callArgs += ", "; callArgs += qtToCallExpr(m.params[i].type, m.params[i].name); } QString call = cFunc + "(" + callArgs + ")"; if (m.returnType.name == "void") { out += " " + call + ";\n"; } else { out += " return " + cRetToQt(m.returnType, call) + ";\n"; } out += "}\n\n"; } return out; }