@@ -179,7 +179,7 @@ impl MoonBitComponent {
179179 pub fn define_bindgen_packages ( & mut self ) -> anyhow:: Result < ( ) > {
180180 let moonbit_root_package = self . moonbit_root_package ( ) ?;
181181 let world_name = self . world_name ( ) ?;
182- let world_snake = world_name . to_snake_case ( ) ;
182+ let world_snake = to_moonbit_ident ( & world_name ) ;
183183
184184 let imported_interfaces = self . get_imported_interfaces ( ) ?;
185185 let exported_interfaces = self . get_exported_interfaces ( ) ?;
@@ -257,8 +257,8 @@ impl MoonBitComponent {
257257 gen_mbt_files. push ( Utf8Path :: new ( "gen" ) . join ( format ! ( "world_{world_snake}_export.mbt" ) ) ) ;
258258
259259 for ( package_name, interface_name) in & imported_interfaces {
260- let pkg_namespace = package_name. namespace . to_snake_case ( ) ;
261- let pkg_name = package_name. name . to_snake_case ( ) ;
260+ let pkg_namespace = to_moonbit_ident ( & package_name. namespace ) ;
261+ let pkg_name = to_moonbit_ident ( & package_name. name ) ;
262262 let interface_name = interface_name. to_lower_camel_case ( ) ;
263263
264264 let name = format ! (
@@ -288,8 +288,10 @@ impl MoonBitComponent {
288288 }
289289
290290 for ( package_name, interface_name) in & exported_interfaces {
291- let pkg_namespace = package_name. namespace . to_snake_case ( ) ;
292- let pkg_name = package_name. name . to_snake_case ( ) ;
291+ let pkg_namespace = to_moonbit_ident ( & package_name. namespace ) ;
292+ let unescaped_pkg_namespace = package_name. namespace . to_snake_case ( ) ;
293+ let pkg_name = to_moonbit_ident ( & package_name. name ) ;
294+ let unescaped_pkg_name = package_name. name . to_snake_case ( ) ;
293295 let interface_name = interface_name. to_lower_camel_case ( ) ;
294296 let snake_interface_name = interface_name. to_snake_case ( ) ;
295297
@@ -325,7 +327,7 @@ impl MoonBitComponent {
325327 interface_name. clone ( ) ,
326328 ) ) ;
327329 gen_mbt_files. push ( Utf8Path :: new ( "gen" ) . join ( format ! (
328- "gen_interface_{pkg_namespace }_{pkg_name }_{snake_interface_name}_export.mbt"
330+ "gen_interface_{unescaped_pkg_namespace }_{unescaped_pkg_name }_{snake_interface_name}_export.mbt"
329331 ) ) ) ;
330332 }
331333
@@ -432,8 +434,13 @@ impl MoonBitComponent {
432434 interface_name : & str ,
433435 moonbit_source : & str ,
434436 ) -> anyhow:: Result < ( ) > {
435- let package_name_snake = package_name. name . to_snake_case ( ) ;
436- let package_namespace_snake = package_name. namespace . to_snake_case ( ) ;
437+ let package_name_snake = to_moonbit_ident ( & package_name. name ) ;
438+ let package_namespace_snake = to_moonbit_ident ( & package_name. namespace ) ;
439+
440+ println ! (
441+ "!!! writing interface stub for {package_name}/{interface_name} to {package_namespace_snake}/{package_name_snake}"
442+ ) ;
443+
437444 let path = self
438445 . dir
439446 . join ( "gen" )
@@ -456,8 +463,8 @@ impl MoonBitComponent {
456463 interface_name : & str ,
457464 json : serde_json:: Value ,
458465 ) -> anyhow:: Result < ( ) > {
459- let package_name_snake = package_name. name . to_snake_case ( ) ;
460- let package_namespace_snake = package_name. namespace . to_snake_case ( ) ;
466+ let package_name_snake = to_moonbit_ident ( & package_name. name ) ;
467+ let package_namespace_snake = to_moonbit_ident ( & package_name. namespace ) ;
461468 let path = self
462469 . dir
463470 . join ( "gen" )
@@ -982,6 +989,31 @@ impl Display for WarningControl {
982989 }
983990}
984991
992+ pub fn to_moonbit_ident ( name : impl AsRef < str > ) -> String {
993+ // Escape MoonBit keywords and reserved keywords
994+ let name = name. as_ref ( ) ;
995+ match name {
996+ // Keywords
997+ "as" | "else" | "extern" | "fn" | "fnalias" | "if" | "let" | "const" | "match" | "using"
998+ | "mut" | "type" | "typealias" | "struct" | "enum" | "trait" | "traitalias" | "derive"
999+ | "while" | "break" | "continue" | "import" | "return" | "throw" | "raise" | "try" | "catch"
1000+ | "pub" | "priv" | "readonly" | "true" | "false" | "_" | "test" | "loop" | "for" | "in" | "impl"
1001+ | "with" | "guard" | "async" | "is" | "suberror" | "and" | "letrec" | "enumview" | "noraise"
1002+ | "defer" | "init" | "main"
1003+ // Reserved keywords
1004+ | "module" | "move" | "ref" | "static" | "super" | "unsafe" | "use" | "where" | "await"
1005+ | "dyn" | "abstract" | "do" | "final" | "macro" | "override" | "typeof" | "virtual" | "yield"
1006+ | "local" | "method" | "alias" | "assert" | "recur" | "isnot" | "define" | "downcast"
1007+ | "inherit" | "member" | "namespace" | "upcast" | "void" | "lazy" | "include" | "mixin"
1008+ | "protected" | "sealed" | "constructor" | "atomic" | "volatile" | "anyframe" | "anytype"
1009+ | "asm" | "comptime" | "errdefer" | "export" | "opaque" | "orelse" | "resume" | "threadlocal"
1010+ | "unreachable" | "dynclass" | "dynobj" | "dynrec" | "var" | "finally" | "noasync" => {
1011+ format ! ( "{name}_" )
1012+ }
1013+ _ => name. to_snake_case ( ) ,
1014+ }
1015+ }
1016+
9851017#[ cfg( test) ]
9861018test_r:: enable!( ) ;
9871019
0 commit comments