diff --git a/lang/src/llvm_ir/boxes/builder.hako b/lang/src/llvm_ir/boxes/builder.hako index 2d7c13a1..68b894c7 100644 --- a/lang/src/llvm_ir/boxes/builder.hako +++ b/lang/src/llvm_ir/boxes/builder.hako @@ -1,3 +1,13 @@ +using "../instructions/const.hako" as ConstInst +using "../instructions/binop.hako" as BinOpInst +using "../instructions/compare.hako" as CompareInst +using "../instructions/ret.hako" as RetInst +using "../instructions/branch.hako" as BranchInst +using "../instructions/jump.hako" as JumpInst +using "../instructions/copy.hako" as CopyInst +using "../instructions/phi.hako" as PhiInst +using "../instructions/loopform.hako" as LoopFormInst + // LLVMBuilderBox — 命令構築(v0: const/binop/ret の骨格) static box LLVMBuilderBox { program_ret0(){ @@ -125,4 +135,258 @@ static box LLVMBuilderBox { "{\\\"op\\\":\\\"const\\\",\\\"dst\\\":3,\\\"value\\\":{\\\"type\\\":\\\"i64\\\",\\\"value\\\":0}}," + "{\\\"op\\\":\\\"ret\\\",\\\"value\\\":3}] } ] } ] }" } + + // 新しい統合定数命令のテスト - ConstInstを使用 + test_const_instructions(){ + local result = {} + + // i64定数テスト + result.i64_const = ConstInst.lower_const(1, {"type": "i64", "value": 42}) + + // f64定数テスト + result.f64_const = ConstInst.lower_const(2, {"type": "f64", "value": 3.14}) + + // void定数テスト + result.void_const = ConstInst.lower_const(3, {"type": "void"}) + + // 文字列定数テスト + result.string_const = ConstInst.lower_const(4, {"type": "string", "value": "Hello, Hakorune!"}) + + // StringBoxハンドルテスト + result.handle_const = ConstInst.lower_const(5, {"type": {"kind": "handle", "box_type": "StringBox"}, "value": "Boxed String"}) + + return result + } + + // 単純な定数命令を使ったプログラム生成 + program_with_new_const(value, const_type){ + local const_inst = ConstInst.lower_const(1, {"type": const_type, "value": value}) + return "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [ { \"id\": 0, \"instructions\": [" + + const_inst + "," + + "{\"op\":\"ret\",\"value\":1}] } ] } ] }" + } + + // 新しい統合二項演算命令のテスト - BinOpInstを使用 + test_binop_instructions(){ + local result = {} + + // 算術演算テスト + result.add = BinOpInst.lower_binop("+", 1, 2, 3) + result.sub = BinOpInst.lower_binop("-", 1, 2, 3) + result.mul = BinOpInst.lower_binop("*", 1, 2, 3) + result.div = BinOpInst.lower_binop("/", 1, 2, 3) + result.mod = BinOpInst.lower_binop("%", 1, 2, 3) + + // ビット演算テスト + result.and = BinOpInst.lower_binop("&", 1, 2, 3) + result.or = BinOpInst.lower_binop("|", 1, 2, 3) + result.xor = BinOpInst.lower_binop("^", 1, 2, 3) + result.shl = BinOpInst.lower_binop("<<", 1, 2, 3) + result.shr = BinOpInst.lower_binop(">>", 1, 2, 3) + + // 比較演算テスト(compareに委譲) + result.eq = BinOpInst.lower_binop("==", 1, 2, 3) + result.ne = BinOpInst.lower_binop("!=", 1, 2, 3) + result.lt = BinOpInst.lower_binop("<", 1, 2, 3) + result.gt = BinOpInst.lower_binop(">", 1, 2, 3) + result.le = BinOpInst.lower_binop("<=", 1, 2, 3) + result.ge = BinOpInst.lower_binop(">=", 1, 2, 3) + + return result + } + + // 二項演算命令を使ったプログラム生成 + program_with_new_binop(lhs, rhs, op){ + local lhs_const = ConstInst.lower_const(1, {"type": "i64", "value": lhs}) + local rhs_const = ConstInst.lower_const(2, {"type": "i64", "value": rhs}) + local binop_inst = BinOpInst.lower_binop(op, 1, 2, 3) + local ret_inst = RetInst.lower_return(3) + + return "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [ { \"id\": 0, \"instructions\": [" + + lhs_const + "," + + rhs_const + "," + + binop_inst + "," + + ret_inst + "] } ] } ] }" + } + + // 全命令の統合テスト + test_all_instructions() { + local result = {} + + // 定数命令テスト + result.const = ConstInst.lower_const(1, {"type": "i64", "value": 42}) + + // 二項演算命令テスト + result.binop = BinOpInst.lower_binop("+", 1, 2, 3) + + // 比較命令テスト + result.compare = CompareInst.lower_compare(">", 1, 2, 3) + + // リターン命令テスト + result.ret = RetInst.lower_return(3) + + return result + } + + // 完全なプログラム生成例 + generate_example_program() { + // プログラム: 42 + 100 > 50 ? 1 : 0 + local const1 = ConstInst.lower_const(1, {"type": "i64", "value": 42}) + local const2 = ConstInst.lower_const(2, {"type": "i64", "value": 100}) + local const3 = ConstInst.lower_const(3, {"type": "i64", "value": 50}) + local add = BinOpInst.lower_binop("+", 1, 2, 4) + local cmp = CompareInst.lower_compare(">", 4, 3, 5) + local const4 = ConstInst.lower_const(6, {"type": "i64", "value": 1}) + local const5 = ConstInst.lower_const(7, {"type": "i64", "value": 0}) + + return "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [ { \"id\": 0, \"instructions\": [" + + const1 + "," + + const2 + "," + + const3 + "," + + add + "," + + cmp + "," + + const4 + "," + + const5 + "," + + "{\"op\":\"ret\",\"value\":6}] } ] } ] }" + } + + // Phase v1制御フロー命令の統合テスト + test_control_flow_instructions() { + local result = {} + + // 分岐命令テスト + result.branch = BranchInst.lower_branch(3, 1, 2) + + // ジャンプ命令テスト + result.jump = JumpInst.lower_jump(5) + + // コピー命令テスト + result.copy = CopyInst.lower_copy(4, 2) + + return result + } + + // 制御フロー命令を使ったプログラム生成 + program_with_control_flow() { + // if (x > 0) { return 1 } else { return 0 } + local const_x = ConstInst.lower_const(1, {"type": "i64", "value": 10}) + local const_0 = ConstInst.lower_const(2, {"type": "i64", "value": 0}) + local const_1 = ConstInst.lower_const(3, {"type": "i64", "value": 1}) + local const_2 = ConstInst.lower_const(4, {"type": "i64", "value": 2}) + + local cmp = CompareInst.lower_compare(">", 1, 2, 5) + local branch = BranchInst.lower_branch(5, 1, 2) + local ret1 = RetInst.lower_return(3) + local ret2 = RetInst.lower_return(4) + + // ブロック1 (then) + local block1 = "{\"id\":1,\"instructions\":[" + ret1 + "]}" + + // ブロック2 (else) + local block2 = "{\"id\":2,\"instructions\":[" + ret2 + "]}" + + // ブロック0 (entry) + local block0 = "{\"id\":0,\"instructions\":[" + const_x + "," + const_0 + "," + const_1 + "," + const_2 + "," + cmp + "," + branch + "]}" + + return "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [" + block0 + "," + block1 + "," + block2 + "] } ] }" + } + + // 全命令の統合テスト(v0 + v1) + test_all_instructions_v1() { + local result = me.test_all_instructions() + + // Phase v1命令を追加 + result.branch = BranchInst.lower_branch(3, 1, 2) + result.jump = JumpInst.lower_jump(5) + result.copy = CopyInst.lower_copy(4, 2) + + return result + } + + // ====== Phase v2-A: PHI Instructions ====== + + // PHI命令の生成(ヘルパー) + // incoming_list: [{"value":1,"block":1}, {"value":2,"block":2}, ...] + emit_phi(dst, incoming_list) { + local phi_box = new PhiInst.LLVMPhiInstructionBox() + return phi_box.lower_phi(dst, incoming_list) + } + + // PHI統合テストプログラム: if-then-else with PHI merge + // val_then と val_else の値を PHI で統合 + program_phi_merge(val_then, val_else) { + // Block 0: Entry (分岐判定) + local const1 = ConstInst.inst_const_i64(1, 1) + local cmp = CompareInst.inst_compare_eq(2, 1, 1) + local branch = BranchInst.inst_if_then_else(2, 1, 2) + local b0 = "{\"id\":0,\"instructions\":[" + const1 + "," + cmp + "," + branch + "]}" + + // Block 1: Then分岐 + local const_then = ConstInst.inst_const_i64(3, val_then) + local jump1 = JumpInst.lower_jump(3) + local b1 = "{\"id\":1,\"instructions\":[" + const_then + "," + jump1 + "]}" + + // Block 2: Else分岐 + local const_else = ConstInst.inst_const_i64(4, val_else) + local jump2 = JumpInst.lower_jump(3) + local b2 = "{\"id\":2,\"instructions\":[" + const_else + "," + jump2 + "]}" + + // Block 3: PHI merge + return + local incoming = new ArrayBox() + local item1 = new MapBox() + item1.set("value", 3) + item1.set("block", 1) + incoming.push(item1) + + local item2 = new MapBox() + item2.set("value", 4) + item2.set("block", 2) + incoming.push(item2) + + local phi = me.emit_phi(5, incoming) + local const_zero = ConstInst.inst_const_i64(6, 0) + local ret = RetInst.inst_ret_value(6) + local b3 = "{\"id\":3,\"instructions\":[" + phi + "," + const_zero + "," + ret + "]}" + + return "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [" + b0 + "," + b1 + "," + b2 + "," + b3 + "] } ] }" + } + + // 全命令の統合テスト(v0 + v1 + v2-A) + test_all_instructions_v2a() { + local result = me.test_all_instructions_v1() + + // Phase v2-A命令を追加 + local phi_incoming = new ArrayBox() + local phi_item1 = new MapBox() + phi_item1.set("value", 1) + phi_item1.set("block", 1) + phi_incoming.push(phi_item1) + + local phi_item2 = new MapBox() + phi_item2.set("value", 2) + phi_item2.set("block", 2) + phi_incoming.push(phi_item2) + + result.phi = me.emit_phi(5, phi_incoming) + + return result + } + + // Phase v2 LoopForm 命令 + // Args: + // self: static box receiver (implicit) + // loop_id: ループID + // blocks: ブロックIDマップ {"preheader": 10, "header": 11, ...} + // condition_vid: 条件式の値ID + // options: オプション設定(省略可) + // Returns: + // LoopForm JSON 文字列 + lower_loopform(self, loop_id, blocks, condition_vid, options) { + return LoopFormInst.lower_loopform(self, loop_id, blocks, condition_vid, options) + } + + // LoopForm 命令を emit(builder メソッド) + emit_loopform(self, loop_id, blocks, condition_vid, options) { + return me.lower_loopform(self, loop_id, blocks, condition_vid, options) + } } diff --git a/lang/src/llvm_ir/instructions/binop.hako b/lang/src/llvm_ir/instructions/binop.hako new file mode 100644 index 00000000..6e791c88 --- /dev/null +++ b/lang/src/llvm_ir/instructions/binop.hako @@ -0,0 +1,119 @@ +// LLVM BinOp Instruction Box — Python binop.py のHakorune実装 +// MIR二項演算命令をJSON形式に変換し、C++バックエンドに渡す + +static box LLVMBinOpInstructionBox { + + // メインエントリーポイント - Pythonのlower_binop()に相当 + lower_binop(op, lhs, rhs, dst) { + // 比較演算子はcompare命令に委譲 + if op == "==" || op == "!=" || op == "<" || op == ">" || op == "<=" || op == ">=" { + return me._delegate_to_compare(op, lhs, rhs, dst) + } + + // 算術演算子 + if op == "+" { + return me.inst_binop_add(lhs, rhs, dst) + } + + if op == "-" { + return me.inst_binop_sub(lhs, rhs, dst) + } + + if op == "*" { + return me.inst_binop_mul(lhs, rhs, dst) + } + + if op == "/" { + return me.inst_binop_div(lhs, rhs, dst) + } + + if op == "%" { + return me.inst_binop_mod(lhs, rhs, dst) + } + + // ビット演算子 + if op == "&" { + return me.inst_binop_and(lhs, rhs, dst) + } + + if op == "|" { + return me.inst_binop_or(lhs, rhs, dst) + } + + if op == "^" { + return me.inst_binop_xor(lhs, rhs, dst) + } + + if op == "<<" { + return me.inst_binop_shl(lhs, rhs, dst) + } + + if op == ">>" { + return me.inst_binop_shr(lhs, rhs, dst) + } + + // 未知の演算子はaddにフォールバック + return me.inst_binop_add(lhs, rhs, dst) + } + + // 比較演算子の委譲 + _delegate_to_compare(op, lhs, rhs, dst) { + // JSON: {"op":"compare","dst":3,"operation":">","lhs":1,"rhs":2} + return "{\"op\":\"compare\",\"dst\":" + dst + ",\"operation\":\"" + op + "\",\"lhs\":" + lhs + ",\"rhs\":" + rhs + "}" + } + + // 算術演算子 + inst_binop_add(lhs, rhs, dst) { + return "{\"op\":\"binop\",\"dst\":" + dst + ",\"operation\":\"+\",\"lhs\":" + lhs + ",\"rhs\":" + rhs + "}" + } + + inst_binop_sub(lhs, rhs, dst) { + return "{\"op\":\"binop\",\"dst\":" + dst + ",\"operation\":\"-\",\"lhs\":" + lhs + ",\"rhs\":" + rhs + "}" + } + + inst_binop_mul(lhs, rhs, dst) { + return "{\"op\":\"binop\",\"dst\":" + dst + ",\"operation\":\"*\",\"lhs\":" + lhs + ",\"rhs\":" + rhs + "}" + } + + inst_binop_div(lhs, rhs, dst) { + return "{\"op\":\"binop\",\"dst\":" + dst + ",\"operation\":\"/\",\"lhs\":" + lhs + ",\"rhs\":" + rhs + "}" + } + + inst_binop_mod(lhs, rhs, dst) { + return "{\"op\":\"binop\",\"dst\":" + dst + ",\"operation\":\"%\",\"lhs\":" + lhs + ",\"rhs\":" + rhs + "}" + } + + // ビット演算子 + inst_binop_and(lhs, rhs, dst) { + return "{\"op\":\"binop\",\"dst\":" + dst + ",\"operation\":\"&\",\"lhs\":" + lhs + ",\"rhs\":" + rhs + "}" + } + + inst_binop_or(lhs, rhs, dst) { + return "{\"op\":\"binop\",\"dst\":" + dst + ",\"operation\":\"|\",\"lhs\":" + lhs + ",\"rhs\":" + rhs + "}" + } + + inst_binop_xor(lhs, rhs, dst) { + return "{\"op\":\"binop\",\"dst\":" + dst + ",\"operation\":\"^\",\"lhs\":" + lhs + ",\"rhs\":" + rhs + "}" + } + + inst_binop_shl(lhs, rhs, dst) { + return "{\"op\":\"binop\",\"dst\":" + dst + ",\"operation\":\"<<\",\"lhs\":" + lhs + ",\"rhs\":" + rhs + "}" + } + + inst_binop_shr(lhs, rhs, dst) { + return "{\"op\":\"binop\",\"dst\":" + dst + ",\"operation\":\">>\",\"lhs\":" + lhs + ",\"rhs\":" + rhs + "}" + } + + // デバッグ用 - 生成された命令の確認 + debug_binop(op, lhs, rhs, dst) { + local json = me.lower_binop(op, lhs, rhs, dst) + print("Generated binop instruction: " + json) + return json + } + + // 文字列連結の特殊処理(簡易版) + // Python: concat_hh → Hakorune: binop "+" に委譲 + inst_string_concat(lhs, rhs, dst) { + return me.inst_binop_add(lhs, rhs, dst) + } +} diff --git a/lang/src/llvm_ir/instructions/branch.hako b/lang/src/llvm_ir/instructions/branch.hako new file mode 100644 index 00000000..bcb6f3e4 --- /dev/null +++ b/lang/src/llvm_ir/instructions/branch.hako @@ -0,0 +1,47 @@ +// LLVM Branch Instruction Box — Python branch.py のHakorune実装 +// MIR分岐命令をJSON形式に変換し、C++バックエンドに渡す + +static box LLVMBranchInstructionBox { + + // メインエントリーポイント - Pythonのlower_branch()に相当 + lower_branch(cond_vid, then_bid, else_bid) { + return me.inst_branch(cond_vid, then_bid, else_bid) + } + + // 分岐命令の生成 + inst_branch(cond_vid, then_bid, else_bid) { + // JSON: {"op":"branch","cond":3,"then":1,"else":2} + return "{\"op\":\"branch\",\"cond\":" + cond_vid + ",\"then\":" + then_bid + ",\"else\":" + else_bid + "}" + } + + // デバッグ用 - 生成された命令の確認 + debug_branch(cond_vid, then_bid, else_bid) { + local json = me.lower_branch(cond_vid, then_bid, else_bid) + print("Generated branch instruction: " + json) + return json + } + + // 条件付きジャンプのヘルパー + if_then_else(condition, then_block, else_block) { + return me.inst_branch(condition, then_block, else_block) + } + + // 単純な条件分岐(true/false) + simple_branch(cond_val, true_block, false_block) { + // cond_val: 0=false, 1=true + return me.inst_branch(cond_val, true_block, false_block) + } + + // 複数の分岐をまとめて生成 + batch_branch(branch_list) { + local results = [] + local i = 0 + while i < branch_list.size() { + local branch = branch_list[i] + local json = me.lower_branch(branch.cond, branch.then_block, branch.else_block) + results.push(json) + i = i + 1 + } + return results + } +} diff --git a/lang/src/llvm_ir/instructions/compare.hako b/lang/src/llvm_ir/instructions/compare.hako new file mode 100644 index 00000000..5d73cf7c --- /dev/null +++ b/lang/src/llvm_ir/instructions/compare.hako @@ -0,0 +1,71 @@ +// LLVM Compare Instruction Box — Python compare.py のHakorune実装 +// MIR比較命令をJSON形式に変換し、C++バックエンドに渡す + +static box LLVMCompareInstructionBox { + + // メインエントリーポイント - Pythonのlower_compare()に相当 + lower_compare(op, lhs, rhs, dst) { + // 比較演算子の検証 + if !me._is_valid_operator(op) { + print("Warning: Invalid compare operator: " + op + ", defaulting to ==") + op = "==" + } + + return me.inst_compare(op, lhs, rhs, dst) + } + + // 有効な比較演算子の検証 + _is_valid_operator(op) { + return op == "==" || op == "!=" || op == "<" || op == ">" || op == "<=" || op == ">=" + } + + // 比較命令の生成 + inst_compare(op, lhs, rhs, dst) { + return "{\"op\":\"compare\",\"dst\":" + dst + ",\"operation\":\"" + op + "\",\"lhs\":" + lhs + ",\"rhs\":" + rhs + "}" + } + + // 各比較演算子の個別メソッド + inst_eq(lhs, rhs, dst) { + return me.inst_compare("==", lhs, rhs, dst) + } + + inst_ne(lhs, rhs, dst) { + return me.inst_compare("!=", lhs, rhs, dst) + } + + inst_lt(lhs, rhs, dst) { + return me.inst_compare("<", lhs, rhs, dst) + } + + inst_gt(lhs, rhs, dst) { + return me.inst_compare(">", lhs, rhs, dst) + } + + inst_le(lhs, rhs, dst) { + return me.inst_compare("<=", lhs, rhs, dst) + } + + inst_ge(lhs, rhs, dst) { + return me.inst_compare(">=", lhs, rhs, dst) + } + + // デバッグ用 - 生成された命令の確認 + debug_compare(op, lhs, rhs, dst) { + local json = me.lower_compare(op, lhs, rhs, dst) + print("Generated compare instruction: " + json) + return json + } + + // 複数の比較をまとめて生成(効率化) + batch_compare(compare_list) { + local results = [] + local i = 0 + while i < compare_list.size() { + local cmp = compare_list[i] + local json = me.lower_compare(cmp.op, cmp.lhs, cmp.rhs, cmp.dst) + results.push(json) + i = i + 1 + } + return results + } +} diff --git a/lang/src/llvm_ir/instructions/const.hako b/lang/src/llvm_ir/instructions/const.hako new file mode 100644 index 00000000..c6d2f74d --- /dev/null +++ b/lang/src/llvm_ir/instructions/const.hako @@ -0,0 +1,80 @@ +// LLVM Const Instruction Box — Python const.py のHakorune実装 +// MIR定数命令をJSON形式に変換し、C++バックエンドに渡す + +static box LLVMConstInstructionBox { + + // メインエントリーポイント - Pythonのlower_const()に相当 + lower_const(dst, value_dict) { + local const_type = value_dict.type + local const_val = value_dict.value + + if const_type == "i64" { + return me.inst_const_i64(dst, const_val) + } + + if const_type == "f64" { + return me.inst_const_f64(dst, const_val) + } + + if const_type == "void" { + return me.inst_const_void(dst) + } + + if const_type == "string" { + return me.inst_const_string(dst, const_val) + } + + // 未知の型の場合はi64の0として扱う(Pythonのフォールバックと同じ) + return me.inst_const_i64(dst, 0) + } + + // i64整数定数 + inst_const_i64(dst, value) { + // JSON形式の定数命令を生成 + // {"op":"const","dst":1,"value":{"type":"i64","value":42}} + return "{\"op\":\"const\",\"dst\":" + dst + ",\"value\":{\"type\":\"i64\",\"value\":" + value + "}}" + } + + // f64浮動小数点定数 + inst_const_f64(dst, value) { + // JSON形式の定数命令を生成 + // {"op":"const","dst":1,"value":{"type":"f64","value":3.14}} + return "{\"op\":\"const\",\"dst\":" + dst + ",\"value\":{\"type\":\"f64\",\"value\":" + value + "}}" + } + + // void/null定数 - i64の0として表現 + inst_const_void(dst) { + // Pythonの実装ではi64の0を使用 + return "{\"op\":\"const\",\"dst\":" + dst + ",\"value\":{\"type\":\"void\",\"value\":0}}" + } + + // 文字列定数 + inst_const_string(dst, str_value) { + // JSON文字列エスケープ処理 + local escaped = me._escape_json_string(str_value) + return "{\"op\":\"const\",\"dst\":" + dst + ",\"value\":{\"type\":\"string\",\"value\":\"" + escaped + "\"}}" + } + + // JSON文字列エスケープヘルパー + _escape_json_string(s) { + if s == null { + return "" + } + + local result = s.toString() + result = result.replace("\\", "\\\\") + result = result.replace("\"", "\\\"") + result = result.replace("\n", "\\n") + result = result.replace("\t", "\\t") + result = result.replace("\r", "\\r") + + return result + } + + // デバッグ用 - 生成された命令の確認 + debug_const(dst, value_dict) { + local json = me.lower_const(dst, value_dict) + print("Generated const instruction: " + json) + return json + } +} diff --git a/lang/src/llvm_ir/instructions/copy.hako b/lang/src/llvm_ir/instructions/copy.hako new file mode 100644 index 00000000..e2bd5f20 --- /dev/null +++ b/lang/src/llvm_ir/instructions/copy.hako @@ -0,0 +1,51 @@ +// LLVM Copy Instruction Box — Python copy.py のHakorune実装 +// MIRコピー命令をJSON形式に変換し、C++バックエンドに渡す + +static box LLVMCopyInstructionBox { + + // メインエントリーポイント - Pythonのlower_copy()に相当 + lower_copy(dst, src) { + return me.inst_copy(dst, src) + } + + // コピー命令の生成 + inst_copy(dst, src) { + // JSON: {"op":"copy","dst":4,"src":2} + return "{\"op\":\"copy\",\"dst\":" + dst + ",\"src\":" + src + "}" + } + + // デバッグ用 - 生成された命令の確認 + debug_copy(dst, src) { + local json = me.lower_copy(dst, src) + print("Generated copy instruction: " + json) + return json + } + + // 値の移動(エイリアス) + move_value(src_reg, dst_reg) { + return me.inst_copy(dst_reg, src_reg) + } + + // レジスタのコピー + copy_register(src, dst) { + return me.inst_copy(dst, src) + } + + // パラメータのコピー + copy_param(param_num, dst_reg) { + return me.inst_copy(dst_reg, param_num) + } + + // 複数のコピーをまとめて生成 + batch_copy(copy_list) { + local results = [] + local i = 0 + while i < copy_list.size() { + local copy = copy_list[i] + local json = me.lower_copy(copy.dst, copy.src) + results.push(json) + i = i + 1 + } + return results + } +} diff --git a/lang/src/llvm_ir/instructions/jump.hako b/lang/src/llvm_ir/instructions/jump.hako new file mode 100644 index 00000000..e741d939 --- /dev/null +++ b/lang/src/llvm_ir/instructions/jump.hako @@ -0,0 +1,56 @@ +// LLVM Jump Instruction Box — Python jump.py のHakorune実装 +// MIRジャンプ命令をJSON形式に変換し、C++バックエンドに渡す + +static box LLVMJumpInstructionBox { + + // メインエントリーポイント - Pythonのlower_jump()に相当 + lower_jump(target_bid) { + return me.inst_jump(target_bid) + } + + // ジャンプ命令の生成 + inst_jump(target_bid) { + // JSON: {"op":"jump","target":5} + return "{\"op\":\"jump\",\"target\":" + target_bid + "}" + } + + // デバッグ用 - 生成された命令の確認 + debug_jump(target_bid) { + local json = me.lower_jump(target_bid) + print("Generated jump instruction: " + json) + return json + } + + // ラベルへのジャンプ + jump_to_label(label_id) { + return me.inst_jump(label_id) + } + + // ループヘッドへのジャンプ + jump_loop_head(loop_block) { + return me.inst_jump(loop_block) + } + + // ループ終了へのジャンプ + jump_loop_end(exit_block) { + return me.inst_jump(exit_block) + } + + // 関数終了へのジャンプ + jump_to_epilogue(epilogue_block) { + return me.inst_jump(epilogue_block) + } + + // 複数のジャンプをまとめて生成 + batch_jump(jump_list) { + local results = [] + local i = 0 + while i < jump_list.size() { + local jump = jump_list[i] + local json = me.lower_jump(jump.target) + results.push(json) + i = i + 1 + } + return results + } +} diff --git a/lang/src/llvm_ir/instructions/loopform.hako b/lang/src/llvm_ir/instructions/loopform.hako new file mode 100644 index 00000000..80426979 --- /dev/null +++ b/lang/src/llvm_ir/instructions/loopform.hako @@ -0,0 +1,271 @@ +// LLVM LoopForm Instruction Box — Python loopform.py のHakorune実装 +// 実験的ループ正規化(paper-e-loop-signal-ir)をJSON形式に変換し、C++バックエンドに渡す +// +// LoopForm は 6-block 構造でループを表現: +// preheader → header → body → dispatch → latch → exit +// ↑__________________| +// +// 特徴: +// - break/continue を tag/payload PHI で明示的に処理 +// - Safepoint 自動挿入(GC 安全点) +// - Iteration counter (structural PHI) + +static box LLVMLoopFormInstructionBox { + + // メインエントリーポイント - Pythonのlower_while_loopform()に相当 + // Stage 1: 基本 LoopForm 構造の JSON 生成 + // Stage 2: PHI incoming 配列化、computed フラグ追加 + // + // Args: + // loop_id: ループID(整数) + // blocks: ブロックIDマップ + // 形式: {"preheader": 10, "header": 11, "body": 12, + // "dispatch": 13, "latch": 14, "exit": 15} + // condition_vid: 条件式の値ID(MIR condition) + // options: オプション設定(MapBox) + // - mode: "mir" | "payload" (default: "mir") + // - payload_max: Payload モード時の上限 (default: 1000000) + // - use_guard: Structural guard 使用 (default: false) + // - enable_safepoint: Safepoint 有効化 (default: true) + // + // Returns: + // JSON文字列: {"op":"loopform","loop_id":1,"blocks":{...},...} + // Stage 2: Header PHI/Dispatch PHI は incoming 配列 + computed フラグ + // + lower_loopform(self, loop_id, blocks, condition_vid, options) { + // Null チェック + if blocks == null { + return me._loopform_error_fallback(self, "blocks is null") + } + + local json = "{" + json = json + "\"op\":\"loopform\"" + json = json + ",\"loop_id\":" + loop_id.toString() + + // Blocks 構造を JSON 化 + json = json + ",\"blocks\":" + me._build_blocks_json(self, blocks) + + // Header PHI 情報を JSON 化 + json = json + ",\"header_phi\":" + me._build_header_phi_json(self, blocks) + + // Condition 情報を JSON 化 + json = json + ",\"condition\":" + me._build_condition_json(self, condition_vid, options) + + // Dispatch PHI 情報を JSON 化 + json = json + ",\"dispatch_phis\":" + me._build_dispatch_phis_json(self, blocks) + + // Safepoint 情報を JSON 化 + json = json + ",\"safepoint\":" + me._build_safepoint_json(self, options) + + json = json + "}" + return json + } + + // Blocks マップを JSON 化 + // Args: + // blocks: {"preheader": 10, "header": 11, ...} + // Returns: + // JSON: {"preheader":10,"header":11,...} + _build_blocks_json(self, blocks) { + local json = "{" + + // 6つのブロックIDを取得 + local preheader = blocks.get("preheader") + local header = blocks.get("header") + local body = blocks.get("body") + local dispatch = blocks.get("dispatch") + local latch = blocks.get("latch") + local exit = blocks.get("exit") + + json = json + "\"preheader\":" + preheader.toString() + json = json + ",\"header\":" + header.toString() + json = json + ",\"body\":" + body.toString() + json = json + ",\"dispatch\":" + dispatch.toString() + json = json + ",\"latch\":" + latch.toString() + json = json + ",\"exit\":" + exit.toString() + + json = json + "}" + return json + } + + // Header PHI 情報を JSON 化 + // Iteration PHI: φ(0 from preheader, i_next from latch) + // Stage 2: incoming 配列形式 - 完全な PHI 構造 + // Args: + // blocks: ブロックIDマップ + // Returns: + // JSON: {"dst":0,"incoming":[{"value":0,"block":10},{"value":0,"block":14,"computed":true}]} + _build_header_phi_json(self, blocks) { + local preheader = blocks.get("preheader") + local latch = blocks.get("latch") + + local json = "{" + json = json + "\"dst\":0" // Placeholder, C++ が決定 + json = json + ",\"incoming\":[" + + // Incoming 1: Preheader からの初期値(定数0) + json = json + "{\"value\":0,\"block\":" + preheader.toString() + "}" + + // Incoming 2: Latch からの継続値(i_next_latch = hdr_phi + 1) + json = json + ",{\"value\":0,\"block\":" + latch.toString() + ",\"computed\":true}" + + json = json + "]" + json = json + "}" + return json + } + + // Condition 情報を JSON 化 + // Args: + // vid: MIR condition の値ID + // options: オプション設定 + // Returns: + // JSON: {"mode":"mir","vid":5} + _build_condition_json(self, vid, options) { + local mode = "mir" // Default mode + local payload_max = 1000000 + local use_guard = 0 + + // Options から設定を取得 + if options != null { + local has_mode = options.has("mode") + if has_mode { + mode = options.get("mode") + } + + local has_max = options.has("payload_max") + if has_max { + payload_max = options.get("payload_max") + } + + local has_guard = options.has("use_guard") + if has_guard { + use_guard = options.get("use_guard") + } + } + + local json = "{" + json = json + "\"mode\":\"" + mode + "\"" + json = json + ",\"vid\":" + vid.toString() + + // Payload モード時は max 値を含める + if mode == "payload" { + json = json + ",\"payload_max\":" + payload_max.toString() + } + + // Guard 使用時 + if use_guard != 0 { + json = json + ",\"use_guard\":true" + } + + json = json + "}" + return json + } + + // Dispatch PHI 情報を JSON 化 + // Tag PHI: φ(1 from header, 0 from body) — break=1, continue=0 + // Payload PHI: φ(0 from header, i_next_body from body) — iteration counter + // Stage 2: computed フラグでBody計算を明示 + // Args: + // blocks: ブロックIDマップ + // Returns: + // JSON: {"tag":{...},"payload":{...}} + _build_dispatch_phis_json(self, blocks) { + local header = blocks.get("header") + local body = blocks.get("body") + + local json = "{" + + // Tag PHI: break(1) / continue(0) signal + json = json + "\"tag\":{" + json = json + "\"dst\":0" // Placeholder, C++ が決定 + json = json + ",\"incoming\":[" + json = json + "{\"value\":1,\"block\":" + header.toString() + "}" // Break from header + json = json + ",{\"value\":0,\"block\":" + body.toString() + "}" // Continue from body + json = json + "]}" + + // Payload PHI: iteration counter + json = json + ",\"payload\":{" + json = json + "\"dst\":0" // Placeholder, C++ が決定 + json = json + ",\"incoming\":[" + json = json + "{\"value\":0,\"block\":" + header.toString() + "}" // Break時は0(初期値) + json = json + ",{\"value\":0,\"block\":" + body.toString() + ",\"computed\":true}" // Continue時はi_next_body(hdr_phi + 1) + json = json + "]}" + + json = json + "}" + return json + } + + // Safepoint 情報を JSON 化 + // Args: + // options: オプション設定 + // Returns: + // JSON: {"enabled":true,"location":"loop_header"} + _build_safepoint_json(self, options) { + local enabled = 1 // Default: enabled + + // Options から設定を取得 + if options != null { + local has_safepoint = options.has("enable_safepoint") + if has_safepoint { + enabled = options.get("enable_safepoint") + } + } + + local json = "{" + json = json + "\"enabled\":" + if enabled != 0 { + json = json + "true" + } + if enabled == 0 { + json = json + "false" + } + json = json + ",\"location\":\"loop_header\"" + json = json + "}" + return json + } + + // エラーフォールバック + _loopform_error_fallback(self, message) { + // エラー時は空の JSON を返す(C++ backend がエラー処理) + return "{\"op\":\"loopform\",\"error\":\"" + message + "\"}" + } + + // デバッグ用 - 生成された命令の確認 + debug_loopform(self, loop_id, blocks, condition_vid, options) { + local json = me.lower_loopform(self, loop_id, blocks, condition_vid, options) + print("Generated LoopForm instruction: " + json) + return json + } + + // ヘルパー: blocks 検証(デバッグ用) + _validate_blocks(self, blocks) { + if blocks == null { + return 0 + } + + // 6つの必須ブロックが存在するか確認 + local keys = new ArrayBox() + keys.push("preheader") + keys.push("header") + keys.push("body") + keys.push("dispatch") + keys.push("latch") + keys.push("exit") + + local i = 0 + local len = keys.length() + loop(i < len) { + local key = keys.get(i) + local has_key = blocks.has(key) + + if has_key == 0 { + print("WARNING: Missing block key: " + key) + return 0 + } + + i = i + 1 + } + + return 1 + } +} diff --git a/lang/src/llvm_ir/instructions/phi.hako b/lang/src/llvm_ir/instructions/phi.hako new file mode 100644 index 00000000..d809b0f7 --- /dev/null +++ b/lang/src/llvm_ir/instructions/phi.hako @@ -0,0 +1,157 @@ +// LLVM PHI Instruction Box — Python phi.py のHakorune実装 +// MIR PHI命令(SSA値マージング)をJSON形式に変換し、C++バックエンドに渡す +// +// PHI命令はSSA形式で制御フローの合流点における値のマージを表現する +// 例: if (cond) { x = 1 } else { x = 2 } → x = PHI(1 from bb1, 2 from bb2) + +static box LLVMPhiInstructionBox { + + // メインエントリーポイント - Pythonのlower_phi()に相当 + // Stage 1: 基本PHI生成(JSON生成のみ) + // + // Args: + // dst: 出力先レジスタID(整数) + // incoming_list: incoming値のリスト + // 形式: [{"value":1,"block":1}, {"value":2,"block":2}, ...] + // - value: 入力値のレジスタID + // - block: その値が来る基本ブロックID + // + // Returns: + // JSON文字列: {"op":"phi","dst":5,"incoming":[...]} + // + lower_phi(dst, incoming_list) { + // 空チェック: incoming が空の場合は 0 定数を返す + // Python: phi.py 34-37行の動作と同じ + if incoming_list == null { + return me._phi_empty_fallback(dst) + } + + local list_len = incoming_list.length() + if list_len == 0 { + return me._phi_empty_fallback(dst) + } + + // incoming配列をJSON化 + local incoming_json = me._build_incoming_array(incoming_list) + + // PHI命令のJSON形式を生成 + // {"op":"phi","dst":5,"incoming":[{"value":1,"block":1},{"value":2,"block":2}]} + return "{\"op\":\"phi\",\"dst\":" + dst + ",\"incoming\":" + incoming_json + "}" + } + + // 空のPHI: 0定数にフォールバック + // Python: phi.py 34-37行 + _phi_empty_fallback(dst) { + // No incoming edges - use zero constant + return "{\"op\":\"const\",\"dst\":" + dst + ",\"value\":{\"type\":\"i64\",\"value\":0}}" + } + + // incoming配列のJSON化 + // + // Args: + // incoming_list: [{"value":1,"block":1}, {"value":2,"block":2}, ...] + // + // Returns: + // JSON配列文字列: [{"value":1,"block":1},{"value":2,"block":2}] + // + _build_incoming_array(incoming_list) { + local result = "[" + local first = 1 + + // 各incoming要素をJSON化 + local i = 0 + local len = incoming_list.length() + + loop(i < len) { + local item = incoming_list.get(i) + + // item は {"value":X, "block":Y} の形式のMapBox + local value_id = item.get("value") + local block_id = item.get("block") + + // カンマ区切り(最初の要素以外) + if first == 0 { + result = result + "," + } + first = 0 + + // {"value":X,"block":Y} 形式で追加 + result = result + "{\"value\":" + value_id + ",\"block\":" + block_id + "}" + + i = i + 1 + } + + result = result + "]" + return result + } + + // デバッグ用 - 生成された命令の確認 + debug_phi(dst, incoming_list) { + local json = me.lower_phi(dst, incoming_list) + print("Generated PHI instruction: " + json) + return json + } + + // Stage 2 プレースホルダー: Block End Values管理(将来実装) + // Python: phi.py 69-79行の block_end_values スナップショット処理 + // 注: Hakorune版では不要(C++バックエンドが処理) + lower_phi_with_snapshot(dst, incoming_list, block_end_values) { + // 現時点では基本版と同じ動作 + return me.lower_phi(dst, incoming_list) + } + + // Stage 3 プレースホルダー: 型変換処理(将来実装) + // Python: phi.py 84-103行の型変換処理 + // 注: Hakorune版では不要(C++バックエンドが処理) + lower_phi_with_type_info(dst, incoming_list, type_info) { + // 現時点では基本版と同じ動作 + return me.lower_phi(dst, incoming_list) + } + + // Stage 4 プレースホルダー: Strict Mode(将来実装) + // Python: phi.py 118-121行の NYASH_LLVM_PHI_STRICT チェック + // 注: C++バックエンドで実装予定 + lower_phi_strict(dst, incoming_list, strict_mode) { + // 現時点では基本版と同じ動作 + return me.lower_phi(dst, incoming_list) + } + + // Stage 5 プレースホルダー: 文字列性伝播(将来実装) + // Python: phi.py 131-142行の resolver.is_stringish() 処理 + // 注: C++バックエンドで実装予定 + lower_phi_with_string_propagation(dst, incoming_list, resolver) { + // 現時点では基本版と同じ動作 + return me.lower_phi(dst, incoming_list) + } + + // ヘルパー: incoming要素の検証(デバッグ用) + _validate_incoming(incoming_list) { + if incoming_list == null { + return 0 + } + + local len = incoming_list.length() + if len == 0 { + return 0 + } + + // 各要素が {"value":X, "block":Y} 形式か確認 + local i = 0 + loop(i < len) { + local item = incoming_list.get(i) + + // value と block フィールドが存在するか + local has_value = item.has("value") + local has_block = item.has("block") + + if has_value == 0 || has_block == 0 { + print("WARNING: Invalid incoming item at index " + i) + return 0 + } + + i = i + 1 + } + + return 1 + } +} diff --git a/lang/src/llvm_ir/instructions/ret.hako b/lang/src/llvm_ir/instructions/ret.hako new file mode 100644 index 00000000..69c0649a --- /dev/null +++ b/lang/src/llvm_ir/instructions/ret.hako @@ -0,0 +1,48 @@ +// LLVM Ret Instruction Box — Python ret.py のHakorune実装 +// MIRリターン命令をJSON形式に変換し、C++バックエンドに渡す + +static box LLVMRetInstructionBox { + + // メインエントリーポイント - Pythonのlower_return()に相当 + lower_return(value_id) { + if value_id == null || value_id == 0 { + // Void return + return me.inst_ret_void() + } else { + // Value return + return me.inst_ret_value(value_id) + } + } + + // Void return命令 + inst_ret_void() { + return "{\"op\":\"ret\",\"value\":null}" + } + + // Value return命令 + inst_ret_value(value_id) { + return "{\"op\":\"ret\",\"value\":" + value_id + "}" + } + + // 定数値を返す(ショートカット) + ret_const_i64(value) { + return "{\"op\":\"ret\",\"value\":null}" // 実際には定数命令 + ret命令が必要 + } + + // デバッグ用 - 生成された命令の確認 + debug_ret(value_id) { + local json = me.lower_return(value_id) + print("Generated ret instruction: " + json) + return json + } + + // プログラム全体のreturn生成(定数+returnの組み合わせ) + program_with_const_ret(const_value) { + local const_inst = "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + const_value + "}}" + local ret_inst = me.inst_ret_value(1) + + return "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [ { \"id\": 0, \"instructions\": [" + + const_inst + "," + + ret_inst + "] } ] } ] }" + } +} diff --git a/tests/phase33/smoke/loopform/for_counter.hako b/tests/phase33/smoke/loopform/for_counter.hako new file mode 100644 index 00000000..3868f86d --- /dev/null +++ b/tests/phase33/smoke/loopform/for_counter.hako @@ -0,0 +1,57 @@ +// LoopForm Smoke Test 2: Counter-based for loop +// Tests for loop with explicit counter using loopform +// +// Expected behavior (when C++ backend implements loopform): +// - Loop from 0 to 9 (10 iterations) +// - Use payload mode for structural counter +// - Return total iterations + +using "lang/src/llvm_ir/instructions/loopform.hako" as LoopFormInst + +static box Main { + main() { + print("=== LoopForm Smoke Test 2: for_counter ===") + + // Simulate for loop: for (i = 0; i < 10; i++) + local blocks = new MapBox() + blocks.set("preheader", 10) + blocks.set("header", 11) + blocks.set("body", 12) + blocks.set("dispatch", 13) + blocks.set("latch", 14) + blocks.set("exit", 15) + + // Use payload mode with max iterations + local options = new MapBox() + options.set("mode", "payload") + options.set("payload_max", 10) + options.set("enable_safepoint", 1) + + // Generate loopform JSON + local json = LoopFormInst.lower_loopform(2, blocks, 20, options) + + // Verify JSON structure + local has_loopform = json.indexOf("\"op\":\"loopform\"") + if has_loopform < 0 { + print("ERROR: loopform op not found") + return 1 + } + + local has_payload_mode = json.indexOf("\"mode\":\"payload\"") + if has_payload_mode < 0 { + print("ERROR: payload mode not found") + return 1 + } + + local has_max = json.indexOf("\"payload_max\":10") + if has_max < 0 { + print("ERROR: payload_max not found") + return 1 + } + + print("✓ PASS: for_counter loopform generated") + print("Note: Actual loop execution requires C++ backend implementation") + + return 0 + } +} diff --git a/tests/phase33/smoke/loopform/if_loop_merge.hako b/tests/phase33/smoke/loopform/if_loop_merge.hako new file mode 100644 index 00000000..433f559f --- /dev/null +++ b/tests/phase33/smoke/loopform/if_loop_merge.hako @@ -0,0 +1,65 @@ +// LoopForm Smoke Test 3: if-else + loop + merge +// Tests complex control flow with loopform +// +// Expected behavior (when C++ backend implements loopform): +// - Conditional branch before loop +// - Loop with early exit (break) +// - Merge point after loop +// - Return merged result + +using "lang/src/llvm_ir/instructions/loopform.hako" as LoopFormInst + +static box Main { + main() { + print("=== LoopForm Smoke Test 3: if_loop_merge ===") + + // Simulate: if (cond) { while (i < 3) { if (i == 2) break; i++; } } + local blocks = new MapBox() + blocks.set("preheader", 20) + blocks.set("header", 21) + blocks.set("body", 22) + blocks.set("dispatch", 23) + blocks.set("latch", 24) + blocks.set("exit", 25) + + // Use guard to combine condition and structural limit + local options = new MapBox() + options.set("mode", "mir") + options.set("use_guard", 1) + options.set("payload_max", 1000000) + options.set("enable_safepoint", 1) + + // Generate loopform JSON + local json = LoopFormInst.lower_loopform(3, blocks, 30, options) + + // Verify JSON structure + local has_loopform = json.indexOf("\"op\":\"loopform\"") + if has_loopform < 0 { + print("ERROR: loopform op not found") + return 1 + } + + local has_guard = json.indexOf("\"use_guard\":true") + if has_guard < 0 { + print("ERROR: use_guard not found") + return 1 + } + + local has_dispatch_tag = json.indexOf("\"tag\"") + if has_dispatch_tag < 0 { + print("ERROR: dispatch tag PHI not found") + return 1 + } + + local has_dispatch_payload = json.indexOf("\"payload\"") + if has_dispatch_payload < 0 { + print("ERROR: dispatch payload PHI not found") + return 1 + } + + print("✓ PASS: if_loop_merge loopform generated") + print("Note: Actual loop execution requires C++ backend implementation") + + return 0 + } +} diff --git a/tests/phase33/smoke/loopform/while_simple.hako b/tests/phase33/smoke/loopform/while_simple.hako new file mode 100644 index 00000000..9d032f49 --- /dev/null +++ b/tests/phase33/smoke/loopform/while_simple.hako @@ -0,0 +1,49 @@ +// LoopForm Smoke Test 1: Basic while loop +// Tests basic while loop structure with loopform +// +// Expected behavior (when C++ backend implements loopform): +// - Loop from 0 to 4 +// - Print each iteration +// - Return final counter value (5) + +using "lang/src/llvm_ir/instructions/loopform.hako" as LoopFormInst + +static box Main { + main() { + print("=== LoopForm Smoke Test 1: while_simple ===") + + // Simulate while loop: while (i < 5) { i++ } + local blocks = new MapBox() + blocks.set("preheader", 0) + blocks.set("header", 1) + blocks.set("body", 2) + blocks.set("dispatch", 3) + blocks.set("latch", 4) + blocks.set("exit", 5) + + local options = new MapBox() + options.set("mode", "mir") + options.set("enable_safepoint", 1) + + // Generate loopform JSON + local json = LoopFormInst.lower_loopform(1, blocks, 10, options) + + // Verify JSON structure + local has_loopform = json.indexOf("\"op\":\"loopform\"") + if has_loopform < 0 { + print("ERROR: loopform op not found") + return 1 + } + + local has_safepoint = json.indexOf("\"enabled\":true") + if has_safepoint < 0 { + print("ERROR: safepoint not enabled") + return 1 + } + + print("✓ PASS: while_simple loopform generated") + print("Note: Actual loop execution requires C++ backend implementation") + + return 0 + } +} diff --git a/tests/phase33/unit/loopform/test_basic.hako b/tests/phase33/unit/loopform/test_basic.hako new file mode 100644 index 00000000..f4d2e44b --- /dev/null +++ b/tests/phase33/unit/loopform/test_basic.hako @@ -0,0 +1,223 @@ +// LoopForm Instruction Box - Unit Test +// Stage 1: Basic LoopForm generation +// Stage 2: PHI incoming arrays + computed flags + +using "lang/src/llvm_ir/instructions/loopform.hako" as LoopFormInst + +static box Main { + main() { + print("=== LoopForm Instruction Unit Test (Stage 1 + 2) ===") + + // Test 1: 基本的な LoopForm 命令生成 + me.test_basic_loopform() + + // Test 2: Blocks 検証 + me.test_blocks_validation() + + // Test 3: Condition モード + me.test_condition_modes() + + // Test 4: PHI incoming 配列検証(Stage 2) + me.test_phi_incoming_arrays() + + print("=== All Tests Passed! ===") + return 0 + } + + // Test 1: 基本的な LoopForm 命令生成 + test_basic_loopform() { + print("\n[Test 1] Basic LoopForm generation") + + // Blocks マップを作成 + local blocks = new MapBox() + blocks.set("preheader", 10) + blocks.set("header", 11) + blocks.set("body", 12) + blocks.set("dispatch", 13) + blocks.set("latch", 14) + blocks.set("exit", 15) + + // Options (null でデフォルト使用) + local options = null + + local result = LoopFormInst.lower_loopform(1, blocks, 5, options) + + // 期待値: {"op":"loopform","loop_id":1,"blocks":{...},...} + print("Generated: " + result) + + // 簡易検証: "loopform" が含まれているか + local contains_op = result.indexOf("loopform") + if contains_op < 0 { + print("ERROR: loopform op not found") + return 1 + } + + // "loop_id":1 が含まれているか + local contains_id = result.indexOf("\"loop_id\":1") + if contains_id < 0 { + print("ERROR: loop_id not found") + return 1 + } + + // "blocks" が含まれているか + local contains_blocks = result.indexOf("\"blocks\"") + if contains_blocks < 0 { + print("ERROR: blocks not found") + return 1 + } + + // "header":11 が含まれているか + local contains_header = result.indexOf("\"header\":11") + if contains_header < 0 { + print("ERROR: header block not found") + return 1 + } + + print("✓ PASS: Basic LoopForm generation") + return 0 + } + + // Test 2: Blocks 検証 + test_blocks_validation() { + print("\n[Test 2] Blocks validation") + + local blocks = new MapBox() + blocks.set("preheader", 20) + blocks.set("header", 21) + blocks.set("body", 22) + blocks.set("dispatch", 23) + blocks.set("latch", 24) + blocks.set("exit", 25) + + local options = null + local result = LoopFormInst.lower_loopform(2, blocks, 10, options) + + // 全ブロックIDが含まれているか確認 + local has_preheader = result.indexOf("\"preheader\":20") + local has_header = result.indexOf("\"header\":21") + local has_body = result.indexOf("\"body\":22") + local has_dispatch = result.indexOf("\"dispatch\":23") + local has_latch = result.indexOf("\"latch\":24") + local has_exit = result.indexOf("\"exit\":25") + + if has_preheader < 0 || has_header < 0 || has_body < 0 || + has_dispatch < 0 || has_latch < 0 || has_exit < 0 { + print("ERROR: Not all blocks found") + return 1 + } + + print("✓ PASS: Blocks validation") + return 0 + } + + // Test 3: Condition モード + test_condition_modes() { + print("\n[Test 3] Condition modes") + + local blocks = new MapBox() + blocks.set("preheader", 30) + blocks.set("header", 31) + blocks.set("body", 32) + blocks.set("dispatch", 33) + blocks.set("latch", 34) + blocks.set("exit", 35) + + // Test 3a: MIR モード(デフォルト) + local options_mir = new MapBox() + options_mir.set("mode", "mir") + + local result_mir = LoopFormInst.lower_loopform(3, blocks, 15, options_mir) + + local has_mir_mode = result_mir.indexOf("\"mode\":\"mir\"") + if has_mir_mode < 0 { + print("ERROR: MIR mode not found") + return 1 + } + + print("✓ PASS: MIR mode") + + // Test 3b: Payload モード(実験的) + local options_payload = new MapBox() + options_payload.set("mode", "payload") + options_payload.set("payload_max", 500000) + + local result_payload = LoopFormInst.lower_loopform(4, blocks, 20, options_payload) + + local has_payload_mode = result_payload.indexOf("\"mode\":\"payload\"") + if has_payload_mode < 0 { + print("ERROR: Payload mode not found") + return 1 + } + + local has_max = result_payload.indexOf("\"payload_max\":500000") + if has_max < 0 { + print("ERROR: payload_max not found") + return 1 + } + + print("✓ PASS: Payload mode") + + return 0 + } + + // Test 4: PHI incoming 配列検証(Stage 2) + test_phi_incoming_arrays() { + print("\n[Test 4] PHI incoming arrays (Stage 2)") + + local blocks = new MapBox() + blocks.set("preheader", 40) + blocks.set("header", 41) + blocks.set("body", 42) + blocks.set("dispatch", 43) + blocks.set("latch", 44) + blocks.set("exit", 45) + + local options = null + local result = LoopFormInst.lower_loopform(5, blocks, 25, options) + + // Test 4a: Header PHI incoming 配列検証 + // Expected: {"dst":0,"incoming":[{"value":0,"block":40},{"value":0,"block":44,"computed":true}]} + local has_header_phi_incoming = result.indexOf("\"header_phi\"") + if has_header_phi_incoming < 0 { + print("ERROR: header_phi not found") + return 1 + } + + local has_incoming_array = result.indexOf("\"incoming\":[") + if has_incoming_array < 0 { + print("ERROR: incoming array not found") + return 1 + } + + local has_preheader_incoming = result.indexOf("{\"value\":0,\"block\":40}") + if has_preheader_incoming < 0 { + print("ERROR: preheader incoming not found") + return 1 + } + + local has_latch_incoming = result.indexOf("{\"value\":0,\"block\":44,\"computed\":true}") + if has_latch_incoming < 0 { + print("ERROR: latch incoming with computed flag not found") + return 1 + } + + print("✓ PASS: Header PHI incoming array") + + // Test 4b: Dispatch PHI computed フラグ検証 + local has_dispatch_phis = result.indexOf("\"dispatch_phis\"") + if has_dispatch_phis < 0 { + print("ERROR: dispatch_phis not found") + return 1 + } + + local has_payload_computed = result.indexOf("{\"value\":0,\"block\":42,\"computed\":true}") + if has_payload_computed < 0 { + print("ERROR: payload PHI computed flag not found") + return 1 + } + + print("✓ PASS: Dispatch PHI computed flags") + + return 0 + } +}