From 33524109412de04e636a15a6a93995875e58ac63 Mon Sep 17 00:00:00 2001 From: Lil-Ran Date: Wed, 5 Nov 2025 17:17:48 +0800 Subject: [PATCH] wip: first submit --- moon.mod.json | 8 ++--- src/bin/main.mbt | 61 +++++++++++++++++++++++++++++++++++ src/bin/moon.pkg.json | 9 +++++- src/typecheck/typechecker.mbt | 8 ++++- 4 files changed, 80 insertions(+), 6 deletions(-) diff --git a/moon.mod.json b/moon.mod.json index 42e0ae1..a195e84 100644 --- a/moon.mod.json +++ b/moon.mod.json @@ -2,8 +2,8 @@ "name": "Lil-Ran/lilunar", "version": "0.1.0", "deps": { - "moonbitlang/x": "0.4.34", - "Yoorkin/ArgParser": "0.1.11" + "moonbitlang/x": "0.4.36", + "Yoorkin/ArgParser": "0.2.0" }, "readme": "README.mbt.md", "repository": "https://github.com/Lil-Ran/lilunar", @@ -15,6 +15,6 @@ "assembly" ], "description": "My MiniMoonBit to RISC-V compiler for MGPIC-2025.", - "preferred-target": "wasm-gc", - "source": "src" + "source": "src", + "preferred-target": "wasm-gc" } \ No newline at end of file diff --git a/src/bin/main.mbt b/src/bin/main.mbt index 4505791..b9281a9 100644 --- a/src/bin/main.mbt +++ b/src/bin/main.mbt @@ -1,4 +1,65 @@ ///| fn main { + let argv = @sys.get_cli_args() + let typecheck_only = Ref::new(false) + let mut in_file = None + let out_file = Ref::new("a.s") + @ArgParser.parse( + [ + ( + "--typecheck", + "", + @ArgParser.Set(typecheck_only), + "Only run type checking", + ), + ( + "--output", + "-o", + @ArgParser.String(s => out_file.val = s), + "Output file (default: a.s)", + ), + ], + fn(s) { + if !in_file.is_empty() { + abort("multiple files are given") + } + in_file = Some(s) + }, + ( + #|Lilunar: Lil-Ran's experimental MiniMoonBit to RISC-V compiler for MGPIC-2025. + #| + #|Usage: lilunar [options] + #| + #|Options: + #| --typecheck Only run type checking + #| -o, --output Output file (default: a.s) + #| + ), + argv, + ) catch { + e => abort("Argument parsing error: \{e}") + } + let file = in_file.unwrap_or_else(abort("no input file provided")) + let contents = @fs.read_file_to_string(file) catch { + e => abort("Failed to read file \{file}: \{e}") + } + let program = try + contents + |> @parser.tokenize() + |> @parser.parse_program() + |> @typecheck.typecheck() + catch { + e => abort("Parsing or type checking error: \{e}") + } + if typecheck_only.val { + println("Type checking passed.") + return + } + // let asm_string = ... + // if out_file.val == "-" { + // println(asm_string) + // } else { + // @fs.write_string_to_file?(out_file.val, asm_string).unwrap() + // } } diff --git a/src/bin/moon.pkg.json b/src/bin/moon.pkg.json index fcc86ba..867b4cf 100644 --- a/src/bin/moon.pkg.json +++ b/src/bin/moon.pkg.json @@ -1,3 +1,10 @@ { - "is-main": true + "is-main": true, + "import": [ + "moonbitlang/x/sys", + "Yoorkin/ArgParser", + "moonbitlang/x/fs", + "Lil-Ran/lilunar/parser", + "Lil-Ran/lilunar/typecheck" + ] } \ No newline at end of file diff --git a/src/typecheck/typechecker.mbt b/src/typecheck/typechecker.mbt index 3529b97..7aaa1ce 100644 --- a/src/typecheck/typechecker.mbt +++ b/src/typecheck/typechecker.mbt @@ -2,7 +2,13 @@ pub fn typecheck(program : @parser.Program) -> Program raise TypeCheckError { let ctx = Context::new() let checked_program = ctx.check_program(program) - ctx.substitute_type_var(checked_program) + let result = ctx.substitute_type_var(checked_program) + + // XXX: do not to_string + if result.to_string().contains("TypeVar") { + raise TypeCheckError("unsubstituted type variable remains") + } + result } ///|