├── src ├── test │ ├── hello │ │ ├── moon.pkg.json │ │ ├── hello.mbt │ │ └── pkg.generated.mbti │ ├── fs.mbt │ ├── moon.pkg.json │ ├── pkg.generated.mbti │ ├── import.mbt │ ├── attributes.mbt │ ├── alias.mbt │ ├── comparision.mbt │ ├── trait.mbt │ ├── string_builder.mbt │ ├── sort.mbt │ ├── constructors.mbt │ ├── eval.mbt │ ├── io_ffi.mbt │ ├── exception.mbt │ ├── json.mbt │ ├── arithmetic.mbt │ ├── syntax.mbt │ ├── map.mbt │ ├── functional.mbt │ ├── array.mbt │ ├── enum.mbt │ ├── basic.mbt │ ├── builtin_methods.mbt │ ├── variables.mbt │ ├── list.mbt │ ├── generic.mbt │ ├── option.mbt │ ├── function.mbt │ ├── iteration.mbt │ ├── pattern_matching.mbt │ ├── literal_overloading.mbt │ ├── packages.mbt │ ├── control_flow.mbt │ └── data_structure.mbt ├── alias.mbt ├── example │ ├── main.mbt │ ├── moon.pkg.json │ └── pkg.generated.mbti ├── interpreter │ ├── moon.pkg.json │ ├── loader.mbt │ ├── parser.mbt │ ├── string_operations.mbt │ ├── json.mbt │ ├── function_context.mbt │ ├── string_builder.mbt │ ├── utils.mbt │ ├── bytes.mbt │ ├── iter2.mbt │ ├── env.mbt │ ├── record_operations.mbt │ ├── assignment_operations.mbt │ ├── int.mbt │ ├── fs.mbt │ ├── module.mbt │ ├── scope.mbt │ ├── control_flow.mbt │ ├── type_constraints.mbt │ ├── type_operations.mbt │ ├── fixedarray.mbt │ ├── functions.mbt │ ├── option.mbt │ ├── method_execution.mbt │ ├── map.mbt │ └── array_view.mbt ├── moon.pkg.json ├── export.mbt ├── pkg.generated.mbti ├── benchmark_test.mbt └── vm.mbt ├── .gitignore ├── qrcode.jpg ├── debug_test.mbt ├── moon.mod.json ├── .github └── workflows │ └── check.yaml ├── .trae └── rules │ └── project_rules.md └── generate_core_modules.py /src/test/hello/moon.pkg.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | .mooncakes/ 3 | __pycache__/ 4 | .DS_Store -------------------------------------------------------------------------------- /qrcode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/oboard/moonbit-eval/main/qrcode.jpg -------------------------------------------------------------------------------- /src/alias.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | using @interpreter {type ClosureInterpreter, type RuntimeValue} 3 | -------------------------------------------------------------------------------- /src/test/hello/hello.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub fn hello() -> String { 3 | "Hello, World!" 4 | } 5 | -------------------------------------------------------------------------------- /src/example/main.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | fn main { 3 | let result = @eval.MoonBitVM::new().eval("1 + 2") 4 | println(result) 5 | } 6 | -------------------------------------------------------------------------------- /src/test/fs.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | test "read_dir" { 3 | let vm = MoonBitVM::new() 4 | println(vm.eval("@fs.read_dir(\"./\")")) 5 | } 6 | -------------------------------------------------------------------------------- /debug_test.mbt: -------------------------------------------------------------------------------- 1 | let vm = MoonBitVM::new(); vm.eval("for idx, val in [10, 20, 30] { println(\"idx: \" + idx.to_string() + \", val: \" + val.to_string()) }") 2 | -------------------------------------------------------------------------------- /src/example/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "is-main": true, 3 | "import": [ 4 | { 5 | "path": "oboard/moonbit-eval", 6 | "alias": "eval" 7 | } 8 | ] 9 | } -------------------------------------------------------------------------------- /src/test/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "import": [ 3 | { 4 | "path": "oboard/moonbit-eval", 5 | "alias": "eval" 6 | }, 7 | "oboard/moonbit-eval/interpreter" 8 | ] 9 | } -------------------------------------------------------------------------------- /src/test/pkg.generated.mbti: -------------------------------------------------------------------------------- 1 | // Generated using `moon info`, DON'T EDIT IT 2 | package "oboard/moonbit-eval/test" 3 | 4 | // Values 5 | 6 | // Errors 7 | 8 | // Types and methods 9 | 10 | // Type aliases 11 | 12 | // Traits 13 | 14 | -------------------------------------------------------------------------------- /src/example/pkg.generated.mbti: -------------------------------------------------------------------------------- 1 | // Generated using `moon info`, DON'T EDIT IT 2 | package "oboard/moonbit-eval/example" 3 | 4 | // Values 5 | 6 | // Errors 7 | 8 | // Types and methods 9 | 10 | // Type aliases 11 | 12 | // Traits 13 | 14 | -------------------------------------------------------------------------------- /src/test/import.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | test "import" { 3 | let vm = MoonBitVM::new() 4 | vm.eval( 5 | ( 6 | #|require("hello", "./src/test/hello") 7 | ), 8 | ) 9 | |> ignore 10 | inspect(vm.eval("@hello.hello()"), content="Hello, World!") 11 | } 12 | -------------------------------------------------------------------------------- /src/test/hello/pkg.generated.mbti: -------------------------------------------------------------------------------- 1 | // Generated using `moon info`, DON'T EDIT IT 2 | package "oboard/moonbit-eval/test/hello" 3 | 4 | // Values 5 | pub fn hello() -> String 6 | 7 | // Errors 8 | 9 | // Types and methods 10 | 11 | // Type aliases 12 | 13 | // Traits 14 | 15 | -------------------------------------------------------------------------------- /src/interpreter/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "import": [ 3 | "moonbitlang/x/encoding", 4 | "moonbitlang/parser/syntax", 5 | "moonbitlang/parser/basic", 6 | "moonbitlang/parser", 7 | "moonbitlang/parser/tokens", 8 | "moonbitlang/parser/attribute", 9 | "moonbitlang/x/fs" 10 | ] 11 | } -------------------------------------------------------------------------------- /src/test/attributes.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | test "alias" { 3 | let vm = MoonBitVM::new() 4 | vm.eval( 5 | ( 6 | #|#alias(number_one) 7 | #|fn one() -> Int { 8 | #| 1 9 | #|} 10 | ), 11 | top=true, 12 | ) 13 | |> ignore 14 | inspect(vm.eval("one()"), content="1") 15 | inspect(vm.eval("number_one()"), content="1") 16 | } 17 | -------------------------------------------------------------------------------- /src/test/alias.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | using @eval {type MoonBitVM} 3 | 4 | ///| 5 | test "function_alias" { 6 | let vm = MoonBitVM::new() 7 | // 测试函数别名定义和使用 8 | vm.eval( 9 | ( 10 | #|fnalias @int.abs 11 | ), 12 | top=true, 13 | ) 14 | |> ignore 15 | inspect(vm.eval("abs"), content="(Int) -> Int") 16 | inspect(vm.eval("abs(-5)"), content="5") 17 | } 18 | -------------------------------------------------------------------------------- /src/test/comparision.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | test "comparison_operators" { 3 | let vm = MoonBitVM::new() 4 | inspect(vm.eval("5 == 5"), content="true") 5 | inspect(vm.eval("5 != 3"), content="true") 6 | inspect(vm.eval("3 < 5"), content="true") 7 | inspect(vm.eval("5 > 3"), content="true") 8 | inspect(vm.eval("3 <= 5"), content="true") 9 | inspect(vm.eval("5 >= 3"), content="true") 10 | } 11 | -------------------------------------------------------------------------------- /moon.mod.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "oboard/moonbit-eval", 3 | "version": "0.8.16", 4 | "deps": { 5 | "moonbitlang/parser": "0.1.12", 6 | "moonbitlang/x": "0.4.37" 7 | }, 8 | "readme": "README.md", 9 | "repository": "https://github.com/oboard/moonbit-eval", 10 | "license": "Apache-2.0", 11 | "keywords": [ 12 | "moonbit", 13 | "eval" 14 | ], 15 | "description": "MoonBit Eval Package", 16 | "source": "src" 17 | } -------------------------------------------------------------------------------- /src/test/trait.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | test { 3 | let vm = MoonBitVM::new() 4 | vm.eval( 5 | ( 6 | #|struct A { 7 | #| a: Int 8 | #|} 9 | #|impl Show for A with to_string(self : A) -> String { 10 | #| "A:\{self.a}" 11 | #|} 12 | ), 13 | top=true, 14 | ) 15 | |> ignore 16 | assert_eq(vm.eval("let a = {a: 1};a").to_string(), "A::{a: 1}") 17 | assert_eq(vm.eval("a.to_string()").to_string(), "A:1") 18 | } 19 | -------------------------------------------------------------------------------- /src/test/string_builder.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | test { 3 | let vm = MoonBitVM::new() 4 | assert_eq( 5 | vm 6 | .eval( 7 | ( 8 | #|let result = StringBuilder::new() 9 | #| ..write_char('a') 10 | #| ..write_object(1001) 11 | #| ..write_string("abcdef") 12 | #| .to_string() 13 | ), 14 | ) 15 | .to_string(), 16 | "()", 17 | ) 18 | assert_eq(vm.eval("result").to_string(), "a1001abcdef") 19 | } 20 | -------------------------------------------------------------------------------- /src/moon.pkg.json: -------------------------------------------------------------------------------- 1 | { 2 | "import": [ 3 | "moonbitlang/parser", 4 | "moonbitlang/parser/syntax", 5 | "oboard/moonbit-eval/interpreter" 6 | ], 7 | "link": { 8 | "js": { 9 | "exports": [ 10 | "create", 11 | "eval", 12 | "eval_result_to_string", 13 | "code_to_ast", 14 | "add_extern_fn", 15 | "add_embedded_fn", 16 | "add_embedded_method", 17 | "value_to_json", 18 | "value_to_string" 19 | ] 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/test/sort.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | test "sort" { 3 | let vm = MoonBitVM::new() 4 | let unsorted = @list.from_array([3, 1, 4, 1, 5, 9, 2, 6]) 5 | inspect(unsorted.sort().to_array(), content="[1, 1, 2, 3, 4, 5, 6, 9]") 6 | // Test list sorting 7 | assert_eq( 8 | vm 9 | .eval("let unsorted = @list.from_array([3, 1, 4, 1, 5, 9, 2, 6])") 10 | .to_string(), 11 | "()", 12 | ) 13 | assert_eq( 14 | vm.eval("unsorted.sort().to_array()").to_string(), 15 | "[1, 1, 2, 3, 4, 5, 6, 9]", 16 | ) 17 | } 18 | -------------------------------------------------------------------------------- /src/interpreter/loader.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub fn load_package_dir(pkg_name : String, path : String) -> RuntimePackage? { 3 | try { 4 | let entries = @fs.read_dir(path) 5 | let _ = @fs.read_file_to_string([path, "moon.pkg.json"].join("/")) 6 | let deps = {} 7 | let files : Map[String, String] = {} 8 | for entry in entries { 9 | let file_path = [path, entry].join("/") 10 | if @fs.is_file(file_path) { 11 | files.set(entry, @fs.read_file_to_string(file_path)) 12 | } 13 | } 14 | Some(RuntimePackage::new(pkg_name, deps~, files~)) 15 | } catch { 16 | _ => None 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/constructors.mbt: -------------------------------------------------------------------------------- 1 | // ============================================================================= 2 | // CONSTRUCTOR AND ADVANCED PATTERN TESTS 3 | // ============================================================================= 4 | // Tests for constructor patterns and advanced pattern matching scenarios 5 | 6 | ///| 7 | test "constructor_single_argument_any_match" { 8 | let vm = MoonBitVM::new() 9 | assert_eq( 10 | vm.eval("let l = @list.from_array([1, 2]); l").to_string(), 11 | "More(1, tail=More(2, tail=Empty))", 12 | ) 13 | assert_eq( 14 | vm 15 | .eval( 16 | ( 17 | #|match l { 18 | #| More(_, tail~) => tail 19 | #| Empty => "empty" 20 | #|} 21 | #| 22 | ), 23 | ) 24 | .to_string(), 25 | "More(2, tail=Empty)", 26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /src/test/eval.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | test "eval" { 3 | let vm = MoonBitVM::new() 4 | let result = vm.eval("eval(\"1 + 2\")") 5 | inspect(result, content="3") 6 | } 7 | 8 | ///| 9 | test "eval eval" { 10 | let vm = MoonBitVM::new() 11 | let result = vm.eval("eval(\"eval(\\\"1 + 2\\\")\")") 12 | inspect(result, content="3") 13 | } 14 | 15 | ///| 16 | test "typeof eval" { 17 | let vm = MoonBitVM::new() 18 | inspect( 19 | vm.eval( 20 | ( 21 | #|typeof(eval("(1+2).to_string()")) 22 | ), 23 | ), 24 | content="@moonbitlang/core/string.String", 25 | ) 26 | inspect( 27 | vm.eval( 28 | ( 29 | #|typeof(eval("1+2")) 30 | ), 31 | ), 32 | content="@moonbitlang/core/int.Int", 33 | ) 34 | inspect( 35 | vm.eval( 36 | ( 37 | #|eval("1+2") is 3 38 | ), 39 | ), 40 | content="true", 41 | ) 42 | } 43 | -------------------------------------------------------------------------------- /src/test/io_ffi.mbt: -------------------------------------------------------------------------------- 1 | // ============================================================================= 2 | // IO AND FFI TESTS 3 | // ============================================================================= 4 | // Tests for input/output operations and foreign function interface 5 | 6 | ///| 7 | test "println" { 8 | let vm = MoonBitVM::new() 9 | inspect(vm.eval("println(\"hello\")"), content="()") 10 | } 11 | 12 | ///| 13 | test "embedded_code" { 14 | let vm = MoonBitVM::new() 15 | vm.interpreter.add_embedded_fn("%string_length2", ctx => if ctx.args 16 | is [{ val: String(s), .. }] { 17 | Int(s.length(), raw=None) 18 | } else { 19 | Unit 20 | }) 21 | inspect( 22 | vm.eval( 23 | "pub fn String::length2(self : String) -> Int = \"%string_length2\"", 24 | ), 25 | content="()", 26 | ) 27 | inspect(vm.eval("\"hello\".length2()"), content="5") 28 | } 29 | -------------------------------------------------------------------------------- /src/test/exception.mbt: -------------------------------------------------------------------------------- 1 | // ============================================================================= 2 | // Exception Handling Tests 3 | // ============================================================================= 4 | // Tests for try-catch expressions and exception handling 5 | 6 | ///| 7 | test "try_catch_expressions" { 8 | let vm = MoonBitVM::new() 9 | // Test try-catch expressions 10 | assert_eq( 11 | vm 12 | .eval( 13 | ( 14 | #|try { 15 | #| let x = 10 / 2 16 | #| x 17 | #|} catch { 18 | #| e => -1 19 | #|} 20 | ), 21 | ) 22 | .to_string(), 23 | "5", 24 | ) 25 | assert_eq( 26 | vm 27 | .eval( 28 | ( 29 | #|try { 30 | #| raise "error" 31 | #| 42 32 | #|} catch { 33 | #| e => 0 34 | #|} 35 | ), 36 | ) 37 | .to_string(), 38 | "0", 39 | ) 40 | } 41 | -------------------------------------------------------------------------------- /src/interpreter/parser.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub fn parse_code_to_expr(code : String) -> Result[@syntax.Expr, String] { 3 | let (impls, diagnostics) = @moonbitlang/parser.parse_string( 4 | "fn init{\n \{code}\n}", 5 | parser=Handrolled, 6 | ) 7 | match impls { 8 | @list.List::More( 9 | @syntax.Impl::TopFuncDef(fun_decl=_, decl_body~, loc=_), 10 | tail=@list.List::Empty 11 | ) => 12 | match decl_body { 13 | @syntax.DeclBody::DeclBody(local_types=_, expr~) => Ok(expr) 14 | _ => Err("Invalid function declaration body") 15 | } 16 | _ => Err(diagnostics.fold(init="", (acc, cur) => "\{acc}\n\{cur}")) 17 | } 18 | } 19 | 20 | ///| 21 | pub fn parse_code_to_impl(code : String) -> Result[@syntax.Impl, String] { 22 | let (impls, diagnostics) = @moonbitlang/parser.parse_string( 23 | code, 24 | parser=Handrolled, 25 | ) 26 | match impls { 27 | @list.List::More(top, tail=@list.List::Empty) => Ok(top) 28 | _ => Err(diagnostics.fold(init="", (acc, cur) => "\{acc}\n\{cur}")) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/test/json.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | test "json_value" { 3 | let vm = MoonBitVM::new() 4 | let _ = vm.eval("let simple_json : Json = 42") 5 | assert_eq( 6 | vm.eval("typeof(simple_json)").to_string(), 7 | "@moonbitlang/core/builtin.Json", 8 | ) 9 | } 10 | 11 | ///| 12 | test "json_array" { 13 | let vm = MoonBitVM::new() 14 | vm.eval("let json_array : Json = [1, 2, 3]") |> ignore 15 | inspect( 16 | vm.eval("json_array"), 17 | content="Array([Number(1), Number(2), Number(3)])", 18 | ) 19 | assert_eq( 20 | vm.eval("typeof(json_array)").to_string(), 21 | "@moonbitlang/core/builtin.Json", 22 | ) 23 | } 24 | 25 | ///| 26 | test "json_type" { 27 | let vm = MoonBitVM::new() 28 | vm.eval("let json : Json = { \"a\": [\"1\", \"2\"], \"b\": [\"3\", \"4\"] }") 29 | |> ignore 30 | assert_eq( 31 | vm.eval("typeof(json)").to_string(), 32 | "@moonbitlang/core/builtin.Json", 33 | ) 34 | assert_eq( 35 | vm.eval("json").to_string(), 36 | ( 37 | #|Object({"a": Array([String("1"), String("2")]), "b": Array([String("3"), String("4")])}) 38 | ), 39 | ) 40 | } 41 | -------------------------------------------------------------------------------- /src/test/arithmetic.mbt: -------------------------------------------------------------------------------- 1 | // ============================================================================= 2 | // 2. ARITHMETIC AND COMPARISON OPERATORS 3 | // ============================================================================= 4 | 5 | ///| 6 | test "arithmetic_operators" { 7 | let vm = MoonBitVM::new() 8 | inspect(vm.eval("1+1"), content="2") 9 | inspect(vm.eval("2-1"), content="1") 10 | inspect(vm.eval("5 * 3"), content="15") 11 | inspect(vm.eval("10 / 2"), content="5") 12 | inspect(vm.eval("7 % 3"), content="1") 13 | } 14 | 15 | ///| 16 | test "math" { 17 | let vm = MoonBitVM::new() 18 | inspect(vm.eval("@math.PI"), content="3.141592653589793") 19 | } 20 | 21 | ///| 22 | test { 23 | let vm = MoonBitVM::new() 24 | inspect(vm.eval("pub const PI = 3.14", top=true), content="3.14") 25 | inspect(vm.eval("PI"), content="3.14") 26 | } 27 | 28 | ///| 29 | test "group_expressions" { 30 | let vm = MoonBitVM::new() 31 | // Test grouped expressions with parentheses 32 | assert_eq(vm.eval("(2 + 3) * (4 + 1)").to_string(), "25") 33 | assert_eq(vm.eval("((1 + 2) * 3) + (4 * (5 + 6))").to_string(), "53") 34 | } 35 | -------------------------------------------------------------------------------- /src/test/syntax.mbt: -------------------------------------------------------------------------------- 1 | // ============================================================================= 2 | // SYNTAX FEATURES TESTS 3 | // ============================================================================= 4 | // Tests for language syntax features like pipe operator and grouping 5 | 6 | ///| 7 | test "pipe_operator" { 8 | let vm = MoonBitVM::new() 9 | inspect(vm.eval("5 |> ignore"), content="()") 10 | inspect(vm.eval("[] |> Array::push(5)"), content="[5]") 11 | inspect( 12 | vm.eval("fn add(x: Int, y: Int) -> Int { x + y }\n1 |> add(5)"), 13 | content="6", 14 | ) 15 | } 16 | 17 | ///| 18 | test "group_expressions" { 19 | let vm = MoonBitVM::new() 20 | // Test grouped expressions with parentheses 21 | assert_eq(vm.eval("(2 + 3) * (4 + 1)").to_string(), "25") 22 | assert_eq(vm.eval("((1 + 2) * 3) + (4 * (5 + 6))").to_string(), "53") 23 | } 24 | 25 | ///| 26 | test "lambda_arrays" { 27 | let a = [x => x + 1, x => x - 1] 28 | inspect(a[1](10), content="9") 29 | } 30 | 31 | ///| 32 | test "lambda_arrays_vm" { 33 | let vm = MoonBitVM::new() 34 | inspect(vm.eval("let a = [x => x + 1, x => x - 1]; a[1](10)"), content="9") 35 | } 36 | -------------------------------------------------------------------------------- /src/test/map.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | test "map_expressions" { 3 | let vm = MoonBitVM::new() 4 | // Test map literal expressions 5 | assert_eq( 6 | vm 7 | .eval( 8 | ( 9 | #|let m = { "a": 1, "b": 2, "c": 3 } 10 | #|m["b"] 11 | ), 12 | ) 13 | .to_string(), 14 | "2", 15 | ) 16 | } 17 | 18 | ///| 19 | test "map_operations" { 20 | let vm = MoonBitVM::new() 21 | // Test simple Map::of creation first 22 | inspect(vm.eval("Map::of([])"), content="{}") 23 | 24 | // Test map literal creation 25 | inspect( 26 | vm.eval("let map1 = { \"key1\": 1, \"key2\": 2, \"key3\": 3 }"), 27 | content="()", 28 | ) 29 | inspect(vm.eval("map1"), content="{\"key1\": 1, \"key2\": 2, \"key3\": 3}") 30 | // Test map length 31 | 32 | // Test map access 33 | inspect(vm.eval("map1[\"key1\"]"), content="1") 34 | 35 | // Test Map::of creation 36 | inspect( 37 | vm.eval("let map2 = Map::of([(\"key1\", 1), (\"key2\", 2), (\"key3\", 3)])"), 38 | content="()", 39 | ) 40 | // inspect(vm.eval("map1 == map2"), content="true") 41 | 42 | // Test map update 43 | inspect(vm.eval("map1[\"key1\"] = 10"), content="()") 44 | inspect(vm.eval("map1"), content="{\"key1\": 10, \"key2\": 2, \"key3\": 3}") 45 | } 46 | -------------------------------------------------------------------------------- /src/test/functional.mbt: -------------------------------------------------------------------------------- 1 | // ============================================================================= 2 | // FUNCTIONAL PROGRAMMING TESTS 3 | // ============================================================================= 4 | // Tests for functional programming features like currying and higher-order functions 5 | 6 | ///| 7 | test "currying" { 8 | let vm = MoonBitVM::new() 9 | assert_eq(vm.eval("let add = x => y => x + y").to_string(), "()") 10 | assert_eq(vm.eval("let f = add(10)").to_string(), "()") 11 | assert_eq(vm.eval("f").to_string(), "(Any) -> Any") 12 | assert_eq(vm.eval("f(1)").to_string(), "11") 13 | assert_eq(vm.eval("add(5)(3)").to_string(), "8") 14 | } 15 | 16 | // Lambda array tests moved to syntax.mbt 17 | 18 | ///| 19 | test "closure_environment" { 20 | let vm = MoonBitVM::new() 21 | inspect( 22 | vm.eval( 23 | ( 24 | #|let mut x = 0 25 | #|fn f1() { x += 1; x } 26 | #|let mut x = 0 27 | #|fn f2() { x += 1; x } 28 | ), 29 | ), 30 | content="() -> Any", 31 | ) 32 | assert_eq(vm.eval("f1()").to_string(), "1") 33 | assert_eq(vm.eval("f1()").to_string(), "2") 34 | assert_eq(vm.eval("f2()").to_string(), "1") 35 | assert_eq(vm.eval("f2()").to_string(), "2") 36 | } 37 | -------------------------------------------------------------------------------- /src/export.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub fn value_to_json(value : RuntimeValue) -> String { 3 | value.to_json().stringify() 4 | } 5 | 6 | ///| 7 | pub fn value_to_string(value : RuntimeValue) -> String { 8 | value.to_string() 9 | } 10 | 11 | ///| 12 | pub fn MoonBitVM::create(log? : Bool = false) -> MoonBitVM { 13 | MoonBitVM::new(log~) 14 | } 15 | 16 | ///| 17 | pub fn eval_result_to_string(result : EvalResult) -> String { 18 | match result { 19 | Success(value, _) => value.to_string() 20 | Error(msg, _) => "Error: " + msg 21 | } 22 | } 23 | 24 | ///| 25 | pub fn code_to_ast(code : String) -> String { 26 | match @interpreter.parse_code_to_impl(code) { 27 | Ok(i) => i.to_json().stringify() 28 | Err(msg) => msg 29 | } 30 | } 31 | 32 | ///| 33 | pub fn add_extern_fn( 34 | vm : MoonBitVM, 35 | name : String, 36 | func : @interpreter.RuntimeFunction, 37 | ) -> Unit { 38 | vm.interpreter.add_extern_fn(name, func) 39 | } 40 | 41 | ///| 42 | pub fn add_embedded_fn( 43 | vm : MoonBitVM, 44 | name : String, 45 | func : @interpreter.RuntimeFunction, 46 | ) -> Unit { 47 | vm.interpreter.add_embedded_fn(name, func) 48 | } 49 | 50 | ///| 51 | pub fn add_embedded_method( 52 | vm : MoonBitVM, 53 | name : String, 54 | method_name : String, 55 | func : @interpreter.RuntimeFunction, 56 | ) -> Unit { 57 | vm.interpreter.add_embedded_method(name, method_name, func) 58 | } 59 | -------------------------------------------------------------------------------- /src/test/array.mbt: -------------------------------------------------------------------------------- 1 | // ============================================================================= 2 | // ARRAY METHODS TESTS 3 | // ============================================================================= 4 | 5 | ///| 6 | test "array_basic_methods" { 7 | let vm = MoonBitVM::new() 8 | // Test array creation and basic methods 9 | inspect(vm.eval("let arr = [1, 2, 3]; arr.length()"), content="3") 10 | inspect(vm.eval("let arr = []; arr.is_empty()"), content="true") 11 | inspect(vm.eval("let arr = [1]; arr.is_empty()"), content="false") 12 | } 13 | 14 | ///| 15 | test "array_get_set_methods" { 16 | let vm = MoonBitVM::new() 17 | // Test get method 18 | inspect(vm.eval("let arr = [1, 2, 3]; arr.get(1)"), content="Some(2)") 19 | inspect(vm.eval("let arr = [1, 2, 3]; arr.get(5)"), content="None") 20 | } 21 | 22 | ///| 23 | test "array_push_pop_methods" { 24 | let vm = MoonBitVM::new() 25 | // Test push and pop 26 | inspect(vm.eval("let arr = [1, 2]; arr.push(3); arr.length()"), content="3") 27 | inspect(vm.eval("let arr = [1, 2, 3]; arr.pop()"), content="Some(3)") 28 | inspect(vm.eval("let arr = []; arr.pop()"), content="None") 29 | } 30 | 31 | ///| 32 | test "array_contains_methods" { 33 | let vm = MoonBitVM::new() 34 | // Test contains method 35 | inspect(vm.eval("let arr = [1, 2, 3]; arr.contains(2)"), content="true") 36 | inspect(vm.eval("let arr = [1, 2, 3]; arr.contains(5)"), content="false") 37 | } 38 | -------------------------------------------------------------------------------- /src/interpreter/string_operations.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | /// 字符串操作模块 - 处理字符串插值和多行字符串 3 | 4 | ///| 5 | /// 处理字符串插值 6 | pub fn ClosureInterpreter::interp_string( 7 | self : ClosureInterpreter, 8 | elems : @list.List[@syntax.InterpElem], 9 | ) -> String raise ControlFlow { 10 | let buffer = @buffer.new() 11 | for elem in elems { 12 | match elem { 13 | Expr(expr~, ..) => buffer.write_string(self.visit(expr).to_string()) 14 | Literal(repr~, ..) => buffer.write_string(repr) 15 | Source({ source, .. }) => 16 | match parse_code_to_expr(source) { 17 | Ok(expr) => buffer.write_string(self.visit(expr).to_string()) 18 | Err(msg) => self.error(msg) 19 | } 20 | } 21 | } 22 | buffer.to_string() 23 | } 24 | 25 | ///| 26 | /// 处理多行字符串 27 | pub fn ClosureInterpreter::visit_multiline_string( 28 | self : ClosureInterpreter, 29 | elems : @list.List[@syntax.MultilineStringElem], 30 | ) -> RuntimeValue raise ControlFlow { 31 | let buf = @buffer.new() 32 | elems.eachi(fn(i, elem) { 33 | match elem { 34 | String(str) => buf.write_string(str) 35 | Interp(elems) => buf.write_string(self.interp_string(elems)) 36 | } 37 | if i < elems.length() - 1 { 38 | buf.write_string("\n") 39 | } 40 | }) 41 | String(buf.to_string()) 42 | } 43 | 44 | ///| 45 | /// 处理字符串插值表达式 (Interp) 46 | pub fn ClosureInterpreter::visit_interp( 47 | self : ClosureInterpreter, 48 | elems : @list.List[@syntax.InterpElem], 49 | ) -> RuntimeValue raise ControlFlow { 50 | String(self.interp_string(elems)) 51 | } 52 | -------------------------------------------------------------------------------- /src/pkg.generated.mbti: -------------------------------------------------------------------------------- 1 | // Generated using `moon info`, DON'T EDIT IT 2 | package "oboard/moonbit-eval" 3 | 4 | import( 5 | "moonbitlang/parser/syntax" 6 | "oboard/moonbit-eval/interpreter" 7 | ) 8 | 9 | // Values 10 | pub fn add_embedded_fn(MoonBitVM, String, (@interpreter.RuntimeFunctionContext) -> @interpreter.RuntimeValue raise @interpreter.ControlFlow) -> Unit 11 | 12 | pub fn add_embedded_method(MoonBitVM, String, String, (@interpreter.RuntimeFunctionContext) -> @interpreter.RuntimeValue raise @interpreter.ControlFlow) -> Unit 13 | 14 | pub fn add_extern_fn(MoonBitVM, String, (@interpreter.RuntimeFunctionContext) -> @interpreter.RuntimeValue raise @interpreter.ControlFlow) -> Unit 15 | 16 | pub fn code_to_ast(String) -> String 17 | 18 | pub fn eval_result_to_string(EvalResult) -> String 19 | 20 | pub fn expr_to_string(@syntax.Expr) -> String 21 | 22 | pub fn value_to_json(@interpreter.RuntimeValue) -> String 23 | 24 | pub fn value_to_string(@interpreter.RuntimeValue) -> String 25 | 26 | // Errors 27 | 28 | // Types and methods 29 | pub enum EvalResult { 30 | Success(@interpreter.RuntimeValue, @interpreter.ClosureInterpreter) 31 | Error(String, @interpreter.ClosureInterpreter) 32 | } 33 | pub impl Show for EvalResult 34 | 35 | pub(all) struct MoonBitVM { 36 | interpreter : @interpreter.ClosureInterpreter 37 | log : Bool 38 | } 39 | pub fn MoonBitVM::create(log? : Bool) -> Self 40 | pub fn MoonBitVM::eval(Self, String, log? : Bool, top? : Bool) -> EvalResult 41 | pub fn MoonBitVM::new(log? : Bool) -> Self 42 | 43 | // Type aliases 44 | 45 | // Traits 46 | 47 | -------------------------------------------------------------------------------- /src/interpreter/json.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | let json_methods : Map[String, RuntimeFunction] = { 3 | "stringify": json_stringify_fn, 4 | "array": json_array_fn, 5 | "boolean": json_boolean_fn, 6 | "null": json_null_fn, 7 | "number": json_number_fn, 8 | "object": json_object_fn, 9 | "string": json_string_fn, 10 | } 11 | 12 | ///| 13 | let json_stringify_fn : RuntimeFunction = ctx => match ctx.args { 14 | [{ val: Json(value), .. }] => String(value.stringify()) 15 | _ => Unit 16 | } 17 | 18 | ///| 19 | let json_array_fn : RuntimeFunction = ctx => match ctx.args { 20 | [{ val: Array(value), .. }] => 21 | Json(Json::array(value.map(i => if i is Json(i) { i } else { panic() }))) 22 | _ => Unit 23 | } 24 | 25 | ///| 26 | let json_boolean_fn : RuntimeFunction = ctx => match ctx.args { 27 | [{ val: Bool(value), .. }] => Json(Json::boolean(value)) 28 | _ => Unit 29 | } 30 | 31 | ///| 32 | let json_null_fn : RuntimeFunction = _ctx => Json(Json::null()) 33 | 34 | ///| 35 | let json_number_fn : RuntimeFunction = ctx => match ctx.args { 36 | [{ val: Double(value), .. }] => Json(Json::number(value)) 37 | _ => Unit 38 | } 39 | 40 | ///| 41 | let json_object_fn : RuntimeFunction = ctx => match ctx.args { 42 | [{ val: Map(value), .. }] => 43 | Json( 44 | Json::object( 45 | value 46 | .to_array() 47 | .map(i => if i is (String(key), Json(json)) { 48 | (key, json) 49 | } else { 50 | panic() 51 | }) 52 | |> Map::from_array, 53 | ), 54 | ) 55 | _ => Unit 56 | } 57 | 58 | ///| 59 | let json_string_fn : RuntimeFunction = ctx => match ctx.args { 60 | [{ val: String(value), .. }] => Json(Json::string(value)) 61 | _ => Unit 62 | } 63 | -------------------------------------------------------------------------------- /.github/workflows/check.yaml: -------------------------------------------------------------------------------- 1 | name: check 2 | 3 | on: 4 | schedule: 5 | # Runs at 02:30, only on Friday. 6 | # https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#schedule 7 | - cron: "30 2 * * 5" 8 | workflow_dispatch: 9 | push: 10 | branches: 11 | - master 12 | - main 13 | 14 | pull_request: 15 | 16 | jobs: 17 | check: 18 | strategy: 19 | matrix: 20 | version: [stable,pre-release] 21 | os: 22 | - name: ubuntu-latest 23 | triple: x86_64-linux-gnu 24 | 25 | # stable check 26 | 27 | # pre-release check 28 | 29 | fail-fast: false 30 | runs-on: ${{ matrix.os.name }} 31 | continue-on-error: false 32 | steps: 33 | - uses: actions/checkout@v4 34 | with: 35 | fetch-depth: 1 36 | 37 | - name: Setup Moon 38 | uses: illusory0x0/setup-moonbit@v0.1.0 39 | with: 40 | version: ${{ matrix.version }} 41 | 42 | - name: moon version 43 | run: | 44 | moon version --all 45 | 46 | - name: install module dependencies 47 | run: | 48 | moon update 49 | moon install 50 | 51 | - name: moon check 52 | run: moon check --deny-warn --target js 53 | 54 | - name: moon info 55 | run: | 56 | moon info --target js 57 | git diff --exit-code 58 | 59 | - name: format diff 60 | run: | 61 | moon fmt 62 | git diff --exit-code 63 | 64 | - name: Setup MSVC 65 | if: ${{ matrix.os.name == 'windows-latest' }} 66 | uses: ilammy/msvc-dev-cmd@v1 67 | 68 | - name: Set ulimit on unix 69 | if: ${{ matrix.os.name != 'windows-latest' }} 70 | run: | 71 | ulimit -s 8176 72 | 73 | - name: moon test 74 | run: | 75 | moon test --target js 76 | moon test --target js -------------------------------------------------------------------------------- /src/test/enum.mbt: -------------------------------------------------------------------------------- 1 | // Enum-related test cases 2 | 3 | ///| 4 | test "basic_enum" { 5 | let vm = MoonBitVM::new() 6 | inspect( 7 | vm.eval( 8 | ( 9 | #|enum Relation { 10 | #| Smaller 11 | #| Greater 12 | #| Equal 13 | #|} 14 | #|fn compare_int(x: Int, y: Int) -> Relation { 15 | #| if x < y { 16 | #| Smaller 17 | #| } else if x > y { 18 | #| Relation::Greater 19 | #| } else { 20 | #| Equal 21 | #| } 22 | #|} 23 | ), 24 | top=true, 25 | ), 26 | content="()", 27 | ) 28 | inspect(vm.eval("compare_int(0, 1)"), content="Smaller") 29 | inspect(vm.eval("compare_int(1, 1)"), content="Equal") 30 | inspect(vm.eval("compare_int(2, 1)"), content="Greater") 31 | } 32 | 33 | ///| 34 | test "enum_with_data" { 35 | let vm = MoonBitVM::new() 36 | inspect( 37 | vm.eval( 38 | ( 39 | #|enum List { 40 | #| Nil 41 | #| Cons(Int, List) 42 | #|} 43 | #|fn is_singleton(l: List) -> Bool { 44 | #| match l { 45 | #| Cons(_, Nil) => true 46 | #| _ => false 47 | #| } 48 | #|} 49 | ), 50 | top=true, 51 | ), 52 | content="()", 53 | ) 54 | inspect(vm.eval("let l = Cons(1, Cons(2, Nil))"), content="()") 55 | inspect(vm.eval("is_singleton(l)"), content="false") 56 | inspect(vm.eval("is_singleton(Cons(1, Nil))"), content="true") 57 | inspect(vm.eval("is_singleton(Nil)"), content="false") 58 | } 59 | 60 | ///| 61 | test "enum_pattern_matching" { 62 | let vm = MoonBitVM::new() 63 | inspect( 64 | vm.eval( 65 | ( 66 | #|enum Maybe { 67 | #| Just(Int) 68 | #| Nothing 69 | #|} 70 | #|fn get_or_default(m: Maybe, default: Int) -> Int { 71 | #| match m { 72 | #| Just(x) => x 73 | #| Nothing => default 74 | #| } 75 | #|} 76 | ), 77 | top=true, 78 | ), 79 | content="()", 80 | ) 81 | inspect(vm.eval("get_or_default(Just(5), 0)"), content="5") 82 | inspect(vm.eval("get_or_default(Nothing, 0)"), content="0") 83 | } 84 | -------------------------------------------------------------------------------- /src/test/basic.mbt: -------------------------------------------------------------------------------- 1 | // ============================================================================= 2 | // 1. BASIC TYPES AND LITERALS 3 | // ============================================================================= 4 | 5 | ///| 6 | test "basic_integers" { 7 | let vm = MoonBitVM::new() 8 | inspect(vm.eval("1"), content="1") 9 | inspect(vm.eval("42"), content="42") 10 | inspect(vm.eval("-5"), content="-5") 11 | } 12 | 13 | ///| 14 | test "basic_booleans" { 15 | let vm = MoonBitVM::new() 16 | inspect(vm.eval("true"), content="true") 17 | inspect(vm.eval("false"), content="false") 18 | inspect(vm.eval("!false"), content="true") 19 | inspect(vm.eval("!true"), content="false") 20 | inspect(vm.eval("not(false)"), content="true") 21 | inspect(vm.eval("not(true)"), content="false") 22 | } 23 | 24 | ///| 25 | test "basic_strings" { 26 | let vm = MoonBitVM::new() 27 | inspect(vm.eval("\"hello\""), content="hello") 28 | inspect(vm.eval("\"hello\"+\"world\""), content="helloworld") 29 | } 30 | 31 | ///| 32 | test "escape_strings" { 33 | let vm = MoonBitVM::new() 34 | inspect(vm.eval("\"hello\\nworld\""), content="hello\nworld") 35 | inspect(vm.eval("\"hello\\tworld\""), content="hello\tworld") 36 | inspect(vm.eval("\"hello\\u0042world\""), content="helloBworld") 37 | inspect(vm.eval("\'\\n\'"), content="\n") 38 | } 39 | 40 | ///| 41 | test "multiline_strings" { 42 | let vm = MoonBitVM::new() 43 | // Test multiline string syntax 44 | assert_eq(vm.eval("#|hello\n#|world").to_string(), "hello\nworld") 45 | assert_eq( 46 | vm.eval("#|line1\n#|line2\n#|line3").to_string(), 47 | "line1\nline2\nline3", 48 | ) 49 | assert_eq(vm.eval("#|single line").to_string(), "single line") 50 | } 51 | 52 | ///| 53 | test "string_interpolation" { 54 | let vm = MoonBitVM::new() 55 | // Test string interpolation 56 | assert_eq( 57 | vm.eval("let x = 42; \"The answer is \\{x}\"").to_string(), 58 | "The answer is 42", 59 | ) 60 | assert_eq( 61 | vm.eval("let name = \"World\"; \"Hello, \\{name}!\"").to_string(), 62 | "Hello, World!", 63 | ) 64 | assert_eq( 65 | vm.eval("let a = 5; let b = 3; \"\\{a} + \\{b} = \\{a + b}\"").to_string(), 66 | "5 + 3 = 8", 67 | ) 68 | } 69 | -------------------------------------------------------------------------------- /src/interpreter/function_context.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | /// Runtime函数执行上下文 - 统一所有函数的执行环境 3 | pub(all) struct RuntimeFunctionContext { 4 | context : ClosureInterpreter 5 | pkg : RuntimePackage 6 | args : FixedArray[RuntimeArgument] 7 | } 8 | 9 | ///| 10 | /// 新的函数类型定义 - 统一的上下文访问 11 | pub type RuntimeFunction = (RuntimeFunctionContext) -> RuntimeValue raise ControlFlow 12 | 13 | ///| 14 | pub fn ClosureInterpreter::create_function( 15 | self : ClosureInterpreter, 16 | func : @syntax.Func, 17 | pkg : RuntimePackage, 18 | name? : String, 19 | ) -> WithType[RuntimeFunction] { 20 | let closure_env = pkg.env.create_closure_env() 21 | { 22 | val: ctx => match func { 23 | @syntax.Func::Lambda(parameters~, body~, return_type~, ..) => { 24 | // 切换到闭包捕获的环境 25 | let old_mod = self.current_pkg 26 | let old_env = pkg.env 27 | self.current_pkg = pkg 28 | self.current_pkg.env = closure_env 29 | self.push_scope( 30 | RuntimeLocation::FunctionCall( 31 | "@" + 32 | pkg.name + 33 | "." + 34 | name.unwrap_or("") + 35 | self.get_function_type_string(func), 36 | ), 37 | ) 38 | // 在新环境中绑定已解释的参数值 39 | self.bind_runtime_parameters(parameters, @list.from_array(ctx.args)) 40 | defer { 41 | self.pop_scope() 42 | self.current_pkg.env = old_env 43 | self.current_pkg = old_mod 44 | } 45 | // 执行函数体 46 | let result = self.visit(body) 47 | match (result.get_type(), result, return_type) { 48 | (Any, Object({ val, .. }), Some(Arrow(res~, ..))) => 49 | Object({ val, ty: self.parse_type(res) }) 50 | _ => result 51 | } 52 | } 53 | _ => self.error("invalid function") 54 | }, 55 | ty: self.parse_function_type(func), 56 | } 57 | } 58 | 59 | ///| 60 | pub fn RuntimeFunctionContext::named( 61 | ctx : RuntimeFunctionContext, 62 | name : String, 63 | ) -> RuntimeValue? { 64 | for arg in ctx.args { 65 | match arg.kind { 66 | Labelled(arg_name) | LabelledOption(arg_name) => 67 | if arg_name == name { 68 | return Some(arg.val) 69 | } 70 | _ => continue 71 | } 72 | } 73 | None 74 | } 75 | -------------------------------------------------------------------------------- /src/test/builtin_methods.mbt: -------------------------------------------------------------------------------- 1 | // ============================================================================= 2 | // BUILT-IN METHODS TESTS 3 | // ============================================================================= 4 | 5 | ///| 6 | test "string_methods" { 7 | let vm = MoonBitVM::new() 8 | inspect(vm.eval("let s = \"hello\""), content="()") 9 | inspect(vm.eval("s.length()"), content="5") 10 | inspect(vm.eval("s.code_unit_at(0)"), content="104") 11 | inspect(vm.eval("s.to_string()"), content="hello") 12 | } 13 | 14 | ///| 15 | test "bool_methods" { 16 | let vm = MoonBitVM::new() 17 | inspect(vm.eval("true.compare(false)"), content="1") 18 | inspect(vm.eval("false.compare(true)"), content="-1") 19 | inspect(vm.eval("true.compare(true)"), content="0") 20 | inspect(vm.eval("Bool::default()"), content="false") 21 | } 22 | 23 | ///| 24 | test "int_methods" { 25 | let vm = MoonBitVM::new() 26 | inspect(vm.eval("(5).lnot()"), content="-6") 27 | inspect(vm.eval("(5).land(3)"), content="1") 28 | inspect(vm.eval("(5).lor(3)"), content="7") 29 | inspect(vm.eval("(5).lxor(3)"), content="6") 30 | inspect(vm.eval("(5).shl(2)"), content="20") 31 | inspect(vm.eval("(20).shr(2)"), content="5") 32 | inspect(vm.eval("(5).compare(3)"), content="1") 33 | inspect(vm.eval("(3).compare(5)"), content="-1") 34 | inspect(vm.eval("(5).compare(5)"), content="0") 35 | inspect(vm.eval("(5).is_pos()"), content="true") 36 | inspect(vm.eval("(-5).is_neg()"), content="true") 37 | inspect(vm.eval("(0).is_pos()"), content="false") 38 | inspect(vm.eval("(8).ctz()"), content="3") 39 | inspect(vm.eval("(8).clz()"), content="28") 40 | inspect(vm.eval("(7).popcnt()"), content="3") 41 | } 42 | 43 | ///| 44 | test "double_methods" { 45 | let vm = MoonBitVM::new() 46 | inspect(vm.eval("5.5.compare(3.5)"), content="1") 47 | inspect(vm.eval("3.5.compare(5.5)"), content="-1") 48 | inspect(vm.eval("3.5.compare(3.5)"), content="0") 49 | inspect(vm.eval("3.5.to_int64()"), content="3") 50 | } 51 | 52 | ///| 53 | test "char_methods" { 54 | let vm = MoonBitVM::new() 55 | inspect(vm.eval("'b'.compare('a')"), content="1") 56 | inspect(vm.eval("'a'.compare('b')"), content="-1") 57 | inspect(vm.eval("'a'.compare('a')"), content="0") 58 | inspect(vm.eval("'a'.to_int()"), content="97") 59 | } 60 | -------------------------------------------------------------------------------- /src/test/variables.mbt: -------------------------------------------------------------------------------- 1 | // ============================================================================= 2 | // VARIABLE AND ASSIGNMENT TESTS 3 | // ============================================================================= 4 | // Tests for variable declarations, mutations, and field assignments 5 | 6 | ///| 7 | test "immutable_variables" { 8 | let vm = MoonBitVM::new() 9 | inspect(vm.eval("let a = 1"), content="()") 10 | inspect(vm.eval("a"), content="1") 11 | } 12 | 13 | ///| 14 | test "shadowing" { 15 | let vm = MoonBitVM::new() 16 | inspect(vm.eval("let a = 0; let a = 1; a"), content="1") 17 | inspect(vm.eval("let mut a = 0; let a = 1; a"), content="1") 18 | } 19 | 20 | ///| 21 | test "mutable_variables" { 22 | let vm = MoonBitVM::new() 23 | inspect(vm.eval("let mut a = 1"), content="()") 24 | inspect(vm.eval("a = 12"), content="()") 25 | inspect(vm.eval("a"), content="12") 26 | } 27 | 28 | ///| 29 | test "basic_mutable_variables" { 30 | let vm = MoonBitVM::new() 31 | assert_eq(vm.eval("let mut x = 0; x = x + 1; x").to_string(), "1") 32 | } 33 | 34 | ///| 35 | test "sequential_assignments" { 36 | let vm = MoonBitVM::new() 37 | assert_eq( 38 | vm 39 | .eval("let mut sum = 0; sum = sum + 1; sum = sum + 2; sum = sum + 3; sum") 40 | .to_string(), 41 | "6", 42 | ) 43 | } 44 | 45 | ///| 46 | test "field_assignment" { 47 | let vm = MoonBitVM::new() 48 | // Test field assignment works - separate top and non-top 49 | assert_eq( 50 | vm 51 | .eval( 52 | ( 53 | #|struct Point { mut x : Int, mut y : Int } 54 | ), 55 | top=true, 56 | ) 57 | .to_string(), 58 | "()", 59 | ) 60 | assert_eq( 61 | vm 62 | .eval( 63 | ( 64 | #|let p = { x: 1, y: 2 } 65 | #|p.x = 10 66 | #|p.y = 20 67 | #|(p.x, p.y) 68 | ), 69 | top=false, 70 | ) 71 | .to_string(), 72 | "(10, 20)", 73 | ) 74 | } 75 | 76 | ///| 77 | test "nested_struct_reference" { 78 | let vm = MoonBitVM::new() 79 | assert_eq( 80 | vm 81 | .eval( 82 | ( 83 | #|struct Inner { value : Int } 84 | #|struct Outer { inner : Inner } 85 | #|let outer = { inner: { value: 42 } } 86 | #|outer.inner.value 87 | ), 88 | ) 89 | .to_string(), 90 | "42", 91 | ) 92 | } 93 | -------------------------------------------------------------------------------- /src/test/list.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | test "list_methods" { 3 | let vm = MoonBitVM::new() 4 | assert_eq( 5 | vm.eval("let list = @list.from_array([1, 2, 3]); list").to_string(), 6 | "More(1, tail=More(2, tail=More(3, tail=Empty)))", 7 | ) 8 | assert_eq(vm.eval("typeof(list)").to_string(), "@moonbitlang/core/list.List") 9 | assert_eq( 10 | vm.eval("list.rev()").to_string(), 11 | "More(3, tail=More(2, tail=More(1, tail=Empty)))", 12 | ) 13 | assert_eq( 14 | vm.eval("list").to_string(), 15 | "More(1, tail=More(2, tail=More(3, tail=Empty)))", 16 | ) 17 | // Test basic list operations 18 | assert_eq(vm.eval("let l = @list.empty()").to_string(), "()") 19 | assert_eq(vm.eval("l.is_empty()").to_string(), "true") 20 | assert_eq(vm.eval("l.length()").to_string(), "0") 21 | 22 | // Test list mapping and filtering 23 | assert_eq( 24 | vm.eval("let l2 = @list.from_array([1, 2, 3, 4, 5])").to_string(), 25 | "()", 26 | ) 27 | assert_eq( 28 | vm.eval("l2.map(x => x * 2).to_array()").to_string(), 29 | "[2, 4, 6, 8, 10]", 30 | ) 31 | assert_eq( 32 | vm.eval("l2.filter(x => x % 2 == 0).to_array()").to_string(), 33 | "[2, 4]", 34 | ) 35 | 36 | // Test list folding 37 | assert_eq(vm.eval("l2.fold(init=0, (acc, x) => acc + x)").to_string(), "15") 38 | 39 | // Test list concatenation and reversal 40 | assert_eq( 41 | vm.eval("let l3 = @list.from_array([6, 7, 8]); l3.to_array()").to_string(), 42 | "[6, 7, 8]", 43 | ) 44 | assert_eq(vm.eval("l3.to_array()").to_string(), "[6, 7, 8]") 45 | assert_eq( 46 | vm.eval("l2.concat(l3).to_array()").to_string(), 47 | "[1, 2, 3, 4, 5, 6, 7, 8]", 48 | ) 49 | assert_eq(vm.eval("l2.rev().to_array()").to_string(), "[5, 4, 3, 2, 1]") 50 | 51 | // Test list searching 52 | assert_eq(vm.eval("l2.contains(3)").to_string(), "true") 53 | assert_eq(vm.eval("l2.find(x => x > 4)").to_string(), "Some(5)") 54 | 55 | // Test list slicing 56 | assert_eq(vm.eval("l2.take(3).to_array()").to_string(), "[1, 2, 3]") 57 | assert_eq(vm.eval("l2.drop(2).to_array()").to_string(), "[3, 4, 5]") 58 | 59 | // zip 60 | assert_eq( 61 | vm 62 | .eval( 63 | "let l4 = @list.from_array([1, 2, 3]); let l5 = @list.from_array([4, 5, 6]); l4.zip(l5).to_array()", 64 | ) 65 | .to_string(), 66 | "[(1, 4), (2, 5), (3, 6)]", 67 | ) 68 | } 69 | -------------------------------------------------------------------------------- /src/test/generic.mbt: -------------------------------------------------------------------------------- 1 | // Generic-related test cases 2 | 3 | ///| 4 | test "generic_list" { 5 | let vm = MoonBitVM::new() 6 | inspect( 7 | vm.eval( 8 | ( 9 | #|enum List[T] { 10 | #| Nil 11 | #| Cons(T, List[T]) 12 | #|} 13 | #| 14 | #|fn[T] List::new() -> List[T] { 15 | #| Nil 16 | #|} 17 | #| 18 | #|fn[T] List::cons(x: T, xs: List[T]) -> List[T] { 19 | #| Cons(x, xs) 20 | #|} 21 | ), 22 | top=true, 23 | ), 24 | content="()", 25 | ) 26 | // 先测试单独的Nil 27 | inspect(vm.eval("Nil"), content="Nil") 28 | // 再测试List::new() 29 | inspect(vm.eval("List::new()"), content="Nil") 30 | // 测试简单的Cons调用 31 | inspect(vm.eval("List::cons(1, Nil)"), content="Cons(1, Nil)") 32 | // 测试嵌套的Cons调用 33 | assert_eq(vm.eval("List::cons(2, List::new())").to_string(), "Cons(2, Nil)") 34 | // 测试中间步骤 35 | inspect( 36 | vm.eval("let inner = List::cons(2, List::new()); inner"), 37 | content="Cons(2, Nil)", 38 | ) 39 | // 测试分步构建 40 | inspect( 41 | vm.eval("let step1 = List::new(); let step2 = List::cons(2, step1); step2"), 42 | content="Cons(2, Nil)", 43 | ) 44 | // 测试直接嵌套调用 45 | inspect(vm.eval("List::cons(2, List::new())"), content="Cons(2, Nil)") 46 | // 测试更深层嵌套 47 | let result = vm.eval("List::cons(1, List::cons(2, List::new()))") 48 | inspect(result, content="Cons(1, Cons(2, Nil))") 49 | inspect( 50 | vm.eval("let list = List::cons(1, List::cons(2, List::new()))"), 51 | content="()", 52 | ) 53 | inspect( 54 | vm.eval( 55 | ( 56 | #|fn[S, T] map(list: List[S], f: (S) -> T) -> List[T] { 57 | #| match list { 58 | #| Nil => Nil 59 | #| Cons(x, xs) => Cons(f(x), map(xs, f)) 60 | #| } 61 | #|} 62 | #| 63 | #|fn[T] sum(list: List[T]) -> T { 64 | #| match list { 65 | #| Nil => 0 66 | #| Cons(x, xs) => x + sum(xs) 67 | #| } 68 | #|} 69 | ), 70 | top=true, 71 | ), 72 | content="()", 73 | ) 74 | inspect( 75 | vm.eval("let list = List::cons(1, List::cons(2, List::new()))"), 76 | content="()", 77 | ) 78 | assert_eq( 79 | vm.eval("map(list, x => x * 2)").to_string(), 80 | "Cons(2, Cons(4, Nil))", 81 | ) 82 | assert_eq(vm.eval("sum(list)").to_string(), "3") 83 | } 84 | -------------------------------------------------------------------------------- /src/interpreter/string_builder.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | let stringbuilder_methods : Map[String, RuntimeFunction] = { 3 | "new": stringbuilder_new_fn, 4 | "is_empty": stringbuilder_is_empty_fn, 5 | "reset": stringbuilder_reset_fn, 6 | "to_string": stringbuilder_to_string_fn, 7 | "write_iter": stringbuilder_write_iter_fn, 8 | "write_object": stringbuilder_write_object_fn, 9 | "write_string": stringbuilder_write_string_fn, 10 | "write_char": stringbuilder_write_char_fn, 11 | "write_view": stringbuilder_write_view_fn, 12 | } 13 | 14 | ///| 15 | let stringbuilder_new_fn : RuntimeFunction = _ => StringBuilder( 16 | StringBuilder::new(), 17 | ) 18 | 19 | ///| 20 | let stringbuilder_is_empty_fn : RuntimeFunction = ctx => match ctx.args { 21 | [{ val: StringBuilder(self), .. }] => Bool(self.is_empty()) 22 | _ => Bool(false) 23 | } 24 | 25 | ///| 26 | let stringbuilder_reset_fn : RuntimeFunction = ctx => match ctx.args { 27 | [{ val: StringBuilder(self), .. }] => { 28 | self.reset() 29 | Unit 30 | } 31 | _ => Unit 32 | } 33 | 34 | ///| 35 | let stringbuilder_to_string_fn : RuntimeFunction = ctx => match ctx.args { 36 | [{ val: StringBuilder(self), .. }] => String(self.to_string()) 37 | _ => String("") 38 | } 39 | 40 | ///| 41 | let stringbuilder_write_iter_fn : RuntimeFunction = ctx => match ctx.args { 42 | [{ val: StringBuilder(self), .. }, { val: Iter(iter), .. }] => { 43 | self.write_iter(iter.map(x => if x is Char(c) { c } else { panic() })) 44 | Unit 45 | } 46 | _ => Unit 47 | } 48 | 49 | ///| 50 | let stringbuilder_write_object_fn : RuntimeFunction = ctx => match ctx.args { 51 | [{ val: StringBuilder(self), .. }, { val: str, .. }] => { 52 | self.write_object(str) 53 | Unit 54 | } 55 | _ => Unit 56 | } 57 | 58 | ///| 59 | let stringbuilder_write_string_fn : RuntimeFunction = ctx => match ctx.args { 60 | [{ val: StringBuilder(self), .. }, { val: String(str), .. }] => { 61 | self.write_string(str) 62 | Unit 63 | } 64 | _ => Unit 65 | } 66 | 67 | ///| 68 | let stringbuilder_write_char_fn : RuntimeFunction = ctx => match ctx.args { 69 | [{ val: StringBuilder(self), .. }, { val: Char(ch), .. }] => { 70 | self.write_char(ch) 71 | Unit 72 | } 73 | _ => Unit 74 | } 75 | 76 | ///| 77 | let stringbuilder_write_view_fn : RuntimeFunction = ctx => match ctx.args { 78 | [{ val: StringBuilder(self), .. }, { val: StringView(view), .. }] => { 79 | self.write_view(view) 80 | Unit 81 | } 82 | _ => Unit 83 | } 84 | -------------------------------------------------------------------------------- /src/benchmark_test.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | /// 解释器性能基准测试 3 | /// 测试核心性能路径:表达式求值、模式匹配、函数调用 4 | 5 | // 表达式求值基准测试 6 | test "benchmark_arithmetic_expressions" (b : @bench.T) { 7 | let vm = MoonBitVM::new(log=false) 8 | let code = "1 + 2 * 3 - 4 / 2 + (5 * 6) - 7" 9 | b.bench(fn() { b.keep(vm.eval(code)) }) 10 | } 11 | 12 | // 变量访问基准测试 13 | 14 | ///| 15 | test "benchmark_variable_access" (b : @bench.T) { 16 | let vm = MoonBitVM::new(log=false) 17 | 18 | // 设置变量 19 | vm.eval("let x = 42; let y = 100; let z = x + y") |> ignore 20 | b.bench(fn() { b.keep(vm.eval("x + y + z")) }) 21 | } 22 | 23 | // 函数调用基准测试 24 | 25 | ///| 26 | test "benchmark_function_calls" (b : @bench.T) { 27 | let vm = MoonBitVM::new(log=false) 28 | let code = "fn add(x, y) { x + y }; fn mul(x, y) { x * y }; fn complex(a, b, c) { add(mul(a, b), c) }; complex(10, 20, 30)" 29 | b.bench(fn() { b.keep(vm.eval(code)) }) 30 | } 31 | 32 | // 数组操作基准测试 33 | 34 | ///| 35 | test "benchmark_array_operations" (b : @bench.T) { 36 | let vm = MoonBitVM::new(log=false) 37 | let code = "let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let sum = arr[0] + arr[1] + arr[2] + arr[3] + arr[4]; sum" 38 | b.bench(fn() { b.keep(vm.eval(code)) }) 39 | } 40 | 41 | // 递归函数基准测试 42 | 43 | ///| 44 | test "benchmark_recursive_functions" (b : @bench.T) { 45 | let vm = MoonBitVM::new(log=false) 46 | let code = "fn fibonacci(n) { if n <= 1 { n } else { fibonacci(n - 1) + fibonacci(n - 2) } }; fibonacci(10)" 47 | b.bench(fn() { b.keep(vm.eval(code)) }) 48 | } 49 | 50 | // 尾递归优化测试 - 证明算法比数据结构更重要 51 | 52 | ///| 53 | test "benchmark_tail_recursive_fibonacci" (b : @bench.T) { 54 | let vm = MoonBitVM::new(log=false) 55 | let code = "fn fib_tail(n, a, b) { if n == 0 { a } else { fib_tail(n - 1, b, a + b) } }; fn fibonacci_fast(n) { fib_tail(n, 0, 1) }; fibonacci_fast(10)" 56 | b.bench(fn() { b.keep(vm.eval(code)) }) 57 | } 58 | 59 | // 迭代版本测试 - 最优算法 60 | 61 | ///| 62 | test "benchmark_iterative_fibonacci" (b : @bench.T) { 63 | let vm = MoonBitVM::new(log=false) 64 | let code = "fn fibonacci_iter(n) { let mut a = 0; let mut b = 1; let mut i = 0; while i < n { let temp = a + b; a = b; b = temp; i = i + 1 }; a }; fibonacci_iter(10)" 65 | b.bench(fn() { b.keep(vm.eval(code)) }) 66 | } 67 | 68 | // 复杂表达式基准测试 69 | 70 | ///| 71 | test "benchmark_complex_expressions" (b : @bench.T) { 72 | let vm = MoonBitVM::new(log=false) 73 | let code = "let a = 10; let b = 20; let c = 30; (a + b) * c - (a * b) + (c / 2) - (a - b)" 74 | b.bench(fn() { b.keep(vm.eval(code)) }) 75 | } 76 | -------------------------------------------------------------------------------- /src/interpreter/utils.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | #callsite(autofill(loc)) 3 | pub fn[A] error(msg : String, loc~ : SourceLoc) -> A raise ControlFlow { 4 | raise ControlFlow::Error(msg + " " + loc.to_string()) 5 | } 6 | 7 | ///| 8 | fn fromCharCode(hex : StringView, base : Int) -> Char { 9 | (try! @strconv.parse_int(hex, base~)).to_char().unwrap_or('?') 10 | } 11 | 12 | ///| 13 | pub fn manualUnescape(input : StringView, buf : StringBuilder) -> Unit { 14 | try { 15 | loop input { 16 | // EOF 17 | "" => break 18 | rest => 19 | continue { 20 | let (c, rest) = lexmatch rest with longest { 21 | ("\\n", rest) => ('\n', rest) 22 | ("\\t", rest) => ('\t', rest) 23 | ("\\r", rest) => ('\r', rest) 24 | // Backspace 25 | ("\\b", rest) => ('\b', rest) 26 | // Unicode escape 27 | ("\\u[0-9a-fA-F]{4}" as raw, rest) => 28 | (fromCharCode(raw[2:], 16), rest) 29 | ("\\x[0-9a-fA-F]{2}" as raw, rest) => 30 | (fromCharCode(raw[2:], 16), rest) 31 | // Unicode escape with braces 32 | ("\\u[{][0-9a-fA-F]+[}]" as raw, rest) => 33 | (fromCharCode(raw[3:-1], 16), rest) 34 | // Octal escape 35 | ("\\o[0-3][0-7]{2}" as raw, rest) => 36 | (fromCharCode(raw[2:], 8), rest) 37 | ("\\\\", rest) => ('\\', rest) 38 | ("." as c, rest) => (c, rest) 39 | _ => break 40 | } 41 | buf.write_char(c) 42 | rest 43 | } 44 | } 45 | } catch { 46 | _ => () 47 | } 48 | } 49 | 50 | ///| 51 | test "manualUnescape" { 52 | let builder = StringBuilder::new() 53 | manualUnescape("\\nhello", builder) 54 | inspect( 55 | builder.to_string(), 56 | content=( 57 | #| 58 | #|hello 59 | ), 60 | ) 61 | let builder = StringBuilder::new() 62 | manualUnescape("hello\\nworld", builder) 63 | inspect( 64 | builder.to_string(), 65 | content=( 66 | #|hello 67 | #|world 68 | ), 69 | ) 70 | let builder = StringBuilder::new() 71 | manualUnescape("\\u0041", builder) 72 | inspect(builder.to_string(), content="A") 73 | let builder = StringBuilder::new() 74 | manualUnescape("\\x41", builder) 75 | inspect(builder.to_string(), content="A") 76 | let builder = StringBuilder::new() 77 | manualUnescape("\\o061", builder) 78 | inspect(builder.to_string(), content="1") 79 | } 80 | -------------------------------------------------------------------------------- /src/test/option.mbt: -------------------------------------------------------------------------------- 1 | // ============================================================================= 2 | // Option Type Tests 3 | // ============================================================================= 4 | // Tests for Option type functionality, pattern matching, and methods 5 | 6 | ///| 7 | test "option_type" { 8 | let vm = MoonBitVM::new() 9 | // Test try operator (?) 10 | assert_eq( 11 | vm 12 | .eval( 13 | ( 14 | #|fn safe_divide(a : Int, b : Int) -> Int? { 15 | #| if b == 0 { None } else { Some(a / b) } 16 | #|} 17 | #|let result = safe_divide(10, 2) 18 | #|result 19 | ), 20 | ) 21 | .to_string(), 22 | "Some(5)", 23 | ) 24 | assert_eq( 25 | vm 26 | .eval( 27 | ( 28 | #|let result = safe_divide(10, 0) 29 | #|result 30 | ), 31 | ) 32 | .to_string(), 33 | "None", 34 | ) 35 | } 36 | 37 | ///| 38 | test "option_basics" { 39 | let vm = MoonBitVM::new() 40 | assert_eq(vm.eval("@option.Some(5)").to_string(), "Some(5)") 41 | assert_eq(vm.eval("Some(5)").to_string(), "Some(5)") 42 | assert_eq(vm.eval("None").to_string(), "None") 43 | assert_eq(vm.eval("Some(5).unwrap()").to_string(), "5") 44 | } 45 | 46 | ///| 47 | test "option_pattern_matching" { 48 | let vm = MoonBitVM::new() 49 | inspect(vm.eval("match Some(5) { Some(x) => x, None => 0 }"), content="5") 50 | inspect( 51 | vm.eval("match Some(5) { Option::Some(x) => x, None => 0 }"), 52 | content="5", 53 | ) 54 | inspect(vm.eval("match None { Some(x) => x, None => 0 }"), content="0") 55 | } 56 | 57 | ///| 58 | test { 59 | inspect( 60 | { 61 | let opt = Some(5) 62 | opt.map(fn(x) { x * 2 }) 63 | }, 64 | content="Some(10)", 65 | ) 66 | } 67 | 68 | ///| 69 | test "option_methods" { 70 | let vm = MoonBitVM::new() 71 | inspect(vm.eval("let opt = Some(42); opt.unwrap()"), content="42") 72 | inspect(vm.eval("let opt = Some(42); opt.unwrap_or(0)"), content="42") 73 | inspect(vm.eval("let opt = None; opt.unwrap_or(0)"), content="0") 74 | inspect(vm.eval("let opt = Some(42); opt.is_empty()"), content="false") 75 | inspect(vm.eval("let opt = None; opt.is_empty()"), content="true") 76 | assert_eq( 77 | vm.eval("let opt = Some(5); opt.map(fn(x) { x * 2 })").to_string(), 78 | "Some(10)", 79 | ) 80 | inspect(vm.eval("let opt = None; opt.map(fn(x) { x * 2 })"), content="None") 81 | inspect( 82 | vm.eval("let opt = Some(5); opt.filter(fn(x) { x > 3 })"), 83 | content="Some(5)", 84 | ) 85 | inspect( 86 | vm.eval("let opt = Some(2); opt.filter(fn(x) { x > 3 })"), 87 | content="None", 88 | ) 89 | } 90 | -------------------------------------------------------------------------------- /src/interpreter/bytes.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub let bytes_methods : Map[String, RuntimeFunction] = { 3 | "length": bytes_length_fn, 4 | "at": bytes_at_fn, 5 | "compare": bytes_compare_fn, 6 | "equal": bytes_equal_fn, 7 | "make": bytes_make_fn, 8 | "makei": bytes_makei_fn, 9 | "new": bytes_new_fn, 10 | "op_equal": bytes_op_equal_fn, 11 | "to_unchecked_string": bytes_to_unchecked_string_fn, 12 | "unsafe_get": bytes_unsafe_get_fn, 13 | } 14 | 15 | ///| 16 | let bytes_at_fn : RuntimeFunction = ctx => match ctx.args { 17 | [{ val: Bytes(b), .. }, { val: Int(i, ..), .. }] => Byte(b[i]) 18 | _ => Unit 19 | } 20 | 21 | ///| 22 | let bytes_compare_fn : RuntimeFunction = ctx => match ctx.args { 23 | [{ val: Bytes(a), .. }, { val: Bytes(b), .. }] => Int(a.compare(b), raw=None) 24 | _ => Unit 25 | } 26 | 27 | ///| 28 | let bytes_equal_fn : RuntimeFunction = ctx => match ctx.args { 29 | [{ val: Bytes(a), .. }, { val: Bytes(b), .. }] => Bool(a == b) 30 | _ => Unit 31 | } 32 | 33 | ///| 34 | let bytes_make_fn : RuntimeFunction = ctx => match ctx.args { 35 | [{ val: Int(len, ..), .. }, { val: Byte(byte), .. }] => 36 | Bytes(Bytes::make(len, byte)) 37 | _ => Unit 38 | } 39 | 40 | ///| 41 | let bytes_makei_fn : RuntimeFunction = ctx => match ctx.args { 42 | [{ val: Int(len, ..), .. }, { val: Fn(f), .. }] => { 43 | let result = Bytes::makei(len, fn(i) { 44 | let arg = Int(i, raw=None) 45 | let ret = ctx.context.call(f.val, ctx.pkg, [ 46 | { val: arg, kind: Positional }, 47 | ]) 48 | match ret { 49 | Byte(b) => b 50 | _ => 0 51 | } 52 | }) 53 | Bytes(result) 54 | } 55 | _ => Unit 56 | } 57 | 58 | ///| 59 | let bytes_new_fn : RuntimeFunction = ctx => match ctx.args { 60 | [{ val: Int(len, ..), .. }] => Bytes(Bytes::new(len)) 61 | _ => Unit 62 | } 63 | 64 | ///| 65 | let bytes_op_equal_fn : RuntimeFunction = ctx => match ctx.args { 66 | [{ val: Bytes(a), .. }, { val: Bytes(b), .. }] => Bool(a == b) 67 | _ => Unit 68 | } 69 | 70 | ///| 71 | let bytes_to_unchecked_string_fn : RuntimeFunction = ctx => match ctx.args { 72 | [{ val: Bytes(b), .. }] => { 73 | let offset = if ctx.named("offset") is Some(Int(i, ..)) { 74 | Some(i) 75 | } else { 76 | None 77 | } 78 | let length = if ctx.named("length") is Some(Int(i, ..)) { 79 | Some(i) 80 | } else { 81 | None 82 | } 83 | String(b.to_unchecked_string(offset?, length?)) 84 | } 85 | _ => Unit 86 | } 87 | 88 | ///| 89 | let bytes_unsafe_get_fn : RuntimeFunction = ctx => match ctx.args { 90 | [{ val: Bytes(b), .. }, { val: Int(i, ..), .. }] => Byte(b.unsafe_get(i)) 91 | _ => Unit 92 | } 93 | 94 | ///| 95 | let bytes_length_fn : RuntimeFunction = ctx => match ctx.args { 96 | [{ val: Bytes(b), .. }] => Int(b.length(), raw=None) 97 | _ => Unit 98 | } 99 | -------------------------------------------------------------------------------- /src/interpreter/iter2.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | /// Iter2 内置方法映射 3 | pub let iter2_methods : Map[String, RuntimeFunction] = { 4 | // "new": iter2_new_fn, 5 | "run": iter2_run_fn, 6 | "each": iter2_each_fn, 7 | "iter": iter2_iter_fn, 8 | "iter2": iter2_iter2_fn, 9 | "to_array": iter2_to_array_fn, 10 | "concat": iter2_concat_fn, 11 | } 12 | 13 | // Basic constructor functions 14 | 15 | // ///| 16 | // let iter2_new_fn : RuntimeFunction = ctx => match ctx.args { 17 | // [{ val, .. }] => Iter2(Iter2::new(f => f(val, val))) 18 | // _ => Unit 19 | // } 20 | 21 | ///| 22 | let iter2_run_fn : RuntimeFunction = ctx => match ctx.args { 23 | [{ val: Iter2(iter2), .. }, { val: Fn(func), .. }] => { 24 | let result = iter2.run(fn(a, b) { 25 | try { 26 | match 27 | ctx.context.call(func.val, ctx.pkg, [ 28 | { val: a, kind: Positional }, 29 | { val: b, kind: Positional }, 30 | ]) { 31 | Unit => IterEnd 32 | _ => IterContinue 33 | } 34 | } catch { 35 | _ => IterEnd 36 | } 37 | }) 38 | match result { 39 | IterEnd => Unit 40 | IterContinue => Unit 41 | } 42 | } 43 | _ => Unit 44 | } 45 | 46 | ///| 47 | let iter2_each_fn : RuntimeFunction = ctx => match ctx.args { 48 | [{ val: Iter2(iter2), .. }, { val: Fn(func), .. }] => { 49 | iter2.each(fn(a, b) { 50 | try 51 | ctx.context.call(func.val, ctx.pkg, [ 52 | { val: a, kind: Positional }, 53 | { val: b, kind: Positional }, 54 | ]) 55 | |> ignore 56 | catch { 57 | _ => () 58 | } 59 | }) 60 | Unit 61 | } 62 | _ => Unit 63 | } 64 | 65 | ///| 66 | let iter2_iter_fn : RuntimeFunction = ctx => match ctx.args { 67 | [{ val: Iter2(iter2), .. }] => { 68 | // 将 Iter2 转换为 Iter,每个元素是一个包含两个值的元组 69 | let iter_impl : Iter[RuntimeValue] = iter2 70 | .iter() 71 | .map(fn(pair) { Tuple([pair.0, pair.1]) }) 72 | Iter(iter_impl) 73 | } 74 | _ => Unit 75 | } 76 | 77 | ///| 78 | let iter2_iter2_fn : RuntimeFunction = ctx => match ctx.args { 79 | [{ val: iter2_val, .. }] => iter2_val // 返回自身 80 | _ => Unit 81 | } 82 | 83 | ///| 84 | let iter2_to_array_fn : RuntimeFunction = ctx => match ctx.args { 85 | [{ val: Iter2(iter2), .. }] => { 86 | let result : Array[RuntimeValue] = iter2 87 | .to_array() 88 | .map(fn(pair) { Tuple([pair.0, pair.1]) }) 89 | Array(result) 90 | } 91 | _ => Unit 92 | } 93 | 94 | ///| 95 | let iter2_concat_fn : RuntimeFunction = ctx => match ctx.args { 96 | [{ val: Iter2(iter2_1), .. }, { val: Iter2(iter2_2), .. }] => { 97 | let concatenated = iter2_1.concat(iter2_2) 98 | Iter2(concatenated) 99 | } 100 | _ => Unit 101 | } 102 | -------------------------------------------------------------------------------- /src/interpreter/env.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub(all) struct RuntimeEnvironment { 3 | values : Map[String, RuntimeValue] 4 | // 跟踪哪些变量是可变的 5 | mutable_vars : Map[String, Bool] 6 | parent : RuntimeEnvironment? 7 | } derive(ToJson) 8 | 9 | ///| 10 | pub fn RuntimeEnvironment::new( 11 | parent? : RuntimeEnvironment, 12 | values? : Map[String, RuntimeValue], 13 | ) -> RuntimeEnvironment { 14 | if parent is Some(parent) { 15 | { 16 | values: values.unwrap_or({}), 17 | mutable_vars: Map::new(), 18 | parent: Some(parent), 19 | } 20 | } else { 21 | { values: values.unwrap_or({}), mutable_vars: Map::new(), parent: None } 22 | } 23 | } 24 | 25 | ///| 26 | /// 深拷贝环境 - 完全复制所有内容 27 | pub fn RuntimeEnvironment::copy( 28 | self : RuntimeEnvironment, 29 | ) -> RuntimeEnvironment { 30 | let values = Map::new() 31 | let mutable_vars = Map::new() 32 | self.values.each(fn(key, value) { values.set(key, value) }) 33 | self.mutable_vars.each(fn(key, is_mutable) { 34 | mutable_vars.set(key, is_mutable) 35 | }) 36 | let parent = match self.parent { 37 | Some(parent) => Some(parent.copy()) 38 | None => None 39 | } 40 | { values, mutable_vars, parent } 41 | } 42 | 43 | ///| 44 | /// 为闭包创建捕获环境 - 实现正确的变量捕获语义 45 | pub fn RuntimeEnvironment::create_closure_env( 46 | self : RuntimeEnvironment, 47 | ) -> RuntimeEnvironment { 48 | let values = Map::new() 49 | let mutable_vars = Map::new() 50 | 51 | // 只捕获不可变变量的值,可变变量通过父环境引用 52 | self.values.each(fn(key, value) { 53 | let is_mutable = self.mutable_vars.get(key).unwrap_or(false) 54 | if not(is_mutable) { 55 | // 不可变变量:捕获当前值 56 | values.set(key, value) 57 | mutable_vars.set(key, false) 58 | } 59 | // 可变变量不在闭包环境中捕获,通过parent引用访问 60 | }) 61 | 62 | // 设置父环境为当前环境,这样可变变量可以通过父环境访问 63 | // 继承父环境的全局状态(如类型定义、方法等) 64 | { values, mutable_vars, parent: Some(self) } 65 | } 66 | 67 | ///| 68 | /// 处理函数声明体,创建Lambda函数 69 | pub fn ClosureInterpreter::top_func_def_to_closure( 70 | self : ClosureInterpreter, 71 | pkg : RuntimePackage, 72 | func : @syntax.Impl, 73 | name? : String, 74 | ) -> (String?, RuntimeValue) { 75 | if func 76 | is TopFuncDef(fun_decl~, decl_body=DeclBody(local_types=_, expr=body), loc~) { 77 | let func = @syntax.Func::Lambda( 78 | parameters=fun_decl.decl_params.unwrap_or(@list.new()), 79 | params_loc=loc, 80 | body~, 81 | return_type=fun_decl.return_type, 82 | error_type=fun_decl.error_type, 83 | kind=Arrow, 84 | has_error=fun_decl.has_error, 85 | is_async=fun_decl.is_async, 86 | loc~, 87 | ) 88 | let type_name = match fun_decl { 89 | { type_name: Some({ name: Ident(name~), .. }), .. } => Some(name) 90 | { type_name: Some({ name: Dot(id~, ..), .. }), .. } => Some(id) 91 | { 92 | decl_params: Some( 93 | More( 94 | Positional( 95 | binder={ name: "self", .. }, 96 | ty=Some(Name(constr_id={ id: Ident(name~), .. }, ..)) 97 | ), 98 | .. 99 | ) 100 | ), 101 | .., 102 | } => Some(name) 103 | _ => None 104 | } 105 | (type_name, Fn(self.create_function(func, pkg, name?))) 106 | } else { 107 | (None, Unit) 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/test/function.mbt: -------------------------------------------------------------------------------- 1 | // ============================================================================= 2 | // 5. FUNCTIONS 3 | // ============================================================================= 4 | 5 | ///| 6 | test "basic_functions" { 7 | let vm = MoonBitVM::new() 8 | assert_eq( 9 | vm.eval("fn double(x: Int) -> Int { x * 2 }").to_string(), 10 | "(Int) -> Int", 11 | ) 12 | inspect(vm.eval("double(2)"), content="4") 13 | assert_eq( 14 | vm.eval("fn add(a: Int, b: Int) -> Int { a + b }").to_string(), 15 | "(Int, Int) -> Int", 16 | ) 17 | inspect(vm.eval("add(1, 2)"), content="3") 18 | } 19 | 20 | ///| 21 | test "named_parameters" { 22 | let vm = MoonBitVM::new() 23 | assert_eq( 24 | vm.eval("fn add_named(a~: Int, b~: Int) -> Int { a + b }").to_string(), 25 | "(Int, Int) -> Int", 26 | ) 27 | inspect(vm.eval("add_named(a=1, b=2)"), content="3") 28 | inspect( 29 | vm.eval("fn add_optional(a~: Int, b~: Int=2) -> Int { a + b }"), 30 | content="(Int, Int) -> Int", 31 | ) 32 | assert_eq(vm.eval("add_optional(a=1)").to_string(), "3") 33 | } 34 | 35 | ///| 36 | test "lambda_functions" { 37 | let vm = MoonBitVM::new() 38 | inspect(vm.eval("let f = x => x * 2"), content="()") 39 | assert_eq(vm.eval("f(3)").to_string(), "6") 40 | assert_eq(vm.eval("let identity = x => x").to_string(), "()") 41 | assert_eq(vm.eval("identity(5)").to_string(), "5") 42 | } 43 | 44 | ///| 45 | test "closure_argument_environment" { 46 | let vm = MoonBitVM::new() 47 | inspect(vm.eval("let x = 10"), content="()") 48 | // 创建闭包,捕获 x = 10 49 | inspect(vm.eval("let make_adder = y => x + y"), content="()") 50 | inspect(vm.eval("make_adder(5)"), content="15") 51 | inspect(vm.eval("let x = 20"), content="()") 52 | inspect(vm.eval("make_adder(x)"), content="30") 53 | let x = 10 54 | let make_adder = y => x + y 55 | inspect(make_adder(x), content="20") 56 | // 先测试简单情况:直接传入数字 57 | inspect(make_adder(5), content="15") 58 | let x = 20 59 | inspect(make_adder(x), content="30") 60 | } 61 | 62 | ///| 63 | test "recursive_functions" { 64 | let vm = MoonBitVM::new() 65 | assert_eq( 66 | vm 67 | .eval( 68 | ( 69 | #|fn fib(n : Int) -> Int { 70 | #| if n <= 1 { 71 | #| 1 72 | #| } else { 73 | #| fib(n - 1) + fib(n - 2) 74 | #| } 75 | #|} 76 | ), 77 | ) 78 | .to_string(), 79 | "(Int) -> Int", 80 | ) 81 | assert_eq(vm.eval("fib(10)").to_string(), "89") 82 | } 83 | 84 | ///| 85 | test "mutually_recursive_functions" { 86 | let vm = MoonBitVM::new() 87 | // Test LetRec for mutually recursive functions 88 | assert_eq( 89 | vm 90 | .eval( 91 | ( 92 | #|fn is_even(n : Int) -> Bool { 93 | #| if n == 0 { true } else { is_odd(n - 1) } 94 | #|} 95 | #|fn is_odd(n : Int) -> Bool { 96 | #| if n == 0 { false } else { is_even(n - 1) } 97 | #|} 98 | #|is_even(4) 99 | ), 100 | ) 101 | .to_string(), 102 | "true", 103 | ) 104 | assert_eq(vm.eval("is_odd(5)").to_string(), "true") 105 | assert_eq(vm.eval("is_even(3)").to_string(), "false") 106 | } 107 | 108 | ///| 109 | test "let_and_bindings" { 110 | let vm = MoonBitVM::new() 111 | // Test LetAnd for simultaneous function definitions 112 | assert_eq( 113 | vm 114 | .eval( 115 | ( 116 | #|letrec even = x => x == 0 || odd(x - 1) 117 | #|and odd = x => x != 0 && even(x - 1) 118 | #|even(4) 119 | ), 120 | ) 121 | .to_string(), 122 | "true", 123 | ) 124 | } 125 | -------------------------------------------------------------------------------- /src/interpreter/record_operations.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | /// 记录操作模块 3 | /// 包含记录更新(RecordUpdate)和字段赋值(Mutate)的处理逻辑 4 | 5 | ///| 6 | /// 处理记录更新表达式 (RecordUpdate) 7 | fn ClosureInterpreter::visit_record_update( 8 | self : ClosureInterpreter, 9 | record : @syntax.Expr, 10 | fields : @list.List[@syntax.FieldDef], 11 | ) -> RuntimeValue raise ControlFlow { 12 | // 先评估原记录 13 | let original_record = self.visit(record) 14 | match original_record { 15 | Object(refer) => { 16 | // 复制原有字段 17 | let new_fields = refer.val.copy() 18 | 19 | // 更新指定字段 20 | fields.each(fn(field) { 21 | let field_name = field.label.name 22 | let field_value = self.visit(field.expr) 23 | new_fields.set(field_name, field_value) 24 | }) 25 | 26 | // 创建新的结构体 27 | Object({ val: new_fields, ty: refer.ty }) 28 | } 29 | _ => self.error("RecordUpdate can only be applied to struct values") 30 | } 31 | } 32 | 33 | ///| 34 | /// 处理字段赋值 (Mutate) 35 | fn ClosureInterpreter::visit_mutate( 36 | self : ClosureInterpreter, 37 | record : @syntax.Expr, 38 | accessor : @syntax.Accessor, 39 | field : @syntax.Expr, 40 | augmented_by : @syntax.Var?, 41 | ) -> RuntimeValue raise ControlFlow { 42 | 43 | // 获取记录的运行时值(支持嵌套字段访问) 44 | match self.visit(record) { 45 | Object(refer) => 46 | match accessor { 47 | Label(label) => 48 | match augmented_by { 49 | Some(op) => { 50 | // 增强赋值操作 (+=, -=, 等) 51 | let op_name = match op.name { 52 | Ident(name~) => name 53 | _ => "+" 54 | } 55 | let base_op = match op_name { 56 | "+" => "+" 57 | "-" => "-" 58 | "*" => "*" 59 | "/" => "/" 60 | "%" => "%" 61 | _ => "+" // 默认 62 | } 63 | let current_val = refer.val 64 | .get(label.name) 65 | .unwrap_or(Int(0, raw=None)) 66 | let right_val = self.visit(field) 67 | let new_val = runtime_value_infix(base_op, current_val, right_val) 68 | refer.val.set(label.name, new_val) 69 | } 70 | None => 71 | // 普通赋值操作 72 | refer.val.set(label.name, self.visit(field)) 73 | } 74 | Index(tuple_index~, ..) => 75 | match augmented_by { 76 | Some(op) => { 77 | // 增强赋值操作 (+=, -=, 等) 78 | let op_name = match op.name { 79 | Ident(name~) => name 80 | _ => "+" 81 | } 82 | let base_op = match op_name { 83 | "+" => "+" 84 | "-" => "-" 85 | "*" => "*" 86 | "/" => "/" 87 | "%" => "%" 88 | _ => "+" // 默认 89 | } 90 | let current_val = refer.val 91 | .get(tuple_index.to_string()) 92 | .unwrap_or(Int(0, raw=None)) 93 | let right_val = self.visit(field) 94 | let new_val = runtime_value_infix(base_op, current_val, right_val) 95 | refer.val.set(tuple_index.to_string(), new_val) 96 | } 97 | None => 98 | // 普通赋值操作 99 | refer.val.set(tuple_index.to_string(), self.visit(field)) 100 | } 101 | Newtype(_) => () 102 | } 103 | Constructor(refer) => 104 | match accessor { 105 | Label({ name, .. }) => { 106 | // 构造函数字段赋值处理 107 | let new_field_value = self.visit(field) 108 | let field = refer.val.fields.search_by(field => field.name == 109 | Some(name)) 110 | // 处理构造函数的字段赋值 111 | if field is Some(i) { 112 | refer.val.fields[i].value = new_field_value 113 | } 114 | } 115 | _ => () // 其他访问器类型暂不支持 116 | } 117 | _ => () 118 | } 119 | Unit 120 | } 121 | -------------------------------------------------------------------------------- /src/interpreter/assignment_operations.mbt: -------------------------------------------------------------------------------- 1 | // Assignment operations for ClosureInterpreter 2 | // This file contains all assignment and augmented assignment operations 3 | 4 | ///| 5 | /// 处理增强赋值操作 6 | fn ClosureInterpreter::visit_augmented_assignment( 7 | self : ClosureInterpreter, 8 | op : String, 9 | lhs : @syntax.Expr, 10 | rhs : @syntax.Expr, 11 | ) -> RuntimeValue raise ControlFlow { 12 | let base_op = match op { 13 | "+=" => "+" 14 | "-=" => "-" 15 | "*=" => "*" 16 | "/=" => "/" 17 | "%=" => "%" 18 | _ => "+" 19 | } 20 | match lhs { 21 | Field(record~, accessor~, ..) => 22 | self.visit_field_augmented_assignment(record, accessor, base_op, rhs) 23 | Ident(id={ name: var_name, .. }, ..) => 24 | self.visit_variable_augmented_assignment(var_name, base_op, rhs) 25 | _ => Unit 26 | } 27 | } 28 | 29 | ///| 30 | /// 处理字段增强赋值 31 | fn ClosureInterpreter::visit_field_augmented_assignment( 32 | self : ClosureInterpreter, 33 | record : @syntax.Expr, 34 | accessor : @syntax.Accessor, 35 | base_op : String, 36 | rhs : @syntax.Expr, 37 | ) -> RuntimeValue raise ControlFlow { 38 | let right_val = self.visit(rhs) 39 | match self.visit(record) { 40 | Object(refer) => 41 | match accessor { 42 | Label(label) => { 43 | let current_val = refer.val 44 | .get(label.name) 45 | .unwrap_or(Int(0, raw=None)) 46 | let new_val = runtime_value_infix(base_op, current_val, right_val) 47 | refer.val.set(label.name, new_val) 48 | } 49 | Index(tuple_index~, ..) => { 50 | let current_val = refer.val 51 | .get(tuple_index.to_string()) 52 | .unwrap_or(Int(0, raw=None)) 53 | let new_val = runtime_value_infix(base_op, current_val, right_val) 54 | refer.val.set(tuple_index.to_string(), new_val) 55 | } 56 | Newtype(_) => () 57 | } 58 | _ => () 59 | } 60 | Unit 61 | } 62 | 63 | ///| 64 | /// 处理变量增强赋值 65 | fn ClosureInterpreter::visit_variable_augmented_assignment( 66 | self : ClosureInterpreter, 67 | var_name : @syntax.LongIdent, 68 | base_op : String, 69 | rhs : @syntax.Expr, 70 | ) -> RuntimeValue raise ControlFlow { 71 | let var_name_str = match var_name { 72 | Ident(name~) => name 73 | _ => "Any" 74 | } 75 | let current_val = self.with_ident(var_name, fn(pkg, name) { 76 | pkg.find(name).unwrap_or(Unit) 77 | }) 78 | let right_val = self.visit(rhs) 79 | let new_val = runtime_value_infix(base_op, current_val, right_val) 80 | self.current_pkg.env.update(var_name_str, new_val) 81 | Unit 82 | } 83 | 84 | ///| 85 | /// 处理数组元素赋值 86 | fn ClosureInterpreter::visit_array_set( 87 | self : ClosureInterpreter, 88 | array : @syntax.Expr, 89 | index : @syntax.Expr, 90 | value : @syntax.Expr, 91 | ) -> RuntimeValue raise ControlFlow { 92 | let array_value = self.visit(array) 93 | match array_value { 94 | Array(arr) => { 95 | let index = self.visit(index) 96 | match index { 97 | Int(index, ..) => { 98 | let value = self.visit(value) 99 | arr[index] = value 100 | } 101 | _ => () 102 | } 103 | } 104 | Map(map) => { 105 | let index = self.visit(index) 106 | let value = self.visit(value) 107 | map.set(index, value) 108 | } 109 | Object({ ty, .. }) => { 110 | let index = self.visit(index) 111 | let value = self.visit(value) 112 | if ty.find_method("_[_]=_") is Some((pkg, func)) { 113 | if func is Fn({ val: func, .. }) { 114 | func({ 115 | context: self, 116 | pkg, 117 | args: [ 118 | RuntimeArgument::{ val: array_value, kind: Positional }, 119 | RuntimeArgument::{ val: index, kind: Positional }, 120 | RuntimeArgument::{ val: value, kind: Positional }, 121 | ], 122 | }) 123 | |> ignore 124 | } 125 | } 126 | } 127 | _ => raise Error("Unsupported array set operation") 128 | } 129 | Unit 130 | } 131 | -------------------------------------------------------------------------------- /src/test/iteration.mbt: -------------------------------------------------------------------------------- 1 | // Iteration-related test cases 2 | 3 | ///| 4 | test "foreach_loop" { 5 | let vm = MoonBitVM::new() 6 | // Test simple for-in loop with array 7 | inspect( 8 | vm.eval( 9 | "let arr = [1, 2, 3]; let sum = 0; for x in arr { sum = sum + x }; sum", 10 | ), 11 | content="6", 12 | ) 13 | 14 | // Test for-in loop with range 15 | inspect( 16 | vm.eval("let sum = 0; for i in 0..<3 { sum = sum + i }; sum"), 17 | content="3", 18 | ) 19 | inspect( 20 | vm.eval( 21 | ( 22 | #|let mut result = "" 23 | #| for i, j in [3,2,1] { 24 | #| result += " i_\{i} = \{j} " 25 | #|} 26 | #|result 27 | ), 28 | ), 29 | content=" i_0 = 3 i_1 = 2 i_2 = 1 ", 30 | ) 31 | } 32 | 33 | ///| 34 | test "array_iteration" { 35 | let vm = MoonBitVM::new() 36 | // 测试循环变量名不冲突的情况 37 | assert_eq( 38 | vm 39 | .eval("let mut sum = 0; for item in [1, 2, 3] { sum = sum + item }; sum") 40 | .to_string(), 41 | "6", 42 | ) 43 | // 测试循环变量名可能冲突的情况 44 | assert_eq( 45 | vm 46 | .eval("let mut sum = 0; for x in [1, 2, 3] { sum = sum + x }; sum") 47 | .to_string(), 48 | "6", 49 | ) 50 | // 测试循环变量名与外部变量名相同的情况 51 | assert_eq( 52 | vm 53 | .eval("let mut sum = 0; for sum in [1, 2, 3] { println(sum) }; sum") 54 | .to_string(), 55 | "0", 56 | ) 57 | } 58 | 59 | ///| 60 | test "string_iteration" { 61 | let vm = MoonBitVM::new() 62 | assert_eq( 63 | vm 64 | .eval( 65 | "let mut result = \"\"; for c in \"abc\" { result = c + result }; result", 66 | ) 67 | .to_string(), 68 | "cba", 69 | ) 70 | } 71 | 72 | ///| 73 | test "map_iteration" { 74 | let vm = MoonBitVM::new() 75 | assert_eq( 76 | vm 77 | .eval( 78 | "let m = {\"a\": 1, \"b\": 2}; let sum = 0; for pair in m { sum = sum + pair.1 }; sum", 79 | ) 80 | .to_string(), 81 | "3", 82 | ) 83 | } 84 | 85 | ///| 86 | test "range_iteration" { 87 | let vm = MoonBitVM::new() 88 | assert_eq( 89 | vm.eval("let sum = 0; for i in 0..<3 { sum = sum + i }; sum").to_string(), 90 | "3", 91 | ) 92 | assert_eq( 93 | vm.eval("let sum = 0; for i in 1..=3 { sum = sum + i }; sum").to_string(), 94 | "6", 95 | ) 96 | } 97 | 98 | ///| 99 | test "break_continue_iteration" { 100 | let vm = MoonBitVM::new() 101 | assert_eq( 102 | vm 103 | .eval( 104 | "let mut sum = 0; for i in 0..<10 { if i == 3 { break }; sum = sum + i }; sum", 105 | ) 106 | .to_string(), 107 | "3", // 0+1+2=3 108 | ) 109 | assert_eq( 110 | vm 111 | .eval( 112 | "let mut sum = 0; for i in 0..<5 { if i == 2 { continue }; sum = sum + i }; sum", 113 | ) 114 | .to_string(), 115 | "8", // 0+1+3+4=8 116 | ) 117 | } 118 | 119 | ///| 120 | test "iterator_methods" { 121 | let vm = MoonBitVM::new() 122 | assert_eq( 123 | vm 124 | .eval( 125 | "let arr = [1, 2, 3]; let mut sum = 0; for x in arr.iter() { sum = sum + x }; sum", 126 | ) 127 | .to_string(), 128 | "6", 129 | ) 130 | assert_eq( 131 | vm 132 | .eval( 133 | "let str = \"hello\"; let mut count = 0; for c in str.iter() { count = count + 1 }; count", 134 | ) 135 | .to_string(), 136 | "5", 137 | ) 138 | assert_eq( 139 | vm 140 | .eval( 141 | "let map = {\"a\": 1, \"b\": 2}; let mut sum = 0; for pair in map.iter() { sum = sum + pair.1 }; sum", 142 | ) 143 | .to_string(), 144 | "3", 145 | ) 146 | } 147 | 148 | ///| 149 | test "nested_iteration" { 150 | let vm = MoonBitVM::new() 151 | assert_eq( 152 | vm 153 | .eval( 154 | "let arr1 = [1, 2]; let arr2 = [3, 4]; let mut sum = 0; for x in arr1 { for y in arr2 { sum = sum + x * y } }; sum", 155 | ) 156 | .to_string(), 157 | "21", // 1*3 + 1*4 + 2*3 + 2*4 = 3+4+6+8 = 21 158 | ) 159 | } 160 | 161 | ///| 162 | test "iterator_control_flow" { 163 | let vm = MoonBitVM::new() 164 | inspect(vm.eval("let arr = [1, 2, 3]"), content="()") 165 | inspect(vm.eval("arr.iter()"), content="") 166 | assert_eq( 167 | vm 168 | .eval( 169 | "let arr = [1, 2, 3, 4, 5]; let mut sum = 0; for x in arr.iter() { if x == 3 { continue }; if x > 4 { break }; sum = sum + x }; sum", 170 | ) 171 | .to_string(), 172 | "7", 173 | ) 174 | } 175 | -------------------------------------------------------------------------------- /src/interpreter/int.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub let int_methods : Map[String, RuntimeFunction] = { 3 | "lnot": int_lnot_fn, 4 | "land": int_land_fn, 5 | "lor": int_lor_fn, 6 | "lxor": int_lxor_fn, 7 | "shl": int_shl_fn, 8 | "shr": int_shr_fn, 9 | "compare": int_compare_fn, 10 | "is_pos": int_is_pos_fn, 11 | "is_neg": int_is_neg_fn, 12 | "ctz": int_ctz_fn, 13 | "clz": int_clz_fn, 14 | "popcnt": int_popcnt_fn, 15 | "to_string": int_to_string_fn, 16 | "unsafe_to_char": char_from_int_fn, 17 | "next_power_of_two": int_next_power_of_two_fn, 18 | "abs": int_abs_fn, 19 | } 20 | 21 | ///| 22 | pub let int_embedded_code : Map[String, RuntimeFunction] = { 23 | "%i32_lnot": int_lnot_fn, 24 | "%i32_land": int_land_fn, 25 | "%i32_lor": int_lor_fn, 26 | "%i32_lxor": int_lxor_fn, 27 | "%i32_shl": int_shl_fn, 28 | "%i32_shr": int_shr_fn, 29 | "%i32_eq": int_eq_fn, 30 | "%i32_compare": int_compare_fn, 31 | "%i32_is_pos": int_is_pos_fn, 32 | "%i32_is_neg": int_is_neg_fn, 33 | "%i32_ctz": int_ctz_fn, 34 | "%i32_clz": int_clz_fn, 35 | "%i32_popcnt": int_popcnt_fn, 36 | } 37 | 38 | // ===== 整数位运算 ===== 39 | 40 | ///| 41 | /// 整数按位取反 42 | let int_lnot_fn : RuntimeFunction = ctx => match ctx.args { 43 | [{ val: Int(i, ..), .. }] => Int(i.lnot(), raw=None) 44 | _ => Unit 45 | } 46 | 47 | ///| 48 | /// 整数按位与 49 | let int_land_fn : RuntimeFunction = ctx => match ctx.args { 50 | [{ val: Int(a, ..), .. }, { val: Int(b, ..), .. }] => Int(a & b, raw=None) 51 | _ => Unit 52 | } 53 | 54 | ///| 55 | /// 整数按位或 56 | let int_lor_fn : RuntimeFunction = ctx => match ctx.args { 57 | [{ val: Int(a, ..), .. }, { val: Int(b, ..), .. }] => Int(a | b, raw=None) 58 | _ => Unit 59 | } 60 | 61 | ///| 62 | /// 整数按位异或 63 | let int_lxor_fn : RuntimeFunction = ctx => match ctx.args { 64 | [{ val: Int(a, ..), .. }, { val: Int(b, ..), .. }] => Int(a ^ b, raw=None) 65 | _ => Unit 66 | } 67 | 68 | ///| 69 | /// 整数左移 70 | let int_shl_fn : RuntimeFunction = ctx => match ctx.args { 71 | [{ val: Int(a, ..), .. }, { val: Int(b, ..), .. }] => Int(a << b, raw=None) 72 | _ => Unit 73 | } 74 | 75 | ///| 76 | /// 整数右移 77 | let int_shr_fn : RuntimeFunction = ctx => match ctx.args { 78 | [{ val: Int(a, ..), .. }, { val: Int(b, ..), .. }] => Int(a >> b, raw=None) 79 | _ => Unit 80 | } 81 | 82 | // ===== 整数比较运算 ===== 83 | 84 | ///| 85 | /// 整数相等比较 86 | let int_eq_fn : RuntimeFunction = ctx => match ctx.args { 87 | [{ val: Int(a, ..), .. }, { val: Int(b, ..), .. }] => Bool(a == b) 88 | _ => Bool(false) 89 | } 90 | 91 | ///| 92 | /// 整数比较 93 | let int_compare_fn : RuntimeFunction = ctx => match ctx.args { 94 | [{ val: Int(a, ..), .. }, { val: Int(b, ..), .. }] => 95 | if a == b { 96 | Int(0, raw=None) 97 | } else if a > b { 98 | Int(1, raw=None) 99 | } else { 100 | Int(-1, raw=None) 101 | } 102 | _ => Int(0, raw=None) 103 | } 104 | 105 | ///| 106 | /// 整数是否为正 107 | let int_is_pos_fn : RuntimeFunction = ctx => match ctx.args { 108 | [{ val: Int(i, ..), .. }] => Bool(i > 0) 109 | _ => Bool(false) 110 | } 111 | 112 | ///| 113 | /// 整数是否为负 114 | let int_is_neg_fn : RuntimeFunction = ctx => match ctx.args { 115 | [{ val: Int(i, ..), .. }] => Bool(i < 0) 116 | _ => Bool(false) 117 | } 118 | 119 | // ===== 整数工具函数 ===== 120 | 121 | ///| 122 | /// 计算尾随零的个数 123 | let int_ctz_fn : RuntimeFunction = ctx => match ctx.args { 124 | [{ val: Int(i, ..), .. }] => Int(i.ctz(), raw=None) 125 | _ => Unit 126 | } 127 | 128 | ///| 129 | /// 计算前导零的个数 130 | let int_clz_fn : RuntimeFunction = ctx => match ctx.args { 131 | [{ val: Int(i, ..), .. }] => Int(i.clz(), raw=None) 132 | _ => Unit 133 | } 134 | 135 | ///| 136 | /// 计算设置位的个数 137 | let int_popcnt_fn : RuntimeFunction = ctx => match ctx.args { 138 | [{ val: Int(i, ..), .. }] => Int(i.popcnt(), raw=None) 139 | _ => Unit 140 | } 141 | 142 | ///| 143 | /// 整数转字符串 144 | let int_to_string_fn : RuntimeFunction = ctx => match ctx.args { 145 | [{ val: Int(i, ..), .. }] => String(i.to_string()) 146 | _ => Unit 147 | } 148 | 149 | ///| 150 | /// 计算不小于该整数的最小2的幂 151 | let int_next_power_of_two_fn : RuntimeFunction = ctx => match ctx.args { 152 | [{ val: Int(i, ..), .. }] => Int(i.next_power_of_two(), raw=None) 153 | _ => Unit 154 | } 155 | 156 | ///| 157 | let int_abs_fn : RuntimeFunction = ctx => match ctx.args { 158 | [{ val: Int(i, ..), .. }] => Int(i.abs(), raw=None) 159 | _ => Unit 160 | } 161 | -------------------------------------------------------------------------------- /src/interpreter/fs.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub let fs_package : RuntimePackage = { 3 | let env = RuntimeEnvironment::new() 4 | { 5 | name: "moonbitlang/x/fs", 6 | traits: Map::new(), 7 | stubs: core_stubs, 8 | type_definitions: Map::new(), 9 | type_derived_traits: Map::new(), 10 | constructors: Map::new(), 11 | struct_methods: Map::new(), 12 | type_aliases: Map::new(), 13 | trait_aliases: Map::new(), 14 | fn_aliases: Map::new(), 15 | trait_methods: Map::new(), 16 | values: fs_methods.map((_, v) => Fn({ val: v, ty: Internal })), 17 | env, 18 | deps: Map::new(), 19 | files: Map::new(), 20 | loaded: true, 21 | } 22 | } 23 | 24 | ///| 25 | pub let fs_methods : Map[String, RuntimeFunction] = { 26 | "read_file": fs_read_file_fn, 27 | "create_dir": fs_create_dir_fn, 28 | "write_file": fs_write_file_fn, 29 | "is_dir": fs_is_dir_fn, 30 | "is_file": fs_is_file_fn, 31 | "path_exists": fs_path_exists_fn, 32 | "read_dir": fs_read_dir_fn, 33 | "read_file_to_bytes": fs_read_file_to_bytes_fn, 34 | "read_file_to_string": fs_read_file_to_string_fn, 35 | "remove_dir": fs_remove_dir_fn, 36 | "remove_file": fs_remove_file_fn, 37 | "write_bytes_to_file": fs_write_bytes_to_file_fn, 38 | } 39 | 40 | ///| 41 | let fs_read_file_fn : RuntimeFunction = ctx => if ctx.args 42 | is [{ val: String(path), .. }] { 43 | Array( 44 | (@fs.read_dir(path) catch { IOError(msg) => raise Raise(String(msg)) }).map( 45 | String(_), 46 | ), 47 | ) 48 | } else { 49 | Unit 50 | } 51 | 52 | ///| 53 | let fs_create_dir_fn : RuntimeFunction = ctx => { 54 | if ctx.args is [{ val: String(path), .. }] { 55 | @fs.create_dir(path) catch { 56 | IOError(msg) => raise Raise(String(msg)) 57 | } 58 | } 59 | Unit 60 | } 61 | 62 | ///| 63 | let fs_write_file_fn : RuntimeFunction = ctx => { 64 | if ctx.args is [{ val: String(path), .. }, { val: String(content), .. }] { 65 | @fs.write_string_to_file(path, content) catch { 66 | IOError(msg) => raise Raise(String(msg)) 67 | } 68 | } 69 | Unit 70 | } 71 | 72 | ///| 73 | let fs_is_dir_fn : RuntimeFunction = ctx => if ctx.args 74 | is [{ val: String(path), .. }] { 75 | Bool(@fs.is_dir(path) catch { IOError(msg) => raise Raise(String(msg)) }) 76 | } else { 77 | Unit 78 | } 79 | 80 | ///| 81 | let fs_is_file_fn : RuntimeFunction = ctx => if ctx.args 82 | is [{ val: String(path), .. }] { 83 | Bool(@fs.is_file(path) catch { IOError(msg) => raise Raise(String(msg)) }) 84 | } else { 85 | Unit 86 | } 87 | 88 | ///| 89 | let fs_path_exists_fn : RuntimeFunction = ctx => if ctx.args 90 | is [{ val: String(path), .. }] { 91 | Bool(@fs.path_exists(path)) 92 | } else { 93 | Unit 94 | } 95 | 96 | ///| 97 | let fs_read_dir_fn : RuntimeFunction = ctx => if ctx.args 98 | is [{ val: String(path), .. }] { 99 | Array( 100 | (@fs.read_dir(path) catch { IOError(msg) => raise Raise(String(msg)) }).map( 101 | String(_), 102 | ), 103 | ) 104 | } else { 105 | Unit 106 | } 107 | 108 | ///| 109 | let fs_read_file_to_bytes_fn : RuntimeFunction = ctx => if ctx.args 110 | is [{ val: String(path), .. }] { 111 | Bytes( 112 | @fs.read_file_to_bytes(path) catch { 113 | IOError(msg) => raise Raise(String(msg)) 114 | }, 115 | ) 116 | } else { 117 | Unit 118 | } 119 | 120 | ///| 121 | let fs_read_file_to_string_fn : RuntimeFunction = ctx => if ctx.args 122 | is [{ val: String(path), .. }] { 123 | String( 124 | @fs.read_file_to_string(path) catch { 125 | IOError(msg) => raise Raise(String(msg)) 126 | }, 127 | ) 128 | } else { 129 | Unit 130 | } 131 | 132 | ///| 133 | let fs_remove_dir_fn : RuntimeFunction = ctx => { 134 | if ctx.args is [{ val: String(path), .. }] { 135 | @fs.remove_dir(path) catch { 136 | IOError(msg) => raise Raise(String(msg)) 137 | } 138 | } 139 | Unit 140 | } 141 | 142 | ///| 143 | let fs_remove_file_fn : RuntimeFunction = ctx => { 144 | if ctx.args is [{ val: String(path), .. }] { 145 | @fs.remove_file(path) catch { 146 | IOError(msg) => raise Raise(String(msg)) 147 | } 148 | } 149 | Unit 150 | } 151 | 152 | ///| 153 | let fs_write_bytes_to_file_fn : RuntimeFunction = ctx => { 154 | if ctx.args is [{ val: String(path), .. }, { val: Bytes(content), .. }] { 155 | @fs.write_bytes_to_file(path, content) catch { 156 | IOError(msg) => raise Raise(String(msg)) 157 | } 158 | } 159 | Unit 160 | } 161 | -------------------------------------------------------------------------------- /src/interpreter/module.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | let url_base = "https://moonbitlang-mooncakes.s3.us-west-2.amazonaws.com/user" 3 | 4 | ///| 5 | pub(all) struct RuntimeModule { 6 | meta : ModuleInfo 7 | pkgs : Map[String, RuntimePackage] 8 | } derive(ToJson) 9 | 10 | ///| 11 | /// 包元数据 12 | pub(all) struct ModuleInfo { 13 | name : String 14 | version : String? 15 | deps : Map[String, String]? 16 | readme : String? 17 | repository : String? 18 | license : String? 19 | keywords : Array[String]? 20 | description : String? 21 | source : String? 22 | } derive(Show, ToJson, FromJson) 23 | 24 | ///| 25 | pub async fn ModuleInfo::get_zip_url(self : ModuleInfo) -> String noraise { 26 | let v = self.version.map_or("", v => "/\{v}") 27 | "\{url_base}/\{self.name}\{v}.zip" 28 | } 29 | 30 | ///| 31 | pub(all) struct RuntimePackage { 32 | name : String 33 | traits : Map[String, @syntax.TraitDecl] 34 | // 函数别名存储 - 存储函数名到其实际实现的映射 35 | fn_aliases : Map[String, RuntimeValue] 36 | type_aliases : Map[String, WithType[@syntax.TypeDecl]] 37 | // trait 别名存储 - 存储 trait 名到其实际实现的映射 38 | trait_aliases : Map[String, WithType[@syntax.TraitDecl]] 39 | // 存根 - 存储函数名到其实际实现的映射 40 | stubs : Map[String, String] 41 | // 类型定义 42 | type_definitions : Map[String, @syntax.TypeDecl] 43 | // 类型派生的trait映射 - 存储类型名到其derive的trait列表 44 | type_derived_traits : Map[String, Array[String]] // type_name -> [trait_name] 45 | // 构造函数集合 - 存储构造函数名 46 | constructors : Map[String, String] // constructor_name -> type_name 47 | struct_methods : Map[String, Map[String, RuntimeValue]] 48 | // trait 方法存储 - 存储 trait_id -> method_name -> function 49 | trait_methods : Map[String, Map[String, RuntimeValue]] 50 | values : Map[String, RuntimeValue] 51 | mut env : RuntimeEnvironment 52 | deps : Map[String, RuntimePackage] 53 | files : Map[String, String] 54 | mut loaded : Bool 55 | } derive(ToJson) 56 | 57 | ///| 58 | /// 模块元数据构造函数 59 | pub fn ModuleInfo::new( 60 | name : String, 61 | version? : String, 62 | readme? : String, 63 | repository? : String, 64 | license? : String, 65 | keywords? : Array[String], 66 | description? : String, 67 | source? : String, 68 | deps? : Map[String, String], 69 | ) -> ModuleInfo { 70 | { 71 | name, 72 | version, 73 | deps, 74 | readme, 75 | repository, 76 | license, 77 | keywords, 78 | description, 79 | source, 80 | } 81 | } 82 | 83 | ///| 84 | pub fn RuntimePackage::new( 85 | pkg : String, 86 | deps? : Map[String, RuntimePackage], 87 | files? : Map[String, String], 88 | ) -> RuntimePackage { 89 | let env = RuntimeEnvironment::new() 90 | { 91 | name: pkg, 92 | traits: Map::new(), 93 | stubs: core_stubs, 94 | type_definitions: Map::new(), 95 | type_derived_traits: Map::new(), 96 | constructors: Map::new(), 97 | struct_methods: Map::new(), 98 | type_aliases: Map::new(), 99 | trait_aliases: Map::new(), 100 | fn_aliases: Map::new(), 101 | trait_methods: Map::new(), 102 | values: Map::new(), 103 | env, 104 | deps: deps.unwrap_or(Map::new()), 105 | files: files.unwrap_or(Map::new()), 106 | loaded: false, 107 | } 108 | } 109 | 110 | ///| 111 | pub fn RuntimePackage::find( 112 | self : RuntimePackage, 113 | name : String, 114 | ) -> RuntimeValue? { 115 | match self.env.find(name) { 116 | None => self.values.get(name) 117 | v => v 118 | } 119 | } 120 | 121 | ///| 122 | /// 构造 Constructor 123 | pub fn RuntimePackage::cons( 124 | self : RuntimePackage, 125 | name : String, 126 | args : Array[RuntimeValue], 127 | ) -> RuntimeValue { 128 | let fields = args.map(value => { name: None, value, mutable: false }) 129 | Constructor({ val: { name, fields }, ty: self.find_static_type(name) }) 130 | } 131 | 132 | ///| 133 | /// 构造带标签参数的 Constructor 134 | pub fn RuntimePackage::cons_with_labels( 135 | self : RuntimePackage, 136 | name : String, 137 | labeled_args : Array[(String?, RuntimeValue, Bool)], // (label, value, mutable) 138 | ) -> RuntimeValue { 139 | let fields = labeled_args.map(fn(arg) { 140 | let (label, value, mutable) = arg 141 | { name: label, value, mutable } 142 | }) 143 | Constructor({ val: { name, fields }, ty: self.find_static_type(name) }) 144 | } 145 | 146 | ///| 147 | /// 148 | /// 检查名称是否为构造函数 149 | pub fn RuntimePackage::is_constructor( 150 | self : RuntimePackage, 151 | name : String, 152 | ) -> Bool { 153 | // 直接检查构造函数集合 154 | self.constructors.contains(name) 155 | } 156 | -------------------------------------------------------------------------------- /src/interpreter/scope.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub enum RuntimeLocation { 3 | FunctionCall(String) 4 | ControlFlow(String) 5 | LetMut(String) 6 | } derive(Show) 7 | 8 | ///| 变量管理模块 9 | 10 | ///| 处理变量查找、设置和作用域管理 11 | 12 | ///| 13 | /// 在解释器中查找变量 14 | pub fn RuntimeEnvironment::find( 15 | self : RuntimeEnvironment, 16 | name : String, 17 | ) -> RuntimeValue? { 18 | let mut cur = Some(self) 19 | // traverse parent environments 20 | while cur is Some(env) { 21 | if env.values.get(name) is Some(v) { 22 | return Some(v) 23 | } 24 | cur = env.parent 25 | } 26 | None 27 | } 28 | 29 | ///| 30 | pub fn ClosureInterpreter::find_pkg( 31 | self : ClosureInterpreter, 32 | pkg_name : String, 33 | ) -> RuntimePackage { 34 | let current_module = self.current_pkg 35 | if current_module.deps.get(pkg_name) is Some(pkg) { 36 | self.load_package(pkg) 37 | pkg 38 | // 检查 main 模块的 deps (core_modules) 中是否有这个包 39 | } else if self.main_pkg.deps.get(pkg_name) is Some(pkg) { 40 | self.load_package(pkg) 41 | pkg 42 | } else { 43 | current_module 44 | } 45 | } 46 | 47 | ///| 48 | pub fn[T] ClosureInterpreter::with_ident( 49 | self : ClosureInterpreter, 50 | long_ident : @syntax.LongIdent, 51 | func : (RuntimePackage, String) -> T raise?, 52 | ) -> T raise? { 53 | let current_pkg = self.current_pkg 54 | match long_ident { 55 | Ident(name~) => { 56 | let f = current_pkg.type_aliases.get(name) 57 | let pkg = match f { 58 | Some(f) => 59 | match f.ty { 60 | Object(pkg~, ..) => pkg 61 | Option(_) => moonbitlang_core_option_module 62 | _ => current_pkg 63 | } 64 | None => current_pkg 65 | } 66 | func(pkg, name) 67 | } 68 | Dot(pkg~, id~) => 69 | if current_pkg.deps.get(pkg) is Some(pkg) { 70 | self.load_package(pkg) 71 | func(pkg, id) 72 | // 检查 main 模块的 deps (core_modules) 中是否有这个包 73 | } else if self.main_pkg.deps.get(pkg) is Some(pkg) { 74 | self.load_package(pkg) 75 | func(pkg, id) 76 | } else { 77 | func(current_pkg, id) 78 | } 79 | } 80 | } 81 | 82 | ///| 83 | /// 设置不可变变量 84 | pub fn RuntimeEnvironment::set( 85 | self : RuntimeEnvironment, 86 | name : String, 87 | value : RuntimeValue, 88 | ) -> Unit { 89 | self.values.set(name, value) 90 | self.mutable_vars.set(name, false) 91 | } 92 | 93 | ///| 94 | pub fn RuntimePackage::set( 95 | self : RuntimePackage, 96 | name : String, 97 | value : RuntimeValue, 98 | ) -> Unit { 99 | self.values.set(name, value) 100 | } 101 | 102 | ///| 103 | /// 设置可变变量 104 | pub fn RuntimeEnvironment::set_mutable_variable( 105 | self : RuntimeEnvironment, 106 | name : String, 107 | value : RuntimeValue, 108 | ) -> Unit { 109 | self.values.set(name, value) 110 | self.mutable_vars.set(name, true) 111 | } 112 | 113 | ///| 更新可变变量的值 114 | 115 | ///| 116 | /// 在可变变量数组中查找并更新指定变量 117 | pub fn RuntimeEnvironment::update( 118 | self : RuntimeEnvironment, 119 | name : String, 120 | new_value : RuntimeValue, 121 | ) -> Unit { 122 | let mut current_env = self 123 | // First check current environment 124 | if current_env.values.contains(name) { 125 | current_env.values.set(name, new_value) 126 | return 127 | } 128 | // Then traverse parent environments 129 | while current_env.parent is Some(parent) { 130 | current_env = parent 131 | if current_env.values.contains(name) { 132 | current_env.values.set(name, new_value) 133 | return 134 | } 135 | } 136 | } 137 | 138 | ///| 139 | /// 查找当前调用的函数名 140 | pub fn ClosureInterpreter::lookup_current_function( 141 | self : ClosureInterpreter, 142 | ) -> String { 143 | let buf = @buffer.new() 144 | self.call_stack.each(frame => if frame is FunctionCall(name) { 145 | buf.write_string("\{name} => ") 146 | }) 147 | buf.to_string() 148 | } 149 | 150 | ///| 151 | /// 创建新的作用域 152 | pub fn ClosureInterpreter::push_scope( 153 | self : ClosureInterpreter, 154 | loc : RuntimeLocation, 155 | ) -> Unit { 156 | self.call_stack.push(loc) 157 | // println(String::make(self.call_stack.length(), ' ') + loc.to_string() + "{") 158 | self.current_pkg.env = RuntimeEnvironment::new(parent=self.current_pkg.env) 159 | } 160 | 161 | ///| 162 | /// 销毁当前作用域 163 | pub fn ClosureInterpreter::pop_scope(self : ClosureInterpreter) -> Unit { 164 | // println(String::make(self.call_stack.length(), ' ') + self.call_stack.pop().to_string() + "}") 165 | self.call_stack.pop() |> ignore 166 | if self.current_pkg.env.parent is Some(parent) { 167 | self.current_pkg.env = parent 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/interpreter/control_flow.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | /// 控制流处理 - For、While、Try、Guard、Defer等 3 | 4 | ///| 5 | /// 处理 For 循环 6 | fn ClosureInterpreter::visit_for( 7 | self : ClosureInterpreter, 8 | binders : @list.List[(@syntax.Binder, @syntax.Expr)], 9 | condition : @syntax.Expr?, 10 | continue_block : @list.List[(@syntax.Binder, @syntax.Expr)], 11 | body : @syntax.Expr, 12 | for_else : @syntax.Expr?, 13 | ) -> RuntimeValue raise ControlFlow { 14 | // 初始化循环变量 15 | for binder_init in binders { 16 | match binder_init { 17 | (binder, init_expr) => { 18 | let init_value = self.visit(init_expr) 19 | self.current_pkg.env.set(binder.name, init_value) 20 | } 21 | } 22 | } 23 | 24 | // 执行更新块的辅助函数 25 | let execute_continue_block = () => for update_tuple in continue_block { 26 | match update_tuple { 27 | (binder, update_expr) => { 28 | let new_value = self.visit(update_expr) catch { _ => Unit } 29 | self.current_pkg.env.update(binder.name, new_value) 30 | } 31 | } 32 | } 33 | 34 | // 执行循环 35 | while true { 36 | // 检查循环条件 37 | let should_continue = match condition { 38 | Some(cond) => { 39 | let condition_result = self.visit(cond) catch { _ => Unit } 40 | match condition_result { 41 | Bool(value) => value 42 | _ => false 43 | } 44 | } 45 | None => true 46 | } 47 | if not(should_continue) { 48 | break 49 | } 50 | 51 | // 执行循环体,处理break和continue 52 | (self.visit_scoped(body, RuntimeLocation::ControlFlow("for")) catch { 53 | Break(value) => return value 54 | Continue(arr) => { 55 | if !arr.is_empty() { 56 | binders.eachi(fn(i, binder) { 57 | self.current_pkg.env.update(binder.0.name, arr[i]) 58 | }) 59 | } else { 60 | execute_continue_block() 61 | } 62 | continue 63 | } 64 | _ => Unit 65 | }) 66 | |> ignore 67 | execute_continue_block() 68 | } 69 | if for_else is Some(expr) { 70 | self.visit_scoped(expr, RuntimeLocation::ControlFlow("for else")) catch { 71 | _ => Unit 72 | } 73 | } else { 74 | Unit 75 | } 76 | } 77 | 78 | ///| 79 | /// 处理 While 循环 80 | fn ClosureInterpreter::visit_while( 81 | self : ClosureInterpreter, 82 | loop_cond : @syntax.Expr, 83 | loop_body : @syntax.Expr, 84 | while_else : @syntax.Expr?, 85 | ) -> RuntimeValue raise ControlFlow { 86 | let mut result = Unit 87 | let mut broke = false 88 | while true { 89 | let cond_result = self.visit(loop_cond) 90 | match cond_result { 91 | Bool(false) => break 92 | _ => () 93 | } 94 | 95 | // 执行循环体,处理break和continue 96 | (self.visit_scoped(loop_body, RuntimeLocation::ControlFlow("while")) catch { 97 | Break(value) => { 98 | result = value 99 | broke = true 100 | break 101 | } 102 | Continue(_) => continue 103 | e => raise e 104 | }) 105 | |> ignore 106 | } 107 | // 如果没有break,执行else分支 108 | if not(broke) { 109 | match while_else { 110 | Some(else_expr) => 111 | result = self.visit_scoped( 112 | else_expr, 113 | RuntimeLocation::ControlFlow("while"), 114 | ) 115 | None => () // 没有else分支 116 | } 117 | } 118 | result 119 | } 120 | 121 | ///| 122 | /// 处理 Guard 表达式 123 | fn ClosureInterpreter::visit_guard( 124 | self : ClosureInterpreter, 125 | cond : @syntax.Expr, 126 | otherwise : @syntax.Expr?, 127 | body : @syntax.Expr, 128 | ) -> RuntimeValue raise ControlFlow { 129 | let cond_val = self.visit(cond) 130 | match cond_val { 131 | Bool(true) => self.visit_scoped(body, RuntimeLocation::ControlFlow("guard")) 132 | Bool(false) => 133 | match otherwise { 134 | Some(expr) => 135 | self.visit_scoped(expr, RuntimeLocation::ControlFlow("guard else")) 136 | None => Unit 137 | } 138 | _ => Unit 139 | } 140 | } 141 | 142 | ///| 143 | /// 处理 Defer 表达式 144 | fn ClosureInterpreter::visit_defer( 145 | self : ClosureInterpreter, 146 | expr : @syntax.Expr, 147 | body : @syntax.Expr, 148 | ) -> RuntimeValue raise ControlFlow { 149 | let res = self.visit(body) 150 | self.visit(expr) |> ignore 151 | res 152 | } 153 | 154 | ///| 155 | /// 处理 Try 表达式 156 | fn ClosureInterpreter::visit_try( 157 | self : ClosureInterpreter, 158 | body : @syntax.Expr, 159 | catch_ : @list.List[@syntax.Case], 160 | ) -> RuntimeValue raise ControlFlow { 161 | self.visit(body) catch { 162 | Raise(value) => self.pattern_match(value, catch_) 163 | e => raise e 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/test/pattern_matching.mbt: -------------------------------------------------------------------------------- 1 | // ============================================================================= 2 | // PATTERN MATCHING TESTS 3 | // ============================================================================= 4 | 5 | ///| 6 | test "basic_pattern_matching" { 7 | let vm = MoonBitVM::new() 8 | inspect( 9 | vm.eval( 10 | ( 11 | #|match 5 { 12 | #| 1 => "one" 13 | #| 2 => "two" 14 | #| x => "other: " + x.to_string() 15 | #|} 16 | ), 17 | ), 18 | content="other: 5", 19 | ) 20 | inspect( 21 | vm.eval( 22 | ( 23 | #|match 2 { 24 | #| 1 => "one" 25 | #| 2 => "two" 26 | #| x => "other: " + x.to_string() 27 | #|} 28 | ), 29 | ), 30 | content="two", 31 | ) 32 | } 33 | 34 | ///| 35 | test "or_patterns" { 36 | let vm = MoonBitVM::new() 37 | inspect( 38 | vm.eval( 39 | ( 40 | #|match 3 { 41 | #| 1 | 2 | 3 => "small" 42 | #| _ => "large" 43 | #|} 44 | ), 45 | ), 46 | content="small", 47 | ) 48 | inspect( 49 | vm.eval( 50 | ( 51 | #|match 5 { 52 | #| 1 | 2 | 3 => "small" 53 | #| _ => "large" 54 | #|} 55 | ), 56 | ), 57 | content="large", 58 | ) 59 | } 60 | 61 | ///| 62 | test "tuple_patterns" { 63 | let vm = MoonBitVM::new() 64 | inspect( 65 | vm.eval( 66 | ( 67 | #|match (1, 2) { 68 | #| (0, y) => "first is zero, second is " + y.to_string() 69 | #| (x, 0) => "first is " + x.to_string() + ", second is zero" 70 | #| (x, y) => "first is " + x.to_string() + ", second is " + y.to_string() 71 | #|} 72 | ), 73 | ), 74 | content="first is 1, second is 2", 75 | ) 76 | } 77 | 78 | ///| 79 | test "array_patterns" { 80 | let vm = MoonBitVM::new() 81 | inspect( 82 | vm.eval( 83 | ( 84 | #|match [1, 2, 3] { 85 | #| [] => "empty" 86 | #| [x] => "single: " + x.to_string() 87 | #| [x, y] => "pair: " + x.to_string() + ", " + y.to_string() 88 | #| [x, y, z] => "triple: " + x.to_string() + ", " + y.to_string() + ", " + z.to_string() 89 | #| _ => "other" 90 | #|} 91 | ), 92 | ), 93 | content="triple: 1, 2, 3", 94 | ) 95 | } 96 | 97 | ///| 98 | test "record_patterns" { 99 | let vm = MoonBitVM::new() 100 | inspect( 101 | vm.eval( 102 | ( 103 | #|struct Point { x : Int; y : Int } 104 | #|let p = { x: 1, y: 2 } 105 | #|match p { 106 | #| { x: 0, y } => "x is zero, y is " + y.to_string() 107 | #| { x, y: 0 } => "x is " + x.to_string() + ", y is zero" 108 | #| { x, y } => "x is " + x.to_string() + ", y is " + y.to_string() 109 | #|} 110 | ), 111 | ), 112 | content="x is 1, y is 2", 113 | ) 114 | } 115 | 116 | ///| 117 | test "nested_patterns" { 118 | let vm = MoonBitVM::new() 119 | inspect( 120 | vm.eval( 121 | ( 122 | #|match (Some(1), Some(2)) { 123 | #| (Some(x), Some(y)) => "both some: " + x.to_string() + ", " + y.to_string() 124 | #| (Some(x), None) => "first some: " + x.to_string() 125 | #| (None, Some(y)) => "second some: " + y.to_string() 126 | #| (None, None) => "both none" 127 | #|} 128 | ), 129 | ), 130 | content="both some: 1, 2", 131 | ) 132 | } 133 | 134 | ///| 135 | test "range_patterns" { 136 | let vm = MoonBitVM::new() 137 | inspect( 138 | vm.eval( 139 | ( 140 | #|match 5 { 141 | #| 1..=3 => "low" 142 | #| 4..=6 => "medium" 143 | #| 7..=9 => "high" 144 | #| _ => "other" 145 | #|} 146 | ), 147 | ), 148 | content="medium", 149 | ) 150 | } 151 | 152 | ///| 153 | test "constructor_patterns" { 154 | let vm = MoonBitVM::new() 155 | inspect( 156 | vm.eval( 157 | ( 158 | #|enum Color { 159 | #| Red 160 | #| Green 161 | #| Blue 162 | #| RGB(Int, Int, Int) 163 | #|} 164 | #|let color = RGB(255, 0, 0) 165 | #|match color { 166 | #| Red => "red" 167 | #| Green => "green" 168 | #| Blue => "blue" 169 | #| RGB(r, g, b) => "rgb(" + r.to_string() + ", " + g.to_string() + ", " + b.to_string() + ")" 170 | #|} 171 | ), 172 | ), 173 | content="rgb(255, 0, 0)", 174 | ) 175 | } 176 | 177 | ///| 178 | test "match_as_pattern" { 179 | let vm = MoonBitVM::new() 180 | inspect( 181 | vm.eval( 182 | ( 183 | #|match Some(42) { 184 | #| Some(x) as opt => "value: " + x.to_string() 185 | #| None => "none" 186 | #|} 187 | ), 188 | ), 189 | content="value: 42", 190 | ) 191 | } 192 | -------------------------------------------------------------------------------- /.trae/rules/project_rules.md: -------------------------------------------------------------------------------- 1 | 使用 moon test 测试,不要创建 temp 或者 debug 文件来测试,可以修改src/test.mbt文件在调用 moon test 来测试 2 | moon test -h 3 | Test the current package 4 | 5 | Usage: moon test [OPTIONS] [SINGLE_FILE] 6 | 7 | Options: 8 | --std Enable the standard library (default) 9 | --nostd Disable the standard library 10 | -g, --debug Emit debug information 11 | --release Compile in release mode 12 | --strip Enable stripping debug information 13 | --no-strip Disable stripping debug information 14 | --target Select output target [possible values: wasm, wasm-gc, js, native, llvm, all] 15 | --enable-coverage Enable coverage instrumentation 16 | --sort-input Sort input files 17 | --output-wat Output WAT instead of WASM 18 | -d, --deny-warn Treat all warnings as errors 19 | --no-render Don't render diagnostics from moonc (don't pass '-error-format json' to moonc) 20 | --warn-list Warn list config 21 | --alert-list Alert list config 22 | -j, --jobs Set the max number of jobs to run in parallel 23 | --render-no-loc Render no-location diagnostics starting from a certain level [default: error] [possible values: info, warn, error] 24 | -p, --package [...] Run test in the specified package 25 | -f, --file Run test in the specified file. Only valid when `--package` is also specified 26 | -i, --index Run only the index-th test in the file. Only valid when `--file` is also specified 27 | --doc-index Run only the index-th doc test in the file. Only valid when `--file` is also specified 28 | -u, --update Update the test snapshot 29 | -l, --limit Limit of expect test update passes to run, in order to avoid infinite loops [default: 256] 30 | -h, --help Print help 31 | 32 | Manifest Options: 33 | --frozen Do not sync dependencies, assuming local dependencies are up-to-date 34 | --build-only Only build, do not run the tests 35 | --no-parallelize Run the tests in a target backend sequentially 36 | --test-failure-json Print failure message in JSON format 37 | --patch-file Path to the patch file 38 | --doc Run doc test 39 | [SINGLE_FILE] Run test in single file (.mbt or .mbt.md) 40 | 41 | Common Options: 42 | -C, --directory The source code directory. Defaults to the current directory 43 | --target-dir The target directory. Defaults to `source_dir/target` 44 | -q, --quiet Suppress output 45 | -v, --verbose Increase verbosity 46 | --trace Trace the execution of the program 47 | --dry-run Do not actually run the command 48 | --build-graph Generate build graph 49 | 50 | # Project Agents.md Guide 51 | 52 | This is a [MoonBit](https://docs.moonbitlang.com) project. 53 | 54 | ## Project Structure 55 | 56 | - MoonBit packages are organized per directory, for each directory, there is a 57 | `package.json` file listing its dependencies. Each package has its files and 58 | blackbox test files (common, ending in `_test.mbt`) and whitebox test files 59 | (ending in `_wbtest.mbt`). 60 | 61 | - In the toplevel directory, this is a `moon.mod.json` file listing about the 62 | module and some meta information. 63 | 64 | ## Coding convention 65 | 66 | - MoonBit code is organized in block style, each block is separated by `///|`, 67 | the order of each block is irrelevant. In some refactorings, you can process 68 | block by block independently. 69 | 70 | - Try to keep deprecated blocks in file called `deprecated.mbt` in each 71 | directory. 72 | 73 | ## Tooling 74 | 75 | - `moon fmt` is used to format your code properly. 76 | 77 | - `moon info` is used to update the generated interface of the package, each 78 | package has a generated interface file `.mbti`, it is a brief formal 79 | description of the package. If nothing in `.mbti` changes, this means your 80 | change does not bring the visible changes to the external package users, it is 81 | typically a safe refactoring. 82 | 83 | - In the last step, run `moon info && moon fmt` to update the interface and 84 | format the code. Check the diffs of `.mbti` file to see if the changes are 85 | expected. 86 | 87 | - Run `moon test` to check the test is passed. MoonBit supports snapshot 88 | testing, so when your changes indeed change the behavior of the code, you 89 | should run `moon test --update` to update the snapshot. 90 | 91 | - You can run `moon check` to check the code is linted correctly. 92 | 93 | - When writing tests, you are encouraged to use `inspect` and run 94 | `moon test --update` to update the snapshots, only use assertions like 95 | `assert_eq` when you are in some loops where each snapshot may vary. You can 96 | use `moon coverage analyze > uncovered.log` to see which parts of your code 97 | are not covered by tests. 98 | 99 | - agent-todo.md has some small tasks that are easy for AI to pick up, agent is 100 | welcome to finish the tasks and check the box when you are done 101 | -------------------------------------------------------------------------------- /src/interpreter/type_constraints.mbt: -------------------------------------------------------------------------------- 1 | ///| 类型约束检查模块 - 专门处理类型约束验证逻辑 2 | 3 | ///| 4 | /// 检查运行时值是否满足类型约束 5 | pub fn RuntimePackage::check_type_constraint( 6 | _self : RuntimePackage, 7 | value : RuntimeValue, 8 | constraint : @syntax.Type, 9 | ) -> Bool { 10 | match (value, constraint) { 11 | // 基本类型检查 12 | ( 13 | Bool(_), 14 | Name(constr_id={ id: Ident(name="Bool") | Dot(id="Bool", ..), .. }, ..), 15 | ) 16 | | ( 17 | Int(_), 18 | Name(constr_id={ id: Ident(name="Int") | Dot(id="Int", ..), .. }, ..), 19 | ) 20 | | ( 21 | UInt(_), 22 | Name(constr_id={ id: Ident(name="UInt") | Dot(id="UInt", ..), .. }, ..), 23 | ) 24 | | ( 25 | Int64(_), 26 | Name(constr_id={ id: Ident(name="Int64") | Dot(id="Int64", ..), .. }, ..), 27 | ) 28 | | ( 29 | UInt16(_), 30 | Name( 31 | constr_id={ id: Ident(name="UInt16") | Dot(id="UInt16", ..), .. }, 32 | .. 33 | ), 34 | ) 35 | | ( 36 | UInt64(_), 37 | Name( 38 | constr_id={ id: Ident(name="UInt64") | Dot(id="UInt64", ..), .. }, 39 | .. 40 | ), 41 | ) 42 | | ( 43 | Float(_), 44 | Name(constr_id={ id: Ident(name="Float") | Dot(id="Float", ..), .. }, ..), 45 | ) 46 | | ( 47 | Double(_), 48 | Name( 49 | constr_id={ id: Ident(name="Double") | Dot(id="Double", ..), .. }, 50 | .. 51 | ), 52 | ) 53 | | ( 54 | String(_), 55 | Name( 56 | constr_id={ id: Ident(name="String") | Dot(id="String", ..), .. }, 57 | .. 58 | ), 59 | ) 60 | | ( 61 | Char(_), 62 | Name(constr_id={ id: Ident(name="Char") | Dot(id="Char", ..), .. }, ..), 63 | ) 64 | | ( 65 | Byte(_), 66 | Name(constr_id={ id: Ident(name="Byte") | Dot(id="Byte", ..), .. }, ..), 67 | ) 68 | | ( 69 | BigInt(_), 70 | Name( 71 | constr_id={ id: Ident(name="BigInt") | Dot(id="BigInt", ..), .. }, 72 | .. 73 | ), 74 | ) 75 | 76 | // 复合类型检查 77 | | ( 78 | Array(_), 79 | Name(constr_id={ id: Ident(name="Array") | Dot(id="Array", ..), .. }, ..), 80 | ) 81 | | ( 82 | Tuple(_), 83 | Name(constr_id={ id: Ident(name="Tuple") | Dot(id="Tuple", ..), .. }, ..), 84 | ) 85 | | ( 86 | Map(_), 87 | Name(constr_id={ id: Ident(name="Map") | Dot(id="Map", ..), .. }, ..), 88 | ) 89 | 90 | // Unit 类型 91 | | ( 92 | Unit, 93 | Name(constr_id={ id: Ident(name="Unit") | Dot(id="Unit", ..), .. }, ..), 94 | ) 95 | 96 | // Json 类型检查 97 | | ( 98 | Json(_), 99 | Name(constr_id={ id: Ident(name="Json") | Dot(id="Json", ..), .. }, ..), 100 | ) 101 | 102 | // Any 类型总是匹配 103 | | (_, Any(..)) 104 | | (_, Name(constr_id={ id: Ident(name="Any") | Dot(id="Any", ..), .. }, ..)) 105 | 106 | // Option 类型检查 107 | | (_, Option(..)) 108 | | ( 109 | _, 110 | Name( 111 | constr_id={ id: Ident(name="Option") | Dot(id="Option", ..), .. }, 112 | .. 113 | ), 114 | ) => true 115 | 116 | // TODO: call equal 117 | // 构造函数类型检查 118 | ( 119 | Constructor({ ty: Name(name=name1, ..), val: { fields, .. } }), 120 | Name(constr_id={ id: Ident(name=name2), .. }, tys~, ..), 121 | ) => 122 | name1 == name2 && 123 | fields.length() == tys.length() && 124 | (for idx, ty in tys { 125 | if !check_type_constraint2(fields[idx].value.get_type(), ty) { 126 | break false 127 | } 128 | } else { 129 | true 130 | }) 131 | ( 132 | Object({ ty: Object(pkg={ name: pkg1, .. }, name=name1), .. }), 133 | Object({ id: Dot(pkg=pkg2, id=name2), .. }), 134 | ) => name1 == name2 && pkg1 == pkg2 135 | ( 136 | Object({ ty: Object(name=name1, ..), .. }), 137 | Object({ id: Ident(name=name2), .. }), 138 | ) => name1 == name2 139 | 140 | // 默认情况:类型不匹配 141 | _ => false 142 | } 143 | } 144 | 145 | ///| 146 | pub fn check_type_constraint2( 147 | value : RuntimeType, 148 | constraint : @syntax.Type, 149 | ) -> Bool { 150 | match (value, constraint) { 151 | (Arrow(_), Arrow(_)) => true 152 | (Tuple(tys1), Tuple(tys=tys2, ..)) => 153 | tys1.length() == tys2.length() && 154 | { 155 | let tys2 = tys2.to_array() 156 | for idx, ty in tys1 { 157 | if !check_type_constraint2(ty, tys2[idx]) { 158 | break false 159 | } 160 | } else { 161 | true 162 | } 163 | } 164 | ( 165 | Name(name=name1, tys=tys1, ..), 166 | Name(constr_id={ id: Ident(name=name2), .. }, tys=tys2, ..), 167 | ) => 168 | name1 == name2 && 169 | tys1.length() == tys2.length() && 170 | { 171 | let tys2 = tys2.to_array() 172 | for idx, ty in tys1 { 173 | if !check_type_constraint2(ty, tys2[idx]) { 174 | break false 175 | } 176 | } else { 177 | true 178 | } 179 | } 180 | ( 181 | Object(pkg={ name: pkg1, .. }, name=name1), 182 | Object({ id: Dot(pkg=pkg2, id=name2), .. }), 183 | ) => name1 == name2 && pkg1 == pkg2 184 | (Object(name=name1, ..), Object({ id: Ident(name=name2), .. })) => 185 | name1 == name2 186 | (Option(ty1), Option(ty=ty2, ..)) => check_type_constraint2(ty1, ty2) 187 | ( 188 | Option(ty), 189 | Name( 190 | constr_id={ id: Ident(name="Option") | Dot(id="Option", ..), .. }, 191 | .. 192 | ), 193 | ) => check_type_constraint2(ty, constraint) 194 | _ => false 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/test/literal_overloading.mbt: -------------------------------------------------------------------------------- 1 | // Literal overloading test cases 2 | 3 | ///| 4 | test "char_literals" { 5 | let vm = MoonBitVM::new() 6 | // Test character literals and conversions 7 | inspect(vm.eval("let c : Char = '1'"), content="()") 8 | assert_eq(vm.eval("c").to_string(), "1") 9 | inspect(vm.eval("let i : Int = '1'"), content="()") 10 | assert_eq(vm.eval("i").to_string(), "49") 11 | } 12 | 13 | ///| 14 | test "numeric_literal_overloading" { 15 | let vm = MoonBitVM::new() 16 | 17 | // Int -> UInt conversion 18 | inspect(vm.eval("let u : UInt = 42"), content="()") 19 | assert_eq(vm.eval("typeof(u)").to_string(), "@moonbitlang/core/uint.UInt") 20 | assert_eq(vm.eval("u").to_string(), "42") 21 | 22 | // Int -> Int64 conversion 23 | inspect(vm.eval("let i64 : Int64 = 123"), content="()") 24 | assert_eq(vm.eval("typeof(i64)").to_string(), "@moonbitlang/core/int64.Int64") 25 | assert_eq(vm.eval("i64").to_string(), "123") 26 | 27 | // Int -> UInt64 conversion 28 | inspect(vm.eval("let u64 : UInt64 = 456"), content="()") 29 | assert_eq( 30 | vm.eval("typeof(u64)").to_string(), 31 | "@moonbitlang/core/uint64.UInt64", 32 | ) 33 | assert_eq(vm.eval("u64").to_string(), "456") 34 | 35 | // Int -> UInt16 conversion 36 | assert_eq(vm.eval("let u16 : UInt16 = 789").to_string(), "()") 37 | assert_eq(vm.eval("u16").to_string(), "789") 38 | assert_eq( 39 | vm.eval("typeof(u16)").to_string(), 40 | "@moonbitlang/core/uint16.UInt16", 41 | ) 42 | 43 | // Int -> Byte conversion 44 | inspect(vm.eval("let b : Byte = 255"), content="()") 45 | assert_eq(vm.eval("typeof(b)").to_string(), "@moonbitlang/core/byte.Byte") 46 | assert_eq(vm.eval("b").to_string(), "255") 47 | 48 | // Int -> Double conversion 49 | inspect(vm.eval("let d : Double = 42"), content="()") 50 | assert_eq(vm.eval("typeof(d)").to_string(), "@moonbitlang/core/double.Double") 51 | assert_eq(vm.eval("d").to_string(), "42") 52 | 53 | // Int -> Float conversion 54 | inspect(vm.eval("let f : Float = 42"), content="()") 55 | assert_eq(vm.eval("typeof(f)").to_string(), "@moonbitlang/core/float.Float") 56 | assert_eq(vm.eval("f").to_string(), "42") 57 | } 58 | 59 | ///| 60 | test "char_literal_overloading" { 61 | let vm = MoonBitVM::new() 62 | 63 | // Char -> Int conversion (ASCII value) 64 | inspect(vm.eval("let i : Int = 'A'"), content="()") 65 | assert_eq(vm.eval("i").to_string(), "65") 66 | 67 | // Char -> Byte conversion 68 | inspect(vm.eval("let b : Byte = 'Z'"), content="()") 69 | assert_eq(vm.eval("b").to_string(), "90") 70 | 71 | // Multiple char conversions 72 | inspect(vm.eval("let zero : Int = '0'"), content="()") 73 | assert_eq(vm.eval("zero").to_string(), "48") 74 | inspect(vm.eval("let nine : Int = '9'"), content="()") 75 | assert_eq(vm.eval("nine").to_string(), "57") 76 | } 77 | 78 | ///| 79 | test "string_literal_overloading" { 80 | let vm = MoonBitVM::new() 81 | 82 | // simple string to bytes conversion 83 | assert_eq(vm.eval("(\"hello\" as Bytes)").to_string(), "b\"hello\"") 84 | 85 | // String -> Bytes conversion - test in single eval call 86 | // Verify the type is correctly converted to Bytes 87 | assert_eq(vm.eval("let b : Bytes = \"hello\"; b.length()").to_string(), "5") 88 | inspect(vm.eval("typeof(b)"), content="@moonbitlang/core/bytes.Bytes") 89 | } 90 | 91 | ///| 92 | test "array_literal_overloading" { 93 | let vm = MoonBitVM::new() 94 | 95 | // Array of Ints -> Bytes conversion 96 | assert_eq( 97 | vm.eval("let bytes : Bytes = [72, 101, 108, 108, 111]").to_string(), 98 | "()", 99 | ) 100 | assert_eq( 101 | vm.eval("typeof(bytes)").to_string(), 102 | "@moonbitlang/core/bytes.Bytes", 103 | ) 104 | // Verify it's converted to Bytes type 105 | assert_eq( 106 | vm.eval("bytes.length()").to_string(), 107 | ( 108 | #|5 109 | ), 110 | ) 111 | 112 | // Array of Chars -> String conversion 113 | inspect(vm.eval("let str : String = ['H', 'i']"), content="()") 114 | assert_eq(vm.eval("str").to_string(), "Hi") 115 | 116 | // Array -> ArrayView conversion 117 | inspect(vm.eval("let view : ArrayView[Int] = [1, 2, 3, 4, 5]"), content="()") 118 | inspect(vm.eval("typeof(view)"), content="@moonbitlang/core/array.ArrayView") 119 | // Verify it's converted to ArrayView type 120 | inspect(vm.eval("view"), content="[1, 2, 3, 4, 5]") 121 | } 122 | 123 | ///| 124 | test "double_literal_overloading" { 125 | let vm = MoonBitVM::new() 126 | 127 | // Double -> Float conversion (precision may vary) 128 | let float_result = vm.eval("(3.14 : Float)").to_string() 129 | assert_true(float_result.contains("3.14")) 130 | 131 | // Large double -> Float (precision test) 132 | inspect(vm.eval("let big_f : Float = 123.456789"), content="()") 133 | inspect(vm.eval("typeof(big_f)"), content="@moonbitlang/core/float.Float") 134 | let result = vm.eval("big_f").to_string() 135 | // Float should have the value (precision may differ) 136 | assert_true(result.contains("123")) 137 | } 138 | 139 | ///| 140 | test "complex_overloading_scenarios" { 141 | let vm = MoonBitVM::new() 142 | 143 | // Mixed type array with overloading 144 | inspect(vm.eval("let mixed_bytes : Bytes = [65, 66, 67]"), content="()") 145 | let mixed_result = vm.eval("mixed_bytes") 146 | assert_eq(mixed_result.to_string() == "[65, 66, 67]", false) 147 | 148 | // Nested overloading in expressions (test direct evaluation) 149 | assert_eq(vm.eval("((10 + 20) as UInt)").to_string(), "30") 150 | 151 | // Function parameter overloading 152 | inspect( 153 | vm.eval("fn test_param(x : UInt64) -> UInt64 { x }"), 154 | content="(UInt64) -> UInt64", 155 | ) 156 | inspect(vm.eval("test_param(42)"), content="42") 157 | } 158 | 159 | ///| 160 | test "overloading_edge_cases" { 161 | let vm = MoonBitVM::new() 162 | 163 | // Zero values 164 | inspect(vm.eval("let zero_uint : UInt = 0"), content="()") 165 | assert_eq(vm.eval("zero_uint").to_string(), "0") 166 | 167 | // Negative to unsigned (should handle gracefully) 168 | // Note: This might fail or wrap around depending on implementation 169 | // inspect(vm.eval("let neg_uint : UInt = -1"), content="()") 170 | 171 | // Maximum values for small types 172 | inspect(vm.eval("let max_byte : Byte = 255"), content="()") 173 | assert_eq(vm.eval("max_byte").to_string(), "255") 174 | 175 | // Empty array overloading 176 | inspect(vm.eval("let empty_bytes : Bytes = []"), content="()") 177 | let empty_result = vm.eval("empty_bytes") 178 | assert_eq(empty_result.to_string() == "[]", false) 179 | } 180 | -------------------------------------------------------------------------------- /src/test/packages.mbt: -------------------------------------------------------------------------------- 1 | // ============================================================================= 2 | // PACKAGE SYSTEM TESTS 3 | // ============================================================================= 4 | // Tests for module system, package imports, and cross-package method calls 5 | 6 | ///| 7 | test "module" { 8 | let vm = MoonBitVM::new() 9 | assert_eq(vm.eval("let max_value = 1").to_string(), "()") 10 | assert_eq(vm.eval("max_value").to_string(), "1") 11 | assert_eq(vm.eval("@int.max_value").to_string(), "2147483647") 12 | // println(vm.interpreter.current_pkg.deps["int"].env.values["max_value"]) 13 | // println(vm.interpreter.current_pkg.deps["int"].struct_methods) 14 | // println(vm.interpreter.current_pkg.deps["int"].struct_methods["Int"]) 15 | // println(vm.interpreter.current_pkg.deps["int"].struct_methods["Int"]["abs"]) 16 | inspect(vm.eval("@int.abs(-1)"), content="1") 17 | inspect(Int::abs(-1), content="1") 18 | } 19 | 20 | ///| 21 | test "math" { 22 | let vm = MoonBitVM::new() 23 | assert_eq(vm.eval("@math.abs(-1.0)").to_string(), "1") 24 | assert_eq(vm.eval("@math.abs").to_string(), "(Double) -> Double") 25 | } 26 | 27 | ///| 28 | test "bigint" { 29 | let vm = MoonBitVM::new() 30 | assert_eq(vm.eval("@bigint.zero").to_string(), "0") 31 | assert_eq(vm.eval("@bigint.radix_bit_len").to_string(), "32") 32 | } 33 | 34 | ///| 35 | test "cmp" { 36 | let vm = MoonBitVM::new() 37 | assert_eq(vm.eval("@cmp.maximum").to_string(), "(T, T) -> T") 38 | assert_eq(vm.eval("@cmp.minimum").to_string(), "(T, T) -> T") 39 | assert_eq(vm.eval("@cmp.maximum(1, 2)").to_string(), "2") 40 | assert_eq(vm.eval("@cmp.minimum(1, 2)").to_string(), "1") 41 | } 42 | 43 | ///| 44 | test "cross_package_method_calling" { 45 | let vm = MoonBitVM::new() 46 | assert_eq( 47 | vm.eval("let list = @list.from_array([1,2,3]); list").to_string(), 48 | "More(1, tail=More(2, tail=More(3, tail=Empty)))", 49 | ) 50 | assert_eq(vm.eval("list.to_array()").to_string(), "[1, 2, 3]") 51 | assert_eq( 52 | vm.eval("let arr1 : Array[Int] = [1, 2, 3, 4, 5]").to_string(), 53 | "()", 54 | ) 55 | assert_eq(vm.eval("arr1.length()").to_string(), "5") 56 | } 57 | 58 | // ///| 59 | // test "online_package" { 60 | // let vm = MoonBitVM::new() 61 | // @mio.run(() => { 62 | // let modules = try? @mooncakes.load_module("wangweigang/hello") 63 | // if modules is Ok(modules) { 64 | // vm.interpreter.main_pkg.deps.set( 65 | // "hello", 66 | // modules.get("wangweigang/hello").unwrap().pkgs["hello"], 67 | // ) 68 | // println(vm.eval("@hello.hello()")) 69 | // } 70 | // }) 71 | // } 72 | 73 | // ///| 74 | // test { 75 | // @mio.run(fn() { 76 | // async fn load(mod_name) noraise { 77 | // let url = "https://mooncakes.io/assets/\{mod_name}/resource.json" 78 | // let info = try? @mio.get(url).unwrap_json() 79 | // if info is Ok(a) { 80 | // let json = a 81 | // println(json) 82 | // } else { 83 | // abort("Failed to get resource.json") 84 | // } 85 | // } 86 | 87 | // load("oboard/mimetype") 88 | // }) 89 | // } 90 | 91 | ///| 92 | // test { 93 | // @mio.run(fn() { 94 | // let module_name = "oboard/mimetype" 95 | // if (try? @mooncakes.load_meta(module_name)) is Ok(a) { 96 | // let res = try? @mio.get(a.get_zip_url()) 97 | // if res is Ok(res) { 98 | // if (try? @zip.Archive::of_bytes(res.data)) is Ok(zip) { 99 | // if zip.find(@fpath.Fpath("moon.mod.json")) is Some(m) { 100 | // if m.kind() is File(data) { 101 | // let module_info : @interpreter.ModuleInfo = @json.from_json( 102 | // @json.parse(@encoding/utf8.decode(data.to_bytes())), 103 | // ) catch { 104 | // _ => abort("Failed to read moon.mod.json") 105 | // } 106 | // // println(module_info) 107 | // let root = if module_info.source is Some(source) { 108 | // source 109 | // } else { 110 | // "" 111 | // } 112 | // // println(root) 113 | // fn collect_files(root : String) -> Map[String, String] { 114 | // let files = {} 115 | // for entry in zip.to_array() { 116 | // if entry.kind() is File(file) { 117 | // let path = entry.path().to_string() 118 | // if path.has_prefix(root) && path.has_suffix(".mbt") { 119 | // try { 120 | // files[path] = @encoding/utf8.decode(file.to_bytes()) 121 | // } catch { 122 | // _ => abort("Failed to decode file content") 123 | // } 124 | // } 125 | // } 126 | // } 127 | // files 128 | // } 129 | // // 找出所有的 packages 130 | // fn scan_packages() -> Array[@interpreter.RuntimePackage] { 131 | // let pkgs = [] 132 | // for entry in zip.to_array() { 133 | // if entry.is_dir() { 134 | // let dir = entry.path().to_string() 135 | // if zip.find(@fpath.Fpath(dir + "moon.pkg.json")) is Some(_) { 136 | // let pkg_name = module_name + 137 | // dir.strip_prefix(root).unwrap_or(dir).to_string() 138 | // // println(pkg_name) 139 | // // println(dir) 140 | // pkgs.push( 141 | // @interpreter.RuntimePackage::new( 142 | // pkg_name, 143 | // files=collect_files(dir), 144 | // ), 145 | // ) 146 | // } 147 | // } 148 | // } 149 | // pkgs 150 | // } 151 | 152 | // let packages = scan_packages() 153 | 154 | // } 155 | // } 156 | // } 157 | // } 158 | // } 159 | // }) 160 | // } 161 | // ///| 162 | // test { 163 | // @mio.run(fn() { 164 | // async fn load(mod_name) noraise { 165 | // let url = "https://mooncakes.io/assets/\{mod_name}/resource.json" 166 | // let info = try? @mio.get(url).unwrap_json() 167 | // if info is Ok(a) { 168 | // let json = a 169 | // println(json) 170 | // } else { 171 | // abort("Failed to get resource.json") 172 | // } 173 | // } 174 | 175 | // load("oboard/mimetype") 176 | // }) 177 | // } 178 | -------------------------------------------------------------------------------- /src/interpreter/type_operations.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | /// 类型操作模块 3 | /// 包含类型推断、类型检查和类型转换相关的方法 4 | 5 | ///| 6 | /// 根据字段名推导结构体类型 7 | fn RuntimePackage::infer_struct_type_from_fields( 8 | self : RuntimePackage, 9 | current_fields : Array[String], 10 | ) -> String { 11 | self.type_definitions 12 | .iter() 13 | .fold(init="Any", fn(result, entry) { 14 | let (type_name, type_def) = entry 15 | match type_def.components { 16 | Record(struct_fields) => { 17 | let all_matched = struct_fields.all(sf => current_fields 18 | .iter() 19 | .any(cf => sf.name.label == cf)) 20 | if struct_fields.length() == current_fields.length() && all_matched { 21 | type_name 22 | } else { 23 | result 24 | } 25 | } 26 | _ => result 27 | } 28 | }) 29 | } 30 | 31 | ///| 32 | /// 查找静态类型定义 33 | fn RuntimePackage::find_static_type( 34 | self : RuntimePackage, 35 | name : String, 36 | ) -> RuntimeType { 37 | match name { 38 | "Bool" => RuntimeType::bool() 39 | "Int" => RuntimeType::int() 40 | "UInt" => RuntimeType::uint() 41 | "Int64" => RuntimeType::int64() 42 | "UInt16" => RuntimeType::uint16() 43 | "UInt64" => RuntimeType::uint64() 44 | "Float" => RuntimeType::float() 45 | "Double" => RuntimeType::double() 46 | "BigInt" => RuntimeType::bigint() 47 | "Char" => RuntimeType::char() 48 | "Byte" => RuntimeType::byte() 49 | "String" => RuntimeType::string() 50 | "Tuple" => RuntimeType::tuple() 51 | "Array" => RuntimeType::array() 52 | "ArrayView" | "View" => RuntimeType::array_view() 53 | "FixedArray" => RuntimeType::fixed_array() 54 | "UninitializedArray" => RuntimeType::uninitialized_array() 55 | "Map" => RuntimeType::map() 56 | "Iter" => RuntimeType::iter() 57 | "Option" | "Some" | "None" => RuntimeType::option() 58 | "StringBuilder" => RuntimeType::string_builder() 59 | // TODO: infer type 60 | _ => 61 | // 首先检查是否是构造函数 62 | if self.constructors.get(name) is Some(type_name) { 63 | if self.type_definitions.get(type_name) is Some(decl) { 64 | Object(pkg=self, name=decl.tycon) 65 | } else { 66 | Any 67 | } 68 | } else if self.type_definitions.get(name) is Some(decl) { 69 | Object(pkg=self, name=decl.tycon) 70 | } else { 71 | Any 72 | } 73 | } 74 | } 75 | 76 | ///| 77 | /// 根据运行时值推断类型 78 | fn RuntimeValue::get_type(self : RuntimeValue) -> RuntimeType { 79 | match self { 80 | Unit => Any 81 | Bool(_) => RuntimeType::bool() 82 | Int(_) => RuntimeType::int() 83 | UInt(_) => RuntimeType::uint() 84 | Int64(_) => RuntimeType::int64() 85 | UInt16(_) => RuntimeType::uint16() 86 | UInt64(_) => RuntimeType::uint64() 87 | Float(_) => RuntimeType::float() 88 | Double(_) => RuntimeType::double() 89 | BigInt(_) => RuntimeType::bigint() 90 | Char(_) => RuntimeType::char() 91 | Byte(_) => RuntimeType::byte() 92 | String(_) => RuntimeType::string() 93 | Bytes(_) => RuntimeType::bytes() 94 | StringView(_) => RuntimeType::string_view() 95 | StringBuilder(_) => RuntimeType::string_builder() 96 | HashMap(_) => RuntimeType::hashmap() 97 | Tuple(_) => RuntimeType::tuple() 98 | Array(_) => RuntimeType::array() 99 | FixedArray(_) => RuntimeType::array() 100 | ArrayView(_) => RuntimeType::array_view() 101 | UninitializedArray(_) => RuntimeType::uninitialized_array() 102 | Map(_) => RuntimeType::map() 103 | Object(data) => data.ty 104 | // Closure(Lambda(parameters~,return_type~,error_type~,is_async~,..),_) => Arrow 105 | // TODO: 闭包类型 106 | Fn(_) => Any 107 | Exception(_) => Any 108 | Constructor({ ty: type_info, .. }) => type_info 109 | Iter(_) => RuntimeType::iter() 110 | Iter2(_) => RuntimeType::iter() 111 | Json(_) => RuntimeType::json() 112 | } 113 | } 114 | 115 | ///| 116 | /// 从函数体推导返回类型 117 | fn ClosureInterpreter::infer_return_type_from_expr( 118 | self : ClosureInterpreter, 119 | body : @syntax.Expr, 120 | ) -> RuntimeType { 121 | match body { 122 | // 处理函数调用表达式 123 | Apply(func~, ..) => 124 | match func { 125 | @syntax.Expr::Ident(id={ name: ident, .. }, ..) => 126 | self.with_ident(ident, (pkg, name) => pkg.env 127 | .find(name) 128 | .unwrap_or(Unit) 129 | .get_type()) 130 | _ => RuntimeType::any() 131 | } 132 | // 处理 match 表达式 133 | Match(..) => RuntimeType::any() 134 | Sequence(last_expr~, ..) => self.infer_return_type_from_expr(last_expr) 135 | Infix(op={ name: Ident(name=op_name), .. }, lhs~, ..) => 136 | match op_name { 137 | "==" | "!=" | "<" | ">" | "<=" | ">=" | "&&" | "||" => 138 | RuntimeType::bool() 139 | _ => self.infer_return_type_from_expr(lhs) 140 | } 141 | _ => RuntimeType::any() 142 | } 143 | } 144 | 145 | ///| 146 | /// 转换为字符串表示(带解释器支持,用于正确的类型推导) 147 | pub fn ClosureInterpreter::get_function_type_string( 148 | self : ClosureInterpreter, 149 | func : @syntax.Func, 150 | ) -> String { 151 | // 从函数中提取参数和返回类型信息 152 | match func { 153 | Lambda(parameters~, return_type~, body~, ..) => { 154 | let param_strs = [] 155 | for param in parameters { 156 | let param_str = match param { 157 | @syntax.Parameter::Positional(binder~, ty~) => 158 | match ty { 159 | Some(t) => binder.name + ": " + type_to_string(t) 160 | None => binder.name 161 | } 162 | @syntax.Parameter::Labelled(binder~, ty~) => 163 | match ty { 164 | Some(t) => binder.name + "~: " + type_to_string(t) 165 | None => binder.name + "~" 166 | } 167 | @syntax.Parameter::Optional(binder~, ty~, default~) => { 168 | let type_str = match ty { 169 | Some(t) => binder.name + "~: " + type_to_string(t) 170 | None => binder.name + "~" 171 | } 172 | match default { 173 | @syntax.Expr::Constant(c=Int(val), ..) => type_str + " = " + val 174 | _ => type_str 175 | } 176 | } 177 | @syntax.Parameter::QuestionOptional(binder~, ty~) => 178 | match ty { 179 | Some(t) => binder.name + "?: " + type_to_string(t) 180 | None => binder.name + "?" 181 | } 182 | @syntax.Parameter::DiscardPositional(..) => "_" 183 | } 184 | param_strs.push(param_str) 185 | } 186 | match return_type { 187 | Some(t) => "(" + param_strs.join(", ") + ") -> " + type_to_string(t) 188 | None => { 189 | // 推断返回类型,对于柯里化函数需要特殊处理 190 | let inferred_type = self.infer_return_type_from_expr(body).to_string() 191 | "(" + param_strs.join(", ") + ") -> " + inferred_type 192 | } 193 | } 194 | } 195 | _ => "" 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /src/interpreter/fixedarray.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub let fixedarray_methods : Map[String, RuntimeFunction] = { 3 | "new": fixedarray_new_fn, 4 | "length": fixedarray_length_fn, 5 | "get": fixedarray_get_fn, 6 | "set": fixedarray_set_fn, 7 | "unsafe_get": fixedarray_unsafe_get_fn, 8 | "unsafe_set": fixedarray_unsafe_set_fn, 9 | "make": fixedarray_make_fn, 10 | "fill": fixedarray_fill_fn, 11 | "blit_to": fixedarray_blit_to_fn, 12 | "unsafe_blit": fixedarray_unsafe_blit_fn, 13 | "is_empty": fixedarray_is_empty_fn, 14 | "iter": fixedarray_iter_fn, 15 | "iter2": fixedarray_iter2_fn, 16 | "binary_search": fixedarray_binary_search_fn, 17 | "binary_search_by": fixedarray_binary_search_by_fn, 18 | "set_utf16le_char_fn": fixedarray_set_utf16le_char_fn, 19 | "set_utf16be_char_fn": fixedarray_set_utf16be_char_fn, 20 | } 21 | 22 | ///| 23 | /// FixedArray::new 操作 - 创建新的固定数组 24 | let fixedarray_new_fn : RuntimeFunction = ctx => match ctx.args { 25 | [] => FixedArray(FixedArray::make(0, Unit)) 26 | _ => Unit 27 | } 28 | 29 | ///| 30 | /// FixedArray::length 操作 - 获取数组长度 31 | let fixedarray_length_fn : RuntimeFunction = ctx => match ctx.args { 32 | [{ val: FixedArray(arr), .. }] => Int(arr.length(), raw=None) 33 | _ => Unit 34 | } 35 | 36 | ///| 37 | /// FixedArray::get 操作 - 安全获取元素 38 | let fixedarray_get_fn : RuntimeFunction = ctx => match ctx.args { 39 | [{ val: FixedArray(arr), .. }, { val: Int(i, ..), .. }] => 40 | if i >= 0 && i < arr.length() { 41 | arr[i] 42 | } else { 43 | Unit 44 | } 45 | _ => Unit 46 | } 47 | 48 | ///| 49 | /// FixedArray::set 操作 - 设置元素 50 | let fixedarray_set_fn : RuntimeFunction = ctx => match ctx.args { 51 | [{ val: FixedArray(arr), .. }, { val: Int(i, ..), .. }, { val, .. }] => { 52 | if i >= 0 && i < arr.length() { 53 | arr[i] = val 54 | } 55 | Unit 56 | } 57 | _ => Unit 58 | } 59 | 60 | ///| 61 | /// FixedArray::unsafe_get 操作 - 不安全获取元素 62 | let fixedarray_unsafe_get_fn : RuntimeFunction = ctx => match ctx.args { 63 | [{ val: FixedArray(arr), .. }, { val: Int(i, ..), .. }] => arr[i] 64 | _ => Unit 65 | } 66 | 67 | ///| 68 | /// FixedArray::unsafe_set 操作 - 不安全设置元素 69 | let fixedarray_unsafe_set_fn : RuntimeFunction = ctx => match ctx.args { 70 | [{ val: FixedArray(arr), .. }, { val: Int(i, ..), .. }, { val, .. }] => { 71 | arr[i] = val 72 | Unit 73 | } 74 | _ => Unit 75 | } 76 | 77 | ///| 78 | /// FixedArray::make 操作 - 创建指定大小和初始值的固定数组 79 | let fixedarray_make_fn : RuntimeFunction = ctx => match ctx.args { 80 | [{ val: Int(len, ..), .. }, { val, .. }] => 81 | FixedArray(FixedArray::make(len, val)) 82 | _ => Unit 83 | } 84 | 85 | ///| 86 | /// FixedArray::fill 操作 - 填充数组 87 | let fixedarray_fill_fn : RuntimeFunction = ctx => match ctx.args { 88 | [{ val: FixedArray(arr), .. }, { val, .. }] => { 89 | arr.fill(val) 90 | Unit 91 | } 92 | _ => Unit 93 | } 94 | 95 | ///| 96 | /// FixedArray::blit_to 操作 - 复制数组内容 97 | let fixedarray_blit_to_fn : RuntimeFunction = ctx => match ctx.args { 98 | [ 99 | { val: Int(dst_offset, ..), .. }, 100 | { val: FixedArray(src), .. }, 101 | { val: Int(src_offset, ..), .. }, 102 | { val: Int(len, ..), .. }, 103 | ] => { 104 | src.unsafe_blit(dst_offset, src, src_offset, len) 105 | Unit 106 | } 107 | _ => Unit 108 | } 109 | 110 | ///| 111 | /// FixedArray::unsafe_blit 操作 - 不安全的数组复制 112 | let fixedarray_unsafe_blit_fn : RuntimeFunction = ctx => match ctx.args { 113 | [ 114 | { val: FixedArray(dst), .. }, 115 | { val: Int(dst_offset, ..), .. }, 116 | { val: FixedArray(src), .. }, 117 | { val: Int(src_offset, ..), .. }, 118 | { val: Int(len, ..), .. }, 119 | ] => { 120 | dst.unsafe_blit(dst_offset, src, src_offset, len) 121 | Unit 122 | } 123 | _ => Unit 124 | } 125 | 126 | ///| 127 | /// FixedArray::is_empty 操作 - 检查数组是否为空 128 | let fixedarray_is_empty_fn : RuntimeFunction = ctx => match ctx.args { 129 | [{ val: FixedArray(arr), .. }] => Bool(arr.is_empty()) 130 | _ => Unit 131 | } 132 | 133 | ///| 134 | /// FixedArray::iter 操作 - 获取迭代器 135 | let fixedarray_iter_fn : RuntimeFunction = ctx => match ctx.args { 136 | [{ val: FixedArray(arr), .. }] => Iter(arr.iter()) 137 | _ => Unit 138 | } 139 | 140 | ///| 141 | /// FixedArray::iter2 操作 - 获取带索引的迭代器 142 | let fixedarray_iter2_fn : RuntimeFunction = ctx => match ctx.args { 143 | [{ val: FixedArray(arr), .. }] => { 144 | let iter2_impl = Iter2::new(yield_fn => { 145 | for i in 0.. return IterEnd 148 | IterContinue => () 149 | } 150 | } 151 | IterEnd 152 | }) 153 | Iter2(iter2_impl) 154 | } 155 | _ => Unit 156 | } 157 | 158 | ///| 159 | /// FixedArray::binary_search 操作 - 二分查找 160 | let fixedarray_binary_search_fn : RuntimeFunction = ctx => match ctx.args { 161 | [{ val: FixedArray(arr), .. }, { val: target, .. }] => 162 | arr.binary_search(target).map(Int(_, raw=None)).map_err(Int(_, raw=None)) 163 | |> RuntimeValue::from_result 164 | _ => Unit 165 | } 166 | 167 | ///| 168 | /// FixedArray::binary_search_by 操作 - 使用比较函数的二分查找 169 | let fixedarray_binary_search_by_fn : RuntimeFunction = ctx => match ctx.args { 170 | [{ val: FixedArray(arr), .. }, { val: Fn(f), .. }] => 171 | arr 172 | .binary_search_by(v => match 173 | ctx.context.call(f.val, ctx.pkg, [{ val: v, kind: Positional }]) { 174 | Int(i, ..) => i 175 | _ => raise Error("binary_search_by closure must return int") 176 | }) 177 | .map(Int(_, raw=None)) 178 | .map_err(Int(_, raw=None)) 179 | |> RuntimeValue::from_result 180 | _ => Unit 181 | } 182 | 183 | ///| 184 | /// FixedArray::set_utf16le_char operation - Set UTF-16LE character bytes 185 | let fixedarray_set_utf16le_char_fn : RuntimeFunction = ctx => match ctx.args { 186 | [ 187 | { val: FixedArray(self), .. }, 188 | { val: Int(offset, ..), .. }, 189 | { val: Char(value), .. }, 190 | ] => { 191 | let code = value.to_uint() 192 | if code < 0x10000 { 193 | self[offset] = Byte((code & 0xFF).to_byte()) 194 | self[offset + 1] = Byte((code >> 8).to_byte()) 195 | Int(2, raw=None) 196 | } else if code < 0x110000 { 197 | let hi = code - 0x10000 198 | let lo = (hi >> 10) | 0xD800 199 | let hi = (hi & 0x3FF) | 0xDC00 200 | self[offset] = Byte((lo & 0xFF).to_byte()) 201 | self[offset + 1] = Byte((lo >> 8).to_byte()) 202 | self[offset + 2] = Byte((hi & 0xFF).to_byte()) 203 | self[offset + 3] = Byte((hi >> 8).to_byte()) 204 | Int(4, raw=None) 205 | } else { 206 | error("Char out of range") 207 | } 208 | } 209 | _ => Unit 210 | } 211 | 212 | ///| 213 | /// FixedArray::set_utf16be_char operation - Set UTF-16BE character bytes 214 | let fixedarray_set_utf16be_char_fn : RuntimeFunction = ctx => match ctx.args { 215 | [ 216 | { val: FixedArray(self), .. }, 217 | { val: Int(offset, ..), .. }, 218 | { val: Char(value), .. }, 219 | ] => { 220 | let code = value.to_uint() 221 | if code < 0x10000 { 222 | self[offset] = Byte((code >> 8).to_byte()) 223 | self[offset + 1] = Byte((code & 0xFF).to_byte()) 224 | Int(2, raw=None) 225 | } else if code < 0x110000 { 226 | let hi = code - 0x10000 227 | let lo = (hi >> 10) | 0xD800 228 | let hi = (hi & 0x3FF) | 0xDC00 229 | self[offset] = Byte((lo >> 8).to_byte()) 230 | self[offset + 1] = Byte((lo & 0xFF).to_byte()) 231 | self[offset + 2] = Byte((hi >> 8).to_byte()) 232 | self[offset + 3] = Byte((hi & 0xFF).to_byte()) 233 | Int(4, raw=None) 234 | } else { 235 | error("Char out of range") 236 | } 237 | } 238 | _ => Unit 239 | } 240 | -------------------------------------------------------------------------------- /src/interpreter/functions.mbt: -------------------------------------------------------------------------------- 1 | ///| 函数管理模块 2 | 3 | ///| 4 | /// 调用闭包函数,恢复捕获的环境 5 | pub fn ClosureInterpreter::call_closure( 6 | self : ClosureInterpreter, 7 | function : @syntax.Func, 8 | pkg : RuntimePackage, 9 | args : @list.List[@syntax.Argument], 10 | name? : String, 11 | ) -> RuntimeValue raise ControlFlow { 12 | match function { 13 | @syntax.Func::Lambda(_) => { 14 | // 在旧环境中解释参数值并转换为RuntimeArgument 15 | let runtime_args = self.convert_to_runtime_arguments(args) 16 | 17 | // 调用运行时版本 18 | self.call( 19 | self.create_function(function, pkg, name?).val, 20 | pkg, 21 | runtime_args, 22 | ) 23 | } 24 | _ => RuntimeValue::Unit 25 | } 26 | } 27 | 28 | ///| 29 | /// 调用闭包函数,使用已求值的运行时参数 30 | pub fn ClosureInterpreter::call( 31 | self : ClosureInterpreter, 32 | function : RuntimeFunction, 33 | pkg : RuntimePackage, 34 | args : FixedArray[RuntimeArgument], 35 | ) -> RuntimeValue raise ControlFlow { 36 | function({ context: self, pkg, args }) 37 | // match function { 38 | // @syntax.Func::Lambda(parameters~, body~, return_type~, ..) => { 39 | // // 切换到闭包捕获的环境 40 | // let old_mod = self.current_pkg 41 | // let old_env = pkg.env 42 | // self.current_pkg = pkg 43 | // self.current_pkg.env = env 44 | // self.push_scope( 45 | // RuntimeLocation::FunctionCall( 46 | // "@" + 47 | // pkg.name + 48 | // "." + 49 | // name.unwrap_or("") + 50 | // self.get_function_type_string(Fn(function, env)), 51 | // ), 52 | // ) 53 | // // 在新环境中绑定已解释的参数值 54 | // self.bind_runtime_parameters(parameters, args) 55 | // defer { 56 | // self.pop_scope() 57 | // self.current_pkg.env = old_env 58 | // self.current_pkg = old_mod 59 | // } 60 | // // 执行函数体 61 | // let result = self.visit(body) 62 | // match (result.get_type(), result, return_type) { 63 | // (Any, Struct({ val, .. }), Some(Arrow(res~, ..))) => 64 | // Struct({ val, ty: self.parse_type(res) }) 65 | // _ => result 66 | // } 67 | // } 68 | // _ => RuntimeValue::Unit 69 | // } 70 | } 71 | 72 | ///| 处理函数定义、调用和参数绑定 73 | 74 | ///| 绑定函数参数到作用域 75 | 76 | ///| 递归处理多个参数,将参数值绑定到函数作用域中 77 | 78 | ///| 79 | /// 支持所有参数类型:位置参数、标签参数、可选参数、问号可选参数、丢弃参数 80 | pub fn ClosureInterpreter::bind_function_parameters( 81 | self : ClosureInterpreter, 82 | params : @list.List[@syntax.Parameter], 83 | args : @list.List[RuntimeArgument], 84 | ) -> Unit raise ControlFlow { 85 | let env = self.current_pkg.env 86 | match (params, args) { 87 | (@list.More(param, tail=rest_params), @list.More(arg, tail=rest_args)) => { 88 | let value = arg.val 89 | match param { 90 | // 位置参数:直接绑定参数值 91 | Positional(binder={ name, .. }, ..) 92 | // 标签参数:绑定带标签的参数值 93 | | Labelled(binder={ name, .. }, ..) 94 | // 可选参数:当有参数提供时绑定参数值,否则使用默认值 95 | | Optional(binder={ name, .. }, ..) 96 | // 问号可选参数:绑定参数值 97 | | QuestionOptional(binder={ name, .. }, ..) => env.set(name, value) 98 | // 丢弃位置参数:不绑定到任何变量,直接跳过 99 | DiscardPositional(..) => 100 | // 丢弃参数不需要绑定,但仍需要求值以保持副作用 101 | () 102 | } 103 | self.bind_function_parameters(rest_params, rest_args) 104 | } 105 | // 处理可选参数的默认值情况 106 | (@list.More(param, tail=rest_params), @list.Empty) => 107 | match param { 108 | // 可选参数没有对应实参时,使用默认值 109 | Optional(binder={ name, .. }, default~, ..) => { 110 | let runtime_value = self.visit(default) 111 | env.set(name, runtime_value) 112 | self.bind_function_parameters(rest_params, @list.new()) 113 | } 114 | // 问号可选参数没有对应实参时,不绑定任何值 115 | QuestionOptional(..) => 116 | self.bind_function_parameters(rest_params, @list.new()) 117 | _ => () 118 | } 119 | (@list.Empty, @list.Empty) => () 120 | _ => () 121 | } 122 | } 123 | 124 | ///| 125 | /// 将语法参数转换为运行时参数 126 | fn ClosureInterpreter::convert_to_runtime_arguments( 127 | self : ClosureInterpreter, 128 | args : @list.List[@syntax.Argument], 129 | ) -> FixedArray[RuntimeArgument] raise ControlFlow { 130 | FixedArray::from_iter( 131 | args 132 | .map(arg => RuntimeArgument::{ 133 | val: self.visit(arg.value), 134 | kind: RuntimeArgumentKind::from_syntax(arg.kind), 135 | }) 136 | .iter(), 137 | ) 138 | } 139 | 140 | ///| 141 | /// 绑定运行时参数到新环境 142 | fn ClosureInterpreter::bind_runtime_parameters( 143 | self : ClosureInterpreter, 144 | params : @list.List[@syntax.Parameter], 145 | args : @list.List[RuntimeArgument], 146 | ) -> Unit raise ControlFlow { 147 | loop (params, args) { 148 | // 处理可选参数的默认值情况 149 | ( 150 | @list.More(param, tail=rest_params), 151 | @list.More({ val: Unit, .. }, tail=rest_args), 152 | ) => 153 | match param { 154 | // 可选参数没有对应实参时,使用默认值 155 | Optional(binder={ name, .. }, default~, ..) => { 156 | let default_value = self.visit(default) 157 | self.current_pkg.env.set(name, default_value) 158 | continue (rest_params, rest_args) 159 | } 160 | // 问号可选参数没有对应实参时,不绑定任何值 161 | QuestionOptional(..) => continue (rest_params, rest_args) 162 | _ => () 163 | } 164 | (@list.More(param, tail=rest_params), @list.More(arg, tail=rest_args)) => { 165 | let value = arg.val 166 | match param { 167 | // 位置参数:直接绑定参数值 168 | Positional(binder={ name, .. }, ..) 169 | // 标签参数:绑定带标签的参数值 170 | | Labelled(binder={ name, .. }, ..) 171 | // 问号可选参数:绑定参数值 172 | | QuestionOptional(binder={ name, .. }, ..) 173 | // 可选参数:当有参数提供时绑定参数值 174 | | Optional(binder={ name, .. }, ..) => 175 | self.current_pkg.env.set(name, value) 176 | // 丢弃位置参数:不绑定到任何变量 177 | DiscardPositional(..) => () 178 | } 179 | continue (rest_params, rest_args) 180 | } 181 | // 处理可选参数的默认值情况 182 | (@list.More(param, tail=rest_params), @list.Empty) => 183 | match param { 184 | // 可选参数没有对应实参时,使用默认值 185 | Optional(binder={ name, .. }, default~, ..) => { 186 | let default_value = self.visit(default) 187 | self.current_pkg.env.set(name, default_value) 188 | continue (rest_params, @list.new()) 189 | } 190 | // 问号可选参数没有对应实参时,不绑定任何值 191 | QuestionOptional(..) => continue (rest_params, @list.new()) 192 | _ => () 193 | } 194 | (@list.Empty, @list.Empty) => () 195 | _ => () 196 | } 197 | } 198 | 199 | ///| 200 | /// 处理函数定义 201 | pub fn ClosureInterpreter::define_struct_method( 202 | self : ClosureInterpreter, 203 | pkg : RuntimePackage, 204 | type_name : String, 205 | method_name : String, 206 | func : @syntax.Func, 207 | ) -> Unit { 208 | let methods = match pkg.struct_methods.get(type_name) { 209 | Some(methods) => methods 210 | None => { 211 | let methods = Map::new() 212 | pkg.struct_methods.set(type_name, methods) 213 | methods 214 | } 215 | } 216 | methods.set( 217 | method_name, 218 | RuntimeValue::Fn(self.create_function(func, pkg, name=method_name)), 219 | ) 220 | } 221 | 222 | ///| 223 | /// 处理trait方法定义 224 | pub fn RuntimePackage::define_trait_method( 225 | self : RuntimePackage, 226 | trait_id : String, 227 | method_name : String, 228 | func : RuntimeValue, 229 | ) -> Unit { 230 | let methods = match self.trait_methods.get(trait_id) { 231 | Some(methods) => methods 232 | None => { 233 | let methods = Map::new() 234 | self.trait_methods.set(trait_id, methods) 235 | methods 236 | } 237 | } 238 | methods.set(method_name, func) 239 | } 240 | -------------------------------------------------------------------------------- /src/test/control_flow.mbt: -------------------------------------------------------------------------------- 1 | // ============================================================================= 2 | // 4. CONTROL FLOW 3 | // ============================================================================= 4 | 5 | ///| 6 | test "if_expressions" { 7 | let vm = MoonBitVM::new() 8 | inspect( 9 | vm.eval("if 1 > 0 { if 2 > 1 { 3 } else { 4 } } else { 5 }"), 10 | content="3", 11 | ) 12 | inspect(vm.eval("if (5 + 3) * 2 > 15 { 1 } else { 2 }"), content="1") 13 | inspect(vm.eval("if true && false || true { 1 } else { 2 }"), content="1") 14 | inspect(vm.eval("if 3 < 2 { 1 }"), content="()") 15 | } 16 | 17 | ///| 18 | test "type_constraints" { 19 | let vm = MoonBitVM::new() 20 | // Test type constraint expressions 21 | assert_eq(vm.eval("(42 : Int)").to_string(), "42") 22 | assert_eq(vm.eval("(true : Bool)").to_string(), "true") 23 | assert_eq(vm.eval("(\"hello\" : String)").to_string(), "hello") 24 | assert_eq(vm.eval("let x = (5 : Int); x + 1").to_string(), "6") 25 | } 26 | 27 | ///| 28 | test "guard_expressions" { 29 | let vm = MoonBitVM::new() 30 | // Test guard expressions 31 | assert_eq( 32 | vm 33 | .eval( 34 | ( 35 | #|fn guarded_get(array : Array[Int], index : Int) -> Int? { 36 | #| guard index >= 0 && index < array.length() else { None } 37 | #| Some(array[index]) 38 | #|} 39 | ), 40 | ) 41 | .to_string(), 42 | "(Array[Int], Int) -> Int?", 43 | ) 44 | assert_eq(vm.eval("guarded_get([1, 2, 3], -1)").to_string(), "None") 45 | } 46 | 47 | ///| 48 | test "is_expressions" { 49 | let vm = MoonBitVM::new() 50 | // Test 'is' pattern matching expressions 51 | assert_eq(vm.eval("5 is 5").to_string(), "true") 52 | assert_eq(vm.eval("5 is 3").to_string(), "false") 53 | assert_eq(vm.eval("Some(2) is Some(_)").to_string(), "true") 54 | assert_eq(vm.eval("Some(2) is Some(1)").to_string(), "false") 55 | assert_eq(vm.eval("Some(1) is Some(1)").to_string(), "true") 56 | assert_eq(vm.eval("None is Some(_)").to_string(), "false") 57 | } 58 | 59 | ///| 60 | test "defer_expressions" { 61 | let vm = MoonBitVM::new() 62 | // Test defer expressions 63 | assert_eq( 64 | vm 65 | .eval( 66 | ( 67 | #|defer println("First defer") 68 | #|defer println("Second defer") 69 | #|println("Do something") 70 | ), 71 | ) 72 | .to_string(), 73 | "()", 74 | ) 75 | } 76 | 77 | ///| 78 | test "for_loops" { 79 | let vm = MoonBitVM::new() 80 | // 简化测试:只测试最基本的for循环 81 | inspect(vm.eval("let mut sum = 0"), content="()") 82 | inspect(vm.eval("sum"), content="0") 83 | inspect(vm.eval("sum += 1"), content="()") 84 | inspect(vm.eval("sum"), content="1") 85 | inspect(vm.eval("sum += 2"), content="()") 86 | inspect(vm.eval("sum"), content="3") 87 | 88 | // 测试for循环 89 | inspect(vm.eval("let mut result = 0"), content="()") 90 | inspect(vm.eval("for i = 0; i < 3; i = i + 1 { result += i }"), content="()") 91 | inspect(vm.eval("result"), content="3") 92 | assert_eq( 93 | vm 94 | .eval( 95 | ( 96 | #|let sum = for i = 1, acc = 0; i <= 6; i = i + 1 { 97 | #| if i % 2 == 0 { 98 | #| println("even: \{i}") 99 | #| continue i + 1, acc + i 100 | #| } 101 | #|} else { 102 | #| acc 103 | #|} 104 | ), 105 | ) 106 | .to_string(), 107 | "()", 108 | ) 109 | assert_eq(vm.eval("sum").to_string(), "12") 110 | } 111 | 112 | ///| 113 | test "for_in" { 114 | let vm = MoonBitVM::new() 115 | // Test array iteration 116 | inspect(vm.eval("let mut sum = 0"), content="()") 117 | inspect(vm.eval("for x in [1, 2, 3, 4, 5] { sum += x }"), content="()") 118 | inspect(vm.eval("sum"), content="15") 119 | 120 | // Test range iteration with exclusive upper bound 121 | inspect(vm.eval("let mut range_sum = 0"), content="()") 122 | inspect(vm.eval("for i in 0..<5 { range_sum += i }"), content="()") 123 | inspect(vm.eval("range_sum"), content="10") 124 | 125 | // Test range iteration with inclusive upper bound 126 | inspect(vm.eval("let mut inclusive_sum = 0"), content="()") 127 | inspect(vm.eval("for i in 0..=5 { inclusive_sum += i }"), content="()") 128 | inspect(vm.eval("inclusive_sum"), content="15") 129 | 130 | // Test iteration with index 131 | inspect(vm.eval("let mut indexed_sum = 0"), content="()") 132 | inspect( 133 | vm.eval("for idx, val in [10, 20, 30] { indexed_sum += idx + val }"), 134 | content="()", 135 | ) 136 | inspect(vm.eval("indexed_sum"), content="63") 137 | } 138 | 139 | ///| 140 | test "while_loops" { 141 | let vm = MoonBitVM::new() 142 | inspect(vm.eval("let mut i = 0"), content="()") 143 | inspect(vm.eval("let mut sum = 0"), content="()") 144 | inspect(vm.eval("while i < 5 { sum += i; i += 1 }"), content="()") 145 | inspect(vm.eval("sum"), content="10") 146 | inspect(vm.eval("i"), content="5") 147 | } 148 | 149 | ///| 150 | test "loop_control" { 151 | let vm = MoonBitVM::new() 152 | assert_eq( 153 | vm 154 | .eval( 155 | ( 156 | #|fn sum_with_continue(n : Int, acc : Int) -> Int { 157 | #| let mut acc = acc 158 | #| for i = 0; i < n; i = i + 1 { 159 | #| if i == 2 { 160 | #| continue 161 | #| } 162 | #| acc = acc + i 163 | #| } 164 | #| acc 165 | #|} 166 | ), 167 | ) 168 | .to_string(), 169 | "(Int, Int) -> Int", 170 | ) 171 | assert_eq(vm.eval("sum_with_continue(5, 1)").to_string(), "9") 172 | } 173 | 174 | ///| 175 | test "return_expressions" { 176 | let vm = MoonBitVM::new() 177 | // Test return expressions in functions 178 | assert_eq( 179 | vm 180 | .eval( 181 | ( 182 | #|fn early_return(x : Int) -> Int { 183 | #| if x < 0 { return -1 } 184 | #| x * 2 185 | #|} 186 | #|early_return(5) 187 | ), 188 | ) 189 | .to_string(), 190 | "10", 191 | ) 192 | assert_eq(vm.eval("early_return(-3)").to_string(), "-1") 193 | } 194 | 195 | ///| 196 | test "raise_expressions" { 197 | let vm = MoonBitVM::new() 198 | // Test raise expressions for exceptions 199 | assert_eq( 200 | vm 201 | .eval( 202 | ( 203 | #|fn divide(a : Int, b : Int) -> Int { 204 | #| if b == 0 { raise "Division by zero" } 205 | #| a / b 206 | #|} 207 | #|divide(10, 2) 208 | ), 209 | ) 210 | .to_string(), 211 | "5", 212 | ) 213 | } 214 | 215 | ///| 216 | test "loop_expressions" { 217 | let vm = MoonBitVM::new() 218 | // Test loop expressions 219 | inspect( 220 | vm.eval( 221 | ( 222 | #|fn sum(xs : @list.List[Int]) -> Int { 223 | #| loop (xs, 0) { 224 | #| (Empty, acc) => break acc // <=> Nil, acc => acc 225 | #| (More(x, tail=rest), acc) => continue (rest, x + acc) 226 | #| } 227 | #|} 228 | ), 229 | ), 230 | content="(List[Int]) -> Int", 231 | ) 232 | inspect(vm.eval("let list = @list.from_array([1, 2, 3])"), content="()") 233 | inspect( 234 | vm.eval("list"), 235 | content="More(1, tail=More(2, tail=More(3, tail=Empty)))", 236 | ) 237 | inspect(vm.eval("sum(list)"), content="6") 238 | inspect(vm.eval("@list.to_array(list)"), content="[1, 2, 3]") 239 | } 240 | 241 | ///| 242 | test "break_continue" { 243 | let vm = MoonBitVM::new() 244 | // Test break and continue in loops 245 | assert_eq( 246 | vm 247 | .eval( 248 | ( 249 | #|let mut result = 0 250 | #|for i = 0; i < 10; i = i + 1 { 251 | #| if i == 3 { continue } 252 | #| if i == 7 { break } 253 | #| result += i 254 | #|} 255 | #|result 256 | ), 257 | ) 258 | .to_string(), 259 | "18", 260 | ) 261 | } 262 | -------------------------------------------------------------------------------- /src/vm.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub(all) struct MoonBitVM { 3 | interpreter : ClosureInterpreter 4 | log : Bool 5 | } 6 | 7 | ///| 8 | pub enum EvalResult { 9 | Success(RuntimeValue, ClosureInterpreter) 10 | Error(String, ClosureInterpreter) 11 | } 12 | 13 | ///| 14 | pub impl Show for EvalResult with output(self : EvalResult, logger : &Logger) -> Unit { 15 | logger.write_string(self.to_string()) 16 | } 17 | 18 | ///| 19 | pub impl Show for EvalResult with to_string(self : EvalResult) -> String { 20 | match self { 21 | Success(value, _) => value.to_string() 22 | Error(msg, _) => "Error: " + msg 23 | } 24 | } 25 | 26 | ///| 27 | pub fn MoonBitVM::new(log? : Bool = false) -> MoonBitVM { 28 | let interpreter = ClosureInterpreter::new() 29 | interpreter.add_extern_fn("println", ctx => match ctx.args { 30 | [{ val: value, .. }] => { 31 | println(value) 32 | Unit 33 | } 34 | _ => Unit 35 | }) 36 | { interpreter, log } 37 | } 38 | 39 | ///| 40 | pub fn expr_to_string(expr : @syntax.Expr) -> String { 41 | match expr { 42 | Constant(c~, ..) => 43 | match c { 44 | Bool(b) => b.to_string() 45 | Byte(b) => b 46 | Bytes(b) => b 47 | Char(c) => c 48 | Int(str) => str 49 | Int64(str) => str 50 | UInt(str) => str 51 | UInt64(str) => str 52 | Float(str) => str 53 | Double(str) => str 54 | String(str) => str 55 | BigInt(str) => str 56 | } 57 | Unit(..) => "()" 58 | Function(func=Lambda(parameters~, return_type~, ..), ..) => { 59 | // 辅助函数:将Type转换为字符串 60 | fn type_to_string(ty : @syntax.Type) -> String { 61 | match ty { 62 | @syntax.Type::Name(constr_id~, ..) => 63 | match constr_id.id { 64 | @syntax.LongIdent::Ident(name~) => name 65 | _ => "Any" 66 | } 67 | _ => "Any" 68 | } 69 | } 70 | 71 | let param_strs = [] 72 | for param in parameters { 73 | let param_str = match param { 74 | @syntax.Parameter::DiscardPositional(ty~, ..) => 75 | match ty { 76 | Some(t) => "_: " + type_to_string(t) 77 | None => "_" 78 | } 79 | @syntax.Parameter::Positional(binder~, ty~) => 80 | match ty { 81 | Some(t) => binder.name + ": " + type_to_string(t) 82 | None => binder.name 83 | } 84 | @syntax.Parameter::Labelled(binder~, ty~) => 85 | match ty { 86 | Some(t) => binder.name + "~: " + type_to_string(t) 87 | None => binder.name + "~" 88 | } 89 | @syntax.Parameter::Optional(binder~, ty~, default~) => 90 | (match ty { 91 | Some(t) => binder.name + "~: " + type_to_string(t) 92 | None => binder.name + "~" 93 | }) + 94 | " = " + 95 | expr_to_string(default) 96 | @syntax.Parameter::QuestionOptional(binder~, ty~) => 97 | match ty { 98 | Some(t) => binder.name + "?: " + type_to_string(t) 99 | None => binder.name + "?" 100 | } 101 | } 102 | param_strs.push(param_str) 103 | } 104 | let params_str = if param_strs.length() == 0 { 105 | "()" 106 | } else { 107 | let mut joined = "" 108 | for i = 0; i < param_strs.length(); i = i + 1 { 109 | if i > 0 { 110 | joined = joined + ", " 111 | } 112 | joined = joined + param_strs[i] 113 | } 114 | "(" + joined + ")" 115 | } 116 | let return_str = match return_type { 117 | Some(rt) => " -> " + type_to_string(rt) 118 | None => "" 119 | } 120 | params_str + return_str 121 | } 122 | 123 | // 处理 Tuple 表达式 124 | Tuple(exprs~, ..) => { 125 | let expr_strs = [] 126 | for expr in exprs { 127 | expr_strs.push(expr_to_string(expr)) 128 | } 129 | let mut joined = "" 130 | for i = 0; i < expr_strs.length(); i = i + 1 { 131 | if i > 0 { 132 | joined = joined + ", " 133 | } 134 | joined = joined + expr_strs[i] 135 | } 136 | "(" + joined + ")" 137 | } 138 | 139 | // 处理 Record 表达式 140 | Record(type_name~, fields~, ..) => { 141 | let field_strs = [] 142 | for field in fields { 143 | let field_str = field.label.name + ": " + expr_to_string(field.expr) 144 | field_strs.push(field_str) 145 | } 146 | let mut joined = "" 147 | for i = 0; i < field_strs.length(); i = i + 1 { 148 | if i == 0 { 149 | joined = field_strs[i] 150 | } else { 151 | joined = joined + ",\n " + field_strs[i] 152 | } 153 | } 154 | let type_prefix = match type_name { 155 | Some(name) => 156 | match name.name { 157 | @syntax.LongIdent::Ident(name~) => name + " " 158 | _ => "" 159 | } 160 | None => "" 161 | } 162 | if joined == "" { 163 | type_prefix + "{}" 164 | } else { 165 | type_prefix + "{\n " + joined + "\n}" 166 | } 167 | } 168 | 169 | // 处理 Array 表达式 170 | Array(exprs~, ..) => { 171 | let expr_strs = [] 172 | for expr in exprs { 173 | expr_strs.push(expr_to_string(expr)) 174 | } 175 | let mut joined = "" 176 | for i = 0; i < expr_strs.length(); i = i + 1 { 177 | if i > 0 { 178 | joined = joined + ", " 179 | } 180 | joined = joined + expr_strs[i] 181 | } 182 | "[" + joined + "]" 183 | } 184 | // 处理Apply表达式 - 包括构造函数调用如Some(5) 185 | Apply(func~, args~, ..) => { 186 | let func_str = expr_to_string(func) 187 | let arg_strs = [] 188 | for arg in args { 189 | arg_strs.push(expr_to_string(arg.value)) 190 | } 191 | let args_joined = arg_strs.join(", ") 192 | func_str + "(" + args_joined + ")" 193 | } 194 | 195 | // 处理Constr表达式 - 构造函数 196 | Constr(constr~, ..) => constr.name.name 197 | 198 | // 处理Ident表达式 199 | Ident(id~, ..) => 200 | match id.name { 201 | @syntax.LongIdent::Ident(name~) => name 202 | @syntax.LongIdent::Dot(pkg~, id~) => 203 | if pkg == "" { 204 | id 205 | } else { 206 | pkg + "." + id 207 | } 208 | } 209 | 210 | // 处理Sequence表达式 - 只显示最后一个表达式的结果 211 | Sequence(last_expr~, ..) => expr_to_string(last_expr) 212 | 213 | // 其他未处理的表达式 214 | _ => "" 215 | } 216 | } 217 | 218 | ///| 219 | pub fn MoonBitVM::eval( 220 | self : MoonBitVM, 221 | code : String, 222 | log? : Bool, 223 | top? : Bool = false, 224 | ) -> EvalResult { 225 | try { 226 | if top { 227 | let (impls, _diagnostics) = @moonbitlang/parser.parse_string( 228 | code, 229 | parser=Handrolled, 230 | ) 231 | let mut last_result = RuntimeValue::Unit 232 | impls.each(node => { 233 | if log.unwrap_or(self.log) { 234 | println(node.to_json().stringify()) 235 | } 236 | let result = self.interpreter.top_visit(node) 237 | last_result = result 238 | }) 239 | return Success(last_result, self.interpreter) 240 | } 241 | match @interpreter.parse_code_to_expr(code) { 242 | Ok(expr) => { 243 | let result_value = self.interpreter.visit(expr) 244 | if log.unwrap_or(self.log) { 245 | println(expr.to_json().stringify()) 246 | } 247 | return Success(result_value, self.interpreter) 248 | } 249 | Err(_) => self.eval(code, log?, top=true) 250 | } 251 | } catch { 252 | @interpreter.ControlFlow::Error(msg) => Error(msg, self.interpreter) 253 | _ => panic() 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /src/interpreter/option.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub let option_methods : Map[String, RuntimeFunction] = { 3 | "unwrap": option_unwrap_fn, 4 | "map": option_map_fn, 5 | "map_or": option_map_or_fn, 6 | "map_or_else": option_map_or_else_fn, 7 | "bind": option_bind_fn, 8 | "flatten": option_flatten_fn, 9 | "is_empty": option_is_empty_fn, 10 | "filter": option_filter_fn, 11 | "unwrap_or": option_unwrap_or_fn, 12 | "unwrap_or_else": option_unwrap_or_else_fn, 13 | "unwrap_or_default": option_unwrap_or_default_fn, 14 | } 15 | 16 | // ===== Option 方法 ===== 17 | 18 | ///| 19 | /// Option unwrap 方法 20 | let option_unwrap_fn : RuntimeFunction = ctx => match ctx.args { 21 | [ 22 | { 23 | val: Constructor( 24 | { val: { name: "Some", fields: [{ value: inner_value, .. }] }, .. } 25 | ), 26 | .., 27 | }, 28 | .., 29 | ] => inner_value 30 | [{ val: Constructor({ val: { name: "None", fields: [] }, .. }), .. }] => Unit 31 | _ => Unit 32 | } 33 | 34 | ///| 35 | /// Option map 方法 36 | let option_map_fn : RuntimeFunction = ctx => match ctx.args { 37 | [ 38 | { 39 | val: Constructor( 40 | { val: { name: "Some", fields: [{ value: inner_value, .. }] }, .. } 41 | ), 42 | .., 43 | }, 44 | { val: Fn(func), .. }, 45 | .., 46 | ] => { 47 | // 执行闭包调用 48 | let result = ctx.context.call(func.val, ctx.pkg, [ 49 | { val: inner_value, kind: Positional }, 50 | ]) 51 | ctx.pkg.cons("Some", [result]) 52 | } 53 | [{ val: Constructor({ val: { name: "None", fields: [] }, .. }), .. }, _, ..] => 54 | ctx.pkg.cons("None", []) 55 | _ => ctx.pkg.cons("None", []) 56 | } 57 | 58 | ///| 59 | /// Option map_or 方法 60 | let option_map_or_fn : RuntimeFunction = ctx => match ctx.args { 61 | [ 62 | { 63 | val: Constructor( 64 | { val: { name: "Some", fields: [{ value: inner_value, .. }] }, .. } 65 | ), 66 | .., 67 | }, 68 | _, 69 | { val: Fn(func), .. }, 70 | .., 71 | ] => 72 | // 对于Some值,执行闭包调用 73 | ctx.context.call(func.val, ctx.pkg, [{ val: inner_value, kind: Positional }]) 74 | [ 75 | { val: Constructor({ val: { name: "None", fields: [] }, .. }), .. }, 76 | { val: default_value, .. }, 77 | _, 78 | .., 79 | ] => default_value 80 | _ => Unit 81 | } 82 | 83 | ///| 84 | /// Option map_or_else 方法 85 | let option_map_or_else_fn : RuntimeFunction = ctx => match ctx.args { 86 | [ 87 | { 88 | val: Constructor( 89 | { val: { name: "Some", fields: [{ value: inner_value, .. }] }, .. } 90 | ), 91 | .., 92 | }, 93 | _, 94 | { val: Fn(map_func), .. }, 95 | .., 96 | ] => 97 | // 对于Some值,执行map闭包 98 | ctx.context.call(map_func.val, ctx.pkg, [ 99 | { val: inner_value, kind: Positional }, 100 | ]) 101 | [ 102 | { val: Constructor({ val: { name: "None", fields: [] }, .. }), .. }, 103 | { val: Fn(else_func), .. }, 104 | _, 105 | .., 106 | ] => 107 | // 对于None值,执行else闭包 108 | ctx.context.call(else_func.val, ctx.pkg, []) 109 | _ => Unit 110 | } 111 | 112 | ///| 113 | /// Option bind 方法 114 | let option_bind_fn : RuntimeFunction = ctx => match ctx.args { 115 | [ 116 | { 117 | val: Constructor( 118 | { val: { name: "Some", fields: [{ value: inner_value, .. }] }, .. } 119 | ), 120 | .., 121 | }, 122 | { val: Fn(func), .. }, 123 | .., 124 | ] => 125 | // 执行闭包调用,bind应该返回函数的结果(应该是Option类型) 126 | ctx.context.call(func.val, ctx.pkg, [{ val: inner_value, kind: Positional }]) 127 | [{ val: Constructor({ val: { name: "None", fields: [] }, .. }), .. }, _, ..] => 128 | ctx.pkg.cons("None", []) 129 | _ => ctx.pkg.cons("None", []) 130 | } 131 | 132 | ///| 133 | /// Option flatten 方法 134 | let option_flatten_fn : RuntimeFunction = ctx => match ctx.args { 135 | [ 136 | { 137 | val: Constructor( 138 | { 139 | val: { 140 | name: "Some", 141 | fields: [ 142 | { 143 | value: Constructor( 144 | { 145 | val: { name: "Some", fields: [{ value: inner_value, .. }] }, 146 | .., 147 | } 148 | ), 149 | .., 150 | }, 151 | ], 152 | }, 153 | .., 154 | } 155 | ), 156 | .., 157 | }, 158 | .., 159 | ] => ctx.pkg.cons("Some", [inner_value]) 160 | [ 161 | { 162 | val: Constructor( 163 | { 164 | val: { 165 | name: "Some", 166 | fields: [ 167 | { 168 | value: Constructor({ val: { name: "None", fields: [] }, .. }), 169 | .., 170 | }, 171 | ], 172 | }, 173 | .., 174 | } 175 | ), 176 | .., 177 | }, 178 | .., 179 | ] => ctx.pkg.cons("None", []) 180 | [{ val: Constructor({ val: { name: "None", fields: [] }, .. }), .. }] => 181 | ctx.pkg.cons("None", []) 182 | _ => ctx.pkg.cons("None", []) 183 | } 184 | 185 | ///| 186 | /// Option is_empty 方法 187 | let option_is_empty_fn : RuntimeFunction = ctx => match ctx.args { 188 | [{ val: Constructor({ val: { name: "Some", .. }, .. }), .. }] => Bool(false) 189 | [{ val: Constructor({ val: { name: "None", fields: [] }, .. }), .. }] => 190 | Bool(true) 191 | _ => Bool(true) 192 | } 193 | 194 | ///| 195 | /// Option filter 方法 196 | let option_filter_fn : RuntimeFunction = ctx => match ctx.args { 197 | [ 198 | { 199 | val: Constructor( 200 | { val: { name: "Some", fields: [{ value: inner_value, .. }] }, .. } 201 | ), 202 | .., 203 | }, 204 | { val: Fn(predicate), .. }, 205 | .., 206 | ] => { 207 | // 执行谓词闭包 208 | let result = ctx.context.call(predicate.val, ctx.pkg, [ 209 | { val: inner_value, kind: Positional }, 210 | ]) 211 | // 根据谓词结果决定是否保留值 212 | match result { 213 | Bool(true) => ctx.pkg.cons("Some", [inner_value]) 214 | _ => ctx.pkg.cons("None", []) 215 | } 216 | } 217 | [{ val: Constructor({ val: { name: "None", fields: [] }, .. }), .. }, _, ..] => 218 | ctx.pkg.cons("None", []) 219 | _ => ctx.pkg.cons("None", []) 220 | } 221 | 222 | ///| 223 | /// Option unwrap_or 方法 224 | let option_unwrap_or_fn : RuntimeFunction = ctx => match ctx.args { 225 | [ 226 | { 227 | val: Constructor( 228 | { val: { name: "Some", fields: [{ value: inner_value, .. }] }, .. } 229 | ), 230 | .., 231 | }, 232 | _, 233 | .., 234 | ] => inner_value 235 | [ 236 | { val: Constructor({ val: { name: "None", fields: [] }, .. }), .. }, 237 | { val: default_value, .. }, 238 | .., 239 | ] => default_value 240 | _ => Unit 241 | } 242 | 243 | // option_unwrap_or_else_fn 已移除,现在使用支持解释器的版本 244 | 245 | ///| 246 | /// Option unwrap_or_default 方法 247 | let option_unwrap_or_default_fn : RuntimeFunction = ctx => match ctx.args { 248 | [ 249 | { 250 | val: Constructor( 251 | { val: { name: "Some", fields: [{ value: inner_value, .. }] }, .. } 252 | ), 253 | .., 254 | }, 255 | .., 256 | ] => inner_value 257 | [{ val: Constructor({ val: { name: "None", fields: [] }, .. }), .. }] => 258 | // 返回默认值,对于数值类型返回0,其他类型返回Unit 259 | // 这里简化实现,实际应该根据泛型类型参数确定默认值 260 | Int(0, raw=None) 261 | _ => Int(0, raw=None) 262 | } 263 | 264 | ///| 265 | /// Option unwrap_or_else 方法 266 | let option_unwrap_or_else_fn : RuntimeFunction = ctx => match ctx.args { 267 | [ 268 | { 269 | val: Constructor( 270 | { val: { name: "Some", fields: [{ value: inner_value, .. }] }, .. } 271 | ), 272 | .., 273 | }, 274 | .., 275 | ] => inner_value 276 | [ 277 | { val: Constructor({ val: { name: "None", fields: [] }, .. }), .. }, 278 | { val: Fn(else_func), .. }, 279 | .., 280 | ] => 281 | // 对于None值,执行else闭包 282 | ctx.context.call(else_func.val, ctx.pkg, []) 283 | _ => Unit 284 | } 285 | -------------------------------------------------------------------------------- /src/interpreter/method_execution.mbt: -------------------------------------------------------------------------------- 1 | // Helper enum for function lookup - SIMPLIFIED 2 | 3 | ///| 4 | priv enum FunctionLookupResult { 5 | DirectFunction(RuntimeFunction) 6 | NotFound 7 | } 8 | 9 | // Method execution operations for ClosureInterpreter 10 | // This file contains all method calling and static method execution logic 11 | 12 | ///| 13 | /// 创建RuntimeFunctionContext的辅助函数 14 | fn ClosureInterpreter::create_function_context( 15 | self : ClosureInterpreter, 16 | args : FixedArray[RuntimeArgument], 17 | ) -> RuntimeFunctionContext { 18 | RuntimeFunctionContext::{ pkg: self.current_pkg, context: self, args } 19 | } 20 | 21 | ///| 22 | /// 查找embedded方法的辅助函数 23 | fn ClosureInterpreter::find_embedded_method( 24 | self : ClosureInterpreter, 25 | type_name : String, 26 | method_name : String, 27 | ) -> RuntimeFunction? { 28 | match self.embedded_methods.get(type_name) { 29 | Some(methods) => methods.get(method_name) 30 | None => None 31 | } 32 | } 33 | 34 | ///| 35 | /// 执行embedded函数的辅助函数 36 | fn ClosureInterpreter::execute_embedded_function( 37 | self : ClosureInterpreter, 38 | func : RuntimeFunction, 39 | args : FixedArray[RuntimeArgument], 40 | ) -> RuntimeValue raise ControlFlow { 41 | func(self.create_function_context(args)) 42 | } 43 | 44 | ///| 45 | /// 查找函数 - 简化版本 46 | fn ClosureInterpreter::lookup_function( 47 | self : ClosureInterpreter, 48 | pkg : RuntimePackage, 49 | name : String, 50 | ) -> FunctionLookupResult { 51 | // 首先查找用户函数 52 | match pkg.find(name).unwrap_or(self.current_pkg.find(name).unwrap_or(Unit)) { 53 | Fn(func) => FunctionLookupResult::DirectFunction(func.val) 54 | _ => 55 | // 查找fn_aliases 56 | match pkg.fn_aliases.get(name) { 57 | Some(Fn(func)) => FunctionLookupResult::DirectFunction(func.val) 58 | _ => 59 | // 查找extern函数 60 | match self.extern_fns.get(name) { 61 | Some(extern_func) => 62 | FunctionLookupResult::DirectFunction(extern_func) 63 | None => 64 | // 查找embedded函数 65 | match self.embedded_fns.get(name) { 66 | Some(embedded_func) => 67 | FunctionLookupResult::DirectFunction(embedded_func) 68 | None => FunctionLookupResult::NotFound 69 | } 70 | } 71 | } 72 | } 73 | } 74 | 75 | ///| 76 | /// 根据函数名执行函数 77 | fn ClosureInterpreter::call_by_name( 78 | self : ClosureInterpreter, 79 | long_ident : @syntax.LongIdent, 80 | args : @list.List[@syntax.Argument], 81 | ) -> RuntimeValue raise ControlFlow { 82 | let evaluated_args : FixedArray[RuntimeArgument] = FixedArray::from_array( 83 | args 84 | .map(arg => RuntimeArgument::{ 85 | val: self.visit(arg.value), 86 | kind: RuntimeArgumentKind::from_syntax(arg.kind), 87 | }) 88 | .to_array(), 89 | ) 90 | self.with_ident(long_ident, (pkg, name) => { 91 | let name = pkg.find_stub(name) 92 | match self.lookup_function(pkg, name) { 93 | FunctionLookupResult::DirectFunction(func) => 94 | self.execute_embedded_function(func, evaluated_args) 95 | FunctionLookupResult::NotFound => 96 | self.error( 97 | "execute_function_by_name method @\{pkg.name}.\{name} not found", 98 | ) 99 | } 100 | }) 101 | } 102 | 103 | ///| 104 | /// 执行结构体方法调用(返回 RuntimeValue) 105 | fn ClosureInterpreter::method_call( 106 | self : ClosureInterpreter, 107 | self_value : RuntimeValue, 108 | method_name : String, 109 | args : @list.List[@syntax.Argument], 110 | ) -> RuntimeValue raise ControlFlow { 111 | let self_type = self_value.get_type() 112 | 113 | // 尝试embedded方法 114 | if self_type is (Object(name~, ..) | Name(name~, ..)) { 115 | match self.find_embedded_method(name, method_name) { 116 | Some(embedded_method) => { 117 | let evaluated_args = self.convert_to_runtime_arguments(args) 118 | return self.execute_embedded_function( 119 | embedded_method, 120 | FixedArray::from_array( 121 | [ 122 | { val: self_value, kind: RuntimeArgumentKind::Positional }, 123 | ..evaluated_args, 124 | ], 125 | ), 126 | ) 127 | } 128 | None => () // Continue to try regular methods 129 | } 130 | } 131 | 132 | // 尝试用户定义的方法 133 | match self_type.find_method(method_name) { 134 | Some((pkg, func)) => 135 | self.execute_user_method(pkg, func, self_value, method_name, args) 136 | None => 137 | self.error("exec: \{self_type.to_string()}::\{method_name} not found") 138 | } 139 | } 140 | 141 | ///| 142 | /// 执行用户定义的方法 143 | fn ClosureInterpreter::execute_user_method( 144 | self : ClosureInterpreter, 145 | pkg : RuntimePackage, 146 | func : RuntimeValue, 147 | self_value : RuntimeValue, 148 | method_name : String, 149 | args : @list.List[@syntax.Argument], 150 | ) -> RuntimeValue raise ControlFlow { 151 | let old_mod = self.current_pkg 152 | let args = FixedArray::from_array( 153 | [ 154 | { val: self_value, kind: RuntimeArgumentKind::Positional }, 155 | ..self.convert_to_runtime_arguments(args), 156 | ], 157 | ) 158 | self.push_scope(RuntimeLocation::FunctionCall(method_name)) 159 | defer { 160 | self.pop_scope() 161 | self.current_pkg = old_mod 162 | } 163 | match func { 164 | Fn(func) => (func.val)({ context: self, pkg, args }) 165 | _ => 166 | self.error( 167 | "exec method: \{self_value.get_type().to_string()}::\{method_name} not found", 168 | ) 169 | } 170 | } 171 | 172 | ///| 173 | /// 执行静态方法调用(如 Bool::default()) 174 | fn ClosureInterpreter::execute_static_method_call( 175 | self : ClosureInterpreter, 176 | type_info : RuntimeType, 177 | method_name : String, 178 | args : @list.List[@syntax.Argument], 179 | ) -> RuntimeValue raise ControlFlow { 180 | let evaluated_args = FixedArray::from_array( 181 | args 182 | .map(arg => { 183 | val: self.visit(arg.value), 184 | kind: RuntimeArgumentKind::from_syntax(arg.kind), 185 | }) 186 | .to_array(), 187 | ) 188 | // 尝试embedded方法 189 | if type_info is Object(name~, ..) { 190 | match self.find_embedded_method(name, method_name) { 191 | Some(embedded_func) => 192 | return self.execute_embedded_function(embedded_func, evaluated_args) 193 | None => () 194 | } 195 | } 196 | 197 | // 尝试用户定义的静态方法 198 | match type_info.find_method(method_name) { 199 | Some((pkg, func)) => 200 | match func { 201 | Fn(func) => self.call(func.val, pkg, evaluated_args) 202 | _ => Unit 203 | } 204 | None => self.error("static method \{type_info}::\{method_name} not found") 205 | } 206 | } 207 | 208 | ///| 209 | /// 查找类型的方法 210 | fn RuntimeType::find_method( 211 | self : RuntimeType, 212 | method_name : String, 213 | ) -> (RuntimePackage, RuntimeValue)? { 214 | match self { 215 | Object(pkg~, name~) => 216 | // 首先查找struct方法 217 | match pkg.struct_methods.get(name) { 218 | Some(methods) => 219 | match methods.get(method_name) { 220 | Some(func) => Some((pkg, func)) 221 | None => find_trait_method(pkg, name, method_name) 222 | } 223 | None => find_trait_method(pkg, name, method_name) 224 | } 225 | _ => None 226 | } 227 | } 228 | 229 | ///| 230 | /// 查找trait方法的辅助函数 231 | fn find_trait_method( 232 | pkg : RuntimePackage, 233 | type_name : String, 234 | method_name : String, 235 | ) -> (RuntimePackage, RuntimeValue)? { 236 | match pkg.type_derived_traits.get(type_name) { 237 | Some(derived_traits) => { 238 | for trait_name in derived_traits { 239 | match pkg.trait_methods.get(trait_name) { 240 | Some(methods) => 241 | match methods.get(method_name) { 242 | Some(func) => return Some((pkg, func)) 243 | None => continue 244 | } 245 | None => continue 246 | } 247 | } 248 | None 249 | } 250 | None => None 251 | } 252 | } 253 | -------------------------------------------------------------------------------- /src/interpreter/map.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub let map_methods : Map[String, RuntimeFunction] = { 3 | "clear": map_clear_fn, 4 | "is_empty": map_is_empty_fn, 5 | "capacity": map_capacity_fn, 6 | "contains": map_contains_fn, 7 | "contains_kv": map_contains_kv_fn, 8 | "copy": map_copy_fn, 9 | "each": map_each_fn, 10 | "eachi": map_eachi_fn, 11 | "from_array": map_from_array_fn, 12 | "from_iter": map_from_iter_fn, 13 | "get": map_get_fn, 14 | "get_or_default": map_get_or_default_fn, 15 | "get_or_init": map_get_or_init_fn, 16 | "iter": map_iter_fn, 17 | "iter2": map_iter2_fn, 18 | "keys": map_keys_fn, 19 | "map": map_map_fn, 20 | "new": map_new_fn, 21 | "of": map_of_fn, 22 | "remove": map_remove_fn, 23 | "set": map_set_fn, 24 | "size": map_size_fn, 25 | "to_array": map_to_array_fn, 26 | "update": map_update_fn, 27 | "values": map_values_fn, 28 | } 29 | 30 | ///| 31 | /// Map clear操作 32 | let map_clear_fn : RuntimeFunction = ctx => match ctx.args { 33 | [{ val: Map(map), .. }] => { 34 | map.clear() 35 | Unit 36 | } 37 | _ => Unit 38 | } 39 | 40 | ///| 41 | /// Map is_empty操作 42 | let map_is_empty_fn : RuntimeFunction = ctx => match ctx.args { 43 | [{ val: Map(map), .. }] => Bool(map.is_empty()) 44 | _ => Unit 45 | } 46 | 47 | ///| 48 | /// Map capacity操作 49 | let map_capacity_fn : RuntimeFunction = ctx => match ctx.args { 50 | [{ val: Map(map), .. }] => Int(map.capacity(), raw=None) 51 | _ => Unit 52 | } 53 | 54 | ///| 55 | /// Map contains操作 56 | let map_contains_fn : RuntimeFunction = ctx => match ctx.args { 57 | [{ val: Map(map), .. }, { val: key, .. }] => Bool(map.contains(key)) 58 | _ => Unit 59 | } 60 | 61 | ///| 62 | /// Map contains_kv操作 63 | let map_contains_kv_fn : RuntimeFunction = ctx => match ctx.args { 64 | [{ val: Map(map), .. }, { val: key, .. }, { val, .. }] => 65 | Bool(map.get(key) == Some(val)) 66 | _ => Unit 67 | } 68 | 69 | ///| 70 | /// Map copy操作 71 | let map_copy_fn : RuntimeFunction = ctx => match ctx.args { 72 | [{ val: Map(map), .. }] => Map(map.copy()) 73 | _ => Unit 74 | } 75 | 76 | ///| 77 | /// Map each操作 78 | let map_each_fn : RuntimeFunction = ctx => match ctx.args { 79 | [{ val: Map(map), .. }, { val: Fn(f), .. }] => { 80 | map.each(fn(key, val) { 81 | ctx.context.call(f.val, ctx.pkg, [ 82 | { val: key, kind: Positional }, 83 | { val, kind: Positional }, 84 | ]) 85 | |> ignore 86 | }) 87 | Unit 88 | } 89 | _ => Unit 90 | } 91 | 92 | ///| 93 | /// Map eachi操作 94 | let map_eachi_fn : RuntimeFunction = ctx => match ctx.args { 95 | [{ val: Map(map), .. }, { val: Fn(f), .. }] => { 96 | map.eachi(fn(i, key, val) { 97 | ctx.context.call(f.val, ctx.pkg, [ 98 | { val: Int(i, raw=None), kind: Positional }, 99 | { val: key, kind: Positional }, 100 | { val, kind: Positional }, 101 | ]) 102 | |> ignore 103 | }) 104 | Unit 105 | } 106 | _ => Unit 107 | } 108 | 109 | ///| 110 | /// Map from_array操作 111 | let map_from_array_fn : RuntimeFunction = ctx => match ctx.args { 112 | [{ val: Array(arr), .. }] => { 113 | let map = Map::new() 114 | arr.each(fn(item) { 115 | match item { 116 | Tuple([key, val]) => map.set(key, val) 117 | _ => () 118 | } 119 | }) 120 | Map(map) 121 | } 122 | _ => Unit 123 | } 124 | 125 | ///| 126 | /// Map from_iter操作 127 | let map_from_iter_fn : RuntimeFunction = ctx => match ctx.args { 128 | [{ val: Iter(iter), .. }] => 129 | Map( 130 | Map::from_iter( 131 | iter.map(item => match item { 132 | Tuple([key, val]) => (key, val) 133 | _ => panic() 134 | }), 135 | ), 136 | ) 137 | _ => Unit 138 | } 139 | 140 | ///| 141 | /// Map get操作 142 | let map_get_fn : RuntimeFunction = ctx => match ctx.args { 143 | [{ val: Map(map), .. }, { val: key, .. }] => 144 | RuntimeValue::from_option(map.get(key)) 145 | _ => Unit 146 | } 147 | 148 | ///| 149 | /// Map get_or_default操作 150 | let map_get_or_default_fn : RuntimeFunction = ctx => match ctx.args { 151 | [{ val: Map(map), .. }, { val: key, .. }, { val: default, .. }] => 152 | match map.get(key) { 153 | Some(val) => val 154 | None => default 155 | } 156 | _ => Unit 157 | } 158 | 159 | ///| 160 | /// Map get_or_init操作 161 | let map_get_or_init_fn : RuntimeFunction = ctx => match ctx.args { 162 | [{ val: Map(map), .. }, { val: key, .. }, { val: Fn(f), .. }] => 163 | match map.get(key) { 164 | Some(val) => val 165 | None => { 166 | let val = ctx.context.call(f.val, ctx.pkg, []) 167 | map.set(key, val) 168 | val 169 | } 170 | } 171 | _ => Unit 172 | } 173 | 174 | ///| 175 | /// Map iter操作 176 | let map_iter_fn : RuntimeFunction = ctx => match ctx.args { 177 | [{ val: Map(self), .. }] => 178 | Iter( 179 | self 180 | .iter() 181 | .map(item => match item { 182 | (key, val) => Tuple([key, val]) 183 | }), 184 | ) 185 | _ => Unit 186 | } 187 | 188 | ///| 189 | /// Map iter2操作 190 | let map_iter2_fn : RuntimeFunction = ctx => match ctx.args { 191 | [{ val: Map(self), .. }] => Iter2(self.iter2()) 192 | _ => Unit 193 | } 194 | 195 | ///| 196 | /// Map keys操作 197 | let map_keys_fn : RuntimeFunction = ctx => match ctx.args { 198 | [{ val: Map(map), .. }] => { 199 | let arr = Array::new() 200 | map.each(fn(key, _val) { arr.push(key) }) 201 | Array(arr) 202 | } 203 | _ => Unit 204 | } 205 | 206 | ///| 207 | /// Map map操作 208 | let map_map_fn : RuntimeFunction = ctx => match ctx.args { 209 | [{ val: Map(map), .. }, { val: Fn(f), .. }] => { 210 | let new_map = Map::new() 211 | map.each(fn(key, val) { 212 | let new_val = ctx.context.call(f.val, ctx.pkg, [ 213 | { val: key, kind: Positional }, 214 | { val, kind: Positional }, 215 | ]) 216 | new_map.set(key, new_val) 217 | }) 218 | Map(new_map) 219 | } 220 | _ => Unit 221 | } 222 | 223 | ///| 224 | /// Map new操作 225 | let map_new_fn : RuntimeFunction = ctx => match ctx.args { 226 | _ => Map(Map::new()) 227 | } 228 | 229 | ///| 230 | /// Map of操作 231 | let map_of_fn : RuntimeFunction = ctx => match ctx.args { 232 | [{ val: Array(arr), .. }] => 233 | Map( 234 | Map::from_array( 235 | arr.map(fn(item) { 236 | match item { 237 | Tuple([key, val]) => (key, val) 238 | _ => error("Map of: (arr: T)") 239 | } 240 | }), 241 | ), 242 | ) 243 | _ => error("Map of: (arr: T)") 244 | } 245 | 246 | ///| 247 | /// Map remove操作 248 | let map_remove_fn : RuntimeFunction = ctx => match ctx.args { 249 | [{ val: Map(map), .. }, { val: key, .. }] => { 250 | map.remove(key) 251 | Unit 252 | } 253 | _ => Unit 254 | } 255 | 256 | ///| 257 | /// Map set操作 258 | let map_set_fn : RuntimeFunction = ctx => match ctx.args { 259 | [{ val: Map(map), .. }, { val: key, .. }, { val, .. }] => { 260 | map.set(key, val) 261 | Unit 262 | } 263 | _ => Unit 264 | } 265 | 266 | ///| 267 | /// Map size操作 268 | let map_size_fn : RuntimeFunction = ctx => match ctx.args { 269 | [{ val: Map(map), .. }] => Int(map.length(), raw=None) 270 | _ => Unit 271 | } 272 | 273 | ///| 274 | /// Map to_array操作 275 | let map_to_array_fn : RuntimeFunction = ctx => match ctx.args { 276 | [{ val: Map(map), .. }] => { 277 | let arr : Array[RuntimeValue] = Array::new() 278 | map.each(fn(key, val) { arr.push(Tuple([key, val])) }) 279 | Array(arr) 280 | } 281 | _ => Unit 282 | } 283 | 284 | ///| 285 | /// Map update操作 286 | let map_update_fn : RuntimeFunction = ctx => match ctx.args { 287 | [{ val: Map(map), .. }, { val: key, .. }, { val: Fn(f), .. }] => { 288 | match map.get(key) { 289 | Some(old_val) => { 290 | let new_val = ctx.context.call(f.val, ctx.pkg, [ 291 | { val: old_val, kind: Positional }, 292 | ]) 293 | map.set(key, new_val) 294 | } 295 | None => () 296 | } 297 | Unit 298 | } 299 | _ => Unit 300 | } 301 | 302 | ///| 303 | /// Map values操作 304 | let map_values_fn : RuntimeFunction = ctx => match ctx.args { 305 | [{ val: Map(map), .. }] => { 306 | let arr = Array::new() 307 | map.each(fn(_key, val) { arr.push(val) }) 308 | Array(arr) 309 | } 310 | _ => Unit 311 | } 312 | -------------------------------------------------------------------------------- /src/test/data_structure.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | test "tuples" { 3 | let vm = MoonBitVM::new() 4 | inspect(vm.eval("let t = (1, 2)"), content="()") 5 | inspect(vm.eval("t.0"), content="1") 6 | inspect(vm.eval("t.1"), content="2") 7 | inspect(vm.eval("t"), content="(1, 2)") 8 | inspect(vm.eval("let (a, b) = t"), content="()") 9 | inspect(vm.eval("a"), content="1") 10 | inspect(vm.eval("b"), content="2") 11 | } 12 | 13 | ///| 14 | test "arrays" { 15 | let vm = MoonBitVM::new() 16 | inspect(vm.eval("let arr = [1, 2, 3]; arr.length()"), content="3") 17 | inspect(vm.eval("let arr = []; arr.is_empty()"), content="true") 18 | inspect(vm.eval("let arr = [1, 2, 3]; arr.is_empty()"), content="false") 19 | inspect( 20 | vm.eval("let arr = [\"1\", \"2\", \"3\"]; arr.join(\"-\")"), 21 | content="1-2-3", 22 | ) 23 | } 24 | 25 | ///| 26 | test "array_spread" { 27 | let vm = MoonBitVM::new() 28 | // Test array spread syntax 29 | assert_eq( 30 | vm 31 | .eval("let arr1 = [1, 2]; let arr2 = [3, 4]; [..arr1, ..arr2]") 32 | .to_string(), 33 | "[1, 2, 3, 4]", 34 | ) 35 | assert_eq( 36 | vm.eval("let arr = [2, 3]; [1, ..arr, 4]").to_string(), 37 | "[1, 2, 3, 4]", 38 | ) 39 | assert_eq(vm.eval("let arr = [1, 2, 3]; [..arr]").to_string(), "[1, 2, 3]") 40 | } 41 | 42 | ///| 43 | test "array_slice_operations" { 44 | let vm = MoonBitVM::new() 45 | // Test array slice get operations 46 | assert_eq( 47 | vm.eval("let arr = [1, 2, 3, 4, 5]; arr[1:3]").to_string(), 48 | "[2, 3]", 49 | ) 50 | assert_eq( 51 | vm.eval("let arr = [1, 2, 3, 4, 5]; arr[2:]").to_string(), 52 | "[3, 4, 5]", 53 | ) 54 | assert_eq( 55 | vm.eval("let arr = [1, 2, 3, 4, 5]; arr[:3]").to_string(), 56 | "[1, 2, 3]", 57 | ) 58 | assert_eq( 59 | vm.eval("let arr = [1, 2, 3, 4, 5]; arr[:]").to_string(), 60 | "[1, 2, 3, 4, 5]", 61 | ) 62 | } 63 | 64 | ///| 65 | test "array_set_operations" { 66 | let vm = MoonBitVM::new() 67 | // Test array set operations 68 | assert_eq( 69 | vm.eval("let mut arr = [1, 2, 3]; arr[1] = 5; arr").to_string(), 70 | "[1, 5, 3]", 71 | ) 72 | assert_eq( 73 | vm.eval("let mut arr = [1, 2, 3]; arr[0] = 10; arr[0]").to_string(), 74 | "10", 75 | ) 76 | } 77 | 78 | ///| 79 | test "array_augmented_set" { 80 | let vm = MoonBitVM::new() 81 | // Test array augmented assignment operations 82 | assert_eq( 83 | vm.eval("let mut arr = [1, 2, 3]; arr[1] += 5; arr").to_string(), 84 | "[1, 7, 3]", 85 | ) 86 | assert_eq( 87 | vm.eval("let mut arr = [10, 20, 30]; arr[0] -= 5; arr[0]").to_string(), 88 | "5", 89 | ) 90 | assert_eq( 91 | vm.eval("let mut arr = [2, 4, 6]; arr[1] *= 3; arr[1]").to_string(), 92 | "12", 93 | ) 94 | } 95 | 96 | ///| 97 | test "structs" { 98 | let vm = MoonBitVM::new() 99 | inspect( 100 | vm.eval( 101 | ( 102 | #|struct S { 103 | #| a: Int 104 | #| b: Int 105 | #|} 106 | #|fn S::sum(self: S) -> Int { 107 | #| self.a + self.b 108 | #|} 109 | ), 110 | top=true, 111 | ), 112 | content="()", 113 | ) 114 | inspect(vm.eval("let s = { a: 23, b: 32 }"), content="()") 115 | inspect(vm.eval("s.sum()"), content="55") 116 | } 117 | 118 | ///| 119 | test "mutable_structs" { 120 | let vm = MoonBitVM::new() 121 | inspect( 122 | vm.eval( 123 | ( 124 | #|struct Point { 125 | #| mut x : Int 126 | #| mut y : Int 127 | #|} 128 | ), 129 | top=true, 130 | ), 131 | content="()", 132 | ) 133 | inspect(vm.eval("let p = { x: 1, y: 2 }"), content="()") 134 | inspect(vm.eval("p.x"), content="1") 135 | inspect(vm.eval("p.y"), content="2") 136 | inspect(vm.eval("p.x = 3"), content="()") 137 | inspect(vm.eval("p.y = 4"), content="()") 138 | inspect(vm.eval("p.x"), content="3") 139 | inspect(vm.eval("p.y"), content="4") 140 | inspect(vm.eval("p"), content="Point::{x: 3, y: 4}") 141 | } 142 | 143 | ///| 144 | test "record_update" { 145 | let vm = MoonBitVM::new() 146 | assert_eq( 147 | vm 148 | .eval( 149 | ( 150 | #|struct Person { 151 | #| name : String 152 | #| age : Int 153 | #|} 154 | ), 155 | top=true, 156 | ) 157 | .to_string(), 158 | "()", 159 | ) 160 | assert_eq(vm.eval("let p1 = { name: \"Alice\", age: 25 }").to_string(), "()") 161 | assert_eq(vm.eval("let p2 = { ..p1, age: 26 }").to_string(), "()") 162 | assert_eq(vm.eval("p2.name").to_string(), "Alice") 163 | assert_eq(vm.eval("p2.age").to_string(), "26") 164 | assert_eq(vm.eval("p1.age").to_string(), "25") 165 | } 166 | 167 | ///| 168 | test "method_calls" { 169 | let vm = MoonBitVM::new() 170 | assert_eq( 171 | vm 172 | .eval( 173 | ( 174 | #|struct Calculator { 175 | #| value : Int 176 | #|} 177 | #|fn Calculator::add(self : Calculator, x : Int) -> Int { 178 | #| self.value + x 179 | #|} 180 | #|fn Calculator::multiply(self : Calculator, x : Int) -> Int { 181 | #| self.value * x 182 | #|} 183 | ), 184 | top=true, 185 | ) 186 | .to_string(), 187 | "()", 188 | ) 189 | assert_eq(vm.eval("let calc = { value: 10 }").to_string(), "()") 190 | assert_eq(vm.eval("calc").to_string(), "Calculator::{value: 10}") 191 | assert_eq(vm.eval("calc.value").to_string(), "10") 192 | assert_eq(vm.eval("calc.add(5)").to_string(), "15") 193 | assert_eq(vm.eval("calc.multiply(3)").to_string(), "30") 194 | assert_eq(vm.eval("Calculator::add").to_string(), "(Calculator, Int) -> Int") 195 | } 196 | 197 | ///| 198 | test "trait_as_expressions" { 199 | let vm = MoonBitVM::new() 200 | // Test basic string operations first 201 | assert_eq(vm.eval("1.to_string()").to_string(), "1") 202 | assert_eq(vm.eval("\"hello\" + \" world\"").to_string(), "hello world") 203 | 204 | // Test 'as' expressions for trait casting 205 | assert_eq( 206 | vm 207 | .eval( 208 | ( 209 | #|trait Show { 210 | #| show(Self) -> String 211 | #|} 212 | #|struct Point { 213 | #| x : Int 214 | #| y : Int 215 | #|} 216 | #|fn Point::show(self : Point) -> String { 217 | #| "(" + self.x.to_string() + ", " + self.y.to_string() + ")" 218 | #|} 219 | ), 220 | top=true, 221 | ) 222 | .to_string(), 223 | "()", 224 | ) 225 | assert_eq(vm.eval("let p = { x: 1, y: 2 }").to_string(), "()") 226 | assert_eq(vm.eval("(p as Show).show()").to_string(), "(1, 2)") 227 | } 228 | 229 | ///| 230 | test "field_mutation" { 231 | let vm = MoonBitVM::new() 232 | assert_eq( 233 | vm 234 | .eval( 235 | ( 236 | #|struct Counter { 237 | #| mut count : Int 238 | #|} 239 | ), 240 | top=true, 241 | ) 242 | .to_string(), 243 | "()", 244 | ) 245 | assert_eq(vm.eval("let c = { count: 0 }").to_string(), "()") 246 | assert_eq(vm.eval("c.count = 5").to_string(), "()") 247 | assert_eq(vm.eval("c.count").to_string(), "5") 248 | 249 | // 测试简单赋值对比 250 | assert_eq(vm.eval("c.count = 5").to_string(), "()") 251 | // 测试 += 是否被解析为 = 252 | assert_eq(vm.eval("c.count = 3").to_string(), "()") 253 | assert_eq(vm.eval("c.count += 3").to_string(), "()") 254 | assert_eq(vm.eval("c.count").to_string(), "6") 255 | assert_eq(vm.eval("c.count *= 2").to_string(), "()") 256 | assert_eq(vm.eval("c.count").to_string(), "12") 257 | } 258 | 259 | ///| 260 | test "references" { 261 | let vm = MoonBitVM::new() 262 | inspect( 263 | vm.eval( 264 | ( 265 | #|struct RefInt { 266 | #| mut value: Int 267 | #|} 268 | ), 269 | top=true, 270 | ), 271 | content="()", 272 | ) 273 | inspect( 274 | vm.eval( 275 | ( 276 | #|let a = { value: 1 } 277 | #|let b = a 278 | #|b.value = 2 279 | ), 280 | ), 281 | content="()", 282 | ) 283 | inspect(vm.eval("a"), content="RefInt::{value: 2}") 284 | inspect(vm.eval("a.value"), content="2") 285 | } 286 | 287 | ///| 288 | test "nested_struct_reference" { 289 | let vm = MoonBitVM::new() 290 | inspect( 291 | vm.eval( 292 | ( 293 | #|struct S { 294 | #| mut a: Int 295 | #|} 296 | #| 297 | #|struct T { 298 | #| a: S 299 | #|} 300 | ), 301 | top=true, 302 | ), 303 | content="()", 304 | ) 305 | inspect(vm.eval("let a = { a: 1 }"), content="()") 306 | inspect(vm.eval("let b = { a: a }"), content="()") 307 | inspect(vm.eval("b.a.a = 2"), content="()") 308 | inspect(vm.eval("a"), content="T::{a: 2}") 309 | } 310 | -------------------------------------------------------------------------------- /src/interpreter/array_view.mbt: -------------------------------------------------------------------------------- 1 | ///| 2 | pub let array_view_methods : Map[String, RuntimeFunction] = { 3 | "length": array_view_length_fn, 4 | "all": array_view_all_fn, 5 | "any": array_view_any_fn, 6 | "contains": array_view_contains_fn, 7 | "each": array_view_each_fn, 8 | "eachi": array_view_eachi_fn, 9 | "filter": array_view_filter_fn, 10 | "fold": array_view_fold_fn, 11 | "foldi": array_view_foldi_fn, 12 | "iter": array_view_iter_fn, 13 | "iter2": array_view_iter2_fn, 14 | "join": array_view_join_fn, 15 | "map": array_view_map_fn, 16 | "mapi": array_view_mapi_fn, 17 | "rev_fold": array_view_rev_fold_fn, 18 | "rev_foldi": array_view_rev_foldi_fn, 19 | "to_array": array_view_to_array_fn, 20 | // "unsafe_extract_bit": array_view_unsafe_extract_bit_fn, 21 | // "unsafe_extract_byte": array_view_unsafe_extract_byte_fn, 22 | // "unsafe_extract_bytesview": array_view_unsafe_extract_bytesview_fn, 23 | // "unsafe_extract_uint64_be": array_view_unsafe_extract_uint64_be_fn, 24 | // "unsafe_extract_uint64_le": array_view_unsafe_extract_uint64_le_fn, 25 | // "unsafe_extract_uint_be": array_view_unsafe_extract_uint_be_fn, 26 | // "unsafe_extract_uint_le": array_view_unsafe_extract_uint_le_fn, 27 | } 28 | 29 | ///| 30 | /// 数组长度 31 | let array_view_length_fn : RuntimeFunction = ctx => match ctx.args { 32 | [{ val: ArrayView(arr), .. }] => Int(arr.length(), raw=None) 33 | _ => Unit 34 | } 35 | 36 | ///| 37 | fn[T] ArrayView::buf(self : ArrayView[T]) -> UninitializedArray[T] = "%arrayview.buf" 38 | 39 | ///| 40 | fn[T] ArrayView::start(self : ArrayView[T]) -> Int = "%arrayview.start" 41 | 42 | ///| 43 | fn[T] ArrayView::len(self : ArrayView[T]) -> Int = "%arrayview.len" 44 | 45 | ///| 46 | /// ArrayView start 方法 - 返回起始索引 47 | let array_view_buf_fn : RuntimeFunction = ctx => match ctx.args { 48 | [{ val: ArrayView(arr), .. }] => UninitializedArray(arr.buf()) 49 | _ => Unit 50 | } 51 | 52 | ///| 53 | /// ArrayView start 方法 - 返回起始索引 54 | let array_view_start_fn : RuntimeFunction = ctx => match ctx.args { 55 | [{ val: ArrayView(arr), .. }] => Int(arr.start(), raw=None) 56 | _ => Unit 57 | } 58 | 59 | ///| 60 | /// ArrayView len 方法 61 | let array_view_len_fn : RuntimeFunction = ctx => match ctx.args { 62 | [{ val: ArrayView(arr), .. }] => Int(arr.len(), raw=None) 63 | _ => Unit 64 | } 65 | 66 | ///| 67 | /// ArrayView all 方法 68 | let array_view_all_fn : RuntimeFunction = ctx => match ctx.args { 69 | [{ val: ArrayView(arr), .. }, { val: Fn(f), .. }] => 70 | Bool( 71 | arr.all(elem => ctx.context.call(f.val, ctx.pkg, [ 72 | { val: elem, kind: Positional }, 73 | ]) 74 | is Bool(true)), 75 | ) 76 | _ => Unit 77 | } 78 | 79 | ///| 80 | /// ArrayView any 方法 81 | let array_view_any_fn : RuntimeFunction = ctx => match ctx.args { 82 | [{ val: ArrayView(arr), .. }, { val: Fn(f), .. }] => 83 | Bool( 84 | arr.any(elem => ctx.context.call(f.val, ctx.pkg, [ 85 | { val: elem, kind: Positional }, 86 | ]) 87 | is Bool(true)), 88 | ) 89 | _ => Unit 90 | } 91 | 92 | ///| 93 | /// ArrayView contains 方法 94 | let array_view_contains_fn : RuntimeFunction = ctx => match ctx.args { 95 | [{ val: ArrayView(arr), .. }, { val: x, .. }] => Bool(arr.contains(x)) 96 | _ => Unit 97 | } 98 | 99 | ///| 100 | /// ArrayView each 方法 101 | let array_view_each_fn : RuntimeFunction = ctx => match ctx.args { 102 | [{ val: ArrayView(arr), .. }, { val: Fn(f), .. }] => { 103 | arr.each(elem => ctx.context.call(f.val, ctx.pkg, [ 104 | { val: elem, kind: Positional }, 105 | ]) 106 | |> ignore) 107 | Unit 108 | } 109 | _ => Unit 110 | } 111 | 112 | ///| 113 | /// ArrayView eachi 方法 114 | let array_view_eachi_fn : RuntimeFunction = ctx => match ctx.args { 115 | [{ val: ArrayView(arr), .. }, { val: Fn(f), .. }] => { 116 | arr.eachi((i, elem) => ctx.context.call(f.val, ctx.pkg, [ 117 | { val: Int(i, raw=None), kind: Positional }, 118 | { val: elem, kind: Positional }, 119 | ]) 120 | |> ignore) 121 | Unit 122 | } 123 | _ => Unit 124 | } 125 | 126 | ///| 127 | /// ArrayView filter 方法 128 | let array_view_filter_fn : RuntimeFunction = ctx => match ctx.args { 129 | [{ val: ArrayView(arr), .. }, { val: Fn(f), .. }] => 130 | Array( 131 | arr.filter(elem => ctx.context.call(f.val, ctx.pkg, [ 132 | { val: elem, kind: Positional }, 133 | ]) 134 | is Bool(true)), 135 | ) 136 | _ => Unit 137 | } 138 | 139 | ///| 140 | /// ArrayView fold 方法 141 | let array_view_fold_fn : RuntimeFunction = ctx => match ctx.args { 142 | [{ val: ArrayView(arr), .. }, { val: init, .. }, { val: Fn(f), .. }] => 143 | arr.fold(init~, fn(acc, elem) { 144 | ctx.context.call(f.val, ctx.pkg, [ 145 | { val: acc, kind: Positional }, 146 | { val: elem, kind: Positional }, 147 | ]) 148 | }) 149 | _ => Unit 150 | } 151 | 152 | ///| 153 | /// ArrayView foldi 方法 154 | let array_view_foldi_fn : RuntimeFunction = ctx => match ctx.args { 155 | [{ val: ArrayView(arr), .. }, { val: init, .. }, { val: Fn(f), .. }] => 156 | arr.foldi(init~, fn(i, acc, elem) { 157 | ctx.context.call(f.val, ctx.pkg, [ 158 | { val: Int(i, raw=None), kind: Positional }, 159 | { val: acc, kind: Positional }, 160 | { val: elem, kind: Positional }, 161 | ]) 162 | }) 163 | _ => Unit 164 | } 165 | 166 | ///| 167 | /// ArrayView iter 方法 168 | let array_view_iter_fn : RuntimeFunction = ctx => match ctx.args { 169 | [{ val: ArrayView(arr), .. }] => Array(arr.iter().collect()) 170 | _ => Unit 171 | } 172 | 173 | ///| 174 | /// ArrayView iter2 方法 175 | let array_view_iter2_fn : RuntimeFunction = ctx => match ctx.args { 176 | [{ val: ArrayView(self), .. }] => 177 | Iter2( 178 | Iter2::new(yield_ => for i, v in self { 179 | guard yield_(Int(i, raw=None), v) is IterContinue else { break IterEnd } 180 | } else { 181 | IterContinue 182 | }), 183 | ) 184 | _ => Unit 185 | } 186 | 187 | ///| 188 | /// ArrayView join 方法 189 | let array_view_join_fn : RuntimeFunction = ctx => match ctx.args { 190 | [{ val: ArrayView(arr), .. }, { val: String(separator), .. }] => 191 | String(arr.map(elem => elem.to_string()).join(separator)) 192 | _ => Unit 193 | } 194 | 195 | ///| 196 | /// ArrayView map 方法 197 | let array_view_map_fn : RuntimeFunction = ctx => match ctx.args { 198 | [{ val: ArrayView(arr), .. }, { val: Fn(f), .. }] => 199 | Array( 200 | arr.map(elem => ctx.context.call(f.val, ctx.pkg, [ 201 | { val: elem, kind: Positional }, 202 | ])), 203 | ) 204 | _ => Unit 205 | } 206 | 207 | ///| 208 | /// ArrayView mapi 方法 209 | let array_view_mapi_fn : RuntimeFunction = ctx => match ctx.args { 210 | [{ val: ArrayView(arr), .. }, { val: Fn(f), .. }] => 211 | Array( 212 | arr.mapi((i, elem) => ctx.context.call(f.val, ctx.pkg, [ 213 | { val: Int(i, raw=None), kind: Positional }, 214 | { val: elem, kind: Positional }, 215 | ])), 216 | ) 217 | _ => Unit 218 | } 219 | 220 | ///| 221 | /// ArrayView rev_fold 方法 222 | let array_view_rev_fold_fn : RuntimeFunction = ctx => match ctx.args { 223 | [{ val: ArrayView(arr), .. }, { val: init, .. }, { val: Fn(f), .. }] => 224 | arr.rev_fold(init~, fn(acc, elem) { 225 | ctx.context.call(f.val, ctx.pkg, [ 226 | { val: acc, kind: Positional }, 227 | { val: elem, kind: Positional }, 228 | ]) 229 | }) 230 | _ => Unit 231 | } 232 | 233 | ///| 234 | /// ArrayView rev_foldi 方法 235 | let array_view_rev_foldi_fn : RuntimeFunction = ctx => match ctx.args { 236 | [{ val: ArrayView(arr), .. }, { val: init, .. }, { val: Fn(f), .. }] => 237 | arr.rev_foldi(init~, fn(i, acc, elem) { 238 | ctx.context.call(f.val, ctx.pkg, [ 239 | { val: Int(i, raw=None), kind: Positional }, 240 | { val: acc, kind: Positional }, 241 | { val: elem, kind: Positional }, 242 | ]) 243 | }) 244 | _ => Unit 245 | } 246 | 247 | ///| 248 | /// ArrayView to_array 方法 249 | let array_view_to_array_fn : RuntimeFunction = ctx => match ctx.args { 250 | [{ val: ArrayView(arr), .. }] => Array(arr.to_array()) 251 | _ => Unit 252 | } 253 | 254 | // ///| 255 | // /// ArrayView unsafe_extract_bit 方法 256 | // let array_view_unsafe_extract_bit_fn : RuntimeFunction = ctx => match ctx.args { 257 | // [{ val: ArrayView(bs), .. }, { val: Int(offset), .. }, { val: Int(_len), .. }] => 258 | // UInt( 259 | // bs 260 | // .map(i => match i { 261 | // Byte(b) => b 262 | // _ => raise Error("ArrayView::unsafe_extract_bit: non-byte element") 263 | // }) 264 | // .unsafe_extract_bit(offset, _len), 265 | // ) 266 | // _ => Unit 267 | // } 268 | -------------------------------------------------------------------------------- /generate_core_modules.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | Generate embedded core modules for moonbit-eval interpreter. 4 | This script reads all modules from moonbitlang/core and generates 5 | RuntimePackage definitions in the format expected by core_modules.mbt. 6 | """ 7 | 8 | from ast import alias 9 | import os 10 | import json 11 | import re 12 | from pathlib import Path 13 | from typing import Dict, List, Set, Tuple 14 | 15 | # Core library path 16 | CORE_PATH = "/Users/oboard/.moon/lib/core" 17 | OUTPUT_FILE = "src/interpreter/core_modules.mbt" 18 | 19 | # Removed extract_all_items function - no longer needed with new format 20 | 21 | def read_module_info(module_dir: Path) -> Dict: 22 | """ 23 | Read module information from a directory. 24 | Returns dict with module name, dependencies, and concatenated code content. 25 | """ 26 | pkg = "moonbitlang/core/" + module_dir.relative_to(CORE_PATH).as_posix() 27 | alias = module_dir.relative_to(CORE_PATH).as_posix() 28 | module_name = pkg.replace('/', '_') 29 | 30 | # Read moon.pkg.json if it exists 31 | pkg_json_path = module_dir / "moon.pkg.json" 32 | dependencies = [] 33 | if pkg_json_path.exists(): 34 | try: 35 | with open(pkg_json_path, 'r') as f: 36 | pkg_data = json.load(f) 37 | dependencies = pkg_data.get('import', []) 38 | except (json.JSONDecodeError, FileNotFoundError): 39 | pass 40 | 41 | # Find all .mbt files (excluding test files) 42 | mbt_files = [f for f in module_dir.glob("*.mbt") 43 | if not f.name.endswith('_test.mbt') and not f.name.endswith('_wbtest.mbt')] 44 | 45 | # Collect file contents with their names 46 | file_contents = {} 47 | 48 | # Add moon.pkg.json if it exists 49 | if pkg_json_path.exists(): 50 | try: 51 | with open(pkg_json_path, 'r', encoding='utf-8') as f: 52 | content = f.read().strip() 53 | if content: 54 | file_contents['moon.pkg.json'] = content 55 | except (UnicodeDecodeError, FileNotFoundError): 56 | pass 57 | 58 | for mbt_file in sorted(mbt_files): # Sort for consistent ordering 59 | try: 60 | with open(mbt_file, 'r', encoding='utf-8') as f: 61 | content = f.read().strip() 62 | if content: # Only add non-empty content 63 | file_contents[mbt_file.name] = content 64 | except (UnicodeDecodeError, FileNotFoundError): 65 | continue 66 | 67 | # Join all content with double newlines for backward compatibility 68 | concatenated_code = '\n\n'.join(file_contents.values()) 69 | 70 | return { 71 | 'alias': alias, 72 | 'pkg': pkg, 73 | 'name': module_name, 74 | 'dependencies': dependencies, 75 | 'code': concatenated_code, 76 | 'files': file_contents 77 | } 78 | 79 | # Removed has_non_self_parameters function - no longer needed with new format 80 | 81 | def generate_module_code(module_info: Dict) -> str: 82 | """ 83 | Generate RuntimePackage code for a single module. 84 | """ 85 | pkg = module_info['pkg'] 86 | module_name = module_info['name'] 87 | code = module_info['code'] 88 | dependencies = module_info['dependencies'] 89 | files = module_info['files'] 90 | 91 | if not code.strip(): 92 | return "" 93 | 94 | # Generate dependencies map 95 | print(dependencies) 96 | dependencies_map_entries = [] 97 | for dep in dependencies: 98 | if isinstance(dep, str): 99 | name = dep.replace('/', '_') 100 | dependencies_map_entries.append(f'"{dep}": {name}_module') 101 | elif isinstance(dep, dict): 102 | name = dep["path"].replace('/', '_') 103 | dependencies_map_entries.append(f'"{dep["alias"]}": {name}_module') 104 | dependencies_map_str = ", ".join(dependencies_map_entries) 105 | 106 | # Generate files map 107 | files_map_entries = [] 108 | for filename, content in files.items(): 109 | # Format the code with #| prefix for each line, filtering out comments and empty lines 110 | code_lines = content.split('\n') 111 | formatted_code_lines = [] 112 | for line in code_lines: 113 | # Skip comment lines and empty lines to reduce file size 114 | stripped_line = line.strip() 115 | if not stripped_line or stripped_line.startswith('//') or stripped_line.startswith('///') or stripped_line.startswith('///'): 116 | continue 117 | # Escape quotes and backslashes for the string literal 118 | formatted_code_lines.append(f' #|{line}') 119 | 120 | if formatted_code_lines: 121 | formatted_content = '\n'.join(formatted_code_lines) 122 | files_map_entries.append(f' "{filename}": (\n{formatted_content}\n )') 123 | else: 124 | # For empty files, generate empty string 125 | files_map_entries.append(f' "{filename}": ""') 126 | 127 | files_map_str = ',\n'.join(files_map_entries) 128 | 129 | module_code = f'''///| 130 | let {module_name}_module : RuntimePackage = RuntimePackage::new( 131 | "{pkg}", 132 | deps={{ {dependencies_map_str} }}, 133 | files={{ 134 | {files_map_str} 135 | }} 136 | )''' 137 | 138 | return module_code 139 | 140 | def generate_core_modules_map(modules: List[dict]) -> str: 141 | """ 142 | Generate the core_modules map declaration. 143 | """ 144 | entries = [] 145 | for module in modules: 146 | entries.append(f'"{module['alias']}": {module['name']}_module') 147 | entries.append(f'"{module['pkg']}": {module['name']}_module') 148 | map_content = ", ".join(entries) 149 | 150 | return f'''///| 151 | let core_modules : Map[String, RuntimePackage] = {{ {map_content} }}''' 152 | 153 | def main(): 154 | """ 155 | Main function to generate all core modules. 156 | """ 157 | core_path = Path(CORE_PATH) 158 | 159 | if not core_path.exists(): 160 | print(f"Error: Core path {CORE_PATH} does not exist") 161 | return 162 | # Get all module directories recursively 163 | module_dirs = [] 164 | for root, dirs, _ in os.walk(core_path): 165 | root_path = Path(root) 166 | # Skip hidden directories and coverage directory 167 | dirs[:] = [d for d in dirs if not d.startswith('.') and d != 'coverage'] 168 | module_dirs.extend([root_path / d for d in dirs]) 169 | 170 | print(f"Found {len(module_dirs)} modules to process") 171 | 172 | generated_modules = [] 173 | module_codes = [] 174 | 175 | # Process each module 176 | for module_dir in sorted(module_dirs): 177 | print(f"Processing module: {module_dir.name}") 178 | 179 | module_info = read_module_info(module_dir) 180 | 181 | if module_info['code'].strip(): 182 | module_code = generate_module_code(module_info) 183 | if module_code: 184 | module_codes.append(module_code) 185 | generated_modules.append(module_info) 186 | code_lines = len([line for line in module_info['code'].split('\n') if line.strip()]) 187 | print(f" Generated module with {code_lines} lines of code") 188 | else: 189 | print(f" No code content found") 190 | 191 | # Generate the complete file content 192 | header = '''///| 193 | /// Auto-generated core modules for moonbit-eval interpreter 194 | /// This file contains embedded RuntimePackage definitions for all moonbitlang/core modules 195 | ''' 196 | 197 | dummy_loc = '''///| 198 | fn dummy_loc() -> @basic.Location { 199 | { 200 | start: { fname: "", lnum: 0, bol: 0, cnum: 0 }, 201 | end: { fname: "", lnum: 0, bol: 0, cnum: 0 }, 202 | } 203 | }''' 204 | 205 | # Generate core_modules map 206 | core_modules_map = generate_core_modules_map(generated_modules) 207 | 208 | # Combine all parts 209 | full_content = "\n\n".join([ 210 | header, 211 | core_modules_map, 212 | dummy_loc 213 | ] + module_codes) 214 | 215 | # Write to output file 216 | output_path = Path(OUTPUT_FILE) 217 | with open(output_path, 'w', encoding='utf-8') as f: 218 | f.write(full_content) 219 | 220 | module_names = [module['name'] for module in generated_modules] 221 | print(f"\nGenerated {len(module_names)} modules:") 222 | for module_name in module_names: 223 | print(f" - {module_name}") 224 | print(f"\nOutput written to: {OUTPUT_FILE}") 225 | 226 | if __name__ == "__main__": 227 | main() --------------------------------------------------------------------------------