From 03b9458f27c1ce909a94d076ac6eb8f6e8646c8c Mon Sep 17 00:00:00 2001 From: Rynco Maekawa Date: Thu, 12 Sep 2024 18:46:34 +0800 Subject: [PATCH] Update interface & utilities --- src/bin/externals.mbt | 207 +++++++++++++++++++ src/bin/knf_eval.mbt | 260 ------------------------ src/bin/main.mbt | 335 +++++++++++++++++++++++++++++++ src/bin/moon.pkg.json | 3 +- src/closure/closure_ir.mbt | 3 + src/closure/json.mbt | 282 ++++++++++++++++++++++++++ src/closure_eval/interpreter.mbt | 296 +++++++++++++++++++++++++++ src/closure_eval/moon.pkg.json | 16 ++ src/knf/json.mbt | 139 +++++++++++++ src/knf/syntax_to_knf.mbt | 7 + src/knf/utils.mbt | 66 ++++++ src/name.mbt | 27 +++ src/riscv/asm_stringify.mbt | 14 +- 13 files changed, 1386 insertions(+), 269 deletions(-) create mode 100644 src/bin/externals.mbt delete mode 100644 src/bin/knf_eval.mbt create mode 100644 src/bin/main.mbt create mode 100644 src/closure/json.mbt create mode 100644 src/closure_eval/interpreter.mbt create mode 100644 src/closure_eval/moon.pkg.json create mode 100644 src/knf/json.mbt create mode 100644 src/knf/utils.mbt diff --git a/src/bin/externals.mbt b/src/bin/externals.mbt new file mode 100644 index 0000000..6b5699f --- /dev/null +++ b/src/bin/externals.mbt @@ -0,0 +1,207 @@ +fn add_interpreter_fns(interpreter : @knf_eval.KnfInterpreter) -> Unit { + interpreter.add_extern_fn( + "minimbt_print_int", + fn(args) { + match args[0] { + Int(i) => @io.print(i) + _ => @util.die("print_int expects Int") + } + Unit + }, + ) + interpreter.add_extern_fn( + "minimbt_print_endline", + fn(_args) { + @io.print("\n") + Unit + }, + ) + let create_array = fn(args : Array[@knf_eval.Value]) { + match args[0] { + Int(n) => @knf_eval.Value::Array(Array::make(n, args[1])) + _ => @util.die("create_array expects Int") + } + } + interpreter.add_extern_fn("minimbt_create_array", create_array) + interpreter.add_extern_fn("minimbt_create_float_array", create_array) + interpreter.add_extern_fn("minimbt_create_ptr_array", create_array) + interpreter.add_extern_fn( + "minimbt_truncate", + fn(args) { + match args[0] { + Double(d) => Int(d.to_int()) + _ => @util.die("truncate expects Double") + } + }, + ) + interpreter.add_extern_fn( + "minimbt_sin", + fn(args) { + match args[0] { + Double(d) => Double(@math.sin(d)) + _ => @util.die("sin expects Double") + } + }, + ) + interpreter.add_extern_fn( + "minimbt_cos", + fn(args) { + match args[0] { + Double(d) => Double(@math.cos(d)) + _ => @util.die("cos expects Double") + } + }, + ) + interpreter.add_extern_fn( + "minimbt_sqrt", + fn(args) { + match args[0] { + Double(d) => Double(d.sqrt()) + _ => @util.die("sqrt expects Double") + } + }, + ) + interpreter.add_extern_fn( + "minimbt_abs_float", + fn(args) { + match args[0] { + Double(d) => Double(@double.abs(d)) + _ => @util.die("abs_float expects Double") + } + }, + ) + interpreter.add_extern_fn( + "minimbt_int_of_float", + fn(args) { + match args[0] { + Double(d) => Int(d.to_int()) + _ => @util.die("int_of_float expects Double") + } + }, + ) + interpreter.add_extern_fn( + "minimbt_float_of_int", + fn(args) { + match args[0] { + Int(i) => Double(i.to_double()) + _ => @util.die("float_of_int expects Int") + } + }, + ) +} + +fn add_closure_interpreter_fns( + interpreter : @closure_eval.ClosureInterpreter +) -> Unit { + interpreter.add_extern_fn( + "minimbt_print_int", + fn(args) { + match args[0] { + Int(i) => @io.print(i) + _ => @util.die("print_int expects Int") + } + Unit + }, + ) + interpreter.add_extern_fn( + "minimbt_print_endline", + fn(_args) { + @io.print("\n") + Unit + }, + ) + let create_array = fn(args : Array[@closure_eval.Value]) { + match args[0] { + Int(n) => @closure_eval.Value::Array(Array::make(n, args[1])) + _ => @util.die("create_array expects Int") + } + } + interpreter.add_extern_fn("minimbt_create_array", create_array) + interpreter.add_extern_fn("minimbt_create_float_array", create_array) + interpreter.add_extern_fn("minimbt_create_ptr_array", create_array) + interpreter.add_extern_fn( + "minimbt_truncate", + fn(args) { + match args[0] { + Double(d) => Int(d.to_int()) + _ => @util.die("truncate expects Double") + } + }, + ) + interpreter.add_extern_fn( + "minimbt_sin", + fn(args) { + match args[0] { + Double(d) => Double(@math.sin(d)) + _ => @util.die("sin expects Double") + } + }, + ) + interpreter.add_extern_fn( + "minimbt_cos", + fn(args) { + match args[0] { + Double(d) => Double(@math.cos(d)) + _ => @util.die("cos expects Double") + } + }, + ) + interpreter.add_extern_fn( + "minimbt_sqrt", + fn(args) { + match args[0] { + Double(d) => Double(d.sqrt()) + _ => @util.die("sqrt expects Double") + } + }, + ) + interpreter.add_extern_fn( + "minimbt_abs_float", + fn(args) { + match args[0] { + Double(d) => Double(@double.abs(d)) + _ => @util.die("abs_float expects Double") + } + }, + ) + interpreter.add_extern_fn( + "minimbt_int_of_float", + fn(args) { + match args[0] { + Double(d) => Int(d.to_int()) + _ => @util.die("int_of_float expects Double") + } + }, + ) + interpreter.add_extern_fn( + "minimbt_float_of_int", + fn(args) { + match args[0] { + Int(i) => Double(i.to_double()) + _ => @util.die("float_of_int expects Int") + } + }, + ) +} + +fn externals() -> @immut/hashmap.T[String, @types.Type] { + @immut/hashmap.T::new() + .add("read_int", @types.Fun([], Int)) + .add("read_char", @types.Fun([], Int)) + .add("print_int", @types.Fun([Int], Unit)) + .add("print_char", @types.Fun([Int], Unit)) + .add("print_endline", @types.Fun([], Unit)) + .add("create_array", @types.Fun([Int, Int], @types.Type::Array(Int))) + .add( + "create_float_array", + @types.Fun([Int, Double], @types.Type::Array(Double)), + ) + .add("create_ptr_array", @types.Fun([Int, Ptr], @types.Type::Array(Ptr))) + .add("truncate", @types.Fun([Double], Int)) + .add("sin", @types.Fun([Double], Double)) + .add("cos", @types.Fun([Double], Double)) + .add("sqrt", @types.Fun([Double], Double)) + .add("abs_float", @types.Fun([Double], Double)) + .add("int_of_float", @types.Fun([Double], Int)) + .add("float_of_int", @types.Fun([Int], Double)) +} diff --git a/src/bin/knf_eval.mbt b/src/bin/knf_eval.mbt deleted file mode 100644 index e4d1da9..0000000 --- a/src/bin/knf_eval.mbt +++ /dev/null @@ -1,260 +0,0 @@ -fn main { - let argv = @env.get_args() - let mut file = None - let no_run = Ref::new(false) - let print_ast = Ref::new(false) - let print_knf = Ref::new(false) - let print_each_knf = Ref::new(false) - let print_final_knf = Ref::new(false) - let print_closure_ir = Ref::new(false) - let print_asm = Ref::new(false) - let knf_opt_iters = Ref::new(10) - let run_with_interpreter = Ref::new(false) - @ArgParser.parse( - [ - ( - "--interpret", - "-i", - @ArgParser.Set(run_with_interpreter), - "Run with interpreter", - ), - ("--print-ast", "", @ArgParser.Set(print_ast), "Print AST"), - ("--no-run", "", @ArgParser.Set(no_run), "Do not run the program"), - ("--print-knf", "", @ArgParser.Set(print_knf), "Print initial KNF"), - ( - "--print-each-knf", - "", - @ArgParser.Set(print_each_knf), - "Print each KNF in optimization", - ), - ( - "--print-final-knf", - "", - @ArgParser.Set(print_final_knf), - "Print final KNF", - ), - ( - "--print-closure-ir", - "", - @ArgParser.Set(print_closure_ir), - "Print closure IR", - ), - ("--print-asm", "", @ArgParser.Set(print_asm), "Print assembly"), - ( - "--knf-opt-iters", - "N", - @ArgParser.String( - fn(s) { - let i = @strconv.parse_int?(s) - match i { - Ok(i) => knf_opt_iters.val = i - Err(e) => @util.die("Invalid number") - } - }, - ), - "Number of optimization iterations", - ), - ], - fn(s) { - if file.is_empty().not() { - @util.die("multiple files are given") - } - file = Some(s) - }, - "", - argv, - ) - - // Input - let file = if file.is_empty() { - println("no input file") - @util.die("no input file") - } else { - file.unwrap() - } - let contents = @fs.read_to_string(file) - let typechecked = to_typechecked(contents) - if print_ast.val { - println(typechecked.to_string()) - } - - // To KNF - let external_fns = externals() - let knf_env = @knf.KnfEnv::new(external_fns) - let knf = knf_env.to_knf(typechecked) - if print_knf.val { - println("Initial KNF:") - println(knf.to_pretty_print()) - } - - // Optimization - let mut knf = knf - for i = 0; i < knf_opt_iters.val; i = i + 1 { - let new_knf = knf_env.opt_pass(knf) - if new_knf == knf { - break - } - knf = new_knf - if print_each_knf.val { - println("KNF Iteration \{i}:") - println(knf.to_pretty_print()) - } - } - if print_final_knf.val || no_run.val { - println("Final KNF:") - println(knf.to_pretty_print()) - } - - // Interpretation - if run_with_interpreter.val { - if no_run.val { - return - } - let interpreter = @knf_eval.KnfInterpreter::new() - add_interpreter_fns(interpreter) - let _result = match interpreter.eval_full?(knf) { - Ok(result) => result - Err(Failure(e)) => { - println("Error: " + e) - @util.die("Evaluation error") - } - } - return - } - - // KNF to closure - let closure_ir = @closure.knf_program_to_closure( - knf, - Map::from_iter(external_fns.iter()), - ) - if print_closure_ir.val { - println("Closure IR:") - println(closure_ir.to_string()) - } - - // Fill in the holes here! - - // Code generation - let real_asm = @riscv.emit(abort("TODO")) - - // Print asm - for asm in real_asm { - println(asm) - println("") - } -} - -fn to_typechecked(source : String) -> @types.Syntax { - abort("todo") -} - -fn add_interpreter_fns(interpreter : @knf_eval.KnfInterpreter) -> Unit { - interpreter.add_extern_fn( - "print_int", - fn(args) { - match args[0] { - Int(i) => @io.print(i) - _ => @util.die("print_int expects Int") - } - Unit - }, - ) - interpreter.add_extern_fn( - "print_endline", - fn(_args) { - @io.print("\n") - Unit - }, - ) - let create_array = fn(args : Array[@knf_eval.Value]) { - match args[0] { - Int(n) => @knf_eval.Value::Array(Array::make(n, args[1])) - _ => @util.die("create_array expects Int") - } - } - interpreter.add_extern_fn("create_array", create_array) - interpreter.add_extern_fn("create_float_array", create_array) - interpreter.add_extern_fn("create_ptr_array", create_array) - interpreter.add_extern_fn( - "truncate", - fn(args) { - match args[0] { - Double(d) => Int(d.to_int()) - _ => @util.die("truncate expects Double") - } - }, - ) - interpreter.add_extern_fn( - "sin", - fn(args) { - match args[0] { - Double(d) => Double(@math.sin(d)) - _ => @util.die("sin expects Double") - } - }, - ) - interpreter.add_extern_fn( - "cos", - fn(args) { - match args[0] { - Double(d) => Double(@math.cos(d)) - _ => @util.die("cos expects Double") - } - }, - ) - interpreter.add_extern_fn( - "sqrt", - fn(args) { - match args[0] { - Double(d) => Double(d.sqrt()) - _ => @util.die("sqrt expects Double") - } - }, - ) - interpreter.add_extern_fn( - "abs_float", - fn(args) { - match args[0] { - Double(d) => Double(@double.abs(d)) - _ => @util.die("abs_float expects Double") - } - }, - ) - interpreter.add_extern_fn( - "int_of_float", - fn(args) { - match args[0] { - Double(d) => Int(d.to_int()) - _ => @util.die("int_of_float expects Double") - } - }, - ) - interpreter.add_extern_fn( - "float_of_int", - fn(args) { - match args[0] { - Int(i) => Double(i.to_double()) - _ => @util.die("float_of_int expects Int") - } - }, - ) -} - -fn externals() -> @immut/hashmap.T[String, @types.Type] { - @immut/hashmap.T::new() - .add("print_int", @types.Fun([Int], Unit)) - .add("print_endline", @types.Fun([], Unit)) - .add("create_array", @types.Fun([Int, Int], @types.Type::Array(Int))) - .add( - "create_float_array", - @types.Fun([Int, Double], @types.Type::Array(Double)), - ) - .add("create_ptr_array", @types.Fun([Int, Ptr], @types.Type::Array(Ptr))) - .add("truncate", @types.Fun([Double], Int)) - .add("sin", @types.Fun([Double], Double)) - .add("cos", @types.Fun([Double], Double)) - .add("sqrt", @types.Fun([Double], Double)) - .add("abs_float", @types.Fun([Double], Double)) - .add("int_of_float", @types.Fun([Double], Int)) - .add("float_of_int", @types.Fun([Int], Double)) -} diff --git a/src/bin/main.mbt b/src/bin/main.mbt new file mode 100644 index 0000000..c0e03b4 --- /dev/null +++ b/src/bin/main.mbt @@ -0,0 +1,335 @@ +/// The stage to be run next. +enum Stages { + Parse + Typecheck + Knf + KnfOpt + Closure + Asm + Finished +} derive(Show, Eq, Compare) + +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) + "riscv" => Some(Stages::Asm) + "finished" => Some(Stages::Finished) + _ => None + } +} + +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 => @util.die("TODO") + Stages::Asm => Stages::Finished + Stages::Finished => Stages::Finished + } +} + +struct CompileStatus { + mut curr_stage : Stages + end_stage : Stages + 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 asm : Array[@riscv.AssemblyFunction]? +} + +fn CompileStatus::initialize( + start_stage : Stages, + end_stage : Stages, + file : String +) -> CompileStatus! { + let v = CompileStatus::{ + curr_stage: start_stage, + end_stage, + source_code: None, + ast: None, + typechecked: None, + knf_env: @knf.KnfEnv::new(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()) + } + _ => fail!("invalid start stage") + } + v +} + +/// Run the next stage of compilation. Returns true if the compilation is finished. +fn CompileStatus::step(self : CompileStatus) -> Bool { + if self.curr_stage >= self.end_stage { + return true + } + match self.curr_stage { + Parse => { + let source_code = self.source_code.unwrap() + let parsed = @util.die("TODO: parse") + self.ast = Some(parsed) + } + Typecheck => { + let typechecked = @util.die("TODO: typecheck") + self.typechecked = Some(typechecked) + } + Knf => { + let knf = self.knf_env.to_knf(self.typechecked.unwrap()) + 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(externals().iter()), + ) + self.closure_ir = Some(closure_ir) + } + Asm => { + let real_asm = @riscv.emit(@util.die("TODO")) + self.asm = Some(real_asm) + } + Finished => () + } + self.curr_stage = self.curr_stage.next() + self.curr_stage >= self.end_stage +} + +fn CompileStatus::output(self : CompileStatus, json : Bool) -> String { + if json { + 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") + 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 => @util.die("TODO") + Finished => @riscv.print_functions(self.asm.unwrap()) + } + } +} + +fn main { + let argv = @env.get_args() + let mut file = None + let knf_opt_iters = Ref::new(10) + let knf_opt_inline_threshold = Ref::new(10) + + // Testing directives + let json = Ref::new(false) + let start_stage = Ref::new(Stages::Parse) + let end_stage = Ref::new(Stages::Finished) + let knf_interpreter = Ref::new(false) + let closure_interpreter = Ref::new(false) + let out_file = Ref::new("-") + let print = Ref::new([]) + + // + @ArgParser.parse( + [ + ( + "--start-stage", + "", + @ArgParser.String( + fn(s) { + match Stages::from_string(s) { + Some(stage) => start_stage.val = stage + None => @util.die("Invalid stage") + } + }, + ), + "Start stage", + ), + ( + "--end-stage", + "", + @ArgParser.String( + fn(s) { + match Stages::from_string(s) { + Some(stage) => end_stage.val = stage + None => @util.die("Invalid stage") + } + }, + ), + "End stage", + ), + ( + "--knf-interpreter", + "", + @ArgParser.Set(knf_interpreter), + "Run with KNF interpreter", + ), + ( + "--closure-interpreter", + "", + @ArgParser.Set(closure_interpreter), + "Run with closure interpreter", + ), + ( + "--out-file", + "-o", + @ArgParser.String(fn(s) { out_file.val = s }), + "Output file", + ), + ("--json", "", @ArgParser.Set(json), "Print results as JSON"), + + // Regular directives + ( + "--print", + "", + @ArgParser.String(fn(s) { print.val = s.split(",").collect() }), + "", + ), + ( + "--knf-opt-iters", + "N", + @ArgParser.String( + fn(s) { + let i = @strconv.parse_int?(s) + match i { + Ok(i) => knf_opt_iters.val = i + Err(e) => @util.die("Invalid number") + } + }, + ), + "Number of optimization iterations", + ), + ( + "--knf-opt-inline-threshold", + "N", + @ArgParser.String( + fn(s) { + let i = @strconv.parse_int?(s) + match i { + Ok(i) => knf_opt_inline_threshold.val = i + Err(e) => @util.die("Invalid number") + } + }, + ), + "Inline threshold for KNF optimization", + ), + ], + fn(s) { + if file.is_empty().not() { + @util.die("multiple files are given") + } + file = Some(s) + }, + "", + argv, + ) + + // Configure pipeline + 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) { + Some(stage) => stage + None => @util.die("Invalid stage to print: \{s}") + } + }, + ) + + // Input + let file = if file.is_empty() { + @util.die("no input file provided") + } else { + file.unwrap() + } + let contents = @fs.read_to_string(file) + + // Compilation + let status = match + CompileStatus::initialize?(start_stage.val, end_stage.val.next(), contents) { + Ok(status) => status + Err(e) => { + println(e) + @util.die("Initialization error") + } + } + + // Run stages + while true { + let stg = status.curr_stage + let stop = status.step() + if stages_to_print.contains(stg) { + println("Stage: \{stg}") + println(status.output(json.val)) + } + if stop { + break + } + } + + // 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") + } + } + } 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) + } + } +} diff --git a/src/bin/moon.pkg.json b/src/bin/moon.pkg.json index 1dd3b2a..48156ab 100644 --- a/src/bin/moon.pkg.json +++ b/src/bin/moon.pkg.json @@ -16,6 +16,7 @@ "lijunchen/unstable_io/io", "moonbitlang/minimbt/closure", "moonbitlang/minimbt/riscv", - "moonbitlang/minimbt/util" + "moonbitlang/minimbt/util", + "moonbitlang/minimbt/closure_eval" ] } diff --git a/src/closure/closure_ir.mbt b/src/closure/closure_ir.mbt index dace896..5e2a59a 100644 --- a/src/closure/closure_ir.mbt +++ b/src/closure/closure_ir.mbt @@ -40,6 +40,9 @@ pub struct Closure { pub struct FuncDef { name : Label old_name : Name + /// true if the function is a closure function, and the closure will be available at `s11` on + /// function entry. + is_closure : Bool ty : LowType args : Array[(Name, LowType)] formal_free_vars : Array[(Name, LowType)] diff --git a/src/closure/json.mbt b/src/closure/json.mbt new file mode 100644 index 0000000..058865b --- /dev/null +++ b/src/closure/json.mbt @@ -0,0 +1,282 @@ +pub fn Expr::to_json(self : Expr) -> Json { + match self { + Expr::Unit => ["Unit"] + Expr::Int(i) => ["Int", Number(i.to_double())] + Expr::Double(d) => ["Double", Number(d)] + Expr::Neg(n) => ["Neg", n.to_json()] + Expr::Add(n1, n2) => ["Add", n1.to_json(), n2.to_json()] + Expr::Sub(n1, n2) => ["Sub", n1.to_json(), n2.to_json()] + Expr::Mul(n1, n2) => ["Mul", n1.to_json(), n2.to_json()] + Expr::Div(n1, n2) => ["Div", n1.to_json(), n2.to_json()] + Expr::FNeg(n) => ["FNeg", n.to_json()] + Expr::FAdd(n1, n2) => ["FAdd", n1.to_json(), n2.to_json()] + Expr::FSub(n1, n2) => ["FSub", n1.to_json(), n2.to_json()] + Expr::FMul(n1, n2) => ["FMul", n1.to_json(), n2.to_json()] + Expr::FDiv(n1, n2) => ["FDiv", n1.to_json(), n2.to_json()] + Expr::IfEq(n1, n2, e1, e2) => + ["IfEq", n1.to_json(), n2.to_json(), e1.to_json(), e2.to_json()] + Expr::IfLe(n1, n2, e1, e2) => + ["IfLe", n1.to_json(), n2.to_json(), e1.to_json(), e2.to_json()] + Expr::Let((n, t), e1, e2) => + ["Let", [n.to_json(), t.to_json()], e1.to_json(), e2.to_json()] + Expr::Var(n) => ["Var", n.to_json()] + Expr::MakeClosure((n, t), c, e) => + ["MakeClosure", [n.to_json(), t.to_json()], c.to_json(), e.to_json()] + Expr::CallClosure(n, ns) => ["CallClosure", n.to_json(), ns.to_json()] + Expr::CallDirect(l, ns) => ["CallDirect", l._.to_json(), ns.to_json()] + Expr::MakeTuple(ns) => ["MakeTuple", ns.to_json()] + Expr::LetTuple(n_ts, n, e) => { + let n_ts_res = [] + for it in n_ts { + let (n, t) = it + n_ts_res.push([n.to_json(), t.to_json()]) + } + ["LetTuple", n_ts_res.to_json(), n.to_json(), e.to_json()] + } + Expr::ArrayGet(n1, n2) => ["ArrayGet", n1.to_json(), n2.to_json()] + Expr::ArrayPut(n1, n2, n3) => + ["ArrayPut", n1.to_json(), n2.to_json(), n3.to_json()] + Expr::ExternalArray(l) => ["ExternalArray", l._.to_json()] + } +} + +pub fn Expr::from_json(json : Json) -> Expr! { + match json { + ["Unit"] => Expr::Unit + ["Int", Number(i)] => Expr::Int(i.to_int()) + ["Double", Number(d)] => Expr::Double(d) + ["Neg", n] => Expr::Neg(Name::from_json!(n)) + ["Add", n1, n2] => Expr::Add(Name::from_json!(n1), Name::from_json!(n2)) + ["Sub", n1, n2] => Expr::Sub(Name::from_json!(n1), Name::from_json!(n2)) + ["Mul", n1, n2] => Expr::Mul(Name::from_json!(n1), Name::from_json!(n2)) + ["Div", n1, n2] => Expr::Div(Name::from_json!(n1), Name::from_json!(n2)) + ["FNeg", n] => Expr::FNeg(Name::from_json!(n)) + ["FAdd", n1, n2] => Expr::FAdd(Name::from_json!(n1), Name::from_json!(n2)) + ["FSub", n1, n2] => Expr::FSub(Name::from_json!(n1), Name::from_json!(n2)) + ["FMul", n1, n2] => Expr::FMul(Name::from_json!(n1), Name::from_json!(n2)) + ["FDiv", n1, n2] => Expr::FDiv(Name::from_json!(n1), Name::from_json!(n2)) + ["IfEq", n1, n2, e1, e2] => + Expr::IfEq( + Name::from_json!(n1), + Name::from_json!(n2), + Expr::from_json!(e1), + Expr::from_json!(e2), + ) + ["IfLe", n1, n2, e1, e2] => + Expr::IfLe( + Name::from_json!(n1), + Name::from_json!(n2), + Expr::from_json!(e1), + Expr::from_json!(e2), + ) + ["Let", [n, t], e1, e2] => + Expr::Let( + (Name::from_json!(n), LowType::from_json!(t)), + Expr::from_json!(e1), + Expr::from_json!(e2), + ) + ["Var", n] => Expr::Var(Name::from_json!(n)) + ["MakeClosure", [n, t], c, e] => + Expr::MakeClosure( + (Name::from_json!(n), LowType::from_json!(t)), + Closure::from_json!(c), + Expr::from_json!(e), + ) + ["CallClosure", n, Array(ns)] => { + let ns_res = [] + for n in ns { + ns_res.push(Name::from_json!(n)) + } + Expr::CallClosure(Name::from_json!(n), ns_res) + } + ["CallDirect", String(l), Array(ns)] => { + let ns_res = [] + for n in ns { + ns_res.push(Name::from_json!(n)) + } + Expr::CallDirect(Label(l), ns_res) + } + ["MakeTuple", Array(ns)] => { + let ns_res = [] + for n in ns { + ns_res.push(Name::from_json!(n)) + } + Expr::MakeTuple(ns_res) + } + ["LetTuple", Array(n_ts), n, e] => { + let n_ts_res = [] + for it in n_ts { + match it { + [n, t] => n_ts_res.push((Name::from_json!(n), LowType::from_json!(t))) + _ => fail!("invalid json") + } + } + Expr::LetTuple(n_ts_res, Name::from_json!(n), Expr::from_json!(e)) + } + ["ArrayGet", n1, n2] => + Expr::ArrayGet(Name::from_json!(n1), Name::from_json!(n2)) + ["ArrayPut", n1, n2, n3] => + Expr::ArrayPut( + Name::from_json!(n1), + Name::from_json!(n2), + Name::from_json!(n3), + ) + ["ExternalArray", l] => Expr::ExternalArray(l.to_string()) + _ => fail!("invalid json") + } +} + +pub fn LowType::to_json(self : LowType) -> Json { + match self { + LowType::Unit => ["Unit"] + LowType::Bool => ["Bool"] + LowType::Int => ["Int"] + LowType::Ptr => ["Ptr"] + LowType::Double => ["Double"] + LowType::Tuple(ts) => ["Tuple", ts.to_json()] + LowType::Array(t) => ["Array", t.to_json()] + LowType::DirectFn(ts, t) => ["DirectFunction", ts.to_json(), t.to_json()] + LowType::ClosureFn(ts, t) => ["ClosureFunction", ts.to_json(), t.to_json()] + } +} + +pub fn LowType::from_json(json : Json) -> LowType! { + match json { + ["Unit"] => LowType::Unit + ["Bool"] => LowType::Bool + ["Int"] => LowType::Int + ["Double"] => LowType::Double + ["Ptr"] => LowType::Ptr + ["Tuple", Array(ts)] => { + let ts_res = [] + for t in ts { + ts_res.push(LowType::from_json!(t)) + } + LowType::Tuple(ts_res) + } + ["Array", t] => LowType::Array(LowType::from_json!(t)) + ["DirectFunction", Array(ts), t] => { + let ts_res = [] + for t in ts { + ts_res.push(LowType::from_json!(t)) + } + LowType::DirectFn(ts_res, LowType::from_json!(t)) + } + ["ClosureFunction", Array(ts), t] => { + let ts_res = [] + for t in ts { + ts_res.push(LowType::from_json!(t)) + } + LowType::ClosureFn(ts_res, LowType::from_json!(t)) + } + _ => fail!("invalid json") + } +} + +pub fn Closure::to_json(self : Closure) -> Json { + { + "name": self.name._.to_json(), + "actual_free_vars": self.actual_free_vars.to_json(), + } +} + +pub fn Closure::from_json(json : Json) -> Closure! { + match json { + { "name": String(name), "actual_free_vars": Array(actual_free_vars) } => { + let actual_free_vars_res = [] + for n in actual_free_vars { + actual_free_vars_res.push(Name::from_json!(n)) + } + { name: Label(name), actual_free_vars: actual_free_vars_res } + } + _ => fail!("invalid json") + } +} + +pub fn FuncDef::to_json(self : FuncDef) -> Json { + { + "name": self.name._.to_json(), + "old_name": self.old_name.to_json(), + "is_closure": self.is_closure.to_json(), + "ty": self.ty.to_json(), + "args": { + let res = [] + for nt in self.args { + let (n, t) = nt + res.push(Json::Array([n.to_json(), t.to_json()])) + } + Array(res) + }, + "formal_free_vars": { + let res = [] + for nt in self.formal_free_vars { + let (n, t) = nt + res.push(Json::Array([n.to_json(), t.to_json()])) + } + Array(res) + }, + "body": self.body.to_json(), + } +} + +pub fn FuncDef::from_json(json : Json) -> FuncDef! { + match json { + { + "name": String(name), + "old_name": n, + "is_closure": b, + "ty": t, + "args": Array(args), + "formal_free_vars": Array(formal_free_vars), + "body": body, + } => { + let args_res = [] + for nt in args { + match nt { + [n, t] => args_res.push((Name::from_json!(n), LowType::from_json!(t))) + _ => fail!("invalid json") + } + } + let formal_free_vars_res = [] + for nt in formal_free_vars { + match nt { + [n, t] => + formal_free_vars_res.push( + (Name::from_json!(n), LowType::from_json!(t)), + ) + _ => fail!("invalid json") + } + } + { + name: Label(name), + old_name: Name::from_json!(n), + is_closure: @json.from_json!(b), + ty: LowType::from_json!(t), + args: args_res, + formal_free_vars: formal_free_vars_res, + body: Expr::from_json!(body), + } + } + _ => fail!("invalid json") + } +} + +pub fn Program::to_json(self : Program) -> Json { + { + "fundefs": Array(self.fundefs.map(FuncDef::to_json)), + "body": self.body.to_json(), + } +} + +pub fn Program::from_json(json : Json) -> Program! { + match json { + { "fundefs": Array(fundefs), "body": body } => { + let fundefs_res = [] + for f in fundefs { + fundefs_res.push(FuncDef::from_json!(f)) + } + { fundefs: fundefs_res, body: Expr::from_json!(body) } + } + _ => fail!("invalid json") + } +} diff --git a/src/closure_eval/interpreter.mbt b/src/closure_eval/interpreter.mbt new file mode 100644 index 0000000..eacc102 --- /dev/null +++ b/src/closure_eval/interpreter.mbt @@ -0,0 +1,296 @@ +struct ClosureInterpreter { + extern_fns : Map[String, (Array[Value]) -> Value] + functions : Map[String, @closure.FuncDef] +} + +pub typealias Name = @types.Name + +pub typealias InterpreterLocalVars = @immut/hashmap.T[Name, Value] + +pub enum Value { + Unit + Int(Int) + Double(Double) + Tuple(Array[Value]) + Array(Array[Value]) + ExternFn(String) + Closure(@closure.FuncDef, Array[Value]) +} derive(Show) + +pub fn Value::op_equal(self : Value, other : Value) -> Bool { + match (self, other) { + (Unit, Unit) => true + (Int(x), Int(y)) => x == y + (Double(x), Double(y)) => x == y + (Tuple(xs), Tuple(ys)) => xs == ys + (Array(xs), Array(ys)) => xs == ys + (ExternFn(x), ExternFn(y)) => x == y + (Closure(_, _), Closure(_, _)) => false + _ => false + } +} + +pub fn ClosureInterpreter::new() -> ClosureInterpreter { + { extern_fns: Map::new(), functions: Map::new() } +} + +pub fn ClosureInterpreter::add_extern_fn( + self : ClosureInterpreter, + name : String, + f : (Array[Value]) -> Value +) -> Unit { + self.extern_fns.set(name, f) +} + +fn find(env : InterpreterLocalVars, name : Name) -> Value!Failure { + env.find(name).or_error!(Failure("variable not found: \{name}")) +} + +pub fn ClosureInterpreter::eval_full( + self : ClosureInterpreter, + expr : @closure.Program +) -> Value!Failure { + for f in expr.fundefs { + self.functions.set(f.name._, f) + } + let env = InterpreterLocalVars::new() + self.eval!(env, expr.body) +} + +pub fn ClosureInterpreter::eval( + self : ClosureInterpreter, + env : InterpreterLocalVars, + expr : @closure.Expr +) -> Value!Failure { + match expr { + Unit => Unit + Int(i) => Int(i) + Double(d) => Double(d) + Var(v) => find!(env, v) + Neg(x) => { + let x = find!(env, x) + match x { + Int(x) => Int(-x) + _ => fail!("type mismatch, neg expects Int") + } + } + Add(x, y) => { + let x = find!(env, x) + let y = find!(env, y) + match (x, y) { + (Int(x), Int(y)) => Int(x + y) + _ => fail!("type mismatch, add expects Int") + } + } + Sub(x, y) => { + let x = find!(env, x) + let y = find!(env, y) + match (x, y) { + (Int(x), Int(y)) => Int(x - y) + _ => fail!("type mismatch, sub expects Int") + } + } + Mul(x, y) => { + let x = find!(env, x) + let y = find!(env, y) + match (x, y) { + (Int(x), Int(y)) => Int(x * y) + _ => fail!("type mismatch, mul expects Int") + } + } + Div(x, y) => { + let x = find!(env, x) + let y = find!(env, y) + match (x, y) { + (Int(x), Int(y)) => Int(x / y) + _ => fail!("type mismatch, div expects Int") + } + } + FNeg(x) => { + let x = find!(env, x) + match x { + Double(x) => Double(-x) + _ => fail!("type mismatch, fneg expects Double") + } + } + FAdd(x, y) => { + let x = find!(env, x) + let y = find!(env, y) + match (x, y) { + (Double(x), Double(y)) => Double(x + y) + _ => fail!("type mismatch, fadd expects Double") + } + } + FSub(x, y) => { + let x = find!(env, x) + let y = find!(env, y) + match (x, y) { + (Double(x), Double(y)) => Double(x - y) + _ => fail!("type mismatch, fsub expects Double") + } + } + FMul(x, y) => { + let x = find!(env, x) + let y = find!(env, y) + match (x, y) { + (Double(x), Double(y)) => Double(x * y) + _ => fail!("type mismatch, fmul expects Double") + } + } + FDiv(x, y) => { + let x = find!(env, x) + let y = find!(env, y) + match (x, y) { + (Double(x), Double(y)) => Double(x / y) + _ => fail!("type mismatch, fdiv expects Double") + } + } + IfEq(x, y, e1, e2) => { + let x = find!(env, x) + let y = find!(env, y) + match (x, y) { + (Int(x), Int(y)) => + if x == y { + self.eval!(env, e1) + } else { + self.eval!(env, e2) + } + (Double(x), Double(y)) => + if x == y { + self.eval!(env, e1) + } else { + self.eval!(env, e2) + } + _ => fail!("type mismatch, ifeq expects Int or Double") + } + } + IfLe(x, y, e1, e2) => { + let x = find!(env, x) + let y = find!(env, y) + match (x, y) { + (Int(x), Int(y)) => + if x <= y { + self.eval!(env, e1) + } else { + self.eval!(env, e2) + } + (Double(x), Double(y)) => + if x <= y { + self.eval!(env, e1) + } else { + self.eval!(env, e2) + } + _ => fail!("type mismatch, ifle expects Int or Double") + } + } + Let((x, _), e1, e2) => { + let v = self.eval!(env, e1) + let new_env = env.add(x, v) + self.eval!(new_env, e2) + } + MakeClosure((n, _), c, e) => { + let closure = self.functions + .get(c.name._) + .or_error!(Failure("closure not found")) + let fv = [] + for x in c.actual_free_vars { + fv.push(find!(env, x)) + } + let new_env = env.add(n, Closure(closure, fv)) + self.eval!(new_env, e) + } + CallDirect(l, xs) => { + let args = [] + for x in xs { + args.push(find!(env, x)) + } + match self.functions.get(l._) { + Some(f) => self.eval_fn!(f, args, []) + None => { + let ext_fn = self.extern_fns + .get(l._) + .or_error!( + Failure( + "Given function \{l} is not found in both internal and external functions", + ), + ) + ext_fn(args) + } + } + } + CallClosure(n, xs) => { + let closure = find!(env, n) + let args = [] + for x in xs { + args.push(find!(env, x)) + } + match closure { + Closure(f, fv) => self.eval_fn!(f, args, fv) + _ => fail!("type mismatch, callclosure expects Closure") + } + } + MakeTuple(xs) => { + let vs = [] + for x in xs { + vs.push(find!(env, x)) + } + Tuple(vs) + } + LetTuple(xts, y, e) => { + let mut new_env = env + let y = find!(env, y) + match y { + Tuple(vs) => { + let len = xts.length() + if len != vs.length() { + fail!("tuple size mismatch") + } + for i = 0; i < len; i = i + 1 { + let (x, _) = xts[i] + new_env = new_env.add(x, vs[i]) + } + } + _ => fail!("type mismatch, lettuple expects Tuple") + } + self.eval!(new_env, e) + } + ArrayGet(arr, idx) => { + let arr = find!(env, arr) + let idx = find!(env, idx) + match (arr, idx) { + (Array(arr), Int(idx)) => arr[idx] + _ => fail!("type mismatch, get expects Array and Int") + } + } + ArrayPut(arr, idx, v) => { + let arr = find!(env, arr) + let idx = find!(env, idx) + let v = find!(env, v) + match (arr, idx) { + (Array(arr), Int(idx)) => arr[idx] = v + _ => fail!("type mismatch, put expects Array and Int") + } + Unit + } + ExternalArray(_) => fail!("ExternalArray is not supported") + } +} + +pub fn ClosureInterpreter::eval_fn( + self : ClosureInterpreter, + func : @closure.FuncDef, + args : Array[Value], + fv : Array[Value] +) -> Value!Failure { + let mut env = InterpreterLocalVars::new() + for i = 0; i < func.args.length(); i = i + 1 { + let (x, _) = func.args[i] + env = env.add(x, args[i]) + } + for i = 0; i < func.formal_free_vars.length(); i = i + 1 { + let (x, _) = func.formal_free_vars[i] + env = env.add(x, fv[i]) + } + env = env.add(func.old_name, Closure(func, fv)) + self.eval!(env, func.body) +} diff --git a/src/closure_eval/moon.pkg.json b/src/closure_eval/moon.pkg.json new file mode 100644 index 0000000..9d152d3 --- /dev/null +++ b/src/closure_eval/moon.pkg.json @@ -0,0 +1,16 @@ +{ + "import": [ + { + "path": "moonbitlang/minimbt", + "alias": "types" + }, + "moonbitlang/minimbt/closure", + "moonbitlang/minimbt/util" + ], + "test-import": [ + "moonbitlang/minimbt/knf", + "moonbitlang/minimbt/parser", + "moonbitlang/minimbt/lex", + "moonbitlang/minimbt/typing" + ] +} diff --git a/src/knf/json.mbt b/src/knf/json.mbt new file mode 100644 index 0000000..c3b757b --- /dev/null +++ b/src/knf/json.mbt @@ -0,0 +1,139 @@ +pub fn Knf::to_json(self : Knf) -> Json { + match self { + Unit => ["Unit"] + Int(i) => ["Int", Number(i.to_double())] + Double(d) => ["Double", Number(d)] + Neg(n) => ["Neg", n.to_json()] + Add(n1, n2) => ["Add", n1.to_json(), n2.to_json()] + Sub(n1, n2) => ["Sub", n1.to_json(), n2.to_json()] + Mul(n1, n2) => ["Mul", n1.to_json(), n2.to_json()] + Div(n1, n2) => ["Div", n1.to_json(), n2.to_json()] + FNeg(n) => ["FNeg", n.to_json()] + FAdd(n1, n2) => ["FAdd", n1.to_json(), n2.to_json()] + FSub(n1, n2) => ["FSub", n1.to_json(), n2.to_json()] + FMul(n1, n2) => ["FMul", n1.to_json(), n2.to_json()] + FDiv(n1, n2) => ["FDiv", n1.to_json(), n2.to_json()] + IfEq(n1, n2, k1, k2) => + ["IfEq", n1.to_json(), n2.to_json(), k1.to_json(), k2.to_json()] + IfLe(n1, n2, k1, k2) => + ["IfLe", n1.to_json(), n2.to_json(), k1.to_json(), k2.to_json()] + Let((n, t), k1, k2) => + ["Let", [n.to_json(), t.to_json()], k1.to_json(), k2.to_json()] + Var(n) => ["Var", n.to_json()] + LetRec(f, k) => ["LetRec", f.to_json(), k.to_json()] + Apply(n, ns) => ["Apply", n.to_json(), ns.to_json()] + Tuple(ns) => ["Tuple", ns.to_json()] + LetTuple(n_ts, n, k) => { + let n_ts_res = [] + for it in n_ts { + let (n, t) = it + n_ts_res.push([n.to_json(), t.to_json()]) + } + ["LetTuple", n_ts_res.to_json(), n.to_json(), k.to_json()] + } + Get(n1, n2) => ["Get", n1.to_json(), n2.to_json()] + Put(n1, n2, n3) => ["Put", n1.to_json(), n2.to_json(), n3.to_json()] + ExternalArray(n) => ["ExternalArray", n.to_json()] + ExternalFunctionApplication(s, ns) => + ["ExternalFunctionApplication", s.to_json(), ns.to_json()] + } +} + +pub fn FuncDef::to_json(self : FuncDef) -> Json { + { + "name": self.name.to_json(), + "ty": self.ty.to_json(), + "args": self.args.to_json(), + "body": self.body.to_json(), + } +} + +pub fn Knf::from_json(json : Json) -> Knf! { + match json { + ["Unit"] => Unit + ["Int", Number(i)] => Int(i.to_int()) + ["Double", Number(d)] => Double(d) + ["Neg", n] => Neg(Name::from_json!(n)) + ["Add", n1, n2] => Add(Name::from_json!(n1), Name::from_json!(n2)) + ["Sub", n1, n2] => Sub(Name::from_json!(n1), Name::from_json!(n2)) + ["Mul", n1, n2] => Mul(Name::from_json!(n1), Name::from_json!(n2)) + ["Div", n1, n2] => Div(Name::from_json!(n1), Name::from_json!(n2)) + ["FNeg", n] => FNeg(Name::from_json!(n)) + ["FAdd", n1, n2] => FAdd(Name::from_json!(n1), Name::from_json!(n2)) + ["FSub", n1, n2] => FSub(Name::from_json!(n1), Name::from_json!(n2)) + ["FMul", n1, n2] => FMul(Name::from_json!(n1), Name::from_json!(n2)) + ["FDiv", n1, n2] => FDiv(Name::from_json!(n1), Name::from_json!(n2)) + ["IfEq", n1, n2, k1, k2] => + IfEq( + Name::from_json!(n1), + Name::from_json!(n2), + Knf::from_json!(k1), + Knf::from_json!(k2), + ) + ["IfLe", n1, n2, k1, k2] => + IfLe( + Name::from_json!(n1), + Name::from_json!(n2), + Knf::from_json!(k1), + Knf::from_json!(k2), + ) + ["Let", [n, t], k1, k2] => + Let( + (Name::from_json!(n), Type::from_json!(t)), + Knf::from_json!(k1), + Knf::from_json!(k2), + ) + ["Var", n] => Var(Name::from_json!(n)) + ["LetRec", f, k] => LetRec(FuncDef::from_json!(f), Knf::from_json!(k)) + ["Apply", n, Array(ns)] => { + let rns = [] + for it in ns { + rns.push(Name::from_json!(it)) + } + Apply(Name::from_json!(n), rns) + } + ["LetTuple", Array(n_ts), n, k] => { + let n_ts_res = [] + for it in n_ts { + match it { + [n, t] => n_ts_res.push((Name::from_json!(n), Type::from_json!(t))) + _ => fail!("Knf::from_json: invalid json: \{json}") + } + } + LetTuple(n_ts_res, Name::from_json!(n), Knf::from_json!(k)) + } + ["Get", n1, n2] => Get(Name::from_json!(n1), Name::from_json!(n2)) + ["Put", n1, n2, n3] => + Put(Name::from_json!(n1), Name::from_json!(n2), Name::from_json!(n3)) + ["ExternalArray", n] => ExternalArray(Name::from_json!(n)) + ["ExternalFunctionApplication", String(s), Array(ns)] => { + let rns = [] + for it in ns { + rns.push(Name::from_json!(it)) + } + ExternalFunctionApplication(s, rns) + } + _ => fail!("Knf::from_json: invalid json: \{json}") + } +} + +pub fn FuncDef::from_json(json : Json) -> FuncDef! { + match json { + { "name": n, "ty": t, "args": Array(args), "body": k } => { + let rargs = [] + for it in args { + match it { + [n, t] => rargs.push((Name::from_json!(n), Type::from_json!(t))) + _ => fail!("FuncDef::from_json: invalid json: \{json}") + } + } + { + name: Name::from_json!(n), + ty: Type::from_json!(t), + args: rargs, + body: Knf::from_json!(k), + } + } + _ => fail!("FuncDef::from_json: invalid json: \{json}") + } +} diff --git a/src/knf/syntax_to_knf.mbt b/src/knf/syntax_to_knf.mbt index 2e1c2ca..afd16eb 100644 --- a/src/knf/syntax_to_knf.mbt +++ b/src/knf/syntax_to_knf.mbt @@ -9,6 +9,13 @@ pub fn KnfEnv::new(externals : @immut/hashmap.T[String, Type]) -> KnfEnv { { counter: 1, externals } } +pub fn KnfEnv::init_counter_from_existing( + self : KnfEnv, + existing : Knf +) -> Unit { + self.counter = knf_max_counter(existing) + 1 +} + fn KnfEnv::new_temp(self : KnfEnv) -> Name { let temp = Name::slot_only(self.counter) self.counter += 1 diff --git a/src/knf/utils.mbt b/src/knf/utils.mbt new file mode 100644 index 0000000..d1bfda5 --- /dev/null +++ b/src/knf/utils.mbt @@ -0,0 +1,66 @@ +pub fn knf_max_counter(knf : Knf) -> Int { + match knf { + Unit => 0 + Int(_) => 0 + Double(_) => 0 + Neg(x) => x.slot + Add(x, y) => @math.maximum(x.slot, y.slot) + Sub(x, y) => @math.maximum(x.slot, y.slot) + Mul(x, y) => @math.maximum(x.slot, y.slot) + Div(x, y) => @math.maximum(x.slot, y.slot) + FNeg(x) => x.slot + FAdd(x, y) => @math.maximum(x.slot, y.slot) + FSub(x, y) => @math.maximum(x.slot, y.slot) + FMul(x, y) => @math.maximum(x.slot, y.slot) + FDiv(x, y) => @math.maximum(x.slot, y.slot) + IfEq(x, y, e1, e2) => + @math.maximum( + x.slot, + @math.maximum( + y.slot, + @math.maximum(knf_max_counter(e1), knf_max_counter(e2)), + ), + ) + IfLe(x, y, e1, e2) => + @math.maximum( + x.slot, + @math.maximum( + y.slot, + @math.maximum(knf_max_counter(e1), knf_max_counter(e2)), + ), + ) + Let((n, _), e1, e2) => + @math.maximum( + n.slot, + @math.maximum(knf_max_counter(e1), knf_max_counter(e2)), + ) + Var(x) => x.slot + LetRec(f, e) => + @math.maximum( + f.name.slot, + @math.maximum(knf_max_counter(f.body), knf_max_counter(e)), + ) + Apply(x, xs) => + @math.maximum( + x.slot, + xs.map(fn(x) { x.slot }).fold(init=0, fn(a, b) { @math.maximum(a, b) }), + ) + Tuple(xs) => + xs.map(fn(x) { x.slot }).fold(init=0, fn(a, b) { @math.maximum(a, b) }) + LetTuple(xts, n, e) => + @math.maximum( + n.slot, + @math.maximum( + xts + .map(fn(x) { x.0.slot }) + .fold(init=0, fn(a, b) { @math.maximum(a, b) }), + knf_max_counter(e), + ), + ) + Get(x, y) => @math.maximum(x.slot, y.slot) + Put(x, y, z) => @math.maximum(x.slot, @math.maximum(y.slot, z.slot)) + ExternalFunctionApplication(_, xs) => + xs.map(fn(x) { x.slot }).fold(init=0, fn(a, b) { @math.maximum(a, b) }) + ExternalArray(_) => 0 + } +} diff --git a/src/name.mbt b/src/name.mbt index b2a03fe..a48d861 100644 --- a/src/name.mbt +++ b/src/name.mbt @@ -7,6 +7,22 @@ pub impl Show for Name with output(self : Name, logger : Logger) -> Unit { logger.write_string(self.to_string()) } +pub fn Name::from_string(s : String) -> Name! { + let first_dot = s.index_of(".") + if first_dot != -1 { + let name = s.substring(start=0, end=first_dot) + let slot = @strconv.parse_int!( + s.substring(start=first_dot + 1, end=s.length()), + ) + Name::name_and_slot(name, slot) + } else if s.starts_with("_") { + let slot = @strconv.parse_int!(s.substring(start=1, end=s.length())) + Name::slot_only(slot) + } else { + Name::name_only(s) + } +} + pub fn Name::to_string(self : Name) -> String { let { name, slot } = self match (name, slot) { @@ -27,3 +43,14 @@ pub fn Name::name_and_slot(name : String, slot : Int) -> Name { pub fn Name::slot_only(slot : Int) -> Name { { name: None, slot } } + +pub fn Name::to_json(self : Name) -> Json { + self.to_string().to_json() +} + +pub fn Name::from_json(json : Json) -> Name! { + match json { + Json::String(s) => Name::from_string!(s) + _ => fail!("Name::from_json: expected a string, but got \{json}") + } +} diff --git a/src/riscv/asm_stringify.mbt b/src/riscv/asm_stringify.mbt index c1e084f..2147065 100644 --- a/src/riscv/asm_stringify.mbt +++ b/src/riscv/asm_stringify.mbt @@ -1,10 +1,8 @@ -pub fn asm_stringify(asm : AssemblyFunction) -> String { - let buf = Buffer::new() - let name = asm.name - buf.write_string("\{name}:\n") - for inst in asm.body { - Show::output(inst, buf) +pub fn print_functions(asm : Array[AssemblyFunction]) -> String { + let logger = Buffer::new() + for f in asm { + f.output(logger) + logger.write_string("\n") } - buf.write_string("\n") - buf.to_string() + logger.to_string() }