diff --git a/bindgen/it/pom.xml b/bindgen/it/pom.xml
new file mode 100644
index 000000000..fbe024187
--- /dev/null
+++ b/bindgen/it/pom.xml
@@ -0,0 +1,87 @@
+
+
+ 4.0.0
+
+
+ com.dylibso.chicory
+ bindgen-parent
+ 999-SNAPSHOT
+ ../pom.xml
+
+ bindgen-it
+ jar
+ Chicory - Bindgen - IT
+ Integration tests for the Chicory Bindgen
+
+
+
+ com.dylibso.chicory
+ bindgen
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+
+
+ ${project.basedir}
+ ${project.version}
+
+
+
+
+
+ integration-test
+ verify
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-invoker-plugin
+
+ ${project.build.directory}/it
+ true
+ src/it/settings.xml
+ verify
+ true
+ ${skipTests}
+ true
+ invoker.properties
+
+ ${project.version}
+ ${project.artifactId}
+ ${project.groupId}
+
+
+
+
+ integration-tests
+
+ install
+ run
+
+
+
+
+
+
+ org.codehaus.mojo
+ templating-maven-plugin
+ 3.0.0
+
+
+ filtering-java-templates
+
+ filter-sources
+
+
+
+
+
+
+
diff --git a/bindgen/it/src/it/base/invoker.properties b/bindgen/it/src/it/base/invoker.properties
new file mode 100644
index 000000000..84099bc5a
--- /dev/null
+++ b/bindgen/it/src/it/base/invoker.properties
@@ -0,0 +1 @@
+invoker.goals=test
diff --git a/bindgen/it/src/it/base/pom.xml b/bindgen/it/src/it/base/pom.xml
new file mode 100644
index 000000000..a0b294234
--- /dev/null
+++ b/bindgen/it/src/it/base/pom.xml
@@ -0,0 +1,70 @@
+
+
+
+ 4.0.0
+ com.dylibso.chicory
+
+ base-chicory-it
+ 0.0-SNAPSHOT
+ jar
+
+
+ @maven.compiler.release@
+
+
+
+
+ com.dylibso.chicory
+ runtime
+ @project.version@
+
+
+ com.dylibso.chicory
+ wasm-corpus
+ @project.version@
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ @junit.version@
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ @junit.version@
+ test
+
+
+
+
+
+
+ com.dylibso.chicory
+ bindgen
+ @project.version@
+
+
+
+ generate
+
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ @maven-compiler-plugin.version@
+
+ ${maven.compiler.release}
+
+
+
+
+
+
diff --git a/bindgen/it/src/it/base/src/test/java/BasicTest.java b/bindgen/it/src/it/base/src/test/java/BasicTest.java
new file mode 100644
index 000000000..8fe868a52
--- /dev/null
+++ b/bindgen/it/src/it/base/src/test/java/BasicTest.java
@@ -0,0 +1,40 @@
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import com.dylibso.chicory.gen.Module;
+import com.dylibso.chicory.runtime.Instance;
+import com.dylibso.chicory.wasm.Parser;
+import org.junit.jupiter.api.Test;
+
+class BasicTest {
+
+ class TestModule extends Module {
+ private final Instance instance;
+
+ public TestModule() {
+ instance =
+ Instance.builder(
+ Parser.parse(
+ BasicTest.class.getResourceAsStream(
+ "/compiled/extism-runtime.wasm")))
+ .build();
+ }
+
+ @Override
+ public Instance instance() {
+ return this.instance;
+ }
+ }
+
+ @Test
+ public void basicModule() {
+ // Arrange
+ var extismModule = new TestModule();
+
+ // Act
+ var ptr = extismModule.alloc(1);
+
+ // Assert
+ assertTrue(ptr > 0);
+ extismModule.free(ptr);
+ }
+}
diff --git a/bindgen/it/src/it/multi-returns/invoker.properties b/bindgen/it/src/it/multi-returns/invoker.properties
new file mode 100644
index 000000000..84099bc5a
--- /dev/null
+++ b/bindgen/it/src/it/multi-returns/invoker.properties
@@ -0,0 +1 @@
+invoker.goals=test
diff --git a/bindgen/it/src/it/multi-returns/pom.xml b/bindgen/it/src/it/multi-returns/pom.xml
new file mode 100644
index 000000000..76dd822a9
--- /dev/null
+++ b/bindgen/it/src/it/multi-returns/pom.xml
@@ -0,0 +1,70 @@
+
+
+
+ 4.0.0
+ com.dylibso.chicory
+
+ multi-returns-chicory-it
+ 0.0-SNAPSHOT
+ jar
+
+
+ @maven.compiler.release@
+
+
+
+
+ com.dylibso.chicory
+ runtime
+ @project.version@
+
+
+ com.dylibso.chicory
+ wasm-corpus
+ @project.version@
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ @junit.version@
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ @junit.version@
+ test
+
+
+
+
+
+
+ com.dylibso.chicory
+ bindgen
+ @project.version@
+
+
+
+ generate
+
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ @maven-compiler-plugin.version@
+
+ ${maven.compiler.release}
+
+
+
+
+
+
diff --git a/bindgen/it/src/it/multi-returns/src/test/java/MultiReturnsTest.java b/bindgen/it/src/it/multi-returns/src/test/java/MultiReturnsTest.java
new file mode 100644
index 000000000..846f09531
--- /dev/null
+++ b/bindgen/it/src/it/multi-returns/src/test/java/MultiReturnsTest.java
@@ -0,0 +1,41 @@
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import com.dylibso.chicory.gen.Module;
+import com.dylibso.chicory.runtime.Instance;
+import com.dylibso.chicory.wasm.Parser;
+import org.junit.jupiter.api.Test;
+
+class MultiReturnsTest {
+
+ class TestModule extends Module {
+ private final Instance instance;
+
+ public TestModule() {
+ instance =
+ Instance.builder(
+ Parser.parse(
+ MultiReturnsTest.class.getResourceAsStream(
+ "/compiled/multi-returns.wat.wasm")))
+ .build();
+ }
+
+ @Override
+ public Instance instance() {
+ return this.instance;
+ }
+ }
+
+ @Test
+ public void multiReturnsModule() {
+ // Arrange
+ var multiReturnsModule = new TestModule();
+
+ // Act
+ var result = multiReturnsModule.example(1L);
+
+ // Assert
+ assertEquals(2, result.length);
+ assertEquals(1L, result[0].asLong());
+ assertEquals(1L, result[1].asLong());
+ }
+}
diff --git a/bindgen/it/src/it/opa/invoker.properties b/bindgen/it/src/it/opa/invoker.properties
new file mode 100644
index 000000000..84099bc5a
--- /dev/null
+++ b/bindgen/it/src/it/opa/invoker.properties
@@ -0,0 +1 @@
+invoker.goals=test
diff --git a/bindgen/it/src/it/opa/pom.xml b/bindgen/it/src/it/opa/pom.xml
new file mode 100644
index 000000000..edd70537c
--- /dev/null
+++ b/bindgen/it/src/it/opa/pom.xml
@@ -0,0 +1,77 @@
+
+
+
+ 4.0.0
+ com.dylibso.chicory
+
+ opa-chicory-it
+ 0.0-SNAPSHOT
+ jar
+
+
+ @maven.compiler.release@
+
+
+
+
+ com.dylibso.chicory
+ runtime
+ @project.version@
+
+
+ com.dylibso.chicory
+ wasm-corpus
+ @project.version@
+
+
+ com.dylibso.chicory
+ function-processor
+ @project.version@
+ provided
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ @junit.version@
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ @junit.version@
+ test
+
+
+
+
+
+
+ com.dylibso.chicory
+ bindgen
+ @project.version@
+
+
+
+ generate
+
+
+ OpaModule
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ @maven-compiler-plugin.version@
+
+ ${maven.compiler.release}
+
+
+
+
+
+
diff --git a/bindgen/it/src/it/opa/src/test/java/OpaTest.java b/bindgen/it/src/it/opa/src/test/java/OpaTest.java
new file mode 100644
index 000000000..4275ab771
--- /dev/null
+++ b/bindgen/it/src/it/opa/src/test/java/OpaTest.java
@@ -0,0 +1,39 @@
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+class OpaTest {
+
+ @Test
+ public void opaModule() {
+ // Arrange
+ var opa = new OpaTestModule();
+
+ // Act
+ var ctxAddr = opa.opaEvalCtxNew();
+ var input = "{\"user\": \"alice\"}";
+ var inputStrAddr = opa.opaMalloc(input.length());
+ opa.instance().memory().writeCString(inputStrAddr, input);
+ var inputAddr = opa.opaJsonParse(inputStrAddr, input.length());
+ opa.opaFree(inputStrAddr);
+ opa.opaEvalCtxSetInput(ctxAddr, inputAddr);
+
+ var data = "{ \"role\" : { \"alice\" : \"admin\", \"bob\" : \"user\" } }";
+ var dataStrAddr = opa.opaMalloc(data.length());
+ opa.instance().memory().writeCString(dataStrAddr, data);
+ var dataAddr = opa.opaJsonParse(dataStrAddr, data.length());
+ opa.opaFree(dataStrAddr);
+ opa.opaEvalCtxSetData(ctxAddr, dataAddr);
+
+ var evalResult = opa.eval(ctxAddr);
+
+ int resultAddr = opa.opaEvalCtxGetResult(ctxAddr);
+ int resultStrAddr = opa.opaJsonDump(resultAddr);
+ var resultStr = opa.instance().memory().readCString(resultStrAddr);
+ opa.opaFree(resultStrAddr);
+
+ // Assert
+ assertEquals(0, evalResult);
+ assertEquals("[{\"result\":true}]", resultStr);
+ }
+}
diff --git a/bindgen/it/src/it/opa/src/test/java/OpaTestModule.java b/bindgen/it/src/it/opa/src/test/java/OpaTestModule.java
new file mode 100644
index 000000000..c2b18238f
--- /dev/null
+++ b/bindgen/it/src/it/opa/src/test/java/OpaTestModule.java
@@ -0,0 +1,77 @@
+import com.dylibso.chicory.function.annotations.HostModule;
+import com.dylibso.chicory.function.annotations.WasmExport;
+import com.dylibso.chicory.gen.OpaModule;
+import com.dylibso.chicory.runtime.HostImports;
+import com.dylibso.chicory.runtime.Instance;
+import com.dylibso.chicory.runtime.Memory;
+import com.dylibso.chicory.wasm.Parser;
+import com.dylibso.chicory.wasm.types.MemoryLimits;
+import java.util.Arrays;
+import java.util.List;
+
+@HostModule("env")
+class OpaTestModule extends OpaModule {
+ private final Memory memory;
+ private final Instance instance;
+
+ public OpaTestModule() {
+ this.memory = new Memory(new MemoryLimits(10));
+ this.instance =
+ Instance.builder(Parser.parse(OpaTest.class.getResourceAsStream("/policy.wasm")))
+ .withHostImports(
+ HostImports.builder()
+ .withFunctions(
+ Arrays.asList(
+ OpaTestModule_ModuleFactory.toHostFunctions(
+ this)))
+ .withMemories(List.of(toHostMemory()))
+ .build())
+ .build();
+ }
+
+ @Override
+ public Memory memory() {
+ return this.memory;
+ }
+
+ @Override
+ public Instance instance() {
+ return this.instance;
+ }
+
+ @WasmExport
+ @Override
+ public int opaBuiltin0(int arg0, int arg1) {
+ throw new RuntimeException("opa_builtin0 - not implemented");
+ }
+
+ @WasmExport
+ @Override
+ public int opaBuiltin1(int arg0, int arg1, int arg2) {
+ throw new RuntimeException("opa_builtin1 - not implemented");
+ }
+
+ @WasmExport
+ @Override
+ public int opaBuiltin2(int arg0, int arg1, int arg2, int arg3) {
+ throw new RuntimeException("opa_builtin2 - not implemented");
+ }
+
+ @WasmExport
+ @Override
+ public int opaBuiltin3(int arg0, int arg1, int arg2, int arg3, int arg4) {
+ throw new RuntimeException("opa_builtin3 - not implemented");
+ }
+
+ @WasmExport
+ @Override
+ public int opaBuiltin4(int arg0, int arg1, int arg2, int arg3, int arg4, int arg5) {
+ throw new RuntimeException("opa_builtin4 - not implemented");
+ }
+
+ @WasmExport
+ @Override
+ public void opaAbort(int arg0) {
+ System.exit(arg0);
+ }
+}
diff --git a/bindgen/it/src/it/opa/src/test/resources/policy.wasm b/bindgen/it/src/it/opa/src/test/resources/policy.wasm
new file mode 100644
index 000000000..efe2c4f4c
Binary files /dev/null and b/bindgen/it/src/it/opa/src/test/resources/policy.wasm differ
diff --git a/bindgen/it/src/it/settings.xml b/bindgen/it/src/it/settings.xml
new file mode 100644
index 000000000..2d90068bb
--- /dev/null
+++ b/bindgen/it/src/it/settings.xml
@@ -0,0 +1,35 @@
+
+
+
+
+ it-repo
+
+ true
+
+
+
+ local.central
+ @localRepositoryUrl@
+
+ true
+
+
+ true
+
+
+
+
+
+ local.central
+ @localRepositoryUrl@
+
+ true
+
+
+ true
+
+
+
+
+
+
diff --git a/bindgen/it/src/it/with-imports/invoker.properties b/bindgen/it/src/it/with-imports/invoker.properties
new file mode 100644
index 000000000..84099bc5a
--- /dev/null
+++ b/bindgen/it/src/it/with-imports/invoker.properties
@@ -0,0 +1 @@
+invoker.goals=test
diff --git a/bindgen/it/src/it/with-imports/pom.xml b/bindgen/it/src/it/with-imports/pom.xml
new file mode 100644
index 000000000..385a2e805
--- /dev/null
+++ b/bindgen/it/src/it/with-imports/pom.xml
@@ -0,0 +1,76 @@
+
+
+
+ 4.0.0
+ com.dylibso.chicory
+
+ with-imports-chicory-it
+ 0.0-SNAPSHOT
+ jar
+
+
+ @maven.compiler.release@
+
+
+
+
+ com.dylibso.chicory
+ runtime
+ @project.version@
+
+
+ com.dylibso.chicory
+ wasm-corpus
+ @project.version@
+
+
+ com.dylibso.chicory
+ function-processor
+ @project.version@
+ provided
+
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ @junit.version@
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ @junit.version@
+ test
+
+
+
+
+
+
+ com.dylibso.chicory
+ bindgen
+ @project.version@
+
+
+
+ generate
+
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ @maven-compiler-plugin.version@
+
+ ${maven.compiler.release}
+
+
+
+
+
+
diff --git a/bindgen/it/src/it/with-imports/src/test/java/chicory/test/WithImportsTest.java b/bindgen/it/src/it/with-imports/src/test/java/chicory/test/WithImportsTest.java
new file mode 100644
index 000000000..81aed653f
--- /dev/null
+++ b/bindgen/it/src/it/with-imports/src/test/java/chicory/test/WithImportsTest.java
@@ -0,0 +1,60 @@
+package chicory.test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import com.dylibso.chicory.function.annotations.HostModule;
+import com.dylibso.chicory.function.annotations.WasmExport;
+import com.dylibso.chicory.gen.Module;
+import com.dylibso.chicory.runtime.HostImports;
+import com.dylibso.chicory.runtime.Instance;
+import com.dylibso.chicory.wasm.Parser;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.junit.jupiter.api.Test;
+
+class WithImportsTest {
+ public final AtomicInteger count = new AtomicInteger();
+
+ @HostModule("console")
+ class TestModule extends Module {
+ private final Instance instance;
+ private static final String EXPECTED = "Hello, World!";
+
+ public TestModule() {
+ instance =
+ Instance.builder(
+ Parser.parse(
+ WithImportsTest.class.getResourceAsStream(
+ "/compiled/host-function.wat.wasm")))
+ .withHostImports(
+ new HostImports(TestModule_ModuleFactory.toHostFunctions(this)))
+ .build();
+ }
+
+ @Override
+ public Instance instance() {
+ return this.instance;
+ }
+
+ @WasmExport
+ @Override
+ public void log(int len, int offset) {
+ var message = instance.memory().readString(offset, len);
+
+ if (EXPECTED.equals(message)) {
+ count.incrementAndGet();
+ }
+ }
+ }
+
+ @Test
+ public void withImportsModule() {
+ // Arrange
+ var withImportsModule = new TestModule();
+
+ // Act
+ withImportsModule.logIt();
+
+ // Assert
+ assertEquals(10, count.get());
+ }
+}
diff --git a/bindgen/plugin/pom.xml b/bindgen/plugin/pom.xml
new file mode 100644
index 000000000..15082cf6c
--- /dev/null
+++ b/bindgen/plugin/pom.xml
@@ -0,0 +1,63 @@
+
+
+ 4.0.0
+
+
+ com.dylibso.chicory
+ bindgen-parent
+ 999-SNAPSHOT
+ ../pom.xml
+
+ bindgen
+ maven-plugin
+ Chicory - Bindgen
+ A Maven Plugin to generate bindings for WebAssembly modules
+
+
+
+ com.dylibso.chicory
+ wasm
+
+
+ com.github.javaparser
+ javaparser-core
+ ${javaparser.version}
+
+
+ org.apache.maven
+ maven-core
+ ${maven-plugin-api.version}
+ provided
+
+
+ org.apache.maven
+ maven-plugin-api
+ ${maven-plugin-api.version}
+ provided
+
+
+ org.apache.maven.plugin-tools
+ maven-plugin-annotations
+ ${maven-plugin-annotations.version}
+ provided
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-plugin-plugin
+
+ prefix
+
+
+
+ default-descriptor
+ process-classes
+
+
+
+
+
+
diff --git a/bindgen/plugin/src/main/java/com/dylibso/chicory/BindGenMojo.java b/bindgen/plugin/src/main/java/com/dylibso/chicory/BindGenMojo.java
new file mode 100644
index 000000000..0b7c26e5c
--- /dev/null
+++ b/bindgen/plugin/src/main/java/com/dylibso/chicory/BindGenMojo.java
@@ -0,0 +1,380 @@
+package com.dylibso.chicory;
+
+import static com.github.javaparser.StaticJavaParser.parseType;
+import static com.github.javaparser.utils.StringEscapeUtils.escapeJava;
+import static org.apache.maven.plugins.annotations.LifecyclePhase.GENERATE_SOURCES;
+
+import com.dylibso.chicory.wasm.Parser;
+import com.dylibso.chicory.wasm.types.ExternalType;
+import com.dylibso.chicory.wasm.types.FunctionImport;
+import com.dylibso.chicory.wasm.types.ValueType;
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.Modifier;
+import com.github.javaparser.ast.NodeList;
+import com.github.javaparser.ast.expr.ArrayAccessExpr;
+import com.github.javaparser.ast.expr.ArrayCreationExpr;
+import com.github.javaparser.ast.expr.ArrayInitializerExpr;
+import com.github.javaparser.ast.expr.Expression;
+import com.github.javaparser.ast.expr.IntegerLiteralExpr;
+import com.github.javaparser.ast.expr.MethodCallExpr;
+import com.github.javaparser.ast.expr.NameExpr;
+import com.github.javaparser.ast.expr.ObjectCreationExpr;
+import com.github.javaparser.ast.expr.SimpleName;
+import com.github.javaparser.ast.expr.StringLiteralExpr;
+import com.github.javaparser.ast.stmt.BlockStmt;
+import com.github.javaparser.ast.stmt.ReturnStmt;
+import com.github.javaparser.utils.SourceRoot;
+import java.io.File;
+import java.nio.file.Path;
+import java.util.List;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.logging.Log;
+import org.apache.maven.plugin.logging.SystemStreamLog;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.project.MavenProject;
+
+/**
+ * This plugin will generate bindings for Wasm modules
+ */
+@Mojo(name = "generate", defaultPhase = GENERATE_SOURCES, threadSafe = true)
+public class BindGenMojo extends AbstractMojo {
+
+ private final Log log = new SystemStreamLog();
+
+ /**
+ * Package name
+ */
+ @Parameter(required = true, defaultValue = "com.dylibso.chicory.gen")
+ private String packageName;
+
+ /**
+ * Name of the bindings
+ */
+ @Parameter(required = true, defaultValue = "Module")
+ private String name;
+
+ /**
+ * Ignore modules
+ */
+ @Parameter(required = true, defaultValue = "[]]")
+ private List ignoredModules;
+
+ // TODO: check multiple executions on multiple files
+ /**
+ * Location of the source wasm file
+ */
+ @Parameter(required = true)
+ private File source;
+
+ /**
+ * Location for the binding generated sources.
+ */
+ @Parameter(
+ required = true,
+ defaultValue = "${project.build.directory}/generated-sources/chciory-bindgen")
+ private File sourceDestinationFolder;
+
+ /**
+ * The current Maven project.
+ */
+ @Parameter(property = "project", required = true, readonly = true)
+ private MavenProject project;
+
+ private static String camelCase(String s) {
+ var sb = new StringBuilder();
+ boolean toUpper = false;
+ for (int i = 0; i < s.length(); i++) {
+ var c = s.charAt(i);
+ if (c == '_') {
+ toUpper = true;
+ } else if (toUpper) {
+ sb.append(Character.toUpperCase(c));
+ toUpper = false;
+ } else {
+ sb.append(c);
+ }
+ }
+ return sb.toString();
+ }
+
+ private boolean isSupported(ValueType vt) {
+ switch (vt) {
+ case I32:
+ case I64:
+ case F32:
+ case F64:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private String valueTypeToJava(ValueType vt) {
+ switch (vt) {
+ case I32:
+ return "int";
+ case I64:
+ return "long";
+ case F32:
+ return "float";
+ case F64:
+ return "double";
+ default:
+ throw new IllegalArgumentException("type not supported " + vt);
+ }
+ }
+
+ private String valueTypeToConverter(ValueType vt) {
+ switch (vt) {
+ case I32:
+ return "asInt";
+ case I64:
+ return "asLong";
+ case F32:
+ return "asFloat";
+ case F64:
+ return "asDouble";
+ default:
+ throw new IllegalArgumentException("type not supported " + vt);
+ }
+ }
+
+ private String javaToValueTypeToConverter(ValueType vt) {
+ switch (vt) {
+ case I32:
+ return "i32";
+ case I64:
+ return "i64";
+ case F32:
+ return "f32";
+ case F64:
+ return "f64";
+ default:
+ throw new IllegalArgumentException("type not supported " + vt);
+ }
+ }
+
+ @SuppressWarnings("StringSplitter")
+ private Path qualifiedDestinationFolder() {
+ var res = sourceDestinationFolder.toPath();
+ for (var p : packageName.split("\\.")) {
+ res = res.resolve(p);
+ }
+ return res;
+ }
+
+ @Override
+ @SuppressWarnings("deprecation")
+ public void execute() throws MojoExecutionException {
+ // Create destination folders
+ if (!sourceDestinationFolder.mkdirs()) {
+ log.warn("Failed to create folder: " + sourceDestinationFolder);
+ }
+
+ // load the user wasm module
+ var module = Parser.parse(source);
+
+ // generate the bindings
+ final SourceRoot dest = new SourceRoot(sourceDestinationFolder.toPath());
+
+ var cu = new CompilationUnit(packageName);
+ cu.setStorage(qualifiedDestinationFolder().resolve(name + ".java"));
+
+ cu.addImport("java.util.List");
+ cu.addImport("com.dylibso.chicory.wasm.types.Value");
+ cu.addImport("com.dylibso.chicory.wasm.types.ValueType");
+ cu.addImport("com.dylibso.chicory.runtime.HostFunction");
+ cu.addImport("com.dylibso.chicory.runtime.HostMemory");
+ cu.addImport("com.dylibso.chicory.runtime.Instance");
+ cu.addImport("com.dylibso.chicory.runtime.Memory");
+
+ var clazz = cu.addClass(name, Modifier.Keyword.ABSTRACT, Modifier.Keyword.PUBLIC);
+ var instanceMethod =
+ clazz.addMethod("instance", Modifier.Keyword.PUBLIC, Modifier.Keyword.ABSTRACT);
+ instanceMethod.setType("Instance").removeBody();
+ var instanceCall = new MethodCallExpr("instance");
+
+ int importedFunctionCount = 0;
+ boolean importedMemory = false;
+
+ for (int importIdx = 0; importIdx < module.importSection().importCount(); importIdx++) {
+ var imprt = module.importSection().getImport(importIdx);
+
+ if (imprt.importType() == ExternalType.MEMORY) {
+ var method =
+ clazz.addMethod(
+ camelCase(imprt.name()),
+ Modifier.Keyword.PUBLIC,
+ Modifier.Keyword.ABSTRACT);
+ method.setType("Memory").removeBody();
+ var toHostMemsMethod = clazz.addMethod("toHostMemory", Modifier.Keyword.PUBLIC);
+ toHostMemsMethod.setType("HostMemory");
+ var toHostMemsBody = toHostMemsMethod.createBody();
+ var memMapping =
+ new ObjectCreationExpr()
+ .setType("HostMemory")
+ .addArgument(new StringLiteralExpr(imprt.moduleName()))
+ .addArgument(new StringLiteralExpr(imprt.name()))
+ .addArgument(new MethodCallExpr("memory"));
+ toHostMemsBody.addStatement(new ReturnStmt(memMapping));
+ importedMemory = true;
+ } else if (imprt.importType() == ExternalType.FUNCTION) {
+ importedFunctionCount++;
+ var importName = camelCase(imprt.name());
+ var method =
+ clazz.addMethod(
+ importName, Modifier.Keyword.PUBLIC, Modifier.Keyword.ABSTRACT);
+
+ if (ignoredModules.contains(imprt.moduleName())) {
+ log.warn("Skipping generation for imported module " + imprt.moduleName());
+ continue;
+ }
+ var importType = module.typeSection().getType(((FunctionImport) imprt).typeIndex());
+ var functionInvoc = new MethodCallExpr(importName);
+ var handleBody = new BlockStmt();
+
+ for (int paramIdx = 0; paramIdx < importType.params().size(); paramIdx++) {
+ var argName = "arg" + paramIdx;
+ functionInvoc.addArgument(
+ new MethodCallExpr(
+ new ArrayAccessExpr(
+ new NameExpr("args"), new IntegerLiteralExpr(paramIdx)),
+ new SimpleName(
+ valueTypeToConverter(
+ importType.params().get(paramIdx)))));
+ method.addParameter(
+ valueTypeToJava(importType.params().get(paramIdx)), argName);
+ }
+ method.removeBody();
+
+ if (importType.returns().size() == 0) {
+ method.setType("void");
+ handleBody.addStatement(functionInvoc);
+ handleBody.addStatement(
+ new ReturnStmt(new ArrayCreationExpr(parseType("Value"))));
+ } else if (importType.returns().size() == 1
+ && isSupported(importType.returns().get(0))) {
+ method.setType(valueTypeToJava(importType.returns().get(0)));
+
+ var arrayReturn = new ArrayCreationExpr(parseType("Value"));
+ var arrayReturnInit = new ArrayInitializerExpr();
+ arrayReturnInit.setValues(
+ NodeList.nodeList(
+ new MethodCallExpr(
+ new NameExpr("Value"),
+ new SimpleName(
+ javaToValueTypeToConverter(
+ importType.returns().get(0))),
+ NodeList.nodeList(functionInvoc))));
+
+ arrayReturn.setInitializer(arrayReturnInit);
+
+ handleBody.addStatement(new ReturnStmt(arrayReturn));
+ } else {
+ method.setType("Value[]");
+ handleBody.addStatement(new ReturnStmt(functionInvoc));
+ }
+ } else {
+ // TODO: explicitly export also the other
+ log.warn(
+ "[chicory-bindgen] no generated code for import type: "
+ + imprt.moduleName()
+ + "."
+ + imprt.name()
+ + " of type "
+ + imprt.importType());
+ }
+ }
+
+ // now the exports
+ for (int exportIdx = 0; exportIdx < module.exportSection().exportCount(); exportIdx++) {
+ var export = module.exportSection().getExport(exportIdx);
+
+ if (export.exportType() == ExternalType.MEMORY && !importedMemory) {
+ var method = clazz.addMethod(camelCase(export.name()), Modifier.Keyword.PUBLIC);
+ method.setType("Memory");
+ var body = method.createBody();
+ body.addStatement(
+ new ReturnStmt(new MethodCallExpr(instanceCall, new SimpleName("memory"))));
+ } else if (export.exportType() == ExternalType.FUNCTION) {
+ var method = clazz.addMethod(camelCase(export.name()), Modifier.Keyword.PUBLIC);
+
+ var funcTypeIdx =
+ module.functionSection()
+ .getFunctionType(export.index() - importedFunctionCount);
+ var exportType = module.typeSection().getType(funcTypeIdx);
+
+ var returnType = "Value[]";
+ var hasReturns = false;
+ var hasJavaReturn = false;
+ String javaReturnConverter = null;
+ var returns = exportType.returns();
+ switch (returns.size()) {
+ case 0:
+ returnType = "void";
+ hasReturns = false;
+ break;
+ case 1:
+ if (isSupported(returns.get(0))) {
+ returnType = valueTypeToJava(returns.get(0));
+ hasJavaReturn = true;
+ javaReturnConverter = valueTypeToConverter(returns.get(0));
+ }
+ // fallthrough
+ default:
+ hasReturns = true;
+ break;
+ }
+ method.setType(returnType);
+
+ var params = exportType.params();
+ Expression[] args = new Expression[params.size()];
+ for (int paramIdx = 0; paramIdx < params.size(); paramIdx++) {
+ var argName = "arg" + paramIdx;
+ method.addParameter(valueTypeToJava(params.get(paramIdx)), argName);
+ args[paramIdx] =
+ new MethodCallExpr(
+ new NameExpr("Value"),
+ new SimpleName(
+ javaToValueTypeToConverter(params.get(paramIdx))),
+ NodeList.nodeList(new NameExpr(argName)));
+ }
+
+ var methodBody = method.createBody();
+ Expression methodCall =
+ new MethodCallExpr(
+ new MethodCallExpr(
+ instanceCall,
+ new SimpleName("export"),
+ NodeList.nodeList(
+ new StringLiteralExpr(escapeJava(export.name())))),
+ new SimpleName("apply"),
+ NodeList.nodeList(args));
+ if (!hasReturns) {
+ methodBody.addStatement(methodCall);
+ } else {
+ if (hasJavaReturn) {
+ methodCall =
+ new MethodCallExpr(
+ new ArrayAccessExpr(methodCall, new IntegerLiteralExpr()),
+ new SimpleName(javaReturnConverter));
+ }
+ methodBody.addStatement(new ReturnStmt(methodCall));
+ }
+ } else {
+ // TODO: explicitly export also the other types
+ log.warn(
+ "[chicory-bindgen] no generated code for export type: "
+ + export.exportType());
+ }
+ }
+
+ dest.add(cu);
+ dest.saveAll();
+
+ // Add the generated tests to the source root
+ project.addTestCompileSourceRoot(sourceDestinationFolder.getAbsolutePath());
+ }
+}
diff --git a/bindgen/pom.xml b/bindgen/pom.xml
new file mode 100644
index 000000000..f7110e972
--- /dev/null
+++ b/bindgen/pom.xml
@@ -0,0 +1,21 @@
+
+
+ 4.0.0
+
+
+ com.dylibso.chicory
+ chicory
+ 999-SNAPSHOT
+ ../pom.xml
+
+ bindgen-parent
+ pom
+ Chicory - Bindgen - Parent
+ Parent module for the Bindgen
+
+
+ it
+ plugin
+
+
+
diff --git a/pom.xml b/pom.xml
index 621be6d83..45a32f76d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -36,6 +36,7 @@
aot
aot-tests
+ bindgen
bom
cli
function-annotations
@@ -138,6 +139,11 @@
aot
${project.version}
+
+ com.dylibso.chicory
+ bindgen
+ ${project.version}
+
com.dylibso.chicory
cli
@@ -407,6 +413,8 @@
**/src/main/java/**/*.java
**/src/test/java/**/*.java
+ **/src/it/**/src/main/java/**/*.java
+ **/src/it/**/src/test/java/**/*.java
1.18.1
@@ -566,6 +574,7 @@
${maven.dependency.failOnWarning}
true
+ com.dylibso.chicory:bindgen
com.dylibso.chicory:wasm-corpus
org.junit.jupiter:junit-jupiter-engine
diff --git a/wasm-corpus/src/main/resources/compiled/multi-returns.wat.wasm b/wasm-corpus/src/main/resources/compiled/multi-returns.wat.wasm
new file mode 100644
index 000000000..48141a965
Binary files /dev/null and b/wasm-corpus/src/main/resources/compiled/multi-returns.wat.wasm differ
diff --git a/wasm-corpus/src/main/resources/wat/multi-returns.wat b/wasm-corpus/src/main/resources/wat/multi-returns.wat
new file mode 100644
index 000000000..4630f1517
--- /dev/null
+++ b/wasm-corpus/src/main/resources/wat/multi-returns.wat
@@ -0,0 +1,6 @@
+(module
+ (type (;0;) (func (param i64) (result i64 i64)))
+ (func (;0;) (type 0) (param i64) (result i64 i64)
+ local.get 0
+ local.get 0)
+ (export "example" (func 0)))