Skip to content

Commit eeca274

Browse files
MoonBit feature updates (#1044)
* feat(moonbit): add export resource support (cherry picked from commit aa2f5e3) * feat(moonbit): auto derive error type (cherry picked from commit 6f8f73e) * fix(moonbit): update api following stdapi change * fix(moonbit): add missing preamble
1 parent c648fc7 commit eeca274

File tree

2 files changed

+173
-38
lines changed

2 files changed

+173
-38
lines changed

crates/moonbit/src/lib.rs

Lines changed: 172 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,9 @@ pub struct Opts {
196196
/// Whether or not to derive Eq for all types
197197
#[cfg_attr(feature = "clap", arg(long, default_value_t = false))]
198198
pub derive_eq: bool,
199+
/// Whether or not to declare as Error type for types ".*error"
200+
#[cfg_attr(feature = "clap", arg(long, default_value_t = false))]
201+
pub derive_error: bool,
199202
/// Whether or not to generate stub files ; useful for update after WIT change
200203
#[cfg_attr(feature = "clap", arg(long, default_value_t = false))]
201204
pub ignore_stub: bool,
@@ -531,7 +534,10 @@ impl WorldGenerator for MoonBit {
531534
}
532535

533536
// Export FFI Utils
534-
files.push(&format!("{FFI_DIR}/top.mbt"), FFI.as_bytes());
537+
let mut body = Source::default();
538+
wit_bindgen_core::generated_preamble(&mut body, version);
539+
body.push_str(FFI);
540+
files.push(&format!("{FFI_DIR}/top.mbt"), indent(&body).as_bytes());
535541
files.push(&format!("{FFI_DIR}/moon.pkg.json"), "{}".as_bytes());
536542

537543
// Export project files
@@ -544,6 +550,7 @@ impl WorldGenerator for MoonBit {
544550
let ffi_qualifier = gen.qualify_package(&FFI_DIR.to_string());
545551

546552
let mut body = Source::default();
553+
wit_bindgen_core::generated_preamble(&mut body, version);
547554
uwriteln!(
548555
&mut body,
549556
"
@@ -1131,30 +1138,96 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
11311138
if self.gen.opts.derive_eq {
11321139
deriviation.push("Eq")
11331140
}
1141+
let declaration = if self.gen.opts.derive_error && name.contains("Error") {
1142+
"type!"
1143+
} else {
1144+
"type"
1145+
};
11341146

11351147
uwrite!(
11361148
self.src,
11371149
r#"
1138-
pub type {name} Int derive({})
1139-
1140-
pub fn {name}::drop(self : {name}) -> Unit {{
1141-
wasmImportResourceDrop{name}(self.0)
1142-
}}
1150+
pub {declaration} {name} Int derive({})
11431151
"#,
11441152
deriviation.join(", "),
11451153
);
11461154

1147-
uwrite!(
1148-
if self.direction == Direction::Import {
1149-
&mut self.ffi
1150-
} else {
1151-
&mut self.src
1152-
},
1153-
r#"
1154-
fn wasmImportResourceDrop{name}(resource : Int) = "{}" "[resource-drop]{type_name}"
1155-
"#,
1156-
self.module
1157-
);
1155+
let module = self.module;
1156+
1157+
if self.direction == Direction::Import {
1158+
uwrite!(
1159+
&mut self.src,
1160+
r#"
1161+
/// Drops a resource handle.
1162+
pub fn {name}::drop(self : {name}) -> Unit {{
1163+
let {name}(resource) = self
1164+
wasmImportResourceDrop{name}(resource)
1165+
}}
1166+
"#,
1167+
);
1168+
1169+
uwrite!(
1170+
&mut self.ffi,
1171+
r#"
1172+
fn wasmImportResourceDrop{name}(resource : Int) = "{module}" "[resource-drop]{type_name}"
1173+
"#,
1174+
)
1175+
} else {
1176+
uwrite!(
1177+
&mut self.src,
1178+
r#"
1179+
/// Creates a new resource with the given `rep` as its representation and returning the handle to this resource.
1180+
pub fn {name}::new(rep : Int) -> {name} {{
1181+
{name}::{name}(wasmExportResourceNew{name}(rep))
1182+
}}
1183+
fn wasmExportResourceNew{name}(rep : Int) -> Int = "[export]{module}" "[resource-new]{type_name}"
1184+
1185+
/// Drops a resource handle.
1186+
pub fn {name}::drop(self : {name}) -> Unit {{
1187+
let {name}(resource) = self
1188+
wasmExportResourceDrop{name}(resource)
1189+
}}
1190+
fn wasmExportResourceDrop{name}(resource : Int) = "[export]{module}" "[resource-drop]{type_name}"
1191+
1192+
/// Gets the `Int` representation of the resource pointed to the given handle.
1193+
pub fn {name}::rep(self : {name}) -> Int {{
1194+
let {name}(resource) = self
1195+
wasmExportResourceRep{name}(resource)
1196+
}}
1197+
fn wasmExportResourceRep{name}(resource : Int) -> Int = "[export]{module}" "[resource-rep]{type_name}"
1198+
"#,
1199+
);
1200+
1201+
uwrite!(
1202+
&mut self.stub,
1203+
r#"
1204+
/// Destructor of the resource.
1205+
pub fn {name}::dtor(self : {name}) -> Unit {{
1206+
abort("todo")
1207+
}}
1208+
"#
1209+
);
1210+
1211+
let func_name = self.gen.export_ns.tmp(&format!("wasmExport{name}Dtor"));
1212+
1213+
let mut gen = self
1214+
.gen
1215+
.interface(self.resolve, EXPORT_DIR, "", Direction::Export);
1216+
1217+
uwrite!(
1218+
self.ffi,
1219+
r#"
1220+
pub fn {func_name}(handle : Int) -> Unit {{
1221+
{}{name}::dtor(handle)
1222+
}}
1223+
"#,
1224+
gen.qualify_package(&self.name.to_string())
1225+
);
1226+
1227+
self.gen
1228+
.export
1229+
.insert(func_name, format!("{module}#[dtor]{type_name}"));
1230+
}
11581231
}
11591232

11601233
fn type_flags(&mut self, _id: TypeId, name: &str, flags: &Flags, docs: &Docs) {
@@ -1204,11 +1277,16 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
12041277
if self.gen.opts.derive_eq {
12051278
deriviation.push("Eq")
12061279
}
1280+
let declaration = if self.gen.opts.derive_error && name.contains("Error") {
1281+
"type!"
1282+
} else {
1283+
"type"
1284+
};
12071285

12081286
uwrite!(
12091287
self.src,
12101288
"
1211-
pub type {name} {ty} derive({})
1289+
pub {declaration} {name} {ty} derive({})
12121290
pub fn {name}::default() -> {name} {{
12131291
{}
12141292
}}
@@ -1221,13 +1299,16 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
12211299
}}
12221300
}}
12231301
pub fn {name}::set(self : {name}, other: {name}Flag) -> {name} {{
1224-
self.0.lor(other.value())
1302+
let {name}(flag) = self
1303+
flag.lor(other.value())
12251304
}}
12261305
pub fn {name}::unset(self : {name}, other: {name}Flag) -> {name} {{
1227-
self.0.land(other.value().lnot())
1306+
let {name}(flag) = self
1307+
flag.land(other.value().lnot())
12281308
}}
12291309
pub fn {name}::is_set(self : {name}, other: {name}Flag) -> Bool {{
1230-
(self.0.land(other.value()) == other.value())
1310+
let {name}(flag) = self
1311+
(flag.land(other.value()) == other.value())
12311312
}}
12321313
",
12331314
deriviation.join(", "),
@@ -1271,11 +1352,16 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
12711352
if self.gen.opts.derive_eq {
12721353
deriviation.push("Eq")
12731354
}
1355+
let declaration = if self.gen.opts.derive_error && name.contains("Error") {
1356+
"type!"
1357+
} else {
1358+
"enum"
1359+
};
12741360

12751361
uwrite!(
12761362
self.src,
12771363
"
1278-
pub enum {name} {{
1364+
pub {declaration} {name} {{
12791365
{cases}
12801366
}} derive({})
12811367
",
@@ -1311,11 +1397,16 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
13111397
if self.gen.opts.derive_eq {
13121398
deriviation.push("Eq")
13131399
}
1400+
let declaration = if self.gen.opts.derive_error && name.contains("Error") {
1401+
"type!"
1402+
} else {
1403+
"enum"
1404+
};
13141405

13151406
uwrite!(
13161407
self.src,
13171408
"
1318-
pub enum {name} {{
1409+
pub {declaration} {name} {{
13191410
{cases}
13201411
}} derive({})
13211412
",
@@ -1642,8 +1733,9 @@ impl Bindgen for FunctionBindgen<'_, '_> {
16421733
Instruction::CharFromI32 => results.push(format!("Char::from_int({})", operands[0])),
16431734
Instruction::I32FromChar => results.push(format!("({}).to_int()", operands[0])),
16441735

1645-
Instruction::I32FromU8 | Instruction::I32FromU16 => {
1646-
results.push(format!("({}).to_int()", operands[0]))
1736+
Instruction::I32FromU8 => results.push(format!("({}).to_int()", operands[0])),
1737+
Instruction::I32FromU16 => {
1738+
results.push(format!("({}).reinterpret_as_int()", operands[0]))
16471739
}
16481740
Instruction::U8FromI32 => results.push(format!("({}).to_byte()", operands[0])),
16491741

@@ -1655,11 +1747,16 @@ impl Bindgen for FunctionBindgen<'_, '_> {
16551747
Instruction::I32FromS16 => {
16561748
results.push(format!("{ffi_qualifier}extend16({})", operands[0]))
16571749
}
1658-
Instruction::U16FromI32 => {
1659-
results.push(format!("({}.land(0xFFFF).to_uint())", operands[0]))
1750+
Instruction::U16FromI32 => results.push(format!(
1751+
"({}.land(0xFFFF).reinterpret_as_uint())",
1752+
operands[0]
1753+
)),
1754+
Instruction::U32FromI32 => {
1755+
results.push(format!("({}).reinterpret_as_uint()", operands[0]))
1756+
}
1757+
Instruction::I32FromU32 => {
1758+
results.push(format!("({}).reinterpret_as_int()", operands[0]))
16601759
}
1661-
Instruction::U32FromI32 => results.push(format!("({}).to_uint()", operands[0])),
1662-
Instruction::I32FromU32 => results.push(format!("({}).to_int()", operands[0])),
16631760

16641761
Instruction::U64FromI64 => results.push(format!("({}).to_uint64()", operands[0])),
16651762
Instruction::I64FromU64 => results.push(format!("({}).to_int64()", operands[0])),
@@ -1669,14 +1766,43 @@ impl Bindgen for FunctionBindgen<'_, '_> {
16691766
}
16701767
Instruction::BoolFromI32 => results.push(format!("({} != 0)", operands[0])),
16711768

1672-
Instruction::FlagsLower { flags, .. } => match flags_repr(flags) {
1673-
Int::U8 | Int::U16 | Int::U32 => {
1674-
results.push(format!("({}).0.to_int()", operands[0]));
1769+
Instruction::FlagsLower { flags, ty, .. } => match flags_repr(flags) {
1770+
Int::U8 => {
1771+
let op = &operands[0];
1772+
let flag = self.locals.tmp("flag");
1773+
let ty = self.gen.type_name(&Type::Id(*ty), false);
1774+
uwriteln!(
1775+
self.src,
1776+
r#"
1777+
let {ty}({flag}) = {op}
1778+
"#
1779+
);
1780+
results.push(format!("{flag}.to_int()"));
1781+
}
1782+
Int::U16 | Int::U32 => {
1783+
let op = &operands[0];
1784+
let flag = self.locals.tmp("flag");
1785+
let ty = self.gen.type_name(&Type::Id(*ty), false);
1786+
uwriteln!(
1787+
self.src,
1788+
r#"
1789+
let {ty}({flag}) = {op}
1790+
"#
1791+
);
1792+
results.push(format!("{flag}.reinterpret_as_int()"));
16751793
}
16761794
Int::U64 => {
16771795
let op = &operands[0];
1678-
results.push(format!("(({op}).0.to_int())"));
1679-
results.push(format!("((({op}).0.lsr(32)).to_int())"));
1796+
let flag = self.locals.tmp("flag");
1797+
let ty = self.gen.type_name(&Type::Id(*ty), false);
1798+
uwriteln!(
1799+
self.src,
1800+
r#"
1801+
let {ty}({flag}) = {op}
1802+
"#
1803+
);
1804+
results.push(format!("({flag}.to_int())"));
1805+
results.push(format!("({flag}.lsr(32)).to_int())"));
16801806
}
16811807
},
16821808

@@ -1690,24 +1816,32 @@ impl Bindgen for FunctionBindgen<'_, '_> {
16901816
}
16911817
Int::U16 | Int::U32 => {
16921818
results.push(format!(
1693-
"{}({}.to_uint())",
1819+
"{}({}.reinterpret_as_uint())",
16941820
self.gen.type_name(&Type::Id(*ty), true),
16951821
operands[0]
16961822
));
16971823
}
16981824
Int::U64 => {
16991825
results.push(format!(
1700-
"{}(({}).to_uint().to_uint64().lor(({}).to_uint().to_uint64.lsl(32)))",
1826+
"{}(({}).reinterpret_as_uint().to_uint64().lor(({}).reinterpret_as_uint().to_uint64.lsl(32)))",
17011827
self.gen.type_name(&Type::Id(*ty), true),
17021828
operands[0],
17031829
operands[1]
17041830
));
17051831
}
17061832
},
17071833

1708-
Instruction::HandleLower { .. } => {
1834+
Instruction::HandleLower { ty, .. } => {
17091835
let op = &operands[0];
1710-
results.push(format!("{op}.0"));
1836+
let handle = self.locals.tmp("handle");
1837+
let ty = self.gen.type_name(&Type::Id(*ty), false);
1838+
uwrite!(
1839+
self.src,
1840+
r#"
1841+
let {ty}({handle}) = {op}
1842+
"#
1843+
);
1844+
results.push(handle);
17111845
}
17121846
Instruction::HandleLift { ty, .. } => {
17131847
let op = &operands[0];

crates/moonbit/tests/codegen.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ macro_rules! codegen_test {
1212
wit_bindgen_moonbit::Opts {
1313
derive_show: true,
1414
derive_eq: true,
15+
derive_error: true,
1516
ignore_stub: false,
1617
}
1718
.build()

0 commit comments

Comments
 (0)