Comments and docs across the repo still claimed this generator emits the Qt
plugin glue, and pointed `--backend qt` users at logos-qt-generator. Neither
is true: the Qt-plugin (provider) glue is emitted by logos-plugin-qt's
logos-qt-host-generator --backend cdylib, on top of the C ABI this tool emits
with --backend cdylib, and logos-qt-generator owns only `consumer` and `ui`
(it refuses the flag too).
Also corrects the LogosModuleContext header, whose comments described the
retired Qt provider path throughout — `<name>_events.cpp` marshalling into a
QVariantList and a provider `onInit` setting the context. The emitted file is
`<name>_events_cdylib.cpp`, it marshals into nlohmann::json, and the C-ABI
export TU installs the callback. The runtime path it named
(runtime_qt/host/module_initializer.cpp) no longer exists.
The only behaviour change is the text of three --backend/--from-header error
messages, which named the wrong tool. Nothing asserts on them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This should have been part of the merge commit and was not. `docs/project.md`
still listed `legacy/` in the project tree, named `legacy_main()` as the
fallthrough target, and described `--api-style` as being threaded through
`legacy/main.cpp` → `generateFromPlugin` / `writeUmbrellaHeader` — a directory,
a function and two emitters that no longer exist. `docs/spec.md` still pointed
backwards-compatibility at `legacy_main()`.
Corrected to `plugin_introspect.{cpp,h}` / `runPluginIntrospectMode()`, with the
provenance kept rather than erased: the tree entry says what it was and why it
was never a library, because "there used to be a legacy generator" is the
question a reader will actually arrive with.
The umbrella line gets the deletion too — `writeUmbrellaHeader` /
`writeUmbrellaSource` were the second, directory-scraping implementation of
logos_sdk.{h,cpp}, and their absence is the point: `makeUmbrella*FromDeps` is
now the only umbrella emitter, so the two cannot drift.
Two nearby lines were stale independently of that move and are fixed with it:
* "the legacy emitters in tests/generator/" — those tests cover the SHARED
generator_lib emitters (test_make_header/source/umbrella, the type maps),
which are not legacy and never were.
* "consumer wrappers real modules get come from legacy/main.cpp →
generateInterfaceWrappers" — generateInterfaceWrappers is in main.cpp and
was already there, so that path was misattributed before this branch.
Every other use of "legacy" in these docs is left alone: `interface: "legacy"`,
legacy Qt types (QVariantMap / QVariantList / QStringList), legacy Q_INVOKABLE
modules and the legacy consumer path are all real things that still exist.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
--backend qt is deleted from logos-qt-generator, and this repo was still
signposting it. main.cpp's refusal said "Use it for --backend qt", and the usage
text advertised --lidl … --backend qt and --from-header … --backend qt. Those
now point at nothing — the exact failure the deletion removes, one repo over.
The refusal names the real replacement chain instead: --backend cdylib here,
then logos-qt-host-generator --backend cdylib for Qt-plugin packaging.
docs/project.md's "Provider Generation" section documented three emitters that
no longer exist; rewritten to state the seam and the two-step pipeline.
docs/spec.md's dataflow diagram showed <name>_qt_glue.h / <name>_dispatch.cpp as
outputs; the diagram is corrected and the sections describing that shape are
marked historical rather than deleted, because the onInit wiring they document
still applies to the cdylib glue.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every provider now goes through the module-impl C ABI, so the LOGOS_METHOD
dispatch path is gone: parseProviderHeader, generateProviderDispatch,
ParsedMethod and the joinDocLines helper only it used (~300 lines), plus the
test that covered it.
`toQVariantConversion` is NOT removed — it is shared with live emitters — and
its test stays.
The flag is REFUSED rather than dropped. Without that, `--provider-header x.h`
falls through to the plugin-path branch, which reads the flag itself as a
plugin path and reports "Plugin file does not exist: --provider-header" — a
missing-file error for what is really a retired mode. It now exits 2 with a
message pointing at interface: "universal".
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The Std surface — std-typed signatures over a QVariant + LogosAPIClient
body — no longer had a caller. `interface: "universal"` modules moved to
`lp` (std types over the Qt-free logos-protocol C ABI), and nothing else
ever selected it, so every Std branch was dead weight sitting in front of
the two live ones.
`--api-style=std` is now rejected with a message naming the retirement
rather than aliased to `qt`. A stale caller that still passes it wants
std signatures; handing it the Qt surface would fail later, further from
the cause.
The collapse is deliberate about the branches where Std was tested BEFORE
Qt, since a naive "delete the block containing ApiStyle::Std" changes Qt
output:
- makeHeader's include block tested Std first, so its `else` is the Qt
include list — the Qt includes are kept and promoted, not deleted.
- recordToWireExpr / recordFromWireExpr returned the Qt map form from a
guarded `if` and the Std form from the function's trailing `return`.
The guard is dropped and the Qt form promoted to the tail; deleting
only the trailing return would have left a path falling off the end.
- The private-member `else if (!events.isEmpty())` arm reads as an event
test but was Std-only; the Qt arm (m_eventReplica + m_eventSource)
survives, so setEventSource/trigger still have their storage.
- `if (apiStyle == Qt || !events.isEmpty())` is a disjunction, not an
Std branch: it unwraps to an unconditional emit, keeping
ensureReplica()'s declaration next to its definition.
- `isRec || style == Std` loses only the right disjunct — dropping
`isRec ||` would double-wrap record fields in QVariant::fromValue.
mapParamTypeStd / mapReturnTypeStd / isStdRefType stay: they are the
shared std type table that ApiStyle::Lp reaches through the non-Qt arm of
paramTypeFor / returnTypeFor / byRefFor and directly from lpPushExpr /
lpFromJsonExpr.
Verified by output equivalence rather than by the build succeeding: the
generator was run over 13 fixture cases (the full_api contract as both a
bound interface and a baked dep, three record-bearing contracts incl.
map-of-record fields, the chat module's production contract, and a
no-events contract) for both qt and lp, before and after. `diff -r` over
the 194 resulting files reports no differences, and the experimental
--lidl backends are byte-identical too. Test suite: 180/180, unchanged.
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* Add per-event documentation + getPluginEvents introspection
Mirror the per-method documentation pipeline for events. Events
(declared in a universal module's logos_events: section) now carry a
description parsed from their /// doc comments, and are introspectable
at runtime via a new getPluginEvents framework call.
- lidl_ast: EventDecl gains a description field.
- impl_header_parser: capture the event's doc comment (previously
discarded) and an optional metadata.json events[].description.
- lidl_gen_provider: generated universal provider emits
getEvents() override, mirroring getMethods() (name/signature/
parameters/description; no returnType/isInvokable — events are void).
- logos_provider_object: default-empty virtual getEvents() so the
legacy provider path and QtProviderObject inherit empty.
- module_proxy / qt_provider_object: intercept getPluginEvents next to
the getPluginMethods special-case.
- docs: spec + README event-documentation notes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Add unit tests for event documentation + getEvents generation
Address review feedback (#71): cover the event-introspection paths that
previously only had method-side tests.
- impl_header_parser test: assert metadata.json events[].description is
parsed; new documented_events fixture asserts `///` doc-comment
capture on a logos_events: block (multi-line joined with \n,
adjacent-only, plain // ignored).
- lidl_gen_provider test: assert the generated dispatch contains
getEvents() emitting each event's name/signature/parameters and an
escaped description, and that events carry no returnType/isInvokable.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Fold event introspection into getMethods() to keep the provider ABI stable
The previous approach added a getEvents() virtual to LogosProviderObject,
which inserted a new vtable slot and shifted every later slot — an ABI
break that would misdispatch virtual calls whenever an old and new
host/module were mixed across the in-process plugin boundary.
Instead, report events INSIDE the existing getMethods() call: it now
returns the module's whole interface, with each entry tagged
type "method" or "event" (events omit returnType/isInvokable). The
provider vtable is therefore byte-for-byte unchanged, so old/new hosts
and modules stay binary-compatible — a new host reading an old module
sees no event entries (zero events), and an old host reading a new
module just ignores the "type" field (cosmetic). An entry with no
"type" is treated as a method.
- logos_provider_object.h: remove the getEvents() virtual; document that
getMethods() carries both, and why.
- generator (lidl_gen_provider): emit events as type "event" entries
inside getMethods(); tag methods type "method"; no getEvents() output.
- module_proxy / qt_provider_object: getPluginMethods()/getPluginEvents()
are now type-filtered views of getMethods(), plus a new
getPluginInterface() returning the whole list. (These are name-
dispatched Q_INVOKABLEs, not vtable surface — adding them is safe.)
- tests: generator asserts events fold into getMethods() tagged "event";
ModuleProxy asserts the three filtered views; parser tests unchanged.
- docs: spec/project/docs/README updated, incl. an ABI rationale note.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* parse adjacent method comments to populate description
* preserve line breaks in method descriptions
Join doc-comment lines with newlines instead of spaces (markers stripped,
leading/trailing blank lines dropped, interior blanks kept), and escape \n
when emitting the description into the generated getMethods(). Both codegen
paths updated; docs corrected.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* don't count braces inside comment lines (impl-header parser)
A brace in a doc/line comment (e.g. `/// returns { ... }`) no longer affects
class-scope tracking, which previously could make the parser think the class
ended early and drop later declarations. Addresses review feedback on #70.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>