Bindgen Annotation Processor - #41
Conversation
An initial implementation of a @Bindgen annotation and corresponding annotation processor is added. This closely mimics the functionality of the Wasmtime bindgen! macro, looking for .wit files in a /wit directory, allowing a typical Java project to keep them in src/main/resources. It also allows specifying WIT definitions direction inline in the annotation. The annotation processor uses wasm-tools to convert the textual WIT format into the corresponding binary .wasm format. The binary representation conforms to the binary format of the Component Model, thus we are then able to use ComponentParser to read the output into a WasmComponent AST and traverse the structure to generate corresponding Java bindings. The annotation processor'a unit tests use the Google compile-testing library to test the processor's output, comparing the generated bindings for a given WIT definition to a set of golden files. A separate bindgen-processor-tests module contains integration tests for the processor. This module configures the annotation processor so that the @Bindgen annotation may be used directly on test classes to fully generate the bindings for the targeted WIT. Core wasm modules written in WAT are used for testing the interaction between the host and guest and validate that the bindings work as intended at runtime. These tests replicate all of the non-async examples from Wasmtime's bindgen! macro. Further work remains to be done to fully generate code for all of the Component Model's types that may cross the host-guest boundary. The full details of what has been implemented so far and what is still planned to be implemented is captured in bindgen-processor/design.md
|
@andreaTP A decent amount of work still remains on the processor, but I thought I should go ahead and clean up what I have so far and get it up here as a starting point. No worries if you don't have time to review this before your vacation, I'm feeling pretty good about the shape of this and am happy to continue work on it in further branches. |
andreaTP
left a comment
There was a problem hiding this comment.
Too long to be reviewed properly in a short amount of time.
I agree with the final goal and this is surely as great starting point.
Do you have rights to merge the PR @jeremyg484 ? (please 🙏 do it so that I know you can work autonomously while I'm away 🙂 )
| </dependency> | ||
| <dependency> | ||
| <groupId>com.google.testing.compile</groupId> | ||
| <artifactId>compile-testing</artifactId> |
| for (WitInterface exported : world.exportedInterfaces()) { | ||
| String name = fieldName(exported.simpleName()); | ||
| type.addMember( | ||
| StaticJavaParser.parseBodyDeclaration( |
There was a problem hiding this comment.
The idea behind using JavaParser is to avoid dumping code in plain strings that is ugly and harder to maintain in the longer run.
In the longer run we should avoid StaticJavaParser.parse
There was a problem hiding this comment.
Agreed. I admittedly let the AI get a bit carried away with this class in particular. I'll make a point to clean it up in the next revision.
| // A bare import carries its function type as a constant, whether or not any interface does. | ||
| Stream<WitFunction> everything = Stream.concat(world.imports().stream(), allImports(world)); | ||
| List<WitFunction> all = everything.collect(Collectors.toList()); | ||
| if (all.stream().anyMatch(WorldGenerator::hasParams)) { |
There was a problem hiding this comment.
I don't think we should be strict about having "just the right imports" in generated code, it's not a big concern for humans(especially in Java) and they complicate the code risking bugs without much in return.
| private String importsInterface(WitTypes types) { | ||
| StringBuilder body = new StringBuilder(); | ||
| body.append("/** The world's imports, which the embedder implements. */\n"); | ||
| body.append("public interface Imports {\n"); |
There was a problem hiding this comment.
Let's use JavaParser AST for those things, it's really hard to read through.
|
|
||
| private String constructor(WitTypes types, String className) { | ||
| StringBuilder body = new StringBuilder(); | ||
| body.append("private ").append(className).append("(ComponentInstance instance) {\n"); |
There was a problem hiding this comment.
my eyes are bleeding at this point 😅
| Code should always use idiomatic Java style and follow the patterns that have already been established throughout | ||
| the codebase. Code should adhere to the style enforced by the project's CheckStyle and Spotless build plugins. | ||
|
|
||
| When writing comments, always prefer simple, clear, and concise sentences. Omit unnecessary words and avoid overly |
There was a problem hiding this comment.
Just switched to a different model and did the same 👍
Yes, it looks like I've got permissions, I'll do it now. Enjoy your time off! |
An initial implementation of a @Bindgen annotation and corresponding
annotation processor is added. This closely mimics the functionality of
the Wasmtime bindgen! macro, looking for .wit files in a /wit directory,
allowing a typical Java project to keep them in src/main/resources. It
also allows specifying WIT definitions direction inline in the
annotation.
The annotation processor uses wasm-tools to convert the textual WIT
format into the corresponding binary .wasm format. The binary
representation conforms to the binary format of the Component Model,
thus we are then able to use ComponentParser to read the output into a
WasmComponent AST and traverse the structure to generate corresponding
Java bindings.
The annotation processor'a unit tests use the Google compile-testing
library to test the processor's output, comparing the generated bindings
for a given WIT definition to a set of golden files.
A separate bindgen-processor-tests module contains integration tests for
the processor. This module configures the annotation processor so that
the @Bindgen annotation may be used directly on test classes to fully
generate the bindings for the targeted WIT. Core wasm modules written in
WAT are used for testing the interaction between the host and guest and
validate that the bindings work as intended at runtime. These tests
replicate all of the non-async examples from Wasmtime's bindgen! macro.
Further work remains to be done to fully generate code for all of the
Component Model's types that may cross the host-guest boundary. The full
details of what has been implemented so far and what is still planned to
be implemented is captured in bindgen-processor/design.md