Java library to read, parse and query KDI (K Description Interface) files produced by the klang compiler — in both CBOR and JSON encodings.
klang-kdi turns a .kdi (binary CBOR) or .kdi.json (text JSON) library
description into a fully-typed, immutable Java object model, and provides a small
query layer to enumerate and resolve the exported symbols (namespaces, aggregates,
methods, functions, enums, unions, …).
Its primary consumer is the IntelliJ klang plugin, which uses it to inspect the public API of an imported K library.
- Coordinates:
com.github.emilienkia.klang:klang-kdi:0.1-SNAPSHOT - Base package:
com.github.emilienkia.kdi - Java: 21+
- License: Apache-2.0
| Feature | Status |
|---|---|
Read KDI from Path, byte[], InputStream |
✅ Implemented |
CBOR decoding (canonical .kdi) |
✅ Implemented |
JSON decoding (.kdi.json) |
✅ Implemented |
| Automatic CBOR vs JSON detection | ✅ Implemented |
| Full typed object model (header, type table, unit tree) | ✅ Implemented |
Polymorphic KdiType hierarchy (sealed) |
✅ Implemented |
Polymorphic KdiLayoutField hierarchy (sealed) |
✅ Implemented |
| Documentation payloads (brief/description, params, throws, tags) | ✅ Implemented |
| Aggregates, methods, ctors/dtors, vtables, bases, layout | ✅ Implemented |
| Enums (incl. object-backed), unions, templates | ✅ Implemented |
| Forward-compatible parsing (unknown fields ignored) | ✅ Implemented |
| Symbol index: lookup by fq-name / mangled-name, child navigation | ✅ Implemented |
Kdi façade with lazy, cached index |
✅ Implemented |
| Schema validation (against KDI v0.1 rules) | ⏳ Planned |
| Writing / serialization back to KDI | ❌ Out of scope (read-only library) |
| Multiple schema versions | ❌ Out of scope (current format only) |
The library targets KDI schema v0.1 (schema_major=0, schema_minor=1), the
current format emitted by klangc.
Build and install locally (the artifact is not yet published to a repository):
mvn installThen depend on it:
<dependency>
<groupId>com.github.emilienkia.klang</groupId>
<artifactId>klang-kdi</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>import com.github.emilienkia.kdi.Kdi;
import com.github.emilienkia.kdi.query.KdiSymbol;
import com.github.emilienkia.kdi.model.KdiMethod;
import java.nio.file.Path;
// Load a .kdi (CBOR) or .kdi.json (JSON) — the encoding is auto-detected.
Kdi kdi = Kdi.read(Path.of("libmath.utils.kdi"));
System.out.println(kdi.moduleName()); // "math::utils"
System.out.println(kdi.dependencies()); // [ival_lib, aval_lib]
// Resolve a binary symbol back to its declaration.
kdi.findByMangledName("_ZNK4math5utils4Vec33dotERKS1_")
.ifPresent(sym -> {
KdiMethod m = sym.payloadAs(KdiMethod.class);
System.out.println(sym.getFqName() + " -> " + m.getLlvmDef());
});
// Enumerate the members of a type.
for (KdiSymbol child : kdi.index().childrenOf("math::utils::Vec3")) {
System.out.println(child.getKind() + " " + child.getName());
}Reading without the façade:
import com.github.emilienkia.kdi.io.KdiReader;
import com.github.emilienkia.kdi.io.KdiFormat;
import com.github.emilienkia.kdi.model.KdiFile;
KdiFile file = KdiReader.defaultReader().read(bytes); // auto-detect
KdiFile json = KdiReader.defaultReader().read(bytes, KdiFormat.JSON); // explicitcom.github.emilienkia.kdi
├── Kdi façade: load + lazily-cached query index
├── io/ decoding
│ ├── KdiReader CBOR + JSON → KdiFile (shared Jackson model)
│ ├── KdiFormat CBOR | JSON, with content-based auto-detection
│ └── KdiException, KdiParseException
├── model/ immutable DTOs (Lombok @Value/@Builder/@Jacksonized)
│ ├── KdiFile, KdiHeader, KdiTypeTable, KdiUnit, KdiNamespace
│ ├── KdiAggregate, KdiBase, KdiMethod, KdiConstructor, KdiDestructor
│ ├── KdiFunction, KdiVariable, KdiParam, KdiVtable
│ ├── KdiEnum, KdiUnion, KdiTemplate* (origin/def/param/arg)
│ ├── Visibility, AggregateKind
│ ├── type/ KdiType sealed hierarchy of all K type variants
│ ├── layout/ KdiLayoutField sealed hierarchy of all LLVM layout entries
│ └── doc/ KdiDocBlock, KdiDocFunction
└── query/ navigation
├── KdiSymbol, SymbolKind
└── KdiSymbolIndex flatten tree; lookup by fq-name / mangled-name
Design notes
- A single Jackson-annotated model serves both encodings: CBOR
.kdifiles use text-string map keys identical to the JSON keys, so the same DTOs decode both. - DTOs are immutable (Lombok
@Value+@Builder+@Jacksonized) and forward-compatible (@JsonIgnoreProperties(ignoreUnknown = true)): a newerklangcthat adds fields will not break parsing. KdiTypeandKdiLayoutFieldaresealedso consumers can use exhaustiveswitchexpressions over their variants.- The query layer is deliberately thin and side-effect-free, so the IntelliJ plugin can build its own caching/indexing on top.
mvn test # compile + run the JUnit 5 / AssertJ suite
mvn package # build the jar
mvn install # install to the local Maven repositoryToolchain note: Lombok must match the JDK used to compile. This project is validated with JDK 21–25; if you upgrade the JDK, bump the
lombok.versionproperty accordingly.
- KDI specification:
klang/doc/spec/kdi/(kdi-schema-abstract.md,kdi-cbor-schema.md) - Reference C++ implementation:
klang/libkdi/ kditoolmanual page:klang/doc/man/kdi.mdAGENT.md— guidance for coding agents, incl. how to track KDI format updatesTODO.md— roadmap and known gaps