MiniMoonbit is a subset of the MoonBit programming language. It serves as a compiler that translates MiniMoonbit source code into multiple targets, including LLVM IR, AArch64 assembly, and RISC-V 64 assembly.
This project leverages the power of the MoonBit ecosystem, particularly:
- MoonLLVM: A refactored version of LLVM written entirely in MoonBit, used for generating LLVM IR.
- MoonMIR: A tool, also written in MoonBit, that translates the LLVM IR from MoonLLVM into target-specific assembly code.
The compilation pipeline can be visualized as:
MiniMoonbit Source -> MiniMoonbit Compiler -> MoonLLVM -> LLVM IR -> MoonMIR -> AArch64 / RISC-V 64 Assembly
- Multi-Target Compilation: Compiles to LLVM IR, AArch64, and RISC-V 64.
- Rich Language Subset: Supports basic arithmetic, control flow, strings, arrays, structs, ADTs, and pattern matching.
- Developer-Friendly Diagnostics: Features simple error recovery and exhaustiveness checks for pattern matching to improve the development experience.
- Introspection Tools: Provides flags to print intermediate representations like tokens, AST, typed AST, and K-Normal Form (KNF) for debugging and educational purposes.
Before using MiniMoonbit, ensure you have the MoonBit toolchain installed.
Linux/macOS:
curl -fsSL https://cli.moonbitlang.cn/install/unix.sh | bashWindows (PowerShell):
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser; irm https://cli.moonbitlang.cn/install/powershell.ps1 | iexYou can run the compiler using the moon run main command. Let {file}.mbt be your MiniMoonbit source file (see the /examples directory for samples).
-
Show Help Information:
# Note: A placeholder argument like 'x' is currently needed due to a bug in the toolchain. moon run main -- x --help -
Compile to LLVM IR (Default):
moon run main -- {file}.mbt # or explicitly moon run main -- {file}.mbt --emit-llvm -
Compile to AArch64 Assembly:
moon run main -- {file}.mbt --target=aarch64 -
Compile to RISC-V 64 Assembly:
moon run main -- {file}.mbt --target=riscv64
Note: When compiling the generated output, remember to link it with the provided runtime.c.
The compiler offers several flags to inspect its internal stages:
--print-tokens: Print the result of lexical analysis.--print-ast: Print the Abstract Syntax Tree (AST).--print-typed-ast: Print the AST with type annotations.--print-knf: Print the K-Normal Form (KNF) representation.
Consider the examples/fib.mbt file.
-
Generate LLVM IR:
moon run main -- examples/fib.mbt
This produces the following LLVM IR:
;; ModuleID = 'demo' ;; Source File = "demo" declare void @print_int(i32) define i32 @fib(i32 %0) { entry: %1 = icmp sle i32 %0, 1 br i1 %1, label %3, label %5 3: ret i32 %0 5: br label %7 7: %8 = sub i32 %0, 1 %9 = sub i32 %0, 2 %10 = call i32 @fib(i32 %8) %11 = call i32 @fib(i32 %9) %12 = add i32 %10, %11 ret i32 %12 } define void @moonbit_main() { entry: %0 = call i32 @fib(i32 10) call void @print_int(i32 %0) ret void }
-
Print the Typed AST:
moon run main -- examples/fib.mbt --print-typed-ast
This shows the structured, type-checked representation of the code:
Top function: fib ├-params: │ └-n: Int ├-return: Int └-block (Int) ├-if expression (Any) │ ├-cond: binary expr: <= (Bool) │ │ ├-variable n (Int) │ │ └-int literal 1 (Int) │ └-then: block (Any) │ └-return statement │ └-variable n (Int) │ └-binary expr: + (Int) ├-function call (Int) │ ├-variable fib ((Int) -> Int) │ └-binary expr: - (Int) │ ├-variable n (Int) │ └-int literal 1 (Int) └-function call (Int) ├-variable fib ((Int) -> Int) └-binary expr: - (Int) ├-variable n (Int) └-int literal 2 (Int) -
Print KNF:
moon run main -- examples/fib.mbt --print-knf
This shows the k normal form:
;; KnfProgram: examples/fib.mbt fn fib(n: Int) -> Int { let tmp : Int = 1; if n <= tmp { return n; }; let tmp$1 : Int = 1; let tmp$2 : Int = n - tmp$1; let tmp$3 : Int = 2; let tmp$4 : Int = n - tmp$3; let tmp$5 : Int = fib(tmp$2); let tmp$6 : Int = fib(tmp$4); tmp$5 + tmp$6; } fn main { let tmp : Int = 10; let result : Int = fib(tmp); print_int(result); } -
Error recovery: MiniMoonBit Compiler supporr error recovery, take
err.mbtas example:moon run main -- err.mbt
You will see:
[err.mbt:10:7] Warning: 9| let y = x + true; 10| let (x) = 5; 11| ^ Warning: Should Not use tuple pattern for single pattern [err.mbt:8:15] Error: 7|fn main { 8| let mut x = 8 + 1.0; 9| ^ TypeMismatch: Binary Expression Must have same type for both side while got Int and Double [err.mbt:9:12] Error: 8| let mut x = 8 + 1.0; 9| let y = x + true; 10| ^ TypeMismatch: Binary Expression Must have same type for both side while got Int and Bool [err.mbt:14:10] Error: 13| 14| match a { 15| ^ Non-exhaustive match expression, some patterns are not covered: RGB(_, _, _) RGB(255, _, _) RGB(255, 0, _) RGBA(_, _, _, _) RGBA(255, _, _, _) ... and 2 more patterns [err.mbt:20:9] Error: 19| 20| return false; 21| ^ Return type mismatch, wanted: Unit, got: Bool Compilation Error: TypeCheckError("Type checking failed.")
MiniMoonbit 是 MoonBit 编程语言的一个子集。它是一个编译器,可将 MiniMoonbit 源代码编译到多个目标,包括 LLVM IR、AArch64 汇编和 RISC-V 64 汇编。
该项目借助了 MoonBit 生态系统的强大能力,特别是:
- MoonLLVM: 一个完全使用 MoonBit 重构的 LLVM 版本,用于生成 LLVM IR。
- MoonMIR: 一个同样由 MoonBit 编写的工具,用于将 MoonLLVM 生成的 LLVM IR 转译为特定目标的汇编代码。
编译流程可以简要地表示为:
MiniMoonbit 源码 -> MiniMoonbit 编译器 -> MoonLLVM -> LLVM IR -> MoonMIR -> AArch64 / RISC-V 64 汇编
- 多目标编译: 可编译至 LLVM IR、AArch64 和 RISC-V 64。
- 丰富的语言子集: 支持基本运算、控制流、字符串、数组、结构体、代数数据类型(ADT)和模式匹配。
- 开发者友好的诊断信息: 具备简单的错误恢复机制和模式匹配的完备性检查,以改善开发体验。
- 内部状态检视工具: 提供多种标志位,用于打印词法分析、抽象语法树(AST)、类型化抽象语法树和 K范式(KNF)等中间表示,便于调试和学习。
- 功能完备: 可以编译如光线追踪这样的中型程序。
在使用 MiniMoonbit 之前,请确保已安装 MoonBit 工具链。
Linux/macOS:
curl -fsSL https://cli.moonbitlang.cn/install/unix.sh | bashWindows (PowerShell):
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser; irm https://cli.moonbitlang.cn/install/powershell.ps1 | iex您可以使用 moon run main 命令来运行编译器。假设 {file}.mbt 是您的 MiniMoonbit 源文件(可参考 examples 目录下的示例)。
-
显示帮助信息:
# 注意:由于当前工具链的一个 bug,需要一个额外的占位符参数,任何参数都可以。 moon run main -- x --help -
编译到 LLVM IR (默认):
moon run main -- {file}.mbt # 或显式指定 moon run main -- {file}.mbt --emit-llvm -
编译到 AArch64 汇编:
moon run main -- {file}.mbt --target=aarch64 -
编译到 RISC-V 64 汇编:
moon run main -- {file}.mbt --target=riscv64
注意: 在编译生成的产物时,请记得链接项目提供的 runtime.c 文件。
编译器提供了几个标志位来检视其内部各个阶段的状态:
--print-tokens: 打印词法分析的结果。--print-ast: 打印抽象语法树(AST)。--print-typed-ast: 打印带类型注解的抽象语法树。--print-knf: 打印 K范式(KNF)表示。
以 examples/fib.mbt 文件为例。
-
生成 LLVM IR:
moon run main -- examples/fib.mbt
这将生成以下 LLVM IR:
;; ModuleID = 'demo' ;; Source File = "demo" declare void @print_int(i32) define i32 @fib(i32 %0) { entry: %1 = icmp sle i32 %0, 1 br i1 %1, label %3, label %5 3: ret i32 %0 5: br label %7 7: %8 = sub i32 %0, 1 %9 = sub i32 %0, 2 %10 = call i32 @fib(i32 %8) %11 = call i32 @fib(i32 %9) %12 = add i32 %10, %11 ret i32 %12 } define void @moonbit_main() { entry: %0 = call i32 @fib(i32 10) call void @print_int(i32 %0) ret void }
-
打印类型化抽象语法树:
moon run main -- examples/fib.mbt --print-typed-ast
这将显示代码的结构化、类型检查后的表示:
Top function: fib ├-params: │ └-n: Int ├-return: Int └-block (Int) ├-if expression (Any) │ ├-cond: binary expr: <= (Bool) │ │ ├-variable n (Int) │ │ └-int literal 1 (Int) │ └-then: block (Any) │ └-return statement │ └-variable n (Int) │ └-binary expr: + (Int) ├-function call (Int) │ ├-variable fib ((Int) -> Int) │ └-binary expr: - (Int) │ ├-variable n (Int) │ └-int literal 1 (Int) └-function call (Int) ├-variable fib ((Int) -> Int) └-binary expr: - (Int) ├-variable n (Int) └-int literal 2 (Int) -
打印KNF:
moon run main -- examples/fib.mbt --print-knf
这将显示代码的KNF表示:
;; KnfProgram: examples/fib.mbt fn fib(n: Int) -> Int { let tmp : Int = 1; if n <= tmp { return n; }; let tmp$1 : Int = 1; let tmp$2 : Int = n - tmp$1; let tmp$3 : Int = 2; let tmp$4 : Int = n - tmp$3; let tmp$5 : Int = fib(tmp$2); let tmp$6 : Int = fib(tmp$4); tmp$5 + tmp$6; } fn main { let tmp : Int = 10; let result : Int = fib(tmp); print_int(result); } -
错误恢复与处理: MiniMoonBit支持一定的错误处理,当代码存在语法错误时,编译器会试图进行错误恢复,以根目录下的err.mbt为例子。
moon run main -- err.mbt
你将会在终端中看到以下错误信息:
[err.mbt:10:7] Warning: 9| let y = x + true; 10| let (x) = 5; 11| ^ Warning: Should Not use tuple pattern for single pattern [err.mbt:8:15] Error: 7|fn main { 8| let mut x = 8 + 1.0; 9| ^ TypeMismatch: Binary Expression Must have same type for both side while got Int and Double [err.mbt:9:12] Error: 8| let mut x = 8 + 1.0; 9| let y = x + true; 10| ^ TypeMismatch: Binary Expression Must have same type for both side while got Int and Bool [err.mbt:14:10] Error: 13| 14| match a { 15| ^ Non-exhaustive match expression, some patterns are not covered: RGB(_, _, _) RGB(255, _, _) RGB(255, 0, _) RGBA(_, _, _, _) RGBA(255, _, _, _) ... and 2 more patterns [err.mbt:20:9] Error: 19| 20| return false; 21| ^ Return type mismatch, wanted: Unit, got: Bool Compilation Error: TypeCheckError("Type checking failed.")