Skip to content

Commit 20d33b5

Browse files
fix: MoonBit update and refactor organization (bytecodealliance#1069)
* feat(moonbit): reorganize directory and add exportation appointment * fix(moonbit): api change * doc(moonbit): update readme * fix(moonbit): add more reserved words * fix(moonbit): ignore more stubs
1 parent f2f444d commit 20d33b5

File tree

3 files changed

+70
-42
lines changed

3 files changed

+70
-42
lines changed

README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -384,19 +384,26 @@ wasm-tools validate main.component.wasm --features component-model
384384
MoonBit can be compiled to WebAssembly using [its toolchain](https://moonbitlang.com/download):
385385

386386
```sh
387-
moon build --target wasm # -g to keep symbols
387+
moon build --target wasm # --debug to keep symbols
388388
```
389389

390-
The generarted core wasm will be found under `target/wasm/release/build/gen/gen.wasm` by default. Then you can use `wasm-tools` to componentize the module:
390+
The generated core wasm will be found under `target/wasm/release/build/gen/gen.wasm` by default. Then you can use `wasm-tools` to componentize the module:
391391

392392
```
393393
wasm-tools component embed wit target/wasm/release/build/gen/gen.wasm -o target/gen.wasm
394394
wasm-tools component new target/gen.wasm -o target/gen.component.wasm
395395
```
396396

397-
When using `wit-bindgen moonbit`, you may use `--derive-show` or `--derive-eq` to derive `Show` or `Eq` for all types.
397+
You may use `--gen-dir` to specify which package should be responsible for the exportation. The default is `gen` as mentioned above.
398+
This can be useful having one project that exports multiple worlds.
399+
400+
When using `wit-bindgen moonbit`, you may use `--derive-show` or `--derive-eq` to derive `Show` or `Eq` traits for all types.
401+
You may also use `--derive-error`, which will make types containing `Error` as error types in MoonBit.
398402

399403
You will find the files to be modified with the name `**/stub.mbt`.
404+
To avoid touching the files during regeneration (including `moon.pkg.json` or `moon.mod.json`) you may use `--ignore-stub`.
405+
406+
/!\ MoonBit is still evolving, so please check out the [Weekly Updates](https://www.moonbitlang.com/weekly-updates/) for any breaking changes or deprecations.
400407

401408
### Guest: Other Languages
402409

crates/moonbit/src/lib.rs

Lines changed: 59 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ use wit_bindgen_core::{
2424
// TODO: Export will share the type signatures with the import by using a newtype alias
2525
// TODO: Export resource is not handled correctly : resource.new / resource.drop / resource.rep / dtor
2626

27-
const EXPORT_DIR: &str = "gen";
28-
2927
const FFI_DIR: &str = "ffi";
3028

3129
const FFI: &str = r#"
@@ -90,7 +88,7 @@ pub fn malloc(size : Int) -> Int {
9088
let words = size / 4 + 1
9189
let address = malloc_inline(8 + words * 4)
9290
store32(address, 1)
93-
store32(address + 4, words.lsl(8).lor(246))
91+
store32(address + 4, (words << 8) | 246)
9492
store8(address + words * 4 + 7, 3 - size % 4)
9593
address + 8
9694
}
@@ -175,7 +173,7 @@ pub fn ptr2double_array(ptr : Int) -> FixedArray[Double] {
175173
176174
fn set_64_header_ffi(offset : Int) -> Unit {
177175
let len = load32(offset)
178-
store32(offset, len.lsr(1))
176+
store32(offset, len >> 1)
179177
store8(offset, 241)
180178
}
181179
@@ -202,6 +200,9 @@ pub struct Opts {
202200
/// Whether or not to generate stub files ; useful for update after WIT change
203201
#[cfg_attr(feature = "clap", arg(long, default_value_t = false))]
204202
pub ignore_stub: bool,
203+
/// The package/dir to generate the program entrance
204+
#[cfg_attr(feature = "clap", arg(long, default_value = "gen"))]
205+
pub gen_dir: String,
205206
}
206207

207208
impl Opts {
@@ -281,7 +282,7 @@ impl WorldGenerator for MoonBit {
281282
id: InterfaceId,
282283
files: &mut Files,
283284
) -> Result<()> {
284-
let name = interface_name(resolve, key, Direction::Import);
285+
let name = interface_name(resolve, key);
285286
let name = self.interface_ns.tmp(&name);
286287
self.import_interface_names.insert(id, name.clone());
287288

@@ -331,7 +332,7 @@ impl WorldGenerator for MoonBit {
331332
id: InterfaceId,
332333
files: &mut Files,
333334
) -> Result<()> {
334-
let name = interface_name(resolve, key, Direction::Export);
335+
let name = format!("{}.{}", self.opts.gen_dir, interface_name(resolve, key));
335336
let name = self.interface_ns.tmp(&name);
336337
self.export_interface_names.insert(id, name.clone());
337338

@@ -363,7 +364,7 @@ impl WorldGenerator for MoonBit {
363364
funcs: &[(&str, &Function)],
364365
_files: &mut Files,
365366
) -> Result<()> {
366-
let name = world_name(resolve, world);
367+
let name = format!("{}.{}", self.opts.gen_dir, world_name(resolve, world));
367368
let mut gen = self.interface(resolve, &name, "$root", Direction::Export);
368369

369370
for (_, func) in funcs {
@@ -412,7 +413,7 @@ impl WorldGenerator for MoonBit {
412413

413414
let version = env!("CARGO_PKG_VERSION");
414415

415-
let mut generate_pkg_definition = |name: &str, files: &mut Files| {
416+
let mut generate_pkg_definition = |name: &String, files: &mut Files| {
416417
let directory = name.replace('.', "/");
417418
let imports: Option<&mut Imports> = self.package_import.get_mut(name);
418419
if let Some(imports) = imports {
@@ -472,7 +473,11 @@ impl WorldGenerator for MoonBit {
472473

473474
files.push(&format!("{directory}/top.mbt"), indent(&src).as_bytes());
474475
if !self.opts.ignore_stub {
475-
files.push(&format!("{directory}/stub.mbt"), indent(&stub).as_bytes());
476+
files.push(
477+
&format!("{}/{directory}/stub.mbt", self.opts.gen_dir),
478+
indent(&stub).as_bytes(),
479+
);
480+
generate_pkg_definition(&format!("{}.{}", self.opts.gen_dir, name), files);
476481
}
477482

478483
let generate_ffi =
@@ -488,7 +493,11 @@ impl WorldGenerator for MoonBit {
488493
uwriteln!(&mut body, "{b}");
489494

490495
files.push(
491-
&format!("{EXPORT_DIR}/{}_export.mbt", directory.to_snake_case()),
496+
&format!(
497+
"{}/{}_export.mbt",
498+
self.opts.gen_dir,
499+
directory.to_snake_case()
500+
),
492501
indent(&body).as_bytes(),
493502
);
494503
};
@@ -528,8 +537,8 @@ impl WorldGenerator for MoonBit {
528537
files.push(&format!("{directory}/top.mbt"), indent(&src).as_bytes());
529538
if !self.opts.ignore_stub {
530539
files.push(&format!("{directory}/stub.mbt"), indent(&stub).as_bytes());
540+
generate_pkg_definition(&name, files);
531541
}
532-
generate_pkg_definition(&name, files);
533542
generate_ffi(directory, fragments, files);
534543
}
535544

@@ -541,12 +550,16 @@ impl WorldGenerator for MoonBit {
541550
files.push(&format!("{FFI_DIR}/moon.pkg.json"), "{}".as_bytes());
542551

543552
// Export project files
544-
let mut body = Source::default();
545-
uwriteln!(&mut body, "{{ \"name\": \"{project_name}\" }}");
546-
files.push(&format!("moon.mod.json"), body.as_bytes());
553+
if !self.opts.ignore_stub {
554+
let mut body = Source::default();
555+
uwriteln!(&mut body, "{{ \"name\": \"{project_name}\" }}");
556+
files.push(&format!("moon.mod.json"), body.as_bytes());
557+
}
558+
559+
let export_dir = self.opts.gen_dir.clone();
547560

548561
// Export project entry point
549-
let mut gen = self.interface(resolve, EXPORT_DIR, "", Direction::Export);
562+
let mut gen = self.interface(resolve, &export_dir.as_str(), "", Direction::Export);
550563
let ffi_qualifier = gen.qualify_package(&FFI_DIR.to_string());
551564

552565
let mut body = Source::default();
@@ -586,7 +599,10 @@ impl WorldGenerator for MoonBit {
586599
self.return_area_size,
587600
);
588601
}
589-
files.push(&format!("{EXPORT_DIR}/ffi.mbt"), indent(&body).as_bytes());
602+
files.push(
603+
&format!("{}/ffi.mbt", self.opts.gen_dir),
604+
indent(&body).as_bytes(),
605+
);
590606
self.export
591607
.insert("cabi_realloc".into(), "cabi_realloc".into());
592608

@@ -612,7 +628,7 @@ impl WorldGenerator for MoonBit {
612628
"#,
613629
exports.join(", ")
614630
);
615-
if let Some(imports) = self.package_import.get_mut(EXPORT_DIR) {
631+
if let Some(imports) = self.package_import.get_mut(&self.opts.gen_dir) {
616632
let mut deps = imports
617633
.packages
618634
.iter()
@@ -635,7 +651,7 @@ impl WorldGenerator for MoonBit {
635651
",
636652
);
637653
files.push(
638-
&format!("{EXPORT_DIR}/moon.pkg.json"),
654+
&format!("{}/moon.pkg.json", self.opts.gen_dir,),
639655
indent(&body).as_bytes(),
640656
);
641657

@@ -830,9 +846,14 @@ impl InterfaceGenerator<'_> {
830846

831847
let export_name = func.legacy_core_export_name(interface_name);
832848

833-
let mut toplevel_generator =
834-
self.gen
835-
.interface(self.resolve, EXPORT_DIR, self.module, Direction::Export);
849+
let export_dir = self.gen.opts.gen_dir.clone();
850+
851+
let mut toplevel_generator = self.gen.interface(
852+
self.resolve,
853+
export_dir.as_str(),
854+
self.module,
855+
Direction::Export,
856+
);
836857

837858
let mut bindgen = FunctionBindgen::new(
838859
&mut toplevel_generator,
@@ -1220,9 +1241,11 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
12201241

12211242
let func_name = self.gen.export_ns.tmp(&format!("wasmExport{name}Dtor"));
12221243

1223-
let mut gen = self
1224-
.gen
1225-
.interface(self.resolve, EXPORT_DIR, "", Direction::Export);
1244+
let export_dir = self.gen.opts.gen_dir.clone();
1245+
1246+
let mut gen =
1247+
self.gen
1248+
.interface(self.resolve, export_dir.as_str(), "", Direction::Export);
12261249

12271250
uwrite!(
12281251
self.ffi,
@@ -1768,8 +1791,12 @@ impl Bindgen for FunctionBindgen<'_, '_> {
17681791
results.push(format!("({}).reinterpret_as_int()", operands[0]))
17691792
}
17701793

1771-
Instruction::U64FromI64 => results.push(format!("({}).to_uint64()", operands[0])),
1772-
Instruction::I64FromU64 => results.push(format!("({}).to_int64()", operands[0])),
1794+
Instruction::U64FromI64 => {
1795+
results.push(format!("({}).reinterpret_as_uint64()", operands[0]))
1796+
}
1797+
Instruction::I64FromU64 => {
1798+
results.push(format!("({}).reinterpret_as_int64()", operands[0]))
1799+
}
17731800

17741801
Instruction::I32FromBool => {
17751802
results.push(format!("(if {} {{ 1 }} else {{ 0 }})", operands[0]));
@@ -1833,7 +1860,7 @@ impl Bindgen for FunctionBindgen<'_, '_> {
18331860
}
18341861
Int::U64 => {
18351862
results.push(format!(
1836-
"{}(({}).reinterpret_as_uint().to_uint64().lor(({}).reinterpret_as_uint().to_uint64.lsl(32)))",
1863+
"{}(({}).reinterpret_as_uint().to_uint64() | (({}).reinterpret_as_uint().to_uint64() << 32))",
18371864
self.gen.type_name(&Type::Id(*ty), true),
18381865
operands[0],
18391866
operands[1]
@@ -2714,13 +2741,10 @@ fn indent(code: &str) -> Source {
27142741
}
27152742

27162743
fn world_name(resolve: &Resolve, world: WorldId) -> String {
2717-
format!(
2718-
"worlds.{}",
2719-
resolve.worlds[world].name.to_lower_camel_case()
2720-
)
2744+
format!("world.{}", resolve.worlds[world].name.to_lower_camel_case())
27212745
}
27222746

2723-
fn interface_name(resolve: &Resolve, name: &WorldKey, direction: Direction) -> String {
2747+
fn interface_name(resolve: &Resolve, name: &WorldKey) -> String {
27242748
let pkg = match name {
27252749
WorldKey::Name(_) => None,
27262750
WorldKey::Interface(id) => {
@@ -2736,11 +2760,7 @@ fn interface_name(resolve: &Resolve, name: &WorldKey, direction: Direction) -> S
27362760
.to_lower_camel_case();
27372761

27382762
format!(
2739-
"interface.{}.{}{name}",
2740-
match direction {
2741-
Direction::Import => "imports",
2742-
Direction::Export => "exports",
2743-
},
2763+
"interface.{}{name}",
27442764
if let Some(name) = &pkg {
27452765
format!(
27462766
"{}.{}.",
@@ -2764,7 +2784,7 @@ impl ToMoonBitIdent for str {
27642784
"continue" | "for" | "match" | "if" | "pub" | "priv" | "readonly" | "break"
27652785
| "raise" | "try" | "except" | "catch" | "else" | "enum" | "struct" | "type"
27662786
| "trait" | "return" | "let" | "mut" | "while" | "loop" | "extern" | "with"
2767-
| "throw" | "init" | "main" | "test" | "in" | "guard" => {
2787+
| "throw" | "init" | "main" | "test" | "in" | "guard" | "typealias" => {
27682788
format!("{self}_")
27692789
}
27702790
_ => self.to_snake_case(),
@@ -2782,7 +2802,7 @@ impl ToMoonBitTypeIdent for str {
27822802
match self.to_upper_camel_case().as_str() {
27832803
type_name @ ("Bool" | "Byte" | "Int" | "Int64" | "UInt" | "UInt64" | "Float"
27842804
| "Double" | "Error" | "Buffer" | "Bytes" | "Array" | "FixedArray"
2785-
| "Map" | "String" | "Option" | "Result" | "Char") => {
2805+
| "Map" | "String" | "Option" | "Result" | "Char" | "Json") => {
27862806
format!("{type_name}_")
27872807
}
27882808
type_name => type_name.to_owned(),

crates/moonbit/tests/codegen.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ macro_rules! codegen_test {
1414
derive_eq: true,
1515
derive_error: true,
1616
ignore_stub: false,
17+
gen_dir: "gen".to_string(),
1718
}
1819
.build()
1920
.generate(resolve, world, files)

0 commit comments

Comments
 (0)