#ifndef GENERATOR_LIB_H #define GENERATOR_LIB_H #include #include #include #include #include struct ParsedMethod { QString returnType; QString name; QVector> params; // (type, name) QString description; // doc comment adjacent to the LOGOS_METHOD declaration }; // Which type surface to expose on the generated per-module wrapper. // Each module's build picks ONE — there's no composite output. Default // is Qt for backward compatibility; `interface: "universal"` modules // flip to Std via the -DLOGOS_API_STYLE=std CMake flag the module // builder threads through. // Qt — legacy Qt-typed surface (QString/QVariant…), body via LogosAPIClient. // Std — std-typed surface, but the body still bridges through QVariant + // LogosAPIClient (so the wrapper .cpp links qt-sdk). // Lp — std-typed surface AND a Qt-free body: the wrapper calls the // logos-protocol C ABI (lp_*) directly via logos::LpClient, so the // module's translation units never include Qt or link qt-sdk. This is // the path that lets a cdylib module do outbound typed calls/event // subscriptions while staying Qt-free (Qt confined to the QRO transport // inside logos-protocol + the generated plugin glue). enum class ApiStyle { Qt, Std, Lp }; // Whether the generated wrapper targets ONE fixed module (the historical // behaviour) or binds to a module name chosen at runtime. // Static — the module name is baked into the ctor + every remote call, // so `(LogosAPI*)` always talks to that one module. // This is what name-baked dependency wrappers use. // Bound — the ctor takes `(LogosAPI*, const QString& moduleName)` and // stores it in `m_moduleName`; every remote call routes through // that member. This is what *interface* wrappers use: one // interface, bound to a concrete module name at runtime. // Default is Static so existing callers and their generated output are // byte-for-byte unchanged. enum class BindMode { Static, Bound }; QString toPascalCase(const QString& name); QString normalizeType(QString t); QString mapParamType(const QString& qtType); QString mapReturnType(const QString& qtType); QString toQVariantConversion(const QString& type, const QString& argExpr); // makeHeader / makeSource emit the single `` wrapper for a // module. When `apiStyle == Std`, parameter / return types come from // the std-typed mapping table (std::string / std::vector // / LogosMap / LogosList / int64_t / StdLogosResult) and the .cpp // body wraps the QVariant wire with inline Qt↔std conversions — // callers never include Qt headers. When `apiStyle == Qt`, the output // matches the legacy Qt-typed surface (QString / QStringList / // QVariantList / QVariantMap / int / LogosResult). The class name is // always `` either way; the two styles are mutually exclusive. // // `events` carries typed event prototypes loaded from a `.lidl` // sidecar via --events-from. Each entry is // { "name": "", "params": [ { "name": "...", "type": "" } ] } // (Qt-typed names — same surface methods come through). When non-empty, // the wrapper also gets one `on(callback)` accessor per // event next to the existing generic `onEvent(name, callback)` channel. // The accessor signature uses the apiStyle's type surface for the // callback's argument types. // // `bindMode` selects a fixed-module wrapper (Static, default) or a // runtime-bound interface wrapper (Bound) — see BindMode above. In Bound // mode `moduleName` is used only for the class/file naming the caller // already decided; the emitted code never bakes it into a call. // // `records` carries the contract's `type Foo { ... }` declarations, as // [ { "name": "Foo", "fields": [ { "name": "...", "type": "" } ] } ] // Each becomes a struct NESTED in the wrapper class (`::Foo`, so two // deps may both declare a `Status`), and every method / event that mentions // one is typed with it instead of falling back to QVariant / LogosMap. Field // types use the same Qt type-name spelling as methods, so a field can name // another record, `QList`, or `QMap`. Empty (the // default, and what the metaobject-introspection path passes) leaves the // generated output exactly as it was. QString makeHeader(const QString& moduleName, const QString& className, const QJsonArray& methods, ApiStyle apiStyle = ApiStyle::Qt, const QJsonArray& events = {}, BindMode bindMode = BindMode::Static, const QJsonArray& records = {}); QString makeSource(const QString& moduleName, const QString& className, const QString& headerBaseName, const QJsonArray& methods, ApiStyle apiStyle = ApiStyle::Qt, const QJsonArray& events = {}, BindMode bindMode = BindMode::Static, const QJsonArray& records = {}); // Qt-free (ApiStyle::Lp) wrapper emission. Same std-typed surface as the Std // flavor, but the generated body calls the logos-protocol C ABI through // logos::LpClient instead of LogosAPIClient — no Qt in the wrapper's TU. // makeHeader/makeSource dispatch here when apiStyle == ApiStyle::Lp. QString makeHeaderLp(const QString& moduleName, const QString& className, const QJsonArray& methods, const QJsonArray& events = {}, BindMode bindMode = BindMode::Static, const QJsonArray& records = {}); QString makeSourceLp(const QString& moduleName, const QString& className, const QString& headerBaseName, const QJsonArray& methods, const QJsonArray& events = {}, BindMode bindMode = BindMode::Static, const QJsonArray& records = {}); QVector parseProviderHeader(const QString& headerPath, QTextStream& err); #endif // GENERATOR_LIB_H