Skip to content

Commit

Permalink
CPS IR, done, TODO: closure conversion
Browse files Browse the repository at this point in the history
  • Loading branch information
glyh committed Oct 5, 2024
1 parent fe76313 commit 69fd34d
Show file tree
Hide file tree
Showing 18 changed files with 777 additions and 88 deletions.
198 changes: 112 additions & 86 deletions src/bin/main.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
enum Stages {
Parse
Typecheck
Knf
KnfOpt
Closure
PreCps
Cps
//Knf
//KnfOpt
//Closure
Asm
Finished
} derive(Show, Eq, Compare)
Expand All @@ -13,9 +15,11 @@ fn Stages::from_string(s : String) -> Stages? {
match s {
"parse" => Some(Stages::Parse)
"typecheck" => Some(Stages::Typecheck)
"knf" => Some(Stages::Knf)
"knf-opt" => Some(Stages::KnfOpt)
"closure" => Some(Stages::Closure)
"precps" => Some(Stages::PreCps)
"cps" => Some(Stages::Cps)
//"knf" => Some(Stages::Knf)
//"knf-opt" => Some(Stages::KnfOpt)
//"closure" => Some(Stages::Closure)
"riscv" => Some(Stages::Asm)
"finished" => Some(Stages::Finished)
_ => None
Expand All @@ -25,11 +29,9 @@ fn Stages::from_string(s : String) -> Stages? {
fn Stages::next(self : Stages) -> Stages {
match self {
Stages::Parse => Stages::Typecheck
Stages::Typecheck => Stages::Knf
Stages::Knf => Stages::KnfOpt
Stages::KnfOpt => Stages::Closure
Stages::Closure => // TODO
Stages::Asm
Stages::Typecheck => Stages::PreCps
Stages::PreCps => Stages::Cps
Stages::Cps => Stages::Asm
Stages::Asm => Stages::Finished
Stages::Finished => Stages::Finished
}
Expand All @@ -41,10 +43,13 @@ struct CompileStatus {
mut source_code : String?
mut ast : @types.Syntax?
mut typechecked : @types.Syntax?
knf_env : @knf.KnfEnv
mut knf : @knf.Knf?
mut opt_knf : @knf.Knf?
mut closure_ir : @closure.Program?
mut precps : @precps.PreCps?
mut precpsenv : @precps.TyEnv?
mut cps : @cps.Cps?
//knf_env : @knf.KnfEnv
//mut knf : @knf.Knf?
//mut opt_knf : @knf.Knf?
//mut closure_ir : @closure.Program?
mut asm : Array[@riscv.AssemblyFunction]?
}

Expand All @@ -59,24 +64,28 @@ fn CompileStatus::initialize(
source_code: None,
ast: None,
typechecked: None,
knf_env: @knf.KnfEnv::new(@types.externals),
knf: None,
opt_knf: None,
closure_ir: None,
precps: None,
precpsenv: None,
cps: None,
//knf_env: @knf.KnfEnv::new(@types.externals),
//knf: None,
//opt_knf: None,
//closure_ir: None,
asm: None,
}
match start_stage {
Parse => v.source_code = Some(file)
Typecheck => v.ast = Some(@types.Syntax::from_json!(@json.parse!(file)))
Knf => v.typechecked = Some(@types.Syntax::from_json!(@json.parse!(file)))
KnfOpt => {
v.knf = Some(@knf.Knf::from_json!(@json.parse!(file)))
v.knf_env.init_counter_from_existing(v.knf.unwrap())
}
Closure => {
v.opt_knf = Some(@knf.Knf::from_json!(@json.parse!(file)))
v.knf_env.init_counter_from_existing(v.opt_knf.unwrap())
}
PreCps =>
v.typechecked = Some(@types.Syntax::from_json!(@json.parse!(file)))
//KnfOpt => {
// v.knf = Some(@knf.Knf::from_json!(@json.parse!(file)))
// v.knf_env.init_counter_from_existing(v.knf.unwrap())
//}
//Closure => {
// v.opt_knf = Some(@knf.Knf::from_json!(@json.parse!(file)))
// v.knf_env.init_counter_from_existing(v.opt_knf.unwrap())
//}
_ => fail!("invalid start stage")
}
v
Expand All @@ -97,27 +106,39 @@ fn CompileStatus::step(self : CompileStatus) -> Bool {
let to_check = self.ast.unwrap().clone()
self.typechecked = Some(@typing.infer_type(to_check))
}
Knf => {
let preprocessed = self.knf_env.syntax_preprocess(
self.typechecked.unwrap(),
)
let knf = self.knf_env.to_knf(preprocessed)
self.knf = Some(knf)
}
KnfOpt => {
let knf = self.knf.unwrap()
// TODO: optimize
self.opt_knf = Some(knf)
PreCps => {
let tyenv = @precps.TyEnv::new(@types.externals)
let entry_inlined = @precps.inline_entry(self.typechecked.unwrap())
self.precps = Some(tyenv.ast2precps(entry_inlined))
self.precpsenv = Some(tyenv)
}
Closure => {
let closure_ir = @closure.knf_program_to_closure(
self.opt_knf.unwrap(),
Map::from_iter(@types.externals.iter()),
)
self.closure_ir = Some(closure_ir)
Cps => {
let cpsenv = @cps.CpsEnv::new(self.precpsenv.unwrap().counter.val)
let mut cps = cpsenv.precps2cps(self.precps.unwrap(), @cps.Cps::Just)
cps = @cps.alias_analysis(cps)
self.cps = Some(cps)
}
//Knf => {
// let preprocessed = self.knf_env.syntax_preprocess(
// self.typechecked.unwrap(),
// )
// let knf = self.knf_env.to_knf(preprocessed)
// self.knf = Some(knf)
//}
//KnfOpt => {
// let knf = self.knf.unwrap()
// // TODO: optimize
// self.opt_knf = Some(knf)
//}
//Closure => {
// let closure_ir = @closure.knf_program_to_closure(
// self.opt_knf.unwrap(),
// Map::from_iter(@types.externals.iter()),
// )
// self.closure_ir = Some(closure_ir)
//}
Asm => {
let real_asm = @riscv.emit(@util.die("TODO"))
let real_asm = @riscv.emit(@util.die("TODO5"))
self.asm = Some(real_asm)
}
Finished => ()
Expand All @@ -131,20 +152,25 @@ fn CompileStatus::output(self : CompileStatus, json : Bool) -> String {
match self.curr_stage {
Parse => self.source_code.unwrap()
Typecheck => @json.stringify(self.ast.unwrap().to_json())
Knf => @json.stringify(self.typechecked.unwrap().to_json())
KnfOpt => @json.stringify(self.knf.unwrap().to_json())
Closure => @json.stringify(self.opt_knf.unwrap().to_json())
Asm => @util.die("TODO")
PreCps => @util.die("TODO1")
Cps => @util.die("TODO2")
//Knf => @json.stringify(self.typechecked.unwrap().to_json())
//KnfOpt => @json.stringify(self.knf.unwrap().to_json())
//Closure => @json.stringify(self.opt_knf.unwrap().to_json())
Asm => @util.die("TODO3")
Finished => @riscv.print_functions(self.asm.unwrap())
}
} else {
match self.curr_stage {
Parse => self.source_code.unwrap()
Typecheck => self.ast.unwrap().to_string()
Knf => self.typechecked.unwrap().to_string()
KnfOpt => self.knf.unwrap().to_string()
Closure => self.opt_knf.unwrap().to_string()
Asm => self.closure_ir.unwrap().to_string()
PreCps => self.typechecked.unwrap().to_string()
Cps => self.precps.unwrap().to_string()
//Knf => self.typechecked.unwrap().to_string()
//KnfOpt => self.knf.unwrap().to_string()
//Closure => self.opt_knf.unwrap().to_string()
Asm => self.cps.unwrap().to_string()
//self.closure_ir.unwrap().to_string()
Finished => @riscv.print_functions(self.asm.unwrap())
}
}
Expand Down Expand Up @@ -261,12 +287,12 @@ fn main {
)

// Configure pipeline
if knf_interpreter.val {
end_stage.val = Stages::Knf
}
if closure_interpreter.val {
end_stage.val = Stages::Closure
}
//if knf_interpreter.val {
// end_stage.val = Stages::Knf
//}
//if closure_interpreter.val {
// end_stage.val = Stages::Closure
//}
let stages_to_print = print.val.map(
fn(s) {
match Stages::from_string(s) {
Expand Down Expand Up @@ -309,32 +335,32 @@ fn main {
}

// Output
if knf_interpreter.val {
let knfi = @knf_eval.KnfInterpreter::new()
add_interpreter_fns(knfi)
match knfi.eval_full?(status.knf.unwrap()) {
Ok(_) => ()
Err(Failure(e)) => {
println(e)
@util.die("KNF interpreter error")
}
}
} else if closure_interpreter.val {
let clsi = @closure_eval.ClosureInterpreter::new()
add_closure_interpreter_fns(clsi)
match clsi.eval_full?(status.closure_ir.unwrap()) {
Ok(_) => ()
Err(Failure(e)) => {
println(e)
@util.die("Closure interpreter error")
}
}
//if knf_interpreter.val {
// let knfi = @knf_eval.KnfInterpreter::new()
// add_interpreter_fns(knfi)
// match knfi.eval_full?(status.knf.unwrap()) {
// Ok(_) => ()
// Err(Failure(e)) => {
// println(e)
// @util.die("KNF interpreter error")
// }
// }
//} else if closure_interpreter.val {
// let clsi = @closure_eval.ClosureInterpreter::new()
// add_closure_interpreter_fns(clsi)
// match clsi.eval_full?(status.closure_ir.unwrap()) {
// Ok(_) => ()
// Err(Failure(e)) => {
// println(e)
// @util.die("Closure interpreter error")
// }
// }
//} else {
let out_string = status.output(json.val)
if out_file.val == "-" {
println(out_string)
} else {
let out_string = status.output(json.val)
if out_file.val == "-" {
println(out_string)
} else {
@fs.write_to_string(out_file.val, out_string)
}
@fs.write_to_string(out_file.val, out_string)
}
//}
}
2 changes: 2 additions & 0 deletions src/bin/moon.pkg.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
"path": "moonbitlang/minimbt",
"alias": "types"
},
"moonbitlang/minimbt/precps",
"moonbitlang/minimbt/cps",
"moonbitlang/minimbt/knf",
"moonbitlang/minimbt/typing",
"moonbitlang/minimbt/knf_eval",
Expand Down
12 changes: 12 additions & 0 deletions src/cps/cps_env.mbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
struct CpsEnv {
counter : Ref[Int]
}

pub fn CpsEnv::new(counter : Int) -> CpsEnv {
{ counter: { val: counter } }
}

fn CpsEnv::new_tmp(self : CpsEnv, t : T) -> Var {
self.counter.val = self.counter.val + 1
{ name: { val: None }, id: self.counter.val, ty: t }
}
86 changes: 86 additions & 0 deletions src/cps/cps_ir.mbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
struct Var {
name : Ref[String?]
id : Int
ty : T
}

fn Var::op_equal(lhs : Var, rhs : Var) -> Bool {
lhs.id == rhs.id
}

fn Var::from_precps(v : @precps.Var, t : T) -> Var {
{ id: v.id, name: { val: v.name }, ty: t }
}

enum Value {
Var(Var)
Label(Var)
Unit
Int(Int)
Double(Double)
} derive(Eq)

fn Value::replace_var_bind(self : Value, from : Var, to : Value) -> Value {
match self {
Var(v) => if v == from { to } else { self }
_ => self
}
}

enum AccessPath {
OffP(Int)
SelP(Int, AccessPath)
} derive(Show)

pub enum Cps {
// T marks the binding's type
Record(Array[(Value, AccessPath)], Var, Cps)
Select(Int, Value, Var, Cps)
Offset(Int, Value, Var, Cps)
Fix(Var, Array[Var], Cps, Cps)
Switch(Value, Array[Cps])
Prim(PrimOp, Array[Value], Var, Cps)
// T marks the return type
App(Value, Array[Value])
Just(Value)
}

fn Cps::replace_var_bind(self : Cps, from : Var, to : Value) -> Cps {
fn rec(s : Cps) {
s.replace_var_bind(from, to)
}

fn recv(v : Value) {
v.replace_var_bind(from, to)
}

match self {
Record(record, bind, rest) => {
let rest_new = if from != bind { rec(rest) } else { rest }
Record(record.map(fn { (v, path) => (recv(v), path) }), bind, rest_new)
}
Select(idx, v, bind, rest) => {
let rest_new = if from != bind { rec(rest) } else { rest }
Select(idx, recv(v), bind, rest_new)
}
Offset(idx, v, bind, rest) => {
let rest_new = if from != bind { rec(rest) } else { rest }
Offset(idx, recv(v), bind, rest_new)
}
Fix(name, args, body, rest) => {
let body_new = if from != name && not(args.contains(from)) {
rec(body)
} else {
body
}
let rest_new = if from != name { rec(rest) } else { body }
Fix(name, args, body_new, rest_new)
}
Switch(v, branches) => Switch(recv(v), branches.map(rec))
Prim(op, args, bind, rest) => {
let rest_new = if from != bind { rec(rest) } else { rest }
Prim(op, args.map(recv), bind, rest_new)
}
App(f, args) => App(recv(f), args.map(recv))
}
}
Loading

0 comments on commit 69fd34d

Please sign in to comment.