EmilienKia/kdi-java

★ 0Forks 0JavaGitHub ↗Compare

README

klang-kdi

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

Features

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.


Installation

Build and install locally (the artifact is not yet published to a repository):

mvn install

Then depend on it:

<dependency>
    <groupId>com.github.emilienkia.klang</groupId>
    <artifactId>klang-kdi</artifactId>
    <version>0.1-SNAPSHOT</version>
</dependency>

Usage

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); // explicit

Architecture

com.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 .kdi files 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 newer klangc that adds fields will not break parsing.
  • KdiType and KdiLayoutField are sealed so consumers can use exhaustive switch expressions 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.

Building & testing

mvn test       # compile + run the JUnit 5 / AssertJ suite
mvn package    # build the jar
mvn install    # install to the local Maven repository

Toolchain 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.version property accordingly.


See also

Contributors

EmilienKia

Issues