feat(joinir): Phase 30.x jsonir v0 - JoinIR JSON serialization
Implement JSON serialization for JoinIR module. Implementation: - src/mir/join_ir/json.rs: JSON serializer (~250 lines, no external deps) - src/tests/joinir_json_min.rs: Integration tests (8 unit + 2 integration) - 10 tests total, all passing Features: - JoinModule → JSON serialization - All instruction types: Call, Jump, Ret, Compute - All MirLikeInst types: Const, BinOp, Compare, BoxCall - Full ConstValue support: Integer, Bool, String, Null - Full operator coverage: Add/Sub/Mul/Div/Or/And, Lt/Le/Gt/Ge/Eq/Ne - JSON string escaping for special characters Usage: use crate::mir::join_ir::json::join_module_to_json_string; let json = join_module_to_json_string(&module); Non-goals (this phase): - CLI flag (--emit-joinir-json) - JSON → JoinIR reverse conversion 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
232
src/tests/joinir_json_min.rs
Normal file
232
src/tests/joinir_json_min.rs
Normal file
@ -0,0 +1,232 @@
|
||||
//! JoinIR JSON シリアライズテスト (Phase 30.x)
|
||||
//!
|
||||
//! 手動構築した JoinIR を JSON に変換し、構造の妥当性を検証する。
|
||||
|
||||
use crate::mir::join_ir::json::join_module_to_json_string;
|
||||
use crate::mir::join_ir::{
|
||||
BinOpKind, CompareOp, ConstValue, JoinContId, JoinFuncId, JoinFunction, JoinInst, JoinModule,
|
||||
MirLikeInst,
|
||||
};
|
||||
use crate::mir::ValueId;
|
||||
|
||||
/// 手動構築した JoinModule の JSON 出力テスト(NYASH_JOINIR_EXPERIMENT 不要)
|
||||
#[test]
|
||||
fn test_manual_joinir_json() {
|
||||
// skip_ws 相当の JoinIR を手動で構築
|
||||
let mut module = JoinModule::new();
|
||||
|
||||
// skip 関数: skip(s) -> i
|
||||
let mut skip_func = JoinFunction::new(
|
||||
JoinFuncId::new(0),
|
||||
"skip".to_string(),
|
||||
vec![ValueId(3000)], // s
|
||||
);
|
||||
|
||||
// i_init = 0
|
||||
skip_func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: ValueId(3001),
|
||||
value: ConstValue::Integer(0),
|
||||
}));
|
||||
|
||||
// n = s.length()
|
||||
skip_func.body.push(JoinInst::Compute(MirLikeInst::BoxCall {
|
||||
dst: Some(ValueId(3002)),
|
||||
box_name: "StringBox".to_string(),
|
||||
method: "length".to_string(),
|
||||
args: vec![ValueId(3000)],
|
||||
}));
|
||||
|
||||
// loop_step(s, i_init, n) - 末尾呼び出し
|
||||
skip_func.body.push(JoinInst::Call {
|
||||
func: JoinFuncId::new(1),
|
||||
args: vec![ValueId(3000), ValueId(3001), ValueId(3002)],
|
||||
k_next: None,
|
||||
dst: None,
|
||||
});
|
||||
|
||||
module.add_function(skip_func);
|
||||
|
||||
// loop_step 関数: loop_step(s, i, n) -> i
|
||||
let mut loop_step = JoinFunction::new(
|
||||
JoinFuncId::new(1),
|
||||
"loop_step".to_string(),
|
||||
vec![ValueId(3100), ValueId(3101), ValueId(3102)], // s, i, n
|
||||
);
|
||||
|
||||
// cond = i < n
|
||||
loop_step.body.push(JoinInst::Compute(MirLikeInst::Compare {
|
||||
dst: ValueId(3103),
|
||||
op: CompareOp::Lt,
|
||||
lhs: ValueId(3101),
|
||||
rhs: ValueId(3102),
|
||||
}));
|
||||
|
||||
// 条件分岐(簡略化: 条件付き ret)
|
||||
loop_step.body.push(JoinInst::Ret {
|
||||
value: Some(ValueId(3101)),
|
||||
});
|
||||
|
||||
module.add_function(loop_step);
|
||||
module.entry = Some(JoinFuncId::new(0));
|
||||
|
||||
// JSON に変換
|
||||
let json = join_module_to_json_string(&module);
|
||||
|
||||
// 構造チェック
|
||||
assert!(json.contains("\"version\":0"));
|
||||
assert!(json.contains("\"entry\":0"));
|
||||
assert!(json.contains("\"name\":\"skip\""));
|
||||
assert!(json.contains("\"name\":\"loop_step\""));
|
||||
|
||||
// 命令チェック
|
||||
assert!(json.contains("\"kind\":\"const\""));
|
||||
assert!(json.contains("\"kind\":\"boxcall\""));
|
||||
assert!(json.contains("\"kind\":\"compare\""));
|
||||
assert!(json.contains("\"type\":\"call\""));
|
||||
assert!(json.contains("\"type\":\"ret\""));
|
||||
|
||||
// 値チェック
|
||||
assert!(json.contains("\"value_type\":\"integer\""));
|
||||
assert!(json.contains("\"value\":0"));
|
||||
assert!(json.contains("\"box\":\"StringBox\""));
|
||||
assert!(json.contains("\"method\":\"length\""));
|
||||
assert!(json.contains("\"op\":\"lt\""));
|
||||
|
||||
eprintln!("[joinir/json] manual JoinIR JSON output:");
|
||||
eprintln!("{}", json);
|
||||
}
|
||||
|
||||
/// 全命令タイプの JSON 出力をカバーするテスト
|
||||
#[test]
|
||||
fn test_all_instruction_types_json() {
|
||||
let mut module = JoinModule::new();
|
||||
let mut func = JoinFunction::new(JoinFuncId::new(0), "all_types".to_string(), vec![]);
|
||||
|
||||
// Const - Integer
|
||||
func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: ValueId(1),
|
||||
value: ConstValue::Integer(42),
|
||||
}));
|
||||
|
||||
// Const - Bool
|
||||
func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: ValueId(2),
|
||||
value: ConstValue::Bool(true),
|
||||
}));
|
||||
|
||||
// Const - String
|
||||
func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: ValueId(3),
|
||||
value: ConstValue::String("hello".to_string()),
|
||||
}));
|
||||
|
||||
// Const - Null
|
||||
func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||
dst: ValueId(4),
|
||||
value: ConstValue::Null,
|
||||
}));
|
||||
|
||||
// BinOp - all types
|
||||
for (i, op) in [
|
||||
BinOpKind::Add,
|
||||
BinOpKind::Sub,
|
||||
BinOpKind::Mul,
|
||||
BinOpKind::Div,
|
||||
BinOpKind::Or,
|
||||
BinOpKind::And,
|
||||
]
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
func.body.push(JoinInst::Compute(MirLikeInst::BinOp {
|
||||
dst: ValueId(10 + i as u32),
|
||||
op: *op,
|
||||
lhs: ValueId(1),
|
||||
rhs: ValueId(1),
|
||||
}));
|
||||
}
|
||||
|
||||
// Compare - all types
|
||||
for (i, op) in [
|
||||
CompareOp::Lt,
|
||||
CompareOp::Le,
|
||||
CompareOp::Gt,
|
||||
CompareOp::Ge,
|
||||
CompareOp::Eq,
|
||||
CompareOp::Ne,
|
||||
]
|
||||
.iter()
|
||||
.enumerate()
|
||||
{
|
||||
func.body.push(JoinInst::Compute(MirLikeInst::Compare {
|
||||
dst: ValueId(20 + i as u32),
|
||||
op: *op,
|
||||
lhs: ValueId(1),
|
||||
rhs: ValueId(1),
|
||||
}));
|
||||
}
|
||||
|
||||
// BoxCall
|
||||
func.body.push(JoinInst::Compute(MirLikeInst::BoxCall {
|
||||
dst: Some(ValueId(30)),
|
||||
box_name: "TestBox".to_string(),
|
||||
method: "test_method".to_string(),
|
||||
args: vec![ValueId(1), ValueId(2)],
|
||||
}));
|
||||
|
||||
// Call
|
||||
func.body.push(JoinInst::Call {
|
||||
func: JoinFuncId::new(1),
|
||||
args: vec![ValueId(1)],
|
||||
k_next: Some(JoinContId::new(2)),
|
||||
dst: Some(ValueId(40)),
|
||||
});
|
||||
|
||||
// Jump (conditional)
|
||||
func.body.push(JoinInst::Jump {
|
||||
cont: JoinContId::new(3),
|
||||
args: vec![ValueId(1)],
|
||||
cond: Some(ValueId(2)),
|
||||
});
|
||||
|
||||
// Jump (unconditional)
|
||||
func.body.push(JoinInst::Jump {
|
||||
cont: JoinContId::new(4),
|
||||
args: vec![],
|
||||
cond: None,
|
||||
});
|
||||
|
||||
// Ret with value
|
||||
func.body.push(JoinInst::Ret {
|
||||
value: Some(ValueId(1)),
|
||||
});
|
||||
|
||||
module.add_function(func);
|
||||
|
||||
// JSON に変換
|
||||
let json = join_module_to_json_string(&module);
|
||||
|
||||
// 全 BinOp タイプをチェック
|
||||
assert!(json.contains("\"op\":\"add\""));
|
||||
assert!(json.contains("\"op\":\"sub\""));
|
||||
assert!(json.contains("\"op\":\"mul\""));
|
||||
assert!(json.contains("\"op\":\"div\""));
|
||||
assert!(json.contains("\"op\":\"or\""));
|
||||
assert!(json.contains("\"op\":\"and\""));
|
||||
|
||||
// 全 Compare タイプをチェック
|
||||
assert!(json.contains("\"op\":\"lt\""));
|
||||
assert!(json.contains("\"op\":\"le\""));
|
||||
assert!(json.contains("\"op\":\"gt\""));
|
||||
assert!(json.contains("\"op\":\"ge\""));
|
||||
assert!(json.contains("\"op\":\"eq\""));
|
||||
assert!(json.contains("\"op\":\"ne\""));
|
||||
|
||||
// 全 ConstValue タイプをチェック
|
||||
assert!(json.contains("\"value_type\":\"integer\""));
|
||||
assert!(json.contains("\"value_type\":\"bool\""));
|
||||
assert!(json.contains("\"value_type\":\"string\""));
|
||||
assert!(json.contains("\"value_type\":\"null\""));
|
||||
|
||||
eprintln!("[joinir/json] all_instruction_types test passed");
|
||||
}
|
||||
@ -6,6 +6,7 @@ pub mod identical_exec;
|
||||
pub mod identical_exec_collections;
|
||||
pub mod identical_exec_instance;
|
||||
pub mod identical_exec_string;
|
||||
pub mod joinir_json_min; // Phase 30.x: JoinIR JSON シリアライズテスト
|
||||
pub mod joinir_runner_min; // Phase 27.2: JoinIR 実行器 A/B 比較テスト
|
||||
pub mod joinir_runner_standalone; // Phase 27-shortterm S-3.2: JoinIR Runner 単体テスト
|
||||
pub mod joinir_vm_bridge_skip_ws; // Phase 27-shortterm S-4.4: JoinIR → Rust VM Bridge A/B Test
|
||||
|
||||
Reference in New Issue
Block a user