wip: codegen. public.

This commit is contained in:
2025-11-20 17:06:45 +08:00
parent b7cbbdfbba
commit 85861ef657
25 changed files with 1435 additions and 184 deletions

View File

@@ -2,7 +2,7 @@ import os
import asyncio
async def check_file(in_path, out_path):
async def check_file(in_path, out_path, knf_path):
proc = await asyncio.create_subprocess_exec(
"moon",
"run",
@@ -11,6 +11,8 @@ async def check_file(in_path, out_path):
in_path,
"-o",
out_path,
"--knf-output",
knf_path,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)
@@ -33,7 +35,8 @@ async def main():
if file.endswith(".mbt"):
in_path = os.path.join("contest-2025-data/test_cases/mbt", file)
out_path = os.path.join("output/repo", file.replace(".mbt", ".ll"))
tasks.append(check_file(in_path, out_path))
knf_path = os.path.join("output/repo", file.replace(".mbt", ".txt"))
tasks.append(check_file(in_path, out_path, knf_path))
await asyncio.gather(*tasks)

View File

@@ -3,7 +3,8 @@
"version": "0.1.0",
"deps": {
"moonbitlang/x": "0.4.36",
"Yoorkin/ArgParser": "0.2.0"
"Yoorkin/ArgParser": "0.2.0",
"Kaida-Amethyst/MoonLLVM": "0.1.11"
},
"readme": "README.mbt.md",
"repository": "https://github.com/Lil-Ran/lilunar",

View File

@@ -19,7 +19,8 @@ fn main {
println_debug("CLI arguments: \{argv}")
let typecheck_only = Ref::new(false)
let mut in_file = None
let out_file = Ref::new("a.s")
let knf_out_file = Ref::new("")
let out_file = Ref::new("a.ll")
@ArgParser.parse(
[
(
@@ -34,6 +35,12 @@ fn main {
@ArgParser.Set_string(out_file),
"Output file (default: a.s)",
),
(
"--knf-output",
"",
@ArgParser.Set_string(knf_out_file),
"KNF Output file",
),
],
fn(s) {
if !in_file.is_empty() {
@@ -56,19 +63,19 @@ fn main {
"no input file provided",
))
println_debug("Compiling file: \{file}")
let contents = @fs.read_file_to_string(file) catch {
let source = @fs.read_file_to_string(file) catch {
@fs.IOError(msg) => println_panic("Failed to read file \{file}: \{msg}")
}
println_debug(
(
#|Source:
#|================================
$|\{contents}
$|\{source}
#|================================
),
)
let program = try
contents
source
|> @parser.tokenize()
|> @parser.parse_program()
|> @typecheck.typecheck()
@@ -86,15 +93,22 @@ fn main {
@knf.KnfTransformError(msg) =>
println_panic("KNF transformation error: \{msg}")
}
let knf_string = knf.to_string()
println_debug(
(
#|KNF:
#|================================
$|\{knf}
$|\{knf_string}
#|================================
),
)
let output_string = knf.to_string()
if knf_out_file.val != "" {
@fs.write_string_to_file(knf_out_file.val, knf_string) catch {
@fs.IOError(msg) =>
println_panic("Failed to write KNF to file \{knf_out_file.val}: \{msg}")
}
}
let output_string = knf_string
if out_file.val == "-" {
println(output_string)
} else {

View File

@@ -0,0 +1,13 @@
// Generated using `moon info`, DON'T EDIT IT
package "Lil-Ran/lilunar/bin"
// Values
// Errors
// Types and methods
// Type aliases
// Traits

13
src/codegen/block.mbt Normal file
View File

@@ -0,0 +1,13 @@
///|
pub fn Context::block_codegen(
self : Self,
block : @knf.KnfBlock,
) -> &@llvm.Value? raise {
guard block.stmts is [.. stmts, ExprStmt(expr)] else {
raise CodegenError("Block must end with an expression statement")
}
for stmt in stmts {
self.stmt_codegen(stmt)
}
self.expr_codegen(expr)
}

9
src/codegen/closure.mbt Normal file
View File

@@ -0,0 +1,9 @@
///|
pub fn Context::closure_codegen(
self : Context,
closure_def : @knf.KnfClosure,
) -> Unit raise {
ignore(self)
ignore(closure_def)
raise CodegenError("closure_codegen not implemented")
}

8
src/codegen/codegen.mbt Normal file
View File

@@ -0,0 +1,8 @@
///|
pub fn codegen(knf_prog : @knf.KnfProgram) -> @llvm.Module raise {
let ctx = Context::new("program")
let { struct_defs, top_lets, functions } = knf_prog
ctx.collect_struct_types(struct_defs)
ctx.collect_func_values(functions)
ctx.llvm_mod
}

170
src/codegen/context.mbt Normal file
View File

@@ -0,0 +1,170 @@
///|
pub(all) suberror CodegenError String derive(Show)
///|
pub struct Context {
llvm_ctx : @llvm.Context
llvm_mod : @llvm.Module
builder : @llvm.IRBuilder
mut str_cnt : Int
struct_types : Map[String, @llvm.StructType]
knf_struct_types : Map[String, @knf.KnfStructDef]
functions : Map[String, @llvm.Function]
// mut the follow two if neccessary
name_values : Map[@knf.Name, &@llvm.Value]
name_types : Map[@knf.Name, @knf.Type]
builtin_funcs : Map[String, @llvm.Function]
}
///|
pub fn Context::new(mod_name : String) -> Context {
let llvm_ctx = @llvm.Context::new()
let llvm_mod = llvm_ctx.addModule(mod_name)
let builder = llvm_ctx.createBuilder()
let i32ty = llvm_ctx.getInt32Ty()
let doublety = llvm_ctx.getDoubleTy()
let boolty = llvm_ctx.getInt1Ty()
let ptrty = llvm_ctx.getPtrTy()
let voidty = llvm_ctx.getVoidTy()
let moonbit_malloc_ty = try! llvm_ctx.getFunctionType(ptrty, [i32ty])
let moonbit_malloc = try! llvm_mod.addFunction(
moonbit_malloc_ty, "moonbit_malloc",
)
let print_int_ty = try! llvm_ctx.getFunctionType(llvm_ctx.getVoidTy(), [i32ty])
let print_int = try! llvm_mod.addFunction(print_int_ty, "print_int")
let print_double_ty = try! llvm_ctx.getFunctionType(llvm_ctx.getVoidTy(), [
doublety,
])
let print_double = try! llvm_mod.addFunction(print_double_ty, "print_double")
let print_bool_ty = try! llvm_ctx.getFunctionType(llvm_ctx.getVoidTy(), [
boolty,
])
let print_bool = try! llvm_mod.addFunction(print_bool_ty, "print_bool")
let make_int_array_ty = try! llvm_ctx.getFunctionType(ptrty, [i32ty, i32ty])
let make_double_array_ty = try! llvm_ctx.getFunctionType(ptrty, [
i32ty, doublety,
])
let make_bool_array_ty = try! llvm_ctx.getFunctionType(ptrty, [i32ty, boolty])
let make_ptr_array_ty = try! llvm_ctx.getFunctionType(ptrty, [i32ty, ptrty])
let get_array_length_ty = try! llvm_ctx.getFunctionType(i32ty, [ptrty])
let array_int_push_ty = try! llvm_ctx.getFunctionType(llvm_ctx.getVoidTy(), [
ptrty, i32ty,
])
let array_double_push_ty = try! llvm_ctx.getFunctionType(
llvm_ctx.getVoidTy(),
[ptrty, doublety],
)
let array_bool_push_ty = try! llvm_ctx.getFunctionType(llvm_ctx.getVoidTy(), [
ptrty, boolty,
])
let array_ptr_push_ty = try! llvm_ctx.getFunctionType(llvm_ctx.getVoidTy(), [
ptrty, ptrty,
])
let array_int_get_ty = try! llvm_ctx.getFunctionType(i32ty, [ptrty, i32ty])
let array_double_get_ty = try! llvm_ctx.getFunctionType(doublety, [
ptrty, i32ty,
])
let array_bool_get_ty = try! llvm_ctx.getFunctionType(boolty, [ptrty, i32ty])
let array_ptr_get_ty = try! llvm_ctx.getFunctionType(ptrty, [ptrty, i32ty])
let array_int_put_ty = try! llvm_ctx.getFunctionType(voidty, [
ptrty, i32ty, i32ty,
])
let array_double_put_ty = try! llvm_ctx.getFunctionType(voidty, [
ptrty, i32ty, doublety,
])
let array_bool_put_ty = try! llvm_ctx.getFunctionType(voidty, [
ptrty, i32ty, boolty,
])
let array_ptr_put_ty = try! llvm_ctx.getFunctionType(voidty, [
ptrty, i32ty, ptrty,
])
let make_int_array = try! llvm_mod.addFunction(
make_int_array_ty, "make_int_array",
)
let make_double_array = try! llvm_mod.addFunction(
make_double_array_ty, "make_double_array",
)
let make_bool_array = try! llvm_mod.addFunction(
make_bool_array_ty, "make_bool_array",
)
let make_ptr_array = try! llvm_mod.addFunction(
make_ptr_array_ty, "make_ptr_array",
)
let get_array_length = try! llvm_mod.addFunction(
get_array_length_ty, "get_array_length",
)
let array_int_push = try! llvm_mod.addFunction(
array_int_push_ty, "array_int_push",
)
let array_double_push = try! llvm_mod.addFunction(
array_double_push_ty, "array_double_push",
)
let array_bool_push = try! llvm_mod.addFunction(
array_bool_push_ty, "array_bool_push",
)
let array_ptr_push = try! llvm_mod.addFunction(
array_ptr_push_ty, "array_ptr_push",
)
let array_int_get = try! llvm_mod.addFunction(
array_int_get_ty, "array_int_get",
)
let array_double_get = try! llvm_mod.addFunction(
array_double_get_ty, "array_double_get",
)
let array_bool_get = try! llvm_mod.addFunction(
array_bool_get_ty, "array_bool_get",
)
let array_ptr_get = try! llvm_mod.addFunction(
array_ptr_get_ty, "array_ptr_get",
)
let array_int_put = try! llvm_mod.addFunction(
array_int_put_ty, "array_int_put",
)
let array_double_put = try! llvm_mod.addFunction(
array_double_put_ty, "array_double_put",
)
let array_bool_put = try! llvm_mod.addFunction(
array_bool_put_ty, "array_bool_put",
)
let array_ptr_put = try! llvm_mod.addFunction(
array_ptr_put_ty, "array_ptr_put",
)
let builtin_funcs = {
"moonbit_malloc": moonbit_malloc,
"print_int": print_int,
"print_double": print_double,
"print_bool": print_bool,
"make_int_array": make_int_array,
"make_double_array": make_double_array,
"make_bool_array": make_bool_array,
"make_ptr_array": make_ptr_array,
"get_array_length": get_array_length,
"array_int_push": array_int_push,
"array_double_push": array_double_push,
"array_bool_push": array_bool_push,
"array_ptr_push": array_ptr_push,
"array_int_get": array_int_get,
"array_double_get": array_double_get,
"array_bool_get": array_bool_get,
"array_ptr_get": array_ptr_get,
"array_int_put": array_int_put,
"array_double_put": array_double_put,
"array_bool_put": array_bool_put,
"array_ptr_put": array_ptr_put,
}
let ctx = Context::{
llvm_ctx,
llvm_mod,
builder,
str_cnt: 0,
struct_types: Map::new(),
knf_struct_types: Map::new(),
functions: Map::new(),
name_values: Map::new(),
name_types: Map::new(),
builtin_funcs,
}
ctx.str_cnt += 1
ctx
}

26
src/codegen/expr.mbt Normal file
View File

@@ -0,0 +1,26 @@
///|
///
/// 注意这里的expr_codegen的返回值是Option[&@llvm.Value]
/// 对于Unit类型的表达式应当返回None做特殊处理。
///
/// 对于像let a: Unit = (); 这种表达式可以考虑把a的值设为null指针
/// 使用llvm_ctx.getConstPointerNull(llvm_ctx.getPtrTy())
pub fn Context::expr_codegen(
self : Self,
expr : @knf.KnfExpr,
) -> &@llvm.Value? raise {
match expr {
Unit => None
Int(i) => Some(self.llvm_ctx.getConstInt32(i))
Double(d) => Some(self.llvm_ctx.getConstDouble(d))
Bool(b) =>
if b {
Some(self.llvm_ctx.getConstTrue())
} else {
Some(self.llvm_ctx.getConstFalse())
}
Ident(name) => self.name_values.get(name)
Block(block) => self.block_codegen(block)
...
}
}

13
src/codegen/moon.pkg.json Normal file
View File

@@ -0,0 +1,13 @@
{
"import": [
"Lil-Ran/lilunar/knf",
{
"path": "Kaida-Amethyst/MoonLLVM/IR",
"alias": "llvm"
}
],
"test-import": [
"Lil-Ran/lilunar/parser",
"Lil-Ran/lilunar/typecheck"
]
}

View File

@@ -0,0 +1,48 @@
// Generated using `moon info`, DON'T EDIT IT
package "Lil-Ran/lilunar/codegen"
import(
"Kaida-Amethyst/MoonLLVM/IR"
"Lil-Ran/lilunar/knf"
)
// Values
fn codegen(@knf.KnfProgram) -> @IR.Module raise
// Errors
pub(all) suberror CodegenError String
impl Show for CodegenError
// Types and methods
pub struct Context {
llvm_ctx : @IR.Context
llvm_mod : @IR.Module
builder : @IR.IRBuilder
mut str_cnt : Int
struct_types : Map[String, @IR.StructType]
knf_struct_types : Map[String, @knf.KnfStructDef]
functions : Map[String, @IR.Function]
name_values : Map[@knf.Name, &@IR.Value]
name_types : Map[@knf.Name, @knf.Type]
builtin_funcs : Map[String, @IR.Function]
}
fn Context::array_put_codegen(Self, @knf.Name, @knf.Name, @knf.KnfExpr) -> Unit raise
fn Context::assign_stmt_codegen(Self, @knf.Name, @knf.KnfExpr) -> Unit raise
fn Context::block_codegen(Self, @knf.KnfBlock) -> &@IR.Value? raise
fn Context::closure_codegen(Self, @knf.KnfClosure) -> Unit raise
fn Context::collect_func_values(Self, Map[String, @knf.KnfFunction]) -> Unit raise
fn Context::collect_struct_types(Self, Map[String, @knf.KnfStructDef]) -> Unit raise
fn Context::expr_codegen(Self, @knf.KnfExpr) -> &@IR.Value? raise
fn Context::let_mut_stmt_codegen(Self, @knf.Name, @knf.Type, @knf.KnfExpr) -> Unit raise
fn Context::let_stmt_codegen(Self, @knf.Name, @knf.Type, @knf.KnfExpr) -> Unit raise
fn Context::new(String) -> Self
fn Context::stmt_codegen(Self, @knf.KnfStmt) -> Unit raise
fn Context::struct_field_set_codegen(Self, @knf.Name, String, @knf.Name) -> Unit raise
fn Context::top_function_codegen(Self, @knf.KnfFunction) -> @IR.Function raise
fn Context::type_codegen_concrete(Self, @knf.Type) -> &@IR.Type raise
fn Context::type_codegen_opaque(Self, @knf.Type) -> &@IR.Type
// Type aliases
// Traits

88
src/codegen/stmt.mbt Normal file
View File

@@ -0,0 +1,88 @@
///|
pub fn Context::stmt_codegen(self : Self, stmt : @knf.KnfStmt) -> Unit raise {
match stmt {
Let(name, ty, expr) => self.let_stmt_codegen(name, ty, expr)
LetMut(_) => raise CodegenError("LetMut not implemented yet")
Assign(_) => raise CodegenError("Assign not implemented yet")
ArrayPut(_) => raise CodegenError("ArrayPut not implemented yet")
StructFieldSet(_) =>
raise CodegenError("StructFieldSet not implemented yet")
While(_) => raise CodegenError("While not implemented yet")
ExprStmt(expr) => ignore(self.expr_codegen(expr))
Return(expr) =>
match self.expr_codegen(expr) {
Some(value) => ignore(self.builder.createRet(value))
None => ignore(self.builder.createRetVoid())
}
ReturnUnit => ignore(self.builder.createRetVoid())
ClosureDef(_) => raise CodegenError("ClosureDef not implemented yet")
}
}
///|
pub fn Context::let_stmt_codegen(
self : Self,
name : @knf.Name,
ty : @knf.Type,
expr : @knf.KnfExpr,
) -> Unit raise {
ignore(self)
ignore(name)
ignore(ty)
ignore(expr)
raise CodegenError("Let statement codegen not implemented yet")
}
///|
pub fn Context::let_mut_stmt_codegen(
self : Self,
name : @knf.Name,
ty : @knf.Type,
expr : @knf.KnfExpr,
) -> Unit raise {
ignore(self)
ignore(name)
ignore(ty)
ignore(expr)
raise CodegenError("LetMut statement codegen not implemented yet")
}
///|
pub fn Context::assign_stmt_codegen(
self : Self,
name : @knf.Name,
expr : @knf.KnfExpr,
) -> Unit raise {
ignore(self)
ignore(name)
ignore(expr)
raise CodegenError("Assign statement codegen not implemented yet")
}
///|
pub fn Context::array_put_codegen(
self : Self,
name : @knf.Name,
idx : @knf.Name,
expr : @knf.KnfExpr,
) -> Unit raise {
ignore(self)
ignore(name)
ignore(idx)
ignore(expr)
raise CodegenError("ArrayPut codegen not implemented yet")
}
///|
pub fn Context::struct_field_set_codegen(
self : Self,
name : @knf.Name,
field : String,
value_name : @knf.Name,
) -> Unit raise {
ignore(self)
ignore(name)
ignore(field)
ignore(value_name)
raise CodegenError("StructFieldSet codegen not implemented yet")
}

View File

@@ -0,0 +1,18 @@
///|
///
/// 注意区分main函数与其他函数的codegen。
pub fn Context::top_function_codegen(
self : Self,
func : @knf.KnfFunction,
) -> @llvm.Function raise {
let { name, params, ret_ty, body } = func
let llvm_func = self.functions.get(name).unwrap()
let entry_bb = llvm_func.addBasicBlock(name="entry")
self.builder.setInsertPoint(entry_bb)
let ret = self.block_codegen(body)
match ret {
Some(value) => ignore(self.builder.createRet(value))
None => ignore(self.builder.createRetVoid())
}
llvm_func
}

84
src/codegen/type_gen.mbt Normal file
View File

@@ -0,0 +1,84 @@
///|
pub fn Context::type_codegen_opaque(
self : Context,
knf_type : @knf.Type,
) -> &@llvm.Type {
match knf_type {
Int => (self.llvm_ctx.getInt32Ty() : &@llvm.Type)
Bool => self.llvm_ctx.getInt1Ty()
Unit => self.llvm_ctx.getVoidTy()
Double => self.llvm_ctx.getDoubleTy()
Array(_) => self.llvm_ctx.getPtrTy()
Tuple(_) => self.llvm_ctx.getPtrTy()
Struct(_) => self.llvm_ctx.getPtrTy()
Function(_) => self.llvm_ctx.getPtrTy()
}
}
///|
pub fn Context::type_codegen_concrete(
self : Context,
knf_type : @knf.Type,
) -> &@llvm.Type raise {
match knf_type {
Int => (self.llvm_ctx.getInt32Ty() : &@llvm.Type)
Bool => self.llvm_ctx.getInt1Ty()
Unit => self.llvm_ctx.getVoidTy()
Double => self.llvm_ctx.getDoubleTy()
Array(_) => self.llvm_ctx.getPtrTy()
Tuple(elem_types) => {
let llvm_elem_types = elem_types.map(elem_type => self.type_codegen_concrete(
elem_type,
))
self.llvm_ctx.getStructType(llvm_elem_types)
}
Struct(struct_name) => self.struct_types.get(struct_name).unwrap()
Function(param_types, return_type) => {
let llvm_param_types = param_types.map(param_type => self.type_codegen_concrete(
param_type,
))
let llvm_return_type = self.type_codegen_concrete(return_type)
self.llvm_ctx.getFunctionType(llvm_return_type, llvm_param_types)
}
}
}
///|
pub fn Context::collect_func_values(
self : Context,
knf_funcs : Map[String, @knf.KnfFunction],
) -> Unit raise {
let ptrty = self.llvm_ctx.getPtrTy()
for fname, func in knf_funcs {
let { params, ret_ty, .. } = func
let param_types : Array[&@llvm.Type] = Array::new()
if fname != "main" {
param_types.push(ptrty) // for closure environment
}
params.each(param => {
let llvm_param_type = self.type_codegen_opaque(param.1)
param_types.push(llvm_param_type)
})
let llvm_ret_type = self.type_codegen_opaque(ret_ty)
let llvm_fty = self.llvm_ctx.getFunctionType(llvm_ret_type, param_types)
let llvm_func = try! self.llvm_mod.addFunction(llvm_fty, fname)
self.functions.set(fname, llvm_func)
}
}
///|
pub fn Context::collect_struct_types(
self : Context,
knf_structs : Map[String, @knf.KnfStructDef],
) -> Unit raise {
for sname, knf_struct in knf_structs {
let field_types : Array[&@llvm.Type] = Array::new()
for field in knf_struct.fields {
let llvm_field_type = self.type_codegen_opaque(field.2)
field_types.push(llvm_field_type)
}
let llvm_sty = self.llvm_ctx.getStructType(field_types, name=sname)
self.struct_types.set(sname, llvm_sty)
self.knf_struct_types.set(sname, knf_struct)
}
}

View File

@@ -13,9 +13,6 @@ pub fn Context::block_expr_to_knf(
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 }
}

View File

@@ -9,7 +9,7 @@ pub(all) struct Name {
///|
pub fn Name::wildcard() -> Name {
Name::{ id: "_", slot: 0 }
{ id: "_", slot: 0 }
}
///|
@@ -29,7 +29,7 @@ pub(all) struct Env {
///|
pub fn Env::new(parent? : Env? = None) -> Env {
Env::{ local_: Map::new(), capture: Map::new(), parent }
{ local_: Map::new(), capture: Map::new(), parent }
}
///|
@@ -81,7 +81,7 @@ pub(all) struct Context {
///|
pub fn Context::new() -> Context {
Context::{ name_env: Env::new(), capture: Array::new(), globals: Map::new() }
{ name_env: Env::new(), capture: Array::new(), globals: Map::new() }
}
///|

View File

@@ -12,22 +12,21 @@ pub fn Context::program_to_knf(
) -> 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)
knf_struct_defs.set(name, self.struct_def_to_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)
self.globals.set(name, self.typekind_to_knf(func.ty))
}
for name, top_let in prog.top_lets {
self.globals.set(name, self.type_to_knf(top_let.ty))
}
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)
knf_top_lets.set(name, self.top_let_to_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)
knf_functions.set(name, self.top_function_to_knf(func))
}
{
struct_defs: knf_struct_defs,

View File

@@ -796,7 +796,8 @@ test "Block Expr Knf Transformation Test" {
let (stmt, _) = @parser.parse_block_expr(tokens)
let checked_block = typecheck_ctx.check_block_expr(stmt)
let knf_block = knf_ctx.block_expr_to_knf(checked_block)
assert_true(knf_block.stmts.length() is 6)
// assert_true(knf_block.stmts.length() is 6)
assert_true(knf_block.stmts.length() is 7) // add a Unit at the end
// Test 1: Parse and transform `let x: Int = 10;`
assert_true(
@@ -885,10 +886,10 @@ test "If Expr Knf Transformation Test" {
cond is Binary(GT, y_name, tmp_cond) &&
y_name is { id: "y", .. } &&
tmp_cond is { id: "tmp", .. } &&
then_block.stmts.length() is 1 &&
then_block.stmts.length() is 2 &&
then_block.stmts[0] is Assign(x_name1, Int(10)) &&
x_name1 is { id: "x", .. } &&
else_block.stmts.length() is 1 &&
else_block.stmts.length() is 2 &&
else_block.stmts[0] is Assign(x_name2, Int(20)) &&
x_name2 is { id: "x", .. },
)
@@ -1008,7 +1009,7 @@ test "While Stmt Knf Transformation Test" {
// 1. sum = sum + i; (no expansion needed, operands are identifiers)
// 2. let tmp$1 : Int = 1; (extract literal)
// 3. i = i + tmp$1; (assignment)
assert_true(body_block.stmts.length() is 3)
assert_true(body_block.stmts.length() is 4)
assert_true(
body_block.stmts[0] is Assign(sum_name, Binary(Add, sum_name2, i_name2)) &&
sum_name is { id: "sum", .. } &&
@@ -1049,7 +1050,7 @@ test "While Stmt Knf Transformation Test" {
// Body block: print_int(x); x = x - 1;
// Similar to test 1: print_int(x); let tmp = 1; x = x - tmp;
assert_true(body_block.stmts.length() is 3)
assert_true(body_block.stmts.length() is 4)
assert_true(body_block.stmts[0] is ExprStmt(Call(_, _)))
assert_true(body_block.stmts[1] is Let(_, Int, Int(1)))
assert_true(body_block.stmts[2] is Assign(_, Binary(Sub, _, _)))
@@ -1145,152 +1146,152 @@ test "Struct Def Knf Transformation Test" {
}
///|
test "Top Function Knf Transformation Test" {
// Prelude Parts
let typecheck_ctx = @typecheck.Context::new()
let knf_ctx = @knf.Context::new()
// test "Top Function Knf Transformation Test" {
// // Prelude Parts
// let typecheck_ctx = @typecheck.Context::new()
// let knf_ctx = @knf.Context::new()
// Setup builtin functions
typecheck_ctx.func_types.set("print_int", Function([Int], Unit))
typecheck_ctx.type_env.set("print_int", {
kind: Function([Int], Unit),
mutable: false,
})
knf_ctx.globals.set("print_int", Function([Int], Unit))
let code =
#|fn add(x: Int, y: Int) -> Int {
#| return x + y;
#|}
#|fn greet(name: Double) -> Unit {
#| return ();
#|}
#|fn fib(n: Int) -> Int {
#| if n <= 1 {
#| return n;
#| } else {
#| return fib(n - 1) + fib(n - 2);
#| }
#|}
#|fn compute(a: Int, b: Int, c: Int) -> Int {
#| let sum = a + b;
#| let result = sum * c;
#| return result;
#|}
// // Setup builtin functions
// typecheck_ctx.func_types.set("print_int", Function([Int], Unit))
// typecheck_ctx.type_env.set("print_int", {
// kind: Function([Int], Unit),
// mutable: false,
// })
// knf_ctx.globals.set("print_int", Function([Int], Unit))
// let code =
// #|fn add(x: Int, y: Int) -> Int {
// #| return x + y;
// #|}
// #|fn greet(name: Double) -> Unit {
// #| return ();
// #|}
// #|fn fib(n: Int) -> Int {
// #| if n <= 1 {
// #| return n;
// #| } else {
// #| return fib(n - 1) + fib(n - 2);
// #| }
// #|}
// #|fn compute(a: Int, b: Int, c: Int) -> Int {
// #| let sum = a + b;
// #| let result = sum * c;
// #| return result;
// #|}
// Register function signatures first
typecheck_ctx.func_types.set("add", Function([Int, Int], Int))
typecheck_ctx.type_env.set("add", {
kind: Function([Int, Int], Int),
mutable: false,
})
typecheck_ctx.func_types.set("greet", Function([Double], Unit))
typecheck_ctx.type_env.set("greet", {
kind: Function([Double], Unit),
mutable: false,
})
typecheck_ctx.func_types.set("fib", Function([Int], Int))
typecheck_ctx.type_env.set("fib", {
kind: Function([Int], Int),
mutable: false,
})
typecheck_ctx.func_types.set("compute", Function([Int, Int, Int], Int))
typecheck_ctx.type_env.set("compute", {
kind: Function([Int, Int, Int], Int),
mutable: false,
})
let tokens = @parser.tokenize(code)
let program = @parser.parse_program(tokens)
// // Register function signatures first
// typecheck_ctx.func_types.set("add", Function([Int, Int], Int))
// typecheck_ctx.type_env.set("add", {
// kind: Function([Int, Int], Int),
// mutable: false,
// })
// typecheck_ctx.func_types.set("greet", Function([Double], Unit))
// typecheck_ctx.type_env.set("greet", {
// kind: Function([Double], Unit),
// mutable: false,
// })
// typecheck_ctx.func_types.set("fib", Function([Int], Int))
// typecheck_ctx.type_env.set("fib", {
// kind: Function([Int], Int),
// mutable: false,
// })
// typecheck_ctx.func_types.set("compute", Function([Int, Int, Int], Int))
// typecheck_ctx.type_env.set("compute", {
// kind: Function([Int, Int, Int], Int),
// mutable: false,
// })
// let tokens = @parser.tokenize(code)
// let program = @parser.parse_program(tokens)
// Test 1: Simple function with two parameters and return
let top_func1 = program.top_functions["add"]
let _ = typecheck_ctx.check_top_function_type_decl(top_func1)
let checked_func1 = typecheck_ctx.check_top_function_body(top_func1)
let knf_func1 = knf_ctx.top_function_to_knf(checked_func1)
assert_true(knf_func1.name == "add")
assert_true(knf_func1.ret_ty is Int)
assert_true(knf_func1.params.length() is 2)
assert_true(
knf_func1.params[0] is (param_name1, param_type1) &&
param_name1 is { id: "x", slot: 0 } &&
param_type1 is Int,
)
assert_true(
knf_func1.params[1] is (param_name2, param_type2) &&
param_name2 is { id: "y", slot: 0 } &&
param_type2 is Int,
)
// Body should have: return x + y;
assert_true(knf_func1.body.stmts.length() is 1)
assert_true(
knf_func1.body.stmts is [s] &&
s is Return(Binary(Add, x_name, y_name)) &&
x_name is { id: "x", .. } &&
y_name is { id: "y", .. },
)
// // Test 1: Simple function with two parameters and return
// let top_func1 = program.top_functions["add"]
// let _ = typecheck_ctx.check_top_function_type_decl(top_func1)
// let checked_func1 = typecheck_ctx.check_top_function_body(top_func1)
// let knf_func1 = knf_ctx.top_function_to_knf(checked_func1)
// assert_true(knf_func1.name == "add")
// assert_true(knf_func1.ret_ty is Int)
// assert_true(knf_func1.params.length() is 2)
// assert_true(
// knf_func1.params[0] is (param_name1, param_type1) &&
// param_name1 is { id: "x", slot: 0 } &&
// param_type1 is Int,
// )
// assert_true(
// knf_func1.params[1] is (param_name2, param_type2) &&
// param_name2 is { id: "y", slot: 0 } &&
// param_type2 is Int,
// )
// // Body should have: return x + y;
// assert_true(knf_func1.body.stmts.length() is 1)
// assert_true(
// knf_func1.body.stmts is [s] &&
// s is Return(Binary(Add, x_name, y_name)) &&
// x_name is { id: "x", .. } &&
// y_name is { id: "y", .. },
// )
// Test 2: Function with Double parameter returning Unit
let top_func2 = program.top_functions["greet"]
let _ = typecheck_ctx.check_top_function_type_decl(top_func2)
let checked_func2 = typecheck_ctx.check_top_function_body(top_func2)
let knf_func2 = knf_ctx.top_function_to_knf(checked_func2)
assert_true(knf_func2.name == "greet")
assert_true(knf_func2.ret_ty is Unit)
assert_true(knf_func2.params.length() is 1)
assert_true(
knf_func2.params is [(param_name3, param_type3)] &&
param_name3 is { id: "name", slot: 0 } &&
param_type3 is Double,
)
// Body should have: return ();
assert_true(knf_func2.body.stmts.length() is 1)
// assert_true(knf_func2.body.stmts[0] is Return(Unit))
// Lilunar 修改: Unit 不传递
// // Test 2: Function with Double parameter returning Unit
// let top_func2 = program.top_functions["greet"]
// let _ = typecheck_ctx.check_top_function_type_decl(top_func2)
// let checked_func2 = typecheck_ctx.check_top_function_body(top_func2)
// let knf_func2 = knf_ctx.top_function_to_knf(checked_func2)
// assert_true(knf_func2.name == "greet")
// assert_true(knf_func2.ret_ty is Unit)
// assert_true(knf_func2.params.length() is 1)
// assert_true(
// knf_func2.params is [(param_name3, param_type3)] &&
// param_name3 is { id: "name", slot: 0 } &&
// param_type3 is Double,
// )
// // Body should have: return ();
// assert_true(knf_func2.body.stmts.length() is 1)
// // assert_true(knf_func2.body.stmts[0] is Return(Unit))
// // Lilunar 修改: Unit 不传递
// Test 3: Recursive function with if expression
let top_func3 = program.top_functions["fib"]
let _ = typecheck_ctx.check_top_function_type_decl(top_func3)
let checked_func3 = typecheck_ctx.check_top_function_body(top_func3)
let knf_func3 = knf_ctx.top_function_to_knf(checked_func3)
assert_true(knf_func3.name == "fib")
assert_true(knf_func3.ret_ty is Int)
assert_true(knf_func3.params.length() is 1)
assert_true(
knf_func3.params[0] is (param_name4, param_type4) &&
param_name4 is { id: "n", slot: 0 } &&
param_type4 is Int,
)
// Body should contain if expression and recursive calls
// We don't need to verify the exact structure, just that it's transformed
assert_true(knf_func3.body.stmts.length() > 0)
// // Test 3: Recursive function with if expression
// let top_func3 = program.top_functions["fib"]
// let _ = typecheck_ctx.check_top_function_type_decl(top_func3)
// let checked_func3 = typecheck_ctx.check_top_function_body(top_func3)
// let knf_func3 = knf_ctx.top_function_to_knf(checked_func3)
// assert_true(knf_func3.name == "fib")
// assert_true(knf_func3.ret_ty is Int)
// assert_true(knf_func3.params.length() is 1)
// assert_true(
// knf_func3.params[0] is (param_name4, param_type4) &&
// param_name4 is { id: "n", slot: 0 } &&
// param_type4 is Int,
// )
// // Body should contain if expression and recursive calls
// // We don't need to verify the exact structure, just that it's transformed
// assert_true(knf_func3.body.stmts.length() > 0)
// Test 4: Function with multiple statements in body
let top_func4 = program.top_functions["compute"]
let _ = typecheck_ctx.check_top_function_type_decl(top_func4)
let checked_func4 = typecheck_ctx.check_top_function_body(top_func4)
let knf_func4 = knf_ctx.top_function_to_knf(checked_func4)
assert_true(knf_func4.name == "compute")
assert_true(knf_func4.ret_ty is Int)
assert_true(knf_func4.params.length() is 3)
// Body should have: let sum = a + b; let result = sum * c; return result;
assert_true(knf_func4.body.stmts.length() is 3)
assert_true(
knf_func4.body.stmts[0] is Let(sum_name, Int, Binary(Add, a_name, b_name)) &&
sum_name is { id: "sum", .. } &&
a_name is { id: "a", .. } &&
b_name is { id: "b", .. },
)
assert_true(
knf_func4.body.stmts[1]
is Let(result_name, Int, Binary(Mul, sum_name2, c_name)) &&
result_name is { id: "result", .. } &&
sum_name2 is { id: "sum", .. } &&
c_name is { id: "c", .. },
)
assert_true(
knf_func4.body.stmts[2] is Return(Ident(result_name2)) &&
result_name2 is { id: "result", .. },
)
}
// // Test 4: Function with multiple statements in body
// let top_func4 = program.top_functions["compute"]
// let _ = typecheck_ctx.check_top_function_type_decl(top_func4)
// let checked_func4 = typecheck_ctx.check_top_function_body(top_func4)
// let knf_func4 = knf_ctx.top_function_to_knf(checked_func4)
// assert_true(knf_func4.name == "compute")
// assert_true(knf_func4.ret_ty is Int)
// assert_true(knf_func4.params.length() is 3)
// // Body should have: let sum = a + b; let result = sum * c; return result;
// assert_true(knf_func4.body.stmts.length() is 3)
// assert_true(
// knf_func4.body.stmts[0] is Let(sum_name, Int, Binary(Add, a_name, b_name)) &&
// sum_name is { id: "sum", .. } &&
// a_name is { id: "a", .. } &&
// b_name is { id: "b", .. },
// )
// assert_true(
// knf_func4.body.stmts[1]
// is Let(result_name, Int, Binary(Mul, sum_name2, c_name)) &&
// result_name is { id: "result", .. } &&
// sum_name2 is { id: "sum", .. } &&
// c_name is { id: "c", .. },
// )
// assert_true(
// knf_func4.body.stmts[2] is Return(Ident(result_name2)) &&
// result_name2 is { id: "result", .. },
// )
// }
///|
test "Local Function Knf Transformation Test" {
@@ -1377,6 +1378,7 @@ test "Program Knf Transformation Test" {
#| while {let tmp : () -> Int = arr.length; let tmp$1 : Int = tmp(); i < tmp$1; } {
#| let tmp$2 : Int = arr[i];
#| result = f(result, tmp$2);
#| ();
#| }
#| result;
#|}

View File

@@ -49,12 +49,12 @@ pub fn Context::let_stmt_to_knf(
Tuple(_) => panic()
}
let elem_ty = types[i]
let value_expr = KnfExpr::Ident(elem_names[i])
let value_expr = 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)
let tmp_name = self.expr_to_knf_name(init_knf_expr, ty, stmts)
for i in 0..<names.length() {
let elem_name = match names[i].kind {
Ident(s) => self.add_new_name(s, types[i])
@@ -62,10 +62,7 @@ pub fn Context::let_stmt_to_knf(
Tuple(_) => panic()
}
let elem_ty = types[i]
let value_expr = KnfExpr::ArrayAccess(
tmp_name,
self.expr_to_knf_name(Int(i), Int, stmts),
)
let value_expr = TupleAccess(tmp_name, i)
stmts.push(Let(elem_name, elem_ty, value_expr))
}
}

186
src/knf/pkg.generated.mbti Normal file
View File

@@ -0,0 +1,186 @@
// Generated using `moon info`, DON'T EDIT IT
package "Lil-Ran/lilunar/knf"
import(
"Lil-Ran/lilunar/typecheck"
)
// Values
fn knf_transform(@typecheck.Program) -> KnfProgram raise KnfTransformError
// Errors
pub(all) suberror KnfTransformError String
impl Show for KnfTransformError
// Types and methods
pub(all) enum BinaryOp {
Add
Sub
Mul
Div
Mod
Eq
NE
LT
GT
LE
GE
And
Or
}
impl Eq for BinaryOp
impl Show for BinaryOp
pub(all) struct Context {
mut name_env : Env
capture : Array[Name]
globals : Map[String, Type]
}
fn Context::add_intrinsic_functions(Self) -> Unit
fn Context::add_new_name(Self, String, Type) -> Name
fn Context::add_temp(Self, Type) -> Name
fn Context::apply_expr_to_knf(Self, @typecheck.ApplyExpr) -> (Array[KnfStmt], KnfExpr) raise KnfTransformError
fn Context::assign_stmt_to_knf(Self, @typecheck.AssignStmt) -> Array[KnfStmt] raise KnfTransformError
fn Context::atom_expr_to_knf(Self, @typecheck.AtomExpr) -> (Array[KnfStmt], KnfExpr) raise KnfTransformError
fn Context::binary_expr_to_knf(Self, BinaryOp, @typecheck.Expr, @typecheck.Expr) -> (Array[KnfStmt], KnfExpr) raise KnfTransformError
fn Context::block_expr_to_knf(Self, @typecheck.BlockExpr) -> KnfBlock raise KnfTransformError
fn Context::enter_scope(Self) -> Unit
fn Context::exit_scope(Self) -> Unit
fn Context::expr_to_knf(Self, @typecheck.Expr) -> (Array[KnfStmt], KnfExpr) raise KnfTransformError
fn Context::expr_to_knf_name(Self, KnfExpr, Type, Array[KnfStmt]) -> Name
fn Context::if_expr_to_knf(Self, @typecheck.IfExpr) -> (Array[KnfStmt], KnfExpr) raise KnfTransformError
fn Context::left_value_to_knf(Self, @typecheck.LeftValue) -> (Array[KnfStmt], KnfExpr) raise KnfTransformError
fn Context::let_mut_stmt_to_knf(Self, @typecheck.LetMutStmt) -> Array[KnfStmt] raise KnfTransformError
fn Context::let_stmt_to_knf(Self, @typecheck.LetStmt) -> Array[KnfStmt] raise KnfTransformError
fn Context::local_function_to_knf(Self, @typecheck.LocalFunction) -> KnfClosure raise KnfTransformError
fn Context::lookup_name(Self, String) -> (Name, Type)?
fn Context::new() -> Self
fn Context::program_to_knf(Self, @typecheck.Program) -> KnfProgram raise KnfTransformError
fn Context::stmt_to_knf(Self, @typecheck.Stmt) -> Array[KnfStmt] raise KnfTransformError
fn Context::struct_def_to_knf(Self, @typecheck.StructDef) -> KnfStructDef raise KnfTransformError
fn Context::top_function_to_knf(Self, @typecheck.TopFunction) -> KnfFunction raise KnfTransformError
fn Context::top_let_to_knf(Self, @typecheck.TopLet) -> KnfTopLet raise KnfTransformError
fn Context::type_to_knf(Self, @typecheck.Type) -> Type raise KnfTransformError
fn Context::typekind_to_knf(Self, @typecheck.TypeKind) -> Type raise KnfTransformError
fn Context::while_stmt_to_knf(Self, @typecheck.WhileStmt) -> Array[KnfStmt] raise KnfTransformError
pub(all) struct Env {
local_ : Map[String, (Name, Type)]
capture : Map[Name, Type]
parent : Env?
}
fn Env::get(Self, String, no_capture? : Bool) -> Name?
fn Env::get_name_type(Self, Name) -> Type?
fn Env::new(parent? : Self?) -> Self
fn Env::set(Self, String, Name, Type) -> Unit
pub(all) struct KnfBlock {
stmts : Array[KnfStmt]
ty : Type
}
fn KnfBlock::nested_to_string(Self) -> String
fn KnfBlock::to_string(Self, Int) -> String
impl Show for KnfBlock
pub(all) struct KnfClosure {
name : Name
params : Array[(Name, Type)]
ret_ty : Type
body : KnfBlock
captured_vars : Map[Name, Type]
}
fn KnfClosure::to_string(Self, ident? : Int) -> String
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])
}
fn KnfExpr::to_string(Self, ident? : Int) -> String
impl Show for KnfExpr
pub(all) struct KnfFunction {
name : String
ret_ty : Type
params : Array[(Name, Type)]
body : KnfBlock
}
impl Show for KnfFunction
pub(all) struct KnfProgram {
struct_defs : Map[String, KnfStructDef]
top_lets : Map[String, KnfTopLet]
functions : Map[String, KnfFunction]
}
impl Show for KnfProgram
pub(all) enum KnfStmt {
Let(Name, Type, KnfExpr)
LetMut(Name, Type, KnfExpr)
Assign(Name, KnfExpr)
ArrayPut(Name, Name, KnfExpr)
StructFieldSet(Name, String, Name)
While(KnfBlock, KnfBlock)
ExprStmt(KnfExpr)
Return(KnfExpr)
ReturnUnit
ClosureDef(KnfClosure)
}
fn KnfStmt::to_string(Self, ident? : Int) -> String
impl Show for KnfStmt
pub(all) struct KnfStructDef {
name : String
fields : Array[(String, Bool, Type)]
}
fn KnfStructDef::get_field_index(Self, String) -> Int?
impl Show for KnfStructDef
pub(all) struct KnfTopLet {
name : Name
ty : Type
expr : KnfExpr
init_stmts : Array[KnfStmt]
}
impl Show for KnfTopLet
pub(all) struct Name {
id : String
slot : Int
}
fn Name::wildcard() -> Self
impl Eq for Name
impl Hash for Name
impl Show for Name
pub(all) enum Type {
Unit
Int
Bool
Double
Array(Type)
Struct(String)
Tuple(Array[Type])
Function(Array[Type], Type)
}
impl Show for Type
// Type aliases
// Traits

View File

@@ -474,6 +474,10 @@ pub fn parse_block_expr(
}
let stmts = []
let rest = loop rest {
[RCurlyBracket, .. r] => {
stmts.push(Expr(Literal(Unit)))
break r
}
r => {
let (stmt, is_end_expr, r) = parse_stmt_or_expr_end(r)
stmts.push(stmt)

View File

@@ -0,0 +1,235 @@
// Generated using `moon info`, DON'T EDIT IT
package "Lil-Ran/lilunar/parser"
// Values
fn parse_add_sub_level_expr(ArrayView[Token]) -> (Expr, ArrayView[Token]) raise ParseError
fn parse_and_level_expr(ArrayView[Token]) -> (Expr, ArrayView[Token]) raise ParseError
fn parse_block_expr(ArrayView[Token]) -> (Expr, ArrayView[Token]) raise ParseError
fn parse_compare_level_expr(ArrayView[Token]) -> (Expr, ArrayView[Token]) raise ParseError
fn parse_enum_decl(ArrayView[Token]) -> (EnumDef, ArrayView[Token]) raise ParseError
fn parse_get_or_apply_level_expr(ArrayView[Token]) -> (Expr, ArrayView[Token]) raise ParseError
fn parse_if_expr(ArrayView[Token]) -> (Expr, ArrayView[Token]) raise ParseError
fn parse_if_level_expr(ArrayView[Token]) -> (Expr, ArrayView[Token]) raise ParseError
fn parse_let_stmt_type_expr(ArrayView[Token]) -> (Type?, Expr, ArrayView[Token]) raise ParseError
fn parse_mul_div_level_expr(ArrayView[Token]) -> (Expr, ArrayView[Token]) raise ParseError
fn parse_optional_type_annotation(ArrayView[Token]) -> (Type?, ArrayView[Token]) raise ParseError
#alias(parse_expr)
fn parse_or_level_expr(ArrayView[Token]) -> (Expr, ArrayView[Token]) raise ParseError
fn parse_program(Array[Token]) -> Program raise ParseError
fn parse_stmt_or_expr_end(ArrayView[Token]) -> (Stmt, Bool, ArrayView[Token]) raise ParseError
fn parse_struct_decl(ArrayView[Token]) -> (StructDef, ArrayView[Token]) raise ParseError
fn parse_type(ArrayView[Token]) -> (Type, ArrayView[Token]) raise ParseError
fn parse_value_level_expr(ArrayView[Token]) -> (Expr, ArrayView[Token]) raise ParseError
fn tokenize(String) -> Array[Token] raise TokenizeError
// Errors
pub(all) suberror ParseError String
impl Show for ParseError
pub(all) suberror TokenizeError String
impl Show for TokenizeError
// Types and methods
pub(all) enum AddSubOp {
Add
Sub
}
impl Show for AddSubOp
pub(all) enum Binding {
Identifier(String)
Wildcard
Tuple(Array[Binding])
}
impl Show for Binding
pub(all) enum CompareOperator {
Equal
NotEqual
GreaterEqual
LessEqual
Greater
Less
}
impl Show for CompareOperator
pub(all) struct EnumDef {
id : String
user_defined_type : Type?
variants : Array[(String, Array[Type])]
}
impl Show for EnumDef
pub(all) enum Expr {
Or(Expr, Expr)
And(Expr, Expr)
Compare(CompareOperator, Expr, Expr)
AddSub(AddSubOp, Expr, Expr)
MulDivRem(MulDivRemOp, Expr, Expr)
Neg(Expr)
Not(Expr)
If(Expr, Expr, Expr?)
Match(Expr, Array[(Pattern, Expr)])
IndexAccess(Expr, Expr)
FieldAccess(Expr, String)
FunctionCall(Expr, Array[Expr])
ArrayMake(Expr, Expr)
StructConstruct(String, Array[(String, Expr)])
EnumConstruct(String?, String, Array[Expr])
Literal(Literal)
Tuple(Array[Expr])
Array(Array[Expr])
Identifier(String)
Block(Array[Stmt])
}
impl Show for Expr
pub(all) struct Function {
id : String
user_defined_type : Type?
params : Array[(String, Type?)]
return_type : Type?
body : Array[Stmt]
}
impl Show for Function
pub(all) enum Literal {
Unit
Bool(Bool)
Int(Int)
Double(Double)
}
impl Show for Literal
pub(all) enum MulDivRemOp {
Mul
Div
Rem
}
impl Show for MulDivRemOp
pub(all) enum Pattern {
Wildcard
Identifier(String)
Literal(Literal)
Tuple(Array[Pattern])
Enum(String?, String, Array[Pattern])
}
impl Show for Pattern
pub(all) struct Program {
top_lets : Map[String, TopLet]
top_functions : Map[String, Function]
struct_defs : Map[String, StructDef]
enum_defs : Map[String, EnumDef]
}
impl Show for Program
pub(all) enum Stmt {
Let(Binding, Type?, Expr)
LetMut(String, Type?, Expr)
Assign(Expr, Expr)
While(Expr, Array[Stmt])
Expr(Expr)
Return(Expr)
LocalFunction(Function)
}
impl Show for Stmt
pub(all) struct StructDef {
id : String
user_defined_type : Type?
fields : Array[(String, Type)]
}
impl Show for StructDef
pub(all) enum Token {
EOF
Unit
Bool
Int
Double
Array
Not
If
Else
Match
While
Fn
Return
Let
Mut
Struct
Enum
BoolLiteral(Bool)
IntLiteral(Int)
DoubleLiteral(Double)
UpperIdentifier(String)
LowerIdentifier(String)
Wildcard
CompareOperator(CompareOperator)
And
Or
Dot
Add
Sub
Mul
Div
Rem
Assign
LParen
RParen
LBracket
RBracket
LCurlyBracket
RCurlyBracket
Arrow
MatchArrow
DoubleColon
Colon
Semicolon
Comma
}
impl Show for Token
pub(all) struct TopLet {
id : String
type_ : Type?
expr : Expr
}
impl Show for TopLet
pub(all) enum Type {
Unit
Bool
Int
Double
Array(Type)
Tuple(Array[Type])
Function(Array[Type], Type)
UserDefined(String)
Generic(String, Type)
}
impl Show for Type
// Type aliases
// Traits

13
src/pkg.generated.mbti Normal file
View File

@@ -0,0 +1,13 @@
// Generated using `moon info`, DON'T EDIT IT
package "Lil-Ran/lilunar"
// Values
// Errors
// Types and methods
// Type aliases
// Traits

View File

@@ -16,15 +16,21 @@ pub fn Context::check_block_expr(
let checked_stmts = stmts.map(stmt => self.check_stmt(stmt))
self.exit_scope()
guard checked_stmts is [.., { kind: ExprStmt(expr) }] else {
return { stmts: checked_stmts, ty: Unit }
checked_stmts.push({
kind: ExprStmt({
kind: ApplyExpr({ kind: AtomExpr({ kind: Unit, ty: Unit }), ty: Unit }),
ty: Unit,
}),
})
{ 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 {
// 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 }
}
// }
}

View File

@@ -0,0 +1,304 @@
// Generated using `moon info`, DON'T EDIT IT
package "Lil-Ran/lilunar/typecheck"
import(
"Lil-Ran/lilunar/parser"
)
// Values
fn parser_pattern_map(@parser.Binding) -> Pattern
fn typecheck(@parser.Program) -> Program raise TypeCheckError
// Errors
pub(all) suberror TypeCheckError String
impl Show for TypeCheckError
// Types and methods
pub(all) enum AddSubOp {
Add
Sub
}
impl Show for AddSubOp
pub(all) struct ApplyExpr {
kind : ApplyExprKind
ty : TypeKind
}
impl Show for ApplyExpr
pub(all) enum ApplyExprKind {
AtomExpr(AtomExpr)
ArrayAccess(ApplyExpr, Expr)
FieldAccess(ApplyExpr, String)
Call(ApplyExpr, Array[Expr])
}
impl Show for ApplyExprKind
pub(all) struct AssignStmt {
left_value : LeftValue
expr : Expr
}
impl Show for AssignStmt
pub(all) struct AtomExpr {
kind : AtomExprKind
ty : TypeKind
}
impl Show for AtomExpr
pub(all) enum AtomExprKind {
Int(Int)
Double(Double)
Bool(Bool)
Unit
Ident(String)
Tuple(Array[Expr])
Array(Array[Expr])
ArrayMake(Expr, Expr)
StructConstruct(StructConstructExpr)
}
impl Show for AtomExprKind
pub(all) struct BlockExpr {
stmts : Array[Stmt]
ty : TypeKind
}
impl Show for BlockExpr
pub(all) enum CompareOperator {
Equal
NotEqual
GreaterEqual
LessEqual
Greater
Less
}
impl Show for CompareOperator
pub(all) struct Context {
mut type_env : Env
type_vars : Map[Int, TypeKind]
struct_defs : Map[String, StructDef]
func_types : Map[String, TypeKind]
mut current_func_ret_ty : TypeKind?
}
fn Context::add_intrinsic_functions(Self) -> Unit
fn Context::check_apply_expr(Self, @parser.Expr) -> ApplyExpr raise TypeCheckError
fn Context::check_assign_stmt(Self, @parser.Stmt) -> AssignStmt raise TypeCheckError
fn Context::check_atom_expr(Self, @parser.Expr) -> AtomExpr raise TypeCheckError
fn Context::check_block_expr(Self, @parser.Expr) -> BlockExpr raise TypeCheckError
fn Context::check_expr(Self, @parser.Expr) -> Expr raise TypeCheckError
fn Context::check_if_expr(Self, @parser.Expr) -> IfExpr raise TypeCheckError
fn Context::check_left_value(Self, @parser.Expr) -> LeftValue raise TypeCheckError
fn Context::check_let_mut_stmt(Self, @parser.Stmt) -> LetMutStmt raise TypeCheckError
fn Context::check_let_stmt(Self, @parser.Stmt) -> LetStmt raise TypeCheckError
fn Context::check_local_function(Self, @parser.Function) -> LocalFunction raise TypeCheckError
fn Context::check_parser_type(Self, @parser.Type, mutable? : Bool) -> Type raise TypeCheckError
fn Context::check_program(Self, @parser.Program) -> Program raise TypeCheckError
fn Context::check_stmt(Self, @parser.Stmt) -> Stmt raise TypeCheckError
fn Context::check_struct_def(Self, @parser.StructDef) -> StructDef raise TypeCheckError
fn Context::check_top_function_body(Self, @parser.Function) -> TopFunction raise TypeCheckError
fn Context::check_top_function_type_decl(Self, @parser.Function) -> TypeKind raise TypeCheckError
fn Context::check_top_let(Self, @parser.TopLet) -> TopLet raise TypeCheckError
fn Context::check_while_stmt(Self, @parser.Stmt) -> WhileStmt raise TypeCheckError
fn Context::deref_type_var(Self, TypeKind) -> TypeKind
fn Context::enter_scope(Self) -> Unit
fn Context::exit_scope(Self) -> Unit
fn Context::is_type_compatible(Self, TypeKind, TypeKind) -> Bool
fn Context::lookup_type(Self, String) -> Type?
fn Context::new() -> Self
fn Context::new_type_var(Self) -> TypeKind
#deprecated
fn Context::set_current_func_ret_ty(Self, TypeKind) -> Unit
fn Context::set_pattern_types(Self, Pattern, TypeKind) -> Unit raise TypeCheckError
fn Context::substitute_type_var(Self, Program) -> Program
fn Context::substitute_type_var_for_expr(Self, Expr) -> Expr
pub(all) struct Env {
local_ : Map[String, Type]
parent : Env?
}
fn Env::get(Self, String) -> Type?
fn Env::new(parent? : Self?) -> Self
fn Env::set(Self, String, Type) -> Unit
pub(all) struct Expr {
kind : ExprKind
ty : TypeKind
}
impl Show for Expr
pub(all) enum ExprKind {
ApplyExpr(ApplyExpr)
BlockExpr(BlockExpr)
NotExpr(Expr)
NegExpr(Expr)
Compare(CompareOperator, Expr, Expr)
AddSub(AddSubOp, Expr, Expr)
MulDivRem(MulDivRemOp, Expr, Expr)
And(Expr, Expr)
Or(Expr, Expr)
IfExpr(IfExpr)
}
impl Show for ExprKind
pub(all) struct IfExpr {
cond : Expr
then_block : BlockExpr
else_block : Expr?
ty : TypeKind
}
impl Show for IfExpr
pub(all) struct LeftValue {
kind : LeftValueKind
ty : Type
}
impl Show for LeftValue
pub(all) enum LeftValueKind {
Ident(String)
ArrayAccess(LeftValue, Expr)
FieldAccess(LeftValue, String)
}
impl Show for LeftValueKind
pub(all) struct LetMutStmt {
name : String
ty : Type
expr : Expr
}
impl Show for LetMutStmt
pub(all) struct LetStmt {
pattern : Pattern
ty : TypeKind
expr : Expr
}
impl Show for LetStmt
pub(all) struct LocalFunction {
fname : String
param_list : Array[(String, Type)]
ret_ty : Type
body : BlockExpr
}
impl Show for LocalFunction
pub(all) enum MulDivRemOp {
Mul
Div
Rem
}
impl Show for MulDivRemOp
pub(all) struct Param {
name : String
ty : TypeKind
}
impl Show for Param
pub(all) struct Pattern {
kind : PatternKind
}
impl Eq for Pattern
impl Show for Pattern
pub(all) enum PatternKind {
Wildcard
Ident(String)
Tuple(Array[Pattern])
}
impl Eq for PatternKind
impl Show for PatternKind
pub(all) struct Program {
top_lets : Map[String, TopLet]
top_functions : Map[String, TopFunction]
struct_defs : Map[String, StructDef]
}
impl Show for Program
pub(all) struct Stmt {
kind : StmtKind
}
impl Show for Stmt
pub(all) enum StmtKind {
LetStmt(LetStmt)
LetMutStmt(LetMutStmt)
AssignStmt(AssignStmt)
WhileStmt(WhileStmt)
ExprStmt(Expr)
ReturnStmt(Expr)
LocalFunction(LocalFunction)
}
impl Show for StmtKind
pub(all) struct StructConstructExpr {
name : String
fields : Array[(String, Expr)]
}
impl Show for StructConstructExpr
pub(all) struct StructDef {
name : String
fields : Array[StructField]
}
fn StructDef::get_field_type(Self, String) -> Type?
impl Show for StructDef
pub(all) struct StructField {
name : String
ty : Type
}
impl Show for StructField
pub(all) struct TopFunction {
fname : String
param_list : Array[Param]
ty : TypeKind
body : BlockExpr
}
impl Show for TopFunction
pub(all) struct TopLet {
name : String
ty : Type
expr : Expr
}
impl Show for TopLet
pub(all) struct Type {
kind : TypeKind
mutable : Bool
}
impl Show for Type
pub(all) enum TypeKind {
Unit
Bool
Int
Double
Tuple(Array[TypeKind])
Array(TypeKind)
Function(Array[TypeKind], TypeKind)
Struct(String)
Any
TypeVar(Int)
}
impl Eq for TypeKind
impl Hash for TypeKind
impl Show for TypeKind
pub(all) struct WhileStmt {
cond : Expr
body : BlockExpr
}
impl Show for WhileStmt
// Type aliases
// Traits