Koffee
Java bytecode assembler as a Kotlin DSL
Install / Use
/learn @char/KoffeeREADME
Koffee
A Kotlin DSL wrapping ObjectWeb's ASM bytecode manipulation library. (In particular, asm-tree.)
Limitations
Since the DSL is in Kotlin, there are a few reserved words that get in our way. In order to get around this, we provide properties with the literal name and use backtick-escaping, and the preferred approach of a leading underscore before the reserved name.
- Since 'interface' is a globally reserved keyword in Kotlin, the access flag
interfacecan be referenced using`interface`or_interface - Since 'super' is a globally reserved keyword in Kotlin, the access flag
supercan be referenced using`super`or_super - Since 'return' is a globally reserved keyword in Kotlin, the instruction
returncan be referenced using`return`or_return
Extras
Kotlin makes life a lot easier for simplifying the user's experience. It allows Koffee to do some useful things:
- All bytecode instructions are represented as simple methods (e.g.
getfield(...)) or properties (e.g.aconst_null) - Fields are created with a single function call (e.g.
field(...)) - Methods are created with an easy way to add individual bytecode (see the example)
- Lots of sugar exists for commonly used constructs:
initandclinitmethods- Object creation (with
construct) - Try/catch blocks (with
guardand its returned object to add exception handlers)
Simple Example
val helloWorld: ClassNode = assembleClass(public, "com/example/HelloWorld") {
method(public + static, "main", void, Array<String>::class) {
getstatic(System::class, "out", PrintStream::class)
ldc("Hello, world!")
invokevirtual(PrintStream::class, "println", void, String::class)
_return
}
}
Complex Example
val myClass = assembleClass(public, "com/example/MyClass") {
field(public + static + final, "theAnswer", int, value = 42)
field(private + static + final, "instance", MyClass::class)
method(public + static, "getInstance", MyClass::class) {
getstatic(MyClass::class, "instance", MyClass::class)
dup
ifnull(L["oh noes"])
_return
+L["oh noes"]
construct(IOException::class, String::class) {
ldc("no instance exists whatever shall we do?")
}
athrow
}
init(public) {
// nothing extra: the superclass is called automatically, and no fields are initialized
}
clinit {
construct(MyClass::class)
putstatic(MyClass::class, "instance", MyClass::class)
}
}
Goals
- Koffee is designed to be used in projects that already make use of ASM, so we don't need to abstract too far away.
- Despite this, Koffee should aim to make the use of ASM easier - High-level abstractions are acceptable if they are common. (e.g. 'load int constant' can be made uniform)
Related Skills
node-connect
338.7kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
83.6kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
338.7kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
83.6kCommit, push, and open a PR
