feat: knf
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
# Lilunar
|
# Lilunar
|
||||||
|
|
||||||
Lil-Ran's MiniMoonBit to RISC-V compiler for [MGPIC-2025](https://www.moonbitlang.cn/2025-mgpic-compiler).
|
🚧 **To be continued...**
|
||||||
|
|
||||||
|
Lil-Ran's MiniMoonBit to LLVM IR compiler for [MGPIC-2025](https://www.moonbitlang.cn/2025-mgpic-compiler).
|
||||||
|
|
||||||
It is not optimized yet.
|
It is not optimized yet.
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ async def main():
|
|||||||
for file in os.listdir("contest-2025-data/test_cases/mbt"):
|
for file in os.listdir("contest-2025-data/test_cases/mbt"):
|
||||||
if file.endswith(".mbt"):
|
if file.endswith(".mbt"):
|
||||||
in_path = os.path.join("contest-2025-data/test_cases/mbt", file)
|
in_path = os.path.join("contest-2025-data/test_cases/mbt", file)
|
||||||
out_path = os.path.join("output/repo", file.replace(".mbt", ".s"))
|
out_path = os.path.join("output/repo", file.replace(".mbt", ".ll"))
|
||||||
tasks.append(check_file(in_path, out_path))
|
tasks.append(check_file(in_path, out_path))
|
||||||
await asyncio.gather(*tasks)
|
await asyncio.gather(*tasks)
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
{
|
{
|
||||||
"emit": "asm"
|
"emit": "llvm"
|
||||||
}
|
}
|
||||||
@@ -11,10 +11,9 @@
|
|||||||
"keywords": [
|
"keywords": [
|
||||||
"MiniMoonBit",
|
"MiniMoonBit",
|
||||||
"compiler",
|
"compiler",
|
||||||
"RISC-V",
|
"MGPIC-2025"
|
||||||
"assembly"
|
|
||||||
],
|
],
|
||||||
"description": "My MiniMoonBit to RISC-V compiler for MGPIC-2025.",
|
"description": "Lil-Ran's MiniMoonBit to LLVM IR compiler for MGPIC-2025.",
|
||||||
"source": "src",
|
"source": "src",
|
||||||
"preferred-target": "wasm-gc"
|
"preferred-target": "wasm-gc"
|
||||||
}
|
}
|
||||||
@@ -42,7 +42,7 @@ fn main {
|
|||||||
in_file = Some(s)
|
in_file = Some(s)
|
||||||
},
|
},
|
||||||
(
|
(
|
||||||
#|Lilunar: Lil-Ran's experimental MiniMoonBit to RISC-V compiler for MGPIC-2025.
|
#|Lilunar: Lil-Ran's experimental MiniMoonBit to LLVM IR compiler for MGPIC-2025.
|
||||||
#|
|
#|
|
||||||
#| usage: lilunar [options] <input-file>
|
#| usage: lilunar [options] <input-file>
|
||||||
#|
|
#|
|
||||||
@@ -61,7 +61,7 @@ fn main {
|
|||||||
}
|
}
|
||||||
println_debug(
|
println_debug(
|
||||||
(
|
(
|
||||||
#|
|
#|Source:
|
||||||
#|================================
|
#|================================
|
||||||
$|\{contents}
|
$|\{contents}
|
||||||
#|================================
|
#|================================
|
||||||
@@ -82,11 +82,25 @@ fn main {
|
|||||||
println_debug("Type checking passed.")
|
println_debug("Type checking passed.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
let knf = @knf.knf_transform(program) catch {
|
||||||
// let asm_string = ...
|
@knf.KnfTransformError(msg) =>
|
||||||
// if out_file.val == "-" {
|
println_panic("KNF transformation error: \{msg}")
|
||||||
// println(asm_string)
|
}
|
||||||
// } else {
|
println_debug(
|
||||||
// @fs.write_string_to_file?(out_file.val, asm_string).unwrap()
|
(
|
||||||
// }
|
#|KNF:
|
||||||
|
#|================================
|
||||||
|
$|\{knf}
|
||||||
|
#|================================
|
||||||
|
),
|
||||||
|
)
|
||||||
|
let output_string = knf.to_string()
|
||||||
|
if out_file.val == "-" {
|
||||||
|
println(output_string)
|
||||||
|
} else {
|
||||||
|
@fs.write_string_to_file(out_file.val, output_string) catch {
|
||||||
|
@fs.IOError(msg) =>
|
||||||
|
println_panic("Failed to write to output file \{out_file.val}: \{msg}")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
"Yoorkin/ArgParser",
|
"Yoorkin/ArgParser",
|
||||||
"moonbitlang/x/fs",
|
"moonbitlang/x/fs",
|
||||||
"Lil-Ran/lilunar/parser",
|
"Lil-Ran/lilunar/parser",
|
||||||
"Lil-Ran/lilunar/typecheck"
|
"Lil-Ran/lilunar/typecheck",
|
||||||
|
"Lil-Ran/lilunar/knf"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
150
src/knf/apply_expr.mbt
Normal file
150
src/knf/apply_expr.mbt
Normal file
@@ -0,0 +1,150 @@
|
|||||||
|
///|
|
||||||
|
pub fn Context::apply_expr_to_knf(
|
||||||
|
self : Context,
|
||||||
|
apply_expr : @typecheck.ApplyExpr,
|
||||||
|
) -> (Array[KnfStmt], KnfExpr) raise KnfTransformError {
|
||||||
|
match apply_expr.kind {
|
||||||
|
AtomExpr(atom_expr) => self.atom_expr_to_knf(atom_expr)
|
||||||
|
ArrayAccess(array_expr, index_expr) => {
|
||||||
|
let stmts = []
|
||||||
|
let (array_stmts, array_knf_expr) = self.apply_expr_to_knf(array_expr)
|
||||||
|
stmts.append(array_stmts)
|
||||||
|
let array_name = self.expr_to_knf_name(
|
||||||
|
array_knf_expr,
|
||||||
|
self.typekind_to_knf(array_expr.ty),
|
||||||
|
stmts,
|
||||||
|
)
|
||||||
|
let (index_stmts, index_knf_expr) = self.expr_to_knf(index_expr)
|
||||||
|
stmts.append(index_stmts)
|
||||||
|
let index_name = self.expr_to_knf_name(
|
||||||
|
index_knf_expr,
|
||||||
|
self.typekind_to_knf(index_expr.ty),
|
||||||
|
stmts,
|
||||||
|
)
|
||||||
|
let knf_expr = ArrayAccess(array_name, index_name)
|
||||||
|
(stmts, knf_expr)
|
||||||
|
}
|
||||||
|
FieldAccess(struct_expr, field_name) => {
|
||||||
|
let stmts = []
|
||||||
|
let (struct_stmts, struct_knf_expr) = self.apply_expr_to_knf(struct_expr)
|
||||||
|
stmts.append(struct_stmts)
|
||||||
|
let struct_name = self.expr_to_knf_name(
|
||||||
|
struct_knf_expr,
|
||||||
|
self.typekind_to_knf(struct_expr.ty),
|
||||||
|
stmts,
|
||||||
|
)
|
||||||
|
let knf_expr = FieldAccess(struct_name, field_name)
|
||||||
|
(stmts, knf_expr)
|
||||||
|
}
|
||||||
|
Call(callee_expr, arg_exprs) => {
|
||||||
|
let stmts = []
|
||||||
|
let (callee_stmts, callee_knf_expr) = self.apply_expr_to_knf(callee_expr)
|
||||||
|
stmts.append(callee_stmts)
|
||||||
|
let callee_name = self.expr_to_knf_name(
|
||||||
|
callee_knf_expr,
|
||||||
|
self.typekind_to_knf(callee_expr.ty),
|
||||||
|
stmts,
|
||||||
|
)
|
||||||
|
let arg_names = []
|
||||||
|
for arg_expr in arg_exprs {
|
||||||
|
let (arg_stmts, arg_knf_expr) = self.expr_to_knf(arg_expr)
|
||||||
|
stmts.append(arg_stmts)
|
||||||
|
let arg_name = self.expr_to_knf_name(
|
||||||
|
arg_knf_expr,
|
||||||
|
self.typekind_to_knf(arg_expr.ty),
|
||||||
|
stmts,
|
||||||
|
)
|
||||||
|
arg_names.push(arg_name)
|
||||||
|
}
|
||||||
|
let knf_expr = Call(callee_name, arg_names)
|
||||||
|
(stmts, knf_expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::atom_expr_to_knf(
|
||||||
|
self : Context,
|
||||||
|
atom_expr : @typecheck.AtomExpr,
|
||||||
|
) -> (Array[KnfStmt], KnfExpr) raise KnfTransformError {
|
||||||
|
let { kind, ty } = atom_expr
|
||||||
|
match kind {
|
||||||
|
Int(v) => ([], Int(v))
|
||||||
|
Double(v) => ([], Double(v))
|
||||||
|
Bool(v) => ([], Bool(v))
|
||||||
|
Unit => ([], Unit)
|
||||||
|
Ident(s) => {
|
||||||
|
guard self.lookup_name(s) is Some((name, _)) else {
|
||||||
|
raise KnfTransformError("undefined identifier in atom expression: \{s}")
|
||||||
|
}
|
||||||
|
([], Ident(name))
|
||||||
|
}
|
||||||
|
Array(elems) => {
|
||||||
|
guard ty is Array(elem_ty) else {
|
||||||
|
raise KnfTransformError("expected array type in array literal")
|
||||||
|
}
|
||||||
|
let stmts = []
|
||||||
|
let elem_names = []
|
||||||
|
for elem in elems {
|
||||||
|
let (elem_stmts, elem_expr) = self.expr_to_knf(elem)
|
||||||
|
stmts.append(elem_stmts)
|
||||||
|
let elem_name = self.expr_to_knf_name(
|
||||||
|
elem_expr,
|
||||||
|
self.typekind_to_knf(elem.ty),
|
||||||
|
stmts,
|
||||||
|
)
|
||||||
|
elem_names.push(elem_name)
|
||||||
|
}
|
||||||
|
(stmts, ArrayLiteral(self.typekind_to_knf(elem_ty), elem_names))
|
||||||
|
}
|
||||||
|
Tuple(elems) => {
|
||||||
|
let stmts = []
|
||||||
|
let elem_names = []
|
||||||
|
for elem in elems {
|
||||||
|
let (elem_stmts, elem_expr) = self.expr_to_knf(elem)
|
||||||
|
stmts.append(elem_stmts)
|
||||||
|
let elem_name = self.expr_to_knf_name(
|
||||||
|
elem_expr,
|
||||||
|
self.typekind_to_knf(elem.ty),
|
||||||
|
stmts,
|
||||||
|
)
|
||||||
|
elem_names.push(elem_name)
|
||||||
|
}
|
||||||
|
(stmts, TupleLiteral(elem_names))
|
||||||
|
}
|
||||||
|
ArrayMake(size_expr, init_expr) => {
|
||||||
|
let stmts = []
|
||||||
|
let (size_stmts, size_knf_expr) = self.expr_to_knf(size_expr)
|
||||||
|
stmts.append(size_stmts)
|
||||||
|
let size_name = self.expr_to_knf_name(
|
||||||
|
size_knf_expr,
|
||||||
|
self.typekind_to_knf(size_expr.ty),
|
||||||
|
stmts,
|
||||||
|
)
|
||||||
|
let (init_stmts, init_knf_expr) = self.expr_to_knf(init_expr)
|
||||||
|
stmts.append(init_stmts)
|
||||||
|
let init_name = self.expr_to_knf_name(
|
||||||
|
init_knf_expr,
|
||||||
|
self.typekind_to_knf(init_expr.ty),
|
||||||
|
stmts,
|
||||||
|
)
|
||||||
|
(stmts, ArrayMake(size_name, init_name))
|
||||||
|
}
|
||||||
|
StructConstruct({ name, fields }) => {
|
||||||
|
let stmts = []
|
||||||
|
let init_names = []
|
||||||
|
for field in fields {
|
||||||
|
let (field_name, field_expr) = field
|
||||||
|
let (field_stmts, field_knf_expr) = self.expr_to_knf(field_expr)
|
||||||
|
stmts.append(field_stmts)
|
||||||
|
let field_name_knf = self.expr_to_knf_name(
|
||||||
|
field_knf_expr,
|
||||||
|
self.typekind_to_knf(field_expr.ty),
|
||||||
|
stmts,
|
||||||
|
)
|
||||||
|
init_names.push((field_name, field_name_knf))
|
||||||
|
}
|
||||||
|
(stmts, CreateStruct(name, init_names))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
67
src/knf/assign_stmt.mbt
Normal file
67
src/knf/assign_stmt.mbt
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
///|
|
||||||
|
pub fn Context::assign_stmt_to_knf(
|
||||||
|
self : Context,
|
||||||
|
assign_stmt : @typecheck.AssignStmt,
|
||||||
|
) -> Array[KnfStmt] raise KnfTransformError {
|
||||||
|
let { left_value, expr } = assign_stmt
|
||||||
|
let stmts = []
|
||||||
|
let (expr_stmts, expr_knf_expr) = self.expr_to_knf(expr)
|
||||||
|
stmts.append(expr_stmts)
|
||||||
|
let expr_ty = self.typekind_to_knf(expr.ty)
|
||||||
|
let (left_value_stmts, left_value_knf_expr) = self.left_value_to_knf(
|
||||||
|
left_value,
|
||||||
|
)
|
||||||
|
stmts.append(left_value_stmts)
|
||||||
|
match left_value_knf_expr {
|
||||||
|
Ident(name) => stmts.push(Assign(name, expr_knf_expr))
|
||||||
|
ArrayAccess(array_name, index_name) =>
|
||||||
|
stmts.push(ArrayPut(array_name, index_name, expr_knf_expr))
|
||||||
|
FieldAccess(struct_name, field_name) =>
|
||||||
|
stmts.push(
|
||||||
|
StructFieldSet(
|
||||||
|
struct_name,
|
||||||
|
field_name,
|
||||||
|
self.expr_to_knf_name(expr_knf_expr, expr_ty, stmts),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
_ => panic() // left_value_to_knf should not produce other kinds
|
||||||
|
}
|
||||||
|
stmts
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::left_value_to_knf(
|
||||||
|
self : Context,
|
||||||
|
left_value : @typecheck.LeftValue,
|
||||||
|
) -> (Array[KnfStmt], KnfExpr) raise KnfTransformError {
|
||||||
|
match left_value.kind {
|
||||||
|
Ident(name_str) => {
|
||||||
|
let (name, _) = self
|
||||||
|
.lookup_name(name_str)
|
||||||
|
.or_error(
|
||||||
|
KnfTransformError("undefined identifier in left value: \{name_str}"),
|
||||||
|
)
|
||||||
|
([], Ident(name))
|
||||||
|
}
|
||||||
|
ArrayAccess(array_expr, index_expr) => {
|
||||||
|
let stmts = []
|
||||||
|
let (array_stmts, array_knf_expr) = self.left_value_to_knf(array_expr)
|
||||||
|
stmts.append(array_stmts)
|
||||||
|
let array_ty = self.type_to_knf(array_expr.ty)
|
||||||
|
let array_name = self.expr_to_knf_name(array_knf_expr, array_ty, stmts)
|
||||||
|
let (index_stmts, index_knf_expr) = self.expr_to_knf(index_expr)
|
||||||
|
stmts.append(index_stmts)
|
||||||
|
let index_ty = self.typekind_to_knf(index_expr.ty)
|
||||||
|
let index_name = self.expr_to_knf_name(index_knf_expr, index_ty, stmts)
|
||||||
|
(stmts, ArrayAccess(array_name, index_name))
|
||||||
|
}
|
||||||
|
FieldAccess(struct_expr, field_name) => {
|
||||||
|
let stmts = []
|
||||||
|
let (struct_stmts, struct_knf_expr) = self.left_value_to_knf(struct_expr)
|
||||||
|
stmts.append(struct_stmts)
|
||||||
|
let struct_ty = self.type_to_knf(struct_expr.ty)
|
||||||
|
let struct_name = self.expr_to_knf_name(struct_knf_expr, struct_ty, stmts)
|
||||||
|
(stmts, FieldAccess(struct_name, field_name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
51
src/knf/block.mbt
Normal file
51
src/knf/block.mbt
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
///|
|
||||||
|
pub(all) struct KnfBlock {
|
||||||
|
stmts : Array[KnfStmt]
|
||||||
|
ty : Type
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::block_expr_to_knf(
|
||||||
|
self : Context,
|
||||||
|
expr : @typecheck.BlockExpr,
|
||||||
|
) -> KnfBlock raise KnfTransformError {
|
||||||
|
let stmts = []
|
||||||
|
for stmt in expr.stmts {
|
||||||
|
stmts.append(self.stmt_to_knf(stmt))
|
||||||
|
}
|
||||||
|
if stmts is [.., ExprStmt(Unit)] {
|
||||||
|
ignore(stmts.pop())
|
||||||
|
}
|
||||||
|
let ty = self.typekind_to_knf(expr.ty)
|
||||||
|
{ stmts, ty }
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn KnfBlock::to_string(self : KnfBlock, ident : Int) -> String {
|
||||||
|
let sb = StringBuilder::new()
|
||||||
|
sb.write_string("{\n")
|
||||||
|
for stmt in self.stmts {
|
||||||
|
sb.write_string(stmt.to_string(ident=ident + 2))
|
||||||
|
sb.write_string("\n")
|
||||||
|
}
|
||||||
|
sb.write_string(" ".repeat(ident))
|
||||||
|
sb.write_string("}")
|
||||||
|
sb.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn KnfBlock::nested_to_string(self : KnfBlock) -> String {
|
||||||
|
let sb = StringBuilder::new()
|
||||||
|
sb.write_string("{")
|
||||||
|
for stmt in self.stmts {
|
||||||
|
sb.write_string(stmt.to_string(ident=0))
|
||||||
|
sb.write_string(" ")
|
||||||
|
}
|
||||||
|
sb.write_string("}")
|
||||||
|
sb.to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub impl Show for KnfBlock with output(self, logger) {
|
||||||
|
logger.write_string(self.to_string(0))
|
||||||
|
}
|
||||||
83
src/knf/closure.mbt
Normal file
83
src/knf/closure.mbt
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
///|
|
||||||
|
pub(all) struct KnfClosure {
|
||||||
|
name : Name
|
||||||
|
params : Array[(Name, Type)]
|
||||||
|
ret_ty : Type
|
||||||
|
body : KnfBlock
|
||||||
|
captured_vars : Map[Name, Type]
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::local_function_to_knf(
|
||||||
|
self : Context,
|
||||||
|
local_function : @typecheck.LocalFunction,
|
||||||
|
) -> KnfClosure raise KnfTransformError {
|
||||||
|
let { fname, param_list, ret_ty, body } = local_function
|
||||||
|
|
||||||
|
// 1. 函数类型构造
|
||||||
|
let knf_params = []
|
||||||
|
let param_types = []
|
||||||
|
for param in param_list {
|
||||||
|
let (param_name, param_ty) = param
|
||||||
|
let knf_param_ty = self.type_to_knf(param_ty)
|
||||||
|
knf_params.push((param_name, knf_param_ty))
|
||||||
|
param_types.push(knf_param_ty)
|
||||||
|
}
|
||||||
|
let knf_ret_ty = self.type_to_knf(ret_ty)
|
||||||
|
let func_type = Function(param_types, knf_ret_ty)
|
||||||
|
let knf_func_name = self.add_new_name(fname, func_type)
|
||||||
|
|
||||||
|
// 2. 进入函数作用域
|
||||||
|
self.enter_scope()
|
||||||
|
|
||||||
|
// 3. 参数处理和函数体转换
|
||||||
|
let knf_param_names = []
|
||||||
|
for param in knf_params {
|
||||||
|
let (param_name, param_ty) = param
|
||||||
|
let knf_param_name = self.add_new_name(param_name, param_ty)
|
||||||
|
knf_param_names.push((knf_param_name, param_ty))
|
||||||
|
}
|
||||||
|
let knf_body = self.block_expr_to_knf(body)
|
||||||
|
|
||||||
|
// 捕获的变量
|
||||||
|
let captured_vars = Map::new()
|
||||||
|
for name in self.name_env.capture.keys() {
|
||||||
|
let ty = self.name_env.capture.get(name).unwrap()
|
||||||
|
captured_vars.set(name, ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 退出作用域并构造闭包
|
||||||
|
self.exit_scope()
|
||||||
|
{
|
||||||
|
name: knf_func_name,
|
||||||
|
params: knf_param_names,
|
||||||
|
ret_ty: knf_ret_ty,
|
||||||
|
body: knf_body,
|
||||||
|
captured_vars,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn KnfClosure::to_string(self : KnfClosure, ident? : Int = 0) -> String {
|
||||||
|
let sb = StringBuilder::new()
|
||||||
|
let indent_str = " ".repeat(ident)
|
||||||
|
if !self.captured_vars.is_empty() {
|
||||||
|
sb.write_string("// Captured variables: \n")
|
||||||
|
for name, ty in self.captured_vars {
|
||||||
|
sb.write_string(indent_str)
|
||||||
|
sb.write_string("// - \{name} : \{ty}\n")
|
||||||
|
}
|
||||||
|
sb.write_string(indent_str)
|
||||||
|
sb.write_string("fn \{self.name}(")
|
||||||
|
} else {
|
||||||
|
sb.write_string("fn \{self.name}(")
|
||||||
|
}
|
||||||
|
let param_strs = self.params.map(name_ty => {
|
||||||
|
let (name, ty) = name_ty
|
||||||
|
"\{name} : \{ty}"
|
||||||
|
})
|
||||||
|
sb.write_string(param_strs.join(", "))
|
||||||
|
sb.write_string(") -> \{self.ret_ty} ")
|
||||||
|
sb.write_string(self.body.to_string(ident))
|
||||||
|
sb.to_string()
|
||||||
|
}
|
||||||
134
src/knf/context.mbt
Normal file
134
src/knf/context.mbt
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
///|
|
||||||
|
pub(all) suberror KnfTransformError String derive(Show)
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub(all) struct Name {
|
||||||
|
id : String
|
||||||
|
slot : Int
|
||||||
|
} derive(Hash, Eq)
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Name::wildcard() -> Name {
|
||||||
|
Name::{ id: "_", slot: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub impl Show for Name with output(self, logger) {
|
||||||
|
logger.write_string(self.id)
|
||||||
|
if self.slot > 0 {
|
||||||
|
logger.write_string("$\{self.slot}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub(all) struct Env {
|
||||||
|
local_ : Map[String, (Name, Type)] // defined in this scope
|
||||||
|
capture : Map[Name, Type] // captured from outer scopes
|
||||||
|
parent : Env?
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Env::new(parent? : Env? = None) -> Env {
|
||||||
|
Env::{ local_: Map::new(), capture: Map::new(), parent }
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Env::get_name_type(self : Env, name : Name) -> Type? {
|
||||||
|
let { id, .. } = name
|
||||||
|
match self.local_.get(id) {
|
||||||
|
Some((_, t)) => Some(t)
|
||||||
|
None =>
|
||||||
|
match self.parent {
|
||||||
|
Some(p) => p.get_name_type(name)
|
||||||
|
None => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Env::get(self : Env, name : String, no_capture? : Bool = false) -> Name? {
|
||||||
|
match self.local_.get(name) {
|
||||||
|
Some((n, _)) => Some(n)
|
||||||
|
None =>
|
||||||
|
match self.parent {
|
||||||
|
Some(p) =>
|
||||||
|
match p.get(name, no_capture~) {
|
||||||
|
Some(n) => {
|
||||||
|
if !no_capture {
|
||||||
|
let ty = p.get_name_type(n).unwrap()
|
||||||
|
self.capture.set(n, ty)
|
||||||
|
}
|
||||||
|
Some(n)
|
||||||
|
}
|
||||||
|
None => None
|
||||||
|
}
|
||||||
|
None => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Env::set(self : Env, s : String, name : Name, ty : Type) -> Unit {
|
||||||
|
self.local_.set(s, (name, ty))
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub(all) struct Context {
|
||||||
|
mut name_env : Env
|
||||||
|
capture : Array[Name]
|
||||||
|
globals : Map[String, Type]
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::new() -> Context {
|
||||||
|
Context::{ name_env: Env::new(), capture: Array::new(), globals: Map::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::lookup_name(self : Context, s : String) -> (Name, Type)? {
|
||||||
|
let local_ = self.name_env.get(s)
|
||||||
|
if local_ is Some(name) {
|
||||||
|
return Some((name, self.name_env.get_name_type(name).unwrap()))
|
||||||
|
}
|
||||||
|
let global = self.globals.get(s)
|
||||||
|
if global is Some(ty) {
|
||||||
|
return Some(({ id: s, slot: 0 }, ty))
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::enter_scope(self : Context) -> Unit {
|
||||||
|
let sub_env = Env::new(parent=Some(self.name_env))
|
||||||
|
self.name_env = sub_env
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::exit_scope(self : Context) -> Unit {
|
||||||
|
self.name_env = match self.name_env.parent {
|
||||||
|
Some(p) => p
|
||||||
|
None => self.name_env
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::add_new_name(self : Context, s : String, ty : Type) -> Name {
|
||||||
|
match self.name_env.get(s, no_capture=true) {
|
||||||
|
Some({ id, slot }) => {
|
||||||
|
let name = Name::{ id, slot: slot + 1 }
|
||||||
|
self.name_env.set(s, name, ty)
|
||||||
|
name
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let name = Name::{ id: s, slot: 0 }
|
||||||
|
self.name_env.set(s, name, ty)
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::add_temp(self : Context, ty : Type) -> Name {
|
||||||
|
let temp_id = "tmp"
|
||||||
|
self.add_new_name(temp_id, ty)
|
||||||
|
}
|
||||||
228
src/knf/expr.mbt
Normal file
228
src/knf/expr.mbt
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
///|
|
||||||
|
pub(all) enum KnfExpr {
|
||||||
|
Unit
|
||||||
|
Int(Int)
|
||||||
|
Bool(Bool)
|
||||||
|
Double(Double)
|
||||||
|
Ident(Name)
|
||||||
|
Not(Name)
|
||||||
|
Neg(Name)
|
||||||
|
Binary(BinaryOp, Name, Name)
|
||||||
|
If(KnfExpr, KnfBlock, KnfBlock)
|
||||||
|
Block(KnfBlock)
|
||||||
|
Call(Name, Array[Name])
|
||||||
|
ArrayAccess(Name, Name)
|
||||||
|
FieldAccess(Name, String)
|
||||||
|
TupleAccess(Name, Int)
|
||||||
|
CreateStruct(String, Array[(String, Name)])
|
||||||
|
ArrayLiteral(Type, Array[Name])
|
||||||
|
ArrayMake(Name, Name)
|
||||||
|
TupleLiteral(Array[Name])
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub(all) enum BinaryOp {
|
||||||
|
Add // +
|
||||||
|
Sub // -
|
||||||
|
Mul // *
|
||||||
|
Div // /
|
||||||
|
Mod // %
|
||||||
|
Eq // ==
|
||||||
|
NE // !=
|
||||||
|
LT // <
|
||||||
|
GT // >
|
||||||
|
LE // <=
|
||||||
|
GE // >=
|
||||||
|
And // &&
|
||||||
|
Or // ||
|
||||||
|
} derive(Eq)
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::expr_to_knf(
|
||||||
|
self : Context,
|
||||||
|
expr : @typecheck.Expr,
|
||||||
|
) -> (Array[KnfStmt], KnfExpr) raise KnfTransformError {
|
||||||
|
match expr.kind {
|
||||||
|
ApplyExpr(apply_expr) => self.apply_expr_to_knf(apply_expr)
|
||||||
|
NotExpr(inner) | NegExpr(inner) => {
|
||||||
|
let stmts = []
|
||||||
|
let (inner_stmts, inner_expr) = self.expr_to_knf(inner)
|
||||||
|
stmts.append(inner_stmts)
|
||||||
|
let ty = self.typekind_to_knf(inner.ty)
|
||||||
|
let tmp_name = self.add_temp(ty)
|
||||||
|
stmts.push(Let(tmp_name, ty, inner_expr))
|
||||||
|
let knf_expr = match expr.kind {
|
||||||
|
NotExpr(_) => Not(tmp_name)
|
||||||
|
NegExpr(_) => Neg(tmp_name)
|
||||||
|
_ => panic()
|
||||||
|
}
|
||||||
|
(stmts, knf_expr)
|
||||||
|
}
|
||||||
|
Compare(op, lhs, rhs) => {
|
||||||
|
let op = match op {
|
||||||
|
Equal => Eq
|
||||||
|
NotEqual => NE
|
||||||
|
Less => LT
|
||||||
|
Greater => GT
|
||||||
|
LessEqual => LE
|
||||||
|
GreaterEqual => GE
|
||||||
|
}
|
||||||
|
self.binary_expr_to_knf(op, lhs, rhs)
|
||||||
|
}
|
||||||
|
AddSub(op, lhs, rhs) => {
|
||||||
|
let op = match op {
|
||||||
|
Add => Add
|
||||||
|
Sub => Sub
|
||||||
|
}
|
||||||
|
self.binary_expr_to_knf(op, lhs, rhs)
|
||||||
|
}
|
||||||
|
MulDivRem(op, lhs, rhs) => {
|
||||||
|
let op = match op {
|
||||||
|
Mul => Mul
|
||||||
|
Div => Div
|
||||||
|
Rem => Mod
|
||||||
|
}
|
||||||
|
self.binary_expr_to_knf(op, lhs, rhs)
|
||||||
|
}
|
||||||
|
Or(lhs, rhs) => self.binary_expr_to_knf(Or, lhs, rhs)
|
||||||
|
And(lhs, rhs) => self.binary_expr_to_knf(And, lhs, rhs)
|
||||||
|
BlockExpr(block_expr) => {
|
||||||
|
let knf_block = self.block_expr_to_knf(block_expr)
|
||||||
|
([], Block(knf_block))
|
||||||
|
}
|
||||||
|
IfExpr(if_expr) => self.if_expr_to_knf(if_expr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::expr_to_knf_name(
|
||||||
|
self : Context,
|
||||||
|
expr : KnfExpr,
|
||||||
|
ty : Type,
|
||||||
|
stmts : Array[KnfStmt],
|
||||||
|
) -> Name {
|
||||||
|
match expr {
|
||||||
|
Ident(name) => name
|
||||||
|
_ => {
|
||||||
|
let tmp_name = self.add_temp(ty)
|
||||||
|
stmts.push(Let(tmp_name, ty, expr))
|
||||||
|
tmp_name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::binary_expr_to_knf(
|
||||||
|
self : Context,
|
||||||
|
op : BinaryOp,
|
||||||
|
lhs : @typecheck.Expr,
|
||||||
|
rhs : @typecheck.Expr,
|
||||||
|
) -> (Array[KnfStmt], KnfExpr) raise KnfTransformError {
|
||||||
|
let stmts = []
|
||||||
|
let (lhs_stmts, lhs_expr) = self.expr_to_knf(lhs)
|
||||||
|
let (rhs_stmts, rhs_expr) = self.expr_to_knf(rhs)
|
||||||
|
stmts.append(lhs_stmts)
|
||||||
|
stmts.append(rhs_stmts)
|
||||||
|
let ty = self.typekind_to_knf(lhs.ty)
|
||||||
|
let lhs_name = self.expr_to_knf_name(lhs_expr, ty, stmts)
|
||||||
|
let rhs_name = self.expr_to_knf_name(rhs_expr, ty, stmts)
|
||||||
|
let knf_expr = Binary(op, lhs_name, rhs_name)
|
||||||
|
(stmts, knf_expr)
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::if_expr_to_knf(
|
||||||
|
self : Context,
|
||||||
|
if_expr : @typecheck.IfExpr,
|
||||||
|
) -> (Array[KnfStmt], KnfExpr) raise KnfTransformError {
|
||||||
|
let stmts = []
|
||||||
|
let (cond_stmts, cond_knf_expr) = self.expr_to_knf(if_expr.cond)
|
||||||
|
stmts.append(cond_stmts)
|
||||||
|
let then_block = self.block_expr_to_knf(if_expr.then_block)
|
||||||
|
let else_block = match if_expr.else_block {
|
||||||
|
None => { stmts: [], ty: Unit }
|
||||||
|
Some(expr) => {
|
||||||
|
let (else_stmts, nested_if_knf) = self.expr_to_knf(expr)
|
||||||
|
stmts.append(else_stmts)
|
||||||
|
match nested_if_knf {
|
||||||
|
Block(knf_block) => knf_block
|
||||||
|
_ =>
|
||||||
|
{
|
||||||
|
stmts: [ExprStmt(nested_if_knf)],
|
||||||
|
ty: self.typekind_to_knf(expr.ty),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
(stmts, If(cond_knf_expr, then_block, else_block))
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub impl Show for BinaryOp with output(self, logger) {
|
||||||
|
let s = match self {
|
||||||
|
Add => "+"
|
||||||
|
Sub => "-"
|
||||||
|
Mul => "*"
|
||||||
|
Div => "/"
|
||||||
|
Mod => "%"
|
||||||
|
Eq => "=="
|
||||||
|
NE => "!="
|
||||||
|
LT => "<"
|
||||||
|
GT => ">"
|
||||||
|
LE => "<="
|
||||||
|
GE => ">="
|
||||||
|
And => "&&"
|
||||||
|
Or => "||"
|
||||||
|
}
|
||||||
|
logger.write_string(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn KnfExpr::to_string(self : KnfExpr, ident? : Int = 0) -> String {
|
||||||
|
match self {
|
||||||
|
Unit => "()"
|
||||||
|
Int(i) => i.to_string()
|
||||||
|
Bool(b) => b.to_string()
|
||||||
|
Double(d) => d.to_string()
|
||||||
|
Ident(name) => name.to_string()
|
||||||
|
Not(name) => "!\{name}"
|
||||||
|
Neg(name) => "-\{name}"
|
||||||
|
Binary(op, lhs, rhs) => "\{lhs} \{op} \{rhs}"
|
||||||
|
Call(func_name, args) => {
|
||||||
|
let args_strs = args.map(arg => arg.to_string()).join(", ")
|
||||||
|
"\{func_name}(\{args_strs})"
|
||||||
|
}
|
||||||
|
ArrayAccess(array_name, index_name) => "\{array_name}[\{index_name}]"
|
||||||
|
FieldAccess(struct_name, field_name) => "\{struct_name}.\{field_name}"
|
||||||
|
TupleAccess(tuple_name, index) => "\{tuple_name}.\{index}"
|
||||||
|
CreateStruct(struct_name, init_arr) => {
|
||||||
|
let init_strs = init_arr.map(field => "\{field.0}: \{field.1}").join(", ")
|
||||||
|
"\{struct_name}::{\{init_strs}}"
|
||||||
|
}
|
||||||
|
ArrayLiteral(ty, elem_names) => {
|
||||||
|
let elems_strs = elem_names.map(elem => elem.to_string()).join(", ")
|
||||||
|
"[\{elems_strs}]::Array[\{ty}]"
|
||||||
|
}
|
||||||
|
ArrayMake(size_name, init_name) => "array_make(\{size_name}, \{init_name})"
|
||||||
|
TupleLiteral(elem_names) => {
|
||||||
|
let elems_strs = elem_names.map(elem => elem.to_string()).join(", ")
|
||||||
|
"(\{elems_strs})"
|
||||||
|
}
|
||||||
|
Block(block) => block.to_string(ident)
|
||||||
|
If(cond, then_block, else_block) => {
|
||||||
|
let cond_str = cond.to_string()
|
||||||
|
let then_str : String = then_block.to_string(ident)
|
||||||
|
if else_block.stmts.is_empty() {
|
||||||
|
"if \{cond_str} \{then_str}"
|
||||||
|
} else {
|
||||||
|
let else_str : String = else_block.to_string(ident)
|
||||||
|
"if \{cond_str} \{then_str} else \{else_str}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub impl Show for KnfExpr with output(self, logger) {
|
||||||
|
logger.write_string(self.to_string(ident=0))
|
||||||
|
}
|
||||||
62
src/knf/function.mbt
Normal file
62
src/knf/function.mbt
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
///|
|
||||||
|
pub(all) struct KnfFunction {
|
||||||
|
name : String
|
||||||
|
ret_ty : Type
|
||||||
|
params : Array[(Name, Type)]
|
||||||
|
body : KnfBlock
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::top_function_to_knf(
|
||||||
|
self : Context,
|
||||||
|
top_func : @typecheck.TopFunction,
|
||||||
|
) -> KnfFunction raise KnfTransformError {
|
||||||
|
let { fname, param_list, ty, body } = top_func
|
||||||
|
let func_type = self.typekind_to_knf(ty)
|
||||||
|
self.globals.set(fname, func_type)
|
||||||
|
|
||||||
|
// 1. 进入函数作用域
|
||||||
|
self.enter_scope()
|
||||||
|
|
||||||
|
// 2. 参数处理
|
||||||
|
let knf_params = []
|
||||||
|
let param_types = []
|
||||||
|
for param in param_list {
|
||||||
|
let { name: param_name, ty: param_ty } = param
|
||||||
|
let knf_param_ty = self.typekind_to_knf(param_ty)
|
||||||
|
let knf_param_name = self.add_new_name(param_name, knf_param_ty)
|
||||||
|
knf_params.push((knf_param_name, knf_param_ty))
|
||||||
|
param_types.push(knf_param_ty)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 返回类型转换
|
||||||
|
guard func_type is Function(_, ret_ty) else {
|
||||||
|
raise KnfTransformError("Function type expected")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 函数体转换
|
||||||
|
let knf_body = self.block_expr_to_knf(body)
|
||||||
|
|
||||||
|
// 5. 退出作用域
|
||||||
|
self.exit_scope()
|
||||||
|
{ name: fname, ret_ty, params: knf_params, body: knf_body }
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub impl Show for KnfFunction with output(self, logger) {
|
||||||
|
let { name, ret_ty, params, body } = self
|
||||||
|
logger.write_string("fn \{name}")
|
||||||
|
if name != "main" {
|
||||||
|
logger.write_string("(")
|
||||||
|
let param_str = params
|
||||||
|
.map(param => {
|
||||||
|
let (param_name, param_ty) = param
|
||||||
|
"\{param_name}: \{param_ty}"
|
||||||
|
})
|
||||||
|
.join(", ")
|
||||||
|
logger.write_string(param_str)
|
||||||
|
logger.write_string(") -> \{ret_ty}")
|
||||||
|
}
|
||||||
|
logger.write_char(' ')
|
||||||
|
logger.write_object(body)
|
||||||
|
}
|
||||||
85
src/knf/knf.mbt
Normal file
85
src/knf/knf.mbt
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
///|
|
||||||
|
pub(all) struct KnfProgram {
|
||||||
|
struct_defs : Map[String, KnfStructDef]
|
||||||
|
top_lets : Map[String, KnfTopLet]
|
||||||
|
functions : Map[String, KnfFunction]
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::program_to_knf(
|
||||||
|
self : Context,
|
||||||
|
prog : @typecheck.Program,
|
||||||
|
) -> KnfProgram raise KnfTransformError {
|
||||||
|
let knf_struct_defs = Map::new()
|
||||||
|
for name, struct_def in prog.struct_defs {
|
||||||
|
let knf_struct_def = self.struct_def_to_knf(struct_def)
|
||||||
|
knf_struct_defs.set(name, knf_struct_def)
|
||||||
|
}
|
||||||
|
for name, func in prog.top_functions {
|
||||||
|
let func_type = self.typekind_to_knf(func.ty)
|
||||||
|
self.globals.set(name, func_type)
|
||||||
|
}
|
||||||
|
let knf_top_lets = Map::new()
|
||||||
|
for name, top_let in prog.top_lets {
|
||||||
|
let knf_top_let = self.top_let_to_knf(top_let)
|
||||||
|
knf_top_lets.set(name, knf_top_let)
|
||||||
|
}
|
||||||
|
let knf_functions = Map::new()
|
||||||
|
for name, func in prog.top_functions {
|
||||||
|
let knf_func = self.top_function_to_knf(func)
|
||||||
|
knf_functions.set(name, knf_func)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
struct_defs: knf_struct_defs,
|
||||||
|
top_lets: knf_top_lets,
|
||||||
|
functions: knf_functions,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn knf_transform(
|
||||||
|
prog : @typecheck.Program,
|
||||||
|
) -> KnfProgram raise KnfTransformError {
|
||||||
|
let context = Context::new()
|
||||||
|
context.add_intrinsic_functions()
|
||||||
|
context.program_to_knf(prog)
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::add_intrinsic_functions(self : Context) -> Unit {
|
||||||
|
let map = Map::of([
|
||||||
|
("read_int", Function([], Int)),
|
||||||
|
("print_int", Function([Int], Unit)),
|
||||||
|
("read_char", Function([], Int)),
|
||||||
|
("print_char", Function([Int], Unit)),
|
||||||
|
("print_endline", Function([], Unit)),
|
||||||
|
("int_of_float", Function([Double], Int)),
|
||||||
|
("float_of_int", Function([Int], Double)),
|
||||||
|
("truncate", Function([Double], Int)),
|
||||||
|
("floor", Function([Double], Double)),
|
||||||
|
("abs_float", Function([Double], Double)),
|
||||||
|
("sqrt", Function([Double], Double)),
|
||||||
|
("sin", Function([Double], Double)),
|
||||||
|
("cos", Function([Double], Double)),
|
||||||
|
("atan", Function([Double], Double)),
|
||||||
|
])
|
||||||
|
for name, ty in map {
|
||||||
|
self.globals.set(name, ty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub impl Show for KnfProgram with output(self, logger) {
|
||||||
|
for _, struct_def in self.struct_defs {
|
||||||
|
logger.write_object(struct_def)
|
||||||
|
logger.write_char('\n')
|
||||||
|
}
|
||||||
|
for _, top_let in self.top_lets {
|
||||||
|
logger.write_object(top_let)
|
||||||
|
logger.write_char('\n')
|
||||||
|
}
|
||||||
|
for _, func in self.functions {
|
||||||
|
logger.write_object(func)
|
||||||
|
logger.write_char('\n')
|
||||||
|
}
|
||||||
|
}
|
||||||
1417
src/knf/knf_test.mbt
Normal file
1417
src/knf/knf_test.mbt
Normal file
File diff suppressed because it is too large
Load Diff
75
src/knf/let_stmt.mbt
Normal file
75
src/knf/let_stmt.mbt
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
///|
|
||||||
|
pub fn Context::let_mut_stmt_to_knf(
|
||||||
|
self : Context,
|
||||||
|
let_mut_stmt : @typecheck.LetMutStmt,
|
||||||
|
) -> Array[KnfStmt] raise KnfTransformError {
|
||||||
|
let { name, ty, expr } = let_mut_stmt
|
||||||
|
let stmts = []
|
||||||
|
let (init_stmts, init_knf_expr) = self.expr_to_knf(expr)
|
||||||
|
stmts.append(init_stmts)
|
||||||
|
let ty = self.type_to_knf(ty)
|
||||||
|
let name = self.add_new_name(name, ty)
|
||||||
|
stmts.push(LetMut(name, ty, init_knf_expr))
|
||||||
|
stmts
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::let_stmt_to_knf(
|
||||||
|
self : Context,
|
||||||
|
let_stmt : @typecheck.LetStmt,
|
||||||
|
) -> Array[KnfStmt] raise KnfTransformError {
|
||||||
|
let { pattern, ty, expr } = let_stmt
|
||||||
|
let stmts = []
|
||||||
|
let (init_stmts, init_knf_expr) = self.expr_to_knf(expr)
|
||||||
|
stmts.append(init_stmts)
|
||||||
|
let ty = self.typekind_to_knf(ty)
|
||||||
|
match pattern.kind {
|
||||||
|
Ident(name) => {
|
||||||
|
let name = self.add_new_name(name, ty)
|
||||||
|
stmts.push(Let(name, ty, init_knf_expr))
|
||||||
|
stmts
|
||||||
|
}
|
||||||
|
Wildcard => {
|
||||||
|
let name = Name::wildcard()
|
||||||
|
stmts.push(Let(name, ty, init_knf_expr))
|
||||||
|
stmts
|
||||||
|
}
|
||||||
|
Tuple(names) => {
|
||||||
|
guard ty is Tuple(types) else {
|
||||||
|
raise KnfTransformError("tuple pattern requires tuple type")
|
||||||
|
}
|
||||||
|
if init_knf_expr is TupleLiteral(elem_names) {
|
||||||
|
guard names.length() == elem_names.length() else {
|
||||||
|
raise KnfTransformError("tuple pattern length mismatch")
|
||||||
|
}
|
||||||
|
for i in 0..<names.length() {
|
||||||
|
let elem_name = match names[i].kind {
|
||||||
|
Ident(s) => self.add_new_name(s, types[i])
|
||||||
|
Wildcard => Name::wildcard()
|
||||||
|
Tuple(_) => panic()
|
||||||
|
}
|
||||||
|
let elem_ty = types[i]
|
||||||
|
let value_expr = KnfExpr::Ident(elem_names[i])
|
||||||
|
stmts.push(Let(elem_name, elem_ty, value_expr))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Handle non-tuple expression case
|
||||||
|
let tmp_name = self.add_temp(ty)
|
||||||
|
for i in 0..<names.length() {
|
||||||
|
let elem_name = match names[i].kind {
|
||||||
|
Ident(s) => self.add_new_name(s, types[i])
|
||||||
|
Wildcard => Name::wildcard()
|
||||||
|
Tuple(_) => panic()
|
||||||
|
}
|
||||||
|
let elem_ty = types[i]
|
||||||
|
let value_expr = KnfExpr::ArrayAccess(
|
||||||
|
tmp_name,
|
||||||
|
self.expr_to_knf_name(Int(i), Int, stmts),
|
||||||
|
)
|
||||||
|
stmts.push(Let(elem_name, elem_ty, value_expr))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stmts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/knf/moon.pkg.json
Normal file
8
src/knf/moon.pkg.json
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"import": [
|
||||||
|
"Lil-Ran/lilunar/typecheck"
|
||||||
|
],
|
||||||
|
"test-import": [
|
||||||
|
"Lil-Ran/lilunar/parser"
|
||||||
|
]
|
||||||
|
}
|
||||||
99
src/knf/stmt.mbt
Normal file
99
src/knf/stmt.mbt
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
///|
|
||||||
|
pub(all) enum KnfStmt {
|
||||||
|
Let(Name, Type, KnfExpr) // let a : Int = 42;
|
||||||
|
LetMut(Name, Type, KnfExpr) // let mut a : Int = 0;
|
||||||
|
Assign(Name, KnfExpr) // a = 10;
|
||||||
|
ArrayPut(Name, Name, KnfExpr) // arr[3] = 5;
|
||||||
|
StructFieldSet(Name, String, Name) // point.x = 10; // MiniMoonBit does not support
|
||||||
|
While(KnfBlock, KnfBlock) // while (cond) { ... }
|
||||||
|
ExprStmt(KnfExpr) // expr;
|
||||||
|
Return(KnfExpr) // return expr;
|
||||||
|
ReturnUnit // return;
|
||||||
|
ClosureDef(KnfClosure) // closure definition
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::stmt_to_knf(
|
||||||
|
self : Context,
|
||||||
|
stmt : @typecheck.Stmt,
|
||||||
|
) -> Array[KnfStmt] raise KnfTransformError {
|
||||||
|
match stmt.kind {
|
||||||
|
LetStmt(let_stmt) => self.let_stmt_to_knf(let_stmt)
|
||||||
|
LetMutStmt(let_mut_stmt) => self.let_mut_stmt_to_knf(let_mut_stmt)
|
||||||
|
AssignStmt(assign_stmt) => self.assign_stmt_to_knf(assign_stmt)
|
||||||
|
WhileStmt(while_stmt) => self.while_stmt_to_knf(while_stmt)
|
||||||
|
ExprStmt(expr_stmt) => {
|
||||||
|
let stmts = []
|
||||||
|
let (expr_stmts, expr_knf_expr) = self.expr_to_knf(expr_stmt)
|
||||||
|
stmts.append(expr_stmts)
|
||||||
|
stmts.push(ExprStmt(expr_knf_expr))
|
||||||
|
stmts
|
||||||
|
}
|
||||||
|
ReturnStmt(return_stmt) =>
|
||||||
|
match return_stmt.ty {
|
||||||
|
Unit => [ReturnUnit]
|
||||||
|
_ => {
|
||||||
|
let stmts = []
|
||||||
|
let (expr_stmts, expr_knf_expr) = self.expr_to_knf(return_stmt)
|
||||||
|
stmts.append(expr_stmts)
|
||||||
|
stmts.push(Return(expr_knf_expr))
|
||||||
|
stmts
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LocalFunction(local_function) => {
|
||||||
|
let closure = self.local_function_to_knf(local_function)
|
||||||
|
[ClosureDef(closure)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::while_stmt_to_knf(
|
||||||
|
self : Context,
|
||||||
|
while_stmt : @typecheck.WhileStmt,
|
||||||
|
) -> Array[KnfStmt] raise KnfTransformError {
|
||||||
|
let (cond_stmts, cond_knf_expr) = self.expr_to_knf(while_stmt.cond)
|
||||||
|
[
|
||||||
|
While(
|
||||||
|
{ stmts: [..cond_stmts, ExprStmt(cond_knf_expr)], ty: Bool },
|
||||||
|
self.block_expr_to_knf(while_stmt.body),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn KnfStmt::to_string(self : KnfStmt, ident? : Int = 0) -> String {
|
||||||
|
let s = match self {
|
||||||
|
Let(name, ty, expr) => "let \{name} : \{ty} = \{expr};"
|
||||||
|
LetMut(name, ty, expr) => "let mut \{name} : \{ty} = \{expr};"
|
||||||
|
Assign(name, expr) => "\{name} = \{expr};"
|
||||||
|
ArrayPut(array_name, index_name, value_expr) =>
|
||||||
|
"\{array_name}[\{index_name}] = \{value_expr};"
|
||||||
|
StructFieldSet(struct_name, field_name, value_name) =>
|
||||||
|
"\{struct_name}.\{field_name} = \{value_name};"
|
||||||
|
While(cond_block, body_block) =>
|
||||||
|
if cond_block.stmts.length() <= 3 {
|
||||||
|
let cond_str = cond_block.nested_to_string()
|
||||||
|
let body_str = body_block.to_string(ident)
|
||||||
|
"while \{cond_str} \{body_str}"
|
||||||
|
} else {
|
||||||
|
let cond_str = cond_block.to_string(ident)
|
||||||
|
let body_str = body_block.to_string(ident)
|
||||||
|
"while \{cond_str} \{body_str}"
|
||||||
|
}
|
||||||
|
ExprStmt(expr) => {
|
||||||
|
let expr_str = expr.to_string(ident~)
|
||||||
|
"\{expr_str};"
|
||||||
|
}
|
||||||
|
Return(expr) => "return \{expr};"
|
||||||
|
ReturnUnit => "return;"
|
||||||
|
ClosureDef(closure) => closure.to_string(ident~)
|
||||||
|
}
|
||||||
|
let indent_str = " ".repeat(ident)
|
||||||
|
"\{indent_str}\{s}"
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub impl Show for KnfStmt with output(self, logger) {
|
||||||
|
logger.write_string(self.to_string(ident=0))
|
||||||
|
}
|
||||||
47
src/knf/struct_def.mbt
Normal file
47
src/knf/struct_def.mbt
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
///|
|
||||||
|
pub(all) struct KnfStructDef {
|
||||||
|
name : String
|
||||||
|
// field name, is_mut, field type
|
||||||
|
fields : Array[(String, Bool, Type)]
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::struct_def_to_knf(
|
||||||
|
self : Context,
|
||||||
|
struct_def : @typecheck.StructDef,
|
||||||
|
) -> KnfStructDef raise KnfTransformError {
|
||||||
|
let { name, fields } = struct_def
|
||||||
|
let knf_fields = []
|
||||||
|
for field in fields {
|
||||||
|
let { name: field_name, ty } = field
|
||||||
|
let field_type = self.typekind_to_knf(ty.kind)
|
||||||
|
knf_fields.push((field_name, ty.mutable, field_type))
|
||||||
|
}
|
||||||
|
{ name, fields: knf_fields }
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn KnfStructDef::get_field_index(
|
||||||
|
self : KnfStructDef,
|
||||||
|
field_name : String,
|
||||||
|
) -> Int? {
|
||||||
|
for i, f in self.fields {
|
||||||
|
let (name, _, _) = f
|
||||||
|
if name == field_name {
|
||||||
|
return Some(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub impl Show for KnfStructDef with output(self, logger) {
|
||||||
|
let { name, fields } = self
|
||||||
|
logger.write_string("struct \{name} {\n")
|
||||||
|
for field in fields {
|
||||||
|
let (field_name, is_mut, field_type) = field
|
||||||
|
let mutability = if is_mut { "mut " } else { "" }
|
||||||
|
logger.write_string(" \{mutability}\{field_name}: \{field_type};\n")
|
||||||
|
}
|
||||||
|
logger.write_string("}\n")
|
||||||
|
}
|
||||||
29
src/knf/top_let.mbt
Normal file
29
src/knf/top_let.mbt
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
///|
|
||||||
|
pub(all) struct KnfTopLet {
|
||||||
|
name : Name
|
||||||
|
ty : Type
|
||||||
|
expr : KnfExpr
|
||||||
|
init_stmts : Array[KnfStmt]
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::top_let_to_knf(
|
||||||
|
self : Context,
|
||||||
|
top_let : @typecheck.TopLet,
|
||||||
|
) -> KnfTopLet raise KnfTransformError {
|
||||||
|
let { name, ty, expr } = top_let
|
||||||
|
let (init_stmts, expr) = self.expr_to_knf(expr)
|
||||||
|
let ty = self.type_to_knf(ty)
|
||||||
|
let name = self.add_new_name(name, ty)
|
||||||
|
self.globals.set(top_let.name, ty)
|
||||||
|
{ name, ty, expr, init_stmts }
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub impl Show for KnfTopLet with output(self, logger) {
|
||||||
|
let { name, ty, expr, init_stmts } = self
|
||||||
|
for stmt in init_stmts {
|
||||||
|
logger.write_string(" \{stmt};")
|
||||||
|
}
|
||||||
|
logger.write_string("let \{name} : \{ty} = \{expr};")
|
||||||
|
}
|
||||||
64
src/knf/type.mbt
Normal file
64
src/knf/type.mbt
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
///|
|
||||||
|
pub(all) enum Type {
|
||||||
|
Unit
|
||||||
|
Int
|
||||||
|
Bool
|
||||||
|
Double
|
||||||
|
Array(Type)
|
||||||
|
Struct(String)
|
||||||
|
Tuple(Array[Type])
|
||||||
|
Function(Array[Type], Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub impl Show for Type with output(self, logger) {
|
||||||
|
let s = match self {
|
||||||
|
Unit => "Unit"
|
||||||
|
Int => "Int"
|
||||||
|
Bool => "Bool"
|
||||||
|
Double => "Double"
|
||||||
|
Array(elem_type) => "Array[\{elem_type}]"
|
||||||
|
Struct(name) => "\{name}"
|
||||||
|
Tuple(elem_types) => {
|
||||||
|
let elem_strs = elem_types.map(et => "\{et}").join(", ")
|
||||||
|
"(\{elem_strs})"
|
||||||
|
}
|
||||||
|
Function(param_types, ret_type) => {
|
||||||
|
let param_strs = param_types.map(pt => "\{pt}").join(", ")
|
||||||
|
"(\{param_strs}) -> \{ret_type}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.write_string(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::typekind_to_knf(
|
||||||
|
self : Context,
|
||||||
|
tk : @typecheck.TypeKind,
|
||||||
|
) -> Type raise KnfTransformError {
|
||||||
|
match tk {
|
||||||
|
Any => raise KnfTransformError("Cannot convert 'Any' to KNF type.")
|
||||||
|
Struct(name) => Struct(name)
|
||||||
|
Function(param_types, ret_type) =>
|
||||||
|
Function(
|
||||||
|
param_types.map(pt => self.typekind_to_knf(pt)),
|
||||||
|
self.typekind_to_knf(ret_type),
|
||||||
|
)
|
||||||
|
Array(t) => Array(self.typekind_to_knf(t))
|
||||||
|
Tuple(types) => Tuple(types.map(t => self.typekind_to_knf(t)))
|
||||||
|
Double => Double
|
||||||
|
Int => Int
|
||||||
|
Bool => Bool
|
||||||
|
Unit => Unit
|
||||||
|
TypeVar(_) =>
|
||||||
|
raise KnfTransformError("Cannot convert 'TypeVar' to KNF type.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///|
|
||||||
|
pub fn Context::type_to_knf(
|
||||||
|
self : Context,
|
||||||
|
t : @typecheck.Type,
|
||||||
|
) -> Type raise KnfTransformError {
|
||||||
|
self.typekind_to_knf(t.kind)
|
||||||
|
}
|
||||||
@@ -81,6 +81,14 @@ pub fn Context::check_atom_expr(
|
|||||||
let field_exprs = []
|
let field_exprs = []
|
||||||
for field in fields {
|
for field in fields {
|
||||||
let (field_name, field_expr) = field
|
let (field_name, field_expr) = field
|
||||||
|
for existing_field in field_exprs {
|
||||||
|
let (existing_field_name, _) = existing_field
|
||||||
|
if existing_field_name == field_name {
|
||||||
|
raise TypeCheckError(
|
||||||
|
"Duplicate field '\{field_name}' in struct '\{name}' construction.",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
let expected_type = def
|
let expected_type = def
|
||||||
.get_field_type(field_name)
|
.get_field_type(field_name)
|
||||||
.or_error(
|
.or_error(
|
||||||
|
|||||||
@@ -15,9 +15,16 @@ pub fn Context::check_block_expr(
|
|||||||
self.enter_scope()
|
self.enter_scope()
|
||||||
let checked_stmts = stmts.map(stmt => self.check_stmt(stmt))
|
let checked_stmts = stmts.map(stmt => self.check_stmt(stmt))
|
||||||
self.exit_scope()
|
self.exit_scope()
|
||||||
let stmts_count = checked_stmts.length()
|
guard checked_stmts is [.., { kind: ExprStmt(expr) }] else {
|
||||||
guard stmts_count > 0 && checked_stmts[stmts_count - 1].kind is ExprStmt(expr) else {
|
|
||||||
return { stmts: checked_stmts, ty: Unit }
|
return { stmts: checked_stmts, ty: Unit }
|
||||||
}
|
}
|
||||||
|
if checked_stmts is [.., { kind: ReturnStmt(ret) }] {
|
||||||
|
{ stmts: checked_stmts, ty: ret.ty }
|
||||||
|
} else if checked_stmts is [.., stmt1, stmt2] &&
|
||||||
|
stmt2.kind is ExprStmt({ ty: Unit, .. }) &&
|
||||||
|
stmt1.kind is ReturnStmt(ret) {
|
||||||
|
{ stmts: checked_stmts, ty: ret.ty }
|
||||||
|
} else {
|
||||||
{ stmts: checked_stmts, ty: expr.ty }
|
{ stmts: checked_stmts, ty: expr.ty }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ pub(all) struct Param {
|
|||||||
pub(all) struct TopFunction {
|
pub(all) struct TopFunction {
|
||||||
fname : String
|
fname : String
|
||||||
param_list : Array[Param]
|
param_list : Array[Param]
|
||||||
ret_ty : TypeKind
|
ty : TypeKind
|
||||||
body : BlockExpr
|
body : BlockExpr
|
||||||
} derive(Show)
|
} derive(Show)
|
||||||
|
|
||||||
@@ -28,7 +28,8 @@ pub fn Context::check_top_function_body(
|
|||||||
}
|
}
|
||||||
let param_names = func.params.map(param => param.0)
|
let param_names = func.params.map(param => param.0)
|
||||||
let param_list = []
|
let param_list = []
|
||||||
guard self.func_types.get(func.id) is Some(Function(param_types, ret_ty)) else {
|
guard self.func_types.get(func.id) is Some(ty) &&
|
||||||
|
ty is Function(param_types, ret_ty) else {
|
||||||
raise TypeCheckError("Function type for '\{func.id}' not found.")
|
raise TypeCheckError("Function type for '\{func.id}' not found.")
|
||||||
}
|
}
|
||||||
self.enter_scope()
|
self.enter_scope()
|
||||||
@@ -48,7 +49,7 @@ pub fn Context::check_top_function_body(
|
|||||||
if func.user_defined_type is Some(UserDefined(udt)) {
|
if func.user_defined_type is Some(UserDefined(udt)) {
|
||||||
self.type_env.local_.remove("$Generic$\{udt}")
|
self.type_env.local_.remove("$Generic$\{udt}")
|
||||||
}
|
}
|
||||||
{ fname: func.id, param_list, ret_ty, body: checked_body }
|
{ fname: func.id, param_list, ty, body: checked_body }
|
||||||
}
|
}
|
||||||
|
|
||||||
///|
|
///|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ pub fn Context::substitute_type_var(
|
|||||||
name: param.name,
|
name: param.name,
|
||||||
ty: self.deref_type_var(param.ty),
|
ty: self.deref_type_var(param.ty),
|
||||||
}),
|
}),
|
||||||
ret_ty: self.deref_type_var(top_func.ret_ty),
|
ty: self.deref_type_var(top_func.ty),
|
||||||
body: self.substitute_type_var_for_block_expr(top_func.body),
|
body: self.substitute_type_var_for_block_expr(top_func.body),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user