Skip to content

Commit fc0bff6

Browse files
fix(moonbit): update syntax and add tests (#1352)
* fix: adapt Moonbit struct tuple & suberror features * fix: update keyword handling in to_moonbit_ident function * style: cargo fmt * test: add new test --------- Co-authored-by: BigOrangeQWQ <2284086963@qq.com>
1 parent 62a2af5 commit fc0bff6

File tree

5 files changed

+279
-23
lines changed

5 files changed

+279
-23
lines changed

crates/moonbit/src/lib.rs

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,15 +1183,15 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
11831183
deriviation.push("Eq")
11841184
}
11851185
let declaration = if self.gen.opts.derive_error && name.contains("Error") {
1186-
"type!"
1186+
"suberror"
11871187
} else {
1188-
"type"
1188+
"struct"
11891189
};
11901190

11911191
uwrite!(
11921192
self.src,
11931193
r#"
1194-
pub(all) {declaration} {name} Int derive({})
1194+
pub(all) {declaration} {name}(Int) derive({})
11951195
"#,
11961196
deriviation.join(", "),
11971197
);
@@ -1227,14 +1227,14 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
12271227
fn wasmExportResourceNew{name}(rep : Int) -> Int = "[export]{module}" "[resource-new]{type_name}"
12281228
12291229
/// Drops a resource handle.
1230-
pub fn {name}::drop(self : {name}) -> Unit {{
1230+
pub fn {name}::drop(self : Self) -> Unit {{
12311231
let {name}(resource) = self
12321232
wasmExportResourceDrop{name}(resource)
12331233
}}
12341234
fn wasmExportResourceDrop{name}(resource : Int) = "[export]{module}" "[resource-drop]{type_name}"
12351235
12361236
/// Gets the `Int` representation of the resource pointed to the given handle.
1237-
pub fn {name}::rep(self : {name}) -> Int {{
1237+
pub fn {name}::rep(self : Self) -> Int {{
12381238
let {name}(resource) = self
12391239
wasmExportResourceRep{name}(resource)
12401240
}}
@@ -1324,15 +1324,15 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
13241324
deriviation.push("Eq")
13251325
}
13261326
let declaration = if self.gen.opts.derive_error && name.contains("Error") {
1327-
"type!"
1327+
"suberror"
13281328
} else {
1329-
"type"
1329+
"struct"
13301330
};
13311331

13321332
uwrite!(
13331333
self.src,
13341334
"
1335-
pub(all) {declaration} {name} {ty} derive({})
1335+
pub(all) {declaration} {name}({ty}) derive({})
13361336
pub fn {name}::default() -> {name} {{
13371337
{}
13381338
}}
@@ -1344,15 +1344,15 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
13441344
{map_to_int}
13451345
}}
13461346
}}
1347-
pub fn {name}::set(self : {name}, other: {name}Flag) -> {name} {{
1347+
pub fn {name}::set(self : Self, other: {name}Flag) -> {name} {{
13481348
let {name}(flag) = self
13491349
flag.lor(other.value())
13501350
}}
1351-
pub fn {name}::unset(self : {name}, other: {name}Flag) -> {name} {{
1351+
pub fn {name}::unset(self : Self, other: {name}Flag) -> {name} {{
13521352
let {name}(flag) = self
13531353
flag.land(other.value().lnot())
13541354
}}
1355-
pub fn {name}::is_set(self : {name}, other: {name}Flag) -> Bool {{
1355+
pub fn {name}::is_set(self : Self, other: {name}Flag) -> Bool {{
13561356
let {name}(flag) = self
13571357
(flag.land(other.value()) == other.value())
13581358
}}
@@ -1399,7 +1399,7 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
13991399
deriviation.push("Eq")
14001400
}
14011401
let declaration = if self.gen.opts.derive_error && name.contains("Error") {
1402-
"type!"
1402+
"suberror"
14031403
} else {
14041404
"enum"
14051405
};
@@ -1444,7 +1444,7 @@ impl<'a> wit_bindgen_core::InterfaceGenerator<'a> for InterfaceGenerator<'a> {
14441444
deriviation.push("Eq")
14451445
}
14461446
let declaration = if self.gen.opts.derive_error && name.contains("Error") {
1447-
"type!"
1447+
"suberror"
14481448
} else {
14491449
"enum"
14501450
};
@@ -1785,7 +1785,9 @@ impl Bindgen for FunctionBindgen<'_, '_> {
17851785
Instruction::F32FromCoreF32 => results.push(operands[0].clone()),
17861786
Instruction::CoreF32FromF32 => results.push(operands[0].clone()),
17871787

1788-
Instruction::CharFromI32 => results.push(format!("Char::from_int({})", operands[0])),
1788+
Instruction::CharFromI32 => {
1789+
results.push(format!("Int::unsafe_to_char({})", operands[0]))
1790+
}
17891791
Instruction::I32FromChar => results.push(format!("({}).to_int()", operands[0])),
17901792

17911793
Instruction::I32FromU8 => results.push(format!("({}).to_int()", operands[0])),
@@ -2874,14 +2876,21 @@ impl ToMoonBitIdent for str {
28742876
fn to_moonbit_ident(&self) -> String {
28752877
// Escape MoonBit keywords and reserved keywords
28762878
match self {
2877-
"module" | "move" | "ref" | "static" | "super" | "unsafe" | "use" | "where"
2878-
| "await" | "dyn" | "abstract" | "do" | "final" | "macro" | "override" | "typeof"
2879-
| "virtual" | "yield" | "local" | "method" | "alias" | "assert" | "as" | "else"
2880-
| "extern" | "fn" | "if" | "let" | "const" | "match" | "mut" | "type" | "typealias"
2881-
| "struct" | "enum" | "trait" | "traitalias" | "derive" | "while" | "break"
2882-
| "continue" | "import" | "return" | "throw" | "raise" | "try" | "catch" | "pub"
2883-
| "priv" | "readonly" | "true" | "false" | "_" | "test" | "loop" | "for" | "in"
2884-
| "impl" | "with" | "guard" | "async" | "is" | "init" | "main" => {
2879+
// Keywords
2880+
"as" | "else" | "extern" | "fn" | "fnalias" | "if" | "let" | "const" | "match" | "using"
2881+
| "mut" | "type" | "typealias" | "struct" | "enum" | "trait" | "traitalias" | "derive"
2882+
| "while" | "break" | "continue" | "import" | "return" | "throw" | "raise" | "try" | "catch"
2883+
| "pub" | "priv" | "readonly" | "true" | "false" | "_" | "test" | "loop" | "for" | "in" | "impl"
2884+
| "with" | "guard" | "async" | "is" | "suberror" | "and" | "letrec" | "enumview" | "noraise"
2885+
| "defer" | "init" | "main"
2886+
// Reserved keywords
2887+
| "module" | "move" | "ref" | "static" | "super" | "unsafe" | "use" | "where" | "await"
2888+
| "dyn" | "abstract" | "do" | "final" | "macro" | "override" | "typeof" | "virtual" | "yield"
2889+
| "local" | "method" | "alias" | "assert" | "package" | "recur" | "isnot" | "define" | "downcast"
2890+
| "inherit" | "member" | "namespace" | "upcast" | "void" | "lazy" | "include" | "mixin"
2891+
| "protected" | "sealed" | "constructor" | "atomic" | "volatile" | "anyframe" | "anytype"
2892+
| "asm" | "comptime" | "errdefer" | "export" | "opaque" | "orelse" | "resume" | "threadlocal"
2893+
| "unreachable" | "dynclass" | "dynobj" | "dynrec" | "var" | "finally" | "noasync" => {
28852894
format!("{self}_")
28862895
}
28872896
_ => self.to_snake_case(),

crates/test/src/moonbit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ impl LanguageMethods for MoonBit {
6565
.arg("embed")
6666
.args(["--encoding", "utf16"])
6767
.args(["-o", artifact.to_str().unwrap()])
68-
.args(["-w", &compile.component.kind.to_string()])
68+
.args(["-w", &compile.component.bindgen.world])
6969
.arg(manifest_dir)
7070
.arg(&artifact);
7171
runner.run_command(&mut cmd)?;

tests/runtime/flavorful/test.mbt

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
//@ [lang]
2+
//@ path = 'gen/interface/test_/flavorful/toTest/stub.mbt'
3+
4+
///|
5+
pub fn f_list_in_record1(_a : ListInRecord1) -> Unit {
6+
try {
7+
assert_eq(_a.a, "list_in_record1")
8+
} catch {
9+
_ => panic()
10+
}
11+
}
12+
13+
///|
14+
pub fn f_list_in_record2() -> ListInRecord2 {
15+
{ a: "list_in_record2" }
16+
}
17+
18+
///|
19+
pub fn f_list_in_record3(_a : ListInRecord3) -> ListInRecord3 {
20+
{ a: "list_in_record3 output" }
21+
}
22+
23+
///|
24+
pub fn f_list_in_record4(_a : ListInRecord4) -> ListInRecord4 {
25+
{ a: "result4".to_string() }
26+
}
27+
28+
///|
29+
pub fn f_list_in_variant1(
30+
_a : String?,
31+
_b : Result[Unit, String],
32+
) -> Unit {
33+
try {
34+
assert_eq(_a.unwrap(), "foo")
35+
assert_eq(_b.unwrap_err(), "bar")
36+
} catch {
37+
_ => panic()
38+
}
39+
}
40+
41+
///|
42+
pub fn f_list_in_variant2() -> String? {
43+
Some("list_in_variant2".to_string())
44+
}
45+
46+
///|
47+
pub fn f_list_in_variant3(_a : String?) -> String? {
48+
try {
49+
assert_eq(_a.unwrap(), "input3")
50+
} catch {
51+
_ => panic()
52+
}
53+
Some("output3".to_string())
54+
}
55+
56+
let first : Ref[Bool] = Ref::new(true);
57+
58+
///|
59+
pub fn errno_result() -> Result[Unit, MyErrno] {
60+
if first.val {
61+
first.val = false;
62+
Err(MyErrno::B)
63+
} else {
64+
Ok(())
65+
}
66+
}
67+
68+
pub fn write_utf8_char(buf : @buffer.T, value : Char) -> Unit {
69+
let code = value.to_uint()
70+
match code {
71+
_..<0x80 => {
72+
let b0 = ((code & 0x7F) | 0x00).to_byte()
73+
buf.write_byte(b0)
74+
}
75+
_..<0x0800 => {
76+
let b0 = (((code >> 6) & 0x1F) | 0xC0).to_byte()
77+
let b1 = ((code & 0x3F) | 0x80).to_byte()
78+
buf.write_byte(b0)
79+
buf.write_byte(b1)
80+
}
81+
_..<0x010000 => {
82+
let b0 = (((code >> 12) & 0x0F) | 0xE0).to_byte()
83+
let b1 = (((code >> 6) & 0x3F) | 0x80).to_byte()
84+
let b2 = ((code & 0x3F) | 0x80).to_byte()
85+
buf.write_byte(b0)
86+
buf.write_byte(b1)
87+
buf.write_byte(b2)
88+
}
89+
_..<0x110000 => {
90+
let b0 = (((code >> 18) & 0x07) | 0xF0).to_byte()
91+
let b1 = (((code >> 12) & 0x3F) | 0x80).to_byte()
92+
let b2 = (((code >> 6) & 0x3F) | 0x80).to_byte()
93+
let b3 = ((code & 0x3F) | 0x80).to_byte()
94+
buf.write_byte(b0)
95+
buf.write_byte(b1)
96+
buf.write_byte(b2)
97+
buf.write_byte(b3)
98+
}
99+
_ => abort("Char out of range")
100+
}
101+
}
102+
103+
pub fn encode_to_utf8(
104+
src : String,
105+
) -> Bytes{
106+
let buf = @buffer.new(size_hint=src.length() * 4)
107+
for c in src {
108+
write_utf8_char(buf, c);
109+
}
110+
buf.to_bytes()
111+
}
112+
113+
///|
114+
pub fn list_typedefs(
115+
_a : String,
116+
_c : Array[String],
117+
) -> (FixedArray[Byte], Array[String]) {
118+
try {
119+
assert_eq(_a, "typedef1")
120+
assert_eq(_c.length(), 1)
121+
assert_eq(_c[0], "typedef2")
122+
} catch {
123+
_ => panic()
124+
}
125+
(encode_to_utf8("typedef3").to_fixedarray(), ["typedef4".to_string()])
126+
}
127+
128+
///|
129+
pub fn list_of_variants(
130+
_a : Array[Bool],
131+
_b : Array[Result[Unit, Unit]],
132+
_c : Array[MyErrno],
133+
) -> (Array[Bool], Array[Result[Unit, Unit]], Array[MyErrno]) {
134+
try {
135+
assert_eq(_a, [true, false])
136+
assert_eq(_b, [Ok(()), Err(())])
137+
assert_eq(_c, [MyErrno::SUCCESS, MyErrno::A])
138+
} catch {
139+
_ => panic()
140+
}
141+
([false, true], [Err(()), Ok(())], [MyErrno::A, MyErrno::B])
142+
}

tests/runtime/many-arguments/test.mbt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//@ [lang]
2+
//@ path = 'gen/interface/test_/many_arguments/toTest/stub.mbt'
3+
///|
4+
pub fn many_arguments(
5+
_a1 : UInt64,
6+
_a2 : UInt64,
7+
_a3 : UInt64,
8+
_a4 : UInt64,
9+
_a5 : UInt64,
10+
_a6 : UInt64,
11+
_a7 : UInt64,
12+
_a8 : UInt64,
13+
_a9 : UInt64,
14+
_a10 : UInt64,
15+
_a11 : UInt64,
16+
_a12 : UInt64,
17+
_a13 : UInt64,
18+
_a14 : UInt64,
19+
_a15 : UInt64,
20+
_a16 : UInt64,
21+
) -> Unit {
22+
try {
23+
assert_eq(_a1, 1)
24+
assert_eq(_a2, 2)
25+
assert_eq(_a3, 3)
26+
assert_eq(_a4, 4)
27+
assert_eq(_a5, 5)
28+
assert_eq(_a6, 6)
29+
assert_eq(_a7, 7)
30+
assert_eq(_a8, 8)
31+
assert_eq(_a9, 9)
32+
assert_eq(_a10, 10)
33+
assert_eq(_a11, 11)
34+
assert_eq(_a12, 12)
35+
assert_eq(_a13, 13)
36+
assert_eq(_a14, 14)
37+
assert_eq(_a15, 15)
38+
assert_eq(_a16, 16)
39+
} catch {
40+
_ => panic()
41+
}
42+
}

tests/runtime/results/leaf.mbt

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//@ [lang]
2+
//@ path = 'gen/interface/test_/results/test/stub.mbt'
3+
4+
///|
5+
pub fn string_error(_a : Float) -> Result[Float, String] {
6+
if _a == 0.0 {
7+
return Err("zero")
8+
}
9+
Ok(_a)
10+
11+
}
12+
13+
///|
14+
pub fn enum_error(_a : Float) -> Result[Float, E] {
15+
if _a == 0.0 {
16+
return Err(E::A)
17+
}
18+
Ok(_a)
19+
}
20+
21+
///|
22+
pub fn record_error(_a : Float) -> Result[Float, E2] {
23+
if _a == 0.0 {
24+
return Err({ line: 420, column: 0 })
25+
} else if _a == 1.0 {
26+
return Err({ line: 77, column: 2 })
27+
}
28+
Ok(_a)
29+
}
30+
31+
///|
32+
pub fn variant_error(_a : Float) -> Result[Float, E3] {
33+
if _a == 0.0 {
34+
return Err(E3::E2({ line: 420, column: 0 }))
35+
} else if _a == 1.0 {
36+
return Err(E3::E1(B))
37+
} else if _a == 2.0 {
38+
return Err(E3::E1(C))
39+
}
40+
Ok(_a)
41+
}
42+
43+
///|
44+
pub fn empty_error(_a : UInt) -> Result[UInt, Unit] {
45+
if _a == 0 {
46+
Err(())
47+
} else if _a == 1 {
48+
Ok(42)
49+
} else {
50+
Ok(_a)
51+
}
52+
}
53+
54+
///|
55+
pub fn double_error(_a : UInt) -> Result[Result[Unit, String], String] {
56+
if _a == 0 {
57+
Ok(Ok(()))
58+
} else if _a == 1 {
59+
Ok(Err("one"))
60+
} else {
61+
Err("two")
62+
}
63+
}

0 commit comments

Comments
 (0)