-
Notifications
You must be signed in to change notification settings - Fork 35
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC - Human friendly HostImports' builders #445
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,11 @@ | |
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertNull; | ||
|
||
import com.dylibso.chicory.wasm.types.Limits; | ||
import com.dylibso.chicory.wasm.types.MemoryLimits; | ||
import com.dylibso.chicory.wasm.types.MutabilityType; | ||
import com.dylibso.chicory.wasm.types.Value; | ||
import com.dylibso.chicory.wasm.types.ValueType; | ||
import java.util.Arrays; | ||
import java.util.Collections; | ||
import org.junit.jupiter.api.Nested; | ||
|
@@ -177,5 +181,82 @@ void addIndex() { | |
assertEquals(1, result.index().length); | ||
} | ||
} | ||
|
||
@Nested | ||
class DSL { | ||
|
||
@Test | ||
void withIndex() { | ||
var moduleName = "module"; | ||
var fieldName = "filed"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Typo "filed"? |
||
HostImports.builder() | ||
.withNewImport(moduleName, fieldName) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I find this style of nested builder to be strange, especially since only one method can be called. For nested builders, I've found that having a All of the Instead, what if we put new methods directly on .addGlobal(moduleName, fieldName, Value.i32(1))
.addGlobal(moduleName, fieldName, MutabilityType.Var, Value.i32(1))
.addMutableGlobal(moduleName, fieldName, Value.i32(1))
.addMemory(moduleName, fieldName)
.addMemory(moduleName, fieldName, new MemoryLimits(1))
.addMemory(moduleName, fieldName, 1) // I'd drop these as the MemoryLimits version seems more clear
.addMemory(moduleName, fieldName, 1, 2)
.addTable(moduleName, fieldName)
.addTable(moduleName, fieldName, ValueType.ExternRef)
.addTable(moduleName, fieldName, new Limits(1))
.addTable(moduleName, fieldName, 1) // same, I'd drop these and use the Limits version
.addTable(moduleName, fieldName, 1, 2)
// does type inference work out if we name all of these "addFunction"?
.addProcedure(moduleName, fieldName, () -> System.out.println("hello world"))
.addProcedure(moduleName, fieldName, (Instance inst) -> () -> System.out.println("hello world"))
.addSupplier(moduleName, fieldName, () -> 1) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for your input @electrum !
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This test might look worse due to repeating the same variables. In actual usage, the field names will need to be unique (and the builder should validate that)? So if we change it to use constants, does it look better? .addGlobal("test", "g1", Value.i32(1))
.addGlobal("test", "g2", MutabilityType.Var, Value.i32(1))
.addMutableGlobal("test", "gmut", Value.i32(1))
.addMemory("test", "m1")
.addMemory("test", "mlim", new MemoryLimits(1))
.addTable("test", "t1")
.addTable("test", "tref", ValueType.ExternRef)
.addTable("test", "t3", new Limits(1)) Another problem is that the code formatter forces each chained call to be on a separate line. If we were formatting the code by hand, it would look better: .add("test", "g1").global(Value.i32(1))
.add("test", "g2").global(MutabilityType.Var, Value.i32(1))
.add("test", "gmut").mutableGlobal(Value.i32(1))
.add("test", "m1").memory()
.add("test", "mlim").memory(new MemoryLimits(1))
.add("test", "t1").table()
.add("test", "tref").table(ValueType.ExternRef)
.add("test", "t3").table(new Limits(1)) Which I agree looks slightly cleaner, but we can't format like that... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I love this! .add("test", "g1").global(Value.i32(1)) I believe that we should not be limited by our own formatter, and we can always disable it when necessary 😏 |
||
.withGlobal(Value.i32(1)) | ||
.withNewImport(moduleName, fieldName) | ||
.withGlobal(MutabilityType.Var, Value.i32(1)) | ||
.withNewImport(moduleName, fieldName) | ||
.withMutableGlobal(Value.i32(1)) | ||
.withNewImport(moduleName, fieldName) | ||
.withGlobal(Value.i32(1)) | ||
.withNewImport(moduleName, fieldName) | ||
.withMemory() | ||
.withNewImport(moduleName, fieldName) | ||
.withMemory(new MemoryLimits(1)) | ||
.withNewImport(moduleName, fieldName) | ||
.withMemory(1) | ||
.withNewImport(moduleName, fieldName) | ||
.withMemory(1, 2) | ||
.withNewImport(moduleName, fieldName) | ||
.withTable() | ||
.withNewImport(moduleName, fieldName) | ||
.withTable(ValueType.ExternRef) | ||
.withNewImport(moduleName, fieldName) | ||
.withTable(new Limits(1)) | ||
.withNewImport(moduleName, fieldName) | ||
.withTable(1) | ||
.withNewImport(moduleName, fieldName) | ||
.withTable(1, 2) | ||
.withNewImport(moduleName, fieldName) | ||
.withProcedure(() -> System.out.println("hello world")) | ||
.withNewImport(moduleName, fieldName) | ||
.withProcedure((Instance inst) -> () -> System.out.println("hello world")) | ||
.withNewImport(moduleName, fieldName) | ||
.withSupplier(() -> 1) | ||
.withNewImport(moduleName, fieldName) | ||
.withSupplier((Instance inst) -> () -> 1) | ||
.withNewImport(moduleName, fieldName) | ||
.withSupplier(() -> 2L) | ||
// this doesn't compile now as expected, since we do not handle Double just | ||
// yet | ||
// .withSupplier(() -> { return 0.0 }) | ||
.withNewImport(moduleName, fieldName) | ||
.withConsumer( | ||
(int i) -> { | ||
var x = i + 1; | ||
}) | ||
.withNewImport(moduleName, fieldName) | ||
.withConsumer( | ||
(long l) -> { | ||
var x = l + 2L; | ||
}) | ||
// this doesn't compile now as expected, since we do not handle Double just | ||
// yet | ||
// .withConsumer((double d) -> { var x = d + 2; }) | ||
.withNewImport(moduleName, fieldName) | ||
.withFunction((int i) -> i + 1) | ||
.withNewImport(moduleName, fieldName) | ||
.withFunction((long l) -> l + 2L) | ||
// this doesn't compile now as expected, since we do not handle Double just | ||
// yet | ||
// .withFunction((double d) -> d + 2.0) | ||
.withNewImport(moduleName, fieldName) | ||
.withFunction( | ||
(Instance inst) -> | ||
(Value[] args) -> { | ||
return new Value[] {}; | ||
}) | ||
.build(); | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The more I look at this approach, the less I'm convinced this is the way to go.
and
are going to be not distinguishable after type erasure.
Currently, I think that leaving only:
and generating the binding out of real modules with something like: https://github.com/andreaTP/chicory-bindgen-poc is the best bet.