From b7ffe3bd6b22ce3c60759005ea7928fd8b0f660f Mon Sep 17 00:00:00 2001 From: oboard Date: Thu, 6 Nov 2025 21:01:18 +0800 Subject: [PATCH 1/4] chore: bump version to 0.8.12 in moon.mod.json --- moon.mod.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/moon.mod.json b/moon.mod.json index 3919046..883b7ed 100644 --- a/moon.mod.json +++ b/moon.mod.json @@ -1,6 +1,6 @@ { "name": "oboard/moonbit-eval", - "version": "0.8.11", + "version": "0.8.12", "deps": { "moonbitlang/parser": "0.1.11", "oboard/mio": "0.4.3", From 83655b560ee56bb1fe4c45d718e0edd450f199de Mon Sep 17 00:00:00 2001 From: oboard Date: Thu, 6 Nov 2025 21:26:54 +0800 Subject: [PATCH 2/4] remove: mooncakes --- moon.mod.json | 3 +- src/mooncakes/loader.mbt | 189 ------------------------------- src/mooncakes/moon.pkg.json | 10 -- src/mooncakes/pkg.generated.mbti | 24 ---- src/test/moon.pkg.json | 4 +- src/test/packages.mbt | 28 ++--- 6 files changed, 16 insertions(+), 242 deletions(-) delete mode 100644 src/mooncakes/loader.mbt delete mode 100644 src/mooncakes/moon.pkg.json delete mode 100644 src/mooncakes/pkg.generated.mbti diff --git a/moon.mod.json b/moon.mod.json index 883b7ed..6cbf4b5 100644 --- a/moon.mod.json +++ b/moon.mod.json @@ -1,9 +1,8 @@ { "name": "oboard/moonbit-eval", - "version": "0.8.12", + "version": "0.8.13", "deps": { "moonbitlang/parser": "0.1.11", - "oboard/mio": "0.4.3", "bobzhang/zip": "0.1.0" }, "readme": "README.md", diff --git a/src/mooncakes/loader.mbt b/src/mooncakes/loader.mbt deleted file mode 100644 index 693c879..0000000 --- a/src/mooncakes/loader.mbt +++ /dev/null @@ -1,189 +0,0 @@ -///| -pub async fn load_meta( - mod_name : String, - version? : String, -) -> @interpreter.ModuleInfo { - ///| - let mod_name = mod_name + (if version is Some(v) { "@" + v } else { "" }) - // 获取模块元信息 - let url = "https://mooncakes.io/assets/\{mod_name}/resource.json" - let info = try? @mio.get(url).unwrap_json() - if info is Ok({ "meta_info": meta_info, .. }) { - @json.from_json(meta_info) - } else { - @interpreter.ModuleInfo::new("") - } -} - -///| -pub async fn load_module( - mod_name : String, - version? : String, -) -> Map[String, @interpreter.RuntimeModule] { - let mod_name = mod_name + (if version is Some(v) { "@" + v } else { "" }) - let modules : Map[String, @interpreter.RuntimeModule] = {} - - // 获取模块元信息 - let meta = load_meta(mod_name, version?) - - // 处理依赖模块 - if meta.deps is Some(deps) { - // for name, version in deps { - let deps = deps.to_array() - while deps.pop() is Some((name, version)) { - let dep_modules = load_module(name, version~) - for name, dep_module in dep_modules { - modules.set(name, dep_module) - } - } - } - let url = "https://mooncakes.io/assets/\{mod_name}/module_index.json" - let module_index = @mio.get(url).unwrap_json() - let pkgs : Map[String, @interpreter.RuntimePackage] = {} - - // Parse package information from module_index.json recursively - async fn parse_child( - child : Json, - pkgs : Map[String, @interpreter.RuntimePackage], - ) { - if child is { "childs": Array(childs), .. } { - while childs.pop() is Some(sub_child) { - parse_child(sub_child, pkgs) - } - } - if child is { "name": String(pkg_name), "package": package_info, .. } { - if package_info is { "path": String(path), .. } { - match load_package(path, pkgs) { - Some(pkg) => pkgs.set(pkg_name, pkg) - None => () - } - } - } - } - - parse_child(module_index, pkgs) - modules.set(mod_name, @interpreter.RuntimeModule::{ meta, pkgs }) - modules -} - -///| -pub async fn load_package( - pkg_name : String, - deps : Map[String, @interpreter.RuntimePackage], -) -> @interpreter.RuntimePackage? { - let url = "https://mooncakes.io/assets/\{pkg_name}/resource.json" - let info = @mio.get(url).unwrap_json() - let sources : Map[String, String] = {} - if info is { "source_files": Array(source_files), .. } { - while source_files.pop() is Some(file) { - if file is String(name) { - let source = @mio.get( - "https://mooncakes.io/assets/\{pkg_name}/\{name}.html", - ).text() catch { - _ => "" - } - let start = source.find("
")
-        let end = source.rev_find("
") - if (start, end) is (Some(start), Some(end)) { - sources.set(name, source[start:end].to_string()) - } - } - } - Some({ - name: pkg_name, - traits: Map::new(), - fn_aliases: Map::new(), - type_aliases: Map::new(), - trait_aliases: Map::new(), - stubs: Map::new(), - trait_methods: Map::new(), - type_definitions: Map::new(), - type_derived_traits: Map::new(), - constructors: Map::new(), - struct_methods: Map::new(), - values: Map::new(), - env: @interpreter.RuntimeEnvironment::new(), - deps, - files: sources, - loaded: false, - }) - } else { - None - } -} - -///| -pub async fn load_module_zip( - mod_name : String, - version? : String, -) -> @interpreter.RuntimeModule { - let module_name = mod_name + (if version is Some(v) { "@" + v } else { "" }) - if (try? load_meta(module_name)) is Ok(a) { - let res = try? @mio.get(a.get_zip_url()) - if res is Ok(res) { - if (try? @zip.Archive::of_bytes(res.data)) is Ok(zip) { - if zip.find(@fpath.Fpath("moon.mod.json")) is Some(m) { - if m.kind() is File(data) { - let module_info : @interpreter.ModuleInfo = @json.from_json( - @json.parse(@encoding/utf8.decode(data.to_bytes())), - ) catch { - _ => abort("Failed to read moon.mod.json") - } - // println(module_info) - let root = if module_info.source is Some(source) { - source - } else { - "" - } - // println(root) - fn collect_files(root : String) -> Map[String, String] { - let files = {} - for entry in zip.to_array() { - if entry.kind() is File(file) { - let path = entry.path().to_string() - if path.has_prefix(root) && path.has_suffix(".mbt") { - try { - files[path] = @encoding/utf8.decode(file.to_bytes()) - } catch { - _ => abort("Failed to decode file content") - } - } - } - } - files - } - // 找出所有的 packages - fn scan_packages() -> Array[@interpreter.RuntimePackage] { - let pkgs = [] - for entry in zip.to_array() { - if entry.is_dir() { - let dir = entry.path().to_string() - if zip.find(@fpath.Fpath(dir + "moon.pkg.json")) is Some(_) { - let pkg_name = module_name + - dir.strip_prefix(root).unwrap_or(dir).to_string() - // println(pkg_name) - // println(dir) - pkgs.push( - @interpreter.RuntimePackage::new( - pkg_name, - files=collect_files(dir), - ), - ) - } - } - } - pkgs - } - - let packages = scan_packages() - return @interpreter.RuntimeModule::{ - meta: a, - pkgs: Map::from_array(packages.map(pkg => (pkg.name, pkg))), - } - } - } - } - } - } - abort("Failed to load module zip") -} diff --git a/src/mooncakes/moon.pkg.json b/src/mooncakes/moon.pkg.json deleted file mode 100644 index 9d895a7..0000000 --- a/src/mooncakes/moon.pkg.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "import": [ - "oboard/moonbit-eval/interpreter", - "oboard/mio", - "bobzhang/zip", - "bobzhang/zip/types/fpath", - "bobzhang/zip/member", - "bobzhang/zip/file" - ] -} \ No newline at end of file diff --git a/src/mooncakes/pkg.generated.mbti b/src/mooncakes/pkg.generated.mbti deleted file mode 100644 index 7d76d53..0000000 --- a/src/mooncakes/pkg.generated.mbti +++ /dev/null @@ -1,24 +0,0 @@ -// Generated using `moon info`, DON'T EDIT IT -package "oboard/moonbit-eval/mooncakes" - -import( - "oboard/moonbit-eval/interpreter" -) - -// Values -async fn load_meta(String, version? : String) -> @interpreter.ModuleInfo - -async fn load_module(String, version? : String) -> Map[String, @interpreter.RuntimeModule] - -async fn load_module_zip(String, version? : String) -> @interpreter.RuntimeModule - -async fn load_package(String, Map[String, @interpreter.RuntimePackage]) -> @interpreter.RuntimePackage? - -// Errors - -// Types and methods - -// Type aliases - -// Traits - diff --git a/src/test/moon.pkg.json b/src/test/moon.pkg.json index 7749243..ee595af 100644 --- a/src/test/moon.pkg.json +++ b/src/test/moon.pkg.json @@ -4,8 +4,6 @@ "path": "oboard/moonbit-eval", "alias": "eval" }, - "oboard/moonbit-eval/interpreter", - "oboard/mio", - "oboard/moonbit-eval/mooncakes" + "oboard/moonbit-eval/interpreter" ] } \ No newline at end of file diff --git a/src/test/packages.mbt b/src/test/packages.mbt index f1ca664..86b4686 100644 --- a/src/test/packages.mbt +++ b/src/test/packages.mbt @@ -54,20 +54,20 @@ test "cross_package_method_calling" { assert_eq(vm.eval("arr1.length()").to_string(), "5") } -///| -test "online_package" { - let vm = MoonBitVM::new() - @mio.run(() => { - let modules = try? @mooncakes.load_module("wangweigang/hello") - if modules is Ok(modules) { - vm.interpreter.main_pkg.deps.set( - "hello", - modules.get("wangweigang/hello").unwrap().pkgs["hello"], - ) - println(vm.eval("@hello.hello()")) - } - }) -} +// ///| +// test "online_package" { +// let vm = MoonBitVM::new() +// @mio.run(() => { +// let modules = try? @mooncakes.load_module("wangweigang/hello") +// if modules is Ok(modules) { +// vm.interpreter.main_pkg.deps.set( +// "hello", +// modules.get("wangweigang/hello").unwrap().pkgs["hello"], +// ) +// println(vm.eval("@hello.hello()")) +// } +// }) +// } // ///| // test { From c7c6fc286c59c9cac85dfc20547f69a1236c7699 Mon Sep 17 00:00:00 2001 From: oboard Date: Thu, 6 Nov 2025 23:26:14 +0800 Subject: [PATCH 3/4] feat(example): add main.mbt and moon.pkg.json for eval example Add new example files demonstrating how to use MoonBitVM eval functionality Update project rules documentation with MoonBit project guidelines --- .trae/rules/project_rules.md | 51 ++++++++++++++++++++++++++++++++++++ src/example/main.mbt | 4 +++ src/example/moon.pkg.json | 9 +++++++ 3 files changed, 64 insertions(+) create mode 100644 src/example/main.mbt create mode 100644 src/example/moon.pkg.json diff --git a/.trae/rules/project_rules.md b/.trae/rules/project_rules.md index 04b37f1..2c4cfa4 100644 --- a/.trae/rules/project_rules.md +++ b/.trae/rules/project_rules.md @@ -47,3 +47,54 @@ Common Options: --dry-run Do not actually run the command --build-graph Generate build graph +# Project Agents.md Guide + +This is a [MoonBit](https://docs.moonbitlang.com) project. + +## Project Structure + +- MoonBit packages are organized per directory, for each directory, there is a + `package.json` file listing its dependencies. Each package has its files and + blackbox test files (common, ending in `_test.mbt`) and whitebox test files + (ending in `_wbtest.mbt`). + +- In the toplevel directory, this is a `moon.mod.json` file listing about the + module and some meta information. + +## Coding convention + +- MoonBit code is organized in block style, each block is separated by `///|`, + the order of each block is irrelevant. In some refactorings, you can process + block by block independently. + +- Try to keep deprecated blocks in file called `deprecated.mbt` in each + directory. + +## Tooling + +- `moon fmt` is used to format your code properly. + +- `moon info` is used to update the generated interface of the package, each + package has a generated interface file `.mbti`, it is a brief formal + description of the package. If nothing in `.mbti` changes, this means your + change does not bring the visible changes to the external package users, it is + typically a safe refactoring. + +- In the last step, run `moon info && moon fmt` to update the interface and + format the code. Check the diffs of `.mbti` file to see if the changes are + expected. + +- Run `moon test` to check the test is passed. MoonBit supports snapshot + testing, so when your changes indeed change the behavior of the code, you + should run `moon test --update` to update the snapshot. + +- You can run `moon check` to check the code is linted correctly. + +- When writing tests, you are encouraged to use `inspect` and run + `moon test --update` to update the snapshots, only use assertions like + `assert_eq` when you are in some loops where each snapshot may vary. You can + use `moon coverage analyze > uncovered.log` to see which parts of your code + are not covered by tests. + +- agent-todo.md has some small tasks that are easy for AI to pick up, agent is + welcome to finish the tasks and check the box when you are done diff --git a/src/example/main.mbt b/src/example/main.mbt new file mode 100644 index 0000000..dc253e8 --- /dev/null +++ b/src/example/main.mbt @@ -0,0 +1,4 @@ +fn main { + let result = @eval.MoonBitVM::new().eval("1 + 2"); + println(result); +} \ No newline at end of file diff --git a/src/example/moon.pkg.json b/src/example/moon.pkg.json new file mode 100644 index 0000000..b9ca184 --- /dev/null +++ b/src/example/moon.pkg.json @@ -0,0 +1,9 @@ +{ + "is-main": true, + "import": [ + { + "path": "oboard/moonbit-eval", + "alias": "eval" + } + ] +} \ No newline at end of file From af7a7d2c040e133a9911b23b136553b117a9af6b Mon Sep 17 00:00:00 2001 From: oboard Date: Thu, 13 Nov 2025 14:20:35 +0800 Subject: [PATCH 4/4] feat: add code_to_ast function for parsing code to AST Implement new function to parse MoonBit code into AST and return as JSON string --- src/example/main.mbt | 7 ++++--- src/example/pkg.generated.mbti | 13 +++++++++++++ src/export.mbt | 8 ++++++++ src/moon.pkg.json | 1 + src/pkg.generated.mbti | 2 ++ 5 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 src/example/pkg.generated.mbti diff --git a/src/example/main.mbt b/src/example/main.mbt index dc253e8..e8e2b4d 100644 --- a/src/example/main.mbt +++ b/src/example/main.mbt @@ -1,4 +1,5 @@ +///| fn main { - let result = @eval.MoonBitVM::new().eval("1 + 2"); - println(result); -} \ No newline at end of file + let result = @eval.MoonBitVM::new().eval("1 + 2") + println(result) +} diff --git a/src/example/pkg.generated.mbti b/src/example/pkg.generated.mbti new file mode 100644 index 0000000..e68579c --- /dev/null +++ b/src/example/pkg.generated.mbti @@ -0,0 +1,13 @@ +// Generated using `moon info`, DON'T EDIT IT +package "oboard/moonbit-eval/example" + +// Values + +// Errors + +// Types and methods + +// Type aliases + +// Traits + diff --git a/src/export.mbt b/src/export.mbt index 70976b7..d843182 100644 --- a/src/export.mbt +++ b/src/export.mbt @@ -21,6 +21,14 @@ pub fn eval_result_to_string(result : EvalResult) -> String { } } +///| +pub fn code_to_ast(code : String) -> String { + match @interpreter.parse_code_to_impl(code) { + Ok(i) => i.to_json().stringify() + Err(msg) => msg + } +} + ///| pub fn add_extern_fn( vm : MoonBitVM, diff --git a/src/moon.pkg.json b/src/moon.pkg.json index 7961e60..aba1ba1 100644 --- a/src/moon.pkg.json +++ b/src/moon.pkg.json @@ -10,6 +10,7 @@ "create", "eval", "eval_result_to_string", + "code_to_ast", "add_extern_fn", "add_embedded_fn", "add_embedded_method", diff --git a/src/pkg.generated.mbti b/src/pkg.generated.mbti index 973df8f..d26589f 100644 --- a/src/pkg.generated.mbti +++ b/src/pkg.generated.mbti @@ -13,6 +13,8 @@ fn add_embedded_method(MoonBitVM, String, String, (@interpreter.RuntimeFunctionC fn add_extern_fn(MoonBitVM, String, (@interpreter.RuntimeFunctionContext) -> @interpreter.RuntimeValue raise @interpreter.ControlFlow) -> Unit +fn code_to_ast(String) -> String + fn eval_result_to_string(EvalResult) -> String fn expr_to_string(@syntax.Expr) -> String